@rslsp1/fa-app-tools 1.0.0 → 1.0.2
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 +22 -7
- package/dist/index.d.ts +22 -7
- package/dist/index.js +302 -99
- package/dist/index.mjs +297 -97
- package/package.json +1 -1
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,
|
|
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 {
|
|
@@ -179,14 +186,22 @@ interface MediaItem {
|
|
|
179
186
|
name?: string;
|
|
180
187
|
}
|
|
181
188
|
interface AvatarArchitectAppProps {
|
|
182
|
-
onGenerateImage: (
|
|
189
|
+
onGenerateImage: (options: Record<string, any>) => Promise<{
|
|
183
190
|
base64: string;
|
|
184
191
|
mediaId?: string;
|
|
185
192
|
}>;
|
|
186
|
-
onGeneratePrompt: (
|
|
193
|
+
onGeneratePrompt: (text: string) => Promise<string>;
|
|
187
194
|
onDownload: (base64: string, mimeType: string, filename: string) => Promise<void>;
|
|
188
195
|
onSelectMedia: () => Promise<MediaItem[]>;
|
|
189
196
|
}
|
|
190
197
|
declare function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }: AvatarArchitectAppProps): react_jsx_runtime.JSX.Element;
|
|
191
198
|
|
|
192
|
-
|
|
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,
|
|
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 {
|
|
@@ -179,14 +186,22 @@ interface MediaItem {
|
|
|
179
186
|
name?: string;
|
|
180
187
|
}
|
|
181
188
|
interface AvatarArchitectAppProps {
|
|
182
|
-
onGenerateImage: (
|
|
189
|
+
onGenerateImage: (options: Record<string, any>) => Promise<{
|
|
183
190
|
base64: string;
|
|
184
191
|
mediaId?: string;
|
|
185
192
|
}>;
|
|
186
|
-
onGeneratePrompt: (
|
|
193
|
+
onGeneratePrompt: (text: string) => Promise<string>;
|
|
187
194
|
onDownload: (base64: string, mimeType: string, filename: string) => Promise<void>;
|
|
188
195
|
onSelectMedia: () => Promise<MediaItem[]>;
|
|
189
196
|
}
|
|
190
197
|
declare function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }: AvatarArchitectAppProps): react_jsx_runtime.JSX.Element;
|
|
191
198
|
|
|
192
|
-
|
|
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,
|
|
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,
|
|
833
|
-
const [edges, setEdges] = (0,
|
|
834
|
-
const [history, setHistory] = (0,
|
|
835
|
-
const [galleryItems, setGalleryItems] = (0,
|
|
836
|
-
const [activePrompt, setActivePrompt] = (0,
|
|
837
|
-
const [isSynthesizing, setIsSynthesizing] = (0,
|
|
838
|
-
const [activeGenerationsCount, setActiveGenerationsCount] = (0,
|
|
839
|
-
const [currentResult, setCurrentResult] = (0,
|
|
840
|
-
const [focusedNodeId, setFocusedNodeId] = (0,
|
|
841
|
-
const [
|
|
842
|
-
const [
|
|
843
|
-
const [
|
|
844
|
-
const [
|
|
845
|
-
const [
|
|
846
|
-
const [
|
|
847
|
-
const [
|
|
848
|
-
const [
|
|
849
|
-
const [
|
|
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,
|
|
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,
|
|
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;
|
|
@@ -890,7 +1030,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
890
1030
|
if (!options.silent) setCurrentResult(newGen);
|
|
891
1031
|
if (seedMode === "random") setSeed(activeSeed);
|
|
892
1032
|
try {
|
|
893
|
-
const { base64, mediaId } = await onGenerateImage(promptToUse, aspectRatio, selectedModel, useReferenceId);
|
|
1033
|
+
const { base64, mediaId } = await onGenerateImage(buildImageGenerationOptions(promptToUse, aspectRatio, selectedModel, useReferenceId));
|
|
894
1034
|
const finishedGen = { ...newGen, status: "done", base64: `data:image/png;base64,${base64}`, mediaId };
|
|
895
1035
|
setHistory((prev) => prev.map((g) => g.id === genId ? finishedGen : g));
|
|
896
1036
|
setGalleryItems((prev) => [finishedGen, ...prev]);
|
|
@@ -910,7 +1050,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
910
1050
|
const handleSynthesizePrompt = async (nodeId, autoGenerate = false) => {
|
|
911
1051
|
setIsSynthesizing(true);
|
|
912
1052
|
try {
|
|
913
|
-
const
|
|
1053
|
+
const payload = buildGenerationPrompt(getSubtreeFormat(nodeId));
|
|
1054
|
+
const raw = await onGeneratePrompt(payload);
|
|
1055
|
+
const prompt = cleanAiResponse(raw);
|
|
914
1056
|
setActivePrompt(prompt);
|
|
915
1057
|
setFocusedNodeId(nodeId);
|
|
916
1058
|
if (autoGenerate) handleGenerateImage(prompt, void 0, nodeId);
|
|
@@ -920,6 +1062,22 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
920
1062
|
setIsSynthesizing(false);
|
|
921
1063
|
}
|
|
922
1064
|
};
|
|
1065
|
+
const handlePromptTabGenerate = async (selectedValues, instructions) => {
|
|
1066
|
+
setIsPromptTabGenerating(true);
|
|
1067
|
+
setPromptFeedback(null);
|
|
1068
|
+
try {
|
|
1069
|
+
const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
|
|
1070
|
+
const payload = buildPromptTabPayload(selectedValues, instructions, treeText);
|
|
1071
|
+
const raw = await onGeneratePrompt(payload);
|
|
1072
|
+
const { prompt, feedback } = parsePromptResponse(raw);
|
|
1073
|
+
setActivePrompt(prompt);
|
|
1074
|
+
setPromptFeedback(feedback);
|
|
1075
|
+
} catch {
|
|
1076
|
+
setActivePrompt("Synthese-Fehler");
|
|
1077
|
+
} finally {
|
|
1078
|
+
setIsPromptTabGenerating(false);
|
|
1079
|
+
}
|
|
1080
|
+
};
|
|
923
1081
|
const handleDownloadSingle = async () => {
|
|
924
1082
|
if (!currentResult?.base64) return;
|
|
925
1083
|
try {
|
|
@@ -975,58 +1133,100 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
975
1133
|
const root = JSON.parse(ev.target?.result);
|
|
976
1134
|
const rawTags = root.tags || root;
|
|
977
1135
|
if (!rawTags?.by_category) return;
|
|
1136
|
+
const filtered = {};
|
|
1137
|
+
const EXCLUDED = ["pdf-export", "book.micro-edit-rules"];
|
|
1138
|
+
Object.entries(rawTags.by_category).forEach(([cat, items]) => {
|
|
1139
|
+
if (EXCLUDED.includes(cat) || !Array.isArray(items)) return;
|
|
1140
|
+
filtered[cat] = items.filter((t) => t && typeof t === "object" && t.label && t.value);
|
|
1141
|
+
});
|
|
1142
|
+
const filteredAll = (rawTags.all || []).filter((t) => t && !EXCLUDED.includes(t.category));
|
|
1143
|
+
setWorkspaceTags({ by_category: filtered, all: filteredAll });
|
|
978
1144
|
} catch (err) {
|
|
979
1145
|
console.error("Workspace Load failed", err);
|
|
980
1146
|
}
|
|
981
1147
|
};
|
|
982
1148
|
reader.readAsText(file);
|
|
983
1149
|
};
|
|
984
|
-
return /* @__PURE__ */ (0,
|
|
985
|
-
/* @__PURE__ */ (0,
|
|
986
|
-
/* @__PURE__ */ (0,
|
|
987
|
-
!isLeftCollapsed && /* @__PURE__ */ (0,
|
|
988
|
-
|
|
1150
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", children: [
|
|
1151
|
+
/* @__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: [
|
|
1152
|
+
/* @__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: [
|
|
1153
|
+
!isLeftCollapsed && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-1 gap-1", children: [
|
|
1154
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1155
|
+
"button",
|
|
1156
|
+
{
|
|
1157
|
+
onClick: () => setLeftTab("hierarchy"),
|
|
1158
|
+
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"}`,
|
|
1159
|
+
children: [
|
|
1160
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
|
|
1161
|
+
"Hierarchie"
|
|
1162
|
+
]
|
|
1163
|
+
}
|
|
1164
|
+
),
|
|
1165
|
+
workspaceTags && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1166
|
+
"button",
|
|
1167
|
+
{
|
|
1168
|
+
onClick: () => setLeftTab("prompt"),
|
|
1169
|
+
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"}`,
|
|
1170
|
+
children: [
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
|
|
1172
|
+
"Prompt"
|
|
1173
|
+
]
|
|
1174
|
+
}
|
|
1175
|
+
)
|
|
1176
|
+
] }),
|
|
1177
|
+
/* @__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
1178
|
] }),
|
|
990
|
-
!isLeftCollapsed && /* @__PURE__ */ (0,
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1179
|
+
!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: [
|
|
1180
|
+
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)(
|
|
1181
|
+
ListView,
|
|
1182
|
+
{
|
|
1183
|
+
nodes,
|
|
1184
|
+
edges,
|
|
1185
|
+
onNodeChange: (id, l) => setNodes((nds) => nds.map((n) => n.id === id ? { ...n, data: { ...n.data, label: l } } : n)),
|
|
1186
|
+
onAddChild: (pId) => {
|
|
1187
|
+
const newId = crypto.randomUUID();
|
|
1188
|
+
setNodes((nds) => [...nds, { id: newId, type: "custom", position: { x: 0, y: 0 }, data: { label: "", placeholder: "Konzept..." } }]);
|
|
1189
|
+
setEdges((eds) => [...eds, { id: `e-${pId}-${newId}`, source: pId, target: newId }]);
|
|
1190
|
+
setFocusedNodeId(newId);
|
|
1191
|
+
return newId;
|
|
1192
|
+
},
|
|
1193
|
+
onDeleteNode: (id) => {
|
|
1194
|
+
setNodes((nds) => nds.filter((n) => n.id !== id));
|
|
1195
|
+
setEdges((eds) => eds.filter((e) => e.source !== id && e.target !== id));
|
|
1196
|
+
},
|
|
1197
|
+
onFocus: setFocusedNodeId,
|
|
1198
|
+
focusedNodeId,
|
|
1199
|
+
activePath,
|
|
1200
|
+
onGenerate: handleSynthesizePrompt,
|
|
1201
|
+
onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
|
|
1202
|
+
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
1203
|
+
}
|
|
1204
|
+
) }, "hierarchy"),
|
|
1205
|
+
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)(
|
|
1206
|
+
PromptTab,
|
|
1207
|
+
{
|
|
1208
|
+
workspaceTags,
|
|
1209
|
+
onGenerate: handlePromptTabGenerate,
|
|
1210
|
+
isGenerating: isPromptTabGenerating,
|
|
1211
|
+
feedback: promptFeedback
|
|
1212
|
+
}
|
|
1213
|
+
) }, "prompt")
|
|
1214
|
+
] }) })
|
|
1015
1215
|
] }),
|
|
1016
|
-
/* @__PURE__ */ (0,
|
|
1017
|
-
/* @__PURE__ */ (0,
|
|
1018
|
-
/* @__PURE__ */ (0,
|
|
1019
|
-
/* @__PURE__ */ (0,
|
|
1020
|
-
/* @__PURE__ */ (0,
|
|
1216
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
|
|
1217
|
+
/* @__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: [
|
|
1218
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-1.5", children: [
|
|
1219
|
+
/* @__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" }] }),
|
|
1220
|
+
/* @__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
1221
|
] }),
|
|
1022
|
-
/* @__PURE__ */ (0,
|
|
1023
|
-
/* @__PURE__ */ (0,
|
|
1024
|
-
/* @__PURE__ */ (0,
|
|
1222
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
1223
|
+
/* @__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" }) }),
|
|
1224
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
|
|
1025
1225
|
] })
|
|
1026
1226
|
] }),
|
|
1027
|
-
/* @__PURE__ */ (0,
|
|
1028
|
-
/* @__PURE__ */ (0,
|
|
1029
|
-
/* @__PURE__ */ (0,
|
|
1227
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
|
|
1228
|
+
/* @__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: [
|
|
1229
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1030
1230
|
"textarea",
|
|
1031
1231
|
{
|
|
1032
1232
|
value: activePrompt,
|
|
@@ -1035,48 +1235,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1035
1235
|
placeholder: "W\xE4hle einen Knoten oder tippe einen Prompt..."
|
|
1036
1236
|
}
|
|
1037
1237
|
),
|
|
1038
|
-
activePrompt && !isSynthesizing && /* @__PURE__ */ (0,
|
|
1238
|
+
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
1239
|
] }) }) }),
|
|
1040
|
-
/* @__PURE__ */ (0,
|
|
1041
|
-
isGenerating && currentResult?.status === "done" && /* @__PURE__ */ (0,
|
|
1042
|
-
/* @__PURE__ */ (0,
|
|
1043
|
-
/* @__PURE__ */ (0,
|
|
1240
|
+
/* @__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: [
|
|
1241
|
+
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: [
|
|
1242
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
|
|
1243
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
|
|
1044
1244
|
] }),
|
|
1045
|
-
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ (0,
|
|
1046
|
-
/* @__PURE__ */ (0,
|
|
1047
|
-
/* @__PURE__ */ (0,
|
|
1048
|
-
] }) : currentResult.status === "error" ? /* @__PURE__ */ (0,
|
|
1049
|
-
/* @__PURE__ */ (0,
|
|
1050
|
-
/* @__PURE__ */ (0,
|
|
1051
|
-
/* @__PURE__ */ (0,
|
|
1052
|
-
/* @__PURE__ */ (0,
|
|
1245
|
+
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col items-center gap-4", children: [
|
|
1246
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
|
|
1247
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
1248
|
+
] }) : 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: [
|
|
1249
|
+
/* @__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" }) }),
|
|
1250
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col gap-2", children: [
|
|
1251
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
|
|
1053
1253
|
] }),
|
|
1054
|
-
/* @__PURE__ */ (0,
|
|
1055
|
-
] }) : /* @__PURE__ */ (0,
|
|
1056
|
-
/* @__PURE__ */ (0,
|
|
1057
|
-
/* @__PURE__ */ (0,
|
|
1058
|
-
/* @__PURE__ */ (0,
|
|
1059
|
-
/* @__PURE__ */ (0,
|
|
1060
|
-
/* @__PURE__ */ (0,
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
|
|
1255
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "h-full w-full relative flex items-center justify-center", children: [
|
|
1256
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
|
|
1257
|
+
/* @__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: [
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
|
|
1259
|
+
/* @__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" }),
|
|
1260
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
|
|
1061
1261
|
] })
|
|
1062
|
-
] }) : /* @__PURE__ */ (0,
|
|
1063
|
-
/* @__PURE__ */ (0,
|
|
1064
|
-
/* @__PURE__ */ (0,
|
|
1262
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
1263
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
1065
1265
|
] })
|
|
1066
1266
|
] }) })
|
|
1067
1267
|
] })
|
|
1068
1268
|
] }),
|
|
1069
|
-
/* @__PURE__ */ (0,
|
|
1070
|
-
/* @__PURE__ */ (0,
|
|
1071
|
-
/* @__PURE__ */ (0,
|
|
1269
|
+
/* @__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: [
|
|
1270
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
|
|
1271
|
+
/* @__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
1272
|
setActiveTab(tab);
|
|
1073
1273
|
setIsRightCollapsed(false);
|
|
1074
|
-
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ (0,
|
|
1075
|
-
/* @__PURE__ */ (0,
|
|
1274
|
+
}, 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)) }),
|
|
1275
|
+
/* @__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
1276
|
] }),
|
|
1077
|
-
!isRightCollapsed && /* @__PURE__ */ (0,
|
|
1078
|
-
activeTab === "history" && /* @__PURE__ */ (0,
|
|
1079
|
-
activeTab === "gallery" && /* @__PURE__ */ (0,
|
|
1277
|
+
!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: [
|
|
1278
|
+
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"),
|
|
1279
|
+
activeTab === "gallery" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1080
1280
|
MediaLibrary,
|
|
1081
1281
|
{
|
|
1082
1282
|
items: galleryItems,
|
|
@@ -1102,8 +1302,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1102
1302
|
},
|
|
1103
1303
|
"gallery"
|
|
1104
1304
|
),
|
|
1105
|
-
activeTab === "inspect" && /* @__PURE__ */ (0,
|
|
1106
|
-
activeTab === "setup" && /* @__PURE__ */ (0,
|
|
1305
|
+
activeTab === "inspect" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(InspectPanel, { currentResult, history, onSelect: setCurrentResult }, "inspect"),
|
|
1306
|
+
activeTab === "setup" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1107
1307
|
SetupPanel,
|
|
1108
1308
|
{
|
|
1109
1309
|
onProjectExport: handleProjectExport,
|
|
@@ -1128,11 +1328,13 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1128
1328
|
ListView,
|
|
1129
1329
|
MediaLibrary,
|
|
1130
1330
|
PillButton,
|
|
1331
|
+
PromptTab,
|
|
1131
1332
|
SectionLabel,
|
|
1132
1333
|
SetupPanel,
|
|
1133
1334
|
buildFallbackPrompt,
|
|
1134
1335
|
buildGenerationPrompt,
|
|
1135
1336
|
buildImageGenerationOptions,
|
|
1337
|
+
buildPromptTabPayload,
|
|
1136
1338
|
cleanAiResponse,
|
|
1137
1339
|
exportProjectToZip,
|
|
1138
1340
|
formatTreeToMarkdown,
|
|
@@ -1141,6 +1343,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1141
1343
|
injectXMPMetadata,
|
|
1142
1344
|
interpretSdkError,
|
|
1143
1345
|
parsePromptFile,
|
|
1346
|
+
parsePromptResponse,
|
|
1144
1347
|
useKeyboardNavigation,
|
|
1145
1348
|
useOnClickOutside
|
|
1146
1349
|
});
|
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
|
|
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] =
|
|
774
|
-
const [edges, setEdges] =
|
|
775
|
-
const [history, setHistory] =
|
|
776
|
-
const [galleryItems, setGalleryItems] =
|
|
777
|
-
const [activePrompt, setActivePrompt] =
|
|
778
|
-
const [isSynthesizing, setIsSynthesizing] =
|
|
779
|
-
const [activeGenerationsCount, setActiveGenerationsCount] =
|
|
780
|
-
const [currentResult, setCurrentResult] =
|
|
781
|
-
const [focusedNodeId, setFocusedNodeId] =
|
|
782
|
-
const [
|
|
783
|
-
const [
|
|
784
|
-
const [
|
|
785
|
-
const [
|
|
786
|
-
const [
|
|
787
|
-
const [
|
|
788
|
-
const [
|
|
789
|
-
const [
|
|
790
|
-
const [
|
|
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) => {
|
|
@@ -831,7 +968,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
831
968
|
if (!options.silent) setCurrentResult(newGen);
|
|
832
969
|
if (seedMode === "random") setSeed(activeSeed);
|
|
833
970
|
try {
|
|
834
|
-
const { base64, mediaId } = await onGenerateImage(promptToUse, aspectRatio, selectedModel, useReferenceId);
|
|
971
|
+
const { base64, mediaId } = await onGenerateImage(buildImageGenerationOptions(promptToUse, aspectRatio, selectedModel, useReferenceId));
|
|
835
972
|
const finishedGen = { ...newGen, status: "done", base64: `data:image/png;base64,${base64}`, mediaId };
|
|
836
973
|
setHistory((prev) => prev.map((g) => g.id === genId ? finishedGen : g));
|
|
837
974
|
setGalleryItems((prev) => [finishedGen, ...prev]);
|
|
@@ -851,7 +988,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
851
988
|
const handleSynthesizePrompt = async (nodeId, autoGenerate = false) => {
|
|
852
989
|
setIsSynthesizing(true);
|
|
853
990
|
try {
|
|
854
|
-
const
|
|
991
|
+
const payload = buildGenerationPrompt(getSubtreeFormat(nodeId));
|
|
992
|
+
const raw = await onGeneratePrompt(payload);
|
|
993
|
+
const prompt = cleanAiResponse(raw);
|
|
855
994
|
setActivePrompt(prompt);
|
|
856
995
|
setFocusedNodeId(nodeId);
|
|
857
996
|
if (autoGenerate) handleGenerateImage(prompt, void 0, nodeId);
|
|
@@ -861,6 +1000,22 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
861
1000
|
setIsSynthesizing(false);
|
|
862
1001
|
}
|
|
863
1002
|
};
|
|
1003
|
+
const handlePromptTabGenerate = async (selectedValues, instructions) => {
|
|
1004
|
+
setIsPromptTabGenerating(true);
|
|
1005
|
+
setPromptFeedback(null);
|
|
1006
|
+
try {
|
|
1007
|
+
const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
|
|
1008
|
+
const payload = buildPromptTabPayload(selectedValues, instructions, treeText);
|
|
1009
|
+
const raw = await onGeneratePrompt(payload);
|
|
1010
|
+
const { prompt, feedback } = parsePromptResponse(raw);
|
|
1011
|
+
setActivePrompt(prompt);
|
|
1012
|
+
setPromptFeedback(feedback);
|
|
1013
|
+
} catch {
|
|
1014
|
+
setActivePrompt("Synthese-Fehler");
|
|
1015
|
+
} finally {
|
|
1016
|
+
setIsPromptTabGenerating(false);
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
864
1019
|
const handleDownloadSingle = async () => {
|
|
865
1020
|
if (!currentResult?.base64) return;
|
|
866
1021
|
try {
|
|
@@ -916,58 +1071,100 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
916
1071
|
const root = JSON.parse(ev.target?.result);
|
|
917
1072
|
const rawTags = root.tags || root;
|
|
918
1073
|
if (!rawTags?.by_category) return;
|
|
1074
|
+
const filtered = {};
|
|
1075
|
+
const EXCLUDED = ["pdf-export", "book.micro-edit-rules"];
|
|
1076
|
+
Object.entries(rawTags.by_category).forEach(([cat, items]) => {
|
|
1077
|
+
if (EXCLUDED.includes(cat) || !Array.isArray(items)) return;
|
|
1078
|
+
filtered[cat] = items.filter((t) => t && typeof t === "object" && t.label && t.value);
|
|
1079
|
+
});
|
|
1080
|
+
const filteredAll = (rawTags.all || []).filter((t) => t && !EXCLUDED.includes(t.category));
|
|
1081
|
+
setWorkspaceTags({ by_category: filtered, all: filteredAll });
|
|
919
1082
|
} catch (err) {
|
|
920
1083
|
console.error("Workspace Load failed", err);
|
|
921
1084
|
}
|
|
922
1085
|
};
|
|
923
1086
|
reader.readAsText(file);
|
|
924
1087
|
};
|
|
925
|
-
return /* @__PURE__ */
|
|
926
|
-
/* @__PURE__ */
|
|
927
|
-
/* @__PURE__ */
|
|
928
|
-
!isLeftCollapsed && /* @__PURE__ */
|
|
929
|
-
|
|
1088
|
+
return /* @__PURE__ */ jsxs9("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", children: [
|
|
1089
|
+
/* @__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: [
|
|
1090
|
+
/* @__PURE__ */ jsxs9("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
|
|
1091
|
+
!isLeftCollapsed && /* @__PURE__ */ jsxs9("div", { className: "flex flex-1 gap-1", children: [
|
|
1092
|
+
/* @__PURE__ */ jsxs9(
|
|
1093
|
+
"button",
|
|
1094
|
+
{
|
|
1095
|
+
onClick: () => setLeftTab("hierarchy"),
|
|
1096
|
+
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"}`,
|
|
1097
|
+
children: [
|
|
1098
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
|
|
1099
|
+
"Hierarchie"
|
|
1100
|
+
]
|
|
1101
|
+
}
|
|
1102
|
+
),
|
|
1103
|
+
workspaceTags && /* @__PURE__ */ jsxs9(
|
|
1104
|
+
"button",
|
|
1105
|
+
{
|
|
1106
|
+
onClick: () => setLeftTab("prompt"),
|
|
1107
|
+
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"}`,
|
|
1108
|
+
children: [
|
|
1109
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
|
|
1110
|
+
"Prompt"
|
|
1111
|
+
]
|
|
1112
|
+
}
|
|
1113
|
+
)
|
|
1114
|
+
] }),
|
|
1115
|
+
/* @__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
1116
|
] }),
|
|
931
|
-
!isLeftCollapsed && /* @__PURE__ */
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1117
|
+
!isLeftCollapsed && /* @__PURE__ */ jsx11("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ jsxs9(AnimatePresence2, { mode: "wait", children: [
|
|
1118
|
+
leftTab === "hierarchy" && /* @__PURE__ */ jsx11(motion6.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ jsx11(
|
|
1119
|
+
ListView,
|
|
1120
|
+
{
|
|
1121
|
+
nodes,
|
|
1122
|
+
edges,
|
|
1123
|
+
onNodeChange: (id, l) => setNodes((nds) => nds.map((n) => n.id === id ? { ...n, data: { ...n.data, label: l } } : n)),
|
|
1124
|
+
onAddChild: (pId) => {
|
|
1125
|
+
const newId = crypto.randomUUID();
|
|
1126
|
+
setNodes((nds) => [...nds, { id: newId, type: "custom", position: { x: 0, y: 0 }, data: { label: "", placeholder: "Konzept..." } }]);
|
|
1127
|
+
setEdges((eds) => [...eds, { id: `e-${pId}-${newId}`, source: pId, target: newId }]);
|
|
1128
|
+
setFocusedNodeId(newId);
|
|
1129
|
+
return newId;
|
|
1130
|
+
},
|
|
1131
|
+
onDeleteNode: (id) => {
|
|
1132
|
+
setNodes((nds) => nds.filter((n) => n.id !== id));
|
|
1133
|
+
setEdges((eds) => eds.filter((e) => e.source !== id && e.target !== id));
|
|
1134
|
+
},
|
|
1135
|
+
onFocus: setFocusedNodeId,
|
|
1136
|
+
focusedNodeId,
|
|
1137
|
+
activePath,
|
|
1138
|
+
onGenerate: handleSynthesizePrompt,
|
|
1139
|
+
onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
|
|
1140
|
+
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
1141
|
+
}
|
|
1142
|
+
) }, "hierarchy"),
|
|
1143
|
+
leftTab === "prompt" && workspaceTags && /* @__PURE__ */ jsx11(motion6.div, { className: "absolute inset-0", initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, children: /* @__PURE__ */ jsx11(
|
|
1144
|
+
PromptTab,
|
|
1145
|
+
{
|
|
1146
|
+
workspaceTags,
|
|
1147
|
+
onGenerate: handlePromptTabGenerate,
|
|
1148
|
+
isGenerating: isPromptTabGenerating,
|
|
1149
|
+
feedback: promptFeedback
|
|
1150
|
+
}
|
|
1151
|
+
) }, "prompt")
|
|
1152
|
+
] }) })
|
|
956
1153
|
] }),
|
|
957
|
-
/* @__PURE__ */
|
|
958
|
-
/* @__PURE__ */
|
|
959
|
-
/* @__PURE__ */
|
|
960
|
-
/* @__PURE__ */
|
|
961
|
-
/* @__PURE__ */
|
|
1154
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
|
|
1155
|
+
/* @__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: [
|
|
1156
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1.5", children: [
|
|
1157
|
+
/* @__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" }] }),
|
|
1158
|
+
/* @__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
1159
|
] }),
|
|
963
|
-
/* @__PURE__ */
|
|
964
|
-
/* @__PURE__ */
|
|
965
|
-
/* @__PURE__ */
|
|
1160
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
1161
|
+
/* @__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" }) }),
|
|
1162
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
|
|
966
1163
|
] })
|
|
967
1164
|
] }),
|
|
968
|
-
/* @__PURE__ */
|
|
969
|
-
/* @__PURE__ */
|
|
970
|
-
/* @__PURE__ */
|
|
1165
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
|
|
1166
|
+
/* @__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: [
|
|
1167
|
+
/* @__PURE__ */ jsx11(
|
|
971
1168
|
"textarea",
|
|
972
1169
|
{
|
|
973
1170
|
value: activePrompt,
|
|
@@ -976,48 +1173,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
976
1173
|
placeholder: "W\xE4hle einen Knoten oder tippe einen Prompt..."
|
|
977
1174
|
}
|
|
978
1175
|
),
|
|
979
|
-
activePrompt && !isSynthesizing && /* @__PURE__ */
|
|
1176
|
+
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
1177
|
] }) }) }),
|
|
981
|
-
/* @__PURE__ */
|
|
982
|
-
isGenerating && currentResult?.status === "done" && /* @__PURE__ */
|
|
983
|
-
/* @__PURE__ */
|
|
984
|
-
/* @__PURE__ */
|
|
1178
|
+
/* @__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: [
|
|
1179
|
+
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: [
|
|
1180
|
+
/* @__PURE__ */ jsx11("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
|
|
1181
|
+
/* @__PURE__ */ jsx11("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
|
|
985
1182
|
] }),
|
|
986
|
-
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */
|
|
987
|
-
/* @__PURE__ */
|
|
988
|
-
/* @__PURE__ */
|
|
989
|
-
] }) : currentResult.status === "error" ? /* @__PURE__ */
|
|
990
|
-
/* @__PURE__ */
|
|
991
|
-
/* @__PURE__ */
|
|
992
|
-
/* @__PURE__ */
|
|
993
|
-
/* @__PURE__ */
|
|
1183
|
+
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center gap-4", children: [
|
|
1184
|
+
/* @__PURE__ */ jsx11("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
|
|
1185
|
+
/* @__PURE__ */ jsx11("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
1186
|
+
] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs9("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
|
|
1187
|
+
/* @__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" }) }),
|
|
1188
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-2", children: [
|
|
1189
|
+
/* @__PURE__ */ jsx11("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
|
|
1190
|
+
/* @__PURE__ */ jsx11("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
|
|
994
1191
|
] }),
|
|
995
|
-
/* @__PURE__ */
|
|
996
|
-
] }) : /* @__PURE__ */
|
|
997
|
-
/* @__PURE__ */
|
|
998
|
-
/* @__PURE__ */
|
|
999
|
-
/* @__PURE__ */
|
|
1000
|
-
/* @__PURE__ */
|
|
1001
|
-
/* @__PURE__ */
|
|
1192
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
|
|
1193
|
+
] }) : /* @__PURE__ */ jsxs9("div", { className: "h-full w-full relative flex items-center justify-center", children: [
|
|
1194
|
+
/* @__PURE__ */ jsx11("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
|
|
1195
|
+
/* @__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: [
|
|
1196
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
|
|
1197
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
|
|
1198
|
+
/* @__PURE__ */ jsx11(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
|
|
1002
1199
|
] })
|
|
1003
|
-
] }) : /* @__PURE__ */
|
|
1004
|
-
/* @__PURE__ */
|
|
1005
|
-
/* @__PURE__ */
|
|
1200
|
+
] }) : /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
1201
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
|
|
1202
|
+
/* @__PURE__ */ jsx11("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
1006
1203
|
] })
|
|
1007
1204
|
] }) })
|
|
1008
1205
|
] })
|
|
1009
1206
|
] }),
|
|
1010
|
-
/* @__PURE__ */
|
|
1011
|
-
/* @__PURE__ */
|
|
1012
|
-
/* @__PURE__ */
|
|
1207
|
+
/* @__PURE__ */ jsxs9(motion6.div, { animate: { width: isRightCollapsed ? 60 : 320 }, className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", children: [
|
|
1208
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
|
|
1209
|
+
/* @__PURE__ */ jsx11("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup"].map((tab) => /* @__PURE__ */ jsx11("button", { onClick: () => {
|
|
1013
1210
|
setActiveTab(tab);
|
|
1014
1211
|
setIsRightCollapsed(false);
|
|
1015
|
-
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */
|
|
1016
|
-
/* @__PURE__ */
|
|
1212
|
+
}, 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)) }),
|
|
1213
|
+
/* @__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
1214
|
] }),
|
|
1018
|
-
!isRightCollapsed && /* @__PURE__ */
|
|
1019
|
-
activeTab === "history" && /* @__PURE__ */
|
|
1020
|
-
activeTab === "gallery" && /* @__PURE__ */
|
|
1215
|
+
!isRightCollapsed && /* @__PURE__ */ jsx11("div", { className: "flex-1 overflow-hidden relative", children: /* @__PURE__ */ jsxs9(AnimatePresence2, { mode: "wait", children: [
|
|
1216
|
+
activeTab === "history" && /* @__PURE__ */ jsx11(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }, "history"),
|
|
1217
|
+
activeTab === "gallery" && /* @__PURE__ */ jsx11(
|
|
1021
1218
|
MediaLibrary,
|
|
1022
1219
|
{
|
|
1023
1220
|
items: galleryItems,
|
|
@@ -1043,8 +1240,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1043
1240
|
},
|
|
1044
1241
|
"gallery"
|
|
1045
1242
|
),
|
|
1046
|
-
activeTab === "inspect" && /* @__PURE__ */
|
|
1047
|
-
activeTab === "setup" && /* @__PURE__ */
|
|
1243
|
+
activeTab === "inspect" && /* @__PURE__ */ jsx11(InspectPanel, { currentResult, history, onSelect: setCurrentResult }, "inspect"),
|
|
1244
|
+
activeTab === "setup" && /* @__PURE__ */ jsx11(
|
|
1048
1245
|
SetupPanel,
|
|
1049
1246
|
{
|
|
1050
1247
|
onProjectExport: handleProjectExport,
|
|
@@ -1068,11 +1265,13 @@ export {
|
|
|
1068
1265
|
ListView,
|
|
1069
1266
|
MediaLibrary,
|
|
1070
1267
|
PillButton,
|
|
1268
|
+
PromptTab,
|
|
1071
1269
|
SectionLabel,
|
|
1072
1270
|
SetupPanel,
|
|
1073
1271
|
buildFallbackPrompt,
|
|
1074
1272
|
buildGenerationPrompt,
|
|
1075
1273
|
buildImageGenerationOptions,
|
|
1274
|
+
buildPromptTabPayload,
|
|
1076
1275
|
cleanAiResponse,
|
|
1077
1276
|
exportProjectToZip,
|
|
1078
1277
|
formatTreeToMarkdown,
|
|
@@ -1081,6 +1280,7 @@ export {
|
|
|
1081
1280
|
injectXMPMetadata,
|
|
1082
1281
|
interpretSdkError,
|
|
1083
1282
|
parsePromptFile,
|
|
1283
|
+
parsePromptResponse,
|
|
1084
1284
|
useKeyboardNavigation,
|
|
1085
1285
|
useOnClickOutside
|
|
1086
1286
|
};
|