PageSourceSearch

https://www.hamienet.com/assets/GraphicManager-BL-ujHp_.js

js hamienet.com collected 2026-10-02 05:01:45 UTC 103,318 bytes, 1,664 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js";
2import { a as api } from "./index-w5lXls15.js";
3import { p as getPlaceholderUrl } from "./utils-CEVb7nN1.js";
4import { b as getGeminiAI, c as getAiImageModel } from "./ai-B0Mlroaa.js";
5import { D as DevDebugInfo } from "./AdminShared-BP_vxG_A.js";
6import { bi as Sparkles, cf as Plus, c_ as ChevronLeft, bF as ChevronRight, f0 as PenLine, b5 as Trash2, aW as X, d9 as Image, b2 as Upload, b6 as LoaderCircle, aY as TriangleAlert, dM as Move, ds as ZoomOut, dt as ZoomIn, b7 as Check, cw as LayoutGrid, dO as Calendar, bb as User, bD as FlaskConical, bW as RefreshCcw, a_ as CircleCheck, fZ as Package, bQ as House, bP as Compass, bO as Library, bN as History, bB as ListMusic, bM as Clock, bL as ThumbsUp, b9 as Settings, be as Menu, bf as Search, bT as Mic, bh as Bell, cd as Save } from "./vendor-D0P4XgNj.js";
7import { D as DEFAULT_TOOLS, a as DEFAULT_BRAND_SVG, H as HamieLogo } from "./labTools-HX5HYAPB.js";
8import "./vendor-i18n-BC7ZMXWQ.js";
9import "./vendor-ai-gQv1oOjO.js";
10const LogoScheduler = () => {
11  const [schedules, setSchedules] = reactExports.useState([]);
12  const [currentDate, setCurrentDate] = reactExports.useState(/* @__PURE__ */ new Date());
13  const [isModalOpen, setIsModalOpen] = reactExports.useState(false);
14  const [isSuggestModalOpen, setIsSuggestModalOpen] = reactExports.useState(false);
15  const [editingId, setEditingId] = reactExports.useState(null);
16  const [formData, setFormData] = reactExports.useState({
17    themeName: "",
18    startDate: "",
19    endDate: "",
20    imageUrl: "",
21    isRecurring: false,
22    priority: 0,
23    aiPrompt: "",
24    aiModel: ""
25  });
26  const [aiPrompt, setAiPrompt] = reactExports.useState("");
27  const [generating, setGenerating] = reactExports.useState(false);
28  const [suggestions, setSuggestions] = reactExports.useState([]);
29  const [suggesting, setSuggesting] = reactExports.useState(false);
30  const [suggestionError, setSuggestionError] = reactExports.useState(null);
31  reactExports.useEffect(() => {
32    fetchSchedules();
33  }, []);
34  const fetchSchedules = async () => {
35    try {
36      const res = await fetch("/api/logo/schedules");
37      if (res.ok) {
38        const data = await res.json();
39        setSchedules(data);
40      }
41    } catch {
42    }
43  };
44  const handleSave = async () => {
45    try {
46      const url = editingId ? `/api/logo/schedules/${editingId}` : "/api/logo/schedules";
47      const method = editingId ? "PUT" : "POST";
48      const res = await fetch(url, {
49        method,
50        headers: { "Content-Type": "application/json" },
51        body: JSON.stringify(formData)
52      });
53      if (res.ok) {
54        setIsModalOpen(false);
55        fetchSchedules();
56        resetForm();
57      }
58    } catch {
59      alert("Failed to save schedule");
60    }
61  };
62  const handleDelete = async (id) => {
63    if (!confirm("Are you sure?")) return;
64    try {
65      await fetch(`/api/logo/schedules/${id}`, { method: "DELETE" });
66      fetchSchedules();
67    } catch {
68      alert("Failed to delete");
69    }
70  };
71  const handleUpload = async (e) => {
72    var _a;
73    const file = (_a = e.target.files) == null ? void 0 : _a[0];
74    if (!file) return;
75    const data = new FormData();
76    data.append("image", file);
77    try {
78      const res = await fetch("/api/logo/upload", {
79        method: "POST",
80        body: data
81      });
82      if (res.ok) {
83        const { url } = await res.json();
84        setFormData({ ...formData, imageUrl: url, aiPrompt: "", aiModel: "" });
85      }
86    } catch {
87      alert("Upload failed");
88    }
89  };
90  const handleGenerate = async () => {
91    if (!aiPrompt) return;
92    setGenerating(true);
93    try {
94      const res = await fetch("/api/logo/generate", {
95        method: "POST",
96        headers: { "Content-Type": "application/json" },
97        body: JSON.stringify({ prompt: aiPrompt })
98      });
99      if (res.ok) {
100        const { url, model } = await res.json();
101        setFormData({ ...formData, imageUrl: url, aiPrompt, aiModel: model });
102      } else {
103        alert("Generation failed");
104      }
105    } catch {
106      alert("Generation error");
107    } finally {
108      setGenerating(false);
109    }
110  };
111  const handleSuggest = async () => {
112    setSuggesting(true);
113    setSuggestionError(null);
114    try {
115      const res = await fetch("/api/logo/suggest", {
116        method: "POST",
117        headers: { "Content-Type": "application/json" },
118        body: JSON.stringify({ context: `Month: ${currentDate.toLocaleStr
118ing("default", { month: "long" })}` })
119      });
120      if (res.ok) {
121        const data = await res.json();
122        setSuggestions(data);
123        if (!data || data.length === 0) {
124          setSuggestionError("No suggestions found for the current period.");
125        }
126      } else {
127        const errData = await res.json().catch(() => ({}));
128        throw new Error(errData.error || "Failed to fetch suggestions");
129      }
130    } catch (error) {
131      console.error("Failed to get suggestions:", error);
132      setSuggestionError(error.message || "An unexpected error occurred while fetching suggestions.");
133      api.logError(error, "LogoScheduler:handleSuggest");
134    } finally {
135      setSuggesting(false);
136    }
137  };
138  const resetForm = () => {
139    setEditingId(null);
140    setFormData({
141      themeName: "",
142      startDate: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
143      endDate: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
144      imageUrl: "",
145      isRecurring: false,
146      priority: 0,
147      aiPrompt: "",
148      aiModel: ""
149    });
150    setAiPrompt("");
151  };
152  const openModal = (schedule) => {
153    if (schedule) {
154      setEditingId(schedule.id);
155      setFormData({
156        themeName: schedule.themeName,
157        startDate: new Date(schedule.startDate).toISOString().split("T")[0],
158        endDate: new Date(schedule.endDate).toISOString().split("T")[0],
159        imageUrl: schedule.imageUrl,
160        isRecurring: schedule.isRecurring,
161        priority: schedule.priority,
162        aiPrompt: schedule.aiPrompt || "",
163        aiModel: schedule.aiModel || ""
164      });
165    } else {
166      resetForm();
167    }
168    setIsModalOpen(true);
169  };
170  const getDaysInMonth = (date) => {
171    const year = date.getFullYear();
172    const month = date.getMonth();
173    const days2 = new Date(year, month + 1, 0).getDate();
174    const firstDay2 = new Date(year, month, 1).getDay();
175    return { days: days2, firstDay: firstDay2 };
176  };
177  const { days, firstDay } = getDaysInMonth(currentDate);
178  const monthName = currentDate.toLocaleString("default", { month: "long", year: "numeric" });
179  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full space-y-6", children: [
180    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [
181      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
182        /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: "Logo Scheduler" }),
183        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500", children: "Manage dynamic logo changes based on dates. Ideal size: 400x100px (approx 4:1 aspect ratio)." })
184      ] }),
185      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
186        /* @__PURE__ */ jsxRuntimeExports.jsxs(
187          "button",
188          {
189            onClick: () => {
190              setIsSuggestModalOpen(true);
191              handleSuggest();
192            },
193            className: "flex items-center gap-2 px-4 py-2 bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 rounded-lg font-bold text-sm hover:bg-indigo-200 dark:hover:bg-indigo-800 transition-colors",
194            children: [
195              /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 16 }),
196              " Suggest Themes"
197            ]
198          }
199        ),
200        /* @__PURE__ */ jsxRuntimeExports.jsxs(
201          "button",
202          {
203            onClick: () => openModal(),
204            className: "flex items-center gap-2 px-4 py-2 bg-zinc-900 dark:bg-white text-white dark:text-black rounded-lg font-bold text-sm hover:opacity-90 transition-opacity",
205            children: [
206              /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 16 }),
207              " Add Schedule"
208            ]
209          }
210        )
211      ] })
212    ] }),
213    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col lg:flex-row gap-6 h-full overflow-hidden", children: [
214      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm flex flex-col", children: [
215        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-6", children: [
216          /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-lg", children: monthName }),
217          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
218            /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setCurrentDate((prev) => new Date(prev.getFullYear(), prev.getMonth() - 1, 1)), className: "p-2 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-lg", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronLeft, { size: 20 }) }),
219            /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setCurrentDate((prev) => new Date(prev.getFullYear(), prev.getMonth() + 1, 1)), className: "p-2 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-lg", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronRight, { size: 20 }) })
220          ] })
221        ] }),
222        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-7 gap-px bg-zinc-200 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-800 rounded-lg overflow-hidden flex-1", children: [
223          ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].map((day) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-zinc-50 dark:bg-zinc-900 p-2 text-center text-xs font-bold text-zinc-500 uppercase", children: day }, day)),
224          Array.from({ length: firstDay }).map((_, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-white dark:bg-zinc-900 min-h-[80px]" }, `empty-${i}`)),
225          Array.from({ length: days }).map((_, i) => {
226            const day = i + 1;
227            const dateStr = new Date(currentDate.getFullYear(), currentDate.getMonth(), day).toISOString().split("T")[0];
228            const daySchedules = schedules.filter((s) => {
229              const start = new Date(s.startDate).toISOString().split("T")[0];
230              const end = new Date(s.endDate).toISOString().split("T")[0];
231              return dateStr >= start && dateStr <= end;
232            });
233            return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 p-2 min-h-[80px] border-t border-zinc-100 dark:border-zinc-800/50 relative group hover:bg-zinc-50 dark:hover:bg-zinc-800/50 transition-colors", children: [
234              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-sm font-bold ${daySchedules.length > 0 ? "text-indigo-600 dark:text-indigo-400" : "text-zinc-400"}`, children: day }),
235              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-1 space-y-1", children: daySchedules.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsx(
236                "div",
237                {
238                  onClick: () => openModal(s),
239                  className: "text-[10px] bg-indigo-50 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 px-1.5 py-0.5 rounded truncate cursor-pointer hover:bg-indigo-100 dark:hover:bg-indigo-900/50",
240                  title: s.themeName,
241                  children: s.themeName
242                },
243                s.id
244              )) })
245            ] }, day);
246          })
247        ] })
248      ] }),
249      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full lg:w-80 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-4 shadow-sm overflow-y-auto", children: [
250        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-sm uppercase text-zinc-500 mb-4", children: "Upcoming Events" }),
251        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
252          schedules.sort((a, b) => new Date(a.startDate).getTime() - new Date(b.startDate).getTime()).map((s) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 p-3 bg-zinc-50 dark:bg-zinc-950/50 rounded-lg border border-zinc-100 dark:border-zinc-800 group", children: [
253            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 bg-white dark:bg-zinc-900 rounded border border-zinc-200 dark:border-zinc-800 flex items-center justify-center overflow-hidden shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: s.imageUrl, className: "w-full h-full object-contain", referrerPolicy: "no-referrer" }) }),
254            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
255              /* @__P
255URE__ */ jsxRuntimeExports.jsx("div", { className: "font-bold text-sm truncate text-zinc-900 dark:text-white", children: s.themeName }),
256              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-500", children: [
257                new Date(s.startDate).toLocaleDateString(void 0, { month: "short", day: "numeric" }),
258                s.isRecurring && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-1 text-indigo-500", children: "(Recurring)" })
259              ] })
260            ] }),
261            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity", children: [
262              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => openModal(s), className: "p-1.5 hover:bg-zinc-200 dark:hover:bg-zinc-800 rounded text-zinc-500", children: /* @__PURE__ */ jsxRuntimeExports.jsx(PenLine, { size: 14 }) }),
263              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => handleDelete(s.id), className: "p-1.5 hover:bg-red-100 dark:hover:bg-red-900/30 rounded text-red-500", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 }) })
264            ] })
265          ] }, s.id)),
266          schedules.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-center text-zinc-400 text-sm py-4", children: "No upcoming schedules." })
267        ] })
268      ] })
269    ] }),
270    isModalOpen && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4", onClick: () => setIsModalOpen(false), children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 w-full max-w-2xl rounded-2xl shadow-2xl border border-zinc-200 dark:border-zinc-800 overflow-hidden flex flex-col max-h-[90vh]", onClick: (e) => e.stopPropagation(), children: [
271      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 border-b border-zinc-200 dark:border-zinc-800 flex justify-between items-center", children: [
272        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: editingId ? "Edit Schedule" : "New Schedule" }),
273        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setIsModalOpen(false), className: "p-2 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-full text-zinc-500 hover:text-zinc-900 dark:hover:text-white transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 24 }) })
274      ] }),
275      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-6 overflow-y-auto space-y-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-6", children: [
276        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
277          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
278            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold uppercase text-zinc-500 mb-1", children: "Theme Name" }),
279            /* @__PURE__ */ jsxRuntimeExports.jsx(
280              "input",
281              {
282                value: formData.themeName,
283                onChange: (e) => setFormData({ ...formData, themeName: e.target.value }),
284                className: "w-full bg-zinc-50 dark:bg-black border border-zinc-300 dark:border-zinc-700 rounded-lg p-2.5 text-sm outline-none focus:border-indigo-500",
285                placeholder: "e.g. Beethoven's Birthday"
286              }
287            )
288          ] }),
289          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
290            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
291              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold uppercase text-zinc-500 mb-1", children: "Start Date" }),
292              /* @__PURE__ */ jsxRuntimeExports.jsx(
293                "input",
294                {
295                  type: "date",
296                  value: formData.startDate,
297                  onChange: (e) => setFormData({ ...formData, startDate: e.target.value }),
298                  className: "w-full bg-zinc-50 dark:bg-black border border-zinc-300 dark:border-zinc-700 rounded-lg p-2.5 text-sm outline-none focus:border-indigo-500"
299                }
300              )
301            ] }),
302            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
303              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold uppercase text-zinc-500 mb-1", children: "End Date" }),
304              /* @__PURE__ */ jsxRuntimeExports.jsx(
305                "input",
306                {
307                  type: "date",
308                  value: formData.endDate,
309                  onChange: (e) => setFormData({ ...formData, endDate: e.target.value }),
310                  className: "w-full bg-zinc-50 dark:bg-black border border-zinc-300 dark:border-zinc-700 rounded-lg p-2.5 text-sm outline-none focus:border-indigo-500"
311                }
312              )
313            ] })
314          ] }),
315          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
316            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [
317              /* @__PURE__ */ jsxRuntimeExports.jsx(
318                "input",
319                {
320                  type: "checkbox",
321                  checked: formData.isRecurring,
322                  onChange: (e) => setFormData({ ...formData, isRecurring: e.target.checked }),
323                  className: "w-4 h-4 rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500"
324                }
325              ),
326              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium", children: "Recurring Yearly" })
327            ] }),
328            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
329              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold uppercase text-zinc-500 mb-1", children: "Priority" }),
330              /* @__PURE__ */ jsxRuntimeExports.jsx(
331                "input",
332                {
333                  type: "number",
334                  value: formData.priority,
335                  onChange: (e) => setFormData({ ...formData, priority: parseInt(e.target.value) }),
336                  className: "w-full bg-zinc-50 dark:bg-black border border-zinc-300 dark:border-zinc-700 rounded-lg p-2 text-sm outline-none focus:border-indigo-500"
337                }
338              )
339            ] })
340          ] })
341        ] }),
342        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
343          /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold uppercase text-zinc-500 mb-1", children: "Logo Image" }),
344          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full h-32 bg-zinc-100 dark:bg-zinc-950 border-2 border-dashed border-zinc-300 dark:border-zinc-700 rounded-xl flex items-center justify-center relative overflow-hidden group", children: [
345            formData.imageUrl ? /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: formData.imageUrl, className: "w-full h-full object-contain", referrerPolicy: "no-referrer" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center text-zinc-400", children: [
346              /* @__PURE__ */ jsxRuntimeExports.jsx(Image, { className: "mx-auto mb-2" }),
347              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "No Image Selected" })
348            ] }),
349            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-2", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "p-2 bg-white text-black rounded-lg cursor-pointer hover:bg-zinc-200", children: [
350              /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 16 }),
351              /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "file", className: "hidden", accept: "image/*", onChange: handleUpload })
352            ] }) })
353          ] }),
354          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "pt-4 border-t border-zinc-200 dark:border-zinc-800", children: [
355            /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold uppercase text-zinc-500 mb-2", children: "AI Generation" }),
356            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
357              /* @__PURE__ */ jsxRuntimeExports.jsx(
358                "input",
359                {
360                  value: aiPrompt,
361                  onChange: (e) => setAiPrompt(e.target.value),
362                  placeholder: "Describe logo (e.g. Jazz Saxophone)...",
363                  className: "flex-1 bg-zinc-50 dark:bg-black border border-zinc-300 dark:border-zinc-700 rounded-lg p-2 text-sm outline-none focus:border-indigo-500"
364                }
365              ),
366              /* @__PURE__ */ jsxRuntimeExports.jsx(
367                "button",
368                {
369                  onClick: handleGenerate,
370                  disabled: generating || !aiPrompt,
371                  className: "px-3 py-2 bg-indigo-600 text-white rounded-lg disabled:opacity-50",
372                  children: generating ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 18 })
373                }
374              )
375            ] })
376          ] })
377        ] })
378      ] }) }),
379      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 border-t border-zinc-200 dark:border-zinc-800 flex justify-end gap-3 bg-zinc-50 dark:bg-zinc-950/50", children: [
380        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setIsModalOpen(false), className: "px-4 py-2 text-zinc-500 font-bold hover:text-zinc-900 dark:hover:text-white transition-colors", children: "Cancel" }),
381        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleSave, className: "px-6 py-2 bg-indigo-600 hover:bg-indigo-700 text-white font-bold rounded-lg shadow-lg shadow-indigo-500/20 transition-all", children: "Save Schedule" })
382      ] })
383    ] }) }),
384    isSuggestModalOpen && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm p-4", onClick: () => setIsSuggestModalOpen(false), children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 w-full max-w-lg rounded-2xl shadow-2xl border border-zinc-200 dark:border-zinc-800 overflow-hidden flex flex-col max-h-[80vh]", onClick: (e) => e.stopPropagation(), children: [
385      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 border-b border-zinc-200 dark:border-zinc-800 flex justify-between items-center", children: [
386        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: "AI Theme Suggestions" }),
387        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setIsSuggestModalOpen(false), className: "p-2 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-full text-zinc-500 hover:text-zinc-900 dark:hover:text-white transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 24 }) })
388      ] }),
389      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-6 overflow-y-auto flex-1", children: suggesting ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-zinc-500", children: [
390        /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "animate-spin mb-4 text-indigo-500", size: 32 }),
391        /* @__P
391URE__ */ jsxRuntimeExports.jsx("p", { children: "Analyzing calendar and music history..." })
392      ] }) : suggestionError ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center py-12 text-center", children: [
393        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 bg-red-50 dark:bg-red-900/20 text-red-500 rounded-full flex items-center justify-center mb-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx(TriangleAlert, { size: 24 }) }),
394        /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "font-bold text-zinc-900 dark:text-white mb-2", children: "Suggestion Error" }),
395        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500 max-w-xs", children: suggestionError }),
396        /* @__PURE__ */ jsxRuntimeExports.jsx(
397          "button",
398          {
399            onClick: handleSuggest,
400            className: "mt-6 px-4 py-2 bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700 rounded-lg text-sm font-bold transition-colors",
401            children: "Try Again"
402          }
403        )
404      ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-3", children: suggestions.length > 0 ? suggestions.map((s, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
405        "div",
406        {
407          className: "p-4 bg-zinc-50 dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800 rounded-xl hover:border-indigo-500 dark:hover:border-indigo-500 transition-colors cursor-pointer group",
408          onClick: () => {
409            setFormData({
410              ...formData,
411              themeName: s.themeName,
412              startDate: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
413              // Default to today
414              endDate: (/* @__PURE__ */ new Date()).toISOString().split("T")[0]
415            });
416            setAiPrompt(s.description || s.themeName);
417            setIsSuggestModalOpen(false);
418            setIsModalOpen(true);
419          },
420          children: [
421            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-start", children: [
422              /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "font-bold text-zinc-900 dark:text-white", children: s.themeName }),
423              /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 16, className: "text-indigo-500 opacity-0 group-hover:opacity-100 transition-opacity" })
424            ] }),
425            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500 mt-1", children: s.description })
426          ]
427        },
428        i
429      )) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center py-8 text-zinc-400", children: "No suggestions available." }) }) }),
430      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 border-t border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950/50 flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
431        "button",
432        {
433          onClick: () => setIsSuggestModalOpen(false),
434          className: "px-4 py-2 text-sm font-bold text-zinc-500 hover:text-zinc-900 dark:hover:text-white transition-colors",
435          children: "Close"
436        }
437      ) })
438    ] }) })
439  ] });
440};
441function LabImageCropper({ imageSrc, toolName, onCropComplete, onCancel }) {
442  const [zoom, setZoom] = reactExports.useState(1);
443  const [position, setPosition] = reactExports.useState({ x: 0, y: 0 });
444  const [isDragging, setIsDragging] = reactExports.useState(false);
445  const dragStart = reactExports.useRef({ x: 0, y: 0 });
446  const viewportRef = reactExports.useRef(null);
447  const imgRef = reactExports.useRef(null);
448  reactExports.useEffect(() => {
449    setZoom(1);
450    setPosition({ x: 0, y: 0 });
451  }, [imageSrc]);
452  const handleMouseDown = (e) => {
453    e.preventDefault();
454    setIsDragging(true);
455    dragStart.current = { x: e.clientX - position.x, y: e.clientY - position.y };
456  };
457  const handleMouseMove = (e) => {
458    if (!isDragging) return;
459    const newX = e.clientX - dragStart.current.x;
460    const newY = e.clientY - dragStart.current.y;
461    setPosition({ x: newX, y: newY });
462  };
463  const handleMouseUp = () => {
464    setIsDragging(false);
465  };
466  const handleTouchStart = (e) => {
467    setIsDragging(true);
468    const touch = e.touches[0];
469    dragStart.current = { x: touch.clientX - position.x, y: touch.clientY - position.y };
470  };
471  const handleTouchMove = (e) => {
472    if (!isDragging) return;
473    const touch = e.touches[0];
474    const newX = touch.clientX - dragStart.current.x;
475    const newY = touch.clientY - dragStart.current.y;
476    setPosition({ x: newX, y: newY });
477  };
478  const handleApply = () => {
479    if (!imgRef.current || !viewportRef.current) return;
480    const img = imgRef.current;
481    const viewport = viewportRef.current;
482    const vWidth = viewport.clientWidth;
483    const vHeight = viewport.clientHeight;
484    const naturalWidth = img.naturalWidth;
485    const naturalHeight = img.naturalHeight;
486    const displayWidth = img.clientWidth;
487    const displayHeight = img.clientHeight;
488    const scaleX = naturalWidth / (displayWidth * zoom);
489    const scaleY = naturalHeight / (displayHeight * zoom);
490    const imgCenterX = displayWidth / 2;
491    const imgCenterY = displayHeight / 2;
492    const originX = vWidth / 2 - imgCenterX * zoom + position.x;
493    const originY = vHeight / 2 - imgCenterY * zoom + position.y;
494    const cropX = -originX * scaleX;
495    const cropY = -originY * scaleY;
496    const cropW = vWidth * scaleX;
497    const cropH = vHeight * scaleY;
498    const canvasOrig = document.createElement("canvas");
499    canvasOrig.width = naturalWidth;
500    canvasOrig.height = naturalHeight;
501    const ctxOrig = canvasOrig.getContext("2d");
502    if (ctxOrig) {
503      ctxOrig.drawImage(img, 0, 0);
504    }
505    const originalWebP = canvasOrig.toDataURL("image/webp", 0.92);
506    const generateCroppedWebp = (targetWidth, targetHeight) => {
507      const canvas = document.createElement("canvas");
508      canvas.width = targetWidth;
509      canvas.height = targetHeight;
510      const ctx = canvas.getContext("2d");
511      if (ctx) {
512        ctx.imageSmoothingEnabled = true;
513        ctx.imageSmoothingQuality = "high";
514        ctx.drawImage(
515          img,
516          cropX,
517          cropY,
518          cropW,
519          cropH,
520          // Source crop
521          0,
522          0,
523          targetWidth,
524          targetHeight
525          // Destination bounds
526        );
527      }
528      return canvas.toDataURL("image/webp", 0.9);
529    };
530    const homeWebP = generateCroppedWebp(480, 270);
531    const labWebP = generateCroppedWebp(640, 360);
532    onCropComplete({
533      original: originalWebP,
534      home: homeWebP,
535      lab: labWebP
536    });
537  };
538  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/85 backdrop-blur-md p-4 animate-in fade-in duration-200", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative w-full max-w-5xl bg-zinc-900 border border-zinc-800 rounded-3xl overflow-hidden shadow-2xl flex flex-col md:flex-row h-[90vh] md:h-auto max-h-[90vh]", children: [
539    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 p-6 flex flex-col items-center justify-between border-b md:border-b-0 md:border-r border-zinc-800 min-h-0 text-white", children: [
540      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full flex justify-between items-center mb-4", children: [
541        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
542          /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-lg font-black text-white leading-none", children: "Crop Thumbnail" }),
543          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-1", children: toolName })
544        ] }),
545        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onCancel, className: "p-1.5 rounded-full hover:bg-zinc-800 text-zinc-400 hover:text-white transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 20 }) })
546      ] }),
547      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative w-full flex-1 flex items-center justify-center bg-black/50 rounded-2xl overflow-hidden border border-zinc-800/80 my-4 min-h-[220px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
548        "div",
549        {
550          ref: viewportRef,
551          className: "relative w-full max-w-[560px] aspect-video bg-zinc-950 overflow-hidden shadow-lg select-none border-2 border-indigo-500/50",
552          onMouseDown: handleMouseDown,
553          onMouseMove: handleMouseMove,
554          onMouseUp: handleMouseUp,
555          onMouseLeave: handleMouseUp,
556          onTouchStart: handleTouchStart,
557          onTouchMove: handleTouchMove,
558          onTouchEnd: handleMouseUp,
559          children: [
560            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 border border-dashed border-white/20 pointer-events-none z-10" }),
561            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 flex items-center justify-center pointer-events-none z-10", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500/30", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Move, { size: 36 }) }) }),
562            /* @__PURE__ */ jsxRuntimeExports.jsx(
563              "img",
564              {
565                ref: imgRef,
566                src: imageSrc,
567                alt: "Source",
568                className: "absolute max-w-none origin-center select-none",
569                style: {
570                  top: "50%",
571                  left: "50%",
572                  transform: `translate(-50%, -50%) translate(${position.x}px, ${position.y}px) scale(${zoom})`,
573                  width: "100%",
574                  height: "auto",
575                  pointerEvents: "none"
576                }
577              }
578            )
579          ]
580        }
581      ) }),
582      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full flex items-center gap-4 px-2", children: [
583        /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomOut, { size: 16, className: "text-zinc-500" }),
584        /* @__PURE__ */ jsxRuntimeExports.jsx(
585          "input",
586          {
587            type: "range",
588            min: "1",
589            max: "4",
590            step: "0.05",
591            value: zoom,
592            onChange: (e) => setZoom(parseFloat(e.target.value)),
593            className: "flex-1 accent-indigo-500 h-1.5 bg-zinc-800 rounded-lg appearance-none cursor-pointer"
594          }
595        ),
596        /* @__PURE__ */ jsxRuntimeExports.jsx(ZoomIn, { size: 16, className: "text-zinc-500" }),
597        /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-bold text-zinc-400 w-10 text-right", children: [
598          Math.round(zoom * 100),
599          "%"
600        ] })
601      ] })
602    ] }),
603    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full md:w-80 p-6 flex flex-col justify-between bg-zinc-950/40 select-none text-white border-t md:border-t-0 md:border-l border-zinc-800", children: [
604      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
605        /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-black uppercase tracking-wider text-zinc-500 mb-5", children: "Live Previews" }),
606        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-6", children: [
607          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
608            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-2", children: [
609              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-300", children: "Home Page Card" }),
610              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-mono text-zinc-500", children: "480 x 270 (16:9)" })
611            ] }),
612            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative w-full aspect-video rounded-xl border border-zinc-800 overflow-hidden bg-zinc-950 shadow-inner", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 overflow-hidden", children: viewportRef.current && imgRef.current && /* @__PURE__ */ jsxRuntimeExports.jsx(
613              "img",
614              {
615                src: imageSrc,
616                alt: "Home Preview",
617                className: "absolute max-w-none origin-center",
618                style: {
619                  top: "50%",
620                  left: "50%",
621                  transform: `translate(-50%, -50%) translate(${position.x}px, ${position.y}px) scale(${zoom})`,
622                  width: "100%",
623                  height: "auto"
624                }
625              }
626            ) }) })
627          ] }),
628          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
629            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-2", children: [
630              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-300", children: "Hamie Lab Page Card" }),
631              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-mono text-zinc-500", children: "640 x 360 (16:9)" })
632            ] }),
633            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative w-full aspect-video rounded-xl border border-zinc-800 overflow-hidden bg-zinc-950 shadow-inner", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 overflow-hidden", children: viewportRef.current && imgRef.current && /* @__PURE__ */ jsxRuntimeExports.jsx(
634              "img",
635              {
636                src: imageSrc,
637                alt: "Lab Preview",
638                className: "absolute max-w-none origin-center",
639                style: {
640                  top: "50%",
641                  left: "50%",
642                  transform: `translate(-50%, -50%) translate(${position.x}px, ${position.y}px) scale(${zoom})`,
643                  width: "100%",
644                  height: "auto"
645                }
646              }
647            ) }) })
648          ] })
649        ] })
650      ] }),
651      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3 mt-8 md:mt-0", children: [
652        /* @__PURE__ */ jsxRuntimeExports.jsx(
653          "button",
654          {
655            onClick: onCancel,
656            className: "flex-1 py-2.5 rounded-xl border border-zinc-800 text-zinc-400 hover:text-white font-bold text-sm hover:bg-zinc-800/40 transition-all active:scale-95",
657            children: "Cancel"
658          }
659        ),
660        /* @__PURE__ */ jsxRuntimeExports.jsxs(
661          "button",
662          {
663            onClick: handleApply,
664            className: "flex-1 py-2.5 rounded-xl bg-indigo-600 hover:bg-indigo-700 text-white font-bold text-sm flex items-center justify-center gap-1.5 transition-all shadow-md active:scale-95",
665            children: [
666              /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 16 }),
667              " Apply Crop"
668            ]
669          }
670        )
671      ] })
672    ] })
673  ] }) });
674}
675const SYSTEM_ICONS = [
676  { key: "nav_home", label: "Home", category: "Sidebar", component: House },
677  { key: "nav_explore", label: "Explore", category: "Sidebar", component: Compass },
678  { key: "nav_subscriptions", label: "Subscriptions", category: "Sidebar", component: Library },
679  { key: "nav_history", label: "History", category: "Sidebar", component: History },
680  { key: "nav_playlists", label: "Playlists", category: "Sidebar", component: ListMusic },
681  { key: "nav_watch_later", label: "Watch Later", category: "Sidebar", component: Clock },
682  { key: "nav_liked", label: "Liked Videos", category: "Sidebar", component: ThumbsUp },
683  { key: "nav_settings", label: "Settings", category: "Sidebar", component: Settings },
684  { key: "action_menu", label: "Menu", category: "Header", component: Menu },
685  { key: "action_search", label: "Search", category: "Header", component: Search },
686  { key: "action_mic", label: "Microphone", category: "Header", component: Mic },
687  { key: "action_upload", label: "Upload", category: "Header", component: Plus },
688  { key: "action_bell", label: "Notifications", category: "Header", component: Bell },
689  { key: "action_user", label: "User Avatar", category: "Header", component: User }
690];
691const STYLE_PRESETS = [
692  { id: "minimalist", label: "Minimalist Flat", prompt: "minimalist, flat vector art, single color, clean lines, white background" },
693  { id: "neon", label: "Neon Glass", prompt: "glowing neon, glassmorphism, dark background style, vibrant indigo and purple gradient" },
694  { id: "pixel", label: "Pixel Art", prompt: "8-bit pixel art, retro game style, limited color palette" },
695  { id: "3d", label: "3D Render", prompt: "3D cute icon, claymorphism, soft lighting, pastel colors" },
696  { id: "sketch", label: "Hand Drawn", prompt: "hand drawn sketch, pencil style, rough edges, artistic" }
697];
698const DEFAULT_CONFIG = {
699  mainLogo: "",
700  favicon: "",
701  defaultThumbnail: "",
702  seasonalLogos: [],
703  icons: {},
704  iconSets: []
705};
706const GraphicManager = ({ activeRole }) => {
707  const [config, setConfig] = reactExports.useState(DEFAULT_CONFIG);
708  const [activeTab, setActiveTab] = reactExports.useState("assets");
709  const [availableAssets, setAvailableAssets] = reactExports.useState([]);
710  const [loadingAssets, setLoadingAssets] = reactExports.useState(false);
711  const [defaultAvatars, setDefaultAvatars] = reactExports.useState([]);
712  const [avatarUploading, setAvatarUploading] = reactExports.useState(false);
713  const [aiPrompt, setAiPrompt] = reactExports.useState("");
714  const [generating, setGenerating] = reactExports.useState(false);
715  const [generatedImage, setGeneratedImage] = reactExports.useState(null);
716  const [targetSlot, setTargetSlot] = reactExports.useState("mainLogo");
717  const [activeStyle, setActiveStyle] = reactExports.useState(STYLE_PRESETS[0]);
718  const [batchResults, setBatchResults] = reactExports.useState({});
719  const [batchProgress, setBatchProgress] = reactExports.useState(0);
720  const [isBatchMode, setIsBatchMode] = reactExports.useState(false);
721  const [visibleCounts, setVisibleCounts] = reactExports.useState({
722    mainLogo: 10,
723    favicon: 10,
724    defaultThumbnail: 10
725  });
726  const [labTools, setLabTools] = reactExports.useState([]);
727  const [selectedToolForCropping, setSelectedToolForCropping] = reactExports.useState(null);
728  const [croppingImageSrc, setCroppingImageSrc] = reactExports.useState(null);
729  const [activeLabToolIdForPaste, setActiveLabToolIdForPaste] = reactExports.useState(null);
730  const [loadingLab, setLoadingLab] = reactExports.useState(false);
731  reactExports.useEffect(() => {
732    loadConfig();
733    loadDefaultAvatars();
734    fetchAssets();
735    loadLabTools();
736  }, []);
737  reactExports.useEffect(() => {
738    if (activeTab !== "lab" || !activeLabToolIdForPaste) return;
739    const handleGlobalPaste = (e) => {
740      var _a;
741      const items = (_a = e.clipboardData) == null ? void 0 : _a.items;
742      if (!items) return;
743      for (let i = 0; i < items.length; i++) {
744        const item = items[i];
745        if (item.type.indexOf("image") !== -1) {
746          const file = item.getAsFile();
747          if (!file) continue;
748          const reader = new FileReader();
749          reader.onloadend = () => {
750            const tool = labTools.find((t) => t.id === activeLabToolIdForPaste);
751            if (tool) {
752              setSelectedToolForCropping(tool);
753              setCroppingImageSrc(reader.result);
754            }
755          };
756          reader.readAsDataURL(file);
757          break;
758        }
759      }
760    };
761    window.addEventListener("paste", handleGlobalPaste);
762    return () => {
763      window.removeEventListener("paste", handleGlobalPaste);
764    };
765  }, [activeTab, activeLabToolIdForPaste, labTools]);
766  const loadLabTools = async () => {
767    setLoadingLab(true);
768    try {
769      const config2 = await api.getLabConfig();
770      if (config2 && config2.tools) {
771        const dbToolsMap = new Map(config2.tools.map((t) => [t.id, t]));
772        const mergedTools = DEFAULT_TOOLS.map((defTool) => {
773          const dbTool = dbToolsMap.get(defTool.id);
774          if (dbTool) {
775            return { ...defTool, enabled: dbTool.enabled };
776          }
777          return defTool;
778        });
779        setLabTools(mergedTools);
780      } else {
781        setLabTools(DEFAULT_TOOLS);
782      }
783    } catch (e) {
784      console.error("Failed to load lab tools:", e);
785      setLabTools(DEFAULT_TOOLS);
786    } finally {
787      setLoadingLab(false);
788    }
789  };
790  const handleLabCropComplete = async (outputs) => {
791    if (!selectedToolForCropping) return;
792    const toolId = selectedToolForCropping.id;
793    setSelectedToolForCropping(null);
794    setCroppingImageSrc(null);
795    try {
796      const [origRes, homeRes, labRes] = await Promise.all([
797        api.saveGeneratedAsset(outputs.original, `lab_orig_${toolId}`),
798        api.saveGeneratedAsset(outputs.home, `lab_home_${toolId}`),
799        api.saveGeneratedAsset(outputs.lab, `lab_page_${toolId}`)
800      ]);
801      const currentThumbnails = config.labThumbnails || {};
802      const updatedThumbnails = {
803        ...currentThumbnails,
804        [toolId]: {
805          original: origRes.url,
806          home: homeRes.url,
807          lab: labRes.url
808        }
809      };
810      await saveConfig({
811        ...config,
812        labThumbnails: updatedThumbnails
813      });
814      fetchAssets();
815    } catch (err) {
816      console.error("Failed to upload cropped thumbnails:", err);
817      alert("Failed to upload cropped thumbnails. Please try again.");
818    }
819  };
820  const handleLabImageSelect = (e, tool) => {
821    var _a;
822    const file = (_a = e.target.files) == null ? void 0 : _a[0];
823    if (file) {
824      const reader = new FileReader();
825      reader.onloadend = () => {
826        setSelectedToolForCropping(tool);
827        setCroppingImageSrc(reader.result);
828      };
829      reader.readAsDataURL(file);
830    }
831  };
832  const handleRemoveLabThumbnail = async (toolId) => {
833    if (!confirm("Are you sure you want to remove the thumbnail for this tool?")) return;
834    const currentThumbnails = config.labThumbnails || {};
835    const updatedThumbnails = { ...currentThumbnails };
836    delete updatedThumbnails[toolId];
837    await saveConfig({
838      ...config,
839      labThumbnails: updatedThumbnails
840    });
841  };
842  const fetchAssets = async () => {
843    setLoadingAssets(true);
844    try {
845      const assets = await api.getAvailableAssets();
846      setAvailableAssets(assets);
847    } catch (err) {
848      console.error("Failed to fetch assets:", err);
849    } finally {
850      setLoadingAssets(false);
851    }
852  };
853  const loadConfig = async () => {
854    const saved = await api.getSystemSetting("site_graphics");
855    if (saved && saved.value && typeof saved.value === "object") {
856      setConfig({ ...DEFAULT_CONFIG, ...saved.value });
857    }
858  };
859  const loadDefaultAvatars = async () => {
860    const avatars = await api.getDefaultAvatars();
861    setDefaultAvatars(avatars);
862  };
863  const handleAvatarUpload = async (e) => {
864    var _a;
865    const file = (_a = e.target.files) == null ? void 0 : _a[0];
866    if (!file) return;
867    setAvatarUploading(true);
868    try {
869      await api.uploadDefaultAvatar(file);
870      await loadDefaultAvatars();
871    } catch (err) {
872      console.error("Failed to upload default avatar:", err);
873    } finally {
874      setAvatarUploading(false);
875    }
876  };
877  const handleDeleteAvatar = async (filename) => {
878    if (!confirm(`Delete default avatar "${filename}"?`)) return;
879    await api.deleteDefaultAvatar(filename);
880    await loadDefaultAvatars();
881  };
882  const saveConfig = async (newConfig) => {
883    try {
884      await api.post("/admin/settings/site_graphics", { value: newConfig });
885      setConfig(newConfig);
886    } catch (err) {
887      console.error("Failed to save config:", err);
888      alert("Failed to save settings.");
889    }
890  };
891  const handleUpload = (e, key, isIcon = false) => {
892    var _a;
893    const file = (_a = e.target.files) == null ? void 0 : _a[0];
894    if (file) {
895      const reader = new FileReader();
896      reader.onloadend = async () => {
897        const dataUrl = reader.result;
898        try {
899          const res = await api.saveGeneratedAsset(dataUrl, key);
900          const permanentUrl = res.url;
901          if (isIcon) {
902            const updatedIcons = { ...config.icons, [key]: permanentUrl };
903            saveConfig({ ...config, icons: updatedIcons });
904          } else {
905            const updated = { ...config, [key]: permanentUrl };
906            saveConfig(updated);
907          }
908          fetchAssets();
909        } catch (err) {
910          console.error("Failed to upload asset:", err);
911          alert("Upload failed. Using local preview temporarily.");
912          if (isIcon) {
913            const updatedIcons = { ...config.icons, [key]: dataUrl };
914            saveConfig({ ...config, icons: updatedIcons });
915          } else {
916            const updated = { ...config, [key]: dataUrl };
917            saveConfig(updated);
918          }
919        }
920      };
921      reader.readAsDataURL(file);
922    }
923  };
924  const handleRemoveIcon = (key) => {
925    const updatedIcons = { ...config.icons };
926    delete updatedIcons[key];
927    saveConfig({ ...config, icons: updatedIcons });
928  };
929  const handleAiGenerate = async () => {
930    var _a, _b, _c;
931    if (!aiPrompt) return;
932    setGenerating(true);
933    setBatchResults({});
934    try {
935      if (targetSlot === "all_icons") {
936        setIsBatchMode(true);
937        setBatchProgress(0);
938        const newBatch = {};
939        const total = SYSTEM_ICONS.length;
940        for (let i = 0; i < total; i++) {
941          const icon = SYSTEM_ICONS[i];
942          const fullPrompt = `Create a high quality, professional icon.
943                    Subject: ${icon.label} (${icon.category} UI Element).
944                    Theme/Description: ${aiPrompt}
945                    Style: ${activeStyle.prompt}
946                    
947                    Important: Return a clean image with a TRANSPARENT background if possible.
948                    Target use: Small UI Icon (24x24px context).`;
949          try {
950            const gemini = getGeminiAI();
951            await gemini.models.generateContent({
952              model: getAiImageModel("gemini-2.5-flash-image"),
953              contents: [{ text: fullPrompt }]
954            });
955            const styleColor = activeStyle.id === "neon" ? "1e1b4b" : activeStyle.id === "3d" ? "ffddd2" : "f3f4f6";
956            const textColor = activeStyle.id === "neon" ? "ffffff" : "000000";
957            const mockGenerated = getPlaceholderUrl(200, 200, icon.label.substring(0, 3), styleColor, textColor);
958            newBatch[icon.key] = mockGenerated;
959            await new Promise((r) => setTimeout(r, 800));
960          } catch (e) {
961            console.error(`Failed to generate icon ${icon.key}`, e);
962          }
963          setBatchProgress(Math.round((i + 1) / total * 100));
964        }
965        setBatchResults(newBatch);
966      } else {
967        setIsBatchMode(false);
968        const fullPrompt = `Create a high quality, professional icon/logo.
969                Subject: ${aiPrompt}
970                Style: ${activeStyle.prompt}
971                
972                Important: Return a clean image with a TRANSPARENT background if possible, or a solid color that is easy to remove.
973                Target use: Website UI component.`;
974        const gemini = getGeminiAI();
975        const response = await gemini.models.generateContent({
976          model: getAiImageModel("gemini-2.5-flash-image"),
977          contents: [{ text: fullPrompt }]
978        });
979        for (const part of ((_c = (_b = (_a = response.candidates) == null ? void 0 : _a[0]) == null ? void 0 : _b.content) == null ? void 0 : _c.parts) || []) {
980          if (part.inlineData) {
981            const imageUrl = `data:${part.inlineData.mimeType};base64,${part.inlineData.data}`;
982            setGeneratedImage(imageUrl);
983            return;
984          }
985        }
986        const styleColor = activeStyle.id === "neon" ? "1e1b4b" : activeStyle.id === "3d" ? "ffddd2" : "f3f4f6";
987        const textColor = activeStyle.id === "neon" ? "white" : "black";
988        const mockGenerated = getPlaceholderUrl(500, 500, aiPrompt.substring(0, 10), styleColor, textColor);
989        setGeneratedImage(mockGenerated);
990      }
991    } catch (e) {
992      console.error("AI Generation Error:", e);
993      alert(`Generation failed: ${e.message || "Unknown error"}. Ensure your API key supports image generation models.`);
994      api.logError(e, "GraphicManager:handleAiGenerate");
995    } finally {
996      setGenerating(false);
997    }
998  };
999  const applyGeneratedImage = async () => {
1000    if (targetSlot === "all_icons") {
1001      if (Object.keys(batchResults).length === 0) return;
1002      const savedBatch = {};
1003      for (const [key, data] of Object.entries(batchResults)) {
1004        try {
1005          const res = await api.saveGeneratedAsset(data, key);
1006          savedBatch[key] = res.url;
1007        } catch (e) {
1008          console.error(`Failed to save icon ${key}:`, e);
1009        }
1010      }
1011      const updatedIcons = { ...config.icons, ...savedBatch };
1012      saveConfig({ ...config, icons: updatedIcons });
1013      setBatchResults({});
1014      setActiveTab("icons");
1015      setIsBatchMode(false);
1016      setAiPrompt("");
1017      fetchAssets();
1018      return;
1019    }
1020    if (!generatedImage) return;
1021    try {
1022      const res = await api.saveGeneratedAsset(generatedImage, targetSlot);
1023      const permanentUrl = res.url;
1024      if (targetSlot === "seasonal") {
1025        const newSeasonal = {
1026          id: `seas-${Date.now()}`,
1027          name: aiPrompt || "AI Generated",
1028          url: permanentUrl,
1029          startDate: "12-01",
1030          endDate: "12-31",
1031          active: true
1032        };
1033        saveConfig({ ...config, seasonalLogos: [...config.seasonalLogos, newSeasonal] });
1034        setActiveTab("seasonal");
1035      } else if (SYSTEM_ICONS.some((icon) => icon.key === targetSlot)) {
1036        const updatedIcons = { ...config.icons, [targetSlot]: permanentUrl };
1037        saveConfig({ ...config, icons: updatedIcons });
1038        setActiveTab("icons");
1039      } else {
1040        saveConfig({ ...config, [targetSlot]: permanentUrl });
1041        setActiveTab("assets");
1042      }
1043      setGeneratedImage(null);
1044      setAiPrompt("");
1045      fetchAssets();
1046    } catch (e) {
1047      alert("Failed to apply image: " + (e instanceof Error ? e.message : String(e)));
1048    }
1049  };
1050  const saveBatchAsSet = () => {
1051    if (!newSetName.trim()) return;
1052    const newSet = {
1053      id: `set-${Date.now()}`,
1054      name: newSetName,
1055      icons: { ...batchResults },
1056      createdAt: (/* @__PURE__ */ new Date()).toISOString()
1057    };
1058    const updatedSets = [...config.iconSets || [], newSet];
1059    saveConfig({ ...config, iconSets: updatedSets });
1060    setNewSetName("");
1061    alert(`Saved icon set "${newSet.name}"!`);
1062  };
1063  const applySet = (set) => {
1064    if (confirm(`Replace current icons with "${set.name}"?`)) {
1065      saveConfig({ ...config, icons: set.icons });
1066    }
1067  };
1068  const deleteSet = (setId) => {
1069    if (confirm("Delete this icon set?")) {
1070      const updated = (config.iconSets || []).filter((s) => s.id !== setId);
1071      saveConfig({ ...config, iconSets: updated });
1072    }
1073  };
1074  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col space-y-6", children: [
1075    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-zinc-100 dark:bg-zinc-800 p-1 rounded-lg w-fit border border-zinc-200 dark:border-zinc-700", children: [
1076      /* @__PURE__ */ jsxRuntimeExports.jsxs(
1077        "button",
1078        {
1079          onClick: () => setActiveTab("assets"),
1080          className: `flex items-center gap-2 px-4 py-2 rounded-md text-sm font-bold transition-all ${activeTab === "assets" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-white"}`,
1081          children: [
1082            /* @__PURE__ */ jsxRuntimeExports.jsx(Image, { size: 16 }),
1083            " Core Assets"
1084          ]
1085        }
1086      ),
1087      /* @__PURE__ */ jsxRuntimeExports.jsxs(
1088        "button",
1089        {
1090          onClick: () => setActiveTab("icons"),
1091          className: `flex items-center gap-2 px-4 py-2 rounded-md text-sm font-bold transition-all ${activeTab === "icons" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-white"}`,
1092          children: [
1093            /* @__PURE__ */ jsxRuntimeExports.jsx(LayoutGrid, { size: 16 }),
1094            " System Icons"
1095          ]
1096        }
1097      ),
1098      /* @__PURE__ */ jsxRuntimeExports.jsxs(
1099        "button",
1100        {
1101          onClick: () => setActiveTab("seasonal"),
1102          className: `flex items-center gap-2 px-4 py-2 rounded-md text-sm font-bold transition-all ${activeTab === "seasonal" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-white"}`,
1103          children: [
1104            /* @__PURE__ */ jsxRuntimeExports.jsx(Calendar, { size: 16 }),
1105            " Logo Scheduler"
1106          ]
1107        }
1108      ),
1109      /* @__PURE__ */ jsxRuntimeExports.jsxs(
1110        "button",
1111        {
1112          onClick: () => setActiveTab("ai"),
1113          className: `flex items-center gap-2 px-4 py-2 rounded-md text-sm font-bold transition-all ${activeTab === "ai" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-white"}`,
1114          children: [
1115            /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 16 }),
1116            " AI Studio"
1117          ]
1118        }
1119      ),
1120      /* @__PURE__ */ jsxRuntimeExports.jsxs(
1121        "button",
1122        {
1123          onClick: () => setActiveTab("avatars"),
1124          className: `flex items-center gap-2 px-4 py-2 rounded-md text-sm font-bold transition-all ${activeTab === "avatars" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-white"}`,
1125          children: [
1126            /* @__PURE__ */ jsxRuntimeExports.jsx(User, { size: 16 }),
1127            " Default Avatars"
1128          ]
1129        }
1130      ),
1131      /* @__PURE__ */ jsxRuntimeExports.jsxs(
1132        "button",
1133        {
1134          onClick: () => setActiveTab("lab"),
1135          className: `flex items-center gap-2 px-4 py-2 rounded-md text-sm font-bold transition-all ${activeTab === "lab" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-white"}`,
1136          children: [
1137            /* @__PURE__ */ jsxRuntimeExports.jsx(FlaskConical, { size: 16 }),
1138            " Hamie Lab"
1139          ]
1140        }
1141      )
1142    ] }),
1143    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto bg-white dark:bg-zinc-900 rounded-xl border border-zinc-200 dark:border-zinc-800 p-6 shadow-sm", children: [
1144      activeTab === "assets" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-8 max-w-5xl", children: [
1145        [
1146          { key: "mainLogo", label: "Main Logo", desc: "Displayed in the header. Ideal size: 400x100px (approx 4:1 aspect ratio). Recommended SVG or transparent PNG." },
1147          { key: "favicon", label: "Favicon", desc: "Browser tab icon. Recommended .ico or .png 32x32 or 64x64." },
1148          { key: "defaultThumbnail", label: "Default Thumbnail", desc: "Fallback for videos without covers. 16:9 aspect ratio (e.g., 1280x720)." }
1149        ].map((item) => {
1150          var _a, _b;
1151          return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col space-y-4 p-6 border border-zinc-200 dark:border-zinc-800 rounded-xl bg-zinc-50/50 dark:bg-zinc-950/50", children: [
1152            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col md:flex-row gap-6", children: [
1153              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
1154                /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-zinc-900 dark:text-white mb-1", children: item.label }),
1155                /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 mb-4", children: item.desc }),
1156                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
1157                  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 px-4 py-2 bg-white dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded-lg cursor-pointer hover:bg-zinc-50 dark:hover:bg-zinc-700 transition-colors", children: [
1158                    /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 14, className: "text-zinc-500" }),
1159                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-700 dark:text-zinc-300", children: "Upload New" }),
1160                    /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "file", className: "hidden", accept: "image/*", onChange: (e) => handleUpload(e, item.key) })
1161                  ] }),
1162                  /* @__PURE__ */ jsxRuntimeExports.jsxs(
1163                    "button",
1164                    {
1165                      onClick: () => {
1166                        setTargetSlot(item.key);
1167                        setActiveTab("ai");
1168                      },
1169                      className: "flex items-center gap-2 px-4 py-2 bg-indigo-50 dark:bg-indigo-900/20 border border-indigo-200 dark:border-indigo-800 rounded-lg hover:bg-indigo-100 dark:hover:bg-indigo-900/40 transition-colors",
1170                      children: [
1171                        /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 14, className: "text-indigo-500" }),
1172                        /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-indigo-700 dark:text-indigo-300", children: "Generate AI" })
1173                      ]
1174                    }
1175                  )
1176                ] }),
1177                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-4", children: [
1178                  /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-[10px] font-black uppercase text-zinc-500 tracking-wider mb-2", children: "Custom URL or SVG Code" }),
1179                  /* @__PURE__ */ jsxRuntimeExports.jsx(
1180                    "textarea",
1181                    {
1182                      value: config[item.key] || "",
1183                      onChange: (e) => saveConfig({ ...config, [item.key]: e.target.value }),
1184                      placeholder: "Paste URL or <svg>...</svg> code",
1185                      className: "w-full h-16 bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg p-2 text-[10px] font-mono focus:ring-2 focus:ring-indigo-500 transition-all resize-none"
1186                    }
1187                  ),
1188                  item.key === "mainLogo" && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1189                    "button",
1190                    {
1191                      onClick: () => saveConfig({ ...config, [item.key]: DEFAULT_BRAND_SVG }),
1192                      className: "mt-1 text-[10px] text-indigo-500 hover:text-indigo-600 font-bold flex items-center gap-1",
1193                      children: [
1194                        /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCcw, { size: 10 }),
1195                        " Load Site Default Template"
1196                      ]
1197                    }
1198                  )
1199                ] })
1200              ] }),
1201              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full md:w-48 h-32 bg-zinc-200 dark:bg-zinc-800 rounded-lg flex items-center justify-center border-2 border-dashed border-zinc-300 dark:border-zinc-700 overflow-hidden relative group", children: config[item.key] ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1202                ((_b = (_a = config[item.key]) == null ? void 0 : _a.trim()) == null ? void 0 : _b.startsWith("<svg")) ? /* @__PURE__ */ jsxRuntimeExports.jsx(
1203                  "div",
1204                  {
1205                    className: "max-w-full max-h-full p-2 flex items-center justify-center [&>svg]:max-w-full [&>svg]:max-h-full",
1206                    dangerouslySetInnerHTML: { __html: config[item.key] }
1207                  }
1208                ) : /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: config[item.key], className: "max-w-full max-h-full object-contain", referrerPolicy: "no-referrer" }),
1209                /* @__PURE__ */ jsxRuntimeExports.jsx(
1210                  "button",
1211                  {
1212                    onClick: () => saveConfig({ ...config, [item.key]: "" }),
1213                    className: "absolute top-2 right-2 p-1 bg-red-500 text-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity z-10",
1214                    children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 12 })
1215                  }
1216                )
1217              ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400 font-medium", children: "No Image" }) })
1218            ] }),
1219            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-4 pt-4 border-t border-zinc-200 dark:border-zinc-800", children: [
1220              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-3", children: [
1221                /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-[10px] font-black uppercase text-zinc-500 tracking-wider", children: "Asset Library" }),
1222                /* @__PURE__ */ jsxRuntimeExports.jsxs(
1223                  "button",
1224                  {
1225                    onClick: fetchAssets,
1226                    className: "text-[10px] text-zinc-400 hover:text-indigo-600 transition-colors flex items-center gap-1",
1227                    children: [
1228                      /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCcw, { size: 10, className: loadingAssets ? "animate-spin" : "" }),
1229                      " Refresh"
1230                    ]
1231                  }
1232                )
1233              ] }),
1234              (() => {
1235                const filtered = availableAssets.filter((asset) => {
1236                  const name = asset.name.toLowerCase();
1237                  if (item.key === "mainLogo") return name.includes("logo") || asset.url === "DEFAULT_SVG";
1238                  if (item.key === "favicon") return (name.includes("favicon") || name.endsWith(".ico")) && !name.includes("logo");
1239                  if (item.key === "defaultThumbnail") return (name.includes("thumbnail") || name.includes("banner")) && !name.includes("logo");
1240                  return true;
1241                });
1242                const visibleLimit = visibleCounts[item.key] || 10;
1243                const visible = filtered.slice(0, visibleLimit);
1244                const hasMore = filtered.length > visibleLimit;
1245                return filtered.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
1246                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-3 overflow-x-auto pb-2 custom-scrollbar mask-fade-right", children: visible.map((asset) => {
1247                    const isActive = config[item.key] === asset.url;
1248                    return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1249                      "button",
1250                      {
1251                        onClick: () => {
1252                          const finalUrl = asset.url === "DEFAULT_SVG" ? "" : asset.url;
1253                          saveConfig({ ...config, [item.key]: finalUrl });
1254                        },
1255                        className: `relative flex-shrink-0 w-24 h-24 rounded-lg border-2 transition-all overflow-hidden group ${isActive || asset.url === "DEFAULT_SVG" && !config[item.key] ? "border-indigo-500 ring-2 ring-indigo-500/20" : "border-zinc-200 dark:border-zinc-800 hover:border-zinc-400 dark:hover:border-zinc-600"}`,
1256                        children: [
1257                          asset.url === "DEFAULT_SVG" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full h-full bg-zinc-100 dark:bg-zinc-800 flex flex-col items-center justify-center p-2", children: [
1258                            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full aspect-[4/1] flex items-center justify-center scale-90", children: /* @__PURE__ */ jsxRuntimeExports.jsx(HamieLogo, {}) }),
1259                            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] font-black uppercase text-zinc-500 mt-1", children: "Site Default" })
1260                          ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: asset.url, className: "w-full h-full object-contain bg-zinc-100 dark:bg-zinc-900", referrerPolicy: "no-referrer" }),
1261                          (isActive || asset.url === "DEFAULT_SVG" && !config[item.key]) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-1 right-1 p-0.5 bg-indigo-500 text-white rounded-full shadow-lg", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { size: 10 }) }),
1262                          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] text-white font-black uppercase", children: "Select" }) })
1263                        ]
1264                      },
1265                      asset.url
1266                    );
1267                  }) }),
1268                  hasMore && /* @__PURE__ */ jsxRuntimeExports.jsxs(
1269                    "button",
1270                    {
1271                      onClick: () => setVisibleCounts({ ...visibleCounts, [item.key]: visibleLimit + 20 }),
1272                      className: "text-[10px] font-bold text-zinc-500 hover:text-indigo-600 py-1 px-3 border border-zinc-200 dark:border-zinc-800 rounded-full transition-colors flex items-center gap-1 mx-auto",
1273                      children: [
1274                        /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 10 }),
1275                        " Show More (+20)"
1276                      ]
1277                    }
1278                  )
1279                ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-400 italic", children: "No relevant assets found for this category." });
1280              })()
1281            ] })
1282          ] }, item.key);
1283        }),
1284        /* @__PURE__ */ jsxRuntimeExports.jsx(DevDebugInfo, { table: "SystemSetting", keyName: "site_graphics", value: config, isSuperAdmin: activeRole == null ? void 0 : activeRole.isSuperAdmin })
1285      ] }),
1286      activeTab === "icons" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [
1287        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-4", children: [
1288          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1289            /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-lg text-zinc-900 dark:text-white", children: "Icon Registry" }),
1290            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500", children: "Manage all system icons. Custom icons override defaults." })
1291          ] }),
1292          /* @__PURE__ */ jsxRuntimeExports.jsxs(
1293            "button",
1294            {
1295              onClick: () => {
1296                setTargetSlot("all_icons");
1297                setActiveTab("ai");
1298              },
1299              className: "flex items-center gap-2 px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-bold shadow-md shadow-indigo-500/20",
1300              children: [
1301                /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 16 }),
1302                " Batch Generate All"
1303              ]
1304            }
1305          )
1306        ] }),
1307        config.iconSets && config.iconSets.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-8 p-4 bg-zinc-50 dark:bg-zinc-900/50 rounded-xl border border-zinc-200 dark:border-zinc-800", children: [
1308          /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-xs font-bold uppercase text-zinc-500 mb-3 flex items-center gap-2", children: [
1309            /* @__PURE__ */ jsxRuntimeExports.jsx(Package, { size: 14 }),
1310            " Saved Icon Sets"
1311          ] }),
1312          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4", children: config.iconSets.map((set) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-3 shadow-sm flex flex-col justify-between group hover:border-indigo-300 dark:hover:border-indigo-700 transition-colors", children: [
1313            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1314              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-2", children: [
1315                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-sm text-zinc-900 dark:text-white truncate", children: set.name }),
1316                /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => deleteSet(set.id), className: "text-zinc-400 hover:text-red-500 transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 }) })
1317              ] }),
1318              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-1 mb-3 overflow-hidden h-6", children: Object.values(set.icons).slice(0, 5).map((src, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src, className: "w-6 h-6 object-contain bg-zinc-100 dark:bg-zinc-800 rounded p-0.5", referrerPolicy: "no-referrer" }, i)) })
1319            ] }),
1320            /* @__PURE__ */ jsxRuntimeExports.jsxs(
1321              "button",
1322              {
1323                onClick: () => applySet(set),
1324                className: "w-full py-1.5 bg-zinc-100 hover:bg-zinc-200 dark:bg-zinc-800 dark:hover:bg-zinc-700 text-zinc-700 dark:text-zinc-300 text-xs font-bold rounded flex items-center justify-center gap-1",
1325                children: [
1326                  /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { size: 12 }),
1327                  " Apply Set"
1328                ]
1329              }
1330            )
1331          ] }, set.id)) })
1332        ] }),
1333        ["Sidebar", "Header"].map((category) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-8", children: [
1334          /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-xs font-bold uppercase text-zinc-500 mb-4 border-b border-zinc-200 dark:border-zinc-800 pb-2", children: [
1335            category,
1336            " Icons"
1337          ] }),
1338          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4", children: SYSTEM_ICONS.filter((i) => i.category === category).map((icon) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-50 dark:bg-zinc-900/50 border border-zinc-200 dark:border-zinc-800 rounded-xl p-4 flex flex-col hover:border-indigo-300 dark:hover:border-indigo-800 transition-all", children: [
1339            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between mb-3", children: [
1340              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-sm text-zinc-900 dark:text-white", children: icon.label }),
1341              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] px-1.5 py-0.5 rounded font-mono ${config.icons[icon.key] ? "bg-indigo-100 text-indigo-700 dark:bg-indigo-900/30 dark:text-indigo-300" : "bg-zinc-200 dark:bg-zinc-800 text-zinc-500"}`, children: config.icons[icon.key] ? "Custom" : "Default" })
1342            ] }),
1343            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-4 items-center justify-center flex-1 min-h-[60px] bg-white dark:bg-zinc-900 rounded-lg border border-zinc-200 dark:border-zinc-800 mb-3 relative overflow-hidden", children: [
1344              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `flex flex-col items-center gap-1 opacity-50 grayscale transition-all ${!config.icons[icon.key] ? "opacity-100 grayscale-0 scale-110" : ""}`, children: [
1345                /* @__PURE__ */ jsxRuntimeExports.jsx(icon.component, { size: 24 }),
1346                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-zinc-400", children: "Default" })
1347              ] }),
1348              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-8 bg-zinc-200 dark:bg-zinc-700" }),
1349              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `flex flex-col items-center gap-1 relative ${config.icons[icon.key] ? "opacity-100 scale-110" : "opacity-20"}`, children: [
1350                config.icons[icon.key] ? /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: config.icons[icon.key], className: "w-6 h-6 object-contain", referrerPolicy: "no-referrer" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-6 h-6 border border-dashed border-zinc-400 rounded flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 10, className: "text-zinc-400" }) }),
1351                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-zinc-400", children: "Custom" })
1352              ] })
1353            ] }),
1354            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
1355              /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex-1 py-1.5 bg-zinc-200 dark:bg-zinc-800 hover:bg-zinc-300 dark:hover:bg-zinc-700 rounded text-xs font-bold text-center cursor-pointer text-zinc-700 dark:text-zinc-300 transition-colors", children: [
1356                "Upload",
1357                /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "file", className: "hidden", accept: "image/*", onChange: (e) => handleUpload(e, icon.key, true) })
1358              ] }),
1359              /* @__PURE__ */ jsxRuntimeExports.jsx(
1360                "button",
1361                {
1362                  onClick: () => {
1363                    setTargetSlot(icon.key);
1364                    setActiveTab("ai");
1365                  },
1366                  className: "px-2 py-1.5 bg-indigo-50 dark:bg-indigo-900/20 hover:bg-indigo-100 dark:hover:bg-indigo-900/40 text-indigo-600 dark:text-indigo-400 rounded transition-colors",
1367                  title: "Generate with AI",
1368                  children: /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 14 })
1369                }
1370              ),
1371              config.icons[icon.key] && /* @__PURE__ */ jsxRuntimeExports.jsx(
1372                "button",
1373                {
1374                  onClick: () => handleRemoveIcon(icon.key),
1375                  className: "px-2 py-1.5 bg-red-50 dark:bg-red-900/20 hover:bg-red-100 dark:hover:bg-red-900/40 text-red-500 rounded transition-colors",
1376                  title: "Revert to Default",
1377                  children: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCcw, { size: 14 })
1378                }
1379              )
1380            ] })
1381          ] }, icon.key)) })
1382        ] }, category))
1383      ] }),
1384      activeTab === "seasonal" && /* @__PURE__ */ jsxRuntimeExports.jsx(LogoScheduler, {}),
1385      activeTab === "ai" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col h-full", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col md:flex-row gap-8", children: [
1386        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 space-y-6", children: [
1387          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1388            /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-lg text-zinc-900 dark:text-white mb-2", children: "Generate Graphic" }),
1389            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500 mb-4", children: "Use Gemini to create icons, logos, or seasonal banners." }),
1390            /* @__PURE__ */ jsxRuntimeExports.jsx(
1391              "textarea",
1392              {
1393                value: aiPrompt,
1394                onChange: (e) => setAiPrompt(e.target.value),
1395                className: "w-full h-24 bg-zinc-50 dark:bg-black border border-zinc-300 dark:border-zinc-800 rounded-lg p-4 text-sm focus:border-indigo-500 outline-none resize-none mb-4",
1396                placeholder: "Describe your graphic (e.g., 'A modern stylized piano key')..."
1397              }
1398            ),
1399            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4 mb-4", children: [
1400              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1401                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-2", children: "Target Use" }),
1402                /* @__PURE__ */ jsxRuntimeExports.jsxs(
1403                  "select",
1404                  {
1405                    value: targetSlot,
1406                    onChange: (e) => setTargetSlot(e.target.value),
1407                    className: "w-full bg-white dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded-lg p-2 text-sm outline-none",
1408                    children: [
1409                      /* @__PURE__ */ jsxRuntimeExports.jsxs("optgroup", { label: "Core Assets", children: [
1410                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "mainLogo", children: "Main Website Logo" }),
1411                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "favicon", children: "Favicon" }),
1412                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "defaultThumbnail", children: "Default Thumbnail" }),
1413                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "seasonal", children: "New Seasonal Event" })
1414                      ] }),
1415                      /* @__PURE__ */ jsxRuntimeExports.jsxs("optgroup", { label: "System Icons", children: [
1416                        /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "all_icons", children: "All System Icons (Batch)" }),
1417                        SYSTEM_ICONS.map((icon) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: icon.key, children: icon.label }, icon.key))
1418                      ] })
1419                    ]
1420                  }
1421                )
1422              ] }),
1423              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1424                /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-500 uppercase mb-2", children: "Style Preset" }),
1425                /* @__PURE__ */ jsxRuntimeExports.jsx(
1426                  "select",
1427                  {
1428                    value: activeStyle.id,
1429                    onChange: (e) => setActiveStyle(STYLE_PRESETS.find((s) => s.id === e.target.value) || STYLE_PRESETS[0]),
1430                    className: "w-full bg-white dark:bg-zinc-800 border border-zinc-300 dark:border-zinc-700 rounded-lg p-2 text-sm outline-none",
1431                    children: STYLE_PRESETS.map((style) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: style.id, children: style.label }, style.id))
1432                  }
1433                )
1434              ] })
1435            ] })
1436          ] }),
1437          /* @__PURE__ */ jsxRuntimeExports.jsxs(
1438            "button",
1439            {
1440              onClick: handleAiGenerate,
1441              disabled: !aiPrompt || generating,
1442              className: "w-full py-3 bg-indigo-600 hover:bg-indigo-700 text-white font-bold rounded-lg transition-all flex items-center justify-center gap-2 disabled:opacity-50",
1443              children: [
1444                generating ? /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, {}),
1445                generating ? targetSlot === "all_icons" ? `Generating Batch (${batchProgress}%)` : "Generating..." : targetSlot === "all_icons" ? "Generate All Icons" : "Generate Image"
1446              ]
1447            }
1448          )
1449        ] }),
1450        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex flex-col items-center justify-center bg-zinc-50 dark:bg-black/30 border-2 border-dashed border-zinc-200 dark:border-zinc-800 rounded-xl min-h-[300px] relative overflow-hidden", children: isBatchMode && Object.keys(batchResults).length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full h-full flex flex-col", children: [
1451          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-100 dark:bg-zinc-900 border-b border-zinc-200 dark:border-zinc-800 flex justify-between items-center shrink-0 gap-3", children: [
1452            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-bold text-zinc-900 dark:text-white truncate", children: "Batch Preview" }),
1453            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
1454              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => {
1455                setBatchResults({});
1456                setIsBatchMode(false);
1457              }, className: "text-xs text-zinc-500 hover:text-red-500", children: "Discard" }),
1458              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: applyGeneratedImage, className: "px-3 py-1 bg-emerald-600 hover:bg-emerald-700 text-white rounded text-xs font-bold", children: "Apply" })
1459            ] })
1460          ] }),
1461          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto p-4 custom-scrollbar", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-3 gap-3", children: Object.entries(batchResults).map(([key, url]) => {
1462            var _a;
1463            return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-black border border-zinc-200 dark:border-zinc-800 rounded-lg p-2 text-center", children: [
1464              /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: url, className: "w-10 h-10 mx-auto object-contain mb-2", referrerPolicy: "no-referrer" }),
1465              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-500 truncate", children: (_a = SYSTEM_ICONS.find((i) => i.key === key)) == null ? void 0 : _a.label })
1466            ] }, key);
1467          }) }) }),
1468          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 border-t border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 flex gap-2", children: [
1469            /* @__PURE__ */ jsxRuntimeExports.jsx(
1470              "input",
1471              {
1472                value: newSetName,
1473                onChange: (e) => setNewSetName(e.target.value),
1474                placeholder: "Set Name (e.g. Neon V2)",
1475                className: "flex-1 bg-zinc-100 dark:bg-black border border-zinc-300 dark:border-zinc-700 rounded px-2 py-1 text-xs outline-none focus:border-indigo-500 text-zinc-900 dark:text-white"
1476              }
1477            ),
1478            /* @__PURE__ */ jsxRuntimeExports.jsxs(
1479              "button",
1480              {
1481                onClick: saveBatchAsSet,
1482                disabled: !newSetName,
1483                className: "px-3 py-1 bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 hover:bg-indigo-200 dark:hover:bg-indigo-800 rounded text-xs font-bold disabled:opacity-50 flex items-center gap-1",
1484                children: [
1485                  /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 12 }),
1486                  " Save Set"
1487                ]
1488              }
1489            )
1490          ] })
1491        ] }) : generatedImage ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative w-full h-full flex flex-col items-center justify-center p-6 animate-in zoom-in-95", children: [
1492          /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: generatedImage, className: "max-w-full max-h-[300px] object-contain shadow-lg rounded-lg mb-6", referrerPolicy: "no-referrer" }),
1493          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3", children: [
1494            /* @__PURE__ */ jsxRuntimeExports.jsx(
1495              "button",
1496              {
1497                onClick: () => setGeneratedImage(null),
1498                className: "px-4 py-2 bg-zinc-200 dark:bg-zinc-800 text-zinc-700 dark:text-zinc-300 rounded-lg text-sm font-bold",
1499                children: "Discard"
1500              }
1501            ),
1502            /* @__PURE__ */ jsxRuntimeExports.jsxs(
1503              "button",
1504              {
1505                onClick: applyGeneratedImage,
1506                className: "px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg text-sm font-bold flex items-center gap-2",
1507                children: [
1508                  /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { size: 16 }),
1509                  " Apply"
1510                ]
1511              }
1512            )
1513          ] })
1514        ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-center text-zinc-400", children: generating ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center", children: [
1515          /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 32, className: "animate-spin text-indigo-500 mb-2" }),
1516          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm", children: "Generating..." }),
1517          targetSlot === "all_icons" && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs mt-1 text-zinc-500", children: [
1518            batchProgress,
1519            "% Complete"
1520          ] })
1521        ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1522          /* @__PURE__ */ jsxRuntimeExports.jsx(Image, { size: 48, className: "mx-auto mb-2 opacity-50" }),
1523          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm", children: "Preview will appear here" })
1524        ] }) }) })
1525      ] }) }),
1526      activeTab === "avatars" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 max-w-4xl", children: [
1527        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [
1528          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1529            /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-lg text-zinc-900 dark:text-white", children: "Default Avatar Collection" }),
1530            /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500", children: "Manage the default avatar images available to users during registration and in profile settings." })
1531          ] }),
1532          /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: `flex items-center gap-2 px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-sm font-bold shadow-md shadow-indigo-500/20 cursor-pointer ${avatarUploading ? "opacity-50 pointer-events-none" : ""}`, children: [
1533            /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 16 }),
1534            " ",
1535            avatarUploading ? "Uploading..." : "Add Avatar",
1536            /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "file", className: "hidden", accept: "image/*", onChange: handleAvatarUpload, disabled: avatarUploading })
1537          ] })
1538        ] }),
1539        defaultAvatars.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-16 text-zinc-400", children: [
1540          /* @__PURE__ */ jsxRuntimeExports.jsx(User, { size: 48, className: "mx-auto mb-3 opacity-40" }),
1541          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-medium", children: "No default avatars yet" }),
1542          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm mt-1", children: "Upload images to create a collection for users to choose from." })
1543        ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 lg:grid-cols-6 xl:grid-cols-8 gap-4", children: defaultAvatars.map((filename) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "group relative aspect-square rounded-xl overflow-hidden border-2 border-zinc-200 dark:border-zinc-800 hover:border-indigo-400 dark:hover:border-indigo-600 transition-all shadow-sm hover:shadow-md", children: [
1544          /* @__PURE__ */ jsxRuntimeExports.jsx(
1545            "img",
1546            {
1547              src: `/storage/avatars/defaults/${filename}`,
1548              alt: filename,
1549              className: "w-full h-full object-cover"
1550            }
1551          ),
1552          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
1553            "button",
1554            {
1555              onClick: () => handleDeleteAvatar(filename),
1556              className: "p-2 bg-red-500 hover:bg-red-600 text-white rounded-full shadow-lg transition-transform hover:scale-110",
1557              title: "Delete avatar",
1558              children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 })
1559            }
1560          ) }),
1561          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/60 to-transparent p-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-white/80 truncate text-center font-medium", children: filename }) })
1562        ] }, filename)) }),
1563        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-zinc-400 pt-4 border-t border-zinc-200 dark:border-zinc-800", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { children: [
1564          "Total: ",
1565          defaultAvatars.length,
1566          " avatar(s) • Stored in ",
1567          /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "bg-zinc-100 dark:bg-zinc-800 px-1 py-0.5 rounded", children: "public/storage/avatars/defaults/" })
1568        ] }) })
1569      ] }),
1570      activeTab === "lab" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 max-w-6xl", children: [
1571        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-between items-start", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1572          /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-lg text-zinc-900 dark:text-white", children: "Hamie Lab Thumbnails" }),
1573          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-zinc-500", children: "Upload or paste screenshot mockups for each application in the Hamie Lab. Previews are generated instantly in optimized WebP format." })
1574        ] }) }),
1575        loadingLab ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center py-20", children: /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "w-8 h-8 animate-spin text-indigo-500" }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-8", children: labTools.map((tool) => {
1576          var _a;
1577          const customThumbs = (_a = config.labThumbnails) == null ? void 0 : _a[tool.id];
1578          const isFocusedForPaste = activeLabToolIdForPaste === tool.id;
1579          return /* @__PURE__ */ jsxRuntimeExports.jsxs(
1580            "div",
1581            {
1582              onClick: () => setActiveLabToolIdForPaste(tool.id),
1583              className: `group relative flex flex-col bg-zinc-50/50 dark:bg-zinc-950/20 border-2 rounded-2xl p-6 transition-all duration-300 ${isFocusedForPaste ? "border-indigo-500 ring-2 ring-indigo-500/10 shadow-lg" : "border-zinc-200 dark:border-zinc-800 hover:border-zinc-300 dark:hover:border-zinc-700"}`,
1584              children: [
1585                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-start mb-4", children: [
1586                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1587                    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-2 py-0.5 rounded-full text-[9px] font-black uppercase bg-indigo-100 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400", children: tool.id }),
1588                    /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-base font-black text-zinc-900 dark:text-white mt-1 leading-none", children: tool.name })
1589                  ] }),
1590                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
1591                    customThumbs && /* @__PURE__ */ jsxRuntimeExports.jsx(
1592                      "button",
1593                      {
1594                        onClick: (e) => {
1595                          e.stopPropagation();
1596                          handleRemoveLabThumbnail(tool.id);
1597                        },
1598                        className: "p-1.5 rounded-lg bg-red-500/10 hover:bg-red-500 text-red-500 hover:text-white transition-colors",
1599                        title: "Remove Thumbnail",
1600                        children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 14 })
1601                      }
1602                    ),
1603                    /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "p-1.5 rounded-lg bg-zinc-200 dark:bg-zinc-800 hover:bg-zinc-300 dark:hover:bg-zinc-700 text-zinc-700 dark:text-zinc-300 cursor-pointer transition-colors", title: "Upload Image File", children: [
1604                      /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 14 }),
1605                      /* @__PURE__ */ jsxRuntimeExports.jsx(
1606                        "input",
1607                        {
1608                          type: "file",
1609                          className: "hidden",
1610                          accept: "image/*",
1611                          onChange: (e) => handleLabImageSelect(e, tool)
1612                        }
1613                      )
1614                    ] })
1615                  ] })
1616                ] }),
1617                /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 mb-4 line-clamp-2 h-8", children: tool.description || "No description available." }),
1618                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4 mt-auto", children: [
1619                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1620                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] font-bold text-zinc-400 mb-1.5 uppercase tracking-tight flex justify-between", children: [
1621                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Home Page (16:9)" }),
1622                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-zinc-500 font-mono", children: "webp / 480x270" })
1623                    ] }),
1624                    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "aspect-video rounded-xl border border-zinc-200 dark:border-zinc-800 overflow-hidden bg-zinc-100 dark:bg-zinc-900 flex items-center justify-center relative", children: (customThumbs == null ? void 0 : customThumbs.home) ? /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: customThumbs.home, alt: "Home Page Thumbnail", className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center p-2", children: [
1625                      /* @__PURE__ */ jsxRuntimeExports.jsx(Image, { size: 20, className: "mx-auto mb-1 text-zinc-400 dark:text-zinc-600" }),
1626                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-zinc-400 font-medium", children: "Fallback Gradient" })
1627                    ] }) })
1628                  ] }),
1629                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1630                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] font-bold text-zinc-400 mb-1.5 uppercase tracking-tight flex justify-between", children: [
1631                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Hamie Lab (16:9)" }),
1632                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-zinc-500 font-mono", children: "webp / 640x360" })
1633                    ] }),
1634                    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "aspect-video rounded-xl border border-zinc-200 dark:border-zinc-800 overflow-hidden bg-zinc-100 dark:bg-zinc-900 flex items-center justify-center relative", children: (customThumbs == null ? void 0 : customThumbs.lab) ? /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: customThumbs.lab, alt: "Hamie Lab Thumbnail", className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center p-2", children: [
1635                      /* @__PURE__ */ jsxRuntimeExports.jsx(Image, { size: 20, className: "mx-auto mb-1 text-zinc-400 dark:text-zinc-600" }),
1636                      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-zinc-400 font-medium", children: "Fallback Gradient" })
1637                    ] }) })
1638                  ] })
1639                ] }),
1640                /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `mt-4 py-1.5 px-3 rounded-lg text-center text-[10px] font-bold transition-all ${isFocusedForPaste ? "bg-indigo-500 text-white animate-pulse" : "bg-zinc-100 dark:bg-zinc-900 text-zinc-500 group-hover:bg-zinc-200 dark:group-hover:bg-zinc-800/80 dark:text-zinc-400"}`, children: isFocusedForPaste ? "Active! Paste screenshot now (Ctrl+V)" : "Click to select and paste screenshot" })
1641              ]
1642            },
1643            tool.id
1644          );
1645        }) })
1646      ] }),
1647      selectedToolForCropping && croppingImageSrc && /* @__PURE__ */ jsxRuntimeExports.jsx(
1648        LabImageCropper,
1649        {
1650          imageSrc: croppingImageSrc,
1651          toolName: selectedToolForCropping.name,
1652          onCropComplete: handleLabCropComplete,
1653          onCancel: () => {
1654            setSelectedToolForCropping(null);
1655            setCroppingImageSrc(null);
1656          }
1657        }
1658      )
1659    ] })
1660  ] });
1661};
1662export {
1663  GraphicManager as default
1664};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.