@rslsp1/fa-app-tools 1.1.3 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -38,6 +38,12 @@ __export(index_exports, {
38
38
  HistoryPanel: () => HistoryPanel,
39
39
  InspectPanel: () => InspectPanel,
40
40
  LIB_VERSION: () => LIB_VERSION,
41
+ LabBlend: () => LabBlend,
42
+ LabCompare: () => LabCompare,
43
+ LabImagePicker: () => LabImagePicker,
44
+ LabLoop: () => LabLoop,
45
+ LabRemix: () => LabRemix,
46
+ LabsTab: () => LabsTab,
41
47
  ListView: () => ListView,
42
48
  MediaLibrary: () => MediaLibrary,
43
49
  PillButton: () => PillButton,
@@ -45,15 +51,25 @@ __export(index_exports, {
45
51
  PromptTab: () => PromptTab,
46
52
  SectionLabel: () => SectionLabel,
47
53
  SetupPanel: () => SetupPanel,
54
+ TagManagerPanel: () => TagManagerPanel,
55
+ autoLabel: () => autoLabel,
56
+ buildBlendInstruction: () => buildBlendInstruction,
57
+ buildCompareInstruction: () => buildCompareInstruction,
48
58
  buildFallbackPrompt: () => buildFallbackPrompt,
49
59
  buildGenerationPrompt: () => buildGenerationPrompt,
50
60
  buildImageGenerationOptions: () => buildImageGenerationOptions,
61
+ buildLoopInstruction: () => buildLoopInstruction,
51
62
  buildPromptTabPayload: () => buildPromptTabPayload,
63
+ buildReferenceImageMediaIds: () => buildReferenceImageMediaIds,
64
+ buildRemixInstruction: () => buildRemixInstruction,
65
+ buildScanInstruction: () => buildScanInstruction,
52
66
  cleanAiResponse: () => cleanAiResponse,
53
67
  createFlowServices: () => createFlowServices,
54
68
  exportProjectToZip: () => exportProjectToZip,
55
69
  formatTreeToMarkdown: () => formatTreeToMarkdown,
70
+ frameToGeneration: () => frameToGeneration,
56
71
  getFormattedTimestamp: () => getFormattedTimestamp,
72
+ groupGenerationsToLabItems: () => groupGenerationsToLabItems,
57
73
  importProjectFromZip: () => importProjectFromZip,
58
74
  injectXMPMetadata: () => injectXMPMetadata,
59
75
  interpretSdkError: () => interpretSdkError,
@@ -263,7 +279,7 @@ function generateMarkdownReport(nodes, history) {
263
279
  });
264
280
  return md;
265
281
  }
266
- async function exportProjectToZip(nodes, edges, history, galleryItems, settings, workspaceTags) {
282
+ async function exportProjectToZip(nodes, edges, history, galleryItems, settings, workspaceTags, recentLabItemIds) {
267
283
  const zip = new import_jszip.default();
268
284
  const projectData = {
269
285
  nodes,
@@ -272,7 +288,8 @@ async function exportProjectToZip(nodes, edges, history, galleryItems, settings,
272
288
  galleryItems: galleryItems.map((g) => ({ ...g, base64: void 0 })),
273
289
  settings,
274
290
  workspaceTags: workspaceTags || null,
275
- version: "1.2.6"
291
+ recentLabItemIds: recentLabItemIds || [],
292
+ version: "1.3.0"
276
293
  };
277
294
  zip.file("project.json", JSON.stringify(projectData, null, 2));
278
295
  zip.file("projekt_bericht.md", generateMarkdownReport(nodes, history));
@@ -428,35 +445,18 @@ function createFlowServices(Flow) {
428
445
  throw interpretSdkError(err);
429
446
  }
430
447
  },
431
- generateText: async (hierarchyText, mode = "creative", images) => {
432
- if (mode === "scan" && images?.length) {
433
- try {
434
- const response = await Flow.generate.text(
435
- "Analyze this image and create a detailed image generation prompt that would recreate it. Focus on: subject, style, lighting, composition, color palette, mood, and technical quality. Output ONLY the prompt string, no explanations.",
436
- {
437
- thinkingLevel: "low",
438
- systemInstruction: "You are an expert image analyst and prompt engineer. Always return ONLY the generation prompt, no headers, no quotes, no conversational filler.",
439
- images
440
- }
441
- );
442
- const result = response?.text?.trim() || "";
443
- if (!result) throw new Error("Empty AI response");
444
- return cleanAiResponse(result);
445
- } catch (err) {
446
- throw interpretSdkError(err);
447
- }
448
- }
449
- const prompt = buildGenerationPrompt(hierarchyText, mode);
448
+ generateText: async (text, options) => {
450
449
  try {
451
- const response = await Flow.generate.text(prompt, {
450
+ const response = await Flow.generate.text(text, {
452
451
  thinkingLevel: "low",
453
- systemInstruction: "You are an expert prompt engineer. Always return ONLY the generated prompt text, no headers, no quotes, no conversational filler."
452
+ systemInstruction: options?.systemInstruction || "You are an expert prompt engineer. Always return ONLY the generated prompt text, no headers, no quotes, no conversational filler.",
453
+ images: options?.images
454
454
  });
455
455
  const result = response?.text?.trim() || "";
456
456
  if (!result) throw new Error("Empty AI response");
457
457
  return cleanAiResponse(result);
458
- } catch {
459
- return buildFallbackPrompt(hierarchyText);
458
+ } catch (err) {
459
+ throw interpretSdkError(err);
460
460
  }
461
461
  }
462
462
  };
@@ -740,7 +740,34 @@ var import_react8 = require("motion/react");
740
740
  var import_jsx_runtime7 = require("react/jsx-runtime");
741
741
  var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
742
742
  const workspaceInputRef = (0, import_react7.useRef)(null);
743
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react8.motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10", children: [
743
+ const [urlInput, setUrlInput] = (0, import_react7.useState)("");
744
+ const [urlStatus, setUrlStatus] = (0, import_react7.useState)("idle");
745
+ const [urlThumb, setUrlThumb] = (0, import_react7.useState)(null);
746
+ const [urlError, setUrlError] = (0, import_react7.useState)(null);
747
+ const handleUrlTest = async () => {
748
+ if (!urlInput.trim()) return;
749
+ setUrlStatus("loading");
750
+ setUrlThumb(null);
751
+ setUrlError(null);
752
+ try {
753
+ const res = await fetch(urlInput.trim());
754
+ if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
755
+ const blob = await res.blob();
756
+ const mimeType = blob.type || "image/jpeg";
757
+ const dataUrl = await new Promise((resolve, reject) => {
758
+ const reader = new FileReader();
759
+ reader.onload = () => resolve(reader.result);
760
+ reader.onerror = () => reject(new Error("FileReader failed"));
761
+ reader.readAsDataURL(blob);
762
+ });
763
+ setUrlThumb(dataUrl);
764
+ setUrlStatus("ok");
765
+ } catch (e) {
766
+ setUrlError(e.message || String(e));
767
+ setUrlStatus("error");
768
+ }
769
+ };
770
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react8.motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10 overflow-y-auto", children: [
744
771
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-4", children: [
745
772
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-1", children: [
746
773
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionLabel, { children: "Workspace Management" }),
@@ -753,6 +780,44 @@ var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
753
780
  e.target.value = "";
754
781
  } })
755
782
  ] }),
783
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-3", children: [
784
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-1", children: [
785
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionLabel, { children: "URL-Fetch Test" }),
786
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Pr\xFCft ob externe URLs als Bild geladen werden k\xF6nnen." })
787
+ ] }),
788
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex gap-2", children: [
789
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
790
+ "input",
791
+ {
792
+ value: urlInput,
793
+ onChange: (e) => setUrlInput(e.target.value),
794
+ onKeyDown: (e) => e.key === "Enter" && handleUrlTest(),
795
+ placeholder: "https://example.com/image.jpg",
796
+ className: "flex-1 bg-white/5 border border-white/10 rounded-xl px-3 py-2 text-[11px] text-white/80 outline-none focus:border-white/20 placeholder:text-white/20"
797
+ }
798
+ ),
799
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
800
+ "button",
801
+ {
802
+ onClick: handleUrlTest,
803
+ disabled: urlStatus === "loading" || !urlInput.trim(),
804
+ className: "px-3 py-2 bg-white/10 hover:bg-white/15 border border-white/10 rounded-xl text-[11px] font-bold text-white/60 transition disabled:opacity-40 shrink-0",
805
+ children: urlStatus === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[16px] animate-spin", children: "sync" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "download" })
806
+ }
807
+ )
808
+ ] }),
809
+ urlStatus === "ok" && urlThumb && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-col gap-2", children: [
810
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: urlThumb, alt: "URL Test", className: "w-full max-h-48 object-contain rounded-xl border border-white/10 bg-black/40" }),
811
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-[10px] text-green-400 font-mono flex items-center gap-1", children: [
812
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "check_circle" }),
813
+ "Fetch erfolgreich"
814
+ ] })
815
+ ] }),
816
+ urlStatus === "error" && urlError && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { className: "text-[10px] text-red-400 font-mono flex items-start gap-1", children: [
817
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "material-symbols-outlined text-[14px] shrink-0", children: "error" }),
818
+ urlError
819
+ ] })
820
+ ] }),
756
821
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "mt-auto p-4 bg-white/5 rounded-2xl border border-white/5 flex flex-col gap-2 opacity-50", children: [
757
822
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-[8px] font-bold text-white/20 uppercase tracking-widest", children: "System Info" }),
758
823
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center justify-between text-[9px] text-white/40", children: [
@@ -922,7 +987,7 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
922
987
  }
923
988
 
924
989
  // src/components/AvatarArchitectApp.tsx
925
- var import_react14 = require("react");
990
+ var import_react21 = require("react");
926
991
 
927
992
  // src/components/PromptTab.tsx
928
993
  var import_react12 = require("react");
@@ -1670,10 +1735,1207 @@ var ProjectSyncTab = ({
1670
1735
  ] }) });
1671
1736
  };
1672
1737
 
1673
- // src/components/AvatarArchitectApp.tsx
1738
+ // src/lib/labHelpers.ts
1739
+ function groupGenerationsToLabItems(generations) {
1740
+ const map = /* @__PURE__ */ new Map();
1741
+ for (const gen of generations) {
1742
+ if (gen.status !== "done" || !gen.base64) continue;
1743
+ const prompt = gen.prompt || "";
1744
+ const existing = map.get(prompt);
1745
+ const frame = {
1746
+ id: gen.id,
1747
+ base64: gen.base64,
1748
+ mediaId: gen.mediaId,
1749
+ seed: gen.seed,
1750
+ model: gen.model,
1751
+ source: gen.type === "import" ? "zip-import" : "generated"
1752
+ };
1753
+ if (existing) {
1754
+ existing.frames.push(frame);
1755
+ } else {
1756
+ map.set(prompt, {
1757
+ id: gen.id,
1758
+ prompt,
1759
+ tags: gen.tags,
1760
+ frames: [frame]
1761
+ });
1762
+ }
1763
+ }
1764
+ return Array.from(map.values());
1765
+ }
1766
+ function frameToGeneration(frame, item) {
1767
+ return {
1768
+ id: frame.id,
1769
+ nodeId: "1",
1770
+ base64: frame.base64,
1771
+ mediaId: frame.mediaId,
1772
+ prompt: item.prompt,
1773
+ seed: frame.seed,
1774
+ model: frame.model,
1775
+ timestamp: Date.now(),
1776
+ status: "done",
1777
+ tags: item.tags || [],
1778
+ type: frame.source === "zip-import" ? "import" : "generation"
1779
+ };
1780
+ }
1781
+ function buildImageContext(images) {
1782
+ const active = images.filter((i) => i.sendToPromptAI);
1783
+ if (!active.length) return "";
1784
+ const lines = active.map((i) => {
1785
+ const role = i.roleForPrompt ? ` (${i.roleForPrompt})` : "";
1786
+ const promptSnippet = i.item.prompt ? `: "${i.item.prompt.slice(0, 120)}"` : "";
1787
+ return `- ${i.label}${role}${promptSnippet}`;
1788
+ });
1789
+ return `
1790
+
1791
+ Reference images:
1792
+ ${lines.join("\n")}`;
1793
+ }
1794
+ function buildScanInstruction() {
1795
+ return {
1796
+ text: "Analyze this image and create a detailed image generation prompt that would recreate it. Focus on: subject, style, lighting, composition, color palette, mood, and technical quality. Output ONLY the prompt string.",
1797
+ systemInstruction: "You are an expert image analyst and prompt engineer. Return ONLY the generation prompt, no headers, no quotes, no explanations."
1798
+ };
1799
+ }
1800
+ function buildRemixInstruction(images, userInstruction, currentPrompt) {
1801
+ const imgContext = buildImageContext(images);
1802
+ return {
1803
+ text: `Current prompt: "${currentPrompt}"
1804
+
1805
+ Instruction: ${userInstruction}${imgContext}
1806
+
1807
+ Create a creative variation of this prompt based on the instruction. Output ONLY the new prompt string.`,
1808
+ systemInstruction: "You are an expert prompt engineer. Return ONLY the new generation prompt, no headers, no quotes, no explanations."
1809
+ };
1810
+ }
1811
+ function buildBlendInstruction(images, userInstruction) {
1812
+ const imgContext = buildImageContext(images);
1813
+ const promptList = images.map((i) => `${i.label}: "${i.item.prompt}"`).join("\n");
1814
+ return {
1815
+ text: `Blend these prompts into one new prompt:
1816
+ ${promptList}
1817
+
1818
+ Instruction: ${userInstruction}${imgContext}
1819
+
1820
+ Output ONLY the blended prompt string.`,
1821
+ systemInstruction: "You are an expert prompt engineer. Blend the given prompts into one coherent generation prompt. Return ONLY the prompt string."
1822
+ };
1823
+ }
1824
+ function buildCompareInstruction(images, userInstruction) {
1825
+ const imgContext = buildImageContext(images);
1826
+ return {
1827
+ text: `${userInstruction}${imgContext}
1828
+
1829
+ Analyze the provided images according to the instruction above.`,
1830
+ systemInstruction: "You are an expert image analyst. Provide a clear, structured analysis. Be concise and actionable."
1831
+ };
1832
+ }
1833
+ function buildLoopInstruction(rounds, newInstruction) {
1834
+ const history = rounds.map(
1835
+ (r, i) => `Round ${i + 1} prompt: "${r.prompt}"
1836
+ Instruction given: "${r.instruction}"`
1837
+ ).join("\n\n");
1838
+ const activeImages = rounds.flatMap((r) => r.images.filter((i) => i.sendToPromptAI));
1839
+ const imgContext = activeImages.length ? buildImageContext(activeImages) : "";
1840
+ return {
1841
+ text: `Previous rounds:
1842
+ ${history}
1843
+
1844
+ New instruction: ${newInstruction}${imgContext}
1845
+
1846
+ Improve the prompt cumulatively based on all previous rounds and the new instruction. Output ONLY the new prompt string.`,
1847
+ systemInstruction: "You are an expert prompt engineer refining prompts iteratively. Each round the prompt should improve. Return ONLY the new prompt string."
1848
+ };
1849
+ }
1850
+ function autoLabel(index) {
1851
+ return `Img${String.fromCharCode(65 + index)}`;
1852
+ }
1853
+ function buildReferenceImageMediaIds(images) {
1854
+ return images.filter((i) => i.sendToImageGen && i.frame.mediaId).map((i) => i.frame.mediaId);
1855
+ }
1856
+
1857
+ // src/components/labs/LabsTab.tsx
1858
+ var import_react19 = require("react");
1859
+
1860
+ // src/components/labs/LabRemix.tsx
1861
+ var import_react15 = require("react");
1862
+
1863
+ // src/components/labs/LabImagePicker.tsx
1864
+ var import_react14 = require("react");
1674
1865
  var import_jsx_runtime13 = require("react/jsx-runtime");
1866
+ var LabImagePicker = ({
1867
+ availableItems,
1868
+ recentItems,
1869
+ onSelect,
1870
+ onClose,
1871
+ title = "Bild w\xE4hlen"
1872
+ }) => {
1873
+ const [search, setSearch] = (0, import_react14.useState)("");
1874
+ const [drillItem, setDrillItem] = (0, import_react14.useState)(null);
1875
+ const filtered = availableItems.filter(
1876
+ (item) => !search || item.prompt.toLowerCase().includes(search.toLowerCase())
1877
+ );
1878
+ const handleItemClick = (item) => {
1879
+ if (item.frames.length === 1) {
1880
+ onSelect(item, item.frames[0]);
1881
+ onClose();
1882
+ } else {
1883
+ setDrillItem(item);
1884
+ }
1885
+ };
1886
+ const renderItemCard = (item) => {
1887
+ const firstFrame = item.frames[0];
1888
+ if (!firstFrame) return null;
1889
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1890
+ "button",
1891
+ {
1892
+ onClick: () => handleItemClick(item),
1893
+ className: "flex flex-col gap-1 p-2 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors text-left",
1894
+ children: [
1895
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative w-full aspect-square rounded-lg overflow-hidden bg-black/40", children: [
1896
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: firstFrame.base64, className: "w-full h-full object-cover" }),
1897
+ item.frames.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "absolute bottom-1 right-1 text-[9px] font-bold bg-black/70 text-white/70 px-1.5 py-0.5 rounded", children: [
1898
+ item.frames.length,
1899
+ "x"
1900
+ ] })
1901
+ ] }),
1902
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-[10px] text-white/50 leading-tight line-clamp-2", children: item.prompt || "(kein Prompt)" })
1903
+ ]
1904
+ },
1905
+ item.id
1906
+ );
1907
+ };
1908
+ if (drillItem) {
1909
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col h-full", children: [
1910
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2 px-4 py-3 border-b border-white/5 shrink-0", children: [
1911
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setDrillItem(null), className: "text-white/40 active:text-white shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "arrow_back" }) }),
1912
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[11px] font-bold uppercase tracking-widest text-white/60 truncate flex-1", children: drillItem.prompt || "(kein Prompt)" }),
1913
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: onClose, className: "text-white/30 active:text-white shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "close" }) })
1914
+ ] }),
1915
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 py-3", children: [
1916
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30 mb-2", children: [
1917
+ drillItem.frames.length,
1918
+ " Varianten"
1919
+ ] }),
1920
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "grid grid-cols-3 gap-2", children: drillItem.frames.map((frame, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1921
+ "button",
1922
+ {
1923
+ onClick: () => {
1924
+ onSelect(drillItem, frame);
1925
+ onClose();
1926
+ },
1927
+ className: "flex flex-col gap-1 p-2 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors text-left",
1928
+ children: [
1929
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "relative w-full aspect-square rounded-lg overflow-hidden bg-black/40", children: [
1930
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: frame.base64, className: "w-full h-full object-cover" }),
1931
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "absolute bottom-1 left-1 text-[9px] font-bold bg-black/70 text-white/50 px-1.5 py-0.5 rounded", children: [
1932
+ "#",
1933
+ i + 1
1934
+ ] })
1935
+ ] }),
1936
+ frame.seed != null && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("p", { className: "text-[9px] text-white/30 font-mono truncate", children: [
1937
+ "seed ",
1938
+ frame.seed
1939
+ ] })
1940
+ ]
1941
+ },
1942
+ frame.id
1943
+ )) })
1944
+ ] })
1945
+ ] });
1946
+ }
1947
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col h-full", children: [
1948
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center justify-between px-4 py-3 border-b border-white/5 shrink-0", children: [
1949
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[11px] font-bold uppercase tracking-widest text-white/60", children: title }),
1950
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: onClose, className: "text-white/30 active:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "close" }) })
1951
+ ] }),
1952
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-3 py-2 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1953
+ "input",
1954
+ {
1955
+ value: search,
1956
+ onChange: (e) => setSearch(e.target.value),
1957
+ placeholder: "Suchen...",
1958
+ className: "w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-[12px] text-white/80 outline-none focus:border-white/20"
1959
+ }
1960
+ ) }),
1961
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 pb-3", children: [
1962
+ recentItems.length > 0 && !search && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1963
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30 mb-2 mt-1", children: "Zuletzt verwendet" }),
1964
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "grid grid-cols-3 gap-2 mb-4", children: recentItems.slice(0, 6).map(renderItemCard) }),
1965
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30 mb-2", children: "Alle Bilder" })
1966
+ ] }),
1967
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "grid grid-cols-3 gap-2", children: filtered.map(renderItemCard) }),
1968
+ filtered.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-center text-[11px] text-white/20 py-8", children: "Keine Bilder vorhanden" })
1969
+ ] })
1970
+ ] });
1971
+ };
1972
+
1973
+ // src/components/labs/LabRemix.tsx
1974
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1975
+ var LabRemix = ({ services, onResult }) => {
1976
+ const [showPicker, setShowPicker] = (0, import_react15.useState)(false);
1977
+ const [selected, setSelected] = (0, import_react15.useState)(null);
1978
+ const [instruction, setInstruction] = (0, import_react15.useState)("");
1979
+ const [generatedPrompt, setGeneratedPrompt] = (0, import_react15.useState)("");
1980
+ const [resultImage, setResultImage] = (0, import_react15.useState)(null);
1981
+ const [isGeneratingPrompt, setIsGeneratingPrompt] = (0, import_react15.useState)(false);
1982
+ const [isGeneratingImage, setIsGeneratingImage] = (0, import_react15.useState)(false);
1983
+ const handleSelectImage = (item, frame) => {
1984
+ services.onItemUsed(item);
1985
+ setSelected({
1986
+ item,
1987
+ frame,
1988
+ label: autoLabel(0),
1989
+ sendToPromptAI: true,
1990
+ sendToImageGen: false,
1991
+ roleForPrompt: "",
1992
+ roleForImage: ""
1993
+ });
1994
+ setGeneratedPrompt("");
1995
+ setResultImage(null);
1996
+ };
1997
+ const handleGeneratePrompt = async () => {
1998
+ if (!selected || !instruction.trim()) return;
1999
+ setIsGeneratingPrompt(true);
2000
+ try {
2001
+ const { text, systemInstruction } = buildRemixInstruction(
2002
+ [selected],
2003
+ instruction,
2004
+ selected.item.prompt
2005
+ );
2006
+ const images = selected.sendToPromptAI ? [{ base64: selected.frame.base64, mimeType: "image/png" }] : void 0;
2007
+ const result = await services.generateText(text, { systemInstruction, images });
2008
+ setGeneratedPrompt(result);
2009
+ } finally {
2010
+ setIsGeneratingPrompt(false);
2011
+ }
2012
+ };
2013
+ const handleGenerateImage = async () => {
2014
+ if (!generatedPrompt) return;
2015
+ setIsGeneratingImage(true);
2016
+ try {
2017
+ const refIds = buildReferenceImageMediaIds(selected ? [selected] : []);
2018
+ const { base64, mediaId } = await services.generateImage({
2019
+ prompt: generatedPrompt,
2020
+ aspectRatio: selected?.frame.aspectRatio || "1:1",
2021
+ modelDisplayName: selected?.frame.model || "\u{1F34C} Nano Banana Pro",
2022
+ ...refIds.length ? { referenceImageMediaIds: refIds } : {}
2023
+ });
2024
+ const newBase64 = `data:image/png;base64,${base64}`;
2025
+ setResultImage(newBase64);
2026
+ const frameId = crypto.randomUUID();
2027
+ const newItem = {
2028
+ id: frameId,
2029
+ prompt: generatedPrompt,
2030
+ tags: selected?.item.tags || [],
2031
+ frames: [{ id: frameId, base64: newBase64, mediaId, source: "generated" }]
2032
+ };
2033
+ services.saveResult?.(newItem);
2034
+ onResult?.(newItem);
2035
+ } finally {
2036
+ setIsGeneratingImage(false);
2037
+ }
2038
+ };
2039
+ if (showPicker) {
2040
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2041
+ LabImagePicker,
2042
+ {
2043
+ availableItems: services.availableItems,
2044
+ recentItems: services.recentItems,
2045
+ onSelect: handleSelectImage,
2046
+ onClose: () => setShowPicker(false),
2047
+ title: "Basis-Bild w\xE4hlen"
2048
+ }
2049
+ );
2050
+ }
2051
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
2052
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
2053
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Basis-Bild" }),
2054
+ selected ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
2055
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("img", { src: selected.frame.base64, className: "w-16 h-16 object-cover rounded-lg shrink-0" }),
2056
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex-1 min-w-0 flex flex-col gap-1.5", children: [
2057
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-[10px] text-white/60 leading-tight line-clamp-2", children: selected.item.prompt }),
2058
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-2 text-[10px] text-white/50", children: [
2059
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2060
+ "input",
2061
+ {
2062
+ type: "checkbox",
2063
+ checked: selected.sendToPromptAI,
2064
+ onChange: (e) => setSelected((s) => s ? { ...s, sendToPromptAI: e.target.checked } : s)
2065
+ }
2066
+ ),
2067
+ "Bild an KI (Prompt)"
2068
+ ] }),
2069
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("label", { className: "flex items-center gap-2 text-[10px] text-white/50", children: [
2070
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2071
+ "input",
2072
+ {
2073
+ type: "checkbox",
2074
+ checked: selected.sendToImageGen,
2075
+ onChange: (e) => setSelected((s) => s ? { ...s, sendToImageGen: e.target.checked } : s)
2076
+ }
2077
+ ),
2078
+ "Bild als Referenz (Generierung)"
2079
+ ] }),
2080
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2081
+ "input",
2082
+ {
2083
+ value: selected.roleForPrompt || "",
2084
+ onChange: (e) => setSelected((s) => s ? { ...s, roleForPrompt: e.target.value } : s),
2085
+ placeholder: "Rolle z.B. Subjekt, Farbreferenz...",
2086
+ className: "bg-black/30 border border-white/10 rounded px-2 py-1 text-[10px] text-white/70 outline-none"
2087
+ }
2088
+ )
2089
+ ] }),
2090
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { onClick: () => setShowPicker(true), className: "text-white/30 active:text-white self-start", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: "swap_horiz" }) })
2091
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2092
+ "button",
2093
+ {
2094
+ onClick: () => setShowPicker(true),
2095
+ className: "w-full py-6 rounded-xl border border-dashed border-white/20 text-[11px] text-white/30 active:bg-white/5 flex items-center justify-center gap-2",
2096
+ children: [
2097
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }),
2098
+ "Bild w\xE4hlen"
2099
+ ]
2100
+ }
2101
+ )
2102
+ ] }),
2103
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
2104
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Anweisung" }),
2105
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2106
+ "textarea",
2107
+ {
2108
+ value: instruction,
2109
+ onChange: (e) => setInstruction(e.target.value),
2110
+ placeholder: "z.B. Mache es dramatischer, andere Lichtstimmung...",
2111
+ className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
2112
+ rows: 3
2113
+ }
2114
+ )
2115
+ ] }),
2116
+ services.workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-[9px] text-white/20 italic", children: "Tags: Workspace-Tags k\xF6nnen unter der Anweisung erg\xE4nzt werden (folgt in n\xE4chstem Update)" }),
2117
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2118
+ "button",
2119
+ {
2120
+ onClick: handleGeneratePrompt,
2121
+ disabled: !selected || !instruction.trim() || isGeneratingPrompt,
2122
+ className: "w-full py-3 rounded-xl bg-white/10 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-white/15 flex items-center justify-center gap-2",
2123
+ children: isGeneratingPrompt ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2124
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2125
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Generiere Prompt..." })
2126
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2127
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "auto_fix_high" }),
2128
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Prompt generieren" })
2129
+ ] })
2130
+ }
2131
+ ),
2132
+ generatedPrompt && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
2133
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Generierter Prompt" }),
2134
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2135
+ "textarea",
2136
+ {
2137
+ value: generatedPrompt,
2138
+ onChange: (e) => setGeneratedPrompt(e.target.value),
2139
+ className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
2140
+ rows: 4
2141
+ }
2142
+ ),
2143
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2144
+ "button",
2145
+ {
2146
+ onClick: handleGenerateImage,
2147
+ disabled: isGeneratingImage,
2148
+ className: "w-full mt-2 py-3 rounded-xl bg-blue-600/80 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-blue-600 flex items-center justify-center gap-2",
2149
+ children: isGeneratingImage ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2150
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2151
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Generiere Bild..." })
2152
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2153
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "image" }),
2154
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: "Bild generieren" })
2155
+ ] })
2156
+ }
2157
+ )
2158
+ ] }),
2159
+ resultImage && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "rounded-xl overflow-hidden border border-white/10", children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("img", { src: resultImage, className: "w-full object-cover" }) })
2160
+ ] });
2161
+ };
2162
+
2163
+ // src/components/labs/LabBlend.tsx
2164
+ var import_react16 = require("react");
2165
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2166
+ var LabBlend = ({ services, onResult }) => {
2167
+ const [showPickerFor, setShowPickerFor] = (0, import_react16.useState)(null);
2168
+ const [selectedImages, setSelectedImages] = (0, import_react16.useState)([]);
2169
+ const [instruction, setInstruction] = (0, import_react16.useState)("");
2170
+ const [generatedPrompt, setGeneratedPrompt] = (0, import_react16.useState)("");
2171
+ const [resultImage, setResultImage] = (0, import_react16.useState)(null);
2172
+ const [isGeneratingPrompt, setIsGeneratingPrompt] = (0, import_react16.useState)(false);
2173
+ const [isGeneratingImage, setIsGeneratingImage] = (0, import_react16.useState)(false);
2174
+ const handleSelectImage = (index, item, frame) => {
2175
+ services.onItemUsed(item);
2176
+ const newImg = {
2177
+ item,
2178
+ frame,
2179
+ label: autoLabel(index),
2180
+ sendToPromptAI: true,
2181
+ sendToImageGen: false,
2182
+ roleForPrompt: "",
2183
+ roleForImage: ""
2184
+ };
2185
+ setSelectedImages((prev) => {
2186
+ const next = [...prev];
2187
+ next[index] = newImg;
2188
+ return next;
2189
+ });
2190
+ setShowPickerFor(null);
2191
+ setGeneratedPrompt("");
2192
+ setResultImage(null);
2193
+ };
2194
+ const addSlot = () => setSelectedImages((prev) => [...prev, null]);
2195
+ const removeSlot = (i) => setSelectedImages((prev) => prev.filter((_, idx) => idx !== i));
2196
+ const updateImg = (i, updates) => setSelectedImages((prev) => prev.map((img, idx) => idx === i && img ? { ...img, ...updates } : img));
2197
+ const handleGeneratePrompt = async () => {
2198
+ const filled = selectedImages.filter(Boolean);
2199
+ if (!filled.length || !instruction.trim()) return;
2200
+ setIsGeneratingPrompt(true);
2201
+ try {
2202
+ const { text, systemInstruction } = buildBlendInstruction(filled, instruction);
2203
+ const images = filled.filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
2204
+ const result = await services.generateText(text, { systemInstruction, images: images.length ? images : void 0 });
2205
+ setGeneratedPrompt(result);
2206
+ } finally {
2207
+ setIsGeneratingPrompt(false);
2208
+ }
2209
+ };
2210
+ const handleGenerateImage = async () => {
2211
+ if (!generatedPrompt) return;
2212
+ setIsGeneratingImage(true);
2213
+ try {
2214
+ const filled = selectedImages.filter(Boolean);
2215
+ const refIds = buildReferenceImageMediaIds(filled);
2216
+ const { base64, mediaId } = await services.generateImage({
2217
+ prompt: generatedPrompt,
2218
+ aspectRatio: "1:1",
2219
+ modelDisplayName: "\u{1F34C} Nano Banana Pro",
2220
+ ...refIds.length ? { referenceImageMediaIds: refIds } : {}
2221
+ });
2222
+ const newBase64 = `data:image/png;base64,${base64}`;
2223
+ setResultImage(newBase64);
2224
+ const frameId = crypto.randomUUID();
2225
+ const newItem = {
2226
+ id: frameId,
2227
+ prompt: generatedPrompt,
2228
+ tags: [],
2229
+ frames: [{ id: frameId, base64: newBase64, mediaId, source: "generated" }]
2230
+ };
2231
+ services.saveResult?.(newItem);
2232
+ onResult?.(newItem);
2233
+ } finally {
2234
+ setIsGeneratingImage(false);
2235
+ }
2236
+ };
2237
+ if (showPickerFor !== null) {
2238
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2239
+ LabImagePicker,
2240
+ {
2241
+ availableItems: services.availableItems,
2242
+ recentItems: services.recentItems,
2243
+ onSelect: (item, frame) => handleSelectImage(showPickerFor, item, frame),
2244
+ onClose: () => setShowPickerFor(null),
2245
+ title: `${autoLabel(showPickerFor)} w\xE4hlen`
2246
+ }
2247
+ );
2248
+ }
2249
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
2250
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40", children: "Bilder" }),
2251
+ selectedImages.map((img, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
2252
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-[10px] font-bold text-white/40 w-6 shrink-0 pt-1", children: autoLabel(i) }),
2253
+ img ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2254
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("img", { src: img.frame.base64, className: "w-12 h-12 object-cover rounded-lg shrink-0", onClick: () => setShowPickerFor(i) }),
2255
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex-1 min-w-0 flex flex-col gap-1", children: [
2256
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-[10px] text-white/50 line-clamp-1", children: img.item.prompt }),
2257
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex gap-3", children: [
2258
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-[10px] text-white/40", children: [
2259
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "checkbox", checked: img.sendToPromptAI, onChange: (e) => updateImg(i, { sendToPromptAI: e.target.checked }) }),
2260
+ "KI-Prompt"
2261
+ ] }),
2262
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("label", { className: "flex items-center gap-1 text-[10px] text-white/40", children: [
2263
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("input", { type: "checkbox", checked: img.sendToImageGen, onChange: (e) => updateImg(i, { sendToImageGen: e.target.checked }) }),
2264
+ "Referenz"
2265
+ ] })
2266
+ ] }),
2267
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2268
+ "input",
2269
+ {
2270
+ value: img.roleForPrompt || "",
2271
+ onChange: (e) => updateImg(i, { roleForPrompt: e.target.value }),
2272
+ placeholder: "Rolle f\xFCr Prompt...",
2273
+ className: "bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
2274
+ }
2275
+ ),
2276
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2277
+ "input",
2278
+ {
2279
+ value: img.roleForImage || "",
2280
+ onChange: (e) => updateImg(i, { roleForImage: e.target.value }),
2281
+ placeholder: "Rolle f\xFCr Generierung...",
2282
+ className: "bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
2283
+ }
2284
+ )
2285
+ ] })
2286
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: () => setShowPickerFor(i), className: "flex-1 py-3 border border-dashed border-white/20 rounded-lg text-[10px] text-white/30 active:bg-white/5", children: "Bild w\xE4hlen" }),
2287
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("button", { onClick: () => removeSlot(i), className: "text-white/20 active:text-red-400 self-start", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "close" }) })
2288
+ ] }, i)),
2289
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2290
+ "button",
2291
+ {
2292
+ onClick: addSlot,
2293
+ className: "w-full py-2 border border-dashed border-white/10 rounded-xl text-[10px] text-white/30 active:bg-white/5 flex items-center justify-center gap-1",
2294
+ children: [
2295
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "add" }),
2296
+ "Bild hinzuf\xFCgen"
2297
+ ]
2298
+ }
2299
+ ),
2300
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
2301
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Blend-Anweisung" }),
2302
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2303
+ "textarea",
2304
+ {
2305
+ value: instruction,
2306
+ onChange: (e) => setInstruction(e.target.value),
2307
+ placeholder: "z.B. Kombiniere die Stimmung von ImgA mit der Komposition von ImgB...",
2308
+ className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
2309
+ rows: 3
2310
+ }
2311
+ )
2312
+ ] }),
2313
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2314
+ "button",
2315
+ {
2316
+ onClick: handleGeneratePrompt,
2317
+ disabled: selectedImages.filter(Boolean).length < 2 || !instruction.trim() || isGeneratingPrompt,
2318
+ className: "w-full py-3 rounded-xl bg-white/10 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-white/15 flex items-center justify-center gap-2",
2319
+ children: isGeneratingPrompt ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2320
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2321
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Blend l\xE4uft..." })
2322
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2323
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "merge" }),
2324
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Prompts blenden" })
2325
+ ] })
2326
+ }
2327
+ ),
2328
+ generatedPrompt && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
2329
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Blend-Prompt" }),
2330
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2331
+ "textarea",
2332
+ {
2333
+ value: generatedPrompt,
2334
+ onChange: (e) => setGeneratedPrompt(e.target.value),
2335
+ className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
2336
+ rows: 4
2337
+ }
2338
+ ),
2339
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2340
+ "button",
2341
+ {
2342
+ onClick: handleGenerateImage,
2343
+ disabled: isGeneratingImage,
2344
+ className: "w-full mt-2 py-3 rounded-xl bg-blue-600/80 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-blue-600 flex items-center justify-center gap-2",
2345
+ children: isGeneratingImage ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2346
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2347
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Generiere..." })
2348
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2349
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "image" }),
2350
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: "Bild generieren" })
2351
+ ] })
2352
+ }
2353
+ )
2354
+ ] }),
2355
+ resultImage && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "rounded-xl overflow-hidden border border-white/10", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("img", { src: resultImage, className: "w-full object-cover" }) })
2356
+ ] });
2357
+ };
2358
+
2359
+ // src/components/labs/LabCompare.tsx
2360
+ var import_react17 = require("react");
2361
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2362
+ var LabCompare = ({ services, onResult }) => {
2363
+ const [showPickerFor, setShowPickerFor] = (0, import_react17.useState)(null);
2364
+ const [selectedImages, setSelectedImages] = (0, import_react17.useState)([]);
2365
+ const [instruction, setInstruction] = (0, import_react17.useState)("");
2366
+ const [analysis, setAnalysis] = (0, import_react17.useState)("");
2367
+ const [generatedPrompt, setGeneratedPrompt] = (0, import_react17.useState)("");
2368
+ const [resultImage, setResultImage] = (0, import_react17.useState)(null);
2369
+ const [isAnalyzing, setIsAnalyzing] = (0, import_react17.useState)(false);
2370
+ const [isGeneratingImage, setIsGeneratingImage] = (0, import_react17.useState)(false);
2371
+ const handleSelectImage = (index, item, frame) => {
2372
+ services.onItemUsed(item);
2373
+ const newImg = {
2374
+ item,
2375
+ frame,
2376
+ label: autoLabel(index),
2377
+ sendToPromptAI: true,
2378
+ sendToImageGen: false,
2379
+ roleForPrompt: "",
2380
+ roleForImage: ""
2381
+ };
2382
+ setSelectedImages((prev) => {
2383
+ const next = [...prev];
2384
+ next[index] = newImg;
2385
+ return next;
2386
+ });
2387
+ setShowPickerFor(null);
2388
+ setAnalysis("");
2389
+ };
2390
+ const updateImg = (i, updates) => setSelectedImages((prev) => prev.map((img, idx) => idx === i && img ? { ...img, ...updates } : img));
2391
+ const addSlot = () => setSelectedImages((prev) => [...prev, null]);
2392
+ const removeSlot = (i) => setSelectedImages((prev) => prev.filter((_, idx) => idx !== i));
2393
+ const handleAnalyze = async () => {
2394
+ const filled = selectedImages.filter(Boolean);
2395
+ if (!filled.length || !instruction.trim()) return;
2396
+ setIsAnalyzing(true);
2397
+ try {
2398
+ const { text, systemInstruction } = buildCompareInstruction(filled, instruction);
2399
+ const images = filled.filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
2400
+ const result = await services.generateText(text, { systemInstruction, images: images.length ? images : void 0 });
2401
+ setAnalysis(result);
2402
+ setGeneratedPrompt("");
2403
+ } finally {
2404
+ setIsAnalyzing(false);
2405
+ }
2406
+ };
2407
+ const handleGenerateImage = async () => {
2408
+ if (!generatedPrompt) return;
2409
+ setIsGeneratingImage(true);
2410
+ try {
2411
+ const { base64, mediaId } = await services.generateImage({ prompt: generatedPrompt, aspectRatio: "1:1", modelDisplayName: "\u{1F34C} Nano Banana Pro" });
2412
+ const newBase64 = `data:image/png;base64,${base64}`;
2413
+ setResultImage(newBase64);
2414
+ const frameId = crypto.randomUUID();
2415
+ const newItem = {
2416
+ id: frameId,
2417
+ prompt: generatedPrompt,
2418
+ tags: [],
2419
+ frames: [{ id: frameId, base64: newBase64, mediaId, source: "generated" }]
2420
+ };
2421
+ services.saveResult?.(newItem);
2422
+ onResult?.(newItem);
2423
+ } finally {
2424
+ setIsGeneratingImage(false);
2425
+ }
2426
+ };
2427
+ if (showPickerFor !== null) {
2428
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2429
+ LabImagePicker,
2430
+ {
2431
+ availableItems: services.availableItems,
2432
+ recentItems: services.recentItems,
2433
+ onSelect: (item, frame) => handleSelectImage(showPickerFor, item, frame),
2434
+ onClose: () => setShowPickerFor(null),
2435
+ title: `${autoLabel(showPickerFor)} w\xE4hlen`
2436
+ }
2437
+ );
2438
+ }
2439
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
2440
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40", children: "Bilder zum Vergleichen" }),
2441
+ selectedImages.map((img, i) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
2442
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "text-[10px] font-bold text-white/40 w-6 shrink-0 pt-1", children: autoLabel(i) }),
2443
+ img ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2444
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("img", { src: img.frame.base64, className: "w-12 h-12 object-cover rounded-lg shrink-0 cursor-pointer", onClick: () => setShowPickerFor(i) }),
2445
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex-1 min-w-0 flex flex-col gap-1", children: [
2446
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-[10px] text-white/50 line-clamp-1", children: img.item.prompt }),
2447
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("label", { className: "flex items-center gap-1 text-[10px] text-white/40", children: [
2448
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { type: "checkbox", checked: img.sendToPromptAI, onChange: (e) => updateImg(i, { sendToPromptAI: e.target.checked }) }),
2449
+ "Bild an KI mitgeben"
2450
+ ] }),
2451
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2452
+ "input",
2453
+ {
2454
+ value: img.roleForPrompt || "",
2455
+ onChange: (e) => updateImg(i, { roleForPrompt: e.target.value }),
2456
+ placeholder: "Rolle z.B. Referenz A, Stilvergleich...",
2457
+ className: "bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
2458
+ }
2459
+ )
2460
+ ] })
2461
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { onClick: () => setShowPickerFor(i), className: "flex-1 py-3 border border-dashed border-white/20 rounded-lg text-[10px] text-white/30 active:bg-white/5", children: "Bild w\xE4hlen" }),
2462
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { onClick: () => removeSlot(i), className: "text-white/20 active:text-red-400 self-start", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "close" }) })
2463
+ ] }, i)),
2464
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { onClick: addSlot, className: "w-full py-2 border border-dashed border-white/10 rounded-xl text-[10px] text-white/30 active:bg-white/5 flex items-center justify-center gap-1", children: [
2465
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "add" }),
2466
+ "Bild hinzuf\xFCgen"
2467
+ ] }),
2468
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
2469
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Analyse-Anweisung" }),
2470
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2471
+ "textarea",
2472
+ {
2473
+ value: instruction,
2474
+ onChange: (e) => setInstruction(e.target.value),
2475
+ placeholder: "z.B. Vergleiche Lichtstimmung und Komposition. Welches ist dramatischer?",
2476
+ className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
2477
+ rows: 3
2478
+ }
2479
+ )
2480
+ ] }),
2481
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2482
+ "button",
2483
+ {
2484
+ onClick: handleAnalyze,
2485
+ disabled: selectedImages.filter(Boolean).length < 1 || !instruction.trim() || isAnalyzing,
2486
+ className: "w-full py-3 rounded-xl bg-white/10 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-white/15 flex items-center justify-center gap-2",
2487
+ children: isAnalyzing ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2488
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2489
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: "Analysiere..." })
2490
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2491
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "compare" }),
2492
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: "Analysieren" })
2493
+ ] })
2494
+ }
2495
+ ),
2496
+ analysis && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
2497
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Analyse" }),
2498
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "bg-white/5 border border-white/10 rounded-xl px-3 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-[12px] text-white/70 leading-relaxed whitespace-pre-wrap", children: analysis }) }),
2499
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "mt-3", children: [
2500
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Als Prompt nutzen" }),
2501
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2502
+ "textarea",
2503
+ {
2504
+ value: generatedPrompt,
2505
+ onChange: (e) => setGeneratedPrompt(e.target.value),
2506
+ placeholder: "Analyse-Ergebnis hier als Prompt einf\xFCgen oder eigenen Prompt schreiben...",
2507
+ className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
2508
+ rows: 3
2509
+ }
2510
+ ),
2511
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2512
+ "button",
2513
+ {
2514
+ onClick: handleGenerateImage,
2515
+ disabled: !generatedPrompt.trim() || isGeneratingImage,
2516
+ className: "w-full mt-2 py-3 rounded-xl bg-blue-600/80 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-blue-600 flex items-center justify-center gap-2",
2517
+ children: isGeneratingImage ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2518
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2519
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: "Generiere..." })
2520
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
2521
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "image" }),
2522
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { children: "Bild generieren" })
2523
+ ] })
2524
+ }
2525
+ )
2526
+ ] })
2527
+ ] }),
2528
+ resultImage && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "rounded-xl overflow-hidden border border-white/10", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("img", { src: resultImage, className: "w-full object-cover" }) })
2529
+ ] });
2530
+ };
2531
+
2532
+ // src/components/labs/LabLoop.tsx
2533
+ var import_react18 = require("react");
2534
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2535
+ var LabLoop = ({ services, onResult }) => {
2536
+ const [rounds, setRounds] = (0, import_react18.useState)([]);
2537
+ const [currentInstruction, setCurrentInstruction] = (0, import_react18.useState)("");
2538
+ const [showPickerForRound, setShowPickerForRound] = (0, import_react18.useState)(null);
2539
+ const [pendingImages, setPendingImages] = (0, import_react18.useState)([]);
2540
+ const [isGenerating, setIsGenerating] = (0, import_react18.useState)(false);
2541
+ const currentPrompt = rounds.length > 0 ? rounds[rounds.length - 1].prompt : "";
2542
+ const handleAddImage = (item, frame) => {
2543
+ services.onItemUsed(item);
2544
+ const label = autoLabel(pendingImages.length);
2545
+ setPendingImages((prev) => [...prev, {
2546
+ item,
2547
+ frame,
2548
+ label,
2549
+ sendToPromptAI: true,
2550
+ sendToImageGen: false,
2551
+ roleForPrompt: "",
2552
+ roleForImage: ""
2553
+ }]);
2554
+ setShowPickerForRound(null);
2555
+ };
2556
+ const updatePendingImage = (i, updates) => setPendingImages((prev) => prev.map((img, idx) => idx === i ? { ...img, ...updates } : img));
2557
+ const handleRunRound = async () => {
2558
+ if (!currentInstruction.trim()) return;
2559
+ setIsGenerating(true);
2560
+ try {
2561
+ const historyForBuilder = rounds.map((r) => ({
2562
+ prompt: r.prompt,
2563
+ instruction: r.instruction,
2564
+ images: r.images
2565
+ }));
2566
+ const { text, systemInstruction } = buildLoopInstruction(historyForBuilder, currentInstruction);
2567
+ const allImages = [...rounds.flatMap((r) => r.images), ...pendingImages].filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
2568
+ const newPrompt = await services.generateText(text, {
2569
+ systemInstruction,
2570
+ images: allImages.length ? allImages : void 0
2571
+ });
2572
+ const { base64, mediaId } = await services.generateImage({
2573
+ prompt: newPrompt,
2574
+ aspectRatio: "1:1",
2575
+ modelDisplayName: "\u{1F34C} Nano Banana Pro"
2576
+ });
2577
+ const newBase64 = `data:image/png;base64,${base64}`;
2578
+ const newFrame = { id: crypto.randomUUID(), base64: newBase64, mediaId, source: "generated" };
2579
+ const newRound = {
2580
+ prompt: newPrompt,
2581
+ instruction: currentInstruction,
2582
+ frame: newFrame,
2583
+ images: [...pendingImages]
2584
+ };
2585
+ setRounds((prev) => [...prev, newRound]);
2586
+ setCurrentInstruction("");
2587
+ setPendingImages([]);
2588
+ const newItem = {
2589
+ id: newFrame.id,
2590
+ prompt: newPrompt,
2591
+ tags: [],
2592
+ frames: [newFrame]
2593
+ };
2594
+ services.saveResult?.(newItem);
2595
+ onResult?.(newItem);
2596
+ } finally {
2597
+ setIsGenerating(false);
2598
+ }
2599
+ };
2600
+ if (showPickerForRound !== null) {
2601
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2602
+ LabImagePicker,
2603
+ {
2604
+ availableItems: services.availableItems,
2605
+ recentItems: services.recentItems,
2606
+ onSelect: handleAddImage,
2607
+ onClose: () => setShowPickerForRound(null),
2608
+ title: "Referenzbild hinzuf\xFCgen"
2609
+ }
2610
+ );
2611
+ }
2612
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
2613
+ rounds.map((round, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
2614
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex flex-col items-center gap-1 shrink-0", children: [
2615
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "text-[9px] font-bold text-white/30", children: [
2616
+ "R",
2617
+ i + 1
2618
+ ] }),
2619
+ round.frame && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("img", { src: round.frame.base64, className: "w-12 h-12 object-cover rounded-lg" })
2620
+ ] }),
2621
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex-1 min-w-0", children: [
2622
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "text-[9px] text-white/30 italic mb-1", children: [
2623
+ '"',
2624
+ round.instruction,
2625
+ '"'
2626
+ ] }),
2627
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-[10px] text-white/60 leading-tight line-clamp-3", children: round.prompt })
2628
+ ] })
2629
+ ] }, i)),
2630
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "rounded-xl border border-white/20 bg-white/5 p-3 flex flex-col gap-3", children: [
2631
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40", children: rounds.length === 0 ? "Runde 1 \u2014 Erster Prompt" : `Runde ${rounds.length + 1}` }),
2632
+ currentPrompt && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "text-[10px] text-white/40 italic line-clamp-2", children: [
2633
+ 'Letzter Prompt: "',
2634
+ currentPrompt,
2635
+ '"'
2636
+ ] }),
2637
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2638
+ "textarea",
2639
+ {
2640
+ value: currentInstruction,
2641
+ onChange: (e) => setCurrentInstruction(e.target.value),
2642
+ placeholder: rounds.length === 0 ? "Ersten Prompt beschreiben..." : "Was soll verbessert werden?",
2643
+ className: "w-full bg-black/30 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
2644
+ rows: 3
2645
+ }
2646
+ ),
2647
+ pendingImages.map((img, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex gap-2 items-center", children: [
2648
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("img", { src: img.frame.base64, className: "w-8 h-8 object-cover rounded" }),
2649
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-[10px] text-white/40", children: img.label }),
2650
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2651
+ "input",
2652
+ {
2653
+ value: img.roleForPrompt || "",
2654
+ onChange: (e) => updatePendingImage(i, { roleForPrompt: e.target.value }),
2655
+ placeholder: "Rolle...",
2656
+ className: "flex-1 bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
2657
+ }
2658
+ ),
2659
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center gap-1 text-[9px] text-white/30", children: [
2660
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { type: "checkbox", checked: img.sendToPromptAI, onChange: (e) => updatePendingImage(i, { sendToPromptAI: e.target.checked }) }),
2661
+ "KI"
2662
+ ] }),
2663
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { onClick: () => setPendingImages((prev) => prev.filter((_, idx) => idx !== i)), className: "text-white/20 active:text-red-400", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
2664
+ ] }, i)),
2665
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
2666
+ "button",
2667
+ {
2668
+ onClick: () => setShowPickerForRound(rounds.length),
2669
+ className: "text-[10px] text-white/30 active:text-white/60 flex items-center gap-1 self-start",
2670
+ children: [
2671
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
2672
+ "Referenzbild hinzuf\xFCgen"
2673
+ ]
2674
+ }
2675
+ ),
2676
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2677
+ "button",
2678
+ {
2679
+ onClick: handleRunRound,
2680
+ disabled: !currentInstruction.trim() || isGenerating,
2681
+ className: "w-full py-3 rounded-xl bg-white/10 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-white/15 flex items-center justify-center gap-2",
2682
+ children: isGenerating ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2683
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2684
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: "Runde l\xE4uft..." })
2685
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2686
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "loop" }),
2687
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: "Runde starten" })
2688
+ ] })
2689
+ }
2690
+ )
2691
+ ] })
2692
+ ] });
2693
+ };
2694
+
2695
+ // src/components/labs/LabsTab.tsx
2696
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2697
+ var TABS = [
2698
+ { key: "remix", label: "Remix", icon: "auto_fix_high" },
2699
+ { key: "blend", label: "Blend", icon: "merge" },
2700
+ { key: "compare", label: "Compare", icon: "compare" },
2701
+ { key: "loop", label: "Loop", icon: "loop" }
2702
+ ];
2703
+ var LabsTab = ({ services, onResult }) => {
2704
+ const [activeTab, setActiveTab] = (0, import_react19.useState)("remix");
2705
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex flex-col h-full overflow-hidden", children: [
2706
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex border-b border-white/5 shrink-0", children: TABS.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2707
+ "button",
2708
+ {
2709
+ onClick: () => setActiveTab(tab.key),
2710
+ className: `flex-1 flex items-center justify-center gap-1 h-10 text-[9px] font-bold uppercase tracking-wide transition-colors ${activeTab === tab.key ? "text-white border-b-2 border-white" : "text-white/30 hover:text-white/60"}`,
2711
+ children: [
2712
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: tab.icon }),
2713
+ tab.label
2714
+ ]
2715
+ },
2716
+ tab.key
2717
+ )) }),
2718
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex-1 overflow-hidden", children: [
2719
+ activeTab === "remix" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LabRemix, { services, onResult }),
2720
+ activeTab === "blend" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LabBlend, { services, onResult }),
2721
+ activeTab === "compare" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LabCompare, { services, onResult }),
2722
+ activeTab === "loop" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LabLoop, { services, onResult })
2723
+ ] })
2724
+ ] });
2725
+ };
2726
+
2727
+ // src/components/TagManagerPanel.tsx
2728
+ var import_react20 = require("react");
2729
+ var import_jsx_runtime19 = require("react/jsx-runtime");
2730
+ function TagManagerPanel({ workspaceTags, onTagCreate, onTagUpdate, onTagDelete, onTagReorder, onTagMove }) {
2731
+ const categories = Object.keys(workspaceTags.by_category).filter(
2732
+ (cat) => (workspaceTags.by_category[cat] || []).some((t) => !t.is_deleted)
2733
+ );
2734
+ const [selectedCategory, setSelectedCategory] = (0, import_react20.useState)(categories[0] || "");
2735
+ const effectiveCategory = categories.includes(selectedCategory) ? selectedCategory : categories[0] || "";
2736
+ const [editingLabel, setEditingLabel] = (0, import_react20.useState)(null);
2737
+ const [editState, setEditState] = (0, import_react20.useState)({ label: "", value: "" });
2738
+ const [newTag, setNewTag] = (0, import_react20.useState)({ label: "", value: "" });
2739
+ const [movingLabel, setMovingLabel] = (0, import_react20.useState)(null);
2740
+ const [moveTarget, setMoveTarget] = (0, import_react20.useState)("");
2741
+ const tags = (workspaceTags.by_category[effectiveCategory] || []).filter((t) => !t.is_deleted);
2742
+ const otherCategories = categories.filter((c) => c !== effectiveCategory);
2743
+ const startEdit = (tag) => {
2744
+ setEditingLabel(tag.label);
2745
+ setEditState({ label: tag.label, value: tag.value });
2746
+ setMovingLabel(null);
2747
+ };
2748
+ const saveEdit = (originalLabel) => {
2749
+ if (!editState.label.trim()) return;
2750
+ onTagUpdate(originalLabel, effectiveCategory, {
2751
+ label: editState.label.trim(),
2752
+ value: editState.value.trim() || editState.label.trim()
2753
+ });
2754
+ setEditingLabel(null);
2755
+ };
2756
+ const handleMoveUp = (index) => {
2757
+ if (index === 0) return;
2758
+ const reordered = [...tags];
2759
+ [reordered[index - 1], reordered[index]] = [reordered[index], reordered[index - 1]];
2760
+ onTagReorder(effectiveCategory, reordered);
2761
+ };
2762
+ const handleMoveDown = (index) => {
2763
+ if (index === tags.length - 1) return;
2764
+ const reordered = [...tags];
2765
+ [reordered[index], reordered[index + 1]] = [reordered[index + 1], reordered[index]];
2766
+ onTagReorder(effectiveCategory, reordered);
2767
+ };
2768
+ const handleMove = (tag) => {
2769
+ if (!moveTarget) return;
2770
+ onTagMove(tag.label, tag.value, effectiveCategory, moveTarget);
2771
+ setMovingLabel(null);
2772
+ setMoveTarget("");
2773
+ };
2774
+ const handleCreate = () => {
2775
+ if (!newTag.label.trim() || !effectiveCategory) return;
2776
+ onTagCreate({ label: newTag.label.trim(), value: newTag.value.trim() || newTag.label.trim(), category: effectiveCategory, is_user_created: true });
2777
+ setNewTag({ label: "", value: "" });
2778
+ };
2779
+ const handleDelete = (tag) => {
2780
+ if (!confirm(`Tag "${tag.label}" l\xF6schen?`)) return;
2781
+ onTagDelete(tag.label, effectiveCategory);
2782
+ };
2783
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col h-full overflow-hidden", children: [
2784
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "px-3 py-2 border-b border-white/5 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[10px] font-bold uppercase tracking-widest text-white/40", children: "Tag Manager" }) }),
2785
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "px-3 py-2 shrink-0 overflow-x-auto", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex gap-1.5 flex-nowrap", children: [
2786
+ categories.map((cat) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2787
+ "button",
2788
+ {
2789
+ onClick: () => {
2790
+ setSelectedCategory(cat);
2791
+ setEditingLabel(null);
2792
+ setMovingLabel(null);
2793
+ },
2794
+ className: `px-2.5 py-1 rounded text-[9px] font-bold border whitespace-nowrap transition ${cat === effectiveCategory ? "bg-blue-900/40 border-blue-600/60 text-blue-300" : "bg-white/5 border-white/10 text-white/40 hover:text-white/70"}`,
2795
+ children: [
2796
+ cat,
2797
+ " ",
2798
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "ml-1 opacity-50", children: (workspaceTags.by_category[cat] || []).filter((t) => !t.is_deleted).length })
2799
+ ]
2800
+ },
2801
+ cat
2802
+ )),
2803
+ categories.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "text-[10px] text-white/20", children: "Erst Workspace importieren" })
2804
+ ] }) }),
2805
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 pb-2 space-y-1", children: [
2806
+ tags.map((tag, i) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { children: [
2807
+ editingLabel === tag.label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "bg-white/5 border border-blue-600/40 rounded-lg p-2.5 space-y-1.5", children: [
2808
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2809
+ "input",
2810
+ {
2811
+ value: editState.label,
2812
+ onChange: (e) => setEditState((s) => ({ ...s, label: e.target.value })),
2813
+ className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1 text-[12px] text-white outline-none focus:border-blue-500/50",
2814
+ placeholder: "Label",
2815
+ autoFocus: true,
2816
+ onKeyDown: (e) => e.key === "Enter" && saveEdit(tag.label)
2817
+ }
2818
+ ),
2819
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2820
+ "textarea",
2821
+ {
2822
+ value: editState.value,
2823
+ onChange: (e) => setEditState((s) => ({ ...s, value: e.target.value })),
2824
+ rows: 2,
2825
+ className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1 text-[11px] text-white/70 outline-none focus:border-blue-500/50 resize-none",
2826
+ placeholder: "Prompt-Wert (leer = Label)"
2827
+ }
2828
+ ),
2829
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex gap-1.5 justify-end", children: [
2830
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => saveEdit(tag.label), className: "px-2.5 py-1 bg-blue-700 hover:bg-blue-600 text-white text-[10px] font-bold rounded transition", children: "SPEICHERN" }),
2831
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => setEditingLabel(null), className: "px-2.5 py-1 bg-white/5 hover:bg-white/10 text-white/50 text-[10px] font-bold rounded transition", children: "ABBRUCH" })
2832
+ ] })
2833
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "group flex items-center gap-1.5 bg-white/3 hover:bg-white/6 border border-white/5 rounded-lg px-2 py-1.5 transition", children: [
2834
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-col gap-0 shrink-0", children: [
2835
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => handleMoveUp(i), disabled: i === 0, className: "text-white/20 hover:text-white/60 disabled:opacity-10 transition leading-none", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "arrow_drop_up" }) }),
2836
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => handleMoveDown(i), disabled: i === tags.length - 1, className: "text-white/20 hover:text-white/60 disabled:opacity-10 transition leading-none", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "arrow_drop_down" }) })
2837
+ ] }),
2838
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex-1 min-w-0", children: [
2839
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "text-[12px] text-white/80 font-medium truncate", children: tag.label }),
2840
+ tag.value && tag.value !== tag.label && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "text-[10px] text-white/30 truncate", children: [
2841
+ tag.value.slice(0, 60),
2842
+ tag.value.length > 60 ? "\u2026" : ""
2843
+ ] })
2844
+ ] }),
2845
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex gap-1 opacity-0 group-hover:opacity-100 transition shrink-0", children: [
2846
+ otherCategories.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2847
+ "button",
2848
+ {
2849
+ onClick: () => {
2850
+ setMovingLabel((l) => l === tag.label ? null : tag.label);
2851
+ setMoveTarget("");
2852
+ setEditingLabel(null);
2853
+ },
2854
+ className: "p-1 rounded text-white/30 hover:text-purple-400 transition",
2855
+ title: "Kategorie wechseln",
2856
+ children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "drive_file_move" })
2857
+ }
2858
+ ),
2859
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => startEdit(tag), className: "p-1 rounded text-white/30 hover:text-blue-400 transition", title: "Bearbeiten", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "edit" }) }),
2860
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => handleDelete(tag), className: "p-1 rounded text-white/30 hover:text-red-400 transition", title: "L\xF6schen", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "material-symbols-outlined text-[16px]", children: "delete" }) })
2861
+ ] })
2862
+ ] }),
2863
+ movingLabel === tag.label && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "mt-1 bg-purple-900/20 border border-purple-700/30 rounded-lg p-2.5 space-y-1.5", children: [
2864
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "text-[9px] font-bold uppercase tracking-widest text-purple-400/70", children: "Verschieben nach Kategorie" }),
2865
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2866
+ "select",
2867
+ {
2868
+ value: moveTarget,
2869
+ onChange: (e) => setMoveTarget(e.target.value),
2870
+ className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1 text-[11px] text-white/70 outline-none",
2871
+ children: [
2872
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: "\u2014 Kategorie w\xE4hlen \u2014" }),
2873
+ otherCategories.map((cat) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: cat, children: cat }, cat))
2874
+ ]
2875
+ }
2876
+ ),
2877
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex gap-1.5 justify-end", children: [
2878
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2879
+ "button",
2880
+ {
2881
+ onClick: () => handleMove(tag),
2882
+ disabled: !moveTarget,
2883
+ className: "px-2.5 py-1 bg-purple-700 hover:bg-purple-600 text-white text-[10px] font-bold rounded transition disabled:opacity-40",
2884
+ children: "VERSCHIEBEN"
2885
+ }
2886
+ ),
2887
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { onClick: () => setMovingLabel(null), className: "px-2.5 py-1 bg-white/5 hover:bg-white/10 text-white/50 text-[10px] font-bold rounded transition", children: "ABBRUCH" })
2888
+ ] })
2889
+ ] })
2890
+ ] }, `${effectiveCategory}-${i}`)),
2891
+ tags.length === 0 && effectiveCategory && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "text-center text-[11px] text-white/20 py-6", children: "Keine Tags in dieser Kategorie." })
2892
+ ] }),
2893
+ effectiveCategory && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "px-3 py-2 border-t border-white/5 shrink-0 space-y-1.5", children: [
2894
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30", children: [
2895
+ "Neuer Tag in \u201E",
2896
+ effectiveCategory,
2897
+ '"'
2898
+ ] }),
2899
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2900
+ "input",
2901
+ {
2902
+ value: newTag.label,
2903
+ onChange: (e) => setNewTag((s) => ({ ...s, label: e.target.value })),
2904
+ onKeyDown: (e) => e.key === "Enter" && !e.shiftKey && handleCreate(),
2905
+ placeholder: "Label\u2026",
2906
+ className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1.5 text-[12px] text-white outline-none focus:border-white/20"
2907
+ }
2908
+ ),
2909
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2910
+ "textarea",
2911
+ {
2912
+ value: newTag.value,
2913
+ onChange: (e) => setNewTag((s) => ({ ...s, value: e.target.value })),
2914
+ rows: 2,
2915
+ placeholder: "Prompt-Wert (leer = Label)",
2916
+ className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1 text-[11px] text-white/60 outline-none focus:border-white/20 resize-none"
2917
+ }
2918
+ ),
2919
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
2920
+ "button",
2921
+ {
2922
+ onClick: handleCreate,
2923
+ disabled: !newTag.label.trim(),
2924
+ className: "w-full py-1.5 bg-white/5 border border-white/10 text-white/60 text-[10px] font-bold rounded hover:bg-white/10 hover:text-white transition disabled:opacity-30 flex items-center justify-center gap-1.5",
2925
+ children: [
2926
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "add" }),
2927
+ "TAG ERSTELLEN"
2928
+ ]
2929
+ }
2930
+ )
2931
+ ] })
2932
+ ] });
2933
+ }
2934
+
2935
+ // src/components/AvatarArchitectApp.tsx
2936
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1675
2937
  function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
1676
- (0, import_react14.useEffect)(() => {
2938
+ (0, import_react21.useEffect)(() => {
1677
2939
  const id = "flow-styles";
1678
2940
  if (!document.getElementById(id)) {
1679
2941
  const style = document.createElement("style");
@@ -1682,16 +2944,16 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1682
2944
  document.head.appendChild(style);
1683
2945
  }
1684
2946
  }, []);
1685
- const [showStart, setShowStart] = (0, import_react14.useState)(true);
1686
- const [layoutChoice, setLayoutChoice] = (0, import_react14.useState)(() => {
2947
+ const [showStart, setShowStart] = (0, import_react21.useState)(true);
2948
+ const [layoutChoice, setLayoutChoice] = (0, import_react21.useState)(() => {
1687
2949
  try {
1688
2950
  return localStorage.getItem("aa-layout") || null;
1689
2951
  } catch {
1690
2952
  return null;
1691
2953
  }
1692
2954
  });
1693
- const [projectLoaded, setProjectLoaded] = (0, import_react14.useState)(false);
1694
- const wsInputRef = (0, import_react14.useRef)(null);
2955
+ const [projectLoaded, setProjectLoaded] = (0, import_react21.useState)(false);
2956
+ const wsInputRef = (0, import_react21.useRef)(null);
1695
2957
  const startApp = (choice) => {
1696
2958
  try {
1697
2959
  localStorage.setItem("aa-layout", choice);
@@ -1700,50 +2962,66 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1700
2962
  setLayoutChoice(choice);
1701
2963
  setShowStart(false);
1702
2964
  };
1703
- const [nodes, setNodes] = (0, import_react14.useState)([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
1704
- const [edges, setEdges] = (0, import_react14.useState)([]);
1705
- const [history, setHistory] = (0, import_react14.useState)([]);
1706
- const [galleryItems, setGalleryItems] = (0, import_react14.useState)([]);
1707
- const [activePrompt, setActivePrompt] = (0, import_react14.useState)("");
1708
- const [isSynthesizing, setIsSynthesizing] = (0, import_react14.useState)(false);
1709
- const [activeGenerationsCount, setActiveGenerationsCount] = (0, import_react14.useState)(0);
1710
- const [currentResult, setCurrentResult] = (0, import_react14.useState)(null);
1711
- const [focusedNodeId, setFocusedNodeId] = (0, import_react14.useState)(null);
1712
- const [leftTab, setLeftTab] = (0, import_react14.useState)("prompt");
1713
- const [promptFeedback, setPromptFeedback] = (0, import_react14.useState)(null);
1714
- const [lastPromptPayload, setLastPromptPayload] = (0, import_react14.useState)(null);
1715
- const [isPromptTabGenerating, setIsPromptTabGenerating] = (0, import_react14.useState)(false);
1716
- const [activeTab, setActiveTab] = (0, import_react14.useState)("history");
1717
- const [mobileTab, setMobileTab] = (0, import_react14.useState)("stage");
1718
- const [aspectRatio, setAspectRatio] = (0, import_react14.useState)("1:1");
1719
- const [selectedModel, setSelectedModel] = (0, import_react14.useState)("\u{1F34C} Nano Banana Pro");
1720
- const [seed, setSeed] = (0, import_react14.useState)(Math.floor(Math.random() * 1e6));
1721
- const [seedMode, setSeedMode] = (0, import_react14.useState)("random");
1722
- const [isLeftCollapsed, setIsLeftCollapsed] = (0, import_react14.useState)(false);
1723
- const [isRightCollapsed, setIsRightCollapsed] = (0, import_react14.useState)(false);
1724
- const [isPromptCollapsed, setIsPromptCollapsed] = (0, import_react14.useState)(false);
1725
- const [projectActionState, setProjectActionState] = (0, import_react14.useState)("idle");
1726
- const syncServerDataRef = (0, import_react14.useRef)(null);
1727
- const [workspaceTags, setWorkspaceTags] = (0, import_react14.useState)(null);
1728
- const [serverProjects, setServerProjects] = (0, import_react14.useState)([]);
1729
- const [isLoadingFromServer, setIsLoadingFromServer] = (0, import_react14.useState)(false);
1730
- const [highContrast, setHighContrast] = (0, import_react14.useState)(() => {
2965
+ const [nodes, setNodes] = (0, import_react21.useState)([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
2966
+ const [edges, setEdges] = (0, import_react21.useState)([]);
2967
+ const [history, setHistory] = (0, import_react21.useState)([]);
2968
+ const [galleryItems, setGalleryItems] = (0, import_react21.useState)([]);
2969
+ const [activePrompt, setActivePrompt] = (0, import_react21.useState)("");
2970
+ const [isSynthesizing, setIsSynthesizing] = (0, import_react21.useState)(false);
2971
+ const [activeGenerationsCount, setActiveGenerationsCount] = (0, import_react21.useState)(0);
2972
+ const [currentResult, setCurrentResult] = (0, import_react21.useState)(null);
2973
+ const [focusedNodeId, setFocusedNodeId] = (0, import_react21.useState)(null);
2974
+ const [leftTab, setLeftTab] = (0, import_react21.useState)("prompt");
2975
+ const [promptFeedback, setPromptFeedback] = (0, import_react21.useState)(null);
2976
+ const [lastPromptPayload, setLastPromptPayload] = (0, import_react21.useState)(null);
2977
+ const [isPromptTabGenerating, setIsPromptTabGenerating] = (0, import_react21.useState)(false);
2978
+ const [activeTab, setActiveTab] = (0, import_react21.useState)("history");
2979
+ const [mobileTab, setMobileTab] = (0, import_react21.useState)("stage");
2980
+ const [middlePanel, setMiddlePanel] = (0, import_react21.useState)("stage");
2981
+ const [recentLabItems, setRecentLabItems] = (0, import_react21.useState)([]);
2982
+ const [aspectRatio, setAspectRatio] = (0, import_react21.useState)("1:1");
2983
+ const [selectedModel, setSelectedModel] = (0, import_react21.useState)("\u{1F34C} Nano Banana Pro");
2984
+ const [seed, setSeed] = (0, import_react21.useState)(Math.floor(Math.random() * 1e6));
2985
+ const [seedMode, setSeedMode] = (0, import_react21.useState)("random");
2986
+ const [isLeftCollapsed, setIsLeftCollapsed] = (0, import_react21.useState)(false);
2987
+ const [isRightCollapsed, setIsRightCollapsed] = (0, import_react21.useState)(false);
2988
+ const [leftPanelWidth, setLeftPanelWidth] = (0, import_react21.useState)(() => {
2989
+ try {
2990
+ return parseInt(localStorage.getItem("aa-left-width") || "260", 10);
2991
+ } catch {
2992
+ return 260;
2993
+ }
2994
+ });
2995
+ const [rightPanelWidth, setRightPanelWidth] = (0, import_react21.useState)(() => {
2996
+ try {
2997
+ return parseInt(localStorage.getItem("aa-right-width") || "320", 10);
2998
+ } catch {
2999
+ return 320;
3000
+ }
3001
+ });
3002
+ const [isPromptCollapsed, setIsPromptCollapsed] = (0, import_react21.useState)(false);
3003
+ const [projectActionState, setProjectActionState] = (0, import_react21.useState)("idle");
3004
+ const syncServerDataRef = (0, import_react21.useRef)(null);
3005
+ const [workspaceTags, setWorkspaceTags] = (0, import_react21.useState)(null);
3006
+ const [serverProjects, setServerProjects] = (0, import_react21.useState)([]);
3007
+ const [isLoadingFromServer, setIsLoadingFromServer] = (0, import_react21.useState)(false);
3008
+ const [highContrast, setHighContrast] = (0, import_react21.useState)(() => {
1731
3009
  try {
1732
3010
  return localStorage.getItem("aa-contrast") === "high";
1733
3011
  } catch {
1734
3012
  return false;
1735
3013
  }
1736
3014
  });
1737
- const [activeReferenceId, setActiveReferenceId] = (0, import_react14.useState)(null);
1738
- const [activeReferenceThumbnail, setActiveReferenceThumbnail] = (0, import_react14.useState)(null);
1739
- const [isScanningImage, setIsScanningImage] = (0, import_react14.useState)(false);
1740
- const [touchStartX, setTouchStartX] = (0, import_react14.useState)(null);
1741
- const [isFullscreen, setIsFullscreen] = (0, import_react14.useState)(false);
1742
- const [zoomScale, setZoomScale] = (0, import_react14.useState)(1);
1743
- const [zoomOffset, setZoomOffset] = (0, import_react14.useState)({ x: 0, y: 0 });
1744
- const lastPinchDist = (0, import_react14.useRef)(null);
1745
- const lastTapTime = (0, import_react14.useRef)(0);
1746
- const dragStart = (0, import_react14.useRef)(null);
3015
+ const [activeReferenceId, setActiveReferenceId] = (0, import_react21.useState)(null);
3016
+ const [activeReferenceThumbnail, setActiveReferenceThumbnail] = (0, import_react21.useState)(null);
3017
+ const [isScanningImage, setIsScanningImage] = (0, import_react21.useState)(false);
3018
+ const [touchStartX, setTouchStartX] = (0, import_react21.useState)(null);
3019
+ const [isFullscreen, setIsFullscreen] = (0, import_react21.useState)(false);
3020
+ const [zoomScale, setZoomScale] = (0, import_react21.useState)(1);
3021
+ const [zoomOffset, setZoomOffset] = (0, import_react21.useState)({ x: 0, y: 0 });
3022
+ const lastPinchDist = (0, import_react21.useRef)(null);
3023
+ const lastTapTime = (0, import_react21.useRef)(0);
3024
+ const dragStart = (0, import_react21.useRef)(null);
1747
3025
  const openFullscreen = () => {
1748
3026
  setIsFullscreen(true);
1749
3027
  setZoomScale(1);
@@ -1806,6 +3084,65 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1806
3084
  setActiveReferenceId(null);
1807
3085
  setActiveReferenceThumbnail(null);
1808
3086
  };
3087
+ const labServices = (0, import_react21.useMemo)(() => {
3088
+ const available = groupGenerationsToLabItems([...galleryItems, ...history]);
3089
+ return {
3090
+ availableItems: available,
3091
+ recentItems: recentLabItems,
3092
+ onItemUsed: (item) => setRecentLabItems(
3093
+ (prev) => [item, ...prev.filter((i) => i.id !== item.id)].slice(0, 10)
3094
+ ),
3095
+ generateText: onGeneratePrompt,
3096
+ generateImage: onGenerateImage,
3097
+ saveResult: async (item) => {
3098
+ const frame = item.frames[0];
3099
+ if (frame?.base64) {
3100
+ const gen = frameToGeneration(frame, item);
3101
+ setGalleryItems((prev) => [gen, ...prev]);
3102
+ setHistory((prev) => [gen, ...prev]);
3103
+ }
3104
+ },
3105
+ workspaceTags: workspaceTags || void 0
3106
+ };
3107
+ }, [galleryItems, history, recentLabItems, onGeneratePrompt, onGenerateImage, workspaceTags]);
3108
+ const startLeftResize = (e) => {
3109
+ e.preventDefault();
3110
+ const startX = e.clientX;
3111
+ const startW = leftPanelWidth;
3112
+ const onMove = (ev) => {
3113
+ const w = Math.max(180, Math.min(520, startW + ev.clientX - startX));
3114
+ setLeftPanelWidth(w);
3115
+ try {
3116
+ localStorage.setItem("aa-left-width", String(w));
3117
+ } catch {
3118
+ }
3119
+ };
3120
+ const onUp = () => {
3121
+ document.removeEventListener("mousemove", onMove);
3122
+ document.removeEventListener("mouseup", onUp);
3123
+ };
3124
+ document.addEventListener("mousemove", onMove);
3125
+ document.addEventListener("mouseup", onUp);
3126
+ };
3127
+ const startRightResize = (e) => {
3128
+ e.preventDefault();
3129
+ const startX = e.clientX;
3130
+ const startW = rightPanelWidth;
3131
+ const onMove = (ev) => {
3132
+ const w = Math.max(180, Math.min(520, startW - (ev.clientX - startX)));
3133
+ setRightPanelWidth(w);
3134
+ try {
3135
+ localStorage.setItem("aa-right-width", String(w));
3136
+ } catch {
3137
+ }
3138
+ };
3139
+ const onUp = () => {
3140
+ document.removeEventListener("mousemove", onMove);
3141
+ document.removeEventListener("mouseup", onUp);
3142
+ };
3143
+ document.addEventListener("mousemove", onMove);
3144
+ document.addEventListener("mouseup", onUp);
3145
+ };
1809
3146
  const handleScanImage = async (file) => {
1810
3147
  setIsScanningImage(true);
1811
3148
  try {
@@ -1815,7 +3152,11 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1815
3152
  reader.onerror = reject;
1816
3153
  reader.readAsDataURL(file);
1817
3154
  });
1818
- const prompt = await onGeneratePrompt("", "scan", [{ base64, mimeType: file.type || "image/png" }]);
3155
+ const { text, systemInstruction } = buildScanInstruction();
3156
+ const prompt = await onGeneratePrompt(text, {
3157
+ images: [{ base64, mimeType: file.type || "image/png" }],
3158
+ systemInstruction
3159
+ });
1819
3160
  setActivePrompt(prompt);
1820
3161
  } catch (err) {
1821
3162
  console.error("Scan fehlgeschlagen:", err);
@@ -1823,17 +3164,17 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1823
3164
  setIsScanningImage(false);
1824
3165
  }
1825
3166
  };
1826
- const currentIndex = (0, import_react14.useMemo)(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
1827
- const goToPrev = (0, import_react14.useCallback)(() => {
3167
+ const currentIndex = (0, import_react21.useMemo)(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
3168
+ const goToPrev = (0, import_react21.useCallback)(() => {
1828
3169
  if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
1829
3170
  }, [currentIndex, history]);
1830
- const goToNext = (0, import_react14.useCallback)(() => {
3171
+ const goToNext = (0, import_react21.useCallback)(() => {
1831
3172
  if (currentIndex < history.length - 1) setCurrentResult(history[currentIndex + 1]);
1832
3173
  }, [currentIndex, history]);
1833
3174
  const hcStyle = highContrast ? { filter: "brightness(1.6) contrast(1.05)" } : void 0;
1834
3175
  const isGenerating = activeGenerationsCount > 0;
1835
3176
  useKeyboardNavigation(history, currentResult, setCurrentResult);
1836
- const getSubtreeFormat = (0, import_react14.useCallback)((nodeId, depth = 0) => {
3177
+ const getSubtreeFormat = (0, import_react21.useCallback)((nodeId, depth = 0) => {
1837
3178
  const node = nodes.find((n) => n.id === nodeId);
1838
3179
  if (!node) return "";
1839
3180
  const childrenIds = edges.filter((e) => e.source === nodeId).map((e) => e.target);
@@ -1841,7 +3182,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1841
3182
  return `${indent}- ${node.data.label || "(unbenannt)"}
1842
3183
  ` + childrenIds.map((id) => getSubtreeFormat(id, depth + 1)).join("");
1843
3184
  }, [nodes, edges]);
1844
- const activePath = (0, import_react14.useMemo)(() => {
3185
+ const activePath = (0, import_react21.useMemo)(() => {
1845
3186
  if (!focusedNodeId) return /* @__PURE__ */ new Set();
1846
3187
  const path = /* @__PURE__ */ new Set([focusedNodeId]);
1847
3188
  let currId = focusedNodeId;
@@ -1931,11 +3272,32 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1931
3272
  return { by_category: { ...prev.by_category, [category]: updatedCat }, all: updatedAll };
1932
3273
  });
1933
3274
  };
3275
+ const handleTagReorder = (category, reorderedTags) => {
3276
+ setWorkspaceTags((prev) => {
3277
+ if (!prev) return prev;
3278
+ const deletedTags = (prev.by_category[category] || []).filter((t) => t.is_deleted);
3279
+ const merged = [...reorderedTags, ...deletedTags];
3280
+ const newAll = [
3281
+ ...prev.all.filter((t) => t.category !== category),
3282
+ ...merged.map((t) => ({ ...t, category }))
3283
+ ];
3284
+ return { by_category: { ...prev.by_category, [category]: merged }, all: newAll };
3285
+ });
3286
+ };
3287
+ const handleTagMove = (label, value, fromCategory, toCategory) => {
3288
+ setWorkspaceTags((prev) => {
3289
+ if (!prev) return prev;
3290
+ const fromTags = (prev.by_category[fromCategory] || []).filter((t) => t.label !== label);
3291
+ const toTags = [...prev.by_category[toCategory] || [], { label, value, is_user_created: true }];
3292
+ const newAll = prev.all.filter((t) => !(t.label === label && t.category === fromCategory)).concat({ label, value, is_user_created: true, category: toCategory });
3293
+ return { by_category: { ...prev.by_category, [fromCategory]: fromTags, [toCategory]: toTags }, all: newAll };
3294
+ });
3295
+ };
1934
3296
  const handlePromptTabGenerate = async (selectedTags, instructions, rules) => {
1935
3297
  setIsPromptTabGenerating(true);
1936
3298
  setPromptFeedback(null);
1937
3299
  try {
1938
- const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
3300
+ const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : nodes.map((n) => n.data.label || "").filter(Boolean).join("\n");
1939
3301
  const payload = buildPromptTabPayload(selectedTags, instructions, rules, treeText);
1940
3302
  setLastPromptPayload(payload);
1941
3303
  const raw = await onGeneratePrompt(payload);
@@ -1963,7 +3325,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1963
3325
  const handleProjectExport = async () => {
1964
3326
  setProjectActionState("working-full");
1965
3327
  try {
1966
- const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags);
3328
+ const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags, recentLabItems.map((i) => i.id));
1967
3329
  await onDownload(base64, "application/zip", `avatar_project_${getFormattedTimestamp()}.zip`);
1968
3330
  setProjectActionState("done");
1969
3331
  setTimeout(() => setProjectActionState("idle"), 3e3);
@@ -1991,6 +3353,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1991
3353
  setSeedMode(data.settings.seedMode || "random");
1992
3354
  }
1993
3355
  if (data.workspaceTags?.by_category) setWorkspaceTags(data.workspaceTags);
3356
+ if (data.recentLabItemIds?.length) {
3357
+ const allGens = [...data.history || [], ...data.galleryItems || []];
3358
+ const labItems = groupGenerationsToLabItems(allGens);
3359
+ const recent = data.recentLabItemIds.map((id) => labItems.find((item) => item.id === id)).filter(Boolean);
3360
+ setRecentLabItems(recent);
3361
+ }
1994
3362
  setProjectActionState("done");
1995
3363
  setProjectLoaded(true);
1996
3364
  setTimeout(() => setProjectActionState("idle"), 2e3);
@@ -2031,7 +3399,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2031
3399
  if (!onServerSave) return;
2032
3400
  setProjectActionState("working-full");
2033
3401
  try {
2034
- const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags);
3402
+ const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags, recentLabItems.map((i) => i.id));
2035
3403
  await onServerSave(base64, name || `avatar_project_${getFormattedTimestamp()}`);
2036
3404
  await fetchServerProjects();
2037
3405
  setProjectActionState("done");
@@ -2075,7 +3443,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2075
3443
  mergedHistory,
2076
3444
  serverData.galleryItems || galleryItems,
2077
3445
  serverData.settings || { aspectRatio, selectedModel, seed, seedMode },
2078
- serverData.workspaceTags || workspaceTags
3446
+ serverData.workspaceTags || workspaceTags,
3447
+ serverData.recentLabItemIds || recentLabItems.map((i) => i.id)
2079
3448
  );
2080
3449
  await onServerSave(base64, `sync_${getFormattedTimestamp()}`);
2081
3450
  await fetchServerProjects();
@@ -2086,12 +3455,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2086
3455
  setTimeout(() => setProjectActionState("idle"), 4e3);
2087
3456
  }
2088
3457
  };
2089
- (0, import_react14.useEffect)(() => {
3458
+ (0, import_react21.useEffect)(() => {
2090
3459
  if (activeTab === "setup" || activeTab === "sync") fetchServerProjects();
2091
3460
  }, [activeTab]);
2092
3461
  if (isFullscreen && currentResult?.base64) {
2093
3462
  const fsBase64 = currentResult.base64.startsWith("data:") ? currentResult.base64 : `data:image/png;base64,${currentResult.base64}`;
2094
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3463
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2095
3464
  "div",
2096
3465
  {
2097
3466
  className: "fixed inset-0 bg-black z-50 flex items-center justify-center overflow-hidden touch-none",
@@ -2099,7 +3468,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2099
3468
  onTouchMove: handleFsTouchMove,
2100
3469
  onTouchEnd: handleFsTouchEnd,
2101
3470
  children: [
2102
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3471
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2103
3472
  "img",
2104
3473
  {
2105
3474
  src: fsBase64,
@@ -2116,76 +3485,76 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2116
3485
  }
2117
3486
  }
2118
3487
  ),
2119
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: closeFullscreen, className: "absolute top-4 right-4 w-10 h-10 flex items-center justify-center rounded-full bg-black/70 border border-white/20 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "close" }) }),
2120
- zoomScale > 1 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => {
3488
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: closeFullscreen, className: "absolute top-4 right-4 w-10 h-10 flex items-center justify-center rounded-full bg-black/70 border border-white/20 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "close" }) }),
3489
+ zoomScale > 1 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => {
2121
3490
  setZoomScale(1);
2122
3491
  setZoomOffset({ x: 0, y: 0 });
2123
- }, className: "absolute top-4 left-4 w-10 h-10 flex items-center justify-center rounded-full bg-black/70 border border-white/20 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "zoom_out_map" }) }),
2124
- history.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2125
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => {
3492
+ }, className: "absolute top-4 left-4 w-10 h-10 flex items-center justify-center rounded-full bg-black/70 border border-white/20 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "zoom_out_map" }) }),
3493
+ history.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3494
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => {
2126
3495
  if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
2127
- }, disabled: currentIndex <= 0, className: "absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
2128
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => {
3496
+ }, disabled: currentIndex <= 0, className: "absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
3497
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => {
2129
3498
  if (currentIndex < history.length - 1) setCurrentResult(history[currentIndex + 1]);
2130
- }, disabled: currentIndex >= history.length - 1, className: "absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
2131
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "absolute bottom-6 left-1/2 -translate-x-1/2 bg-black/60 rounded-full px-3 py-0.5 text-[10px] text-white/40 font-mono", children: [
3499
+ }, disabled: currentIndex >= history.length - 1, className: "absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
3500
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "absolute bottom-6 left-1/2 -translate-x-1/2 bg-black/60 rounded-full px-3 py-0.5 text-[10px] text-white/40 font-mono", children: [
2132
3501
  currentIndex + 1,
2133
3502
  " / ",
2134
3503
  history.length
2135
3504
  ] })
2136
3505
  ] }),
2137
- zoomScale === 1 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute bottom-6 right-4 text-[9px] text-white/20 font-mono", children: "Pinch zum Zoomen \xB7 Doppeltipp 2.5\xD7" })
3506
+ zoomScale === 1 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "absolute bottom-6 right-4 text-[9px] text-white/20 font-mono", children: "Pinch zum Zoomen \xB7 Doppeltipp 2.5\xD7" })
2138
3507
  ]
2139
3508
  }
2140
3509
  );
2141
3510
  }
2142
3511
  if (showStart) {
2143
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "fixed inset-0 bg-[#0e0e0e] flex flex-col items-center justify-center p-6", style: { gap: 28, ...hcStyle }, children: [
2144
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { ref: wsInputRef, type: "file", accept: ".zip", className: "hidden", onChange: (e) => {
3512
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "fixed inset-0 bg-[#0e0e0e] flex flex-col items-center justify-center p-6", style: { gap: 28, ...hcStyle }, children: [
3513
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("input", { ref: wsInputRef, type: "file", accept: ".zip", className: "hidden", onChange: (e) => {
2145
3514
  const f = e.target.files?.[0];
2146
3515
  if (f) handleProjectImport(f);
2147
3516
  e.target.value = "";
2148
3517
  } }),
2149
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-center gap-1", children: [
2150
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-white/15 text-[44px]", children: "palette" }),
2151
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-white/25 text-[10px] font-bold uppercase tracking-[0.25em]", children: "Avatar Architect" }),
2152
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "text-white text-[13px] font-mono", children: [
3518
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-center gap-1", children: [
3519
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-white/15 text-[44px]", children: "palette" }),
3520
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-white/25 text-[10px] font-bold uppercase tracking-[0.25em]", children: "Avatar Architect" }),
3521
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "text-white text-[13px] font-mono", children: [
2153
3522
  "v",
2154
3523
  LIB_VERSION
2155
3524
  ] })
2156
3525
  ] }),
2157
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3526
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2158
3527
  "button",
2159
3528
  {
2160
3529
  onClick: toggleContrast,
2161
3530
  className: "flex items-center gap-3 px-5 py-3 rounded-2xl border transition-colors",
2162
3531
  style: { borderColor: highContrast ? "rgba(255,255,255,0.3)" : "rgba(255,255,255,0.08)", background: highContrast ? "rgba(255,255,255,0.08)" : "transparent" },
2163
3532
  children: [
2164
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[22px]", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.35)" }, children: highContrast ? "light_mode" : "dark_mode" }),
2165
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-start", children: [
2166
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[13px] font-bold", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.5)" }, children: highContrast ? "Hoher Kontrast" : "Normaler Kontrast" }),
2167
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[10px]", style: { color: "rgba(255,255,255,0.25)" }, children: "Tippen zum Umschalten" })
3533
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[22px]", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.35)" }, children: highContrast ? "light_mode" : "dark_mode" }),
3534
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-start", children: [
3535
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[13px] font-bold", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.5)" }, children: highContrast ? "Hoher Kontrast" : "Normaler Kontrast" }),
3536
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[10px]", style: { color: "rgba(255,255,255,0.25)" }, children: "Tippen zum Umschalten" })
2168
3537
  ] })
2169
3538
  ]
2170
3539
  }
2171
3540
  ),
2172
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
2173
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3541
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
3542
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2174
3543
  "button",
2175
3544
  {
2176
3545
  onClick: () => wsInputRef.current?.click(),
2177
3546
  className: "w-full flex items-center justify-center gap-3 rounded-2xl font-bold text-[14px] uppercase tracking-wide text-white active:scale-95 transition-transform",
2178
3547
  style: { height: 56, background: projectLoaded ? "#16a34a" : "#0284c7" },
2179
3548
  children: [
2180
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: projectLoaded ? "check_circle" : "folder_zip" }),
3549
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: projectLoaded ? "check_circle" : "folder_zip" }),
2181
3550
  projectLoaded ? "Projekt geladen \u2713" : "Projekt laden (.zip)"
2182
3551
  ]
2183
3552
  }
2184
3553
  ),
2185
- !projectLoaded && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-white/20 text-[10px] text-center", children: "Baum, Bilder und Einstellungen wiederherstellen" })
3554
+ !projectLoaded && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-white/20 text-[10px] text-center", children: "Baum, Bilder und Einstellungen wiederherstellen" })
2186
3555
  ] }),
2187
- onFetchServerProjects && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
2188
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3556
+ onFetchServerProjects && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
3557
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2189
3558
  "button",
2190
3559
  {
2191
3560
  disabled: isLoadingFromServer,
@@ -2206,35 +3575,35 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2206
3575
  className: "w-full flex items-center justify-center gap-3 rounded-2xl font-bold text-[14px] uppercase tracking-wide text-white active:scale-95 transition-transform disabled:opacity-50",
2207
3576
  style: { height: 56, background: "#7c3aed" },
2208
3577
  children: [
2209
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: `material-symbols-outlined text-[22px]${isLoadingFromServer ? " animate-spin" : ""}`, children: isLoadingFromServer ? "sync" : "cloud_download" }),
3578
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: `material-symbols-outlined text-[22px]${isLoadingFromServer ? " animate-spin" : ""}`, children: isLoadingFromServer ? "sync" : "cloud_download" }),
2210
3579
  isLoadingFromServer ? "Laden\u2026" : "Vom Server laden"
2211
3580
  ]
2212
3581
  }
2213
3582
  ),
2214
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-white/20 text-[10px] text-center", children: "Letzten Stand vom Server wiederherstellen" })
3583
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-white/20 text-[10px] text-center", children: "Letzten Stand vom Server wiederherstellen" })
2215
3584
  ] }),
2216
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
2217
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-white/25 text-[10px] uppercase tracking-widest font-bold", children: "Layout w\xE4hlen & starten" }),
2218
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "grid grid-cols-2 gap-2 w-full", children: [
3585
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
3586
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-white/25 text-[10px] uppercase tracking-widest font-bold", children: "Layout w\xE4hlen & starten" }),
3587
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "grid grid-cols-2 gap-2 w-full", children: [
2219
3588
  { id: "mobile", icon: "smartphone", label: "Mobile" },
2220
3589
  { id: "mobile-desktop", icon: "phonelink", label: "Mobile+" },
2221
3590
  { id: "desktop", icon: "desktop_windows", label: "Desktop" },
2222
3591
  { id: "tablet-landscape", icon: "tablet", label: "Landscape" }
2223
- ].map((opt) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3592
+ ].map((opt) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2224
3593
  "button",
2225
3594
  {
2226
3595
  onClick: () => startApp(opt.id),
2227
3596
  className: "flex flex-col items-center gap-2 py-4 rounded-2xl border transition-colors",
2228
3597
  style: { borderColor: layoutChoice === opt.id ? "rgba(255,255,255,0.35)" : "rgba(255,255,255,0.08)", background: layoutChoice === opt.id ? "rgba(255,255,255,0.07)" : "transparent" },
2229
3598
  children: [
2230
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[24px]", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.icon }),
2231
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[11px] font-bold", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.label })
3599
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[24px]", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.icon }),
3600
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[11px] font-bold", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.label })
2232
3601
  ]
2233
3602
  },
2234
3603
  opt.id
2235
3604
  )) }),
2236
- layoutChoice === "mobile-desktop" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-white/20 text-[9px] text-center", children: "Mobil-Layout skaliert f\xFCr Desktop-Modus" }),
2237
- layoutChoice === "tablet-landscape" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-white/20 text-[9px] text-center", children: "2-Spalten-Layout f\xFCr Landscape-Tablet im Desktop-Mode" })
3605
+ layoutChoice === "mobile-desktop" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-white/20 text-[9px] text-center", children: "Mobil-Layout skaliert f\xFCr Desktop-Modus" }),
3606
+ layoutChoice === "tablet-landscape" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-white/20 text-[9px] text-center", children: "2-Spalten-Layout f\xFCr Landscape-Tablet im Desktop-Mode" })
2238
3607
  ] })
2239
3608
  ] });
2240
3609
  }
@@ -2243,28 +3612,46 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2243
3612
  const mdScale = mdMode ? window.innerWidth / 430 : 1;
2244
3613
  const mdW = mdMode ? 430 : void 0;
2245
3614
  const mdH = mdMode ? Math.ceil(window.innerHeight / mdScale) : void 0;
2246
- const mobileRoot = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col bg-[#0e0e0e] text-white overflow-hidden", style: {
3615
+ const mobileRoot = /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col bg-[#0e0e0e] text-white overflow-hidden", style: {
2247
3616
  width: mdMode ? mdW : "100vw",
2248
3617
  height: mdMode ? mdH : "100dvh",
2249
3618
  transform: mdMode ? `scale(${mdScale})` : void 0,
2250
3619
  transformOrigin: mdMode ? "top left" : void 0,
2251
3620
  ...hcStyle || {}
2252
3621
  }, children: [
2253
- mobileTab === "stage" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col flex-1 min-h-0", children: [
2254
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2 px-3 border-b border-white/5 bg-black/30 shrink-0", style: { height: 52 }, children: [
2255
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
2256
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
2257
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex-1" }),
2258
- activeReferenceThumbnail ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
2259
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
2260
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
2261
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 active:text-white/80 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
2262
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: handleSelectReference, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }) }),
2263
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: toggleContrast, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: highContrast ? "light_mode" : "dark_mode" }) }),
2264
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setShowStart(true), className: "text-white/20 active:text-white/60 transition-colors mr-1", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "desktop_windows" }) })
3622
+ mobileTab === "labs" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-col flex-1 min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LabsTab, { services: labServices, onResult: (item) => {
3623
+ const frame = item.frames[0];
3624
+ if (frame?.base64) {
3625
+ setCurrentResult(frameToGeneration(frame, item));
3626
+ setMobileTab("stage");
3627
+ }
3628
+ } }) }),
3629
+ mobileTab === "tags" && workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-col flex-1 min-h-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3630
+ TagManagerPanel,
3631
+ {
3632
+ workspaceTags,
3633
+ onTagCreate: handleTagCreate,
3634
+ onTagUpdate: handleTagUpdate,
3635
+ onTagDelete: handleTagDelete,
3636
+ onTagReorder: handleTagReorder,
3637
+ onTagMove: handleTagMove
3638
+ }
3639
+ ) }),
3640
+ mobileTab === "stage" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col flex-1 min-h-0", children: [
3641
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2 px-3 border-b border-white/5 bg-black/30 shrink-0", style: { height: 52 }, children: [
3642
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
3643
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
3644
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex-1" }),
3645
+ activeReferenceThumbnail ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
3646
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
3647
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
3648
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 active:text-white/80 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
3649
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: handleSelectReference, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }) }),
3650
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: toggleContrast, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: highContrast ? "light_mode" : "dark_mode" }) }),
3651
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setShowStart(true), className: "text-white/20 active:text-white/60 transition-colors mr-1", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "desktop_windows" }) })
2265
3652
  ] }),
2266
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-3 pt-3 pb-2 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `relative rounded-xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
2267
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3653
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "px-3 pt-3 pb-2 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: `relative rounded-xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
3654
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2268
3655
  "textarea",
2269
3656
  {
2270
3657
  value: activePrompt,
@@ -2274,26 +3661,26 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2274
3661
  placeholder: "Prompt eingeben..."
2275
3662
  }
2276
3663
  ),
2277
- activePrompt && !isSynthesizing && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-8 h-8 flex items-center justify-center text-white/20 active:text-white transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: "close" }) })
3664
+ activePrompt && !isSynthesizing && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-8 h-8 flex items-center justify-center text-white/20 active:text-white transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: "close" }) })
2278
3665
  ] }) }),
2279
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-3 pb-3 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3666
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "px-3 pb-3 shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2280
3667
  "button",
2281
3668
  {
2282
3669
  onClick: () => handleGenerateImage(),
2283
3670
  disabled: !activePrompt.trim() || isGenerating,
2284
3671
  className: "w-full flex items-center justify-center gap-2 rounded-xl font-bold text-[14px] uppercase tracking-wide transition-all disabled:opacity-30 active:scale-95",
2285
3672
  style: { height: 48, background: activePrompt.trim() && !isGenerating ? "#0284c7" : void 0, border: "1px solid rgba(255,255,255,0.1)" },
2286
- children: isGenerating ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2287
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "w-4 h-4 border-t-2 border-white rounded-full animate-spin" }),
2288
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Generiere..." })
2289
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2290
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "bolt" }),
2291
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Generieren" })
3673
+ children: isGenerating ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3674
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "w-4 h-4 border-t-2 border-white rounded-full animate-spin" }),
3675
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "Generiere..." })
3676
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3677
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "bolt" }),
3678
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "Generieren" })
2292
3679
  ] })
2293
3680
  }
2294
3681
  ) }),
2295
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 min-h-0 px-3 pb-3 flex flex-col", children: [
2296
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
3682
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 min-h-0 px-3 pb-3 flex flex-col", children: [
3683
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
2297
3684
  "div",
2298
3685
  {
2299
3686
  className: "w-full rounded-2xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center",
@@ -2307,25 +3694,25 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2307
3694
  setTouchStartX(null);
2308
3695
  },
2309
3696
  children: [
2310
- currentResult?.status === "processing" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-center gap-3", children: [
2311
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
2312
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[11px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
3697
+ currentResult?.status === "processing" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-center gap-3", children: [
3698
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
3699
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[11px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
2313
3700
  ] }),
2314
- currentResult?.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "p-6 text-center flex flex-col items-center gap-3", children: [
2315
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-red-400 text-[36px]", children: "warning" }),
2316
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-white/50 text-[13px]", children: currentResult.error?.message }),
2317
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => handleGenerateImage(currentResult.prompt), className: "px-4 py-2 rounded-lg border border-white/20 text-[13px] text-white/70 active:bg-white/10", children: "Erneut versuchen" })
3701
+ currentResult?.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "p-6 text-center flex flex-col items-center gap-3", children: [
3702
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-red-400 text-[36px]", children: "warning" }),
3703
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-white/50 text-[13px]", children: currentResult.error?.message }),
3704
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => handleGenerateImage(currentResult.prompt), className: "px-4 py-2 rounded-lg border border-white/20 text-[13px] text-white/70 active:bg-white/10", children: "Erneut versuchen" })
2318
3705
  ] }),
2319
- currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: currentResult.base64, className: "w-full h-full object-contain" }),
2320
- !currentResult && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
2321
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[64px]", children: "palette" }),
2322
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[11px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
3706
+ currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("img", { src: currentResult.base64, className: "w-full h-full object-contain" }),
3707
+ !currentResult && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
3708
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[64px]", children: "palette" }),
3709
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[11px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
2323
3710
  ] }),
2324
- currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: openFullscreen, className: "absolute top-2 right-2 w-8 h-8 flex items-center justify-center rounded-full bg-black/60 border border-white/10 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: "fullscreen" }) }),
2325
- history.length > 1 && currentResult && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2326
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: goToPrev, disabled: currentIndex <= 0, className: "absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
2327
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, className: "absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
2328
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "absolute bottom-2 left-1/2 -translate-x-1/2 bg-black/60 rounded-full px-3 py-0.5 text-[10px] text-white/40 font-mono", children: [
3711
+ currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: openFullscreen, className: "absolute top-2 right-2 w-8 h-8 flex items-center justify-center rounded-full bg-black/60 border border-white/10 z-10", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: "fullscreen" }) }),
3712
+ history.length > 1 && currentResult && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3713
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: goToPrev, disabled: currentIndex <= 0, className: "absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
3714
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, className: "absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
3715
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "absolute bottom-2 left-1/2 -translate-x-1/2 bg-black/60 rounded-full px-3 py-0.5 text-[10px] text-white/40 font-mono", children: [
2329
3716
  currentIndex + 1,
2330
3717
  " / ",
2331
3718
  history.length
@@ -2334,30 +3721,30 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2334
3721
  ]
2335
3722
  }
2336
3723
  ),
2337
- currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex gap-2 mt-3", children: [
2338
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => setActivePrompt(currentResult.prompt || ""), className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors", style: { height: 44 }, children: [
2339
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "replay" }),
2340
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[12px] text-white/60", children: "Prompt" })
3724
+ currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex gap-2 mt-3", children: [
3725
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => setActivePrompt(currentResult.prompt || ""), className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors", style: { height: 44 }, children: [
3726
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "replay" }),
3727
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[12px] text-white/60", children: "Prompt" })
2341
3728
  ] }),
2342
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl bg-white/10 active:bg-white/15 transition-colors", style: { height: 44 }, children: [
2343
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[18px] text-white/80", children: "auto_fix_high" }),
2344
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[12px] text-white/80 font-bold", children: "Referenz" })
3729
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl bg-white/10 active:bg-white/15 transition-colors", style: { height: 44 }, children: [
3730
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[18px] text-white/80", children: "auto_fix_high" }),
3731
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[12px] text-white/80 font-bold", children: "Referenz" })
2345
3732
  ] }),
2346
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: handleDownloadSingle, className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors", style: { height: 44 }, children: [
2347
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "download" }),
2348
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[12px] text-white/60", children: "Laden" })
3733
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: handleDownloadSingle, className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors", style: { height: 44 }, children: [
3734
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "download" }),
3735
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[12px] text-white/60", children: "Laden" })
2349
3736
  ] })
2350
3737
  ] })
2351
3738
  ] })
2352
3739
  ] }),
2353
- mobileTab === "browse" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col flex-1 min-h-0", children: [
2354
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: ["history", "gallery", "inspect"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setActiveTab(tab), className: `flex-1 flex items-center justify-center gap-1.5 transition-colors text-[11px] font-bold uppercase tracking-wide ${activeTab === tab ? "text-white border-b-2 border-white" : "text-white/30"}`, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : "info" }) }, tab)) }),
2355
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
2356
- activeTab === "history" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: (g) => {
3740
+ mobileTab === "browse" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col flex-1 min-h-0", children: [
3741
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: ["history", "gallery", "inspect"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setActiveTab(tab), className: `flex-1 flex items-center justify-center gap-1.5 transition-colors text-[11px] font-bold uppercase tracking-wide ${activeTab === tab ? "text-white border-b-2 border-white" : "text-white/30"}`, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : "info" }) }, tab)) }),
3742
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
3743
+ activeTab === "history" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: (g) => {
2357
3744
  setCurrentResult(g);
2358
3745
  setMobileTab("stage");
2359
3746
  }, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
2360
- activeTab === "gallery" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3747
+ activeTab === "gallery" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2361
3748
  MediaLibrary,
2362
3749
  {
2363
3750
  items: galleryItems,
@@ -2377,38 +3764,39 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2377
3764
  }
2378
3765
  }
2379
3766
  ),
2380
- activeTab === "inspect" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(InspectPanel, { currentResult, history, onSelect: (g) => {
3767
+ activeTab === "inspect" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(InspectPanel, { currentResult, history, onSelect: (g) => {
2381
3768
  setCurrentResult(g);
2382
3769
  } })
2383
3770
  ] })
2384
3771
  ] }),
2385
- mobileTab === "tools" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col flex-1 min-h-0", children: [
2386
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: [
2387
- workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => {
3772
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: mobileTab === "tools" ? "flex" : "none" }, className: "flex flex-col flex-1 min-h-0", children: [
3773
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: [
3774
+ workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => {
2388
3775
  setLeftTab("prompt");
2389
3776
  if (activeTab === "setup" || activeTab === "sync") setActiveTab("history");
2390
3777
  }, className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${leftTab === "prompt" && activeTab !== "setup" && activeTab !== "sync" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
2391
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "auto_fix_high" }),
3778
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "auto_fix_high" }),
2392
3779
  "Prompt"
2393
3780
  ] }),
2394
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => {
3781
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => {
2395
3782
  setLeftTab("hierarchy");
2396
3783
  if (activeTab === "setup" || activeTab === "sync") setActiveTab("history");
2397
3784
  }, className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${leftTab === "hierarchy" && activeTab !== "setup" && activeTab !== "sync" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
2398
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "account_tree" }),
3785
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "account_tree" }),
2399
3786
  "Hierarchie"
2400
3787
  ] }),
2401
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => setActiveTab("setup"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "setup" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
2402
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "settings" }),
3788
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => setActiveTab("setup"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "setup" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
3789
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "settings" }),
2403
3790
  "Setup"
2404
3791
  ] }),
2405
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => setActiveTab("sync"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "sync" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
2406
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "cloud_sync" }),
3792
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => setActiveTab("sync"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "sync" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
3793
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "cloud_sync" }),
2407
3794
  "Sync"
2408
- ] })
3795
+ ] }),
3796
+ workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setActiveTab("tags"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "tags" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "label" }) })
2409
3797
  ] }),
2410
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
2411
- leftTab === "hierarchy" && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute inset-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3798
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
3799
+ leftTab === "hierarchy" && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "absolute inset-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2412
3800
  ListView,
2413
3801
  {
2414
3802
  nodes,
@@ -2439,12 +3827,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2439
3827
  isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
2440
3828
  }
2441
3829
  ) }),
2442
- leftTab === "prompt" && workspaceTags && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => {
3830
+ workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { display: leftTab === "prompt" && activeTab !== "setup" && activeTab !== "sync" ? "flex" : "none" }, className: "absolute inset-0 flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => {
2443
3831
  handleGenerateImage(prompt);
2444
3832
  setMobileTab("stage");
2445
- }, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }),
2446
- activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
2447
- activeTab === "sync" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3833
+ }, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }) }),
3834
+ activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
3835
+ activeTab === "sync" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2448
3836
  ProjectSyncTab,
2449
3837
  {
2450
3838
  onProjectExport: handleProjectExport,
@@ -2459,20 +3847,33 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2459
3847
  onComputeSyncDiff: onFetchServerProjects && onServerLoad && onServerSave ? handleComputeSyncDiff : void 0,
2460
3848
  onExecuteSync: onFetchServerProjects && onServerLoad && onServerSave ? handleExecuteSync : void 0
2461
3849
  }
3850
+ ),
3851
+ activeTab === "tags" && workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3852
+ TagManagerPanel,
3853
+ {
3854
+ workspaceTags,
3855
+ onTagCreate: handleTagCreate,
3856
+ onTagUpdate: handleTagUpdate,
3857
+ onTagDelete: handleTagDelete,
3858
+ onTagReorder: handleTagReorder,
3859
+ onTagMove: handleTagMove
3860
+ }
2462
3861
  )
2463
3862
  ] })
2464
3863
  ] }),
2465
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex border-t border-white/10 bg-black shrink-0", style: { height: 56, paddingBottom: "env(safe-area-inset-bottom, 0px)" }, children: [
3864
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex border-t border-white/10 bg-black shrink-0", style: { height: 56, paddingBottom: "env(safe-area-inset-bottom, 0px)" }, children: [
2466
3865
  { id: "tools", icon: "auto_fix_high", label: "Prompt" },
2467
3866
  { id: "stage", icon: "palette", label: "Stage" },
3867
+ { id: "labs", icon: "science", label: "Labs" },
3868
+ ...workspaceTags ? [{ id: "tags", icon: "label", label: "Tags" }] : [],
2468
3869
  { id: "browse", icon: "photo_library", label: "Galerie" }
2469
- ].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => setMobileTab(tab.id), className: `flex-1 flex flex-col items-center justify-center gap-0.5 transition-colors ${mobileTab === tab.id ? "text-white" : "text-white/30"}`, children: [
2470
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[24px]", children: tab.icon }),
2471
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[10px] font-bold uppercase tracking-wide", children: tab.label })
3870
+ ].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => setMobileTab(tab.id), className: `flex-1 flex flex-col items-center justify-center gap-0.5 transition-colors ${mobileTab === tab.id ? "text-white" : "text-white/30"}`, children: [
3871
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[24px]", children: tab.icon }),
3872
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[10px] font-bold uppercase tracking-wide", children: tab.label })
2472
3873
  ] }, tab.id)) })
2473
3874
  ] });
2474
3875
  if (mdMode) {
2475
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { position: "fixed", inset: 0, overflow: "hidden", background: "#0e0e0e" }, children: mobileRoot });
3876
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { position: "fixed", inset: 0, overflow: "hidden", background: "#0e0e0e" }, children: mobileRoot });
2476
3877
  }
2477
3878
  return mobileRoot;
2478
3879
  }
@@ -2480,17 +3881,17 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2480
3881
  const tlScale = Math.min(window.innerWidth / 920, window.innerHeight / 520);
2481
3882
  const tlW = 920;
2482
3883
  const tlH = 520;
2483
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { position: "fixed", inset: 0, background: "#0e0e0e", display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden", ...hcStyle || {} }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { width: tlW, height: tlH, transform: `scale(${tlScale})`, transformOrigin: "center center", display: "flex", flexDirection: "row", color: "#fff", overflow: "hidden", borderRadius: 0 }, children: [
2484
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { width: 320, height: tlH, display: "flex", flexDirection: "column", borderRight: "1px solid rgba(255,255,255,0.05)", background: "#000", flexShrink: 0 }, children: [
2485
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { height: 52, borderBottom: "1px solid rgba(255,255,255,0.05)", display: "flex", alignItems: "center", gap: 8, padding: "0 12px", flexShrink: 0 }, children: [
2486
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
2487
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
2488
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flex: 1 } }),
2489
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: toggleContrast, style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: highContrast ? "light_mode" : "dark_mode" }) }),
2490
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setShowStart(true), style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "apps" }) })
3884
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { position: "fixed", inset: 0, background: "#0e0e0e", display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden", ...hcStyle || {} }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { width: tlW, height: tlH, transform: `scale(${tlScale})`, transformOrigin: "center center", display: "flex", flexDirection: "row", color: "#fff", overflow: "hidden", borderRadius: 0 }, children: [
3885
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { width: 320, height: tlH, display: "flex", flexDirection: "column", borderRight: "1px solid rgba(255,255,255,0.05)", background: "#000", flexShrink: 0 }, children: [
3886
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { height: 52, borderBottom: "1px solid rgba(255,255,255,0.05)", display: "flex", alignItems: "center", gap: 8, padding: "0 12px", flexShrink: 0 }, children: [
3887
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
3888
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
3889
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { flex: 1 } }),
3890
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: toggleContrast, style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: highContrast ? "light_mode" : "dark_mode" }) }),
3891
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setShowStart(true), style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "apps" }) })
2491
3892
  ] }),
2492
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { padding: "12px 12px 8px", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "relative", borderRadius: 12, border: `1px solid ${isSynthesizing ? "rgba(255,255,255,0.2)" : "rgba(255,255,255,0.1)"}`, background: "rgba(255,255,255,0.05)" }, children: [
2493
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3893
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { padding: "12px 12px 8px", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { position: "relative", borderRadius: 12, border: `1px solid ${isSynthesizing ? "rgba(255,255,255,0.2)" : "rgba(255,255,255,0.1)"}`, background: "rgba(255,255,255,0.05)" }, children: [
3894
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2494
3895
  "textarea",
2495
3896
  {
2496
3897
  value: activePrompt,
@@ -2499,27 +3900,27 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2499
3900
  placeholder: "Prompt eingeben..."
2500
3901
  }
2501
3902
  ),
2502
- activePrompt && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setActivePrompt(""), style: { position: "absolute", top: 6, right: 6, width: 22, height: 22, display: "flex", alignItems: "center", justifyContent: "center", color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 15 }, children: "close" }) })
3903
+ activePrompt && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setActivePrompt(""), style: { position: "absolute", top: 6, right: 6, width: 22, height: 22, display: "flex", alignItems: "center", justifyContent: "center", color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 15 }, children: "close" }) })
2503
3904
  ] }) }),
2504
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { padding: "0 12px 10px", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3905
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { padding: "0 12px 10px", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2505
3906
  "button",
2506
3907
  {
2507
3908
  onClick: () => handleGenerateImage(),
2508
3909
  disabled: !activePrompt.trim() || isGenerating,
2509
3910
  style: { width: "100%", height: 42, display: "flex", alignItems: "center", justifyContent: "center", gap: 8, borderRadius: 10, fontWeight: "bold", fontSize: 13, textTransform: "uppercase", letterSpacing: "0.05em", border: "1px solid rgba(255,255,255,0.1)", background: activePrompt.trim() && !isGenerating ? "#0284c7" : "transparent", color: "#fff", cursor: activePrompt.trim() && !isGenerating ? "pointer" : "default", opacity: !activePrompt.trim() || isGenerating ? 0.3 : 1, fontFamily: "inherit", transition: "background 0.2s" },
2510
- children: isGenerating ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2511
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { width: 14, height: 14, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
2512
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Generiere..." })
2513
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2514
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "bolt" }),
2515
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Generieren" })
3911
+ children: isGenerating ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3912
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { width: 14, height: 14, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
3913
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "Generiere..." })
3914
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3915
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "bolt" }),
3916
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "Generieren" })
2516
3917
  ] })
2517
3918
  }
2518
3919
  ) }),
2519
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }) })
3920
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }) })
2520
3921
  ] }),
2521
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { flex: 1, height: tlH, display: "flex", flexDirection: "column", background: "#0b0b0b" }, children: [
2522
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3922
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { flex: 1, height: tlH, display: "flex", flexDirection: "column", background: "#0b0b0b" }, children: [
3923
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2523
3924
  "div",
2524
3925
  {
2525
3926
  style: { flex: 1, padding: 16, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" },
@@ -2531,26 +3932,26 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2531
3932
  else if (dx > 50) goToPrev();
2532
3933
  setTouchStartX(null);
2533
3934
  },
2534
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { height: "100%", width: "100%", borderRadius: 20, border: "1px solid rgba(255,255,255,0.05)", background: "rgba(0,0,0,0.4)", position: "relative", overflow: "hidden", display: "flex", alignItems: "center", justifyContent: "center" }, children: [
2535
- currentResult?.status === "processing" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
2536
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { width: 36, height: 36, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
2537
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 10, color: "rgba(255,255,255,0.4)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
3935
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { height: "100%", width: "100%", borderRadius: 20, border: "1px solid rgba(255,255,255,0.05)", background: "rgba(0,0,0,0.4)", position: "relative", overflow: "hidden", display: "flex", alignItems: "center", justifyContent: "center" }, children: [
3936
+ currentResult?.status === "processing" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
3937
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { width: 36, height: 36, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
3938
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { fontSize: 10, color: "rgba(255,255,255,0.4)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
2538
3939
  ] }),
2539
- currentResult?.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { padding: 24, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
2540
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 32, color: "#f87171" }, children: "warning" }),
2541
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: currentResult.error?.message }),
2542
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => handleGenerateImage(currentResult.prompt), style: { padding: "8px 16px", borderRadius: 8, border: "1px solid rgba(255,255,255,0.2)", fontSize: 11, color: "rgba(255,255,255,0.7)", background: "none", cursor: "pointer", fontFamily: "inherit" }, children: "Erneut versuchen" })
3940
+ currentResult?.status === "error" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { padding: 24, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
3941
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 32, color: "#f87171" }, children: "warning" }),
3942
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: currentResult.error?.message }),
3943
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => handleGenerateImage(currentResult.prompt), style: { padding: "8px 16px", borderRadius: 8, border: "1px solid rgba(255,255,255,0.2)", fontSize: 11, color: "rgba(255,255,255,0.7)", background: "none", cursor: "pointer", fontFamily: "inherit" }, children: "Erneut versuchen" })
2543
3944
  ] }),
2544
- currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: currentResult.base64, style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain" } }),
2545
- !currentResult && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 8, opacity: 0.1 }, children: [
2546
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 64 }, children: "palette" }),
2547
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 11, fontWeight: "bold", textTransform: "uppercase", letterSpacing: "0.2em" }, children: "Avatar Architect" })
3945
+ currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("img", { src: currentResult.base64, style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain" } }),
3946
+ !currentResult && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 8, opacity: 0.1 }, children: [
3947
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 64 }, children: "palette" }),
3948
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { style: { fontSize: 11, fontWeight: "bold", textTransform: "uppercase", letterSpacing: "0.2em" }, children: "Avatar Architect" })
2548
3949
  ] }),
2549
- currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: openFullscreen, style: { position: "absolute", top: 8, right: 8, width: 32, height: 32, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff" }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "fullscreen" }) }),
2550
- history.length > 1 && currentResult && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2551
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: goToPrev, disabled: currentIndex <= 0, style: { position: "absolute", left: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex <= 0 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_left" }) }),
2552
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, style: { position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex >= history.length - 1 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_right" }) }),
2553
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { position: "absolute", bottom: 8, left: "50%", transform: "translateX(-50%)", background: "rgba(0,0,0,0.6)", borderRadius: 999, padding: "2px 12px", fontSize: 10, color: "rgba(255,255,255,0.4)", fontFamily: "monospace" }, children: [
3950
+ currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: openFullscreen, style: { position: "absolute", top: 8, right: 8, width: 32, height: 32, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "fullscreen" }) }),
3951
+ history.length > 1 && currentResult && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
3952
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: goToPrev, disabled: currentIndex <= 0, style: { position: "absolute", left: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex <= 0 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_left" }) }),
3953
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, style: { position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex >= history.length - 1 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_right" }) }),
3954
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { position: "absolute", bottom: 8, left: "50%", transform: "translateX(-50%)", background: "rgba(0,0,0,0.6)", borderRadius: 999, padding: "2px 12px", fontSize: 10, color: "rgba(255,255,255,0.4)", fontFamily: "monospace" }, children: [
2554
3955
  currentIndex + 1,
2555
3956
  " / ",
2556
3957
  history.length
@@ -2559,41 +3960,57 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2559
3960
  ] })
2560
3961
  }
2561
3962
  ),
2562
- currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { padding: "0 16px 16px", display: "flex", gap: 8, flexShrink: 0 }, children: [
2563
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => setActivePrompt(currentResult.prompt || ""), style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "1px solid rgba(255,255,255,0.1)", background: "rgba(255,255,255,0.05)", color: "rgba(255,255,255,0.6)", fontSize: 11, cursor: "pointer", fontFamily: "inherit" }, children: [
2564
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "replay" }),
2565
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Prompt" })
3963
+ currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { padding: "0 16px 16px", display: "flex", gap: 8, flexShrink: 0 }, children: [
3964
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => setActivePrompt(currentResult.prompt || ""), style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "1px solid rgba(255,255,255,0.1)", background: "rgba(255,255,255,0.05)", color: "rgba(255,255,255,0.6)", fontSize: 11, cursor: "pointer", fontFamily: "inherit" }, children: [
3965
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "replay" }),
3966
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "Prompt" })
2566
3967
  ] }),
2567
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "none", background: "rgba(255,255,255,0.1)", color: "rgba(255,255,255,0.8)", fontSize: 11, fontWeight: "bold", cursor: "pointer", fontFamily: "inherit" }, children: [
2568
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "auto_fix_high" }),
2569
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Referenz" })
3968
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "none", background: "rgba(255,255,255,0.1)", color: "rgba(255,255,255,0.8)", fontSize: 11, fontWeight: "bold", cursor: "pointer", fontFamily: "inherit" }, children: [
3969
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "auto_fix_high" }),
3970
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "Referenz" })
2570
3971
  ] }),
2571
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: handleDownloadSingle, style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "1px solid rgba(255,255,255,0.1)", background: "rgba(255,255,255,0.05)", color: "rgba(255,255,255,0.6)", fontSize: 11, cursor: "pointer", fontFamily: "inherit" }, children: [
2572
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "download" }),
2573
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Laden" })
3972
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: handleDownloadSingle, style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "1px solid rgba(255,255,255,0.1)", background: "rgba(255,255,255,0.05)", color: "rgba(255,255,255,0.6)", fontSize: 11, cursor: "pointer", fontFamily: "inherit" }, children: [
3973
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "download" }),
3974
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "Laden" })
2574
3975
  ] })
2575
3976
  ] })
2576
3977
  ] })
2577
3978
  ] }) });
2578
3979
  }
2579
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", style: hcStyle, children: [
2580
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute top-2 right-2 z-50", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setShowStart(true), className: "text-white/10 hover:text-white/30 transition-colors text-[10px]", children: "\u21C4" }) }),
2581
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", style: { width: isLeftCollapsed ? 48 : 260, transition: "width 0.2s" }, children: [
2582
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
2583
- !isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-1 gap-1", children: [
2584
- workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => setLeftTab("prompt"), className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "prompt" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`, children: [
2585
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
3980
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", style: hcStyle, children: [
3981
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "absolute top-2 right-2 z-50", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setShowStart(true), className: "text-white/10 hover:text-white/30 transition-colors text-[10px]", children: "\u21C4" }) }),
3982
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", style: { width: isLeftCollapsed ? 48 : leftPanelWidth, transition: "none" }, children: [
3983
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
3984
+ !isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-1 gap-1", children: [
3985
+ workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => setLeftTab("prompt"), className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "prompt" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`, children: [
3986
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
2586
3987
  "Prompt"
2587
3988
  ] }),
2588
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: () => setLeftTab("hierarchy"), className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "hierarchy" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`, children: [
2589
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
3989
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: () => setLeftTab("hierarchy"), className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "hierarchy" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`, children: [
3990
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
2590
3991
  "Hierarchie"
2591
- ] })
3992
+ ] }),
3993
+ workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setActiveTab("tags"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "tags" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: "label" }) })
2592
3994
  ] }),
2593
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setIsLeftCollapsed(!isLeftCollapsed), className: "material-symbols-outlined text-[18px] text-white/40 hover:text-white transition-all w-10 flex items-center justify-center", children: isLeftCollapsed ? "chevron_right" : "chevron_left" })
3995
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setIsLeftCollapsed(!isLeftCollapsed), className: "material-symbols-outlined text-[18px] text-white/40 hover:text-white transition-all w-10 flex items-center justify-center", children: isLeftCollapsed ? "chevron_right" : "chevron_left" })
2594
3996
  ] }),
2595
- !isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
2596
- leftTab === "hierarchy" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "absolute inset-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3997
+ !isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
3998
+ activeTab === "tags" && workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
3999
+ TagManagerPanel,
4000
+ {
4001
+ workspaceTags,
4002
+ onTagCreate: handleTagCreate,
4003
+ onTagUpdate: handleTagUpdate,
4004
+ onTagDelete: handleTagDelete,
4005
+ onTagReorder: handleTagReorder,
4006
+ onTagMove: handleTagMove
4007
+ }
4008
+ ),
4009
+ activeTab === "tags" && !workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex items-center justify-center h-full p-8 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { children: [
4010
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[40px] text-white/10 block mb-3", children: "label_off" }),
4011
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-[11px] text-white/20", children: "Erst Workspace importieren um Tags zu verwalten." })
4012
+ ] }) }),
4013
+ leftTab === "hierarchy" && activeTab !== "tags" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "absolute inset-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2597
4014
  ListView,
2598
4015
  {
2599
4016
  nodes,
@@ -2618,73 +4035,111 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2618
4035
  isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
2619
4036
  }
2620
4037
  ) }),
2621
- leftTab === "prompt" && workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => handleGenerateImage(prompt), onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage })
4038
+ leftTab === "prompt" && workspaceTags && activeTab !== "tags" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => handleGenerateImage(prompt), onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage })
2622
4039
  ] })
2623
4040
  ] }),
2624
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
2625
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
2626
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1.5", children: [
2627
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
2628
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] })
4041
+ !isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { onMouseDown: startLeftResize, className: "w-1 shrink-0 cursor-col-resize hover:bg-white/20 active:bg-white/30 transition-colors", style: { background: "transparent" } }),
4042
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
4043
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
4044
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5", children: [
4045
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
4046
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] })
2629
4047
  ] }),
2630
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-2", children: [
2631
- activeReferenceThumbnail ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden", style: { height: 28 }, children: [
2632
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
2633
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
2634
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 hover:text-white/80 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
2635
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { onClick: handleSelectReference, className: "flex items-center gap-1 h-7 px-2 rounded-lg border border-white/10 text-white/30 hover:text-white/60 hover:border-white/20 transition-colors text-[10px] font-bold uppercase tracking-wide", children: [
2636
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
2637
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: "Ref" })
4048
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1 mx-auto", children: [
4049
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4050
+ "button",
4051
+ {
4052
+ onClick: () => setMiddlePanel("stage"),
4053
+ className: `px-3 h-7 rounded-lg text-[9px] font-bold uppercase tracking-wide transition-colors ${middlePanel === "stage" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/50"}`,
4054
+ children: "Stage"
4055
+ }
4056
+ ),
4057
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4058
+ "button",
4059
+ {
4060
+ onClick: () => setMiddlePanel("labs"),
4061
+ className: `px-3 h-7 rounded-lg text-[9px] font-bold uppercase tracking-wide transition-colors ${middlePanel === "labs" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/50"}`,
4062
+ children: "Labs"
4063
+ }
4064
+ )
4065
+ ] }),
4066
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-2", children: [
4067
+ activeReferenceThumbnail ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden", style: { height: 28 }, children: [
4068
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
4069
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
4070
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 hover:text-white/80 transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
4071
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("button", { onClick: handleSelectReference, className: "flex items-center gap-1 h-7 px-2 rounded-lg border border-white/10 text-white/30 hover:text-white/60 hover:border-white/20 transition-colors text-[10px] font-bold uppercase tracking-wide", children: [
4072
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
4073
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: "Ref" })
2638
4074
  ] }),
2639
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
2640
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
4075
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
4076
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
2641
4077
  ] })
2642
4078
  ] }),
2643
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
2644
- !isPromptCollapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
2645
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("textarea", { value: activePrompt, onChange: (e) => setActivePrompt(e.target.value), className: "w-full bg-transparent border-none outline-none text-[12px] leading-relaxed text-white/80 resize-none h-20 dark-scrollbar", placeholder: "W\xE4hle einen Knoten oder tippe einen Prompt..." }),
2646
- activePrompt && !isSynthesizing && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-6 h-6 rounded-full bg-white/5 hover:bg-white/10 flex items-center justify-center transition-colors text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
4079
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
4080
+ !isPromptCollapsed && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
4081
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("textarea", { value: activePrompt, onChange: (e) => setActivePrompt(e.target.value), className: "w-full bg-transparent border-none outline-none text-[12px] leading-relaxed text-white/80 resize-none h-20 dark-scrollbar", placeholder: "W\xE4hle einen Knoten oder tippe einen Prompt..." }),
4082
+ activePrompt && !isSynthesizing && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-6 h-6 rounded-full bg-white/5 hover:bg-white/10 flex items-center justify-center transition-colors text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
2647
4083
  ] }) }),
2648
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: [
2649
- isGenerating && currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "absolute top-6 right-6 z-30 bg-black/60 backdrop-blur-md px-4 py-2 rounded-full border border-white/10 flex items-center gap-3", children: [
2650
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
2651
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
4084
+ middlePanel === "labs" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LabsTab, { services: labServices, onResult: (item) => {
4085
+ const frame = item.frames[0];
4086
+ if (frame?.base64) setCurrentResult(frameToGeneration(frame, item));
4087
+ } }) }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: [
4088
+ isGenerating && currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "absolute top-6 right-6 z-30 bg-black/60 backdrop-blur-md px-4 py-2 rounded-full border border-white/10 flex items-center gap-3", children: [
4089
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
4090
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
2652
4091
  ] }),
2653
- currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
2654
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
2655
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
2656
- ] }) : currentResult.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
2657
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
2658
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col gap-2", children: [
2659
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
2660
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
4092
+ currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
4093
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
4094
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
4095
+ ] }) : currentResult.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
4096
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
4097
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col gap-2", children: [
4098
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
4099
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
2661
4100
  ] }),
2662
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
2663
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "h-full w-full relative flex items-center justify-center", children: [
2664
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
2665
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "absolute bottom-6 flex gap-2 opacity-0 group-hover:opacity-100 transition-all translate-y-4 group-hover:translate-y-0 z-20", children: [
2666
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
2667
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
2668
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
4101
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
4102
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "h-full w-full relative flex items-center justify-center", children: [
4103
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
4104
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "absolute bottom-6 flex gap-2 opacity-0 group-hover:opacity-100 transition-all translate-y-4 group-hover:translate-y-0 z-20", children: [
4105
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
4106
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
4107
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
2669
4108
  ] })
2670
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
2671
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
2672
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
4109
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
4110
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
4111
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
2673
4112
  ] })
2674
4113
  ] }) })
2675
4114
  ] })
2676
4115
  ] }),
2677
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", style: { width: isRightCollapsed ? 60 : 320, transition: "width 0.2s" }, children: [
2678
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
2679
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup", "sync"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => {
4116
+ !isRightCollapsed && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { onMouseDown: startRightResize, className: "w-1 shrink-0 cursor-col-resize hover:bg-white/20 active:bg-white/30 transition-colors", style: { background: "transparent" } }),
4117
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", style: { width: isRightCollapsed ? 60 : rightPanelWidth, transition: "none" }, children: [
4118
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
4119
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup", "sync", "tags"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => {
2680
4120
  setActiveTab(tab);
2681
4121
  setIsRightCollapsed(false);
2682
- }, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : tab === "setup" ? "settings" : "cloud_sync" }) }, tab)) }),
2683
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
4122
+ }, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : tab === "setup" ? "settings" : tab === "sync" ? "cloud_sync" : "label" }) }, tab)) }),
4123
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
2684
4124
  ] }),
2685
- !isRightCollapsed && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
2686
- activeTab === "history" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
2687
- activeTab === "gallery" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4125
+ !isRightCollapsed && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex-1 overflow-hidden relative", children: [
4126
+ activeTab === "tags" && workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4127
+ TagManagerPanel,
4128
+ {
4129
+ workspaceTags,
4130
+ onTagCreate: handleTagCreate,
4131
+ onTagUpdate: handleTagUpdate,
4132
+ onTagDelete: handleTagDelete,
4133
+ onTagReorder: handleTagReorder,
4134
+ onTagMove: handleTagMove
4135
+ }
4136
+ ),
4137
+ activeTab === "tags" && !workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "flex items-center justify-center h-full p-8 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { children: [
4138
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { className: "material-symbols-outlined text-[40px] text-white/10 block mb-3", children: "label_off" }),
4139
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-[11px] text-white/20", children: "Erst Workspace importieren um Tags zu verwalten." })
4140
+ ] }) }),
4141
+ activeTab === "history" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
4142
+ activeTab === "gallery" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2688
4143
  MediaLibrary,
2689
4144
  {
2690
4145
  items: galleryItems,
@@ -2698,9 +4153,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2698
4153
  onGenerateReference: (item) => handleGenerateImage(item.prompt || activePrompt, item.mediaId, void 0, { silent: true })
2699
4154
  }
2700
4155
  ),
2701
- activeTab === "inspect" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(InspectPanel, { currentResult, history, onSelect: setCurrentResult }),
2702
- activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
2703
- activeTab === "sync" && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
4156
+ activeTab === "inspect" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(InspectPanel, { currentResult, history, onSelect: setCurrentResult }),
4157
+ activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
4158
+ activeTab === "sync" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2704
4159
  ProjectSyncTab,
2705
4160
  {
2706
4161
  onProjectExport: handleProjectExport,
@@ -2722,7 +4177,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2722
4177
  }
2723
4178
 
2724
4179
  // src/index.ts
2725
- var LIB_VERSION = "1.1.3";
4180
+ var LIB_VERSION = "1.2.1";
2726
4181
  // Annotate the CommonJS export names for ESM import in node:
2727
4182
  0 && (module.exports = {
2728
4183
  AvatarArchitectApp,
@@ -2733,6 +4188,12 @@ var LIB_VERSION = "1.1.3";
2733
4188
  HistoryPanel,
2734
4189
  InspectPanel,
2735
4190
  LIB_VERSION,
4191
+ LabBlend,
4192
+ LabCompare,
4193
+ LabImagePicker,
4194
+ LabLoop,
4195
+ LabRemix,
4196
+ LabsTab,
2736
4197
  ListView,
2737
4198
  MediaLibrary,
2738
4199
  PillButton,
@@ -2740,15 +4201,25 @@ var LIB_VERSION = "1.1.3";
2740
4201
  PromptTab,
2741
4202
  SectionLabel,
2742
4203
  SetupPanel,
4204
+ TagManagerPanel,
4205
+ autoLabel,
4206
+ buildBlendInstruction,
4207
+ buildCompareInstruction,
2743
4208
  buildFallbackPrompt,
2744
4209
  buildGenerationPrompt,
2745
4210
  buildImageGenerationOptions,
4211
+ buildLoopInstruction,
2746
4212
  buildPromptTabPayload,
4213
+ buildReferenceImageMediaIds,
4214
+ buildRemixInstruction,
4215
+ buildScanInstruction,
2747
4216
  cleanAiResponse,
2748
4217
  createFlowServices,
2749
4218
  exportProjectToZip,
2750
4219
  formatTreeToMarkdown,
4220
+ frameToGeneration,
2751
4221
  getFormattedTimestamp,
4222
+ groupGenerationsToLabItems,
2752
4223
  importProjectFromZip,
2753
4224
  injectXMPMetadata,
2754
4225
  interpretSdkError,