@rslsp1/fa-app-tools 0.1.14 → 1.0.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.d.mts CHANGED
@@ -4,11 +4,13 @@ import { Node, Edge } from '@xyflow/react';
4
4
 
5
5
  declare function useOnClickOutside(ref: RefObject<HTMLElement | null>, handler: (e: MouseEvent | TouchEvent) => void): void;
6
6
 
7
+ interface TagOption {
8
+ label: string;
9
+ value: string;
10
+ }
7
11
  interface WorkspaceTags {
8
- by_category: Record<string, string[]>;
9
- all: Array<{
10
- label: string;
11
- value: string;
12
+ by_category: Record<string, TagOption[]>;
13
+ all: Array<TagOption & {
12
14
  category: string;
13
15
  }>;
14
16
  }
@@ -69,6 +71,11 @@ declare function buildGenerationPrompt(hierarchyText: string, mode?: 'literal' |
69
71
  declare function buildFallbackPrompt(hierarchyText: string): string;
70
72
  declare function cleanAiResponse(text: string): string;
71
73
  declare function buildImageGenerationOptions(prompt: string, aspectRatio: string, model: string, referenceMediaId?: string): Record<string, any>;
74
+ declare function buildPromptTabPayload(selectedValues: string[], instructions: string, treeText?: string): string;
75
+ declare function parsePromptResponse(raw: string): {
76
+ prompt: string;
77
+ feedback: string | null;
78
+ };
72
79
  declare function interpretSdkError(err: any): Error;
73
80
 
74
81
  interface ExtractedCharacter {
@@ -189,4 +196,12 @@ interface AvatarArchitectAppProps {
189
196
  }
190
197
  declare function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }: AvatarArchitectAppProps): react_jsx_runtime.JSX.Element;
191
198
 
192
- export { AvatarArchitectApp, type AvatarArchitectAppProps, CompactDropdown, type ExtractedCharacter, FaToolsBadge, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectSettings, SectionLabel, SetupPanel, type WorkspaceTags, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, cleanAiResponse, exportProjectToZip, formatTreeToMarkdown, getFormattedTimestamp, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, useKeyboardNavigation, useOnClickOutside };
199
+ interface PromptTabProps {
200
+ workspaceTags: WorkspaceTags;
201
+ onGenerate: (selectedValues: string[], instructions: string) => Promise<void>;
202
+ isGenerating: boolean;
203
+ feedback: string | null;
204
+ }
205
+ declare const PromptTab: React.FC<PromptTabProps>;
206
+
207
+ export { AvatarArchitectApp, type AvatarArchitectAppProps, CompactDropdown, type ExtractedCharacter, FaToolsBadge, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectSettings, PromptTab, SectionLabel, SetupPanel, type TagOption, type WorkspaceTags, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildPromptTabPayload, cleanAiResponse, exportProjectToZip, formatTreeToMarkdown, getFormattedTimestamp, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
package/dist/index.d.ts CHANGED
@@ -4,11 +4,13 @@ import { Node, Edge } from '@xyflow/react';
4
4
 
5
5
  declare function useOnClickOutside(ref: RefObject<HTMLElement | null>, handler: (e: MouseEvent | TouchEvent) => void): void;
6
6
 
7
+ interface TagOption {
8
+ label: string;
9
+ value: string;
10
+ }
7
11
  interface WorkspaceTags {
8
- by_category: Record<string, string[]>;
9
- all: Array<{
10
- label: string;
11
- value: string;
12
+ by_category: Record<string, TagOption[]>;
13
+ all: Array<TagOption & {
12
14
  category: string;
13
15
  }>;
14
16
  }
@@ -69,6 +71,11 @@ declare function buildGenerationPrompt(hierarchyText: string, mode?: 'literal' |
69
71
  declare function buildFallbackPrompt(hierarchyText: string): string;
70
72
  declare function cleanAiResponse(text: string): string;
71
73
  declare function buildImageGenerationOptions(prompt: string, aspectRatio: string, model: string, referenceMediaId?: string): Record<string, any>;
74
+ declare function buildPromptTabPayload(selectedValues: string[], instructions: string, treeText?: string): string;
75
+ declare function parsePromptResponse(raw: string): {
76
+ prompt: string;
77
+ feedback: string | null;
78
+ };
72
79
  declare function interpretSdkError(err: any): Error;
73
80
 
74
81
  interface ExtractedCharacter {
@@ -189,4 +196,12 @@ interface AvatarArchitectAppProps {
189
196
  }
190
197
  declare function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }: AvatarArchitectAppProps): react_jsx_runtime.JSX.Element;
191
198
 
192
- export { AvatarArchitectApp, type AvatarArchitectAppProps, CompactDropdown, type ExtractedCharacter, FaToolsBadge, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectSettings, SectionLabel, SetupPanel, type WorkspaceTags, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, cleanAiResponse, exportProjectToZip, formatTreeToMarkdown, getFormattedTimestamp, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, useKeyboardNavigation, useOnClickOutside };
199
+ interface PromptTabProps {
200
+ workspaceTags: WorkspaceTags;
201
+ onGenerate: (selectedValues: string[], instructions: string) => Promise<void>;
202
+ isGenerating: boolean;
203
+ feedback: string | null;
204
+ }
205
+ declare const PromptTab: React.FC<PromptTabProps>;
206
+
207
+ export { AvatarArchitectApp, type AvatarArchitectAppProps, CompactDropdown, type ExtractedCharacter, FaToolsBadge, GLOBAL_STYLES, type Generation, HistoryPanel, InspectPanel, ListView, type MediaItem, MediaLibrary, PillButton, type ProjectSettings, PromptTab, SectionLabel, SetupPanel, type TagOption, type WorkspaceTags, buildFallbackPrompt, buildGenerationPrompt, buildImageGenerationOptions, buildPromptTabPayload, cleanAiResponse, exportProjectToZip, formatTreeToMarkdown, getFormattedTimestamp, importProjectFromZip, injectXMPMetadata, interpretSdkError, parsePromptFile, parsePromptResponse, useKeyboardNavigation, useOnClickOutside };
package/dist/index.js CHANGED
@@ -39,11 +39,13 @@ __export(index_exports, {
39
39
  ListView: () => ListView,
40
40
  MediaLibrary: () => MediaLibrary,
41
41
  PillButton: () => PillButton,
42
+ PromptTab: () => PromptTab,
42
43
  SectionLabel: () => SectionLabel,
43
44
  SetupPanel: () => SetupPanel,
44
45
  buildFallbackPrompt: () => buildFallbackPrompt,
45
46
  buildGenerationPrompt: () => buildGenerationPrompt,
46
47
  buildImageGenerationOptions: () => buildImageGenerationOptions,
48
+ buildPromptTabPayload: () => buildPromptTabPayload,
47
49
  cleanAiResponse: () => cleanAiResponse,
48
50
  exportProjectToZip: () => exportProjectToZip,
49
51
  formatTreeToMarkdown: () => formatTreeToMarkdown,
@@ -52,6 +54,7 @@ __export(index_exports, {
52
54
  injectXMPMetadata: () => injectXMPMetadata,
53
55
  interpretSdkError: () => interpretSdkError,
54
56
  parsePromptFile: () => parsePromptFile,
57
+ parsePromptResponse: () => parsePromptResponse,
55
58
  useKeyboardNavigation: () => useKeyboardNavigation,
56
59
  useOnClickOutside: () => useOnClickOutside
57
60
  });
@@ -352,6 +355,33 @@ function buildImageGenerationOptions(prompt, aspectRatio, model, referenceMediaI
352
355
  }
353
356
  return options;
354
357
  }
358
+ function buildPromptTabPayload(selectedValues, instructions, treeText) {
359
+ const parts = [];
360
+ if (treeText) parts.push(`HIERARCHY:
361
+ ${treeText}`);
362
+ if (selectedValues.length > 0) parts.push(`SELECTED TAGS:
363
+ ${selectedValues.join(", ")}`);
364
+ if (instructions.trim()) parts.push(`ADDITIONAL INSTRUCTIONS:
365
+ ${instructions.trim()}`);
366
+ return [
367
+ "Create a high-quality image generation prompt based on the following inputs. Translate everything to English.",
368
+ `Return a JSON object with exactly two keys: "prompt" (the prompt string) and "feedback" (a short note on your choices in the user's language, or null).`,
369
+ "Output ONLY the JSON object, no markdown, no wrapping.",
370
+ "",
371
+ ...parts
372
+ ].join("\n");
373
+ }
374
+ function parsePromptResponse(raw) {
375
+ const cleaned = raw.replace(/^```json\s*/i, "").replace(/^```\s*/i, "").replace(/```$/i, "").trim();
376
+ try {
377
+ const parsed = JSON.parse(cleaned);
378
+ if (typeof parsed?.prompt === "string") {
379
+ return { prompt: parsed.prompt.trim(), feedback: parsed.feedback ?? null };
380
+ }
381
+ } catch {
382
+ }
383
+ return { prompt: cleaned, feedback: null };
384
+ }
355
385
  function interpretSdkError(err) {
356
386
  const msg = err?.message || "Generierung fehlgeschlagen";
357
387
  if (msg.includes("PUBLIC_ERROR_SOMETHING_WENT_WRONG")) {
@@ -603,8 +633,8 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
603
633
  Object.entries(workspaceTags.by_category).map(([cat, tags]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-col gap-2", children: [
604
634
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-[8px] font-bold text-white/30 uppercase tracking-widest px-1", children: cat }),
605
635
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex flex-wrap gap-1.5", children: tags.map((t) => {
606
- const isActive = (currentResult.tags || []).includes(t);
607
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: () => onTagToggle?.(t), className: `px-2.5 py-1 rounded-lg text-[8px] font-bold uppercase transition-all border ${isActive ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_10px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/20 hover:text-white/50 hover:bg-white/10"}`, children: t }, t);
636
+ const isActive = (currentResult.tags || []).includes(t.label);
637
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: () => onTagToggle?.(t.label), className: `px-2.5 py-1 rounded-lg text-[8px] font-bold uppercase transition-all border ${isActive ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_10px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/20 hover:text-white/50 hover:bg-white/10"}`, children: t.label }, t.label);
608
638
  }) })
609
639
  ] }, cat))
610
640
  ] })
@@ -816,11 +846,117 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
816
846
  }
817
847
 
818
848
  // src/components/AvatarArchitectApp.tsx
849
+ var import_react12 = require("react");
850
+ var import_react13 = require("motion/react");
851
+
852
+ // src/components/PromptTab.tsx
819
853
  var import_react10 = require("react");
820
854
  var import_react11 = require("motion/react");
821
855
  var import_jsx_runtime10 = require("react/jsx-runtime");
856
+ var PromptTab = ({ workspaceTags, onGenerate, isGenerating, feedback }) => {
857
+ const [selectedLabels, setSelectedLabels] = (0, import_react10.useState)(/* @__PURE__ */ new Set());
858
+ const [instructions, setInstructions] = (0, import_react10.useState)("");
859
+ const [showFeedback, setShowFeedback] = (0, import_react10.useState)(true);
860
+ const toggleTag = (label) => {
861
+ setSelectedLabels((prev) => {
862
+ const next = new Set(prev);
863
+ if (next.has(label)) next.delete(label);
864
+ else next.add(label);
865
+ return next;
866
+ });
867
+ };
868
+ const handleGenerate = () => {
869
+ const selectedValues = workspaceTags.all.filter((t) => selectedLabels.has(t.label)).map((t) => t.value);
870
+ onGenerate(selectedValues, instructions);
871
+ };
872
+ const categories = Object.entries(workspaceTags.by_category).filter(([, tags]) => tags.length > 0);
873
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "absolute inset-0 flex flex-col overflow-hidden", children: [
874
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 py-3 flex flex-col gap-4", children: [
875
+ categories.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-center justify-center py-16 gap-3 opacity-20", children: [
876
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[48px]", children: "label_off" }),
877
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { className: "text-[9px] font-bold uppercase tracking-widest text-center", children: [
878
+ "Keine Tags geladen.",
879
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("br", {}),
880
+ "Importiere ein Workspace-JSON im Setup-Tab."
881
+ ] })
882
+ ] }) : categories.map(([cat, tags]) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2", children: [
883
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionLabel, { children: cat }),
884
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-wrap gap-1", children: tags.map((t) => {
885
+ const active = selectedLabels.has(t.label);
886
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
887
+ "button",
888
+ {
889
+ onClick: () => toggleTag(t.label),
890
+ className: `px-2 py-1 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-all border ${active ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_8px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/30 hover:text-white/60 hover:bg-white/10"}`,
891
+ children: t.label
892
+ },
893
+ t.label
894
+ );
895
+ }) })
896
+ ] }, cat)),
897
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2 mt-2", children: [
898
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SectionLabel, { children: "Zus\xE4tzliche Anweisungen" }),
899
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
900
+ "textarea",
901
+ {
902
+ value: instructions,
903
+ onChange: (e) => setInstructions(e.target.value),
904
+ placeholder: "Weitere Vorgaben f\xFCr den AI-Prompt...",
905
+ className: "w-full bg-white/5 border border-white/10 rounded-xl p-3 text-[10px] text-white/70 placeholder-white/20 resize-none h-20 outline-none focus:border-white/20 dark-scrollbar"
906
+ }
907
+ )
908
+ ] })
909
+ ] }),
910
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "shrink-0 border-t border-white/5 p-3 flex flex-col gap-2", children: [
911
+ feedback && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col", children: [
912
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
913
+ "button",
914
+ {
915
+ onClick: () => setShowFeedback((p) => !p),
916
+ className: "flex items-center gap-1.5 text-[8px] font-bold uppercase text-amber-400/60 hover:text-amber-400 transition-colors mb-1",
917
+ children: [
918
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[12px]", children: "psychology" }),
919
+ "KI-Analyse",
920
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[12px] ml-auto", children: showFeedback ? "expand_less" : "expand_more" })
921
+ ]
922
+ }
923
+ ),
924
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react11.AnimatePresence, { children: showFeedback && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
925
+ import_react11.motion.div,
926
+ {
927
+ initial: { height: 0, opacity: 0 },
928
+ animate: { height: "auto", opacity: 1 },
929
+ exit: { height: 0, opacity: 0 },
930
+ className: "overflow-hidden",
931
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-[9px] text-amber-400/50 leading-relaxed bg-amber-500/5 border border-amber-500/10 rounded-xl p-2 italic", children: feedback })
932
+ }
933
+ ) })
934
+ ] }),
935
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
936
+ selectedLabels.size > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { className: "text-[8px] text-white/30 font-bold uppercase", children: [
937
+ selectedLabels.size,
938
+ " Tags gew\xE4hlt"
939
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[8px] text-white/20 italic", children: "Keine Tags gew\xE4hlt" }),
940
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
941
+ PillButton,
942
+ {
943
+ variant: "solid",
944
+ icon: "auto_fix_high",
945
+ loading: isGenerating,
946
+ disabled: selectedLabels.size === 0 && !instructions.trim(),
947
+ onClick: handleGenerate,
948
+ children: "Prompt bauen"
949
+ }
950
+ )
951
+ ] })
952
+ ] })
953
+ ] });
954
+ };
955
+
956
+ // src/components/AvatarArchitectApp.tsx
957
+ var import_jsx_runtime11 = require("react/jsx-runtime");
822
958
  function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }) {
823
- (0, import_react10.useEffect)(() => {
959
+ (0, import_react12.useEffect)(() => {
824
960
  const id = "flow-styles";
825
961
  if (!document.getElementById(id)) {
826
962
  const style = document.createElement("style");
@@ -829,27 +965,31 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
829
965
  document.head.appendChild(style);
830
966
  }
831
967
  }, []);
832
- const [nodes, setNodes] = (0, import_react10.useState)([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
833
- const [edges, setEdges] = (0, import_react10.useState)([]);
834
- const [history, setHistory] = (0, import_react10.useState)([]);
835
- const [galleryItems, setGalleryItems] = (0, import_react10.useState)([]);
836
- const [activePrompt, setActivePrompt] = (0, import_react10.useState)("");
837
- const [isSynthesizing, setIsSynthesizing] = (0, import_react10.useState)(false);
838
- const [activeGenerationsCount, setActiveGenerationsCount] = (0, import_react10.useState)(0);
839
- const [currentResult, setCurrentResult] = (0, import_react10.useState)(null);
840
- const [focusedNodeId, setFocusedNodeId] = (0, import_react10.useState)(null);
841
- const [activeTab, setActiveTab] = (0, import_react10.useState)("history");
842
- const [aspectRatio, setAspectRatio] = (0, import_react10.useState)("1:1");
843
- const [selectedModel, setSelectedModel] = (0, import_react10.useState)("\u{1F34C} Nano Banana Pro");
844
- const [seed, setSeed] = (0, import_react10.useState)(Math.floor(Math.random() * 1e6));
845
- const [seedMode, setSeedMode] = (0, import_react10.useState)("random");
846
- const [isLeftCollapsed, setIsLeftCollapsed] = (0, import_react10.useState)(false);
847
- const [isRightCollapsed, setIsRightCollapsed] = (0, import_react10.useState)(false);
848
- const [isPromptCollapsed, setIsPromptCollapsed] = (0, import_react10.useState)(false);
849
- const [projectActionState, setProjectActionState] = (0, import_react10.useState)("idle");
968
+ const [nodes, setNodes] = (0, import_react12.useState)([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
969
+ const [edges, setEdges] = (0, import_react12.useState)([]);
970
+ const [history, setHistory] = (0, import_react12.useState)([]);
971
+ const [galleryItems, setGalleryItems] = (0, import_react12.useState)([]);
972
+ const [activePrompt, setActivePrompt] = (0, import_react12.useState)("");
973
+ const [isSynthesizing, setIsSynthesizing] = (0, import_react12.useState)(false);
974
+ const [activeGenerationsCount, setActiveGenerationsCount] = (0, import_react12.useState)(0);
975
+ const [currentResult, setCurrentResult] = (0, import_react12.useState)(null);
976
+ const [focusedNodeId, setFocusedNodeId] = (0, import_react12.useState)(null);
977
+ const [leftTab, setLeftTab] = (0, import_react12.useState)("hierarchy");
978
+ const [promptFeedback, setPromptFeedback] = (0, import_react12.useState)(null);
979
+ const [isPromptTabGenerating, setIsPromptTabGenerating] = (0, import_react12.useState)(false);
980
+ const [activeTab, setActiveTab] = (0, import_react12.useState)("history");
981
+ const [aspectRatio, setAspectRatio] = (0, import_react12.useState)("1:1");
982
+ const [selectedModel, setSelectedModel] = (0, import_react12.useState)("\u{1F34C} Nano Banana Pro");
983
+ const [seed, setSeed] = (0, import_react12.useState)(Math.floor(Math.random() * 1e6));
984
+ const [seedMode, setSeedMode] = (0, import_react12.useState)("random");
985
+ const [isLeftCollapsed, setIsLeftCollapsed] = (0, import_react12.useState)(false);
986
+ const [isRightCollapsed, setIsRightCollapsed] = (0, import_react12.useState)(false);
987
+ const [isPromptCollapsed, setIsPromptCollapsed] = (0, import_react12.useState)(false);
988
+ const [projectActionState, setProjectActionState] = (0, import_react12.useState)("idle");
989
+ const [workspaceTags, setWorkspaceTags] = (0, import_react12.useState)(null);
850
990
  const isGenerating = activeGenerationsCount > 0;
851
991
  useKeyboardNavigation(history, currentResult, setCurrentResult);
852
- const getSubtreeFormat = (0, import_react10.useCallback)((nodeId, depth = 0) => {
992
+ const getSubtreeFormat = (0, import_react12.useCallback)((nodeId, depth = 0) => {
853
993
  const node = nodes.find((n) => n.id === nodeId);
854
994
  if (!node) return "";
855
995
  const childrenIds = edges.filter((e) => e.source === nodeId).map((e) => e.target);
@@ -857,7 +997,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
857
997
  return `${indent}- ${node.data.label || "(unbenannt)"}
858
998
  ` + childrenIds.map((id) => getSubtreeFormat(id, depth + 1)).join("");
859
999
  }, [nodes, edges]);
860
- const activePath = (0, import_react10.useMemo)(() => {
1000
+ const activePath = (0, import_react12.useMemo)(() => {
861
1001
  if (!focusedNodeId) return /* @__PURE__ */ new Set();
862
1002
  const path = /* @__PURE__ */ new Set([focusedNodeId]);
863
1003
  let currId = focusedNodeId;
@@ -910,16 +1050,32 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
910
1050
  const handleSynthesizePrompt = async (nodeId, autoGenerate = false) => {
911
1051
  setIsSynthesizing(true);
912
1052
  try {
913
- const prompt = await onGeneratePrompt(getSubtreeFormat(nodeId));
914
- setActivePrompt(prompt);
1053
+ const raw = await onGeneratePrompt(getSubtreeFormat(nodeId));
1054
+ setActivePrompt(raw);
915
1055
  setFocusedNodeId(nodeId);
916
- if (autoGenerate) handleGenerateImage(prompt, void 0, nodeId);
1056
+ if (autoGenerate) handleGenerateImage(raw, void 0, nodeId);
917
1057
  } catch {
918
1058
  setActivePrompt("Synthese-Fehler");
919
1059
  } finally {
920
1060
  setIsSynthesizing(false);
921
1061
  }
922
1062
  };
1063
+ const handlePromptTabGenerate = async (selectedValues, instructions) => {
1064
+ setIsPromptTabGenerating(true);
1065
+ setPromptFeedback(null);
1066
+ try {
1067
+ const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
1068
+ const payload = buildPromptTabPayload(selectedValues, instructions, treeText);
1069
+ const raw = await onGeneratePrompt(payload);
1070
+ const { prompt, feedback } = parsePromptResponse(raw);
1071
+ setActivePrompt(prompt);
1072
+ setPromptFeedback(feedback);
1073
+ } catch {
1074
+ setActivePrompt("Synthese-Fehler");
1075
+ } finally {
1076
+ setIsPromptTabGenerating(false);
1077
+ }
1078
+ };
923
1079
  const handleDownloadSingle = async () => {
924
1080
  if (!currentResult?.base64) return;
925
1081
  try {
@@ -975,58 +1131,100 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
975
1131
  const root = JSON.parse(ev.target?.result);
976
1132
  const rawTags = root.tags || root;
977
1133
  if (!rawTags?.by_category) return;
1134
+ const filtered = {};
1135
+ const EXCLUDED = ["pdf-export", "book.micro-edit-rules"];
1136
+ Object.entries(rawTags.by_category).forEach(([cat, items]) => {
1137
+ if (EXCLUDED.includes(cat) || !Array.isArray(items)) return;
1138
+ filtered[cat] = items.filter((t) => t && typeof t === "object" && t.label && t.value);
1139
+ });
1140
+ const filteredAll = (rawTags.all || []).filter((t) => t && !EXCLUDED.includes(t.category));
1141
+ setWorkspaceTags({ by_category: filtered, all: filteredAll });
978
1142
  } catch (err) {
979
1143
  console.error("Workspace Load failed", err);
980
1144
  }
981
1145
  };
982
1146
  reader.readAsText(file);
983
1147
  };
984
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", children: [
985
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react11.motion.div, { animate: { width: isLeftCollapsed ? 48 : 260 }, className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", children: [
986
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "h-14 px-4 border-b border-white/5 flex items-center justify-between shrink-0", children: [
987
- !isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] font-bold uppercase text-white/40", children: "Hierarchie" }),
988
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { onClick: () => setIsLeftCollapsed(!isLeftCollapsed), className: "material-symbols-outlined text-[18px] text-white/40 hover:text-white transition-all", children: isLeftCollapsed ? "chevron_right" : "chevron_left" })
1148
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", children: [
1149
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react13.motion.div, { animate: { width: isLeftCollapsed ? 48 : 260 }, className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", children: [
1150
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
1151
+ !isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-1 gap-1", children: [
1152
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1153
+ "button",
1154
+ {
1155
+ onClick: () => setLeftTab("hierarchy"),
1156
+ 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"}`,
1157
+ children: [
1158
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
1159
+ "Hierarchie"
1160
+ ]
1161
+ }
1162
+ ),
1163
+ workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1164
+ "button",
1165
+ {
1166
+ onClick: () => setLeftTab("prompt"),
1167
+ 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"}`,
1168
+ children: [
1169
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
1170
+ "Prompt"
1171
+ ]
1172
+ }
1173
+ )
1174
+ ] }),
1175
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => setIsLeftCollapsed(!isLeftCollapsed), className: "material-symbols-outlined text-[18px] text-white/40 hover:text-white transition-all w-10 flex items-center justify-center", children: isLeftCollapsed ? "chevron_right" : "chevron_left" })
989
1176
  ] }),
990
- !isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
991
- ListView,
992
- {
993
- nodes,
994
- edges,
995
- onNodeChange: (id, l) => setNodes((nds) => nds.map((n) => n.id === id ? { ...n, data: { ...n.data, label: l } } : n)),
996
- onAddChild: (pId) => {
997
- const newId = crypto.randomUUID();
998
- setNodes((nds) => [...nds, { id: newId, type: "custom", position: { x: 0, y: 0 }, data: { label: "", placeholder: "Konzept..." } }]);
999
- setEdges((eds) => [...eds, { id: `e-${pId}-${newId}`, source: pId, target: newId }]);
1000
- setFocusedNodeId(newId);
1001
- return newId;
1002
- },
1003
- onDeleteNode: (id) => {
1004
- setNodes((nds) => nds.filter((n) => n.id !== id));
1005
- setEdges((eds) => eds.filter((e) => e.source !== id && e.target !== id));
1006
- },
1007
- onFocus: setFocusedNodeId,
1008
- focusedNodeId,
1009
- activePath,
1010
- onGenerate: handleSynthesizePrompt,
1011
- onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
1012
- isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
1013
- }
1014
- )
1177
+ !isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react13.AnimatePresence, { mode: "wait", children: [
1178
+ leftTab === "hierarchy" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react13.motion.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1179
+ ListView,
1180
+ {
1181
+ nodes,
1182
+ edges,
1183
+ onNodeChange: (id, l) => setNodes((nds) => nds.map((n) => n.id === id ? { ...n, data: { ...n.data, label: l } } : n)),
1184
+ onAddChild: (pId) => {
1185
+ const newId = crypto.randomUUID();
1186
+ setNodes((nds) => [...nds, { id: newId, type: "custom", position: { x: 0, y: 0 }, data: { label: "", placeholder: "Konzept..." } }]);
1187
+ setEdges((eds) => [...eds, { id: `e-${pId}-${newId}`, source: pId, target: newId }]);
1188
+ setFocusedNodeId(newId);
1189
+ return newId;
1190
+ },
1191
+ onDeleteNode: (id) => {
1192
+ setNodes((nds) => nds.filter((n) => n.id !== id));
1193
+ setEdges((eds) => eds.filter((e) => e.source !== id && e.target !== id));
1194
+ },
1195
+ onFocus: setFocusedNodeId,
1196
+ focusedNodeId,
1197
+ activePath,
1198
+ onGenerate: handleSynthesizePrompt,
1199
+ onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
1200
+ isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
1201
+ }
1202
+ ) }, "hierarchy"),
1203
+ leftTab === "prompt" && workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react13.motion.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1204
+ PromptTab,
1205
+ {
1206
+ workspaceTags,
1207
+ onGenerate: handlePromptTabGenerate,
1208
+ isGenerating: isPromptTabGenerating,
1209
+ feedback: promptFeedback
1210
+ }
1211
+ ) }, "prompt")
1212
+ ] }) })
1015
1213
  ] }),
1016
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
1017
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
1018
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-1.5", children: [
1019
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
1020
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] })
1214
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
1215
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
1216
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1.5", children: [
1217
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
1218
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] })
1021
1219
  ] }),
1022
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
1023
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
1024
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
1220
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2", children: [
1221
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
1222
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
1025
1223
  ] })
1026
1224
  ] }),
1027
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
1028
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react11.AnimatePresence, { children: !isPromptCollapsed && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react11.motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
1029
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1225
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
1226
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react13.AnimatePresence, { children: !isPromptCollapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react13.motion.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
1227
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1030
1228
  "textarea",
1031
1229
  {
1032
1230
  value: activePrompt,
@@ -1035,48 +1233,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1035
1233
  placeholder: "W\xE4hle einen Knoten oder tippe einen Prompt..."
1036
1234
  }
1037
1235
  ),
1038
- activePrompt && !isSynthesizing && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-6 h-6 rounded-full bg-white/5 hover:bg-white/10 flex items-center justify-center transition-colors text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
1236
+ activePrompt && !isSynthesizing && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-6 h-6 rounded-full bg-white/5 hover:bg-white/10 flex items-center justify-center transition-colors text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
1039
1237
  ] }) }) }),
1040
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: [
1041
- isGenerating && currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "absolute top-6 right-6 z-30 bg-black/60 backdrop-blur-md px-4 py-2 rounded-full border border-white/10 flex items-center gap-3", children: [
1042
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
1043
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
1238
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: [
1239
+ isGenerating && currentResult?.status === "done" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "absolute top-6 right-6 z-30 bg-black/60 backdrop-blur-md px-4 py-2 rounded-full border border-white/10 flex items-center gap-3", children: [
1240
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
1241
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
1044
1242
  ] }),
1045
- currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
1046
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
1047
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
1048
- ] }) : currentResult.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
1049
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
1050
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col gap-2", children: [
1051
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
1052
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
1243
+ currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
1244
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
1245
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
1246
+ ] }) : currentResult.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
1247
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
1248
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-2", children: [
1249
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
1250
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
1053
1251
  ] }),
1054
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
1055
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "h-full w-full relative flex items-center justify-center", children: [
1056
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
1057
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "absolute bottom-6 flex gap-2 opacity-0 group-hover:opacity-100 transition-all translate-y-4 group-hover:translate-y-0 z-20", children: [
1058
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
1059
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
1060
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
1252
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
1253
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "h-full w-full relative flex items-center justify-center", children: [
1254
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
1255
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "absolute bottom-6 flex gap-2 opacity-0 group-hover:opacity-100 transition-all translate-y-4 group-hover:translate-y-0 z-20", children: [
1256
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
1257
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
1258
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
1061
1259
  ] })
1062
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
1063
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
1064
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
1260
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
1261
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
1262
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
1065
1263
  ] })
1066
1264
  ] }) })
1067
1265
  ] })
1068
1266
  ] }),
1069
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react11.motion.div, { animate: { width: isRightCollapsed ? 60 : 320 }, className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", children: [
1070
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
1071
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { onClick: () => {
1267
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react13.motion.div, { animate: { width: isRightCollapsed ? 60 : 320 }, className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", children: [
1268
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
1269
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup"].map((tab) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => {
1072
1270
  setActiveTab(tab);
1073
1271
  setIsRightCollapsed(false);
1074
- }, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : "settings" }) }, tab)) }),
1075
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
1272
+ }, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : "settings" }) }, tab)) }),
1273
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
1076
1274
  ] }),
1077
- !isRightCollapsed && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react11.AnimatePresence, { mode: "wait", children: [
1078
- activeTab === "history" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }, "history"),
1079
- activeTab === "gallery" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1275
+ !isRightCollapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_react13.AnimatePresence, { mode: "wait", children: [
1276
+ activeTab === "history" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }, "history"),
1277
+ activeTab === "gallery" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1080
1278
  MediaLibrary,
1081
1279
  {
1082
1280
  items: galleryItems,
@@ -1102,8 +1300,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1102
1300
  },
1103
1301
  "gallery"
1104
1302
  ),
1105
- activeTab === "inspect" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(InspectPanel, { currentResult, history, onSelect: setCurrentResult }, "inspect"),
1106
- activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1303
+ activeTab === "inspect" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(InspectPanel, { currentResult, history, onSelect: setCurrentResult }, "inspect"),
1304
+ activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1107
1305
  SetupPanel,
1108
1306
  {
1109
1307
  onProjectExport: handleProjectExport,
@@ -1128,11 +1326,13 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1128
1326
  ListView,
1129
1327
  MediaLibrary,
1130
1328
  PillButton,
1329
+ PromptTab,
1131
1330
  SectionLabel,
1132
1331
  SetupPanel,
1133
1332
  buildFallbackPrompt,
1134
1333
  buildGenerationPrompt,
1135
1334
  buildImageGenerationOptions,
1335
+ buildPromptTabPayload,
1136
1336
  cleanAiResponse,
1137
1337
  exportProjectToZip,
1138
1338
  formatTreeToMarkdown,
@@ -1141,6 +1341,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1141
1341
  injectXMPMetadata,
1142
1342
  interpretSdkError,
1143
1343
  parsePromptFile,
1344
+ parsePromptResponse,
1144
1345
  useKeyboardNavigation,
1145
1346
  useOnClickOutside
1146
1347
  });
package/dist/index.mjs CHANGED
@@ -293,6 +293,33 @@ function buildImageGenerationOptions(prompt, aspectRatio, model, referenceMediaI
293
293
  }
294
294
  return options;
295
295
  }
296
+ function buildPromptTabPayload(selectedValues, instructions, treeText) {
297
+ const parts = [];
298
+ if (treeText) parts.push(`HIERARCHY:
299
+ ${treeText}`);
300
+ if (selectedValues.length > 0) parts.push(`SELECTED TAGS:
301
+ ${selectedValues.join(", ")}`);
302
+ if (instructions.trim()) parts.push(`ADDITIONAL INSTRUCTIONS:
303
+ ${instructions.trim()}`);
304
+ return [
305
+ "Create a high-quality image generation prompt based on the following inputs. Translate everything to English.",
306
+ `Return a JSON object with exactly two keys: "prompt" (the prompt string) and "feedback" (a short note on your choices in the user's language, or null).`,
307
+ "Output ONLY the JSON object, no markdown, no wrapping.",
308
+ "",
309
+ ...parts
310
+ ].join("\n");
311
+ }
312
+ function parsePromptResponse(raw) {
313
+ const cleaned = raw.replace(/^```json\s*/i, "").replace(/^```\s*/i, "").replace(/```$/i, "").trim();
314
+ try {
315
+ const parsed = JSON.parse(cleaned);
316
+ if (typeof parsed?.prompt === "string") {
317
+ return { prompt: parsed.prompt.trim(), feedback: parsed.feedback ?? null };
318
+ }
319
+ } catch {
320
+ }
321
+ return { prompt: cleaned, feedback: null };
322
+ }
296
323
  function interpretSdkError(err) {
297
324
  const msg = err?.message || "Generierung fehlgeschlagen";
298
325
  if (msg.includes("PUBLIC_ERROR_SOMETHING_WENT_WRONG")) {
@@ -544,8 +571,8 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
544
571
  Object.entries(workspaceTags.by_category).map(([cat, tags]) => /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-2", children: [
545
572
  /* @__PURE__ */ jsx6("span", { className: "text-[8px] font-bold text-white/30 uppercase tracking-widest px-1", children: cat }),
546
573
  /* @__PURE__ */ jsx6("div", { className: "flex flex-wrap gap-1.5", children: tags.map((t) => {
547
- const isActive = (currentResult.tags || []).includes(t);
548
- return /* @__PURE__ */ jsx6("button", { onClick: () => onTagToggle?.(t), className: `px-2.5 py-1 rounded-lg text-[8px] font-bold uppercase transition-all border ${isActive ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_10px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/20 hover:text-white/50 hover:bg-white/10"}`, children: t }, t);
574
+ const isActive = (currentResult.tags || []).includes(t.label);
575
+ return /* @__PURE__ */ jsx6("button", { onClick: () => onTagToggle?.(t.label), className: `px-2.5 py-1 rounded-lg text-[8px] font-bold uppercase transition-all border ${isActive ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_10px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/20 hover:text-white/50 hover:bg-white/10"}`, children: t.label }, t.label);
549
576
  }) })
550
577
  ] }, cat))
551
578
  ] })
@@ -757,9 +784,115 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
757
784
  }
758
785
 
759
786
  // src/components/AvatarArchitectApp.tsx
760
- import { useState as useState3, useCallback, useMemo, useEffect as useEffect4 } from "react";
787
+ import { useState as useState4, useCallback, useMemo, useEffect as useEffect4 } from "react";
788
+ import { motion as motion6, AnimatePresence as AnimatePresence2 } from "motion/react";
789
+
790
+ // src/components/PromptTab.tsx
791
+ import { useState as useState3 } from "react";
761
792
  import { motion as motion5, AnimatePresence } from "motion/react";
762
793
  import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
794
+ var PromptTab = ({ workspaceTags, onGenerate, isGenerating, feedback }) => {
795
+ const [selectedLabels, setSelectedLabels] = useState3(/* @__PURE__ */ new Set());
796
+ const [instructions, setInstructions] = useState3("");
797
+ const [showFeedback, setShowFeedback] = useState3(true);
798
+ const toggleTag = (label) => {
799
+ setSelectedLabels((prev) => {
800
+ const next = new Set(prev);
801
+ if (next.has(label)) next.delete(label);
802
+ else next.add(label);
803
+ return next;
804
+ });
805
+ };
806
+ const handleGenerate = () => {
807
+ const selectedValues = workspaceTags.all.filter((t) => selectedLabels.has(t.label)).map((t) => t.value);
808
+ onGenerate(selectedValues, instructions);
809
+ };
810
+ const categories = Object.entries(workspaceTags.by_category).filter(([, tags]) => tags.length > 0);
811
+ return /* @__PURE__ */ jsxs8("div", { className: "absolute inset-0 flex flex-col overflow-hidden", children: [
812
+ /* @__PURE__ */ jsxs8("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 py-3 flex flex-col gap-4", children: [
813
+ categories.length === 0 ? /* @__PURE__ */ jsxs8("div", { className: "flex flex-col items-center justify-center py-16 gap-3 opacity-20", children: [
814
+ /* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[48px]", children: "label_off" }),
815
+ /* @__PURE__ */ jsxs8("p", { className: "text-[9px] font-bold uppercase tracking-widest text-center", children: [
816
+ "Keine Tags geladen.",
817
+ /* @__PURE__ */ jsx10("br", {}),
818
+ "Importiere ein Workspace-JSON im Setup-Tab."
819
+ ] })
820
+ ] }) : categories.map(([cat, tags]) => /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
821
+ /* @__PURE__ */ jsx10(SectionLabel, { children: cat }),
822
+ /* @__PURE__ */ jsx10("div", { className: "flex flex-wrap gap-1", children: tags.map((t) => {
823
+ const active = selectedLabels.has(t.label);
824
+ return /* @__PURE__ */ jsx10(
825
+ "button",
826
+ {
827
+ onClick: () => toggleTag(t.label),
828
+ className: `px-2 py-1 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-all border ${active ? "bg-blue-500 border-blue-400 text-white shadow-[0_0_8px_rgba(59,130,246,0.3)]" : "bg-white/5 border-white/5 text-white/30 hover:text-white/60 hover:bg-white/10"}`,
829
+ children: t.label
830
+ },
831
+ t.label
832
+ );
833
+ }) })
834
+ ] }, cat)),
835
+ /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2 mt-2", children: [
836
+ /* @__PURE__ */ jsx10(SectionLabel, { children: "Zus\xE4tzliche Anweisungen" }),
837
+ /* @__PURE__ */ jsx10(
838
+ "textarea",
839
+ {
840
+ value: instructions,
841
+ onChange: (e) => setInstructions(e.target.value),
842
+ placeholder: "Weitere Vorgaben f\xFCr den AI-Prompt...",
843
+ className: "w-full bg-white/5 border border-white/10 rounded-xl p-3 text-[10px] text-white/70 placeholder-white/20 resize-none h-20 outline-none focus:border-white/20 dark-scrollbar"
844
+ }
845
+ )
846
+ ] })
847
+ ] }),
848
+ /* @__PURE__ */ jsxs8("div", { className: "shrink-0 border-t border-white/5 p-3 flex flex-col gap-2", children: [
849
+ feedback && /* @__PURE__ */ jsxs8("div", { className: "flex flex-col", children: [
850
+ /* @__PURE__ */ jsxs8(
851
+ "button",
852
+ {
853
+ onClick: () => setShowFeedback((p) => !p),
854
+ className: "flex items-center gap-1.5 text-[8px] font-bold uppercase text-amber-400/60 hover:text-amber-400 transition-colors mb-1",
855
+ children: [
856
+ /* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[12px]", children: "psychology" }),
857
+ "KI-Analyse",
858
+ /* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[12px] ml-auto", children: showFeedback ? "expand_less" : "expand_more" })
859
+ ]
860
+ }
861
+ ),
862
+ /* @__PURE__ */ jsx10(AnimatePresence, { children: showFeedback && /* @__PURE__ */ jsx10(
863
+ motion5.div,
864
+ {
865
+ initial: { height: 0, opacity: 0 },
866
+ animate: { height: "auto", opacity: 1 },
867
+ exit: { height: 0, opacity: 0 },
868
+ className: "overflow-hidden",
869
+ children: /* @__PURE__ */ jsx10("p", { className: "text-[9px] text-amber-400/50 leading-relaxed bg-amber-500/5 border border-amber-500/10 rounded-xl p-2 italic", children: feedback })
870
+ }
871
+ ) })
872
+ ] }),
873
+ /* @__PURE__ */ jsxs8("div", { className: "flex items-center justify-between", children: [
874
+ selectedLabels.size > 0 ? /* @__PURE__ */ jsxs8("span", { className: "text-[8px] text-white/30 font-bold uppercase", children: [
875
+ selectedLabels.size,
876
+ " Tags gew\xE4hlt"
877
+ ] }) : /* @__PURE__ */ jsx10("span", { className: "text-[8px] text-white/20 italic", children: "Keine Tags gew\xE4hlt" }),
878
+ /* @__PURE__ */ jsx10(
879
+ PillButton,
880
+ {
881
+ variant: "solid",
882
+ icon: "auto_fix_high",
883
+ loading: isGenerating,
884
+ disabled: selectedLabels.size === 0 && !instructions.trim(),
885
+ onClick: handleGenerate,
886
+ children: "Prompt bauen"
887
+ }
888
+ )
889
+ ] })
890
+ ] })
891
+ ] });
892
+ };
893
+
894
+ // src/components/AvatarArchitectApp.tsx
895
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
763
896
  function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }) {
764
897
  useEffect4(() => {
765
898
  const id = "flow-styles";
@@ -770,24 +903,28 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
770
903
  document.head.appendChild(style);
771
904
  }
772
905
  }, []);
773
- const [nodes, setNodes] = useState3([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
774
- const [edges, setEdges] = useState3([]);
775
- const [history, setHistory] = useState3([]);
776
- const [galleryItems, setGalleryItems] = useState3([]);
777
- const [activePrompt, setActivePrompt] = useState3("");
778
- const [isSynthesizing, setIsSynthesizing] = useState3(false);
779
- const [activeGenerationsCount, setActiveGenerationsCount] = useState3(0);
780
- const [currentResult, setCurrentResult] = useState3(null);
781
- const [focusedNodeId, setFocusedNodeId] = useState3(null);
782
- const [activeTab, setActiveTab] = useState3("history");
783
- const [aspectRatio, setAspectRatio] = useState3("1:1");
784
- const [selectedModel, setSelectedModel] = useState3("\u{1F34C} Nano Banana Pro");
785
- const [seed, setSeed] = useState3(Math.floor(Math.random() * 1e6));
786
- const [seedMode, setSeedMode] = useState3("random");
787
- const [isLeftCollapsed, setIsLeftCollapsed] = useState3(false);
788
- const [isRightCollapsed, setIsRightCollapsed] = useState3(false);
789
- const [isPromptCollapsed, setIsPromptCollapsed] = useState3(false);
790
- const [projectActionState, setProjectActionState] = useState3("idle");
906
+ const [nodes, setNodes] = useState4([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
907
+ const [edges, setEdges] = useState4([]);
908
+ const [history, setHistory] = useState4([]);
909
+ const [galleryItems, setGalleryItems] = useState4([]);
910
+ const [activePrompt, setActivePrompt] = useState4("");
911
+ const [isSynthesizing, setIsSynthesizing] = useState4(false);
912
+ const [activeGenerationsCount, setActiveGenerationsCount] = useState4(0);
913
+ const [currentResult, setCurrentResult] = useState4(null);
914
+ const [focusedNodeId, setFocusedNodeId] = useState4(null);
915
+ const [leftTab, setLeftTab] = useState4("hierarchy");
916
+ const [promptFeedback, setPromptFeedback] = useState4(null);
917
+ const [isPromptTabGenerating, setIsPromptTabGenerating] = useState4(false);
918
+ const [activeTab, setActiveTab] = useState4("history");
919
+ const [aspectRatio, setAspectRatio] = useState4("1:1");
920
+ const [selectedModel, setSelectedModel] = useState4("\u{1F34C} Nano Banana Pro");
921
+ const [seed, setSeed] = useState4(Math.floor(Math.random() * 1e6));
922
+ const [seedMode, setSeedMode] = useState4("random");
923
+ const [isLeftCollapsed, setIsLeftCollapsed] = useState4(false);
924
+ const [isRightCollapsed, setIsRightCollapsed] = useState4(false);
925
+ const [isPromptCollapsed, setIsPromptCollapsed] = useState4(false);
926
+ const [projectActionState, setProjectActionState] = useState4("idle");
927
+ const [workspaceTags, setWorkspaceTags] = useState4(null);
791
928
  const isGenerating = activeGenerationsCount > 0;
792
929
  useKeyboardNavigation(history, currentResult, setCurrentResult);
793
930
  const getSubtreeFormat = useCallback((nodeId, depth = 0) => {
@@ -851,16 +988,32 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
851
988
  const handleSynthesizePrompt = async (nodeId, autoGenerate = false) => {
852
989
  setIsSynthesizing(true);
853
990
  try {
854
- const prompt = await onGeneratePrompt(getSubtreeFormat(nodeId));
855
- setActivePrompt(prompt);
991
+ const raw = await onGeneratePrompt(getSubtreeFormat(nodeId));
992
+ setActivePrompt(raw);
856
993
  setFocusedNodeId(nodeId);
857
- if (autoGenerate) handleGenerateImage(prompt, void 0, nodeId);
994
+ if (autoGenerate) handleGenerateImage(raw, void 0, nodeId);
858
995
  } catch {
859
996
  setActivePrompt("Synthese-Fehler");
860
997
  } finally {
861
998
  setIsSynthesizing(false);
862
999
  }
863
1000
  };
1001
+ const handlePromptTabGenerate = async (selectedValues, instructions) => {
1002
+ setIsPromptTabGenerating(true);
1003
+ setPromptFeedback(null);
1004
+ try {
1005
+ const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
1006
+ const payload = buildPromptTabPayload(selectedValues, instructions, treeText);
1007
+ const raw = await onGeneratePrompt(payload);
1008
+ const { prompt, feedback } = parsePromptResponse(raw);
1009
+ setActivePrompt(prompt);
1010
+ setPromptFeedback(feedback);
1011
+ } catch {
1012
+ setActivePrompt("Synthese-Fehler");
1013
+ } finally {
1014
+ setIsPromptTabGenerating(false);
1015
+ }
1016
+ };
864
1017
  const handleDownloadSingle = async () => {
865
1018
  if (!currentResult?.base64) return;
866
1019
  try {
@@ -916,58 +1069,100 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
916
1069
  const root = JSON.parse(ev.target?.result);
917
1070
  const rawTags = root.tags || root;
918
1071
  if (!rawTags?.by_category) return;
1072
+ const filtered = {};
1073
+ const EXCLUDED = ["pdf-export", "book.micro-edit-rules"];
1074
+ Object.entries(rawTags.by_category).forEach(([cat, items]) => {
1075
+ if (EXCLUDED.includes(cat) || !Array.isArray(items)) return;
1076
+ filtered[cat] = items.filter((t) => t && typeof t === "object" && t.label && t.value);
1077
+ });
1078
+ const filteredAll = (rawTags.all || []).filter((t) => t && !EXCLUDED.includes(t.category));
1079
+ setWorkspaceTags({ by_category: filtered, all: filteredAll });
919
1080
  } catch (err) {
920
1081
  console.error("Workspace Load failed", err);
921
1082
  }
922
1083
  };
923
1084
  reader.readAsText(file);
924
1085
  };
925
- return /* @__PURE__ */ jsxs8("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", children: [
926
- /* @__PURE__ */ jsxs8(motion5.div, { animate: { width: isLeftCollapsed ? 48 : 260 }, className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", children: [
927
- /* @__PURE__ */ jsxs8("div", { className: "h-14 px-4 border-b border-white/5 flex items-center justify-between shrink-0", children: [
928
- !isLeftCollapsed && /* @__PURE__ */ jsx10("span", { className: "text-[10px] font-bold uppercase text-white/40", children: "Hierarchie" }),
929
- /* @__PURE__ */ jsx10("button", { onClick: () => setIsLeftCollapsed(!isLeftCollapsed), className: "material-symbols-outlined text-[18px] text-white/40 hover:text-white transition-all", children: isLeftCollapsed ? "chevron_right" : "chevron_left" })
1086
+ return /* @__PURE__ */ jsxs9("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", children: [
1087
+ /* @__PURE__ */ jsxs9(motion6.div, { animate: { width: isLeftCollapsed ? 48 : 260 }, className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", children: [
1088
+ /* @__PURE__ */ jsxs9("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
1089
+ !isLeftCollapsed && /* @__PURE__ */ jsxs9("div", { className: "flex flex-1 gap-1", children: [
1090
+ /* @__PURE__ */ jsxs9(
1091
+ "button",
1092
+ {
1093
+ onClick: () => setLeftTab("hierarchy"),
1094
+ 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"}`,
1095
+ children: [
1096
+ /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
1097
+ "Hierarchie"
1098
+ ]
1099
+ }
1100
+ ),
1101
+ workspaceTags && /* @__PURE__ */ jsxs9(
1102
+ "button",
1103
+ {
1104
+ onClick: () => setLeftTab("prompt"),
1105
+ 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"}`,
1106
+ children: [
1107
+ /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
1108
+ "Prompt"
1109
+ ]
1110
+ }
1111
+ )
1112
+ ] }),
1113
+ /* @__PURE__ */ jsx11("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" })
930
1114
  ] }),
931
- !isLeftCollapsed && /* @__PURE__ */ jsx10(
932
- ListView,
933
- {
934
- nodes,
935
- edges,
936
- onNodeChange: (id, l) => setNodes((nds) => nds.map((n) => n.id === id ? { ...n, data: { ...n.data, label: l } } : n)),
937
- onAddChild: (pId) => {
938
- const newId = crypto.randomUUID();
939
- setNodes((nds) => [...nds, { id: newId, type: "custom", position: { x: 0, y: 0 }, data: { label: "", placeholder: "Konzept..." } }]);
940
- setEdges((eds) => [...eds, { id: `e-${pId}-${newId}`, source: pId, target: newId }]);
941
- setFocusedNodeId(newId);
942
- return newId;
943
- },
944
- onDeleteNode: (id) => {
945
- setNodes((nds) => nds.filter((n) => n.id !== id));
946
- setEdges((eds) => eds.filter((e) => e.source !== id && e.target !== id));
947
- },
948
- onFocus: setFocusedNodeId,
949
- focusedNodeId,
950
- activePath,
951
- onGenerate: handleSynthesizePrompt,
952
- onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
953
- isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
954
- }
955
- )
1115
+ !isLeftCollapsed && /* @__PURE__ */ jsx11("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ jsxs9(AnimatePresence2, { mode: "wait", children: [
1116
+ leftTab === "hierarchy" && /* @__PURE__ */ jsx11(motion6.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ jsx11(
1117
+ ListView,
1118
+ {
1119
+ nodes,
1120
+ edges,
1121
+ onNodeChange: (id, l) => setNodes((nds) => nds.map((n) => n.id === id ? { ...n, data: { ...n.data, label: l } } : n)),
1122
+ onAddChild: (pId) => {
1123
+ const newId = crypto.randomUUID();
1124
+ setNodes((nds) => [...nds, { id: newId, type: "custom", position: { x: 0, y: 0 }, data: { label: "", placeholder: "Konzept..." } }]);
1125
+ setEdges((eds) => [...eds, { id: `e-${pId}-${newId}`, source: pId, target: newId }]);
1126
+ setFocusedNodeId(newId);
1127
+ return newId;
1128
+ },
1129
+ onDeleteNode: (id) => {
1130
+ setNodes((nds) => nds.filter((n) => n.id !== id));
1131
+ setEdges((eds) => eds.filter((e) => e.source !== id && e.target !== id));
1132
+ },
1133
+ onFocus: setFocusedNodeId,
1134
+ focusedNodeId,
1135
+ activePath,
1136
+ onGenerate: handleSynthesizePrompt,
1137
+ onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
1138
+ isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
1139
+ }
1140
+ ) }, "hierarchy"),
1141
+ leftTab === "prompt" && workspaceTags && /* @__PURE__ */ jsx11(motion6.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ jsx11(
1142
+ PromptTab,
1143
+ {
1144
+ workspaceTags,
1145
+ onGenerate: handlePromptTabGenerate,
1146
+ isGenerating: isPromptTabGenerating,
1147
+ feedback: promptFeedback
1148
+ }
1149
+ ) }, "prompt")
1150
+ ] }) })
956
1151
  ] }),
957
- /* @__PURE__ */ jsxs8("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
958
- /* @__PURE__ */ jsxs8("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
959
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-1.5", children: [
960
- /* @__PURE__ */ jsx10(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
961
- /* @__PURE__ */ jsx10(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" }] })
1152
+ /* @__PURE__ */ jsxs9("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
1153
+ /* @__PURE__ */ jsxs9("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
1154
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1.5", children: [
1155
+ /* @__PURE__ */ jsx11(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
1156
+ /* @__PURE__ */ jsx11(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" }] })
962
1157
  ] }),
963
- /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
964
- /* @__PURE__ */ jsx10("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
965
- /* @__PURE__ */ jsx10(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
1158
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
1159
+ /* @__PURE__ */ jsx11("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
1160
+ /* @__PURE__ */ jsx11(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
966
1161
  ] })
967
1162
  ] }),
968
- /* @__PURE__ */ jsxs8("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
969
- /* @__PURE__ */ jsx10(AnimatePresence, { children: !isPromptCollapsed && /* @__PURE__ */ jsx10(motion5.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ jsxs8("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
970
- /* @__PURE__ */ jsx10(
1163
+ /* @__PURE__ */ jsxs9("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
1164
+ /* @__PURE__ */ jsx11(AnimatePresence2, { children: !isPromptCollapsed && /* @__PURE__ */ jsx11(motion6.div, { initial: { height: 0 }, animate: { height: "auto" }, exit: { height: 0 }, className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ jsxs9("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
1165
+ /* @__PURE__ */ jsx11(
971
1166
  "textarea",
972
1167
  {
973
1168
  value: activePrompt,
@@ -976,48 +1171,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
976
1171
  placeholder: "W\xE4hle einen Knoten oder tippe einen Prompt..."
977
1172
  }
978
1173
  ),
979
- activePrompt && !isSynthesizing && /* @__PURE__ */ jsx10("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__ */ jsx10("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
1174
+ activePrompt && !isSynthesizing && /* @__PURE__ */ jsx11("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__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
980
1175
  ] }) }) }),
981
- /* @__PURE__ */ jsx10("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsxs8("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: [
982
- isGenerating && currentResult?.status === "done" && /* @__PURE__ */ jsxs8("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: [
983
- /* @__PURE__ */ jsx10("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
984
- /* @__PURE__ */ jsx10("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
1176
+ /* @__PURE__ */ jsx11("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsxs9("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: [
1177
+ isGenerating && currentResult?.status === "done" && /* @__PURE__ */ jsxs9("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: [
1178
+ /* @__PURE__ */ jsx11("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
1179
+ /* @__PURE__ */ jsx11("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
985
1180
  ] }),
986
- currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs8("div", { className: "flex flex-col items-center gap-4", children: [
987
- /* @__PURE__ */ jsx10("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
988
- /* @__PURE__ */ jsx10("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
989
- ] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs8("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
990
- /* @__PURE__ */ jsx10("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
991
- /* @__PURE__ */ jsxs8("div", { className: "flex flex-col gap-2", children: [
992
- /* @__PURE__ */ jsx10("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
993
- /* @__PURE__ */ jsx10("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
1181
+ currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center gap-4", children: [
1182
+ /* @__PURE__ */ jsx11("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
1183
+ /* @__PURE__ */ jsx11("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
1184
+ ] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs9("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
1185
+ /* @__PURE__ */ jsx11("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
1186
+ /* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-2", children: [
1187
+ /* @__PURE__ */ jsx11("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
1188
+ /* @__PURE__ */ jsx11("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
994
1189
  ] }),
995
- /* @__PURE__ */ jsx10(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
996
- ] }) : /* @__PURE__ */ jsxs8("div", { className: "h-full w-full relative flex items-center justify-center", children: [
997
- /* @__PURE__ */ jsx10("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
998
- /* @__PURE__ */ jsxs8("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: [
999
- /* @__PURE__ */ jsx10(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
1000
- /* @__PURE__ */ jsx10(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
1001
- /* @__PURE__ */ jsx10(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
1190
+ /* @__PURE__ */ jsx11(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
1191
+ ] }) : /* @__PURE__ */ jsxs9("div", { className: "h-full w-full relative flex items-center justify-center", children: [
1192
+ /* @__PURE__ */ jsx11("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
1193
+ /* @__PURE__ */ jsxs9("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: [
1194
+ /* @__PURE__ */ jsx11(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
1195
+ /* @__PURE__ */ jsx11(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
1196
+ /* @__PURE__ */ jsx11(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
1002
1197
  ] })
1003
- ] }) : /* @__PURE__ */ jsxs8("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
1004
- /* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
1005
- /* @__PURE__ */ jsx10("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
1198
+ ] }) : /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
1199
+ /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
1200
+ /* @__PURE__ */ jsx11("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
1006
1201
  ] })
1007
1202
  ] }) })
1008
1203
  ] })
1009
1204
  ] }),
1010
- /* @__PURE__ */ jsxs8(motion5.div, { animate: { width: isRightCollapsed ? 60 : 320 }, className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", children: [
1011
- /* @__PURE__ */ jsxs8("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
1012
- /* @__PURE__ */ jsx10("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup"].map((tab) => /* @__PURE__ */ jsx10("button", { onClick: () => {
1205
+ /* @__PURE__ */ jsxs9(motion6.div, { animate: { width: isRightCollapsed ? 60 : 320 }, className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", children: [
1206
+ /* @__PURE__ */ jsxs9("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
1207
+ /* @__PURE__ */ jsx11("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup"].map((tab) => /* @__PURE__ */ jsx11("button", { onClick: () => {
1013
1208
  setActiveTab(tab);
1014
1209
  setIsRightCollapsed(false);
1015
- }, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : "settings" }) }, tab)) }),
1016
- /* @__PURE__ */ jsx10("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
1210
+ }, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : "settings" }) }, tab)) }),
1211
+ /* @__PURE__ */ jsx11("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
1017
1212
  ] }),
1018
- !isRightCollapsed && /* @__PURE__ */ jsx10("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ jsxs8(AnimatePresence, { mode: "wait", children: [
1019
- activeTab === "history" && /* @__PURE__ */ jsx10(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }, "history"),
1020
- activeTab === "gallery" && /* @__PURE__ */ jsx10(
1213
+ !isRightCollapsed && /* @__PURE__ */ jsx11("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ jsxs9(AnimatePresence2, { mode: "wait", children: [
1214
+ activeTab === "history" && /* @__PURE__ */ jsx11(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }, "history"),
1215
+ activeTab === "gallery" && /* @__PURE__ */ jsx11(
1021
1216
  MediaLibrary,
1022
1217
  {
1023
1218
  items: galleryItems,
@@ -1043,8 +1238,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
1043
1238
  },
1044
1239
  "gallery"
1045
1240
  ),
1046
- activeTab === "inspect" && /* @__PURE__ */ jsx10(InspectPanel, { currentResult, history, onSelect: setCurrentResult }, "inspect"),
1047
- activeTab === "setup" && /* @__PURE__ */ jsx10(
1241
+ activeTab === "inspect" && /* @__PURE__ */ jsx11(InspectPanel, { currentResult, history, onSelect: setCurrentResult }, "inspect"),
1242
+ activeTab === "setup" && /* @__PURE__ */ jsx11(
1048
1243
  SetupPanel,
1049
1244
  {
1050
1245
  onProjectExport: handleProjectExport,
@@ -1068,11 +1263,13 @@ export {
1068
1263
  ListView,
1069
1264
  MediaLibrary,
1070
1265
  PillButton,
1266
+ PromptTab,
1071
1267
  SectionLabel,
1072
1268
  SetupPanel,
1073
1269
  buildFallbackPrompt,
1074
1270
  buildGenerationPrompt,
1075
1271
  buildImageGenerationOptions,
1272
+ buildPromptTabPayload,
1076
1273
  cleanAiResponse,
1077
1274
  exportProjectToZip,
1078
1275
  formatTreeToMarkdown,
@@ -1081,6 +1278,7 @@ export {
1081
1278
  injectXMPMetadata,
1082
1279
  interpretSdkError,
1083
1280
  parsePromptFile,
1281
+ parsePromptResponse,
1084
1282
  useKeyboardNavigation,
1085
1283
  useOnClickOutside
1086
1284
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rslsp1/fa-app-tools",
3
- "version": "0.1.14",
3
+ "version": "1.0.1",
4
4
  "description": "Shared tools and hooks for Fine Art flow apps",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",