@rslsp1/fa-app-tools 1.1.4 → 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.mjs CHANGED
@@ -197,7 +197,7 @@ function generateMarkdownReport(nodes, history) {
197
197
  });
198
198
  return md;
199
199
  }
200
- async function exportProjectToZip(nodes, edges, history, galleryItems, settings, workspaceTags) {
200
+ async function exportProjectToZip(nodes, edges, history, galleryItems, settings, workspaceTags, recentLabItemIds) {
201
201
  const zip = new JSZip();
202
202
  const projectData = {
203
203
  nodes,
@@ -206,7 +206,8 @@ async function exportProjectToZip(nodes, edges, history, galleryItems, settings,
206
206
  galleryItems: galleryItems.map((g) => ({ ...g, base64: void 0 })),
207
207
  settings,
208
208
  workspaceTags: workspaceTags || null,
209
- version: "1.2.6"
209
+ recentLabItemIds: recentLabItemIds || [],
210
+ version: "1.3.0"
210
211
  };
211
212
  zip.file("project.json", JSON.stringify(projectData, null, 2));
212
213
  zip.file("projekt_bericht.md", generateMarkdownReport(nodes, history));
@@ -362,35 +363,18 @@ function createFlowServices(Flow) {
362
363
  throw interpretSdkError(err);
363
364
  }
364
365
  },
365
- generateText: async (hierarchyText, mode = "creative", images) => {
366
- if (mode === "scan" && images?.length) {
367
- try {
368
- const response = await Flow.generate.text(
369
- "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.",
370
- {
371
- thinkingLevel: "low",
372
- systemInstruction: "You are an expert image analyst and prompt engineer. Always return ONLY the generation prompt, no headers, no quotes, no conversational filler.",
373
- images
374
- }
375
- );
376
- const result = response?.text?.trim() || "";
377
- if (!result) throw new Error("Empty AI response");
378
- return cleanAiResponse(result);
379
- } catch (err) {
380
- throw interpretSdkError(err);
381
- }
382
- }
383
- const prompt = buildGenerationPrompt(hierarchyText, mode);
366
+ generateText: async (text, options) => {
384
367
  try {
385
- const response = await Flow.generate.text(prompt, {
368
+ const response = await Flow.generate.text(text, {
386
369
  thinkingLevel: "low",
387
- systemInstruction: "You are an expert prompt engineer. Always return ONLY the generated prompt text, no headers, no quotes, no conversational filler."
370
+ systemInstruction: options?.systemInstruction || "You are an expert prompt engineer. Always return ONLY the generated prompt text, no headers, no quotes, no conversational filler.",
371
+ images: options?.images
388
372
  });
389
373
  const result = response?.text?.trim() || "";
390
374
  if (!result) throw new Error("Empty AI response");
391
375
  return cleanAiResponse(result);
392
- } catch {
393
- return buildFallbackPrompt(hierarchyText);
376
+ } catch (err) {
377
+ throw interpretSdkError(err);
394
378
  }
395
379
  }
396
380
  };
@@ -669,12 +653,39 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
669
653
  };
670
654
 
671
655
  // src/components/SetupPanel.tsx
672
- import { useRef as useRef2 } from "react";
656
+ import { useRef as useRef2, useState as useState2 } from "react";
673
657
  import { motion as motion3 } from "motion/react";
674
658
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
675
659
  var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
676
660
  const workspaceInputRef = useRef2(null);
677
- return /* @__PURE__ */ jsxs5(motion3.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10", children: [
661
+ const [urlInput, setUrlInput] = useState2("");
662
+ const [urlStatus, setUrlStatus] = useState2("idle");
663
+ const [urlThumb, setUrlThumb] = useState2(null);
664
+ const [urlError, setUrlError] = useState2(null);
665
+ const handleUrlTest = async () => {
666
+ if (!urlInput.trim()) return;
667
+ setUrlStatus("loading");
668
+ setUrlThumb(null);
669
+ setUrlError(null);
670
+ try {
671
+ const res = await fetch(urlInput.trim());
672
+ if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
673
+ const blob = await res.blob();
674
+ const mimeType = blob.type || "image/jpeg";
675
+ const dataUrl = await new Promise((resolve, reject) => {
676
+ const reader = new FileReader();
677
+ reader.onload = () => resolve(reader.result);
678
+ reader.onerror = () => reject(new Error("FileReader failed"));
679
+ reader.readAsDataURL(blob);
680
+ });
681
+ setUrlThumb(dataUrl);
682
+ setUrlStatus("ok");
683
+ } catch (e) {
684
+ setUrlError(e.message || String(e));
685
+ setUrlStatus("error");
686
+ }
687
+ };
688
+ return /* @__PURE__ */ jsxs5(motion3.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10 overflow-y-auto", children: [
678
689
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-4", children: [
679
690
  /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", children: [
680
691
  /* @__PURE__ */ jsx7(SectionLabel, { children: "Workspace Management" }),
@@ -687,6 +698,44 @@ var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
687
698
  e.target.value = "";
688
699
  } })
689
700
  ] }),
701
+ /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-3", children: [
702
+ /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", children: [
703
+ /* @__PURE__ */ jsx7(SectionLabel, { children: "URL-Fetch Test" }),
704
+ /* @__PURE__ */ jsx7("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Pr\xFCft ob externe URLs als Bild geladen werden k\xF6nnen." })
705
+ ] }),
706
+ /* @__PURE__ */ jsxs5("div", { className: "flex gap-2", children: [
707
+ /* @__PURE__ */ jsx7(
708
+ "input",
709
+ {
710
+ value: urlInput,
711
+ onChange: (e) => setUrlInput(e.target.value),
712
+ onKeyDown: (e) => e.key === "Enter" && handleUrlTest(),
713
+ placeholder: "https://example.com/image.jpg",
714
+ 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"
715
+ }
716
+ ),
717
+ /* @__PURE__ */ jsx7(
718
+ "button",
719
+ {
720
+ onClick: handleUrlTest,
721
+ disabled: urlStatus === "loading" || !urlInput.trim(),
722
+ 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",
723
+ children: urlStatus === "loading" ? /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[16px] animate-spin", children: "sync" }) : /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[16px]", children: "download" })
724
+ }
725
+ )
726
+ ] }),
727
+ urlStatus === "ok" && urlThumb && /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
728
+ /* @__PURE__ */ jsx7("img", { src: urlThumb, alt: "URL Test", className: "w-full max-h-48 object-contain rounded-xl border border-white/10 bg-black/40" }),
729
+ /* @__PURE__ */ jsxs5("p", { className: "text-[10px] text-green-400 font-mono flex items-center gap-1", children: [
730
+ /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[14px]", children: "check_circle" }),
731
+ "Fetch erfolgreich"
732
+ ] })
733
+ ] }),
734
+ urlStatus === "error" && urlError && /* @__PURE__ */ jsxs5("p", { className: "text-[10px] text-red-400 font-mono flex items-start gap-1", children: [
735
+ /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[14px] shrink-0", children: "error" }),
736
+ urlError
737
+ ] })
738
+ ] }),
690
739
  /* @__PURE__ */ jsxs5("div", { className: "mt-auto p-4 bg-white/5 rounded-2xl border border-white/5 flex flex-col gap-2 opacity-50", children: [
691
740
  /* @__PURE__ */ jsx7("span", { className: "text-[8px] font-bold text-white/20 uppercase tracking-widest", children: "System Info" }),
692
741
  /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between text-[9px] text-white/40", children: [
@@ -763,7 +812,7 @@ var MediaLibrary = ({ items, onImport, onDelete, onSelect, onToggleSelection, on
763
812
  };
764
813
 
765
814
  // src/components/ListView.tsx
766
- import { useEffect as useEffect3, useRef as useRef3, useState as useState2 } from "react";
815
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
767
816
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
768
817
  var ListNode = ({ node, depth, onNodeChange, onAddChild, onDeleteNode, onMoveNode, onIndentNode, onOutdentNode, onAddSibling, isActive, isInPath, onFocus, onGenerate, onGenerateBranch, onGenerateSubtree, isGenerating, isCollapsed, toggleCollapse, renderNode, children }) => {
769
818
  const inputRef = useRef3(null);
@@ -828,7 +877,7 @@ var ListNode = ({ node, depth, onNodeChange, onAddChild, onDeleteNode, onMoveNod
828
877
  ] });
829
878
  };
830
879
  function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMoveNode, onIndentNode, onOutdentNode, onAddSibling, focusedNodeId, onFocus, activePath, onGenerate, onGenerateBranch, onGenerateSubtree, isGeneratingNodeId }) {
831
- const [collapsed, setCollapsed] = useState2(/* @__PURE__ */ new Set());
880
+ const [collapsed, setCollapsed] = useState3(/* @__PURE__ */ new Set());
832
881
  const toggleCollapse = (id) => {
833
882
  setCollapsed((prev) => {
834
883
  const next = new Set(prev);
@@ -856,13 +905,13 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
856
905
  }
857
906
 
858
907
  // src/components/AvatarArchitectApp.tsx
859
- import { useState as useState6, useCallback, useMemo as useMemo2, useEffect as useEffect4, useRef as useRef6 } from "react";
908
+ import { useState as useState14, useCallback, useMemo as useMemo2, useEffect as useEffect4, useRef as useRef6 } from "react";
860
909
 
861
910
  // src/components/PromptTab.tsx
862
- import { useRef as useRef4, useState as useState4 } from "react";
911
+ import { useRef as useRef4, useState as useState5 } from "react";
863
912
 
864
913
  // src/components/CollapsibleCard.tsx
865
- import { useState as useState3 } from "react";
914
+ import { useState as useState4 } from "react";
866
915
  import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
867
916
  var CollapsibleCard = ({
868
917
  title,
@@ -873,7 +922,7 @@ var CollapsibleCard = ({
873
922
  collapsible = true,
874
923
  className = ""
875
924
  }) => {
876
- const [isOpen, setIsOpen] = useState3(defaultOpen);
925
+ const [isOpen, setIsOpen] = useState4(defaultOpen);
877
926
  return /* @__PURE__ */ jsxs8("div", { className: `border border-neutral-800 rounded-lg ${className}`, children: [
878
927
  /* @__PURE__ */ jsxs8(
879
928
  "div",
@@ -920,18 +969,18 @@ var PromptTab = ({
920
969
  onTagUpdate,
921
970
  onTagDelete
922
971
  }) => {
923
- const [selectedLabels, setSelectedLabels] = useState4(/* @__PURE__ */ new Set());
924
- const [instructions, setInstructions] = useState4("");
925
- const [rules, setRules] = useState4("");
926
- const [activeCategory, setActiveCategory] = useState4(null);
927
- const [copied, setCopied] = useState4(false);
972
+ const [selectedLabels, setSelectedLabels] = useState5(/* @__PURE__ */ new Set());
973
+ const [instructions, setInstructions] = useState5("");
974
+ const [rules, setRules] = useState5("");
975
+ const [activeCategory, setActiveCategory] = useState5(null);
976
+ const [copied, setCopied] = useState5(false);
928
977
  const imgInputRef = useRef4(null);
929
- const [addingInCat, setAddingInCat] = useState4(null);
930
- const [newLabel, setNewLabel] = useState4("");
931
- const [newValue, setNewValue] = useState4("");
932
- const [editingTag, setEditingTag] = useState4(null);
933
- const [editLabel, setEditLabel] = useState4("");
934
- const [editValue, setEditValue] = useState4("");
978
+ const [addingInCat, setAddingInCat] = useState5(null);
979
+ const [newLabel, setNewLabel] = useState5("");
980
+ const [newValue, setNewValue] = useState5("");
981
+ const [editingTag, setEditingTag] = useState5(null);
982
+ const [editLabel, setEditLabel] = useState5("");
983
+ const [editValue, setEditValue] = useState5("");
935
984
  const longPressTimer = useRef4(null);
936
985
  const longPressActivated = useRef4(false);
937
986
  const toggleTag = (label) => {
@@ -1380,7 +1429,7 @@ var PromptTab = ({
1380
1429
  };
1381
1430
 
1382
1431
  // src/components/ProjectSyncTab.tsx
1383
- import { useRef as useRef5, useState as useState5 } from "react";
1432
+ import { useRef as useRef5, useState as useState6 } from "react";
1384
1433
  import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1385
1434
  var ProjectSyncTab = ({
1386
1435
  onProjectExport,
@@ -1397,12 +1446,12 @@ var ProjectSyncTab = ({
1397
1446
  }) => {
1398
1447
  const projectInputRef = useRef5(null);
1399
1448
  const workspaceInputRef = useRef5(null);
1400
- const [saveName, setSaveName] = useState5("");
1401
- const [isSaving, setIsSaving] = useState5(false);
1402
- const [isExporting, setIsExporting] = useState5(false);
1403
- const [syncState, setSyncState] = useState5("idle");
1404
- const [syncDiff, setSyncDiff] = useState5(null);
1405
- const [selectedLocalIds, setSelectedLocalIds] = useState5(/* @__PURE__ */ new Set());
1449
+ const [saveName, setSaveName] = useState6("");
1450
+ const [isSaving, setIsSaving] = useState6(false);
1451
+ const [isExporting, setIsExporting] = useState6(false);
1452
+ const [syncState, setSyncState] = useState6("idle");
1453
+ const [syncDiff, setSyncDiff] = useState6(null);
1454
+ const [selectedLocalIds, setSelectedLocalIds] = useState6(/* @__PURE__ */ new Set());
1406
1455
  const handleExport = async () => {
1407
1456
  if (!onProjectExport) return;
1408
1457
  setIsExporting(true);
@@ -1604,8 +1653,1205 @@ var ProjectSyncTab = ({
1604
1653
  ] }) });
1605
1654
  };
1606
1655
 
1607
- // src/components/AvatarArchitectApp.tsx
1656
+ // src/lib/labHelpers.ts
1657
+ function groupGenerationsToLabItems(generations) {
1658
+ const map = /* @__PURE__ */ new Map();
1659
+ for (const gen of generations) {
1660
+ if (gen.status !== "done" || !gen.base64) continue;
1661
+ const prompt = gen.prompt || "";
1662
+ const existing = map.get(prompt);
1663
+ const frame = {
1664
+ id: gen.id,
1665
+ base64: gen.base64,
1666
+ mediaId: gen.mediaId,
1667
+ seed: gen.seed,
1668
+ model: gen.model,
1669
+ source: gen.type === "import" ? "zip-import" : "generated"
1670
+ };
1671
+ if (existing) {
1672
+ existing.frames.push(frame);
1673
+ } else {
1674
+ map.set(prompt, {
1675
+ id: gen.id,
1676
+ prompt,
1677
+ tags: gen.tags,
1678
+ frames: [frame]
1679
+ });
1680
+ }
1681
+ }
1682
+ return Array.from(map.values());
1683
+ }
1684
+ function frameToGeneration(frame, item) {
1685
+ return {
1686
+ id: frame.id,
1687
+ nodeId: "1",
1688
+ base64: frame.base64,
1689
+ mediaId: frame.mediaId,
1690
+ prompt: item.prompt,
1691
+ seed: frame.seed,
1692
+ model: frame.model,
1693
+ timestamp: Date.now(),
1694
+ status: "done",
1695
+ tags: item.tags || [],
1696
+ type: frame.source === "zip-import" ? "import" : "generation"
1697
+ };
1698
+ }
1699
+ function buildImageContext(images) {
1700
+ const active = images.filter((i) => i.sendToPromptAI);
1701
+ if (!active.length) return "";
1702
+ const lines = active.map((i) => {
1703
+ const role = i.roleForPrompt ? ` (${i.roleForPrompt})` : "";
1704
+ const promptSnippet = i.item.prompt ? `: "${i.item.prompt.slice(0, 120)}"` : "";
1705
+ return `- ${i.label}${role}${promptSnippet}`;
1706
+ });
1707
+ return `
1708
+
1709
+ Reference images:
1710
+ ${lines.join("\n")}`;
1711
+ }
1712
+ function buildScanInstruction() {
1713
+ return {
1714
+ 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.",
1715
+ systemInstruction: "You are an expert image analyst and prompt engineer. Return ONLY the generation prompt, no headers, no quotes, no explanations."
1716
+ };
1717
+ }
1718
+ function buildRemixInstruction(images, userInstruction, currentPrompt) {
1719
+ const imgContext = buildImageContext(images);
1720
+ return {
1721
+ text: `Current prompt: "${currentPrompt}"
1722
+
1723
+ Instruction: ${userInstruction}${imgContext}
1724
+
1725
+ Create a creative variation of this prompt based on the instruction. Output ONLY the new prompt string.`,
1726
+ systemInstruction: "You are an expert prompt engineer. Return ONLY the new generation prompt, no headers, no quotes, no explanations."
1727
+ };
1728
+ }
1729
+ function buildBlendInstruction(images, userInstruction) {
1730
+ const imgContext = buildImageContext(images);
1731
+ const promptList = images.map((i) => `${i.label}: "${i.item.prompt}"`).join("\n");
1732
+ return {
1733
+ text: `Blend these prompts into one new prompt:
1734
+ ${promptList}
1735
+
1736
+ Instruction: ${userInstruction}${imgContext}
1737
+
1738
+ Output ONLY the blended prompt string.`,
1739
+ systemInstruction: "You are an expert prompt engineer. Blend the given prompts into one coherent generation prompt. Return ONLY the prompt string."
1740
+ };
1741
+ }
1742
+ function buildCompareInstruction(images, userInstruction) {
1743
+ const imgContext = buildImageContext(images);
1744
+ return {
1745
+ text: `${userInstruction}${imgContext}
1746
+
1747
+ Analyze the provided images according to the instruction above.`,
1748
+ systemInstruction: "You are an expert image analyst. Provide a clear, structured analysis. Be concise and actionable."
1749
+ };
1750
+ }
1751
+ function buildLoopInstruction(rounds, newInstruction) {
1752
+ const history = rounds.map(
1753
+ (r, i) => `Round ${i + 1} prompt: "${r.prompt}"
1754
+ Instruction given: "${r.instruction}"`
1755
+ ).join("\n\n");
1756
+ const activeImages = rounds.flatMap((r) => r.images.filter((i) => i.sendToPromptAI));
1757
+ const imgContext = activeImages.length ? buildImageContext(activeImages) : "";
1758
+ return {
1759
+ text: `Previous rounds:
1760
+ ${history}
1761
+
1762
+ New instruction: ${newInstruction}${imgContext}
1763
+
1764
+ Improve the prompt cumulatively based on all previous rounds and the new instruction. Output ONLY the new prompt string.`,
1765
+ systemInstruction: "You are an expert prompt engineer refining prompts iteratively. Each round the prompt should improve. Return ONLY the new prompt string."
1766
+ };
1767
+ }
1768
+ function autoLabel(index) {
1769
+ return `Img${String.fromCharCode(65 + index)}`;
1770
+ }
1771
+ function buildReferenceImageMediaIds(images) {
1772
+ return images.filter((i) => i.sendToImageGen && i.frame.mediaId).map((i) => i.frame.mediaId);
1773
+ }
1774
+
1775
+ // src/components/labs/LabsTab.tsx
1776
+ import { useState as useState12 } from "react";
1777
+
1778
+ // src/components/labs/LabRemix.tsx
1779
+ import { useState as useState8 } from "react";
1780
+
1781
+ // src/components/labs/LabImagePicker.tsx
1782
+ import { useState as useState7 } from "react";
1608
1783
  import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1784
+ var LabImagePicker = ({
1785
+ availableItems,
1786
+ recentItems,
1787
+ onSelect,
1788
+ onClose,
1789
+ title = "Bild w\xE4hlen"
1790
+ }) => {
1791
+ const [search, setSearch] = useState7("");
1792
+ const [drillItem, setDrillItem] = useState7(null);
1793
+ const filtered = availableItems.filter(
1794
+ (item) => !search || item.prompt.toLowerCase().includes(search.toLowerCase())
1795
+ );
1796
+ const handleItemClick = (item) => {
1797
+ if (item.frames.length === 1) {
1798
+ onSelect(item, item.frames[0]);
1799
+ onClose();
1800
+ } else {
1801
+ setDrillItem(item);
1802
+ }
1803
+ };
1804
+ const renderItemCard = (item) => {
1805
+ const firstFrame = item.frames[0];
1806
+ if (!firstFrame) return null;
1807
+ return /* @__PURE__ */ jsxs11(
1808
+ "button",
1809
+ {
1810
+ onClick: () => handleItemClick(item),
1811
+ 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",
1812
+ children: [
1813
+ /* @__PURE__ */ jsxs11("div", { className: "relative w-full aspect-square rounded-lg overflow-hidden bg-black/40", children: [
1814
+ /* @__PURE__ */ jsx13("img", { src: firstFrame.base64, className: "w-full h-full object-cover" }),
1815
+ item.frames.length > 1 && /* @__PURE__ */ jsxs11("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: [
1816
+ item.frames.length,
1817
+ "x"
1818
+ ] })
1819
+ ] }),
1820
+ /* @__PURE__ */ jsx13("p", { className: "text-[10px] text-white/50 leading-tight line-clamp-2", children: item.prompt || "(kein Prompt)" })
1821
+ ]
1822
+ },
1823
+ item.id
1824
+ );
1825
+ };
1826
+ if (drillItem) {
1827
+ return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col h-full", children: [
1828
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 px-4 py-3 border-b border-white/5 shrink-0", children: [
1829
+ /* @__PURE__ */ jsx13("button", { onClick: () => setDrillItem(null), className: "text-white/40 active:text-white shrink-0", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "arrow_back" }) }),
1830
+ /* @__PURE__ */ jsx13("span", { className: "text-[11px] font-bold uppercase tracking-widest text-white/60 truncate flex-1", children: drillItem.prompt || "(kein Prompt)" }),
1831
+ /* @__PURE__ */ jsx13("button", { onClick: onClose, className: "text-white/30 active:text-white shrink-0", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "close" }) })
1832
+ ] }),
1833
+ /* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 py-3", children: [
1834
+ /* @__PURE__ */ jsxs11("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30 mb-2", children: [
1835
+ drillItem.frames.length,
1836
+ " Varianten"
1837
+ ] }),
1838
+ /* @__PURE__ */ jsx13("div", { className: "grid grid-cols-3 gap-2", children: drillItem.frames.map((frame, i) => /* @__PURE__ */ jsxs11(
1839
+ "button",
1840
+ {
1841
+ onClick: () => {
1842
+ onSelect(drillItem, frame);
1843
+ onClose();
1844
+ },
1845
+ 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",
1846
+ children: [
1847
+ /* @__PURE__ */ jsxs11("div", { className: "relative w-full aspect-square rounded-lg overflow-hidden bg-black/40", children: [
1848
+ /* @__PURE__ */ jsx13("img", { src: frame.base64, className: "w-full h-full object-cover" }),
1849
+ /* @__PURE__ */ jsxs11("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: [
1850
+ "#",
1851
+ i + 1
1852
+ ] })
1853
+ ] }),
1854
+ frame.seed != null && /* @__PURE__ */ jsxs11("p", { className: "text-[9px] text-white/30 font-mono truncate", children: [
1855
+ "seed ",
1856
+ frame.seed
1857
+ ] })
1858
+ ]
1859
+ },
1860
+ frame.id
1861
+ )) })
1862
+ ] })
1863
+ ] });
1864
+ }
1865
+ return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col h-full", children: [
1866
+ /* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between px-4 py-3 border-b border-white/5 shrink-0", children: [
1867
+ /* @__PURE__ */ jsx13("span", { className: "text-[11px] font-bold uppercase tracking-widest text-white/60", children: title }),
1868
+ /* @__PURE__ */ jsx13("button", { onClick: onClose, className: "text-white/30 active:text-white", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "close" }) })
1869
+ ] }),
1870
+ /* @__PURE__ */ jsx13("div", { className: "px-3 py-2 shrink-0", children: /* @__PURE__ */ jsx13(
1871
+ "input",
1872
+ {
1873
+ value: search,
1874
+ onChange: (e) => setSearch(e.target.value),
1875
+ placeholder: "Suchen...",
1876
+ 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"
1877
+ }
1878
+ ) }),
1879
+ /* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 pb-3", children: [
1880
+ recentItems.length > 0 && !search && /* @__PURE__ */ jsxs11(Fragment4, { children: [
1881
+ /* @__PURE__ */ jsx13("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30 mb-2 mt-1", children: "Zuletzt verwendet" }),
1882
+ /* @__PURE__ */ jsx13("div", { className: "grid grid-cols-3 gap-2 mb-4", children: recentItems.slice(0, 6).map(renderItemCard) }),
1883
+ /* @__PURE__ */ jsx13("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30 mb-2", children: "Alle Bilder" })
1884
+ ] }),
1885
+ /* @__PURE__ */ jsx13("div", { className: "grid grid-cols-3 gap-2", children: filtered.map(renderItemCard) }),
1886
+ filtered.length === 0 && /* @__PURE__ */ jsx13("p", { className: "text-center text-[11px] text-white/20 py-8", children: "Keine Bilder vorhanden" })
1887
+ ] })
1888
+ ] });
1889
+ };
1890
+
1891
+ // src/components/labs/LabRemix.tsx
1892
+ import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1893
+ var LabRemix = ({ services, onResult }) => {
1894
+ const [showPicker, setShowPicker] = useState8(false);
1895
+ const [selected, setSelected] = useState8(null);
1896
+ const [instruction, setInstruction] = useState8("");
1897
+ const [generatedPrompt, setGeneratedPrompt] = useState8("");
1898
+ const [resultImage, setResultImage] = useState8(null);
1899
+ const [isGeneratingPrompt, setIsGeneratingPrompt] = useState8(false);
1900
+ const [isGeneratingImage, setIsGeneratingImage] = useState8(false);
1901
+ const handleSelectImage = (item, frame) => {
1902
+ services.onItemUsed(item);
1903
+ setSelected({
1904
+ item,
1905
+ frame,
1906
+ label: autoLabel(0),
1907
+ sendToPromptAI: true,
1908
+ sendToImageGen: false,
1909
+ roleForPrompt: "",
1910
+ roleForImage: ""
1911
+ });
1912
+ setGeneratedPrompt("");
1913
+ setResultImage(null);
1914
+ };
1915
+ const handleGeneratePrompt = async () => {
1916
+ if (!selected || !instruction.trim()) return;
1917
+ setIsGeneratingPrompt(true);
1918
+ try {
1919
+ const { text, systemInstruction } = buildRemixInstruction(
1920
+ [selected],
1921
+ instruction,
1922
+ selected.item.prompt
1923
+ );
1924
+ const images = selected.sendToPromptAI ? [{ base64: selected.frame.base64, mimeType: "image/png" }] : void 0;
1925
+ const result = await services.generateText(text, { systemInstruction, images });
1926
+ setGeneratedPrompt(result);
1927
+ } finally {
1928
+ setIsGeneratingPrompt(false);
1929
+ }
1930
+ };
1931
+ const handleGenerateImage = async () => {
1932
+ if (!generatedPrompt) return;
1933
+ setIsGeneratingImage(true);
1934
+ try {
1935
+ const refIds = buildReferenceImageMediaIds(selected ? [selected] : []);
1936
+ const { base64, mediaId } = await services.generateImage({
1937
+ prompt: generatedPrompt,
1938
+ aspectRatio: selected?.frame.aspectRatio || "1:1",
1939
+ modelDisplayName: selected?.frame.model || "\u{1F34C} Nano Banana Pro",
1940
+ ...refIds.length ? { referenceImageMediaIds: refIds } : {}
1941
+ });
1942
+ const newBase64 = `data:image/png;base64,${base64}`;
1943
+ setResultImage(newBase64);
1944
+ const frameId = crypto.randomUUID();
1945
+ const newItem = {
1946
+ id: frameId,
1947
+ prompt: generatedPrompt,
1948
+ tags: selected?.item.tags || [],
1949
+ frames: [{ id: frameId, base64: newBase64, mediaId, source: "generated" }]
1950
+ };
1951
+ services.saveResult?.(newItem);
1952
+ onResult?.(newItem);
1953
+ } finally {
1954
+ setIsGeneratingImage(false);
1955
+ }
1956
+ };
1957
+ if (showPicker) {
1958
+ return /* @__PURE__ */ jsx14(
1959
+ LabImagePicker,
1960
+ {
1961
+ availableItems: services.availableItems,
1962
+ recentItems: services.recentItems,
1963
+ onSelect: handleSelectImage,
1964
+ onClose: () => setShowPicker(false),
1965
+ title: "Basis-Bild w\xE4hlen"
1966
+ }
1967
+ );
1968
+ }
1969
+ return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
1970
+ /* @__PURE__ */ jsxs12("div", { children: [
1971
+ /* @__PURE__ */ jsx14("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Basis-Bild" }),
1972
+ selected ? /* @__PURE__ */ jsxs12("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
1973
+ /* @__PURE__ */ jsx14("img", { src: selected.frame.base64, className: "w-16 h-16 object-cover rounded-lg shrink-0" }),
1974
+ /* @__PURE__ */ jsxs12("div", { className: "flex-1 min-w-0 flex flex-col gap-1.5", children: [
1975
+ /* @__PURE__ */ jsx14("p", { className: "text-[10px] text-white/60 leading-tight line-clamp-2", children: selected.item.prompt }),
1976
+ /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-[10px] text-white/50", children: [
1977
+ /* @__PURE__ */ jsx14(
1978
+ "input",
1979
+ {
1980
+ type: "checkbox",
1981
+ checked: selected.sendToPromptAI,
1982
+ onChange: (e) => setSelected((s) => s ? { ...s, sendToPromptAI: e.target.checked } : s)
1983
+ }
1984
+ ),
1985
+ "Bild an KI (Prompt)"
1986
+ ] }),
1987
+ /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-[10px] text-white/50", children: [
1988
+ /* @__PURE__ */ jsx14(
1989
+ "input",
1990
+ {
1991
+ type: "checkbox",
1992
+ checked: selected.sendToImageGen,
1993
+ onChange: (e) => setSelected((s) => s ? { ...s, sendToImageGen: e.target.checked } : s)
1994
+ }
1995
+ ),
1996
+ "Bild als Referenz (Generierung)"
1997
+ ] }),
1998
+ /* @__PURE__ */ jsx14(
1999
+ "input",
2000
+ {
2001
+ value: selected.roleForPrompt || "",
2002
+ onChange: (e) => setSelected((s) => s ? { ...s, roleForPrompt: e.target.value } : s),
2003
+ placeholder: "Rolle z.B. Subjekt, Farbreferenz...",
2004
+ className: "bg-black/30 border border-white/10 rounded px-2 py-1 text-[10px] text-white/70 outline-none"
2005
+ }
2006
+ )
2007
+ ] }),
2008
+ /* @__PURE__ */ jsx14("button", { onClick: () => setShowPicker(true), className: "text-white/30 active:text-white self-start", children: /* @__PURE__ */ jsx14("span", { className: "material-symbols-outlined text-[18px]", children: "swap_horiz" }) })
2009
+ ] }) : /* @__PURE__ */ jsxs12(
2010
+ "button",
2011
+ {
2012
+ onClick: () => setShowPicker(true),
2013
+ 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",
2014
+ children: [
2015
+ /* @__PURE__ */ jsx14("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }),
2016
+ "Bild w\xE4hlen"
2017
+ ]
2018
+ }
2019
+ )
2020
+ ] }),
2021
+ /* @__PURE__ */ jsxs12("div", { children: [
2022
+ /* @__PURE__ */ jsx14("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Anweisung" }),
2023
+ /* @__PURE__ */ jsx14(
2024
+ "textarea",
2025
+ {
2026
+ value: instruction,
2027
+ onChange: (e) => setInstruction(e.target.value),
2028
+ placeholder: "z.B. Mache es dramatischer, andere Lichtstimmung...",
2029
+ 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",
2030
+ rows: 3
2031
+ }
2032
+ )
2033
+ ] }),
2034
+ services.workspaceTags && /* @__PURE__ */ jsx14("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)" }),
2035
+ /* @__PURE__ */ jsx14(
2036
+ "button",
2037
+ {
2038
+ onClick: handleGeneratePrompt,
2039
+ disabled: !selected || !instruction.trim() || isGeneratingPrompt,
2040
+ 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",
2041
+ children: isGeneratingPrompt ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
2042
+ /* @__PURE__ */ jsx14("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2043
+ /* @__PURE__ */ jsx14("span", { children: "Generiere Prompt..." })
2044
+ ] }) : /* @__PURE__ */ jsxs12(Fragment5, { children: [
2045
+ /* @__PURE__ */ jsx14("span", { className: "material-symbols-outlined text-[16px]", children: "auto_fix_high" }),
2046
+ /* @__PURE__ */ jsx14("span", { children: "Prompt generieren" })
2047
+ ] })
2048
+ }
2049
+ ),
2050
+ generatedPrompt && /* @__PURE__ */ jsxs12("div", { children: [
2051
+ /* @__PURE__ */ jsx14("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Generierter Prompt" }),
2052
+ /* @__PURE__ */ jsx14(
2053
+ "textarea",
2054
+ {
2055
+ value: generatedPrompt,
2056
+ onChange: (e) => setGeneratedPrompt(e.target.value),
2057
+ 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",
2058
+ rows: 4
2059
+ }
2060
+ ),
2061
+ /* @__PURE__ */ jsx14(
2062
+ "button",
2063
+ {
2064
+ onClick: handleGenerateImage,
2065
+ disabled: isGeneratingImage,
2066
+ 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",
2067
+ children: isGeneratingImage ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
2068
+ /* @__PURE__ */ jsx14("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2069
+ /* @__PURE__ */ jsx14("span", { children: "Generiere Bild..." })
2070
+ ] }) : /* @__PURE__ */ jsxs12(Fragment5, { children: [
2071
+ /* @__PURE__ */ jsx14("span", { className: "material-symbols-outlined text-[16px]", children: "image" }),
2072
+ /* @__PURE__ */ jsx14("span", { children: "Bild generieren" })
2073
+ ] })
2074
+ }
2075
+ )
2076
+ ] }),
2077
+ resultImage && /* @__PURE__ */ jsx14("div", { className: "rounded-xl overflow-hidden border border-white/10", children: /* @__PURE__ */ jsx14("img", { src: resultImage, className: "w-full object-cover" }) })
2078
+ ] });
2079
+ };
2080
+
2081
+ // src/components/labs/LabBlend.tsx
2082
+ import { useState as useState9 } from "react";
2083
+ import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2084
+ var LabBlend = ({ services, onResult }) => {
2085
+ const [showPickerFor, setShowPickerFor] = useState9(null);
2086
+ const [selectedImages, setSelectedImages] = useState9([]);
2087
+ const [instruction, setInstruction] = useState9("");
2088
+ const [generatedPrompt, setGeneratedPrompt] = useState9("");
2089
+ const [resultImage, setResultImage] = useState9(null);
2090
+ const [isGeneratingPrompt, setIsGeneratingPrompt] = useState9(false);
2091
+ const [isGeneratingImage, setIsGeneratingImage] = useState9(false);
2092
+ const handleSelectImage = (index, item, frame) => {
2093
+ services.onItemUsed(item);
2094
+ const newImg = {
2095
+ item,
2096
+ frame,
2097
+ label: autoLabel(index),
2098
+ sendToPromptAI: true,
2099
+ sendToImageGen: false,
2100
+ roleForPrompt: "",
2101
+ roleForImage: ""
2102
+ };
2103
+ setSelectedImages((prev) => {
2104
+ const next = [...prev];
2105
+ next[index] = newImg;
2106
+ return next;
2107
+ });
2108
+ setShowPickerFor(null);
2109
+ setGeneratedPrompt("");
2110
+ setResultImage(null);
2111
+ };
2112
+ const addSlot = () => setSelectedImages((prev) => [...prev, null]);
2113
+ const removeSlot = (i) => setSelectedImages((prev) => prev.filter((_, idx) => idx !== i));
2114
+ const updateImg = (i, updates) => setSelectedImages((prev) => prev.map((img, idx) => idx === i && img ? { ...img, ...updates } : img));
2115
+ const handleGeneratePrompt = async () => {
2116
+ const filled = selectedImages.filter(Boolean);
2117
+ if (!filled.length || !instruction.trim()) return;
2118
+ setIsGeneratingPrompt(true);
2119
+ try {
2120
+ const { text, systemInstruction } = buildBlendInstruction(filled, instruction);
2121
+ const images = filled.filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
2122
+ const result = await services.generateText(text, { systemInstruction, images: images.length ? images : void 0 });
2123
+ setGeneratedPrompt(result);
2124
+ } finally {
2125
+ setIsGeneratingPrompt(false);
2126
+ }
2127
+ };
2128
+ const handleGenerateImage = async () => {
2129
+ if (!generatedPrompt) return;
2130
+ setIsGeneratingImage(true);
2131
+ try {
2132
+ const filled = selectedImages.filter(Boolean);
2133
+ const refIds = buildReferenceImageMediaIds(filled);
2134
+ const { base64, mediaId } = await services.generateImage({
2135
+ prompt: generatedPrompt,
2136
+ aspectRatio: "1:1",
2137
+ modelDisplayName: "\u{1F34C} Nano Banana Pro",
2138
+ ...refIds.length ? { referenceImageMediaIds: refIds } : {}
2139
+ });
2140
+ const newBase64 = `data:image/png;base64,${base64}`;
2141
+ setResultImage(newBase64);
2142
+ const frameId = crypto.randomUUID();
2143
+ const newItem = {
2144
+ id: frameId,
2145
+ prompt: generatedPrompt,
2146
+ tags: [],
2147
+ frames: [{ id: frameId, base64: newBase64, mediaId, source: "generated" }]
2148
+ };
2149
+ services.saveResult?.(newItem);
2150
+ onResult?.(newItem);
2151
+ } finally {
2152
+ setIsGeneratingImage(false);
2153
+ }
2154
+ };
2155
+ if (showPickerFor !== null) {
2156
+ return /* @__PURE__ */ jsx15(
2157
+ LabImagePicker,
2158
+ {
2159
+ availableItems: services.availableItems,
2160
+ recentItems: services.recentItems,
2161
+ onSelect: (item, frame) => handleSelectImage(showPickerFor, item, frame),
2162
+ onClose: () => setShowPickerFor(null),
2163
+ title: `${autoLabel(showPickerFor)} w\xE4hlen`
2164
+ }
2165
+ );
2166
+ }
2167
+ return /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
2168
+ /* @__PURE__ */ jsx15("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40", children: "Bilder" }),
2169
+ selectedImages.map((img, i) => /* @__PURE__ */ jsxs13("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
2170
+ /* @__PURE__ */ jsx15("span", { className: "text-[10px] font-bold text-white/40 w-6 shrink-0 pt-1", children: autoLabel(i) }),
2171
+ img ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
2172
+ /* @__PURE__ */ jsx15("img", { src: img.frame.base64, className: "w-12 h-12 object-cover rounded-lg shrink-0", onClick: () => setShowPickerFor(i) }),
2173
+ /* @__PURE__ */ jsxs13("div", { className: "flex-1 min-w-0 flex flex-col gap-1", children: [
2174
+ /* @__PURE__ */ jsx15("p", { className: "text-[10px] text-white/50 line-clamp-1", children: img.item.prompt }),
2175
+ /* @__PURE__ */ jsxs13("div", { className: "flex gap-3", children: [
2176
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1 text-[10px] text-white/40", children: [
2177
+ /* @__PURE__ */ jsx15("input", { type: "checkbox", checked: img.sendToPromptAI, onChange: (e) => updateImg(i, { sendToPromptAI: e.target.checked }) }),
2178
+ "KI-Prompt"
2179
+ ] }),
2180
+ /* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1 text-[10px] text-white/40", children: [
2181
+ /* @__PURE__ */ jsx15("input", { type: "checkbox", checked: img.sendToImageGen, onChange: (e) => updateImg(i, { sendToImageGen: e.target.checked }) }),
2182
+ "Referenz"
2183
+ ] })
2184
+ ] }),
2185
+ /* @__PURE__ */ jsx15(
2186
+ "input",
2187
+ {
2188
+ value: img.roleForPrompt || "",
2189
+ onChange: (e) => updateImg(i, { roleForPrompt: e.target.value }),
2190
+ placeholder: "Rolle f\xFCr Prompt...",
2191
+ className: "bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
2192
+ }
2193
+ ),
2194
+ /* @__PURE__ */ jsx15(
2195
+ "input",
2196
+ {
2197
+ value: img.roleForImage || "",
2198
+ onChange: (e) => updateImg(i, { roleForImage: e.target.value }),
2199
+ placeholder: "Rolle f\xFCr Generierung...",
2200
+ className: "bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
2201
+ }
2202
+ )
2203
+ ] })
2204
+ ] }) : /* @__PURE__ */ jsx15("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" }),
2205
+ /* @__PURE__ */ jsx15("button", { onClick: () => removeSlot(i), className: "text-white/20 active:text-red-400 self-start", children: /* @__PURE__ */ jsx15("span", { className: "material-symbols-outlined text-[16px]", children: "close" }) })
2206
+ ] }, i)),
2207
+ /* @__PURE__ */ jsxs13(
2208
+ "button",
2209
+ {
2210
+ onClick: addSlot,
2211
+ 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",
2212
+ children: [
2213
+ /* @__PURE__ */ jsx15("span", { className: "material-symbols-outlined text-[14px]", children: "add" }),
2214
+ "Bild hinzuf\xFCgen"
2215
+ ]
2216
+ }
2217
+ ),
2218
+ /* @__PURE__ */ jsxs13("div", { children: [
2219
+ /* @__PURE__ */ jsx15("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Blend-Anweisung" }),
2220
+ /* @__PURE__ */ jsx15(
2221
+ "textarea",
2222
+ {
2223
+ value: instruction,
2224
+ onChange: (e) => setInstruction(e.target.value),
2225
+ placeholder: "z.B. Kombiniere die Stimmung von ImgA mit der Komposition von ImgB...",
2226
+ 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",
2227
+ rows: 3
2228
+ }
2229
+ )
2230
+ ] }),
2231
+ /* @__PURE__ */ jsx15(
2232
+ "button",
2233
+ {
2234
+ onClick: handleGeneratePrompt,
2235
+ disabled: selectedImages.filter(Boolean).length < 2 || !instruction.trim() || isGeneratingPrompt,
2236
+ 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",
2237
+ children: isGeneratingPrompt ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
2238
+ /* @__PURE__ */ jsx15("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2239
+ /* @__PURE__ */ jsx15("span", { children: "Blend l\xE4uft..." })
2240
+ ] }) : /* @__PURE__ */ jsxs13(Fragment6, { children: [
2241
+ /* @__PURE__ */ jsx15("span", { className: "material-symbols-outlined text-[16px]", children: "merge" }),
2242
+ /* @__PURE__ */ jsx15("span", { children: "Prompts blenden" })
2243
+ ] })
2244
+ }
2245
+ ),
2246
+ generatedPrompt && /* @__PURE__ */ jsxs13("div", { children: [
2247
+ /* @__PURE__ */ jsx15("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Blend-Prompt" }),
2248
+ /* @__PURE__ */ jsx15(
2249
+ "textarea",
2250
+ {
2251
+ value: generatedPrompt,
2252
+ onChange: (e) => setGeneratedPrompt(e.target.value),
2253
+ 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",
2254
+ rows: 4
2255
+ }
2256
+ ),
2257
+ /* @__PURE__ */ jsx15(
2258
+ "button",
2259
+ {
2260
+ onClick: handleGenerateImage,
2261
+ disabled: isGeneratingImage,
2262
+ 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",
2263
+ children: isGeneratingImage ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
2264
+ /* @__PURE__ */ jsx15("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2265
+ /* @__PURE__ */ jsx15("span", { children: "Generiere..." })
2266
+ ] }) : /* @__PURE__ */ jsxs13(Fragment6, { children: [
2267
+ /* @__PURE__ */ jsx15("span", { className: "material-symbols-outlined text-[16px]", children: "image" }),
2268
+ /* @__PURE__ */ jsx15("span", { children: "Bild generieren" })
2269
+ ] })
2270
+ }
2271
+ )
2272
+ ] }),
2273
+ resultImage && /* @__PURE__ */ jsx15("div", { className: "rounded-xl overflow-hidden border border-white/10", children: /* @__PURE__ */ jsx15("img", { src: resultImage, className: "w-full object-cover" }) })
2274
+ ] });
2275
+ };
2276
+
2277
+ // src/components/labs/LabCompare.tsx
2278
+ import { useState as useState10 } from "react";
2279
+ import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2280
+ var LabCompare = ({ services, onResult }) => {
2281
+ const [showPickerFor, setShowPickerFor] = useState10(null);
2282
+ const [selectedImages, setSelectedImages] = useState10([]);
2283
+ const [instruction, setInstruction] = useState10("");
2284
+ const [analysis, setAnalysis] = useState10("");
2285
+ const [generatedPrompt, setGeneratedPrompt] = useState10("");
2286
+ const [resultImage, setResultImage] = useState10(null);
2287
+ const [isAnalyzing, setIsAnalyzing] = useState10(false);
2288
+ const [isGeneratingImage, setIsGeneratingImage] = useState10(false);
2289
+ const handleSelectImage = (index, item, frame) => {
2290
+ services.onItemUsed(item);
2291
+ const newImg = {
2292
+ item,
2293
+ frame,
2294
+ label: autoLabel(index),
2295
+ sendToPromptAI: true,
2296
+ sendToImageGen: false,
2297
+ roleForPrompt: "",
2298
+ roleForImage: ""
2299
+ };
2300
+ setSelectedImages((prev) => {
2301
+ const next = [...prev];
2302
+ next[index] = newImg;
2303
+ return next;
2304
+ });
2305
+ setShowPickerFor(null);
2306
+ setAnalysis("");
2307
+ };
2308
+ const updateImg = (i, updates) => setSelectedImages((prev) => prev.map((img, idx) => idx === i && img ? { ...img, ...updates } : img));
2309
+ const addSlot = () => setSelectedImages((prev) => [...prev, null]);
2310
+ const removeSlot = (i) => setSelectedImages((prev) => prev.filter((_, idx) => idx !== i));
2311
+ const handleAnalyze = async () => {
2312
+ const filled = selectedImages.filter(Boolean);
2313
+ if (!filled.length || !instruction.trim()) return;
2314
+ setIsAnalyzing(true);
2315
+ try {
2316
+ const { text, systemInstruction } = buildCompareInstruction(filled, instruction);
2317
+ const images = filled.filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
2318
+ const result = await services.generateText(text, { systemInstruction, images: images.length ? images : void 0 });
2319
+ setAnalysis(result);
2320
+ setGeneratedPrompt("");
2321
+ } finally {
2322
+ setIsAnalyzing(false);
2323
+ }
2324
+ };
2325
+ const handleGenerateImage = async () => {
2326
+ if (!generatedPrompt) return;
2327
+ setIsGeneratingImage(true);
2328
+ try {
2329
+ const { base64, mediaId } = await services.generateImage({ prompt: generatedPrompt, aspectRatio: "1:1", modelDisplayName: "\u{1F34C} Nano Banana Pro" });
2330
+ const newBase64 = `data:image/png;base64,${base64}`;
2331
+ setResultImage(newBase64);
2332
+ const frameId = crypto.randomUUID();
2333
+ const newItem = {
2334
+ id: frameId,
2335
+ prompt: generatedPrompt,
2336
+ tags: [],
2337
+ frames: [{ id: frameId, base64: newBase64, mediaId, source: "generated" }]
2338
+ };
2339
+ services.saveResult?.(newItem);
2340
+ onResult?.(newItem);
2341
+ } finally {
2342
+ setIsGeneratingImage(false);
2343
+ }
2344
+ };
2345
+ if (showPickerFor !== null) {
2346
+ return /* @__PURE__ */ jsx16(
2347
+ LabImagePicker,
2348
+ {
2349
+ availableItems: services.availableItems,
2350
+ recentItems: services.recentItems,
2351
+ onSelect: (item, frame) => handleSelectImage(showPickerFor, item, frame),
2352
+ onClose: () => setShowPickerFor(null),
2353
+ title: `${autoLabel(showPickerFor)} w\xE4hlen`
2354
+ }
2355
+ );
2356
+ }
2357
+ return /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
2358
+ /* @__PURE__ */ jsx16("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40", children: "Bilder zum Vergleichen" }),
2359
+ selectedImages.map((img, i) => /* @__PURE__ */ jsxs14("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
2360
+ /* @__PURE__ */ jsx16("span", { className: "text-[10px] font-bold text-white/40 w-6 shrink-0 pt-1", children: autoLabel(i) }),
2361
+ img ? /* @__PURE__ */ jsxs14(Fragment7, { children: [
2362
+ /* @__PURE__ */ jsx16("img", { src: img.frame.base64, className: "w-12 h-12 object-cover rounded-lg shrink-0 cursor-pointer", onClick: () => setShowPickerFor(i) }),
2363
+ /* @__PURE__ */ jsxs14("div", { className: "flex-1 min-w-0 flex flex-col gap-1", children: [
2364
+ /* @__PURE__ */ jsx16("p", { className: "text-[10px] text-white/50 line-clamp-1", children: img.item.prompt }),
2365
+ /* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1 text-[10px] text-white/40", children: [
2366
+ /* @__PURE__ */ jsx16("input", { type: "checkbox", checked: img.sendToPromptAI, onChange: (e) => updateImg(i, { sendToPromptAI: e.target.checked }) }),
2367
+ "Bild an KI mitgeben"
2368
+ ] }),
2369
+ /* @__PURE__ */ jsx16(
2370
+ "input",
2371
+ {
2372
+ value: img.roleForPrompt || "",
2373
+ onChange: (e) => updateImg(i, { roleForPrompt: e.target.value }),
2374
+ placeholder: "Rolle z.B. Referenz A, Stilvergleich...",
2375
+ className: "bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
2376
+ }
2377
+ )
2378
+ ] })
2379
+ ] }) : /* @__PURE__ */ jsx16("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" }),
2380
+ /* @__PURE__ */ jsx16("button", { onClick: () => removeSlot(i), className: "text-white/20 active:text-red-400 self-start", children: /* @__PURE__ */ jsx16("span", { className: "material-symbols-outlined text-[16px]", children: "close" }) })
2381
+ ] }, i)),
2382
+ /* @__PURE__ */ jsxs14("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: [
2383
+ /* @__PURE__ */ jsx16("span", { className: "material-symbols-outlined text-[14px]", children: "add" }),
2384
+ "Bild hinzuf\xFCgen"
2385
+ ] }),
2386
+ /* @__PURE__ */ jsxs14("div", { children: [
2387
+ /* @__PURE__ */ jsx16("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Analyse-Anweisung" }),
2388
+ /* @__PURE__ */ jsx16(
2389
+ "textarea",
2390
+ {
2391
+ value: instruction,
2392
+ onChange: (e) => setInstruction(e.target.value),
2393
+ placeholder: "z.B. Vergleiche Lichtstimmung und Komposition. Welches ist dramatischer?",
2394
+ 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",
2395
+ rows: 3
2396
+ }
2397
+ )
2398
+ ] }),
2399
+ /* @__PURE__ */ jsx16(
2400
+ "button",
2401
+ {
2402
+ onClick: handleAnalyze,
2403
+ disabled: selectedImages.filter(Boolean).length < 1 || !instruction.trim() || isAnalyzing,
2404
+ 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",
2405
+ children: isAnalyzing ? /* @__PURE__ */ jsxs14(Fragment7, { children: [
2406
+ /* @__PURE__ */ jsx16("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2407
+ /* @__PURE__ */ jsx16("span", { children: "Analysiere..." })
2408
+ ] }) : /* @__PURE__ */ jsxs14(Fragment7, { children: [
2409
+ /* @__PURE__ */ jsx16("span", { className: "material-symbols-outlined text-[16px]", children: "compare" }),
2410
+ /* @__PURE__ */ jsx16("span", { children: "Analysieren" })
2411
+ ] })
2412
+ }
2413
+ ),
2414
+ analysis && /* @__PURE__ */ jsxs14("div", { children: [
2415
+ /* @__PURE__ */ jsx16("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Analyse" }),
2416
+ /* @__PURE__ */ jsx16("div", { className: "bg-white/5 border border-white/10 rounded-xl px-3 py-3", children: /* @__PURE__ */ jsx16("p", { className: "text-[12px] text-white/70 leading-relaxed whitespace-pre-wrap", children: analysis }) }),
2417
+ /* @__PURE__ */ jsxs14("div", { className: "mt-3", children: [
2418
+ /* @__PURE__ */ jsx16("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Als Prompt nutzen" }),
2419
+ /* @__PURE__ */ jsx16(
2420
+ "textarea",
2421
+ {
2422
+ value: generatedPrompt,
2423
+ onChange: (e) => setGeneratedPrompt(e.target.value),
2424
+ placeholder: "Analyse-Ergebnis hier als Prompt einf\xFCgen oder eigenen Prompt schreiben...",
2425
+ 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",
2426
+ rows: 3
2427
+ }
2428
+ ),
2429
+ /* @__PURE__ */ jsx16(
2430
+ "button",
2431
+ {
2432
+ onClick: handleGenerateImage,
2433
+ disabled: !generatedPrompt.trim() || isGeneratingImage,
2434
+ 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",
2435
+ children: isGeneratingImage ? /* @__PURE__ */ jsxs14(Fragment7, { children: [
2436
+ /* @__PURE__ */ jsx16("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2437
+ /* @__PURE__ */ jsx16("span", { children: "Generiere..." })
2438
+ ] }) : /* @__PURE__ */ jsxs14(Fragment7, { children: [
2439
+ /* @__PURE__ */ jsx16("span", { className: "material-symbols-outlined text-[16px]", children: "image" }),
2440
+ /* @__PURE__ */ jsx16("span", { children: "Bild generieren" })
2441
+ ] })
2442
+ }
2443
+ )
2444
+ ] })
2445
+ ] }),
2446
+ resultImage && /* @__PURE__ */ jsx16("div", { className: "rounded-xl overflow-hidden border border-white/10", children: /* @__PURE__ */ jsx16("img", { src: resultImage, className: "w-full object-cover" }) })
2447
+ ] });
2448
+ };
2449
+
2450
+ // src/components/labs/LabLoop.tsx
2451
+ import { useState as useState11 } from "react";
2452
+ import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2453
+ var LabLoop = ({ services, onResult }) => {
2454
+ const [rounds, setRounds] = useState11([]);
2455
+ const [currentInstruction, setCurrentInstruction] = useState11("");
2456
+ const [showPickerForRound, setShowPickerForRound] = useState11(null);
2457
+ const [pendingImages, setPendingImages] = useState11([]);
2458
+ const [isGenerating, setIsGenerating] = useState11(false);
2459
+ const currentPrompt = rounds.length > 0 ? rounds[rounds.length - 1].prompt : "";
2460
+ const handleAddImage = (item, frame) => {
2461
+ services.onItemUsed(item);
2462
+ const label = autoLabel(pendingImages.length);
2463
+ setPendingImages((prev) => [...prev, {
2464
+ item,
2465
+ frame,
2466
+ label,
2467
+ sendToPromptAI: true,
2468
+ sendToImageGen: false,
2469
+ roleForPrompt: "",
2470
+ roleForImage: ""
2471
+ }]);
2472
+ setShowPickerForRound(null);
2473
+ };
2474
+ const updatePendingImage = (i, updates) => setPendingImages((prev) => prev.map((img, idx) => idx === i ? { ...img, ...updates } : img));
2475
+ const handleRunRound = async () => {
2476
+ if (!currentInstruction.trim()) return;
2477
+ setIsGenerating(true);
2478
+ try {
2479
+ const historyForBuilder = rounds.map((r) => ({
2480
+ prompt: r.prompt,
2481
+ instruction: r.instruction,
2482
+ images: r.images
2483
+ }));
2484
+ const { text, systemInstruction } = buildLoopInstruction(historyForBuilder, currentInstruction);
2485
+ const allImages = [...rounds.flatMap((r) => r.images), ...pendingImages].filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
2486
+ const newPrompt = await services.generateText(text, {
2487
+ systemInstruction,
2488
+ images: allImages.length ? allImages : void 0
2489
+ });
2490
+ const { base64, mediaId } = await services.generateImage({
2491
+ prompt: newPrompt,
2492
+ aspectRatio: "1:1",
2493
+ modelDisplayName: "\u{1F34C} Nano Banana Pro"
2494
+ });
2495
+ const newBase64 = `data:image/png;base64,${base64}`;
2496
+ const newFrame = { id: crypto.randomUUID(), base64: newBase64, mediaId, source: "generated" };
2497
+ const newRound = {
2498
+ prompt: newPrompt,
2499
+ instruction: currentInstruction,
2500
+ frame: newFrame,
2501
+ images: [...pendingImages]
2502
+ };
2503
+ setRounds((prev) => [...prev, newRound]);
2504
+ setCurrentInstruction("");
2505
+ setPendingImages([]);
2506
+ const newItem = {
2507
+ id: newFrame.id,
2508
+ prompt: newPrompt,
2509
+ tags: [],
2510
+ frames: [newFrame]
2511
+ };
2512
+ services.saveResult?.(newItem);
2513
+ onResult?.(newItem);
2514
+ } finally {
2515
+ setIsGenerating(false);
2516
+ }
2517
+ };
2518
+ if (showPickerForRound !== null) {
2519
+ return /* @__PURE__ */ jsx17(
2520
+ LabImagePicker,
2521
+ {
2522
+ availableItems: services.availableItems,
2523
+ recentItems: services.recentItems,
2524
+ onSelect: handleAddImage,
2525
+ onClose: () => setShowPickerForRound(null),
2526
+ title: "Referenzbild hinzuf\xFCgen"
2527
+ }
2528
+ );
2529
+ }
2530
+ return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
2531
+ rounds.map((round, i) => /* @__PURE__ */ jsxs15("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
2532
+ /* @__PURE__ */ jsxs15("div", { className: "flex flex-col items-center gap-1 shrink-0", children: [
2533
+ /* @__PURE__ */ jsxs15("span", { className: "text-[9px] font-bold text-white/30", children: [
2534
+ "R",
2535
+ i + 1
2536
+ ] }),
2537
+ round.frame && /* @__PURE__ */ jsx17("img", { src: round.frame.base64, className: "w-12 h-12 object-cover rounded-lg" })
2538
+ ] }),
2539
+ /* @__PURE__ */ jsxs15("div", { className: "flex-1 min-w-0", children: [
2540
+ /* @__PURE__ */ jsxs15("p", { className: "text-[9px] text-white/30 italic mb-1", children: [
2541
+ '"',
2542
+ round.instruction,
2543
+ '"'
2544
+ ] }),
2545
+ /* @__PURE__ */ jsx17("p", { className: "text-[10px] text-white/60 leading-tight line-clamp-3", children: round.prompt })
2546
+ ] })
2547
+ ] }, i)),
2548
+ /* @__PURE__ */ jsxs15("div", { className: "rounded-xl border border-white/20 bg-white/5 p-3 flex flex-col gap-3", children: [
2549
+ /* @__PURE__ */ jsx17("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}` }),
2550
+ currentPrompt && /* @__PURE__ */ jsxs15("p", { className: "text-[10px] text-white/40 italic line-clamp-2", children: [
2551
+ 'Letzter Prompt: "',
2552
+ currentPrompt,
2553
+ '"'
2554
+ ] }),
2555
+ /* @__PURE__ */ jsx17(
2556
+ "textarea",
2557
+ {
2558
+ value: currentInstruction,
2559
+ onChange: (e) => setCurrentInstruction(e.target.value),
2560
+ placeholder: rounds.length === 0 ? "Ersten Prompt beschreiben..." : "Was soll verbessert werden?",
2561
+ 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",
2562
+ rows: 3
2563
+ }
2564
+ ),
2565
+ pendingImages.map((img, i) => /* @__PURE__ */ jsxs15("div", { className: "flex gap-2 items-center", children: [
2566
+ /* @__PURE__ */ jsx17("img", { src: img.frame.base64, className: "w-8 h-8 object-cover rounded" }),
2567
+ /* @__PURE__ */ jsx17("span", { className: "text-[10px] text-white/40", children: img.label }),
2568
+ /* @__PURE__ */ jsx17(
2569
+ "input",
2570
+ {
2571
+ value: img.roleForPrompt || "",
2572
+ onChange: (e) => updatePendingImage(i, { roleForPrompt: e.target.value }),
2573
+ placeholder: "Rolle...",
2574
+ className: "flex-1 bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
2575
+ }
2576
+ ),
2577
+ /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-[9px] text-white/30", children: [
2578
+ /* @__PURE__ */ jsx17("input", { type: "checkbox", checked: img.sendToPromptAI, onChange: (e) => updatePendingImage(i, { sendToPromptAI: e.target.checked }) }),
2579
+ "KI"
2580
+ ] }),
2581
+ /* @__PURE__ */ jsx17("button", { onClick: () => setPendingImages((prev) => prev.filter((_, idx) => idx !== i)), className: "text-white/20 active:text-red-400", children: /* @__PURE__ */ jsx17("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
2582
+ ] }, i)),
2583
+ /* @__PURE__ */ jsxs15(
2584
+ "button",
2585
+ {
2586
+ onClick: () => setShowPickerForRound(rounds.length),
2587
+ className: "text-[10px] text-white/30 active:text-white/60 flex items-center gap-1 self-start",
2588
+ children: [
2589
+ /* @__PURE__ */ jsx17("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
2590
+ "Referenzbild hinzuf\xFCgen"
2591
+ ]
2592
+ }
2593
+ ),
2594
+ /* @__PURE__ */ jsx17(
2595
+ "button",
2596
+ {
2597
+ onClick: handleRunRound,
2598
+ disabled: !currentInstruction.trim() || isGenerating,
2599
+ 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",
2600
+ children: isGenerating ? /* @__PURE__ */ jsxs15(Fragment8, { children: [
2601
+ /* @__PURE__ */ jsx17("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
2602
+ /* @__PURE__ */ jsx17("span", { children: "Runde l\xE4uft..." })
2603
+ ] }) : /* @__PURE__ */ jsxs15(Fragment8, { children: [
2604
+ /* @__PURE__ */ jsx17("span", { className: "material-symbols-outlined text-[16px]", children: "loop" }),
2605
+ /* @__PURE__ */ jsx17("span", { children: "Runde starten" })
2606
+ ] })
2607
+ }
2608
+ )
2609
+ ] })
2610
+ ] });
2611
+ };
2612
+
2613
+ // src/components/labs/LabsTab.tsx
2614
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2615
+ var TABS = [
2616
+ { key: "remix", label: "Remix", icon: "auto_fix_high" },
2617
+ { key: "blend", label: "Blend", icon: "merge" },
2618
+ { key: "compare", label: "Compare", icon: "compare" },
2619
+ { key: "loop", label: "Loop", icon: "loop" }
2620
+ ];
2621
+ var LabsTab = ({ services, onResult }) => {
2622
+ const [activeTab, setActiveTab] = useState12("remix");
2623
+ return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col h-full overflow-hidden", children: [
2624
+ /* @__PURE__ */ jsx18("div", { className: "flex border-b border-white/5 shrink-0", children: TABS.map((tab) => /* @__PURE__ */ jsxs16(
2625
+ "button",
2626
+ {
2627
+ onClick: () => setActiveTab(tab.key),
2628
+ 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"}`,
2629
+ children: [
2630
+ /* @__PURE__ */ jsx18("span", { className: "material-symbols-outlined text-[14px]", children: tab.icon }),
2631
+ tab.label
2632
+ ]
2633
+ },
2634
+ tab.key
2635
+ )) }),
2636
+ /* @__PURE__ */ jsxs16("div", { className: "flex-1 overflow-hidden", children: [
2637
+ activeTab === "remix" && /* @__PURE__ */ jsx18(LabRemix, { services, onResult }),
2638
+ activeTab === "blend" && /* @__PURE__ */ jsx18(LabBlend, { services, onResult }),
2639
+ activeTab === "compare" && /* @__PURE__ */ jsx18(LabCompare, { services, onResult }),
2640
+ activeTab === "loop" && /* @__PURE__ */ jsx18(LabLoop, { services, onResult })
2641
+ ] })
2642
+ ] });
2643
+ };
2644
+
2645
+ // src/components/TagManagerPanel.tsx
2646
+ import { useState as useState13 } from "react";
2647
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
2648
+ function TagManagerPanel({ workspaceTags, onTagCreate, onTagUpdate, onTagDelete, onTagReorder, onTagMove }) {
2649
+ const categories = Object.keys(workspaceTags.by_category).filter(
2650
+ (cat) => (workspaceTags.by_category[cat] || []).some((t) => !t.is_deleted)
2651
+ );
2652
+ const [selectedCategory, setSelectedCategory] = useState13(categories[0] || "");
2653
+ const effectiveCategory = categories.includes(selectedCategory) ? selectedCategory : categories[0] || "";
2654
+ const [editingLabel, setEditingLabel] = useState13(null);
2655
+ const [editState, setEditState] = useState13({ label: "", value: "" });
2656
+ const [newTag, setNewTag] = useState13({ label: "", value: "" });
2657
+ const [movingLabel, setMovingLabel] = useState13(null);
2658
+ const [moveTarget, setMoveTarget] = useState13("");
2659
+ const tags = (workspaceTags.by_category[effectiveCategory] || []).filter((t) => !t.is_deleted);
2660
+ const otherCategories = categories.filter((c) => c !== effectiveCategory);
2661
+ const startEdit = (tag) => {
2662
+ setEditingLabel(tag.label);
2663
+ setEditState({ label: tag.label, value: tag.value });
2664
+ setMovingLabel(null);
2665
+ };
2666
+ const saveEdit = (originalLabel) => {
2667
+ if (!editState.label.trim()) return;
2668
+ onTagUpdate(originalLabel, effectiveCategory, {
2669
+ label: editState.label.trim(),
2670
+ value: editState.value.trim() || editState.label.trim()
2671
+ });
2672
+ setEditingLabel(null);
2673
+ };
2674
+ const handleMoveUp = (index) => {
2675
+ if (index === 0) return;
2676
+ const reordered = [...tags];
2677
+ [reordered[index - 1], reordered[index]] = [reordered[index], reordered[index - 1]];
2678
+ onTagReorder(effectiveCategory, reordered);
2679
+ };
2680
+ const handleMoveDown = (index) => {
2681
+ if (index === tags.length - 1) return;
2682
+ const reordered = [...tags];
2683
+ [reordered[index], reordered[index + 1]] = [reordered[index + 1], reordered[index]];
2684
+ onTagReorder(effectiveCategory, reordered);
2685
+ };
2686
+ const handleMove = (tag) => {
2687
+ if (!moveTarget) return;
2688
+ onTagMove(tag.label, tag.value, effectiveCategory, moveTarget);
2689
+ setMovingLabel(null);
2690
+ setMoveTarget("");
2691
+ };
2692
+ const handleCreate = () => {
2693
+ if (!newTag.label.trim() || !effectiveCategory) return;
2694
+ onTagCreate({ label: newTag.label.trim(), value: newTag.value.trim() || newTag.label.trim(), category: effectiveCategory, is_user_created: true });
2695
+ setNewTag({ label: "", value: "" });
2696
+ };
2697
+ const handleDelete = (tag) => {
2698
+ if (!confirm(`Tag "${tag.label}" l\xF6schen?`)) return;
2699
+ onTagDelete(tag.label, effectiveCategory);
2700
+ };
2701
+ return /* @__PURE__ */ jsxs17("div", { className: "flex flex-col h-full overflow-hidden", children: [
2702
+ /* @__PURE__ */ jsx19("div", { className: "px-3 py-2 border-b border-white/5 shrink-0", children: /* @__PURE__ */ jsx19("span", { className: "text-[10px] font-bold uppercase tracking-widest text-white/40", children: "Tag Manager" }) }),
2703
+ /* @__PURE__ */ jsx19("div", { className: "px-3 py-2 shrink-0 overflow-x-auto", children: /* @__PURE__ */ jsxs17("div", { className: "flex gap-1.5 flex-nowrap", children: [
2704
+ categories.map((cat) => /* @__PURE__ */ jsxs17(
2705
+ "button",
2706
+ {
2707
+ onClick: () => {
2708
+ setSelectedCategory(cat);
2709
+ setEditingLabel(null);
2710
+ setMovingLabel(null);
2711
+ },
2712
+ 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"}`,
2713
+ children: [
2714
+ cat,
2715
+ " ",
2716
+ /* @__PURE__ */ jsx19("span", { className: "ml-1 opacity-50", children: (workspaceTags.by_category[cat] || []).filter((t) => !t.is_deleted).length })
2717
+ ]
2718
+ },
2719
+ cat
2720
+ )),
2721
+ categories.length === 0 && /* @__PURE__ */ jsx19("span", { className: "text-[10px] text-white/20", children: "Erst Workspace importieren" })
2722
+ ] }) }),
2723
+ /* @__PURE__ */ jsxs17("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 pb-2 space-y-1", children: [
2724
+ tags.map((tag, i) => /* @__PURE__ */ jsxs17("div", { children: [
2725
+ editingLabel === tag.label ? /* @__PURE__ */ jsxs17("div", { className: "bg-white/5 border border-blue-600/40 rounded-lg p-2.5 space-y-1.5", children: [
2726
+ /* @__PURE__ */ jsx19(
2727
+ "input",
2728
+ {
2729
+ value: editState.label,
2730
+ onChange: (e) => setEditState((s) => ({ ...s, label: e.target.value })),
2731
+ 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",
2732
+ placeholder: "Label",
2733
+ autoFocus: true,
2734
+ onKeyDown: (e) => e.key === "Enter" && saveEdit(tag.label)
2735
+ }
2736
+ ),
2737
+ /* @__PURE__ */ jsx19(
2738
+ "textarea",
2739
+ {
2740
+ value: editState.value,
2741
+ onChange: (e) => setEditState((s) => ({ ...s, value: e.target.value })),
2742
+ rows: 2,
2743
+ 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",
2744
+ placeholder: "Prompt-Wert (leer = Label)"
2745
+ }
2746
+ ),
2747
+ /* @__PURE__ */ jsxs17("div", { className: "flex gap-1.5 justify-end", children: [
2748
+ /* @__PURE__ */ jsx19("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" }),
2749
+ /* @__PURE__ */ jsx19("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" })
2750
+ ] })
2751
+ ] }) : /* @__PURE__ */ jsxs17("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: [
2752
+ /* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-0 shrink-0", children: [
2753
+ /* @__PURE__ */ jsx19("button", { onClick: () => handleMoveUp(i), disabled: i === 0, className: "text-white/20 hover:text-white/60 disabled:opacity-10 transition leading-none", children: /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[14px]", children: "arrow_drop_up" }) }),
2754
+ /* @__PURE__ */ jsx19("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__ */ jsx19("span", { className: "material-symbols-outlined text-[14px]", children: "arrow_drop_down" }) })
2755
+ ] }),
2756
+ /* @__PURE__ */ jsxs17("div", { className: "flex-1 min-w-0", children: [
2757
+ /* @__PURE__ */ jsx19("div", { className: "text-[12px] text-white/80 font-medium truncate", children: tag.label }),
2758
+ tag.value && tag.value !== tag.label && /* @__PURE__ */ jsxs17("div", { className: "text-[10px] text-white/30 truncate", children: [
2759
+ tag.value.slice(0, 60),
2760
+ tag.value.length > 60 ? "\u2026" : ""
2761
+ ] })
2762
+ ] }),
2763
+ /* @__PURE__ */ jsxs17("div", { className: "flex gap-1 opacity-0 group-hover:opacity-100 transition shrink-0", children: [
2764
+ otherCategories.length > 0 && /* @__PURE__ */ jsx19(
2765
+ "button",
2766
+ {
2767
+ onClick: () => {
2768
+ setMovingLabel((l) => l === tag.label ? null : tag.label);
2769
+ setMoveTarget("");
2770
+ setEditingLabel(null);
2771
+ },
2772
+ className: "p-1 rounded text-white/30 hover:text-purple-400 transition",
2773
+ title: "Kategorie wechseln",
2774
+ children: /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[16px]", children: "drive_file_move" })
2775
+ }
2776
+ ),
2777
+ /* @__PURE__ */ jsx19("button", { onClick: () => startEdit(tag), className: "p-1 rounded text-white/30 hover:text-blue-400 transition", title: "Bearbeiten", children: /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[16px]", children: "edit" }) }),
2778
+ /* @__PURE__ */ jsx19("button", { onClick: () => handleDelete(tag), className: "p-1 rounded text-white/30 hover:text-red-400 transition", title: "L\xF6schen", children: /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[16px]", children: "delete" }) })
2779
+ ] })
2780
+ ] }),
2781
+ movingLabel === tag.label && /* @__PURE__ */ jsxs17("div", { className: "mt-1 bg-purple-900/20 border border-purple-700/30 rounded-lg p-2.5 space-y-1.5", children: [
2782
+ /* @__PURE__ */ jsx19("div", { className: "text-[9px] font-bold uppercase tracking-widest text-purple-400/70", children: "Verschieben nach Kategorie" }),
2783
+ /* @__PURE__ */ jsxs17(
2784
+ "select",
2785
+ {
2786
+ value: moveTarget,
2787
+ onChange: (e) => setMoveTarget(e.target.value),
2788
+ className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1 text-[11px] text-white/70 outline-none",
2789
+ children: [
2790
+ /* @__PURE__ */ jsx19("option", { value: "", children: "\u2014 Kategorie w\xE4hlen \u2014" }),
2791
+ otherCategories.map((cat) => /* @__PURE__ */ jsx19("option", { value: cat, children: cat }, cat))
2792
+ ]
2793
+ }
2794
+ ),
2795
+ /* @__PURE__ */ jsxs17("div", { className: "flex gap-1.5 justify-end", children: [
2796
+ /* @__PURE__ */ jsx19(
2797
+ "button",
2798
+ {
2799
+ onClick: () => handleMove(tag),
2800
+ disabled: !moveTarget,
2801
+ className: "px-2.5 py-1 bg-purple-700 hover:bg-purple-600 text-white text-[10px] font-bold rounded transition disabled:opacity-40",
2802
+ children: "VERSCHIEBEN"
2803
+ }
2804
+ ),
2805
+ /* @__PURE__ */ jsx19("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" })
2806
+ ] })
2807
+ ] })
2808
+ ] }, `${effectiveCategory}-${i}`)),
2809
+ tags.length === 0 && effectiveCategory && /* @__PURE__ */ jsx19("div", { className: "text-center text-[11px] text-white/20 py-6", children: "Keine Tags in dieser Kategorie." })
2810
+ ] }),
2811
+ effectiveCategory && /* @__PURE__ */ jsxs17("div", { className: "px-3 py-2 border-t border-white/5 shrink-0 space-y-1.5", children: [
2812
+ /* @__PURE__ */ jsxs17("div", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30", children: [
2813
+ "Neuer Tag in \u201E",
2814
+ effectiveCategory,
2815
+ '"'
2816
+ ] }),
2817
+ /* @__PURE__ */ jsx19(
2818
+ "input",
2819
+ {
2820
+ value: newTag.label,
2821
+ onChange: (e) => setNewTag((s) => ({ ...s, label: e.target.value })),
2822
+ onKeyDown: (e) => e.key === "Enter" && !e.shiftKey && handleCreate(),
2823
+ placeholder: "Label\u2026",
2824
+ 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"
2825
+ }
2826
+ ),
2827
+ /* @__PURE__ */ jsx19(
2828
+ "textarea",
2829
+ {
2830
+ value: newTag.value,
2831
+ onChange: (e) => setNewTag((s) => ({ ...s, value: e.target.value })),
2832
+ rows: 2,
2833
+ placeholder: "Prompt-Wert (leer = Label)",
2834
+ 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"
2835
+ }
2836
+ ),
2837
+ /* @__PURE__ */ jsxs17(
2838
+ "button",
2839
+ {
2840
+ onClick: handleCreate,
2841
+ disabled: !newTag.label.trim(),
2842
+ 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",
2843
+ children: [
2844
+ /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[14px]", children: "add" }),
2845
+ "TAG ERSTELLEN"
2846
+ ]
2847
+ }
2848
+ )
2849
+ ] })
2850
+ ] });
2851
+ }
2852
+
2853
+ // src/components/AvatarArchitectApp.tsx
2854
+ import { Fragment as Fragment9, jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
1609
2855
  function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
1610
2856
  useEffect4(() => {
1611
2857
  const id = "flow-styles";
@@ -1616,15 +2862,15 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1616
2862
  document.head.appendChild(style);
1617
2863
  }
1618
2864
  }, []);
1619
- const [showStart, setShowStart] = useState6(true);
1620
- const [layoutChoice, setLayoutChoice] = useState6(() => {
2865
+ const [showStart, setShowStart] = useState14(true);
2866
+ const [layoutChoice, setLayoutChoice] = useState14(() => {
1621
2867
  try {
1622
2868
  return localStorage.getItem("aa-layout") || null;
1623
2869
  } catch {
1624
2870
  return null;
1625
2871
  }
1626
2872
  });
1627
- const [projectLoaded, setProjectLoaded] = useState6(false);
2873
+ const [projectLoaded, setProjectLoaded] = useState14(false);
1628
2874
  const wsInputRef = useRef6(null);
1629
2875
  const startApp = (choice) => {
1630
2876
  try {
@@ -1634,61 +2880,63 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1634
2880
  setLayoutChoice(choice);
1635
2881
  setShowStart(false);
1636
2882
  };
1637
- const [nodes, setNodes] = useState6([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
1638
- const [edges, setEdges] = useState6([]);
1639
- const [history, setHistory] = useState6([]);
1640
- const [galleryItems, setGalleryItems] = useState6([]);
1641
- const [activePrompt, setActivePrompt] = useState6("");
1642
- const [isSynthesizing, setIsSynthesizing] = useState6(false);
1643
- const [activeGenerationsCount, setActiveGenerationsCount] = useState6(0);
1644
- const [currentResult, setCurrentResult] = useState6(null);
1645
- const [focusedNodeId, setFocusedNodeId] = useState6(null);
1646
- const [leftTab, setLeftTab] = useState6("prompt");
1647
- const [promptFeedback, setPromptFeedback] = useState6(null);
1648
- const [lastPromptPayload, setLastPromptPayload] = useState6(null);
1649
- const [isPromptTabGenerating, setIsPromptTabGenerating] = useState6(false);
1650
- const [activeTab, setActiveTab] = useState6("history");
1651
- const [mobileTab, setMobileTab] = useState6("stage");
1652
- const [aspectRatio, setAspectRatio] = useState6("1:1");
1653
- const [selectedModel, setSelectedModel] = useState6("\u{1F34C} Nano Banana Pro");
1654
- const [seed, setSeed] = useState6(Math.floor(Math.random() * 1e6));
1655
- const [seedMode, setSeedMode] = useState6("random");
1656
- const [isLeftCollapsed, setIsLeftCollapsed] = useState6(false);
1657
- const [isRightCollapsed, setIsRightCollapsed] = useState6(false);
1658
- const [leftPanelWidth, setLeftPanelWidth] = useState6(() => {
2883
+ const [nodes, setNodes] = useState14([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
2884
+ const [edges, setEdges] = useState14([]);
2885
+ const [history, setHistory] = useState14([]);
2886
+ const [galleryItems, setGalleryItems] = useState14([]);
2887
+ const [activePrompt, setActivePrompt] = useState14("");
2888
+ const [isSynthesizing, setIsSynthesizing] = useState14(false);
2889
+ const [activeGenerationsCount, setActiveGenerationsCount] = useState14(0);
2890
+ const [currentResult, setCurrentResult] = useState14(null);
2891
+ const [focusedNodeId, setFocusedNodeId] = useState14(null);
2892
+ const [leftTab, setLeftTab] = useState14("prompt");
2893
+ const [promptFeedback, setPromptFeedback] = useState14(null);
2894
+ const [lastPromptPayload, setLastPromptPayload] = useState14(null);
2895
+ const [isPromptTabGenerating, setIsPromptTabGenerating] = useState14(false);
2896
+ const [activeTab, setActiveTab] = useState14("history");
2897
+ const [mobileTab, setMobileTab] = useState14("stage");
2898
+ const [middlePanel, setMiddlePanel] = useState14("stage");
2899
+ const [recentLabItems, setRecentLabItems] = useState14([]);
2900
+ const [aspectRatio, setAspectRatio] = useState14("1:1");
2901
+ const [selectedModel, setSelectedModel] = useState14("\u{1F34C} Nano Banana Pro");
2902
+ const [seed, setSeed] = useState14(Math.floor(Math.random() * 1e6));
2903
+ const [seedMode, setSeedMode] = useState14("random");
2904
+ const [isLeftCollapsed, setIsLeftCollapsed] = useState14(false);
2905
+ const [isRightCollapsed, setIsRightCollapsed] = useState14(false);
2906
+ const [leftPanelWidth, setLeftPanelWidth] = useState14(() => {
1659
2907
  try {
1660
2908
  return parseInt(localStorage.getItem("aa-left-width") || "260", 10);
1661
2909
  } catch {
1662
2910
  return 260;
1663
2911
  }
1664
2912
  });
1665
- const [rightPanelWidth, setRightPanelWidth] = useState6(() => {
2913
+ const [rightPanelWidth, setRightPanelWidth] = useState14(() => {
1666
2914
  try {
1667
2915
  return parseInt(localStorage.getItem("aa-right-width") || "320", 10);
1668
2916
  } catch {
1669
2917
  return 320;
1670
2918
  }
1671
2919
  });
1672
- const [isPromptCollapsed, setIsPromptCollapsed] = useState6(false);
1673
- const [projectActionState, setProjectActionState] = useState6("idle");
2920
+ const [isPromptCollapsed, setIsPromptCollapsed] = useState14(false);
2921
+ const [projectActionState, setProjectActionState] = useState14("idle");
1674
2922
  const syncServerDataRef = useRef6(null);
1675
- const [workspaceTags, setWorkspaceTags] = useState6(null);
1676
- const [serverProjects, setServerProjects] = useState6([]);
1677
- const [isLoadingFromServer, setIsLoadingFromServer] = useState6(false);
1678
- const [highContrast, setHighContrast] = useState6(() => {
2923
+ const [workspaceTags, setWorkspaceTags] = useState14(null);
2924
+ const [serverProjects, setServerProjects] = useState14([]);
2925
+ const [isLoadingFromServer, setIsLoadingFromServer] = useState14(false);
2926
+ const [highContrast, setHighContrast] = useState14(() => {
1679
2927
  try {
1680
2928
  return localStorage.getItem("aa-contrast") === "high";
1681
2929
  } catch {
1682
2930
  return false;
1683
2931
  }
1684
2932
  });
1685
- const [activeReferenceId, setActiveReferenceId] = useState6(null);
1686
- const [activeReferenceThumbnail, setActiveReferenceThumbnail] = useState6(null);
1687
- const [isScanningImage, setIsScanningImage] = useState6(false);
1688
- const [touchStartX, setTouchStartX] = useState6(null);
1689
- const [isFullscreen, setIsFullscreen] = useState6(false);
1690
- const [zoomScale, setZoomScale] = useState6(1);
1691
- const [zoomOffset, setZoomOffset] = useState6({ x: 0, y: 0 });
2933
+ const [activeReferenceId, setActiveReferenceId] = useState14(null);
2934
+ const [activeReferenceThumbnail, setActiveReferenceThumbnail] = useState14(null);
2935
+ const [isScanningImage, setIsScanningImage] = useState14(false);
2936
+ const [touchStartX, setTouchStartX] = useState14(null);
2937
+ const [isFullscreen, setIsFullscreen] = useState14(false);
2938
+ const [zoomScale, setZoomScale] = useState14(1);
2939
+ const [zoomOffset, setZoomOffset] = useState14({ x: 0, y: 0 });
1692
2940
  const lastPinchDist = useRef6(null);
1693
2941
  const lastTapTime = useRef6(0);
1694
2942
  const dragStart = useRef6(null);
@@ -1754,6 +3002,27 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1754
3002
  setActiveReferenceId(null);
1755
3003
  setActiveReferenceThumbnail(null);
1756
3004
  };
3005
+ const labServices = useMemo2(() => {
3006
+ const available = groupGenerationsToLabItems([...galleryItems, ...history]);
3007
+ return {
3008
+ availableItems: available,
3009
+ recentItems: recentLabItems,
3010
+ onItemUsed: (item) => setRecentLabItems(
3011
+ (prev) => [item, ...prev.filter((i) => i.id !== item.id)].slice(0, 10)
3012
+ ),
3013
+ generateText: onGeneratePrompt,
3014
+ generateImage: onGenerateImage,
3015
+ saveResult: async (item) => {
3016
+ const frame = item.frames[0];
3017
+ if (frame?.base64) {
3018
+ const gen = frameToGeneration(frame, item);
3019
+ setGalleryItems((prev) => [gen, ...prev]);
3020
+ setHistory((prev) => [gen, ...prev]);
3021
+ }
3022
+ },
3023
+ workspaceTags: workspaceTags || void 0
3024
+ };
3025
+ }, [galleryItems, history, recentLabItems, onGeneratePrompt, onGenerateImage, workspaceTags]);
1757
3026
  const startLeftResize = (e) => {
1758
3027
  e.preventDefault();
1759
3028
  const startX = e.clientX;
@@ -1801,7 +3070,11 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1801
3070
  reader.onerror = reject;
1802
3071
  reader.readAsDataURL(file);
1803
3072
  });
1804
- const prompt = await onGeneratePrompt("", "scan", [{ base64, mimeType: file.type || "image/png" }]);
3073
+ const { text, systemInstruction } = buildScanInstruction();
3074
+ const prompt = await onGeneratePrompt(text, {
3075
+ images: [{ base64, mimeType: file.type || "image/png" }],
3076
+ systemInstruction
3077
+ });
1805
3078
  setActivePrompt(prompt);
1806
3079
  } catch (err) {
1807
3080
  console.error("Scan fehlgeschlagen:", err);
@@ -1917,11 +3190,32 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1917
3190
  return { by_category: { ...prev.by_category, [category]: updatedCat }, all: updatedAll };
1918
3191
  });
1919
3192
  };
3193
+ const handleTagReorder = (category, reorderedTags) => {
3194
+ setWorkspaceTags((prev) => {
3195
+ if (!prev) return prev;
3196
+ const deletedTags = (prev.by_category[category] || []).filter((t) => t.is_deleted);
3197
+ const merged = [...reorderedTags, ...deletedTags];
3198
+ const newAll = [
3199
+ ...prev.all.filter((t) => t.category !== category),
3200
+ ...merged.map((t) => ({ ...t, category }))
3201
+ ];
3202
+ return { by_category: { ...prev.by_category, [category]: merged }, all: newAll };
3203
+ });
3204
+ };
3205
+ const handleTagMove = (label, value, fromCategory, toCategory) => {
3206
+ setWorkspaceTags((prev) => {
3207
+ if (!prev) return prev;
3208
+ const fromTags = (prev.by_category[fromCategory] || []).filter((t) => t.label !== label);
3209
+ const toTags = [...prev.by_category[toCategory] || [], { label, value, is_user_created: true }];
3210
+ const newAll = prev.all.filter((t) => !(t.label === label && t.category === fromCategory)).concat({ label, value, is_user_created: true, category: toCategory });
3211
+ return { by_category: { ...prev.by_category, [fromCategory]: fromTags, [toCategory]: toTags }, all: newAll };
3212
+ });
3213
+ };
1920
3214
  const handlePromptTabGenerate = async (selectedTags, instructions, rules) => {
1921
3215
  setIsPromptTabGenerating(true);
1922
3216
  setPromptFeedback(null);
1923
3217
  try {
1924
- const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
3218
+ const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : nodes.map((n) => n.data.label || "").filter(Boolean).join("\n");
1925
3219
  const payload = buildPromptTabPayload(selectedTags, instructions, rules, treeText);
1926
3220
  setLastPromptPayload(payload);
1927
3221
  const raw = await onGeneratePrompt(payload);
@@ -1949,7 +3243,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1949
3243
  const handleProjectExport = async () => {
1950
3244
  setProjectActionState("working-full");
1951
3245
  try {
1952
- const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags);
3246
+ const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags, recentLabItems.map((i) => i.id));
1953
3247
  await onDownload(base64, "application/zip", `avatar_project_${getFormattedTimestamp()}.zip`);
1954
3248
  setProjectActionState("done");
1955
3249
  setTimeout(() => setProjectActionState("idle"), 3e3);
@@ -1977,6 +3271,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1977
3271
  setSeedMode(data.settings.seedMode || "random");
1978
3272
  }
1979
3273
  if (data.workspaceTags?.by_category) setWorkspaceTags(data.workspaceTags);
3274
+ if (data.recentLabItemIds?.length) {
3275
+ const allGens = [...data.history || [], ...data.galleryItems || []];
3276
+ const labItems = groupGenerationsToLabItems(allGens);
3277
+ const recent = data.recentLabItemIds.map((id) => labItems.find((item) => item.id === id)).filter(Boolean);
3278
+ setRecentLabItems(recent);
3279
+ }
1980
3280
  setProjectActionState("done");
1981
3281
  setProjectLoaded(true);
1982
3282
  setTimeout(() => setProjectActionState("idle"), 2e3);
@@ -2017,7 +3317,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2017
3317
  if (!onServerSave) return;
2018
3318
  setProjectActionState("working-full");
2019
3319
  try {
2020
- const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags);
3320
+ const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags, recentLabItems.map((i) => i.id));
2021
3321
  await onServerSave(base64, name || `avatar_project_${getFormattedTimestamp()}`);
2022
3322
  await fetchServerProjects();
2023
3323
  setProjectActionState("done");
@@ -2061,7 +3361,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2061
3361
  mergedHistory,
2062
3362
  serverData.galleryItems || galleryItems,
2063
3363
  serverData.settings || { aspectRatio, selectedModel, seed, seedMode },
2064
- serverData.workspaceTags || workspaceTags
3364
+ serverData.workspaceTags || workspaceTags,
3365
+ serverData.recentLabItemIds || recentLabItems.map((i) => i.id)
2065
3366
  );
2066
3367
  await onServerSave(base64, `sync_${getFormattedTimestamp()}`);
2067
3368
  await fetchServerProjects();
@@ -2077,7 +3378,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2077
3378
  }, [activeTab]);
2078
3379
  if (isFullscreen && currentResult?.base64) {
2079
3380
  const fsBase64 = currentResult.base64.startsWith("data:") ? currentResult.base64 : `data:image/png;base64,${currentResult.base64}`;
2080
- return /* @__PURE__ */ jsxs11(
3381
+ return /* @__PURE__ */ jsxs18(
2081
3382
  "div",
2082
3383
  {
2083
3384
  className: "fixed inset-0 bg-black z-50 flex items-center justify-center overflow-hidden touch-none",
@@ -2085,7 +3386,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2085
3386
  onTouchMove: handleFsTouchMove,
2086
3387
  onTouchEnd: handleFsTouchEnd,
2087
3388
  children: [
2088
- /* @__PURE__ */ jsx13(
3389
+ /* @__PURE__ */ jsx20(
2089
3390
  "img",
2090
3391
  {
2091
3392
  src: fsBase64,
@@ -2102,76 +3403,76 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2102
3403
  }
2103
3404
  }
2104
3405
  ),
2105
- /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "close" }) }),
2106
- zoomScale > 1 && /* @__PURE__ */ jsx13("button", { onClick: () => {
3406
+ /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "close" }) }),
3407
+ zoomScale > 1 && /* @__PURE__ */ jsx20("button", { onClick: () => {
2107
3408
  setZoomScale(1);
2108
3409
  setZoomOffset({ x: 0, y: 0 });
2109
- }, 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__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "zoom_out_map" }) }),
2110
- history.length > 1 && /* @__PURE__ */ jsxs11(Fragment4, { children: [
2111
- /* @__PURE__ */ jsx13("button", { onClick: () => {
3410
+ }, 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__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "zoom_out_map" }) }),
3411
+ history.length > 1 && /* @__PURE__ */ jsxs18(Fragment9, { children: [
3412
+ /* @__PURE__ */ jsx20("button", { onClick: () => {
2112
3413
  if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
2113
- }, 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__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
2114
- /* @__PURE__ */ jsx13("button", { onClick: () => {
3414
+ }, 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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
3415
+ /* @__PURE__ */ jsx20("button", { onClick: () => {
2115
3416
  if (currentIndex < history.length - 1) setCurrentResult(history[currentIndex + 1]);
2116
- }, 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__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
2117
- /* @__PURE__ */ jsxs11("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: [
3417
+ }, 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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
3418
+ /* @__PURE__ */ jsxs18("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: [
2118
3419
  currentIndex + 1,
2119
3420
  " / ",
2120
3421
  history.length
2121
3422
  ] })
2122
3423
  ] }),
2123
- zoomScale === 1 && /* @__PURE__ */ jsx13("div", { className: "absolute bottom-6 right-4 text-[9px] text-white/20 font-mono", children: "Pinch zum Zoomen \xB7 Doppeltipp 2.5\xD7" })
3424
+ zoomScale === 1 && /* @__PURE__ */ jsx20("div", { className: "absolute bottom-6 right-4 text-[9px] text-white/20 font-mono", children: "Pinch zum Zoomen \xB7 Doppeltipp 2.5\xD7" })
2124
3425
  ]
2125
3426
  }
2126
3427
  );
2127
3428
  }
2128
3429
  if (showStart) {
2129
- return /* @__PURE__ */ jsxs11("div", { className: "fixed inset-0 bg-[#0e0e0e] flex flex-col items-center justify-center p-6", style: { gap: 28, ...hcStyle }, children: [
2130
- /* @__PURE__ */ jsx13("input", { ref: wsInputRef, type: "file", accept: ".zip", className: "hidden", onChange: (e) => {
3430
+ return /* @__PURE__ */ jsxs18("div", { className: "fixed inset-0 bg-[#0e0e0e] flex flex-col items-center justify-center p-6", style: { gap: 28, ...hcStyle }, children: [
3431
+ /* @__PURE__ */ jsx20("input", { ref: wsInputRef, type: "file", accept: ".zip", className: "hidden", onChange: (e) => {
2131
3432
  const f = e.target.files?.[0];
2132
3433
  if (f) handleProjectImport(f);
2133
3434
  e.target.value = "";
2134
3435
  } }),
2135
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-1", children: [
2136
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-white/15 text-[44px]", children: "palette" }),
2137
- /* @__PURE__ */ jsx13("span", { className: "text-white/25 text-[10px] font-bold uppercase tracking-[0.25em]", children: "Avatar Architect" }),
2138
- /* @__PURE__ */ jsxs11("span", { className: "text-white text-[13px] font-mono", children: [
3436
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-1", children: [
3437
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-white/15 text-[44px]", children: "palette" }),
3438
+ /* @__PURE__ */ jsx20("span", { className: "text-white/25 text-[10px] font-bold uppercase tracking-[0.25em]", children: "Avatar Architect" }),
3439
+ /* @__PURE__ */ jsxs18("span", { className: "text-white text-[13px] font-mono", children: [
2139
3440
  "v",
2140
3441
  LIB_VERSION
2141
3442
  ] })
2142
3443
  ] }),
2143
- /* @__PURE__ */ jsxs11(
3444
+ /* @__PURE__ */ jsxs18(
2144
3445
  "button",
2145
3446
  {
2146
3447
  onClick: toggleContrast,
2147
3448
  className: "flex items-center gap-3 px-5 py-3 rounded-2xl border transition-colors",
2148
3449
  style: { borderColor: highContrast ? "rgba(255,255,255,0.3)" : "rgba(255,255,255,0.08)", background: highContrast ? "rgba(255,255,255,0.08)" : "transparent" },
2149
3450
  children: [
2150
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.35)" }, children: highContrast ? "light_mode" : "dark_mode" }),
2151
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-start", children: [
2152
- /* @__PURE__ */ jsx13("span", { className: "text-[13px] font-bold", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.5)" }, children: highContrast ? "Hoher Kontrast" : "Normaler Kontrast" }),
2153
- /* @__PURE__ */ jsx13("span", { className: "text-[10px]", style: { color: "rgba(255,255,255,0.25)" }, children: "Tippen zum Umschalten" })
3451
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.35)" }, children: highContrast ? "light_mode" : "dark_mode" }),
3452
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-start", children: [
3453
+ /* @__PURE__ */ jsx20("span", { className: "text-[13px] font-bold", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.5)" }, children: highContrast ? "Hoher Kontrast" : "Normaler Kontrast" }),
3454
+ /* @__PURE__ */ jsx20("span", { className: "text-[10px]", style: { color: "rgba(255,255,255,0.25)" }, children: "Tippen zum Umschalten" })
2154
3455
  ] })
2155
3456
  ]
2156
3457
  }
2157
3458
  ),
2158
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
2159
- /* @__PURE__ */ jsxs11(
3459
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
3460
+ /* @__PURE__ */ jsxs18(
2160
3461
  "button",
2161
3462
  {
2162
3463
  onClick: () => wsInputRef.current?.click(),
2163
3464
  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",
2164
3465
  style: { height: 56, background: projectLoaded ? "#16a34a" : "#0284c7" },
2165
3466
  children: [
2166
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: projectLoaded ? "check_circle" : "folder_zip" }),
3467
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: projectLoaded ? "check_circle" : "folder_zip" }),
2167
3468
  projectLoaded ? "Projekt geladen \u2713" : "Projekt laden (.zip)"
2168
3469
  ]
2169
3470
  }
2170
3471
  ),
2171
- !projectLoaded && /* @__PURE__ */ jsx13("span", { className: "text-white/20 text-[10px] text-center", children: "Baum, Bilder und Einstellungen wiederherstellen" })
3472
+ !projectLoaded && /* @__PURE__ */ jsx20("span", { className: "text-white/20 text-[10px] text-center", children: "Baum, Bilder und Einstellungen wiederherstellen" })
2172
3473
  ] }),
2173
- onFetchServerProjects && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
2174
- /* @__PURE__ */ jsxs11(
3474
+ onFetchServerProjects && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
3475
+ /* @__PURE__ */ jsxs18(
2175
3476
  "button",
2176
3477
  {
2177
3478
  disabled: isLoadingFromServer,
@@ -2192,35 +3493,35 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2192
3493
  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",
2193
3494
  style: { height: 56, background: "#7c3aed" },
2194
3495
  children: [
2195
- /* @__PURE__ */ jsx13("span", { className: `material-symbols-outlined text-[22px]${isLoadingFromServer ? " animate-spin" : ""}`, children: isLoadingFromServer ? "sync" : "cloud_download" }),
3496
+ /* @__PURE__ */ jsx20("span", { className: `material-symbols-outlined text-[22px]${isLoadingFromServer ? " animate-spin" : ""}`, children: isLoadingFromServer ? "sync" : "cloud_download" }),
2196
3497
  isLoadingFromServer ? "Laden\u2026" : "Vom Server laden"
2197
3498
  ]
2198
3499
  }
2199
3500
  ),
2200
- /* @__PURE__ */ jsx13("span", { className: "text-white/20 text-[10px] text-center", children: "Letzten Stand vom Server wiederherstellen" })
3501
+ /* @__PURE__ */ jsx20("span", { className: "text-white/20 text-[10px] text-center", children: "Letzten Stand vom Server wiederherstellen" })
2201
3502
  ] }),
2202
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
2203
- /* @__PURE__ */ jsx13("span", { className: "text-white/25 text-[10px] uppercase tracking-widest font-bold", children: "Layout w\xE4hlen & starten" }),
2204
- /* @__PURE__ */ jsx13("div", { className: "grid grid-cols-2 gap-2 w-full", children: [
3503
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
3504
+ /* @__PURE__ */ jsx20("span", { className: "text-white/25 text-[10px] uppercase tracking-widest font-bold", children: "Layout w\xE4hlen & starten" }),
3505
+ /* @__PURE__ */ jsx20("div", { className: "grid grid-cols-2 gap-2 w-full", children: [
2205
3506
  { id: "mobile", icon: "smartphone", label: "Mobile" },
2206
3507
  { id: "mobile-desktop", icon: "phonelink", label: "Mobile+" },
2207
3508
  { id: "desktop", icon: "desktop_windows", label: "Desktop" },
2208
3509
  { id: "tablet-landscape", icon: "tablet", label: "Landscape" }
2209
- ].map((opt) => /* @__PURE__ */ jsxs11(
3510
+ ].map((opt) => /* @__PURE__ */ jsxs18(
2210
3511
  "button",
2211
3512
  {
2212
3513
  onClick: () => startApp(opt.id),
2213
3514
  className: "flex flex-col items-center gap-2 py-4 rounded-2xl border transition-colors",
2214
3515
  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" },
2215
3516
  children: [
2216
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[24px]", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.icon }),
2217
- /* @__PURE__ */ jsx13("span", { className: "text-[11px] font-bold", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.label })
3517
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[24px]", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.icon }),
3518
+ /* @__PURE__ */ jsx20("span", { className: "text-[11px] font-bold", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.label })
2218
3519
  ]
2219
3520
  },
2220
3521
  opt.id
2221
3522
  )) }),
2222
- layoutChoice === "mobile-desktop" && /* @__PURE__ */ jsx13("span", { className: "text-white/20 text-[9px] text-center", children: "Mobil-Layout skaliert f\xFCr Desktop-Modus" }),
2223
- layoutChoice === "tablet-landscape" && /* @__PURE__ */ jsx13("span", { className: "text-white/20 text-[9px] text-center", children: "2-Spalten-Layout f\xFCr Landscape-Tablet im Desktop-Mode" })
3523
+ layoutChoice === "mobile-desktop" && /* @__PURE__ */ jsx20("span", { className: "text-white/20 text-[9px] text-center", children: "Mobil-Layout skaliert f\xFCr Desktop-Modus" }),
3524
+ layoutChoice === "tablet-landscape" && /* @__PURE__ */ jsx20("span", { className: "text-white/20 text-[9px] text-center", children: "2-Spalten-Layout f\xFCr Landscape-Tablet im Desktop-Mode" })
2224
3525
  ] })
2225
3526
  ] });
2226
3527
  }
@@ -2229,28 +3530,46 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2229
3530
  const mdScale = mdMode ? window.innerWidth / 430 : 1;
2230
3531
  const mdW = mdMode ? 430 : void 0;
2231
3532
  const mdH = mdMode ? Math.ceil(window.innerHeight / mdScale) : void 0;
2232
- const mobileRoot = /* @__PURE__ */ jsxs11("div", { className: "flex flex-col bg-[#0e0e0e] text-white overflow-hidden", style: {
3533
+ const mobileRoot = /* @__PURE__ */ jsxs18("div", { className: "flex flex-col bg-[#0e0e0e] text-white overflow-hidden", style: {
2233
3534
  width: mdMode ? mdW : "100vw",
2234
3535
  height: mdMode ? mdH : "100dvh",
2235
3536
  transform: mdMode ? `scale(${mdScale})` : void 0,
2236
3537
  transformOrigin: mdMode ? "top left" : void 0,
2237
3538
  ...hcStyle || {}
2238
3539
  }, children: [
2239
- mobileTab === "stage" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col flex-1 min-h-0", children: [
2240
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 px-3 border-b border-white/5 bg-black/30 shrink-0", style: { height: 52 }, children: [
2241
- /* @__PURE__ */ jsx13(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
2242
- /* @__PURE__ */ jsx13(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" }] }),
2243
- /* @__PURE__ */ jsx13("div", { className: "flex-1" }),
2244
- activeReferenceThumbnail ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
2245
- /* @__PURE__ */ jsx13("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
2246
- /* @__PURE__ */ jsx13("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
2247
- /* @__PURE__ */ jsx13("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 active:text-white/80 transition-colors", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
2248
- ] }) : /* @__PURE__ */ jsx13("button", { onClick: handleSelectReference, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }) }),
2249
- /* @__PURE__ */ jsx13("button", { onClick: toggleContrast, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: highContrast ? "light_mode" : "dark_mode" }) }),
2250
- /* @__PURE__ */ jsx13("button", { onClick: () => setShowStart(true), className: "text-white/20 active:text-white/60 transition-colors mr-1", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "desktop_windows" }) })
3540
+ mobileTab === "labs" && /* @__PURE__ */ jsx20("div", { className: "flex flex-col flex-1 min-h-0", children: /* @__PURE__ */ jsx20(LabsTab, { services: labServices, onResult: (item) => {
3541
+ const frame = item.frames[0];
3542
+ if (frame?.base64) {
3543
+ setCurrentResult(frameToGeneration(frame, item));
3544
+ setMobileTab("stage");
3545
+ }
3546
+ } }) }),
3547
+ mobileTab === "tags" && workspaceTags && /* @__PURE__ */ jsx20("div", { className: "flex flex-col flex-1 min-h-0", children: /* @__PURE__ */ jsx20(
3548
+ TagManagerPanel,
3549
+ {
3550
+ workspaceTags,
3551
+ onTagCreate: handleTagCreate,
3552
+ onTagUpdate: handleTagUpdate,
3553
+ onTagDelete: handleTagDelete,
3554
+ onTagReorder: handleTagReorder,
3555
+ onTagMove: handleTagMove
3556
+ }
3557
+ ) }),
3558
+ mobileTab === "stage" && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col flex-1 min-h-0", children: [
3559
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-2 px-3 border-b border-white/5 bg-black/30 shrink-0", style: { height: 52 }, children: [
3560
+ /* @__PURE__ */ jsx20(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
3561
+ /* @__PURE__ */ jsx20(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" }] }),
3562
+ /* @__PURE__ */ jsx20("div", { className: "flex-1" }),
3563
+ activeReferenceThumbnail ? /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
3564
+ /* @__PURE__ */ jsx20("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
3565
+ /* @__PURE__ */ jsx20("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
3566
+ /* @__PURE__ */ jsx20("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 active:text-white/80 transition-colors", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
3567
+ ] }) : /* @__PURE__ */ jsx20("button", { onClick: handleSelectReference, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }) }),
3568
+ /* @__PURE__ */ jsx20("button", { onClick: toggleContrast, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: highContrast ? "light_mode" : "dark_mode" }) }),
3569
+ /* @__PURE__ */ jsx20("button", { onClick: () => setShowStart(true), className: "text-white/20 active:text-white/60 transition-colors mr-1", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "desktop_windows" }) })
2251
3570
  ] }),
2252
- /* @__PURE__ */ jsx13("div", { className: "px-3 pt-3 pb-2 shrink-0", children: /* @__PURE__ */ jsxs11("div", { className: `relative rounded-xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
2253
- /* @__PURE__ */ jsx13(
3571
+ /* @__PURE__ */ jsx20("div", { className: "px-3 pt-3 pb-2 shrink-0", children: /* @__PURE__ */ jsxs18("div", { className: `relative rounded-xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
3572
+ /* @__PURE__ */ jsx20(
2254
3573
  "textarea",
2255
3574
  {
2256
3575
  value: activePrompt,
@@ -2260,26 +3579,26 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2260
3579
  placeholder: "Prompt eingeben..."
2261
3580
  }
2262
3581
  ),
2263
- activePrompt && !isSynthesizing && /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined text-[18px]", children: "close" }) })
3582
+ activePrompt && !isSynthesizing && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[18px]", children: "close" }) })
2264
3583
  ] }) }),
2265
- /* @__PURE__ */ jsx13("div", { className: "px-3 pb-3 shrink-0", children: /* @__PURE__ */ jsx13(
3584
+ /* @__PURE__ */ jsx20("div", { className: "px-3 pb-3 shrink-0", children: /* @__PURE__ */ jsx20(
2266
3585
  "button",
2267
3586
  {
2268
3587
  onClick: () => handleGenerateImage(),
2269
3588
  disabled: !activePrompt.trim() || isGenerating,
2270
3589
  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",
2271
3590
  style: { height: 48, background: activePrompt.trim() && !isGenerating ? "#0284c7" : void 0, border: "1px solid rgba(255,255,255,0.1)" },
2272
- children: isGenerating ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
2273
- /* @__PURE__ */ jsx13("div", { className: "w-4 h-4 border-t-2 border-white rounded-full animate-spin" }),
2274
- /* @__PURE__ */ jsx13("span", { children: "Generiere..." })
2275
- ] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
2276
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "bolt" }),
2277
- /* @__PURE__ */ jsx13("span", { children: "Generieren" })
3591
+ children: isGenerating ? /* @__PURE__ */ jsxs18(Fragment9, { children: [
3592
+ /* @__PURE__ */ jsx20("div", { className: "w-4 h-4 border-t-2 border-white rounded-full animate-spin" }),
3593
+ /* @__PURE__ */ jsx20("span", { children: "Generiere..." })
3594
+ ] }) : /* @__PURE__ */ jsxs18(Fragment9, { children: [
3595
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "bolt" }),
3596
+ /* @__PURE__ */ jsx20("span", { children: "Generieren" })
2278
3597
  ] })
2279
3598
  }
2280
3599
  ) }),
2281
- /* @__PURE__ */ jsxs11("div", { className: "flex-1 min-h-0 px-3 pb-3 flex flex-col", children: [
2282
- /* @__PURE__ */ jsxs11(
3600
+ /* @__PURE__ */ jsxs18("div", { className: "flex-1 min-h-0 px-3 pb-3 flex flex-col", children: [
3601
+ /* @__PURE__ */ jsxs18(
2283
3602
  "div",
2284
3603
  {
2285
3604
  className: "w-full rounded-2xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center",
@@ -2293,25 +3612,25 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2293
3612
  setTouchStartX(null);
2294
3613
  },
2295
3614
  children: [
2296
- currentResult?.status === "processing" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-3", children: [
2297
- /* @__PURE__ */ jsx13("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
2298
- /* @__PURE__ */ jsx13("span", { className: "text-[11px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
3615
+ currentResult?.status === "processing" && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-3", children: [
3616
+ /* @__PURE__ */ jsx20("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
3617
+ /* @__PURE__ */ jsx20("span", { className: "text-[11px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
2299
3618
  ] }),
2300
- currentResult?.status === "error" && /* @__PURE__ */ jsxs11("div", { className: "p-6 text-center flex flex-col items-center gap-3", children: [
2301
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-red-400 text-[36px]", children: "warning" }),
2302
- /* @__PURE__ */ jsx13("p", { className: "text-white/50 text-[13px]", children: currentResult.error?.message }),
2303
- /* @__PURE__ */ jsx13("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" })
3619
+ currentResult?.status === "error" && /* @__PURE__ */ jsxs18("div", { className: "p-6 text-center flex flex-col items-center gap-3", children: [
3620
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-red-400 text-[36px]", children: "warning" }),
3621
+ /* @__PURE__ */ jsx20("p", { className: "text-white/50 text-[13px]", children: currentResult.error?.message }),
3622
+ /* @__PURE__ */ jsx20("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" })
2304
3623
  ] }),
2305
- currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ jsx13("img", { src: currentResult.base64, className: "w-full h-full object-contain" }),
2306
- !currentResult && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
2307
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[64px]", children: "palette" }),
2308
- /* @__PURE__ */ jsx13("span", { className: "text-[11px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
3624
+ currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ jsx20("img", { src: currentResult.base64, className: "w-full h-full object-contain" }),
3625
+ !currentResult && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
3626
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[64px]", children: "palette" }),
3627
+ /* @__PURE__ */ jsx20("span", { className: "text-[11px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
2309
3628
  ] }),
2310
- currentResult?.status === "done" && /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined text-[18px]", children: "fullscreen" }) }),
2311
- history.length > 1 && currentResult && /* @__PURE__ */ jsxs11(Fragment4, { children: [
2312
- /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
2313
- /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
2314
- /* @__PURE__ */ jsxs11("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: [
3629
+ currentResult?.status === "done" && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[18px]", children: "fullscreen" }) }),
3630
+ history.length > 1 && currentResult && /* @__PURE__ */ jsxs18(Fragment9, { children: [
3631
+ /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
3632
+ /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
3633
+ /* @__PURE__ */ jsxs18("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: [
2315
3634
  currentIndex + 1,
2316
3635
  " / ",
2317
3636
  history.length
@@ -2320,30 +3639,30 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2320
3639
  ]
2321
3640
  }
2322
3641
  ),
2323
- currentResult?.status === "done" && /* @__PURE__ */ jsxs11("div", { className: "flex gap-2 mt-3", children: [
2324
- /* @__PURE__ */ jsxs11("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: [
2325
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "replay" }),
2326
- /* @__PURE__ */ jsx13("span", { className: "text-[12px] text-white/60", children: "Prompt" })
3642
+ currentResult?.status === "done" && /* @__PURE__ */ jsxs18("div", { className: "flex gap-2 mt-3", children: [
3643
+ /* @__PURE__ */ jsxs18("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: [
3644
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "replay" }),
3645
+ /* @__PURE__ */ jsx20("span", { className: "text-[12px] text-white/60", children: "Prompt" })
2327
3646
  ] }),
2328
- /* @__PURE__ */ jsxs11("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: [
2329
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px] text-white/80", children: "auto_fix_high" }),
2330
- /* @__PURE__ */ jsx13("span", { className: "text-[12px] text-white/80 font-bold", children: "Referenz" })
3647
+ /* @__PURE__ */ jsxs18("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: [
3648
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[18px] text-white/80", children: "auto_fix_high" }),
3649
+ /* @__PURE__ */ jsx20("span", { className: "text-[12px] text-white/80 font-bold", children: "Referenz" })
2331
3650
  ] }),
2332
- /* @__PURE__ */ jsxs11("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: [
2333
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "download" }),
2334
- /* @__PURE__ */ jsx13("span", { className: "text-[12px] text-white/60", children: "Laden" })
3651
+ /* @__PURE__ */ jsxs18("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: [
3652
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "download" }),
3653
+ /* @__PURE__ */ jsx20("span", { className: "text-[12px] text-white/60", children: "Laden" })
2335
3654
  ] })
2336
3655
  ] })
2337
3656
  ] })
2338
3657
  ] }),
2339
- mobileTab === "browse" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col flex-1 min-h-0", children: [
2340
- /* @__PURE__ */ jsx13("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: ["history", "gallery", "inspect"].map((tab) => /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : "info" }) }, tab)) }),
2341
- /* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-hidden relative", children: [
2342
- activeTab === "history" && /* @__PURE__ */ jsx13(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: (g) => {
3658
+ mobileTab === "browse" && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col flex-1 min-h-0", children: [
3659
+ /* @__PURE__ */ jsx20("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: ["history", "gallery", "inspect"].map((tab) => /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : "info" }) }, tab)) }),
3660
+ /* @__PURE__ */ jsxs18("div", { className: "flex-1 overflow-hidden relative", children: [
3661
+ activeTab === "history" && /* @__PURE__ */ jsx20(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: (g) => {
2343
3662
  setCurrentResult(g);
2344
3663
  setMobileTab("stage");
2345
3664
  }, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
2346
- activeTab === "gallery" && /* @__PURE__ */ jsx13(
3665
+ activeTab === "gallery" && /* @__PURE__ */ jsx20(
2347
3666
  MediaLibrary,
2348
3667
  {
2349
3668
  items: galleryItems,
@@ -2363,38 +3682,39 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2363
3682
  }
2364
3683
  }
2365
3684
  ),
2366
- activeTab === "inspect" && /* @__PURE__ */ jsx13(InspectPanel, { currentResult, history, onSelect: (g) => {
3685
+ activeTab === "inspect" && /* @__PURE__ */ jsx20(InspectPanel, { currentResult, history, onSelect: (g) => {
2367
3686
  setCurrentResult(g);
2368
3687
  } })
2369
3688
  ] })
2370
3689
  ] }),
2371
- /* @__PURE__ */ jsxs11("div", { style: { display: mobileTab === "tools" ? "flex" : "none" }, className: "flex flex-col flex-1 min-h-0", children: [
2372
- /* @__PURE__ */ jsxs11("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: [
2373
- workspaceTags && /* @__PURE__ */ jsxs11("button", { onClick: () => {
3690
+ /* @__PURE__ */ jsxs18("div", { style: { display: mobileTab === "tools" ? "flex" : "none" }, className: "flex flex-col flex-1 min-h-0", children: [
3691
+ /* @__PURE__ */ jsxs18("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: [
3692
+ workspaceTags && /* @__PURE__ */ jsxs18("button", { onClick: () => {
2374
3693
  setLeftTab("prompt");
2375
3694
  if (activeTab === "setup" || activeTab === "sync") setActiveTab("history");
2376
3695
  }, 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: [
2377
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "auto_fix_high" }),
3696
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "auto_fix_high" }),
2378
3697
  "Prompt"
2379
3698
  ] }),
2380
- /* @__PURE__ */ jsxs11("button", { onClick: () => {
3699
+ /* @__PURE__ */ jsxs18("button", { onClick: () => {
2381
3700
  setLeftTab("hierarchy");
2382
3701
  if (activeTab === "setup" || activeTab === "sync") setActiveTab("history");
2383
3702
  }, 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: [
2384
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "account_tree" }),
3703
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "account_tree" }),
2385
3704
  "Hierarchie"
2386
3705
  ] }),
2387
- /* @__PURE__ */ jsxs11("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: [
2388
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "settings" }),
3706
+ /* @__PURE__ */ jsxs18("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: [
3707
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "settings" }),
2389
3708
  "Setup"
2390
3709
  ] }),
2391
- /* @__PURE__ */ jsxs11("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: [
2392
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "cloud_sync" }),
3710
+ /* @__PURE__ */ jsxs18("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: [
3711
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "cloud_sync" }),
2393
3712
  "Sync"
2394
- ] })
3713
+ ] }),
3714
+ workspaceTags && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "label" }) })
2395
3715
  ] }),
2396
- /* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-hidden relative", children: [
2397
- leftTab === "hierarchy" && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ jsx13("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx13(
3716
+ /* @__PURE__ */ jsxs18("div", { className: "flex-1 overflow-hidden relative", children: [
3717
+ leftTab === "hierarchy" && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ jsx20("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx20(
2398
3718
  ListView,
2399
3719
  {
2400
3720
  nodes,
@@ -2425,12 +3745,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2425
3745
  isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
2426
3746
  }
2427
3747
  ) }),
2428
- workspaceTags && /* @__PURE__ */ jsx13("div", { style: { display: leftTab === "prompt" && activeTab !== "setup" && activeTab !== "sync" ? "flex" : "none" }, className: "absolute inset-0 flex-col", children: /* @__PURE__ */ jsx13(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => {
3748
+ workspaceTags && /* @__PURE__ */ jsx20("div", { style: { display: leftTab === "prompt" && activeTab !== "setup" && activeTab !== "sync" ? "flex" : "none" }, className: "absolute inset-0 flex-col", children: /* @__PURE__ */ jsx20(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => {
2429
3749
  handleGenerateImage(prompt);
2430
3750
  setMobileTab("stage");
2431
3751
  }, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }) }),
2432
- activeTab === "setup" && /* @__PURE__ */ jsx13(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
2433
- activeTab === "sync" && /* @__PURE__ */ jsx13(
3752
+ activeTab === "setup" && /* @__PURE__ */ jsx20(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
3753
+ activeTab === "sync" && /* @__PURE__ */ jsx20(
2434
3754
  ProjectSyncTab,
2435
3755
  {
2436
3756
  onProjectExport: handleProjectExport,
@@ -2445,20 +3765,33 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2445
3765
  onComputeSyncDiff: onFetchServerProjects && onServerLoad && onServerSave ? handleComputeSyncDiff : void 0,
2446
3766
  onExecuteSync: onFetchServerProjects && onServerLoad && onServerSave ? handleExecuteSync : void 0
2447
3767
  }
3768
+ ),
3769
+ activeTab === "tags" && workspaceTags && /* @__PURE__ */ jsx20(
3770
+ TagManagerPanel,
3771
+ {
3772
+ workspaceTags,
3773
+ onTagCreate: handleTagCreate,
3774
+ onTagUpdate: handleTagUpdate,
3775
+ onTagDelete: handleTagDelete,
3776
+ onTagReorder: handleTagReorder,
3777
+ onTagMove: handleTagMove
3778
+ }
2448
3779
  )
2449
3780
  ] })
2450
3781
  ] }),
2451
- /* @__PURE__ */ jsx13("div", { className: "flex border-t border-white/10 bg-black shrink-0", style: { height: 56, paddingBottom: "env(safe-area-inset-bottom, 0px)" }, children: [
3782
+ /* @__PURE__ */ jsx20("div", { className: "flex border-t border-white/10 bg-black shrink-0", style: { height: 56, paddingBottom: "env(safe-area-inset-bottom, 0px)" }, children: [
2452
3783
  { id: "tools", icon: "auto_fix_high", label: "Prompt" },
2453
3784
  { id: "stage", icon: "palette", label: "Stage" },
3785
+ { id: "labs", icon: "science", label: "Labs" },
3786
+ ...workspaceTags ? [{ id: "tags", icon: "label", label: "Tags" }] : [],
2454
3787
  { id: "browse", icon: "photo_library", label: "Galerie" }
2455
- ].map((tab) => /* @__PURE__ */ jsxs11("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: [
2456
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[24px]", children: tab.icon }),
2457
- /* @__PURE__ */ jsx13("span", { className: "text-[10px] font-bold uppercase tracking-wide", children: tab.label })
3788
+ ].map((tab) => /* @__PURE__ */ jsxs18("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: [
3789
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[24px]", children: tab.icon }),
3790
+ /* @__PURE__ */ jsx20("span", { className: "text-[10px] font-bold uppercase tracking-wide", children: tab.label })
2458
3791
  ] }, tab.id)) })
2459
3792
  ] });
2460
3793
  if (mdMode) {
2461
- return /* @__PURE__ */ jsx13("div", { style: { position: "fixed", inset: 0, overflow: "hidden", background: "#0e0e0e" }, children: mobileRoot });
3794
+ return /* @__PURE__ */ jsx20("div", { style: { position: "fixed", inset: 0, overflow: "hidden", background: "#0e0e0e" }, children: mobileRoot });
2462
3795
  }
2463
3796
  return mobileRoot;
2464
3797
  }
@@ -2466,17 +3799,17 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2466
3799
  const tlScale = Math.min(window.innerWidth / 920, window.innerHeight / 520);
2467
3800
  const tlW = 920;
2468
3801
  const tlH = 520;
2469
- return /* @__PURE__ */ jsx13("div", { style: { position: "fixed", inset: 0, background: "#0e0e0e", display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden", ...hcStyle || {} }, children: /* @__PURE__ */ jsxs11("div", { style: { width: tlW, height: tlH, transform: `scale(${tlScale})`, transformOrigin: "center center", display: "flex", flexDirection: "row", color: "#fff", overflow: "hidden", borderRadius: 0 }, children: [
2470
- /* @__PURE__ */ jsxs11("div", { style: { width: 320, height: tlH, display: "flex", flexDirection: "column", borderRight: "1px solid rgba(255,255,255,0.05)", background: "#000", flexShrink: 0 }, children: [
2471
- /* @__PURE__ */ jsxs11("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: [
2472
- /* @__PURE__ */ jsx13(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
2473
- /* @__PURE__ */ jsx13(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" }] }),
2474
- /* @__PURE__ */ jsx13("div", { style: { flex: 1 } }),
2475
- /* @__PURE__ */ jsx13("button", { onClick: toggleContrast, style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: highContrast ? "light_mode" : "dark_mode" }) }),
2476
- /* @__PURE__ */ jsx13("button", { onClick: () => setShowStart(true), style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "apps" }) })
3802
+ return /* @__PURE__ */ jsx20("div", { style: { position: "fixed", inset: 0, background: "#0e0e0e", display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden", ...hcStyle || {} }, children: /* @__PURE__ */ jsxs18("div", { style: { width: tlW, height: tlH, transform: `scale(${tlScale})`, transformOrigin: "center center", display: "flex", flexDirection: "row", color: "#fff", overflow: "hidden", borderRadius: 0 }, children: [
3803
+ /* @__PURE__ */ jsxs18("div", { style: { width: 320, height: tlH, display: "flex", flexDirection: "column", borderRight: "1px solid rgba(255,255,255,0.05)", background: "#000", flexShrink: 0 }, children: [
3804
+ /* @__PURE__ */ jsxs18("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: [
3805
+ /* @__PURE__ */ jsx20(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
3806
+ /* @__PURE__ */ jsx20(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" }] }),
3807
+ /* @__PURE__ */ jsx20("div", { style: { flex: 1 } }),
3808
+ /* @__PURE__ */ jsx20("button", { onClick: toggleContrast, style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: highContrast ? "light_mode" : "dark_mode" }) }),
3809
+ /* @__PURE__ */ jsx20("button", { onClick: () => setShowStart(true), style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "apps" }) })
2477
3810
  ] }),
2478
- /* @__PURE__ */ jsx13("div", { style: { padding: "12px 12px 8px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs11("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: [
2479
- /* @__PURE__ */ jsx13(
3811
+ /* @__PURE__ */ jsx20("div", { style: { padding: "12px 12px 8px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs18("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: [
3812
+ /* @__PURE__ */ jsx20(
2480
3813
  "textarea",
2481
3814
  {
2482
3815
  value: activePrompt,
@@ -2485,27 +3818,27 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2485
3818
  placeholder: "Prompt eingeben..."
2486
3819
  }
2487
3820
  ),
2488
- activePrompt && /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 15 }, children: "close" }) })
3821
+ activePrompt && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 15 }, children: "close" }) })
2489
3822
  ] }) }),
2490
- /* @__PURE__ */ jsx13("div", { style: { padding: "0 12px 10px", flexShrink: 0 }, children: /* @__PURE__ */ jsx13(
3823
+ /* @__PURE__ */ jsx20("div", { style: { padding: "0 12px 10px", flexShrink: 0 }, children: /* @__PURE__ */ jsx20(
2491
3824
  "button",
2492
3825
  {
2493
3826
  onClick: () => handleGenerateImage(),
2494
3827
  disabled: !activePrompt.trim() || isGenerating,
2495
3828
  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" },
2496
- children: isGenerating ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
2497
- /* @__PURE__ */ jsx13("div", { style: { width: 14, height: 14, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
2498
- /* @__PURE__ */ jsx13("span", { children: "Generiere..." })
2499
- ] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
2500
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "bolt" }),
2501
- /* @__PURE__ */ jsx13("span", { children: "Generieren" })
3829
+ children: isGenerating ? /* @__PURE__ */ jsxs18(Fragment9, { children: [
3830
+ /* @__PURE__ */ jsx20("div", { style: { width: 14, height: 14, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
3831
+ /* @__PURE__ */ jsx20("span", { children: "Generiere..." })
3832
+ ] }) : /* @__PURE__ */ jsxs18(Fragment9, { children: [
3833
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "bolt" }),
3834
+ /* @__PURE__ */ jsx20("span", { children: "Generieren" })
2502
3835
  ] })
2503
3836
  }
2504
3837
  ) }),
2505
- /* @__PURE__ */ jsx13("div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ jsx13(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }) })
3838
+ /* @__PURE__ */ jsx20("div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ jsx20(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }) })
2506
3839
  ] }),
2507
- /* @__PURE__ */ jsxs11("div", { style: { flex: 1, height: tlH, display: "flex", flexDirection: "column", background: "#0b0b0b" }, children: [
2508
- /* @__PURE__ */ jsx13(
3840
+ /* @__PURE__ */ jsxs18("div", { style: { flex: 1, height: tlH, display: "flex", flexDirection: "column", background: "#0b0b0b" }, children: [
3841
+ /* @__PURE__ */ jsx20(
2509
3842
  "div",
2510
3843
  {
2511
3844
  style: { flex: 1, padding: 16, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" },
@@ -2517,26 +3850,26 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2517
3850
  else if (dx > 50) goToPrev();
2518
3851
  setTouchStartX(null);
2519
3852
  },
2520
- children: /* @__PURE__ */ jsxs11("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: [
2521
- currentResult?.status === "processing" && /* @__PURE__ */ jsxs11("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
2522
- /* @__PURE__ */ jsx13("div", { style: { width: 36, height: 36, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
2523
- /* @__PURE__ */ jsx13("span", { style: { fontSize: 10, color: "rgba(255,255,255,0.4)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
3853
+ children: /* @__PURE__ */ jsxs18("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: [
3854
+ currentResult?.status === "processing" && /* @__PURE__ */ jsxs18("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
3855
+ /* @__PURE__ */ jsx20("div", { style: { width: 36, height: 36, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
3856
+ /* @__PURE__ */ jsx20("span", { style: { fontSize: 10, color: "rgba(255,255,255,0.4)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
2524
3857
  ] }),
2525
- currentResult?.status === "error" && /* @__PURE__ */ jsxs11("div", { style: { padding: 24, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
2526
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 32, color: "#f87171" }, children: "warning" }),
2527
- /* @__PURE__ */ jsx13("p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: currentResult.error?.message }),
2528
- /* @__PURE__ */ jsx13("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" })
3858
+ currentResult?.status === "error" && /* @__PURE__ */ jsxs18("div", { style: { padding: 24, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
3859
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 32, color: "#f87171" }, children: "warning" }),
3860
+ /* @__PURE__ */ jsx20("p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: currentResult.error?.message }),
3861
+ /* @__PURE__ */ jsx20("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" })
2529
3862
  ] }),
2530
- currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ jsx13("img", { src: currentResult.base64, style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain" } }),
2531
- !currentResult && /* @__PURE__ */ jsxs11("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 8, opacity: 0.1 }, children: [
2532
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 64 }, children: "palette" }),
2533
- /* @__PURE__ */ jsx13("span", { style: { fontSize: 11, fontWeight: "bold", textTransform: "uppercase", letterSpacing: "0.2em" }, children: "Avatar Architect" })
3863
+ currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ jsx20("img", { src: currentResult.base64, style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain" } }),
3864
+ !currentResult && /* @__PURE__ */ jsxs18("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 8, opacity: 0.1 }, children: [
3865
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 64 }, children: "palette" }),
3866
+ /* @__PURE__ */ jsx20("span", { style: { fontSize: 11, fontWeight: "bold", textTransform: "uppercase", letterSpacing: "0.2em" }, children: "Avatar Architect" })
2534
3867
  ] }),
2535
- currentResult?.status === "done" && /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "fullscreen" }) }),
2536
- history.length > 1 && currentResult && /* @__PURE__ */ jsxs11(Fragment4, { children: [
2537
- /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_left" }) }),
2538
- /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_right" }) }),
2539
- /* @__PURE__ */ jsxs11("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: [
3868
+ currentResult?.status === "done" && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "fullscreen" }) }),
3869
+ history.length > 1 && currentResult && /* @__PURE__ */ jsxs18(Fragment9, { children: [
3870
+ /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_left" }) }),
3871
+ /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_right" }) }),
3872
+ /* @__PURE__ */ jsxs18("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: [
2540
3873
  currentIndex + 1,
2541
3874
  " / ",
2542
3875
  history.length
@@ -2545,41 +3878,57 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2545
3878
  ] })
2546
3879
  }
2547
3880
  ),
2548
- currentResult?.status === "done" && /* @__PURE__ */ jsxs11("div", { style: { padding: "0 16px 16px", display: "flex", gap: 8, flexShrink: 0 }, children: [
2549
- /* @__PURE__ */ jsxs11("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: [
2550
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "replay" }),
2551
- /* @__PURE__ */ jsx13("span", { children: "Prompt" })
3881
+ currentResult?.status === "done" && /* @__PURE__ */ jsxs18("div", { style: { padding: "0 16px 16px", display: "flex", gap: 8, flexShrink: 0 }, children: [
3882
+ /* @__PURE__ */ jsxs18("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: [
3883
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "replay" }),
3884
+ /* @__PURE__ */ jsx20("span", { children: "Prompt" })
2552
3885
  ] }),
2553
- /* @__PURE__ */ jsxs11("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: [
2554
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "auto_fix_high" }),
2555
- /* @__PURE__ */ jsx13("span", { children: "Referenz" })
3886
+ /* @__PURE__ */ jsxs18("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: [
3887
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "auto_fix_high" }),
3888
+ /* @__PURE__ */ jsx20("span", { children: "Referenz" })
2556
3889
  ] }),
2557
- /* @__PURE__ */ jsxs11("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: [
2558
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "download" }),
2559
- /* @__PURE__ */ jsx13("span", { children: "Laden" })
3890
+ /* @__PURE__ */ jsxs18("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: [
3891
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "download" }),
3892
+ /* @__PURE__ */ jsx20("span", { children: "Laden" })
2560
3893
  ] })
2561
3894
  ] })
2562
3895
  ] })
2563
3896
  ] }) });
2564
3897
  }
2565
- return /* @__PURE__ */ jsxs11("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", style: hcStyle, children: [
2566
- /* @__PURE__ */ jsx13("div", { className: "absolute top-2 right-2 z-50", children: /* @__PURE__ */ jsx13("button", { onClick: () => setShowStart(true), className: "text-white/10 hover:text-white/30 transition-colors text-[10px]", children: "\u21C4" }) }),
2567
- /* @__PURE__ */ jsxs11("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: [
2568
- /* @__PURE__ */ jsxs11("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
2569
- !isLeftCollapsed && /* @__PURE__ */ jsxs11("div", { className: "flex flex-1 gap-1", children: [
2570
- workspaceTags && /* @__PURE__ */ jsxs11("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: [
2571
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
3898
+ return /* @__PURE__ */ jsxs18("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", style: hcStyle, children: [
3899
+ /* @__PURE__ */ jsx20("div", { className: "absolute top-2 right-2 z-50", children: /* @__PURE__ */ jsx20("button", { onClick: () => setShowStart(true), className: "text-white/10 hover:text-white/30 transition-colors text-[10px]", children: "\u21C4" }) }),
3900
+ /* @__PURE__ */ jsxs18("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: [
3901
+ /* @__PURE__ */ jsxs18("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
3902
+ !isLeftCollapsed && /* @__PURE__ */ jsxs18("div", { className: "flex flex-1 gap-1", children: [
3903
+ workspaceTags && /* @__PURE__ */ jsxs18("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: [
3904
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
2572
3905
  "Prompt"
2573
3906
  ] }),
2574
- /* @__PURE__ */ jsxs11("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: [
2575
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
3907
+ /* @__PURE__ */ jsxs18("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: [
3908
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
2576
3909
  "Hierarchie"
2577
- ] })
3910
+ ] }),
3911
+ workspaceTags && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "label" }) })
2578
3912
  ] }),
2579
- /* @__PURE__ */ jsx13("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" })
3913
+ /* @__PURE__ */ jsx20("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" })
2580
3914
  ] }),
2581
- !isLeftCollapsed && /* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-hidden relative", children: [
2582
- leftTab === "hierarchy" && /* @__PURE__ */ jsx13("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx13(
3915
+ !isLeftCollapsed && /* @__PURE__ */ jsxs18("div", { className: "flex-1 overflow-hidden relative", children: [
3916
+ activeTab === "tags" && workspaceTags && /* @__PURE__ */ jsx20(
3917
+ TagManagerPanel,
3918
+ {
3919
+ workspaceTags,
3920
+ onTagCreate: handleTagCreate,
3921
+ onTagUpdate: handleTagUpdate,
3922
+ onTagDelete: handleTagDelete,
3923
+ onTagReorder: handleTagReorder,
3924
+ onTagMove: handleTagMove
3925
+ }
3926
+ ),
3927
+ activeTab === "tags" && !workspaceTags && /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-center h-full p-8 text-center", children: /* @__PURE__ */ jsxs18("div", { children: [
3928
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[40px] text-white/10 block mb-3", children: "label_off" }),
3929
+ /* @__PURE__ */ jsx20("p", { className: "text-[11px] text-white/20", children: "Erst Workspace importieren um Tags zu verwalten." })
3930
+ ] }) }),
3931
+ leftTab === "hierarchy" && activeTab !== "tags" && /* @__PURE__ */ jsx20("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx20(
2583
3932
  ListView,
2584
3933
  {
2585
3934
  nodes,
@@ -2604,75 +3953,111 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2604
3953
  isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
2605
3954
  }
2606
3955
  ) }),
2607
- leftTab === "prompt" && workspaceTags && /* @__PURE__ */ jsx13(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 })
3956
+ leftTab === "prompt" && workspaceTags && activeTab !== "tags" && /* @__PURE__ */ jsx20(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 })
2608
3957
  ] })
2609
3958
  ] }),
2610
- !isLeftCollapsed && /* @__PURE__ */ jsx13("div", { onMouseDown: startLeftResize, className: "w-1 shrink-0 cursor-col-resize hover:bg-white/20 active:bg-white/30 transition-colors", style: { background: "transparent" } }),
2611
- /* @__PURE__ */ jsxs11("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
2612
- /* @__PURE__ */ jsxs11("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
2613
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5", children: [
2614
- /* @__PURE__ */ jsx13(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
2615
- /* @__PURE__ */ jsx13(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" }] })
3959
+ !isLeftCollapsed && /* @__PURE__ */ jsx20("div", { onMouseDown: startLeftResize, className: "w-1 shrink-0 cursor-col-resize hover:bg-white/20 active:bg-white/30 transition-colors", style: { background: "transparent" } }),
3960
+ /* @__PURE__ */ jsxs18("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
3961
+ /* @__PURE__ */ jsxs18("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
3962
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-1.5", children: [
3963
+ /* @__PURE__ */ jsx20(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
3964
+ /* @__PURE__ */ jsx20(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" }] })
2616
3965
  ] }),
2617
- /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
2618
- activeReferenceThumbnail ? /* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden", style: { height: 28 }, children: [
2619
- /* @__PURE__ */ jsx13("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
2620
- /* @__PURE__ */ jsx13("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
2621
- /* @__PURE__ */ jsx13("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 hover:text-white/80 transition-colors", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
2622
- ] }) : /* @__PURE__ */ jsxs11("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: [
2623
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
2624
- /* @__PURE__ */ jsx13("span", { children: "Ref" })
3966
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-1 mx-auto", children: [
3967
+ /* @__PURE__ */ jsx20(
3968
+ "button",
3969
+ {
3970
+ onClick: () => setMiddlePanel("stage"),
3971
+ 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"}`,
3972
+ children: "Stage"
3973
+ }
3974
+ ),
3975
+ /* @__PURE__ */ jsx20(
3976
+ "button",
3977
+ {
3978
+ onClick: () => setMiddlePanel("labs"),
3979
+ 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"}`,
3980
+ children: "Labs"
3981
+ }
3982
+ )
3983
+ ] }),
3984
+ /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-2", children: [
3985
+ activeReferenceThumbnail ? /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden", style: { height: 28 }, children: [
3986
+ /* @__PURE__ */ jsx20("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
3987
+ /* @__PURE__ */ jsx20("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
3988
+ /* @__PURE__ */ jsx20("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 hover:text-white/80 transition-colors", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
3989
+ ] }) : /* @__PURE__ */ jsxs18("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: [
3990
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
3991
+ /* @__PURE__ */ jsx20("span", { children: "Ref" })
2625
3992
  ] }),
2626
- /* @__PURE__ */ jsx13("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
2627
- /* @__PURE__ */ jsx13(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
3993
+ /* @__PURE__ */ jsx20("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
3994
+ /* @__PURE__ */ jsx20(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
2628
3995
  ] })
2629
3996
  ] }),
2630
- /* @__PURE__ */ jsxs11("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
2631
- !isPromptCollapsed && /* @__PURE__ */ jsx13("div", { className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ jsxs11("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
2632
- /* @__PURE__ */ jsx13("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..." }),
2633
- activePrompt && !isSynthesizing && /* @__PURE__ */ jsx13("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__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
3997
+ /* @__PURE__ */ jsxs18("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
3998
+ !isPromptCollapsed && /* @__PURE__ */ jsx20("div", { className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ jsxs18("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
3999
+ /* @__PURE__ */ jsx20("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..." }),
4000
+ activePrompt && !isSynthesizing && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
2634
4001
  ] }) }),
2635
- /* @__PURE__ */ jsx13("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsxs11("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: [
2636
- isGenerating && currentResult?.status === "done" && /* @__PURE__ */ jsxs11("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: [
2637
- /* @__PURE__ */ jsx13("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
2638
- /* @__PURE__ */ jsx13("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
4002
+ middlePanel === "labs" ? /* @__PURE__ */ jsx20("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx20(LabsTab, { services: labServices, onResult: (item) => {
4003
+ const frame = item.frames[0];
4004
+ if (frame?.base64) setCurrentResult(frameToGeneration(frame, item));
4005
+ } }) }) : /* @__PURE__ */ jsx20("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsxs18("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: [
4006
+ isGenerating && currentResult?.status === "done" && /* @__PURE__ */ jsxs18("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: [
4007
+ /* @__PURE__ */ jsx20("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
4008
+ /* @__PURE__ */ jsx20("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
2639
4009
  ] }),
2640
- currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-4", children: [
2641
- /* @__PURE__ */ jsx13("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
2642
- /* @__PURE__ */ jsx13("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
2643
- ] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs11("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
2644
- /* @__PURE__ */ jsx13("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
2645
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-2", children: [
2646
- /* @__PURE__ */ jsx13("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
2647
- /* @__PURE__ */ jsx13("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
4010
+ currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-4", children: [
4011
+ /* @__PURE__ */ jsx20("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
4012
+ /* @__PURE__ */ jsx20("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
4013
+ ] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs18("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
4014
+ /* @__PURE__ */ jsx20("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
4015
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-2", children: [
4016
+ /* @__PURE__ */ jsx20("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
4017
+ /* @__PURE__ */ jsx20("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
2648
4018
  ] }),
2649
- /* @__PURE__ */ jsx13(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
2650
- ] }) : /* @__PURE__ */ jsxs11("div", { className: "h-full w-full relative flex items-center justify-center", children: [
2651
- /* @__PURE__ */ jsx13("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
2652
- /* @__PURE__ */ jsxs11("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: [
2653
- /* @__PURE__ */ jsx13(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
2654
- /* @__PURE__ */ jsx13(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
2655
- /* @__PURE__ */ jsx13(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
4019
+ /* @__PURE__ */ jsx20(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
4020
+ ] }) : /* @__PURE__ */ jsxs18("div", { className: "h-full w-full relative flex items-center justify-center", children: [
4021
+ /* @__PURE__ */ jsx20("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
4022
+ /* @__PURE__ */ jsxs18("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: [
4023
+ /* @__PURE__ */ jsx20(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
4024
+ /* @__PURE__ */ jsx20(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
4025
+ /* @__PURE__ */ jsx20(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
2656
4026
  ] })
2657
- ] }) : /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
2658
- /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
2659
- /* @__PURE__ */ jsx13("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
4027
+ ] }) : /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
4028
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
4029
+ /* @__PURE__ */ jsx20("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
2660
4030
  ] })
2661
4031
  ] }) })
2662
4032
  ] })
2663
4033
  ] }),
2664
- !isRightCollapsed && /* @__PURE__ */ jsx13("div", { onMouseDown: startRightResize, className: "w-1 shrink-0 cursor-col-resize hover:bg-white/20 active:bg-white/30 transition-colors", style: { background: "transparent" } }),
2665
- /* @__PURE__ */ jsxs11("div", { className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", style: { width: isRightCollapsed ? 60 : rightPanelWidth, transition: "none" }, children: [
2666
- /* @__PURE__ */ jsxs11("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
2667
- /* @__PURE__ */ jsx13("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup", "sync"].map((tab) => /* @__PURE__ */ jsx13("button", { onClick: () => {
4034
+ !isRightCollapsed && /* @__PURE__ */ jsx20("div", { onMouseDown: startRightResize, className: "w-1 shrink-0 cursor-col-resize hover:bg-white/20 active:bg-white/30 transition-colors", style: { background: "transparent" } }),
4035
+ /* @__PURE__ */ jsxs18("div", { className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", style: { width: isRightCollapsed ? 60 : rightPanelWidth, transition: "none" }, children: [
4036
+ /* @__PURE__ */ jsxs18("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
4037
+ /* @__PURE__ */ jsx20("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup", "sync", "tags"].map((tab) => /* @__PURE__ */ jsx20("button", { onClick: () => {
2668
4038
  setActiveTab(tab);
2669
4039
  setIsRightCollapsed(false);
2670
- }, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : tab === "setup" ? "settings" : "cloud_sync" }) }, tab)) }),
2671
- /* @__PURE__ */ jsx13("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
4040
+ }, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ jsx20("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)) }),
4041
+ /* @__PURE__ */ jsx20("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
2672
4042
  ] }),
2673
- !isRightCollapsed && /* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-hidden relative", children: [
2674
- activeTab === "history" && /* @__PURE__ */ jsx13(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
2675
- activeTab === "gallery" && /* @__PURE__ */ jsx13(
4043
+ !isRightCollapsed && /* @__PURE__ */ jsxs18("div", { className: "flex-1 overflow-hidden relative", children: [
4044
+ activeTab === "tags" && workspaceTags && /* @__PURE__ */ jsx20(
4045
+ TagManagerPanel,
4046
+ {
4047
+ workspaceTags,
4048
+ onTagCreate: handleTagCreate,
4049
+ onTagUpdate: handleTagUpdate,
4050
+ onTagDelete: handleTagDelete,
4051
+ onTagReorder: handleTagReorder,
4052
+ onTagMove: handleTagMove
4053
+ }
4054
+ ),
4055
+ activeTab === "tags" && !workspaceTags && /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-center h-full p-8 text-center", children: /* @__PURE__ */ jsxs18("div", { children: [
4056
+ /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[40px] text-white/10 block mb-3", children: "label_off" }),
4057
+ /* @__PURE__ */ jsx20("p", { className: "text-[11px] text-white/20", children: "Erst Workspace importieren um Tags zu verwalten." })
4058
+ ] }) }),
4059
+ activeTab === "history" && /* @__PURE__ */ jsx20(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
4060
+ activeTab === "gallery" && /* @__PURE__ */ jsx20(
2676
4061
  MediaLibrary,
2677
4062
  {
2678
4063
  items: galleryItems,
@@ -2686,9 +4071,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2686
4071
  onGenerateReference: (item) => handleGenerateImage(item.prompt || activePrompt, item.mediaId, void 0, { silent: true })
2687
4072
  }
2688
4073
  ),
2689
- activeTab === "inspect" && /* @__PURE__ */ jsx13(InspectPanel, { currentResult, history, onSelect: setCurrentResult }),
2690
- activeTab === "setup" && /* @__PURE__ */ jsx13(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
2691
- activeTab === "sync" && /* @__PURE__ */ jsx13(
4074
+ activeTab === "inspect" && /* @__PURE__ */ jsx20(InspectPanel, { currentResult, history, onSelect: setCurrentResult }),
4075
+ activeTab === "setup" && /* @__PURE__ */ jsx20(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
4076
+ activeTab === "sync" && /* @__PURE__ */ jsx20(
2692
4077
  ProjectSyncTab,
2693
4078
  {
2694
4079
  onProjectExport: handleProjectExport,
@@ -2710,7 +4095,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
2710
4095
  }
2711
4096
 
2712
4097
  // src/index.ts
2713
- var LIB_VERSION = "1.1.4";
4098
+ var LIB_VERSION = "1.2.1";
2714
4099
  export {
2715
4100
  AvatarArchitectApp,
2716
4101
  CollapsibleCard,
@@ -2720,6 +4105,12 @@ export {
2720
4105
  HistoryPanel,
2721
4106
  InspectPanel,
2722
4107
  LIB_VERSION,
4108
+ LabBlend,
4109
+ LabCompare,
4110
+ LabImagePicker,
4111
+ LabLoop,
4112
+ LabRemix,
4113
+ LabsTab,
2723
4114
  ListView,
2724
4115
  MediaLibrary,
2725
4116
  PillButton,
@@ -2727,15 +4118,25 @@ export {
2727
4118
  PromptTab,
2728
4119
  SectionLabel,
2729
4120
  SetupPanel,
4121
+ TagManagerPanel,
4122
+ autoLabel,
4123
+ buildBlendInstruction,
4124
+ buildCompareInstruction,
2730
4125
  buildFallbackPrompt,
2731
4126
  buildGenerationPrompt,
2732
4127
  buildImageGenerationOptions,
4128
+ buildLoopInstruction,
2733
4129
  buildPromptTabPayload,
4130
+ buildReferenceImageMediaIds,
4131
+ buildRemixInstruction,
4132
+ buildScanInstruction,
2734
4133
  cleanAiResponse,
2735
4134
  createFlowServices,
2736
4135
  exportProjectToZip,
2737
4136
  formatTreeToMarkdown,
4137
+ frameToGeneration,
2738
4138
  getFormattedTimestamp,
4139
+ groupGenerationsToLabItems,
2739
4140
  importProjectFromZip,
2740
4141
  injectXMPMetadata,
2741
4142
  interpretSdkError,