@rslsp1/fa-app-tools 1.0.2 → 1.0.4
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 +102 -9
- package/dist/index.d.ts +102 -9
- package/dist/index.js +1599 -261
- package/dist/index.mjs +1581 -246
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -197,7 +197,7 @@ function generateMarkdownReport(nodes, history) {
|
|
|
197
197
|
});
|
|
198
198
|
return md;
|
|
199
199
|
}
|
|
200
|
-
async function exportProjectToZip(nodes, edges, history, galleryItems, settings) {
|
|
200
|
+
async function exportProjectToZip(nodes, edges, history, galleryItems, settings, workspaceTags) {
|
|
201
201
|
const zip = new JSZip();
|
|
202
202
|
const projectData = {
|
|
203
203
|
nodes,
|
|
@@ -205,6 +205,7 @@ async function exportProjectToZip(nodes, edges, history, galleryItems, settings)
|
|
|
205
205
|
history: history.map((h) => ({ ...h, base64: void 0 })),
|
|
206
206
|
galleryItems: galleryItems.map((g) => ({ ...g, base64: void 0 })),
|
|
207
207
|
settings,
|
|
208
|
+
workspaceTags: workspaceTags || null,
|
|
208
209
|
version: "1.2.6"
|
|
209
210
|
};
|
|
210
211
|
zip.file("project.json", JSON.stringify(projectData, null, 2));
|
|
@@ -293,14 +294,44 @@ function buildImageGenerationOptions(prompt, aspectRatio, model, referenceMediaI
|
|
|
293
294
|
}
|
|
294
295
|
return options;
|
|
295
296
|
}
|
|
296
|
-
|
|
297
|
+
var CONTENT_FIRST = ["subject", "clothing", "environment", "mood", "action", "content", "general"];
|
|
298
|
+
var RULES_LAST = ["system", "rules", "safety", "generated", "source", "status", "type", "model"];
|
|
299
|
+
function categoryZone(cat) {
|
|
300
|
+
const c = cat.toLowerCase();
|
|
301
|
+
if (CONTENT_FIRST.some((k) => c.includes(k))) return 0;
|
|
302
|
+
if (RULES_LAST.some((k) => c.includes(k))) return 2;
|
|
303
|
+
return 1;
|
|
304
|
+
}
|
|
305
|
+
var ZONE_SEPARATORS = { 1: "\u2500\u2500\u2500\u2500 STYLE \u2500\u2500\u2500\u2500", 2: "\u2500\u2500\u2500\u2500 SYSTEM / RULES \u2500\u2500\u2500\u2500" };
|
|
306
|
+
function buildPromptTabPayload(selectedTags, instructions, rules, treeText) {
|
|
297
307
|
const parts = [];
|
|
298
308
|
if (treeText) parts.push(`HIERARCHY:
|
|
299
309
|
${treeText}`);
|
|
300
|
-
if (
|
|
301
|
-
|
|
302
|
-
|
|
310
|
+
if (selectedTags.length > 0) {
|
|
311
|
+
const sorted = [...selectedTags].sort((a, b) => categoryZone(a.category) - categoryZone(b.category) || a.category.localeCompare(b.category));
|
|
312
|
+
const byCategory = sorted.reduce((acc, t) => {
|
|
313
|
+
(acc[t.category] = acc[t.category] || []).push(t);
|
|
314
|
+
return acc;
|
|
315
|
+
}, {});
|
|
316
|
+
const tagParts = [];
|
|
317
|
+
let lastZone = -1;
|
|
318
|
+
for (const [cat, tags] of Object.entries(byCategory)) {
|
|
319
|
+
const zone = categoryZone(cat);
|
|
320
|
+
if (lastZone >= 0 && zone > lastZone && ZONE_SEPARATORS[zone]) {
|
|
321
|
+
tagParts.push(ZONE_SEPARATORS[zone]);
|
|
322
|
+
}
|
|
323
|
+
tagParts.push(...tags.map((t) => `[${cat.toUpperCase()}]
|
|
324
|
+
${t.value}`));
|
|
325
|
+
lastZone = zone;
|
|
326
|
+
}
|
|
327
|
+
parts.push(`SELECTED TAGS:
|
|
328
|
+
|
|
329
|
+
${tagParts.join("\n\n")}`);
|
|
330
|
+
}
|
|
331
|
+
if (instructions.trim()) parts.push(`DESCRIPTION:
|
|
303
332
|
${instructions.trim()}`);
|
|
333
|
+
if (rules.trim()) parts.push(`GENERATION RULES:
|
|
334
|
+
${rules.trim()}`);
|
|
304
335
|
return [
|
|
305
336
|
"Create a high-quality image generation prompt based on the following inputs. Translate everything to English.",
|
|
306
337
|
`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).`,
|
|
@@ -320,6 +351,33 @@ function parsePromptResponse(raw) {
|
|
|
320
351
|
}
|
|
321
352
|
return { prompt: cleaned, feedback: null };
|
|
322
353
|
}
|
|
354
|
+
function createFlowServices(Flow) {
|
|
355
|
+
return {
|
|
356
|
+
generateImage: async (options) => {
|
|
357
|
+
try {
|
|
358
|
+
const result = await Flow.generate.image(options);
|
|
359
|
+
if (!result?.base64) throw new Error("Keine Bilddaten vom SDK erhalten.");
|
|
360
|
+
return { base64: result.base64, mediaId: result.mediaId };
|
|
361
|
+
} catch (err) {
|
|
362
|
+
throw interpretSdkError(err);
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
generateText: async (hierarchyText, mode = "creative") => {
|
|
366
|
+
const prompt = buildGenerationPrompt(hierarchyText, mode);
|
|
367
|
+
try {
|
|
368
|
+
const response = await Flow.generate.text(prompt, {
|
|
369
|
+
thinkingLevel: "low",
|
|
370
|
+
systemInstruction: "You are an expert prompt engineer. Always return ONLY the generated prompt text, no headers, no quotes, no conversational filler."
|
|
371
|
+
});
|
|
372
|
+
const result = response?.text?.trim() || "";
|
|
373
|
+
if (!result) throw new Error("Empty AI response");
|
|
374
|
+
return cleanAiResponse(result);
|
|
375
|
+
} catch {
|
|
376
|
+
return buildFallbackPrompt(hierarchyText);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
}
|
|
323
381
|
function interpretSdkError(err) {
|
|
324
382
|
const msg = err?.message || "Generierung fehlgeschlagen";
|
|
325
383
|
if (msg.includes("PUBLIC_ERROR_SOMETHING_WENT_WRONG")) {
|
|
@@ -529,9 +587,11 @@ var HistoryPanel = ({ history, currentResultId, onSelect, onDelete }) => {
|
|
|
529
587
|
};
|
|
530
588
|
|
|
531
589
|
// src/components/InspectPanel.tsx
|
|
590
|
+
import { useMemo } from "react";
|
|
532
591
|
import { motion as motion2 } from "motion/react";
|
|
533
|
-
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
592
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
534
593
|
var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagToggle }) => {
|
|
594
|
+
const currentIndex = useMemo(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
|
|
535
595
|
if (!currentResult) {
|
|
536
596
|
return /* @__PURE__ */ jsxs4("div", { className: "flex flex-col items-center justify-center py-20 text-center gap-4 opacity-10", children: [
|
|
537
597
|
/* @__PURE__ */ jsx6("span", { className: "material-symbols-outlined text-[64px]", children: "info" }),
|
|
@@ -543,7 +603,18 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
|
|
|
543
603
|
/* @__PURE__ */ jsx6("div", { className: "flex-shrink-0 border-b border-white/5 bg-black/20 py-3 px-4", children: /* @__PURE__ */ jsx6("div", { className: "flex gap-2 overflow-x-auto no-scrollbar pb-1", children: history.map((gen) => /* @__PURE__ */ jsx6("button", { onClick: () => onSelect(gen), className: `w-10 h-10 rounded-lg overflow-hidden border shrink-0 transition-all ${currentResult.id === gen.id ? "border-white scale-105 shadow-lg" : "border-white/5 opacity-40 hover:opacity-100"}`, children: /* @__PURE__ */ jsx6("img", { src: gen.base64 ? gen.base64.startsWith("data:") ? gen.base64 : `data:image/png;base64,${gen.base64}` : "", className: "w-full h-full object-cover", alt: "Thumbnail" }) }, gen.id)) }) }),
|
|
544
604
|
/* @__PURE__ */ jsx6("div", { className: "flex-1 overflow-y-auto p-4 flex flex-col gap-6 dark-scrollbar pb-10", children: /* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-4", children: [
|
|
545
605
|
/* @__PURE__ */ jsx6(SectionLabel, { children: "Vorschau" }),
|
|
546
|
-
/* @__PURE__ */
|
|
606
|
+
/* @__PURE__ */ jsxs4("div", { className: "aspect-square w-full rounded-2xl bg-black overflow-hidden border border-white/10 shadow-2xl relative", children: [
|
|
607
|
+
/* @__PURE__ */ jsx6("img", { src: currentResult.base64 ? currentResult.base64.startsWith("data:") ? currentResult.base64 : `data:image/png;base64,${currentResult.base64}` : "", className: "w-full h-full object-cover", alt: "Preview" }),
|
|
608
|
+
history.length > 1 && /* @__PURE__ */ jsxs4(Fragment, { children: [
|
|
609
|
+
/* @__PURE__ */ jsx6("button", { onClick: () => currentIndex > 0 && onSelect(history[currentIndex - 1]), disabled: currentIndex <= 0, className: "absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ jsx6("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
|
|
610
|
+
/* @__PURE__ */ jsx6("button", { onClick: () => currentIndex < history.length - 1 && onSelect(history[currentIndex + 1]), disabled: currentIndex >= history.length - 1, className: "absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ jsx6("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
|
|
611
|
+
/* @__PURE__ */ jsxs4("div", { className: "absolute bottom-2 left-1/2 -translate-x-1/2 bg-black/60 rounded-full px-3 py-0.5 text-[10px] text-white/40 font-mono", children: [
|
|
612
|
+
currentIndex + 1,
|
|
613
|
+
" / ",
|
|
614
|
+
history.length
|
|
615
|
+
] })
|
|
616
|
+
] })
|
|
617
|
+
] }),
|
|
547
618
|
/* @__PURE__ */ jsxs4("div", { className: "p-4 bg-white/5 rounded-2xl border border-white/5", children: [
|
|
548
619
|
/* @__PURE__ */ jsx6("p", { className: "text-[8px] font-bold text-white/20 uppercase mb-2 tracking-widest", children: "Prompt Details" }),
|
|
549
620
|
/* @__PURE__ */ jsxs4("p", { className: "text-[10px] text-white/70 italic leading-relaxed font-medium", children: [
|
|
@@ -584,9 +655,8 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
|
|
|
584
655
|
import { useRef as useRef2 } from "react";
|
|
585
656
|
import { motion as motion3 } from "motion/react";
|
|
586
657
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
587
|
-
var SetupPanel = ({ onWorkspaceImport,
|
|
658
|
+
var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
|
|
588
659
|
const workspaceInputRef = useRef2(null);
|
|
589
|
-
const projectInputRef = useRef2(null);
|
|
590
660
|
return /* @__PURE__ */ jsxs5(motion3.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10", children: [
|
|
591
661
|
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-4", children: [
|
|
592
662
|
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", children: [
|
|
@@ -600,30 +670,15 @@ var SetupPanel = ({ onWorkspaceImport, onProjectExport, onProjectImport, project
|
|
|
600
670
|
e.target.value = "";
|
|
601
671
|
} })
|
|
602
672
|
] }),
|
|
603
|
-
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-4", children: [
|
|
604
|
-
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", children: [
|
|
605
|
-
/* @__PURE__ */ jsx7(SectionLabel, { children: "Projekt Management" }),
|
|
606
|
-
/* @__PURE__ */ jsx7("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Speichere den gesamten Baum und alle Assets." })
|
|
607
|
-
] }),
|
|
608
|
-
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
|
|
609
|
-
/* @__PURE__ */ jsx7(PillButton, { variant: "filled", icon: "download", onClick: onProjectExport, loading: projectActionState === "working", children: "Exportieren (.zip)" }),
|
|
610
|
-
/* @__PURE__ */ jsx7(PillButton, { variant: "outline", icon: "upload", onClick: () => projectInputRef.current?.click(), children: "Projekt laden (.zip)" }),
|
|
611
|
-
/* @__PURE__ */ jsx7("input", { ref: projectInputRef, type: "file", accept: ".zip", className: "hidden", onChange: (e) => {
|
|
612
|
-
const f = e.target.files?.[0];
|
|
613
|
-
if (f) onProjectImport(f);
|
|
614
|
-
e.target.value = "";
|
|
615
|
-
} })
|
|
616
|
-
] })
|
|
617
|
-
] }),
|
|
618
673
|
/* @__PURE__ */ jsxs5("div", { className: "mt-auto p-4 bg-white/5 rounded-2xl border border-white/5 flex flex-col gap-2 opacity-50", children: [
|
|
619
674
|
/* @__PURE__ */ jsx7("span", { className: "text-[8px] font-bold text-white/20 uppercase tracking-widest", children: "System Info" }),
|
|
620
|
-
/* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between text-[9px] text-white/40", children: [
|
|
621
|
-
/* @__PURE__ */ jsx7("span", { children: "Version" }),
|
|
622
|
-
/* @__PURE__ */ jsx7("span", { className: "font-mono", children: "1.2.0" })
|
|
623
|
-
] }),
|
|
624
675
|
/* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between text-[9px] text-white/40", children: [
|
|
625
676
|
/* @__PURE__ */ jsx7("span", { children: "Engine" }),
|
|
626
677
|
/* @__PURE__ */ jsx7("span", { className: "font-mono", children: "Avatar Architect" })
|
|
678
|
+
] }),
|
|
679
|
+
buildInfo && /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between text-[9px] text-white/40", children: [
|
|
680
|
+
/* @__PURE__ */ jsx7("span", { children: "Build" }),
|
|
681
|
+
/* @__PURE__ */ jsx7("span", { className: "font-mono", children: buildInfo })
|
|
627
682
|
] })
|
|
628
683
|
] })
|
|
629
684
|
] });
|
|
@@ -784,17 +839,84 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
|
|
|
784
839
|
}
|
|
785
840
|
|
|
786
841
|
// src/components/AvatarArchitectApp.tsx
|
|
787
|
-
import { useState as
|
|
788
|
-
import { motion as motion6, AnimatePresence as AnimatePresence2 } from "motion/react";
|
|
842
|
+
import { useState as useState6, useCallback, useMemo as useMemo2, useEffect as useEffect4, useRef as useRef6 } from "react";
|
|
789
843
|
|
|
790
844
|
// src/components/PromptTab.tsx
|
|
845
|
+
import { useRef as useRef4, useState as useState4 } from "react";
|
|
846
|
+
|
|
847
|
+
// src/components/CollapsibleCard.tsx
|
|
791
848
|
import { useState as useState3 } from "react";
|
|
792
|
-
import { motion as motion5, AnimatePresence } from "motion/react";
|
|
793
849
|
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
794
|
-
var
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
850
|
+
var CollapsibleCard = ({
|
|
851
|
+
title,
|
|
852
|
+
icon,
|
|
853
|
+
actions,
|
|
854
|
+
children,
|
|
855
|
+
defaultOpen = true,
|
|
856
|
+
collapsible = true,
|
|
857
|
+
className = ""
|
|
858
|
+
}) => {
|
|
859
|
+
const [isOpen, setIsOpen] = useState3(defaultOpen);
|
|
860
|
+
return /* @__PURE__ */ jsxs8("div", { className: `border border-neutral-800 rounded-lg ${className}`, children: [
|
|
861
|
+
/* @__PURE__ */ jsxs8(
|
|
862
|
+
"div",
|
|
863
|
+
{
|
|
864
|
+
className: `flex items-center justify-between px-4 py-3 bg-neutral-900/50 ${collapsible ? "cursor-pointer active:bg-neutral-800/70 select-none" : ""}`,
|
|
865
|
+
onClick: () => collapsible && setIsOpen((o) => !o),
|
|
866
|
+
children: [
|
|
867
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
868
|
+
icon && /* @__PURE__ */ jsx10("span", { className: "text-neutral-400", children: icon }),
|
|
869
|
+
/* @__PURE__ */ jsx10("span", { className: "text-sm font-bold uppercase tracking-widest text-neutral-300", children: title })
|
|
870
|
+
] }),
|
|
871
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
872
|
+
actions && /* @__PURE__ */ jsx10("div", { onClick: (e) => e.stopPropagation(), children: actions }),
|
|
873
|
+
collapsible && /* @__PURE__ */ jsx10("span", { className: "material-symbols-outlined text-[16px] text-neutral-500", children: isOpen ? "expand_less" : "expand_more" })
|
|
874
|
+
] })
|
|
875
|
+
]
|
|
876
|
+
}
|
|
877
|
+
),
|
|
878
|
+
isOpen && /* @__PURE__ */ jsx10("div", { children })
|
|
879
|
+
] });
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
// src/components/PromptTab.tsx
|
|
883
|
+
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
884
|
+
var EXCLUDED = ["pdf-export", "book.micro-edit-rules"];
|
|
885
|
+
var LONG_PRESS_MS = 500;
|
|
886
|
+
var PromptTab = ({
|
|
887
|
+
workspaceTags,
|
|
888
|
+
onGenerate,
|
|
889
|
+
isGenerating,
|
|
890
|
+
feedback,
|
|
891
|
+
promptResult,
|
|
892
|
+
lastPayload,
|
|
893
|
+
onGenerateImage,
|
|
894
|
+
isGeneratingImage,
|
|
895
|
+
onRandom,
|
|
896
|
+
onTokenize,
|
|
897
|
+
isTokenizing,
|
|
898
|
+
onScanImage,
|
|
899
|
+
isScanning,
|
|
900
|
+
onExpand,
|
|
901
|
+
isExpanding,
|
|
902
|
+
onTagCreate,
|
|
903
|
+
onTagUpdate,
|
|
904
|
+
onTagDelete
|
|
905
|
+
}) => {
|
|
906
|
+
const [selectedLabels, setSelectedLabels] = useState4(/* @__PURE__ */ new Set());
|
|
907
|
+
const [instructions, setInstructions] = useState4("");
|
|
908
|
+
const [rules, setRules] = useState4("");
|
|
909
|
+
const [activeCategory, setActiveCategory] = useState4(null);
|
|
910
|
+
const [copied, setCopied] = useState4(false);
|
|
911
|
+
const imgInputRef = useRef4(null);
|
|
912
|
+
const [addingInCat, setAddingInCat] = useState4(null);
|
|
913
|
+
const [newLabel, setNewLabel] = useState4("");
|
|
914
|
+
const [newValue, setNewValue] = useState4("");
|
|
915
|
+
const [editingTag, setEditingTag] = useState4(null);
|
|
916
|
+
const [editLabel, setEditLabel] = useState4("");
|
|
917
|
+
const [editValue, setEditValue] = useState4("");
|
|
918
|
+
const longPressTimer = useRef4(null);
|
|
919
|
+
const longPressActivated = useRef4(false);
|
|
798
920
|
const toggleTag = (label) => {
|
|
799
921
|
setSelectedLabels((prev) => {
|
|
800
922
|
const next = new Set(prev);
|
|
@@ -804,96 +926,670 @@ var PromptTab = ({ workspaceTags, onGenerate, isGenerating, feedback }) => {
|
|
|
804
926
|
});
|
|
805
927
|
};
|
|
806
928
|
const handleGenerate = () => {
|
|
807
|
-
const
|
|
808
|
-
onGenerate(
|
|
929
|
+
const selectedTags = workspaceTags.all.filter((t) => selectedLabels.has(t.label) && !t.is_deleted).map((t) => ({ label: t.label, value: t.value, category: t.category }));
|
|
930
|
+
onGenerate(selectedTags, instructions, rules);
|
|
809
931
|
};
|
|
810
|
-
const
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
932
|
+
const handleCopy = () => {
|
|
933
|
+
if (!promptResult) return;
|
|
934
|
+
navigator.clipboard.writeText(promptResult).then(() => {
|
|
935
|
+
setCopied(true);
|
|
936
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
937
|
+
});
|
|
938
|
+
};
|
|
939
|
+
const startLongPress = (tag, cat) => {
|
|
940
|
+
longPressActivated.current = false;
|
|
941
|
+
longPressTimer.current = setTimeout(() => {
|
|
942
|
+
longPressActivated.current = true;
|
|
943
|
+
setEditingTag({ ...tag, category: cat });
|
|
944
|
+
setEditLabel(tag.label);
|
|
945
|
+
setEditValue(tag.value);
|
|
946
|
+
}, LONG_PRESS_MS);
|
|
947
|
+
};
|
|
948
|
+
const cancelLongPress = () => {
|
|
949
|
+
if (longPressTimer.current) {
|
|
950
|
+
clearTimeout(longPressTimer.current);
|
|
951
|
+
longPressTimer.current = null;
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
const handleTagClick = (label) => {
|
|
955
|
+
if (longPressActivated.current) return;
|
|
956
|
+
toggleTag(label);
|
|
957
|
+
};
|
|
958
|
+
const handleSaveEdit = () => {
|
|
959
|
+
if (!editingTag || !editLabel.trim()) return;
|
|
960
|
+
onTagUpdate?.(editingTag.label, editingTag.category, {
|
|
961
|
+
label: editLabel.trim(),
|
|
962
|
+
value: editValue.trim() || editLabel.trim()
|
|
963
|
+
});
|
|
964
|
+
setSelectedLabels((prev) => {
|
|
965
|
+
const next = new Set(prev);
|
|
966
|
+
if (next.has(editingTag.label)) {
|
|
967
|
+
next.delete(editingTag.label);
|
|
968
|
+
next.add(editLabel.trim());
|
|
969
|
+
}
|
|
970
|
+
return next;
|
|
971
|
+
});
|
|
972
|
+
setEditingTag(null);
|
|
973
|
+
};
|
|
974
|
+
const handleDeleteTag = () => {
|
|
975
|
+
if (!editingTag) return;
|
|
976
|
+
onTagDelete?.(editingTag.label, editingTag.category);
|
|
977
|
+
setSelectedLabels((prev) => {
|
|
978
|
+
const next = new Set(prev);
|
|
979
|
+
next.delete(editingTag.label);
|
|
980
|
+
return next;
|
|
981
|
+
});
|
|
982
|
+
setEditingTag(null);
|
|
983
|
+
};
|
|
984
|
+
const handleCreateBased = () => {
|
|
985
|
+
if (!editingTag) return;
|
|
986
|
+
setAddingInCat(editingTag.category);
|
|
987
|
+
setActiveCategory(editingTag.category);
|
|
988
|
+
setNewLabel(editingTag.label);
|
|
989
|
+
setNewValue(editingTag.value);
|
|
990
|
+
setEditingTag(null);
|
|
991
|
+
};
|
|
992
|
+
const categories = Object.entries(workspaceTags.by_category).filter(([cat, tags]) => !EXCLUDED.includes(cat) && tags.some((t) => !t.is_deleted));
|
|
993
|
+
const tagToolbar = /* @__PURE__ */ jsxs9("div", { className: "flex gap-1.5", children: [
|
|
994
|
+
/* @__PURE__ */ jsx11(
|
|
995
|
+
"button",
|
|
996
|
+
{
|
|
997
|
+
onClick: onRandom,
|
|
998
|
+
disabled: !onRandom,
|
|
999
|
+
className: "text-[9px] font-bold uppercase px-2 py-1 rounded border border-neutral-700 text-neutral-400 active:bg-neutral-800 disabled:opacity-30",
|
|
1000
|
+
children: "RANDOM"
|
|
1001
|
+
}
|
|
1002
|
+
),
|
|
1003
|
+
/* @__PURE__ */ jsx11(
|
|
1004
|
+
"button",
|
|
1005
|
+
{
|
|
1006
|
+
onClick: onTokenize,
|
|
1007
|
+
disabled: !onTokenize || isTokenizing || !instructions,
|
|
1008
|
+
className: "text-[9px] font-bold uppercase px-2 py-1 rounded border border-neutral-700 text-neutral-400 active:bg-neutral-800 disabled:opacity-30",
|
|
1009
|
+
children: isTokenizing ? "..." : "TOKENIZE"
|
|
1010
|
+
}
|
|
1011
|
+
),
|
|
1012
|
+
/* @__PURE__ */ jsx11(
|
|
1013
|
+
"button",
|
|
1014
|
+
{
|
|
1015
|
+
onClick: () => imgInputRef.current?.click(),
|
|
1016
|
+
disabled: !onScanImage || isScanning,
|
|
1017
|
+
className: "text-[9px] font-bold uppercase px-2 py-1 rounded border border-neutral-700 text-neutral-400 active:bg-neutral-800 disabled:opacity-30",
|
|
1018
|
+
children: isScanning ? "..." : "SCAN"
|
|
1019
|
+
}
|
|
1020
|
+
),
|
|
1021
|
+
/* @__PURE__ */ jsx11(
|
|
1022
|
+
"input",
|
|
1023
|
+
{
|
|
1024
|
+
ref: imgInputRef,
|
|
1025
|
+
type: "file",
|
|
1026
|
+
accept: "image/*",
|
|
1027
|
+
className: "hidden",
|
|
1028
|
+
onChange: (e) => {
|
|
1029
|
+
if (e.target.files?.[0] && onScanImage) onScanImage(e.target.files[0]);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
),
|
|
1033
|
+
/* @__PURE__ */ jsx11(
|
|
1034
|
+
"button",
|
|
1035
|
+
{
|
|
1036
|
+
onClick: onExpand,
|
|
1037
|
+
disabled: !onExpand || isExpanding || !instructions,
|
|
1038
|
+
className: "text-[9px] font-bold uppercase px-2 py-1 rounded border border-neutral-700 text-neutral-400 active:bg-neutral-800 disabled:opacity-30",
|
|
1039
|
+
children: isExpanding ? "..." : "EXPAND"
|
|
1040
|
+
}
|
|
1041
|
+
)
|
|
1042
|
+
] });
|
|
1043
|
+
const canGenerate = selectedLabels.size > 0 || instructions.trim().length > 0 || rules.trim().length > 0;
|
|
1044
|
+
return /* @__PURE__ */ jsxs9("div", { className: "absolute inset-0 overflow-y-auto dark-scrollbar flex flex-col", children: [
|
|
1045
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col gap-3 p-3 pb-6", children: [
|
|
1046
|
+
categories.length === 0 ? /* @__PURE__ */ jsxs9("div", { className: "flex flex-col items-center justify-center py-16 gap-3 opacity-20", children: [
|
|
1047
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[48px]", children: "label_off" }),
|
|
1048
|
+
/* @__PURE__ */ jsxs9("p", { className: "text-[9px] font-bold uppercase tracking-widest text-center", children: [
|
|
816
1049
|
"Keine Tags geladen.",
|
|
817
|
-
/* @__PURE__ */
|
|
1050
|
+
/* @__PURE__ */ jsx11("br", {}),
|
|
818
1051
|
"Importiere ein Workspace-JSON im Setup-Tab."
|
|
819
1052
|
] })
|
|
820
|
-
] }) :
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
1053
|
+
] }) : /* @__PURE__ */ jsx11(
|
|
1054
|
+
CollapsibleCard,
|
|
1055
|
+
{
|
|
1056
|
+
title: "INHALT",
|
|
1057
|
+
icon: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px]", children: "layers" }),
|
|
1058
|
+
defaultOpen: true,
|
|
1059
|
+
children: categories.map(([cat, tags]) => {
|
|
1060
|
+
const visibleTags = tags.filter((t) => !t.is_deleted);
|
|
1061
|
+
const selectedInCat = visibleTags.filter((t) => selectedLabels.has(t.label));
|
|
1062
|
+
const isOpen = activeCategory === cat;
|
|
1063
|
+
const isAdding = addingInCat === cat;
|
|
1064
|
+
const commitNewTag = () => {
|
|
1065
|
+
if (!newLabel.trim()) return;
|
|
1066
|
+
const valueToUse = newValue.trim() || newLabel.trim();
|
|
1067
|
+
onTagCreate?.({ label: newLabel.trim(), value: valueToUse, category: cat, is_user_created: true });
|
|
1068
|
+
setNewLabel("");
|
|
1069
|
+
setNewValue("");
|
|
1070
|
+
setAddingInCat(null);
|
|
1071
|
+
};
|
|
1072
|
+
return /* @__PURE__ */ jsxs9("div", { className: "border-b border-neutral-800 last:border-0", children: [
|
|
1073
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center", children: [
|
|
1074
|
+
/* @__PURE__ */ jsxs9(
|
|
1075
|
+
"button",
|
|
1076
|
+
{
|
|
1077
|
+
onClick: () => setActiveCategory(isOpen ? null : cat),
|
|
1078
|
+
className: "flex-grow flex items-center justify-between px-4 py-3 active:bg-white/5",
|
|
1079
|
+
children: [
|
|
1080
|
+
/* @__PURE__ */ jsx11("span", { className: "text-sm font-bold tracking-widest uppercase text-blue-400", children: cat }),
|
|
1081
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
1082
|
+
selectedInCat.length > 0 && /* @__PURE__ */ jsx11("span", { className: "text-[10px] text-green-400 truncate max-w-[150px]", children: selectedInCat.map((t) => t.label).join(", ") }),
|
|
1083
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[16px] text-white/30 shrink-0", children: isOpen ? "expand_less" : "expand_more" })
|
|
1084
|
+
] })
|
|
1085
|
+
]
|
|
1086
|
+
}
|
|
1087
|
+
),
|
|
1088
|
+
onTagCreate && /* @__PURE__ */ jsx11(
|
|
1089
|
+
"button",
|
|
1090
|
+
{
|
|
1091
|
+
onClick: (e) => {
|
|
1092
|
+
e.stopPropagation();
|
|
1093
|
+
setAddingInCat(isAdding ? null : cat);
|
|
1094
|
+
setActiveCategory(cat);
|
|
1095
|
+
setNewLabel("");
|
|
1096
|
+
setNewValue("");
|
|
1097
|
+
},
|
|
1098
|
+
className: "px-3 py-3 text-white/20 active:text-white/60 hover:text-white/50 transition-colors",
|
|
1099
|
+
title: "Neues Tag anlegen",
|
|
1100
|
+
children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[16px]", children: "add" })
|
|
1101
|
+
}
|
|
1102
|
+
)
|
|
1103
|
+
] }),
|
|
1104
|
+
isOpen && /* @__PURE__ */ jsx11("div", { className: "px-4 pb-3 flex flex-wrap gap-1.5", children: visibleTags.map((t) => {
|
|
1105
|
+
const active = selectedLabels.has(t.label);
|
|
1106
|
+
return /* @__PURE__ */ jsx11(
|
|
1107
|
+
"button",
|
|
1108
|
+
{
|
|
1109
|
+
onMouseDown: () => startLongPress(t, cat),
|
|
1110
|
+
onMouseUp: cancelLongPress,
|
|
1111
|
+
onMouseLeave: cancelLongPress,
|
|
1112
|
+
onTouchStart: () => startLongPress(t, cat),
|
|
1113
|
+
onTouchEnd: cancelLongPress,
|
|
1114
|
+
onTouchCancel: cancelLongPress,
|
|
1115
|
+
onContextMenu: (e) => e.preventDefault(),
|
|
1116
|
+
onClick: () => handleTagClick(t.label),
|
|
1117
|
+
className: `px-2.5 py-1.5 rounded text-xs font-medium border transition-colors ${active ? "bg-blue-900/50 text-blue-200 border-blue-700" : "bg-blue-900/20 text-blue-400 border-blue-900/50 active:bg-blue-900/40 active:text-blue-200"} ${t.is_user_created ? "border-dashed" : ""}`,
|
|
1118
|
+
children: t.label
|
|
1119
|
+
},
|
|
1120
|
+
t.label
|
|
1121
|
+
);
|
|
1122
|
+
}) }),
|
|
1123
|
+
isAdding && /* @__PURE__ */ jsxs9("div", { className: "px-4 pb-3 space-y-2 border-t border-neutral-800/50 pt-2", children: [
|
|
1124
|
+
/* @__PURE__ */ jsx11(
|
|
1125
|
+
"input",
|
|
1126
|
+
{
|
|
1127
|
+
autoFocus: true,
|
|
1128
|
+
value: newLabel,
|
|
1129
|
+
onChange: (e) => setNewLabel(e.target.value),
|
|
1130
|
+
onKeyDown: (e) => {
|
|
1131
|
+
if (e.key === "Enter") {
|
|
1132
|
+
e.preventDefault();
|
|
1133
|
+
commitNewTag();
|
|
1134
|
+
}
|
|
1135
|
+
},
|
|
1136
|
+
placeholder: "Label (z.B. Picasso)",
|
|
1137
|
+
className: "w-full bg-black border border-neutral-700 rounded px-3 py-1.5 text-xs text-white outline-none focus:border-blue-600"
|
|
1138
|
+
}
|
|
1139
|
+
),
|
|
1140
|
+
/* @__PURE__ */ jsx11(
|
|
1141
|
+
"textarea",
|
|
1142
|
+
{
|
|
1143
|
+
value: newValue,
|
|
1144
|
+
onChange: (e) => setNewValue(e.target.value),
|
|
1145
|
+
placeholder: "Value (Prompt-Text) \u2014 leer l\xE4sst Label als Value",
|
|
1146
|
+
rows: 3,
|
|
1147
|
+
className: "w-full bg-black border border-neutral-700 rounded px-3 py-1.5 text-xs text-white outline-none focus:border-blue-600 resize-none"
|
|
1148
|
+
}
|
|
1149
|
+
),
|
|
1150
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex gap-2", children: [
|
|
1151
|
+
/* @__PURE__ */ jsxs9(
|
|
1152
|
+
"button",
|
|
1153
|
+
{
|
|
1154
|
+
onClick: commitNewTag,
|
|
1155
|
+
disabled: !newLabel.trim(),
|
|
1156
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded text-xs font-bold bg-blue-700 text-white disabled:opacity-30 active:bg-blue-600",
|
|
1157
|
+
children: [
|
|
1158
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "check" }),
|
|
1159
|
+
" Speichern"
|
|
1160
|
+
]
|
|
1161
|
+
}
|
|
1162
|
+
),
|
|
1163
|
+
/* @__PURE__ */ jsx11(
|
|
1164
|
+
"button",
|
|
1165
|
+
{
|
|
1166
|
+
onClick: () => {
|
|
1167
|
+
setAddingInCat(null);
|
|
1168
|
+
setNewLabel("");
|
|
1169
|
+
setNewValue("");
|
|
1170
|
+
},
|
|
1171
|
+
className: "flex items-center gap-1 px-3 py-1.5 rounded text-xs text-white/40 border border-neutral-700 active:bg-neutral-800",
|
|
1172
|
+
children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "close" })
|
|
1173
|
+
}
|
|
1174
|
+
)
|
|
1175
|
+
] })
|
|
1176
|
+
] })
|
|
1177
|
+
] }, cat);
|
|
1178
|
+
})
|
|
1179
|
+
}
|
|
1180
|
+
),
|
|
1181
|
+
/* @__PURE__ */ jsx11(
|
|
1182
|
+
CollapsibleCard,
|
|
1183
|
+
{
|
|
1184
|
+
title: "BESCHREIBUNG",
|
|
1185
|
+
icon: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px]", children: "edit_note" }),
|
|
1186
|
+
actions: tagToolbar,
|
|
1187
|
+
defaultOpen: true,
|
|
1188
|
+
children: /* @__PURE__ */ jsx11("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsx11(
|
|
1189
|
+
"textarea",
|
|
826
1190
|
{
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
1191
|
+
value: instructions,
|
|
1192
|
+
onChange: (e) => setInstructions(e.target.value),
|
|
1193
|
+
placeholder: "...",
|
|
1194
|
+
className: "w-full bg-black border border-neutral-800 rounded outline-none text-xs text-white/80 placeholder-neutral-700 resize-none dark-scrollbar p-3",
|
|
1195
|
+
style: { minHeight: 80 }
|
|
1196
|
+
}
|
|
1197
|
+
) })
|
|
1198
|
+
}
|
|
1199
|
+
),
|
|
1200
|
+
/* @__PURE__ */ jsx11(
|
|
1201
|
+
CollapsibleCard,
|
|
1202
|
+
{
|
|
1203
|
+
title: "REGELN",
|
|
1204
|
+
icon: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px]", children: "rule" }),
|
|
1205
|
+
defaultOpen: false,
|
|
1206
|
+
children: /* @__PURE__ */ jsx11("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsx11(
|
|
1207
|
+
"textarea",
|
|
1208
|
+
{
|
|
1209
|
+
value: rules,
|
|
1210
|
+
onChange: (e) => setRules(e.target.value),
|
|
1211
|
+
placeholder: "z.B. Verwende immer explizite Nacktheit unter transparentem Stoff. Tags in Flie\xDFtext einbauen. Kein Markdown.",
|
|
1212
|
+
className: "w-full bg-black border border-neutral-800 rounded outline-none text-xs text-white/80 placeholder-neutral-700 resize-none dark-scrollbar p-3",
|
|
1213
|
+
style: { minHeight: 80 }
|
|
1214
|
+
}
|
|
1215
|
+
) })
|
|
1216
|
+
}
|
|
1217
|
+
),
|
|
1218
|
+
selectedLabels.size > 0 && /* @__PURE__ */ jsxs9("button", { onClick: () => setSelectedLabels(/* @__PURE__ */ new Set()), className: "flex items-center gap-1 text-[10px] text-white/30 active:text-white/60 self-start", children: [
|
|
1219
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "close" }),
|
|
1220
|
+
selectedLabels.size,
|
|
1221
|
+
" Tags gew\xE4hlt"
|
|
1222
|
+
] }),
|
|
1223
|
+
/* @__PURE__ */ jsx11(
|
|
1224
|
+
"button",
|
|
1225
|
+
{
|
|
1226
|
+
onClick: handleGenerate,
|
|
1227
|
+
disabled: isGenerating || !canGenerate,
|
|
1228
|
+
className: "w-full py-4 rounded-lg font-bold text-sm flex items-center justify-center gap-2 bg-white text-black disabled:opacity-40 active:bg-neutral-200",
|
|
1229
|
+
children: isGenerating ? /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1230
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px] animate-spin", children: "autorenew" }),
|
|
1231
|
+
"BAUT PROMPT..."
|
|
1232
|
+
] }) : /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1233
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px]", children: "auto_fix_high" }),
|
|
1234
|
+
"PROMPT BAUEN"
|
|
1235
|
+
] })
|
|
1236
|
+
}
|
|
1237
|
+
),
|
|
1238
|
+
promptResult && /* @__PURE__ */ jsxs9(Fragment2, { children: [
|
|
1239
|
+
lastPayload && /* @__PURE__ */ jsx11(
|
|
1240
|
+
CollapsibleCard,
|
|
1241
|
+
{
|
|
1242
|
+
title: "INPUT MONITOR",
|
|
1243
|
+
icon: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px]", children: "terminal" }),
|
|
1244
|
+
defaultOpen: false,
|
|
1245
|
+
children: /* @__PURE__ */ jsx11("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsx11("pre", { className: "text-[10px] font-mono text-blue-300/80 bg-blue-950/10 border border-blue-900/20 rounded p-3 overflow-x-auto whitespace-pre-wrap leading-relaxed", children: lastPayload }) })
|
|
1246
|
+
}
|
|
1247
|
+
),
|
|
1248
|
+
feedback && /* @__PURE__ */ jsx11(
|
|
1249
|
+
CollapsibleCard,
|
|
839
1250
|
{
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
className: "
|
|
1251
|
+
title: "ANALYSE",
|
|
1252
|
+
icon: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px]", children: "chat" }),
|
|
1253
|
+
defaultOpen: true,
|
|
1254
|
+
children: /* @__PURE__ */ jsx11("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsx11("p", { className: "text-xs font-mono text-orange-200/80 bg-orange-950/10 border border-orange-900/20 rounded p-3 leading-relaxed", children: feedback }) })
|
|
1255
|
+
}
|
|
1256
|
+
),
|
|
1257
|
+
/* @__PURE__ */ jsxs9("div", { className: "border border-neutral-800 rounded-lg", children: [
|
|
1258
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between px-4 py-3 bg-neutral-900/50 rounded-t-lg", children: [
|
|
1259
|
+
/* @__PURE__ */ jsx11("span", { className: "text-[10px] font-bold uppercase tracking-widest text-neutral-400", children: "Prompt" }),
|
|
1260
|
+
/* @__PURE__ */ jsxs9(
|
|
1261
|
+
"button",
|
|
1262
|
+
{
|
|
1263
|
+
onClick: handleCopy,
|
|
1264
|
+
className: "flex items-center gap-1.5 text-[9px] font-bold uppercase px-2 py-1 rounded border border-neutral-700 text-neutral-400 active:bg-neutral-800",
|
|
1265
|
+
children: [
|
|
1266
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: copied ? "check" : "content_copy" }),
|
|
1267
|
+
copied ? "KOPIERT" : "KOPIEREN"
|
|
1268
|
+
]
|
|
1269
|
+
}
|
|
1270
|
+
)
|
|
1271
|
+
] }),
|
|
1272
|
+
/* @__PURE__ */ jsx11("div", { className: "px-4 py-3", children: /* @__PURE__ */ jsx11("p", { className: "text-xs text-white/80 leading-relaxed italic", children: promptResult }) })
|
|
1273
|
+
] }),
|
|
1274
|
+
onGenerateImage && /* @__PURE__ */ jsxs9(
|
|
1275
|
+
"button",
|
|
1276
|
+
{
|
|
1277
|
+
onClick: () => onGenerateImage(promptResult),
|
|
1278
|
+
disabled: isGeneratingImage,
|
|
1279
|
+
className: "w-full py-4 rounded-lg bg-white text-black font-bold text-sm flex items-center justify-center gap-2 disabled:opacity-40 active:bg-neutral-200",
|
|
1280
|
+
children: [
|
|
1281
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[18px]", children: isGeneratingImage ? "hourglass_empty" : "image" }),
|
|
1282
|
+
isGeneratingImage ? "GENERIERE..." : "GENERIEREN"
|
|
1283
|
+
]
|
|
844
1284
|
}
|
|
845
1285
|
)
|
|
846
1286
|
] })
|
|
847
1287
|
] }),
|
|
848
|
-
/* @__PURE__ */
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
1288
|
+
editingTag && /* @__PURE__ */ jsx11(
|
|
1289
|
+
"div",
|
|
1290
|
+
{
|
|
1291
|
+
className: "fixed inset-0 z-50 flex items-end justify-center",
|
|
1292
|
+
style: { background: "rgba(0,0,0,0.75)" },
|
|
1293
|
+
onClick: () => setEditingTag(null),
|
|
1294
|
+
children: /* @__PURE__ */ jsxs9(
|
|
1295
|
+
"div",
|
|
852
1296
|
{
|
|
853
|
-
|
|
854
|
-
|
|
1297
|
+
className: "w-full max-w-lg bg-[#1c1c1c] border border-neutral-700 rounded-t-2xl p-5 space-y-4",
|
|
1298
|
+
onClick: (e) => e.stopPropagation(),
|
|
855
1299
|
children: [
|
|
856
|
-
/* @__PURE__ */
|
|
857
|
-
|
|
858
|
-
|
|
1300
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
|
|
1301
|
+
/* @__PURE__ */ jsx11("span", { className: "text-[10px] font-bold text-neutral-400 uppercase tracking-widest", children: editingTag.category }),
|
|
1302
|
+
/* @__PURE__ */ jsx11("button", { onClick: () => setEditingTag(null), className: "text-white/30 active:text-white", children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[20px]", children: "close" }) })
|
|
1303
|
+
] }),
|
|
1304
|
+
/* @__PURE__ */ jsx11(
|
|
1305
|
+
"input",
|
|
1306
|
+
{
|
|
1307
|
+
autoFocus: true,
|
|
1308
|
+
value: editLabel,
|
|
1309
|
+
onChange: (e) => setEditLabel(e.target.value),
|
|
1310
|
+
placeholder: "Label",
|
|
1311
|
+
className: "w-full bg-black border border-neutral-700 rounded px-3 py-2 text-sm text-white outline-none focus:border-blue-600"
|
|
1312
|
+
}
|
|
1313
|
+
),
|
|
1314
|
+
/* @__PURE__ */ jsx11(
|
|
1315
|
+
"textarea",
|
|
1316
|
+
{
|
|
1317
|
+
value: editValue,
|
|
1318
|
+
onChange: (e) => setEditValue(e.target.value),
|
|
1319
|
+
placeholder: "Value (Prompt-Text)",
|
|
1320
|
+
rows: 4,
|
|
1321
|
+
className: "w-full bg-black border border-neutral-700 rounded px-3 py-2 text-xs text-white outline-none focus:border-blue-600 resize-none"
|
|
1322
|
+
}
|
|
1323
|
+
),
|
|
1324
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex gap-2 flex-wrap", children: [
|
|
1325
|
+
/* @__PURE__ */ jsxs9(
|
|
1326
|
+
"button",
|
|
1327
|
+
{
|
|
1328
|
+
onClick: handleSaveEdit,
|
|
1329
|
+
disabled: !editLabel.trim(),
|
|
1330
|
+
className: "flex-1 flex items-center justify-center gap-1.5 px-3 py-2.5 rounded text-sm font-bold bg-blue-700 text-white disabled:opacity-30 active:bg-blue-600",
|
|
1331
|
+
children: [
|
|
1332
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[16px]", children: "check" }),
|
|
1333
|
+
" Speichern"
|
|
1334
|
+
]
|
|
1335
|
+
}
|
|
1336
|
+
),
|
|
1337
|
+
/* @__PURE__ */ jsxs9(
|
|
1338
|
+
"button",
|
|
1339
|
+
{
|
|
1340
|
+
onClick: handleCreateBased,
|
|
1341
|
+
className: "flex-1 flex items-center justify-center gap-1.5 px-3 py-2.5 rounded text-sm font-bold border border-neutral-600 text-white/70 active:bg-neutral-800",
|
|
1342
|
+
children: [
|
|
1343
|
+
/* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[16px]", children: "content_copy" }),
|
|
1344
|
+
" Neu auf Basis"
|
|
1345
|
+
]
|
|
1346
|
+
}
|
|
1347
|
+
),
|
|
1348
|
+
onTagDelete && /* @__PURE__ */ jsx11(
|
|
1349
|
+
"button",
|
|
1350
|
+
{
|
|
1351
|
+
onClick: handleDeleteTag,
|
|
1352
|
+
className: "flex items-center justify-center gap-1.5 px-3 py-2.5 rounded text-sm font-bold border border-red-900/60 text-red-400 active:bg-red-900/20",
|
|
1353
|
+
children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[16px]", children: "delete" })
|
|
1354
|
+
}
|
|
1355
|
+
)
|
|
1356
|
+
] })
|
|
859
1357
|
]
|
|
860
1358
|
}
|
|
1359
|
+
)
|
|
1360
|
+
}
|
|
1361
|
+
)
|
|
1362
|
+
] });
|
|
1363
|
+
};
|
|
1364
|
+
|
|
1365
|
+
// src/components/ProjectSyncTab.tsx
|
|
1366
|
+
import { useRef as useRef5, useState as useState5 } from "react";
|
|
1367
|
+
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1368
|
+
var ProjectSyncTab = ({
|
|
1369
|
+
onProjectExport,
|
|
1370
|
+
onProjectImport,
|
|
1371
|
+
onWorkspaceImport,
|
|
1372
|
+
projectActionState,
|
|
1373
|
+
serverProjects,
|
|
1374
|
+
onServerSave,
|
|
1375
|
+
onServerLoad,
|
|
1376
|
+
onServerDelete,
|
|
1377
|
+
onRefreshServerProjects,
|
|
1378
|
+
onComputeSyncDiff,
|
|
1379
|
+
onExecuteSync
|
|
1380
|
+
}) => {
|
|
1381
|
+
const projectInputRef = useRef5(null);
|
|
1382
|
+
const workspaceInputRef = useRef5(null);
|
|
1383
|
+
const [saveName, setSaveName] = useState5("");
|
|
1384
|
+
const [isSaving, setIsSaving] = useState5(false);
|
|
1385
|
+
const [isExporting, setIsExporting] = useState5(false);
|
|
1386
|
+
const [syncState, setSyncState] = useState5("idle");
|
|
1387
|
+
const [syncDiff, setSyncDiff] = useState5(null);
|
|
1388
|
+
const [selectedLocalIds, setSelectedLocalIds] = useState5(/* @__PURE__ */ new Set());
|
|
1389
|
+
const handleExport = async () => {
|
|
1390
|
+
if (!onProjectExport) return;
|
|
1391
|
+
setIsExporting(true);
|
|
1392
|
+
try {
|
|
1393
|
+
await onProjectExport();
|
|
1394
|
+
} finally {
|
|
1395
|
+
setIsExporting(false);
|
|
1396
|
+
}
|
|
1397
|
+
};
|
|
1398
|
+
const handleComputeDiff = async () => {
|
|
1399
|
+
if (!onComputeSyncDiff) return;
|
|
1400
|
+
setSyncState("computing");
|
|
1401
|
+
setSyncDiff(null);
|
|
1402
|
+
try {
|
|
1403
|
+
const diff = await onComputeSyncDiff();
|
|
1404
|
+
setSyncDiff(diff);
|
|
1405
|
+
setSelectedLocalIds(new Set(diff.localOnly.map((g) => g.id)));
|
|
1406
|
+
setSyncState("ready");
|
|
1407
|
+
} catch {
|
|
1408
|
+
setSyncState("error");
|
|
1409
|
+
setTimeout(() => setSyncState("idle"), 4e3);
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
const handleExecuteSync = async () => {
|
|
1413
|
+
if (!onExecuteSync || !syncDiff) return;
|
|
1414
|
+
setSyncState("executing");
|
|
1415
|
+
try {
|
|
1416
|
+
await onExecuteSync([...selectedLocalIds]);
|
|
1417
|
+
setSyncState("done");
|
|
1418
|
+
setSyncDiff(null);
|
|
1419
|
+
setTimeout(() => setSyncState("idle"), 3e3);
|
|
1420
|
+
} catch {
|
|
1421
|
+
setSyncState("error");
|
|
1422
|
+
setTimeout(() => setSyncState("idle"), 4e3);
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
const toggleLocalId = (id) => {
|
|
1426
|
+
setSelectedLocalIds((prev) => {
|
|
1427
|
+
const next = new Set(prev);
|
|
1428
|
+
if (next.has(id)) next.delete(id);
|
|
1429
|
+
else next.add(id);
|
|
1430
|
+
return next;
|
|
1431
|
+
});
|
|
1432
|
+
};
|
|
1433
|
+
const isWorking = projectActionState === "working" || projectActionState === "working-full";
|
|
1434
|
+
return /* @__PURE__ */ jsx12("div", { className: "absolute inset-0 overflow-y-auto dark-scrollbar", children: /* @__PURE__ */ jsxs10("div", { className: "p-6 flex flex-col gap-8", children: [
|
|
1435
|
+
(onProjectExport || onProjectImport || onWorkspaceImport) && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-4", children: [
|
|
1436
|
+
/* @__PURE__ */ jsx12(SectionLabel, { children: "Projekt-ZIP" }),
|
|
1437
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-2", children: [
|
|
1438
|
+
onProjectExport && /* @__PURE__ */ jsx12(PillButton, { variant: "filled", icon: "download", loading: isExporting || isWorking, onClick: handleExport, children: "Exportieren (.zip)" }),
|
|
1439
|
+
onProjectImport && /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1440
|
+
/* @__PURE__ */ jsx12(PillButton, { variant: "outline", icon: "upload", onClick: () => projectInputRef.current?.click(), children: "ZIP laden" }),
|
|
1441
|
+
/* @__PURE__ */ jsx12(
|
|
1442
|
+
"input",
|
|
1443
|
+
{
|
|
1444
|
+
ref: projectInputRef,
|
|
1445
|
+
type: "file",
|
|
1446
|
+
accept: ".zip",
|
|
1447
|
+
className: "hidden",
|
|
1448
|
+
onChange: (e) => {
|
|
1449
|
+
const f = e.target.files?.[0];
|
|
1450
|
+
if (f) onProjectImport(f);
|
|
1451
|
+
e.target.value = "";
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
)
|
|
1455
|
+
] })
|
|
1456
|
+
] }),
|
|
1457
|
+
onWorkspaceImport && /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1458
|
+
/* @__PURE__ */ jsx12(PillButton, { variant: "outline", icon: "upload_file", onClick: () => workspaceInputRef.current?.click(), children: "Tags laden (.json)" }),
|
|
1459
|
+
/* @__PURE__ */ jsx12(
|
|
1460
|
+
"input",
|
|
1461
|
+
{
|
|
1462
|
+
ref: workspaceInputRef,
|
|
1463
|
+
type: "file",
|
|
1464
|
+
accept: ".json",
|
|
1465
|
+
className: "hidden",
|
|
1466
|
+
onChange: (e) => {
|
|
1467
|
+
const f = e.target.files?.[0];
|
|
1468
|
+
if (f) onWorkspaceImport(f);
|
|
1469
|
+
e.target.value = "";
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
)
|
|
1473
|
+
] })
|
|
1474
|
+
] }),
|
|
1475
|
+
(onServerSave || serverProjects || onServerDelete) && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-4", children: [
|
|
1476
|
+
/* @__PURE__ */ jsx12(SectionLabel, { children: "Server-Speicher" }),
|
|
1477
|
+
onServerSave && /* @__PURE__ */ jsxs10("div", { className: "flex gap-2", children: [
|
|
1478
|
+
/* @__PURE__ */ jsx12(
|
|
1479
|
+
"input",
|
|
1480
|
+
{
|
|
1481
|
+
type: "text",
|
|
1482
|
+
value: saveName,
|
|
1483
|
+
onChange: (e) => setSaveName(e.target.value),
|
|
1484
|
+
placeholder: "Name (optional)",
|
|
1485
|
+
className: "flex-1 bg-white/5 border border-white/10 rounded-xl px-3 text-[12px] text-white/70 outline-none placeholder:text-white/20",
|
|
1486
|
+
style: { height: 40 }
|
|
1487
|
+
}
|
|
861
1488
|
),
|
|
862
|
-
/* @__PURE__ */
|
|
863
|
-
|
|
1489
|
+
/* @__PURE__ */ jsx12(
|
|
1490
|
+
PillButton,
|
|
864
1491
|
{
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1492
|
+
variant: "filled",
|
|
1493
|
+
icon: "cloud_upload",
|
|
1494
|
+
loading: isSaving,
|
|
1495
|
+
onClick: async () => {
|
|
1496
|
+
setIsSaving(true);
|
|
1497
|
+
try {
|
|
1498
|
+
await onServerSave(saveName || void 0);
|
|
1499
|
+
setSaveName("");
|
|
1500
|
+
await onRefreshServerProjects?.();
|
|
1501
|
+
} finally {
|
|
1502
|
+
setIsSaving(false);
|
|
1503
|
+
}
|
|
1504
|
+
},
|
|
1505
|
+
children: "Speichern"
|
|
870
1506
|
}
|
|
871
|
-
)
|
|
1507
|
+
)
|
|
872
1508
|
] }),
|
|
873
|
-
/* @__PURE__ */
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
"
|
|
877
|
-
|
|
878
|
-
|
|
1509
|
+
(!serverProjects || serverProjects.length === 0) && /* @__PURE__ */ jsx12("p", { className: "text-[10px] text-white/20 px-2", children: "Noch nichts gespeichert." }),
|
|
1510
|
+
serverProjects && serverProjects.length > 0 && /* @__PURE__ */ jsx12("div", { className: "flex flex-col gap-1", children: serverProjects.map((p) => /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 px-3 py-2 rounded-xl bg-white/5 border border-white/5", children: [
|
|
1511
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-0", children: [
|
|
1512
|
+
/* @__PURE__ */ jsx12("p", { className: "text-[11px] text-white/70 font-bold truncate", children: p.name }),
|
|
1513
|
+
/* @__PURE__ */ jsxs10("p", { className: "text-[9px] text-white/25", children: [
|
|
1514
|
+
new Date(p.saved_at).toLocaleString("de-DE", { dateStyle: "short", timeStyle: "short" }),
|
|
1515
|
+
" \xB7 ",
|
|
1516
|
+
(p.size / 1024).toFixed(0),
|
|
1517
|
+
" KB"
|
|
1518
|
+
] })
|
|
1519
|
+
] }),
|
|
1520
|
+
onServerLoad && /* @__PURE__ */ jsx12("button", { onClick: () => onServerLoad(p.id), className: "w-8 h-8 flex items-center justify-center text-white/30 active:text-white transition-colors", children: /* @__PURE__ */ jsx12("span", { className: "material-symbols-outlined text-[18px]", children: "cloud_download" }) }),
|
|
1521
|
+
/* @__PURE__ */ jsx12("button", { onClick: () => onServerDelete?.(p.id), className: "w-8 h-8 flex items-center justify-center text-white/20 active:text-red-400 transition-colors", children: /* @__PURE__ */ jsx12("span", { className: "material-symbols-outlined text-[18px]", children: "delete" }) })
|
|
1522
|
+
] }, p.id)) })
|
|
1523
|
+
] }),
|
|
1524
|
+
onComputeSyncDiff && onExecuteSync && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-4", children: [
|
|
1525
|
+
/* @__PURE__ */ jsx12(SectionLabel, { children: "Sync" }),
|
|
1526
|
+
(syncState === "idle" || syncState === "computing") && /* @__PURE__ */ jsx12(PillButton, { variant: "outline", icon: "compare_arrows", loading: syncState === "computing", onClick: handleComputeDiff, children: "Diff berechnen" }),
|
|
1527
|
+
syncState === "done" && /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-2 px-2 text-[11px] text-green-400", children: [
|
|
1528
|
+
/* @__PURE__ */ jsx12("span", { className: "material-symbols-outlined text-[16px]", children: "check_circle" }),
|
|
1529
|
+
"Sync abgeschlossen"
|
|
1530
|
+
] }),
|
|
1531
|
+
syncState === "error" && /* @__PURE__ */ jsx12("p", { className: "text-[11px] text-red-400 px-2", children: "Fehler beim Sync." }),
|
|
1532
|
+
syncDiff && (syncState === "ready" || syncState === "executing") && /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1533
|
+
syncDiff.localOnly.length === 0 && syncDiff.serverOnly.length === 0 && /* @__PURE__ */ jsx12("p", { className: "text-[10px] text-white/30 px-2", children: "Alles synchron \u2014 keine Unterschiede." }),
|
|
1534
|
+
syncDiff.localOnly.length > 0 && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-2", children: [
|
|
1535
|
+
/* @__PURE__ */ jsxs10("p", { className: "text-[9px] text-white/30 uppercase tracking-widest px-1 font-bold", children: [
|
|
1536
|
+
"Nur lokal (",
|
|
1537
|
+
syncDiff.localOnly.length,
|
|
1538
|
+
")"
|
|
1539
|
+
] }),
|
|
1540
|
+
syncDiff.localOnly.map((gen) => /* @__PURE__ */ jsxs10(
|
|
1541
|
+
"button",
|
|
1542
|
+
{
|
|
1543
|
+
onClick: () => toggleLocalId(gen.id),
|
|
1544
|
+
className: `flex items-center gap-3 px-3 py-2 rounded-xl border transition-all text-left ${selectedLocalIds.has(gen.id) ? "bg-blue-500/10 border-blue-500/30" : "bg-white/3 border-white/5 opacity-60"}`,
|
|
1545
|
+
children: [
|
|
1546
|
+
/* @__PURE__ */ jsx12("div", { className: `w-4 h-4 rounded border flex items-center justify-center flex-shrink-0 ${selectedLocalIds.has(gen.id) ? "bg-blue-500 border-blue-500" : "border-white/20"}`, children: selectedLocalIds.has(gen.id) && /* @__PURE__ */ jsx12("span", { className: "material-symbols-outlined text-[11px] text-white", children: "check" }) }),
|
|
1547
|
+
gen.base64 && /* @__PURE__ */ jsx12("img", { src: gen.base64, className: "w-10 h-10 rounded object-cover flex-shrink-0" }),
|
|
1548
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-0", children: [
|
|
1549
|
+
/* @__PURE__ */ jsx12("p", { className: "text-[10px] text-white/60 truncate", children: gen.prompt || "Kein Prompt" }),
|
|
1550
|
+
/* @__PURE__ */ jsx12("p", { className: "text-[9px] text-white/25", children: new Date(gen.timestamp).toLocaleString("de-DE", { dateStyle: "short", timeStyle: "short" }) })
|
|
1551
|
+
] })
|
|
1552
|
+
]
|
|
1553
|
+
},
|
|
1554
|
+
gen.id
|
|
1555
|
+
))
|
|
1556
|
+
] }),
|
|
1557
|
+
syncDiff.serverOnly.length > 0 && /* @__PURE__ */ jsxs10("div", { className: "flex flex-col gap-2", children: [
|
|
1558
|
+
/* @__PURE__ */ jsxs10("p", { className: "text-[9px] text-white/30 uppercase tracking-widest px-1 font-bold", children: [
|
|
1559
|
+
"Nur auf Server (",
|
|
1560
|
+
syncDiff.serverOnly.length,
|
|
1561
|
+
")"
|
|
1562
|
+
] }),
|
|
1563
|
+
syncDiff.serverOnly.map((gen) => /* @__PURE__ */ jsxs10("div", { className: "flex items-center gap-3 px-3 py-2 rounded-xl bg-white/3 border border-white/5 opacity-40", children: [
|
|
1564
|
+
gen.base64 && /* @__PURE__ */ jsx12("img", { src: gen.base64, className: "w-10 h-10 rounded object-cover flex-shrink-0" }),
|
|
1565
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex-1 min-w-0", children: [
|
|
1566
|
+
/* @__PURE__ */ jsx12("p", { className: "text-[10px] text-white/60 truncate", children: gen.prompt || "Kein Prompt" }),
|
|
1567
|
+
/* @__PURE__ */ jsx12("p", { className: "text-[9px] text-white/25", children: new Date(gen.timestamp).toLocaleString("de-DE", { dateStyle: "short", timeStyle: "short" }) })
|
|
1568
|
+
] })
|
|
1569
|
+
] }, gen.id))
|
|
1570
|
+
] }),
|
|
1571
|
+
(syncDiff.localOnly.length > 0 || syncDiff.serverOnly.length > 0) && /* @__PURE__ */ jsxs10(
|
|
879
1572
|
PillButton,
|
|
880
1573
|
{
|
|
881
1574
|
variant: "solid",
|
|
882
|
-
icon: "
|
|
883
|
-
loading:
|
|
884
|
-
disabled:
|
|
885
|
-
onClick:
|
|
886
|
-
children:
|
|
1575
|
+
icon: "sync",
|
|
1576
|
+
loading: syncState === "executing",
|
|
1577
|
+
disabled: selectedLocalIds.size === 0,
|
|
1578
|
+
onClick: handleExecuteSync,
|
|
1579
|
+
children: [
|
|
1580
|
+
selectedLocalIds.size,
|
|
1581
|
+
" \xFCbertragen"
|
|
1582
|
+
]
|
|
887
1583
|
}
|
|
888
1584
|
)
|
|
889
1585
|
] })
|
|
890
1586
|
] })
|
|
891
|
-
] });
|
|
1587
|
+
] }) });
|
|
892
1588
|
};
|
|
893
1589
|
|
|
894
1590
|
// src/components/AvatarArchitectApp.tsx
|
|
895
|
-
import { jsx as
|
|
896
|
-
function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia }) {
|
|
1591
|
+
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1592
|
+
function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
|
|
897
1593
|
useEffect4(() => {
|
|
898
1594
|
const id = "flow-styles";
|
|
899
1595
|
if (!document.getElementById(id)) {
|
|
@@ -903,28 +1599,122 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
903
1599
|
document.head.appendChild(style);
|
|
904
1600
|
}
|
|
905
1601
|
}, []);
|
|
906
|
-
const [
|
|
907
|
-
const [
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const [
|
|
915
|
-
const
|
|
916
|
-
const
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
const [
|
|
925
|
-
const [
|
|
926
|
-
const [
|
|
927
|
-
const [
|
|
1602
|
+
const [showStart, setShowStart] = useState6(true);
|
|
1603
|
+
const [layoutChoice, setLayoutChoice] = useState6(() => {
|
|
1604
|
+
try {
|
|
1605
|
+
return localStorage.getItem("aa-layout") || null;
|
|
1606
|
+
} catch {
|
|
1607
|
+
return null;
|
|
1608
|
+
}
|
|
1609
|
+
});
|
|
1610
|
+
const [projectLoaded, setProjectLoaded] = useState6(false);
|
|
1611
|
+
const wsInputRef = useRef6(null);
|
|
1612
|
+
const startApp = (choice) => {
|
|
1613
|
+
try {
|
|
1614
|
+
localStorage.setItem("aa-layout", choice);
|
|
1615
|
+
} catch {
|
|
1616
|
+
}
|
|
1617
|
+
setLayoutChoice(choice);
|
|
1618
|
+
setShowStart(false);
|
|
1619
|
+
};
|
|
1620
|
+
const [nodes, setNodes] = useState6([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
|
|
1621
|
+
const [edges, setEdges] = useState6([]);
|
|
1622
|
+
const [history, setHistory] = useState6([]);
|
|
1623
|
+
const [galleryItems, setGalleryItems] = useState6([]);
|
|
1624
|
+
const [activePrompt, setActivePrompt] = useState6("");
|
|
1625
|
+
const [isSynthesizing, setIsSynthesizing] = useState6(false);
|
|
1626
|
+
const [activeGenerationsCount, setActiveGenerationsCount] = useState6(0);
|
|
1627
|
+
const [currentResult, setCurrentResult] = useState6(null);
|
|
1628
|
+
const [focusedNodeId, setFocusedNodeId] = useState6(null);
|
|
1629
|
+
const [leftTab, setLeftTab] = useState6("prompt");
|
|
1630
|
+
const [promptFeedback, setPromptFeedback] = useState6(null);
|
|
1631
|
+
const [lastPromptPayload, setLastPromptPayload] = useState6(null);
|
|
1632
|
+
const [isPromptTabGenerating, setIsPromptTabGenerating] = useState6(false);
|
|
1633
|
+
const [activeTab, setActiveTab] = useState6("history");
|
|
1634
|
+
const [mobileTab, setMobileTab] = useState6("stage");
|
|
1635
|
+
const [aspectRatio, setAspectRatio] = useState6("1:1");
|
|
1636
|
+
const [selectedModel, setSelectedModel] = useState6("\u{1F34C} Nano Banana Pro");
|
|
1637
|
+
const [seed, setSeed] = useState6(Math.floor(Math.random() * 1e6));
|
|
1638
|
+
const [seedMode, setSeedMode] = useState6("random");
|
|
1639
|
+
const [isLeftCollapsed, setIsLeftCollapsed] = useState6(false);
|
|
1640
|
+
const [isRightCollapsed, setIsRightCollapsed] = useState6(false);
|
|
1641
|
+
const [isPromptCollapsed, setIsPromptCollapsed] = useState6(false);
|
|
1642
|
+
const [projectActionState, setProjectActionState] = useState6("idle");
|
|
1643
|
+
const syncServerDataRef = useRef6(null);
|
|
1644
|
+
const [workspaceTags, setWorkspaceTags] = useState6(null);
|
|
1645
|
+
const [serverProjects, setServerProjects] = useState6([]);
|
|
1646
|
+
const [isLoadingFromServer, setIsLoadingFromServer] = useState6(false);
|
|
1647
|
+
const [highContrast, setHighContrast] = useState6(() => {
|
|
1648
|
+
try {
|
|
1649
|
+
return localStorage.getItem("aa-contrast") === "high";
|
|
1650
|
+
} catch {
|
|
1651
|
+
return false;
|
|
1652
|
+
}
|
|
1653
|
+
});
|
|
1654
|
+
const [touchStartX, setTouchStartX] = useState6(null);
|
|
1655
|
+
const [isFullscreen, setIsFullscreen] = useState6(false);
|
|
1656
|
+
const [zoomScale, setZoomScale] = useState6(1);
|
|
1657
|
+
const [zoomOffset, setZoomOffset] = useState6({ x: 0, y: 0 });
|
|
1658
|
+
const lastPinchDist = useRef6(null);
|
|
1659
|
+
const lastTapTime = useRef6(0);
|
|
1660
|
+
const dragStart = useRef6(null);
|
|
1661
|
+
const openFullscreen = () => {
|
|
1662
|
+
setIsFullscreen(true);
|
|
1663
|
+
setZoomScale(1);
|
|
1664
|
+
setZoomOffset({ x: 0, y: 0 });
|
|
1665
|
+
};
|
|
1666
|
+
const closeFullscreen = () => {
|
|
1667
|
+
setIsFullscreen(false);
|
|
1668
|
+
setZoomScale(1);
|
|
1669
|
+
setZoomOffset({ x: 0, y: 0 });
|
|
1670
|
+
};
|
|
1671
|
+
const handleFsTouchStart = (e) => {
|
|
1672
|
+
if (e.touches.length === 2) {
|
|
1673
|
+
lastPinchDist.current = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY);
|
|
1674
|
+
} else if (e.touches.length === 1) {
|
|
1675
|
+
const now = Date.now();
|
|
1676
|
+
if (now - lastTapTime.current < 280) {
|
|
1677
|
+
setZoomScale((s) => s > 1 ? 1 : 2.5);
|
|
1678
|
+
setZoomOffset({ x: 0, y: 0 });
|
|
1679
|
+
}
|
|
1680
|
+
lastTapTime.current = now;
|
|
1681
|
+
dragStart.current = { x: e.touches[0].clientX, y: e.touches[0].clientY, ox: zoomOffset.x, oy: zoomOffset.y };
|
|
1682
|
+
}
|
|
1683
|
+
};
|
|
1684
|
+
const handleFsTouchMove = (e) => {
|
|
1685
|
+
if (e.touches.length === 2 && lastPinchDist.current !== null) {
|
|
1686
|
+
const dist = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY);
|
|
1687
|
+
setZoomScale((s) => Math.min(Math.max(s * (dist / lastPinchDist.current), 1), 5));
|
|
1688
|
+
lastPinchDist.current = dist;
|
|
1689
|
+
} else if (e.touches.length === 1 && dragStart.current && zoomScale > 1) {
|
|
1690
|
+
setZoomOffset({ x: dragStart.current.ox + e.touches[0].clientX - dragStart.current.x, y: dragStart.current.oy + e.touches[0].clientY - dragStart.current.y });
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1693
|
+
const handleFsTouchEnd = (e) => {
|
|
1694
|
+
lastPinchDist.current = null;
|
|
1695
|
+
if (e.changedTouches.length === 1 && zoomScale <= 1 && dragStart.current) {
|
|
1696
|
+
const dx = e.changedTouches[0].clientX - dragStart.current.x;
|
|
1697
|
+
if (dx < -50) goToNext();
|
|
1698
|
+
else if (dx > 50) goToPrev();
|
|
1699
|
+
}
|
|
1700
|
+
dragStart.current = null;
|
|
1701
|
+
};
|
|
1702
|
+
const toggleContrast = () => {
|
|
1703
|
+
const next = !highContrast;
|
|
1704
|
+
setHighContrast(next);
|
|
1705
|
+
try {
|
|
1706
|
+
localStorage.setItem("aa-contrast", next ? "high" : "low");
|
|
1707
|
+
} catch {
|
|
1708
|
+
}
|
|
1709
|
+
};
|
|
1710
|
+
const currentIndex = useMemo2(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
|
|
1711
|
+
const goToPrev = useCallback(() => {
|
|
1712
|
+
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
1713
|
+
}, [currentIndex, history]);
|
|
1714
|
+
const goToNext = useCallback(() => {
|
|
1715
|
+
if (currentIndex < history.length - 1) setCurrentResult(history[currentIndex + 1]);
|
|
1716
|
+
}, [currentIndex, history]);
|
|
1717
|
+
const hcStyle = highContrast ? { filter: "brightness(1.6) contrast(1.05)" } : void 0;
|
|
928
1718
|
const isGenerating = activeGenerationsCount > 0;
|
|
929
1719
|
useKeyboardNavigation(history, currentResult, setCurrentResult);
|
|
930
1720
|
const getSubtreeFormat = useCallback((nodeId, depth = 0) => {
|
|
@@ -935,7 +1725,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
935
1725
|
return `${indent}- ${node.data.label || "(unbenannt)"}
|
|
936
1726
|
` + childrenIds.map((id) => getSubtreeFormat(id, depth + 1)).join("");
|
|
937
1727
|
}, [nodes, edges]);
|
|
938
|
-
const activePath =
|
|
1728
|
+
const activePath = useMemo2(() => {
|
|
939
1729
|
if (!focusedNodeId) return /* @__PURE__ */ new Set();
|
|
940
1730
|
const path = /* @__PURE__ */ new Set([focusedNodeId]);
|
|
941
1731
|
let currId = focusedNodeId;
|
|
@@ -953,17 +1743,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
953
1743
|
setActiveGenerationsCount((prev) => prev + 1);
|
|
954
1744
|
const genId = crypto.randomUUID();
|
|
955
1745
|
const activeSeed = seedMode === "random" ? Math.floor(Math.random() * 1e9) : seed;
|
|
956
|
-
const newGen = {
|
|
957
|
-
id: genId,
|
|
958
|
-
nodeId: overrideNodeId || focusedNodeId || "1",
|
|
959
|
-
status: "processing",
|
|
960
|
-
timestamp: Date.now(),
|
|
961
|
-
prompt: promptToUse,
|
|
962
|
-
seed: activeSeed,
|
|
963
|
-
model: selectedModel,
|
|
964
|
-
tags: [],
|
|
965
|
-
type: "generation"
|
|
966
|
-
};
|
|
1746
|
+
const newGen = { id: genId, nodeId: overrideNodeId || focusedNodeId || "1", status: "processing", timestamp: Date.now(), prompt: promptToUse, seed: activeSeed, model: selectedModel, tags: [], type: "generation" };
|
|
967
1747
|
setHistory((prev) => [newGen, ...prev]);
|
|
968
1748
|
if (!options.silent) setCurrentResult(newGen);
|
|
969
1749
|
if (seedMode === "random") setSeed(activeSeed);
|
|
@@ -1000,12 +1780,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1000
1780
|
setIsSynthesizing(false);
|
|
1001
1781
|
}
|
|
1002
1782
|
};
|
|
1003
|
-
const
|
|
1783
|
+
const handleTagCreate = (tag) => {
|
|
1784
|
+
setWorkspaceTags((prev) => {
|
|
1785
|
+
if (!prev) return prev;
|
|
1786
|
+
const newTagOption = { label: tag.label, value: tag.value, is_user_created: true };
|
|
1787
|
+
const updatedCat = [...prev.by_category[tag.category] || [], newTagOption];
|
|
1788
|
+
return {
|
|
1789
|
+
by_category: { ...prev.by_category, [tag.category]: updatedCat },
|
|
1790
|
+
all: [...prev.all, { ...newTagOption, category: tag.category }]
|
|
1791
|
+
};
|
|
1792
|
+
});
|
|
1793
|
+
};
|
|
1794
|
+
const handleTagUpdate = (originalLabel, originalCategory, updates) => {
|
|
1795
|
+
setWorkspaceTags((prev) => {
|
|
1796
|
+
if (!prev) return prev;
|
|
1797
|
+
const updatedCat = (prev.by_category[originalCategory] || []).map(
|
|
1798
|
+
(t) => t.label === originalLabel ? { ...t, ...updates } : t
|
|
1799
|
+
);
|
|
1800
|
+
const updatedAll = prev.all.map(
|
|
1801
|
+
(t) => t.label === originalLabel && t.category === originalCategory ? { ...t, ...updates } : t
|
|
1802
|
+
);
|
|
1803
|
+
return { by_category: { ...prev.by_category, [originalCategory]: updatedCat }, all: updatedAll };
|
|
1804
|
+
});
|
|
1805
|
+
};
|
|
1806
|
+
const handleTagDelete = (label, category) => {
|
|
1807
|
+
setWorkspaceTags((prev) => {
|
|
1808
|
+
if (!prev) return prev;
|
|
1809
|
+
const updatedCat = (prev.by_category[category] || []).map(
|
|
1810
|
+
(t) => t.label === label ? { ...t, is_deleted: true } : t
|
|
1811
|
+
);
|
|
1812
|
+
const updatedAll = prev.all.map(
|
|
1813
|
+
(t) => t.label === label && t.category === category ? { ...t, is_deleted: true } : t
|
|
1814
|
+
);
|
|
1815
|
+
return { by_category: { ...prev.by_category, [category]: updatedCat }, all: updatedAll };
|
|
1816
|
+
});
|
|
1817
|
+
};
|
|
1818
|
+
const handlePromptTabGenerate = async (selectedTags, instructions, rules) => {
|
|
1004
1819
|
setIsPromptTabGenerating(true);
|
|
1005
1820
|
setPromptFeedback(null);
|
|
1006
1821
|
try {
|
|
1007
1822
|
const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
|
|
1008
|
-
const payload = buildPromptTabPayload(
|
|
1823
|
+
const payload = buildPromptTabPayload(selectedTags, instructions, rules, treeText);
|
|
1824
|
+
setLastPromptPayload(payload);
|
|
1009
1825
|
const raw = await onGeneratePrompt(payload);
|
|
1010
1826
|
const { prompt, feedback } = parsePromptResponse(raw);
|
|
1011
1827
|
setActivePrompt(prompt);
|
|
@@ -1022,9 +1838,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1022
1838
|
const base64Data = currentResult.base64.split(",")[1];
|
|
1023
1839
|
const mimeType = currentResult.base64.split(";")[0].split(":")[1] || "image/png";
|
|
1024
1840
|
let finalBase64 = base64Data;
|
|
1025
|
-
if (mimeType === "image/png")
|
|
1026
|
-
finalBase64 = injectXMPMetadata(base64Data, currentResult.prompt || "", currentResult.seed, currentResult.model, currentResult.id, currentResult.tags || [], getSubtreeFormat(currentResult.nodeId));
|
|
1027
|
-
}
|
|
1841
|
+
if (mimeType === "image/png") finalBase64 = injectXMPMetadata(base64Data, currentResult.prompt || "", currentResult.seed, currentResult.model, currentResult.id, currentResult.tags || [], getSubtreeFormat(currentResult.nodeId));
|
|
1028
1842
|
await onDownload(finalBase64, mimeType, `avatar_${currentResult.id.slice(0, 5)}.${mimeType.split("/")[1]}`);
|
|
1029
1843
|
} catch (e) {
|
|
1030
1844
|
console.error("Download Error", e);
|
|
@@ -1033,7 +1847,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1033
1847
|
const handleProjectExport = async () => {
|
|
1034
1848
|
setProjectActionState("working-full");
|
|
1035
1849
|
try {
|
|
1036
|
-
const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode });
|
|
1850
|
+
const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags);
|
|
1037
1851
|
await onDownload(base64, "application/zip", `avatar_project_${getFormattedTimestamp()}.zip`);
|
|
1038
1852
|
setProjectActionState("done");
|
|
1039
1853
|
setTimeout(() => setProjectActionState("idle"), 3e3);
|
|
@@ -1049,7 +1863,10 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1049
1863
|
const data = await importProjectFromZip(file);
|
|
1050
1864
|
if (data.nodes) setNodes(data.nodes);
|
|
1051
1865
|
if (data.edges) setEdges(data.edges);
|
|
1052
|
-
if (data.history)
|
|
1866
|
+
if (data.history) {
|
|
1867
|
+
setHistory(data.history);
|
|
1868
|
+
if (data.history.length > 0) setCurrentResult(data.history[0]);
|
|
1869
|
+
}
|
|
1053
1870
|
if (data.galleryItems) setGalleryItems(data.galleryItems);
|
|
1054
1871
|
if (data.settings) {
|
|
1055
1872
|
setAspectRatio(data.settings.aspectRatio || "1:1");
|
|
@@ -1057,7 +1874,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1057
1874
|
setSeed(data.settings.seed || 0);
|
|
1058
1875
|
setSeedMode(data.settings.seedMode || "random");
|
|
1059
1876
|
}
|
|
1877
|
+
if (data.workspaceTags?.by_category) setWorkspaceTags(data.workspaceTags);
|
|
1060
1878
|
setProjectActionState("done");
|
|
1879
|
+
setProjectLoaded(true);
|
|
1061
1880
|
setTimeout(() => setProjectActionState("idle"), 2e3);
|
|
1062
1881
|
} catch {
|
|
1063
1882
|
setProjectActionState("error");
|
|
@@ -1072,12 +1891,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1072
1891
|
const rawTags = root.tags || root;
|
|
1073
1892
|
if (!rawTags?.by_category) return;
|
|
1074
1893
|
const filtered = {};
|
|
1075
|
-
const
|
|
1894
|
+
const EXCLUDED2 = ["pdf-export", "book.micro-edit-rules"];
|
|
1076
1895
|
Object.entries(rawTags.by_category).forEach(([cat, items]) => {
|
|
1077
|
-
if (
|
|
1896
|
+
if (EXCLUDED2.includes(cat) || !Array.isArray(items)) return;
|
|
1078
1897
|
filtered[cat] = items.filter((t) => t && typeof t === "object" && t.label && t.value);
|
|
1079
1898
|
});
|
|
1080
|
-
const filteredAll = (rawTags.all || []).filter((t) => t && !
|
|
1899
|
+
const filteredAll = (rawTags.all || []).filter((t) => t && !EXCLUDED2.includes(t.category));
|
|
1081
1900
|
setWorkspaceTags({ by_category: filtered, all: filteredAll });
|
|
1082
1901
|
} catch (err) {
|
|
1083
1902
|
console.error("Workspace Load failed", err);
|
|
@@ -1085,37 +1904,571 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1085
1904
|
};
|
|
1086
1905
|
reader.readAsText(file);
|
|
1087
1906
|
};
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1907
|
+
const fetchServerProjects = async () => {
|
|
1908
|
+
if (!onFetchServerProjects) return;
|
|
1909
|
+
try {
|
|
1910
|
+
setServerProjects(await onFetchServerProjects());
|
|
1911
|
+
} catch {
|
|
1912
|
+
}
|
|
1913
|
+
};
|
|
1914
|
+
const handleServerSave = async (name) => {
|
|
1915
|
+
if (!onServerSave) return;
|
|
1916
|
+
setProjectActionState("working-full");
|
|
1917
|
+
try {
|
|
1918
|
+
const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags);
|
|
1919
|
+
await onServerSave(base64, name || `avatar_project_${getFormattedTimestamp()}`);
|
|
1920
|
+
await fetchServerProjects();
|
|
1921
|
+
setProjectActionState("done");
|
|
1922
|
+
setTimeout(() => setProjectActionState("idle"), 2e3);
|
|
1923
|
+
} catch {
|
|
1924
|
+
setProjectActionState("error");
|
|
1925
|
+
setTimeout(() => setProjectActionState("idle"), 4e3);
|
|
1926
|
+
}
|
|
1927
|
+
};
|
|
1928
|
+
const handleServerLoad = async (id) => {
|
|
1929
|
+
if (!onServerLoad) return;
|
|
1930
|
+
const file = await onServerLoad(id);
|
|
1931
|
+
await handleProjectImport(file);
|
|
1932
|
+
};
|
|
1933
|
+
const handleServerDelete = async (id) => {
|
|
1934
|
+
if (!onServerDelete) return;
|
|
1935
|
+
await onServerDelete(id);
|
|
1936
|
+
await fetchServerProjects();
|
|
1937
|
+
};
|
|
1938
|
+
const handleComputeSyncDiff = async () => {
|
|
1939
|
+
if (!onFetchServerProjects || !onServerLoad) throw new Error("Server nicht konfiguriert");
|
|
1940
|
+
const projects = await onFetchServerProjects();
|
|
1941
|
+
if (projects.length === 0) return { localOnly: [...history], serverOnly: [] };
|
|
1942
|
+
const file = await onServerLoad(projects[0].id);
|
|
1943
|
+
const serverData = await importProjectFromZip(file);
|
|
1944
|
+
syncServerDataRef.current = serverData;
|
|
1945
|
+
const localOnly = history.filter((h) => !(serverData.history || []).find((s) => s.id === h.id));
|
|
1946
|
+
const serverOnly = (serverData.history || []).filter((s) => !history.find((h) => h.id === s.id));
|
|
1947
|
+
return { localOnly, serverOnly };
|
|
1948
|
+
};
|
|
1949
|
+
const handleExecuteSync = async (selectedLocalIds) => {
|
|
1950
|
+
const serverData = syncServerDataRef.current;
|
|
1951
|
+
if (!serverData || !onServerSave) return;
|
|
1952
|
+
setProjectActionState("working-full");
|
|
1953
|
+
try {
|
|
1954
|
+
const selectedLocal = history.filter((h) => selectedLocalIds.includes(h.id));
|
|
1955
|
+
const mergedHistory = [...serverData.history || [], ...selectedLocal];
|
|
1956
|
+
const { base64 } = await exportProjectToZip(
|
|
1957
|
+
serverData.nodes || nodes,
|
|
1958
|
+
serverData.edges || edges,
|
|
1959
|
+
mergedHistory,
|
|
1960
|
+
serverData.galleryItems || galleryItems,
|
|
1961
|
+
serverData.settings || { aspectRatio, selectedModel, seed, seedMode },
|
|
1962
|
+
serverData.workspaceTags || workspaceTags
|
|
1963
|
+
);
|
|
1964
|
+
await onServerSave(base64, `sync_${getFormattedTimestamp()}`);
|
|
1965
|
+
await fetchServerProjects();
|
|
1966
|
+
setProjectActionState("done");
|
|
1967
|
+
setTimeout(() => setProjectActionState("idle"), 2e3);
|
|
1968
|
+
} catch {
|
|
1969
|
+
setProjectActionState("error");
|
|
1970
|
+
setTimeout(() => setProjectActionState("idle"), 4e3);
|
|
1971
|
+
}
|
|
1972
|
+
};
|
|
1973
|
+
useEffect4(() => {
|
|
1974
|
+
if (activeTab === "setup" || activeTab === "sync") fetchServerProjects();
|
|
1975
|
+
}, [activeTab]);
|
|
1976
|
+
if (isFullscreen && currentResult?.base64) {
|
|
1977
|
+
const fsBase64 = currentResult.base64.startsWith("data:") ? currentResult.base64 : `data:image/png;base64,${currentResult.base64}`;
|
|
1978
|
+
return /* @__PURE__ */ jsxs11(
|
|
1979
|
+
"div",
|
|
1980
|
+
{
|
|
1981
|
+
className: "fixed inset-0 bg-black z-50 flex items-center justify-center overflow-hidden touch-none",
|
|
1982
|
+
onTouchStart: handleFsTouchStart,
|
|
1983
|
+
onTouchMove: handleFsTouchMove,
|
|
1984
|
+
onTouchEnd: handleFsTouchEnd,
|
|
1985
|
+
children: [
|
|
1986
|
+
/* @__PURE__ */ jsx13(
|
|
1987
|
+
"img",
|
|
1094
1988
|
{
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
"
|
|
1100
|
-
|
|
1989
|
+
src: fsBase64,
|
|
1990
|
+
alt: "",
|
|
1991
|
+
draggable: false,
|
|
1992
|
+
style: {
|
|
1993
|
+
width: "100%",
|
|
1994
|
+
height: "100%",
|
|
1995
|
+
objectFit: "contain",
|
|
1996
|
+
transform: `scale(${zoomScale}) translate(${zoomOffset.x / zoomScale}px, ${zoomOffset.y / zoomScale}px)`,
|
|
1997
|
+
transformOrigin: "center center",
|
|
1998
|
+
userSelect: "none",
|
|
1999
|
+
pointerEvents: "none"
|
|
2000
|
+
}
|
|
1101
2001
|
}
|
|
1102
2002
|
),
|
|
1103
|
-
|
|
1104
|
-
|
|
2003
|
+
/* @__PURE__ */ jsx13("button", { onClick: closeFullscreen, className: "absolute top-4 right-4 w-10 h-10 flex items-center justify-center rounded-full bg-black/70 border border-white/20 z-10", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "close" }) }),
|
|
2004
|
+
zoomScale > 1 && /* @__PURE__ */ jsx13("button", { onClick: () => {
|
|
2005
|
+
setZoomScale(1);
|
|
2006
|
+
setZoomOffset({ x: 0, y: 0 });
|
|
2007
|
+
}, className: "absolute top-4 left-4 w-10 h-10 flex items-center justify-center rounded-full bg-black/70 border border-white/20 z-10", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "zoom_out_map" }) }),
|
|
2008
|
+
history.length > 1 && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2009
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => {
|
|
2010
|
+
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
2011
|
+
}, disabled: currentIndex <= 0, className: "absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
|
|
2012
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => {
|
|
2013
|
+
if (currentIndex < history.length - 1) setCurrentResult(history[currentIndex + 1]);
|
|
2014
|
+
}, disabled: currentIndex >= history.length - 1, className: "absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
|
|
2015
|
+
/* @__PURE__ */ jsxs11("div", { className: "absolute bottom-6 left-1/2 -translate-x-1/2 bg-black/60 rounded-full px-3 py-0.5 text-[10px] text-white/40 font-mono", children: [
|
|
2016
|
+
currentIndex + 1,
|
|
2017
|
+
" / ",
|
|
2018
|
+
history.length
|
|
2019
|
+
] })
|
|
2020
|
+
] }),
|
|
2021
|
+
zoomScale === 1 && /* @__PURE__ */ jsx13("div", { className: "absolute bottom-6 right-4 text-[9px] text-white/20 font-mono", children: "Pinch zum Zoomen \xB7 Doppeltipp 2.5\xD7" })
|
|
2022
|
+
]
|
|
2023
|
+
}
|
|
2024
|
+
);
|
|
2025
|
+
}
|
|
2026
|
+
if (showStart) {
|
|
2027
|
+
return /* @__PURE__ */ jsxs11("div", { className: "fixed inset-0 bg-[#0e0e0e] flex flex-col items-center justify-center p-6", style: { gap: 28, ...hcStyle }, children: [
|
|
2028
|
+
/* @__PURE__ */ jsx13("input", { ref: wsInputRef, type: "file", accept: ".zip", className: "hidden", onChange: (e) => {
|
|
2029
|
+
const f = e.target.files?.[0];
|
|
2030
|
+
if (f) handleProjectImport(f);
|
|
2031
|
+
e.target.value = "";
|
|
2032
|
+
} }),
|
|
2033
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-1", children: [
|
|
2034
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-white/15 text-[44px]", children: "palette" }),
|
|
2035
|
+
/* @__PURE__ */ jsx13("span", { className: "text-white/25 text-[10px] font-bold uppercase tracking-[0.25em]", children: "Avatar Architect" })
|
|
2036
|
+
] }),
|
|
2037
|
+
/* @__PURE__ */ jsxs11(
|
|
2038
|
+
"button",
|
|
2039
|
+
{
|
|
2040
|
+
onClick: toggleContrast,
|
|
2041
|
+
className: "flex items-center gap-3 px-5 py-3 rounded-2xl border transition-colors",
|
|
2042
|
+
style: { borderColor: highContrast ? "rgba(255,255,255,0.3)" : "rgba(255,255,255,0.08)", background: highContrast ? "rgba(255,255,255,0.08)" : "transparent" },
|
|
2043
|
+
children: [
|
|
2044
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.35)" }, children: highContrast ? "light_mode" : "dark_mode" }),
|
|
2045
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-start", children: [
|
|
2046
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[13px] font-bold", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.5)" }, children: highContrast ? "Hoher Kontrast" : "Normaler Kontrast" }),
|
|
2047
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[10px]", style: { color: "rgba(255,255,255,0.25)" }, children: "Tippen zum Umschalten" })
|
|
2048
|
+
] })
|
|
2049
|
+
]
|
|
2050
|
+
}
|
|
2051
|
+
),
|
|
2052
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
|
|
2053
|
+
/* @__PURE__ */ jsxs11(
|
|
2054
|
+
"button",
|
|
2055
|
+
{
|
|
2056
|
+
onClick: () => wsInputRef.current?.click(),
|
|
2057
|
+
className: "w-full flex items-center justify-center gap-3 rounded-2xl font-bold text-[14px] uppercase tracking-wide text-white active:scale-95 transition-transform",
|
|
2058
|
+
style: { height: 56, background: projectLoaded ? "#16a34a" : "#0284c7" },
|
|
2059
|
+
children: [
|
|
2060
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: projectLoaded ? "check_circle" : "folder_zip" }),
|
|
2061
|
+
projectLoaded ? "Projekt geladen \u2713" : "Projekt laden (.zip)"
|
|
2062
|
+
]
|
|
2063
|
+
}
|
|
2064
|
+
),
|
|
2065
|
+
!projectLoaded && /* @__PURE__ */ jsx13("span", { className: "text-white/20 text-[10px] text-center", children: "Baum, Bilder und Einstellungen wiederherstellen" })
|
|
2066
|
+
] }),
|
|
2067
|
+
onFetchServerProjects && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
|
|
2068
|
+
/* @__PURE__ */ jsxs11(
|
|
2069
|
+
"button",
|
|
2070
|
+
{
|
|
2071
|
+
disabled: isLoadingFromServer,
|
|
2072
|
+
onClick: async () => {
|
|
2073
|
+
setIsLoadingFromServer(true);
|
|
2074
|
+
try {
|
|
2075
|
+
const projects = await onFetchServerProjects();
|
|
2076
|
+
setServerProjects(projects);
|
|
2077
|
+
if (projects.length > 0 && onServerLoad) {
|
|
2078
|
+
const file = await onServerLoad(projects[0].id);
|
|
2079
|
+
await handleProjectImport(file);
|
|
2080
|
+
}
|
|
2081
|
+
} catch {
|
|
2082
|
+
} finally {
|
|
2083
|
+
setIsLoadingFromServer(false);
|
|
2084
|
+
}
|
|
2085
|
+
},
|
|
2086
|
+
className: "w-full flex items-center justify-center gap-3 rounded-2xl font-bold text-[14px] uppercase tracking-wide text-white active:scale-95 transition-transform disabled:opacity-50",
|
|
2087
|
+
style: { height: 56, background: "#7c3aed" },
|
|
2088
|
+
children: [
|
|
2089
|
+
/* @__PURE__ */ jsx13("span", { className: `material-symbols-outlined text-[22px]${isLoadingFromServer ? " animate-spin" : ""}`, children: isLoadingFromServer ? "sync" : "cloud_download" }),
|
|
2090
|
+
isLoadingFromServer ? "Laden\u2026" : "Vom Server laden"
|
|
2091
|
+
]
|
|
2092
|
+
}
|
|
2093
|
+
),
|
|
2094
|
+
/* @__PURE__ */ jsx13("span", { className: "text-white/20 text-[10px] text-center", children: "Letzten Stand vom Server wiederherstellen" })
|
|
2095
|
+
] }),
|
|
2096
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
|
|
2097
|
+
/* @__PURE__ */ jsx13("span", { className: "text-white/25 text-[10px] uppercase tracking-widest font-bold", children: "Layout w\xE4hlen & starten" }),
|
|
2098
|
+
/* @__PURE__ */ jsx13("div", { className: "grid grid-cols-2 gap-2 w-full", children: [
|
|
2099
|
+
{ id: "mobile", icon: "smartphone", label: "Mobile" },
|
|
2100
|
+
{ id: "mobile-desktop", icon: "phonelink", label: "Mobile+" },
|
|
2101
|
+
{ id: "desktop", icon: "desktop_windows", label: "Desktop" },
|
|
2102
|
+
{ id: "tablet-landscape", icon: "tablet", label: "Landscape" }
|
|
2103
|
+
].map((opt) => /* @__PURE__ */ jsxs11(
|
|
2104
|
+
"button",
|
|
2105
|
+
{
|
|
2106
|
+
onClick: () => startApp(opt.id),
|
|
2107
|
+
className: "flex flex-col items-center gap-2 py-4 rounded-2xl border transition-colors",
|
|
2108
|
+
style: { borderColor: layoutChoice === opt.id ? "rgba(255,255,255,0.35)" : "rgba(255,255,255,0.08)", background: layoutChoice === opt.id ? "rgba(255,255,255,0.07)" : "transparent" },
|
|
2109
|
+
children: [
|
|
2110
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[24px]", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.icon }),
|
|
2111
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[11px] font-bold", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.label })
|
|
2112
|
+
]
|
|
2113
|
+
},
|
|
2114
|
+
opt.id
|
|
2115
|
+
)) }),
|
|
2116
|
+
layoutChoice === "mobile-desktop" && /* @__PURE__ */ jsx13("span", { className: "text-white/20 text-[9px] text-center", children: "Mobil-Layout skaliert f\xFCr Desktop-Modus" }),
|
|
2117
|
+
layoutChoice === "tablet-landscape" && /* @__PURE__ */ jsx13("span", { className: "text-white/20 text-[9px] text-center", children: "2-Spalten-Layout f\xFCr Landscape-Tablet im Desktop-Mode" })
|
|
2118
|
+
] })
|
|
2119
|
+
] });
|
|
2120
|
+
}
|
|
2121
|
+
if (layoutChoice === "mobile" || layoutChoice === "mobile-desktop") {
|
|
2122
|
+
const mdMode = layoutChoice === "mobile-desktop";
|
|
2123
|
+
const mdScale = mdMode ? window.innerWidth / 430 : 1;
|
|
2124
|
+
const mdW = mdMode ? 430 : void 0;
|
|
2125
|
+
const mdH = mdMode ? Math.ceil(window.innerHeight / mdScale) : void 0;
|
|
2126
|
+
const mobileRoot = /* @__PURE__ */ jsxs11("div", { className: "flex flex-col bg-[#0e0e0e] text-white overflow-hidden", style: {
|
|
2127
|
+
width: mdMode ? mdW : "100vw",
|
|
2128
|
+
height: mdMode ? mdH : "100dvh",
|
|
2129
|
+
transform: mdMode ? `scale(${mdScale})` : void 0,
|
|
2130
|
+
transformOrigin: mdMode ? "top left" : void 0,
|
|
2131
|
+
...hcStyle || {}
|
|
2132
|
+
}, children: [
|
|
2133
|
+
mobileTab === "stage" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
2134
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 px-3 border-b border-white/5 bg-black/30 shrink-0", style: { height: 52 }, children: [
|
|
2135
|
+
/* @__PURE__ */ jsx13(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
|
|
2136
|
+
/* @__PURE__ */ jsx13(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
|
|
2137
|
+
/* @__PURE__ */ jsx13("div", { className: "flex-1" }),
|
|
2138
|
+
/* @__PURE__ */ jsx13("button", { onClick: toggleContrast, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: highContrast ? "light_mode" : "dark_mode" }) }),
|
|
2139
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => setShowStart(true), className: "text-white/20 active:text-white/60 transition-colors mr-1", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "desktop_windows" }) })
|
|
2140
|
+
] }),
|
|
2141
|
+
/* @__PURE__ */ jsx13("div", { className: "px-3 pt-3 pb-2 shrink-0", children: /* @__PURE__ */ jsxs11("div", { className: `relative rounded-xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
|
|
2142
|
+
/* @__PURE__ */ jsx13(
|
|
2143
|
+
"textarea",
|
|
1105
2144
|
{
|
|
1106
|
-
|
|
1107
|
-
|
|
2145
|
+
value: activePrompt,
|
|
2146
|
+
onChange: (e) => setActivePrompt(e.target.value),
|
|
2147
|
+
className: "w-full bg-transparent border-none outline-none text-[14px] leading-relaxed text-white/80 resize-none dark-scrollbar px-4 pt-3 pb-3",
|
|
2148
|
+
style: { height: 80 },
|
|
2149
|
+
placeholder: "Prompt eingeben..."
|
|
2150
|
+
}
|
|
2151
|
+
),
|
|
2152
|
+
activePrompt && !isSynthesizing && /* @__PURE__ */ jsx13("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-8 h-8 flex items-center justify-center text-white/20 active:text-white transition-colors", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px]", children: "close" }) })
|
|
2153
|
+
] }) }),
|
|
2154
|
+
/* @__PURE__ */ jsx13("div", { className: "px-3 pb-3 shrink-0", children: /* @__PURE__ */ jsx13(
|
|
2155
|
+
"button",
|
|
2156
|
+
{
|
|
2157
|
+
onClick: () => handleGenerateImage(),
|
|
2158
|
+
disabled: !activePrompt.trim() || isGenerating,
|
|
2159
|
+
className: "w-full flex items-center justify-center gap-2 rounded-xl font-bold text-[14px] uppercase tracking-wide transition-all disabled:opacity-30 active:scale-95",
|
|
2160
|
+
style: { height: 48, background: activePrompt.trim() && !isGenerating ? "#0284c7" : void 0, border: "1px solid rgba(255,255,255,0.1)" },
|
|
2161
|
+
children: isGenerating ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2162
|
+
/* @__PURE__ */ jsx13("div", { className: "w-4 h-4 border-t-2 border-white rounded-full animate-spin" }),
|
|
2163
|
+
/* @__PURE__ */ jsx13("span", { children: "Generiere..." })
|
|
2164
|
+
] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2165
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "bolt" }),
|
|
2166
|
+
/* @__PURE__ */ jsx13("span", { children: "Generieren" })
|
|
2167
|
+
] })
|
|
2168
|
+
}
|
|
2169
|
+
) }),
|
|
2170
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex-1 min-h-0 px-3 pb-3 flex flex-col", children: [
|
|
2171
|
+
/* @__PURE__ */ jsxs11(
|
|
2172
|
+
"div",
|
|
2173
|
+
{
|
|
2174
|
+
className: "w-full rounded-2xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center",
|
|
2175
|
+
style: { aspectRatio: "1/1" },
|
|
2176
|
+
onTouchStart: (e) => setTouchStartX(e.touches[0].clientX),
|
|
2177
|
+
onTouchEnd: (e) => {
|
|
2178
|
+
if (touchStartX === null) return;
|
|
2179
|
+
const dx = e.changedTouches[0].clientX - touchStartX;
|
|
2180
|
+
if (dx < -50) goToNext();
|
|
2181
|
+
else if (dx > 50) goToPrev();
|
|
2182
|
+
setTouchStartX(null);
|
|
2183
|
+
},
|
|
1108
2184
|
children: [
|
|
1109
|
-
/* @__PURE__ */
|
|
1110
|
-
|
|
2185
|
+
currentResult?.status === "processing" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-3", children: [
|
|
2186
|
+
/* @__PURE__ */ jsx13("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
|
|
2187
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[11px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
2188
|
+
] }),
|
|
2189
|
+
currentResult?.status === "error" && /* @__PURE__ */ jsxs11("div", { className: "p-6 text-center flex flex-col items-center gap-3", children: [
|
|
2190
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-red-400 text-[36px]", children: "warning" }),
|
|
2191
|
+
/* @__PURE__ */ jsx13("p", { className: "text-white/50 text-[13px]", children: currentResult.error?.message }),
|
|
2192
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => handleGenerateImage(currentResult.prompt), className: "px-4 py-2 rounded-lg border border-white/20 text-[13px] text-white/70 active:bg-white/10", children: "Erneut versuchen" })
|
|
2193
|
+
] }),
|
|
2194
|
+
currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ jsx13("img", { src: currentResult.base64, className: "w-full h-full object-contain" }),
|
|
2195
|
+
!currentResult && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
2196
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[64px]", children: "palette" }),
|
|
2197
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[11px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
2198
|
+
] }),
|
|
2199
|
+
currentResult?.status === "done" && /* @__PURE__ */ jsx13("button", { onClick: openFullscreen, className: "absolute top-2 right-2 w-8 h-8 flex items-center justify-center rounded-full bg-black/60 border border-white/10 z-10", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px]", children: "fullscreen" }) }),
|
|
2200
|
+
history.length > 1 && currentResult && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2201
|
+
/* @__PURE__ */ jsx13("button", { onClick: goToPrev, disabled: currentIndex <= 0, className: "absolute left-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
|
|
2202
|
+
/* @__PURE__ */ jsx13("button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, className: "absolute right-2 top-1/2 -translate-y-1/2 w-10 h-10 flex items-center justify-center rounded-full bg-black/60 border border-white/10 disabled:opacity-0 transition-opacity", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
|
|
2203
|
+
/* @__PURE__ */ jsxs11("div", { className: "absolute bottom-2 left-1/2 -translate-x-1/2 bg-black/60 rounded-full px-3 py-0.5 text-[10px] text-white/40 font-mono", children: [
|
|
2204
|
+
currentIndex + 1,
|
|
2205
|
+
" / ",
|
|
2206
|
+
history.length
|
|
2207
|
+
] })
|
|
2208
|
+
] })
|
|
1111
2209
|
]
|
|
1112
2210
|
}
|
|
2211
|
+
),
|
|
2212
|
+
currentResult?.status === "done" && /* @__PURE__ */ jsxs11("div", { className: "flex gap-2 mt-3", children: [
|
|
2213
|
+
/* @__PURE__ */ jsxs11("button", { onClick: () => setActivePrompt(currentResult.prompt || ""), className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors", style: { height: 44 }, children: [
|
|
2214
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "replay" }),
|
|
2215
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[12px] text-white/60", children: "Prompt" })
|
|
2216
|
+
] }),
|
|
2217
|
+
/* @__PURE__ */ jsxs11("button", { onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl bg-white/10 active:bg-white/15 transition-colors", style: { height: 44 }, children: [
|
|
2218
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px] text-white/80", children: "auto_fix_high" }),
|
|
2219
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[12px] text-white/80 font-bold", children: "Referenz" })
|
|
2220
|
+
] }),
|
|
2221
|
+
/* @__PURE__ */ jsxs11("button", { onClick: handleDownloadSingle, className: "flex-1 flex items-center justify-center gap-1.5 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors", style: { height: 44 }, children: [
|
|
2222
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "download" }),
|
|
2223
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[12px] text-white/60", children: "Laden" })
|
|
2224
|
+
] })
|
|
2225
|
+
] })
|
|
2226
|
+
] })
|
|
2227
|
+
] }),
|
|
2228
|
+
mobileTab === "browse" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
2229
|
+
/* @__PURE__ */ jsx13("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: ["history", "gallery", "inspect"].map((tab) => /* @__PURE__ */ jsx13("button", { onClick: () => setActiveTab(tab), className: `flex-1 flex items-center justify-center gap-1.5 transition-colors text-[11px] font-bold uppercase tracking-wide ${activeTab === tab ? "text-white border-b-2 border-white" : "text-white/30"}`, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : "info" }) }, tab)) }),
|
|
2230
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
2231
|
+
activeTab === "history" && /* @__PURE__ */ jsx13(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: (g) => {
|
|
2232
|
+
setCurrentResult(g);
|
|
2233
|
+
setMobileTab("stage");
|
|
2234
|
+
}, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
|
|
2235
|
+
activeTab === "gallery" && /* @__PURE__ */ jsx13(
|
|
2236
|
+
MediaLibrary,
|
|
2237
|
+
{
|
|
2238
|
+
items: galleryItems,
|
|
2239
|
+
onImport: async () => {
|
|
2240
|
+
const media = await onSelectMedia();
|
|
2241
|
+
if (!media?.length) return;
|
|
2242
|
+
setGalleryItems((prev) => [...media.map((m) => ({ id: crypto.randomUUID(), nodeId: "1", base64: `data:${m.mimeType};base64,${m.base64}`, mediaId: m.mediaId, prompt: m.name || "Importiert", timestamp: Date.now(), status: "done", tags: [], type: "import" })), ...prev]);
|
|
2243
|
+
},
|
|
2244
|
+
onDelete: (id) => setGalleryItems((g) => g.filter((x) => x.id !== id)),
|
|
2245
|
+
onSelect: (g) => {
|
|
2246
|
+
setCurrentResult(g);
|
|
2247
|
+
setMobileTab("stage");
|
|
2248
|
+
},
|
|
2249
|
+
onGenerateReference: (item) => {
|
|
2250
|
+
handleGenerateImage(item.prompt || activePrompt, item.mediaId, void 0, { silent: true });
|
|
2251
|
+
setMobileTab("stage");
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
),
|
|
2255
|
+
activeTab === "inspect" && /* @__PURE__ */ jsx13(InspectPanel, { currentResult, history, onSelect: (g) => {
|
|
2256
|
+
setCurrentResult(g);
|
|
2257
|
+
} })
|
|
2258
|
+
] })
|
|
2259
|
+
] }),
|
|
2260
|
+
mobileTab === "tools" && /* @__PURE__ */ jsxs11("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
2261
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: [
|
|
2262
|
+
workspaceTags && /* @__PURE__ */ jsxs11("button", { onClick: () => {
|
|
2263
|
+
setLeftTab("prompt");
|
|
2264
|
+
if (activeTab === "setup" || activeTab === "sync") setActiveTab("history");
|
|
2265
|
+
}, className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${leftTab === "prompt" && activeTab !== "setup" && activeTab !== "sync" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
|
|
2266
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "auto_fix_high" }),
|
|
2267
|
+
"Prompt"
|
|
2268
|
+
] }),
|
|
2269
|
+
/* @__PURE__ */ jsxs11("button", { onClick: () => {
|
|
2270
|
+
setLeftTab("hierarchy");
|
|
2271
|
+
if (activeTab === "setup" || activeTab === "sync") setActiveTab("history");
|
|
2272
|
+
}, className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${leftTab === "hierarchy" && activeTab !== "setup" && activeTab !== "sync" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
|
|
2273
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "account_tree" }),
|
|
2274
|
+
"Hierarchie"
|
|
2275
|
+
] }),
|
|
2276
|
+
/* @__PURE__ */ jsxs11("button", { onClick: () => setActiveTab("setup"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "setup" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
|
|
2277
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "settings" }),
|
|
2278
|
+
"Setup"
|
|
2279
|
+
] }),
|
|
2280
|
+
/* @__PURE__ */ jsxs11("button", { onClick: () => setActiveTab("sync"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "sync" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: [
|
|
2281
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "cloud_sync" }),
|
|
2282
|
+
"Sync"
|
|
2283
|
+
] })
|
|
2284
|
+
] }),
|
|
2285
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
2286
|
+
leftTab === "hierarchy" && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ jsx13("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx13(
|
|
2287
|
+
ListView,
|
|
2288
|
+
{
|
|
2289
|
+
nodes,
|
|
2290
|
+
edges,
|
|
2291
|
+
onNodeChange: (id, l) => setNodes((nds) => nds.map((n) => n.id === id ? { ...n, data: { ...n.data, label: l } } : n)),
|
|
2292
|
+
onAddChild: (pId) => {
|
|
2293
|
+
const newId = crypto.randomUUID();
|
|
2294
|
+
setNodes((nds) => [...nds, { id: newId, type: "custom", position: { x: 0, y: 0 }, data: { label: "", placeholder: "Konzept..." } }]);
|
|
2295
|
+
setEdges((eds) => [...eds, { id: `e-${pId}-${newId}`, source: pId, target: newId }]);
|
|
2296
|
+
setFocusedNodeId(newId);
|
|
2297
|
+
return newId;
|
|
2298
|
+
},
|
|
2299
|
+
onDeleteNode: (id) => {
|
|
2300
|
+
setNodes((nds) => nds.filter((n) => n.id !== id));
|
|
2301
|
+
setEdges((eds) => eds.filter((e) => e.source !== id && e.target !== id));
|
|
2302
|
+
},
|
|
2303
|
+
onFocus: setFocusedNodeId,
|
|
2304
|
+
focusedNodeId,
|
|
2305
|
+
activePath,
|
|
2306
|
+
onGenerate: (id) => {
|
|
2307
|
+
handleSynthesizePrompt(id);
|
|
2308
|
+
setMobileTab("stage");
|
|
2309
|
+
},
|
|
2310
|
+
onGenerateBranch: (id) => {
|
|
2311
|
+
handleSynthesizePrompt(id, true);
|
|
2312
|
+
setMobileTab("stage");
|
|
2313
|
+
},
|
|
2314
|
+
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
2315
|
+
}
|
|
2316
|
+
) }),
|
|
2317
|
+
leftTab === "prompt" && workspaceTags && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ jsx13(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => {
|
|
2318
|
+
handleGenerateImage(prompt);
|
|
2319
|
+
setMobileTab("stage");
|
|
2320
|
+
}, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete }),
|
|
2321
|
+
activeTab === "setup" && /* @__PURE__ */ jsx13(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
|
|
2322
|
+
activeTab === "sync" && /* @__PURE__ */ jsx13(
|
|
2323
|
+
ProjectSyncTab,
|
|
2324
|
+
{
|
|
2325
|
+
onProjectExport: handleProjectExport,
|
|
2326
|
+
onProjectImport: (f) => handleProjectImport(f),
|
|
2327
|
+
onWorkspaceImport: handleWorkspaceImport,
|
|
2328
|
+
projectActionState,
|
|
2329
|
+
serverProjects: onFetchServerProjects ? serverProjects : void 0,
|
|
2330
|
+
onServerSave: onServerSave ? handleServerSave : void 0,
|
|
2331
|
+
onServerLoad: onServerLoad ? handleServerLoad : void 0,
|
|
2332
|
+
onServerDelete: onServerDelete ? handleServerDelete : void 0,
|
|
2333
|
+
onRefreshServerProjects: onFetchServerProjects ? fetchServerProjects : void 0,
|
|
2334
|
+
onComputeSyncDiff: onFetchServerProjects && onServerLoad && onServerSave ? handleComputeSyncDiff : void 0,
|
|
2335
|
+
onExecuteSync: onFetchServerProjects && onServerLoad && onServerSave ? handleExecuteSync : void 0
|
|
2336
|
+
}
|
|
1113
2337
|
)
|
|
2338
|
+
] })
|
|
2339
|
+
] }),
|
|
2340
|
+
/* @__PURE__ */ jsx13("div", { className: "flex border-t border-white/10 bg-black shrink-0", style: { height: 56, paddingBottom: "env(safe-area-inset-bottom, 0px)" }, children: [
|
|
2341
|
+
{ id: "tools", icon: "auto_fix_high", label: "Prompt" },
|
|
2342
|
+
{ id: "stage", icon: "palette", label: "Stage" },
|
|
2343
|
+
{ id: "browse", icon: "photo_library", label: "Galerie" }
|
|
2344
|
+
].map((tab) => /* @__PURE__ */ jsxs11("button", { onClick: () => setMobileTab(tab.id), className: `flex-1 flex flex-col items-center justify-center gap-0.5 transition-colors ${mobileTab === tab.id ? "text-white" : "text-white/30"}`, children: [
|
|
2345
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[24px]", children: tab.icon }),
|
|
2346
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[10px] font-bold uppercase tracking-wide", children: tab.label })
|
|
2347
|
+
] }, tab.id)) })
|
|
2348
|
+
] });
|
|
2349
|
+
if (mdMode) {
|
|
2350
|
+
return /* @__PURE__ */ jsx13("div", { style: { position: "fixed", inset: 0, overflow: "hidden", background: "#0e0e0e" }, children: mobileRoot });
|
|
2351
|
+
}
|
|
2352
|
+
return mobileRoot;
|
|
2353
|
+
}
|
|
2354
|
+
if (layoutChoice === "tablet-landscape") {
|
|
2355
|
+
const tlScale = Math.min(window.innerWidth / 920, window.innerHeight / 520);
|
|
2356
|
+
const tlW = 920;
|
|
2357
|
+
const tlH = 520;
|
|
2358
|
+
return /* @__PURE__ */ jsx13("div", { style: { position: "fixed", inset: 0, background: "#0e0e0e", display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden", ...hcStyle || {} }, children: /* @__PURE__ */ jsxs11("div", { style: { width: tlW, height: tlH, transform: `scale(${tlScale})`, transformOrigin: "center center", display: "flex", flexDirection: "row", color: "#fff", overflow: "hidden", borderRadius: 0 }, children: [
|
|
2359
|
+
/* @__PURE__ */ jsxs11("div", { style: { width: 320, height: tlH, display: "flex", flexDirection: "column", borderRight: "1px solid rgba(255,255,255,0.05)", background: "#000", flexShrink: 0 }, children: [
|
|
2360
|
+
/* @__PURE__ */ jsxs11("div", { style: { height: 52, borderBottom: "1px solid rgba(255,255,255,0.05)", display: "flex", alignItems: "center", gap: 8, padding: "0 12px", flexShrink: 0 }, children: [
|
|
2361
|
+
/* @__PURE__ */ jsx13(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
|
|
2362
|
+
/* @__PURE__ */ jsx13(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] }),
|
|
2363
|
+
/* @__PURE__ */ jsx13("div", { style: { flex: 1 } }),
|
|
2364
|
+
/* @__PURE__ */ jsx13("button", { onClick: toggleContrast, style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: highContrast ? "light_mode" : "dark_mode" }) }),
|
|
2365
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => setShowStart(true), style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "apps" }) })
|
|
1114
2366
|
] }),
|
|
1115
|
-
/* @__PURE__ */
|
|
2367
|
+
/* @__PURE__ */ jsx13("div", { style: { padding: "12px 12px 8px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs11("div", { style: { position: "relative", borderRadius: 12, border: `1px solid ${isSynthesizing ? "rgba(255,255,255,0.2)" : "rgba(255,255,255,0.1)"}`, background: "rgba(255,255,255,0.05)" }, children: [
|
|
2368
|
+
/* @__PURE__ */ jsx13(
|
|
2369
|
+
"textarea",
|
|
2370
|
+
{
|
|
2371
|
+
value: activePrompt,
|
|
2372
|
+
onChange: (e) => setActivePrompt(e.target.value),
|
|
2373
|
+
style: { width: "100%", background: "transparent", border: "none", outline: "none", fontSize: 12, lineHeight: 1.5, color: "rgba(255,255,255,0.8)", resize: "none", height: 80, padding: "10px 32px 10px 12px", fontFamily: "inherit", boxSizing: "border-box", display: "block" },
|
|
2374
|
+
placeholder: "Prompt eingeben..."
|
|
2375
|
+
}
|
|
2376
|
+
),
|
|
2377
|
+
activePrompt && /* @__PURE__ */ jsx13("button", { onClick: () => setActivePrompt(""), style: { position: "absolute", top: 6, right: 6, width: 22, height: 22, display: "flex", alignItems: "center", justifyContent: "center", color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 0 }, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 15 }, children: "close" }) })
|
|
2378
|
+
] }) }),
|
|
2379
|
+
/* @__PURE__ */ jsx13("div", { style: { padding: "0 12px 10px", flexShrink: 0 }, children: /* @__PURE__ */ jsx13(
|
|
2380
|
+
"button",
|
|
2381
|
+
{
|
|
2382
|
+
onClick: () => handleGenerateImage(),
|
|
2383
|
+
disabled: !activePrompt.trim() || isGenerating,
|
|
2384
|
+
style: { width: "100%", height: 42, display: "flex", alignItems: "center", justifyContent: "center", gap: 8, borderRadius: 10, fontWeight: "bold", fontSize: 13, textTransform: "uppercase", letterSpacing: "0.05em", border: "1px solid rgba(255,255,255,0.1)", background: activePrompt.trim() && !isGenerating ? "#0284c7" : "transparent", color: "#fff", cursor: activePrompt.trim() && !isGenerating ? "pointer" : "default", opacity: !activePrompt.trim() || isGenerating ? 0.3 : 1, fontFamily: "inherit", transition: "background 0.2s" },
|
|
2385
|
+
children: isGenerating ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2386
|
+
/* @__PURE__ */ jsx13("div", { style: { width: 14, height: 14, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
|
|
2387
|
+
/* @__PURE__ */ jsx13("span", { children: "Generiere..." })
|
|
2388
|
+
] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2389
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "bolt" }),
|
|
2390
|
+
/* @__PURE__ */ jsx13("span", { children: "Generieren" })
|
|
2391
|
+
] })
|
|
2392
|
+
}
|
|
2393
|
+
) }),
|
|
2394
|
+
/* @__PURE__ */ jsx13("div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ jsx13(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }) })
|
|
1116
2395
|
] }),
|
|
1117
|
-
|
|
1118
|
-
|
|
2396
|
+
/* @__PURE__ */ jsxs11("div", { style: { flex: 1, height: tlH, display: "flex", flexDirection: "column", background: "#0b0b0b" }, children: [
|
|
2397
|
+
/* @__PURE__ */ jsx13(
|
|
2398
|
+
"div",
|
|
2399
|
+
{
|
|
2400
|
+
style: { flex: 1, padding: 16, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" },
|
|
2401
|
+
onTouchStart: (e) => setTouchStartX(e.touches[0].clientX),
|
|
2402
|
+
onTouchEnd: (e) => {
|
|
2403
|
+
if (touchStartX === null) return;
|
|
2404
|
+
const dx = e.changedTouches[0].clientX - touchStartX;
|
|
2405
|
+
if (dx < -50) goToNext();
|
|
2406
|
+
else if (dx > 50) goToPrev();
|
|
2407
|
+
setTouchStartX(null);
|
|
2408
|
+
},
|
|
2409
|
+
children: /* @__PURE__ */ jsxs11("div", { style: { height: "100%", width: "100%", borderRadius: 20, border: "1px solid rgba(255,255,255,0.05)", background: "rgba(0,0,0,0.4)", position: "relative", overflow: "hidden", display: "flex", alignItems: "center", justifyContent: "center" }, children: [
|
|
2410
|
+
currentResult?.status === "processing" && /* @__PURE__ */ jsxs11("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
|
|
2411
|
+
/* @__PURE__ */ jsx13("div", { style: { width: 36, height: 36, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
|
|
2412
|
+
/* @__PURE__ */ jsx13("span", { style: { fontSize: 10, color: "rgba(255,255,255,0.4)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
|
|
2413
|
+
] }),
|
|
2414
|
+
currentResult?.status === "error" && /* @__PURE__ */ jsxs11("div", { style: { padding: 24, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
|
|
2415
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 32, color: "#f87171" }, children: "warning" }),
|
|
2416
|
+
/* @__PURE__ */ jsx13("p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: currentResult.error?.message }),
|
|
2417
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => handleGenerateImage(currentResult.prompt), style: { padding: "8px 16px", borderRadius: 8, border: "1px solid rgba(255,255,255,0.2)", fontSize: 11, color: "rgba(255,255,255,0.7)", background: "none", cursor: "pointer", fontFamily: "inherit" }, children: "Erneut versuchen" })
|
|
2418
|
+
] }),
|
|
2419
|
+
currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ jsx13("img", { src: currentResult.base64, style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain" } }),
|
|
2420
|
+
!currentResult && /* @__PURE__ */ jsxs11("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 8, opacity: 0.1 }, children: [
|
|
2421
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 64 }, children: "palette" }),
|
|
2422
|
+
/* @__PURE__ */ jsx13("span", { style: { fontSize: 11, fontWeight: "bold", textTransform: "uppercase", letterSpacing: "0.2em" }, children: "Avatar Architect" })
|
|
2423
|
+
] }),
|
|
2424
|
+
currentResult?.status === "done" && /* @__PURE__ */ jsx13("button", { onClick: openFullscreen, style: { position: "absolute", top: 8, right: 8, width: 32, height: 32, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff" }, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "fullscreen" }) }),
|
|
2425
|
+
history.length > 1 && currentResult && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2426
|
+
/* @__PURE__ */ jsx13("button", { onClick: goToPrev, disabled: currentIndex <= 0, style: { position: "absolute", left: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex <= 0 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_left" }) }),
|
|
2427
|
+
/* @__PURE__ */ jsx13("button", { onClick: goToNext, disabled: currentIndex >= history.length - 1, style: { position: "absolute", right: 8, top: "50%", transform: "translateY(-50%)", width: 36, height: 36, display: "flex", alignItems: "center", justifyContent: "center", borderRadius: "50%", background: "rgba(0,0,0,0.6)", border: "1px solid rgba(255,255,255,0.1)", cursor: "pointer", color: "#fff", opacity: currentIndex >= history.length - 1 ? 0 : 1, transition: "opacity 0.2s" }, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_right" }) }),
|
|
2428
|
+
/* @__PURE__ */ jsxs11("div", { style: { position: "absolute", bottom: 8, left: "50%", transform: "translateX(-50%)", background: "rgba(0,0,0,0.6)", borderRadius: 999, padding: "2px 12px", fontSize: 10, color: "rgba(255,255,255,0.4)", fontFamily: "monospace" }, children: [
|
|
2429
|
+
currentIndex + 1,
|
|
2430
|
+
" / ",
|
|
2431
|
+
history.length
|
|
2432
|
+
] })
|
|
2433
|
+
] })
|
|
2434
|
+
] })
|
|
2435
|
+
}
|
|
2436
|
+
),
|
|
2437
|
+
currentResult?.status === "done" && /* @__PURE__ */ jsxs11("div", { style: { padding: "0 16px 16px", display: "flex", gap: 8, flexShrink: 0 }, children: [
|
|
2438
|
+
/* @__PURE__ */ jsxs11("button", { onClick: () => setActivePrompt(currentResult.prompt || ""), style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "1px solid rgba(255,255,255,0.1)", background: "rgba(255,255,255,0.05)", color: "rgba(255,255,255,0.6)", fontSize: 11, cursor: "pointer", fontFamily: "inherit" }, children: [
|
|
2439
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "replay" }),
|
|
2440
|
+
/* @__PURE__ */ jsx13("span", { children: "Prompt" })
|
|
2441
|
+
] }),
|
|
2442
|
+
/* @__PURE__ */ jsxs11("button", { onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "none", background: "rgba(255,255,255,0.1)", color: "rgba(255,255,255,0.8)", fontSize: 11, fontWeight: "bold", cursor: "pointer", fontFamily: "inherit" }, children: [
|
|
2443
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "auto_fix_high" }),
|
|
2444
|
+
/* @__PURE__ */ jsx13("span", { children: "Referenz" })
|
|
2445
|
+
] }),
|
|
2446
|
+
/* @__PURE__ */ jsxs11("button", { onClick: handleDownloadSingle, style: { flex: 1, height: 40, display: "flex", alignItems: "center", justifyContent: "center", gap: 6, borderRadius: 10, border: "1px solid rgba(255,255,255,0.1)", background: "rgba(255,255,255,0.05)", color: "rgba(255,255,255,0.6)", fontSize: 11, cursor: "pointer", fontFamily: "inherit" }, children: [
|
|
2447
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "download" }),
|
|
2448
|
+
/* @__PURE__ */ jsx13("span", { children: "Laden" })
|
|
2449
|
+
] })
|
|
2450
|
+
] })
|
|
2451
|
+
] })
|
|
2452
|
+
] }) });
|
|
2453
|
+
}
|
|
2454
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", style: hcStyle, children: [
|
|
2455
|
+
/* @__PURE__ */ jsx13("div", { className: "absolute top-2 right-2 z-50", children: /* @__PURE__ */ jsx13("button", { onClick: () => setShowStart(true), className: "text-white/10 hover:text-white/30 transition-colors text-[10px]", children: "\u21C4" }) }),
|
|
2456
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", style: { width: isLeftCollapsed ? 48 : 260, transition: "width 0.2s" }, children: [
|
|
2457
|
+
/* @__PURE__ */ jsxs11("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
|
|
2458
|
+
!isLeftCollapsed && /* @__PURE__ */ jsxs11("div", { className: "flex flex-1 gap-1", children: [
|
|
2459
|
+
workspaceTags && /* @__PURE__ */ jsxs11("button", { onClick: () => setLeftTab("prompt"), className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "prompt" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`, children: [
|
|
2460
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
|
|
2461
|
+
"Prompt"
|
|
2462
|
+
] }),
|
|
2463
|
+
/* @__PURE__ */ jsxs11("button", { onClick: () => setLeftTab("hierarchy"), className: `flex-1 flex items-center justify-center gap-1 h-8 rounded-lg text-[8px] font-bold uppercase tracking-wide transition-colors ${leftTab === "hierarchy" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/60"}`, children: [
|
|
2464
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
|
|
2465
|
+
"Hierarchie"
|
|
2466
|
+
] })
|
|
2467
|
+
] }),
|
|
2468
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => setIsLeftCollapsed(!isLeftCollapsed), className: "material-symbols-outlined text-[18px] text-white/40 hover:text-white transition-all w-10 flex items-center justify-center", children: isLeftCollapsed ? "chevron_right" : "chevron_left" })
|
|
2469
|
+
] }),
|
|
2470
|
+
!isLeftCollapsed && /* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
2471
|
+
leftTab === "hierarchy" && /* @__PURE__ */ jsx13("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx13(
|
|
1119
2472
|
ListView,
|
|
1120
2473
|
{
|
|
1121
2474
|
nodes,
|
|
@@ -1139,124 +2492,104 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1139
2492
|
onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
|
|
1140
2493
|
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
1141
2494
|
}
|
|
1142
|
-
) }
|
|
1143
|
-
leftTab === "prompt" && workspaceTags && /* @__PURE__ */
|
|
1144
|
-
|
|
1145
|
-
{
|
|
1146
|
-
workspaceTags,
|
|
1147
|
-
onGenerate: handlePromptTabGenerate,
|
|
1148
|
-
isGenerating: isPromptTabGenerating,
|
|
1149
|
-
feedback: promptFeedback
|
|
1150
|
-
}
|
|
1151
|
-
) }, "prompt")
|
|
1152
|
-
] }) })
|
|
2495
|
+
) }),
|
|
2496
|
+
leftTab === "prompt" && workspaceTags && /* @__PURE__ */ jsx13(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => handleGenerateImage(prompt), onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete })
|
|
2497
|
+
] })
|
|
1153
2498
|
] }),
|
|
1154
|
-
/* @__PURE__ */
|
|
1155
|
-
/* @__PURE__ */
|
|
1156
|
-
/* @__PURE__ */
|
|
1157
|
-
/* @__PURE__ */
|
|
1158
|
-
/* @__PURE__ */
|
|
2499
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
|
|
2500
|
+
/* @__PURE__ */ jsxs11("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
|
|
2501
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5", children: [
|
|
2502
|
+
/* @__PURE__ */ jsx13(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
|
|
2503
|
+
/* @__PURE__ */ jsx13(CompactDropdown, { value: selectedModel, onChange: setSelectedModel, options: [{ value: "\u{1F34C} Nano Banana Pro", label: "\u{1F34C} Nano Banana Pro" }, { value: "\u{1F34C} Nano Banana 2", label: "\u{1F34C} Nano Banana 2" }, { value: "Imagen 4", label: "Imagen 4" }] })
|
|
1159
2504
|
] }),
|
|
1160
|
-
/* @__PURE__ */
|
|
1161
|
-
/* @__PURE__ */
|
|
1162
|
-
/* @__PURE__ */
|
|
2505
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2", children: [
|
|
2506
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
|
|
2507
|
+
/* @__PURE__ */ jsx13(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
|
|
1163
2508
|
] })
|
|
1164
2509
|
] }),
|
|
1165
|
-
/* @__PURE__ */
|
|
1166
|
-
|
|
1167
|
-
/* @__PURE__ */
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1175
|
-
),
|
|
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" }) })
|
|
1177
|
-
] }) }) }),
|
|
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..." })
|
|
2510
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
|
|
2511
|
+
!isPromptCollapsed && /* @__PURE__ */ jsx13("div", { className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ jsxs11("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
|
|
2512
|
+
/* @__PURE__ */ jsx13("textarea", { value: activePrompt, onChange: (e) => setActivePrompt(e.target.value), className: "w-full bg-transparent border-none outline-none text-[12px] leading-relaxed text-white/80 resize-none h-20 dark-scrollbar", placeholder: "W\xE4hle einen Knoten oder tippe einen Prompt..." }),
|
|
2513
|
+
activePrompt && !isSynthesizing && /* @__PURE__ */ jsx13("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-6 h-6 rounded-full bg-white/5 hover:bg-white/10 flex items-center justify-center transition-colors text-white/20 hover:text-white", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
2514
|
+
] }) }),
|
|
2515
|
+
/* @__PURE__ */ jsx13("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsxs11("div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: [
|
|
2516
|
+
isGenerating && currentResult?.status === "done" && /* @__PURE__ */ jsxs11("div", { className: "absolute top-6 right-6 z-30 bg-black/60 backdrop-blur-md px-4 py-2 rounded-full border border-white/10 flex items-center gap-3", children: [
|
|
2517
|
+
/* @__PURE__ */ jsx13("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
|
|
2518
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
|
|
1182
2519
|
] }),
|
|
1183
|
-
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
/* @__PURE__ */
|
|
1186
|
-
] }) : currentResult.status === "error" ? /* @__PURE__ */
|
|
1187
|
-
/* @__PURE__ */
|
|
1188
|
-
/* @__PURE__ */
|
|
1189
|
-
/* @__PURE__ */
|
|
1190
|
-
/* @__PURE__ */
|
|
2520
|
+
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-4", children: [
|
|
2521
|
+
/* @__PURE__ */ jsx13("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
|
|
2522
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
2523
|
+
] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs11("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
|
|
2524
|
+
/* @__PURE__ */ jsx13("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
|
|
2525
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-col gap-2", children: [
|
|
2526
|
+
/* @__PURE__ */ jsx13("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
|
|
2527
|
+
/* @__PURE__ */ jsx13("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
|
|
1191
2528
|
] }),
|
|
1192
|
-
/* @__PURE__ */
|
|
1193
|
-
] }) : /* @__PURE__ */
|
|
1194
|
-
/* @__PURE__ */
|
|
1195
|
-
/* @__PURE__ */
|
|
1196
|
-
/* @__PURE__ */
|
|
1197
|
-
/* @__PURE__ */
|
|
1198
|
-
/* @__PURE__ */
|
|
2529
|
+
/* @__PURE__ */ jsx13(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
|
|
2530
|
+
] }) : /* @__PURE__ */ jsxs11("div", { className: "h-full w-full relative flex items-center justify-center", children: [
|
|
2531
|
+
/* @__PURE__ */ jsx13("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
|
|
2532
|
+
/* @__PURE__ */ jsxs11("div", { className: "absolute bottom-6 flex gap-2 opacity-0 group-hover:opacity-100 transition-all translate-y-4 group-hover:translate-y-0 z-20", children: [
|
|
2533
|
+
/* @__PURE__ */ jsx13(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
|
|
2534
|
+
/* @__PURE__ */ jsx13(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
|
|
2535
|
+
/* @__PURE__ */ jsx13(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
|
|
1199
2536
|
] })
|
|
1200
|
-
] }) : /* @__PURE__ */
|
|
1201
|
-
/* @__PURE__ */
|
|
1202
|
-
/* @__PURE__ */
|
|
2537
|
+
] }) : /* @__PURE__ */ jsxs11("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
2538
|
+
/* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
|
|
2539
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
1203
2540
|
] })
|
|
1204
2541
|
] }) })
|
|
1205
2542
|
] })
|
|
1206
2543
|
] }),
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
/* @__PURE__ */
|
|
1209
|
-
/* @__PURE__ */
|
|
2544
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", style: { width: isRightCollapsed ? 60 : 320, transition: "width 0.2s" }, children: [
|
|
2545
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
|
|
2546
|
+
/* @__PURE__ */ jsx13("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup", "sync"].map((tab) => /* @__PURE__ */ jsx13("button", { onClick: () => {
|
|
1210
2547
|
setActiveTab(tab);
|
|
1211
2548
|
setIsRightCollapsed(false);
|
|
1212
|
-
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */
|
|
1213
|
-
/* @__PURE__ */
|
|
2549
|
+
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : tab === "setup" ? "settings" : "cloud_sync" }) }, tab)) }),
|
|
2550
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
|
|
1214
2551
|
] }),
|
|
1215
|
-
!isRightCollapsed && /* @__PURE__ */
|
|
1216
|
-
activeTab === "history" && /* @__PURE__ */
|
|
1217
|
-
activeTab === "gallery" && /* @__PURE__ */
|
|
2552
|
+
!isRightCollapsed && /* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
2553
|
+
activeTab === "history" && /* @__PURE__ */ jsx13(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
|
|
2554
|
+
activeTab === "gallery" && /* @__PURE__ */ jsx13(
|
|
1218
2555
|
MediaLibrary,
|
|
1219
2556
|
{
|
|
1220
2557
|
items: galleryItems,
|
|
1221
2558
|
onImport: async () => {
|
|
1222
2559
|
const media = await onSelectMedia();
|
|
1223
2560
|
if (!media?.length) return;
|
|
1224
|
-
|
|
1225
|
-
id: crypto.randomUUID(),
|
|
1226
|
-
nodeId: "1",
|
|
1227
|
-
base64: `data:${m.mimeType};base64,${m.base64}`,
|
|
1228
|
-
mediaId: m.mediaId,
|
|
1229
|
-
prompt: m.name || "Importiert",
|
|
1230
|
-
timestamp: Date.now(),
|
|
1231
|
-
status: "done",
|
|
1232
|
-
tags: [],
|
|
1233
|
-
type: "import"
|
|
1234
|
-
}));
|
|
1235
|
-
setGalleryItems((prev) => [...newItems, ...prev]);
|
|
2561
|
+
setGalleryItems((prev) => [...media.map((m) => ({ id: crypto.randomUUID(), nodeId: "1", base64: `data:${m.mimeType};base64,${m.base64}`, mediaId: m.mediaId, prompt: m.name || "Importiert", timestamp: Date.now(), status: "done", tags: [], type: "import" })), ...prev]);
|
|
1236
2562
|
},
|
|
1237
2563
|
onDelete: (id) => setGalleryItems((g) => g.filter((x) => x.id !== id)),
|
|
1238
2564
|
onSelect: setCurrentResult,
|
|
1239
2565
|
onGenerateReference: (item) => handleGenerateImage(item.prompt || activePrompt, item.mediaId, void 0, { silent: true })
|
|
1240
|
-
}
|
|
1241
|
-
"gallery"
|
|
2566
|
+
}
|
|
1242
2567
|
),
|
|
1243
|
-
activeTab === "inspect" && /* @__PURE__ */
|
|
1244
|
-
activeTab === "setup" && /* @__PURE__ */
|
|
1245
|
-
|
|
2568
|
+
activeTab === "inspect" && /* @__PURE__ */ jsx13(InspectPanel, { currentResult, history, onSelect: setCurrentResult }),
|
|
2569
|
+
activeTab === "setup" && /* @__PURE__ */ jsx13(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
|
|
2570
|
+
activeTab === "sync" && /* @__PURE__ */ jsx13(
|
|
2571
|
+
ProjectSyncTab,
|
|
1246
2572
|
{
|
|
1247
2573
|
onProjectExport: handleProjectExport,
|
|
1248
|
-
onProjectImport: handleProjectImport,
|
|
2574
|
+
onProjectImport: (f) => handleProjectImport(f),
|
|
1249
2575
|
onWorkspaceImport: handleWorkspaceImport,
|
|
1250
|
-
projectActionState
|
|
1251
|
-
|
|
1252
|
-
|
|
2576
|
+
projectActionState,
|
|
2577
|
+
serverProjects: onFetchServerProjects ? serverProjects : void 0,
|
|
2578
|
+
onServerSave: onServerSave ? handleServerSave : void 0,
|
|
2579
|
+
onServerLoad: onServerLoad ? handleServerLoad : void 0,
|
|
2580
|
+
onServerDelete: onServerDelete ? handleServerDelete : void 0,
|
|
2581
|
+
onRefreshServerProjects: onFetchServerProjects ? fetchServerProjects : void 0,
|
|
2582
|
+
onComputeSyncDiff: onFetchServerProjects && onServerLoad && onServerSave ? handleComputeSyncDiff : void 0,
|
|
2583
|
+
onExecuteSync: onFetchServerProjects && onServerLoad && onServerSave ? handleExecuteSync : void 0
|
|
2584
|
+
}
|
|
1253
2585
|
)
|
|
1254
|
-
] })
|
|
2586
|
+
] })
|
|
1255
2587
|
] })
|
|
1256
2588
|
] });
|
|
1257
2589
|
}
|
|
1258
2590
|
export {
|
|
1259
2591
|
AvatarArchitectApp,
|
|
2592
|
+
CollapsibleCard,
|
|
1260
2593
|
CompactDropdown,
|
|
1261
2594
|
FaToolsBadge,
|
|
1262
2595
|
GLOBAL_STYLES,
|
|
@@ -1265,6 +2598,7 @@ export {
|
|
|
1265
2598
|
ListView,
|
|
1266
2599
|
MediaLibrary,
|
|
1267
2600
|
PillButton,
|
|
2601
|
+
ProjectSyncTab,
|
|
1268
2602
|
PromptTab,
|
|
1269
2603
|
SectionLabel,
|
|
1270
2604
|
SetupPanel,
|
|
@@ -1273,6 +2607,7 @@ export {
|
|
|
1273
2607
|
buildImageGenerationOptions,
|
|
1274
2608
|
buildPromptTabPayload,
|
|
1275
2609
|
cleanAiResponse,
|
|
2610
|
+
createFlowServices,
|
|
1276
2611
|
exportProjectToZip,
|
|
1277
2612
|
formatTreeToMarkdown,
|
|
1278
2613
|
getFormattedTimestamp,
|