Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb35e49981 |
+297
-249
@@ -16,7 +16,7 @@ import {
|
||||
verticalListSortingStrategy,
|
||||
} from "@dnd-kit/sortable"
|
||||
import { CSS } from "@dnd-kit/utilities"
|
||||
import { AlignCenter, AlignJustify, AlignLeft, AlignRight, ChevronLeft, ChevronRight, Copy, Download, Eye, GripVertical, Maximize2, Minimize2, Monitor, Palette, PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen, Plus, Settings2, Smartphone, Tablet, Trash2, Type, Underline } from "lucide-react"
|
||||
import { Box, ChevronLeft, ChevronRight, Copy, Download, Eye, GripVertical, Link2, Link2Off, Maximize2, Minimize2, Monitor, Palette, PanelLeftClose, PanelLeftOpen, PanelRightClose, PanelRightOpen, Plus, Settings2, Smartphone, Tablet, Trash2 } from "lucide-react"
|
||||
|
||||
import { BuilderPreview } from "@/components/builder-preview"
|
||||
import { OpenInHButton } from "@/components/open-in-h-button"
|
||||
@@ -39,17 +39,25 @@ import {
|
||||
SelectValue,
|
||||
} from "@/registry/default/ui/select"
|
||||
import { Separator } from "@/registry/default/ui/separator"
|
||||
import { Slider } from "@/registry/default/ui/slider"
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "@/registry/default/ui/tabs"
|
||||
import {
|
||||
ToggleGroup,
|
||||
ToggleGroupItem,
|
||||
} from "@/registry/default/ui/toggle-group"
|
||||
|
||||
interface BoxModelValue {
|
||||
top?: string
|
||||
right?: string
|
||||
bottom?: string
|
||||
left?: string
|
||||
}
|
||||
|
||||
interface BoxModel {
|
||||
margin?: BoxModelValue
|
||||
padding?: BoxModelValue
|
||||
border?: BoxModelValue
|
||||
}
|
||||
|
||||
interface PageItem {
|
||||
id: string
|
||||
@@ -59,8 +67,16 @@ interface PageItem {
|
||||
layoutType?: "flex" | "grid" | "stack"
|
||||
children?: PageItem[]
|
||||
props?: Record<string, any>
|
||||
boxModel?: BoxModel
|
||||
}
|
||||
|
||||
// Tailwind spacing scale
|
||||
const SPACING_SCALE = [
|
||||
"0", "px", "0.5", "1", "1.5", "2", "2.5", "3", "3.5", "4", "5", "6", "7", "8",
|
||||
"9", "10", "11", "12", "14", "16", "20", "24", "28", "32", "36", "40", "44",
|
||||
"48", "52", "56", "60", "64", "72", "80", "96"
|
||||
]
|
||||
|
||||
export default function EnhancedBuilder() {
|
||||
const [blocks, setBlocks] = React.useState<string[]>([])
|
||||
const [components, setComponents] = React.useState<string[]>([])
|
||||
@@ -76,6 +92,11 @@ export default function EnhancedBuilder() {
|
||||
const [leftSidebarCollapsed, setLeftSidebarCollapsed] = React.useState(false)
|
||||
const [rightSidebarCollapsed, setRightSidebarCollapsed] = React.useState(false)
|
||||
|
||||
// Box model link states
|
||||
const [marginLinked, setMarginLinked] = React.useState(true)
|
||||
const [paddingLinked, setPaddingLinked] = React.useState(true)
|
||||
const [borderLinked, setBorderLinked] = React.useState(true)
|
||||
|
||||
React.useEffect(() => {
|
||||
// Get blocks from registry
|
||||
const blockIds = Object.keys(Index).filter((key) => {
|
||||
@@ -390,6 +411,37 @@ ${renderItems(pageItems, 3)}
|
||||
)
|
||||
}
|
||||
|
||||
const updateBoxModel = (
|
||||
id: string,
|
||||
property: "margin" | "padding" | "border",
|
||||
side: "top" | "right" | "bottom" | "left" | "all",
|
||||
value: string
|
||||
) => {
|
||||
setPageItems((items) =>
|
||||
items.map((item) => {
|
||||
if (item.id !== id) return item
|
||||
|
||||
const currentBoxModel = item.boxModel || {}
|
||||
const currentProperty = currentBoxModel[property] || {}
|
||||
|
||||
let newProperty: BoxModelValue
|
||||
if (side === "all") {
|
||||
newProperty = { top: value, right: value, bottom: value, left: value }
|
||||
} else {
|
||||
newProperty = { ...currentProperty, [side]: value }
|
||||
}
|
||||
|
||||
return {
|
||||
...item,
|
||||
boxModel: {
|
||||
...currentBoxModel,
|
||||
[property]: newProperty
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const addChildToContainer = (containerId: string, child: PageItem) => {
|
||||
setPageItems((items) =>
|
||||
items.map((item) =>
|
||||
@@ -802,281 +854,277 @@ ${renderItems(pageItems, 3)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Typography */}
|
||||
{/* Box Model */}
|
||||
<div className="space-y-3">
|
||||
<h3 className="text-sm font-semibold flex items-center gap-2">
|
||||
<Type className="h-4 w-4" />
|
||||
Typography
|
||||
<Box className="h-4 w-4" />
|
||||
Box Model
|
||||
</h3>
|
||||
|
||||
<div className="space-y-3">
|
||||
{/* Font Family */}
|
||||
<div className="space-y-2">
|
||||
{/* Margin */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Font Family
|
||||
Margin
|
||||
</label>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setMarginLinked(!marginLinked)}
|
||||
className="h-6 w-6 p-0"
|
||||
>
|
||||
{marginLinked ? (
|
||||
<Link2 className="h-3 w-3" />
|
||||
) : (
|
||||
<Link2Off className="h-3 w-3" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{marginLinked ? (
|
||||
<Select
|
||||
value={selectedItemData.props?.fontFamily || "default"}
|
||||
value={selectedItemData.boxModel?.margin?.top || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateItemProps(selectedItemData.id, {
|
||||
fontFamily: value === "default" ? undefined : value,
|
||||
})
|
||||
updateBoxModel(selectedItemData.id, "margin", "all", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select font" />
|
||||
<SelectValue placeholder="Select spacing" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="default">Default</SelectItem>
|
||||
<SelectItem value="font-sans">Sans Serif</SelectItem>
|
||||
<SelectItem value="font-serif">Serif</SelectItem>
|
||||
<SelectItem value="font-mono">Monospace</SelectItem>
|
||||
<SelectItem value="font-inter">Inter</SelectItem>
|
||||
<SelectItem value="font-roboto">Roboto</SelectItem>
|
||||
<SelectItem value="font-open-sans">Open Sans</SelectItem>
|
||||
<SelectItem value="font-lato">Lato</SelectItem>
|
||||
<SelectItem value="font-montserrat">Montserrat</SelectItem>
|
||||
<SelectItem value="font-poppins">Poppins</SelectItem>
|
||||
<SelectItem value="font-playfair">Playfair Display</SelectItem>
|
||||
<SelectItem value="font-merriweather">Merriweather</SelectItem>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* Font Size */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Font Size
|
||||
</label>
|
||||
<Select
|
||||
value={selectedItemData.props?.fontSize || "text-base"}
|
||||
onValueChange={(value) =>
|
||||
updateItemProps(selectedItemData.id, {
|
||||
fontSize: value === "text-base" ? undefined : value,
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="text-xs">Extra Small (xs)</SelectItem>
|
||||
<SelectItem value="text-sm">Small (sm)</SelectItem>
|
||||
<SelectItem value="text-base">Base</SelectItem>
|
||||
<SelectItem value="text-lg">Large (lg)</SelectItem>
|
||||
<SelectItem value="text-xl">Extra Large (xl)</SelectItem>
|
||||
<SelectItem value="text-2xl">2XL</SelectItem>
|
||||
<SelectItem value="text-3xl">3XL</SelectItem>
|
||||
<SelectItem value="text-4xl">4XL</SelectItem>
|
||||
<SelectItem value="text-5xl">5XL</SelectItem>
|
||||
<SelectItem value="text-6xl">6XL</SelectItem>
|
||||
<SelectItem value="text-7xl">7XL</SelectItem>
|
||||
<SelectItem value="text-8xl">8XL</SelectItem>
|
||||
<SelectItem value="text-9xl">9XL</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Top</label>
|
||||
<Select
|
||||
value={selectedItemData.boxModel?.margin?.top || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateBoxModel(selectedItemData.id, "margin", "top", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Right</label>
|
||||
<Select
|
||||
value={selectedItemData.boxModel?.margin?.right || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateBoxModel(selectedItemData.id, "margin", "right", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Bottom</label>
|
||||
<Select
|
||||
value={selectedItemData.boxModel?.margin?.bottom || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateBoxModel(selectedItemData.id, "margin", "bottom", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Left</label>
|
||||
<Select
|
||||
value={selectedItemData.boxModel?.margin?.left || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateBoxModel(selectedItemData.id, "margin", "left", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Font Weight */}
|
||||
<div className="space-y-2">
|
||||
{/* Padding */}
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Font Weight
|
||||
Padding
|
||||
</label>
|
||||
<Select
|
||||
value={selectedItemData.props?.fontWeight || "font-normal"}
|
||||
onValueChange={(value) =>
|
||||
updateItemProps(selectedItemData.id, {
|
||||
fontWeight: value === "font-normal" ? undefined : value,
|
||||
})
|
||||
}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => setPaddingLinked(!paddingLinked)}
|
||||
className="h-6 w-6 p-0"
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="font-thin">Thin (100)</SelectItem>
|
||||
<SelectItem value="font-extralight">Extra Light (200)</SelectItem>
|
||||
<SelectItem value="font-light">Light (300)</SelectItem>
|
||||
<SelectItem value="font-normal">Normal (400)</SelectItem>
|
||||
<SelectItem value="font-medium">Medium (500)</SelectItem>
|
||||
<SelectItem value="font-semibold">Semibold (600)</SelectItem>
|
||||
<SelectItem value="font-bold">Bold (700)</SelectItem>
|
||||
<SelectItem value="font-extrabold">Extra Bold (800)</SelectItem>
|
||||
<SelectItem value="font-black">Black (900)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{paddingLinked ? (
|
||||
<Link2 className="h-3 w-3" />
|
||||
) : (
|
||||
<Link2Off className="h-3 w-3" />
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Line Height */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Line Height
|
||||
</label>
|
||||
{paddingLinked ? (
|
||||
<Select
|
||||
value={selectedItemData.props?.lineHeight || "leading-normal"}
|
||||
value={selectedItemData.boxModel?.padding?.top || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateItemProps(selectedItemData.id, {
|
||||
lineHeight: value === "leading-normal" ? undefined : value,
|
||||
})
|
||||
updateBoxModel(selectedItemData.id, "padding", "all", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
<SelectValue placeholder="Select spacing" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="leading-none">None (1)</SelectItem>
|
||||
<SelectItem value="leading-tight">Tight (1.25)</SelectItem>
|
||||
<SelectItem value="leading-snug">Snug (1.375)</SelectItem>
|
||||
<SelectItem value="leading-normal">Normal (1.5)</SelectItem>
|
||||
<SelectItem value="leading-relaxed">Relaxed (1.625)</SelectItem>
|
||||
<SelectItem value="leading-loose">Loose (2)</SelectItem>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Top</label>
|
||||
<Select
|
||||
value={selectedItemData.boxModel?.padding?.top || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateBoxModel(selectedItemData.id, "padding", "top", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Right</label>
|
||||
<Select
|
||||
value={selectedItemData.boxModel?.padding?.right || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateBoxModel(selectedItemData.id, "padding", "right", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Bottom</label>
|
||||
<Select
|
||||
value={selectedItemData.boxModel?.padding?.bottom || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateBoxModel(selectedItemData.id, "padding", "bottom", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Left</label>
|
||||
<Select
|
||||
value={selectedItemData.boxModel?.padding?.left || "0"}
|
||||
onValueChange={(value) =>
|
||||
updateBoxModel(selectedItemData.id, "padding", "left", value)
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{SPACING_SCALE.map((scale) => (
|
||||
<SelectItem key={scale} value={scale}>
|
||||
{scale}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Letter Spacing */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Letter Spacing
|
||||
</label>
|
||||
<Select
|
||||
value={selectedItemData.props?.letterSpacing || "tracking-normal"}
|
||||
onValueChange={(value) =>
|
||||
updateItemProps(selectedItemData.id, {
|
||||
letterSpacing: value === "tracking-normal" ? undefined : value,
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="tracking-tighter">Tighter (-0.05em)</SelectItem>
|
||||
<SelectItem value="tracking-tight">Tight (-0.025em)</SelectItem>
|
||||
<SelectItem value="tracking-normal">Normal (0)</SelectItem>
|
||||
<SelectItem value="tracking-wide">Wide (0.025em)</SelectItem>
|
||||
<SelectItem value="tracking-wider">Wider (0.05em)</SelectItem>
|
||||
<SelectItem value="tracking-widest">Widest (0.1em)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* Text Alignment */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Text Alignment
|
||||
</label>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
value={selectedItemData.props?.textAlign || "text-left"}
|
||||
onValueChange={(value) => {
|
||||
if (value) {
|
||||
updateItemProps(selectedItemData.id, {
|
||||
textAlign: value === "text-left" ? undefined : value,
|
||||
})
|
||||
}
|
||||
}}
|
||||
className="justify-start"
|
||||
>
|
||||
<ToggleGroupItem value="text-left" aria-label="Align left">
|
||||
<AlignLeft className="h-4 w-4" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="text-center" aria-label="Align center">
|
||||
<AlignCenter className="h-4 w-4" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="text-right" aria-label="Align right">
|
||||
<AlignRight className="h-4 w-4" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="text-justify" aria-label="Justify">
|
||||
<AlignJustify className="h-4 w-4" />
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
|
||||
{/* Text Transform */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Text Transform
|
||||
</label>
|
||||
<Select
|
||||
value={selectedItemData.props?.textTransform || "normal-case"}
|
||||
onValueChange={(value) =>
|
||||
updateItemProps(selectedItemData.id, {
|
||||
textTransform: value === "normal-case" ? undefined : value,
|
||||
})
|
||||
}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="normal-case">Normal Case</SelectItem>
|
||||
<SelectItem value="uppercase">UPPERCASE</SelectItem>
|
||||
<SelectItem value="lowercase">lowercase</SelectItem>
|
||||
<SelectItem value="capitalize">Capitalize</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* Text Decoration */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Text Decoration
|
||||
</label>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
value={selectedItemData.props?.textDecoration || "no-underline"}
|
||||
onValueChange={(value) => {
|
||||
if (value) {
|
||||
updateItemProps(selectedItemData.id, {
|
||||
textDecoration: value === "no-underline" ? undefined : value,
|
||||
})
|
||||
}
|
||||
}}
|
||||
className="justify-start"
|
||||
>
|
||||
<ToggleGroupItem value="no-underline" aria-label="No decoration">
|
||||
None
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="underline" aria-label="Underline">
|
||||
<Underline className="h-4 w-4" />
|
||||
</ToggleGroupItem>
|
||||
<ToggleGroupItem value="line-through" aria-label="Line through">
|
||||
<span className="text-sm">Strike</span>
|
||||
</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
|
||||
{/* Font Color */}
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
Font Color
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
type="color"
|
||||
value={selectedItemData.props?.color || "#000000"}
|
||||
onChange={(e) =>
|
||||
updateItemProps(selectedItemData.id, {
|
||||
color: e.target.value,
|
||||
})
|
||||
}
|
||||
className="h-10 w-20"
|
||||
/>
|
||||
<Input
|
||||
placeholder="e.g. text-primary"
|
||||
value={selectedItemData.props?.textColor || ""}
|
||||
onChange={(e) =>
|
||||
updateItemProps(selectedItemData.id, {
|
||||
textColor: e.target.value,
|
||||
})
|
||||
}
|
||||
className="flex-1"
|
||||
/>
|
||||
{/* Visual Box Model Diagram */}
|
||||
<div className="rounded-lg border bg-muted/50 p-4">
|
||||
<div className="space-y-1 text-center">
|
||||
<div className="text-xs font-medium text-orange-500">
|
||||
Margin: {selectedItemData.boxModel?.margin?.top || "0"}
|
||||
</div>
|
||||
<div className="rounded border-2 border-orange-200 bg-orange-50 p-3 dark:border-orange-900 dark:bg-orange-950/20">
|
||||
<div className="text-xs font-medium text-blue-500">
|
||||
Padding: {selectedItemData.boxModel?.padding?.top || "0"}
|
||||
</div>
|
||||
<div className="mt-1 rounded border-2 border-blue-200 bg-blue-50 p-3 dark:border-blue-900 dark:bg-blue-950/20">
|
||||
<div className="text-xs font-medium text-foreground">
|
||||
Content
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Use color picker or Tailwind class
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user