@rslsp1/fa-app-tools 1.0.2 → 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 +74 -9
- package/dist/index.d.ts +74 -9
- package/dist/index.js +1570 -261
- package/dist/index.mjs +1553 -246
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -197,7 +197,7 @@ function generateMarkdownReport(nodes, history) {
|
|
|
197
197
|
});
|
|
198
198
|
return md;
|
|
199
199
|
}
|
|
200
|
-
async function exportProjectToZip(nodes, edges, history, galleryItems, settings) {
|
|
200
|
+
async function exportProjectToZip(nodes, edges, history, galleryItems, settings, workspaceTags) {
|
|
201
201
|
const zip = new JSZip();
|
|
202
202
|
const projectData = {
|
|
203
203
|
nodes,
|
|
@@ -205,6 +205,7 @@ async function exportProjectToZip(nodes, edges, history, galleryItems, settings)
|
|
|
205
205
|
history: history.map((h) => ({ ...h, base64: void 0 })),
|
|
206
206
|
galleryItems: galleryItems.map((g) => ({ ...g, base64: void 0 })),
|
|
207
207
|
settings,
|
|
208
|
+
workspaceTags: workspaceTags || null,
|
|
208
209
|
version: "1.2.6"
|
|
209
210
|
};
|
|
210
211
|
zip.file("project.json", JSON.stringify(projectData, null, 2));
|
|
@@ -293,14 +294,44 @@ function buildImageGenerationOptions(prompt, aspectRatio, model, referenceMediaI
|
|
|
293
294
|
}
|
|
294
295
|
return options;
|
|
295
296
|
}
|
|
296
|
-
|
|
297
|
+
var CONTENT_FIRST = ["subject", "clothing", "environment", "mood", "action", "content", "general"];
|
|
298
|
+
var RULES_LAST = ["system", "rules", "safety", "generated", "source", "status", "type", "model"];
|
|
299
|
+
function categoryZone(cat) {
|
|
300
|
+
const c = cat.toLowerCase();
|
|
301
|
+
if (CONTENT_FIRST.some((k) => c.includes(k))) return 0;
|
|
302
|
+
if (RULES_LAST.some((k) => c.includes(k))) return 2;
|
|
303
|
+
return 1;
|
|
304
|
+
}
|
|
305
|
+
var ZONE_SEPARATORS = { 1: "\u2500\u2500\u2500\u2500 STYLE \u2500\u2500\u2500\u2500", 2: "\u2500\u2500\u2500\u2500 SYSTEM / RULES \u2500\u2500\u2500\u2500" };
|
|
306
|
+
function buildPromptTabPayload(selectedTags, instructions, rules, treeText) {
|
|
297
307
|
const parts = [];
|
|
298
308
|
if (treeText) parts.push(`HIERARCHY:
|
|
299
309
|
${treeText}`);
|
|
300
|
-
if (
|
|
301
|
-
|
|
302
|
-
|
|
310
|
+
if (selectedTags.length > 0) {
|
|
311
|
+
const sorted = [...selectedTags].sort((a, b) => categoryZone(a.category) - categoryZone(b.category) || a.category.localeCompare(b.category));
|
|
312
|
+
const byCategory = sorted.reduce((acc, t) => {
|
|
313
|
+
(acc[t.category] = acc[t.category] || []).push(t);
|
|
314
|
+
return acc;
|
|
315
|
+
}, {});
|
|
316
|
+
const tagParts = [];
|
|
317
|
+
let lastZone = -1;
|
|
318
|
+
for (const [cat, tags] of Object.entries(byCategory)) {
|
|
319
|
+
const zone = categoryZone(cat);
|
|
320
|
+
if (lastZone >= 0 && zone > lastZone && ZONE_SEPARATORS[zone]) {
|
|
321
|
+
tagParts.push(ZONE_SEPARATORS[zone]);
|
|
322
|
+
}
|
|
323
|
+
tagParts.push(...tags.map((t) => `[${cat.toUpperCase()}]
|
|
324
|
+
${t.value}`));
|
|
325
|
+
lastZone = zone;
|
|
326
|
+
}
|
|
327
|
+
parts.push(`SELECTED TAGS:
|
|
328
|
+
|
|
329
|
+
${tagParts.join("\n\n")}`);
|
|
330
|
+
}
|
|
331
|
+
if (instructions.trim()) parts.push(`DESCRIPTION:
|
|
303
332
|
${instructions.trim()}`);
|
|
333
|
+
if (rules.trim()) parts.push(`GENERATION RULES:
|
|
334
|
+
${rules.trim()}`);
|
|
304
335
|
return [
|
|
305
336
|
"Create a high-quality image generation prompt based on the following inputs. Translate everything to English.",
|
|
306
337
|
`Return a JSON object with exactly two keys: "prompt" (the prompt string) and "feedback" (a short note on your choices in the user's language, or null).`,
|
|
@@ -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);
|
|
904
|
+
};
|
|
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);
|
|
809
946
|
};
|
|
810
|
-
const
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
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
|
+
)
|
|
872
1481
|
] }),
|
|
873
|
-
/* @__PURE__ */
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
"
|
|
877
|
-
|
|
878
|
-
|
|
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"
|
|
1503
|
+
] }),
|
|
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,17 +1716,7 @@ 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);
|
|
@@ -1000,12 +1753,48 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1000
1753
|
setIsSynthesizing(false);
|
|
1001
1754
|
}
|
|
1002
1755
|
};
|
|
1003
|
-
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) => {
|
|
1004
1792
|
setIsPromptTabGenerating(true);
|
|
1005
1793
|
setPromptFeedback(null);
|
|
1006
1794
|
try {
|
|
1007
1795
|
const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : void 0;
|
|
1008
|
-
const payload = buildPromptTabPayload(
|
|
1796
|
+
const payload = buildPromptTabPayload(selectedTags, instructions, rules, treeText);
|
|
1797
|
+
setLastPromptPayload(payload);
|
|
1009
1798
|
const raw = await onGeneratePrompt(payload);
|
|
1010
1799
|
const { prompt, feedback } = parsePromptResponse(raw);
|
|
1011
1800
|
setActivePrompt(prompt);
|
|
@@ -1022,9 +1811,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1022
1811
|
const base64Data = currentResult.base64.split(",")[1];
|
|
1023
1812
|
const mimeType = currentResult.base64.split(";")[0].split(":")[1] || "image/png";
|
|
1024
1813
|
let finalBase64 = base64Data;
|
|
1025
|
-
if (mimeType === "image/png")
|
|
1026
|
-
finalBase64 = injectXMPMetadata(base64Data, currentResult.prompt || "", currentResult.seed, currentResult.model, currentResult.id, currentResult.tags || [], getSubtreeFormat(currentResult.nodeId));
|
|
1027
|
-
}
|
|
1814
|
+
if (mimeType === "image/png") finalBase64 = injectXMPMetadata(base64Data, currentResult.prompt || "", currentResult.seed, currentResult.model, currentResult.id, currentResult.tags || [], getSubtreeFormat(currentResult.nodeId));
|
|
1028
1815
|
await onDownload(finalBase64, mimeType, `avatar_${currentResult.id.slice(0, 5)}.${mimeType.split("/")[1]}`);
|
|
1029
1816
|
} catch (e) {
|
|
1030
1817
|
console.error("Download Error", e);
|
|
@@ -1033,7 +1820,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1033
1820
|
const handleProjectExport = async () => {
|
|
1034
1821
|
setProjectActionState("working-full");
|
|
1035
1822
|
try {
|
|
1036
|
-
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);
|
|
1037
1824
|
await onDownload(base64, "application/zip", `avatar_project_${getFormattedTimestamp()}.zip`);
|
|
1038
1825
|
setProjectActionState("done");
|
|
1039
1826
|
setTimeout(() => setProjectActionState("idle"), 3e3);
|
|
@@ -1049,7 +1836,10 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1049
1836
|
const data = await importProjectFromZip(file);
|
|
1050
1837
|
if (data.nodes) setNodes(data.nodes);
|
|
1051
1838
|
if (data.edges) setEdges(data.edges);
|
|
1052
|
-
if (data.history)
|
|
1839
|
+
if (data.history) {
|
|
1840
|
+
setHistory(data.history);
|
|
1841
|
+
if (data.history.length > 0) setCurrentResult(data.history[0]);
|
|
1842
|
+
}
|
|
1053
1843
|
if (data.galleryItems) setGalleryItems(data.galleryItems);
|
|
1054
1844
|
if (data.settings) {
|
|
1055
1845
|
setAspectRatio(data.settings.aspectRatio || "1:1");
|
|
@@ -1057,7 +1847,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1057
1847
|
setSeed(data.settings.seed || 0);
|
|
1058
1848
|
setSeedMode(data.settings.seedMode || "random");
|
|
1059
1849
|
}
|
|
1850
|
+
if (data.workspaceTags?.by_category) setWorkspaceTags(data.workspaceTags);
|
|
1060
1851
|
setProjectActionState("done");
|
|
1852
|
+
setProjectLoaded(true);
|
|
1061
1853
|
setTimeout(() => setProjectActionState("idle"), 2e3);
|
|
1062
1854
|
} catch {
|
|
1063
1855
|
setProjectActionState("error");
|
|
@@ -1072,12 +1864,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1072
1864
|
const rawTags = root.tags || root;
|
|
1073
1865
|
if (!rawTags?.by_category) return;
|
|
1074
1866
|
const filtered = {};
|
|
1075
|
-
const
|
|
1867
|
+
const EXCLUDED2 = ["pdf-export", "book.micro-edit-rules"];
|
|
1076
1868
|
Object.entries(rawTags.by_category).forEach(([cat, items]) => {
|
|
1077
|
-
if (
|
|
1869
|
+
if (EXCLUDED2.includes(cat) || !Array.isArray(items)) return;
|
|
1078
1870
|
filtered[cat] = items.filter((t) => t && typeof t === "object" && t.label && t.value);
|
|
1079
1871
|
});
|
|
1080
|
-
const filteredAll = (rawTags.all || []).filter((t) => t && !
|
|
1872
|
+
const filteredAll = (rawTags.all || []).filter((t) => t && !EXCLUDED2.includes(t.category));
|
|
1081
1873
|
setWorkspaceTags({ by_category: filtered, all: filteredAll });
|
|
1082
1874
|
} catch (err) {
|
|
1083
1875
|
console.error("Workspace Load failed", err);
|
|
@@ -1085,37 +1877,571 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1085
1877
|
};
|
|
1086
1878
|
reader.readAsText(file);
|
|
1087
1879
|
};
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
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",
|
|
1094
1961
|
{
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
"
|
|
1100
|
-
|
|
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
|
+
}
|
|
1101
1974
|
}
|
|
1102
1975
|
),
|
|
1103
|
-
|
|
1104
|
-
|
|
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",
|
|
1105
2117
|
{
|
|
1106
|
-
|
|
1107
|
-
|
|
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
|
+
},
|
|
1108
2157
|
children: [
|
|
1109
|
-
/* @__PURE__ */
|
|
1110
|
-
|
|
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
|
+
] })
|
|
1111
2182
|
]
|
|
1112
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
|
+
}
|
|
1113
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" }) })
|
|
1114
2339
|
] }),
|
|
1115
|
-
/* @__PURE__ */
|
|
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)) }) })
|
|
1116
2368
|
] }),
|
|
1117
|
-
|
|
1118
|
-
|
|
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
|
+
] })
|
|
2440
|
+
] }),
|
|
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" })
|
|
2442
|
+
] }),
|
|
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(
|
|
1119
2445
|
ListView,
|
|
1120
2446
|
{
|
|
1121
2447
|
nodes,
|
|
@@ -1139,124 +2465,104 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1139
2465
|
onGenerateBranch: (id) => handleSynthesizePrompt(id, true),
|
|
1140
2466
|
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
1141
2467
|
}
|
|
1142
|
-
) }
|
|
1143
|
-
leftTab === "prompt" && workspaceTags && /* @__PURE__ */
|
|
1144
|
-
|
|
1145
|
-
{
|
|
1146
|
-
workspaceTags,
|
|
1147
|
-
onGenerate: handlePromptTabGenerate,
|
|
1148
|
-
isGenerating: isPromptTabGenerating,
|
|
1149
|
-
feedback: promptFeedback
|
|
1150
|
-
}
|
|
1151
|
-
) }, "prompt")
|
|
1152
|
-
] }) })
|
|
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
|
+
] })
|
|
1153
2471
|
] }),
|
|
1154
|
-
/* @__PURE__ */
|
|
1155
|
-
/* @__PURE__ */
|
|
1156
|
-
/* @__PURE__ */
|
|
1157
|
-
/* @__PURE__ */
|
|
1158
|
-
/* @__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" }] })
|
|
1159
2477
|
] }),
|
|
1160
|
-
/* @__PURE__ */
|
|
1161
|
-
/* @__PURE__ */
|
|
1162
|
-
/* @__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" })
|
|
1163
2481
|
] })
|
|
1164
2482
|
] }),
|
|
1165
|
-
/* @__PURE__ */
|
|
1166
|
-
|
|
1167
|
-
/* @__PURE__ */
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1175
|
-
),
|
|
1176
|
-
activePrompt && !isSynthesizing && /* @__PURE__ */ jsx11("button", { onClick: () => setActivePrompt(""), className: "absolute top-2 right-2 w-6 h-6 rounded-full bg-white/5 hover:bg-white/10 flex items-center justify-center transition-colors text-white/20 hover:text-white", children: /* @__PURE__ */ jsx11("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
1177
|
-
] }) }) }),
|
|
1178
|
-
/* @__PURE__ */ jsx11("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsxs9("div", { className: "h-full w-full max-w-4xl aspect-square rounded-3xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center group shadow-2xl", children: [
|
|
1179
|
-
isGenerating && currentResult?.status === "done" && /* @__PURE__ */ jsxs9("div", { className: "absolute top-6 right-6 z-30 bg-black/60 backdrop-blur-md px-4 py-2 rounded-full border border-white/10 flex items-center gap-3", children: [
|
|
1180
|
-
/* @__PURE__ */ jsx11("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
|
|
1181
|
-
/* @__PURE__ */ jsx11("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
|
|
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..." })
|
|
1182
2492
|
] }),
|
|
1183
|
-
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */
|
|
1184
|
-
/* @__PURE__ */
|
|
1185
|
-
/* @__PURE__ */
|
|
1186
|
-
] }) : currentResult.status === "error" ? /* @__PURE__ */
|
|
1187
|
-
/* @__PURE__ */
|
|
1188
|
-
/* @__PURE__ */
|
|
1189
|
-
/* @__PURE__ */
|
|
1190
|
-
/* @__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 })
|
|
1191
2501
|
] }),
|
|
1192
|
-
/* @__PURE__ */
|
|
1193
|
-
] }) : /* @__PURE__ */
|
|
1194
|
-
/* @__PURE__ */
|
|
1195
|
-
/* @__PURE__ */
|
|
1196
|
-
/* @__PURE__ */
|
|
1197
|
-
/* @__PURE__ */
|
|
1198
|
-
/* @__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" })
|
|
1199
2509
|
] })
|
|
1200
|
-
] }) : /* @__PURE__ */
|
|
1201
|
-
/* @__PURE__ */
|
|
1202
|
-
/* @__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" })
|
|
1203
2513
|
] })
|
|
1204
2514
|
] }) })
|
|
1205
2515
|
] })
|
|
1206
2516
|
] }),
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
/* @__PURE__ */
|
|
1209
|
-
/* @__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: () => {
|
|
1210
2520
|
setActiveTab(tab);
|
|
1211
2521
|
setIsRightCollapsed(false);
|
|
1212
|
-
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */
|
|
1213
|
-
/* @__PURE__ */
|
|
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" }) })
|
|
1214
2524
|
] }),
|
|
1215
|
-
!isRightCollapsed && /* @__PURE__ */
|
|
1216
|
-
activeTab === "history" && /* @__PURE__ */
|
|
1217
|
-
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(
|
|
1218
2528
|
MediaLibrary,
|
|
1219
2529
|
{
|
|
1220
2530
|
items: galleryItems,
|
|
1221
2531
|
onImport: async () => {
|
|
1222
2532
|
const media = await onSelectMedia();
|
|
1223
2533
|
if (!media?.length) return;
|
|
1224
|
-
|
|
1225
|
-
id: crypto.randomUUID(),
|
|
1226
|
-
nodeId: "1",
|
|
1227
|
-
base64: `data:${m.mimeType};base64,${m.base64}`,
|
|
1228
|
-
mediaId: m.mediaId,
|
|
1229
|
-
prompt: m.name || "Importiert",
|
|
1230
|
-
timestamp: Date.now(),
|
|
1231
|
-
status: "done",
|
|
1232
|
-
tags: [],
|
|
1233
|
-
type: "import"
|
|
1234
|
-
}));
|
|
1235
|
-
setGalleryItems((prev) => [...newItems, ...prev]);
|
|
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]);
|
|
1236
2535
|
},
|
|
1237
2536
|
onDelete: (id) => setGalleryItems((g) => g.filter((x) => x.id !== id)),
|
|
1238
2537
|
onSelect: setCurrentResult,
|
|
1239
2538
|
onGenerateReference: (item) => handleGenerateImage(item.prompt || activePrompt, item.mediaId, void 0, { silent: true })
|
|
1240
|
-
}
|
|
1241
|
-
"gallery"
|
|
2539
|
+
}
|
|
1242
2540
|
),
|
|
1243
|
-
activeTab === "inspect" && /* @__PURE__ */
|
|
1244
|
-
activeTab === "setup" && /* @__PURE__ */
|
|
1245
|
-
|
|
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,
|
|
1246
2545
|
{
|
|
1247
2546
|
onProjectExport: handleProjectExport,
|
|
1248
|
-
onProjectImport: handleProjectImport,
|
|
2547
|
+
onProjectImport: (f) => handleProjectImport(f),
|
|
1249
2548
|
onWorkspaceImport: handleWorkspaceImport,
|
|
1250
|
-
projectActionState
|
|
1251
|
-
|
|
1252
|
-
|
|
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
|
+
}
|
|
1253
2558
|
)
|
|
1254
|
-
] })
|
|
2559
|
+
] })
|
|
1255
2560
|
] })
|
|
1256
2561
|
] });
|
|
1257
2562
|
}
|
|
1258
2563
|
export {
|
|
1259
2564
|
AvatarArchitectApp,
|
|
2565
|
+
CollapsibleCard,
|
|
1260
2566
|
CompactDropdown,
|
|
1261
2567
|
FaToolsBadge,
|
|
1262
2568
|
GLOBAL_STYLES,
|
|
@@ -1265,6 +2571,7 @@ export {
|
|
|
1265
2571
|
ListView,
|
|
1266
2572
|
MediaLibrary,
|
|
1267
2573
|
PillButton,
|
|
2574
|
+
ProjectSyncTab,
|
|
1268
2575
|
PromptTab,
|
|
1269
2576
|
SectionLabel,
|
|
1270
2577
|
SetupPanel,
|