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