"use client"; import { useState } from "react"; import { deleteScope, duplicateScope, saveScopeValues, } from "@/actions/theme-builder"; import { ColorField } from "@/components/admin/color-field"; import { Button } from "@/components/ui/button"; import { BLOCK_KEY_PREFIX, type EffectKey, getBlocksByCategory, type LayoutKey, type MediaKey, } from "@/lib/theme-blocks"; import type { ThemeColorKey } from "@/lib/theme-presets"; interface ScopeInfo { id: number; name: string; type: string; parentId: number | null; siteDomain: string | null; routePath: string | null; moduleId: string | null; isActive: boolean; } interface ScopeValues { light: Record; dark: Record; blocks: Record; layout: Record; effects: Record; media: Record; custom: Record; } // ─── Color fields ──────────────────────────────────────────────────────────── const COLOR_FIELDS: Array<{ key: ThemeColorKey; label: string; def: string; desc: string; bgKey?: string; }> = [ { key: "color_background", label: "Page background", def: "#f8fafc", desc: "Main page background", }, { key: "color_surface", label: "Card / surface", def: "#ffffff", desc: "Cards, panels, elevated surfaces", }, { key: "color_dropdown", label: "Dropdown", def: "#ffffff", desc: "Dropdown menus", }, { key: "color_navbar", label: "Navbar", def: "#ffffff", desc: "Navigation bar background", }, { key: "color_navbar_text", label: "Navbar text", def: "#1e293b", desc: "Nav text color", bgKey: "color_navbar", }, { key: "color_text", label: "Body text", def: "#0f172a", desc: "Main text color", bgKey: "color_surface", }, { key: "color_text_muted", label: "Muted text", def: "#64748b", desc: "Secondary text", bgKey: "color_surface", }, { key: "color_primary", label: "Primary accent", def: "#f59e0b", desc: "Main brand color", }, { key: "color_accent", label: "Secondary accent", def: "#10b981", desc: "Secondary brand color", }, { key: "color_success", label: "Success", def: "#16a34a", desc: "Success states", }, { key: "color_warning", label: "Warning", def: "#eab308", desc: "Warning states", }, { key: "color_error", label: "Error", def: "#ef4444", desc: "Error states" }, { key: "color_info", label: "Info", def: "#0ea5e9", desc: "Information states", }, { key: "button_primary_color", label: "Button primary", def: "#f59e0b", desc: "Primary button background", }, { key: "button_text_color", label: "Button primary text", def: "#1e293b", desc: "Primary button text", }, { key: "button_secondary_color", label: "Button secondary", def: "#22c55e", desc: "Secondary button background", }, { key: "button_secondary_text_color", label: "Button secondary text", def: "#ffffff", desc: "Secondary button text", }, { key: "button_danger_color", label: "Button danger", def: "#ef4444", desc: "Danger button background", }, { key: "button_danger_text_color", label: "Button danger text", def: "#ffffff", desc: "Danger button text", }, { key: "button_outline_color", label: "Button outline", def: "#eeb425", desc: "Outline button border", }, { key: "button_outline_text_color", label: "Button outline text", def: "#1a1a2e", desc: "Outline button text", }, { key: "link_color", label: "Link color", def: "#b77900", desc: "Link text color", }, { key: "link_hover_color", label: "Link hover", def: "#8a5b00", desc: "Link hover color", }, { key: "border_color", label: "Border color", def: "#eeb425", desc: "General borders", }, { key: "panel_border_color", label: "Panel border", def: "#e9b124", desc: "Panel borders", }, { key: "gradient_from", label: "Gradient start", def: "#f59e0b", desc: "Gradient from color", }, { key: "gradient_to", label: "Gradient end", def: "#10b981", desc: "Gradient to color", }, ]; // ─── Layout fields ─────────────────────────────────────────────────────────── const LAYOUT_FIELDS: Array<{ key: LayoutKey; label: string; def: string; desc: string; type?: string; }> = [ { key: "layout:max_width", label: "Max Width", def: "1280px", desc: "Maximum content width", }, { key: "layout:spacing", label: "Grid Spacing", def: "1.5rem", desc: "Gap between grid items", }, { key: "layout:grid_columns", label: "Grid Columns", def: "12", desc: "Number of grid columns", type: "number", }, { key: "layout:content_padding", label: "Content Padding", def: "0.75rem", desc: "Horizontal padding on content", }, { key: "layout:navbar_height", label: "Navbar Height", def: "56px", desc: "Height of the navigation bar", }, ]; // ─── Effect fields ─────────────────────────────────────────────────────────── const EFFECT_FIELDS: Array<{ key: EffectKey; label: string; def: string; desc: string; type?: string; }> = [ { key: "effect:card_shadow", label: "Card Shadow", def: "0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04)", desc: "Default card box shadow", }, { key: "effect:card_shadow_hover", label: "Card Shadow (hover)", def: "0 8px 24px rgba(0,0,0,0.1), 0 2px 6px rgba(0,0,0,0.06)", desc: "Card box shadow on hover", }, { key: "effect:border_style", label: "Border Style", def: "solid", desc: "CSS border-style (solid, dashed, dotted, etc.)", }, { key: "effect:border_width", label: "Border Width", def: "1px", desc: "Default border width", }, { key: "effect:transition_duration", label: "Transition Duration", def: "200ms", desc: "Duration for hover/transition effects", }, { key: "effect:animation_scale", label: "Animation Scale", def: "1", desc: "Scale factor for animations (1 = normal)", type: "number", }, ]; // ─── Media fields ──────────────────────────────────────────────────────────── const MEDIA_FIELDS: Array<{ key: MediaKey; label: string; def: string; desc: string; type?: string; }> = [ { key: "media:logo_url", label: "Logo URL", def: "", desc: "Custom logo image URL (overrides default)", }, { key: "media:background_image", label: "Background Image", def: "", desc: "Page background image URL", }, { key: "media:background_position", label: "Background Position", def: "center", desc: "CSS background-position", }, { key: "media:background_size", label: "Background Size", def: "cover", desc: "CSS background-size (cover, contain, auto)", }, { key: "media:background_repeat", label: "Background Repeat", def: "no-repeat", desc: "CSS background-repeat", }, ]; // ─── Helpers ───────────────────────────────────────────────────────────────── function getVal( values: ScopeValues | null, key: string, mode: "light" | "dark", ): string { if (!values) return ""; if (key.startsWith("block:")) return values.blocks[key] ?? ""; if (key.startsWith("layout:")) return values.layout[key] ?? ""; if (key.startsWith("effect:")) return values.effects[key] ?? ""; if (key.startsWith("media:")) return values.media[key] ?? ""; if (key.startsWith("custom:")) return values.custom[key] ?? ""; if (mode === "dark") return values.dark[key] ?? ""; return values.light[key] ?? ""; } const TYPE_LABELS: Record = { global: "🌍 Global", site: "🌐 Site", module: "📦 Module", route: "📄 Route", }; type Tab = "colors" | "blocks" | "layout" | "effects" | "media" | "custom"; // ─── Main Component ────────────────────────────────────────────────────────── export function ThemeEditor({ scopeId, scopes, values, }: { scopeId: number; scopes: ScopeInfo[]; values: ScopeValues; }) { const [mode, setMode] = useState<"light" | "dark">("light"); const [tab, setTab] = useState("colors"); const scope = scopes.find((s) => s.id === scopeId); if (!scope) return null; const tabs: Array<{ id: Tab; label: string; icon: string }> = [ { id: "colors", label: "Colors", icon: "🎨" }, { id: "blocks", label: "Blocks", icon: "🧩" }, { id: "layout", label: "Layout", icon: "📐" }, { id: "effects", label: "Effects", icon: "✨" }, { id: "media", label: "Media", icon: "🖼" }, { id: "custom", label: "Custom", icon: "💻" }, ]; return (
{/* Header */}

{TYPE_LABELS[scope.type] ?? scope.type} — {scope.name}

{scope.type === "route" && `Path: ${scope.routePath}`} {scope.type === "module" && `Module: ${scope.moduleId}`} {scope.type === "site" && `Domain: ${scope.siteDomain}`} {scope.type === "global" && "Applies to all pages (default theme)"}

{scope.type !== "global" ? (
) : null}
{/* Mode toggle (only for colors tab) */} {tab === "colors" && (
Editing:
)} {/* Tabs */}
{tabs.map((t) => ( ))}
{/* Tab content */}
{tab === "colors" && } {tab === "blocks" && } {tab === "layout" && } {tab === "effects" && } {tab === "media" && } {tab === "custom" && }
); } // ─── Colors Tab ────────────────────────────────────────────────────────────── function ColorsTab({ values, mode, }: { values: ScopeValues; mode: "light" | "dark"; }) { return (

Colors ({mode} mode)

Only values you set here override the parent scope. Leave empty to inherit.

{COLOR_FIELDS.map((field) => ( ))}
); } // ─── Blocks Tab ────────────────────────────────────────────────────────────── function BlocksTab({ values }: { values: ScopeValues }) { const grouped = getBlocksByCategory(); const categoryLabels: Record = { chrome: "Site Chrome", layout: "Layout", components: "Components", effects: "Effects", }; return (
{Object.entries(grouped).map(([category, blocks]) => (

{categoryLabels[category] ?? category}

Toggle visibility of blocks in this scope. Hidden blocks use{" "} display: none .

{blocks.map((block) => { const key = `${BLOCK_KEY_PREFIX}${block.id}`; const currentVal = values.blocks[key]; const isChecked = currentVal === "true" || (currentVal === undefined && block.defaultVisible); return ( ); })}
))}
); } // ─── Layout Tab ────────────────────────────────────────────────────────────── function LayoutTab({ values }: { values: ScopeValues }) { return (

Layout Settings

Control spacing, width, and grid settings for this scope. Values are applied as CSS custom properties.

{LAYOUT_FIELDS.map((field) => (
))}
); } // ─── Effects Tab ───────────────────────────────────────────────────────────── function EffectsTab({ values }: { values: ScopeValues }) { return (

Effects & Transitions

Control shadows, borders, and animation timing for this scope.

{EFFECT_FIELDS.map((field) => (
))}
); } // ─── Media Tab ─────────────────────────────────────────────────────────────── function MediaTab({ values }: { values: ScopeValues }) { return (

Media & Backgrounds

Set custom logos, background images, and background properties for this scope.

{MEDIA_FIELDS.map((field) => (
))}
); } // ─── Custom Tab ────────────────────────────────────────────────────────────── function CustomTab({ values }: { values: ScopeValues }) { return (

Custom CSS

Add custom CSS that applies within this scope. Use{" "} &{" "} {" "} as a placeholder for the scope selector (e.g.{" "} & .content-card {"{"} border: 2px solid red; {"}"} ).