PageSourceSearch

https://www.hamienet.com/assets/AdminModuleStudio-DNzT_tWg.js

js hamienet.com collected 2026-10-02 05:01:23 UTC 58,779 bytes, 926 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 { a as ai, g as getAiModel } from "./ai-B0Mlroaa.js";
4import { aX as ArrowLeft, eH as WandSparkles, bN as History, b2 as Upload, c4 as RotateCcw, fi as PanelLeft, b9 as Settings, bK as PanelsTopLeft, fj as Braces, dZ as Server, fk as FileCode, bo as Monitor, cf as Plus, fl as FolderSearch, fm as ArrowUpNarrowWide, fn as ArrowDownWideNarrow, cx as List, ez as CirclePlus, cd as Save, f5 as GripVertical, b5 as Trash2, cM as RefreshCw } from "./vendor-D0P4XgNj.js";
5import "./vendor-i18n-BC7ZMXWQ.js";
6import "./vendor-ai-gQv1oOjO.js";
7let DEFAULT_CODE = {
8  ui: `import React from 'react';
9
10const NewModule = () => {
11  return <div className="p-6">New Module</div>;
12};
13
14export default NewModule;`,
15  api: `// Add to lib/api.ts
16
17getNewData: async () => {
18  const res = await fetch('/api/new-module');
19  return res.json();
20},`,
21  server: `// Add to server.js
22
23app.get('/api/new-module', async (req, res) => {
24  res.json({ message: 'Hello from Server' });
25});`
26};
27let ICONS = ["box", "users", "shield", "activity", "database", "lock", "flag", "star", "music", "settings"];
28const HIDDEN_SUB_MODULES = [
29  "RegionManager",
30  "TranslationManager",
31  "AdminSettings",
32  "SocialSettings",
33  "EmailSettings",
34  "AppearanceSettings",
35  "TrustScoreConfig",
36  "CreditManager",
37  "SearchSettings",
38  "BackupManager",
39  "AiSettings"
40];
41const SNAKE_TO_LEGACY_MAP = {
42  admin_module_studio: "modules",
43  admin_settings: "settings",
44  appearance_settings: "appearance",
45  b_i_dashboard: "dashboard",
46  backup_manager: "backup",
47  credit_manager: "coins",
48  data_migration: "migration",
49  database_manager: "database",
50  dev_agent: "dev_agent",
51  docu_center: "documentation",
52  email_settings: "email_settings",
53  file_system: "files",
54  graphic_manager: "graphics",
55  help_center_manager: "help_content",
56  media_library: "media",
57  region_manager: "region_manager",
58  site_module_studio: "site_modules",
59  social_settings: "social_settings",
60  system_info: "info",
61  system_logs: "logs",
62  system_settings: "system_settings",
63  tag_manager: "tags",
64  ticket_support: "tickets",
65  translation_manager: "languages",
66  trust_safety: "trust",
67  trust_score_config: "trust_score_config",
68  user_management: "users",
69  ai_settings: "ai_settings",
70  worker_manager: "worker_manager",
71  web_scraper: "scraper"
72};
73const DEFAULT_SYSTEM_MODULES = [
74  { id: "dashboard", label: "Intelligence Dashboard" },
75  { id: "documentation", label: "DocuCenter" },
76  { id: "dev_agent", label: "AI Developer" },
77  { id: "trust", label: "Trust & Safety" },
78  { id: "users", label: "User Governance" },
79  { id: "media", label: "Content Assets" },
80  { id: "worker_manager", label: "Worker Manager" },
81  { id: "tags", label: "Tag Dictionary" },
82  { id: "tickets", label: "Support Desk" },
83  { id: "help_content", label: "Resource Center" },
84  { id: "modules", label: "Admin Module Studio" },
85  { id: "site_modules", label: "Site Architect" },
86  { id: "menu_manager", label: "Menu Manager" },
87  { id: "files", label: "File System" },
88  { id: "graphics", label: "Graphic Manager" },
89  { id: "database", label: "Schema & Data" },
90  { id: "info", label: "System Overview" },
91  { id: "logs", label: "System Logs" },
92  { id: "system_settings", label: "System Settings" },
93  { id: "backup", label: "Backup Manager" },
94  { id: "appearance", label: "Appearance" },
95  { id: "settings", label: "Admin Roles" },
96  { id: "languages", label: "Translation Manager" },
97  { id: "system_manager", label: "System Deployments" },
98  { id: "ai_settings", label: "AI Configuration" },
99  { id: "email_settings", label: "Email Configuration" },
100  { id: "search_settings", label: "Search Engine" },
101  { id: "social_settings", label: "Social & Sharing" },
102  { id: "trust_score_config", label: "Trust Score Rules" },
103  { id: "region_manager", label: "Regional Settings" },
104  { id: "migration", label: "Data Migration" },
105  { id: "coins", label: "Usage & Quotas" },
106  { id: "soundfonts", label: "Soundfont Engine" },
107  { id: "scraper", label: "Web Scraper & Importer" },
108  { id: "archive_importer", label: "High-Speed MIDI Archive Importer" },
109  { id: "cluster_sync", label: "Multi-Region Cluster" },
110  { id: "wireguard", label: "Wireguard Management" },
111  { id: "monitoring", label: "Infrastructure Analytics" },
112  { id: "live_monitor", label: "Live Monitor" },
113  { id: "gsc_settings", label: "Google Search Console" },
114  { id: "subscription_manager", label: "Supporter Registry" }
115];
116const DEFAULT_MENU_CONFIG = [
117  { id: "head-dashboard", type: "heading", label: "Dashboard & Performance" },
118  { id: "dashboard", type: "module" },
119  { id: "info", type: "module" },
120  { id: "logs", type: "module" },
121  { id: "live_monitor", type: "module" },
122  { id: "worker_manager", type: "module" },
123  { id: "system_manager", type: "module" },
124  { id: "dev_agent", type: "module" },
125  { id: "sep-dash", type: "separator" },
126  { id: "head-content", type: "heading", label: "Content & Media" },
127  { id: "media", type: "module" },
128  { id: "tags", type: "module" },
129  { id: "graphics", type: "module" },
130  { id: "files", type: "module" },
131  { id: "documentation", type: "module" },
132  { id: "soundfonts", type: "module" },
133  { id: "scraper", type: "module" },
134  { id: "sep-cont", type: "separator" },
135  { id: "head-user", type: "heading", label: "User Governance" },
136  { id: "users", type: "module" },
137  { id: "subscription_manager", type: "module" },
138  { id: "coins", type: "module" },
139  { id: "trust", type: "module" },
140  { id: "tickets", type: "module" },
141  { id: "help_content", type: "module" },
142  { id: "sep-user", type: "separator" },
143  { id: "head-creative", type: "heading", label: "Creative Studio" },
144  { id: "modules", type: "module" },
145  { id: "site_modules", type: "module" },
146  { id: "menu_manager", type: "module" },
147  { id: "languages", type: "module" },
148  { id: "region_manager", type: "module" },
149  { id: "sep-create", type: "separator" },
150  { id: "head-db", type: "heading", label: "Database Operations" },
151  { id: "backup", type: "module" },
152  { id: "database", type: "module" },
153  { id: "migration", type: "module" },
154  { id: "sep-db", type: "separator" },
155  { id: "head-sys", type: "heading", label: "System Settings" },
156  { id: "system_settings", type: "module" },
157  { id: "ai_settings", type: "module" },
158  { id: "appearance", type: "module" },
159  { id: "email_settings", type: "module" },
160  { id: "search_settings", type: "module" },
161  { id: "social_settings", type: "module" },
162  { id: "trust_score_config", type: "module" },
163  { id: "settings", type: "module" }
164];
165const ModuleCard = ({ module, onClick }) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { onClick, className: "group relative bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-5 hover:border-indigo-500 hover:shadow-lg transition-all cursor-pointer flex flex-col h-48", children: [
166  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-start mb-3", children: [
167    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `p-2 rounded-lg ${module.status === "active" ? "bg-indigo-50 text-indigo-600 dark:bg-indigo-900/20 dark:text-indigo-400" : "bg-zinc-100 text-zinc-500 dark:bg-zinc-800"}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Monitor, { size: 24 }) }),
168    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `px-2 py-0.5 rounded text-[10px] font-bold uppercase tracking-wider ${module.status === "active" ? "bg-emerald-100 text-emerald-700" : "bg-amber-100 text-amber-700"}`, children: module.status })
169  ] }),
170  /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-zinc-900 dark:text-white mb-1 group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors", children: module.name }),
171  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 line-clamp-2 mb-4", children: module.description }),
172  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-auto flex items-center justify-between text-xs text-zinc-400", children: [
173    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
174      "v",
175      1,
176      " • ",
177      module.updatedBy
178    ] }),
179    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: new Date(module.lastUpdated).toLocaleDateString() })
180  ] })
181] });
182const ModuleListItem = ({ module, onClick }) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { onClick, className: "group flex items-center gap-4 p-4 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl hover:border-indigo-500 hover:shadow-md transition-all cursor-pointer", children: [
183  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `p-2 rounded-lg shrink-0 ${module.status === "active" ? "bg-indigo-50 text-indigo-600 dark:bg-indigo-900/20 dark:text-indigo-400" : "bg-zinc-100 text-zinc-500 dark:bg-zinc-800"}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(Monitor, { size: 20 }) }),
184  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
185    /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-zinc-900 dark:text-white text-sm truncate group-hover:text-indigo-600 dark:group-hover:text-indigo-400 transition-colors", children: module.name }),
186    /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 truncate", children: module.description })
187  ] }),
188  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4 shrink-0", children: [
189    /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `px-2 py-0.5 rounded text-[10px] font-bold uppercase tracking-wider ${module.status === "active" ? "bg-emerald-100 text-emerald-700" : "bg-amber-100 text-amber-700"}`, children: module.status }),
190    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-zinc-400 flex flex-col items-end min-w-[80px]", children: [
191      /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: new Date(module.lastUpdated).toLocaleDateString() }),
192      /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] opacity-70", children: [
193        "by ",
194        module.updatedBy
195      ] })
196    ] })
197  ] })
198] });
199const MenuManager = ({ modules }) => {
200  const [menuItems, setMenuItems] = reactExports.useState([]);
201  const [availableItems, setAvailableItems] = reactExports.useState([]);
202  const [isSaving, setIsSaving] = reactExports.useState(false);
203  const [isScanning, setIsScanning] = reactExports.useState(false);
204  const [draggedIdx, setDraggedIdx] = reactExports.useState(null);
205  const [scannedModules, setScannedModules] = reactExports.useState(DEFAULT_SYSTEM_MODULES);
206  reactExports.useEffect(() => {
207    loadMenu();
208  }, [modules, scannedModules]);
209  const handleScan = async () => {
210    setIsScanning(true);
211    try {
212      const fileData = await api.readDevAgentFile(["web/src/pages/AdminPage.tsx", "src/pages/AdminPage.tsx"]);
213      const content = fileData["web/src/pages/AdminPage.tsx"] || fileData["src/pages/AdminPage.tsx"];
214      if (content) {
215        const regexNew = /['"]?([a-zA-Z0-9_-]+)['"]?\s*:\s*{\s*id:\s*['"]\1['"],\s*label:\s*['"]([^'"]+)['"]/g;
216        const regexLegacy = /['"]?([a-zA-Z0-9_-]+)['"]?\s*:\s*{\s*filename:\s*['"][^'"]+['"],\s*label:\s*['"]([^'"]+)['"]/g;
217        let match;
218        const foundModules = [];
219        while ((match = regexNew.exec(content)) !== null) {
220          foundModules.push({ id: match[1], label: match[2] });
221        }
222        while ((match = regexLegacy.exec(content)) !== null) {
223          if (!foundModules.some((m) => m.id === match[1])) {
224            foundModules.push({ id: match[1], label: match[2] });
225          }
226        }
227        if (foundModules.length > 0) {
228          setScannedModules(foundModules);
229          alert(`Scan complete. Found ${foundModules.length} registered modules.`);
230        } else {
231          alert("Scan complete but no modules found using standard registry pattern.");
232        }
233      } else {
234        alert("Could not read AdminPage.tsx. Ensure server is running.");
235      }
236    } catch (e) {
237      console.error(e);
238      alert("Scan failed.");
239    } finally {
240      setIsScanning(false);
241    }
242  };
243  const loadMenu = async () => {
244    const setting = await api.getSystemSetting("admin_menu_config");
245    const settingValue = setting == null ? void 0 : setting.value;
246    const currentConfig = settingValue && settingValue.length > 0 ? settingValue : DEFAULT_MENU_CONFIG;
247    const activeIds = new Set(currentConfig.map((i) => i.id));
248    const available = [];
249    scannedModules.forEach((sys) => {
250      if (!activeIds.has(sys.id)) {
251        available.push({ id: sys.id, label: sys.label, type: "module", isSystem: true });
252      }
253    });
254    modules.forEach((mod) => {
255      const legacyId = SNAKE_TO_LEGACY_MAP[mod.id] || mod.id;
256      if (activeIds.has(mod.id) || activeIds.has(legacyId)) return;
257      if (!available.some((a) => a.id === mod.id || a.id === legacyId)) {
258        available.push({ id: mod.id, label: mod.name, type: "module", isSystem: false });
259      }
260    });
261    const hydratedMenu = currentConfig.map((item) => {
262      if (item.type === "separator") return { ...item, label: "--- Separator ---" };
263      if (item.type === "heading") return { ...item, label: item.label || "New Section" };
264      const sys = scannedModules.find((s) => s.id === item.id);
265      if (sys) return { ...item, label: sys.label, isSystem: true };
266      const mod = modules.find((m) => m.id === item.id || SNAKE_TO_LEGACY_MAP[m.id] === item.id);
267      if (mod) return { ...item, label: mod.name, isSystem: false };
268      return { ...item, label: `Unknown Module (${item.id})`, isMissing: true };
269    });
270    setMenuItems(hydratedMenu);
271    setAvailableItems(available);
272  };
273  const handleSave = async () => {
274    setIsSaving(true);
275    const configToSave = menuItems.map((item) => ({
276      id: item.id,
277      type: item.type,
278      label: item.type === "heading" ? item.label : void 0
279    }));
280    await api.saveSystemSetting("admin_menu_config", configToSave);
281    setIsSaving(false);
282    alert("Menu Configuration Saved.");
283  };
284  const addToMenu = (item) => {
285    setMenuItems([...menuItems, item]);
286    setAvailableItems(availableItems.filter((i) => i.id !== item.id));
287  };
288  const removeFromMenu = (index) => {
289    const item = menuItems[index];
290    setMenuItems(menuItems.filter((_, i) => i !== index));
291    if (item.type === "module") {
292      setAvailableItems([...availableItems, item]);
293    }
294  };
295  const addSeparator = () => {
296    setMenuItems([...menuItems, { id: `sep-${Date.now()}`, type: "separator", label: "--- Separator ---" }]);
297  };
298  const addHeading = () => {
299    setMenuItems([...menuItems, { id: `heading-${Date.now()}`, type: "heading", label: "NEW SECTION" }]);
300  };
301  const handleReset = () => {
302    if (confirm("Reset menu to default layout?")) {
303      const currentConfig = DEFAULT_MENU_CONFIG;
304      const activeIds = new Set(currentConfig.map((i) => i.id));
305      const available = [];
306      scannedModules.forEach((sys) => {
307        if (!activeIds.has(sys.id)) available.push({ id: sys.id, label: sys.label, type: "module", isSystem: true });
308      });
309      modules.forEach((mod) => {
310        if (!activeIds.has(mod.id)) available.push({ id: mod.id, label: mod.name, type: "module", isSystem: false });
311      });
312      const hydratedMenu = currentConfig.map((item) => {
313        if (item.type === "separator") return { ...item, label: "--- Separator ---" };
314        if (item.type === "heading") return { ...item, label: item.label || "New Section" };
315        const sys = scannedModules.find((s) => s.id === item.id);
316        if (sys) return { ...item, label: sys.label, isSystem: true };
317        const mod = modules.find((m) => m.id === item.id);
318        if (mod) return { ...item, label: mod.name, isSystem: false };
319        return { ...item, label: "Unknown Module (Missing)", isMissing: true };
320      });
321      setMenuItems(hydratedMenu);
322      setAvailableItems(available);
323    }
324  };
325  const onDragStart = (e, index) => {
326    setDraggedIdx(index);
327    e.dataTransfer.effectAllowed = "move";
328    e.dataTransfer.setData("text/plain", index.toString());
329  };
330  const onDragOver = (e, index) => {
331    e.preventDefault();
332    e.dataTransfer.dropEffect = "move";
333  };
334  const onDrop = (e, dropIndex) => {
335    e.preventDefault();
336    const dragIndexStr = e.dataTransfer.getData("text/plain");
337    const dragIndex = parseInt(dragIndexStr);
338    const actualDragIdx = !isNaN(dragIndex) ? dragIndex : draggedIdx;
339    if (actualDragIdx === null || actualDragIdx === dropIndex) return;
340    const newItems = [...menuItems];
341    const [draggedItem] = newItems.splice(actualDragIdx, 1);
342    newItems.splice(dropIndex, 0, draggedItem);
343    setMenuItems(newItems);
344    setDraggedIdx(null);
345  };
346  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex h-full gap-6", children: [
347    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden shadow-sm", children: [
348      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 border-b border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 flex justify-between items-center", children: [
349        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-zinc-900 dark:text-white", children: "Active Sidebar Menu" }),
350        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
351          /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleReset, className: "px-3 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-zinc-700 dark:text-zinc-300", children: "Reset" }),
352          /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: addSeparator, className: "px-3 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-zinc-700 dark:text-zinc-300 flex items-center gap-1", children: [
353            /* @__PURE__ */ jsxRuntimeExports.jsx(CirclePlus, { size: 14 }),
354            " Separator"
355          ] }),
356          /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: addHeading, className: "px-3 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-zinc-700 dark:text-zinc-300 flex items-center gap-1", children: [
357            /* @__PURE__ */ jsxRuntimeExports.jsx(CirclePlus, { size: 14 }),
358            " Section Header"
359          ] }),
360          /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleSave, disabled: isSaving, className: "px-4 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded text-xs font-bold flex items-center gap-1 disabled:opacity-50", children: isSaving ? "Saving..." : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
361            /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 14 }),
362            " Save Layout"
363          ] }) })
364        ] })
365      ] }),
366      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto p-2 space-y-1 bg-zinc-100 dark:bg-zinc-950/50", children: [
367        menuItems.map((item, idx) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
368          "div",
369          {
370            draggable: true,
371            onDragStart: (e) => onDragStart(e, idx),
372            onDragOver: (e) => onDragOver(e),
373            onDrop: (e) => onDrop(e, idx),
374            className: `flex items-center gap-3 p-2 rounded-lg border cursor-move transition-all ${draggedIdx === idx ? "opacity-50 border-dashed border-indigo-500 bg-indigo-50 dark:bg-indigo-900/10" : item.type === "separator" ? "bg-zinc-200/50 dark:bg-zinc-800/50 border-dashed border-zinc-400 dark:border-zinc-600" : item.type === "heading" ? "bg-indigo-50/50 dark:bg-indigo-950/10 border-indigo-200 dark:border-indigo-800 shadow-sm" : "bg-white dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 shadow-sm hover:border-indigo-300 dark:hover:border-indigo-700"}`,
375            children: [
376              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-0.5 text-zinc-400 cursor-grab active:cursor-grabbing", children: /* @__PURE__ */ jsxRuntimeExports.jsx(GripVertical, { size: 16 }) }),
377              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: item.type === "separator" ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-mono text-zinc-500 uppercase tracking-widest text-center block w-full", children: "Separator" }) : item.type === "heading" ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
378                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold uppercase tracking-wider text-indigo-500 shrink-0", children: "Section:" }),
379                /* @__PURE__ */ jsxRuntimeExports.jsx(
380                  "input",
381                  {
382                    type: "text",
383                    value: item.label,
384                    onChange: (e) => {
385                      const newItems = [...menuItems];
386                      newItems[idx].label = e.target.value;
387                      setMenuItems(newItems);
388                    },
389                    className: "bg-transparent border-b border-zinc-300 dark:border-zinc-700 focus:border-indigo-500 text-xs font-black uppercase tracking-wider text-zinc-800 dark:text-white outline-none w-full px-1 py-0.5",
390                    placeholder: "Enter section name..."
391                  }
392                )
393              ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
394                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-zinc-800 dark:text-zinc-200", children: item.label }),
395                item.isSystem ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] bg-indigo-100 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400 px-1.5 rounded", children: "System" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] bg-emerald-100 dark:bg-emerald-900/30 text-emerald-600 dark:text-emerald-400 px-1.5 rounded", children: "Dynamic" }),
396                item.isMissing && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] bg-red-100 text-red-600 px-1.5 rounded", children: "Missing" })
397              ] }) }),
398              /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => removeFromMenu(idx), className: "p-1.5 text-zinc-400 hover:text-red-500 transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 16 }) })
399            ]
400          },
401          item.id
402        )),
403        menuItems.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-8 text-center text-zinc-400 text-sm", children: "Menu is empty. Add items from the list." })
404      ] })
405    ] }),
406    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-80 flex flex-col bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden shadow-sm", children: [
407      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 border-b border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 flex justify-between items-center", children: [
408        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-zinc-900 dark:text-white", children: "Available Items" }),
409        /* @__PURE__ */ jsxRuntimeExports.jsxs(
410          "button",
411          {
412            onClick: handleScan,
413            disabled: isScanning,
414            className: "text-xs bg-indigo-100 hover:bg-indigo-200 text-indigo-700 dark:bg-indigo-900/40 dark:hover:bg-indigo-900/60 dark:text-indigo-300 font-bold px-2 py-1 rounded flex items-center gap-1 transition-colors border border-indigo-200 dark:border-indigo-800 shadow-sm",
415            title: "Scan AdminPage.tsx for new modules",
416            children: [
417              /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 12, className: isScanning ? "animate-spin" : "" }),
418              " ",
419              isScanning ? "Scanning..." : "Scan"
420            ]
421          }
422        )
423      ] }),
424      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto p-2 space-y-1", children: [
425        availableItems.map((item) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between p-3 bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg hover:border-indigo-400 dark:hover:border-indigo-600 transition-colors group", children: [
426          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
427            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-medium text-zinc-700 dark:text-zinc-300", children: item.label }),
428            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-400", children: item.isSystem ? "System Module" : "Custom Module" })
429          ] }),
430          /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => addToMenu(item), className: "p-1.5 bg-zinc-100 dark:bg-zinc-700 hover:bg-indigo-100 dark:hover:bg-indigo-900/30 text-zinc-500 hover:text-indigo-600 dark:hover:text-indigo-400 rounded-full transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 16 }) })
431        ] }, item.id)),
432        availableItems.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-8 text-center text-zinc-400 text-sm", children: "All items added." })
433      ] })
434    ] })
435  ] });
436};
437const AdminModuleStudio = ({ refreshTrigger }) => {
438  const [modules, setModules] = reactExports.useState([]);
439  const [studioConfig, setStudioConfig] = reactExports.useState(null);
440  reactExports.useEffect(() => {
441    fetch("/api/admin/studio/config").then((res) => res.json()).then((data) => {
442      if (data.admin) {
443        if (data.admin.defaultCode) DEFAULT_CODE = data.admin.defaultCode;
444        if (data.admin.icons) ICONS = data.admin.icons;
445        setStudioConfig(data.admin);
446      }
447    }).catch(console.error);
448  }, []);
449  const [activeDraft, setActiveDraft] = reactExports.useState(null);
450  const [activeTab, setActiveTab] = reactExports.useState("ui");
451  const [isAiGenerating, setIsAiGenerating] = reactExports.useState(false);
452  const [prompt, setPrompt] = reactExports.useState("");
453  const [deployStep, setDeployStep] = reactExports.useState(0);
454  const [history, setHistory] = reactExports.useState([]);
455  const [showHistory, setShowHistory] = reactExports.useState(false);
456  const [mainViewMode, setMainViewMode] = reactExports.useState("studio");
457  const [viewMode, setViewMode] = reactExports.useState("list");
458  const [sortBy, setSortBy] = reactExports.useState("updated");
459  const [sortDir, setSortDir] = reactExports.useState("desc");
460  reactExports.useEffect(() => {
461    loadModules();
462  }, [refreshTrigger]);
463  reactExports.useEffect(() => {
464    if (activeDraft && !activeDraft.isNew) {
465      loadHistory(activeDraft.id);
466    }
467  }, [activeDraft == null ? void 0 : activeDraft.id]);
468  const loadModules = async () => {
469    const data = await api.getAdminModules();
470    setModules(data);
471  };
472  const loadHistory = async (id) => {
473    const data = await api.getModuleHistory(id);
474    setHistory(data);
475  };
476  const sortedModules = [...modules].sort((a, b) => {
477    let res = 0;
478    if (sortBy === "name") res = a.name.localeCompare(b.name);
479    else if (sortBy === "status") res = a.status.localeCompare(b.status);
480    else res = new Date(a.lastUpdated).getTime() - new Date(b.lastUpdated).getTime();
481    return sortDir === "asc" ? res : -res;
482  });
483  const handleSelect = (mod) => {
484    setActiveDraft({
485      id: mod.id,
486      name: mod.name,
487      description: mod.description,
488      path: mod.path,
489      iconKey: mod.iconKey || "box",
490      addToSidebar: true,
491      requiresSuperAdmin: false,
492      codes: {
493        ui: mod.content,
494        api: `// API logic for ${mod.name} would appear here`,
495        server: `// Server logic for ${mod.name} would appear here`
496      },
497      isNew: false
498    });
499    setShowHistory(false);
500  };
501  const handleNew = () => {
502    setActiveDraft({
503      id: `mod-${Date.now()}`,
504      name: "Untitled Module",
505      description: "A new system module.",
506      path: "/src/pages/AdminModules/Untitled.tsx",
507      iconKey: "box",
508      addToSidebar: true,
509      requiresSuperAdmin: false,
510      codes: { ...DEFAULT_CODE },
511      isNew: true
512    });
513    setHistory([]);
514    setShowHistory(false);
515  };
516  const handleScanFiles = async () => {
517    var _a;
518    if (!confirm("Scan file system for unregistered Admin Modules? This will add any found files in 'pages/AdminModules' to the database.")) return;
519    try {
520      const files = await api.getFileSystem();
521      const moduleFiles = files.filter(
522        (f) => (f.path.startsWith("/src/pages/AdminModules/") || f.path.startsWith("/web/src/pages/AdminModules/")) && f.path.endsWith(".tsx") && !HIDDEN_SUB_MODULES.some((hidden) => f.path.includes(hidden))
523      );
524      const dbModules = await api.getAdminModules();
525      const existingPaths = new Set(dbModules.map((m) => m.path));
526      let addedCount = 0;
527      for (const file of moduleFiles) {
528        const normalizedPath = file.path.startsWith("/") ? file.path : "/" + file.path;
529        const alreadyExists = Array.from(existingPaths).some(
530          (p) => (p.startsWith("/") ? p : "/" + p) === normalizedPath
531        );
532        if (!alreadyExists) {
533          const filename = ((_a = normalizedPath.split("/").pop()) == null ? void 0 : _a.replace(".tsx", "")) || "Unknown";
534          const name = filename.replace(/([A-Z])/g, " $1").trim();
535          const id = filename.toLowerCase().replace(/\s+/g, "_");
536          await api.createAdminModule(
537            name,
538            normalizedPath,
539            "Automatically imported from file system.",
540            file.content,
541            "System Scanner"
542          );
543          addedCount++;
544        }
545      }
546      alert(`Scan complete. Registered ${addedCount} new modules.`);
547      loadModules();
548    } catch (e) {
549      console.error(e);
550      alert("Scan failed.");
551    }
552  };
553  const handleAiGenerate = async () => {
554    if (!prompt) return;
555    setIsAiGenerating(true);
556    try {
557      const currentCode = (activeDraft == null ? void 0 : activeDraft.codes.ui) || "";
558      const isUpdate = !(activeDraft == null ? void 0 : activeDraft.isNew) && currentCode.length > 50;
559      const uiPrompt = isUpdate ? `You are an expert React Developer. UPDATE the following existing component code based on the user request: "${prompt}".
560                   Current Code:
561                   ${currentCode}
562                   
563                   Return the FULL updated code. Do not use markdown.` : `You are a Full Stack Engineer. Generate a React Admin Dashboard Component based on: "${prompt}".
564                   Requirements:
565                   - Use Tailwind CSS for styling (dark mode compatible).
566                   - Use Lucide React icons.
567                   - Export as default.
568                   - Provide ONLY code, no markdown.`;
569      const uiResponse = await ai.models.generateContent({
570        model: getAiModel("gemini-3-pro-preview"),
571        // High reasoning
572        contents: uiPrompt
573      });
574      const uiCode = (uiResponse.text || "").replace(/^```(tsx|jsx|javascript)?/, "").replace(/```$/, "").trim();
575      if (activeDraft) {
576        setActiveDraft({
577          ...activeDraft,
578          // If it was new, suggest a name based on prompt
579          name: activeDraft.isNew ? prompt.split(" ")[0] + " Manager" : activeDraft.name,
580          description: activeDraft.isNew ? `AI Generated module for: ${prompt}` : activeDraft.description,
581          codes: {
582            ...activeDraft.codes,
583            ui: uiCode
584          }
585        });
586      }
587    } catch (e) {
588      console.error("AI Gen Error", e);
589      alert("Failed to generate module. Check API Key.");
590    } finally {
591      setIsAiGenerating(false);
592      setPrompt("");
593    }
594  };
595  const handleDeploy = async () => {
596    setDeployStep(2);
597    await new Promise((r) => setTimeout(r, 1e3));
598    if (activeDraft) {
599      if (activeDraft.isNew) {
600        await api.createAdminModule(activeDraft.name, activeDraft.path, activeDraft.description, activeDraft.codes.ui, "Admin (Architect)");
601      } else {
602        await api.updateAdminModule(activeDraft.id, activeDraft.codes.ui, "Deployed via Studio", "Admin");
603      }
604    }
605    setDeployStep(0);
606    loadModules();
607    if (activeDraft && !activeDraft.isNew) loadHistory(activeDraft.id);
608    alert("Module Deployed Successfully!");
609  };
610  const handleRevert = async (version) => {
611    if (!activeDraft || !confirm(`Revert to version from ${new Date(version.createdAt).toLocaleString()}?`)) return;
612    await api.revertModuleVersion(activeDraft.id, version.id);
613    const updatedHistory = await api.getModuleHistory(activeDraft.id);
614    const latestModule = (await api.getAdminModules()).find((m) => m.id === activeDraft.id);
615    if (latestModule) {
616      setActiveDraft((prev) => prev ? {
617        ...prev,
618        codes: { ...prev.codes, ui: latestModule.content }
619      } : null);
620      setHistory(updatedHistory);
621    }
622  };
623  if (activeDraft) {
624    return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full bg-zinc-50 dark:bg-black fixed inset-0 z-[50]", children: [
625      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-16 border-b border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-900 px-6 flex items-center justify-between shrink-0", children: [
626        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [
627          /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setActiveDraft(null), className: "p-2 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-full transition-colors text-zinc-500", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { size: 20 }) }),
628          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [
629            /* @__PURE__ */ jsxRuntimeExports.jsx(
630              "input",
631              {
632                className: "font-bold text-zinc-900 dark:text-white bg-transparent outline-none placeholder:text-zinc-400",
633                value: activeDraft.name,
634                onChange: (e) => setActiveDraft({ ...activeDraft, name: e.target.value }),
635                placeholder: "Module Name"
636              }
637            ),
638            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-xs text-zinc-500", children: [
639              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: activeDraft.path }),
640              !activeDraft.isNew && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "bg-zinc-100 dark:bg-zinc-800 px-1.5 rounded", children: [
641                "v",
642                history.length + 1
643              ] })
644            ] })
645          ] })
646        ] }),
647        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
648          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "hidden md:flex items-center bg-zinc-100 dark:bg-zinc-800 rounded-lg p-1 border border-zinc-200 dark:border-zinc-700", children: [
649            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-2 text-indigo-500", children: /* @__PURE__ */ jsxRuntimeExports.jsx(WandSparkles, { size: 16, className: isAiGenerating ? "animate-spin" : "" }) }),
650            /* @__PURE__ */ jsxRuntimeExports.jsx(
651              "input",
652              {
653                value: prompt,
654                onChange: (e) => setPrompt(e.target.value),
655                onKeyDown: (e) => e.key === "Enter" && handleAiGenerate(),
656                placeholder: activeDraft.isNew ? "Describe a new module..." : "Describe changes...",
657                className: "bg-transparent border-none outline-none text-xs w-64 text-zinc-900 dark:text-white",
658                disabled: isAiGenerating
659              }
660            ),
661            /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleAiGenerate, disabled: !prompt || isAiGenerating, className: "px-3 py-1 bg-white dark:bg-zinc-700 rounded-md text-xs font-bold shadow-sm hover:text-indigo-500 transition-colors", children: activeDraft.isNew ? "Generate" : "Update" })
662          ] }),
663          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-8 w-px bg-zinc-200 dark:bg-zinc-800 mx-2" }),
664          /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setShowHistory(!showHistory), className: `p-2 rounded-lg hover:bg-zinc-100 dark:hover:bg-zinc-800 text-zinc-500 transition-colors ${showHistory ? "bg-zinc-100 dark:bg-zinc-800 text-indigo-500" : ""}`, title: "Version History", children: /* @__PURE__ */ jsxRuntimeExports.jsx(History, { size: 20 }) }),
665          /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => setDeployStep(1), className: "flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-bold bg-indigo-600 hover:bg-indigo-700 text-white transition-colors shadow-lg shadow-indigo-500/20", children: [
666            /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 16 }),
667            " Deploy"
668          ] })
669        ] })
670      ] }),
671      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex overflow-hidden", children: [
672        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-72 bg-white dark:bg-zinc-900 border-r border-zinc-200 dark:border-zinc-800 flex flex-col shrink-0 transition-all", children: showHistory ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full", children: [
673          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 border-b border-zinc-200 dark:border-zinc-800 font-bold text-xs uppercase text-zinc-500 flex justify-between items-center", children: [
674            "Version History",
675            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "bg-zinc-100 dark:bg-zinc-800 px-1.5 py-0.5 rounded", children: history.length })
676          ] }),
677          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto p-2 space-y-2", children: [
678            history.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-center text-xs text-zinc-500 py-4", children: "No history available." }),
679            history.map((ver) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 rounded-lg border border-zinc-200 dark:border-zinc-800 bg-zinc-50 dark:bg-zinc-950 hover:border-indigo-300 dark:hover:border-indigo-700 transition-colors group", children: [
680              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-start mb-1", children: [
681                /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-bold text-xs text-zinc-900 dark:text-white", children: [
682                  "v",
683                  ver.versionNumber
684                ] }),
685                /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-500", children: new Date(ver.createdAt).toLocaleDateString() })
686              ] }),
687              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 line-clamp-2 mb-2", children: ver.changeLog }),
688              /* @__PURE__ */ jsxRuntimeExports.jsxs(
689                "button",
690                {
691                  onClick: () => handleRevert(ver),
692                  className: "w-full py-1 text-[10px] font-bold bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded text-zinc-600 dark:text-zinc-400 hover:text-indigo-500 hover:border-indigo-500 transition-colors flex items-center justify-center gap-1",
693                  children: [
694                    /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 10 }),
695                    " Revert to this version"
696                  ]
697                }
698              )
699            ] }, ver.id))
700          ] })
701        ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
702          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 border-b border-zinc-200 dark:border-zinc-800 font-bold text-xs uppercase text-zinc-500", children: "Configuration" }),
703          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 space-y-6 overflow-y-auto", children: [
704            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
705              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-2", children: "Description" }),
706              /* @__PURE__ */ jsxRuntimeExports.jsx(
707                "textarea",
708                {
709                  className: "w-full bg-zinc-50 dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800 rounded-lg p-3 text-xs resize-none h-24 focus:border-indigo-500 outline-none text-zinc-900 dark:text-white",
710                  value: activeDraft.description,
711                  onChange: (e) => setActiveDraft({ ...activeDraft, description: e.target.value })
712                }
713              )
714            ] }),
715            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
716              /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-xs font-bold text-zinc-700 dark:text-zinc-300 mb-2", children: "Icon" }),
717              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-5 gap-2", children: ICONS.map((icon) => /* @__PURE__ */ jsxRuntimeExports.jsx(
718                "button",
719                {
720                  onClick: () => setActiveDraft({ ...activeDraft, iconKey: icon }),
721                  className: `aspect-square rounded-lg flex items-center justify-center border transition-all ${activeDraft.iconKey === icon ? "bg-indigo-50 border-indigo-500 text-indigo-600" : "bg-zinc-50 dark:bg-zinc-800 border-transparent text-zinc-400 hover:border-zinc-300"}`,
722                  children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-4 h-4 bg-current rounded-full" })
723                },
724                icon
725              )) })
726            ] }),
727            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [
728              /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-3 p-3 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg cursor-pointer hover:bg-zinc-100 dark:hover:bg-zinc-800 border border-transparent hover:border-zinc-300 dark:hover:border-zinc-700 transition-all", children: [
729                /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: activeDraft.addToSidebar, onChange: (e) => setActiveDraft({ ...activeDraft, addToSidebar: e.target.checked }), className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500" }),
730                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
731                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-bold text-zinc-900 dark:text-white flex items-center gap-2", children: [
732                    /* @__PURE__ */ jsxRuntimeExports.jsx(PanelLeft, { size: 14 }),
733                    " Add to Sidebar"
734                  ] }),
735                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-500", children: "Auto-register in AdminPage" })
736                ] })
737              ] }),
738              /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-3 p-3 bg-zinc-50 dark:bg-zinc-800/50 rounded-lg cursor-pointer hover:bg-zinc-100 dark:hover:bg-zinc-800 border border-transparent hover:border-zinc-300 dark:hover:border-zinc-700 transition-all", children: [
739                /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", checked: activeDraft.requiresSuperAdmin, onChange: (e) => setActiveDraft({ ...activeDraft, requiresSuperAdmin: e.target.checked }), className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500" }),
740                /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
741                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-bold text-zinc-900 dark:text-white flex items-center gap-2", children: [
742                    /* @__PURE__ */ jsxRuntimeExports.jsx(Settings, { size: 14 }),
743                    " Super Admin Only"
744                  ] }),
745                  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-500", children: "Restrict access level" })
746                ] })
747              ] })
748            ] })
749          ] })
750        ] }) }),
751        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col bg-[#1e1e1e]", children: [
752          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center bg-[#252526] border-b border-[#333]", children: [
753            /* @__PURE__ */ jsxRuntimeExports.jsxs(
754              "button",
755              {
756                onClick: () => setActiveTab("ui"),
757                className: `px-6 py-3 text-xs font-bold flex items-center gap-2 border-r border-[#333] transition-colors ${activeTab === "ui" ? "bg-[#1e1e1e] text-white border-t-2 border-t-indigo-500" : "text-zinc-500 hover:text-zinc-300"}`,
758                children: [
759                  /* @__PURE__ */ jsxRuntimeExports.jsx(PanelsTopLeft, { size: 14 }),
760                  " UI Component (.tsx)"
761                ]
762              }
763            ),
764            /* @__PURE__ */ jsxRuntimeExports.jsxs(
765              "button",
766              {
767                onClick: () => setActiveTab("api"),
768                className: `px-6 py-3 text-xs font-bold flex items-center gap-2 border-r border-[#333] transition-colors ${activeTab === "api" ? "bg-[#1e1e1e] text-white border-t-2 border-t-indigo-500" : "text-zinc-500 hover:text-zinc-300"}`,
769                children: [
770                  /* @__PURE__ */ jsxRuntimeExports.jsx(Braces, { size: 14 }),
771                  " Client API (.ts)"
772                ]
773              }
774            ),
775            /* @__PURE__ */ jsxRuntimeExports.jsxs(
776              "button",
777              {
778                onClick: () => setActiveTab("server"),
779                className: `px-6 py-3 text-xs font-bold flex items-center gap-2 border-r border-[#333] transition-colors ${activeTab === "server" ? "bg-[#1e1e1e] text-white border-t-2 border-t-indigo-500" : "text-zinc-500 hover:text-zinc-300"}`,
780                children: [
781                  /* @__PURE__ */ jsxRuntimeExports.jsx(Server, { size: 14 }),
782                  " Server Routes (.js)"
783                ]
784              }
785            )
786          ] }),
787          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 relative", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
788            "textarea",
789            {
790              value: activeDraft.codes[activeTab],
791              onChange: (e) => setActiveDraft({
792                ...activeDraft,
793                codes: { ...activeDraft.codes, [activeTab]: e.target.value }
794              }),
795              className: "absolute inset-0 w-full h-full bg-transparent text-zinc-300 font-mono text-sm p-6 resize-none outline-none",
796              spellCheck: false
797            }
798          ) })
799        ] })
800      ] }),
801      deployStep > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "fixed inset-0 z-[100] flex items-center justify-center p-4", children: [
802        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-0 bg-black/80 backdrop-blur-sm", onClick: () => setDeployStep(0) }),
803        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "relative w-full max-w-2xl bg-white dark:bg-zinc-900 rounded-xl shadow-2xl p-8 border border-zinc-200 dark:border-zinc-800 animate-in zoom-in-95", children: deployStep === 1 ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
804          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4 mb-6", children: [
805            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3 bg-indigo-100 dark:bg-indigo-900/30 rounded-full text-indigo-600 dark:text-indigo-400", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 24 }) }),
806            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
807              /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: "Deploy Module?" }),
808              /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 dark:text-zinc-400", children: activeDraft.isNew ? "This will create a new module and register system files." : "This will update the live module and archive the current version." })
809            ] })
810          ] }),
811          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-3 mb-8", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between p-3 bg-zinc-50 dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700", children: [
812            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
813              /* @__PURE__ */ jsxRuntimeExports.jsx(FileCode, { size: 18, className: "text-blue-500" }),
814              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-bold text-zinc-700 dark:text-zinc-300", children: activeDraft.path })
815            ] }),
816            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-xs px-2 py-0.5 rounded font-bold ${activeDraft.isNew ? "bg-emerald-100 text-emerald-700" : "bg-amber-100 text-amber-700"}`, children: activeDraft.isNew ? "CREATE" : "UPDATE" })
817          ] }) }),
818          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-3 justify-end", children: [
819            /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setDeployStep(0), className: "px-4 py-2 text-zinc-500 hover:text-zinc-900 dark:hover:text-white font-bold", children: "Cancel" }),
820            /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleDeploy, className: "px-6 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg font-bold shadow-lg shadow-indigo-500/20", children: "Confirm Deployment" })
821          ] })
822        ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center py-8", children: [
823          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-16 h-16 border-4 border-indigo-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" }),
824          /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-xl font-bold text-zinc-900 dark:text-white", children: "Deploying..." }),
825          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 mt-2", children: "Compiling assets and updating database." })
826        ] }) })
827      ] })
828    ] });
829  }
830  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-6 max-w-[1600px] mx-auto h-full flex flex-col animate-in fade-in", children: [
831    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-4", children: [
832      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
833        /* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-2xl font-bold text-zinc-900 dark:text-white flex items-center gap-2", children: [
834          /* @__PURE__ */ jsxRuntimeExports.jsx(Monitor, { size: 28, className: "text-indigo-500" }),
835          " Admin Module Studio"
836        ] }),
837        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-zinc-500 dark:text-zinc-400 mt-1", children: "Full-stack module generator and menu manager." })
838      ] }),
839      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-zinc-100 dark:bg-zinc-800 p-1 rounded-lg border border-zinc-200 dark:border-zinc-700", children: [
840        /* @__PURE__ */ jsxRuntimeExports.jsx(
841          "button",
842          {
843            onClick: () => setMainViewMode("studio"),
844            className: `px-4 py-2 rounded-md text-sm font-bold transition-all ${mainViewMode === "studio" ? "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"}`,
845            children: "Module Editor"
846          }
847        ),
848        /* @__PURE__ */ jsxRuntimeExports.jsx(
849          "button",
850          {
851            onClick: () => setMainViewMode("menu"),
852            className: `px-4 py-2 rounded-md text-sm font-bold transition-all ${mainViewMode === "menu" ? "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"}`,
853            children: "Menu Manager"
854          }
855        )
856      ] })
857    ] }),
858    mainViewMode === "menu" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(MenuManager, { modules }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
859      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row justify-between items-end sm:items-center mb-6 gap-4", children: [
860        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
861          /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: handleNew, className: "bg-zinc-900 dark:bg-white text-white dark:text-black hover:opacity-90 px-4 py-2 rounded-lg font-bold flex items-center gap-2 transition-all", children: [
862            /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 18 }),
863            " New Module"
864          ] }),
865          /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: handleScanFiles, className: "bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 hover:bg-indigo-200 dark:hover:bg-indigo-900/50 px-4 py-2 rounded-lg font-bold flex items-center gap-2 transition-all border border-indigo-200 dark:border-indigo-800", children: [
866            /* @__PURE__ */ jsxRuntimeExports.jsx(FolderSearch, { size: 18 }),
867            " Scan Files"
868          ] }),
869          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-8 w-px bg-zinc-200 dark:bg-zinc-800 mx-2" }),
870          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-lg p-1", children: [
871            /* @__PURE__ */ jsxRuntimeExports.jsxs(
872              "select",
873              {
874                value: sortBy,
875                onChange: (e) => setSortBy(e.target.value),
876                className: "bg-transparent text-xs font-bold text-zinc-700 dark:text-zinc-300 outline-none px-2 py-1 cursor-pointer",
877                children: [
878                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "updated", children: "Last Updated" }),
879                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "name", children: "Name" }),
880                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "status", children: "Status" })
881                ]
882              }
883            ),
884            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-px h-4 bg-zinc-200 dark:bg-zinc-800 mx-1" }),
885            /* @__PURE__ */ jsxRuntimeExports.jsx(
886              "button",
887              {
888                onClick: () => setSortDir((prev) => prev === "asc" ? "desc" : "asc"),
889                className: "p-1 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded text-zinc-500",
890                children: sortDir === "asc" ? /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowUpNarrowWide, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowDownWideNarrow, { size: 14 })
891              }
892            )
893          ] })
894        ] }),
895        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-zinc-100 dark:bg-zinc-800 p-1 rounded-lg border border-zinc-200 dark:border-zinc-700", children: [
896          /* @__PURE__ */ jsxRuntimeExports.jsx(
897            "button",
898            {
899              onClick: () => setViewMode("grid"),
900              className: `p-1.5 rounded-md transition-all ${viewMode === "grid" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-zinc-300"}`,
901              children: /* @__PURE__ */ jsxRuntimeExports.jsx(PanelsTopLeft, { size: 16 })
902            }
903          ),
904          /* @__PURE__ */ jsxRuntimeExports.jsx(
905            "button",
906            {
907              onClick: () => setViewMode("list"),
908              className: `p-1.5 rounded-md transition-all ${viewMode === "list" ? "bg-white dark:bg-zinc-700 shadow text-indigo-600 dark:text-indigo-400" : "text-zinc-500 hover:text-zinc-900 dark:hover:text-zinc-300"}`,
909              children: /* @__PURE__ */ jsxRuntimeExports.jsx(List, { size: 16 })
910            }
911          )
912        ] })
913      ] }),
914      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: viewMode === "grid" ? "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 pb-20 overflow-y-auto" : "flex flex-col gap-3 pb-20 overflow-y-auto", children: [
915        sortedModules.map((mod) => viewMode === "grid" ? /* @__PURE__ */ jsxRuntimeExports.jsx(ModuleCard, { module: mod, onClick: () => handleSelect(mod) }, mod.id) : /* @__PURE__ */ jsxRuntimeExports.jsx(ModuleListItem, { module: mod, onClick: () => handleSelect(mod) }, mod.id)),
916        viewMode === "grid" && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: handleNew, className: "border-2 border-dashed border-zinc-300 dark:border-zinc-800 rounded-xl p-5 flex flex-col items-center justify-center text-zinc-400 hover:border-indigo-500 hover:text-indigo-500 transition-all h-48 group bg-zinc-50/50 dark:bg-zinc-900/50", children: [
917          /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 rounded-full bg-zinc-100 dark:bg-zinc-800 group-hover:bg-indigo-50 dark:group-hover:bg-indigo-900/20 flex items-center justify-center mb-2 transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 24 }) }),
918          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-bold text-sm", children: "Create New" })
919        ] })
920      ] })
921    ] })
922  ] });
923};
924export {
925  AdminModuleStudio as default
926};

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.