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