@rslsp1/fa-app-tools 1.1.3 → 1.2.1
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 +145 -8
- package/dist/index.d.ts +145 -8
- package/dist/index.js +1786 -315
- package/dist/index.mjs +1782 -327
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -197,7 +197,7 @@ function generateMarkdownReport(nodes, history) {
|
|
|
197
197
|
});
|
|
198
198
|
return md;
|
|
199
199
|
}
|
|
200
|
-
async function exportProjectToZip(nodes, edges, history, galleryItems, settings, workspaceTags) {
|
|
200
|
+
async function exportProjectToZip(nodes, edges, history, galleryItems, settings, workspaceTags, recentLabItemIds) {
|
|
201
201
|
const zip = new JSZip();
|
|
202
202
|
const projectData = {
|
|
203
203
|
nodes,
|
|
@@ -206,7 +206,8 @@ async function exportProjectToZip(nodes, edges, history, galleryItems, settings,
|
|
|
206
206
|
galleryItems: galleryItems.map((g) => ({ ...g, base64: void 0 })),
|
|
207
207
|
settings,
|
|
208
208
|
workspaceTags: workspaceTags || null,
|
|
209
|
-
|
|
209
|
+
recentLabItemIds: recentLabItemIds || [],
|
|
210
|
+
version: "1.3.0"
|
|
210
211
|
};
|
|
211
212
|
zip.file("project.json", JSON.stringify(projectData, null, 2));
|
|
212
213
|
zip.file("projekt_bericht.md", generateMarkdownReport(nodes, history));
|
|
@@ -362,35 +363,18 @@ function createFlowServices(Flow) {
|
|
|
362
363
|
throw interpretSdkError(err);
|
|
363
364
|
}
|
|
364
365
|
},
|
|
365
|
-
generateText: async (
|
|
366
|
-
if (mode === "scan" && images?.length) {
|
|
367
|
-
try {
|
|
368
|
-
const response = await Flow.generate.text(
|
|
369
|
-
"Analyze this image and create a detailed image generation prompt that would recreate it. Focus on: subject, style, lighting, composition, color palette, mood, and technical quality. Output ONLY the prompt string, no explanations.",
|
|
370
|
-
{
|
|
371
|
-
thinkingLevel: "low",
|
|
372
|
-
systemInstruction: "You are an expert image analyst and prompt engineer. Always return ONLY the generation prompt, no headers, no quotes, no conversational filler.",
|
|
373
|
-
images
|
|
374
|
-
}
|
|
375
|
-
);
|
|
376
|
-
const result = response?.text?.trim() || "";
|
|
377
|
-
if (!result) throw new Error("Empty AI response");
|
|
378
|
-
return cleanAiResponse(result);
|
|
379
|
-
} catch (err) {
|
|
380
|
-
throw interpretSdkError(err);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
const prompt = buildGenerationPrompt(hierarchyText, mode);
|
|
366
|
+
generateText: async (text, options) => {
|
|
384
367
|
try {
|
|
385
|
-
const response = await Flow.generate.text(
|
|
368
|
+
const response = await Flow.generate.text(text, {
|
|
386
369
|
thinkingLevel: "low",
|
|
387
|
-
systemInstruction: "You are an expert prompt engineer. Always return ONLY the generated prompt text, no headers, no quotes, no conversational filler."
|
|
370
|
+
systemInstruction: options?.systemInstruction || "You are an expert prompt engineer. Always return ONLY the generated prompt text, no headers, no quotes, no conversational filler.",
|
|
371
|
+
images: options?.images
|
|
388
372
|
});
|
|
389
373
|
const result = response?.text?.trim() || "";
|
|
390
374
|
if (!result) throw new Error("Empty AI response");
|
|
391
375
|
return cleanAiResponse(result);
|
|
392
|
-
} catch {
|
|
393
|
-
|
|
376
|
+
} catch (err) {
|
|
377
|
+
throw interpretSdkError(err);
|
|
394
378
|
}
|
|
395
379
|
}
|
|
396
380
|
};
|
|
@@ -669,12 +653,39 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
|
|
|
669
653
|
};
|
|
670
654
|
|
|
671
655
|
// src/components/SetupPanel.tsx
|
|
672
|
-
import { useRef as useRef2 } from "react";
|
|
656
|
+
import { useRef as useRef2, useState as useState2 } from "react";
|
|
673
657
|
import { motion as motion3 } from "motion/react";
|
|
674
658
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
675
659
|
var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
|
|
676
660
|
const workspaceInputRef = useRef2(null);
|
|
677
|
-
|
|
661
|
+
const [urlInput, setUrlInput] = useState2("");
|
|
662
|
+
const [urlStatus, setUrlStatus] = useState2("idle");
|
|
663
|
+
const [urlThumb, setUrlThumb] = useState2(null);
|
|
664
|
+
const [urlError, setUrlError] = useState2(null);
|
|
665
|
+
const handleUrlTest = async () => {
|
|
666
|
+
if (!urlInput.trim()) return;
|
|
667
|
+
setUrlStatus("loading");
|
|
668
|
+
setUrlThumb(null);
|
|
669
|
+
setUrlError(null);
|
|
670
|
+
try {
|
|
671
|
+
const res = await fetch(urlInput.trim());
|
|
672
|
+
if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
673
|
+
const blob = await res.blob();
|
|
674
|
+
const mimeType = blob.type || "image/jpeg";
|
|
675
|
+
const dataUrl = await new Promise((resolve, reject) => {
|
|
676
|
+
const reader = new FileReader();
|
|
677
|
+
reader.onload = () => resolve(reader.result);
|
|
678
|
+
reader.onerror = () => reject(new Error("FileReader failed"));
|
|
679
|
+
reader.readAsDataURL(blob);
|
|
680
|
+
});
|
|
681
|
+
setUrlThumb(dataUrl);
|
|
682
|
+
setUrlStatus("ok");
|
|
683
|
+
} catch (e) {
|
|
684
|
+
setUrlError(e.message || String(e));
|
|
685
|
+
setUrlStatus("error");
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
return /* @__PURE__ */ jsxs5(motion3.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, className: "absolute inset-0 p-6 flex flex-col gap-10 overflow-y-auto", children: [
|
|
678
689
|
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-4", children: [
|
|
679
690
|
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", children: [
|
|
680
691
|
/* @__PURE__ */ jsx7(SectionLabel, { children: "Workspace Management" }),
|
|
@@ -687,6 +698,44 @@ var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
|
|
|
687
698
|
e.target.value = "";
|
|
688
699
|
} })
|
|
689
700
|
] }),
|
|
701
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-3", children: [
|
|
702
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-1", children: [
|
|
703
|
+
/* @__PURE__ */ jsx7(SectionLabel, { children: "URL-Fetch Test" }),
|
|
704
|
+
/* @__PURE__ */ jsx7("p", { className: "text-[9px] text-white/30 px-2 italic", children: "Pr\xFCft ob externe URLs als Bild geladen werden k\xF6nnen." })
|
|
705
|
+
] }),
|
|
706
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex gap-2", children: [
|
|
707
|
+
/* @__PURE__ */ jsx7(
|
|
708
|
+
"input",
|
|
709
|
+
{
|
|
710
|
+
value: urlInput,
|
|
711
|
+
onChange: (e) => setUrlInput(e.target.value),
|
|
712
|
+
onKeyDown: (e) => e.key === "Enter" && handleUrlTest(),
|
|
713
|
+
placeholder: "https://example.com/image.jpg",
|
|
714
|
+
className: "flex-1 bg-white/5 border border-white/10 rounded-xl px-3 py-2 text-[11px] text-white/80 outline-none focus:border-white/20 placeholder:text-white/20"
|
|
715
|
+
}
|
|
716
|
+
),
|
|
717
|
+
/* @__PURE__ */ jsx7(
|
|
718
|
+
"button",
|
|
719
|
+
{
|
|
720
|
+
onClick: handleUrlTest,
|
|
721
|
+
disabled: urlStatus === "loading" || !urlInput.trim(),
|
|
722
|
+
className: "px-3 py-2 bg-white/10 hover:bg-white/15 border border-white/10 rounded-xl text-[11px] font-bold text-white/60 transition disabled:opacity-40 shrink-0",
|
|
723
|
+
children: urlStatus === "loading" ? /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[16px] animate-spin", children: "sync" }) : /* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[16px]", children: "download" })
|
|
724
|
+
}
|
|
725
|
+
)
|
|
726
|
+
] }),
|
|
727
|
+
urlStatus === "ok" && urlThumb && /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-2", children: [
|
|
728
|
+
/* @__PURE__ */ jsx7("img", { src: urlThumb, alt: "URL Test", className: "w-full max-h-48 object-contain rounded-xl border border-white/10 bg-black/40" }),
|
|
729
|
+
/* @__PURE__ */ jsxs5("p", { className: "text-[10px] text-green-400 font-mono flex items-center gap-1", children: [
|
|
730
|
+
/* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[14px]", children: "check_circle" }),
|
|
731
|
+
"Fetch erfolgreich"
|
|
732
|
+
] })
|
|
733
|
+
] }),
|
|
734
|
+
urlStatus === "error" && urlError && /* @__PURE__ */ jsxs5("p", { className: "text-[10px] text-red-400 font-mono flex items-start gap-1", children: [
|
|
735
|
+
/* @__PURE__ */ jsx7("span", { className: "material-symbols-outlined text-[14px] shrink-0", children: "error" }),
|
|
736
|
+
urlError
|
|
737
|
+
] })
|
|
738
|
+
] }),
|
|
690
739
|
/* @__PURE__ */ jsxs5("div", { className: "mt-auto p-4 bg-white/5 rounded-2xl border border-white/5 flex flex-col gap-2 opacity-50", children: [
|
|
691
740
|
/* @__PURE__ */ jsx7("span", { className: "text-[8px] font-bold text-white/20 uppercase tracking-widest", children: "System Info" }),
|
|
692
741
|
/* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between text-[9px] text-white/40", children: [
|
|
@@ -763,7 +812,7 @@ var MediaLibrary = ({ items, onImport, onDelete, onSelect, onToggleSelection, on
|
|
|
763
812
|
};
|
|
764
813
|
|
|
765
814
|
// src/components/ListView.tsx
|
|
766
|
-
import { useEffect as useEffect3, useRef as useRef3, useState as
|
|
815
|
+
import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
767
816
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
768
817
|
var ListNode = ({ node, depth, onNodeChange, onAddChild, onDeleteNode, onMoveNode, onIndentNode, onOutdentNode, onAddSibling, isActive, isInPath, onFocus, onGenerate, onGenerateBranch, onGenerateSubtree, isGenerating, isCollapsed, toggleCollapse, renderNode, children }) => {
|
|
769
818
|
const inputRef = useRef3(null);
|
|
@@ -828,7 +877,7 @@ var ListNode = ({ node, depth, onNodeChange, onAddChild, onDeleteNode, onMoveNod
|
|
|
828
877
|
] });
|
|
829
878
|
};
|
|
830
879
|
function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMoveNode, onIndentNode, onOutdentNode, onAddSibling, focusedNodeId, onFocus, activePath, onGenerate, onGenerateBranch, onGenerateSubtree, isGeneratingNodeId }) {
|
|
831
|
-
const [collapsed, setCollapsed] =
|
|
880
|
+
const [collapsed, setCollapsed] = useState3(/* @__PURE__ */ new Set());
|
|
832
881
|
const toggleCollapse = (id) => {
|
|
833
882
|
setCollapsed((prev) => {
|
|
834
883
|
const next = new Set(prev);
|
|
@@ -856,13 +905,13 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
|
|
|
856
905
|
}
|
|
857
906
|
|
|
858
907
|
// src/components/AvatarArchitectApp.tsx
|
|
859
|
-
import { useState as
|
|
908
|
+
import { useState as useState14, useCallback, useMemo as useMemo2, useEffect as useEffect4, useRef as useRef6 } from "react";
|
|
860
909
|
|
|
861
910
|
// src/components/PromptTab.tsx
|
|
862
|
-
import { useRef as useRef4, useState as
|
|
911
|
+
import { useRef as useRef4, useState as useState5 } from "react";
|
|
863
912
|
|
|
864
913
|
// src/components/CollapsibleCard.tsx
|
|
865
|
-
import { useState as
|
|
914
|
+
import { useState as useState4 } from "react";
|
|
866
915
|
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
867
916
|
var CollapsibleCard = ({
|
|
868
917
|
title,
|
|
@@ -873,7 +922,7 @@ var CollapsibleCard = ({
|
|
|
873
922
|
collapsible = true,
|
|
874
923
|
className = ""
|
|
875
924
|
}) => {
|
|
876
|
-
const [isOpen, setIsOpen] =
|
|
925
|
+
const [isOpen, setIsOpen] = useState4(defaultOpen);
|
|
877
926
|
return /* @__PURE__ */ jsxs8("div", { className: `border border-neutral-800 rounded-lg ${className}`, children: [
|
|
878
927
|
/* @__PURE__ */ jsxs8(
|
|
879
928
|
"div",
|
|
@@ -920,18 +969,18 @@ var PromptTab = ({
|
|
|
920
969
|
onTagUpdate,
|
|
921
970
|
onTagDelete
|
|
922
971
|
}) => {
|
|
923
|
-
const [selectedLabels, setSelectedLabels] =
|
|
924
|
-
const [instructions, setInstructions] =
|
|
925
|
-
const [rules, setRules] =
|
|
926
|
-
const [activeCategory, setActiveCategory] =
|
|
927
|
-
const [copied, setCopied] =
|
|
972
|
+
const [selectedLabels, setSelectedLabels] = useState5(/* @__PURE__ */ new Set());
|
|
973
|
+
const [instructions, setInstructions] = useState5("");
|
|
974
|
+
const [rules, setRules] = useState5("");
|
|
975
|
+
const [activeCategory, setActiveCategory] = useState5(null);
|
|
976
|
+
const [copied, setCopied] = useState5(false);
|
|
928
977
|
const imgInputRef = useRef4(null);
|
|
929
|
-
const [addingInCat, setAddingInCat] =
|
|
930
|
-
const [newLabel, setNewLabel] =
|
|
931
|
-
const [newValue, setNewValue] =
|
|
932
|
-
const [editingTag, setEditingTag] =
|
|
933
|
-
const [editLabel, setEditLabel] =
|
|
934
|
-
const [editValue, setEditValue] =
|
|
978
|
+
const [addingInCat, setAddingInCat] = useState5(null);
|
|
979
|
+
const [newLabel, setNewLabel] = useState5("");
|
|
980
|
+
const [newValue, setNewValue] = useState5("");
|
|
981
|
+
const [editingTag, setEditingTag] = useState5(null);
|
|
982
|
+
const [editLabel, setEditLabel] = useState5("");
|
|
983
|
+
const [editValue, setEditValue] = useState5("");
|
|
935
984
|
const longPressTimer = useRef4(null);
|
|
936
985
|
const longPressActivated = useRef4(false);
|
|
937
986
|
const toggleTag = (label) => {
|
|
@@ -1380,7 +1429,7 @@ var PromptTab = ({
|
|
|
1380
1429
|
};
|
|
1381
1430
|
|
|
1382
1431
|
// src/components/ProjectSyncTab.tsx
|
|
1383
|
-
import { useRef as useRef5, useState as
|
|
1432
|
+
import { useRef as useRef5, useState as useState6 } from "react";
|
|
1384
1433
|
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1385
1434
|
var ProjectSyncTab = ({
|
|
1386
1435
|
onProjectExport,
|
|
@@ -1397,12 +1446,12 @@ var ProjectSyncTab = ({
|
|
|
1397
1446
|
}) => {
|
|
1398
1447
|
const projectInputRef = useRef5(null);
|
|
1399
1448
|
const workspaceInputRef = useRef5(null);
|
|
1400
|
-
const [saveName, setSaveName] =
|
|
1401
|
-
const [isSaving, setIsSaving] =
|
|
1402
|
-
const [isExporting, setIsExporting] =
|
|
1403
|
-
const [syncState, setSyncState] =
|
|
1404
|
-
const [syncDiff, setSyncDiff] =
|
|
1405
|
-
const [selectedLocalIds, setSelectedLocalIds] =
|
|
1449
|
+
const [saveName, setSaveName] = useState6("");
|
|
1450
|
+
const [isSaving, setIsSaving] = useState6(false);
|
|
1451
|
+
const [isExporting, setIsExporting] = useState6(false);
|
|
1452
|
+
const [syncState, setSyncState] = useState6("idle");
|
|
1453
|
+
const [syncDiff, setSyncDiff] = useState6(null);
|
|
1454
|
+
const [selectedLocalIds, setSelectedLocalIds] = useState6(/* @__PURE__ */ new Set());
|
|
1406
1455
|
const handleExport = async () => {
|
|
1407
1456
|
if (!onProjectExport) return;
|
|
1408
1457
|
setIsExporting(true);
|
|
@@ -1604,8 +1653,1205 @@ var ProjectSyncTab = ({
|
|
|
1604
1653
|
] }) });
|
|
1605
1654
|
};
|
|
1606
1655
|
|
|
1607
|
-
// src/
|
|
1656
|
+
// src/lib/labHelpers.ts
|
|
1657
|
+
function groupGenerationsToLabItems(generations) {
|
|
1658
|
+
const map = /* @__PURE__ */ new Map();
|
|
1659
|
+
for (const gen of generations) {
|
|
1660
|
+
if (gen.status !== "done" || !gen.base64) continue;
|
|
1661
|
+
const prompt = gen.prompt || "";
|
|
1662
|
+
const existing = map.get(prompt);
|
|
1663
|
+
const frame = {
|
|
1664
|
+
id: gen.id,
|
|
1665
|
+
base64: gen.base64,
|
|
1666
|
+
mediaId: gen.mediaId,
|
|
1667
|
+
seed: gen.seed,
|
|
1668
|
+
model: gen.model,
|
|
1669
|
+
source: gen.type === "import" ? "zip-import" : "generated"
|
|
1670
|
+
};
|
|
1671
|
+
if (existing) {
|
|
1672
|
+
existing.frames.push(frame);
|
|
1673
|
+
} else {
|
|
1674
|
+
map.set(prompt, {
|
|
1675
|
+
id: gen.id,
|
|
1676
|
+
prompt,
|
|
1677
|
+
tags: gen.tags,
|
|
1678
|
+
frames: [frame]
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
return Array.from(map.values());
|
|
1683
|
+
}
|
|
1684
|
+
function frameToGeneration(frame, item) {
|
|
1685
|
+
return {
|
|
1686
|
+
id: frame.id,
|
|
1687
|
+
nodeId: "1",
|
|
1688
|
+
base64: frame.base64,
|
|
1689
|
+
mediaId: frame.mediaId,
|
|
1690
|
+
prompt: item.prompt,
|
|
1691
|
+
seed: frame.seed,
|
|
1692
|
+
model: frame.model,
|
|
1693
|
+
timestamp: Date.now(),
|
|
1694
|
+
status: "done",
|
|
1695
|
+
tags: item.tags || [],
|
|
1696
|
+
type: frame.source === "zip-import" ? "import" : "generation"
|
|
1697
|
+
};
|
|
1698
|
+
}
|
|
1699
|
+
function buildImageContext(images) {
|
|
1700
|
+
const active = images.filter((i) => i.sendToPromptAI);
|
|
1701
|
+
if (!active.length) return "";
|
|
1702
|
+
const lines = active.map((i) => {
|
|
1703
|
+
const role = i.roleForPrompt ? ` (${i.roleForPrompt})` : "";
|
|
1704
|
+
const promptSnippet = i.item.prompt ? `: "${i.item.prompt.slice(0, 120)}"` : "";
|
|
1705
|
+
return `- ${i.label}${role}${promptSnippet}`;
|
|
1706
|
+
});
|
|
1707
|
+
return `
|
|
1708
|
+
|
|
1709
|
+
Reference images:
|
|
1710
|
+
${lines.join("\n")}`;
|
|
1711
|
+
}
|
|
1712
|
+
function buildScanInstruction() {
|
|
1713
|
+
return {
|
|
1714
|
+
text: "Analyze this image and create a detailed image generation prompt that would recreate it. Focus on: subject, style, lighting, composition, color palette, mood, and technical quality. Output ONLY the prompt string.",
|
|
1715
|
+
systemInstruction: "You are an expert image analyst and prompt engineer. Return ONLY the generation prompt, no headers, no quotes, no explanations."
|
|
1716
|
+
};
|
|
1717
|
+
}
|
|
1718
|
+
function buildRemixInstruction(images, userInstruction, currentPrompt) {
|
|
1719
|
+
const imgContext = buildImageContext(images);
|
|
1720
|
+
return {
|
|
1721
|
+
text: `Current prompt: "${currentPrompt}"
|
|
1722
|
+
|
|
1723
|
+
Instruction: ${userInstruction}${imgContext}
|
|
1724
|
+
|
|
1725
|
+
Create a creative variation of this prompt based on the instruction. Output ONLY the new prompt string.`,
|
|
1726
|
+
systemInstruction: "You are an expert prompt engineer. Return ONLY the new generation prompt, no headers, no quotes, no explanations."
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
function buildBlendInstruction(images, userInstruction) {
|
|
1730
|
+
const imgContext = buildImageContext(images);
|
|
1731
|
+
const promptList = images.map((i) => `${i.label}: "${i.item.prompt}"`).join("\n");
|
|
1732
|
+
return {
|
|
1733
|
+
text: `Blend these prompts into one new prompt:
|
|
1734
|
+
${promptList}
|
|
1735
|
+
|
|
1736
|
+
Instruction: ${userInstruction}${imgContext}
|
|
1737
|
+
|
|
1738
|
+
Output ONLY the blended prompt string.`,
|
|
1739
|
+
systemInstruction: "You are an expert prompt engineer. Blend the given prompts into one coherent generation prompt. Return ONLY the prompt string."
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
function buildCompareInstruction(images, userInstruction) {
|
|
1743
|
+
const imgContext = buildImageContext(images);
|
|
1744
|
+
return {
|
|
1745
|
+
text: `${userInstruction}${imgContext}
|
|
1746
|
+
|
|
1747
|
+
Analyze the provided images according to the instruction above.`,
|
|
1748
|
+
systemInstruction: "You are an expert image analyst. Provide a clear, structured analysis. Be concise and actionable."
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
function buildLoopInstruction(rounds, newInstruction) {
|
|
1752
|
+
const history = rounds.map(
|
|
1753
|
+
(r, i) => `Round ${i + 1} prompt: "${r.prompt}"
|
|
1754
|
+
Instruction given: "${r.instruction}"`
|
|
1755
|
+
).join("\n\n");
|
|
1756
|
+
const activeImages = rounds.flatMap((r) => r.images.filter((i) => i.sendToPromptAI));
|
|
1757
|
+
const imgContext = activeImages.length ? buildImageContext(activeImages) : "";
|
|
1758
|
+
return {
|
|
1759
|
+
text: `Previous rounds:
|
|
1760
|
+
${history}
|
|
1761
|
+
|
|
1762
|
+
New instruction: ${newInstruction}${imgContext}
|
|
1763
|
+
|
|
1764
|
+
Improve the prompt cumulatively based on all previous rounds and the new instruction. Output ONLY the new prompt string.`,
|
|
1765
|
+
systemInstruction: "You are an expert prompt engineer refining prompts iteratively. Each round the prompt should improve. Return ONLY the new prompt string."
|
|
1766
|
+
};
|
|
1767
|
+
}
|
|
1768
|
+
function autoLabel(index) {
|
|
1769
|
+
return `Img${String.fromCharCode(65 + index)}`;
|
|
1770
|
+
}
|
|
1771
|
+
function buildReferenceImageMediaIds(images) {
|
|
1772
|
+
return images.filter((i) => i.sendToImageGen && i.frame.mediaId).map((i) => i.frame.mediaId);
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
// src/components/labs/LabsTab.tsx
|
|
1776
|
+
import { useState as useState12 } from "react";
|
|
1777
|
+
|
|
1778
|
+
// src/components/labs/LabRemix.tsx
|
|
1779
|
+
import { useState as useState8 } from "react";
|
|
1780
|
+
|
|
1781
|
+
// src/components/labs/LabImagePicker.tsx
|
|
1782
|
+
import { useState as useState7 } from "react";
|
|
1608
1783
|
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1784
|
+
var LabImagePicker = ({
|
|
1785
|
+
availableItems,
|
|
1786
|
+
recentItems,
|
|
1787
|
+
onSelect,
|
|
1788
|
+
onClose,
|
|
1789
|
+
title = "Bild w\xE4hlen"
|
|
1790
|
+
}) => {
|
|
1791
|
+
const [search, setSearch] = useState7("");
|
|
1792
|
+
const [drillItem, setDrillItem] = useState7(null);
|
|
1793
|
+
const filtered = availableItems.filter(
|
|
1794
|
+
(item) => !search || item.prompt.toLowerCase().includes(search.toLowerCase())
|
|
1795
|
+
);
|
|
1796
|
+
const handleItemClick = (item) => {
|
|
1797
|
+
if (item.frames.length === 1) {
|
|
1798
|
+
onSelect(item, item.frames[0]);
|
|
1799
|
+
onClose();
|
|
1800
|
+
} else {
|
|
1801
|
+
setDrillItem(item);
|
|
1802
|
+
}
|
|
1803
|
+
};
|
|
1804
|
+
const renderItemCard = (item) => {
|
|
1805
|
+
const firstFrame = item.frames[0];
|
|
1806
|
+
if (!firstFrame) return null;
|
|
1807
|
+
return /* @__PURE__ */ jsxs11(
|
|
1808
|
+
"button",
|
|
1809
|
+
{
|
|
1810
|
+
onClick: () => handleItemClick(item),
|
|
1811
|
+
className: "flex flex-col gap-1 p-2 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors text-left",
|
|
1812
|
+
children: [
|
|
1813
|
+
/* @__PURE__ */ jsxs11("div", { className: "relative w-full aspect-square rounded-lg overflow-hidden bg-black/40", children: [
|
|
1814
|
+
/* @__PURE__ */ jsx13("img", { src: firstFrame.base64, className: "w-full h-full object-cover" }),
|
|
1815
|
+
item.frames.length > 1 && /* @__PURE__ */ jsxs11("span", { className: "absolute bottom-1 right-1 text-[9px] font-bold bg-black/70 text-white/70 px-1.5 py-0.5 rounded", children: [
|
|
1816
|
+
item.frames.length,
|
|
1817
|
+
"x"
|
|
1818
|
+
] })
|
|
1819
|
+
] }),
|
|
1820
|
+
/* @__PURE__ */ jsx13("p", { className: "text-[10px] text-white/50 leading-tight line-clamp-2", children: item.prompt || "(kein Prompt)" })
|
|
1821
|
+
]
|
|
1822
|
+
},
|
|
1823
|
+
item.id
|
|
1824
|
+
);
|
|
1825
|
+
};
|
|
1826
|
+
if (drillItem) {
|
|
1827
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col h-full", children: [
|
|
1828
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 px-4 py-3 border-b border-white/5 shrink-0", children: [
|
|
1829
|
+
/* @__PURE__ */ jsx13("button", { onClick: () => setDrillItem(null), className: "text-white/40 active:text-white shrink-0", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "arrow_back" }) }),
|
|
1830
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[11px] font-bold uppercase tracking-widest text-white/60 truncate flex-1", children: drillItem.prompt || "(kein Prompt)" }),
|
|
1831
|
+
/* @__PURE__ */ jsx13("button", { onClick: onClose, className: "text-white/30 active:text-white shrink-0", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "close" }) })
|
|
1832
|
+
] }),
|
|
1833
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 py-3", children: [
|
|
1834
|
+
/* @__PURE__ */ jsxs11("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30 mb-2", children: [
|
|
1835
|
+
drillItem.frames.length,
|
|
1836
|
+
" Varianten"
|
|
1837
|
+
] }),
|
|
1838
|
+
/* @__PURE__ */ jsx13("div", { className: "grid grid-cols-3 gap-2", children: drillItem.frames.map((frame, i) => /* @__PURE__ */ jsxs11(
|
|
1839
|
+
"button",
|
|
1840
|
+
{
|
|
1841
|
+
onClick: () => {
|
|
1842
|
+
onSelect(drillItem, frame);
|
|
1843
|
+
onClose();
|
|
1844
|
+
},
|
|
1845
|
+
className: "flex flex-col gap-1 p-2 rounded-xl border border-white/10 bg-white/5 active:bg-white/10 transition-colors text-left",
|
|
1846
|
+
children: [
|
|
1847
|
+
/* @__PURE__ */ jsxs11("div", { className: "relative w-full aspect-square rounded-lg overflow-hidden bg-black/40", children: [
|
|
1848
|
+
/* @__PURE__ */ jsx13("img", { src: frame.base64, className: "w-full h-full object-cover" }),
|
|
1849
|
+
/* @__PURE__ */ jsxs11("span", { className: "absolute bottom-1 left-1 text-[9px] font-bold bg-black/70 text-white/50 px-1.5 py-0.5 rounded", children: [
|
|
1850
|
+
"#",
|
|
1851
|
+
i + 1
|
|
1852
|
+
] })
|
|
1853
|
+
] }),
|
|
1854
|
+
frame.seed != null && /* @__PURE__ */ jsxs11("p", { className: "text-[9px] text-white/30 font-mono truncate", children: [
|
|
1855
|
+
"seed ",
|
|
1856
|
+
frame.seed
|
|
1857
|
+
] })
|
|
1858
|
+
]
|
|
1859
|
+
},
|
|
1860
|
+
frame.id
|
|
1861
|
+
)) })
|
|
1862
|
+
] })
|
|
1863
|
+
] });
|
|
1864
|
+
}
|
|
1865
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex flex-col h-full", children: [
|
|
1866
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex items-center justify-between px-4 py-3 border-b border-white/5 shrink-0", children: [
|
|
1867
|
+
/* @__PURE__ */ jsx13("span", { className: "text-[11px] font-bold uppercase tracking-widest text-white/60", children: title }),
|
|
1868
|
+
/* @__PURE__ */ jsx13("button", { onClick: onClose, className: "text-white/30 active:text-white", children: /* @__PURE__ */ jsx13("span", { className: "material-symbols-outlined text-[20px]", children: "close" }) })
|
|
1869
|
+
] }),
|
|
1870
|
+
/* @__PURE__ */ jsx13("div", { className: "px-3 py-2 shrink-0", children: /* @__PURE__ */ jsx13(
|
|
1871
|
+
"input",
|
|
1872
|
+
{
|
|
1873
|
+
value: search,
|
|
1874
|
+
onChange: (e) => setSearch(e.target.value),
|
|
1875
|
+
placeholder: "Suchen...",
|
|
1876
|
+
className: "w-full bg-white/5 border border-white/10 rounded-lg px-3 py-2 text-[12px] text-white/80 outline-none focus:border-white/20"
|
|
1877
|
+
}
|
|
1878
|
+
) }),
|
|
1879
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 pb-3", children: [
|
|
1880
|
+
recentItems.length > 0 && !search && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1881
|
+
/* @__PURE__ */ jsx13("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30 mb-2 mt-1", children: "Zuletzt verwendet" }),
|
|
1882
|
+
/* @__PURE__ */ jsx13("div", { className: "grid grid-cols-3 gap-2 mb-4", children: recentItems.slice(0, 6).map(renderItemCard) }),
|
|
1883
|
+
/* @__PURE__ */ jsx13("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30 mb-2", children: "Alle Bilder" })
|
|
1884
|
+
] }),
|
|
1885
|
+
/* @__PURE__ */ jsx13("div", { className: "grid grid-cols-3 gap-2", children: filtered.map(renderItemCard) }),
|
|
1886
|
+
filtered.length === 0 && /* @__PURE__ */ jsx13("p", { className: "text-center text-[11px] text-white/20 py-8", children: "Keine Bilder vorhanden" })
|
|
1887
|
+
] })
|
|
1888
|
+
] });
|
|
1889
|
+
};
|
|
1890
|
+
|
|
1891
|
+
// src/components/labs/LabRemix.tsx
|
|
1892
|
+
import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1893
|
+
var LabRemix = ({ services, onResult }) => {
|
|
1894
|
+
const [showPicker, setShowPicker] = useState8(false);
|
|
1895
|
+
const [selected, setSelected] = useState8(null);
|
|
1896
|
+
const [instruction, setInstruction] = useState8("");
|
|
1897
|
+
const [generatedPrompt, setGeneratedPrompt] = useState8("");
|
|
1898
|
+
const [resultImage, setResultImage] = useState8(null);
|
|
1899
|
+
const [isGeneratingPrompt, setIsGeneratingPrompt] = useState8(false);
|
|
1900
|
+
const [isGeneratingImage, setIsGeneratingImage] = useState8(false);
|
|
1901
|
+
const handleSelectImage = (item, frame) => {
|
|
1902
|
+
services.onItemUsed(item);
|
|
1903
|
+
setSelected({
|
|
1904
|
+
item,
|
|
1905
|
+
frame,
|
|
1906
|
+
label: autoLabel(0),
|
|
1907
|
+
sendToPromptAI: true,
|
|
1908
|
+
sendToImageGen: false,
|
|
1909
|
+
roleForPrompt: "",
|
|
1910
|
+
roleForImage: ""
|
|
1911
|
+
});
|
|
1912
|
+
setGeneratedPrompt("");
|
|
1913
|
+
setResultImage(null);
|
|
1914
|
+
};
|
|
1915
|
+
const handleGeneratePrompt = async () => {
|
|
1916
|
+
if (!selected || !instruction.trim()) return;
|
|
1917
|
+
setIsGeneratingPrompt(true);
|
|
1918
|
+
try {
|
|
1919
|
+
const { text, systemInstruction } = buildRemixInstruction(
|
|
1920
|
+
[selected],
|
|
1921
|
+
instruction,
|
|
1922
|
+
selected.item.prompt
|
|
1923
|
+
);
|
|
1924
|
+
const images = selected.sendToPromptAI ? [{ base64: selected.frame.base64, mimeType: "image/png" }] : void 0;
|
|
1925
|
+
const result = await services.generateText(text, { systemInstruction, images });
|
|
1926
|
+
setGeneratedPrompt(result);
|
|
1927
|
+
} finally {
|
|
1928
|
+
setIsGeneratingPrompt(false);
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
const handleGenerateImage = async () => {
|
|
1932
|
+
if (!generatedPrompt) return;
|
|
1933
|
+
setIsGeneratingImage(true);
|
|
1934
|
+
try {
|
|
1935
|
+
const refIds = buildReferenceImageMediaIds(selected ? [selected] : []);
|
|
1936
|
+
const { base64, mediaId } = await services.generateImage({
|
|
1937
|
+
prompt: generatedPrompt,
|
|
1938
|
+
aspectRatio: selected?.frame.aspectRatio || "1:1",
|
|
1939
|
+
modelDisplayName: selected?.frame.model || "\u{1F34C} Nano Banana Pro",
|
|
1940
|
+
...refIds.length ? { referenceImageMediaIds: refIds } : {}
|
|
1941
|
+
});
|
|
1942
|
+
const newBase64 = `data:image/png;base64,${base64}`;
|
|
1943
|
+
setResultImage(newBase64);
|
|
1944
|
+
const frameId = crypto.randomUUID();
|
|
1945
|
+
const newItem = {
|
|
1946
|
+
id: frameId,
|
|
1947
|
+
prompt: generatedPrompt,
|
|
1948
|
+
tags: selected?.item.tags || [],
|
|
1949
|
+
frames: [{ id: frameId, base64: newBase64, mediaId, source: "generated" }]
|
|
1950
|
+
};
|
|
1951
|
+
services.saveResult?.(newItem);
|
|
1952
|
+
onResult?.(newItem);
|
|
1953
|
+
} finally {
|
|
1954
|
+
setIsGeneratingImage(false);
|
|
1955
|
+
}
|
|
1956
|
+
};
|
|
1957
|
+
if (showPicker) {
|
|
1958
|
+
return /* @__PURE__ */ jsx14(
|
|
1959
|
+
LabImagePicker,
|
|
1960
|
+
{
|
|
1961
|
+
availableItems: services.availableItems,
|
|
1962
|
+
recentItems: services.recentItems,
|
|
1963
|
+
onSelect: handleSelectImage,
|
|
1964
|
+
onClose: () => setShowPicker(false),
|
|
1965
|
+
title: "Basis-Bild w\xE4hlen"
|
|
1966
|
+
}
|
|
1967
|
+
);
|
|
1968
|
+
}
|
|
1969
|
+
return /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
|
|
1970
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1971
|
+
/* @__PURE__ */ jsx14("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Basis-Bild" }),
|
|
1972
|
+
selected ? /* @__PURE__ */ jsxs12("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
|
|
1973
|
+
/* @__PURE__ */ jsx14("img", { src: selected.frame.base64, className: "w-16 h-16 object-cover rounded-lg shrink-0" }),
|
|
1974
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex-1 min-w-0 flex flex-col gap-1.5", children: [
|
|
1975
|
+
/* @__PURE__ */ jsx14("p", { className: "text-[10px] text-white/60 leading-tight line-clamp-2", children: selected.item.prompt }),
|
|
1976
|
+
/* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-[10px] text-white/50", children: [
|
|
1977
|
+
/* @__PURE__ */ jsx14(
|
|
1978
|
+
"input",
|
|
1979
|
+
{
|
|
1980
|
+
type: "checkbox",
|
|
1981
|
+
checked: selected.sendToPromptAI,
|
|
1982
|
+
onChange: (e) => setSelected((s) => s ? { ...s, sendToPromptAI: e.target.checked } : s)
|
|
1983
|
+
}
|
|
1984
|
+
),
|
|
1985
|
+
"Bild an KI (Prompt)"
|
|
1986
|
+
] }),
|
|
1987
|
+
/* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-[10px] text-white/50", children: [
|
|
1988
|
+
/* @__PURE__ */ jsx14(
|
|
1989
|
+
"input",
|
|
1990
|
+
{
|
|
1991
|
+
type: "checkbox",
|
|
1992
|
+
checked: selected.sendToImageGen,
|
|
1993
|
+
onChange: (e) => setSelected((s) => s ? { ...s, sendToImageGen: e.target.checked } : s)
|
|
1994
|
+
}
|
|
1995
|
+
),
|
|
1996
|
+
"Bild als Referenz (Generierung)"
|
|
1997
|
+
] }),
|
|
1998
|
+
/* @__PURE__ */ jsx14(
|
|
1999
|
+
"input",
|
|
2000
|
+
{
|
|
2001
|
+
value: selected.roleForPrompt || "",
|
|
2002
|
+
onChange: (e) => setSelected((s) => s ? { ...s, roleForPrompt: e.target.value } : s),
|
|
2003
|
+
placeholder: "Rolle z.B. Subjekt, Farbreferenz...",
|
|
2004
|
+
className: "bg-black/30 border border-white/10 rounded px-2 py-1 text-[10px] text-white/70 outline-none"
|
|
2005
|
+
}
|
|
2006
|
+
)
|
|
2007
|
+
] }),
|
|
2008
|
+
/* @__PURE__ */ jsx14("button", { onClick: () => setShowPicker(true), className: "text-white/30 active:text-white self-start", children: /* @__PURE__ */ jsx14("span", { className: "material-symbols-outlined text-[18px]", children: "swap_horiz" }) })
|
|
2009
|
+
] }) : /* @__PURE__ */ jsxs12(
|
|
2010
|
+
"button",
|
|
2011
|
+
{
|
|
2012
|
+
onClick: () => setShowPicker(true),
|
|
2013
|
+
className: "w-full py-6 rounded-xl border border-dashed border-white/20 text-[11px] text-white/30 active:bg-white/5 flex items-center justify-center gap-2",
|
|
2014
|
+
children: [
|
|
2015
|
+
/* @__PURE__ */ jsx14("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }),
|
|
2016
|
+
"Bild w\xE4hlen"
|
|
2017
|
+
]
|
|
2018
|
+
}
|
|
2019
|
+
)
|
|
2020
|
+
] }),
|
|
2021
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
2022
|
+
/* @__PURE__ */ jsx14("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Anweisung" }),
|
|
2023
|
+
/* @__PURE__ */ jsx14(
|
|
2024
|
+
"textarea",
|
|
2025
|
+
{
|
|
2026
|
+
value: instruction,
|
|
2027
|
+
onChange: (e) => setInstruction(e.target.value),
|
|
2028
|
+
placeholder: "z.B. Mache es dramatischer, andere Lichtstimmung...",
|
|
2029
|
+
className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
|
|
2030
|
+
rows: 3
|
|
2031
|
+
}
|
|
2032
|
+
)
|
|
2033
|
+
] }),
|
|
2034
|
+
services.workspaceTags && /* @__PURE__ */ jsx14("p", { className: "text-[9px] text-white/20 italic", children: "Tags: Workspace-Tags k\xF6nnen unter der Anweisung erg\xE4nzt werden (folgt in n\xE4chstem Update)" }),
|
|
2035
|
+
/* @__PURE__ */ jsx14(
|
|
2036
|
+
"button",
|
|
2037
|
+
{
|
|
2038
|
+
onClick: handleGeneratePrompt,
|
|
2039
|
+
disabled: !selected || !instruction.trim() || isGeneratingPrompt,
|
|
2040
|
+
className: "w-full py-3 rounded-xl bg-white/10 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-white/15 flex items-center justify-center gap-2",
|
|
2041
|
+
children: isGeneratingPrompt ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
2042
|
+
/* @__PURE__ */ jsx14("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
|
|
2043
|
+
/* @__PURE__ */ jsx14("span", { children: "Generiere Prompt..." })
|
|
2044
|
+
] }) : /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
2045
|
+
/* @__PURE__ */ jsx14("span", { className: "material-symbols-outlined text-[16px]", children: "auto_fix_high" }),
|
|
2046
|
+
/* @__PURE__ */ jsx14("span", { children: "Prompt generieren" })
|
|
2047
|
+
] })
|
|
2048
|
+
}
|
|
2049
|
+
),
|
|
2050
|
+
generatedPrompt && /* @__PURE__ */ jsxs12("div", { children: [
|
|
2051
|
+
/* @__PURE__ */ jsx14("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Generierter Prompt" }),
|
|
2052
|
+
/* @__PURE__ */ jsx14(
|
|
2053
|
+
"textarea",
|
|
2054
|
+
{
|
|
2055
|
+
value: generatedPrompt,
|
|
2056
|
+
onChange: (e) => setGeneratedPrompt(e.target.value),
|
|
2057
|
+
className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
|
|
2058
|
+
rows: 4
|
|
2059
|
+
}
|
|
2060
|
+
),
|
|
2061
|
+
/* @__PURE__ */ jsx14(
|
|
2062
|
+
"button",
|
|
2063
|
+
{
|
|
2064
|
+
onClick: handleGenerateImage,
|
|
2065
|
+
disabled: isGeneratingImage,
|
|
2066
|
+
className: "w-full mt-2 py-3 rounded-xl bg-blue-600/80 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-blue-600 flex items-center justify-center gap-2",
|
|
2067
|
+
children: isGeneratingImage ? /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
2068
|
+
/* @__PURE__ */ jsx14("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
|
|
2069
|
+
/* @__PURE__ */ jsx14("span", { children: "Generiere Bild..." })
|
|
2070
|
+
] }) : /* @__PURE__ */ jsxs12(Fragment5, { children: [
|
|
2071
|
+
/* @__PURE__ */ jsx14("span", { className: "material-symbols-outlined text-[16px]", children: "image" }),
|
|
2072
|
+
/* @__PURE__ */ jsx14("span", { children: "Bild generieren" })
|
|
2073
|
+
] })
|
|
2074
|
+
}
|
|
2075
|
+
)
|
|
2076
|
+
] }),
|
|
2077
|
+
resultImage && /* @__PURE__ */ jsx14("div", { className: "rounded-xl overflow-hidden border border-white/10", children: /* @__PURE__ */ jsx14("img", { src: resultImage, className: "w-full object-cover" }) })
|
|
2078
|
+
] });
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
// src/components/labs/LabBlend.tsx
|
|
2082
|
+
import { useState as useState9 } from "react";
|
|
2083
|
+
import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2084
|
+
var LabBlend = ({ services, onResult }) => {
|
|
2085
|
+
const [showPickerFor, setShowPickerFor] = useState9(null);
|
|
2086
|
+
const [selectedImages, setSelectedImages] = useState9([]);
|
|
2087
|
+
const [instruction, setInstruction] = useState9("");
|
|
2088
|
+
const [generatedPrompt, setGeneratedPrompt] = useState9("");
|
|
2089
|
+
const [resultImage, setResultImage] = useState9(null);
|
|
2090
|
+
const [isGeneratingPrompt, setIsGeneratingPrompt] = useState9(false);
|
|
2091
|
+
const [isGeneratingImage, setIsGeneratingImage] = useState9(false);
|
|
2092
|
+
const handleSelectImage = (index, item, frame) => {
|
|
2093
|
+
services.onItemUsed(item);
|
|
2094
|
+
const newImg = {
|
|
2095
|
+
item,
|
|
2096
|
+
frame,
|
|
2097
|
+
label: autoLabel(index),
|
|
2098
|
+
sendToPromptAI: true,
|
|
2099
|
+
sendToImageGen: false,
|
|
2100
|
+
roleForPrompt: "",
|
|
2101
|
+
roleForImage: ""
|
|
2102
|
+
};
|
|
2103
|
+
setSelectedImages((prev) => {
|
|
2104
|
+
const next = [...prev];
|
|
2105
|
+
next[index] = newImg;
|
|
2106
|
+
return next;
|
|
2107
|
+
});
|
|
2108
|
+
setShowPickerFor(null);
|
|
2109
|
+
setGeneratedPrompt("");
|
|
2110
|
+
setResultImage(null);
|
|
2111
|
+
};
|
|
2112
|
+
const addSlot = () => setSelectedImages((prev) => [...prev, null]);
|
|
2113
|
+
const removeSlot = (i) => setSelectedImages((prev) => prev.filter((_, idx) => idx !== i));
|
|
2114
|
+
const updateImg = (i, updates) => setSelectedImages((prev) => prev.map((img, idx) => idx === i && img ? { ...img, ...updates } : img));
|
|
2115
|
+
const handleGeneratePrompt = async () => {
|
|
2116
|
+
const filled = selectedImages.filter(Boolean);
|
|
2117
|
+
if (!filled.length || !instruction.trim()) return;
|
|
2118
|
+
setIsGeneratingPrompt(true);
|
|
2119
|
+
try {
|
|
2120
|
+
const { text, systemInstruction } = buildBlendInstruction(filled, instruction);
|
|
2121
|
+
const images = filled.filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
|
|
2122
|
+
const result = await services.generateText(text, { systemInstruction, images: images.length ? images : void 0 });
|
|
2123
|
+
setGeneratedPrompt(result);
|
|
2124
|
+
} finally {
|
|
2125
|
+
setIsGeneratingPrompt(false);
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
const handleGenerateImage = async () => {
|
|
2129
|
+
if (!generatedPrompt) return;
|
|
2130
|
+
setIsGeneratingImage(true);
|
|
2131
|
+
try {
|
|
2132
|
+
const filled = selectedImages.filter(Boolean);
|
|
2133
|
+
const refIds = buildReferenceImageMediaIds(filled);
|
|
2134
|
+
const { base64, mediaId } = await services.generateImage({
|
|
2135
|
+
prompt: generatedPrompt,
|
|
2136
|
+
aspectRatio: "1:1",
|
|
2137
|
+
modelDisplayName: "\u{1F34C} Nano Banana Pro",
|
|
2138
|
+
...refIds.length ? { referenceImageMediaIds: refIds } : {}
|
|
2139
|
+
});
|
|
2140
|
+
const newBase64 = `data:image/png;base64,${base64}`;
|
|
2141
|
+
setResultImage(newBase64);
|
|
2142
|
+
const frameId = crypto.randomUUID();
|
|
2143
|
+
const newItem = {
|
|
2144
|
+
id: frameId,
|
|
2145
|
+
prompt: generatedPrompt,
|
|
2146
|
+
tags: [],
|
|
2147
|
+
frames: [{ id: frameId, base64: newBase64, mediaId, source: "generated" }]
|
|
2148
|
+
};
|
|
2149
|
+
services.saveResult?.(newItem);
|
|
2150
|
+
onResult?.(newItem);
|
|
2151
|
+
} finally {
|
|
2152
|
+
setIsGeneratingImage(false);
|
|
2153
|
+
}
|
|
2154
|
+
};
|
|
2155
|
+
if (showPickerFor !== null) {
|
|
2156
|
+
return /* @__PURE__ */ jsx15(
|
|
2157
|
+
LabImagePicker,
|
|
2158
|
+
{
|
|
2159
|
+
availableItems: services.availableItems,
|
|
2160
|
+
recentItems: services.recentItems,
|
|
2161
|
+
onSelect: (item, frame) => handleSelectImage(showPickerFor, item, frame),
|
|
2162
|
+
onClose: () => setShowPickerFor(null),
|
|
2163
|
+
title: `${autoLabel(showPickerFor)} w\xE4hlen`
|
|
2164
|
+
}
|
|
2165
|
+
);
|
|
2166
|
+
}
|
|
2167
|
+
return /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
|
|
2168
|
+
/* @__PURE__ */ jsx15("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40", children: "Bilder" }),
|
|
2169
|
+
selectedImages.map((img, i) => /* @__PURE__ */ jsxs13("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
|
|
2170
|
+
/* @__PURE__ */ jsx15("span", { className: "text-[10px] font-bold text-white/40 w-6 shrink-0 pt-1", children: autoLabel(i) }),
|
|
2171
|
+
img ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
2172
|
+
/* @__PURE__ */ jsx15("img", { src: img.frame.base64, className: "w-12 h-12 object-cover rounded-lg shrink-0", onClick: () => setShowPickerFor(i) }),
|
|
2173
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex-1 min-w-0 flex flex-col gap-1", children: [
|
|
2174
|
+
/* @__PURE__ */ jsx15("p", { className: "text-[10px] text-white/50 line-clamp-1", children: img.item.prompt }),
|
|
2175
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex gap-3", children: [
|
|
2176
|
+
/* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1 text-[10px] text-white/40", children: [
|
|
2177
|
+
/* @__PURE__ */ jsx15("input", { type: "checkbox", checked: img.sendToPromptAI, onChange: (e) => updateImg(i, { sendToPromptAI: e.target.checked }) }),
|
|
2178
|
+
"KI-Prompt"
|
|
2179
|
+
] }),
|
|
2180
|
+
/* @__PURE__ */ jsxs13("label", { className: "flex items-center gap-1 text-[10px] text-white/40", children: [
|
|
2181
|
+
/* @__PURE__ */ jsx15("input", { type: "checkbox", checked: img.sendToImageGen, onChange: (e) => updateImg(i, { sendToImageGen: e.target.checked }) }),
|
|
2182
|
+
"Referenz"
|
|
2183
|
+
] })
|
|
2184
|
+
] }),
|
|
2185
|
+
/* @__PURE__ */ jsx15(
|
|
2186
|
+
"input",
|
|
2187
|
+
{
|
|
2188
|
+
value: img.roleForPrompt || "",
|
|
2189
|
+
onChange: (e) => updateImg(i, { roleForPrompt: e.target.value }),
|
|
2190
|
+
placeholder: "Rolle f\xFCr Prompt...",
|
|
2191
|
+
className: "bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
|
|
2192
|
+
}
|
|
2193
|
+
),
|
|
2194
|
+
/* @__PURE__ */ jsx15(
|
|
2195
|
+
"input",
|
|
2196
|
+
{
|
|
2197
|
+
value: img.roleForImage || "",
|
|
2198
|
+
onChange: (e) => updateImg(i, { roleForImage: e.target.value }),
|
|
2199
|
+
placeholder: "Rolle f\xFCr Generierung...",
|
|
2200
|
+
className: "bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
|
|
2201
|
+
}
|
|
2202
|
+
)
|
|
2203
|
+
] })
|
|
2204
|
+
] }) : /* @__PURE__ */ jsx15("button", { onClick: () => setShowPickerFor(i), className: "flex-1 py-3 border border-dashed border-white/20 rounded-lg text-[10px] text-white/30 active:bg-white/5", children: "Bild w\xE4hlen" }),
|
|
2205
|
+
/* @__PURE__ */ jsx15("button", { onClick: () => removeSlot(i), className: "text-white/20 active:text-red-400 self-start", children: /* @__PURE__ */ jsx15("span", { className: "material-symbols-outlined text-[16px]", children: "close" }) })
|
|
2206
|
+
] }, i)),
|
|
2207
|
+
/* @__PURE__ */ jsxs13(
|
|
2208
|
+
"button",
|
|
2209
|
+
{
|
|
2210
|
+
onClick: addSlot,
|
|
2211
|
+
className: "w-full py-2 border border-dashed border-white/10 rounded-xl text-[10px] text-white/30 active:bg-white/5 flex items-center justify-center gap-1",
|
|
2212
|
+
children: [
|
|
2213
|
+
/* @__PURE__ */ jsx15("span", { className: "material-symbols-outlined text-[14px]", children: "add" }),
|
|
2214
|
+
"Bild hinzuf\xFCgen"
|
|
2215
|
+
]
|
|
2216
|
+
}
|
|
2217
|
+
),
|
|
2218
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
2219
|
+
/* @__PURE__ */ jsx15("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Blend-Anweisung" }),
|
|
2220
|
+
/* @__PURE__ */ jsx15(
|
|
2221
|
+
"textarea",
|
|
2222
|
+
{
|
|
2223
|
+
value: instruction,
|
|
2224
|
+
onChange: (e) => setInstruction(e.target.value),
|
|
2225
|
+
placeholder: "z.B. Kombiniere die Stimmung von ImgA mit der Komposition von ImgB...",
|
|
2226
|
+
className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
|
|
2227
|
+
rows: 3
|
|
2228
|
+
}
|
|
2229
|
+
)
|
|
2230
|
+
] }),
|
|
2231
|
+
/* @__PURE__ */ jsx15(
|
|
2232
|
+
"button",
|
|
2233
|
+
{
|
|
2234
|
+
onClick: handleGeneratePrompt,
|
|
2235
|
+
disabled: selectedImages.filter(Boolean).length < 2 || !instruction.trim() || isGeneratingPrompt,
|
|
2236
|
+
className: "w-full py-3 rounded-xl bg-white/10 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-white/15 flex items-center justify-center gap-2",
|
|
2237
|
+
children: isGeneratingPrompt ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
2238
|
+
/* @__PURE__ */ jsx15("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
|
|
2239
|
+
/* @__PURE__ */ jsx15("span", { children: "Blend l\xE4uft..." })
|
|
2240
|
+
] }) : /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
2241
|
+
/* @__PURE__ */ jsx15("span", { className: "material-symbols-outlined text-[16px]", children: "merge" }),
|
|
2242
|
+
/* @__PURE__ */ jsx15("span", { children: "Prompts blenden" })
|
|
2243
|
+
] })
|
|
2244
|
+
}
|
|
2245
|
+
),
|
|
2246
|
+
generatedPrompt && /* @__PURE__ */ jsxs13("div", { children: [
|
|
2247
|
+
/* @__PURE__ */ jsx15("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Blend-Prompt" }),
|
|
2248
|
+
/* @__PURE__ */ jsx15(
|
|
2249
|
+
"textarea",
|
|
2250
|
+
{
|
|
2251
|
+
value: generatedPrompt,
|
|
2252
|
+
onChange: (e) => setGeneratedPrompt(e.target.value),
|
|
2253
|
+
className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
|
|
2254
|
+
rows: 4
|
|
2255
|
+
}
|
|
2256
|
+
),
|
|
2257
|
+
/* @__PURE__ */ jsx15(
|
|
2258
|
+
"button",
|
|
2259
|
+
{
|
|
2260
|
+
onClick: handleGenerateImage,
|
|
2261
|
+
disabled: isGeneratingImage,
|
|
2262
|
+
className: "w-full mt-2 py-3 rounded-xl bg-blue-600/80 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-blue-600 flex items-center justify-center gap-2",
|
|
2263
|
+
children: isGeneratingImage ? /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
2264
|
+
/* @__PURE__ */ jsx15("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
|
|
2265
|
+
/* @__PURE__ */ jsx15("span", { children: "Generiere..." })
|
|
2266
|
+
] }) : /* @__PURE__ */ jsxs13(Fragment6, { children: [
|
|
2267
|
+
/* @__PURE__ */ jsx15("span", { className: "material-symbols-outlined text-[16px]", children: "image" }),
|
|
2268
|
+
/* @__PURE__ */ jsx15("span", { children: "Bild generieren" })
|
|
2269
|
+
] })
|
|
2270
|
+
}
|
|
2271
|
+
)
|
|
2272
|
+
] }),
|
|
2273
|
+
resultImage && /* @__PURE__ */ jsx15("div", { className: "rounded-xl overflow-hidden border border-white/10", children: /* @__PURE__ */ jsx15("img", { src: resultImage, className: "w-full object-cover" }) })
|
|
2274
|
+
] });
|
|
2275
|
+
};
|
|
2276
|
+
|
|
2277
|
+
// src/components/labs/LabCompare.tsx
|
|
2278
|
+
import { useState as useState10 } from "react";
|
|
2279
|
+
import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2280
|
+
var LabCompare = ({ services, onResult }) => {
|
|
2281
|
+
const [showPickerFor, setShowPickerFor] = useState10(null);
|
|
2282
|
+
const [selectedImages, setSelectedImages] = useState10([]);
|
|
2283
|
+
const [instruction, setInstruction] = useState10("");
|
|
2284
|
+
const [analysis, setAnalysis] = useState10("");
|
|
2285
|
+
const [generatedPrompt, setGeneratedPrompt] = useState10("");
|
|
2286
|
+
const [resultImage, setResultImage] = useState10(null);
|
|
2287
|
+
const [isAnalyzing, setIsAnalyzing] = useState10(false);
|
|
2288
|
+
const [isGeneratingImage, setIsGeneratingImage] = useState10(false);
|
|
2289
|
+
const handleSelectImage = (index, item, frame) => {
|
|
2290
|
+
services.onItemUsed(item);
|
|
2291
|
+
const newImg = {
|
|
2292
|
+
item,
|
|
2293
|
+
frame,
|
|
2294
|
+
label: autoLabel(index),
|
|
2295
|
+
sendToPromptAI: true,
|
|
2296
|
+
sendToImageGen: false,
|
|
2297
|
+
roleForPrompt: "",
|
|
2298
|
+
roleForImage: ""
|
|
2299
|
+
};
|
|
2300
|
+
setSelectedImages((prev) => {
|
|
2301
|
+
const next = [...prev];
|
|
2302
|
+
next[index] = newImg;
|
|
2303
|
+
return next;
|
|
2304
|
+
});
|
|
2305
|
+
setShowPickerFor(null);
|
|
2306
|
+
setAnalysis("");
|
|
2307
|
+
};
|
|
2308
|
+
const updateImg = (i, updates) => setSelectedImages((prev) => prev.map((img, idx) => idx === i && img ? { ...img, ...updates } : img));
|
|
2309
|
+
const addSlot = () => setSelectedImages((prev) => [...prev, null]);
|
|
2310
|
+
const removeSlot = (i) => setSelectedImages((prev) => prev.filter((_, idx) => idx !== i));
|
|
2311
|
+
const handleAnalyze = async () => {
|
|
2312
|
+
const filled = selectedImages.filter(Boolean);
|
|
2313
|
+
if (!filled.length || !instruction.trim()) return;
|
|
2314
|
+
setIsAnalyzing(true);
|
|
2315
|
+
try {
|
|
2316
|
+
const { text, systemInstruction } = buildCompareInstruction(filled, instruction);
|
|
2317
|
+
const images = filled.filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
|
|
2318
|
+
const result = await services.generateText(text, { systemInstruction, images: images.length ? images : void 0 });
|
|
2319
|
+
setAnalysis(result);
|
|
2320
|
+
setGeneratedPrompt("");
|
|
2321
|
+
} finally {
|
|
2322
|
+
setIsAnalyzing(false);
|
|
2323
|
+
}
|
|
2324
|
+
};
|
|
2325
|
+
const handleGenerateImage = async () => {
|
|
2326
|
+
if (!generatedPrompt) return;
|
|
2327
|
+
setIsGeneratingImage(true);
|
|
2328
|
+
try {
|
|
2329
|
+
const { base64, mediaId } = await services.generateImage({ prompt: generatedPrompt, aspectRatio: "1:1", modelDisplayName: "\u{1F34C} Nano Banana Pro" });
|
|
2330
|
+
const newBase64 = `data:image/png;base64,${base64}`;
|
|
2331
|
+
setResultImage(newBase64);
|
|
2332
|
+
const frameId = crypto.randomUUID();
|
|
2333
|
+
const newItem = {
|
|
2334
|
+
id: frameId,
|
|
2335
|
+
prompt: generatedPrompt,
|
|
2336
|
+
tags: [],
|
|
2337
|
+
frames: [{ id: frameId, base64: newBase64, mediaId, source: "generated" }]
|
|
2338
|
+
};
|
|
2339
|
+
services.saveResult?.(newItem);
|
|
2340
|
+
onResult?.(newItem);
|
|
2341
|
+
} finally {
|
|
2342
|
+
setIsGeneratingImage(false);
|
|
2343
|
+
}
|
|
2344
|
+
};
|
|
2345
|
+
if (showPickerFor !== null) {
|
|
2346
|
+
return /* @__PURE__ */ jsx16(
|
|
2347
|
+
LabImagePicker,
|
|
2348
|
+
{
|
|
2349
|
+
availableItems: services.availableItems,
|
|
2350
|
+
recentItems: services.recentItems,
|
|
2351
|
+
onSelect: (item, frame) => handleSelectImage(showPickerFor, item, frame),
|
|
2352
|
+
onClose: () => setShowPickerFor(null),
|
|
2353
|
+
title: `${autoLabel(showPickerFor)} w\xE4hlen`
|
|
2354
|
+
}
|
|
2355
|
+
);
|
|
2356
|
+
}
|
|
2357
|
+
return /* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
|
|
2358
|
+
/* @__PURE__ */ jsx16("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40", children: "Bilder zum Vergleichen" }),
|
|
2359
|
+
selectedImages.map((img, i) => /* @__PURE__ */ jsxs14("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
|
|
2360
|
+
/* @__PURE__ */ jsx16("span", { className: "text-[10px] font-bold text-white/40 w-6 shrink-0 pt-1", children: autoLabel(i) }),
|
|
2361
|
+
img ? /* @__PURE__ */ jsxs14(Fragment7, { children: [
|
|
2362
|
+
/* @__PURE__ */ jsx16("img", { src: img.frame.base64, className: "w-12 h-12 object-cover rounded-lg shrink-0 cursor-pointer", onClick: () => setShowPickerFor(i) }),
|
|
2363
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex-1 min-w-0 flex flex-col gap-1", children: [
|
|
2364
|
+
/* @__PURE__ */ jsx16("p", { className: "text-[10px] text-white/50 line-clamp-1", children: img.item.prompt }),
|
|
2365
|
+
/* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-1 text-[10px] text-white/40", children: [
|
|
2366
|
+
/* @__PURE__ */ jsx16("input", { type: "checkbox", checked: img.sendToPromptAI, onChange: (e) => updateImg(i, { sendToPromptAI: e.target.checked }) }),
|
|
2367
|
+
"Bild an KI mitgeben"
|
|
2368
|
+
] }),
|
|
2369
|
+
/* @__PURE__ */ jsx16(
|
|
2370
|
+
"input",
|
|
2371
|
+
{
|
|
2372
|
+
value: img.roleForPrompt || "",
|
|
2373
|
+
onChange: (e) => updateImg(i, { roleForPrompt: e.target.value }),
|
|
2374
|
+
placeholder: "Rolle z.B. Referenz A, Stilvergleich...",
|
|
2375
|
+
className: "bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
|
|
2376
|
+
}
|
|
2377
|
+
)
|
|
2378
|
+
] })
|
|
2379
|
+
] }) : /* @__PURE__ */ jsx16("button", { onClick: () => setShowPickerFor(i), className: "flex-1 py-3 border border-dashed border-white/20 rounded-lg text-[10px] text-white/30 active:bg-white/5", children: "Bild w\xE4hlen" }),
|
|
2380
|
+
/* @__PURE__ */ jsx16("button", { onClick: () => removeSlot(i), className: "text-white/20 active:text-red-400 self-start", children: /* @__PURE__ */ jsx16("span", { className: "material-symbols-outlined text-[16px]", children: "close" }) })
|
|
2381
|
+
] }, i)),
|
|
2382
|
+
/* @__PURE__ */ jsxs14("button", { onClick: addSlot, className: "w-full py-2 border border-dashed border-white/10 rounded-xl text-[10px] text-white/30 active:bg-white/5 flex items-center justify-center gap-1", children: [
|
|
2383
|
+
/* @__PURE__ */ jsx16("span", { className: "material-symbols-outlined text-[14px]", children: "add" }),
|
|
2384
|
+
"Bild hinzuf\xFCgen"
|
|
2385
|
+
] }),
|
|
2386
|
+
/* @__PURE__ */ jsxs14("div", { children: [
|
|
2387
|
+
/* @__PURE__ */ jsx16("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Analyse-Anweisung" }),
|
|
2388
|
+
/* @__PURE__ */ jsx16(
|
|
2389
|
+
"textarea",
|
|
2390
|
+
{
|
|
2391
|
+
value: instruction,
|
|
2392
|
+
onChange: (e) => setInstruction(e.target.value),
|
|
2393
|
+
placeholder: "z.B. Vergleiche Lichtstimmung und Komposition. Welches ist dramatischer?",
|
|
2394
|
+
className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
|
|
2395
|
+
rows: 3
|
|
2396
|
+
}
|
|
2397
|
+
)
|
|
2398
|
+
] }),
|
|
2399
|
+
/* @__PURE__ */ jsx16(
|
|
2400
|
+
"button",
|
|
2401
|
+
{
|
|
2402
|
+
onClick: handleAnalyze,
|
|
2403
|
+
disabled: selectedImages.filter(Boolean).length < 1 || !instruction.trim() || isAnalyzing,
|
|
2404
|
+
className: "w-full py-3 rounded-xl bg-white/10 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-white/15 flex items-center justify-center gap-2",
|
|
2405
|
+
children: isAnalyzing ? /* @__PURE__ */ jsxs14(Fragment7, { children: [
|
|
2406
|
+
/* @__PURE__ */ jsx16("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
|
|
2407
|
+
/* @__PURE__ */ jsx16("span", { children: "Analysiere..." })
|
|
2408
|
+
] }) : /* @__PURE__ */ jsxs14(Fragment7, { children: [
|
|
2409
|
+
/* @__PURE__ */ jsx16("span", { className: "material-symbols-outlined text-[16px]", children: "compare" }),
|
|
2410
|
+
/* @__PURE__ */ jsx16("span", { children: "Analysieren" })
|
|
2411
|
+
] })
|
|
2412
|
+
}
|
|
2413
|
+
),
|
|
2414
|
+
analysis && /* @__PURE__ */ jsxs14("div", { children: [
|
|
2415
|
+
/* @__PURE__ */ jsx16("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Analyse" }),
|
|
2416
|
+
/* @__PURE__ */ jsx16("div", { className: "bg-white/5 border border-white/10 rounded-xl px-3 py-3", children: /* @__PURE__ */ jsx16("p", { className: "text-[12px] text-white/70 leading-relaxed whitespace-pre-wrap", children: analysis }) }),
|
|
2417
|
+
/* @__PURE__ */ jsxs14("div", { className: "mt-3", children: [
|
|
2418
|
+
/* @__PURE__ */ jsx16("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40 mb-2", children: "Als Prompt nutzen" }),
|
|
2419
|
+
/* @__PURE__ */ jsx16(
|
|
2420
|
+
"textarea",
|
|
2421
|
+
{
|
|
2422
|
+
value: generatedPrompt,
|
|
2423
|
+
onChange: (e) => setGeneratedPrompt(e.target.value),
|
|
2424
|
+
placeholder: "Analyse-Ergebnis hier als Prompt einf\xFCgen oder eigenen Prompt schreiben...",
|
|
2425
|
+
className: "w-full bg-white/5 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
|
|
2426
|
+
rows: 3
|
|
2427
|
+
}
|
|
2428
|
+
),
|
|
2429
|
+
/* @__PURE__ */ jsx16(
|
|
2430
|
+
"button",
|
|
2431
|
+
{
|
|
2432
|
+
onClick: handleGenerateImage,
|
|
2433
|
+
disabled: !generatedPrompt.trim() || isGeneratingImage,
|
|
2434
|
+
className: "w-full mt-2 py-3 rounded-xl bg-blue-600/80 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-blue-600 flex items-center justify-center gap-2",
|
|
2435
|
+
children: isGeneratingImage ? /* @__PURE__ */ jsxs14(Fragment7, { children: [
|
|
2436
|
+
/* @__PURE__ */ jsx16("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
|
|
2437
|
+
/* @__PURE__ */ jsx16("span", { children: "Generiere..." })
|
|
2438
|
+
] }) : /* @__PURE__ */ jsxs14(Fragment7, { children: [
|
|
2439
|
+
/* @__PURE__ */ jsx16("span", { className: "material-symbols-outlined text-[16px]", children: "image" }),
|
|
2440
|
+
/* @__PURE__ */ jsx16("span", { children: "Bild generieren" })
|
|
2441
|
+
] })
|
|
2442
|
+
}
|
|
2443
|
+
)
|
|
2444
|
+
] })
|
|
2445
|
+
] }),
|
|
2446
|
+
resultImage && /* @__PURE__ */ jsx16("div", { className: "rounded-xl overflow-hidden border border-white/10", children: /* @__PURE__ */ jsx16("img", { src: resultImage, className: "w-full object-cover" }) })
|
|
2447
|
+
] });
|
|
2448
|
+
};
|
|
2449
|
+
|
|
2450
|
+
// src/components/labs/LabLoop.tsx
|
|
2451
|
+
import { useState as useState11 } from "react";
|
|
2452
|
+
import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2453
|
+
var LabLoop = ({ services, onResult }) => {
|
|
2454
|
+
const [rounds, setRounds] = useState11([]);
|
|
2455
|
+
const [currentInstruction, setCurrentInstruction] = useState11("");
|
|
2456
|
+
const [showPickerForRound, setShowPickerForRound] = useState11(null);
|
|
2457
|
+
const [pendingImages, setPendingImages] = useState11([]);
|
|
2458
|
+
const [isGenerating, setIsGenerating] = useState11(false);
|
|
2459
|
+
const currentPrompt = rounds.length > 0 ? rounds[rounds.length - 1].prompt : "";
|
|
2460
|
+
const handleAddImage = (item, frame) => {
|
|
2461
|
+
services.onItemUsed(item);
|
|
2462
|
+
const label = autoLabel(pendingImages.length);
|
|
2463
|
+
setPendingImages((prev) => [...prev, {
|
|
2464
|
+
item,
|
|
2465
|
+
frame,
|
|
2466
|
+
label,
|
|
2467
|
+
sendToPromptAI: true,
|
|
2468
|
+
sendToImageGen: false,
|
|
2469
|
+
roleForPrompt: "",
|
|
2470
|
+
roleForImage: ""
|
|
2471
|
+
}]);
|
|
2472
|
+
setShowPickerForRound(null);
|
|
2473
|
+
};
|
|
2474
|
+
const updatePendingImage = (i, updates) => setPendingImages((prev) => prev.map((img, idx) => idx === i ? { ...img, ...updates } : img));
|
|
2475
|
+
const handleRunRound = async () => {
|
|
2476
|
+
if (!currentInstruction.trim()) return;
|
|
2477
|
+
setIsGenerating(true);
|
|
2478
|
+
try {
|
|
2479
|
+
const historyForBuilder = rounds.map((r) => ({
|
|
2480
|
+
prompt: r.prompt,
|
|
2481
|
+
instruction: r.instruction,
|
|
2482
|
+
images: r.images
|
|
2483
|
+
}));
|
|
2484
|
+
const { text, systemInstruction } = buildLoopInstruction(historyForBuilder, currentInstruction);
|
|
2485
|
+
const allImages = [...rounds.flatMap((r) => r.images), ...pendingImages].filter((i) => i.sendToPromptAI).map((i) => ({ base64: i.frame.base64, mimeType: "image/png" }));
|
|
2486
|
+
const newPrompt = await services.generateText(text, {
|
|
2487
|
+
systemInstruction,
|
|
2488
|
+
images: allImages.length ? allImages : void 0
|
|
2489
|
+
});
|
|
2490
|
+
const { base64, mediaId } = await services.generateImage({
|
|
2491
|
+
prompt: newPrompt,
|
|
2492
|
+
aspectRatio: "1:1",
|
|
2493
|
+
modelDisplayName: "\u{1F34C} Nano Banana Pro"
|
|
2494
|
+
});
|
|
2495
|
+
const newBase64 = `data:image/png;base64,${base64}`;
|
|
2496
|
+
const newFrame = { id: crypto.randomUUID(), base64: newBase64, mediaId, source: "generated" };
|
|
2497
|
+
const newRound = {
|
|
2498
|
+
prompt: newPrompt,
|
|
2499
|
+
instruction: currentInstruction,
|
|
2500
|
+
frame: newFrame,
|
|
2501
|
+
images: [...pendingImages]
|
|
2502
|
+
};
|
|
2503
|
+
setRounds((prev) => [...prev, newRound]);
|
|
2504
|
+
setCurrentInstruction("");
|
|
2505
|
+
setPendingImages([]);
|
|
2506
|
+
const newItem = {
|
|
2507
|
+
id: newFrame.id,
|
|
2508
|
+
prompt: newPrompt,
|
|
2509
|
+
tags: [],
|
|
2510
|
+
frames: [newFrame]
|
|
2511
|
+
};
|
|
2512
|
+
services.saveResult?.(newItem);
|
|
2513
|
+
onResult?.(newItem);
|
|
2514
|
+
} finally {
|
|
2515
|
+
setIsGenerating(false);
|
|
2516
|
+
}
|
|
2517
|
+
};
|
|
2518
|
+
if (showPickerForRound !== null) {
|
|
2519
|
+
return /* @__PURE__ */ jsx17(
|
|
2520
|
+
LabImagePicker,
|
|
2521
|
+
{
|
|
2522
|
+
availableItems: services.availableItems,
|
|
2523
|
+
recentItems: services.recentItems,
|
|
2524
|
+
onSelect: handleAddImage,
|
|
2525
|
+
onClose: () => setShowPickerForRound(null),
|
|
2526
|
+
title: "Referenzbild hinzuf\xFCgen"
|
|
2527
|
+
}
|
|
2528
|
+
);
|
|
2529
|
+
}
|
|
2530
|
+
return /* @__PURE__ */ jsxs15("div", { className: "flex flex-col gap-3 p-4 overflow-y-auto dark-scrollbar", children: [
|
|
2531
|
+
rounds.map((round, i) => /* @__PURE__ */ jsxs15("div", { className: "flex gap-3 p-3 rounded-xl border border-white/10 bg-white/5", children: [
|
|
2532
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex flex-col items-center gap-1 shrink-0", children: [
|
|
2533
|
+
/* @__PURE__ */ jsxs15("span", { className: "text-[9px] font-bold text-white/30", children: [
|
|
2534
|
+
"R",
|
|
2535
|
+
i + 1
|
|
2536
|
+
] }),
|
|
2537
|
+
round.frame && /* @__PURE__ */ jsx17("img", { src: round.frame.base64, className: "w-12 h-12 object-cover rounded-lg" })
|
|
2538
|
+
] }),
|
|
2539
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex-1 min-w-0", children: [
|
|
2540
|
+
/* @__PURE__ */ jsxs15("p", { className: "text-[9px] text-white/30 italic mb-1", children: [
|
|
2541
|
+
'"',
|
|
2542
|
+
round.instruction,
|
|
2543
|
+
'"'
|
|
2544
|
+
] }),
|
|
2545
|
+
/* @__PURE__ */ jsx17("p", { className: "text-[10px] text-white/60 leading-tight line-clamp-3", children: round.prompt })
|
|
2546
|
+
] })
|
|
2547
|
+
] }, i)),
|
|
2548
|
+
/* @__PURE__ */ jsxs15("div", { className: "rounded-xl border border-white/20 bg-white/5 p-3 flex flex-col gap-3", children: [
|
|
2549
|
+
/* @__PURE__ */ jsx17("p", { className: "text-[9px] font-bold uppercase tracking-widest text-white/40", children: rounds.length === 0 ? "Runde 1 \u2014 Erster Prompt" : `Runde ${rounds.length + 1}` }),
|
|
2550
|
+
currentPrompt && /* @__PURE__ */ jsxs15("p", { className: "text-[10px] text-white/40 italic line-clamp-2", children: [
|
|
2551
|
+
'Letzter Prompt: "',
|
|
2552
|
+
currentPrompt,
|
|
2553
|
+
'"'
|
|
2554
|
+
] }),
|
|
2555
|
+
/* @__PURE__ */ jsx17(
|
|
2556
|
+
"textarea",
|
|
2557
|
+
{
|
|
2558
|
+
value: currentInstruction,
|
|
2559
|
+
onChange: (e) => setCurrentInstruction(e.target.value),
|
|
2560
|
+
placeholder: rounds.length === 0 ? "Ersten Prompt beschreiben..." : "Was soll verbessert werden?",
|
|
2561
|
+
className: "w-full bg-black/30 border border-white/10 rounded-xl px-3 py-2.5 text-[12px] text-white/80 outline-none resize-none dark-scrollbar",
|
|
2562
|
+
rows: 3
|
|
2563
|
+
}
|
|
2564
|
+
),
|
|
2565
|
+
pendingImages.map((img, i) => /* @__PURE__ */ jsxs15("div", { className: "flex gap-2 items-center", children: [
|
|
2566
|
+
/* @__PURE__ */ jsx17("img", { src: img.frame.base64, className: "w-8 h-8 object-cover rounded" }),
|
|
2567
|
+
/* @__PURE__ */ jsx17("span", { className: "text-[10px] text-white/40", children: img.label }),
|
|
2568
|
+
/* @__PURE__ */ jsx17(
|
|
2569
|
+
"input",
|
|
2570
|
+
{
|
|
2571
|
+
value: img.roleForPrompt || "",
|
|
2572
|
+
onChange: (e) => updatePendingImage(i, { roleForPrompt: e.target.value }),
|
|
2573
|
+
placeholder: "Rolle...",
|
|
2574
|
+
className: "flex-1 bg-black/30 border border-white/10 rounded px-2 py-0.5 text-[10px] text-white/60 outline-none"
|
|
2575
|
+
}
|
|
2576
|
+
),
|
|
2577
|
+
/* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-1 text-[9px] text-white/30", children: [
|
|
2578
|
+
/* @__PURE__ */ jsx17("input", { type: "checkbox", checked: img.sendToPromptAI, onChange: (e) => updatePendingImage(i, { sendToPromptAI: e.target.checked }) }),
|
|
2579
|
+
"KI"
|
|
2580
|
+
] }),
|
|
2581
|
+
/* @__PURE__ */ jsx17("button", { onClick: () => setPendingImages((prev) => prev.filter((_, idx) => idx !== i)), className: "text-white/20 active:text-red-400", children: /* @__PURE__ */ jsx17("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
2582
|
+
] }, i)),
|
|
2583
|
+
/* @__PURE__ */ jsxs15(
|
|
2584
|
+
"button",
|
|
2585
|
+
{
|
|
2586
|
+
onClick: () => setShowPickerForRound(rounds.length),
|
|
2587
|
+
className: "text-[10px] text-white/30 active:text-white/60 flex items-center gap-1 self-start",
|
|
2588
|
+
children: [
|
|
2589
|
+
/* @__PURE__ */ jsx17("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
|
|
2590
|
+
"Referenzbild hinzuf\xFCgen"
|
|
2591
|
+
]
|
|
2592
|
+
}
|
|
2593
|
+
),
|
|
2594
|
+
/* @__PURE__ */ jsx17(
|
|
2595
|
+
"button",
|
|
2596
|
+
{
|
|
2597
|
+
onClick: handleRunRound,
|
|
2598
|
+
disabled: !currentInstruction.trim() || isGenerating,
|
|
2599
|
+
className: "w-full py-3 rounded-xl bg-white/10 text-white font-bold text-[12px] uppercase tracking-wide disabled:opacity-30 active:bg-white/15 flex items-center justify-center gap-2",
|
|
2600
|
+
children: isGenerating ? /* @__PURE__ */ jsxs15(Fragment8, { children: [
|
|
2601
|
+
/* @__PURE__ */ jsx17("div", { className: "w-3 h-3 border-t border-white rounded-full animate-spin" }),
|
|
2602
|
+
/* @__PURE__ */ jsx17("span", { children: "Runde l\xE4uft..." })
|
|
2603
|
+
] }) : /* @__PURE__ */ jsxs15(Fragment8, { children: [
|
|
2604
|
+
/* @__PURE__ */ jsx17("span", { className: "material-symbols-outlined text-[16px]", children: "loop" }),
|
|
2605
|
+
/* @__PURE__ */ jsx17("span", { children: "Runde starten" })
|
|
2606
|
+
] })
|
|
2607
|
+
}
|
|
2608
|
+
)
|
|
2609
|
+
] })
|
|
2610
|
+
] });
|
|
2611
|
+
};
|
|
2612
|
+
|
|
2613
|
+
// src/components/labs/LabsTab.tsx
|
|
2614
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2615
|
+
var TABS = [
|
|
2616
|
+
{ key: "remix", label: "Remix", icon: "auto_fix_high" },
|
|
2617
|
+
{ key: "blend", label: "Blend", icon: "merge" },
|
|
2618
|
+
{ key: "compare", label: "Compare", icon: "compare" },
|
|
2619
|
+
{ key: "loop", label: "Loop", icon: "loop" }
|
|
2620
|
+
];
|
|
2621
|
+
var LabsTab = ({ services, onResult }) => {
|
|
2622
|
+
const [activeTab, setActiveTab] = useState12("remix");
|
|
2623
|
+
return /* @__PURE__ */ jsxs16("div", { className: "flex flex-col h-full overflow-hidden", children: [
|
|
2624
|
+
/* @__PURE__ */ jsx18("div", { className: "flex border-b border-white/5 shrink-0", children: TABS.map((tab) => /* @__PURE__ */ jsxs16(
|
|
2625
|
+
"button",
|
|
2626
|
+
{
|
|
2627
|
+
onClick: () => setActiveTab(tab.key),
|
|
2628
|
+
className: `flex-1 flex items-center justify-center gap-1 h-10 text-[9px] font-bold uppercase tracking-wide transition-colors ${activeTab === tab.key ? "text-white border-b-2 border-white" : "text-white/30 hover:text-white/60"}`,
|
|
2629
|
+
children: [
|
|
2630
|
+
/* @__PURE__ */ jsx18("span", { className: "material-symbols-outlined text-[14px]", children: tab.icon }),
|
|
2631
|
+
tab.label
|
|
2632
|
+
]
|
|
2633
|
+
},
|
|
2634
|
+
tab.key
|
|
2635
|
+
)) }),
|
|
2636
|
+
/* @__PURE__ */ jsxs16("div", { className: "flex-1 overflow-hidden", children: [
|
|
2637
|
+
activeTab === "remix" && /* @__PURE__ */ jsx18(LabRemix, { services, onResult }),
|
|
2638
|
+
activeTab === "blend" && /* @__PURE__ */ jsx18(LabBlend, { services, onResult }),
|
|
2639
|
+
activeTab === "compare" && /* @__PURE__ */ jsx18(LabCompare, { services, onResult }),
|
|
2640
|
+
activeTab === "loop" && /* @__PURE__ */ jsx18(LabLoop, { services, onResult })
|
|
2641
|
+
] })
|
|
2642
|
+
] });
|
|
2643
|
+
};
|
|
2644
|
+
|
|
2645
|
+
// src/components/TagManagerPanel.tsx
|
|
2646
|
+
import { useState as useState13 } from "react";
|
|
2647
|
+
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2648
|
+
function TagManagerPanel({ workspaceTags, onTagCreate, onTagUpdate, onTagDelete, onTagReorder, onTagMove }) {
|
|
2649
|
+
const categories = Object.keys(workspaceTags.by_category).filter(
|
|
2650
|
+
(cat) => (workspaceTags.by_category[cat] || []).some((t) => !t.is_deleted)
|
|
2651
|
+
);
|
|
2652
|
+
const [selectedCategory, setSelectedCategory] = useState13(categories[0] || "");
|
|
2653
|
+
const effectiveCategory = categories.includes(selectedCategory) ? selectedCategory : categories[0] || "";
|
|
2654
|
+
const [editingLabel, setEditingLabel] = useState13(null);
|
|
2655
|
+
const [editState, setEditState] = useState13({ label: "", value: "" });
|
|
2656
|
+
const [newTag, setNewTag] = useState13({ label: "", value: "" });
|
|
2657
|
+
const [movingLabel, setMovingLabel] = useState13(null);
|
|
2658
|
+
const [moveTarget, setMoveTarget] = useState13("");
|
|
2659
|
+
const tags = (workspaceTags.by_category[effectiveCategory] || []).filter((t) => !t.is_deleted);
|
|
2660
|
+
const otherCategories = categories.filter((c) => c !== effectiveCategory);
|
|
2661
|
+
const startEdit = (tag) => {
|
|
2662
|
+
setEditingLabel(tag.label);
|
|
2663
|
+
setEditState({ label: tag.label, value: tag.value });
|
|
2664
|
+
setMovingLabel(null);
|
|
2665
|
+
};
|
|
2666
|
+
const saveEdit = (originalLabel) => {
|
|
2667
|
+
if (!editState.label.trim()) return;
|
|
2668
|
+
onTagUpdate(originalLabel, effectiveCategory, {
|
|
2669
|
+
label: editState.label.trim(),
|
|
2670
|
+
value: editState.value.trim() || editState.label.trim()
|
|
2671
|
+
});
|
|
2672
|
+
setEditingLabel(null);
|
|
2673
|
+
};
|
|
2674
|
+
const handleMoveUp = (index) => {
|
|
2675
|
+
if (index === 0) return;
|
|
2676
|
+
const reordered = [...tags];
|
|
2677
|
+
[reordered[index - 1], reordered[index]] = [reordered[index], reordered[index - 1]];
|
|
2678
|
+
onTagReorder(effectiveCategory, reordered);
|
|
2679
|
+
};
|
|
2680
|
+
const handleMoveDown = (index) => {
|
|
2681
|
+
if (index === tags.length - 1) return;
|
|
2682
|
+
const reordered = [...tags];
|
|
2683
|
+
[reordered[index], reordered[index + 1]] = [reordered[index + 1], reordered[index]];
|
|
2684
|
+
onTagReorder(effectiveCategory, reordered);
|
|
2685
|
+
};
|
|
2686
|
+
const handleMove = (tag) => {
|
|
2687
|
+
if (!moveTarget) return;
|
|
2688
|
+
onTagMove(tag.label, tag.value, effectiveCategory, moveTarget);
|
|
2689
|
+
setMovingLabel(null);
|
|
2690
|
+
setMoveTarget("");
|
|
2691
|
+
};
|
|
2692
|
+
const handleCreate = () => {
|
|
2693
|
+
if (!newTag.label.trim() || !effectiveCategory) return;
|
|
2694
|
+
onTagCreate({ label: newTag.label.trim(), value: newTag.value.trim() || newTag.label.trim(), category: effectiveCategory, is_user_created: true });
|
|
2695
|
+
setNewTag({ label: "", value: "" });
|
|
2696
|
+
};
|
|
2697
|
+
const handleDelete = (tag) => {
|
|
2698
|
+
if (!confirm(`Tag "${tag.label}" l\xF6schen?`)) return;
|
|
2699
|
+
onTagDelete(tag.label, effectiveCategory);
|
|
2700
|
+
};
|
|
2701
|
+
return /* @__PURE__ */ jsxs17("div", { className: "flex flex-col h-full overflow-hidden", children: [
|
|
2702
|
+
/* @__PURE__ */ jsx19("div", { className: "px-3 py-2 border-b border-white/5 shrink-0", children: /* @__PURE__ */ jsx19("span", { className: "text-[10px] font-bold uppercase tracking-widest text-white/40", children: "Tag Manager" }) }),
|
|
2703
|
+
/* @__PURE__ */ jsx19("div", { className: "px-3 py-2 shrink-0 overflow-x-auto", children: /* @__PURE__ */ jsxs17("div", { className: "flex gap-1.5 flex-nowrap", children: [
|
|
2704
|
+
categories.map((cat) => /* @__PURE__ */ jsxs17(
|
|
2705
|
+
"button",
|
|
2706
|
+
{
|
|
2707
|
+
onClick: () => {
|
|
2708
|
+
setSelectedCategory(cat);
|
|
2709
|
+
setEditingLabel(null);
|
|
2710
|
+
setMovingLabel(null);
|
|
2711
|
+
},
|
|
2712
|
+
className: `px-2.5 py-1 rounded text-[9px] font-bold border whitespace-nowrap transition ${cat === effectiveCategory ? "bg-blue-900/40 border-blue-600/60 text-blue-300" : "bg-white/5 border-white/10 text-white/40 hover:text-white/70"}`,
|
|
2713
|
+
children: [
|
|
2714
|
+
cat,
|
|
2715
|
+
" ",
|
|
2716
|
+
/* @__PURE__ */ jsx19("span", { className: "ml-1 opacity-50", children: (workspaceTags.by_category[cat] || []).filter((t) => !t.is_deleted).length })
|
|
2717
|
+
]
|
|
2718
|
+
},
|
|
2719
|
+
cat
|
|
2720
|
+
)),
|
|
2721
|
+
categories.length === 0 && /* @__PURE__ */ jsx19("span", { className: "text-[10px] text-white/20", children: "Erst Workspace importieren" })
|
|
2722
|
+
] }) }),
|
|
2723
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex-1 overflow-y-auto dark-scrollbar px-3 pb-2 space-y-1", children: [
|
|
2724
|
+
tags.map((tag, i) => /* @__PURE__ */ jsxs17("div", { children: [
|
|
2725
|
+
editingLabel === tag.label ? /* @__PURE__ */ jsxs17("div", { className: "bg-white/5 border border-blue-600/40 rounded-lg p-2.5 space-y-1.5", children: [
|
|
2726
|
+
/* @__PURE__ */ jsx19(
|
|
2727
|
+
"input",
|
|
2728
|
+
{
|
|
2729
|
+
value: editState.label,
|
|
2730
|
+
onChange: (e) => setEditState((s) => ({ ...s, label: e.target.value })),
|
|
2731
|
+
className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1 text-[12px] text-white outline-none focus:border-blue-500/50",
|
|
2732
|
+
placeholder: "Label",
|
|
2733
|
+
autoFocus: true,
|
|
2734
|
+
onKeyDown: (e) => e.key === "Enter" && saveEdit(tag.label)
|
|
2735
|
+
}
|
|
2736
|
+
),
|
|
2737
|
+
/* @__PURE__ */ jsx19(
|
|
2738
|
+
"textarea",
|
|
2739
|
+
{
|
|
2740
|
+
value: editState.value,
|
|
2741
|
+
onChange: (e) => setEditState((s) => ({ ...s, value: e.target.value })),
|
|
2742
|
+
rows: 2,
|
|
2743
|
+
className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1 text-[11px] text-white/70 outline-none focus:border-blue-500/50 resize-none",
|
|
2744
|
+
placeholder: "Prompt-Wert (leer = Label)"
|
|
2745
|
+
}
|
|
2746
|
+
),
|
|
2747
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex gap-1.5 justify-end", children: [
|
|
2748
|
+
/* @__PURE__ */ jsx19("button", { onClick: () => saveEdit(tag.label), className: "px-2.5 py-1 bg-blue-700 hover:bg-blue-600 text-white text-[10px] font-bold rounded transition", children: "SPEICHERN" }),
|
|
2749
|
+
/* @__PURE__ */ jsx19("button", { onClick: () => setEditingLabel(null), className: "px-2.5 py-1 bg-white/5 hover:bg-white/10 text-white/50 text-[10px] font-bold rounded transition", children: "ABBRUCH" })
|
|
2750
|
+
] })
|
|
2751
|
+
] }) : /* @__PURE__ */ jsxs17("div", { className: "group flex items-center gap-1.5 bg-white/3 hover:bg-white/6 border border-white/5 rounded-lg px-2 py-1.5 transition", children: [
|
|
2752
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex flex-col gap-0 shrink-0", children: [
|
|
2753
|
+
/* @__PURE__ */ jsx19("button", { onClick: () => handleMoveUp(i), disabled: i === 0, className: "text-white/20 hover:text-white/60 disabled:opacity-10 transition leading-none", children: /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[14px]", children: "arrow_drop_up" }) }),
|
|
2754
|
+
/* @__PURE__ */ jsx19("button", { onClick: () => handleMoveDown(i), disabled: i === tags.length - 1, className: "text-white/20 hover:text-white/60 disabled:opacity-10 transition leading-none", children: /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[14px]", children: "arrow_drop_down" }) })
|
|
2755
|
+
] }),
|
|
2756
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex-1 min-w-0", children: [
|
|
2757
|
+
/* @__PURE__ */ jsx19("div", { className: "text-[12px] text-white/80 font-medium truncate", children: tag.label }),
|
|
2758
|
+
tag.value && tag.value !== tag.label && /* @__PURE__ */ jsxs17("div", { className: "text-[10px] text-white/30 truncate", children: [
|
|
2759
|
+
tag.value.slice(0, 60),
|
|
2760
|
+
tag.value.length > 60 ? "\u2026" : ""
|
|
2761
|
+
] })
|
|
2762
|
+
] }),
|
|
2763
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex gap-1 opacity-0 group-hover:opacity-100 transition shrink-0", children: [
|
|
2764
|
+
otherCategories.length > 0 && /* @__PURE__ */ jsx19(
|
|
2765
|
+
"button",
|
|
2766
|
+
{
|
|
2767
|
+
onClick: () => {
|
|
2768
|
+
setMovingLabel((l) => l === tag.label ? null : tag.label);
|
|
2769
|
+
setMoveTarget("");
|
|
2770
|
+
setEditingLabel(null);
|
|
2771
|
+
},
|
|
2772
|
+
className: "p-1 rounded text-white/30 hover:text-purple-400 transition",
|
|
2773
|
+
title: "Kategorie wechseln",
|
|
2774
|
+
children: /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[16px]", children: "drive_file_move" })
|
|
2775
|
+
}
|
|
2776
|
+
),
|
|
2777
|
+
/* @__PURE__ */ jsx19("button", { onClick: () => startEdit(tag), className: "p-1 rounded text-white/30 hover:text-blue-400 transition", title: "Bearbeiten", children: /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[16px]", children: "edit" }) }),
|
|
2778
|
+
/* @__PURE__ */ jsx19("button", { onClick: () => handleDelete(tag), className: "p-1 rounded text-white/30 hover:text-red-400 transition", title: "L\xF6schen", children: /* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[16px]", children: "delete" }) })
|
|
2779
|
+
] })
|
|
2780
|
+
] }),
|
|
2781
|
+
movingLabel === tag.label && /* @__PURE__ */ jsxs17("div", { className: "mt-1 bg-purple-900/20 border border-purple-700/30 rounded-lg p-2.5 space-y-1.5", children: [
|
|
2782
|
+
/* @__PURE__ */ jsx19("div", { className: "text-[9px] font-bold uppercase tracking-widest text-purple-400/70", children: "Verschieben nach Kategorie" }),
|
|
2783
|
+
/* @__PURE__ */ jsxs17(
|
|
2784
|
+
"select",
|
|
2785
|
+
{
|
|
2786
|
+
value: moveTarget,
|
|
2787
|
+
onChange: (e) => setMoveTarget(e.target.value),
|
|
2788
|
+
className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1 text-[11px] text-white/70 outline-none",
|
|
2789
|
+
children: [
|
|
2790
|
+
/* @__PURE__ */ jsx19("option", { value: "", children: "\u2014 Kategorie w\xE4hlen \u2014" }),
|
|
2791
|
+
otherCategories.map((cat) => /* @__PURE__ */ jsx19("option", { value: cat, children: cat }, cat))
|
|
2792
|
+
]
|
|
2793
|
+
}
|
|
2794
|
+
),
|
|
2795
|
+
/* @__PURE__ */ jsxs17("div", { className: "flex gap-1.5 justify-end", children: [
|
|
2796
|
+
/* @__PURE__ */ jsx19(
|
|
2797
|
+
"button",
|
|
2798
|
+
{
|
|
2799
|
+
onClick: () => handleMove(tag),
|
|
2800
|
+
disabled: !moveTarget,
|
|
2801
|
+
className: "px-2.5 py-1 bg-purple-700 hover:bg-purple-600 text-white text-[10px] font-bold rounded transition disabled:opacity-40",
|
|
2802
|
+
children: "VERSCHIEBEN"
|
|
2803
|
+
}
|
|
2804
|
+
),
|
|
2805
|
+
/* @__PURE__ */ jsx19("button", { onClick: () => setMovingLabel(null), className: "px-2.5 py-1 bg-white/5 hover:bg-white/10 text-white/50 text-[10px] font-bold rounded transition", children: "ABBRUCH" })
|
|
2806
|
+
] })
|
|
2807
|
+
] })
|
|
2808
|
+
] }, `${effectiveCategory}-${i}`)),
|
|
2809
|
+
tags.length === 0 && effectiveCategory && /* @__PURE__ */ jsx19("div", { className: "text-center text-[11px] text-white/20 py-6", children: "Keine Tags in dieser Kategorie." })
|
|
2810
|
+
] }),
|
|
2811
|
+
effectiveCategory && /* @__PURE__ */ jsxs17("div", { className: "px-3 py-2 border-t border-white/5 shrink-0 space-y-1.5", children: [
|
|
2812
|
+
/* @__PURE__ */ jsxs17("div", { className: "text-[9px] font-bold uppercase tracking-widest text-white/30", children: [
|
|
2813
|
+
"Neuer Tag in \u201E",
|
|
2814
|
+
effectiveCategory,
|
|
2815
|
+
'"'
|
|
2816
|
+
] }),
|
|
2817
|
+
/* @__PURE__ */ jsx19(
|
|
2818
|
+
"input",
|
|
2819
|
+
{
|
|
2820
|
+
value: newTag.label,
|
|
2821
|
+
onChange: (e) => setNewTag((s) => ({ ...s, label: e.target.value })),
|
|
2822
|
+
onKeyDown: (e) => e.key === "Enter" && !e.shiftKey && handleCreate(),
|
|
2823
|
+
placeholder: "Label\u2026",
|
|
2824
|
+
className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1.5 text-[12px] text-white outline-none focus:border-white/20"
|
|
2825
|
+
}
|
|
2826
|
+
),
|
|
2827
|
+
/* @__PURE__ */ jsx19(
|
|
2828
|
+
"textarea",
|
|
2829
|
+
{
|
|
2830
|
+
value: newTag.value,
|
|
2831
|
+
onChange: (e) => setNewTag((s) => ({ ...s, value: e.target.value })),
|
|
2832
|
+
rows: 2,
|
|
2833
|
+
placeholder: "Prompt-Wert (leer = Label)",
|
|
2834
|
+
className: "w-full bg-black/40 border border-white/10 rounded px-2 py-1 text-[11px] text-white/60 outline-none focus:border-white/20 resize-none"
|
|
2835
|
+
}
|
|
2836
|
+
),
|
|
2837
|
+
/* @__PURE__ */ jsxs17(
|
|
2838
|
+
"button",
|
|
2839
|
+
{
|
|
2840
|
+
onClick: handleCreate,
|
|
2841
|
+
disabled: !newTag.label.trim(),
|
|
2842
|
+
className: "w-full py-1.5 bg-white/5 border border-white/10 text-white/60 text-[10px] font-bold rounded hover:bg-white/10 hover:text-white transition disabled:opacity-30 flex items-center justify-center gap-1.5",
|
|
2843
|
+
children: [
|
|
2844
|
+
/* @__PURE__ */ jsx19("span", { className: "material-symbols-outlined text-[14px]", children: "add" }),
|
|
2845
|
+
"TAG ERSTELLEN"
|
|
2846
|
+
]
|
|
2847
|
+
}
|
|
2848
|
+
)
|
|
2849
|
+
] })
|
|
2850
|
+
] });
|
|
2851
|
+
}
|
|
2852
|
+
|
|
2853
|
+
// src/components/AvatarArchitectApp.tsx
|
|
2854
|
+
import { Fragment as Fragment9, jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1609
2855
|
function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
|
|
1610
2856
|
useEffect4(() => {
|
|
1611
2857
|
const id = "flow-styles";
|
|
@@ -1616,15 +2862,15 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1616
2862
|
document.head.appendChild(style);
|
|
1617
2863
|
}
|
|
1618
2864
|
}, []);
|
|
1619
|
-
const [showStart, setShowStart] =
|
|
1620
|
-
const [layoutChoice, setLayoutChoice] =
|
|
2865
|
+
const [showStart, setShowStart] = useState14(true);
|
|
2866
|
+
const [layoutChoice, setLayoutChoice] = useState14(() => {
|
|
1621
2867
|
try {
|
|
1622
2868
|
return localStorage.getItem("aa-layout") || null;
|
|
1623
2869
|
} catch {
|
|
1624
2870
|
return null;
|
|
1625
2871
|
}
|
|
1626
2872
|
});
|
|
1627
|
-
const [projectLoaded, setProjectLoaded] =
|
|
2873
|
+
const [projectLoaded, setProjectLoaded] = useState14(false);
|
|
1628
2874
|
const wsInputRef = useRef6(null);
|
|
1629
2875
|
const startApp = (choice) => {
|
|
1630
2876
|
try {
|
|
@@ -1634,47 +2880,63 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1634
2880
|
setLayoutChoice(choice);
|
|
1635
2881
|
setShowStart(false);
|
|
1636
2882
|
};
|
|
1637
|
-
const [nodes, setNodes] =
|
|
1638
|
-
const [edges, setEdges] =
|
|
1639
|
-
const [history, setHistory] =
|
|
1640
|
-
const [galleryItems, setGalleryItems] =
|
|
1641
|
-
const [activePrompt, setActivePrompt] =
|
|
1642
|
-
const [isSynthesizing, setIsSynthesizing] =
|
|
1643
|
-
const [activeGenerationsCount, setActiveGenerationsCount] =
|
|
1644
|
-
const [currentResult, setCurrentResult] =
|
|
1645
|
-
const [focusedNodeId, setFocusedNodeId] =
|
|
1646
|
-
const [leftTab, setLeftTab] =
|
|
1647
|
-
const [promptFeedback, setPromptFeedback] =
|
|
1648
|
-
const [lastPromptPayload, setLastPromptPayload] =
|
|
1649
|
-
const [isPromptTabGenerating, setIsPromptTabGenerating] =
|
|
1650
|
-
const [activeTab, setActiveTab] =
|
|
1651
|
-
const [mobileTab, setMobileTab] =
|
|
1652
|
-
const [
|
|
1653
|
-
const [
|
|
1654
|
-
const [
|
|
1655
|
-
const [
|
|
1656
|
-
const [
|
|
1657
|
-
const [
|
|
1658
|
-
const [
|
|
1659
|
-
const [
|
|
2883
|
+
const [nodes, setNodes] = useState14([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
|
|
2884
|
+
const [edges, setEdges] = useState14([]);
|
|
2885
|
+
const [history, setHistory] = useState14([]);
|
|
2886
|
+
const [galleryItems, setGalleryItems] = useState14([]);
|
|
2887
|
+
const [activePrompt, setActivePrompt] = useState14("");
|
|
2888
|
+
const [isSynthesizing, setIsSynthesizing] = useState14(false);
|
|
2889
|
+
const [activeGenerationsCount, setActiveGenerationsCount] = useState14(0);
|
|
2890
|
+
const [currentResult, setCurrentResult] = useState14(null);
|
|
2891
|
+
const [focusedNodeId, setFocusedNodeId] = useState14(null);
|
|
2892
|
+
const [leftTab, setLeftTab] = useState14("prompt");
|
|
2893
|
+
const [promptFeedback, setPromptFeedback] = useState14(null);
|
|
2894
|
+
const [lastPromptPayload, setLastPromptPayload] = useState14(null);
|
|
2895
|
+
const [isPromptTabGenerating, setIsPromptTabGenerating] = useState14(false);
|
|
2896
|
+
const [activeTab, setActiveTab] = useState14("history");
|
|
2897
|
+
const [mobileTab, setMobileTab] = useState14("stage");
|
|
2898
|
+
const [middlePanel, setMiddlePanel] = useState14("stage");
|
|
2899
|
+
const [recentLabItems, setRecentLabItems] = useState14([]);
|
|
2900
|
+
const [aspectRatio, setAspectRatio] = useState14("1:1");
|
|
2901
|
+
const [selectedModel, setSelectedModel] = useState14("\u{1F34C} Nano Banana Pro");
|
|
2902
|
+
const [seed, setSeed] = useState14(Math.floor(Math.random() * 1e6));
|
|
2903
|
+
const [seedMode, setSeedMode] = useState14("random");
|
|
2904
|
+
const [isLeftCollapsed, setIsLeftCollapsed] = useState14(false);
|
|
2905
|
+
const [isRightCollapsed, setIsRightCollapsed] = useState14(false);
|
|
2906
|
+
const [leftPanelWidth, setLeftPanelWidth] = useState14(() => {
|
|
2907
|
+
try {
|
|
2908
|
+
return parseInt(localStorage.getItem("aa-left-width") || "260", 10);
|
|
2909
|
+
} catch {
|
|
2910
|
+
return 260;
|
|
2911
|
+
}
|
|
2912
|
+
});
|
|
2913
|
+
const [rightPanelWidth, setRightPanelWidth] = useState14(() => {
|
|
2914
|
+
try {
|
|
2915
|
+
return parseInt(localStorage.getItem("aa-right-width") || "320", 10);
|
|
2916
|
+
} catch {
|
|
2917
|
+
return 320;
|
|
2918
|
+
}
|
|
2919
|
+
});
|
|
2920
|
+
const [isPromptCollapsed, setIsPromptCollapsed] = useState14(false);
|
|
2921
|
+
const [projectActionState, setProjectActionState] = useState14("idle");
|
|
1660
2922
|
const syncServerDataRef = useRef6(null);
|
|
1661
|
-
const [workspaceTags, setWorkspaceTags] =
|
|
1662
|
-
const [serverProjects, setServerProjects] =
|
|
1663
|
-
const [isLoadingFromServer, setIsLoadingFromServer] =
|
|
1664
|
-
const [highContrast, setHighContrast] =
|
|
2923
|
+
const [workspaceTags, setWorkspaceTags] = useState14(null);
|
|
2924
|
+
const [serverProjects, setServerProjects] = useState14([]);
|
|
2925
|
+
const [isLoadingFromServer, setIsLoadingFromServer] = useState14(false);
|
|
2926
|
+
const [highContrast, setHighContrast] = useState14(() => {
|
|
1665
2927
|
try {
|
|
1666
2928
|
return localStorage.getItem("aa-contrast") === "high";
|
|
1667
2929
|
} catch {
|
|
1668
2930
|
return false;
|
|
1669
2931
|
}
|
|
1670
2932
|
});
|
|
1671
|
-
const [activeReferenceId, setActiveReferenceId] =
|
|
1672
|
-
const [activeReferenceThumbnail, setActiveReferenceThumbnail] =
|
|
1673
|
-
const [isScanningImage, setIsScanningImage] =
|
|
1674
|
-
const [touchStartX, setTouchStartX] =
|
|
1675
|
-
const [isFullscreen, setIsFullscreen] =
|
|
1676
|
-
const [zoomScale, setZoomScale] =
|
|
1677
|
-
const [zoomOffset, setZoomOffset] =
|
|
2933
|
+
const [activeReferenceId, setActiveReferenceId] = useState14(null);
|
|
2934
|
+
const [activeReferenceThumbnail, setActiveReferenceThumbnail] = useState14(null);
|
|
2935
|
+
const [isScanningImage, setIsScanningImage] = useState14(false);
|
|
2936
|
+
const [touchStartX, setTouchStartX] = useState14(null);
|
|
2937
|
+
const [isFullscreen, setIsFullscreen] = useState14(false);
|
|
2938
|
+
const [zoomScale, setZoomScale] = useState14(1);
|
|
2939
|
+
const [zoomOffset, setZoomOffset] = useState14({ x: 0, y: 0 });
|
|
1678
2940
|
const lastPinchDist = useRef6(null);
|
|
1679
2941
|
const lastTapTime = useRef6(0);
|
|
1680
2942
|
const dragStart = useRef6(null);
|
|
@@ -1740,6 +3002,65 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1740
3002
|
setActiveReferenceId(null);
|
|
1741
3003
|
setActiveReferenceThumbnail(null);
|
|
1742
3004
|
};
|
|
3005
|
+
const labServices = useMemo2(() => {
|
|
3006
|
+
const available = groupGenerationsToLabItems([...galleryItems, ...history]);
|
|
3007
|
+
return {
|
|
3008
|
+
availableItems: available,
|
|
3009
|
+
recentItems: recentLabItems,
|
|
3010
|
+
onItemUsed: (item) => setRecentLabItems(
|
|
3011
|
+
(prev) => [item, ...prev.filter((i) => i.id !== item.id)].slice(0, 10)
|
|
3012
|
+
),
|
|
3013
|
+
generateText: onGeneratePrompt,
|
|
3014
|
+
generateImage: onGenerateImage,
|
|
3015
|
+
saveResult: async (item) => {
|
|
3016
|
+
const frame = item.frames[0];
|
|
3017
|
+
if (frame?.base64) {
|
|
3018
|
+
const gen = frameToGeneration(frame, item);
|
|
3019
|
+
setGalleryItems((prev) => [gen, ...prev]);
|
|
3020
|
+
setHistory((prev) => [gen, ...prev]);
|
|
3021
|
+
}
|
|
3022
|
+
},
|
|
3023
|
+
workspaceTags: workspaceTags || void 0
|
|
3024
|
+
};
|
|
3025
|
+
}, [galleryItems, history, recentLabItems, onGeneratePrompt, onGenerateImage, workspaceTags]);
|
|
3026
|
+
const startLeftResize = (e) => {
|
|
3027
|
+
e.preventDefault();
|
|
3028
|
+
const startX = e.clientX;
|
|
3029
|
+
const startW = leftPanelWidth;
|
|
3030
|
+
const onMove = (ev) => {
|
|
3031
|
+
const w = Math.max(180, Math.min(520, startW + ev.clientX - startX));
|
|
3032
|
+
setLeftPanelWidth(w);
|
|
3033
|
+
try {
|
|
3034
|
+
localStorage.setItem("aa-left-width", String(w));
|
|
3035
|
+
} catch {
|
|
3036
|
+
}
|
|
3037
|
+
};
|
|
3038
|
+
const onUp = () => {
|
|
3039
|
+
document.removeEventListener("mousemove", onMove);
|
|
3040
|
+
document.removeEventListener("mouseup", onUp);
|
|
3041
|
+
};
|
|
3042
|
+
document.addEventListener("mousemove", onMove);
|
|
3043
|
+
document.addEventListener("mouseup", onUp);
|
|
3044
|
+
};
|
|
3045
|
+
const startRightResize = (e) => {
|
|
3046
|
+
e.preventDefault();
|
|
3047
|
+
const startX = e.clientX;
|
|
3048
|
+
const startW = rightPanelWidth;
|
|
3049
|
+
const onMove = (ev) => {
|
|
3050
|
+
const w = Math.max(180, Math.min(520, startW - (ev.clientX - startX)));
|
|
3051
|
+
setRightPanelWidth(w);
|
|
3052
|
+
try {
|
|
3053
|
+
localStorage.setItem("aa-right-width", String(w));
|
|
3054
|
+
} catch {
|
|
3055
|
+
}
|
|
3056
|
+
};
|
|
3057
|
+
const onUp = () => {
|
|
3058
|
+
document.removeEventListener("mousemove", onMove);
|
|
3059
|
+
document.removeEventListener("mouseup", onUp);
|
|
3060
|
+
};
|
|
3061
|
+
document.addEventListener("mousemove", onMove);
|
|
3062
|
+
document.addEventListener("mouseup", onUp);
|
|
3063
|
+
};
|
|
1743
3064
|
const handleScanImage = async (file) => {
|
|
1744
3065
|
setIsScanningImage(true);
|
|
1745
3066
|
try {
|
|
@@ -1749,7 +3070,11 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1749
3070
|
reader.onerror = reject;
|
|
1750
3071
|
reader.readAsDataURL(file);
|
|
1751
3072
|
});
|
|
1752
|
-
const
|
|
3073
|
+
const { text, systemInstruction } = buildScanInstruction();
|
|
3074
|
+
const prompt = await onGeneratePrompt(text, {
|
|
3075
|
+
images: [{ base64, mimeType: file.type || "image/png" }],
|
|
3076
|
+
systemInstruction
|
|
3077
|
+
});
|
|
1753
3078
|
setActivePrompt(prompt);
|
|
1754
3079
|
} catch (err) {
|
|
1755
3080
|
console.error("Scan fehlgeschlagen:", err);
|
|
@@ -1865,11 +3190,32 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1865
3190
|
return { by_category: { ...prev.by_category, [category]: updatedCat }, all: updatedAll };
|
|
1866
3191
|
});
|
|
1867
3192
|
};
|
|
3193
|
+
const handleTagReorder = (category, reorderedTags) => {
|
|
3194
|
+
setWorkspaceTags((prev) => {
|
|
3195
|
+
if (!prev) return prev;
|
|
3196
|
+
const deletedTags = (prev.by_category[category] || []).filter((t) => t.is_deleted);
|
|
3197
|
+
const merged = [...reorderedTags, ...deletedTags];
|
|
3198
|
+
const newAll = [
|
|
3199
|
+
...prev.all.filter((t) => t.category !== category),
|
|
3200
|
+
...merged.map((t) => ({ ...t, category }))
|
|
3201
|
+
];
|
|
3202
|
+
return { by_category: { ...prev.by_category, [category]: merged }, all: newAll };
|
|
3203
|
+
});
|
|
3204
|
+
};
|
|
3205
|
+
const handleTagMove = (label, value, fromCategory, toCategory) => {
|
|
3206
|
+
setWorkspaceTags((prev) => {
|
|
3207
|
+
if (!prev) return prev;
|
|
3208
|
+
const fromTags = (prev.by_category[fromCategory] || []).filter((t) => t.label !== label);
|
|
3209
|
+
const toTags = [...prev.by_category[toCategory] || [], { label, value, is_user_created: true }];
|
|
3210
|
+
const newAll = prev.all.filter((t) => !(t.label === label && t.category === fromCategory)).concat({ label, value, is_user_created: true, category: toCategory });
|
|
3211
|
+
return { by_category: { ...prev.by_category, [fromCategory]: fromTags, [toCategory]: toTags }, all: newAll };
|
|
3212
|
+
});
|
|
3213
|
+
};
|
|
1868
3214
|
const handlePromptTabGenerate = async (selectedTags, instructions, rules) => {
|
|
1869
3215
|
setIsPromptTabGenerating(true);
|
|
1870
3216
|
setPromptFeedback(null);
|
|
1871
3217
|
try {
|
|
1872
|
-
const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) :
|
|
3218
|
+
const treeText = focusedNodeId ? getSubtreeFormat(focusedNodeId) : nodes.map((n) => n.data.label || "").filter(Boolean).join("\n");
|
|
1873
3219
|
const payload = buildPromptTabPayload(selectedTags, instructions, rules, treeText);
|
|
1874
3220
|
setLastPromptPayload(payload);
|
|
1875
3221
|
const raw = await onGeneratePrompt(payload);
|
|
@@ -1897,7 +3243,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1897
3243
|
const handleProjectExport = async () => {
|
|
1898
3244
|
setProjectActionState("working-full");
|
|
1899
3245
|
try {
|
|
1900
|
-
const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags);
|
|
3246
|
+
const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags, recentLabItems.map((i) => i.id));
|
|
1901
3247
|
await onDownload(base64, "application/zip", `avatar_project_${getFormattedTimestamp()}.zip`);
|
|
1902
3248
|
setProjectActionState("done");
|
|
1903
3249
|
setTimeout(() => setProjectActionState("idle"), 3e3);
|
|
@@ -1925,6 +3271,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1925
3271
|
setSeedMode(data.settings.seedMode || "random");
|
|
1926
3272
|
}
|
|
1927
3273
|
if (data.workspaceTags?.by_category) setWorkspaceTags(data.workspaceTags);
|
|
3274
|
+
if (data.recentLabItemIds?.length) {
|
|
3275
|
+
const allGens = [...data.history || [], ...data.galleryItems || []];
|
|
3276
|
+
const labItems = groupGenerationsToLabItems(allGens);
|
|
3277
|
+
const recent = data.recentLabItemIds.map((id) => labItems.find((item) => item.id === id)).filter(Boolean);
|
|
3278
|
+
setRecentLabItems(recent);
|
|
3279
|
+
}
|
|
1928
3280
|
setProjectActionState("done");
|
|
1929
3281
|
setProjectLoaded(true);
|
|
1930
3282
|
setTimeout(() => setProjectActionState("idle"), 2e3);
|
|
@@ -1965,7 +3317,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
1965
3317
|
if (!onServerSave) return;
|
|
1966
3318
|
setProjectActionState("working-full");
|
|
1967
3319
|
try {
|
|
1968
|
-
const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags);
|
|
3320
|
+
const { base64 } = await exportProjectToZip(nodes, edges, history, galleryItems, { aspectRatio, selectedModel, seed, seedMode }, workspaceTags, recentLabItems.map((i) => i.id));
|
|
1969
3321
|
await onServerSave(base64, name || `avatar_project_${getFormattedTimestamp()}`);
|
|
1970
3322
|
await fetchServerProjects();
|
|
1971
3323
|
setProjectActionState("done");
|
|
@@ -2009,7 +3361,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2009
3361
|
mergedHistory,
|
|
2010
3362
|
serverData.galleryItems || galleryItems,
|
|
2011
3363
|
serverData.settings || { aspectRatio, selectedModel, seed, seedMode },
|
|
2012
|
-
serverData.workspaceTags || workspaceTags
|
|
3364
|
+
serverData.workspaceTags || workspaceTags,
|
|
3365
|
+
serverData.recentLabItemIds || recentLabItems.map((i) => i.id)
|
|
2013
3366
|
);
|
|
2014
3367
|
await onServerSave(base64, `sync_${getFormattedTimestamp()}`);
|
|
2015
3368
|
await fetchServerProjects();
|
|
@@ -2025,7 +3378,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2025
3378
|
}, [activeTab]);
|
|
2026
3379
|
if (isFullscreen && currentResult?.base64) {
|
|
2027
3380
|
const fsBase64 = currentResult.base64.startsWith("data:") ? currentResult.base64 : `data:image/png;base64,${currentResult.base64}`;
|
|
2028
|
-
return /* @__PURE__ */
|
|
3381
|
+
return /* @__PURE__ */ jsxs18(
|
|
2029
3382
|
"div",
|
|
2030
3383
|
{
|
|
2031
3384
|
className: "fixed inset-0 bg-black z-50 flex items-center justify-center overflow-hidden touch-none",
|
|
@@ -2033,7 +3386,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2033
3386
|
onTouchMove: handleFsTouchMove,
|
|
2034
3387
|
onTouchEnd: handleFsTouchEnd,
|
|
2035
3388
|
children: [
|
|
2036
|
-
/* @__PURE__ */
|
|
3389
|
+
/* @__PURE__ */ jsx20(
|
|
2037
3390
|
"img",
|
|
2038
3391
|
{
|
|
2039
3392
|
src: fsBase64,
|
|
@@ -2050,76 +3403,76 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2050
3403
|
}
|
|
2051
3404
|
}
|
|
2052
3405
|
),
|
|
2053
|
-
/* @__PURE__ */
|
|
2054
|
-
zoomScale > 1 && /* @__PURE__ */
|
|
3406
|
+
/* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "close" }) }),
|
|
3407
|
+
zoomScale > 1 && /* @__PURE__ */ jsx20("button", { onClick: () => {
|
|
2055
3408
|
setZoomScale(1);
|
|
2056
3409
|
setZoomOffset({ x: 0, y: 0 });
|
|
2057
|
-
}, 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__ */
|
|
2058
|
-
history.length > 1 && /* @__PURE__ */
|
|
2059
|
-
/* @__PURE__ */
|
|
3410
|
+
}, 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__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "zoom_out_map" }) }),
|
|
3411
|
+
history.length > 1 && /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
3412
|
+
/* @__PURE__ */ jsx20("button", { onClick: () => {
|
|
2060
3413
|
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
2061
|
-
}, 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__ */
|
|
2062
|
-
/* @__PURE__ */
|
|
3414
|
+
}, 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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
|
|
3415
|
+
/* @__PURE__ */ jsx20("button", { onClick: () => {
|
|
2063
3416
|
if (currentIndex < history.length - 1) setCurrentResult(history[currentIndex + 1]);
|
|
2064
|
-
}, 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__ */
|
|
2065
|
-
/* @__PURE__ */
|
|
3417
|
+
}, 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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
|
|
3418
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
2066
3419
|
currentIndex + 1,
|
|
2067
3420
|
" / ",
|
|
2068
3421
|
history.length
|
|
2069
3422
|
] })
|
|
2070
3423
|
] }),
|
|
2071
|
-
zoomScale === 1 && /* @__PURE__ */
|
|
3424
|
+
zoomScale === 1 && /* @__PURE__ */ jsx20("div", { className: "absolute bottom-6 right-4 text-[9px] text-white/20 font-mono", children: "Pinch zum Zoomen \xB7 Doppeltipp 2.5\xD7" })
|
|
2072
3425
|
]
|
|
2073
3426
|
}
|
|
2074
3427
|
);
|
|
2075
3428
|
}
|
|
2076
3429
|
if (showStart) {
|
|
2077
|
-
return /* @__PURE__ */
|
|
2078
|
-
/* @__PURE__ */
|
|
3430
|
+
return /* @__PURE__ */ jsxs18("div", { className: "fixed inset-0 bg-[#0e0e0e] flex flex-col items-center justify-center p-6", style: { gap: 28, ...hcStyle }, children: [
|
|
3431
|
+
/* @__PURE__ */ jsx20("input", { ref: wsInputRef, type: "file", accept: ".zip", className: "hidden", onChange: (e) => {
|
|
2079
3432
|
const f = e.target.files?.[0];
|
|
2080
3433
|
if (f) handleProjectImport(f);
|
|
2081
3434
|
e.target.value = "";
|
|
2082
3435
|
} }),
|
|
2083
|
-
/* @__PURE__ */
|
|
2084
|
-
/* @__PURE__ */
|
|
2085
|
-
/* @__PURE__ */
|
|
2086
|
-
/* @__PURE__ */
|
|
3436
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-1", children: [
|
|
3437
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-white/15 text-[44px]", children: "palette" }),
|
|
3438
|
+
/* @__PURE__ */ jsx20("span", { className: "text-white/25 text-[10px] font-bold uppercase tracking-[0.25em]", children: "Avatar Architect" }),
|
|
3439
|
+
/* @__PURE__ */ jsxs18("span", { className: "text-white text-[13px] font-mono", children: [
|
|
2087
3440
|
"v",
|
|
2088
3441
|
LIB_VERSION
|
|
2089
3442
|
] })
|
|
2090
3443
|
] }),
|
|
2091
|
-
/* @__PURE__ */
|
|
3444
|
+
/* @__PURE__ */ jsxs18(
|
|
2092
3445
|
"button",
|
|
2093
3446
|
{
|
|
2094
3447
|
onClick: toggleContrast,
|
|
2095
3448
|
className: "flex items-center gap-3 px-5 py-3 rounded-2xl border transition-colors",
|
|
2096
3449
|
style: { borderColor: highContrast ? "rgba(255,255,255,0.3)" : "rgba(255,255,255,0.08)", background: highContrast ? "rgba(255,255,255,0.08)" : "transparent" },
|
|
2097
3450
|
children: [
|
|
2098
|
-
/* @__PURE__ */
|
|
2099
|
-
/* @__PURE__ */
|
|
2100
|
-
/* @__PURE__ */
|
|
2101
|
-
/* @__PURE__ */
|
|
3451
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.35)" }, children: highContrast ? "light_mode" : "dark_mode" }),
|
|
3452
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-start", children: [
|
|
3453
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[13px] font-bold", style: { color: highContrast ? "#fff" : "rgba(255,255,255,0.5)" }, children: highContrast ? "Hoher Kontrast" : "Normaler Kontrast" }),
|
|
3454
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[10px]", style: { color: "rgba(255,255,255,0.25)" }, children: "Tippen zum Umschalten" })
|
|
2102
3455
|
] })
|
|
2103
3456
|
]
|
|
2104
3457
|
}
|
|
2105
3458
|
),
|
|
2106
|
-
/* @__PURE__ */
|
|
2107
|
-
/* @__PURE__ */
|
|
3459
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
|
|
3460
|
+
/* @__PURE__ */ jsxs18(
|
|
2108
3461
|
"button",
|
|
2109
3462
|
{
|
|
2110
3463
|
onClick: () => wsInputRef.current?.click(),
|
|
2111
3464
|
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",
|
|
2112
3465
|
style: { height: 56, background: projectLoaded ? "#16a34a" : "#0284c7" },
|
|
2113
3466
|
children: [
|
|
2114
|
-
/* @__PURE__ */
|
|
3467
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: projectLoaded ? "check_circle" : "folder_zip" }),
|
|
2115
3468
|
projectLoaded ? "Projekt geladen \u2713" : "Projekt laden (.zip)"
|
|
2116
3469
|
]
|
|
2117
3470
|
}
|
|
2118
3471
|
),
|
|
2119
|
-
!projectLoaded && /* @__PURE__ */
|
|
3472
|
+
!projectLoaded && /* @__PURE__ */ jsx20("span", { className: "text-white/20 text-[10px] text-center", children: "Baum, Bilder und Einstellungen wiederherstellen" })
|
|
2120
3473
|
] }),
|
|
2121
|
-
onFetchServerProjects && /* @__PURE__ */
|
|
2122
|
-
/* @__PURE__ */
|
|
3474
|
+
onFetchServerProjects && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
|
|
3475
|
+
/* @__PURE__ */ jsxs18(
|
|
2123
3476
|
"button",
|
|
2124
3477
|
{
|
|
2125
3478
|
disabled: isLoadingFromServer,
|
|
@@ -2140,35 +3493,35 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2140
3493
|
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",
|
|
2141
3494
|
style: { height: 56, background: "#7c3aed" },
|
|
2142
3495
|
children: [
|
|
2143
|
-
/* @__PURE__ */
|
|
3496
|
+
/* @__PURE__ */ jsx20("span", { className: `material-symbols-outlined text-[22px]${isLoadingFromServer ? " animate-spin" : ""}`, children: isLoadingFromServer ? "sync" : "cloud_download" }),
|
|
2144
3497
|
isLoadingFromServer ? "Laden\u2026" : "Vom Server laden"
|
|
2145
3498
|
]
|
|
2146
3499
|
}
|
|
2147
3500
|
),
|
|
2148
|
-
/* @__PURE__ */
|
|
3501
|
+
/* @__PURE__ */ jsx20("span", { className: "text-white/20 text-[10px] text-center", children: "Letzten Stand vom Server wiederherstellen" })
|
|
2149
3502
|
] }),
|
|
2150
|
-
/* @__PURE__ */
|
|
2151
|
-
/* @__PURE__ */
|
|
2152
|
-
/* @__PURE__ */
|
|
3503
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 w-full max-w-[280px]", children: [
|
|
3504
|
+
/* @__PURE__ */ jsx20("span", { className: "text-white/25 text-[10px] uppercase tracking-widest font-bold", children: "Layout w\xE4hlen & starten" }),
|
|
3505
|
+
/* @__PURE__ */ jsx20("div", { className: "grid grid-cols-2 gap-2 w-full", children: [
|
|
2153
3506
|
{ id: "mobile", icon: "smartphone", label: "Mobile" },
|
|
2154
3507
|
{ id: "mobile-desktop", icon: "phonelink", label: "Mobile+" },
|
|
2155
3508
|
{ id: "desktop", icon: "desktop_windows", label: "Desktop" },
|
|
2156
3509
|
{ id: "tablet-landscape", icon: "tablet", label: "Landscape" }
|
|
2157
|
-
].map((opt) => /* @__PURE__ */
|
|
3510
|
+
].map((opt) => /* @__PURE__ */ jsxs18(
|
|
2158
3511
|
"button",
|
|
2159
3512
|
{
|
|
2160
3513
|
onClick: () => startApp(opt.id),
|
|
2161
3514
|
className: "flex flex-col items-center gap-2 py-4 rounded-2xl border transition-colors",
|
|
2162
3515
|
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" },
|
|
2163
3516
|
children: [
|
|
2164
|
-
/* @__PURE__ */
|
|
2165
|
-
/* @__PURE__ */
|
|
3517
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[24px]", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.icon }),
|
|
3518
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[11px] font-bold", style: { color: layoutChoice === opt.id ? "#fff" : "rgba(255,255,255,0.4)" }, children: opt.label })
|
|
2166
3519
|
]
|
|
2167
3520
|
},
|
|
2168
3521
|
opt.id
|
|
2169
3522
|
)) }),
|
|
2170
|
-
layoutChoice === "mobile-desktop" && /* @__PURE__ */
|
|
2171
|
-
layoutChoice === "tablet-landscape" && /* @__PURE__ */
|
|
3523
|
+
layoutChoice === "mobile-desktop" && /* @__PURE__ */ jsx20("span", { className: "text-white/20 text-[9px] text-center", children: "Mobil-Layout skaliert f\xFCr Desktop-Modus" }),
|
|
3524
|
+
layoutChoice === "tablet-landscape" && /* @__PURE__ */ jsx20("span", { className: "text-white/20 text-[9px] text-center", children: "2-Spalten-Layout f\xFCr Landscape-Tablet im Desktop-Mode" })
|
|
2172
3525
|
] })
|
|
2173
3526
|
] });
|
|
2174
3527
|
}
|
|
@@ -2177,28 +3530,46 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2177
3530
|
const mdScale = mdMode ? window.innerWidth / 430 : 1;
|
|
2178
3531
|
const mdW = mdMode ? 430 : void 0;
|
|
2179
3532
|
const mdH = mdMode ? Math.ceil(window.innerHeight / mdScale) : void 0;
|
|
2180
|
-
const mobileRoot = /* @__PURE__ */
|
|
3533
|
+
const mobileRoot = /* @__PURE__ */ jsxs18("div", { className: "flex flex-col bg-[#0e0e0e] text-white overflow-hidden", style: {
|
|
2181
3534
|
width: mdMode ? mdW : "100vw",
|
|
2182
3535
|
height: mdMode ? mdH : "100dvh",
|
|
2183
3536
|
transform: mdMode ? `scale(${mdScale})` : void 0,
|
|
2184
3537
|
transformOrigin: mdMode ? "top left" : void 0,
|
|
2185
3538
|
...hcStyle || {}
|
|
2186
3539
|
}, children: [
|
|
2187
|
-
mobileTab === "
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
3540
|
+
mobileTab === "labs" && /* @__PURE__ */ jsx20("div", { className: "flex flex-col flex-1 min-h-0", children: /* @__PURE__ */ jsx20(LabsTab, { services: labServices, onResult: (item) => {
|
|
3541
|
+
const frame = item.frames[0];
|
|
3542
|
+
if (frame?.base64) {
|
|
3543
|
+
setCurrentResult(frameToGeneration(frame, item));
|
|
3544
|
+
setMobileTab("stage");
|
|
3545
|
+
}
|
|
3546
|
+
} }) }),
|
|
3547
|
+
mobileTab === "tags" && workspaceTags && /* @__PURE__ */ jsx20("div", { className: "flex flex-col flex-1 min-h-0", children: /* @__PURE__ */ jsx20(
|
|
3548
|
+
TagManagerPanel,
|
|
3549
|
+
{
|
|
3550
|
+
workspaceTags,
|
|
3551
|
+
onTagCreate: handleTagCreate,
|
|
3552
|
+
onTagUpdate: handleTagUpdate,
|
|
3553
|
+
onTagDelete: handleTagDelete,
|
|
3554
|
+
onTagReorder: handleTagReorder,
|
|
3555
|
+
onTagMove: handleTagMove
|
|
3556
|
+
}
|
|
3557
|
+
) }),
|
|
3558
|
+
mobileTab === "stage" && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
3559
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-2 px-3 border-b border-white/5 bg-black/30 shrink-0", style: { height: 52 }, children: [
|
|
3560
|
+
/* @__PURE__ */ jsx20(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
|
|
3561
|
+
/* @__PURE__ */ jsx20(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" }] }),
|
|
3562
|
+
/* @__PURE__ */ jsx20("div", { className: "flex-1" }),
|
|
3563
|
+
activeReferenceThumbnail ? /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
|
|
3564
|
+
/* @__PURE__ */ jsx20("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
|
|
3565
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
|
|
3566
|
+
/* @__PURE__ */ jsx20("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 active:text-white/80 transition-colors", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
3567
|
+
] }) : /* @__PURE__ */ jsx20("button", { onClick: handleSelectReference, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "add_photo_alternate" }) }),
|
|
3568
|
+
/* @__PURE__ */ jsx20("button", { onClick: toggleContrast, className: "text-white/20 active:text-white/60 transition-colors mr-2", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: highContrast ? "light_mode" : "dark_mode" }) }),
|
|
3569
|
+
/* @__PURE__ */ jsx20("button", { onClick: () => setShowStart(true), className: "text-white/20 active:text-white/60 transition-colors mr-1", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "desktop_windows" }) })
|
|
2199
3570
|
] }),
|
|
2200
|
-
/* @__PURE__ */
|
|
2201
|
-
/* @__PURE__ */
|
|
3571
|
+
/* @__PURE__ */ jsx20("div", { className: "px-3 pt-3 pb-2 shrink-0", children: /* @__PURE__ */ jsxs18("div", { className: `relative rounded-xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
|
|
3572
|
+
/* @__PURE__ */ jsx20(
|
|
2202
3573
|
"textarea",
|
|
2203
3574
|
{
|
|
2204
3575
|
value: activePrompt,
|
|
@@ -2208,26 +3579,26 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2208
3579
|
placeholder: "Prompt eingeben..."
|
|
2209
3580
|
}
|
|
2210
3581
|
),
|
|
2211
|
-
activePrompt && !isSynthesizing && /* @__PURE__ */
|
|
3582
|
+
activePrompt && !isSynthesizing && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[18px]", children: "close" }) })
|
|
2212
3583
|
] }) }),
|
|
2213
|
-
/* @__PURE__ */
|
|
3584
|
+
/* @__PURE__ */ jsx20("div", { className: "px-3 pb-3 shrink-0", children: /* @__PURE__ */ jsx20(
|
|
2214
3585
|
"button",
|
|
2215
3586
|
{
|
|
2216
3587
|
onClick: () => handleGenerateImage(),
|
|
2217
3588
|
disabled: !activePrompt.trim() || isGenerating,
|
|
2218
3589
|
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",
|
|
2219
3590
|
style: { height: 48, background: activePrompt.trim() && !isGenerating ? "#0284c7" : void 0, border: "1px solid rgba(255,255,255,0.1)" },
|
|
2220
|
-
children: isGenerating ? /* @__PURE__ */
|
|
2221
|
-
/* @__PURE__ */
|
|
2222
|
-
/* @__PURE__ */
|
|
2223
|
-
] }) : /* @__PURE__ */
|
|
2224
|
-
/* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
3591
|
+
children: isGenerating ? /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
3592
|
+
/* @__PURE__ */ jsx20("div", { className: "w-4 h-4 border-t-2 border-white rounded-full animate-spin" }),
|
|
3593
|
+
/* @__PURE__ */ jsx20("span", { children: "Generiere..." })
|
|
3594
|
+
] }) : /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
3595
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "bolt" }),
|
|
3596
|
+
/* @__PURE__ */ jsx20("span", { children: "Generieren" })
|
|
2226
3597
|
] })
|
|
2227
3598
|
}
|
|
2228
3599
|
) }),
|
|
2229
|
-
/* @__PURE__ */
|
|
2230
|
-
/* @__PURE__ */
|
|
3600
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex-1 min-h-0 px-3 pb-3 flex flex-col", children: [
|
|
3601
|
+
/* @__PURE__ */ jsxs18(
|
|
2231
3602
|
"div",
|
|
2232
3603
|
{
|
|
2233
3604
|
className: "w-full rounded-2xl border border-white/5 bg-black/40 relative overflow-hidden flex items-center justify-center",
|
|
@@ -2241,25 +3612,25 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2241
3612
|
setTouchStartX(null);
|
|
2242
3613
|
},
|
|
2243
3614
|
children: [
|
|
2244
|
-
currentResult?.status === "processing" && /* @__PURE__ */
|
|
2245
|
-
/* @__PURE__ */
|
|
2246
|
-
/* @__PURE__ */
|
|
3615
|
+
currentResult?.status === "processing" && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-3", children: [
|
|
3616
|
+
/* @__PURE__ */ jsx20("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
|
|
3617
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[11px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
2247
3618
|
] }),
|
|
2248
|
-
currentResult?.status === "error" && /* @__PURE__ */
|
|
2249
|
-
/* @__PURE__ */
|
|
2250
|
-
/* @__PURE__ */
|
|
2251
|
-
/* @__PURE__ */
|
|
3619
|
+
currentResult?.status === "error" && /* @__PURE__ */ jsxs18("div", { className: "p-6 text-center flex flex-col items-center gap-3", children: [
|
|
3620
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-red-400 text-[36px]", children: "warning" }),
|
|
3621
|
+
/* @__PURE__ */ jsx20("p", { className: "text-white/50 text-[13px]", children: currentResult.error?.message }),
|
|
3622
|
+
/* @__PURE__ */ jsx20("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" })
|
|
2252
3623
|
] }),
|
|
2253
|
-
currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */
|
|
2254
|
-
!currentResult && /* @__PURE__ */
|
|
2255
|
-
/* @__PURE__ */
|
|
2256
|
-
/* @__PURE__ */
|
|
3624
|
+
currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ jsx20("img", { src: currentResult.base64, className: "w-full h-full object-contain" }),
|
|
3625
|
+
!currentResult && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
3626
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[64px]", children: "palette" }),
|
|
3627
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[11px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
2257
3628
|
] }),
|
|
2258
|
-
currentResult?.status === "done" && /* @__PURE__ */
|
|
2259
|
-
history.length > 1 && currentResult && /* @__PURE__ */
|
|
2260
|
-
/* @__PURE__ */
|
|
2261
|
-
/* @__PURE__ */
|
|
2262
|
-
/* @__PURE__ */
|
|
3629
|
+
currentResult?.status === "done" && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[18px]", children: "fullscreen" }) }),
|
|
3630
|
+
history.length > 1 && currentResult && /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
3631
|
+
/* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_left" }) }),
|
|
3632
|
+
/* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[22px]", children: "chevron_right" }) }),
|
|
3633
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
2263
3634
|
currentIndex + 1,
|
|
2264
3635
|
" / ",
|
|
2265
3636
|
history.length
|
|
@@ -2268,30 +3639,30 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2268
3639
|
]
|
|
2269
3640
|
}
|
|
2270
3641
|
),
|
|
2271
|
-
currentResult?.status === "done" && /* @__PURE__ */
|
|
2272
|
-
/* @__PURE__ */
|
|
2273
|
-
/* @__PURE__ */
|
|
2274
|
-
/* @__PURE__ */
|
|
3642
|
+
currentResult?.status === "done" && /* @__PURE__ */ jsxs18("div", { className: "flex gap-2 mt-3", children: [
|
|
3643
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3644
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "replay" }),
|
|
3645
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[12px] text-white/60", children: "Prompt" })
|
|
2275
3646
|
] }),
|
|
2276
|
-
/* @__PURE__ */
|
|
2277
|
-
/* @__PURE__ */
|
|
2278
|
-
/* @__PURE__ */
|
|
3647
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3648
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[18px] text-white/80", children: "auto_fix_high" }),
|
|
3649
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[12px] text-white/80 font-bold", children: "Referenz" })
|
|
2279
3650
|
] }),
|
|
2280
|
-
/* @__PURE__ */
|
|
2281
|
-
/* @__PURE__ */
|
|
2282
|
-
/* @__PURE__ */
|
|
3651
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3652
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "download" }),
|
|
3653
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[12px] text-white/60", children: "Laden" })
|
|
2283
3654
|
] })
|
|
2284
3655
|
] })
|
|
2285
3656
|
] })
|
|
2286
3657
|
] }),
|
|
2287
|
-
mobileTab === "browse" && /* @__PURE__ */
|
|
2288
|
-
/* @__PURE__ */
|
|
2289
|
-
/* @__PURE__ */
|
|
2290
|
-
activeTab === "history" && /* @__PURE__ */
|
|
3658
|
+
mobileTab === "browse" && /* @__PURE__ */ jsxs18("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
3659
|
+
/* @__PURE__ */ jsx20("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: ["history", "gallery", "inspect"].map((tab) => /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : "info" }) }, tab)) }),
|
|
3660
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
3661
|
+
activeTab === "history" && /* @__PURE__ */ jsx20(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: (g) => {
|
|
2291
3662
|
setCurrentResult(g);
|
|
2292
3663
|
setMobileTab("stage");
|
|
2293
3664
|
}, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
|
|
2294
|
-
activeTab === "gallery" && /* @__PURE__ */
|
|
3665
|
+
activeTab === "gallery" && /* @__PURE__ */ jsx20(
|
|
2295
3666
|
MediaLibrary,
|
|
2296
3667
|
{
|
|
2297
3668
|
items: galleryItems,
|
|
@@ -2311,38 +3682,39 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2311
3682
|
}
|
|
2312
3683
|
}
|
|
2313
3684
|
),
|
|
2314
|
-
activeTab === "inspect" && /* @__PURE__ */
|
|
3685
|
+
activeTab === "inspect" && /* @__PURE__ */ jsx20(InspectPanel, { currentResult, history, onSelect: (g) => {
|
|
2315
3686
|
setCurrentResult(g);
|
|
2316
3687
|
} })
|
|
2317
3688
|
] })
|
|
2318
3689
|
] }),
|
|
2319
|
-
mobileTab === "tools"
|
|
2320
|
-
/* @__PURE__ */
|
|
2321
|
-
workspaceTags && /* @__PURE__ */
|
|
3690
|
+
/* @__PURE__ */ jsxs18("div", { style: { display: mobileTab === "tools" ? "flex" : "none" }, className: "flex flex-col flex-1 min-h-0", children: [
|
|
3691
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex border-b border-white/5 shrink-0", style: { height: 52 }, children: [
|
|
3692
|
+
workspaceTags && /* @__PURE__ */ jsxs18("button", { onClick: () => {
|
|
2322
3693
|
setLeftTab("prompt");
|
|
2323
3694
|
if (activeTab === "setup" || activeTab === "sync") setActiveTab("history");
|
|
2324
3695
|
}, 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: [
|
|
2325
|
-
/* @__PURE__ */
|
|
3696
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "auto_fix_high" }),
|
|
2326
3697
|
"Prompt"
|
|
2327
3698
|
] }),
|
|
2328
|
-
/* @__PURE__ */
|
|
3699
|
+
/* @__PURE__ */ jsxs18("button", { onClick: () => {
|
|
2329
3700
|
setLeftTab("hierarchy");
|
|
2330
3701
|
if (activeTab === "setup" || activeTab === "sync") setActiveTab("history");
|
|
2331
3702
|
}, 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: [
|
|
2332
|
-
/* @__PURE__ */
|
|
3703
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "account_tree" }),
|
|
2333
3704
|
"Hierarchie"
|
|
2334
3705
|
] }),
|
|
2335
|
-
/* @__PURE__ */
|
|
2336
|
-
/* @__PURE__ */
|
|
3706
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3707
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "settings" }),
|
|
2337
3708
|
"Setup"
|
|
2338
3709
|
] }),
|
|
2339
|
-
/* @__PURE__ */
|
|
2340
|
-
/* @__PURE__ */
|
|
3710
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3711
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "cloud_sync" }),
|
|
2341
3712
|
"Sync"
|
|
2342
|
-
] })
|
|
3713
|
+
] }),
|
|
3714
|
+
workspaceTags && /* @__PURE__ */ jsx20("button", { onClick: () => setActiveTab("tags"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "tags" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "label" }) })
|
|
2343
3715
|
] }),
|
|
2344
|
-
/* @__PURE__ */
|
|
2345
|
-
leftTab === "hierarchy" && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */
|
|
3716
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
3717
|
+
leftTab === "hierarchy" && activeTab !== "setup" && activeTab !== "sync" && /* @__PURE__ */ jsx20("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx20(
|
|
2346
3718
|
ListView,
|
|
2347
3719
|
{
|
|
2348
3720
|
nodes,
|
|
@@ -2373,12 +3745,12 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2373
3745
|
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
2374
3746
|
}
|
|
2375
3747
|
) }),
|
|
2376
|
-
leftTab === "prompt" &&
|
|
3748
|
+
workspaceTags && /* @__PURE__ */ jsx20("div", { style: { display: leftTab === "prompt" && activeTab !== "setup" && activeTab !== "sync" ? "flex" : "none" }, className: "absolute inset-0 flex-col", children: /* @__PURE__ */ jsx20(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => {
|
|
2377
3749
|
handleGenerateImage(prompt);
|
|
2378
3750
|
setMobileTab("stage");
|
|
2379
|
-
}, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }),
|
|
2380
|
-
activeTab === "setup" && /* @__PURE__ */
|
|
2381
|
-
activeTab === "sync" && /* @__PURE__ */
|
|
3751
|
+
}, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }) }),
|
|
3752
|
+
activeTab === "setup" && /* @__PURE__ */ jsx20(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
|
|
3753
|
+
activeTab === "sync" && /* @__PURE__ */ jsx20(
|
|
2382
3754
|
ProjectSyncTab,
|
|
2383
3755
|
{
|
|
2384
3756
|
onProjectExport: handleProjectExport,
|
|
@@ -2393,20 +3765,33 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2393
3765
|
onComputeSyncDiff: onFetchServerProjects && onServerLoad && onServerSave ? handleComputeSyncDiff : void 0,
|
|
2394
3766
|
onExecuteSync: onFetchServerProjects && onServerLoad && onServerSave ? handleExecuteSync : void 0
|
|
2395
3767
|
}
|
|
3768
|
+
),
|
|
3769
|
+
activeTab === "tags" && workspaceTags && /* @__PURE__ */ jsx20(
|
|
3770
|
+
TagManagerPanel,
|
|
3771
|
+
{
|
|
3772
|
+
workspaceTags,
|
|
3773
|
+
onTagCreate: handleTagCreate,
|
|
3774
|
+
onTagUpdate: handleTagUpdate,
|
|
3775
|
+
onTagDelete: handleTagDelete,
|
|
3776
|
+
onTagReorder: handleTagReorder,
|
|
3777
|
+
onTagMove: handleTagMove
|
|
3778
|
+
}
|
|
2396
3779
|
)
|
|
2397
3780
|
] })
|
|
2398
3781
|
] }),
|
|
2399
|
-
/* @__PURE__ */
|
|
3782
|
+
/* @__PURE__ */ jsx20("div", { className: "flex border-t border-white/10 bg-black shrink-0", style: { height: 56, paddingBottom: "env(safe-area-inset-bottom, 0px)" }, children: [
|
|
2400
3783
|
{ id: "tools", icon: "auto_fix_high", label: "Prompt" },
|
|
2401
3784
|
{ id: "stage", icon: "palette", label: "Stage" },
|
|
3785
|
+
{ id: "labs", icon: "science", label: "Labs" },
|
|
3786
|
+
...workspaceTags ? [{ id: "tags", icon: "label", label: "Tags" }] : [],
|
|
2402
3787
|
{ id: "browse", icon: "photo_library", label: "Galerie" }
|
|
2403
|
-
].map((tab) => /* @__PURE__ */
|
|
2404
|
-
/* @__PURE__ */
|
|
2405
|
-
/* @__PURE__ */
|
|
3788
|
+
].map((tab) => /* @__PURE__ */ jsxs18("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: [
|
|
3789
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[24px]", children: tab.icon }),
|
|
3790
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[10px] font-bold uppercase tracking-wide", children: tab.label })
|
|
2406
3791
|
] }, tab.id)) })
|
|
2407
3792
|
] });
|
|
2408
3793
|
if (mdMode) {
|
|
2409
|
-
return /* @__PURE__ */
|
|
3794
|
+
return /* @__PURE__ */ jsx20("div", { style: { position: "fixed", inset: 0, overflow: "hidden", background: "#0e0e0e" }, children: mobileRoot });
|
|
2410
3795
|
}
|
|
2411
3796
|
return mobileRoot;
|
|
2412
3797
|
}
|
|
@@ -2414,17 +3799,17 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2414
3799
|
const tlScale = Math.min(window.innerWidth / 920, window.innerHeight / 520);
|
|
2415
3800
|
const tlW = 920;
|
|
2416
3801
|
const tlH = 520;
|
|
2417
|
-
return /* @__PURE__ */
|
|
2418
|
-
/* @__PURE__ */
|
|
2419
|
-
/* @__PURE__ */
|
|
2420
|
-
/* @__PURE__ */
|
|
2421
|
-
/* @__PURE__ */
|
|
2422
|
-
/* @__PURE__ */
|
|
2423
|
-
/* @__PURE__ */
|
|
2424
|
-
/* @__PURE__ */
|
|
3802
|
+
return /* @__PURE__ */ jsx20("div", { style: { position: "fixed", inset: 0, background: "#0e0e0e", display: "flex", alignItems: "center", justifyContent: "center", overflow: "hidden", ...hcStyle || {} }, children: /* @__PURE__ */ jsxs18("div", { style: { width: tlW, height: tlH, transform: `scale(${tlScale})`, transformOrigin: "center center", display: "flex", flexDirection: "row", color: "#fff", overflow: "hidden", borderRadius: 0 }, children: [
|
|
3803
|
+
/* @__PURE__ */ jsxs18("div", { style: { width: 320, height: tlH, display: "flex", flexDirection: "column", borderRight: "1px solid rgba(255,255,255,0.05)", background: "#000", flexShrink: 0 }, children: [
|
|
3804
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3805
|
+
/* @__PURE__ */ jsx20(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
|
|
3806
|
+
/* @__PURE__ */ jsx20(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" }] }),
|
|
3807
|
+
/* @__PURE__ */ jsx20("div", { style: { flex: 1 } }),
|
|
3808
|
+
/* @__PURE__ */ jsx20("button", { onClick: toggleContrast, style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: highContrast ? "light_mode" : "dark_mode" }) }),
|
|
3809
|
+
/* @__PURE__ */ jsx20("button", { onClick: () => setShowStart(true), style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "apps" }) })
|
|
2425
3810
|
] }),
|
|
2426
|
-
/* @__PURE__ */
|
|
2427
|
-
/* @__PURE__ */
|
|
3811
|
+
/* @__PURE__ */ jsx20("div", { style: { padding: "12px 12px 8px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs18("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: [
|
|
3812
|
+
/* @__PURE__ */ jsx20(
|
|
2428
3813
|
"textarea",
|
|
2429
3814
|
{
|
|
2430
3815
|
value: activePrompt,
|
|
@@ -2433,27 +3818,27 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2433
3818
|
placeholder: "Prompt eingeben..."
|
|
2434
3819
|
}
|
|
2435
3820
|
),
|
|
2436
|
-
activePrompt && /* @__PURE__ */
|
|
3821
|
+
activePrompt && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 15 }, children: "close" }) })
|
|
2437
3822
|
] }) }),
|
|
2438
|
-
/* @__PURE__ */
|
|
3823
|
+
/* @__PURE__ */ jsx20("div", { style: { padding: "0 12px 10px", flexShrink: 0 }, children: /* @__PURE__ */ jsx20(
|
|
2439
3824
|
"button",
|
|
2440
3825
|
{
|
|
2441
3826
|
onClick: () => handleGenerateImage(),
|
|
2442
3827
|
disabled: !activePrompt.trim() || isGenerating,
|
|
2443
3828
|
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" },
|
|
2444
|
-
children: isGenerating ? /* @__PURE__ */
|
|
2445
|
-
/* @__PURE__ */
|
|
2446
|
-
/* @__PURE__ */
|
|
2447
|
-
] }) : /* @__PURE__ */
|
|
2448
|
-
/* @__PURE__ */
|
|
2449
|
-
/* @__PURE__ */
|
|
3829
|
+
children: isGenerating ? /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
3830
|
+
/* @__PURE__ */ jsx20("div", { style: { width: 14, height: 14, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
|
|
3831
|
+
/* @__PURE__ */ jsx20("span", { children: "Generiere..." })
|
|
3832
|
+
] }) : /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
3833
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "bolt" }),
|
|
3834
|
+
/* @__PURE__ */ jsx20("span", { children: "Generieren" })
|
|
2450
3835
|
] })
|
|
2451
3836
|
}
|
|
2452
3837
|
) }),
|
|
2453
|
-
/* @__PURE__ */
|
|
3838
|
+
/* @__PURE__ */ jsx20("div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ jsx20(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }) })
|
|
2454
3839
|
] }),
|
|
2455
|
-
/* @__PURE__ */
|
|
2456
|
-
/* @__PURE__ */
|
|
3840
|
+
/* @__PURE__ */ jsxs18("div", { style: { flex: 1, height: tlH, display: "flex", flexDirection: "column", background: "#0b0b0b" }, children: [
|
|
3841
|
+
/* @__PURE__ */ jsx20(
|
|
2457
3842
|
"div",
|
|
2458
3843
|
{
|
|
2459
3844
|
style: { flex: 1, padding: 16, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" },
|
|
@@ -2465,26 +3850,26 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2465
3850
|
else if (dx > 50) goToPrev();
|
|
2466
3851
|
setTouchStartX(null);
|
|
2467
3852
|
},
|
|
2468
|
-
children: /* @__PURE__ */
|
|
2469
|
-
currentResult?.status === "processing" && /* @__PURE__ */
|
|
2470
|
-
/* @__PURE__ */
|
|
2471
|
-
/* @__PURE__ */
|
|
3853
|
+
children: /* @__PURE__ */ jsxs18("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: [
|
|
3854
|
+
currentResult?.status === "processing" && /* @__PURE__ */ jsxs18("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
|
|
3855
|
+
/* @__PURE__ */ jsx20("div", { style: { width: 36, height: 36, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
|
|
3856
|
+
/* @__PURE__ */ jsx20("span", { style: { fontSize: 10, color: "rgba(255,255,255,0.4)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
|
|
2472
3857
|
] }),
|
|
2473
|
-
currentResult?.status === "error" && /* @__PURE__ */
|
|
2474
|
-
/* @__PURE__ */
|
|
2475
|
-
/* @__PURE__ */
|
|
2476
|
-
/* @__PURE__ */
|
|
3858
|
+
currentResult?.status === "error" && /* @__PURE__ */ jsxs18("div", { style: { padding: 24, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
|
|
3859
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 32, color: "#f87171" }, children: "warning" }),
|
|
3860
|
+
/* @__PURE__ */ jsx20("p", { style: { fontSize: 11, color: "rgba(255,255,255,0.5)", margin: 0 }, children: currentResult.error?.message }),
|
|
3861
|
+
/* @__PURE__ */ jsx20("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" })
|
|
2477
3862
|
] }),
|
|
2478
|
-
currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */
|
|
2479
|
-
!currentResult && /* @__PURE__ */
|
|
2480
|
-
/* @__PURE__ */
|
|
2481
|
-
/* @__PURE__ */
|
|
3863
|
+
currentResult?.status === "done" && currentResult.base64 && /* @__PURE__ */ jsx20("img", { src: currentResult.base64, style: { maxWidth: "100%", maxHeight: "100%", objectFit: "contain" } }),
|
|
3864
|
+
!currentResult && /* @__PURE__ */ jsxs18("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 8, opacity: 0.1 }, children: [
|
|
3865
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 64 }, children: "palette" }),
|
|
3866
|
+
/* @__PURE__ */ jsx20("span", { style: { fontSize: 11, fontWeight: "bold", textTransform: "uppercase", letterSpacing: "0.2em" }, children: "Avatar Architect" })
|
|
2482
3867
|
] }),
|
|
2483
|
-
currentResult?.status === "done" && /* @__PURE__ */
|
|
2484
|
-
history.length > 1 && currentResult && /* @__PURE__ */
|
|
2485
|
-
/* @__PURE__ */
|
|
2486
|
-
/* @__PURE__ */
|
|
2487
|
-
/* @__PURE__ */
|
|
3868
|
+
currentResult?.status === "done" && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "fullscreen" }) }),
|
|
3869
|
+
history.length > 1 && currentResult && /* @__PURE__ */ jsxs18(Fragment9, { children: [
|
|
3870
|
+
/* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_left" }) }),
|
|
3871
|
+
/* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 20 }, children: "chevron_right" }) }),
|
|
3872
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
2488
3873
|
currentIndex + 1,
|
|
2489
3874
|
" / ",
|
|
2490
3875
|
history.length
|
|
@@ -2493,41 +3878,57 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2493
3878
|
] })
|
|
2494
3879
|
}
|
|
2495
3880
|
),
|
|
2496
|
-
currentResult?.status === "done" && /* @__PURE__ */
|
|
2497
|
-
/* @__PURE__ */
|
|
2498
|
-
/* @__PURE__ */
|
|
2499
|
-
/* @__PURE__ */
|
|
3881
|
+
currentResult?.status === "done" && /* @__PURE__ */ jsxs18("div", { style: { padding: "0 16px 16px", display: "flex", gap: 8, flexShrink: 0 }, children: [
|
|
3882
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3883
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "replay" }),
|
|
3884
|
+
/* @__PURE__ */ jsx20("span", { children: "Prompt" })
|
|
2500
3885
|
] }),
|
|
2501
|
-
/* @__PURE__ */
|
|
2502
|
-
/* @__PURE__ */
|
|
2503
|
-
/* @__PURE__ */
|
|
3886
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3887
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "auto_fix_high" }),
|
|
3888
|
+
/* @__PURE__ */ jsx20("span", { children: "Referenz" })
|
|
2504
3889
|
] }),
|
|
2505
|
-
/* @__PURE__ */
|
|
2506
|
-
/* @__PURE__ */
|
|
2507
|
-
/* @__PURE__ */
|
|
3890
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3891
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "download" }),
|
|
3892
|
+
/* @__PURE__ */ jsx20("span", { children: "Laden" })
|
|
2508
3893
|
] })
|
|
2509
3894
|
] })
|
|
2510
3895
|
] })
|
|
2511
3896
|
] }) });
|
|
2512
3897
|
}
|
|
2513
|
-
return /* @__PURE__ */
|
|
2514
|
-
/* @__PURE__ */
|
|
2515
|
-
/* @__PURE__ */
|
|
2516
|
-
/* @__PURE__ */
|
|
2517
|
-
!isLeftCollapsed && /* @__PURE__ */
|
|
2518
|
-
workspaceTags && /* @__PURE__ */
|
|
2519
|
-
/* @__PURE__ */
|
|
3898
|
+
return /* @__PURE__ */ jsxs18("div", { className: "flex h-screen w-screen bg-[#0e0e0e] text-white overflow-hidden", style: hcStyle, children: [
|
|
3899
|
+
/* @__PURE__ */ jsx20("div", { className: "absolute top-2 right-2 z-50", children: /* @__PURE__ */ jsx20("button", { onClick: () => setShowStart(true), className: "text-white/10 hover:text-white/30 transition-colors text-[10px]", children: "\u21C4" }) }),
|
|
3900
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col border-r border-white/5 overflow-hidden relative bg-black/10 shrink-0", style: { width: isLeftCollapsed ? 48 : leftPanelWidth, transition: "none" }, children: [
|
|
3901
|
+
/* @__PURE__ */ jsxs18("div", { className: "h-14 border-b border-white/5 flex items-center justify-between shrink-0 px-1", children: [
|
|
3902
|
+
!isLeftCollapsed && /* @__PURE__ */ jsxs18("div", { className: "flex flex-1 gap-1", children: [
|
|
3903
|
+
workspaceTags && /* @__PURE__ */ jsxs18("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: [
|
|
3904
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "auto_fix_high" }),
|
|
2520
3905
|
"Prompt"
|
|
2521
3906
|
] }),
|
|
2522
|
-
/* @__PURE__ */
|
|
2523
|
-
/* @__PURE__ */
|
|
3907
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
3908
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "account_tree" }),
|
|
2524
3909
|
"Hierarchie"
|
|
2525
|
-
] })
|
|
3910
|
+
] }),
|
|
3911
|
+
workspaceTags && /* @__PURE__ */ jsx20("button", { onClick: () => setActiveTab("tags"), className: `flex-1 flex items-center justify-center gap-1.5 text-[11px] font-bold uppercase tracking-wide transition-colors ${activeTab === "tags" ? "text-white border-b-2 border-white" : "text-white/30"}`, children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: "label" }) })
|
|
2526
3912
|
] }),
|
|
2527
|
-
/* @__PURE__ */
|
|
3913
|
+
/* @__PURE__ */ jsx20("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" })
|
|
2528
3914
|
] }),
|
|
2529
|
-
!isLeftCollapsed && /* @__PURE__ */
|
|
2530
|
-
|
|
3915
|
+
!isLeftCollapsed && /* @__PURE__ */ jsxs18("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
3916
|
+
activeTab === "tags" && workspaceTags && /* @__PURE__ */ jsx20(
|
|
3917
|
+
TagManagerPanel,
|
|
3918
|
+
{
|
|
3919
|
+
workspaceTags,
|
|
3920
|
+
onTagCreate: handleTagCreate,
|
|
3921
|
+
onTagUpdate: handleTagUpdate,
|
|
3922
|
+
onTagDelete: handleTagDelete,
|
|
3923
|
+
onTagReorder: handleTagReorder,
|
|
3924
|
+
onTagMove: handleTagMove
|
|
3925
|
+
}
|
|
3926
|
+
),
|
|
3927
|
+
activeTab === "tags" && !workspaceTags && /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-center h-full p-8 text-center", children: /* @__PURE__ */ jsxs18("div", { children: [
|
|
3928
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[40px] text-white/10 block mb-3", children: "label_off" }),
|
|
3929
|
+
/* @__PURE__ */ jsx20("p", { className: "text-[11px] text-white/20", children: "Erst Workspace importieren um Tags zu verwalten." })
|
|
3930
|
+
] }) }),
|
|
3931
|
+
leftTab === "hierarchy" && activeTab !== "tags" && /* @__PURE__ */ jsx20("div", { className: "absolute inset-0", children: /* @__PURE__ */ jsx20(
|
|
2531
3932
|
ListView,
|
|
2532
3933
|
{
|
|
2533
3934
|
nodes,
|
|
@@ -2552,73 +3953,111 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2552
3953
|
isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
|
|
2553
3954
|
}
|
|
2554
3955
|
) }),
|
|
2555
|
-
leftTab === "prompt" && workspaceTags && /* @__PURE__ */
|
|
3956
|
+
leftTab === "prompt" && workspaceTags && activeTab !== "tags" && /* @__PURE__ */ jsx20(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => handleGenerateImage(prompt), onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage })
|
|
2556
3957
|
] })
|
|
2557
3958
|
] }),
|
|
2558
|
-
/* @__PURE__ */
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
/* @__PURE__ */
|
|
3959
|
+
!isLeftCollapsed && /* @__PURE__ */ jsx20("div", { onMouseDown: startLeftResize, className: "w-1 shrink-0 cursor-col-resize hover:bg-white/20 active:bg-white/30 transition-colors", style: { background: "transparent" } }),
|
|
3960
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex-1 flex flex-col bg-[#0b0b0b] overflow-hidden", children: [
|
|
3961
|
+
/* @__PURE__ */ jsxs18("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
|
|
3962
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-1.5", children: [
|
|
3963
|
+
/* @__PURE__ */ jsx20(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
|
|
3964
|
+
/* @__PURE__ */ jsx20(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" }] })
|
|
2563
3965
|
] }),
|
|
2564
|
-
/* @__PURE__ */
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
3966
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-1 mx-auto", children: [
|
|
3967
|
+
/* @__PURE__ */ jsx20(
|
|
3968
|
+
"button",
|
|
3969
|
+
{
|
|
3970
|
+
onClick: () => setMiddlePanel("stage"),
|
|
3971
|
+
className: `px-3 h-7 rounded-lg text-[9px] font-bold uppercase tracking-wide transition-colors ${middlePanel === "stage" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/50"}`,
|
|
3972
|
+
children: "Stage"
|
|
3973
|
+
}
|
|
3974
|
+
),
|
|
3975
|
+
/* @__PURE__ */ jsx20(
|
|
3976
|
+
"button",
|
|
3977
|
+
{
|
|
3978
|
+
onClick: () => setMiddlePanel("labs"),
|
|
3979
|
+
className: `px-3 h-7 rounded-lg text-[9px] font-bold uppercase tracking-wide transition-colors ${middlePanel === "labs" ? "bg-white/10 text-white" : "text-white/30 hover:text-white/50"}`,
|
|
3980
|
+
children: "Labs"
|
|
3981
|
+
}
|
|
3982
|
+
)
|
|
3983
|
+
] }),
|
|
3984
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-2", children: [
|
|
3985
|
+
activeReferenceThumbnail ? /* @__PURE__ */ jsxs18("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden", style: { height: 28 }, children: [
|
|
3986
|
+
/* @__PURE__ */ jsx20("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
|
|
3987
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
|
|
3988
|
+
/* @__PURE__ */ jsx20("button", { onClick: clearReference, className: "w-6 h-full flex items-center justify-center text-white/30 hover:text-white/80 transition-colors", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
3989
|
+
] }) : /* @__PURE__ */ jsxs18("button", { onClick: handleSelectReference, className: "flex items-center gap-1 h-7 px-2 rounded-lg border border-white/10 text-white/30 hover:text-white/60 hover:border-white/20 transition-colors text-[10px] font-bold uppercase tracking-wide", children: [
|
|
3990
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "add_photo_alternate" }),
|
|
3991
|
+
/* @__PURE__ */ jsx20("span", { children: "Ref" })
|
|
2572
3992
|
] }),
|
|
2573
|
-
/* @__PURE__ */
|
|
2574
|
-
/* @__PURE__ */
|
|
3993
|
+
/* @__PURE__ */ jsx20("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
|
|
3994
|
+
/* @__PURE__ */ jsx20(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
|
|
2575
3995
|
] })
|
|
2576
3996
|
] }),
|
|
2577
|
-
/* @__PURE__ */
|
|
2578
|
-
!isPromptCollapsed && /* @__PURE__ */
|
|
2579
|
-
/* @__PURE__ */
|
|
2580
|
-
activePrompt && !isSynthesizing && /* @__PURE__ */
|
|
3997
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
|
|
3998
|
+
!isPromptCollapsed && /* @__PURE__ */ jsx20("div", { className: "px-6 py-4 border-b border-white/5 bg-black/10 overflow-hidden shrink-0", children: /* @__PURE__ */ jsxs18("div", { className: `relative min-h-[60px] p-4 rounded-2xl border transition-all ${isSynthesizing ? "prompt-loading" : "bg-white/5 border-white/10"}`, children: [
|
|
3999
|
+
/* @__PURE__ */ jsx20("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..." }),
|
|
4000
|
+
activePrompt && !isSynthesizing && /* @__PURE__ */ jsx20("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__ */ jsx20("span", { className: "material-symbols-outlined text-[14px]", children: "close" }) })
|
|
2581
4001
|
] }) }),
|
|
2582
|
-
/* @__PURE__ */
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
4002
|
+
middlePanel === "labs" ? /* @__PURE__ */ jsx20("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx20(LabsTab, { services: labServices, onResult: (item) => {
|
|
4003
|
+
const frame = item.frames[0];
|
|
4004
|
+
if (frame?.base64) setCurrentResult(frameToGeneration(frame, item));
|
|
4005
|
+
} }) }) : /* @__PURE__ */ jsx20("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsxs18("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: [
|
|
4006
|
+
isGenerating && currentResult?.status === "done" && /* @__PURE__ */ jsxs18("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: [
|
|
4007
|
+
/* @__PURE__ */ jsx20("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
|
|
4008
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
|
|
2586
4009
|
] }),
|
|
2587
|
-
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */
|
|
2588
|
-
/* @__PURE__ */
|
|
2589
|
-
/* @__PURE__ */
|
|
2590
|
-
] }) : currentResult.status === "error" ? /* @__PURE__ */
|
|
2591
|
-
/* @__PURE__ */
|
|
2592
|
-
/* @__PURE__ */
|
|
2593
|
-
/* @__PURE__ */
|
|
2594
|
-
/* @__PURE__ */
|
|
4010
|
+
currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-4", children: [
|
|
4011
|
+
/* @__PURE__ */ jsx20("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
|
|
4012
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
|
|
4013
|
+
] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs18("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
|
|
4014
|
+
/* @__PURE__ */ jsx20("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
|
|
4015
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col gap-2", children: [
|
|
4016
|
+
/* @__PURE__ */ jsx20("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
|
|
4017
|
+
/* @__PURE__ */ jsx20("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
|
|
2595
4018
|
] }),
|
|
2596
|
-
/* @__PURE__ */
|
|
2597
|
-
] }) : /* @__PURE__ */
|
|
2598
|
-
/* @__PURE__ */
|
|
2599
|
-
/* @__PURE__ */
|
|
2600
|
-
/* @__PURE__ */
|
|
2601
|
-
/* @__PURE__ */
|
|
2602
|
-
/* @__PURE__ */
|
|
4019
|
+
/* @__PURE__ */ jsx20(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
|
|
4020
|
+
] }) : /* @__PURE__ */ jsxs18("div", { className: "h-full w-full relative flex items-center justify-center", children: [
|
|
4021
|
+
/* @__PURE__ */ jsx20("img", { src: currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
|
|
4022
|
+
/* @__PURE__ */ jsxs18("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: [
|
|
4023
|
+
/* @__PURE__ */ jsx20(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
|
|
4024
|
+
/* @__PURE__ */ jsx20(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
|
|
4025
|
+
/* @__PURE__ */ jsx20(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
|
|
2603
4026
|
] })
|
|
2604
|
-
] }) : /* @__PURE__ */
|
|
2605
|
-
/* @__PURE__ */
|
|
2606
|
-
/* @__PURE__ */
|
|
4027
|
+
] }) : /* @__PURE__ */ jsxs18("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
|
|
4028
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
|
|
4029
|
+
/* @__PURE__ */ jsx20("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
|
|
2607
4030
|
] })
|
|
2608
4031
|
] }) })
|
|
2609
4032
|
] })
|
|
2610
4033
|
] }),
|
|
2611
|
-
/* @__PURE__ */
|
|
2612
|
-
|
|
2613
|
-
|
|
4034
|
+
!isRightCollapsed && /* @__PURE__ */ jsx20("div", { onMouseDown: startRightResize, className: "w-1 shrink-0 cursor-col-resize hover:bg-white/20 active:bg-white/30 transition-colors", style: { background: "transparent" } }),
|
|
4035
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex flex-col border-l border-white/5 bg-[#0e0e0e] shrink-0", style: { width: isRightCollapsed ? 60 : rightPanelWidth, transition: "none" }, children: [
|
|
4036
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex border-b border-white/5 h-14 shrink-0 overflow-hidden", children: [
|
|
4037
|
+
/* @__PURE__ */ jsx20("div", { className: "flex flex-1", children: ["history", "gallery", "inspect", "setup", "sync", "tags"].map((tab) => /* @__PURE__ */ jsx20("button", { onClick: () => {
|
|
2614
4038
|
setActiveTab(tab);
|
|
2615
4039
|
setIsRightCollapsed(false);
|
|
2616
|
-
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */
|
|
2617
|
-
/* @__PURE__ */
|
|
4040
|
+
}, className: `flex-1 flex items-center justify-center relative transition-colors ${activeTab === tab ? "text-white" : "text-white/20"}`, children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[20px]", children: tab === "history" ? "history" : tab === "gallery" ? "photo_library" : tab === "inspect" ? "info" : tab === "setup" ? "settings" : tab === "sync" ? "cloud_sync" : "label" }) }, tab)) }),
|
|
4041
|
+
/* @__PURE__ */ jsx20("button", { onClick: () => setIsRightCollapsed(!isRightCollapsed), className: "w-10 flex items-center justify-center text-white/20 hover:text-white", children: /* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[18px]", children: isRightCollapsed ? "chevron_left" : "chevron_right" }) })
|
|
2618
4042
|
] }),
|
|
2619
|
-
!isRightCollapsed && /* @__PURE__ */
|
|
2620
|
-
activeTab === "
|
|
2621
|
-
|
|
4043
|
+
!isRightCollapsed && /* @__PURE__ */ jsxs18("div", { className: "flex-1 overflow-hidden relative", children: [
|
|
4044
|
+
activeTab === "tags" && workspaceTags && /* @__PURE__ */ jsx20(
|
|
4045
|
+
TagManagerPanel,
|
|
4046
|
+
{
|
|
4047
|
+
workspaceTags,
|
|
4048
|
+
onTagCreate: handleTagCreate,
|
|
4049
|
+
onTagUpdate: handleTagUpdate,
|
|
4050
|
+
onTagDelete: handleTagDelete,
|
|
4051
|
+
onTagReorder: handleTagReorder,
|
|
4052
|
+
onTagMove: handleTagMove
|
|
4053
|
+
}
|
|
4054
|
+
),
|
|
4055
|
+
activeTab === "tags" && !workspaceTags && /* @__PURE__ */ jsx20("div", { className: "flex items-center justify-center h-full p-8 text-center", children: /* @__PURE__ */ jsxs18("div", { children: [
|
|
4056
|
+
/* @__PURE__ */ jsx20("span", { className: "material-symbols-outlined text-[40px] text-white/10 block mb-3", children: "label_off" }),
|
|
4057
|
+
/* @__PURE__ */ jsx20("p", { className: "text-[11px] text-white/20", children: "Erst Workspace importieren um Tags zu verwalten." })
|
|
4058
|
+
] }) }),
|
|
4059
|
+
activeTab === "history" && /* @__PURE__ */ jsx20(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: setCurrentResult, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
|
|
4060
|
+
activeTab === "gallery" && /* @__PURE__ */ jsx20(
|
|
2622
4061
|
MediaLibrary,
|
|
2623
4062
|
{
|
|
2624
4063
|
items: galleryItems,
|
|
@@ -2632,9 +4071,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2632
4071
|
onGenerateReference: (item) => handleGenerateImage(item.prompt || activePrompt, item.mediaId, void 0, { silent: true })
|
|
2633
4072
|
}
|
|
2634
4073
|
),
|
|
2635
|
-
activeTab === "inspect" && /* @__PURE__ */
|
|
2636
|
-
activeTab === "setup" && /* @__PURE__ */
|
|
2637
|
-
activeTab === "sync" && /* @__PURE__ */
|
|
4074
|
+
activeTab === "inspect" && /* @__PURE__ */ jsx20(InspectPanel, { currentResult, history, onSelect: setCurrentResult }),
|
|
4075
|
+
activeTab === "setup" && /* @__PURE__ */ jsx20(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
|
|
4076
|
+
activeTab === "sync" && /* @__PURE__ */ jsx20(
|
|
2638
4077
|
ProjectSyncTab,
|
|
2639
4078
|
{
|
|
2640
4079
|
onProjectExport: handleProjectExport,
|
|
@@ -2656,7 +4095,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
2656
4095
|
}
|
|
2657
4096
|
|
|
2658
4097
|
// src/index.ts
|
|
2659
|
-
var LIB_VERSION = "1.1
|
|
4098
|
+
var LIB_VERSION = "1.2.1";
|
|
2660
4099
|
export {
|
|
2661
4100
|
AvatarArchitectApp,
|
|
2662
4101
|
CollapsibleCard,
|
|
@@ -2666,6 +4105,12 @@ export {
|
|
|
2666
4105
|
HistoryPanel,
|
|
2667
4106
|
InspectPanel,
|
|
2668
4107
|
LIB_VERSION,
|
|
4108
|
+
LabBlend,
|
|
4109
|
+
LabCompare,
|
|
4110
|
+
LabImagePicker,
|
|
4111
|
+
LabLoop,
|
|
4112
|
+
LabRemix,
|
|
4113
|
+
LabsTab,
|
|
2669
4114
|
ListView,
|
|
2670
4115
|
MediaLibrary,
|
|
2671
4116
|
PillButton,
|
|
@@ -2673,15 +4118,25 @@ export {
|
|
|
2673
4118
|
PromptTab,
|
|
2674
4119
|
SectionLabel,
|
|
2675
4120
|
SetupPanel,
|
|
4121
|
+
TagManagerPanel,
|
|
4122
|
+
autoLabel,
|
|
4123
|
+
buildBlendInstruction,
|
|
4124
|
+
buildCompareInstruction,
|
|
2676
4125
|
buildFallbackPrompt,
|
|
2677
4126
|
buildGenerationPrompt,
|
|
2678
4127
|
buildImageGenerationOptions,
|
|
4128
|
+
buildLoopInstruction,
|
|
2679
4129
|
buildPromptTabPayload,
|
|
4130
|
+
buildReferenceImageMediaIds,
|
|
4131
|
+
buildRemixInstruction,
|
|
4132
|
+
buildScanInstruction,
|
|
2680
4133
|
cleanAiResponse,
|
|
2681
4134
|
createFlowServices,
|
|
2682
4135
|
exportProjectToZip,
|
|
2683
4136
|
formatTreeToMarkdown,
|
|
4137
|
+
frameToGeneration,
|
|
2684
4138
|
getFormattedTimestamp,
|
|
4139
|
+
groupGenerationsToLabItems,
|
|
2685
4140
|
importProjectFromZip,
|
|
2686
4141
|
injectXMPMetadata,
|
|
2687
4142
|
interpretSdkError,
|