@easybits.cloud/html-tailwind-generator 0.2.109 → 0.2.111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TSRXGD7T.js → chunk-5MDDRBEO.js} +5 -2
- package/dist/chunk-5MDDRBEO.js.map +1 -0
- package/dist/{chunk-2KKW53BF.js → chunk-C4D2NT5N.js} +31 -2
- package/dist/{chunk-2KKW53BF.js.map → chunk-C4D2NT5N.js.map} +1 -1
- package/dist/{chunk-K2OYJF74.js → chunk-JDBCNVE7.js} +14 -3
- package/dist/chunk-JDBCNVE7.js.map +1 -0
- package/dist/components.js +1 -1
- package/dist/generate.d.ts +11 -3
- package/dist/generate.js +1 -1
- package/dist/index.js +3 -3
- package/dist/refine.d.ts +2 -0
- package/dist/refine.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-K2OYJF74.js.map +0 -1
- package/dist/chunk-TSRXGD7T.js.map +0 -1
|
@@ -411,7 +411,10 @@ function FloatingToolbar({
|
|
|
411
411
|
setRefImageName(null);
|
|
412
412
|
setShowTagPicker(false);
|
|
413
413
|
setActiveTab(null);
|
|
414
|
-
|
|
414
|
+
const isText = ["P", "SPAN", "H1", "H2", "H3", "H4", "H5", "H6", "BLOCKQUOTE", "LI", "A"].includes(selection?.tagName ?? "");
|
|
415
|
+
if (!isText) {
|
|
416
|
+
setTimeout(() => inputRef.current?.focus(), 50);
|
|
417
|
+
}
|
|
415
418
|
}, [selection?.sectionId, selection?.elementPath]);
|
|
416
419
|
useEffect2(() => {
|
|
417
420
|
if (selection?.attrs) {
|
|
@@ -1363,4 +1366,4 @@ export {
|
|
|
1363
1366
|
ViewportToggle,
|
|
1364
1367
|
useUndoStack
|
|
1365
1368
|
};
|
|
1366
|
-
//# sourceMappingURL=chunk-
|
|
1369
|
+
//# sourceMappingURL=chunk-5MDDRBEO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/Canvas.tsx","../src/components/SectionList.tsx","../src/components/FloatingToolbar.tsx","../src/components/CodeEditor.tsx","../src/components/ViewportToggle.tsx","../src/hooks/useUndoStack.ts"],"sourcesContent":["import React, { useRef, useEffect, useCallback, useState, forwardRef, useImperativeHandle } from \"react\";\nimport type { Section3, IframeMessage } from \"../types\";\nimport { buildPreviewHtml } from \"../buildHtml\";\n\nexport interface CanvasHandle {\n scrollToSection: (id: string) => void;\n postMessage: (msg: Record<string, unknown>) => void;\n}\n\ninterface CanvasProps {\n sections: Section3[];\n theme?: string;\n onMessage: (msg: IframeMessage) => void;\n iframeRectRef: React.MutableRefObject<DOMRect | null>;\n onReady?: () => void;\n}\n\nexport const Canvas = forwardRef<CanvasHandle, CanvasProps>(function Canvas({ sections, theme, onMessage, iframeRectRef, onReady: onReadyProp }, ref) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const [ready, setReady] = useState(false);\n // Track what the iframe currently has so we can diff\n const knownSectionsRef = useRef<Map<string, string>>(new Map());\n const initializedRef = useRef(false);\n const onReadyRef = useRef(onReadyProp);\n onReadyRef.current = onReadyProp;\n\n // Post a message to the iframe\n const postToIframe = useCallback((msg: Record<string, unknown>) => {\n iframeRef.current?.contentWindow?.postMessage(msg, \"*\");\n }, []);\n\n useImperativeHandle(ref, () => ({\n scrollToSection(id: string) {\n postToIframe({ action: \"scroll-to-section\", id });\n },\n postMessage(msg: Record<string, unknown>) {\n postToIframe(msg);\n },\n }), [postToIframe]);\n\n // Initial write: set up the iframe shell (empty body + script + tailwind)\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe || initializedRef.current) return;\n initializedRef.current = true;\n\n const html = buildPreviewHtml([]);\n const doc = iframe.contentDocument;\n if (!doc) return;\n doc.open();\n doc.write(html);\n doc.close();\n }, []);\n\n // Handle \"ready\" from iframe — then inject current sections\n const handleReady = useCallback(() => {\n setReady(true);\n // Inject all current sections\n const sorted = [...sections].sort((a, b) => a.order - b.order);\n for (const s of sorted) {\n postToIframe({ action: \"add-section\", id: s.id, html: s.html, scroll: false });\n knownSectionsRef.current.set(s.id, s.html);\n }\n // Restore scroll position from sessionStorage\n const savedY = sessionStorage.getItem(\"landing-v3-iframe-scrollY\");\n if (savedY) {\n setTimeout(() => postToIframe({ action: \"restore-scroll\", y: Number(savedY) }), 100);\n }\n onReadyRef.current?.();\n }, [sections, postToIframe]);\n\n // Incremental diff: detect added/updated/removed/renamed sections\n useEffect(() => {\n if (!ready) return;\n\n const known = knownSectionsRef.current;\n const currentIds = new Set(sections.map((s) => s.id));\n const sorted = [...sections].sort((a, b) => a.order - b.order);\n\n // Detect renames: a known id disappears and a new id appears at the same index\n const removedIds = [...known.keys()].filter((id) => !currentIds.has(id));\n const addedSections = sorted.filter((s) => !known.has(s.id));\n\n // Match removed → added by position for rename (e.g. __building__ → real id)\n const renamedSet = new Set<string>();\n for (const removedId of removedIds) {\n if (addedSections.length > 0) {\n const added = addedSections.shift()!;\n postToIframe({ action: \"rename-section\", oldId: removedId, newId: added.id, html: added.html });\n known.delete(removedId);\n known.set(added.id, added.html);\n renamedSet.add(added.id);\n }\n }\n\n // Add truly new sections (not renamed)\n for (const s of sorted) {\n if (renamedSet.has(s.id)) continue;\n if (!known.has(s.id)) {\n postToIframe({ action: \"add-section\", id: s.id, html: s.html, scroll: s.id !== \"__building__\" });\n known.set(s.id, s.html);\n } else if (known.get(s.id) !== s.html) {\n // Update changed sections\n postToIframe({ action: \"update-section\", id: s.id, html: s.html });\n known.set(s.id, s.html);\n }\n }\n\n // Remove deleted sections (that weren't renamed)\n for (const id of [...known.keys()]) {\n if (!currentIds.has(id)) {\n postToIframe({ action: \"remove-section\", id });\n known.delete(id);\n }\n }\n\n // Reorder if needed\n const knownOrder = [...known.keys()];\n const desiredOrder = sorted.map((s) => s.id);\n if (knownOrder.length !== desiredOrder.length || knownOrder.some((id, i) => id !== desiredOrder[i])) {\n postToIframe({ action: \"reorder-sections\", order: desiredOrder });\n // Rebuild Map in new order so subsequent diffs compare correctly\n const reordered = new Map<string, string>();\n for (const id of desiredOrder) {\n const html = known.get(id);\n if (html !== undefined) reordered.set(id, html);\n }\n knownSectionsRef.current = reordered;\n }\n }, [sections, ready, postToIframe]);\n\n // Send theme changes to iframe\n useEffect(() => {\n if (!ready) return;\n postToIframe({ action: \"set-theme\", theme: theme || \"default\" });\n }, [theme, ready, postToIframe]);\n\n // Update iframe rect on resize/scroll\n const updateRect = useCallback(() => {\n if (iframeRef.current) {\n iframeRectRef.current = iframeRef.current.getBoundingClientRect();\n }\n }, [iframeRectRef]);\n\n useEffect(() => {\n updateRect();\n window.addEventListener(\"resize\", updateRect);\n window.addEventListener(\"scroll\", updateRect, true);\n return () => {\n window.removeEventListener(\"resize\", updateRect);\n window.removeEventListener(\"scroll\", updateRect, true);\n };\n }, [updateRect]);\n\n // Periodically save iframe scroll position\n useEffect(() => {\n if (!ready) return;\n const interval = setInterval(() => {\n postToIframe({ action: \"get-scroll\" });\n }, 2000);\n return () => clearInterval(interval);\n }, [ready, postToIframe]);\n\n // Listen for postMessage from iframe\n useEffect(() => {\n function handleMessage(e: MessageEvent) {\n const data = e.data;\n if (!data || typeof data.type !== \"string\") return;\n\n if (data.type === \"ready\") {\n handleReady();\n return;\n }\n\n if (data.type === \"scroll-position\") {\n sessionStorage.setItem(\"landing-v3-iframe-scrollY\", String(data.y));\n return;\n }\n\n if (\n [\"element-selected\", \"element-contextmenu\", \"text-edited\", \"element-deselected\", \"section-html-updated\", \"undo\", \"redo\"].includes(\n data.type\n )\n ) {\n // Sync known HTML so the diff doesn't re-send to iframe\n if (data.type === \"section-html-updated\" && data.sectionId && data.sectionHtml) {\n knownSectionsRef.current.set(data.sectionId, data.sectionHtml);\n }\n updateRect();\n onMessage(data as IframeMessage);\n }\n }\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [onMessage, updateRect, handleReady]);\n\n return (\n <div className=\"flex-1 overflow-hidden relative\">\n <iframe\n ref={iframeRef}\n title=\"Landing preview\"\n className=\"w-full h-full border-0\"\n sandbox=\"allow-scripts allow-same-origin\"\n style={{ minHeight: \"calc(100vh - 120px)\" }}\n />\n {!ready && sections.length > 0 && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-white/80\">\n <span className=\"w-6 h-6 border-2 border-gray-400 border-t-gray-800 rounded-full animate-spin\" />\n </div>\n )}\n <a href=\"https://www.easybits.cloud\" target=\"_blank\" rel=\"noopener noreferrer\"\n className=\"absolute bottom-2 right-3 text-xs text-gray-400 hover:text-gray-600 transition-colors\">\n Powered by easybits.cloud\n </a>\n </div>\n );\n});\n","import React, { useRef, useState } from \"react\";\nimport type { Section3 } from \"../types\";\nimport { LANDING_THEMES, type CustomColors } from \"../themes\";\n\ninterface SectionListProps {\n sections: Section3[];\n selectedSectionId: string | null;\n theme: string;\n customColors?: CustomColors;\n onThemeChange: (themeId: string) => void;\n onCustomColorChange?: (colors: Partial<CustomColors>) => void;\n onSelect: (id: string) => void;\n onOpenCode: (id: string) => void;\n onReorder: (fromIndex: number, toIndex: number) => void;\n onDelete: (id: string) => void;\n onRename: (id: string, label: string) => void;\n onAdd: () => void;\n}\n\nexport function SectionList({\n sections,\n selectedSectionId,\n theme,\n customColors,\n onThemeChange,\n onCustomColorChange,\n onSelect,\n onOpenCode,\n onReorder,\n onDelete,\n onRename,\n onAdd,\n}: SectionListProps) {\n const sorted = [...sections].sort((a, b) => a.order - b.order);\n const colorInputRef = useRef<HTMLInputElement>(null);\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editingLabel, setEditingLabel] = useState(\"\");\n\n return (\n <div className=\"flex flex-col flex-1 overflow-hidden\">\n <div className=\"p-3 border-b border-gray-200\">\n <h3 className=\"text-xs font-black uppercase tracking-wider text-gray-500 mb-2\">\n Tema\n </h3>\n <div className=\"flex gap-1.5 flex-wrap\">\n {LANDING_THEMES.map((t) => (\n <button\n key={t.id}\n onClick={() => onThemeChange(t.id)}\n title={t.label}\n className={`w-6 h-6 rounded-full border-2 transition-all ${\n theme === t.id\n ? \"border-black scale-110 shadow-sm\"\n : \"border-gray-300 hover:border-gray-400\"\n }`}\n style={{ backgroundColor: t.colors.primary }}\n />\n ))}\n {/* Custom color picker */}\n <button\n onClick={() => colorInputRef.current?.click()}\n title=\"Color personalizado\"\n className={`w-6 h-6 rounded-full border-2 transition-all relative overflow-hidden ${\n theme === \"custom\"\n ? \"border-black scale-110 shadow-sm\"\n : \"border-gray-300 hover:border-gray-400\"\n }`}\n style={theme === \"custom\" && customColors?.primary ? { backgroundColor: customColors.primary } : undefined}\n >\n {theme !== \"custom\" && (\n <span className=\"absolute inset-0 rounded-full\"\n style={{ background: \"conic-gradient(#ef4444, #eab308, #22c55e, #3b82f6, #a855f7, #ef4444)\" }}\n />\n )}\n </button>\n <input\n ref={colorInputRef}\n type=\"color\"\n value={customColors?.primary || \"#6366f1\"}\n onChange={(e) => onCustomColorChange?.({ primary: e.target.value })}\n className=\"sr-only\"\n />\n </div>\n {/* Multi-color pickers when custom theme is active */}\n {theme === \"custom\" && (\n <div className=\"flex items-center gap-2 mt-2\">\n {([\n { key: \"primary\" as const, label: \"Pri\", fallback: \"#6366f1\" },\n { key: \"secondary\" as const, label: \"Sec\", fallback: \"#f59e0b\" },\n { key: \"accent\" as const, label: \"Acc\", fallback: \"#06b6d4\" },\n { key: \"surface\" as const, label: \"Sur\", fallback: \"#ffffff\" },\n ]).map((c) => (\n <label key={c.key} className=\"flex flex-col items-center gap-0.5 cursor-pointer\">\n <input\n type=\"color\"\n value={customColors?.[c.key] || c.fallback}\n onChange={(e) => onCustomColorChange?.({ [c.key]: e.target.value })}\n className=\"w-5 h-5 rounded border border-gray-300 cursor-pointer p-0 [&::-webkit-color-swatch-wrapper]:p-0 [&::-webkit-color-swatch]:border-none [&::-webkit-color-swatch]:rounded\"\n />\n <span className=\"text-[9px] font-bold text-gray-400 uppercase\">{c.label}</span>\n </label>\n ))}\n </div>\n )}\n </div>\n <div className=\"p-3 border-b border-gray-200\">\n <h3 className=\"text-xs font-black uppercase tracking-wider text-gray-500\">\n Secciones\n </h3>\n </div>\n\n <div className=\"flex-1 overflow-y-auto py-1\">\n {sorted.map((section, i) => (\n <div\n key={section.id}\n onClick={() => onSelect(section.id)}\n className={`group flex items-center gap-2 px-3 py-2 cursor-pointer transition-colors ${\n selectedSectionId === section.id\n ? \"bg-blue-50 border-l-2 border-blue-500\"\n : \"hover:bg-gray-50 border-l-2 border-transparent\"\n }`}\n >\n <span className=\"text-[10px] font-mono text-gray-400 w-4 text-right\">\n {i + 1}\n </span>\n {editingId === section.id ? (\n <input\n type=\"text\"\n value={editingLabel}\n onChange={(e) => setEditingLabel(e.target.value)}\n onBlur={() => {\n if (editingLabel.trim()) onRename(section.id, editingLabel.trim());\n setEditingId(null);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n if (editingLabel.trim()) onRename(section.id, editingLabel.trim());\n setEditingId(null);\n } else if (e.key === \"Escape\") {\n setEditingId(null);\n }\n }}\n className=\"text-sm font-bold flex-1 min-w-0 bg-transparent border-b border-blue-500 outline-none px-0 py-0\"\n autoFocus\n onClick={(e) => e.stopPropagation()}\n />\n ) : (\n <span\n className=\"text-sm font-bold truncate flex-1\"\n onDoubleClick={(e) => {\n e.stopPropagation();\n setEditingId(section.id);\n setEditingLabel(section.label);\n }}\n >\n {section.label}\n </span>\n )}\n <div className=\"hidden group-hover:flex gap-0.5 shrink-0\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n onOpenCode(section.id);\n }}\n className=\"w-5 h-5 flex items-center justify-center rounded text-gray-400 hover:text-gray-700 hover:bg-gray-200\"\n title=\"Editar HTML\"\n >\n <svg className=\"w-3 h-3\" viewBox=\"0 0 16 16\" fill=\"currentColor\"><path d=\"M5.854 4.854a.5.5 0 1 0-.708-.708l-3.5 3.5a.5.5 0 0 0 0 .708l3.5 3.5a.5.5 0 0 0 .708-.708L2.707 8l3.147-3.146zm4.292 0a.5.5 0 0 1 .708-.708l3.5 3.5a.5.5 0 0 1 0 .708l-3.5 3.5a.5.5 0 0 1-.708-.708L13.293 8l-3.147-3.146z\"/></svg>\n </button>\n {i > 0 && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onReorder(i, i - 1);\n }}\n className=\"w-5 h-5 flex items-center justify-center rounded text-gray-400 hover:text-gray-700 hover:bg-gray-200 text-[10px]\"\n >\n ↑\n </button>\n )}\n {i < sorted.length - 1 && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onReorder(i, i + 1);\n }}\n className=\"w-5 h-5 flex items-center justify-center rounded text-gray-400 hover:text-gray-700 hover:bg-gray-200 text-[10px]\"\n >\n ↓\n </button>\n )}\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDelete(section.id);\n }}\n className=\"w-5 h-5 flex items-center justify-center rounded text-gray-400 hover:text-red-600 hover:bg-red-50 text-[10px]\"\n title=\"Eliminar seccion\"\n >\n ✕\n </button>\n </div>\n </div>\n ))}\n </div>\n\n <div className=\"p-3 border-t border-gray-200\">\n <button\n onClick={onAdd}\n className=\"w-full text-center py-2 text-sm font-bold text-blue-600 hover:bg-blue-50 rounded-lg transition-colors\"\n >\n + Agregar seccion\n </button>\n </div>\n </div>\n );\n}\n","import React, { useState, useRef, useEffect } from \"react\";\nimport { HiSparkles } from \"react-icons/hi2\";\nimport type { IframeMessage } from \"../types\";\nimport type { LandingTheme } from \"../themes\";\n\nconst STYLE_PRESETS = [\n { label: \"Minimal\", icon: \"○\", instruction: \"Redisena esta seccion con estetica minimal: mucho espacio en blanco, tipografia limpia, sin bordes ni sombras innecesarias. Manten el mismo contenido.\" },\n { label: \"Cards\", icon: \"▦\", instruction: \"Redisena esta seccion usando layout de cards en grid: cada item en su propia card con padding, sombra sutil y bordes redondeados. Manten el mismo contenido.\" },\n { label: \"Bold\", icon: \"■\", instruction: \"Redisena esta seccion con estilo bold/brutalist: tipografia grande y gruesa, colores de alto contraste, bordes solidos, sin gradientes. Manten el mismo contenido.\" },\n { label: \"Glass\", icon: \"◇\", instruction: \"Redisena esta seccion con glassmorphism: fondos translucidos con backdrop-blur, bordes sutiles blancos, sombras suaves. Usa un fondo oscuro o con gradiente detras. Manten el mismo contenido.\" },\n { label: \"Dark\", icon: \"●\", instruction: \"Redisena esta seccion con fondo oscuro (#111 o similar), texto claro, acentos de color vibrantes. Manten el mismo contenido.\" },\n];\n\n// SVG icons for tab bar\nconst PaletteIcon = () => (\n <svg className=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"13.5\" cy=\"6.5\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"17.5\" cy=\"10.5\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"8.5\" cy=\"7.5\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"6.5\" cy=\"12\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\" />\n <path d=\"M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 011.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z\" />\n </svg>\n);\n\nconst RulerIcon = () => (\n <svg className=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21.3 15.3a2.4 2.4 0 010 3.4l-2.6 2.6a2.4 2.4 0 01-3.4 0L2.7 8.7a2.4 2.4 0 010-3.4l2.6-2.6a2.4 2.4 0 013.4 0z\" />\n <path d=\"M14.5 12.5l2-2\" />\n <path d=\"M11.5 9.5l2-2\" />\n <path d=\"M8.5 6.5l2-2\" />\n <path d=\"M17.5 15.5l2-2\" />\n </svg>\n);\n\nconst LinkIcon = () => (\n <svg className=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71\" />\n </svg>\n);\n\ntype TabType = \"style\" | \"attrs\" | null;\n\ninterface FloatingToolbarProps {\n selection: IframeMessage | null;\n iframeRect: DOMRect | null;\n onRefine: (instruction: string, referenceImage?: string, opts?: { isVariant?: boolean }) => void;\n onMoveUp: () => void;\n onMoveDown: () => void;\n onDelete: () => void;\n onClose: () => void;\n onViewCode: () => void;\n onUpdateAttribute?: (sectionId: string, elementPath: string, attr: string, value: string) => void;\n onChangeTag?: (sectionId: string, elementPath: string, newTag: string) => void;\n onReplaceClass?: (sectionId: string, elementPath: string, removePrefixes: string[], addClass: string) => void;\n onDeleteElement?: (sectionId: string, elementPath: string) => void;\n isRefining: boolean;\n hideStylePresets?: boolean;\n themeColors?: LandingTheme[\"colors\"];\n}\n\nexport function FloatingToolbar({\n selection,\n iframeRect,\n onRefine,\n onMoveUp,\n onMoveDown,\n onDelete,\n onClose,\n onViewCode,\n onUpdateAttribute,\n onChangeTag,\n onReplaceClass,\n onDeleteElement,\n isRefining,\n hideStylePresets,\n themeColors,\n}: FloatingToolbarProps) {\n const [prompt, setPrompt] = useState(\"\");\n const [showCode, setShowCode] = useState(false);\n const [refImage, setRefImage] = useState<string | null>(null);\n const [refImageName, setRefImageName] = useState<string | null>(null);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const toolbarRef = useRef<HTMLDivElement>(null);\n\n const [showTagPicker, setShowTagPicker] = useState(false);\n const [activeTab, setActiveTab] = useState<TabType>('style');\n\n // Local attr editing state\n const [imgSrc, setImgSrc] = useState(\"\");\n const [imgAlt, setImgAlt] = useState(\"\");\n const [linkHref, setLinkHref] = useState(\"\");\n\n useEffect(() => {\n setPrompt(\"\");\n setShowCode(false);\n setRefImage(null);\n setRefImageName(null);\n setShowTagPicker(false);\n setActiveTab(null);\n // Auto-focus AI input only for section roots (not text elements where user may want to double-click edit)\n const isText = [\"P\", \"SPAN\", \"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"BLOCKQUOTE\", \"LI\", \"A\"].includes(selection?.tagName ?? \"\");\n if (!isText) {\n setTimeout(() => inputRef.current?.focus(), 50);\n }\n }, [selection?.sectionId, selection?.elementPath]);\n\n // Sync attr inputs when selection changes\n useEffect(() => {\n if (selection?.attrs) {\n setImgSrc(selection.attrs.src || \"\");\n setImgAlt(selection.attrs.alt || \"\");\n setLinkHref(selection.attrs.href || \"\");\n }\n }, [selection?.attrs, selection?.elementPath]);\n\n // ESC closes toolbar\n useEffect(() => {\n function handleKey(e: KeyboardEvent) {\n if (e.key === \"Escape\") onClose();\n }\n document.addEventListener(\"keydown\", handleKey);\n return () => document.removeEventListener(\"keydown\", handleKey);\n }, [onClose]);\n\n if (!selection || !selection.rect || !iframeRect) return null;\n\n const toolbarWidth = toolbarRef.current?.offsetWidth || 600;\n const toolbarHeight = toolbarRef.current?.offsetHeight || 60;\n const top = iframeRect.top + selection.rect.top + selection.rect.height + 8;\n const left = iframeRect.left + selection.rect.left;\n const clampedLeft = Math.max(8, Math.min(left, window.innerWidth - toolbarWidth - 8));\n const showAbove = top + toolbarHeight + 8 > window.innerHeight;\n const finalTop = Math.max(8, showAbove\n ? iframeRect.top + selection.rect.top - toolbarHeight - 8\n : top);\n\n function handleSubmit(e: React.FormEvent) {\n e.preventDefault();\n if (isRefining || !selection) return;\n if (prompt.trim()) {\n onRefine(prompt.trim(), refImage || undefined);\n } else {\n // No text — request variant\n const tag = selection.tagName?.toLowerCase();\n const text = selection.text?.substring(0, 80);\n const variantPrompt = selection.isSectionRoot\n ? \"Genera una variante completamente diferente de esta seccion. Manten el mismo contenido/informacion pero cambia radicalmente el layout, la estructura visual, y el estilo. Sorprendeme con un diseno creativo e inesperado.\"\n : `Modifica SOLO el elemento <${tag}> que contiene \"${text}\". Genera una variante visual diferente de ESE elemento (diferente estilo, layout, tipografia). NO modifiques ningun otro elemento de la seccion.`;\n onRefine(variantPrompt, refImage || undefined, { isVariant: selection.isSectionRoot ? true : undefined });\n }\n setPrompt(\"\");\n if (inputRef.current) inputRef.current.style.height = \"auto\";\n setRefImage(null);\n setRefImageName(null);\n }\n\n function handleFileSelect(e: React.ChangeEvent<HTMLInputElement>) {\n const file = e.target.files?.[0];\n if (!file) return;\n setRefImageName(file.name);\n\n const img = new Image();\n img.onload = () => {\n const MAX = 1024;\n let { width, height } = img;\n if (width > MAX || height > MAX) {\n const ratio = Math.min(MAX / width, MAX / height);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n canvas.getContext(\"2d\")!.drawImage(img, 0, 0, width, height);\n canvas.toBlob(\n (blob) => {\n if (!blob) return;\n const reader = new FileReader();\n reader.onload = () => setRefImage(reader.result as string);\n reader.readAsDataURL(blob);\n },\n \"image/jpeg\",\n 0.7\n );\n URL.revokeObjectURL(img.src);\n };\n img.src = URL.createObjectURL(file);\n e.target.value = \"\";\n }\n\n function handleSetAttr(attr: string, value: string) {\n if (!selection?.sectionId || !selection?.elementPath || !onUpdateAttribute) return;\n onUpdateAttribute(selection.sectionId, selection.elementPath, attr, value);\n }\n\n const isImg = selection.tagName === \"IMG\";\n const isLink = selection.tagName === \"A\";\n const hasAttrEditing = (isImg || isLink) && onUpdateAttribute;\n\n function handleReplaceClass(removePrefixes: string[], addClass: string) {\n if (!selection?.sectionId || !selection?.elementPath || !onUpdateAttribute) return;\n const currentClasses = (selection.className || \"\").split(/\\s+/).filter(Boolean);\n const filtered = currentClasses.filter(cls => {\n const bare = cls.includes(\":\") ? cls.substring(cls.lastIndexOf(\":\") + 1) : cls;\n return !removePrefixes.some(pfx => bare === pfx || bare.startsWith(pfx));\n });\n if (addClass) {\n for (const c of addClass.split(/\\s+/).filter(Boolean)) {\n if (!filtered.includes(c)) filtered.push(c);\n }\n }\n onUpdateAttribute(selection.sectionId, selection.elementPath, \"class\", filtered.join(\" \"));\n }\n\n // Determine size presets based on element type\n const sizePresets = (() => {\n if (!onUpdateAttribute || !selection.tagName) return null;\n const tag = selection.tagName.toUpperCase();\n const CONTAINERS = [\"DIV\", \"SECTION\", \"ARTICLE\", \"ASIDE\", \"HEADER\", \"FOOTER\", \"NAV\", \"MAIN\"];\n const TEXT_TAGS = [\"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"P\", \"SPAN\", \"BLOCKQUOTE\"];\n const currentClasses = (selection.className || \"\").split(/\\s+/);\n\n if (CONTAINERS.includes(tag)) {\n const W_PREFIXES = [\"w-\"];\n const MAX_W_PREFIXES = [\"max-w-\"];\n const P_PREFIXES = [\"p-\", \"px-\", \"py-\"];\n const widthOptions = [\n { label: \"Full\", cls: \"w-full\", prefixes: W_PREFIXES },\n { label: \"3/4\", cls: \"w-3/4\", prefixes: W_PREFIXES },\n { label: \"2/3\", cls: \"w-2/3\", prefixes: W_PREFIXES },\n { label: \"1/2\", cls: \"w-1/2\", prefixes: W_PREFIXES },\n { label: \"1/3\", cls: \"w-1/3\", prefixes: W_PREFIXES },\n ];\n const maxWOptions = [\n { label: \"sm\", cls: \"max-w-sm\", prefixes: MAX_W_PREFIXES },\n { label: \"md\", cls: \"max-w-md\", prefixes: MAX_W_PREFIXES },\n { label: \"lg\", cls: \"max-w-lg\", prefixes: MAX_W_PREFIXES },\n { label: \"xl\", cls: \"max-w-xl\", prefixes: MAX_W_PREFIXES },\n { label: \"2xl\", cls: \"max-w-2xl\", prefixes: MAX_W_PREFIXES },\n { label: \"full\", cls: \"max-w-full\", prefixes: MAX_W_PREFIXES },\n ];\n const paddingOptions = [\n { label: \"0\", cls: \"p-0\", prefixes: P_PREFIXES },\n { label: \"4\", cls: \"p-4\", prefixes: P_PREFIXES },\n { label: \"8\", cls: \"p-8\", prefixes: P_PREFIXES },\n { label: \"12\", cls: \"p-12\", prefixes: P_PREFIXES },\n { label: \"16\", cls: \"p-16\", prefixes: P_PREFIXES },\n ];\n const M_PREFIXES = [\"m-\", \"mx-\", \"my-\", \"mt-\", \"mb-\"];\n const marginOptions = [\n { label: \"0\", cls: \"m-0\", prefixes: M_PREFIXES },\n { label: \"auto\", cls: \"mx-auto\", prefixes: M_PREFIXES },\n { label: \"2\", cls: \"m-2\", prefixes: M_PREFIXES },\n { label: \"4\", cls: \"m-4\", prefixes: M_PREFIXES },\n { label: \"8\", cls: \"m-8\", prefixes: M_PREFIXES },\n ];\n return { width: widthOptions, maxW: maxWOptions, padding: paddingOptions, margin: marginOptions, currentClasses };\n }\n\n if (TEXT_TAGS.includes(tag)) {\n const TEXT_SIZE_EXACT = [\"text-xs\", \"text-sm\", \"text-base\", \"text-lg\", \"text-xl\", \"text-2xl\", \"text-3xl\", \"text-4xl\", \"text-5xl\", \"text-6xl\", \"text-7xl\", \"text-8xl\", \"text-9xl\"];\n const FONT_WEIGHT_EXACT = [\"font-thin\", \"font-extralight\", \"font-light\", \"font-normal\", \"font-medium\", \"font-semibold\", \"font-bold\", \"font-extrabold\", \"font-black\"];\n const textSizes = [\n { label: \"sm\", cls: \"text-sm\", prefixes: TEXT_SIZE_EXACT },\n { label: \"base\", cls: \"text-base\", prefixes: TEXT_SIZE_EXACT },\n { label: \"lg\", cls: \"text-lg\", prefixes: TEXT_SIZE_EXACT },\n { label: \"xl\", cls: \"text-xl\", prefixes: TEXT_SIZE_EXACT },\n { label: \"2xl\", cls: \"text-2xl\", prefixes: TEXT_SIZE_EXACT },\n { label: \"3xl\", cls: \"text-3xl\", prefixes: TEXT_SIZE_EXACT },\n { label: \"4xl\", cls: \"text-4xl\", prefixes: TEXT_SIZE_EXACT },\n { label: \"5xl\", cls: \"text-5xl\", prefixes: TEXT_SIZE_EXACT },\n ];\n const fontWeight = [\n { label: \"light\", cls: \"font-light\", prefixes: FONT_WEIGHT_EXACT },\n { label: \"normal\", cls: \"font-normal\", prefixes: FONT_WEIGHT_EXACT },\n { label: \"medium\", cls: \"font-medium\", prefixes: FONT_WEIGHT_EXACT },\n { label: \"semibold\", cls: \"font-semibold\", prefixes: FONT_WEIGHT_EXACT },\n { label: \"bold\", cls: \"font-bold\", prefixes: FONT_WEIGHT_EXACT },\n ];\n const M_PREFIXES = [\"m-\", \"mx-\", \"my-\", \"mt-\", \"mb-\"];\n const marginOptions = [\n { label: \"0\", cls: \"m-0\", prefixes: M_PREFIXES },\n { label: \"auto\", cls: \"mx-auto\", prefixes: M_PREFIXES },\n { label: \"2\", cls: \"m-2\", prefixes: M_PREFIXES },\n { label: \"4\", cls: \"m-4\", prefixes: M_PREFIXES },\n { label: \"8\", cls: \"m-8\", prefixes: M_PREFIXES },\n ];\n return { textSize: textSizes, fontWeight, margin: marginOptions, currentClasses };\n }\n\n if (tag === \"BUTTON\" || tag === \"A\") {\n const W_PREFIXES = [\"w-\"];\n const P_PREFIXES = [\"p-\", \"px-\", \"py-\"];\n const M_PREFIXES = [\"m-\", \"mx-\", \"my-\", \"mt-\", \"mb-\"];\n const widthOptions = [\n { label: \"auto\", cls: \"w-auto\", prefixes: W_PREFIXES },\n { label: \"Full\", cls: \"w-full\", prefixes: W_PREFIXES },\n { label: \"1/2\", cls: \"w-1/2\", prefixes: W_PREFIXES },\n { label: \"1/3\", cls: \"w-1/3\", prefixes: W_PREFIXES },\n ];\n const paddingOptions = [\n { label: \"0\", cls: \"p-0\", prefixes: P_PREFIXES },\n { label: \"2\", cls: \"px-2 py-1\", prefixes: P_PREFIXES },\n { label: \"4\", cls: \"px-4 py-2\", prefixes: P_PREFIXES },\n { label: \"6\", cls: \"px-6 py-3\", prefixes: P_PREFIXES },\n { label: \"8\", cls: \"px-8 py-4\", prefixes: P_PREFIXES },\n ];\n const marginOptions = [\n { label: \"0\", cls: \"m-0\", prefixes: M_PREFIXES },\n { label: \"auto\", cls: \"mx-auto\", prefixes: M_PREFIXES },\n { label: \"2\", cls: \"m-2\", prefixes: M_PREFIXES },\n { label: \"4\", cls: \"m-4\", prefixes: M_PREFIXES },\n ];\n return { width: widthOptions, padding: paddingOptions, margin: marginOptions, currentClasses };\n }\n\n if (tag === \"IMG\") {\n const IMG_SIZE_PREFIXES = [\"w-\", \"max-w-\"];\n const ROUNDED_PREFIXES = [\"rounded\"];\n const imgSizes = [\n { label: \"sm\", cls: \"max-w-xs\", prefixes: IMG_SIZE_PREFIXES },\n { label: \"md\", cls: \"max-w-md\", prefixes: IMG_SIZE_PREFIXES },\n { label: \"lg\", cls: \"max-w-lg\", prefixes: IMG_SIZE_PREFIXES },\n { label: \"xl\", cls: \"max-w-xl\", prefixes: IMG_SIZE_PREFIXES },\n { label: \"full\", cls: \"w-full\", prefixes: IMG_SIZE_PREFIXES },\n ];\n const rounded = [\n { label: \"none\", cls: \"rounded-none\", prefixes: ROUNDED_PREFIXES },\n { label: \"md\", cls: \"rounded-md\", prefixes: ROUNDED_PREFIXES },\n { label: \"lg\", cls: \"rounded-lg\", prefixes: ROUNDED_PREFIXES },\n { label: \"xl\", cls: \"rounded-xl\", prefixes: ROUNDED_PREFIXES },\n { label: \"full\", cls: \"rounded-full\", prefixes: ROUNDED_PREFIXES },\n ];\n return { imgSize: imgSizes, rounded, currentClasses };\n }\n\n return null;\n })();\n\n // Determine which tabs are available\n const hasStyleTab = true; // Always available (colors + size for non-section, style presets for section)\n const hasAttrsTab = hasAttrEditing;\n\n function toggleTab(tab: TabType) {\n setActiveTab(prev => prev === tab ? null : tab);\n }\n\n // Render color swatches panel\n function renderColorPanel() {\n if (selection!.isSectionRoot) {\n // Style presets for section root\n if (hideStylePresets) return null;\n return (\n <div className=\"flex items-center gap-1 pt-1 pb-0.5\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider mr-1 shrink-0\">Estilo</span>\n {STYLE_PRESETS.map((preset) => (\n <button\n key={preset.label}\n onClick={() => onRefine(preset.instruction)}\n disabled={isRefining}\n className=\"px-2 py-0.5 text-[11px] font-medium rounded-md bg-gray-800 hover:bg-gray-700 disabled:opacity-30 transition-colors whitespace-nowrap\"\n title={preset.label}\n >\n <span className=\"mr-1\">{preset.icon}</span>\n {preset.label}\n </button>\n ))}\n </div>\n );\n }\n\n // Color swatches for non-section elements\n if (!onUpdateAttribute || selection!.tagName === 'IMG') {\n // Still show size panel for IMG even without color swatches\n if (selection!.tagName === 'IMG' && sizePresets) return <div className=\"pt-1 pb-0.5\">{renderSizePanel()}</div>;\n return null;\n }\n\n const containerTags = ['DIV', 'SECTION', 'HEADER', 'FOOTER', 'NAV', 'ASIDE', 'MAIN', 'ARTICLE'];\n const isContainer = containerTags.includes(selection!.tagName ?? '');\n\n const TEXT_COLOR_PREFIXES = [\"text-primary\", \"text-secondary\", \"text-accent\", \"text-on-surface\", \"text-on-primary\", \"text-on-surface-muted\", \"text-white\", \"text-black\", \"text-transparent\"];\n const BG_COLOR_PREFIXES = [\"bg-primary\", \"bg-primary-dark\", \"bg-secondary\", \"bg-accent\", \"bg-surface\", \"bg-surface-alt\", \"bg-white\", \"bg-black\", \"bg-transparent\"];\n\n const themeSwatches = themeColors ? [\n { color: themeColors.primary, textCls: \"text-primary\", bgCls: \"bg-primary\", label: \"Primary\" },\n { color: themeColors.secondary, textCls: \"text-secondary\", bgCls: \"bg-secondary\", label: \"Secondary\" },\n { color: themeColors.accent, textCls: \"text-accent\", bgCls: \"bg-accent\", label: \"Accent\" },\n { color: themeColors.surface, textCls: \"text-on-surface\", bgCls: \"bg-surface\", label: \"Surface\" },\n ] : [];\n\n const fixedSwatches = [\n { color: \"#ffffff\", textCls: \"text-white\", bgCls: \"bg-white\", label: \"Blanco\" },\n { color: \"#000000\", textCls: \"text-black\", bgCls: \"bg-black\", label: \"Negro\" },\n { color: \"transparent\", textCls: \"text-transparent\", bgCls: \"bg-transparent\", label: \"Transparente\" },\n ];\n\n const renderColorRow = (label: string, mode: \"text\" | \"bg\") => (\n <div key={mode} className=\"flex items-center gap-1 pt-0.5 pb-0.5\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider mr-1 shrink-0 w-10\">{label}</span>\n {fixedSwatches.map(({ color, textCls, bgCls, label: swatchLabel }) => (\n <button\n key={swatchLabel}\n onClick={() => {\n const prefixes = mode === \"text\" ? TEXT_COLOR_PREFIXES : BG_COLOR_PREFIXES;\n const cls = mode === \"text\" ? textCls : bgCls;\n handleReplaceClass(prefixes, cls);\n handleSetAttr(\"style\", \"\");\n }}\n className=\"w-5 h-5 rounded-full border border-gray-600 hover:scale-125 transition-transform shrink-0\"\n style={color === \"transparent\" ? {\n backgroundImage: \"repeating-conic-gradient(#808080 0% 25%, #c0c0c0 0% 50%)\",\n backgroundSize: \"8px 8px\",\n } : { backgroundColor: color }}\n title={swatchLabel}\n />\n ))}\n {themeSwatches.map(({ color, textCls, bgCls, label: swatchLabel }) => (\n <button\n key={swatchLabel}\n onClick={() => {\n const prefixes = mode === \"text\" ? TEXT_COLOR_PREFIXES : BG_COLOR_PREFIXES;\n const cls = mode === \"text\" ? textCls : bgCls;\n handleReplaceClass(prefixes, cls);\n handleSetAttr(\"style\", \"\");\n }}\n className=\"w-5 h-5 rounded-full border border-gray-600 hover:scale-125 transition-transform shrink-0\"\n style={{ backgroundColor: color }}\n title={swatchLabel}\n />\n ))}\n <input\n type=\"color\"\n onChange={(e) => {\n handleReplaceClass(mode === \"text\" ? TEXT_COLOR_PREFIXES : BG_COLOR_PREFIXES, \"\");\n const cssProp = mode === \"text\" ? \"color\" : \"background-color\";\n handleSetAttr(\"style\", `${cssProp}: ${e.target.value}`);\n }}\n className=\"w-5 h-5 rounded-full border border-gray-600 cursor-pointer shrink-0 p-0 bg-transparent [&::-webkit-color-swatch-wrapper]:p-0 [&::-webkit-color-swatch]:rounded-full [&::-webkit-color-swatch]:border-0\"\n title=\"Color personalizado\"\n />\n </div>\n );\n\n return (\n <div className=\"pt-1 pb-0.5\">\n {renderColorRow(\"Color\", \"text\")}\n {isContainer && renderColorRow(\"Fondo\", \"bg\")}\n {renderSizePanel()}\n </div>\n );\n }\n\n // Render size presets panel\n function renderSizePanel() {\n if (!sizePresets || selection!.isSectionRoot) return null;\n const groups = Object.entries(sizePresets).filter(([k]) => k !== 'currentClasses') as [string, { label: string; cls: string; prefixes: string[] }[]][];\n const labels: Record<string, string> = { width: \"Ancho\", maxW: \"Max\", padding: \"Padding\", margin: \"Margin\", textSize: \"Texto\", fontWeight: \"Peso\", imgSize: \"Tamaño\", rounded: \"Borde\" };\n return (\n <div className=\"pt-1 pb-0.5\">\n {groups.map(([key, options]) => (\n <div key={key} className=\"flex items-center gap-1 pt-0.5 pb-0.5\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider mr-1 shrink-0 w-10\">{labels[key] || key}</span>\n {options.map((opt) => {\n const isActive = sizePresets.currentClasses.includes(opt.cls);\n return (\n <button\n key={opt.cls}\n onClick={() => handleReplaceClass(opt.prefixes, opt.cls)}\n className={`px-2 py-0.5 text-[10px] font-mono font-bold rounded-md transition-colors whitespace-nowrap ${\n isActive ? \"bg-blue-600 text-white\" : \"bg-gray-800 hover:bg-gray-700 text-gray-300\"\n }`}\n >\n {opt.label}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n );\n }\n\n // Render attributes panel\n function renderAttrsPanel() {\n if (!hasAttrEditing) return null;\n return (\n <div className=\"pt-1 pb-0.5\">\n {isImg && (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider w-8 shrink-0\">src</span>\n <input\n type=\"text\"\n value={imgSrc}\n onChange={(e) => setImgSrc(e.target.value)}\n onKeyDown={(e) => { if (e.key === \"Enter\") handleSetAttr(\"src\", imgSrc); }}\n className=\"flex-1 bg-gray-800 text-xs text-white rounded px-2 py-1 outline-none min-w-0\"\n placeholder=\"URL de imagen...\"\n />\n <button\n onClick={() => handleSetAttr(\"src\", imgSrc)}\n className=\"px-2 py-1 text-[10px] font-bold rounded bg-blue-500 hover:bg-blue-600 transition-colors shrink-0\"\n >\n Set\n </button>\n </div>\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider w-8 shrink-0\">alt</span>\n <input\n type=\"text\"\n value={imgAlt}\n onChange={(e) => setImgAlt(e.target.value)}\n onKeyDown={(e) => { if (e.key === \"Enter\") handleSetAttr(\"alt\", imgAlt); }}\n className=\"flex-1 bg-gray-800 text-xs text-white rounded px-2 py-1 outline-none min-w-0\"\n placeholder=\"Alt text...\"\n />\n <button\n onClick={() => handleSetAttr(\"alt\", imgAlt)}\n className=\"px-2 py-1 text-[10px] font-bold rounded bg-blue-500 hover:bg-blue-600 transition-colors shrink-0\"\n >\n Set\n </button>\n </div>\n </div>\n )}\n {isLink && (\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider w-8 shrink-0\">href</span>\n <input\n type=\"text\"\n value={linkHref}\n onChange={(e) => setLinkHref(e.target.value)}\n onKeyDown={(e) => { if (e.key === \"Enter\") handleSetAttr(\"href\", linkHref); }}\n className=\"flex-1 bg-gray-800 text-xs text-white rounded px-2 py-1 outline-none min-w-0\"\n placeholder=\"URL del enlace...\"\n />\n <button\n onClick={() => handleSetAttr(\"href\", linkHref)}\n className=\"px-2 py-1 text-[10px] font-bold rounded bg-blue-500 hover:bg-blue-600 transition-colors shrink-0\"\n >\n Set\n </button>\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div\n ref={toolbarRef}\n className=\"fixed z-50 flex flex-col bg-gray-900 text-white rounded-xl shadow-2xl px-2 py-1.5 border border-gray-700\"\n style={{ top: finalTop, left: clampedLeft, maxWidth: \"min(600px, calc(100vw - 16px))\" }}\n >\n {/* Main row */}\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {/* Tag badge / switcher */}\n {selection.tagName && (() => {\n const tag = selection.tagName.toUpperCase();\n const HEADINGS = [\"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\"];\n const TEXT = [\"P\", \"SPAN\", \"DIV\", \"BLOCKQUOTE\"];\n const CONTAINERS = [\"DIV\", \"SECTION\", \"ARTICLE\", \"ASIDE\", \"HEADER\", \"FOOTER\", \"NAV\", \"MAIN\"];\n const NO_SWITCH = [\"A\", \"IMG\", \"INPUT\", \"BUTTON\", \"SVG\", \"VIDEO\", \"IFRAME\", \"TABLE\", \"UL\", \"OL\", \"LI\", \"FORM\"];\n\n let tagOptions: string[] = [];\n if (HEADINGS.includes(tag)) tagOptions = [...HEADINGS, \"P\"];\n else if (TEXT.includes(tag) && !CONTAINERS.includes(tag)) tagOptions = [...TEXT, \"H1\", \"H2\", \"H3\"];\n else if (CONTAINERS.includes(tag)) tagOptions = [...CONTAINERS, \"P\", \"SPAN\"];\n tagOptions = tagOptions.filter((t) => t !== tag);\n const canSwitch = !NO_SWITCH.includes(tag) && tagOptions.length > 0 && onChangeTag;\n\n return canSwitch ? (\n <div className=\"relative shrink-0\">\n <button\n onClick={() => setShowTagPicker(!showTagPicker)}\n className=\"px-2 py-0.5 rounded-md bg-blue-600 hover:bg-blue-500 text-[10px] font-mono font-bold uppercase tracking-wider transition-colors flex items-center gap-0.5\"\n >\n {tag.toLowerCase()}\n <svg className=\"w-2.5 h-2.5 opacity-60\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\" clipRule=\"evenodd\" />\n </svg>\n </button>\n {showTagPicker && (\n <div className={`absolute left-0 bg-gray-800 border border-gray-600 rounded-lg shadow-xl py-1 z-50 min-w-[4rem] max-h-[200px] overflow-y-auto ${showAbove ? \"bottom-full mb-1\" : \"top-full mt-1\"}`}>\n {tagOptions.map((t) => (\n <button\n key={t}\n onClick={() => {\n if (selection.sectionId && selection.elementPath) {\n onChangeTag(selection.sectionId, selection.elementPath, t.toLowerCase());\n }\n setShowTagPicker(false);\n }}\n className=\"block w-full text-left px-3 py-1 text-[11px] font-mono font-bold uppercase hover:bg-gray-700 transition-colors\"\n >\n {t.toLowerCase()}\n </button>\n ))}\n </div>\n )}\n </div>\n ) : (\n <span className=\"px-2 py-0.5 rounded-md bg-blue-600 text-[10px] font-mono font-bold uppercase tracking-wider shrink-0\">\n {tag.toLowerCase()}\n </span>\n );\n })()}\n\n {/* AI prompt input */}\n <form onSubmit={handleSubmit} className=\"flex items-start gap-1 flex-1\">\n <textarea\n ref={inputRef}\n value={prompt}\n onChange={(e) => {\n setPrompt(e.target.value);\n e.target.style.height = \"auto\";\n e.target.style.height = Math.min(e.target.scrollHeight, 96) + \"px\";\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit(e);\n }\n }}\n placeholder={refImage ? \"Instruccion + imagen...\" : \"Editar con AI...\"}\n disabled={isRefining}\n rows={1}\n className=\"bg-transparent text-sm text-white placeholder:text-gray-500 outline-none min-w-[6rem] sm:min-w-[10rem] flex-1 px-2 py-1 resize-none overflow-hidden\"\n />\n <button\n type=\"submit\"\n disabled={isRefining}\n className={`flex items-center justify-center rounded-lg bg-blue-500 hover:bg-blue-600 disabled:opacity-30 transition-colors shrink-0 ${\n prompt.trim() ? \"w-7 h-7\" : \"px-2.5 py-1 text-[11px] font-bold whitespace-nowrap\"\n }`}\n >\n {isRefining ? (\n <span className=\"w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin\" />\n ) : prompt.trim() ? (\n <HiSparkles className=\"w-3.5 h-3.5\" />\n ) : (\n \"✦ Variante\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n disabled={isRefining}\n className={`w-7 h-7 flex items-center justify-center rounded-lg transition-colors shrink-0 ${\n refImage\n ? \"bg-blue-600 text-white\"\n : \"hover:bg-gray-800 text-gray-400 hover:text-white\"\n }`}\n title={refImage ? `Imagen: ${refImageName}` : \"Adjuntar imagen de referencia\"}\n >\n <svg className=\"w-3.5 h-3.5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M1 5.25A2.25 2.25 0 013.25 3h13.5A2.25 2.25 0 0119 5.25v9.5A2.25 2.25 0 0116.75 17H3.25A2.25 2.25 0 011 14.75v-9.5zm1.5 5.81V14.75c0 .414.336.75.75.75h13.5a.75.75 0 00.75-.75v-2.06l-2.22-2.22a.75.75 0 00-1.06 0L8.56 16.1l-3.28-3.28a.75.75 0 00-1.06 0l-1.72 1.72zm12-4.06a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0z\" clipRule=\"evenodd\"/>\n </svg>\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileSelect}\n className=\"hidden\"\n />\n </form>\n\n {/* Section-level actions (move/delete) */}\n {selection.isSectionRoot && (\n <span className=\"hidden sm:contents\">\n <div className=\"w-px h-5 bg-gray-700\" />\n <button\n onClick={onMoveUp}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-gray-800 transition-colors text-xs\"\n title=\"Mover arriba\"\n >\n ↑\n </button>\n <button\n onClick={onMoveDown}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-gray-800 transition-colors text-xs\"\n title=\"Mover abajo\"\n >\n ↓\n </button>\n </span>\n )}\n\n {selection.isSectionRoot ? (\n <>\n <div className=\"w-px h-5 bg-gray-700\" />\n <button\n onClick={onDelete}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-red-900/50 text-red-400 transition-colors\"\n title=\"Eliminar seccion\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\" />\n <path d=\"M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2\" />\n </svg>\n </button>\n </>\n ) : onDeleteElement && (\n <>\n <div className=\"w-px h-5 bg-gray-700\" />\n <button\n onClick={() => {\n if (selection.sectionId && selection.elementPath) {\n onDeleteElement(selection.sectionId, selection.elementPath);\n }\n }}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-red-900/50 text-red-400 transition-colors\"\n title=\"Eliminar elemento\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\" />\n <path d=\"M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2\" />\n </svg>\n </button>\n </>\n )}\n\n {/* Close button */}\n <div className=\"w-px h-5 bg-gray-700\" />\n <button\n onClick={onClose}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-gray-800 text-gray-400 hover:text-white transition-colors shrink-0\"\n title=\"Cerrar (ESC)\"\n >\n ✕\n </button>\n </div>\n\n {/* Reference image preview */}\n {refImage && (\n <div className=\"flex items-center gap-2 pt-0.5 pb-0.5 border-t border-gray-700/50\">\n <img src={refImage} alt=\"Referencia\" className=\"w-10 h-10 rounded object-cover border border-gray-600\" />\n <span className=\"text-[10px] text-gray-400 truncate flex-1\">{refImageName}</span>\n <button\n onClick={() => { setRefImage(null); setRefImageName(null); }}\n className=\"text-[10px] text-gray-500 hover:text-white px-1\"\n >\n ✕\n </button>\n </div>\n )}\n\n {/* Tab bar */}\n <div className=\"flex items-center gap-1 pt-1 border-t border-gray-700/50 overflow-x-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]\">\n {hasStyleTab && (\n <button\n onClick={() => toggleTab(\"style\")}\n className={`flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-medium transition-colors ${\n activeTab === \"style\" ? \"bg-blue-600 text-white\" : \"bg-gray-800 hover:bg-gray-700 text-gray-400\"\n }`}\n title=\"Estilo y tamaño\"\n >\n <PaletteIcon />\n <span>Estilo</span>\n </button>\n )}\n\n {hasAttrsTab && (\n <button\n onClick={() => toggleTab(\"attrs\")}\n className={`flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-medium transition-colors ${\n activeTab === \"attrs\" ? \"bg-blue-600 text-white\" : \"bg-gray-800 hover:bg-gray-700 text-gray-400\"\n }`}\n title=\"Atributos\"\n >\n <LinkIcon />\n <span>Attrs</span>\n </button>\n )}\n <button\n onClick={onViewCode}\n className=\"hidden sm:flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-medium bg-gray-800 hover:bg-gray-700 text-gray-400 transition-colors font-mono\"\n title=\"Ver código\"\n >\n </>\n </button>\n </div>\n\n {/* Active tab panel */}\n {activeTab === \"style\" && renderColorPanel()}\n {activeTab === \"attrs\" && renderAttrsPanel()}\n </div>\n );\n}\n","import React, { useEffect, useRef, useCallback, useState } from \"react\";\nimport { EditorView, keymap, lineNumbers, highlightActiveLine, highlightActiveLineGutter, Decoration, type DecorationSet } from \"@codemirror/view\";\nimport { EditorState, StateField, StateEffect } from \"@codemirror/state\";\nimport { html } from \"@codemirror/lang-html\";\nimport { oneDark } from \"@codemirror/theme-one-dark\";\nimport { defaultKeymap, indentWithTab, history, historyKeymap } from \"@codemirror/commands\";\nimport { searchKeymap, highlightSelectionMatches } from \"@codemirror/search\";\nimport { bracketMatching, foldGutter, foldKeymap } from \"@codemirror/language\";\nimport { closeBrackets, closeBracketsKeymap } from \"@codemirror/autocomplete\";\n\ninterface CodeEditorProps {\n code: string;\n label: string;\n scrollToText?: string;\n onSave: (code: string) => void;\n onClose: () => void;\n}\n\nfunction formatHtml(html: string): string {\n let result = html.replace(/>\\s*</g, \">\\n<\");\n const lines = result.split(\"\\n\");\n const output: string[] = [];\n let indent = 0;\n for (const raw of lines) {\n const line = raw.trim();\n if (!line) continue;\n const isClosing = /^<\\//.test(line);\n const isSelfClosing =\n /\\/>$/.test(line) ||\n /^<(img|br|hr|input|meta|link|col|area|base|embed|source|track|wbr)\\b/i.test(line);\n const hasInlineClose = /^<[^/][^>]*>.*<\\//.test(line);\n if (isClosing) indent = Math.max(0, indent - 1);\n output.push(\" \".repeat(indent) + line);\n if (!isClosing && !isSelfClosing && !hasInlineClose && /^<[a-zA-Z]/.test(line)) {\n indent++;\n }\n }\n return output.join(\"\\n\");\n}\n\n// Flash highlight effect for scroll-to-code\nconst flashLineEffect = StateEffect.define<{ from: number; to: number }>();\nconst clearFlashEffect = StateEffect.define<null>();\n\nconst flashLineDeco = Decoration.line({ class: \"cm-flash-line\" });\n\nconst flashLineField = StateField.define<DecorationSet>({\n create: () => Decoration.none,\n update(decos, tr) {\n for (const e of tr.effects) {\n if (e.is(flashLineEffect)) {\n return Decoration.set([flashLineDeco.range(e.value.from)]);\n }\n if (e.is(clearFlashEffect)) {\n return Decoration.none;\n }\n }\n return decos;\n },\n provide: (f) => EditorView.decorations.from(f),\n});\n\n\nfunction scrollToTarget(view: EditorView, target?: string) {\n if (!target) return;\n const docText = view.state.doc.toString();\n const normalized = target.replace(/\"/g, \"'\");\n let idx = docText.indexOf(normalized);\n if (idx === -1) idx = docText.indexOf(target);\n\n // If exact match fails, extract tag+class and search line by line\n if (idx === -1) {\n const tagMatch = target.match(/^<(\\w+)/);\n const classMatch = target.match(/class=[\"']([^\"']*?)[\"']/);\n if (tagMatch) {\n const searchTag = tagMatch[0];\n const searchClass = classMatch ? classMatch[1].split(\" \")[0] : null;\n for (let i = 1; i <= view.state.doc.lines; i++) {\n const line = view.state.doc.line(i);\n if (line.text.includes(searchTag) && (!searchClass || line.text.includes(searchClass))) {\n idx = line.from;\n break;\n }\n }\n }\n }\n\n if (idx !== -1) {\n const line = view.state.doc.lineAt(idx);\n view.dispatch({\n selection: { anchor: line.from },\n effects: [\n EditorView.scrollIntoView(line.from, { y: \"center\" }),\n flashLineEffect.of({ from: line.from, to: line.to }),\n ],\n });\n // Clear flash after 2s\n setTimeout(() => {\n view.dispatch({ effects: clearFlashEffect.of(null) });\n }, 2000);\n }\n}\n\nexport function CodeEditor({ code, label, scrollToText, onSave, onClose }: CodeEditorProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const viewRef = useRef<EditorView | null>(null);\n const [stats, setStats] = useState({ lines: 0, kb: \"0.0\" });\n\n const onSaveRef = useRef(onSave);\n const onCloseRef = useRef(onClose);\n onSaveRef.current = onSave;\n onCloseRef.current = onClose;\n\n const updateStats = useCallback((doc: { length: number; lines: number }) => {\n setStats({ lines: doc.lines, kb: (doc.length / 1024).toFixed(1) });\n }, []);\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n const initialDoc = code.includes(\"\\n\") ? code : formatHtml(code);\n\n const state = EditorState.create({\n doc: initialDoc,\n extensions: [\n lineNumbers(),\n highlightActiveLine(),\n highlightActiveLineGutter(),\n bracketMatching(),\n closeBrackets(),\n foldGutter(),\n highlightSelectionMatches(),\n html(),\n oneDark,\n history(),\n EditorView.lineWrapping,\n keymap.of([\n { key: \"Mod-s\", run: (v) => { onSaveRef.current(v.state.doc.toString()); return true; } },\n { key: \"Escape\", run: () => { onCloseRef.current(); return true; } },\n indentWithTab,\n ...closeBracketsKeymap,\n ...searchKeymap,\n ...foldKeymap,\n ...historyKeymap,\n ...defaultKeymap,\n ]),\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n updateStats(update.state.doc);\n }\n }),\n flashLineField,\n EditorView.theme({\n \"&\": { height: \"100%\", fontSize: \"13px\" },\n \".cm-scroller\": { overflow: \"auto\", fontFamily: \"ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace\" },\n \".cm-content\": { padding: \"8px 0\" },\n \".cm-gutters\": { borderRight: \"1px solid #21262d\" },\n \".cm-flash-line\": { backgroundColor: \"rgba(250, 204, 21, 0.25)\", transition: \"background-color 2s ease-out\" },\n }),\n ],\n });\n\n const view = new EditorView({ state, parent: containerRef.current });\n viewRef.current = view;\n\n updateStats(view.state.doc);\n scrollToTarget(view, scrollToText);\n view.focus();\n\n return () => { view.destroy(); };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Re-scroll when scrollToText changes while editor is already open\n useEffect(() => {\n const view = viewRef.current;\n if (!view || !scrollToText) return;\n scrollToTarget(view, scrollToText);\n }, [scrollToText]);\n\n function handleFormat() {\n const view = viewRef.current;\n if (!view) return;\n const formatted = formatHtml(view.state.doc.toString());\n view.dispatch({\n changes: { from: 0, to: view.state.doc.length, insert: formatted },\n });\n }\n\n function handleSave() {\n const view = viewRef.current;\n if (!view) return;\n onSave(view.state.doc.toString());\n }\n\n return (\n <div className=\"flex flex-col h-full bg-[#0d1117]\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-gray-800 shrink-0\">\n <div className=\"flex items-center gap-3\">\n <span className=\"px-2 py-0.5 rounded bg-orange-600/20 text-orange-400 text-[10px] font-mono font-bold uppercase tracking-wider\">\n HTML\n </span>\n <span className=\"text-sm font-bold text-gray-300\">{label}</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={handleFormat}\n className=\"px-3 py-1.5 text-xs font-bold rounded-lg bg-gray-800 text-gray-400 hover:text-white hover:bg-gray-700 transition-colors\"\n >\n Formatear\n </button>\n <button\n onClick={handleSave}\n className=\"px-4 py-1.5 text-xs font-bold rounded-lg bg-blue-500 text-white hover:bg-blue-600 transition-colors\"\n >\n Guardar\n </button>\n <button\n onClick={onClose}\n className=\"px-3 py-1.5 text-xs font-bold rounded-lg bg-gray-800 text-gray-400 hover:text-white hover:bg-gray-700 transition-colors\"\n >\n Cerrar\n </button>\n </div>\n </div>\n\n {/* Editor */}\n <div ref={containerRef} className=\"flex-1 overflow-hidden\" />\n\n {/* Footer */}\n <div className=\"flex items-center justify-between px-4 py-1.5 border-t border-gray-800 text-[10px] text-gray-500 font-mono shrink-0\">\n <span>{stats.lines} lineas</span>\n <span>Tab = indentar · Cmd+S = guardar · Esc = cerrar</span>\n <span>{stats.kb} KB</span>\n </div>\n </div>\n );\n}\n","import React from \"react\";\n\nexport type Viewport = \"desktop\" | \"tablet\" | \"mobile\";\n\nconst VIEWPORTS: { id: Viewport; label: string; icon: React.ReactElement }[] = [\n {\n id: \"desktop\",\n label: \"Desktop\",\n icon: (\n <svg className=\"w-4 h-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M2 4.25A2.25 2.25 0 014.25 2h11.5A2.25 2.25 0 0118 4.25v8.5A2.25 2.25 0 0115.75 15h-3.105a3.501 3.501 0 001.1 1.677A.75.75 0 0113.26 18H6.74a.75.75 0 01-.484-1.323A3.501 3.501 0 007.355 15H4.25A2.25 2.25 0 012 12.75v-8.5zm1.5 0a.75.75 0 01.75-.75h11.5a.75.75 0 01.75.75v8.5a.75.75 0 01-.75.75H4.25a.75.75 0 01-.75-.75v-8.5z\"\n clipRule=\"evenodd\"\n />\n </svg>\n ),\n },\n {\n id: \"tablet\",\n label: \"Tablet\",\n icon: (\n <svg className=\"w-4 h-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M5 1a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V3a2 2 0 00-2-2H5zm0 1.5h10a.5.5 0 01.5.5v14a.5.5 0 01-.5.5H5a.5.5 0 01-.5-.5V3a.5.5 0 01.5-.5zm4 14a1 1 0 112 0 1 1 0 01-2 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n ),\n },\n {\n id: \"mobile\",\n label: \"Mobile\",\n icon: (\n <svg className=\"w-4 h-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M6 2a2 2 0 00-2 2v12a2 2 0 002 2h8a2 2 0 002-2V4a2 2 0 00-2-2H6zm0 1.5h8a.5.5 0 01.5.5v12a.5.5 0 01-.5.5H6a.5.5 0 01-.5-.5V4a.5.5 0 01.5-.5zm3 13a1 1 0 112 0 1 1 0 01-2 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n ),\n },\n];\n\nexport function ViewportToggle({\n value,\n onChange,\n activeClass = \"bg-blue-100 text-blue-700\",\n inactiveClass = \"text-gray-400 hover:text-gray-600 hover:bg-gray-100\",\n}: {\n value: Viewport;\n onChange: (v: Viewport) => void;\n activeClass?: string;\n inactiveClass?: string;\n}) {\n return (\n <div className=\"flex items-center justify-center gap-1 py-2 shrink-0 bg-gray-50 border-b border-gray-200\">\n {VIEWPORTS.map((v) => (\n <button\n key={v.id}\n type=\"button\"\n onClick={() => onChange(v.id)}\n title={v.label}\n className={`p-1.5 rounded-lg transition-colors ${\n value === v.id ? activeClass : inactiveClass\n }`}\n >\n {v.icon}\n </button>\n ))}\n </div>\n );\n}\n","import { useState, useCallback, useRef } from \"react\";\n\nconst MAX_STACK = 30;\n\nexport function useUndoStack<T>() {\n const undoStack = useRef<T[]>([]);\n const redoStack = useRef<T[]>([]);\n const [canUndo, setCanUndo] = useState(false);\n const [canRedo, setCanRedo] = useState(false);\n\n const pushUndo = useCallback((snapshot: T) => {\n undoStack.current.push(JSON.parse(JSON.stringify(snapshot)));\n if (undoStack.current.length > MAX_STACK) undoStack.current.shift();\n redoStack.current = [];\n setCanUndo(true);\n setCanRedo(false);\n }, []);\n\n const undo = useCallback((current: T): T | null => {\n if (undoStack.current.length === 0) return null;\n redoStack.current.push(JSON.parse(JSON.stringify(current)));\n const prev = undoStack.current.pop()!;\n setCanUndo(undoStack.current.length > 0);\n setCanRedo(true);\n return prev;\n }, []);\n\n const redo = useCallback((current: T): T | null => {\n if (redoStack.current.length === 0) return null;\n undoStack.current.push(JSON.parse(JSON.stringify(current)));\n const next = redoStack.current.pop()!;\n setCanUndo(true);\n setCanRedo(redoStack.current.length > 0);\n return next;\n }, []);\n\n return { pushUndo, undo, redo, canUndo, canRedo };\n}\n"],"mappings":"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","names":["Canvas","html","useRef","useState","jsx","jsxs","useRef","useState","useState","useRef","useEffect","jsx","jsxs","jsxs","jsx","useState","useRef","useEffect","useEffect","useRef","useCallback","useState","jsx","jsxs","html","jsx","useState","useCallback","useRef"]}
|
|
@@ -88,14 +88,43 @@ Generate 7-9 sections. Always start with Hero and end with Footer.
|
|
|
88
88
|
IMPORTANT: Make each section VISUALLY UNIQUE \u2014 different layouts, different background colors, different grid structures.
|
|
89
89
|
Think like a premium design agency creating a $50K landing page.
|
|
90
90
|
NO generic Bootstrap layouts. Use creative grids, bento layouts, overlapping elements, asymmetric columns.`;
|
|
91
|
+
function buildVisualContext(themeColors, brandKit) {
|
|
92
|
+
if (!themeColors && !brandKit) return "";
|
|
93
|
+
const lines = ["\n\n## Visual Context \u2014 MANDATORY"];
|
|
94
|
+
if (themeColors) {
|
|
95
|
+
lines.push("You MUST use these exact semantic color values in your design. The CSS variables are already configured \u2014 just use the semantic classes (bg-primary, text-on-surface, etc). Here are the actual color values for reference so you understand the palette:");
|
|
96
|
+
for (const [key, value] of Object.entries(themeColors)) {
|
|
97
|
+
lines.push(`- --color-${key}: ${value}`);
|
|
98
|
+
}
|
|
99
|
+
const isDark = themeColors.surface && parseInt(themeColors.surface.slice(1, 3), 16) < 128;
|
|
100
|
+
if (isDark) {
|
|
101
|
+
lines.push("This is a DARK theme \u2014 surfaces are dark, text is light. Design accordingly.");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (brandKit?.fonts) {
|
|
105
|
+
const { heading, body } = brandKit.fonts;
|
|
106
|
+
if (heading) lines.push(`- Heading font: use font-family: '${heading}' via inline style on h1-h6`);
|
|
107
|
+
if (body) lines.push(`- Body font: use font-family: '${body}' via inline style on p, li, span`);
|
|
108
|
+
}
|
|
109
|
+
if (brandKit?.mood) {
|
|
110
|
+
lines.push(`- Design mood: ${brandKit.mood} \u2014 adapt spacing, imagery style, and visual weight to match this mood`);
|
|
111
|
+
}
|
|
112
|
+
if (brandKit?.logoUrl) {
|
|
113
|
+
lines.push(`- Brand logo: include <img src="${brandKit.logoUrl}" alt="Logo" class="h-8 w-auto" /> in the navbar/hero area`);
|
|
114
|
+
}
|
|
115
|
+
return lines.join("\n");
|
|
116
|
+
}
|
|
91
117
|
async function generateLanding(options) {
|
|
92
118
|
const {
|
|
93
119
|
prompt,
|
|
94
120
|
referenceImage,
|
|
95
121
|
extraInstructions,
|
|
96
122
|
systemPrompt = SYSTEM_PROMPT,
|
|
123
|
+
themeColors,
|
|
124
|
+
brandKit,
|
|
97
125
|
...rest
|
|
98
126
|
} = options;
|
|
127
|
+
const visualContext = buildVisualContext(themeColors, brandKit);
|
|
99
128
|
const extra = extraInstructions ? `
|
|
100
129
|
Additional instructions: ${extraInstructions}` : "";
|
|
101
130
|
const content = [];
|
|
@@ -120,7 +149,7 @@ IMPORTANT: Use the reference image as a DIRECT visual guide. Replicate its layou
|
|
|
120
149
|
}
|
|
121
150
|
return streamGenerate({
|
|
122
151
|
...rest,
|
|
123
|
-
systemPrompt,
|
|
152
|
+
systemPrompt: systemPrompt + visualContext,
|
|
124
153
|
userContent: content
|
|
125
154
|
});
|
|
126
155
|
}
|
|
@@ -130,4 +159,4 @@ export {
|
|
|
130
159
|
PROMPT_SUFFIX,
|
|
131
160
|
generateLanding
|
|
132
161
|
};
|
|
133
|
-
//# sourceMappingURL=chunk-
|
|
162
|
+
//# sourceMappingURL=chunk-C4D2NT5N.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/generate.ts"],"sourcesContent":["import { streamGenerate, dataUrlToImagePart, extractJsonObjects } from \"./streamCore\";\nimport type { Section3 } from \"./types\";\n\nexport { extractJsonObjects };\n\nexport const SYSTEM_PROMPT = `You are a world-class web designer who creates AWARD-WINNING landing pages. Your designs win Awwwards, FWA, and CSS Design Awards. You think in terms of visual hierarchy, whitespace, and emotional impact.\n\nRULES:\n- Each section is a complete <section> tag with Tailwind CSS classes\n- Use Tailwind CDN classes ONLY (no custom CSS, no @apply, no @import, no @tailwind directives)\n- NO JavaScript, only HTML+Tailwind\n- Each section must be independent and self-contained\n- Responsive: mobile-first with sm/md/lg/xl breakpoints\n- All text content in Spanish unless the prompt specifies otherwise\n- Use real-looking content (not Lorem ipsum) — make it specific to the prompt\n\nRESPONSIVE — MANDATORY:\n- EVERY grid: grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 (NEVER grid-cols-3 alone)\n- EVERY flex row: flex flex-col md:flex-row (NEVER flex flex-row alone)\n- Text sizes: text-3xl md:text-5xl lg:text-7xl (NEVER text-7xl alone)\n- Images: w-full h-auto object-cover max-w-full\n- Padding: px-4 md:px-8 lg:px-16 (NEVER px-16 alone)\n- Hide decorative on mobile if breaks layout: hidden md:block\n\nIMAGES — CRITICAL:\n- EVERY image MUST use: <img data-image-query=\"english search query\" alt=\"description\" class=\"w-full h-auto object-cover rounded-xl\"/>\n- NEVER use <img> without data-image-query\n- NEVER include a src attribute — the system auto-replaces data-image-query with a real image URL\n- Queries must be generic stock-photo friendly (e.g. \"modern office\" not \"Juan's cybercafe\")\n- For avatar-like elements, use colored divs with initials instead of img tags (e.g. <div class=\"w-10 h-10 rounded-full bg-primary flex items-center justify-center text-on-primary font-bold\">JD</div>)\n\nCOLOR SYSTEM — CRITICAL (READ CAREFULLY):\n- Use semantic color classes: bg-primary, text-primary, bg-primary-light, bg-primary-dark, text-on-primary, bg-surface, bg-surface-alt, text-on-surface, text-on-surface-muted, bg-secondary, text-secondary, bg-accent, text-accent\n- NEVER use hardcoded Tailwind color classes: NO bg-gray-*, bg-black, bg-white, bg-indigo-*, bg-blue-*, bg-purple-*, text-gray-*, text-black, text-white, etc.\n- The ONLY exception: border-gray-200 or border-gray-700 for subtle dividers.\n- ALL backgrounds MUST use: bg-primary, bg-primary-dark, bg-surface, bg-surface-alt\n- ALL text MUST use: text-on-surface, text-on-surface-muted, text-on-primary, text-accent. Use text-primary ONLY on bg-surface/bg-surface-alt (it's the same hue as bg-primary — invisible on primary backgrounds).\n- CONTRAST RULE: on bg-primary or bg-primary-dark → use ONLY text-on-primary. On bg-surface or bg-surface-alt → use text-on-surface, text-on-surface-muted, or text-primary. NEVER use text-primary on bg-primary — they are the SAME COLOR. NEVER put text-on-surface on bg-primary or text-on-primary on bg-surface. text-accent is decorative — use sparingly on bg-surface/bg-surface-alt only.\n- ANTI-PATTERN: NEVER put bg-primary on BOTH the section AND elements inside it. If section is bg-primary, inner cards/elements should be bg-surface. If section is bg-surface, cards can use bg-surface-alt or bg-primary.\n- For gradients: from-primary to-primary-dark, from-surface to-surface-alt\n- For hover: hover:bg-primary-dark, hover:bg-primary-light\n\nDESIGN PHILOSOPHY — what separates good from GREAT:\n- WHITESPACE is your best friend. Generous padding (py-24, py-32, px-8). Let elements breathe.\n- CONTRAST: mix dark sections with light ones. Alternate bg-primary and bg-surface sections.\n- TYPOGRAPHY: use extreme size differences for hierarchy (text-7xl headline next to text-sm label)\n- DEPTH: overlapping elements, negative margins (-mt-12), z-index layering, shadows\n- ASYMMETRY: avoid centering everything. Use grid-cols-5 with col-span-3 + col-span-2. Offset elements.\n- TEXTURE: use subtle patterns, gradients, border treatments, rounded-3xl mixed with sharp edges\n- Each section should have a COMPLETELY DIFFERENT layout from the others\n\nSECTION LAYOUT — CRITICAL:\n- Each <section> must be full-width (bg goes edge-to-edge). NO max-w on the section itself.\n- Constrain content inside with a wrapper div: <section class=\"bg-primary py-24\"><div class=\"max-w-7xl mx-auto px-4 md:px-8\">...content...</div></section>\n- EVERY section follows this pattern. The <section> handles bg color + vertical padding. The inner <div> handles horizontal padding + max-width.\n\nTESTIMONIALS SECTION:\n- Cards MUST use bg-surface or bg-surface-alt with text-on-surface\n- If section bg is bg-primary or bg-primary-dark, cards MUST be bg-surface (light cards on dark bg)\n- Quote text: text-on-surface, italic\n- Avatar: colored div with initials (bg-accent text-on-primary or bg-primary-light text-on-primary)\n- Name: text-on-surface font-semibold. Role/company: text-on-surface-muted\n- NEVER use same dark bg for both section AND cards\n\nHERO SECTION — your masterpiece:\n- Use a 2-column grid (lg:grid-cols-2) that fills the full height, NOT content floating in empty space\n- Left column: headline + description + CTAs, vertically centered with flex flex-col justify-center\n- Right column: large hero image (data-image-query) filling the column, or a bento-grid of image + stat cards\n- Bold oversized headline (text-4xl md:text-6xl lg:text-7xl font-black leading-tight)\n- Tag/label above headline (uppercase, tracking-wider, text-xs text-accent)\n- Short description paragraph (text-lg text-on-surface-muted, max-w-lg)\n- 2 CTAs: primary (large, px-8 py-4, with → arrow) + secondary (ghost/outlined)\n- Optional: social proof bar below CTAs (avatar stack + \"2,847+ users\" text)\n- Min height: min-h-[90vh] with items-center on the grid so content is vertically centered\n- CRITICAL: the grid must stretch to fill the section height. Use min-h-[90vh] on the grid container itself, not just the section\n- NEVER leave large empty areas — if using min-h-[90vh], content must be centered/distributed within it\n\nTAILWIND v3 NOTES:\n- Standard Tailwind v3 classes (shadow-sm, shadow-md, rounded-md, etc.)\n- Borders: border + border-gray-200 for visible borders`;\n\nexport const PROMPT_SUFFIX = `\n\nOUTPUT FORMAT: NDJSON — one JSON object per line, NO wrapper array, NO markdown fences.\nEach line: {\"label\": \"Short Label\", \"html\": \"<section>...</section>\"}\n\nGenerate 7-9 sections. Always start with Hero and end with Footer.\nIMPORTANT: Make each section VISUALLY UNIQUE — different layouts, different background colors, different grid structures.\nThink like a premium design agency creating a $50K landing page.\nNO generic Bootstrap layouts. Use creative grids, bento layouts, overlapping elements, asymmetric columns.`;\n\nexport interface GenerateOptions {\n anthropicApiKey?: string;\n openaiApiKey?: string;\n prompt: string;\n referenceImage?: string;\n extraInstructions?: string;\n systemPrompt?: string;\n model?: string;\n pexelsApiKey?: string;\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n onSection?: (section: Section3) => void;\n onImageUpdate?: (sectionId: string, html: string) => void;\n onDone?: (sections: Section3[]) => void;\n onError?: (error: Error) => void;\n}\n\n/**\n * Generate a landing page with streaming AI + image enrichment.\n */\nexport async function generateLanding(options: GenerateOptions): Promise<Section3[]> {\n const {\n prompt,\n referenceImage,\n extraInstructions,\n systemPrompt = SYSTEM_PROMPT,\n ...rest\n } = options;\n\n const extra = extraInstructions ? `\\nAdditional instructions: ${extraInstructions}` : \"\";\n const content: any[] = [];\n\n if (referenceImage) {\n const converted = dataUrlToImagePart(referenceImage);\n if (converted) {\n content.push({ type: \"image\", ...converted });\n } else {\n content.push({ type: \"image\", image: referenceImage });\n }\n content.push({\n type: \"text\",\n text: `Generate a landing page for: ${prompt}${extra}\\n\\nIMPORTANT: Use the reference image as a DIRECT visual guide. Replicate its layout structure, grid arrangement, spacing, visual hierarchy, and section organization as closely as possible. Match the number of columns, element positioning, and overall composition. Adapt the content to the prompt but keep the visual DNA of the reference.${PROMPT_SUFFIX}`,\n });\n } else {\n content.push({\n type: \"text\",\n text: `Generate a landing page for: ${prompt}${extra}${PROMPT_SUFFIX}`,\n });\n }\n\n return streamGenerate({\n ...rest,\n systemPrompt,\n userContent: content,\n });\n}\n"],"mappings":";;;;;;AAKO,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4EtB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6B7B,eAAsB,gBAAgB,SAA+C;AACnF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,QAAQ,oBAAoB;AAAA,2BAA8B,iBAAiB,KAAK;AACtF,QAAM,UAAiB,CAAC;AAExB,MAAI,gBAAgB;AAClB,UAAM,YAAY,mBAAmB,cAAc;AACnD,QAAI,WAAW;AACb,cAAQ,KAAK,EAAE,MAAM,SAAS,GAAG,UAAU,CAAC;AAAA,IAC9C,OAAO;AACL,cAAQ,KAAK,EAAE,MAAM,SAAS,OAAO,eAAe,CAAC;AAAA,IACvD;AACA,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,MAAM,gCAAgC,MAAM,GAAG,KAAK;AAAA;AAAA,iVAAsV,aAAa;AAAA,IACzZ,CAAC;AAAA,EACH,OAAO;AACL,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,MAAM,gCAAgC,MAAM,GAAG,KAAK,GAAG,aAAa;AAAA,IACtE,CAAC;AAAA,EACH;AAEA,SAAO,eAAe;AAAA,IACpB,GAAG;AAAA,IACH;AAAA,IACA,aAAa;AAAA,EACf,CAAC;AACH;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/generate.ts"],"sourcesContent":["import { streamGenerate, dataUrlToImagePart, extractJsonObjects } from \"./streamCore\";\nimport type { Section3 } from \"./types\";\n\nexport { extractJsonObjects };\n\nexport const SYSTEM_PROMPT = `You are a world-class web designer who creates AWARD-WINNING landing pages. Your designs win Awwwards, FWA, and CSS Design Awards. You think in terms of visual hierarchy, whitespace, and emotional impact.\n\nRULES:\n- Each section is a complete <section> tag with Tailwind CSS classes\n- Use Tailwind CDN classes ONLY (no custom CSS, no @apply, no @import, no @tailwind directives)\n- NO JavaScript, only HTML+Tailwind\n- Each section must be independent and self-contained\n- Responsive: mobile-first with sm/md/lg/xl breakpoints\n- All text content in Spanish unless the prompt specifies otherwise\n- Use real-looking content (not Lorem ipsum) — make it specific to the prompt\n\nRESPONSIVE — MANDATORY:\n- EVERY grid: grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 (NEVER grid-cols-3 alone)\n- EVERY flex row: flex flex-col md:flex-row (NEVER flex flex-row alone)\n- Text sizes: text-3xl md:text-5xl lg:text-7xl (NEVER text-7xl alone)\n- Images: w-full h-auto object-cover max-w-full\n- Padding: px-4 md:px-8 lg:px-16 (NEVER px-16 alone)\n- Hide decorative on mobile if breaks layout: hidden md:block\n\nIMAGES — CRITICAL:\n- EVERY image MUST use: <img data-image-query=\"english search query\" alt=\"description\" class=\"w-full h-auto object-cover rounded-xl\"/>\n- NEVER use <img> without data-image-query\n- NEVER include a src attribute — the system auto-replaces data-image-query with a real image URL\n- Queries must be generic stock-photo friendly (e.g. \"modern office\" not \"Juan's cybercafe\")\n- For avatar-like elements, use colored divs with initials instead of img tags (e.g. <div class=\"w-10 h-10 rounded-full bg-primary flex items-center justify-center text-on-primary font-bold\">JD</div>)\n\nCOLOR SYSTEM — CRITICAL (READ CAREFULLY):\n- Use semantic color classes: bg-primary, text-primary, bg-primary-light, bg-primary-dark, text-on-primary, bg-surface, bg-surface-alt, text-on-surface, text-on-surface-muted, bg-secondary, text-secondary, bg-accent, text-accent\n- NEVER use hardcoded Tailwind color classes: NO bg-gray-*, bg-black, bg-white, bg-indigo-*, bg-blue-*, bg-purple-*, text-gray-*, text-black, text-white, etc.\n- The ONLY exception: border-gray-200 or border-gray-700 for subtle dividers.\n- ALL backgrounds MUST use: bg-primary, bg-primary-dark, bg-surface, bg-surface-alt\n- ALL text MUST use: text-on-surface, text-on-surface-muted, text-on-primary, text-accent. Use text-primary ONLY on bg-surface/bg-surface-alt (it's the same hue as bg-primary — invisible on primary backgrounds).\n- CONTRAST RULE: on bg-primary or bg-primary-dark → use ONLY text-on-primary. On bg-surface or bg-surface-alt → use text-on-surface, text-on-surface-muted, or text-primary. NEVER use text-primary on bg-primary — they are the SAME COLOR. NEVER put text-on-surface on bg-primary or text-on-primary on bg-surface. text-accent is decorative — use sparingly on bg-surface/bg-surface-alt only.\n- ANTI-PATTERN: NEVER put bg-primary on BOTH the section AND elements inside it. If section is bg-primary, inner cards/elements should be bg-surface. If section is bg-surface, cards can use bg-surface-alt or bg-primary.\n- For gradients: from-primary to-primary-dark, from-surface to-surface-alt\n- For hover: hover:bg-primary-dark, hover:bg-primary-light\n\nDESIGN PHILOSOPHY — what separates good from GREAT:\n- WHITESPACE is your best friend. Generous padding (py-24, py-32, px-8). Let elements breathe.\n- CONTRAST: mix dark sections with light ones. Alternate bg-primary and bg-surface sections.\n- TYPOGRAPHY: use extreme size differences for hierarchy (text-7xl headline next to text-sm label)\n- DEPTH: overlapping elements, negative margins (-mt-12), z-index layering, shadows\n- ASYMMETRY: avoid centering everything. Use grid-cols-5 with col-span-3 + col-span-2. Offset elements.\n- TEXTURE: use subtle patterns, gradients, border treatments, rounded-3xl mixed with sharp edges\n- Each section should have a COMPLETELY DIFFERENT layout from the others\n\nSECTION LAYOUT — CRITICAL:\n- Each <section> must be full-width (bg goes edge-to-edge). NO max-w on the section itself.\n- Constrain content inside with a wrapper div: <section class=\"bg-primary py-24\"><div class=\"max-w-7xl mx-auto px-4 md:px-8\">...content...</div></section>\n- EVERY section follows this pattern. The <section> handles bg color + vertical padding. The inner <div> handles horizontal padding + max-width.\n\nTESTIMONIALS SECTION:\n- Cards MUST use bg-surface or bg-surface-alt with text-on-surface\n- If section bg is bg-primary or bg-primary-dark, cards MUST be bg-surface (light cards on dark bg)\n- Quote text: text-on-surface, italic\n- Avatar: colored div with initials (bg-accent text-on-primary or bg-primary-light text-on-primary)\n- Name: text-on-surface font-semibold. Role/company: text-on-surface-muted\n- NEVER use same dark bg for both section AND cards\n\nHERO SECTION — your masterpiece:\n- Use a 2-column grid (lg:grid-cols-2) that fills the full height, NOT content floating in empty space\n- Left column: headline + description + CTAs, vertically centered with flex flex-col justify-center\n- Right column: large hero image (data-image-query) filling the column, or a bento-grid of image + stat cards\n- Bold oversized headline (text-4xl md:text-6xl lg:text-7xl font-black leading-tight)\n- Tag/label above headline (uppercase, tracking-wider, text-xs text-accent)\n- Short description paragraph (text-lg text-on-surface-muted, max-w-lg)\n- 2 CTAs: primary (large, px-8 py-4, with → arrow) + secondary (ghost/outlined)\n- Optional: social proof bar below CTAs (avatar stack + \"2,847+ users\" text)\n- Min height: min-h-[90vh] with items-center on the grid so content is vertically centered\n- CRITICAL: the grid must stretch to fill the section height. Use min-h-[90vh] on the grid container itself, not just the section\n- NEVER leave large empty areas — if using min-h-[90vh], content must be centered/distributed within it\n\nTAILWIND v3 NOTES:\n- Standard Tailwind v3 classes (shadow-sm, shadow-md, rounded-md, etc.)\n- Borders: border + border-gray-200 for visible borders`;\n\nexport const PROMPT_SUFFIX = `\n\nOUTPUT FORMAT: NDJSON — one JSON object per line, NO wrapper array, NO markdown fences.\nEach line: {\"label\": \"Short Label\", \"html\": \"<section>...</section>\"}\n\nGenerate 7-9 sections. Always start with Hero and end with Footer.\nIMPORTANT: Make each section VISUALLY UNIQUE — different layouts, different background colors, different grid structures.\nThink like a premium design agency creating a $50K landing page.\nNO generic Bootstrap layouts. Use creative grids, bento layouts, overlapping elements, asymmetric columns.`;\n\nexport interface GenerateOptions {\n anthropicApiKey?: string;\n openaiApiKey?: string;\n prompt: string;\n referenceImage?: string;\n extraInstructions?: string;\n systemPrompt?: string;\n model?: string;\n pexelsApiKey?: string;\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n onSection?: (section: Section3) => void;\n onImageUpdate?: (sectionId: string, html: string) => void;\n onDone?: (sections: Section3[]) => void;\n onError?: (error: Error) => void;\n /** Theme colors to inject into the AI prompt */\n themeColors?: Record<string, string>;\n /** Brand kit info for AI context */\n brandKit?: {\n fonts?: { heading?: string; body?: string };\n mood?: string;\n logoUrl?: string;\n };\n}\n\n/**\n * Generate a landing page with streaming AI + image enrichment.\n */\nfunction buildVisualContext(themeColors?: Record<string, string>, brandKit?: GenerateOptions[\"brandKit\"]): string {\n if (!themeColors && !brandKit) return \"\";\n\n const lines: string[] = [\"\\n\\n## Visual Context — MANDATORY\"];\n\n if (themeColors) {\n lines.push(\"You MUST use these exact semantic color values in your design. The CSS variables are already configured — just use the semantic classes (bg-primary, text-on-surface, etc). Here are the actual color values for reference so you understand the palette:\");\n for (const [key, value] of Object.entries(themeColors)) {\n lines.push(`- --color-${key}: ${value}`);\n }\n const isDark = themeColors.surface && parseInt(themeColors.surface.slice(1, 3), 16) < 128;\n if (isDark) {\n lines.push(\"This is a DARK theme — surfaces are dark, text is light. Design accordingly.\");\n }\n }\n\n if (brandKit?.fonts) {\n const { heading, body } = brandKit.fonts;\n if (heading) lines.push(`- Heading font: use font-family: '${heading}' via inline style on h1-h6`);\n if (body) lines.push(`- Body font: use font-family: '${body}' via inline style on p, li, span`);\n }\n\n if (brandKit?.mood) {\n lines.push(`- Design mood: ${brandKit.mood} — adapt spacing, imagery style, and visual weight to match this mood`);\n }\n\n if (brandKit?.logoUrl) {\n lines.push(`- Brand logo: include <img src=\"${brandKit.logoUrl}\" alt=\"Logo\" class=\"h-8 w-auto\" /> in the navbar/hero area`);\n }\n\n return lines.join(\"\\n\");\n}\n\nexport async function generateLanding(options: GenerateOptions): Promise<Section3[]> {\n const {\n prompt,\n referenceImage,\n extraInstructions,\n systemPrompt = SYSTEM_PROMPT,\n themeColors,\n brandKit,\n ...rest\n } = options;\n\n const visualContext = buildVisualContext(themeColors, brandKit);\n const extra = extraInstructions ? `\\nAdditional instructions: ${extraInstructions}` : \"\";\n const content: any[] = [];\n\n if (referenceImage) {\n const converted = dataUrlToImagePart(referenceImage);\n if (converted) {\n content.push({ type: \"image\", ...converted });\n } else {\n content.push({ type: \"image\", image: referenceImage });\n }\n content.push({\n type: \"text\",\n text: `Generate a landing page for: ${prompt}${extra}\\n\\nIMPORTANT: Use the reference image as a DIRECT visual guide. Replicate its layout structure, grid arrangement, spacing, visual hierarchy, and section organization as closely as possible. Match the number of columns, element positioning, and overall composition. Adapt the content to the prompt but keep the visual DNA of the reference.${PROMPT_SUFFIX}`,\n });\n } else {\n content.push({\n type: \"text\",\n text: `Generate a landing page for: ${prompt}${extra}${PROMPT_SUFFIX}`,\n });\n }\n\n return streamGenerate({\n ...rest,\n systemPrompt: systemPrompt + visualContext,\n userContent: content,\n });\n}\n"],"mappings":";;;;;;AAKO,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4EtB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqC7B,SAAS,mBAAmB,aAAsC,UAAgD;AAChH,MAAI,CAAC,eAAe,CAAC,SAAU,QAAO;AAEtC,QAAM,QAAkB,CAAC,wCAAmC;AAE5D,MAAI,aAAa;AACf,UAAM,KAAK,gQAA2P;AACtQ,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,WAAW,GAAG;AACtD,YAAM,KAAK,aAAa,GAAG,KAAK,KAAK,EAAE;AAAA,IACzC;AACA,UAAM,SAAS,YAAY,WAAW,SAAS,YAAY,QAAQ,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AACtF,QAAI,QAAQ;AACV,YAAM,KAAK,mFAA8E;AAAA,IAC3F;AAAA,EACF;AAEA,MAAI,UAAU,OAAO;AACnB,UAAM,EAAE,SAAS,KAAK,IAAI,SAAS;AACnC,QAAI,QAAS,OAAM,KAAK,qCAAqC,OAAO,6BAA6B;AACjG,QAAI,KAAM,OAAM,KAAK,kCAAkC,IAAI,mCAAmC;AAAA,EAChG;AAEA,MAAI,UAAU,MAAM;AAClB,UAAM,KAAK,kBAAkB,SAAS,IAAI,4EAAuE;AAAA,EACnH;AAEA,MAAI,UAAU,SAAS;AACrB,UAAM,KAAK,mCAAmC,SAAS,OAAO,4DAA4D;AAAA,EAC5H;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,eAAsB,gBAAgB,SAA+C;AACnF,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AAEJ,QAAM,gBAAgB,mBAAmB,aAAa,QAAQ;AAC9D,QAAM,QAAQ,oBAAoB;AAAA,2BAA8B,iBAAiB,KAAK;AACtF,QAAM,UAAiB,CAAC;AAExB,MAAI,gBAAgB;AAClB,UAAM,YAAY,mBAAmB,cAAc;AACnD,QAAI,WAAW;AACb,cAAQ,KAAK,EAAE,MAAM,SAAS,GAAG,UAAU,CAAC;AAAA,IAC9C,OAAO;AACL,cAAQ,KAAK,EAAE,MAAM,SAAS,OAAO,eAAe,CAAC;AAAA,IACvD;AACA,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,MAAM,gCAAgC,MAAM,GAAG,KAAK;AAAA;AAAA,iVAAsV,aAAa;AAAA,IACzZ,CAAC;AAAA,EACH,OAAO;AACL,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,MAAM,gCAAgC,MAAM,GAAG,KAAK,GAAG,aAAa;AAAA,IACtE,CAAC;AAAA,EACH;AAEA,SAAO,eAAe;AAAA,IACpB,GAAG;AAAA,IACH,cAAc,eAAe;AAAA,IAC7B,aAAa;AAAA,EACf,CAAC;AACH;","names":[]}
|
|
@@ -64,7 +64,8 @@ async function refineLanding(options) {
|
|
|
64
64
|
persistImage,
|
|
65
65
|
onChunk,
|
|
66
66
|
onDone,
|
|
67
|
-
onError
|
|
67
|
+
onError,
|
|
68
|
+
themeColors
|
|
68
69
|
} = options;
|
|
69
70
|
const openaiApiKey = _openaiApiKey || process.env.OPENAI_API_KEY;
|
|
70
71
|
const useVision = !!referenceImage;
|
|
@@ -99,9 +100,19 @@ Instruction: ${instruction}
|
|
|
99
100
|
Return the updated HTML.`
|
|
100
101
|
});
|
|
101
102
|
}
|
|
103
|
+
let finalSystem = systemPrompt + currentDateLine();
|
|
104
|
+
if (themeColors) {
|
|
105
|
+
const colorLines = Object.entries(themeColors).map(([k, v]) => `- --color-${k}: ${v}`).join("\n");
|
|
106
|
+
const isDark = themeColors.surface && parseInt(themeColors.surface.slice(1, 3), 16) < 128;
|
|
107
|
+
finalSystem += `
|
|
108
|
+
|
|
109
|
+
## Active Theme Colors
|
|
110
|
+
The landing uses these semantic color values. Keep using semantic classes (bg-primary, text-on-surface, etc):
|
|
111
|
+
${colorLines}${isDark ? "\nThis is a DARK theme." : ""}`;
|
|
112
|
+
}
|
|
102
113
|
const result = streamText({
|
|
103
114
|
model,
|
|
104
|
-
system:
|
|
115
|
+
system: finalSystem,
|
|
105
116
|
messages: [{ role: "user", content }],
|
|
106
117
|
...isVariant && !referenceImage ? { temperature: 1.2 } : {}
|
|
107
118
|
});
|
|
@@ -131,4 +142,4 @@ export {
|
|
|
131
142
|
extractSectionDescription,
|
|
132
143
|
refineLanding
|
|
133
144
|
};
|
|
134
|
-
//# sourceMappingURL=chunk-
|
|
145
|
+
//# sourceMappingURL=chunk-JDBCNVE7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/refine.ts"],"sourcesContent":["import { streamText } from \"ai\";\nimport { enrichImages } from \"./images/enrichImages\";\nimport { sanitizeSemanticColors } from \"./sanitizeColors\";\nimport { resolveModel, currentDateLine } from \"./streamCore\";\n\nexport const REFINE_SYSTEM = `You are an expert HTML/Tailwind CSS developer. You receive the current HTML of a landing page section and a user instruction.\n\nRULES:\n- Return ONLY the modified HTML — no full page, no <html>/<head>/<body> tags\n- Use Tailwind CSS classes (CDN loaded)\n- You may use inline styles for specific adjustments\n- Images: use data-image-query=\"english search query\" for new images\n- Keep all text in its original language unless asked to translate\n- Be creative — don't just make minimal changes, improve the design\n- Return raw HTML only — no markdown fences, no explanations\n\nCOLOR SYSTEM — CRITICAL:\n- Use semantic color classes: bg-primary, text-primary, bg-primary-light, bg-primary-dark, text-on-primary, bg-surface, bg-surface-alt, text-on-surface, text-on-surface-muted, bg-secondary, text-secondary, bg-accent, text-accent\n- NEVER use hardcoded colors: NO bg-gray-*, bg-black, bg-white, text-gray-*, text-black, text-white, etc.\n- The ONLY exception: border-gray-200 or border-gray-700 for subtle dividers.\n- ALL text MUST use: text-on-surface, text-on-surface-muted, text-on-primary, text-accent. Use text-primary ONLY on bg-surface/bg-surface-alt (it's the same hue as bg-primary — invisible on primary backgrounds).\n- CONTRAST RULE: on bg-primary or bg-primary-dark → use ONLY text-on-primary. On bg-surface or bg-surface-alt → use text-on-surface, text-on-surface-muted, or text-primary. NEVER use text-primary on bg-primary — they are the SAME COLOR. NEVER put text-on-surface on bg-primary or text-on-primary on bg-surface.\n\nTAILWIND v3 NOTES:\n- Standard Tailwind v3 classes (shadow-sm, shadow-md, rounded-md, etc.)\n- Borders: border + border-gray-200 for visible borders`;\n\n/**\n * Extract a text description from HTML for variant generation.\n * Instead of sending full HTML to the model, we send a content summary\n * so the model generates a completely new layout rather than tweaking colors.\n */\nexport function extractSectionDescription(html: string, label?: string): { content: string; layoutHint: string } {\n // Extract headings\n const headings = [...html.matchAll(/<h[1-6][^>]*>([\\s\\S]*?)<\\/h[1-6]>/gi)]\n .map(m => m[1].replace(/<[^>]+>/g, \"\").trim())\n .filter(Boolean);\n\n // Extract paragraphs\n const paragraphs = [...html.matchAll(/<p[^>]*>([\\s\\S]*?)<\\/p>/gi)]\n .map(m => m[1].replace(/<[^>]+>/g, \"\").trim())\n .filter(Boolean);\n\n // Extract button/CTA text\n const buttons = [...html.matchAll(/<(?:button|a)[^>]*>([\\s\\S]*?)<\\/(?:button|a)>/gi)]\n .map(m => m[1].replace(/<[^>]+>/g, \"\").trim())\n .filter(t => t.length > 0 && t.length < 60);\n\n // Count items (cards, list items, grid children)\n const listItems = (html.match(/<li[\\s>]/gi) || []).length;\n const gridMatch = html.match(/grid-cols-(\\d)/);\n const gridCols = gridMatch ? parseInt(gridMatch[1]) : 0;\n\n // Detect layout patterns for negative prompt\n const layouts: string[] = [];\n if (html.includes(\"grid\")) layouts.push(\"grid\");\n if (html.includes(\"flex-col\")) layouts.push(\"vertical-stack\");\n if (html.includes(\"flex-row\") || html.includes(\"md:flex-row\")) layouts.push(\"horizontal-flex\");\n if (html.includes(\"text-center\") && !html.includes(\"text-left\")) layouts.push(\"centered\");\n if (gridCols) layouts.push(`${gridCols}-column-grid`);\n\n const content = [\n label ? `Section: ${label}` : \"\",\n headings.length ? `Headings: ${headings.join(\" | \")}` : \"\",\n paragraphs.length ? `Text: ${paragraphs.slice(0, 3).join(\" \")}` : \"\",\n buttons.length ? `CTAs: ${buttons.join(\", \")}` : \"\",\n listItems > 0 ? `${listItems} list/card items` : \"\",\n ].filter(Boolean).join(\"\\n\");\n\n return { content, layoutHint: layouts.join(\", \") };\n}\n\nexport interface RefineOptions {\n /** Anthropic API key. Falls back to ANTHROPIC_API_KEY env var */\n anthropicApiKey?: string;\n /** OpenAI API key. If provided, uses GPT-4o-mini instead of Claude */\n openaiApiKey?: string;\n /** Current HTML of the section being refined */\n currentHtml: string;\n /** User instruction for refinement */\n instruction: string;\n /** Reference image (base64 data URI) for vision-based refinement */\n referenceImage?: string;\n /** When true, generates a completely new layout variant instead of refining */\n isVariant?: boolean;\n /** Custom system prompt (overrides default REFINE_SYSTEM) */\n systemPrompt?: string;\n /** Model ID (default: gpt-4o-mini/gpt-4o for OpenAI, claude-haiku/claude-sonnet for Anthropic) */\n model?: string;\n /** Pexels API key for image enrichment. Falls back to PEXELS_API_KEY env var */\n pexelsApiKey?: string;\n /** Called with temp DALL-E URL + query, returns permanent URL. Use to persist to S3/etc. */\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n /** Called with accumulated HTML as it streams */\n onChunk?: (html: string) => void;\n /** Called when refinement is complete with final enriched HTML */\n onDone?: (html: string) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n /** Theme colors for AI context */\n themeColors?: Record<string, string>;\n}\n\n/**\n * Refine a landing page section with streaming AI.\n * Returns the final enriched HTML.\n */\nexport async function refineLanding(options: RefineOptions): Promise<string> {\n const {\n anthropicApiKey,\n openaiApiKey: _openaiApiKey,\n currentHtml,\n instruction,\n referenceImage,\n isVariant,\n systemPrompt = REFINE_SYSTEM,\n model: modelId,\n pexelsApiKey,\n persistImage,\n onChunk,\n onDone,\n onError,\n themeColors,\n } = options;\n\n const openaiApiKey = _openaiApiKey || process.env.OPENAI_API_KEY;\n const useVision = !!referenceImage;\n const defaultOpenai = useVision ? \"gpt-4o\" : \"gpt-4o-mini\";\n const defaultAnthropic = useVision ? \"claude-sonnet-4-6\" : \"claude-haiku-4-5-20251001\";\n const model = await resolveModel({ openaiApiKey, anthropicApiKey, modelId, defaultOpenai, defaultAnthropic });\n\n // Build content (supports multimodal with reference image)\n const content: any[] = [];\n if (referenceImage) {\n content.push({ type: \"image\", image: referenceImage });\n }\n\n if (isVariant && !referenceImage) {\n // Variant mode: send description instead of HTML to force creative layout\n const { content: desc, layoutHint } = extractSectionDescription(currentHtml);\n content.push({\n type: \"text\",\n text: `Generate a COMPLETELY NEW section with the following content. Create an original, creative layout.\\n\\nContent:\\n${desc}\\n\\n${layoutHint ? `DO NOT use these layout patterns (the current design already uses them): ${layoutHint}. Choose a radically different structure.` : \"\"}\\n\\nReturn ONLY the <section>...</section> HTML with Tailwind classes.`,\n });\n } else {\n content.push({\n type: \"text\",\n text: `Current HTML:\\n${currentHtml}\\n\\nInstruction: ${instruction}\\n\\nReturn the updated HTML.`,\n });\n }\n\n // Inject theme context if available\n let finalSystem = systemPrompt + currentDateLine();\n if (themeColors) {\n const colorLines = Object.entries(themeColors)\n .map(([k, v]) => `- --color-${k}: ${v}`)\n .join(\"\\n\");\n const isDark = themeColors.surface && parseInt(themeColors.surface.slice(1, 3), 16) < 128;\n finalSystem += `\\n\\n## Active Theme Colors\\nThe landing uses these semantic color values. Keep using semantic classes (bg-primary, text-on-surface, etc):\\n${colorLines}${isDark ? \"\\nThis is a DARK theme.\" : \"\"}`;\n }\n\n const result = streamText({\n model,\n system: finalSystem,\n messages: [{ role: \"user\", content }],\n ...(isVariant && !referenceImage ? { temperature: 1.2 } : {}),\n });\n\n try {\n let accumulated = \"\";\n\n for await (const chunk of result.textStream) {\n accumulated += chunk;\n onChunk?.(accumulated);\n }\n\n // Clean up markdown fences if present\n let html = accumulated.trim();\n if (html.startsWith(\"```\")) {\n html = html.replace(/^```(?:html|xml)?\\s*/, \"\").replace(/\\s*```$/, \"\");\n }\n\n // Sanitize hardcoded colors to semantic classes\n html = sanitizeSemanticColors(html);\n\n // Enrich images (DALL-E if openaiApiKey, otherwise Pexels)\n html = await enrichImages(html, { pexelsApiKey, openaiApiKey, persistImage });\n\n onDone?.(html);\n return html;\n } catch (err: any) {\n const error = err instanceof Error ? err : new Error(err?.message || \"Refine failed\");\n onError?.(error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/components.js
CHANGED
package/dist/generate.d.ts
CHANGED
|
@@ -21,10 +21,18 @@ interface GenerateOptions {
|
|
|
21
21
|
onImageUpdate?: (sectionId: string, html: string) => void;
|
|
22
22
|
onDone?: (sections: Section3[]) => void;
|
|
23
23
|
onError?: (error: Error) => void;
|
|
24
|
+
/** Theme colors to inject into the AI prompt */
|
|
25
|
+
themeColors?: Record<string, string>;
|
|
26
|
+
/** Brand kit info for AI context */
|
|
27
|
+
brandKit?: {
|
|
28
|
+
fonts?: {
|
|
29
|
+
heading?: string;
|
|
30
|
+
body?: string;
|
|
31
|
+
};
|
|
32
|
+
mood?: string;
|
|
33
|
+
logoUrl?: string;
|
|
34
|
+
};
|
|
24
35
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Generate a landing page with streaming AI + image enrichment.
|
|
27
|
-
*/
|
|
28
36
|
declare function generateLanding(options: GenerateOptions): Promise<Section3[]>;
|
|
29
37
|
|
|
30
38
|
export { type GenerateOptions, PROMPT_SUFFIX, SYSTEM_PROMPT, extractJsonObjects, generateLanding };
|
package/dist/generate.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
FloatingToolbar,
|
|
5
5
|
SectionList,
|
|
6
6
|
ViewportToggle
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5MDDRBEO.js";
|
|
8
8
|
import "./chunk-MJ34S5ZC.js";
|
|
9
9
|
import {
|
|
10
10
|
PROMPT_SUFFIX,
|
|
11
11
|
SYSTEM_PROMPT,
|
|
12
12
|
generateLanding
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-C4D2NT5N.js";
|
|
14
14
|
import {
|
|
15
15
|
DOCUMENT_PROMPT_SUFFIX,
|
|
16
16
|
DOCUMENT_SYSTEM_PROMPT,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
import {
|
|
20
20
|
REFINE_SYSTEM,
|
|
21
21
|
refineLanding
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-JDBCNVE7.js";
|
|
23
23
|
import {
|
|
24
24
|
deployToEasyBits,
|
|
25
25
|
deployToS3
|
package/dist/refine.d.ts
CHANGED
|
@@ -35,6 +35,8 @@ interface RefineOptions {
|
|
|
35
35
|
onDone?: (html: string) => void;
|
|
36
36
|
/** Called on error */
|
|
37
37
|
onError?: (error: Error) => void;
|
|
38
|
+
/** Theme colors for AI context */
|
|
39
|
+
themeColors?: Record<string, string>;
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
40
42
|
* Refine a landing page section with streaming AI.
|
package/dist/refine.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@easybits.cloud/html-tailwind-generator",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.111",
|
|
4
4
|
"description": "AI-powered landing page generator with Tailwind CSS — canvas editor, streaming generation, and one-click deploy",
|
|
5
5
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
6
6
|
"type": "module",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/refine.ts"],"sourcesContent":["import { streamText } from \"ai\";\nimport { enrichImages } from \"./images/enrichImages\";\nimport { sanitizeSemanticColors } from \"./sanitizeColors\";\nimport { resolveModel, currentDateLine } from \"./streamCore\";\n\nexport const REFINE_SYSTEM = `You are an expert HTML/Tailwind CSS developer. You receive the current HTML of a landing page section and a user instruction.\n\nRULES:\n- Return ONLY the modified HTML — no full page, no <html>/<head>/<body> tags\n- Use Tailwind CSS classes (CDN loaded)\n- You may use inline styles for specific adjustments\n- Images: use data-image-query=\"english search query\" for new images\n- Keep all text in its original language unless asked to translate\n- Be creative — don't just make minimal changes, improve the design\n- Return raw HTML only — no markdown fences, no explanations\n\nCOLOR SYSTEM — CRITICAL:\n- Use semantic color classes: bg-primary, text-primary, bg-primary-light, bg-primary-dark, text-on-primary, bg-surface, bg-surface-alt, text-on-surface, text-on-surface-muted, bg-secondary, text-secondary, bg-accent, text-accent\n- NEVER use hardcoded colors: NO bg-gray-*, bg-black, bg-white, text-gray-*, text-black, text-white, etc.\n- The ONLY exception: border-gray-200 or border-gray-700 for subtle dividers.\n- ALL text MUST use: text-on-surface, text-on-surface-muted, text-on-primary, text-accent. Use text-primary ONLY on bg-surface/bg-surface-alt (it's the same hue as bg-primary — invisible on primary backgrounds).\n- CONTRAST RULE: on bg-primary or bg-primary-dark → use ONLY text-on-primary. On bg-surface or bg-surface-alt → use text-on-surface, text-on-surface-muted, or text-primary. NEVER use text-primary on bg-primary — they are the SAME COLOR. NEVER put text-on-surface on bg-primary or text-on-primary on bg-surface.\n\nTAILWIND v3 NOTES:\n- Standard Tailwind v3 classes (shadow-sm, shadow-md, rounded-md, etc.)\n- Borders: border + border-gray-200 for visible borders`;\n\n/**\n * Extract a text description from HTML for variant generation.\n * Instead of sending full HTML to the model, we send a content summary\n * so the model generates a completely new layout rather than tweaking colors.\n */\nexport function extractSectionDescription(html: string, label?: string): { content: string; layoutHint: string } {\n // Extract headings\n const headings = [...html.matchAll(/<h[1-6][^>]*>([\\s\\S]*?)<\\/h[1-6]>/gi)]\n .map(m => m[1].replace(/<[^>]+>/g, \"\").trim())\n .filter(Boolean);\n\n // Extract paragraphs\n const paragraphs = [...html.matchAll(/<p[^>]*>([\\s\\S]*?)<\\/p>/gi)]\n .map(m => m[1].replace(/<[^>]+>/g, \"\").trim())\n .filter(Boolean);\n\n // Extract button/CTA text\n const buttons = [...html.matchAll(/<(?:button|a)[^>]*>([\\s\\S]*?)<\\/(?:button|a)>/gi)]\n .map(m => m[1].replace(/<[^>]+>/g, \"\").trim())\n .filter(t => t.length > 0 && t.length < 60);\n\n // Count items (cards, list items, grid children)\n const listItems = (html.match(/<li[\\s>]/gi) || []).length;\n const gridMatch = html.match(/grid-cols-(\\d)/);\n const gridCols = gridMatch ? parseInt(gridMatch[1]) : 0;\n\n // Detect layout patterns for negative prompt\n const layouts: string[] = [];\n if (html.includes(\"grid\")) layouts.push(\"grid\");\n if (html.includes(\"flex-col\")) layouts.push(\"vertical-stack\");\n if (html.includes(\"flex-row\") || html.includes(\"md:flex-row\")) layouts.push(\"horizontal-flex\");\n if (html.includes(\"text-center\") && !html.includes(\"text-left\")) layouts.push(\"centered\");\n if (gridCols) layouts.push(`${gridCols}-column-grid`);\n\n const content = [\n label ? `Section: ${label}` : \"\",\n headings.length ? `Headings: ${headings.join(\" | \")}` : \"\",\n paragraphs.length ? `Text: ${paragraphs.slice(0, 3).join(\" \")}` : \"\",\n buttons.length ? `CTAs: ${buttons.join(\", \")}` : \"\",\n listItems > 0 ? `${listItems} list/card items` : \"\",\n ].filter(Boolean).join(\"\\n\");\n\n return { content, layoutHint: layouts.join(\", \") };\n}\n\nexport interface RefineOptions {\n /** Anthropic API key. Falls back to ANTHROPIC_API_KEY env var */\n anthropicApiKey?: string;\n /** OpenAI API key. If provided, uses GPT-4o-mini instead of Claude */\n openaiApiKey?: string;\n /** Current HTML of the section being refined */\n currentHtml: string;\n /** User instruction for refinement */\n instruction: string;\n /** Reference image (base64 data URI) for vision-based refinement */\n referenceImage?: string;\n /** When true, generates a completely new layout variant instead of refining */\n isVariant?: boolean;\n /** Custom system prompt (overrides default REFINE_SYSTEM) */\n systemPrompt?: string;\n /** Model ID (default: gpt-4o-mini/gpt-4o for OpenAI, claude-haiku/claude-sonnet for Anthropic) */\n model?: string;\n /** Pexels API key for image enrichment. Falls back to PEXELS_API_KEY env var */\n pexelsApiKey?: string;\n /** Called with temp DALL-E URL + query, returns permanent URL. Use to persist to S3/etc. */\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n /** Called with accumulated HTML as it streams */\n onChunk?: (html: string) => void;\n /** Called when refinement is complete with final enriched HTML */\n onDone?: (html: string) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n}\n\n/**\n * Refine a landing page section with streaming AI.\n * Returns the final enriched HTML.\n */\nexport async function refineLanding(options: RefineOptions): Promise<string> {\n const {\n anthropicApiKey,\n openaiApiKey: _openaiApiKey,\n currentHtml,\n instruction,\n referenceImage,\n isVariant,\n systemPrompt = REFINE_SYSTEM,\n model: modelId,\n pexelsApiKey,\n persistImage,\n onChunk,\n onDone,\n onError,\n } = options;\n\n const openaiApiKey = _openaiApiKey || process.env.OPENAI_API_KEY;\n const useVision = !!referenceImage;\n const defaultOpenai = useVision ? \"gpt-4o\" : \"gpt-4o-mini\";\n const defaultAnthropic = useVision ? \"claude-sonnet-4-6\" : \"claude-haiku-4-5-20251001\";\n const model = await resolveModel({ openaiApiKey, anthropicApiKey, modelId, defaultOpenai, defaultAnthropic });\n\n // Build content (supports multimodal with reference image)\n const content: any[] = [];\n if (referenceImage) {\n content.push({ type: \"image\", image: referenceImage });\n }\n\n if (isVariant && !referenceImage) {\n // Variant mode: send description instead of HTML to force creative layout\n const { content: desc, layoutHint } = extractSectionDescription(currentHtml);\n content.push({\n type: \"text\",\n text: `Generate a COMPLETELY NEW section with the following content. Create an original, creative layout.\\n\\nContent:\\n${desc}\\n\\n${layoutHint ? `DO NOT use these layout patterns (the current design already uses them): ${layoutHint}. Choose a radically different structure.` : \"\"}\\n\\nReturn ONLY the <section>...</section> HTML with Tailwind classes.`,\n });\n } else {\n content.push({\n type: \"text\",\n text: `Current HTML:\\n${currentHtml}\\n\\nInstruction: ${instruction}\\n\\nReturn the updated HTML.`,\n });\n }\n\n const result = streamText({\n model,\n system: systemPrompt + currentDateLine(),\n messages: [{ role: \"user\", content }],\n ...(isVariant && !referenceImage ? { temperature: 1.2 } : {}),\n });\n\n try {\n let accumulated = \"\";\n\n for await (const chunk of result.textStream) {\n accumulated += chunk;\n onChunk?.(accumulated);\n }\n\n // Clean up markdown fences if present\n let html = accumulated.trim();\n if (html.startsWith(\"```\")) {\n html = html.replace(/^```(?:html|xml)?\\s*/, \"\").replace(/\\s*```$/, \"\");\n }\n\n // Sanitize hardcoded colors to semantic classes\n html = sanitizeSemanticColors(html);\n\n // Enrich images (DALL-E if openaiApiKey, otherwise Pexels)\n html = await enrichImages(html, { pexelsApiKey, openaiApiKey, persistImage });\n\n onDone?.(html);\n return html;\n } catch (err: any) {\n const error = err instanceof Error ? err : new Error(err?.message || \"Refine failed\");\n onError?.(error);\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Canvas.tsx","../src/components/SectionList.tsx","../src/components/FloatingToolbar.tsx","../src/components/CodeEditor.tsx","../src/components/ViewportToggle.tsx","../src/hooks/useUndoStack.ts"],"sourcesContent":["import React, { useRef, useEffect, useCallback, useState, forwardRef, useImperativeHandle } from \"react\";\nimport type { Section3, IframeMessage } from \"../types\";\nimport { buildPreviewHtml } from \"../buildHtml\";\n\nexport interface CanvasHandle {\n scrollToSection: (id: string) => void;\n postMessage: (msg: Record<string, unknown>) => void;\n}\n\ninterface CanvasProps {\n sections: Section3[];\n theme?: string;\n onMessage: (msg: IframeMessage) => void;\n iframeRectRef: React.MutableRefObject<DOMRect | null>;\n onReady?: () => void;\n}\n\nexport const Canvas = forwardRef<CanvasHandle, CanvasProps>(function Canvas({ sections, theme, onMessage, iframeRectRef, onReady: onReadyProp }, ref) {\n const iframeRef = useRef<HTMLIFrameElement>(null);\n const [ready, setReady] = useState(false);\n // Track what the iframe currently has so we can diff\n const knownSectionsRef = useRef<Map<string, string>>(new Map());\n const initializedRef = useRef(false);\n const onReadyRef = useRef(onReadyProp);\n onReadyRef.current = onReadyProp;\n\n // Post a message to the iframe\n const postToIframe = useCallback((msg: Record<string, unknown>) => {\n iframeRef.current?.contentWindow?.postMessage(msg, \"*\");\n }, []);\n\n useImperativeHandle(ref, () => ({\n scrollToSection(id: string) {\n postToIframe({ action: \"scroll-to-section\", id });\n },\n postMessage(msg: Record<string, unknown>) {\n postToIframe(msg);\n },\n }), [postToIframe]);\n\n // Initial write: set up the iframe shell (empty body + script + tailwind)\n useEffect(() => {\n const iframe = iframeRef.current;\n if (!iframe || initializedRef.current) return;\n initializedRef.current = true;\n\n const html = buildPreviewHtml([]);\n const doc = iframe.contentDocument;\n if (!doc) return;\n doc.open();\n doc.write(html);\n doc.close();\n }, []);\n\n // Handle \"ready\" from iframe — then inject current sections\n const handleReady = useCallback(() => {\n setReady(true);\n // Inject all current sections\n const sorted = [...sections].sort((a, b) => a.order - b.order);\n for (const s of sorted) {\n postToIframe({ action: \"add-section\", id: s.id, html: s.html, scroll: false });\n knownSectionsRef.current.set(s.id, s.html);\n }\n // Restore scroll position from sessionStorage\n const savedY = sessionStorage.getItem(\"landing-v3-iframe-scrollY\");\n if (savedY) {\n setTimeout(() => postToIframe({ action: \"restore-scroll\", y: Number(savedY) }), 100);\n }\n onReadyRef.current?.();\n }, [sections, postToIframe]);\n\n // Incremental diff: detect added/updated/removed/renamed sections\n useEffect(() => {\n if (!ready) return;\n\n const known = knownSectionsRef.current;\n const currentIds = new Set(sections.map((s) => s.id));\n const sorted = [...sections].sort((a, b) => a.order - b.order);\n\n // Detect renames: a known id disappears and a new id appears at the same index\n const removedIds = [...known.keys()].filter((id) => !currentIds.has(id));\n const addedSections = sorted.filter((s) => !known.has(s.id));\n\n // Match removed → added by position for rename (e.g. __building__ → real id)\n const renamedSet = new Set<string>();\n for (const removedId of removedIds) {\n if (addedSections.length > 0) {\n const added = addedSections.shift()!;\n postToIframe({ action: \"rename-section\", oldId: removedId, newId: added.id, html: added.html });\n known.delete(removedId);\n known.set(added.id, added.html);\n renamedSet.add(added.id);\n }\n }\n\n // Add truly new sections (not renamed)\n for (const s of sorted) {\n if (renamedSet.has(s.id)) continue;\n if (!known.has(s.id)) {\n postToIframe({ action: \"add-section\", id: s.id, html: s.html, scroll: s.id !== \"__building__\" });\n known.set(s.id, s.html);\n } else if (known.get(s.id) !== s.html) {\n // Update changed sections\n postToIframe({ action: \"update-section\", id: s.id, html: s.html });\n known.set(s.id, s.html);\n }\n }\n\n // Remove deleted sections (that weren't renamed)\n for (const id of [...known.keys()]) {\n if (!currentIds.has(id)) {\n postToIframe({ action: \"remove-section\", id });\n known.delete(id);\n }\n }\n\n // Reorder if needed\n const knownOrder = [...known.keys()];\n const desiredOrder = sorted.map((s) => s.id);\n if (knownOrder.length !== desiredOrder.length || knownOrder.some((id, i) => id !== desiredOrder[i])) {\n postToIframe({ action: \"reorder-sections\", order: desiredOrder });\n // Rebuild Map in new order so subsequent diffs compare correctly\n const reordered = new Map<string, string>();\n for (const id of desiredOrder) {\n const html = known.get(id);\n if (html !== undefined) reordered.set(id, html);\n }\n knownSectionsRef.current = reordered;\n }\n }, [sections, ready, postToIframe]);\n\n // Send theme changes to iframe\n useEffect(() => {\n if (!ready) return;\n postToIframe({ action: \"set-theme\", theme: theme || \"default\" });\n }, [theme, ready, postToIframe]);\n\n // Update iframe rect on resize/scroll\n const updateRect = useCallback(() => {\n if (iframeRef.current) {\n iframeRectRef.current = iframeRef.current.getBoundingClientRect();\n }\n }, [iframeRectRef]);\n\n useEffect(() => {\n updateRect();\n window.addEventListener(\"resize\", updateRect);\n window.addEventListener(\"scroll\", updateRect, true);\n return () => {\n window.removeEventListener(\"resize\", updateRect);\n window.removeEventListener(\"scroll\", updateRect, true);\n };\n }, [updateRect]);\n\n // Periodically save iframe scroll position\n useEffect(() => {\n if (!ready) return;\n const interval = setInterval(() => {\n postToIframe({ action: \"get-scroll\" });\n }, 2000);\n return () => clearInterval(interval);\n }, [ready, postToIframe]);\n\n // Listen for postMessage from iframe\n useEffect(() => {\n function handleMessage(e: MessageEvent) {\n const data = e.data;\n if (!data || typeof data.type !== \"string\") return;\n\n if (data.type === \"ready\") {\n handleReady();\n return;\n }\n\n if (data.type === \"scroll-position\") {\n sessionStorage.setItem(\"landing-v3-iframe-scrollY\", String(data.y));\n return;\n }\n\n if (\n [\"element-selected\", \"element-contextmenu\", \"text-edited\", \"element-deselected\", \"section-html-updated\", \"undo\", \"redo\"].includes(\n data.type\n )\n ) {\n // Sync known HTML so the diff doesn't re-send to iframe\n if (data.type === \"section-html-updated\" && data.sectionId && data.sectionHtml) {\n knownSectionsRef.current.set(data.sectionId, data.sectionHtml);\n }\n updateRect();\n onMessage(data as IframeMessage);\n }\n }\n window.addEventListener(\"message\", handleMessage);\n return () => window.removeEventListener(\"message\", handleMessage);\n }, [onMessage, updateRect, handleReady]);\n\n return (\n <div className=\"flex-1 overflow-hidden relative\">\n <iframe\n ref={iframeRef}\n title=\"Landing preview\"\n className=\"w-full h-full border-0\"\n sandbox=\"allow-scripts allow-same-origin\"\n style={{ minHeight: \"calc(100vh - 120px)\" }}\n />\n {!ready && sections.length > 0 && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-white/80\">\n <span className=\"w-6 h-6 border-2 border-gray-400 border-t-gray-800 rounded-full animate-spin\" />\n </div>\n )}\n <a href=\"https://www.easybits.cloud\" target=\"_blank\" rel=\"noopener noreferrer\"\n className=\"absolute bottom-2 right-3 text-xs text-gray-400 hover:text-gray-600 transition-colors\">\n Powered by easybits.cloud\n </a>\n </div>\n );\n});\n","import React, { useRef, useState } from \"react\";\nimport type { Section3 } from \"../types\";\nimport { LANDING_THEMES, type CustomColors } from \"../themes\";\n\ninterface SectionListProps {\n sections: Section3[];\n selectedSectionId: string | null;\n theme: string;\n customColors?: CustomColors;\n onThemeChange: (themeId: string) => void;\n onCustomColorChange?: (colors: Partial<CustomColors>) => void;\n onSelect: (id: string) => void;\n onOpenCode: (id: string) => void;\n onReorder: (fromIndex: number, toIndex: number) => void;\n onDelete: (id: string) => void;\n onRename: (id: string, label: string) => void;\n onAdd: () => void;\n}\n\nexport function SectionList({\n sections,\n selectedSectionId,\n theme,\n customColors,\n onThemeChange,\n onCustomColorChange,\n onSelect,\n onOpenCode,\n onReorder,\n onDelete,\n onRename,\n onAdd,\n}: SectionListProps) {\n const sorted = [...sections].sort((a, b) => a.order - b.order);\n const colorInputRef = useRef<HTMLInputElement>(null);\n const [editingId, setEditingId] = useState<string | null>(null);\n const [editingLabel, setEditingLabel] = useState(\"\");\n\n return (\n <div className=\"flex flex-col flex-1 overflow-hidden\">\n <div className=\"p-3 border-b border-gray-200\">\n <h3 className=\"text-xs font-black uppercase tracking-wider text-gray-500 mb-2\">\n Tema\n </h3>\n <div className=\"flex gap-1.5 flex-wrap\">\n {LANDING_THEMES.map((t) => (\n <button\n key={t.id}\n onClick={() => onThemeChange(t.id)}\n title={t.label}\n className={`w-6 h-6 rounded-full border-2 transition-all ${\n theme === t.id\n ? \"border-black scale-110 shadow-sm\"\n : \"border-gray-300 hover:border-gray-400\"\n }`}\n style={{ backgroundColor: t.colors.primary }}\n />\n ))}\n {/* Custom color picker */}\n <button\n onClick={() => colorInputRef.current?.click()}\n title=\"Color personalizado\"\n className={`w-6 h-6 rounded-full border-2 transition-all relative overflow-hidden ${\n theme === \"custom\"\n ? \"border-black scale-110 shadow-sm\"\n : \"border-gray-300 hover:border-gray-400\"\n }`}\n style={theme === \"custom\" && customColors?.primary ? { backgroundColor: customColors.primary } : undefined}\n >\n {theme !== \"custom\" && (\n <span className=\"absolute inset-0 rounded-full\"\n style={{ background: \"conic-gradient(#ef4444, #eab308, #22c55e, #3b82f6, #a855f7, #ef4444)\" }}\n />\n )}\n </button>\n <input\n ref={colorInputRef}\n type=\"color\"\n value={customColors?.primary || \"#6366f1\"}\n onChange={(e) => onCustomColorChange?.({ primary: e.target.value })}\n className=\"sr-only\"\n />\n </div>\n {/* Multi-color pickers when custom theme is active */}\n {theme === \"custom\" && (\n <div className=\"flex items-center gap-2 mt-2\">\n {([\n { key: \"primary\" as const, label: \"Pri\", fallback: \"#6366f1\" },\n { key: \"secondary\" as const, label: \"Sec\", fallback: \"#f59e0b\" },\n { key: \"accent\" as const, label: \"Acc\", fallback: \"#06b6d4\" },\n { key: \"surface\" as const, label: \"Sur\", fallback: \"#ffffff\" },\n ]).map((c) => (\n <label key={c.key} className=\"flex flex-col items-center gap-0.5 cursor-pointer\">\n <input\n type=\"color\"\n value={customColors?.[c.key] || c.fallback}\n onChange={(e) => onCustomColorChange?.({ [c.key]: e.target.value })}\n className=\"w-5 h-5 rounded border border-gray-300 cursor-pointer p-0 [&::-webkit-color-swatch-wrapper]:p-0 [&::-webkit-color-swatch]:border-none [&::-webkit-color-swatch]:rounded\"\n />\n <span className=\"text-[9px] font-bold text-gray-400 uppercase\">{c.label}</span>\n </label>\n ))}\n </div>\n )}\n </div>\n <div className=\"p-3 border-b border-gray-200\">\n <h3 className=\"text-xs font-black uppercase tracking-wider text-gray-500\">\n Secciones\n </h3>\n </div>\n\n <div className=\"flex-1 overflow-y-auto py-1\">\n {sorted.map((section, i) => (\n <div\n key={section.id}\n onClick={() => onSelect(section.id)}\n className={`group flex items-center gap-2 px-3 py-2 cursor-pointer transition-colors ${\n selectedSectionId === section.id\n ? \"bg-blue-50 border-l-2 border-blue-500\"\n : \"hover:bg-gray-50 border-l-2 border-transparent\"\n }`}\n >\n <span className=\"text-[10px] font-mono text-gray-400 w-4 text-right\">\n {i + 1}\n </span>\n {editingId === section.id ? (\n <input\n type=\"text\"\n value={editingLabel}\n onChange={(e) => setEditingLabel(e.target.value)}\n onBlur={() => {\n if (editingLabel.trim()) onRename(section.id, editingLabel.trim());\n setEditingId(null);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") {\n if (editingLabel.trim()) onRename(section.id, editingLabel.trim());\n setEditingId(null);\n } else if (e.key === \"Escape\") {\n setEditingId(null);\n }\n }}\n className=\"text-sm font-bold flex-1 min-w-0 bg-transparent border-b border-blue-500 outline-none px-0 py-0\"\n autoFocus\n onClick={(e) => e.stopPropagation()}\n />\n ) : (\n <span\n className=\"text-sm font-bold truncate flex-1\"\n onDoubleClick={(e) => {\n e.stopPropagation();\n setEditingId(section.id);\n setEditingLabel(section.label);\n }}\n >\n {section.label}\n </span>\n )}\n <div className=\"hidden group-hover:flex gap-0.5 shrink-0\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n onOpenCode(section.id);\n }}\n className=\"w-5 h-5 flex items-center justify-center rounded text-gray-400 hover:text-gray-700 hover:bg-gray-200\"\n title=\"Editar HTML\"\n >\n <svg className=\"w-3 h-3\" viewBox=\"0 0 16 16\" fill=\"currentColor\"><path d=\"M5.854 4.854a.5.5 0 1 0-.708-.708l-3.5 3.5a.5.5 0 0 0 0 .708l3.5 3.5a.5.5 0 0 0 .708-.708L2.707 8l3.147-3.146zm4.292 0a.5.5 0 0 1 .708-.708l3.5 3.5a.5.5 0 0 1 0 .708l-3.5 3.5a.5.5 0 0 1-.708-.708L13.293 8l-3.147-3.146z\"/></svg>\n </button>\n {i > 0 && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onReorder(i, i - 1);\n }}\n className=\"w-5 h-5 flex items-center justify-center rounded text-gray-400 hover:text-gray-700 hover:bg-gray-200 text-[10px]\"\n >\n ↑\n </button>\n )}\n {i < sorted.length - 1 && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onReorder(i, i + 1);\n }}\n className=\"w-5 h-5 flex items-center justify-center rounded text-gray-400 hover:text-gray-700 hover:bg-gray-200 text-[10px]\"\n >\n ↓\n </button>\n )}\n <button\n onClick={(e) => {\n e.stopPropagation();\n onDelete(section.id);\n }}\n className=\"w-5 h-5 flex items-center justify-center rounded text-gray-400 hover:text-red-600 hover:bg-red-50 text-[10px]\"\n title=\"Eliminar seccion\"\n >\n ✕\n </button>\n </div>\n </div>\n ))}\n </div>\n\n <div className=\"p-3 border-t border-gray-200\">\n <button\n onClick={onAdd}\n className=\"w-full text-center py-2 text-sm font-bold text-blue-600 hover:bg-blue-50 rounded-lg transition-colors\"\n >\n + Agregar seccion\n </button>\n </div>\n </div>\n );\n}\n","import React, { useState, useRef, useEffect } from \"react\";\nimport { HiSparkles } from \"react-icons/hi2\";\nimport type { IframeMessage } from \"../types\";\nimport type { LandingTheme } from \"../themes\";\n\nconst STYLE_PRESETS = [\n { label: \"Minimal\", icon: \"○\", instruction: \"Redisena esta seccion con estetica minimal: mucho espacio en blanco, tipografia limpia, sin bordes ni sombras innecesarias. Manten el mismo contenido.\" },\n { label: \"Cards\", icon: \"▦\", instruction: \"Redisena esta seccion usando layout de cards en grid: cada item en su propia card con padding, sombra sutil y bordes redondeados. Manten el mismo contenido.\" },\n { label: \"Bold\", icon: \"■\", instruction: \"Redisena esta seccion con estilo bold/brutalist: tipografia grande y gruesa, colores de alto contraste, bordes solidos, sin gradientes. Manten el mismo contenido.\" },\n { label: \"Glass\", icon: \"◇\", instruction: \"Redisena esta seccion con glassmorphism: fondos translucidos con backdrop-blur, bordes sutiles blancos, sombras suaves. Usa un fondo oscuro o con gradiente detras. Manten el mismo contenido.\" },\n { label: \"Dark\", icon: \"●\", instruction: \"Redisena esta seccion con fondo oscuro (#111 o similar), texto claro, acentos de color vibrantes. Manten el mismo contenido.\" },\n];\n\n// SVG icons for tab bar\nconst PaletteIcon = () => (\n <svg className=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <circle cx=\"13.5\" cy=\"6.5\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"17.5\" cy=\"10.5\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"8.5\" cy=\"7.5\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"6.5\" cy=\"12\" r=\"0.5\" fill=\"currentColor\" stroke=\"none\" />\n <path d=\"M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 011.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z\" />\n </svg>\n);\n\nconst RulerIcon = () => (\n <svg className=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M21.3 15.3a2.4 2.4 0 010 3.4l-2.6 2.6a2.4 2.4 0 01-3.4 0L2.7 8.7a2.4 2.4 0 010-3.4l2.6-2.6a2.4 2.4 0 013.4 0z\" />\n <path d=\"M14.5 12.5l2-2\" />\n <path d=\"M11.5 9.5l2-2\" />\n <path d=\"M8.5 6.5l2-2\" />\n <path d=\"M17.5 15.5l2-2\" />\n </svg>\n);\n\nconst LinkIcon = () => (\n <svg className=\"w-3.5 h-3.5\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71\" />\n <path d=\"M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71\" />\n </svg>\n);\n\ntype TabType = \"style\" | \"attrs\" | null;\n\ninterface FloatingToolbarProps {\n selection: IframeMessage | null;\n iframeRect: DOMRect | null;\n onRefine: (instruction: string, referenceImage?: string, opts?: { isVariant?: boolean }) => void;\n onMoveUp: () => void;\n onMoveDown: () => void;\n onDelete: () => void;\n onClose: () => void;\n onViewCode: () => void;\n onUpdateAttribute?: (sectionId: string, elementPath: string, attr: string, value: string) => void;\n onChangeTag?: (sectionId: string, elementPath: string, newTag: string) => void;\n onReplaceClass?: (sectionId: string, elementPath: string, removePrefixes: string[], addClass: string) => void;\n onDeleteElement?: (sectionId: string, elementPath: string) => void;\n isRefining: boolean;\n hideStylePresets?: boolean;\n themeColors?: LandingTheme[\"colors\"];\n}\n\nexport function FloatingToolbar({\n selection,\n iframeRect,\n onRefine,\n onMoveUp,\n onMoveDown,\n onDelete,\n onClose,\n onViewCode,\n onUpdateAttribute,\n onChangeTag,\n onReplaceClass,\n onDeleteElement,\n isRefining,\n hideStylePresets,\n themeColors,\n}: FloatingToolbarProps) {\n const [prompt, setPrompt] = useState(\"\");\n const [showCode, setShowCode] = useState(false);\n const [refImage, setRefImage] = useState<string | null>(null);\n const [refImageName, setRefImageName] = useState<string | null>(null);\n const inputRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const toolbarRef = useRef<HTMLDivElement>(null);\n\n const [showTagPicker, setShowTagPicker] = useState(false);\n const [activeTab, setActiveTab] = useState<TabType>('style');\n\n // Local attr editing state\n const [imgSrc, setImgSrc] = useState(\"\");\n const [imgAlt, setImgAlt] = useState(\"\");\n const [linkHref, setLinkHref] = useState(\"\");\n\n useEffect(() => {\n setPrompt(\"\");\n setShowCode(false);\n setRefImage(null);\n setRefImageName(null);\n setShowTagPicker(false);\n setActiveTab(null);\n // Auto-focus the AI prompt input when toolbar appears\n setTimeout(() => inputRef.current?.focus(), 50);\n }, [selection?.sectionId, selection?.elementPath]);\n\n // Sync attr inputs when selection changes\n useEffect(() => {\n if (selection?.attrs) {\n setImgSrc(selection.attrs.src || \"\");\n setImgAlt(selection.attrs.alt || \"\");\n setLinkHref(selection.attrs.href || \"\");\n }\n }, [selection?.attrs, selection?.elementPath]);\n\n // ESC closes toolbar\n useEffect(() => {\n function handleKey(e: KeyboardEvent) {\n if (e.key === \"Escape\") onClose();\n }\n document.addEventListener(\"keydown\", handleKey);\n return () => document.removeEventListener(\"keydown\", handleKey);\n }, [onClose]);\n\n if (!selection || !selection.rect || !iframeRect) return null;\n\n const toolbarWidth = toolbarRef.current?.offsetWidth || 600;\n const toolbarHeight = toolbarRef.current?.offsetHeight || 60;\n const top = iframeRect.top + selection.rect.top + selection.rect.height + 8;\n const left = iframeRect.left + selection.rect.left;\n const clampedLeft = Math.max(8, Math.min(left, window.innerWidth - toolbarWidth - 8));\n const showAbove = top + toolbarHeight + 8 > window.innerHeight;\n const finalTop = Math.max(8, showAbove\n ? iframeRect.top + selection.rect.top - toolbarHeight - 8\n : top);\n\n function handleSubmit(e: React.FormEvent) {\n e.preventDefault();\n if (isRefining || !selection) return;\n if (prompt.trim()) {\n onRefine(prompt.trim(), refImage || undefined);\n } else {\n // No text — request variant\n const tag = selection.tagName?.toLowerCase();\n const text = selection.text?.substring(0, 80);\n const variantPrompt = selection.isSectionRoot\n ? \"Genera una variante completamente diferente de esta seccion. Manten el mismo contenido/informacion pero cambia radicalmente el layout, la estructura visual, y el estilo. Sorprendeme con un diseno creativo e inesperado.\"\n : `Modifica SOLO el elemento <${tag}> que contiene \"${text}\". Genera una variante visual diferente de ESE elemento (diferente estilo, layout, tipografia). NO modifiques ningun otro elemento de la seccion.`;\n onRefine(variantPrompt, refImage || undefined, { isVariant: selection.isSectionRoot ? true : undefined });\n }\n setPrompt(\"\");\n if (inputRef.current) inputRef.current.style.height = \"auto\";\n setRefImage(null);\n setRefImageName(null);\n }\n\n function handleFileSelect(e: React.ChangeEvent<HTMLInputElement>) {\n const file = e.target.files?.[0];\n if (!file) return;\n setRefImageName(file.name);\n\n const img = new Image();\n img.onload = () => {\n const MAX = 1024;\n let { width, height } = img;\n if (width > MAX || height > MAX) {\n const ratio = Math.min(MAX / width, MAX / height);\n width = Math.round(width * ratio);\n height = Math.round(height * ratio);\n }\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n canvas.getContext(\"2d\")!.drawImage(img, 0, 0, width, height);\n canvas.toBlob(\n (blob) => {\n if (!blob) return;\n const reader = new FileReader();\n reader.onload = () => setRefImage(reader.result as string);\n reader.readAsDataURL(blob);\n },\n \"image/jpeg\",\n 0.7\n );\n URL.revokeObjectURL(img.src);\n };\n img.src = URL.createObjectURL(file);\n e.target.value = \"\";\n }\n\n function handleSetAttr(attr: string, value: string) {\n if (!selection?.sectionId || !selection?.elementPath || !onUpdateAttribute) return;\n onUpdateAttribute(selection.sectionId, selection.elementPath, attr, value);\n }\n\n const isImg = selection.tagName === \"IMG\";\n const isLink = selection.tagName === \"A\";\n const hasAttrEditing = (isImg || isLink) && onUpdateAttribute;\n\n function handleReplaceClass(removePrefixes: string[], addClass: string) {\n if (!selection?.sectionId || !selection?.elementPath || !onUpdateAttribute) return;\n const currentClasses = (selection.className || \"\").split(/\\s+/).filter(Boolean);\n const filtered = currentClasses.filter(cls => {\n const bare = cls.includes(\":\") ? cls.substring(cls.lastIndexOf(\":\") + 1) : cls;\n return !removePrefixes.some(pfx => bare === pfx || bare.startsWith(pfx));\n });\n if (addClass) {\n for (const c of addClass.split(/\\s+/).filter(Boolean)) {\n if (!filtered.includes(c)) filtered.push(c);\n }\n }\n onUpdateAttribute(selection.sectionId, selection.elementPath, \"class\", filtered.join(\" \"));\n }\n\n // Determine size presets based on element type\n const sizePresets = (() => {\n if (!onUpdateAttribute || !selection.tagName) return null;\n const tag = selection.tagName.toUpperCase();\n const CONTAINERS = [\"DIV\", \"SECTION\", \"ARTICLE\", \"ASIDE\", \"HEADER\", \"FOOTER\", \"NAV\", \"MAIN\"];\n const TEXT_TAGS = [\"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\", \"P\", \"SPAN\", \"BLOCKQUOTE\"];\n const currentClasses = (selection.className || \"\").split(/\\s+/);\n\n if (CONTAINERS.includes(tag)) {\n const W_PREFIXES = [\"w-\"];\n const MAX_W_PREFIXES = [\"max-w-\"];\n const P_PREFIXES = [\"p-\", \"px-\", \"py-\"];\n const widthOptions = [\n { label: \"Full\", cls: \"w-full\", prefixes: W_PREFIXES },\n { label: \"3/4\", cls: \"w-3/4\", prefixes: W_PREFIXES },\n { label: \"2/3\", cls: \"w-2/3\", prefixes: W_PREFIXES },\n { label: \"1/2\", cls: \"w-1/2\", prefixes: W_PREFIXES },\n { label: \"1/3\", cls: \"w-1/3\", prefixes: W_PREFIXES },\n ];\n const maxWOptions = [\n { label: \"sm\", cls: \"max-w-sm\", prefixes: MAX_W_PREFIXES },\n { label: \"md\", cls: \"max-w-md\", prefixes: MAX_W_PREFIXES },\n { label: \"lg\", cls: \"max-w-lg\", prefixes: MAX_W_PREFIXES },\n { label: \"xl\", cls: \"max-w-xl\", prefixes: MAX_W_PREFIXES },\n { label: \"2xl\", cls: \"max-w-2xl\", prefixes: MAX_W_PREFIXES },\n { label: \"full\", cls: \"max-w-full\", prefixes: MAX_W_PREFIXES },\n ];\n const paddingOptions = [\n { label: \"0\", cls: \"p-0\", prefixes: P_PREFIXES },\n { label: \"4\", cls: \"p-4\", prefixes: P_PREFIXES },\n { label: \"8\", cls: \"p-8\", prefixes: P_PREFIXES },\n { label: \"12\", cls: \"p-12\", prefixes: P_PREFIXES },\n { label: \"16\", cls: \"p-16\", prefixes: P_PREFIXES },\n ];\n const M_PREFIXES = [\"m-\", \"mx-\", \"my-\", \"mt-\", \"mb-\"];\n const marginOptions = [\n { label: \"0\", cls: \"m-0\", prefixes: M_PREFIXES },\n { label: \"auto\", cls: \"mx-auto\", prefixes: M_PREFIXES },\n { label: \"2\", cls: \"m-2\", prefixes: M_PREFIXES },\n { label: \"4\", cls: \"m-4\", prefixes: M_PREFIXES },\n { label: \"8\", cls: \"m-8\", prefixes: M_PREFIXES },\n ];\n return { width: widthOptions, maxW: maxWOptions, padding: paddingOptions, margin: marginOptions, currentClasses };\n }\n\n if (TEXT_TAGS.includes(tag)) {\n const TEXT_SIZE_EXACT = [\"text-xs\", \"text-sm\", \"text-base\", \"text-lg\", \"text-xl\", \"text-2xl\", \"text-3xl\", \"text-4xl\", \"text-5xl\", \"text-6xl\", \"text-7xl\", \"text-8xl\", \"text-9xl\"];\n const FONT_WEIGHT_EXACT = [\"font-thin\", \"font-extralight\", \"font-light\", \"font-normal\", \"font-medium\", \"font-semibold\", \"font-bold\", \"font-extrabold\", \"font-black\"];\n const textSizes = [\n { label: \"sm\", cls: \"text-sm\", prefixes: TEXT_SIZE_EXACT },\n { label: \"base\", cls: \"text-base\", prefixes: TEXT_SIZE_EXACT },\n { label: \"lg\", cls: \"text-lg\", prefixes: TEXT_SIZE_EXACT },\n { label: \"xl\", cls: \"text-xl\", prefixes: TEXT_SIZE_EXACT },\n { label: \"2xl\", cls: \"text-2xl\", prefixes: TEXT_SIZE_EXACT },\n { label: \"3xl\", cls: \"text-3xl\", prefixes: TEXT_SIZE_EXACT },\n { label: \"4xl\", cls: \"text-4xl\", prefixes: TEXT_SIZE_EXACT },\n { label: \"5xl\", cls: \"text-5xl\", prefixes: TEXT_SIZE_EXACT },\n ];\n const fontWeight = [\n { label: \"light\", cls: \"font-light\", prefixes: FONT_WEIGHT_EXACT },\n { label: \"normal\", cls: \"font-normal\", prefixes: FONT_WEIGHT_EXACT },\n { label: \"medium\", cls: \"font-medium\", prefixes: FONT_WEIGHT_EXACT },\n { label: \"semibold\", cls: \"font-semibold\", prefixes: FONT_WEIGHT_EXACT },\n { label: \"bold\", cls: \"font-bold\", prefixes: FONT_WEIGHT_EXACT },\n ];\n const M_PREFIXES = [\"m-\", \"mx-\", \"my-\", \"mt-\", \"mb-\"];\n const marginOptions = [\n { label: \"0\", cls: \"m-0\", prefixes: M_PREFIXES },\n { label: \"auto\", cls: \"mx-auto\", prefixes: M_PREFIXES },\n { label: \"2\", cls: \"m-2\", prefixes: M_PREFIXES },\n { label: \"4\", cls: \"m-4\", prefixes: M_PREFIXES },\n { label: \"8\", cls: \"m-8\", prefixes: M_PREFIXES },\n ];\n return { textSize: textSizes, fontWeight, margin: marginOptions, currentClasses };\n }\n\n if (tag === \"BUTTON\" || tag === \"A\") {\n const W_PREFIXES = [\"w-\"];\n const P_PREFIXES = [\"p-\", \"px-\", \"py-\"];\n const M_PREFIXES = [\"m-\", \"mx-\", \"my-\", \"mt-\", \"mb-\"];\n const widthOptions = [\n { label: \"auto\", cls: \"w-auto\", prefixes: W_PREFIXES },\n { label: \"Full\", cls: \"w-full\", prefixes: W_PREFIXES },\n { label: \"1/2\", cls: \"w-1/2\", prefixes: W_PREFIXES },\n { label: \"1/3\", cls: \"w-1/3\", prefixes: W_PREFIXES },\n ];\n const paddingOptions = [\n { label: \"0\", cls: \"p-0\", prefixes: P_PREFIXES },\n { label: \"2\", cls: \"px-2 py-1\", prefixes: P_PREFIXES },\n { label: \"4\", cls: \"px-4 py-2\", prefixes: P_PREFIXES },\n { label: \"6\", cls: \"px-6 py-3\", prefixes: P_PREFIXES },\n { label: \"8\", cls: \"px-8 py-4\", prefixes: P_PREFIXES },\n ];\n const marginOptions = [\n { label: \"0\", cls: \"m-0\", prefixes: M_PREFIXES },\n { label: \"auto\", cls: \"mx-auto\", prefixes: M_PREFIXES },\n { label: \"2\", cls: \"m-2\", prefixes: M_PREFIXES },\n { label: \"4\", cls: \"m-4\", prefixes: M_PREFIXES },\n ];\n return { width: widthOptions, padding: paddingOptions, margin: marginOptions, currentClasses };\n }\n\n if (tag === \"IMG\") {\n const IMG_SIZE_PREFIXES = [\"w-\", \"max-w-\"];\n const ROUNDED_PREFIXES = [\"rounded\"];\n const imgSizes = [\n { label: \"sm\", cls: \"max-w-xs\", prefixes: IMG_SIZE_PREFIXES },\n { label: \"md\", cls: \"max-w-md\", prefixes: IMG_SIZE_PREFIXES },\n { label: \"lg\", cls: \"max-w-lg\", prefixes: IMG_SIZE_PREFIXES },\n { label: \"xl\", cls: \"max-w-xl\", prefixes: IMG_SIZE_PREFIXES },\n { label: \"full\", cls: \"w-full\", prefixes: IMG_SIZE_PREFIXES },\n ];\n const rounded = [\n { label: \"none\", cls: \"rounded-none\", prefixes: ROUNDED_PREFIXES },\n { label: \"md\", cls: \"rounded-md\", prefixes: ROUNDED_PREFIXES },\n { label: \"lg\", cls: \"rounded-lg\", prefixes: ROUNDED_PREFIXES },\n { label: \"xl\", cls: \"rounded-xl\", prefixes: ROUNDED_PREFIXES },\n { label: \"full\", cls: \"rounded-full\", prefixes: ROUNDED_PREFIXES },\n ];\n return { imgSize: imgSizes, rounded, currentClasses };\n }\n\n return null;\n })();\n\n // Determine which tabs are available\n const hasStyleTab = true; // Always available (colors + size for non-section, style presets for section)\n const hasAttrsTab = hasAttrEditing;\n\n function toggleTab(tab: TabType) {\n setActiveTab(prev => prev === tab ? null : tab);\n }\n\n // Render color swatches panel\n function renderColorPanel() {\n if (selection!.isSectionRoot) {\n // Style presets for section root\n if (hideStylePresets) return null;\n return (\n <div className=\"flex items-center gap-1 pt-1 pb-0.5\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider mr-1 shrink-0\">Estilo</span>\n {STYLE_PRESETS.map((preset) => (\n <button\n key={preset.label}\n onClick={() => onRefine(preset.instruction)}\n disabled={isRefining}\n className=\"px-2 py-0.5 text-[11px] font-medium rounded-md bg-gray-800 hover:bg-gray-700 disabled:opacity-30 transition-colors whitespace-nowrap\"\n title={preset.label}\n >\n <span className=\"mr-1\">{preset.icon}</span>\n {preset.label}\n </button>\n ))}\n </div>\n );\n }\n\n // Color swatches for non-section elements\n if (!onUpdateAttribute || selection!.tagName === 'IMG') {\n // Still show size panel for IMG even without color swatches\n if (selection!.tagName === 'IMG' && sizePresets) return <div className=\"pt-1 pb-0.5\">{renderSizePanel()}</div>;\n return null;\n }\n\n const containerTags = ['DIV', 'SECTION', 'HEADER', 'FOOTER', 'NAV', 'ASIDE', 'MAIN', 'ARTICLE'];\n const isContainer = containerTags.includes(selection!.tagName ?? '');\n\n const TEXT_COLOR_PREFIXES = [\"text-primary\", \"text-secondary\", \"text-accent\", \"text-on-surface\", \"text-on-primary\", \"text-on-surface-muted\", \"text-white\", \"text-black\", \"text-transparent\"];\n const BG_COLOR_PREFIXES = [\"bg-primary\", \"bg-primary-dark\", \"bg-secondary\", \"bg-accent\", \"bg-surface\", \"bg-surface-alt\", \"bg-white\", \"bg-black\", \"bg-transparent\"];\n\n const themeSwatches = themeColors ? [\n { color: themeColors.primary, textCls: \"text-primary\", bgCls: \"bg-primary\", label: \"Primary\" },\n { color: themeColors.secondary, textCls: \"text-secondary\", bgCls: \"bg-secondary\", label: \"Secondary\" },\n { color: themeColors.accent, textCls: \"text-accent\", bgCls: \"bg-accent\", label: \"Accent\" },\n { color: themeColors.surface, textCls: \"text-on-surface\", bgCls: \"bg-surface\", label: \"Surface\" },\n ] : [];\n\n const fixedSwatches = [\n { color: \"#ffffff\", textCls: \"text-white\", bgCls: \"bg-white\", label: \"Blanco\" },\n { color: \"#000000\", textCls: \"text-black\", bgCls: \"bg-black\", label: \"Negro\" },\n { color: \"transparent\", textCls: \"text-transparent\", bgCls: \"bg-transparent\", label: \"Transparente\" },\n ];\n\n const renderColorRow = (label: string, mode: \"text\" | \"bg\") => (\n <div key={mode} className=\"flex items-center gap-1 pt-0.5 pb-0.5\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider mr-1 shrink-0 w-10\">{label}</span>\n {fixedSwatches.map(({ color, textCls, bgCls, label: swatchLabel }) => (\n <button\n key={swatchLabel}\n onClick={() => {\n const prefixes = mode === \"text\" ? TEXT_COLOR_PREFIXES : BG_COLOR_PREFIXES;\n const cls = mode === \"text\" ? textCls : bgCls;\n handleReplaceClass(prefixes, cls);\n handleSetAttr(\"style\", \"\");\n }}\n className=\"w-5 h-5 rounded-full border border-gray-600 hover:scale-125 transition-transform shrink-0\"\n style={color === \"transparent\" ? {\n backgroundImage: \"repeating-conic-gradient(#808080 0% 25%, #c0c0c0 0% 50%)\",\n backgroundSize: \"8px 8px\",\n } : { backgroundColor: color }}\n title={swatchLabel}\n />\n ))}\n {themeSwatches.map(({ color, textCls, bgCls, label: swatchLabel }) => (\n <button\n key={swatchLabel}\n onClick={() => {\n const prefixes = mode === \"text\" ? TEXT_COLOR_PREFIXES : BG_COLOR_PREFIXES;\n const cls = mode === \"text\" ? textCls : bgCls;\n handleReplaceClass(prefixes, cls);\n handleSetAttr(\"style\", \"\");\n }}\n className=\"w-5 h-5 rounded-full border border-gray-600 hover:scale-125 transition-transform shrink-0\"\n style={{ backgroundColor: color }}\n title={swatchLabel}\n />\n ))}\n <input\n type=\"color\"\n onChange={(e) => {\n handleReplaceClass(mode === \"text\" ? TEXT_COLOR_PREFIXES : BG_COLOR_PREFIXES, \"\");\n const cssProp = mode === \"text\" ? \"color\" : \"background-color\";\n handleSetAttr(\"style\", `${cssProp}: ${e.target.value}`);\n }}\n className=\"w-5 h-5 rounded-full border border-gray-600 cursor-pointer shrink-0 p-0 bg-transparent [&::-webkit-color-swatch-wrapper]:p-0 [&::-webkit-color-swatch]:rounded-full [&::-webkit-color-swatch]:border-0\"\n title=\"Color personalizado\"\n />\n </div>\n );\n\n return (\n <div className=\"pt-1 pb-0.5\">\n {renderColorRow(\"Color\", \"text\")}\n {isContainer && renderColorRow(\"Fondo\", \"bg\")}\n {renderSizePanel()}\n </div>\n );\n }\n\n // Render size presets panel\n function renderSizePanel() {\n if (!sizePresets || selection!.isSectionRoot) return null;\n const groups = Object.entries(sizePresets).filter(([k]) => k !== 'currentClasses') as [string, { label: string; cls: string; prefixes: string[] }[]][];\n const labels: Record<string, string> = { width: \"Ancho\", maxW: \"Max\", padding: \"Padding\", margin: \"Margin\", textSize: \"Texto\", fontWeight: \"Peso\", imgSize: \"Tamaño\", rounded: \"Borde\" };\n return (\n <div className=\"pt-1 pb-0.5\">\n {groups.map(([key, options]) => (\n <div key={key} className=\"flex items-center gap-1 pt-0.5 pb-0.5\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider mr-1 shrink-0 w-10\">{labels[key] || key}</span>\n {options.map((opt) => {\n const isActive = sizePresets.currentClasses.includes(opt.cls);\n return (\n <button\n key={opt.cls}\n onClick={() => handleReplaceClass(opt.prefixes, opt.cls)}\n className={`px-2 py-0.5 text-[10px] font-mono font-bold rounded-md transition-colors whitespace-nowrap ${\n isActive ? \"bg-blue-600 text-white\" : \"bg-gray-800 hover:bg-gray-700 text-gray-300\"\n }`}\n >\n {opt.label}\n </button>\n );\n })}\n </div>\n ))}\n </div>\n );\n }\n\n // Render attributes panel\n function renderAttrsPanel() {\n if (!hasAttrEditing) return null;\n return (\n <div className=\"pt-1 pb-0.5\">\n {isImg && (\n <div className=\"flex flex-col gap-1\">\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider w-8 shrink-0\">src</span>\n <input\n type=\"text\"\n value={imgSrc}\n onChange={(e) => setImgSrc(e.target.value)}\n onKeyDown={(e) => { if (e.key === \"Enter\") handleSetAttr(\"src\", imgSrc); }}\n className=\"flex-1 bg-gray-800 text-xs text-white rounded px-2 py-1 outline-none min-w-0\"\n placeholder=\"URL de imagen...\"\n />\n <button\n onClick={() => handleSetAttr(\"src\", imgSrc)}\n className=\"px-2 py-1 text-[10px] font-bold rounded bg-blue-500 hover:bg-blue-600 transition-colors shrink-0\"\n >\n Set\n </button>\n </div>\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider w-8 shrink-0\">alt</span>\n <input\n type=\"text\"\n value={imgAlt}\n onChange={(e) => setImgAlt(e.target.value)}\n onKeyDown={(e) => { if (e.key === \"Enter\") handleSetAttr(\"alt\", imgAlt); }}\n className=\"flex-1 bg-gray-800 text-xs text-white rounded px-2 py-1 outline-none min-w-0\"\n placeholder=\"Alt text...\"\n />\n <button\n onClick={() => handleSetAttr(\"alt\", imgAlt)}\n className=\"px-2 py-1 text-[10px] font-bold rounded bg-blue-500 hover:bg-blue-600 transition-colors shrink-0\"\n >\n Set\n </button>\n </div>\n </div>\n )}\n {isLink && (\n <div className=\"flex items-center gap-1\">\n <span className=\"text-[10px] text-gray-500 uppercase tracking-wider w-8 shrink-0\">href</span>\n <input\n type=\"text\"\n value={linkHref}\n onChange={(e) => setLinkHref(e.target.value)}\n onKeyDown={(e) => { if (e.key === \"Enter\") handleSetAttr(\"href\", linkHref); }}\n className=\"flex-1 bg-gray-800 text-xs text-white rounded px-2 py-1 outline-none min-w-0\"\n placeholder=\"URL del enlace...\"\n />\n <button\n onClick={() => handleSetAttr(\"href\", linkHref)}\n className=\"px-2 py-1 text-[10px] font-bold rounded bg-blue-500 hover:bg-blue-600 transition-colors shrink-0\"\n >\n Set\n </button>\n </div>\n )}\n </div>\n );\n }\n\n return (\n <div\n ref={toolbarRef}\n className=\"fixed z-50 flex flex-col bg-gray-900 text-white rounded-xl shadow-2xl px-2 py-1.5 border border-gray-700\"\n style={{ top: finalTop, left: clampedLeft, maxWidth: \"min(600px, calc(100vw - 16px))\" }}\n >\n {/* Main row */}\n <div className=\"flex items-center gap-1.5 flex-wrap\">\n {/* Tag badge / switcher */}\n {selection.tagName && (() => {\n const tag = selection.tagName.toUpperCase();\n const HEADINGS = [\"H1\", \"H2\", \"H3\", \"H4\", \"H5\", \"H6\"];\n const TEXT = [\"P\", \"SPAN\", \"DIV\", \"BLOCKQUOTE\"];\n const CONTAINERS = [\"DIV\", \"SECTION\", \"ARTICLE\", \"ASIDE\", \"HEADER\", \"FOOTER\", \"NAV\", \"MAIN\"];\n const NO_SWITCH = [\"A\", \"IMG\", \"INPUT\", \"BUTTON\", \"SVG\", \"VIDEO\", \"IFRAME\", \"TABLE\", \"UL\", \"OL\", \"LI\", \"FORM\"];\n\n let tagOptions: string[] = [];\n if (HEADINGS.includes(tag)) tagOptions = [...HEADINGS, \"P\"];\n else if (TEXT.includes(tag) && !CONTAINERS.includes(tag)) tagOptions = [...TEXT, \"H1\", \"H2\", \"H3\"];\n else if (CONTAINERS.includes(tag)) tagOptions = [...CONTAINERS, \"P\", \"SPAN\"];\n tagOptions = tagOptions.filter((t) => t !== tag);\n const canSwitch = !NO_SWITCH.includes(tag) && tagOptions.length > 0 && onChangeTag;\n\n return canSwitch ? (\n <div className=\"relative shrink-0\">\n <button\n onClick={() => setShowTagPicker(!showTagPicker)}\n className=\"px-2 py-0.5 rounded-md bg-blue-600 hover:bg-blue-500 text-[10px] font-mono font-bold uppercase tracking-wider transition-colors flex items-center gap-0.5\"\n >\n {tag.toLowerCase()}\n <svg className=\"w-2.5 h-2.5 opacity-60\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\" clipRule=\"evenodd\" />\n </svg>\n </button>\n {showTagPicker && (\n <div className={`absolute left-0 bg-gray-800 border border-gray-600 rounded-lg shadow-xl py-1 z-50 min-w-[4rem] max-h-[200px] overflow-y-auto ${showAbove ? \"bottom-full mb-1\" : \"top-full mt-1\"}`}>\n {tagOptions.map((t) => (\n <button\n key={t}\n onClick={() => {\n if (selection.sectionId && selection.elementPath) {\n onChangeTag(selection.sectionId, selection.elementPath, t.toLowerCase());\n }\n setShowTagPicker(false);\n }}\n className=\"block w-full text-left px-3 py-1 text-[11px] font-mono font-bold uppercase hover:bg-gray-700 transition-colors\"\n >\n {t.toLowerCase()}\n </button>\n ))}\n </div>\n )}\n </div>\n ) : (\n <span className=\"px-2 py-0.5 rounded-md bg-blue-600 text-[10px] font-mono font-bold uppercase tracking-wider shrink-0\">\n {tag.toLowerCase()}\n </span>\n );\n })()}\n\n {/* AI prompt input */}\n <form onSubmit={handleSubmit} className=\"flex items-start gap-1 flex-1\">\n <textarea\n ref={inputRef}\n value={prompt}\n onChange={(e) => {\n setPrompt(e.target.value);\n e.target.style.height = \"auto\";\n e.target.style.height = Math.min(e.target.scrollHeight, 96) + \"px\";\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n handleSubmit(e);\n }\n }}\n placeholder={refImage ? \"Instruccion + imagen...\" : \"Editar con AI...\"}\n disabled={isRefining}\n rows={1}\n className=\"bg-transparent text-sm text-white placeholder:text-gray-500 outline-none min-w-[6rem] sm:min-w-[10rem] flex-1 px-2 py-1 resize-none overflow-hidden\"\n />\n <button\n type=\"submit\"\n disabled={isRefining}\n className={`flex items-center justify-center rounded-lg bg-blue-500 hover:bg-blue-600 disabled:opacity-30 transition-colors shrink-0 ${\n prompt.trim() ? \"w-7 h-7\" : \"px-2.5 py-1 text-[11px] font-bold whitespace-nowrap\"\n }`}\n >\n {isRefining ? (\n <span className=\"w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin\" />\n ) : prompt.trim() ? (\n <HiSparkles className=\"w-3.5 h-3.5\" />\n ) : (\n \"✦ Variante\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n disabled={isRefining}\n className={`w-7 h-7 flex items-center justify-center rounded-lg transition-colors shrink-0 ${\n refImage\n ? \"bg-blue-600 text-white\"\n : \"hover:bg-gray-800 text-gray-400 hover:text-white\"\n }`}\n title={refImage ? `Imagen: ${refImageName}` : \"Adjuntar imagen de referencia\"}\n >\n <svg className=\"w-3.5 h-3.5\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path fillRule=\"evenodd\" d=\"M1 5.25A2.25 2.25 0 013.25 3h13.5A2.25 2.25 0 0119 5.25v9.5A2.25 2.25 0 0116.75 17H3.25A2.25 2.25 0 011 14.75v-9.5zm1.5 5.81V14.75c0 .414.336.75.75.75h13.5a.75.75 0 00.75-.75v-2.06l-2.22-2.22a.75.75 0 00-1.06 0L8.56 16.1l-3.28-3.28a.75.75 0 00-1.06 0l-1.72 1.72zm12-4.06a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0z\" clipRule=\"evenodd\"/>\n </svg>\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*\"\n onChange={handleFileSelect}\n className=\"hidden\"\n />\n </form>\n\n {/* Section-level actions (move/delete) */}\n {selection.isSectionRoot && (\n <span className=\"hidden sm:contents\">\n <div className=\"w-px h-5 bg-gray-700\" />\n <button\n onClick={onMoveUp}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-gray-800 transition-colors text-xs\"\n title=\"Mover arriba\"\n >\n ↑\n </button>\n <button\n onClick={onMoveDown}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-gray-800 transition-colors text-xs\"\n title=\"Mover abajo\"\n >\n ↓\n </button>\n </span>\n )}\n\n {selection.isSectionRoot ? (\n <>\n <div className=\"w-px h-5 bg-gray-700\" />\n <button\n onClick={onDelete}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-red-900/50 text-red-400 transition-colors\"\n title=\"Eliminar seccion\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\" />\n <path d=\"M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2\" />\n </svg>\n </button>\n </>\n ) : onDeleteElement && (\n <>\n <div className=\"w-px h-5 bg-gray-700\" />\n <button\n onClick={() => {\n if (selection.sectionId && selection.elementPath) {\n onDeleteElement(selection.sectionId, selection.elementPath);\n }\n }}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-red-900/50 text-red-400 transition-colors\"\n title=\"Eliminar elemento\"\n >\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\" />\n <path d=\"M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2\" />\n </svg>\n </button>\n </>\n )}\n\n {/* Close button */}\n <div className=\"w-px h-5 bg-gray-700\" />\n <button\n onClick={onClose}\n className=\"w-7 h-7 flex items-center justify-center rounded-lg hover:bg-gray-800 text-gray-400 hover:text-white transition-colors shrink-0\"\n title=\"Cerrar (ESC)\"\n >\n ✕\n </button>\n </div>\n\n {/* Reference image preview */}\n {refImage && (\n <div className=\"flex items-center gap-2 pt-0.5 pb-0.5 border-t border-gray-700/50\">\n <img src={refImage} alt=\"Referencia\" className=\"w-10 h-10 rounded object-cover border border-gray-600\" />\n <span className=\"text-[10px] text-gray-400 truncate flex-1\">{refImageName}</span>\n <button\n onClick={() => { setRefImage(null); setRefImageName(null); }}\n className=\"text-[10px] text-gray-500 hover:text-white px-1\"\n >\n ✕\n </button>\n </div>\n )}\n\n {/* Tab bar */}\n <div className=\"flex items-center gap-1 pt-1 border-t border-gray-700/50 overflow-x-auto [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]\">\n {hasStyleTab && (\n <button\n onClick={() => toggleTab(\"style\")}\n className={`flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-medium transition-colors ${\n activeTab === \"style\" ? \"bg-blue-600 text-white\" : \"bg-gray-800 hover:bg-gray-700 text-gray-400\"\n }`}\n title=\"Estilo y tamaño\"\n >\n <PaletteIcon />\n <span>Estilo</span>\n </button>\n )}\n\n {hasAttrsTab && (\n <button\n onClick={() => toggleTab(\"attrs\")}\n className={`flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-medium transition-colors ${\n activeTab === \"attrs\" ? \"bg-blue-600 text-white\" : \"bg-gray-800 hover:bg-gray-700 text-gray-400\"\n }`}\n title=\"Atributos\"\n >\n <LinkIcon />\n <span>Attrs</span>\n </button>\n )}\n <button\n onClick={onViewCode}\n className=\"hidden sm:flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-medium bg-gray-800 hover:bg-gray-700 text-gray-400 transition-colors font-mono\"\n title=\"Ver código\"\n >\n </>\n </button>\n </div>\n\n {/* Active tab panel */}\n {activeTab === \"style\" && renderColorPanel()}\n {activeTab === \"attrs\" && renderAttrsPanel()}\n </div>\n );\n}\n","import React, { useEffect, useRef, useCallback, useState } from \"react\";\nimport { EditorView, keymap, lineNumbers, highlightActiveLine, highlightActiveLineGutter, Decoration, type DecorationSet } from \"@codemirror/view\";\nimport { EditorState, StateField, StateEffect } from \"@codemirror/state\";\nimport { html } from \"@codemirror/lang-html\";\nimport { oneDark } from \"@codemirror/theme-one-dark\";\nimport { defaultKeymap, indentWithTab, history, historyKeymap } from \"@codemirror/commands\";\nimport { searchKeymap, highlightSelectionMatches } from \"@codemirror/search\";\nimport { bracketMatching, foldGutter, foldKeymap } from \"@codemirror/language\";\nimport { closeBrackets, closeBracketsKeymap } from \"@codemirror/autocomplete\";\n\ninterface CodeEditorProps {\n code: string;\n label: string;\n scrollToText?: string;\n onSave: (code: string) => void;\n onClose: () => void;\n}\n\nfunction formatHtml(html: string): string {\n let result = html.replace(/>\\s*</g, \">\\n<\");\n const lines = result.split(\"\\n\");\n const output: string[] = [];\n let indent = 0;\n for (const raw of lines) {\n const line = raw.trim();\n if (!line) continue;\n const isClosing = /^<\\//.test(line);\n const isSelfClosing =\n /\\/>$/.test(line) ||\n /^<(img|br|hr|input|meta|link|col|area|base|embed|source|track|wbr)\\b/i.test(line);\n const hasInlineClose = /^<[^/][^>]*>.*<\\//.test(line);\n if (isClosing) indent = Math.max(0, indent - 1);\n output.push(\" \".repeat(indent) + line);\n if (!isClosing && !isSelfClosing && !hasInlineClose && /^<[a-zA-Z]/.test(line)) {\n indent++;\n }\n }\n return output.join(\"\\n\");\n}\n\n// Flash highlight effect for scroll-to-code\nconst flashLineEffect = StateEffect.define<{ from: number; to: number }>();\nconst clearFlashEffect = StateEffect.define<null>();\n\nconst flashLineDeco = Decoration.line({ class: \"cm-flash-line\" });\n\nconst flashLineField = StateField.define<DecorationSet>({\n create: () => Decoration.none,\n update(decos, tr) {\n for (const e of tr.effects) {\n if (e.is(flashLineEffect)) {\n return Decoration.set([flashLineDeco.range(e.value.from)]);\n }\n if (e.is(clearFlashEffect)) {\n return Decoration.none;\n }\n }\n return decos;\n },\n provide: (f) => EditorView.decorations.from(f),\n});\n\n\nfunction scrollToTarget(view: EditorView, target?: string) {\n if (!target) return;\n const docText = view.state.doc.toString();\n const normalized = target.replace(/\"/g, \"'\");\n let idx = docText.indexOf(normalized);\n if (idx === -1) idx = docText.indexOf(target);\n\n // If exact match fails, extract tag+class and search line by line\n if (idx === -1) {\n const tagMatch = target.match(/^<(\\w+)/);\n const classMatch = target.match(/class=[\"']([^\"']*?)[\"']/);\n if (tagMatch) {\n const searchTag = tagMatch[0];\n const searchClass = classMatch ? classMatch[1].split(\" \")[0] : null;\n for (let i = 1; i <= view.state.doc.lines; i++) {\n const line = view.state.doc.line(i);\n if (line.text.includes(searchTag) && (!searchClass || line.text.includes(searchClass))) {\n idx = line.from;\n break;\n }\n }\n }\n }\n\n if (idx !== -1) {\n const line = view.state.doc.lineAt(idx);\n view.dispatch({\n selection: { anchor: line.from },\n effects: [\n EditorView.scrollIntoView(line.from, { y: \"center\" }),\n flashLineEffect.of({ from: line.from, to: line.to }),\n ],\n });\n // Clear flash after 2s\n setTimeout(() => {\n view.dispatch({ effects: clearFlashEffect.of(null) });\n }, 2000);\n }\n}\n\nexport function CodeEditor({ code, label, scrollToText, onSave, onClose }: CodeEditorProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const viewRef = useRef<EditorView | null>(null);\n const [stats, setStats] = useState({ lines: 0, kb: \"0.0\" });\n\n const onSaveRef = useRef(onSave);\n const onCloseRef = useRef(onClose);\n onSaveRef.current = onSave;\n onCloseRef.current = onClose;\n\n const updateStats = useCallback((doc: { length: number; lines: number }) => {\n setStats({ lines: doc.lines, kb: (doc.length / 1024).toFixed(1) });\n }, []);\n\n useEffect(() => {\n if (!containerRef.current) return;\n\n const initialDoc = code.includes(\"\\n\") ? code : formatHtml(code);\n\n const state = EditorState.create({\n doc: initialDoc,\n extensions: [\n lineNumbers(),\n highlightActiveLine(),\n highlightActiveLineGutter(),\n bracketMatching(),\n closeBrackets(),\n foldGutter(),\n highlightSelectionMatches(),\n html(),\n oneDark,\n history(),\n EditorView.lineWrapping,\n keymap.of([\n { key: \"Mod-s\", run: (v) => { onSaveRef.current(v.state.doc.toString()); return true; } },\n { key: \"Escape\", run: () => { onCloseRef.current(); return true; } },\n indentWithTab,\n ...closeBracketsKeymap,\n ...searchKeymap,\n ...foldKeymap,\n ...historyKeymap,\n ...defaultKeymap,\n ]),\n EditorView.updateListener.of((update) => {\n if (update.docChanged) {\n updateStats(update.state.doc);\n }\n }),\n flashLineField,\n EditorView.theme({\n \"&\": { height: \"100%\", fontSize: \"13px\" },\n \".cm-scroller\": { overflow: \"auto\", fontFamily: \"ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace\" },\n \".cm-content\": { padding: \"8px 0\" },\n \".cm-gutters\": { borderRight: \"1px solid #21262d\" },\n \".cm-flash-line\": { backgroundColor: \"rgba(250, 204, 21, 0.25)\", transition: \"background-color 2s ease-out\" },\n }),\n ],\n });\n\n const view = new EditorView({ state, parent: containerRef.current });\n viewRef.current = view;\n\n updateStats(view.state.doc);\n scrollToTarget(view, scrollToText);\n view.focus();\n\n return () => { view.destroy(); };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Re-scroll when scrollToText changes while editor is already open\n useEffect(() => {\n const view = viewRef.current;\n if (!view || !scrollToText) return;\n scrollToTarget(view, scrollToText);\n }, [scrollToText]);\n\n function handleFormat() {\n const view = viewRef.current;\n if (!view) return;\n const formatted = formatHtml(view.state.doc.toString());\n view.dispatch({\n changes: { from: 0, to: view.state.doc.length, insert: formatted },\n });\n }\n\n function handleSave() {\n const view = viewRef.current;\n if (!view) return;\n onSave(view.state.doc.toString());\n }\n\n return (\n <div className=\"flex flex-col h-full bg-[#0d1117]\">\n {/* Header */}\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-gray-800 shrink-0\">\n <div className=\"flex items-center gap-3\">\n <span className=\"px-2 py-0.5 rounded bg-orange-600/20 text-orange-400 text-[10px] font-mono font-bold uppercase tracking-wider\">\n HTML\n </span>\n <span className=\"text-sm font-bold text-gray-300\">{label}</span>\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n onClick={handleFormat}\n className=\"px-3 py-1.5 text-xs font-bold rounded-lg bg-gray-800 text-gray-400 hover:text-white hover:bg-gray-700 transition-colors\"\n >\n Formatear\n </button>\n <button\n onClick={handleSave}\n className=\"px-4 py-1.5 text-xs font-bold rounded-lg bg-blue-500 text-white hover:bg-blue-600 transition-colors\"\n >\n Guardar\n </button>\n <button\n onClick={onClose}\n className=\"px-3 py-1.5 text-xs font-bold rounded-lg bg-gray-800 text-gray-400 hover:text-white hover:bg-gray-700 transition-colors\"\n >\n Cerrar\n </button>\n </div>\n </div>\n\n {/* Editor */}\n <div ref={containerRef} className=\"flex-1 overflow-hidden\" />\n\n {/* Footer */}\n <div className=\"flex items-center justify-between px-4 py-1.5 border-t border-gray-800 text-[10px] text-gray-500 font-mono shrink-0\">\n <span>{stats.lines} lineas</span>\n <span>Tab = indentar · Cmd+S = guardar · Esc = cerrar</span>\n <span>{stats.kb} KB</span>\n </div>\n </div>\n );\n}\n","import React from \"react\";\n\nexport type Viewport = \"desktop\" | \"tablet\" | \"mobile\";\n\nconst VIEWPORTS: { id: Viewport; label: string; icon: React.ReactElement }[] = [\n {\n id: \"desktop\",\n label: \"Desktop\",\n icon: (\n <svg className=\"w-4 h-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M2 4.25A2.25 2.25 0 014.25 2h11.5A2.25 2.25 0 0118 4.25v8.5A2.25 2.25 0 0115.75 15h-3.105a3.501 3.501 0 001.1 1.677A.75.75 0 0113.26 18H6.74a.75.75 0 01-.484-1.323A3.501 3.501 0 007.355 15H4.25A2.25 2.25 0 012 12.75v-8.5zm1.5 0a.75.75 0 01.75-.75h11.5a.75.75 0 01.75.75v8.5a.75.75 0 01-.75.75H4.25a.75.75 0 01-.75-.75v-8.5z\"\n clipRule=\"evenodd\"\n />\n </svg>\n ),\n },\n {\n id: \"tablet\",\n label: \"Tablet\",\n icon: (\n <svg className=\"w-4 h-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M5 1a2 2 0 00-2 2v14a2 2 0 002 2h10a2 2 0 002-2V3a2 2 0 00-2-2H5zm0 1.5h10a.5.5 0 01.5.5v14a.5.5 0 01-.5.5H5a.5.5 0 01-.5-.5V3a.5.5 0 01.5-.5zm4 14a1 1 0 112 0 1 1 0 01-2 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n ),\n },\n {\n id: \"mobile\",\n label: \"Mobile\",\n icon: (\n <svg className=\"w-4 h-4\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path\n fillRule=\"evenodd\"\n d=\"M6 2a2 2 0 00-2 2v12a2 2 0 002 2h8a2 2 0 002-2V4a2 2 0 00-2-2H6zm0 1.5h8a.5.5 0 01.5.5v12a.5.5 0 01-.5.5H6a.5.5 0 01-.5-.5V4a.5.5 0 01.5-.5zm3 13a1 1 0 112 0 1 1 0 01-2 0z\"\n clipRule=\"evenodd\"\n />\n </svg>\n ),\n },\n];\n\nexport function ViewportToggle({\n value,\n onChange,\n activeClass = \"bg-blue-100 text-blue-700\",\n inactiveClass = \"text-gray-400 hover:text-gray-600 hover:bg-gray-100\",\n}: {\n value: Viewport;\n onChange: (v: Viewport) => void;\n activeClass?: string;\n inactiveClass?: string;\n}) {\n return (\n <div className=\"flex items-center justify-center gap-1 py-2 shrink-0 bg-gray-50 border-b border-gray-200\">\n {VIEWPORTS.map((v) => (\n <button\n key={v.id}\n type=\"button\"\n onClick={() => onChange(v.id)}\n title={v.label}\n className={`p-1.5 rounded-lg transition-colors ${\n value === v.id ? activeClass : inactiveClass\n }`}\n >\n {v.icon}\n </button>\n ))}\n </div>\n );\n}\n","import { useState, useCallback, useRef } from \"react\";\n\nconst MAX_STACK = 30;\n\nexport function useUndoStack<T>() {\n const undoStack = useRef<T[]>([]);\n const redoStack = useRef<T[]>([]);\n const [canUndo, setCanUndo] = useState(false);\n const [canRedo, setCanRedo] = useState(false);\n\n const pushUndo = useCallback((snapshot: T) => {\n undoStack.current.push(JSON.parse(JSON.stringify(snapshot)));\n if (undoStack.current.length > MAX_STACK) undoStack.current.shift();\n redoStack.current = [];\n setCanUndo(true);\n setCanRedo(false);\n }, []);\n\n const undo = useCallback((current: T): T | null => {\n if (undoStack.current.length === 0) return null;\n redoStack.current.push(JSON.parse(JSON.stringify(current)));\n const prev = undoStack.current.pop()!;\n setCanUndo(undoStack.current.length > 0);\n setCanRedo(true);\n return prev;\n }, []);\n\n const redo = useCallback((current: T): T | null => {\n if (redoStack.current.length === 0) return null;\n undoStack.current.push(JSON.parse(JSON.stringify(current)));\n const next = redoStack.current.pop()!;\n setCanUndo(true);\n setCanRedo(redoStack.current.length > 0);\n return next;\n }, []);\n\n return { pushUndo, undo, redo, canUndo, canRedo };\n}\n"],"mappings":"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","names":["Canvas","html","useRef","useState","jsx","jsxs","useRef","useState","useState","useRef","useEffect","jsx","jsxs","jsxs","jsx","useState","useRef","useEffect","useEffect","useRef","useCallback","useState","jsx","jsxs","html","jsx","useState","useCallback","useRef"]}
|