@easybits.cloud/html-tailwind-generator 0.2.108 → 0.2.110

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  dataUrlToImagePart,
3
3
  streamGenerate
4
- } from "./chunk-HTGS346J.js";
4
+ } from "./chunk-PBISG7UJ.js";
5
5
 
6
6
  // src/generate.ts
7
7
  var 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.
@@ -130,4 +130,4 @@ export {
130
130
  PROMPT_SUFFIX,
131
131
  generateLanding
132
132
  };
133
- //# sourceMappingURL=chunk-ZWOEBRPC.js.map
133
+ //# sourceMappingURL=chunk-2KKW53BF.js.map
@@ -371,13 +371,6 @@ var PaletteIcon = () => /* @__PURE__ */ jsxs3("svg", { className: "w-3.5 h-3.5",
371
371
  /* @__PURE__ */ jsx3("circle", { cx: "6.5", cy: "12", r: "0.5", fill: "currentColor", stroke: "none" }),
372
372
  /* @__PURE__ */ jsx3("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" })
373
373
  ] });
374
- var RulerIcon = () => /* @__PURE__ */ jsxs3("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
375
- /* @__PURE__ */ jsx3("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" }),
376
- /* @__PURE__ */ jsx3("path", { d: "M14.5 12.5l2-2" }),
377
- /* @__PURE__ */ jsx3("path", { d: "M11.5 9.5l2-2" }),
378
- /* @__PURE__ */ jsx3("path", { d: "M8.5 6.5l2-2" }),
379
- /* @__PURE__ */ jsx3("path", { d: "M17.5 15.5l2-2" })
380
- ] });
381
374
  var LinkIcon = () => /* @__PURE__ */ jsxs3("svg", { className: "w-3.5 h-3.5", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
382
375
  /* @__PURE__ */ jsx3("path", { d: "M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71" }),
383
376
  /* @__PURE__ */ jsx3("path", { d: "M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71" })
@@ -418,7 +411,10 @@ function FloatingToolbar({
418
411
  setRefImageName(null);
419
412
  setShowTagPicker(false);
420
413
  setActiveTab(null);
421
- setTimeout(() => inputRef.current?.focus(), 50);
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
+ }
422
418
  }, [selection?.sectionId, selection?.elementPath]);
423
419
  useEffect2(() => {
424
420
  if (selection?.attrs) {
@@ -630,7 +626,6 @@ function FloatingToolbar({
630
626
  return null;
631
627
  })();
632
628
  const hasStyleTab = true;
633
- const hasSizeTab = sizePresets && !selection.isSectionRoot;
634
629
  const hasAttrsTab = hasAttrEditing;
635
630
  function toggleTab(tab) {
636
631
  setActiveTab((prev) => prev === tab ? null : tab);
@@ -656,7 +651,10 @@ function FloatingToolbar({
656
651
  ))
657
652
  ] });
658
653
  }
659
- if (!onUpdateAttribute || selection.tagName === "IMG") return null;
654
+ if (!onUpdateAttribute || selection.tagName === "IMG") {
655
+ if (selection.tagName === "IMG" && sizePresets) return /* @__PURE__ */ jsx3("div", { className: "pt-1 pb-0.5", children: renderSizePanel() });
656
+ return null;
657
+ }
660
658
  const containerTags = ["DIV", "SECTION", "HEADER", "FOOTER", "NAV", "ASIDE", "MAIN", "ARTICLE"];
661
659
  const isContainer = containerTags.includes(selection.tagName ?? "");
662
660
  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"];
@@ -723,7 +721,8 @@ function FloatingToolbar({
723
721
  ] }, mode);
724
722
  return /* @__PURE__ */ jsxs3("div", { className: "pt-1 pb-0.5", children: [
725
723
  renderColorRow("Color", "text"),
726
- isContainer && renderColorRow("Fondo", "bg")
724
+ isContainer && renderColorRow("Fondo", "bg"),
725
+ renderSizePanel()
727
726
  ] });
728
727
  }
729
728
  function renderSizePanel() {
@@ -1013,25 +1012,13 @@ function FloatingToolbar({
1013
1012
  {
1014
1013
  onClick: () => toggleTab("style"),
1015
1014
  className: `flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-medium transition-colors ${activeTab === "style" ? "bg-blue-600 text-white" : "bg-gray-800 hover:bg-gray-700 text-gray-400"}`,
1016
- title: "Estilo",
1015
+ title: "Estilo y tama\xF1o",
1017
1016
  children: [
1018
1017
  /* @__PURE__ */ jsx3(PaletteIcon, {}),
1019
1018
  /* @__PURE__ */ jsx3("span", { children: "Estilo" })
1020
1019
  ]
1021
1020
  }
1022
1021
  ),
1023
- hasSizeTab && /* @__PURE__ */ jsxs3(
1024
- "button",
1025
- {
1026
- onClick: () => toggleTab("size"),
1027
- className: `flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-medium transition-colors ${activeTab === "size" ? "bg-blue-600 text-white" : "bg-gray-800 hover:bg-gray-700 text-gray-400"}`,
1028
- title: "Tama\xF1o",
1029
- children: [
1030
- /* @__PURE__ */ jsx3(RulerIcon, {}),
1031
- /* @__PURE__ */ jsx3("span", { children: "Tama\xF1o" })
1032
- ]
1033
- }
1034
- ),
1035
1022
  hasAttrsTab && /* @__PURE__ */ jsxs3(
1036
1023
  "button",
1037
1024
  {
@@ -1055,7 +1042,6 @@ function FloatingToolbar({
1055
1042
  )
1056
1043
  ] }),
1057
1044
  activeTab === "style" && renderColorPanel(),
1058
- activeTab === "size" && renderSizePanel(),
1059
1045
  activeTab === "attrs" && renderAttrsPanel()
1060
1046
  ]
1061
1047
  }
@@ -1380,4 +1366,4 @@ export {
1380
1366
  ViewportToggle,
1381
1367
  useUndoStack
1382
1368
  };
1383
- //# sourceMappingURL=chunk-65HFGJZY.js.map
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 &lt;/&gt;\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 &middot; Cmd+S = guardar &middot; 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"]}
@@ -3,7 +3,7 @@ import {
3
3
  enrichImages,
4
4
  resolveModel,
5
5
  sanitizeSemanticColors
6
- } from "./chunk-HTGS346J.js";
6
+ } from "./chunk-PBISG7UJ.js";
7
7
 
8
8
  // src/refine.ts
9
9
  import { streamText } from "ai";
@@ -131,4 +131,4 @@ export {
131
131
  extractSectionDescription,
132
132
  refineLanding
133
133
  };
134
- //# sourceMappingURL=chunk-OQOOZCFY.js.map
134
+ //# sourceMappingURL=chunk-K2OYJF74.js.map
@@ -91,14 +91,14 @@ var FAKE_DOMAINS = [
91
91
  function findImageSlots(html) {
92
92
  const matches = [];
93
93
  const seen = /* @__PURE__ */ new Set();
94
- const diqRegex = /<img\s[^>]*data-image-query="([^"]+)"[^>]*>/gi;
94
+ const diqRegex = /<img\s[^>]*data-image-query=["']([^"']+)["'][^>]*>/gi;
95
95
  let m;
96
96
  while ((m = diqRegex.exec(html)) !== null) {
97
97
  const fullTag = m[0];
98
98
  const query = m[1];
99
99
  if (seen.has(query)) continue;
100
100
  seen.add(query);
101
- const cleanedTag = fullTag.replace(/\ssrc="[^"]*"/, "").replace(/\sdata-image-query="[^"]*"/, "");
101
+ const cleanedTag = fullTag.replace(/\ssrc=["'][^"']*["']/, "").replace(/\sdata-image-query=["'][^"']*["']/, "");
102
102
  const replaceTag = cleanedTag.replace(
103
103
  /^<img/,
104
104
  `<img src="{url}" data-enriched="true"`
@@ -669,4 +669,4 @@ export {
669
669
  enrichSectionSvgCharts,
670
670
  streamGenerate
671
671
  };
672
- //# sourceMappingURL=chunk-HTGS346J.js.map
672
+ //# sourceMappingURL=chunk-PBISG7UJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/images/pexels.ts","../src/images/dalleImages.ts","../src/images/enrichImages.ts","../src/images/svgGenerator.ts","../src/streamCore.ts","../src/sanitizeColors.ts"],"sourcesContent":["export interface PexelsResult {\n url: string;\n photographer: string;\n alt: string;\n}\n\nexport async function searchImage(query: string, apiKey?: string): Promise<PexelsResult | null> {\n const key = apiKey || process.env.PEXELS_API_KEY;\n if (!key) return null;\n try {\n const res = await fetch(\n `https://api.pexels.com/v1/search?query=${encodeURIComponent(query)}&per_page=5&orientation=landscape&locale=en-US`,\n { headers: { Authorization: key } }\n );\n if (!res.ok) {\n console.warn(`[pexels] ${res.status} for \"${query}\", trying unsplash fallback`);\n return searchUnsplash(query);\n }\n const data = await res.json();\n const photos = data.photos;\n if (!photos || photos.length === 0) {\n console.warn(`[pexels] 0 results for \"${query}\"`);\n return null;\n }\n const photo = photos[Math.floor(Math.random() * photos.length)];\n return {\n url: photo.src.large,\n photographer: photo.photographer,\n alt: photo.alt || query,\n };\n } catch {\n return searchUnsplash(query);\n }\n}\n\nasync function searchUnsplash(query: string): Promise<PexelsResult | null> {\n try {\n const res = await fetch(\n `https://unsplash.com/napi/search/photos?query=${encodeURIComponent(query)}&per_page=5&orientation=landscape`\n );\n if (!res.ok) return null;\n const data = await res.json();\n const results = data.results;\n if (!results || results.length === 0) return null;\n const photo = results[Math.floor(Math.random() * results.length)];\n return {\n url: photo.urls?.regular || photo.urls?.small,\n photographer: photo.user?.name || \"Unsplash\",\n alt: photo.alt_description || query,\n };\n } catch {\n return null;\n }\n}\n","/**\n * Generate an image using DALL-E 3 API.\n */\nexport async function generateImage(\n query: string,\n openaiApiKey: string\n): Promise<string> {\n const res = await fetch(\"https://api.openai.com/v1/images/generations\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${openaiApiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: \"dall-e-3\",\n prompt: query,\n n: 1,\n size: \"1792x1024\",\n }),\n });\n\n if (!res.ok) {\n const err = await res.text().catch(() => \"Unknown error\");\n throw new Error(`DALL-E API error ${res.status}: ${err}`);\n }\n\n const data = await res.json();\n return data.data[0].url;\n}\n","import { searchImage } from \"./pexels\";\nimport { generateImage } from \"./dalleImages\";\n\ninterface ImageMatch {\n query: string;\n searchStr: string;\n replaceStr: string;\n}\n\nexport interface EnrichImagesOptions {\n pexelsApiKey?: string;\n openaiApiKey?: string;\n /** Called with temp URL + query, returns permanent URL. Use to persist DALL-E images to S3/etc. */\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n}\n\nconst FAKE_DOMAINS = [\n \"images.unsplash.com\",\n \"unsplash.com\",\n \"via.placeholder.com\",\n \"placeholder.com\",\n \"placehold.co\",\n \"placehold.it\",\n \"placekitten.com\",\n \"picsum.photos\",\n \"loremflickr.com\",\n \"source.unsplash.com\",\n \"dummyimage.com\",\n \"fakeimg.pl\",\n \"example.com\",\n \"img.freepik.com\",\n \"cdn.pixabay.com\",\n];\n\n/**\n * Find all images in HTML that need Pexels enrichment.\n * Two strategies:\n * 1. data-image-query=\"...\" — AI followed instructions\n * 2. <img src=\"fake-url\" — detect fake domains, use alt/class/nearby text as query\n */\nexport function findImageSlots(html: string): ImageMatch[] {\n const matches: ImageMatch[] = [];\n const seen = new Set<string>();\n\n // 1. data-image-query=\"...\" or '...' — match the full <img> tag so we can replace src + data-image-query together\n const diqRegex = /<img\\s[^>]*data-image-query=[\"']([^\"']+)[\"'][^>]*>/gi;\n let m: RegExpExecArray | null;\n while ((m = diqRegex.exec(html)) !== null) {\n const fullTag = m[0];\n const query = m[1];\n if (seen.has(query)) continue;\n seen.add(query);\n // Build replacement tag: replace src (if any) and data-image-query with final src\n const cleanedTag = fullTag\n .replace(/\\ssrc=[\"'][^\"']*[\"']/, \"\")\n .replace(/\\sdata-image-query=[\"'][^\"']*[\"']/, \"\");\n // Insert src and data-enriched right after <img\n const replaceTag = cleanedTag.replace(\n /^<img/,\n `<img src=\"{url}\" data-enriched=\"true\"`\n );\n matches.push({\n query,\n searchStr: fullTag,\n replaceStr: replaceTag,\n });\n }\n\n // 2. <img with fake/non-existent src URLs\n const imgRegex = /<img\\s[^>]*src=\"(https?:\\/\\/[^\"]+)\"[^>]*>/gi;\n while ((m = imgRegex.exec(html)) !== null) {\n const fullTag = m[0];\n const srcUrl = m[1];\n\n if (fullTag.includes(\"data-enriched\")) continue;\n if (srcUrl.includes(\"pexels.com\")) continue;\n if (seen.has(srcUrl)) continue;\n\n // Check if domain is fake\n let isFake = false;\n try {\n const domain = new URL(srcUrl).hostname;\n isFake = FAKE_DOMAINS.some((d) => domain.includes(d));\n } catch {\n isFake = true;\n }\n if (!isFake) continue;\n\n // Extract query: try alt, then class context, then URL path words\n const altMatch = fullTag.match(/alt=\"([^\"]*?)\"/);\n let query = altMatch?.[1]?.trim() || \"\";\n\n if (!query) {\n // Try to extract meaningful words from the URL path\n try {\n const path = new URL(srcUrl).pathname;\n const words = path\n .replace(/[^a-zA-Z]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 2)\n .slice(0, 4)\n .join(\" \");\n if (words.length > 3) query = words;\n } catch { /* ignore */ }\n }\n\n if (!query) query = \"professional website hero image\";\n\n seen.add(srcUrl);\n matches.push({\n query,\n searchStr: `src=\"${srcUrl}\"`,\n replaceStr: `src=\"{url}\" data-enriched=\"true\"`,\n });\n }\n\n return matches;\n}\n\n/**\n * Enrich all images in an HTML string.\n * Strategy: Pexels (free) → DALL-E fallback (if openaiApiKey) → placeholder.\n * All images resolved in parallel. If persistImage callback provided, temp DALL-E URLs are persisted.\n */\nexport async function enrichImages(html: string, pexelsApiKeyOrOpts?: string | EnrichImagesOptions, openaiApiKey?: string): Promise<string> {\n // Support both legacy (string, string) and new (options object) signatures\n let opts: EnrichImagesOptions;\n if (typeof pexelsApiKeyOrOpts === \"object\" && pexelsApiKeyOrOpts !== null) {\n opts = pexelsApiKeyOrOpts;\n } else {\n opts = { pexelsApiKey: pexelsApiKeyOrOpts, openaiApiKey };\n }\n\n const slots = findImageSlots(html);\n if (slots.length === 0) return html;\n\n // Resolve all images in parallel\n const resolved = await Promise.allSettled(\n slots.map(async (slot) => {\n let url: string | null = null;\n\n // 1. Pexels first (free)\n if (opts.pexelsApiKey) {\n const img = await searchImage(slot.query, opts.pexelsApiKey).catch(() => null);\n url = img?.url || null;\n }\n\n // 2. DALL-E fallback if Pexels found nothing\n if (!url && opts.openaiApiKey) {\n try {\n const tempUrl = await generateImage(slot.query, opts.openaiApiKey);\n url = opts.persistImage\n ? await opts.persistImage(tempUrl, slot.query)\n : tempUrl;\n } catch (e) {\n console.warn(`[dalle] failed for \"${slot.query}\":`, e);\n }\n }\n\n // 3. Placeholder fallback\n url ??= `https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(slot.query.slice(0, 30))}`;\n\n return { slot, url };\n })\n );\n\n let result = html;\n for (const r of resolved) {\n if (r.status === \"fulfilled\" && r.value) {\n const { slot, url } = r.value;\n const replacement = slot.replaceStr.replace(\"{url}\", url);\n result = result.replaceAll(slot.searchStr, replacement);\n }\n }\n\n // Catch any remaining <img> tags without src\n result = result.replace(/<img\\s(?![^>]*\\bsrc=)([^>]*?)>/gi, (_match, attrs) => {\n const altMatch = attrs.match(/alt=\"([^\"]*?)\"/);\n const query = altMatch?.[1] || \"professional image\";\n return `<img src=\"https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(query.slice(0, 30))}\" ${attrs}>`;\n });\n\n return result;\n}\n","import { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { generateText } from \"ai\";\nimport { currentDateLine } from \"../streamCore\";\n\nconst SVG_SYSTEM_PROMPT = `You are a professional SVG designer. Generate clean, compact SVG graphics for documents.\n\nSTRICT SIZE RULES:\n- ALWAYS use viewBox=\"0 0 600 300\" (2:1 ratio) — no exceptions\n- ALWAYS set width=\"100%\" height=\"auto\" — NEVER use fixed pixel width/height\n- NO internal padding or margins — content fills the viewBox edge-to-edge (leave only 10-20px padding)\n- Keep SVGs under 2KB — simplicity is key\n\nSTYLE RULES:\n- Output ONLY the <svg>...</svg> tag — no markdown, no explanation\n- Flat design: solid fills, no drop shadows, minimal gradients (max 1-2)\n- Max 8-10 elements total — prefer fewer, larger shapes over many small ones\n- Color palette: use the provided theme colors, or defaults (#6366f1, #8b5cf6, #ec4899, #14b8a6, #f59e0b)\n- Text: font-family=\"system-ui, sans-serif\", font-size 12-16px, max 5 text labels\n- Self-contained: no external references, all styles inline\n\nCHART TYPES:\n- Bar charts (vertical/horizontal) — max 6 bars, rounded caps\n- Pie/donut charts — max 5 segments\n- Line charts — smooth paths, max 8 data points\n- Progress/gauge charts\n- Simple comparison charts\n- Stat cards with visual elements\n\nAVOID: complex illustrations, many small elements, decorative borders, nested groups deeper than 2 levels.`;\n\n\nexport async function generateSvg(\n prompt: string,\n anthropicApiKey?: string,\n options?: { width?: number; height?: number; themeColors?: string }\n): Promise<string> {\n const apiKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n const anthropic = createAnthropic({ apiKey: apiKey || undefined });\n\n const sizeHint = options?.width && options?.height\n ? ` Target dimensions: ${options.width}x${options.height}px.`\n : \"\";\n const colorHint = options?.themeColors\n ? ` Use these theme colors: ${options.themeColors}.`\n : \"\";\n\n const result = await generateText({\n model: anthropic(\"claude-haiku-4-5-20251001\"),\n system: SVG_SYSTEM_PROMPT + currentDateLine(),\n messages: [\n {\n role: \"user\",\n content: `Generate an SVG for: ${prompt}${sizeHint}${colorHint}`,\n },\n ],\n maxOutputTokens: 2000,\n });\n\n // Extract just the SVG tag\n const svgMatch = result.text.match(/<svg[\\s\\S]*<\\/svg>/i);\n if (!svgMatch) {\n throw new Error(\"SVG generation failed — no <svg> tag in response\");\n }\n\n return svgMatch[0];\n}\n","import { streamText } from \"ai\";\nimport { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { nanoid } from \"nanoid\";\nimport { findImageSlots } from \"./images/enrichImages\";\nimport { searchImage } from \"./images/pexels\";\nimport { generateImage } from \"./images/dalleImages\";\nimport { generateSvg } from \"./images/svgGenerator\";\nimport type { Section3 } from \"./types\";\nimport { sanitizeSemanticColors } from \"./sanitizeColors\";\n\nexport function currentDateLine(): string {\n return `\\nToday's date is ${new Date().toISOString().split(\"T\")[0]}. Use this for any date references.\\n`;\n}\n\n/**\n * Resolve AI model from available keys.\n * If modelId is already a LanguageModel object, return it directly.\n * Prefers Anthropic, falls back to OpenAI.\n */\nfunction isOpenAiModel(id: string): boolean {\n return /^(gpt-|o[1-9]|dall-e|tts-|whisper|chatgpt-)/.test(id);\n}\n\nfunction isLanguageModel(value: unknown): value is import(\"ai\").LanguageModel {\n return typeof value === \"object\" && value !== null && \"modelId\" in value && \"provider\" in value;\n}\n\nexport async function resolveModel(opts: {\n openaiApiKey?: string;\n anthropicApiKey?: string;\n modelId?: string | import(\"ai\").LanguageModel;\n defaultOpenai: string;\n defaultAnthropic: string;\n}) {\n // If modelId is already a model object, return it directly\n if (opts.modelId && isLanguageModel(opts.modelId)) {\n return opts.modelId;\n }\n\n const modelId = opts.modelId as string | undefined;\n\n if (modelId && isOpenAiModel(modelId)) {\n const openaiKey = opts.openaiApiKey || process.env.OPENAI_API_KEY;\n if (openaiKey) {\n const { createOpenAI } = await import(\"@ai-sdk/openai\");\n return createOpenAI({ apiKey: openaiKey })(modelId);\n }\n // OpenAI model requested but no key — fall through to Anthropic default\n } else if (modelId) {\n const anthropicKey = opts.anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n if (anthropicKey) {\n return createAnthropic({ apiKey: anthropicKey })(modelId);\n }\n }\n // No explicit modelId — prefer Anthropic, fallback to OpenAI\n const anthropicKey = opts.anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n if (anthropicKey) {\n return createAnthropic({ apiKey: anthropicKey })(opts.defaultAnthropic);\n }\n const openaiKey = opts.openaiApiKey || process.env.OPENAI_API_KEY;\n if (openaiKey) {\n const { createOpenAI } = await import(\"@ai-sdk/openai\");\n return createOpenAI({ apiKey: openaiKey })(opts.defaultOpenai);\n }\n return createAnthropic()(opts.defaultAnthropic);\n}\n\n/**\n * Convert data URL to Uint8Array for AI SDK vision.\n */\nexport function dataUrlToImagePart(dataUrl: string): { image: Uint8Array; mimeType: string } | null {\n const match = dataUrl.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) return null;\n return {\n image: new Uint8Array(Buffer.from(match[2], \"base64\")),\n mimeType: match[1],\n };\n}\n\n/**\n * Extract complete JSON objects from accumulated text using brace-depth tracking.\n */\nexport function extractJsonObjects(text: string): [any[], string] {\n const objects: any[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n remaining = remaining.trimStart();\n if (!remaining.startsWith(\"{\")) {\n const nextBrace = remaining.indexOf(\"{\");\n if (nextBrace === -1) break;\n remaining = remaining.slice(nextBrace);\n continue;\n }\n\n let depth = 0;\n let inString = false;\n let escape = false;\n let end = -1;\n\n for (let i = 0; i < remaining.length; i++) {\n const ch = remaining[i];\n if (escape) { escape = false; continue; }\n if (ch === \"\\\\\") { escape = true; continue; }\n if (ch === '\"') { inString = !inString; continue; }\n if (inString) continue;\n if (ch === \"{\") depth++;\n if (ch === \"}\") { depth--; if (depth === 0) { end = i; break; } }\n }\n\n if (end === -1) break;\n\n const candidate = remaining.slice(0, end + 1);\n remaining = remaining.slice(end + 1);\n\n try {\n objects.push(JSON.parse(candidate));\n } catch {\n // malformed, skip\n }\n }\n\n return [objects, remaining];\n}\n\n/** Inline shimmer SVG used as src for loading image placeholders */\nconst LOADING_PLACEHOLDER_SRC = `data:image/svg+xml,${encodeURIComponent('<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"800\" height=\"500\" viewBox=\"0 0 800 500\"><rect fill=\"#f3f4f6\" width=\"800\" height=\"500\" rx=\"12\"/><g opacity=\".4\"><rect x=\"320\" y=\"200\" width=\"160\" height=\"4\" rx=\"2\" fill=\"#d1d5db\"><animate attributeName=\"opacity\" values=\".3;.8;.3\" dur=\"1.5s\" repeatCount=\"indefinite\"/></rect><rect x=\"280\" y=\"215\" width=\"240\" height=\"4\" rx=\"2\" fill=\"#d1d5db\"><animate attributeName=\"opacity\" values=\".3;.8;.3\" dur=\"1.5s\" begin=\".3s\" repeatCount=\"indefinite\"/></rect><rect x=\"340\" y=\"230\" width=\"120\" height=\"4\" rx=\"2\" fill=\"#d1d5db\"><animate attributeName=\"opacity\" values=\".3;.8;.3\" dur=\"1.5s\" begin=\".6s\" repeatCount=\"indefinite\"/></rect></g><g transform=\"translate(376,150)\" opacity=\".3\"><path d=\"M0 28V4a4 4 0 014-4h40a4 4 0 014 4v24a4 4 0 01-4 4H4a4 4 0 01-4-4z\" fill=\"#d1d5db\"/><circle cx=\"14\" cy=\"12\" r=\"4\" fill=\"#9ca3af\"/><path d=\"M4 28l10-10 6 6 8-8 16 16H4z\" fill=\"#9ca3af\" opacity=\".5\"/></g></svg>')}`;\n\n/** Inline SVG placeholder for loading charts */\nconst SVG_LOADING_PLACEHOLDER = `<div class=\"w-full h-48 bg-gray-50 rounded-lg flex items-center justify-center animate-pulse\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#9ca3af\" stroke-width=\"1.5\"><rect x=\"3\" y=\"12\" width=\"4\" height=\"9\" rx=\"1\"/><rect x=\"10\" y=\"7\" width=\"4\" height=\"14\" rx=\"1\"/><rect x=\"17\" y=\"3\" width=\"4\" height=\"18\" rx=\"1\"/></svg></div>`;\n\n/** Replace data-svg-chart divs with loading placeholders */\nexport function addSvgLoadingPlaceholders(html: string): string {\n return html.replace(\n /<div\\s([^>]*?)data-svg-chart=\"([^\"]+)\"([^>]*?)>[\\s\\S]*?<\\/div>/gi,\n (_match, before, chart, after) => {\n return `<div ${before}data-svg-chart=\"${chart}\"${after}>${SVG_LOADING_PLACEHOLDER}</div>`;\n }\n );\n}\n\n/** Replace data-image-query attrs with animated loading placeholders */\nexport function addLoadingPlaceholders(html: string): string {\n return html.replace(\n /(<img\\s[^>]*)data-image-query=\"([^\"]+)\"([^>]*?)(?:\\s*\\/?>)/gi,\n (_match, before, query, after) => {\n if (before.includes('src=') || after.includes('src=')) return _match;\n return `${before}src=\"${LOADING_PLACEHOLDER_SRC}\" data-image-query=\"${query}\" alt=\"${query}\"${after}>`;\n }\n );\n}\n\n/** Enrich a section's images (Pexels → DALL-E → placeholder fallback). Mutates section.html in place. */\nexport async function enrichSectionImages(\n section: Section3,\n opts: {\n pexelsApiKey?: string;\n openaiApiKey?: string;\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n onImageUpdate?: (sectionId: string, html: string) => void;\n }\n): Promise<void> {\n const slots = findImageSlots(section.html);\n if (slots.length === 0) return;\n const results = await Promise.allSettled(\n slots.map(async (slot) => {\n let url: string | null = null;\n if (opts.pexelsApiKey) {\n const img = await searchImage(slot.query, opts.pexelsApiKey).catch(() => null);\n url = img?.url || null;\n }\n if (!url && opts.openaiApiKey) {\n try {\n const tempUrl = await generateImage(slot.query, opts.openaiApiKey);\n url = opts.persistImage ? await opts.persistImage(tempUrl, slot.query) : tempUrl;\n } catch (e) {\n console.warn(`[dalle] failed for \"${slot.query}\":`, e);\n }\n }\n url ??= `https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(slot.query.slice(0, 30))}`;\n return { slot, url };\n })\n );\n let html = section.html;\n for (const r of results) {\n if (r.status === \"fulfilled\" && r.value) {\n const { slot, url } = r.value;\n const replacement = slot.replaceStr.replace(\"{url}\", url);\n html = html.replaceAll(slot.searchStr, replacement);\n }\n }\n if (html !== section.html) {\n section.html = html;\n opts.onImageUpdate?.(section.id, html);\n }\n}\n\n/** Enrich a section's SVG chart placeholders. Mutates section.html in place. */\nexport async function enrichSectionSvgCharts(\n section: Section3,\n opts: {\n anthropicApiKey?: string;\n onImageUpdate?: (sectionId: string, html: string) => void;\n }\n): Promise<void> {\n const svgRegex = /<div\\s[^>]*data-svg-chart=\"([^\"]+)\"[^>]*>[\\s\\S]*?<\\/div>/gi;\n const svgMatches: { fullMatch: string; prompt: string }[] = [];\n let svgM: RegExpExecArray | null;\n while ((svgM = svgRegex.exec(section.html)) !== null) {\n svgMatches.push({ fullMatch: svgM[0], prompt: svgM[1] });\n }\n if (svgMatches.length === 0) return;\n const anthropicKey = opts.anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n const results = await Promise.allSettled(\n svgMatches.map(async ({ fullMatch, prompt }) => {\n try {\n const svg = await generateSvg(prompt, anthropicKey);\n return { fullMatch, svg };\n } catch (e) {\n console.warn(`[svg] failed for \"${prompt}\":`, e);\n return { fullMatch, svg: `<div class=\"w-full h-48 bg-gray-100 rounded-lg flex items-center justify-center text-gray-400 text-sm\">${prompt}</div>` };\n }\n })\n );\n let html = section.html;\n for (const r of results) {\n if (r.status === \"fulfilled\" && r.value) {\n html = html.replace(r.value.fullMatch, r.value.svg);\n }\n }\n if (html !== section.html) {\n section.html = html;\n opts.onImageUpdate?.(section.id, html);\n }\n}\n\nexport interface StreamGenerateOptions {\n /** Anthropic API key */\n anthropicApiKey?: string;\n /** OpenAI API key */\n openaiApiKey?: string;\n /** Model ID override or pre-built LanguageModel object */\n model?: string | import(\"ai\").LanguageModel;\n /** System prompt */\n systemPrompt: string;\n /** User message content (text or multimodal parts) */\n userContent: any[];\n /** Pexels API key for image enrichment */\n pexelsApiKey?: string;\n /** Persist DALL-E images to permanent storage */\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n /** Called when a new section is parsed */\n onSection?: (section: Section3) => void;\n /** Called when a section's images are enriched */\n onImageUpdate?: (sectionId: string, html: string) => void;\n /** Called with raw text buffer for real-time partial streaming */\n onRawChunk?: (buffer: string, completedCount: number) => void;\n /** Called when generation is complete */\n onDone?: (sections: Section3[]) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n}\n\n/**\n * Core streaming generation: stream AI text → parse NDJSON → emit sections → enrich images.\n * Used by both generateLanding and generateDocument.\n */\nexport async function streamGenerate(options: StreamGenerateOptions): Promise<Section3[]> {\n const {\n anthropicApiKey,\n openaiApiKey: _openaiApiKey,\n model: modelId,\n systemPrompt,\n userContent,\n pexelsApiKey,\n persistImage,\n onSection,\n onImageUpdate,\n onRawChunk,\n onDone,\n onError,\n } = options;\n\n const openaiApiKey = _openaiApiKey || process.env.OPENAI_API_KEY;\n const model = await resolveModel({\n openaiApiKey,\n anthropicApiKey,\n modelId,\n defaultOpenai: \"gpt-4o\",\n defaultAnthropic: \"claude-sonnet-4-6\",\n });\n\n const result = streamText({\n model,\n system: systemPrompt + currentDateLine(),\n messages: [{ role: \"user\", content: userContent }],\n });\n\n const allSections: Section3[] = [];\n const imagePromises: Promise<void>[] = [];\n let sectionOrder = 0;\n let buffer = \"\";\n\n function enrichSvgCharts(sectionRef: Section3) {\n const svgRegex = /<div\\s[^>]*data-svg-chart=\"([^\"]+)\"[^>]*>[\\s\\S]*?<\\/div>/gi;\n const svgMatches: { fullMatch: string; prompt: string }[] = [];\n let svgM: RegExpExecArray | null;\n while ((svgM = svgRegex.exec(sectionRef.html)) !== null) {\n svgMatches.push({ fullMatch: svgM[0], prompt: svgM[1] });\n }\n if (svgMatches.length === 0) return;\n\n const anthropicKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n imagePromises.push(\n (async () => {\n const results = await Promise.allSettled(\n svgMatches.map(async ({ fullMatch, prompt }) => {\n try {\n const svg = await generateSvg(prompt, anthropicKey);\n return { fullMatch, svg };\n } catch (e) {\n console.warn(`[svg] failed for \"${prompt}\":`, e);\n return { fullMatch, svg: `<div class=\"w-full h-48 bg-gray-100 rounded-lg flex items-center justify-center text-gray-400 text-sm\">${prompt}</div>` };\n }\n })\n );\n let html = sectionRef.html;\n for (const r of results) {\n if (r.status === \"fulfilled\" && r.value) {\n html = html.replace(r.value.fullMatch, r.value.svg);\n }\n }\n if (html !== sectionRef.html) {\n sectionRef.html = html;\n onImageUpdate?.(sectionRef.id, html);\n }\n })()\n );\n }\n\n function enrichSection(sectionRef: Section3) {\n const slots = findImageSlots(sectionRef.html);\n if (slots.length === 0) return;\n const slotsSnapshot = slots.map((s) => ({ ...s }));\n imagePromises.push(\n (async () => {\n const results = await Promise.allSettled(\n slotsSnapshot.map(async (slot) => {\n let url: string | null = null;\n // 1. Pexels first (free, fast)\n if (pexelsApiKey) {\n const img = await searchImage(slot.query, pexelsApiKey).catch(() => null);\n url = img?.url || null;\n }\n // 2. DALL-E fallback\n if (!url && openaiApiKey) {\n try {\n const tempUrl = await generateImage(slot.query, openaiApiKey);\n url = persistImage ? await persistImage(tempUrl, slot.query) : tempUrl;\n } catch (e) {\n console.warn(`[dalle] failed for \"${slot.query}\":`, e);\n }\n }\n url ??= `https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(slot.query.slice(0, 30))}`;\n return { slot, url };\n })\n );\n let html = sectionRef.html;\n for (const r of results) {\n if (r.status === \"fulfilled\" && r.value) {\n const { slot, url } = r.value;\n const replacement = slot.replaceStr.replace(\"{url}\", url);\n html = html.replaceAll(slot.searchStr, replacement);\n }\n }\n if (html !== sectionRef.html) {\n sectionRef.html = html;\n onImageUpdate?.(sectionRef.id, html);\n }\n })()\n );\n }\n\n function processObject(obj: any) {\n if (!obj.html || !obj.label) return;\n const section: Section3 = {\n id: nanoid(8),\n order: sectionOrder++,\n html: sanitizeSemanticColors(addSvgLoadingPlaceholders(addLoadingPlaceholders(obj.html))),\n label: obj.label,\n };\n allSections.push(section);\n onSection?.(section);\n enrichSection(section);\n enrichSvgCharts(section);\n }\n\n try {\n let chunkCount = 0;\n for await (const chunk of result.textStream) {\n buffer += chunk;\n chunkCount++;\n\n const [objects, remaining] = extractJsonObjects(buffer);\n buffer = remaining;\n for (const obj of objects) {\n chunkCount = 0;\n processObject(obj);\n }\n\n if (onRawChunk && chunkCount % 5 === 0 && buffer.length > 20) {\n onRawChunk(buffer, allSections.length);\n }\n }\n\n // Parse remaining buffer\n if (buffer.trim()) {\n let cleaned = buffer.trim();\n if (cleaned.startsWith(\"```\")) {\n cleaned = cleaned.replace(/^```(?:json)?\\s*/, \"\").replace(/\\s*```$/, \"\");\n }\n const [lastObjects] = extractJsonObjects(cleaned);\n for (const obj of lastObjects) processObject(obj);\n }\n\n // Wait for image enrichment\n await Promise.allSettled(imagePromises);\n\n // Final fallback for images without src\n for (const section of allSections) {\n const before = section.html;\n section.html = section.html.replace(\n /<img\\s(?![^>]*\\bsrc=)([^>]*?)>/gi,\n (_match, attrs) => {\n const altMatch = attrs.match(/alt=\"([^\"]*?)\"/);\n const query = altMatch?.[1] || \"image\";\n return `<img src=\"https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(query.slice(0, 30))}\" ${attrs}>`;\n }\n );\n section.html = section.html.replace(\n /data-image-query=\"([^\"]+)\"/g,\n (_match, query) => {\n return `src=\"https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(query.slice(0, 30))}\" data-enriched=\"placeholder\"`;\n }\n );\n if (section.html !== before) {\n onImageUpdate?.(section.id, section.html);\n }\n }\n\n onDone?.(allSections);\n return allSections;\n } catch (err: any) {\n const error = err instanceof Error ? err : new Error(err?.message || \"Generation failed\");\n onError?.(error);\n throw error;\n }\n}\n","/**\n * Replace hardcoded Tailwind color classes with semantic color classes\n * (bg-primary, text-primary, etc.). Gray/white/black/slate/zinc/neutral stay intact.\n *\n * Covers ALL chromatic Tailwind colors the model might generate.\n */\n\n// All chromatic colors Tailwind ships (excluding neutrals: slate, gray, zinc, neutral, stone)\nconst COLORS =\n \"red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose\";\n\nfunction re(prefix: string, shades: string): RegExp {\n return new RegExp(`\\\\b${prefix}-(${COLORS})-(${shades})\\\\b`, \"g\");\n}\n\nconst replacements: [RegExp, string][] = [\n // Background\n [re(\"bg\", \"500|600|700\"), \"bg-primary\"],\n [re(\"bg\", \"50|100\"), \"bg-primary-light\"],\n [re(\"bg\", \"800|900|950\"), \"bg-primary-dark\"],\n [re(\"bg\", \"200|300|400\"), \"bg-primary\"],\n\n // Text\n [re(\"text\", \"500|600|700\"), \"text-primary\"],\n [re(\"text\", \"800|900|950\"), \"text-primary-dark\"],\n [re(\"text\", \"50|100|200|300\"), \"text-on-primary\"],\n [re(\"text\", \"400\"), \"text-primary\"],\n\n // Border\n [re(\"border\", \"\\\\d{2,3}\"), \"border-primary\"],\n\n // Ring\n [re(\"ring\", \"\\\\d{2,3}\"), \"ring-primary\"],\n\n // Gradients\n [re(\"from\", \"\\\\d{2,3}\"), \"from-primary\"],\n [re(\"to\", \"\\\\d{2,3}\"), \"to-primary\"],\n [re(\"via\", \"\\\\d{2,3}\"), \"via-primary\"],\n\n // Hover/focus variants\n [new RegExp(`\\\\bhover:bg-(${COLORS})-(500|600|700|800|900|950)\\\\b`, \"g\"), \"hover:bg-primary-dark\"],\n [new RegExp(`\\\\bhover:bg-(${COLORS})-(50|100|200|300|400)\\\\b`, \"g\"), \"hover:bg-primary-light\"],\n [new RegExp(`\\\\bhover:text-(${COLORS})-\\\\d{2,3}\\\\b`, \"g\"), \"hover:text-primary\"],\n [new RegExp(`\\\\bfocus:ring-(${COLORS})-\\\\d{2,3}\\\\b`, \"g\"), \"focus:ring-primary\"],\n [new RegExp(`\\\\bfocus:border-(${COLORS})-\\\\d{2,3}\\\\b`, \"g\"), \"focus:border-primary\"],\n\n // Divide\n [re(\"divide\", \"\\\\d{2,3}\"), \"divide-primary\"],\n\n // Placeholder\n [re(\"placeholder\", \"\\\\d{2,3}\"), \"placeholder-primary\"],\n\n // Outline\n [re(\"outline\", \"\\\\d{2,3}\"), \"outline-primary\"],\n\n // Shadow colored\n [re(\"shadow\", \"\\\\d{2,3}\"), \"shadow-primary\"],\n\n // Decoration\n [re(\"decoration\", \"\\\\d{2,3}\"), \"decoration-primary\"],\n\n // Accent\n [re(\"accent\", \"\\\\d{2,3}\"), \"accent-primary\"],\n];\n\nexport function sanitizeSemanticColors(html: string): string {\n let result = html;\n for (const [pattern, replacement] of replacements) {\n result = result.replace(pattern, replacement);\n }\n return result;\n}\n"],"mappings":"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","names":["createAnthropic","openaiKey","anthropicKey","createAnthropic"]}
@@ -9,7 +9,7 @@ import {
9
9
  resolveModel,
10
10
  sanitizeSemanticColors,
11
11
  streamGenerate
12
- } from "./chunk-HTGS346J.js";
12
+ } from "./chunk-PBISG7UJ.js";
13
13
 
14
14
  // src/generateDocument.ts
15
15
  import { generateObject, streamText } from "ai";
@@ -505,4 +505,4 @@ export {
505
505
  generateDocument,
506
506
  generateDocumentParallel
507
507
  };
508
- //# sourceMappingURL=chunk-ABRLILH6.js.map
508
+ //# sourceMappingURL=chunk-VQTANZBA.js.map
@@ -5,7 +5,7 @@ import {
5
5
  SectionList,
6
6
  ViewportToggle,
7
7
  useUndoStack
8
- } from "./chunk-65HFGJZY.js";
8
+ } from "./chunk-5MDDRBEO.js";
9
9
  import "./chunk-OZ3RKRER.js";
10
10
  export {
11
11
  Canvas,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  currentDateLine,
3
3
  resolveModel
4
- } from "./chunk-HTGS346J.js";
4
+ } from "./chunk-PBISG7UJ.js";
5
5
 
6
6
  // src/directions.ts
7
7
  import { generateObject, streamText } from "ai";
package/dist/generate.js CHANGED
@@ -2,10 +2,10 @@ import {
2
2
  PROMPT_SUFFIX,
3
3
  SYSTEM_PROMPT,
4
4
  generateLanding
5
- } from "./chunk-ZWOEBRPC.js";
5
+ } from "./chunk-2KKW53BF.js";
6
6
  import {
7
7
  extractJsonObjects
8
- } from "./chunk-HTGS346J.js";
8
+ } from "./chunk-PBISG7UJ.js";
9
9
  export {
10
10
  PROMPT_SUFFIX,
11
11
  SYSTEM_PROMPT,
@@ -3,8 +3,8 @@ import {
3
3
  DOCUMENT_SYSTEM_PROMPT,
4
4
  generateDocument,
5
5
  generateDocumentParallel
6
- } from "./chunk-ABRLILH6.js";
7
- import "./chunk-HTGS346J.js";
6
+ } from "./chunk-VQTANZBA.js";
7
+ import "./chunk-PBISG7UJ.js";
8
8
  export {
9
9
  DOCUMENT_PROMPT_SUFFIX,
10
10
  DOCUMENT_SYSTEM_PROMPT,
package/dist/images.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  generateImage,
6
6
  generateSvg,
7
7
  searchImage
8
- } from "./chunk-HTGS346J.js";
8
+ } from "./chunk-PBISG7UJ.js";
9
9
  export {
10
10
  enrichImages,
11
11
  findImageSlots,
package/dist/index.js CHANGED
@@ -4,22 +4,22 @@ import {
4
4
  FloatingToolbar,
5
5
  SectionList,
6
6
  ViewportToggle
7
- } from "./chunk-65HFGJZY.js";
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-ZWOEBRPC.js";
13
+ } from "./chunk-2KKW53BF.js";
14
14
  import {
15
15
  DOCUMENT_PROMPT_SUFFIX,
16
16
  DOCUMENT_SYSTEM_PROMPT,
17
17
  generateDocument
18
- } from "./chunk-ABRLILH6.js";
18
+ } from "./chunk-VQTANZBA.js";
19
19
  import {
20
20
  REFINE_SYSTEM,
21
21
  refineLanding
22
- } from "./chunk-OQOOZCFY.js";
22
+ } from "./chunk-K2OYJF74.js";
23
23
  import {
24
24
  deployToEasyBits,
25
25
  deployToS3
@@ -41,7 +41,7 @@ import {
41
41
  generateImage,
42
42
  generateSvg,
43
43
  searchImage
44
- } from "./chunk-HTGS346J.js";
44
+ } from "./chunk-PBISG7UJ.js";
45
45
  export {
46
46
  Canvas,
47
47
  CodeEditor,
package/dist/refine.js CHANGED
@@ -2,8 +2,8 @@ import {
2
2
  REFINE_SYSTEM,
3
3
  extractSectionDescription,
4
4
  refineLanding
5
- } from "./chunk-OQOOZCFY.js";
6
- import "./chunk-HTGS346J.js";
5
+ } from "./chunk-K2OYJF74.js";
6
+ import "./chunk-PBISG7UJ.js";
7
7
  export {
8
8
  REFINE_SYSTEM,
9
9
  extractSectionDescription,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easybits.cloud/html-tailwind-generator",
3
- "version": "0.2.108",
3
+ "version": "0.2.110",
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/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\" | \"size\" | \"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 for non-section, style presets for section)\n const hasSizeTab = sizePresets && !selection.isSectionRoot;\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') return null;\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 </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\"\n >\n <PaletteIcon />\n <span>Estilo</span>\n </button>\n )}\n {hasSizeTab && (\n <button\n onClick={() => toggleTab(\"size\")}\n className={`flex items-center gap-1 px-2 py-1 rounded-md text-[10px] font-medium transition-colors ${\n activeTab === \"size\" ? \"bg-blue-600 text-white\" : \"bg-gray-800 hover:bg-gray-700 text-gray-400\"\n }`}\n title=\"Tamaño\"\n >\n <RulerIcon />\n <span>Tamaño</span>\n </button>\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 &lt;/&gt;\n </button>\n </div>\n\n {/* Active tab panel */}\n {activeTab === \"style\" && renderColorPanel()}\n {activeTab === \"size\" && renderSizePanel()}\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 &middot; Cmd+S = guardar &middot; 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","useEffect","useRef","useCallback","useState","jsx","jsxs","html","jsx","useState","useCallback","useRef"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/images/pexels.ts","../src/images/dalleImages.ts","../src/images/enrichImages.ts","../src/images/svgGenerator.ts","../src/streamCore.ts","../src/sanitizeColors.ts"],"sourcesContent":["export interface PexelsResult {\n url: string;\n photographer: string;\n alt: string;\n}\n\nexport async function searchImage(query: string, apiKey?: string): Promise<PexelsResult | null> {\n const key = apiKey || process.env.PEXELS_API_KEY;\n if (!key) return null;\n try {\n const res = await fetch(\n `https://api.pexels.com/v1/search?query=${encodeURIComponent(query)}&per_page=5&orientation=landscape&locale=en-US`,\n { headers: { Authorization: key } }\n );\n if (!res.ok) {\n console.warn(`[pexels] ${res.status} for \"${query}\", trying unsplash fallback`);\n return searchUnsplash(query);\n }\n const data = await res.json();\n const photos = data.photos;\n if (!photos || photos.length === 0) {\n console.warn(`[pexels] 0 results for \"${query}\"`);\n return null;\n }\n const photo = photos[Math.floor(Math.random() * photos.length)];\n return {\n url: photo.src.large,\n photographer: photo.photographer,\n alt: photo.alt || query,\n };\n } catch {\n return searchUnsplash(query);\n }\n}\n\nasync function searchUnsplash(query: string): Promise<PexelsResult | null> {\n try {\n const res = await fetch(\n `https://unsplash.com/napi/search/photos?query=${encodeURIComponent(query)}&per_page=5&orientation=landscape`\n );\n if (!res.ok) return null;\n const data = await res.json();\n const results = data.results;\n if (!results || results.length === 0) return null;\n const photo = results[Math.floor(Math.random() * results.length)];\n return {\n url: photo.urls?.regular || photo.urls?.small,\n photographer: photo.user?.name || \"Unsplash\",\n alt: photo.alt_description || query,\n };\n } catch {\n return null;\n }\n}\n","/**\n * Generate an image using DALL-E 3 API.\n */\nexport async function generateImage(\n query: string,\n openaiApiKey: string\n): Promise<string> {\n const res = await fetch(\"https://api.openai.com/v1/images/generations\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${openaiApiKey}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: \"dall-e-3\",\n prompt: query,\n n: 1,\n size: \"1792x1024\",\n }),\n });\n\n if (!res.ok) {\n const err = await res.text().catch(() => \"Unknown error\");\n throw new Error(`DALL-E API error ${res.status}: ${err}`);\n }\n\n const data = await res.json();\n return data.data[0].url;\n}\n","import { searchImage } from \"./pexels\";\nimport { generateImage } from \"./dalleImages\";\n\ninterface ImageMatch {\n query: string;\n searchStr: string;\n replaceStr: string;\n}\n\nexport interface EnrichImagesOptions {\n pexelsApiKey?: string;\n openaiApiKey?: string;\n /** Called with temp URL + query, returns permanent URL. Use to persist DALL-E images to S3/etc. */\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n}\n\nconst FAKE_DOMAINS = [\n \"images.unsplash.com\",\n \"unsplash.com\",\n \"via.placeholder.com\",\n \"placeholder.com\",\n \"placehold.co\",\n \"placehold.it\",\n \"placekitten.com\",\n \"picsum.photos\",\n \"loremflickr.com\",\n \"source.unsplash.com\",\n \"dummyimage.com\",\n \"fakeimg.pl\",\n \"example.com\",\n \"img.freepik.com\",\n \"cdn.pixabay.com\",\n];\n\n/**\n * Find all images in HTML that need Pexels enrichment.\n * Two strategies:\n * 1. data-image-query=\"...\" — AI followed instructions\n * 2. <img src=\"fake-url\" — detect fake domains, use alt/class/nearby text as query\n */\nexport function findImageSlots(html: string): ImageMatch[] {\n const matches: ImageMatch[] = [];\n const seen = new Set<string>();\n\n // 1. data-image-query=\"...\" — match the full <img> tag so we can replace src + data-image-query together\n const diqRegex = /<img\\s[^>]*data-image-query=\"([^\"]+)\"[^>]*>/gi;\n let m: RegExpExecArray | null;\n while ((m = diqRegex.exec(html)) !== null) {\n const fullTag = m[0];\n const query = m[1];\n if (seen.has(query)) continue;\n seen.add(query);\n // Build replacement tag: replace src (if any) and data-image-query with final src\n const cleanedTag = fullTag\n .replace(/\\ssrc=\"[^\"]*\"/, \"\")\n .replace(/\\sdata-image-query=\"[^\"]*\"/, \"\");\n // Insert src and data-enriched right after <img\n const replaceTag = cleanedTag.replace(\n /^<img/,\n `<img src=\"{url}\" data-enriched=\"true\"`\n );\n matches.push({\n query,\n searchStr: fullTag,\n replaceStr: replaceTag,\n });\n }\n\n // 2. <img with fake/non-existent src URLs\n const imgRegex = /<img\\s[^>]*src=\"(https?:\\/\\/[^\"]+)\"[^>]*>/gi;\n while ((m = imgRegex.exec(html)) !== null) {\n const fullTag = m[0];\n const srcUrl = m[1];\n\n if (fullTag.includes(\"data-enriched\")) continue;\n if (srcUrl.includes(\"pexels.com\")) continue;\n if (seen.has(srcUrl)) continue;\n\n // Check if domain is fake\n let isFake = false;\n try {\n const domain = new URL(srcUrl).hostname;\n isFake = FAKE_DOMAINS.some((d) => domain.includes(d));\n } catch {\n isFake = true;\n }\n if (!isFake) continue;\n\n // Extract query: try alt, then class context, then URL path words\n const altMatch = fullTag.match(/alt=\"([^\"]*?)\"/);\n let query = altMatch?.[1]?.trim() || \"\";\n\n if (!query) {\n // Try to extract meaningful words from the URL path\n try {\n const path = new URL(srcUrl).pathname;\n const words = path\n .replace(/[^a-zA-Z]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 2)\n .slice(0, 4)\n .join(\" \");\n if (words.length > 3) query = words;\n } catch { /* ignore */ }\n }\n\n if (!query) query = \"professional website hero image\";\n\n seen.add(srcUrl);\n matches.push({\n query,\n searchStr: `src=\"${srcUrl}\"`,\n replaceStr: `src=\"{url}\" data-enriched=\"true\"`,\n });\n }\n\n return matches;\n}\n\n/**\n * Enrich all images in an HTML string.\n * Strategy: Pexels (free) → DALL-E fallback (if openaiApiKey) → placeholder.\n * All images resolved in parallel. If persistImage callback provided, temp DALL-E URLs are persisted.\n */\nexport async function enrichImages(html: string, pexelsApiKeyOrOpts?: string | EnrichImagesOptions, openaiApiKey?: string): Promise<string> {\n // Support both legacy (string, string) and new (options object) signatures\n let opts: EnrichImagesOptions;\n if (typeof pexelsApiKeyOrOpts === \"object\" && pexelsApiKeyOrOpts !== null) {\n opts = pexelsApiKeyOrOpts;\n } else {\n opts = { pexelsApiKey: pexelsApiKeyOrOpts, openaiApiKey };\n }\n\n const slots = findImageSlots(html);\n if (slots.length === 0) return html;\n\n // Resolve all images in parallel\n const resolved = await Promise.allSettled(\n slots.map(async (slot) => {\n let url: string | null = null;\n\n // 1. Pexels first (free)\n if (opts.pexelsApiKey) {\n const img = await searchImage(slot.query, opts.pexelsApiKey).catch(() => null);\n url = img?.url || null;\n }\n\n // 2. DALL-E fallback if Pexels found nothing\n if (!url && opts.openaiApiKey) {\n try {\n const tempUrl = await generateImage(slot.query, opts.openaiApiKey);\n url = opts.persistImage\n ? await opts.persistImage(tempUrl, slot.query)\n : tempUrl;\n } catch (e) {\n console.warn(`[dalle] failed for \"${slot.query}\":`, e);\n }\n }\n\n // 3. Placeholder fallback\n url ??= `https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(slot.query.slice(0, 30))}`;\n\n return { slot, url };\n })\n );\n\n let result = html;\n for (const r of resolved) {\n if (r.status === \"fulfilled\" && r.value) {\n const { slot, url } = r.value;\n const replacement = slot.replaceStr.replace(\"{url}\", url);\n result = result.replaceAll(slot.searchStr, replacement);\n }\n }\n\n // Catch any remaining <img> tags without src\n result = result.replace(/<img\\s(?![^>]*\\bsrc=)([^>]*?)>/gi, (_match, attrs) => {\n const altMatch = attrs.match(/alt=\"([^\"]*?)\"/);\n const query = altMatch?.[1] || \"professional image\";\n return `<img src=\"https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(query.slice(0, 30))}\" ${attrs}>`;\n });\n\n return result;\n}\n","import { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { generateText } from \"ai\";\nimport { currentDateLine } from \"../streamCore\";\n\nconst SVG_SYSTEM_PROMPT = `You are a professional SVG designer. Generate clean, compact SVG graphics for documents.\n\nSTRICT SIZE RULES:\n- ALWAYS use viewBox=\"0 0 600 300\" (2:1 ratio) — no exceptions\n- ALWAYS set width=\"100%\" height=\"auto\" — NEVER use fixed pixel width/height\n- NO internal padding or margins — content fills the viewBox edge-to-edge (leave only 10-20px padding)\n- Keep SVGs under 2KB — simplicity is key\n\nSTYLE RULES:\n- Output ONLY the <svg>...</svg> tag — no markdown, no explanation\n- Flat design: solid fills, no drop shadows, minimal gradients (max 1-2)\n- Max 8-10 elements total — prefer fewer, larger shapes over many small ones\n- Color palette: use the provided theme colors, or defaults (#6366f1, #8b5cf6, #ec4899, #14b8a6, #f59e0b)\n- Text: font-family=\"system-ui, sans-serif\", font-size 12-16px, max 5 text labels\n- Self-contained: no external references, all styles inline\n\nCHART TYPES:\n- Bar charts (vertical/horizontal) — max 6 bars, rounded caps\n- Pie/donut charts — max 5 segments\n- Line charts — smooth paths, max 8 data points\n- Progress/gauge charts\n- Simple comparison charts\n- Stat cards with visual elements\n\nAVOID: complex illustrations, many small elements, decorative borders, nested groups deeper than 2 levels.`;\n\n\nexport async function generateSvg(\n prompt: string,\n anthropicApiKey?: string,\n options?: { width?: number; height?: number; themeColors?: string }\n): Promise<string> {\n const apiKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n const anthropic = createAnthropic({ apiKey: apiKey || undefined });\n\n const sizeHint = options?.width && options?.height\n ? ` Target dimensions: ${options.width}x${options.height}px.`\n : \"\";\n const colorHint = options?.themeColors\n ? ` Use these theme colors: ${options.themeColors}.`\n : \"\";\n\n const result = await generateText({\n model: anthropic(\"claude-haiku-4-5-20251001\"),\n system: SVG_SYSTEM_PROMPT + currentDateLine(),\n messages: [\n {\n role: \"user\",\n content: `Generate an SVG for: ${prompt}${sizeHint}${colorHint}`,\n },\n ],\n maxOutputTokens: 2000,\n });\n\n // Extract just the SVG tag\n const svgMatch = result.text.match(/<svg[\\s\\S]*<\\/svg>/i);\n if (!svgMatch) {\n throw new Error(\"SVG generation failed — no <svg> tag in response\");\n }\n\n return svgMatch[0];\n}\n","import { streamText } from \"ai\";\nimport { createAnthropic } from \"@ai-sdk/anthropic\";\nimport { nanoid } from \"nanoid\";\nimport { findImageSlots } from \"./images/enrichImages\";\nimport { searchImage } from \"./images/pexels\";\nimport { generateImage } from \"./images/dalleImages\";\nimport { generateSvg } from \"./images/svgGenerator\";\nimport type { Section3 } from \"./types\";\nimport { sanitizeSemanticColors } from \"./sanitizeColors\";\n\nexport function currentDateLine(): string {\n return `\\nToday's date is ${new Date().toISOString().split(\"T\")[0]}. Use this for any date references.\\n`;\n}\n\n/**\n * Resolve AI model from available keys.\n * If modelId is already a LanguageModel object, return it directly.\n * Prefers Anthropic, falls back to OpenAI.\n */\nfunction isOpenAiModel(id: string): boolean {\n return /^(gpt-|o[1-9]|dall-e|tts-|whisper|chatgpt-)/.test(id);\n}\n\nfunction isLanguageModel(value: unknown): value is import(\"ai\").LanguageModel {\n return typeof value === \"object\" && value !== null && \"modelId\" in value && \"provider\" in value;\n}\n\nexport async function resolveModel(opts: {\n openaiApiKey?: string;\n anthropicApiKey?: string;\n modelId?: string | import(\"ai\").LanguageModel;\n defaultOpenai: string;\n defaultAnthropic: string;\n}) {\n // If modelId is already a model object, return it directly\n if (opts.modelId && isLanguageModel(opts.modelId)) {\n return opts.modelId;\n }\n\n const modelId = opts.modelId as string | undefined;\n\n if (modelId && isOpenAiModel(modelId)) {\n const openaiKey = opts.openaiApiKey || process.env.OPENAI_API_KEY;\n if (openaiKey) {\n const { createOpenAI } = await import(\"@ai-sdk/openai\");\n return createOpenAI({ apiKey: openaiKey })(modelId);\n }\n // OpenAI model requested but no key — fall through to Anthropic default\n } else if (modelId) {\n const anthropicKey = opts.anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n if (anthropicKey) {\n return createAnthropic({ apiKey: anthropicKey })(modelId);\n }\n }\n // No explicit modelId — prefer Anthropic, fallback to OpenAI\n const anthropicKey = opts.anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n if (anthropicKey) {\n return createAnthropic({ apiKey: anthropicKey })(opts.defaultAnthropic);\n }\n const openaiKey = opts.openaiApiKey || process.env.OPENAI_API_KEY;\n if (openaiKey) {\n const { createOpenAI } = await import(\"@ai-sdk/openai\");\n return createOpenAI({ apiKey: openaiKey })(opts.defaultOpenai);\n }\n return createAnthropic()(opts.defaultAnthropic);\n}\n\n/**\n * Convert data URL to Uint8Array for AI SDK vision.\n */\nexport function dataUrlToImagePart(dataUrl: string): { image: Uint8Array; mimeType: string } | null {\n const match = dataUrl.match(/^data:([^;]+);base64,(.+)$/);\n if (!match) return null;\n return {\n image: new Uint8Array(Buffer.from(match[2], \"base64\")),\n mimeType: match[1],\n };\n}\n\n/**\n * Extract complete JSON objects from accumulated text using brace-depth tracking.\n */\nexport function extractJsonObjects(text: string): [any[], string] {\n const objects: any[] = [];\n let remaining = text;\n\n while (remaining.length > 0) {\n remaining = remaining.trimStart();\n if (!remaining.startsWith(\"{\")) {\n const nextBrace = remaining.indexOf(\"{\");\n if (nextBrace === -1) break;\n remaining = remaining.slice(nextBrace);\n continue;\n }\n\n let depth = 0;\n let inString = false;\n let escape = false;\n let end = -1;\n\n for (let i = 0; i < remaining.length; i++) {\n const ch = remaining[i];\n if (escape) { escape = false; continue; }\n if (ch === \"\\\\\") { escape = true; continue; }\n if (ch === '\"') { inString = !inString; continue; }\n if (inString) continue;\n if (ch === \"{\") depth++;\n if (ch === \"}\") { depth--; if (depth === 0) { end = i; break; } }\n }\n\n if (end === -1) break;\n\n const candidate = remaining.slice(0, end + 1);\n remaining = remaining.slice(end + 1);\n\n try {\n objects.push(JSON.parse(candidate));\n } catch {\n // malformed, skip\n }\n }\n\n return [objects, remaining];\n}\n\n/** Inline shimmer SVG used as src for loading image placeholders */\nconst LOADING_PLACEHOLDER_SRC = `data:image/svg+xml,${encodeURIComponent('<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"800\" height=\"500\" viewBox=\"0 0 800 500\"><rect fill=\"#f3f4f6\" width=\"800\" height=\"500\" rx=\"12\"/><g opacity=\".4\"><rect x=\"320\" y=\"200\" width=\"160\" height=\"4\" rx=\"2\" fill=\"#d1d5db\"><animate attributeName=\"opacity\" values=\".3;.8;.3\" dur=\"1.5s\" repeatCount=\"indefinite\"/></rect><rect x=\"280\" y=\"215\" width=\"240\" height=\"4\" rx=\"2\" fill=\"#d1d5db\"><animate attributeName=\"opacity\" values=\".3;.8;.3\" dur=\"1.5s\" begin=\".3s\" repeatCount=\"indefinite\"/></rect><rect x=\"340\" y=\"230\" width=\"120\" height=\"4\" rx=\"2\" fill=\"#d1d5db\"><animate attributeName=\"opacity\" values=\".3;.8;.3\" dur=\"1.5s\" begin=\".6s\" repeatCount=\"indefinite\"/></rect></g><g transform=\"translate(376,150)\" opacity=\".3\"><path d=\"M0 28V4a4 4 0 014-4h40a4 4 0 014 4v24a4 4 0 01-4 4H4a4 4 0 01-4-4z\" fill=\"#d1d5db\"/><circle cx=\"14\" cy=\"12\" r=\"4\" fill=\"#9ca3af\"/><path d=\"M4 28l10-10 6 6 8-8 16 16H4z\" fill=\"#9ca3af\" opacity=\".5\"/></g></svg>')}`;\n\n/** Inline SVG placeholder for loading charts */\nconst SVG_LOADING_PLACEHOLDER = `<div class=\"w-full h-48 bg-gray-50 rounded-lg flex items-center justify-center animate-pulse\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#9ca3af\" stroke-width=\"1.5\"><rect x=\"3\" y=\"12\" width=\"4\" height=\"9\" rx=\"1\"/><rect x=\"10\" y=\"7\" width=\"4\" height=\"14\" rx=\"1\"/><rect x=\"17\" y=\"3\" width=\"4\" height=\"18\" rx=\"1\"/></svg></div>`;\n\n/** Replace data-svg-chart divs with loading placeholders */\nexport function addSvgLoadingPlaceholders(html: string): string {\n return html.replace(\n /<div\\s([^>]*?)data-svg-chart=\"([^\"]+)\"([^>]*?)>[\\s\\S]*?<\\/div>/gi,\n (_match, before, chart, after) => {\n return `<div ${before}data-svg-chart=\"${chart}\"${after}>${SVG_LOADING_PLACEHOLDER}</div>`;\n }\n );\n}\n\n/** Replace data-image-query attrs with animated loading placeholders */\nexport function addLoadingPlaceholders(html: string): string {\n return html.replace(\n /(<img\\s[^>]*)data-image-query=\"([^\"]+)\"([^>]*?)(?:\\s*\\/?>)/gi,\n (_match, before, query, after) => {\n if (before.includes('src=') || after.includes('src=')) return _match;\n return `${before}src=\"${LOADING_PLACEHOLDER_SRC}\" data-image-query=\"${query}\" alt=\"${query}\"${after}>`;\n }\n );\n}\n\n/** Enrich a section's images (Pexels → DALL-E → placeholder fallback). Mutates section.html in place. */\nexport async function enrichSectionImages(\n section: Section3,\n opts: {\n pexelsApiKey?: string;\n openaiApiKey?: string;\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n onImageUpdate?: (sectionId: string, html: string) => void;\n }\n): Promise<void> {\n const slots = findImageSlots(section.html);\n if (slots.length === 0) return;\n const results = await Promise.allSettled(\n slots.map(async (slot) => {\n let url: string | null = null;\n if (opts.pexelsApiKey) {\n const img = await searchImage(slot.query, opts.pexelsApiKey).catch(() => null);\n url = img?.url || null;\n }\n if (!url && opts.openaiApiKey) {\n try {\n const tempUrl = await generateImage(slot.query, opts.openaiApiKey);\n url = opts.persistImage ? await opts.persistImage(tempUrl, slot.query) : tempUrl;\n } catch (e) {\n console.warn(`[dalle] failed for \"${slot.query}\":`, e);\n }\n }\n url ??= `https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(slot.query.slice(0, 30))}`;\n return { slot, url };\n })\n );\n let html = section.html;\n for (const r of results) {\n if (r.status === \"fulfilled\" && r.value) {\n const { slot, url } = r.value;\n const replacement = slot.replaceStr.replace(\"{url}\", url);\n html = html.replaceAll(slot.searchStr, replacement);\n }\n }\n if (html !== section.html) {\n section.html = html;\n opts.onImageUpdate?.(section.id, html);\n }\n}\n\n/** Enrich a section's SVG chart placeholders. Mutates section.html in place. */\nexport async function enrichSectionSvgCharts(\n section: Section3,\n opts: {\n anthropicApiKey?: string;\n onImageUpdate?: (sectionId: string, html: string) => void;\n }\n): Promise<void> {\n const svgRegex = /<div\\s[^>]*data-svg-chart=\"([^\"]+)\"[^>]*>[\\s\\S]*?<\\/div>/gi;\n const svgMatches: { fullMatch: string; prompt: string }[] = [];\n let svgM: RegExpExecArray | null;\n while ((svgM = svgRegex.exec(section.html)) !== null) {\n svgMatches.push({ fullMatch: svgM[0], prompt: svgM[1] });\n }\n if (svgMatches.length === 0) return;\n const anthropicKey = opts.anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n const results = await Promise.allSettled(\n svgMatches.map(async ({ fullMatch, prompt }) => {\n try {\n const svg = await generateSvg(prompt, anthropicKey);\n return { fullMatch, svg };\n } catch (e) {\n console.warn(`[svg] failed for \"${prompt}\":`, e);\n return { fullMatch, svg: `<div class=\"w-full h-48 bg-gray-100 rounded-lg flex items-center justify-center text-gray-400 text-sm\">${prompt}</div>` };\n }\n })\n );\n let html = section.html;\n for (const r of results) {\n if (r.status === \"fulfilled\" && r.value) {\n html = html.replace(r.value.fullMatch, r.value.svg);\n }\n }\n if (html !== section.html) {\n section.html = html;\n opts.onImageUpdate?.(section.id, html);\n }\n}\n\nexport interface StreamGenerateOptions {\n /** Anthropic API key */\n anthropicApiKey?: string;\n /** OpenAI API key */\n openaiApiKey?: string;\n /** Model ID override or pre-built LanguageModel object */\n model?: string | import(\"ai\").LanguageModel;\n /** System prompt */\n systemPrompt: string;\n /** User message content (text or multimodal parts) */\n userContent: any[];\n /** Pexels API key for image enrichment */\n pexelsApiKey?: string;\n /** Persist DALL-E images to permanent storage */\n persistImage?: (tempUrl: string, query: string) => Promise<string>;\n /** Called when a new section is parsed */\n onSection?: (section: Section3) => void;\n /** Called when a section's images are enriched */\n onImageUpdate?: (sectionId: string, html: string) => void;\n /** Called with raw text buffer for real-time partial streaming */\n onRawChunk?: (buffer: string, completedCount: number) => void;\n /** Called when generation is complete */\n onDone?: (sections: Section3[]) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n}\n\n/**\n * Core streaming generation: stream AI text → parse NDJSON → emit sections → enrich images.\n * Used by both generateLanding and generateDocument.\n */\nexport async function streamGenerate(options: StreamGenerateOptions): Promise<Section3[]> {\n const {\n anthropicApiKey,\n openaiApiKey: _openaiApiKey,\n model: modelId,\n systemPrompt,\n userContent,\n pexelsApiKey,\n persistImage,\n onSection,\n onImageUpdate,\n onRawChunk,\n onDone,\n onError,\n } = options;\n\n const openaiApiKey = _openaiApiKey || process.env.OPENAI_API_KEY;\n const model = await resolveModel({\n openaiApiKey,\n anthropicApiKey,\n modelId,\n defaultOpenai: \"gpt-4o\",\n defaultAnthropic: \"claude-sonnet-4-6\",\n });\n\n const result = streamText({\n model,\n system: systemPrompt + currentDateLine(),\n messages: [{ role: \"user\", content: userContent }],\n });\n\n const allSections: Section3[] = [];\n const imagePromises: Promise<void>[] = [];\n let sectionOrder = 0;\n let buffer = \"\";\n\n function enrichSvgCharts(sectionRef: Section3) {\n const svgRegex = /<div\\s[^>]*data-svg-chart=\"([^\"]+)\"[^>]*>[\\s\\S]*?<\\/div>/gi;\n const svgMatches: { fullMatch: string; prompt: string }[] = [];\n let svgM: RegExpExecArray | null;\n while ((svgM = svgRegex.exec(sectionRef.html)) !== null) {\n svgMatches.push({ fullMatch: svgM[0], prompt: svgM[1] });\n }\n if (svgMatches.length === 0) return;\n\n const anthropicKey = anthropicApiKey || process.env.ANTHROPIC_API_KEY;\n imagePromises.push(\n (async () => {\n const results = await Promise.allSettled(\n svgMatches.map(async ({ fullMatch, prompt }) => {\n try {\n const svg = await generateSvg(prompt, anthropicKey);\n return { fullMatch, svg };\n } catch (e) {\n console.warn(`[svg] failed for \"${prompt}\":`, e);\n return { fullMatch, svg: `<div class=\"w-full h-48 bg-gray-100 rounded-lg flex items-center justify-center text-gray-400 text-sm\">${prompt}</div>` };\n }\n })\n );\n let html = sectionRef.html;\n for (const r of results) {\n if (r.status === \"fulfilled\" && r.value) {\n html = html.replace(r.value.fullMatch, r.value.svg);\n }\n }\n if (html !== sectionRef.html) {\n sectionRef.html = html;\n onImageUpdate?.(sectionRef.id, html);\n }\n })()\n );\n }\n\n function enrichSection(sectionRef: Section3) {\n const slots = findImageSlots(sectionRef.html);\n if (slots.length === 0) return;\n const slotsSnapshot = slots.map((s) => ({ ...s }));\n imagePromises.push(\n (async () => {\n const results = await Promise.allSettled(\n slotsSnapshot.map(async (slot) => {\n let url: string | null = null;\n // 1. Pexels first (free, fast)\n if (pexelsApiKey) {\n const img = await searchImage(slot.query, pexelsApiKey).catch(() => null);\n url = img?.url || null;\n }\n // 2. DALL-E fallback\n if (!url && openaiApiKey) {\n try {\n const tempUrl = await generateImage(slot.query, openaiApiKey);\n url = persistImage ? await persistImage(tempUrl, slot.query) : tempUrl;\n } catch (e) {\n console.warn(`[dalle] failed for \"${slot.query}\":`, e);\n }\n }\n url ??= `https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(slot.query.slice(0, 30))}`;\n return { slot, url };\n })\n );\n let html = sectionRef.html;\n for (const r of results) {\n if (r.status === \"fulfilled\" && r.value) {\n const { slot, url } = r.value;\n const replacement = slot.replaceStr.replace(\"{url}\", url);\n html = html.replaceAll(slot.searchStr, replacement);\n }\n }\n if (html !== sectionRef.html) {\n sectionRef.html = html;\n onImageUpdate?.(sectionRef.id, html);\n }\n })()\n );\n }\n\n function processObject(obj: any) {\n if (!obj.html || !obj.label) return;\n const section: Section3 = {\n id: nanoid(8),\n order: sectionOrder++,\n html: sanitizeSemanticColors(addSvgLoadingPlaceholders(addLoadingPlaceholders(obj.html))),\n label: obj.label,\n };\n allSections.push(section);\n onSection?.(section);\n enrichSection(section);\n enrichSvgCharts(section);\n }\n\n try {\n let chunkCount = 0;\n for await (const chunk of result.textStream) {\n buffer += chunk;\n chunkCount++;\n\n const [objects, remaining] = extractJsonObjects(buffer);\n buffer = remaining;\n for (const obj of objects) {\n chunkCount = 0;\n processObject(obj);\n }\n\n if (onRawChunk && chunkCount % 5 === 0 && buffer.length > 20) {\n onRawChunk(buffer, allSections.length);\n }\n }\n\n // Parse remaining buffer\n if (buffer.trim()) {\n let cleaned = buffer.trim();\n if (cleaned.startsWith(\"```\")) {\n cleaned = cleaned.replace(/^```(?:json)?\\s*/, \"\").replace(/\\s*```$/, \"\");\n }\n const [lastObjects] = extractJsonObjects(cleaned);\n for (const obj of lastObjects) processObject(obj);\n }\n\n // Wait for image enrichment\n await Promise.allSettled(imagePromises);\n\n // Final fallback for images without src\n for (const section of allSections) {\n const before = section.html;\n section.html = section.html.replace(\n /<img\\s(?![^>]*\\bsrc=)([^>]*?)>/gi,\n (_match, attrs) => {\n const altMatch = attrs.match(/alt=\"([^\"]*?)\"/);\n const query = altMatch?.[1] || \"image\";\n return `<img src=\"https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(query.slice(0, 30))}\" ${attrs}>`;\n }\n );\n section.html = section.html.replace(\n /data-image-query=\"([^\"]+)\"/g,\n (_match, query) => {\n return `src=\"https://placehold.co/800x500/1f2937/9ca3af?text=${encodeURIComponent(query.slice(0, 30))}\" data-enriched=\"placeholder\"`;\n }\n );\n if (section.html !== before) {\n onImageUpdate?.(section.id, section.html);\n }\n }\n\n onDone?.(allSections);\n return allSections;\n } catch (err: any) {\n const error = err instanceof Error ? err : new Error(err?.message || \"Generation failed\");\n onError?.(error);\n throw error;\n }\n}\n","/**\n * Replace hardcoded Tailwind color classes with semantic color classes\n * (bg-primary, text-primary, etc.). Gray/white/black/slate/zinc/neutral stay intact.\n *\n * Covers ALL chromatic Tailwind colors the model might generate.\n */\n\n// All chromatic colors Tailwind ships (excluding neutrals: slate, gray, zinc, neutral, stone)\nconst COLORS =\n \"red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose\";\n\nfunction re(prefix: string, shades: string): RegExp {\n return new RegExp(`\\\\b${prefix}-(${COLORS})-(${shades})\\\\b`, \"g\");\n}\n\nconst replacements: [RegExp, string][] = [\n // Background\n [re(\"bg\", \"500|600|700\"), \"bg-primary\"],\n [re(\"bg\", \"50|100\"), \"bg-primary-light\"],\n [re(\"bg\", \"800|900|950\"), \"bg-primary-dark\"],\n [re(\"bg\", \"200|300|400\"), \"bg-primary\"],\n\n // Text\n [re(\"text\", \"500|600|700\"), \"text-primary\"],\n [re(\"text\", \"800|900|950\"), \"text-primary-dark\"],\n [re(\"text\", \"50|100|200|300\"), \"text-on-primary\"],\n [re(\"text\", \"400\"), \"text-primary\"],\n\n // Border\n [re(\"border\", \"\\\\d{2,3}\"), \"border-primary\"],\n\n // Ring\n [re(\"ring\", \"\\\\d{2,3}\"), \"ring-primary\"],\n\n // Gradients\n [re(\"from\", \"\\\\d{2,3}\"), \"from-primary\"],\n [re(\"to\", \"\\\\d{2,3}\"), \"to-primary\"],\n [re(\"via\", \"\\\\d{2,3}\"), \"via-primary\"],\n\n // Hover/focus variants\n [new RegExp(`\\\\bhover:bg-(${COLORS})-(500|600|700|800|900|950)\\\\b`, \"g\"), \"hover:bg-primary-dark\"],\n [new RegExp(`\\\\bhover:bg-(${COLORS})-(50|100|200|300|400)\\\\b`, \"g\"), \"hover:bg-primary-light\"],\n [new RegExp(`\\\\bhover:text-(${COLORS})-\\\\d{2,3}\\\\b`, \"g\"), \"hover:text-primary\"],\n [new RegExp(`\\\\bfocus:ring-(${COLORS})-\\\\d{2,3}\\\\b`, \"g\"), \"focus:ring-primary\"],\n [new RegExp(`\\\\bfocus:border-(${COLORS})-\\\\d{2,3}\\\\b`, \"g\"), \"focus:border-primary\"],\n\n // Divide\n [re(\"divide\", \"\\\\d{2,3}\"), \"divide-primary\"],\n\n // Placeholder\n [re(\"placeholder\", \"\\\\d{2,3}\"), \"placeholder-primary\"],\n\n // Outline\n [re(\"outline\", \"\\\\d{2,3}\"), \"outline-primary\"],\n\n // Shadow colored\n [re(\"shadow\", \"\\\\d{2,3}\"), \"shadow-primary\"],\n\n // Decoration\n [re(\"decoration\", \"\\\\d{2,3}\"), \"decoration-primary\"],\n\n // Accent\n [re(\"accent\", \"\\\\d{2,3}\"), \"accent-primary\"],\n];\n\nexport function sanitizeSemanticColors(html: string): string {\n let result = html;\n for (const [pattern, replacement] of replacements) {\n result = result.replace(pattern, replacement);\n }\n return result;\n}\n"],"mappings":"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","names":["createAnthropic","openaiKey","anthropicKey","createAnthropic"]}