@rslsp1/fa-app-tools 2.0.56 → 2.0.61

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.mjs CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  setHFToken,
22
22
  tsFromEventPath,
23
23
  writeHFEvent
24
- } from "./chunk-TTJTQP43.mjs";
24
+ } from "./chunk-VVLKEBHL.mjs";
25
25
 
26
26
  // src/hooks/useOnClickOutside.ts
27
27
  import { useEffect } from "react";
@@ -353,10 +353,8 @@ var CompactDropdown = ({
353
353
  };
354
354
 
355
355
  // src/components/HistoryPanel.tsx
356
- import { useState as useState2 } from "react";
357
356
  import { motion } from "motion/react";
358
357
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
359
- var PAGE_SIZE = 20;
360
358
  var formatFriendlyTimestamp = (timestamp) => {
361
359
  const date = new Date(timestamp);
362
360
  const now = /* @__PURE__ */ new Date();
@@ -368,8 +366,7 @@ var formatFriendlyTimestamp = (timestamp) => {
368
366
  if (date.toDateString() === yesterday.toDateString()) return `Gestern, ${timeStr}`;
369
367
  return `${date.toLocaleDateString([], { day: "2-digit", month: "2-digit" })}, ${timeStr}`;
370
368
  };
371
- var HistoryPanel = ({ history, currentResultId, onSelect, onDelete }) => {
372
- const [visibleCount, setVisibleCount] = useState2(PAGE_SIZE);
369
+ var HistoryPanel = ({ history, currentResultId, onSelect, onDelete, visibleCount, onLoadMore }) => {
373
370
  const visibleHistory = history.slice(0, visibleCount);
374
371
  if (history.length === 0) {
375
372
  return /* @__PURE__ */ jsxs3("div", { className: "flex flex-col items-center justify-center py-20 text-center gap-4 opacity-10", children: [
@@ -413,7 +410,7 @@ var HistoryPanel = ({ history, currentResultId, onSelect, onDelete }) => {
413
410
  },
414
411
  gen.id
415
412
  )),
416
- visibleCount < history.length && /* @__PURE__ */ jsxs3("button", { type: "button", onClick: () => setVisibleCount((c) => c + PAGE_SIZE), className: "w-full py-2 bg-white/5 hover:bg-white/10 border border-white/10 rounded-xl text-[10px] font-bold uppercase text-white/60 hover:text-white transition-all", children: [
413
+ visibleCount < history.length && /* @__PURE__ */ jsxs3("button", { type: "button", onClick: onLoadMore, className: "w-full py-2 bg-white/5 hover:bg-white/10 border border-white/10 rounded-xl text-[10px] font-bold uppercase text-white/60 hover:text-white transition-all", children: [
417
414
  history.length - visibleCount,
418
415
  " weitere laden"
419
416
  ] })
@@ -486,7 +483,7 @@ var InspectPanel = ({ currentResult, history, onSelect, workspaceTags, onTagTogg
486
483
  };
487
484
 
488
485
  // src/components/SetupPanel.tsx
489
- import { useRef as useRef2, useState as useState3 } from "react";
486
+ import { useRef as useRef2, useState as useState2 } from "react";
490
487
  import { motion as motion3 } from "motion/react";
491
488
  import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
492
489
  var PRESET_URLS = [
@@ -496,11 +493,11 @@ var PRESET_URLS = [
496
493
  ];
497
494
  var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
498
495
  const workspaceInputRef = useRef2(null);
499
- const [urlInput, setUrlInput] = useState3("");
500
- const [tokenInput, setTokenInput] = useState3("");
501
- const [testStatus, setTestStatus] = useState3("idle");
502
- const [result, setResult] = useState3(null);
503
- const [fetchError, setFetchError] = useState3(null);
496
+ const [urlInput, setUrlInput] = useState2("");
497
+ const [tokenInput, setTokenInput] = useState2("");
498
+ const [testStatus, setTestStatus] = useState2("idle");
499
+ const [result, setResult] = useState2(null);
500
+ const [fetchError, setFetchError] = useState2(null);
504
501
  const runTest = async (url) => {
505
502
  if (!url.trim()) return;
506
503
  setTestStatus("loading");
@@ -663,7 +660,6 @@ var SetupPanel = ({ onWorkspaceImport, buildInfo }) => {
663
660
  };
664
661
 
665
662
  // src/components/MediaLibrary.tsx
666
- import { useState as useState4 } from "react";
667
663
  import { motion as motion4 } from "motion/react";
668
664
 
669
665
  // src/lib/grouping.ts
@@ -689,9 +685,7 @@ function groupByPrompt(items) {
689
685
 
690
686
  // src/components/MediaLibrary.tsx
691
687
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
692
- var PAGE_SIZE2 = 20;
693
- var MediaLibrary = ({ items, onImport, onDelete, onSelect, onToggleSelection, onBatchDownload, onGenerateReference }) => {
694
- const [visibleCount, setVisibleCount] = useState4(PAGE_SIZE2);
688
+ var MediaLibrary = ({ items, onImport, onDelete, onSelect, onToggleSelection, onBatchDownload, onGenerateReference, visibleCount, onLoadMore }) => {
695
689
  const selectedCount = items.filter((i) => i.selectedForExport).length;
696
690
  const groups = groupByPrompt(items);
697
691
  const visibleGroups = groups.slice(0, visibleCount);
@@ -764,7 +758,7 @@ var MediaLibrary = ({ items, onImport, onDelete, onSelect, onToggleSelection, on
764
758
  rep.id
765
759
  );
766
760
  }),
767
- visibleCount < groups.length && /* @__PURE__ */ jsx8("div", { className: "col-span-2 flex justify-center pt-2 pb-4", children: /* @__PURE__ */ jsxs6("button", { type: "button", onClick: () => setVisibleCount((c) => c + PAGE_SIZE2), className: "px-4 py-2 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg text-[10px] font-bold uppercase text-white/60 hover:text-white transition-all", children: [
761
+ visibleCount < groups.length && /* @__PURE__ */ jsx8("div", { className: "col-span-2 flex justify-center pt-2 pb-4", children: /* @__PURE__ */ jsxs6("button", { type: "button", onClick: onLoadMore, className: "px-4 py-2 bg-white/5 hover:bg-white/10 border border-white/10 rounded-lg text-[10px] font-bold uppercase text-white/60 hover:text-white transition-all", children: [
768
762
  groups.length - visibleCount,
769
763
  " weitere laden"
770
764
  ] }) })
@@ -773,7 +767,7 @@ var MediaLibrary = ({ items, onImport, onDelete, onSelect, onToggleSelection, on
773
767
  };
774
768
 
775
769
  // src/components/ListView.tsx
776
- import { useEffect as useEffect3, useRef as useRef3, useState as useState5 } from "react";
770
+ import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
777
771
  import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
778
772
  var ListNode = ({ node, depth, onNodeChange, onAddChild, onDeleteNode, onMoveNode, onIndentNode, onOutdentNode, onAddSibling, isActive, isInPath, onFocus, onGenerate, onGenerateBranch, onGenerateSubtree, isGenerating, isCollapsed, toggleCollapse, renderNode, children }) => {
779
773
  const inputRef = useRef3(null);
@@ -838,7 +832,7 @@ var ListNode = ({ node, depth, onNodeChange, onAddChild, onDeleteNode, onMoveNod
838
832
  ] });
839
833
  };
840
834
  function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMoveNode, onIndentNode, onOutdentNode, onAddSibling, focusedNodeId, onFocus, activePath, onGenerate, onGenerateBranch, onGenerateSubtree, isGeneratingNodeId }) {
841
- const [collapsed, setCollapsed] = useState5(/* @__PURE__ */ new Set());
835
+ const [collapsed, setCollapsed] = useState3(/* @__PURE__ */ new Set());
842
836
  const toggleCollapse = (id) => {
843
837
  setCollapsed((prev) => {
844
838
  const next = new Set(prev);
@@ -866,13 +860,13 @@ function ListView({ nodes, edges, onNodeChange, onAddChild, onDeleteNode, onMove
866
860
  }
867
861
 
868
862
  // src/components/AvatarArchitectApp.tsx
869
- import { useState as useState20, useCallback as useCallback3, useMemo as useMemo2, useEffect as useEffect7, useRef as useRef8 } from "react";
863
+ import { useState as useState18, useCallback as useCallback3, useMemo as useMemo2, useEffect as useEffect7, useRef as useRef8 } from "react";
870
864
 
871
865
  // src/components/PromptTab.tsx
872
- import { useRef as useRef4, useState as useState7 } from "react";
866
+ import { useRef as useRef4, useState as useState5 } from "react";
873
867
 
874
868
  // src/components/CollapsibleCard.tsx
875
- import { useState as useState6 } from "react";
869
+ import { useState as useState4 } from "react";
876
870
  import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
877
871
  var CollapsibleCard = ({
878
872
  title,
@@ -883,7 +877,7 @@ var CollapsibleCard = ({
883
877
  collapsible = true,
884
878
  className = ""
885
879
  }) => {
886
- const [isOpen, setIsOpen] = useState6(defaultOpen);
880
+ const [isOpen, setIsOpen] = useState4(defaultOpen);
887
881
  return /* @__PURE__ */ jsxs8("div", { className: `border border-neutral-800 rounded-lg ${className}`, children: [
888
882
  /* @__PURE__ */ jsxs8(
889
883
  "div",
@@ -930,18 +924,18 @@ var PromptTab = ({
930
924
  onTagUpdate,
931
925
  onTagDelete
932
926
  }) => {
933
- const [selectedLabels, setSelectedLabels] = useState7(/* @__PURE__ */ new Set());
934
- const [instructions, setInstructions] = useState7("");
935
- const [rules, setRules] = useState7("");
936
- const [activeCategory, setActiveCategory] = useState7(null);
937
- const [copied, setCopied] = useState7(false);
927
+ const [selectedLabels, setSelectedLabels] = useState5(/* @__PURE__ */ new Set());
928
+ const [instructions, setInstructions] = useState5("");
929
+ const [rules, setRules] = useState5("");
930
+ const [activeCategory, setActiveCategory] = useState5(null);
931
+ const [copied, setCopied] = useState5(false);
938
932
  const imgInputRef = useRef4(null);
939
- const [addingInCat, setAddingInCat] = useState7(null);
940
- const [newLabel, setNewLabel] = useState7("");
941
- const [newValue, setNewValue] = useState7("");
942
- const [editingTag, setEditingTag] = useState7(null);
943
- const [editLabel, setEditLabel] = useState7("");
944
- const [editValue, setEditValue] = useState7("");
933
+ const [addingInCat, setAddingInCat] = useState5(null);
934
+ const [newLabel, setNewLabel] = useState5("");
935
+ const [newValue, setNewValue] = useState5("");
936
+ const [editingTag, setEditingTag] = useState5(null);
937
+ const [editLabel, setEditLabel] = useState5("");
938
+ const [editValue, setEditValue] = useState5("");
945
939
  const longPressTimer = useRef4(null);
946
940
  const longPressActivated = useRef4(false);
947
941
  const toggleTag = (label) => {
@@ -1390,7 +1384,7 @@ var PromptTab = ({
1390
1384
  };
1391
1385
 
1392
1386
  // src/components/ProjectSyncTab.tsx
1393
- import { useRef as useRef5, useState as useState8, useEffect as useEffect4 } from "react";
1387
+ import { useRef as useRef5, useState as useState6, useEffect as useEffect4 } from "react";
1394
1388
  import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1395
1389
  var ProjectSyncTab = ({
1396
1390
  topSlot,
@@ -1412,12 +1406,12 @@ var ProjectSyncTab = ({
1412
1406
  }) => {
1413
1407
  const projectInputRef = useRef5(null);
1414
1408
  const workspaceInputRef = useRef5(null);
1415
- const [saveName, setSaveName] = useState8("");
1416
- const [isSaving, setIsSaving] = useState8(false);
1417
- const [isExporting, setIsExporting] = useState8(false);
1418
- const [syncState, setSyncState] = useState8("idle");
1419
- const [syncDiff, setSyncDiff] = useState8(null);
1420
- const [selectedLocalIds, setSelectedLocalIds] = useState8(/* @__PURE__ */ new Set());
1409
+ const [saveName, setSaveName] = useState6("");
1410
+ const [isSaving, setIsSaving] = useState6(false);
1411
+ const [isExporting, setIsExporting] = useState6(false);
1412
+ const [syncState, setSyncState] = useState6("idle");
1413
+ const [syncDiff, setSyncDiff] = useState6(null);
1414
+ const [selectedLocalIds, setSelectedLocalIds] = useState6(/* @__PURE__ */ new Set());
1421
1415
  const handleExport = async () => {
1422
1416
  if (!onProjectExport) return;
1423
1417
  setIsExporting(true);
@@ -1463,13 +1457,13 @@ var ProjectSyncTab = ({
1463
1457
  });
1464
1458
  };
1465
1459
  const isWorking = projectActionState === "working" || projectActionState === "working-full";
1466
- const [hfProjects, setHfProjects] = useState8([]);
1467
- const [hfLoading, setHfLoading] = useState8(false);
1468
- const [hfSaving, setHfSaving] = useState8(false);
1469
- const [hfError, setHfError] = useState8(null);
1470
- const [hfSaveName, setHfSaveName] = useState8("");
1471
- const [hfSyncProgress, setHfSyncProgress] = useState8(null);
1472
- const [hfSyncing, setHfSyncing] = useState8(false);
1460
+ const [hfProjects, setHfProjects] = useState6([]);
1461
+ const [hfLoading, setHfLoading] = useState6(false);
1462
+ const [hfSaving, setHfSaving] = useState6(false);
1463
+ const [hfError, setHfError] = useState6(null);
1464
+ const [hfSaveName, setHfSaveName] = useState6("");
1465
+ const [hfSyncProgress, setHfSyncProgress] = useState6(null);
1466
+ const [hfSyncing, setHfSyncing] = useState6(false);
1473
1467
  const loadHfProjects = async (token) => {
1474
1468
  setHfLoading(true);
1475
1469
  setHfError(null);
@@ -1666,7 +1660,7 @@ var ProjectSyncTab = ({
1666
1660
  {
1667
1661
  onClick: async () => {
1668
1662
  try {
1669
- const { hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-5BU5DVQ6.mjs");
1663
+ const { hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-PHK6676C.mjs");
1670
1664
  const file = await hfDownloadProject2(p.path, hfToken);
1671
1665
  onHfLoad(file);
1672
1666
  } catch (e) {
@@ -1888,7 +1882,7 @@ function toPromptImages(images) {
1888
1882
  }
1889
1883
 
1890
1884
  // src/hooks/useHFState.ts
1891
- import { useState as useState9, useEffect as useEffect5, useRef as useRef6, useCallback } from "react";
1885
+ import { useState as useState7, useEffect as useEffect5, useRef as useRef6, useCallback } from "react";
1892
1886
 
1893
1887
  // src/lib/hfReducer.ts
1894
1888
  function applyEvent(state, event) {
@@ -2020,16 +2014,17 @@ function writeOfflineBuffer(events) {
2020
2014
  }
2021
2015
  }
2022
2016
  function useHFState(token, namespace) {
2023
- const [state, setState] = useState9(null);
2024
- const [isLoading, setIsLoading] = useState9(false);
2025
- const [error, setError] = useState9(null);
2026
- const [eventCount, setEventCount] = useState9(0);
2027
- const [localOnlyCount, setLocalOnlyCount] = useState9(0);
2028
- const [forks, setForks] = useState9([]);
2029
- const [pendingBufferCount, setPendingBufferCount] = useState9(readOfflineBuffer().length);
2030
- const [lastEventTs, setLastEventTs] = useState9(0);
2031
- const [hasStateZip, setHasStateZip] = useState9(false);
2017
+ const [state, setState] = useState7(null);
2018
+ const [isLoading, setIsLoading] = useState7(false);
2019
+ const [error, setError] = useState7(null);
2020
+ const [eventCount, setEventCount] = useState7(0);
2021
+ const [localOnlyCount, setLocalOnlyCount] = useState7(0);
2022
+ const [forks, setForks] = useState7([]);
2023
+ const [pendingBufferCount, setPendingBufferCount] = useState7(readOfflineBuffer().length);
2024
+ const [lastEventTs, setLastEventTs] = useState7(0);
2025
+ const [hasStateZip, setHasStateZip] = useState7(false);
2032
2026
  const knownEventPaths = useRef6(/* @__PURE__ */ new Set());
2027
+ const knownFilePaths = useRef6(/* @__PURE__ */ new Set());
2033
2028
  const allEventsRef = useRef6([]);
2034
2029
  const applyNewEvents = useCallback((snapshot, newEvents) => {
2035
2030
  if (!newEvents.length && allEventsRef.current.length === 0) {
@@ -2049,6 +2044,7 @@ function useHFState(token, namespace) {
2049
2044
  if (!token || !namespace) return;
2050
2045
  setIsLoading(true);
2051
2046
  setError(null);
2047
+ knownFilePaths.current = /* @__PURE__ */ new Set();
2052
2048
  try {
2053
2049
  const snapshot = await loadHFState(namespace, token);
2054
2050
  setHasStateZip(snapshot !== null);
@@ -2057,7 +2053,7 @@ function useHFState(token, namespace) {
2057
2053
  tags: { by_category: {}, all: [] },
2058
2054
  meta: { consolidatedAt: 0, version: 1 }
2059
2055
  };
2060
- const hfEvents = await loadPendingEvents(namespace, token, base.meta.consolidatedAt);
2056
+ const hfEvents = await loadPendingEvents(namespace, token, base.meta.consolidatedAt, knownFilePaths.current);
2061
2057
  const hfEventKeys = new Set(hfEvents.map((e) => `${e.ts}_${e.clientId}`));
2062
2058
  const localOnlyEvents = allEventsRef.current.filter(
2063
2059
  (e) => !hfEventKeys.has(`${e.ts}_${e.clientId}`)
@@ -2082,7 +2078,7 @@ function useHFState(token, namespace) {
2082
2078
  }
2083
2079
  writeOfflineBuffer(failed);
2084
2080
  setPendingBufferCount(failed.length);
2085
- const freshEvents = await loadPendingEvents(namespace, token, base.meta.consolidatedAt);
2081
+ const freshEvents = await loadPendingEvents(namespace, token, base.meta.consolidatedAt, knownFilePaths.current);
2086
2082
  freshEvents.forEach((e) => knownEventPaths.current.add(`${e.ts}_${e.clientId}`));
2087
2083
  setState((prev) => prev ? applyNewEvents(base, freshEvents) : prev);
2088
2084
  }
@@ -2095,7 +2091,7 @@ function useHFState(token, namespace) {
2095
2091
  const pollNew = useCallback(async () => {
2096
2092
  if (!token || !namespace || !state) return;
2097
2093
  try {
2098
- const events = await loadPendingEvents(namespace, token, state.meta.consolidatedAt);
2094
+ const events = await loadPendingEvents(namespace, token, state.meta.consolidatedAt, knownFilePaths.current);
2099
2095
  const newEvents = events.filter((e) => !knownEventPaths.current.has(`${e.ts}_${e.clientId}`));
2100
2096
  if (!newEvents.length) return;
2101
2097
  newEvents.forEach((e) => knownEventPaths.current.add(`${e.ts}_${e.clientId}`));
@@ -2164,13 +2160,13 @@ function useHFState(token, namespace) {
2164
2160
  }
2165
2161
 
2166
2162
  // src/components/labs/LabsTab.tsx
2167
- import { useState as useState16 } from "react";
2163
+ import { useState as useState14 } from "react";
2168
2164
 
2169
2165
  // src/components/labs/LabRemix.tsx
2170
- import { useState as useState11 } from "react";
2166
+ import { useState as useState9 } from "react";
2171
2167
 
2172
2168
  // src/components/labs/LabImagePicker.tsx
2173
- import { useState as useState10 } from "react";
2169
+ import { useState as useState8 } from "react";
2174
2170
  import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2175
2171
  var LabImagePicker = ({
2176
2172
  availableItems,
@@ -2179,8 +2175,8 @@ var LabImagePicker = ({
2179
2175
  onClose,
2180
2176
  title = "Bild w\xE4hlen"
2181
2177
  }) => {
2182
- const [search, setSearch] = useState10("");
2183
- const [drillItem, setDrillItem] = useState10(null);
2178
+ const [search, setSearch] = useState8("");
2179
+ const [drillItem, setDrillItem] = useState8(null);
2184
2180
  const filtered = availableItems.filter(
2185
2181
  (item) => !search || item.prompt.toLowerCase().includes(search.toLowerCase())
2186
2182
  );
@@ -2282,13 +2278,13 @@ var LabImagePicker = ({
2282
2278
  // src/components/labs/LabRemix.tsx
2283
2279
  import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2284
2280
  var LabRemix = ({ services, onResult }) => {
2285
- const [showPicker, setShowPicker] = useState11(false);
2286
- const [selected, setSelected] = useState11(null);
2287
- const [instruction, setInstruction] = useState11("");
2288
- const [generatedPrompt, setGeneratedPrompt] = useState11("");
2289
- const [resultImage, setResultImage] = useState11(null);
2290
- const [isGeneratingPrompt, setIsGeneratingPrompt] = useState11(false);
2291
- const [isGeneratingImage, setIsGeneratingImage] = useState11(false);
2281
+ const [showPicker, setShowPicker] = useState9(false);
2282
+ const [selected, setSelected] = useState9(null);
2283
+ const [instruction, setInstruction] = useState9("");
2284
+ const [generatedPrompt, setGeneratedPrompt] = useState9("");
2285
+ const [resultImage, setResultImage] = useState9(null);
2286
+ const [isGeneratingPrompt, setIsGeneratingPrompt] = useState9(false);
2287
+ const [isGeneratingImage, setIsGeneratingImage] = useState9(false);
2292
2288
  const handleSelectImage = (item, frame) => {
2293
2289
  services.onItemUsed(item);
2294
2290
  setSelected({
@@ -2471,16 +2467,16 @@ var LabRemix = ({ services, onResult }) => {
2471
2467
  };
2472
2468
 
2473
2469
  // src/components/labs/LabBlend.tsx
2474
- import { useState as useState12 } from "react";
2470
+ import { useState as useState10 } from "react";
2475
2471
  import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2476
2472
  var LabBlend = ({ services, onResult }) => {
2477
- const [showPickerFor, setShowPickerFor] = useState12(null);
2478
- const [selectedImages, setSelectedImages] = useState12([]);
2479
- const [instruction, setInstruction] = useState12("");
2480
- const [generatedPrompt, setGeneratedPrompt] = useState12("");
2481
- const [resultImage, setResultImage] = useState12(null);
2482
- const [isGeneratingPrompt, setIsGeneratingPrompt] = useState12(false);
2483
- const [isGeneratingImage, setIsGeneratingImage] = useState12(false);
2473
+ const [showPickerFor, setShowPickerFor] = useState10(null);
2474
+ const [selectedImages, setSelectedImages] = useState10([]);
2475
+ const [instruction, setInstruction] = useState10("");
2476
+ const [generatedPrompt, setGeneratedPrompt] = useState10("");
2477
+ const [resultImage, setResultImage] = useState10(null);
2478
+ const [isGeneratingPrompt, setIsGeneratingPrompt] = useState10(false);
2479
+ const [isGeneratingImage, setIsGeneratingImage] = useState10(false);
2484
2480
  const handleSelectImage = (index, item, frame) => {
2485
2481
  services.onItemUsed(item);
2486
2482
  const newImg = {
@@ -2667,17 +2663,17 @@ var LabBlend = ({ services, onResult }) => {
2667
2663
  };
2668
2664
 
2669
2665
  // src/components/labs/LabCompare.tsx
2670
- import { useState as useState13 } from "react";
2666
+ import { useState as useState11 } from "react";
2671
2667
  import { Fragment as Fragment7, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2672
2668
  var LabCompare = ({ services, onResult }) => {
2673
- const [showPickerFor, setShowPickerFor] = useState13(null);
2674
- const [selectedImages, setSelectedImages] = useState13([]);
2675
- const [instruction, setInstruction] = useState13("");
2676
- const [analysis, setAnalysis] = useState13("");
2677
- const [generatedPrompt, setGeneratedPrompt] = useState13("");
2678
- const [resultImage, setResultImage] = useState13(null);
2679
- const [isAnalyzing, setIsAnalyzing] = useState13(false);
2680
- const [isGeneratingImage, setIsGeneratingImage] = useState13(false);
2669
+ const [showPickerFor, setShowPickerFor] = useState11(null);
2670
+ const [selectedImages, setSelectedImages] = useState11([]);
2671
+ const [instruction, setInstruction] = useState11("");
2672
+ const [analysis, setAnalysis] = useState11("");
2673
+ const [generatedPrompt, setGeneratedPrompt] = useState11("");
2674
+ const [resultImage, setResultImage] = useState11(null);
2675
+ const [isAnalyzing, setIsAnalyzing] = useState11(false);
2676
+ const [isGeneratingImage, setIsGeneratingImage] = useState11(false);
2681
2677
  const handleSelectImage = (index, item, frame) => {
2682
2678
  services.onItemUsed(item);
2683
2679
  const newImg = {
@@ -2840,14 +2836,14 @@ var LabCompare = ({ services, onResult }) => {
2840
2836
  };
2841
2837
 
2842
2838
  // src/components/labs/LabLoop.tsx
2843
- import { useState as useState14 } from "react";
2839
+ import { useState as useState12 } from "react";
2844
2840
  import { Fragment as Fragment8, jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2845
2841
  var LabLoop = ({ services, onResult }) => {
2846
- const [rounds, setRounds] = useState14([]);
2847
- const [currentInstruction, setCurrentInstruction] = useState14("");
2848
- const [showPickerForRound, setShowPickerForRound] = useState14(null);
2849
- const [pendingImages, setPendingImages] = useState14([]);
2850
- const [isGenerating, setIsGenerating] = useState14(false);
2842
+ const [rounds, setRounds] = useState12([]);
2843
+ const [currentInstruction, setCurrentInstruction] = useState12("");
2844
+ const [showPickerForRound, setShowPickerForRound] = useState12(null);
2845
+ const [pendingImages, setPendingImages] = useState12([]);
2846
+ const [isGenerating, setIsGenerating] = useState12(false);
2851
2847
  const currentPrompt = rounds.length > 0 ? rounds[rounds.length - 1].prompt : "";
2852
2848
  const handleAddImage = (item, frame) => {
2853
2849
  services.onItemUsed(item);
@@ -3003,7 +2999,7 @@ var LabLoop = ({ services, onResult }) => {
3003
2999
  };
3004
3000
 
3005
3001
  // src/components/labs/LabFrameExtractor.tsx
3006
- import { useRef as useRef7, useState as useState15, useCallback as useCallback2 } from "react";
3002
+ import { useRef as useRef7, useState as useState13, useCallback as useCallback2 } from "react";
3007
3003
  import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3008
3004
  var formatTime = (s) => {
3009
3005
  const m = Math.floor(s / 60);
@@ -3020,12 +3016,12 @@ var LabFrameExtractor = ({
3020
3016
  const videoRef = useRef7(null);
3021
3017
  const canvasRef = useRef7(null);
3022
3018
  const cancelledRef = useRef7(false);
3023
- const [selectedItem, setSelectedItem] = useState15(null);
3024
- const [videoSrc, setVideoSrc] = useState15(null);
3025
- const [videoReady, setVideoReady] = useState15(false);
3026
- const [frames, setFrames] = useState15([]);
3027
- const [isExtracting, setIsExtracting] = useState15(false);
3028
- const [intervalSec, setIntervalSec] = useState15("1");
3019
+ const [selectedItem, setSelectedItem] = useState13(null);
3020
+ const [videoSrc, setVideoSrc] = useState13(null);
3021
+ const [videoReady, setVideoReady] = useState13(false);
3022
+ const [frames, setFrames] = useState13([]);
3023
+ const [isExtracting, setIsExtracting] = useState13(false);
3024
+ const [intervalSec, setIntervalSec] = useState13("1");
3029
3025
  const handleVideoSelect = (item) => {
3030
3026
  const mediaId = item.frames[0]?.mediaId;
3031
3027
  if (!mediaId) return;
@@ -3262,7 +3258,7 @@ var BASE_TABS = [
3262
3258
  ];
3263
3259
  var FRAMES_TAB = { key: "frames", label: "Frames", icon: "crop_original" };
3264
3260
  var LabsTab = ({ services, onResult, videoItems, resolveVideoUrl }) => {
3265
- const [activeTab, setActiveTab] = useState16("remix");
3261
+ const [activeTab, setActiveTab] = useState14("remix");
3266
3262
  const showFrames = !!(videoItems && resolveVideoUrl);
3267
3263
  const tabs = showFrames ? [...BASE_TABS, FRAMES_TAB] : BASE_TABS;
3268
3264
  return /* @__PURE__ */ jsxs17("div", { className: "flex flex-col h-full overflow-hidden", children: [
@@ -3296,19 +3292,19 @@ var LabsTab = ({ services, onResult, videoItems, resolveVideoUrl }) => {
3296
3292
  };
3297
3293
 
3298
3294
  // src/components/TagManagerPanel.tsx
3299
- import { useState as useState17 } from "react";
3295
+ import { useState as useState15 } from "react";
3300
3296
  import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
3301
3297
  function TagManagerPanel({ workspaceTags, onTagCreate, onTagUpdate, onTagDelete, onTagReorder, onTagMove }) {
3302
3298
  const categories = Object.keys(workspaceTags.by_category).filter(
3303
3299
  (cat) => (workspaceTags.by_category[cat] || []).some((t) => !t.is_deleted)
3304
3300
  );
3305
- const [selectedCategory, setSelectedCategory] = useState17(categories[0] || "");
3301
+ const [selectedCategory, setSelectedCategory] = useState15(categories[0] || "");
3306
3302
  const effectiveCategory = categories.includes(selectedCategory) ? selectedCategory : categories[0] || "";
3307
- const [editingLabel, setEditingLabel] = useState17(null);
3308
- const [editState, setEditState] = useState17({ label: "", value: "" });
3309
- const [newTag, setNewTag] = useState17({ label: "", value: "" });
3310
- const [movingLabel, setMovingLabel] = useState17(null);
3311
- const [moveTarget, setMoveTarget] = useState17("");
3303
+ const [editingLabel, setEditingLabel] = useState15(null);
3304
+ const [editState, setEditState] = useState15({ label: "", value: "" });
3305
+ const [newTag, setNewTag] = useState15({ label: "", value: "" });
3306
+ const [movingLabel, setMovingLabel] = useState15(null);
3307
+ const [moveTarget, setMoveTarget] = useState15("");
3312
3308
  const tags = (workspaceTags.by_category[effectiveCategory] || []).filter((t) => !t.is_deleted);
3313
3309
  const otherCategories = categories.filter((c) => c !== effectiveCategory);
3314
3310
  const startEdit = (tag) => {
@@ -3504,7 +3500,7 @@ function TagManagerPanel({ workspaceTags, onTagCreate, onTagUpdate, onTagDelete,
3504
3500
  }
3505
3501
 
3506
3502
  // src/components/HFTestTab.tsx
3507
- import { useState as useState18 } from "react";
3503
+ import { useState as useState16 } from "react";
3508
3504
  import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
3509
3505
  var HF_BASE = "https://huggingface.co";
3510
3506
  var HF_REPO = "RolandSch/fa-app-state";
@@ -3697,7 +3693,7 @@ function tryFmt(s) {
3697
3693
  }
3698
3694
  }
3699
3695
  function CopyBtn({ text }) {
3700
- const [done, setDone] = useState18(false);
3696
+ const [done, setDone] = useState16(false);
3701
3697
  return /* @__PURE__ */ jsxs19(
3702
3698
  "button",
3703
3699
  {
@@ -3869,9 +3865,9 @@ function EventMonitor({ events, confirmedEventKeys, galleryItems, imageUploadSta
3869
3865
  ] });
3870
3866
  }
3871
3867
  function HFTestTab({ token, namespace, galleryItems, allEvents = [], confirmedEventKeys = /* @__PURE__ */ new Set(), imageUploadStatus = /* @__PURE__ */ new Map(), missingImages = [] }) {
3872
- const [selected, setSelected] = useState18(null);
3873
- const [results, setResults] = useState18({});
3874
- const [expanded, setExpanded] = useState18({});
3868
+ const [selected, setSelected] = useState16(null);
3869
+ const [results, setResults] = useState16({});
3870
+ const [expanded, setExpanded] = useState16({});
3875
3871
  const withResults = galleryItems.filter((g) => g.base64 && g.status === "done");
3876
3872
  const setRunning = (id) => setResults((r) => ({ ...r, [id]: { status: "running", steps: [], totalMs: 0 } }));
3877
3873
  const setDone = (id, steps, t0) => {
@@ -4069,7 +4065,7 @@ function HFTestTab({ token, namespace, galleryItems, allEvents = [], confirmedEv
4069
4065
  }
4070
4066
 
4071
4067
  // src/components/ServerTab.tsx
4072
- import { useState as useState19, useEffect as useEffect6 } from "react";
4068
+ import { useState as useState17, useEffect as useEffect6 } from "react";
4073
4069
  import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
4074
4070
  function StarRating({ rating = 0 }) {
4075
4071
  return /* @__PURE__ */ jsx22("div", { className: "flex gap-[2px]", children: [1, 2, 3, 4, 5].map((i) => /* @__PURE__ */ jsx22("span", { className: `material-symbols-outlined text-[12px] ${i <= rating ? "text-yellow-400" : "text-white/15"}`, children: "star" }, i)) });
@@ -4082,20 +4078,20 @@ async function serverGet(baseUrl, path) {
4082
4078
  return json && typeof json === "object" && "data" in json ? json.data : json;
4083
4079
  }
4084
4080
  function ServerTab({ serverBaseUrl }) {
4085
- const [step, setStep] = useState19("user");
4086
- const [users, setUsers] = useState19([]);
4087
- const [usersLoading, setUsersLoading] = useState19(false);
4088
- const [usersError, setUsersError] = useState19(null);
4089
- const [selectedUser, setSelectedUser] = useState19(null);
4090
- const [contexts, setContexts] = useState19([]);
4091
- const [contextsLoading, setContextsLoading] = useState19(false);
4092
- const [selectedContext, setSelectedContext] = useState19(null);
4093
- const [tags, setTags] = useState19([]);
4094
- const [items, setItems] = useState19([]);
4095
- const [libLoading, setLibLoading] = useState19(false);
4096
- const [libError, setLibError] = useState19(null);
4097
- const [activeTag, setActiveTag] = useState19(null);
4098
- const [preview, setPreview] = useState19(null);
4081
+ const [step, setStep] = useState17("user");
4082
+ const [users, setUsers] = useState17([]);
4083
+ const [usersLoading, setUsersLoading] = useState17(false);
4084
+ const [usersError, setUsersError] = useState17(null);
4085
+ const [selectedUser, setSelectedUser] = useState17(null);
4086
+ const [contexts, setContexts] = useState17([]);
4087
+ const [contextsLoading, setContextsLoading] = useState17(false);
4088
+ const [selectedContext, setSelectedContext] = useState17(null);
4089
+ const [tags, setTags] = useState17([]);
4090
+ const [items, setItems] = useState17([]);
4091
+ const [libLoading, setLibLoading] = useState17(false);
4092
+ const [libError, setLibError] = useState17(null);
4093
+ const [activeTag, setActiveTag] = useState17(null);
4094
+ const [preview, setPreview] = useState17(null);
4099
4095
  useEffect6(() => {
4100
4096
  if (!serverBaseUrl) return;
4101
4097
  setUsersLoading(true);
@@ -4258,19 +4254,19 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4258
4254
  document.head.appendChild(style);
4259
4255
  }
4260
4256
  }, []);
4261
- const [showStart, setShowStart] = useState20(true);
4262
- const [layoutChoice, setLayoutChoice] = useState20(() => {
4257
+ const [showStart, setShowStart] = useState18(true);
4258
+ const [layoutChoice, setLayoutChoice] = useState18(() => {
4263
4259
  try {
4264
4260
  return localStorage.getItem("aa-layout") || null;
4265
4261
  } catch {
4266
4262
  return null;
4267
4263
  }
4268
4264
  });
4269
- const [projectLoaded, setProjectLoaded] = useState20(false);
4270
- const [hfToken, setHfToken] = useState20(initialHfToken || "");
4271
- const [hfTokenInput, setHfTokenInput] = useState20(initialHfToken || "");
4272
- const [isLoadingFromHF, setIsLoadingFromHF] = useState20(false);
4273
- const [hfNamespaceLocal, setHfNamespaceLocal] = useState20(() => {
4265
+ const [projectLoaded, setProjectLoaded] = useState18(false);
4266
+ const [hfToken, setHfToken] = useState18(initialHfToken || "");
4267
+ const [hfTokenInput, setHfTokenInput] = useState18(initialHfToken || "");
4268
+ const [isLoadingFromHF, setIsLoadingFromHF] = useState18(false);
4269
+ const [hfNamespaceLocal, setHfNamespaceLocal] = useState18(() => {
4274
4270
  const KNOWN = ["app.art-by-rolands.de/", "dev-app.art-by-rolands.de/"];
4275
4271
  const DEFAULT = "app.art-by-rolands.de/";
4276
4272
  try {
@@ -4282,7 +4278,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4282
4278
  return DEFAULT;
4283
4279
  }
4284
4280
  });
4285
- const [hfNamespaceFromServer, setHfNamespaceFromServer] = useState20(null);
4281
+ const [hfNamespaceFromServer, setHfNamespaceFromServer] = useState18(null);
4286
4282
  useEffect7(() => {
4287
4283
  if (hfNamespace !== void 0) return;
4288
4284
  const backendUrl = typeof window !== "undefined" ? window.BACKEND_URL || window.location.origin : null;
@@ -4305,10 +4301,10 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4305
4301
  refresh: refreshHF,
4306
4302
  hasStateZip
4307
4303
  } = useHFState(hfToken, effectiveNamespace);
4308
- const [imageUploadStatus, setImageUploadStatus] = useState20(/* @__PURE__ */ new Map());
4309
- const [bootstrapLog, setBootstrapLog] = useState20([]);
4310
- const [isBootstrapping, setIsBootstrapping] = useState20(false);
4311
- const [hfMissingImages, setHfMissingImages] = useState20([]);
4304
+ const [imageUploadStatus, setImageUploadStatus] = useState18(/* @__PURE__ */ new Map());
4305
+ const [bootstrapLog, setBootstrapLog] = useState18([]);
4306
+ const [isBootstrapping, setIsBootstrapping] = useState18(false);
4307
+ const [hfMissingImages, setHfMissingImages] = useState18([]);
4312
4308
  const syncTopSlot = /* @__PURE__ */ jsxs21(Fragment9, { children: [
4313
4309
  localOnlyCount > 0 && /* @__PURE__ */ jsxs21("div", { style: { background: "rgba(234,179,8,0.15)", border: "1px solid rgba(234,179,8,0.3)", padding: "4px 10px", fontSize: 11, color: "#fbbf24", borderRadius: 4, marginBottom: 4 }, children: [
4314
4310
  "\u26A0 ",
@@ -4367,15 +4363,36 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4367
4363
  setLayoutChoice(choice);
4368
4364
  setShowStart(false);
4369
4365
  };
4370
- const [nodes, setNodes] = useState20([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
4371
- const [edges, setEdges] = useState20([]);
4372
- const [history, setHistory] = useState20([]);
4373
- const [galleryItems, setGalleryItems] = useState20([]);
4366
+ const [nodes, setNodes] = useState18([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
4367
+ const [edges, setEdges] = useState18([]);
4368
+ const [history, setHistory] = useState18([]);
4369
+ const [galleryItems, setGalleryItems] = useState18([]);
4374
4370
  const galleryItemsRef = useRef8([]);
4375
4371
  useEffect7(() => {
4376
4372
  galleryItemsRef.current = galleryItems;
4377
4373
  }, [galleryItems]);
4378
4374
  const hfImageNotFoundRef = useRef8(/* @__PURE__ */ new Map());
4375
+ const [galleryVisibleCount, setGalleryVisibleCount] = useState18(20);
4376
+ const [historyVisibleCount, setHistoryVisibleCount] = useState18(20);
4377
+ const loadThumbnailsForEntries = useCallback3(async (entries) => {
4378
+ for (const entry of entries) {
4379
+ if (galleryItemsRef.current.find((g) => g.id === entry.id)?.base64) continue;
4380
+ if (hfImageNotFoundRef.current.has(entry.id)) continue;
4381
+ try {
4382
+ const b64 = await hfLoadImageAsBase64(entry.id, hfToken, effectiveNamespace, entry.filename, void 0, entry.mimeType, entry.hasThumb);
4383
+ if (!b64) {
4384
+ hfImageNotFoundRef.current.set(entry.id, Date.now());
4385
+ setHfMissingImages((prev) => prev.find((e) => e.id === entry.id) ? prev : [...prev, { id: entry.id, filename: entry.filename, mimeType: entry.mimeType ?? "image/jpeg", timestamp: entry.timestamp ?? 0 }]);
4386
+ continue;
4387
+ }
4388
+ const prefix = `data:${entry.mimeType || "image/jpeg"};base64,`;
4389
+ setGalleryItems((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
4390
+ setHistory((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
4391
+ } catch {
4392
+ hfImageNotFoundRef.current.set(entry.id, Date.now());
4393
+ }
4394
+ }
4395
+ }, [hfToken, effectiveNamespace]);
4379
4396
  useEffect7(() => {
4380
4397
  if (!hfState) return;
4381
4398
  if (hfState.tags?.by_category) setWorkspaceTags(hfState.tags);
@@ -4402,87 +4419,94 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4402
4419
  const merged = skeletons.map((s) => prev.find((g) => g.id === s.id) ?? s);
4403
4420
  return [...localOnly, ...merged].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
4404
4421
  });
4405
- const sortedEntries = [...hfState.metadata].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
4406
- const galleryRepIds = new Set(groupByPrompt(skeletons).slice(0, 20).map((g) => g.representative.id));
4407
- const historyIds = new Set(sortedEntries.slice(0, 20).map((e) => e.id));
4408
- const initialIds = /* @__PURE__ */ new Set([...galleryRepIds, ...historyIds]);
4409
- const toLoad = sortedEntries.filter((e) => initialIds.has(e.id));
4410
- (async () => {
4411
- for (const entry of toLoad) {
4412
- if (galleryItemsRef.current.find((g) => g.id === entry.id)?.base64) continue;
4413
- if (hfImageNotFoundRef.current.has(entry.id)) continue;
4414
- try {
4415
- const b64 = await hfLoadImageAsBase64(entry.id, hfToken, effectiveNamespace, entry.filename, void 0, entry.mimeType, entry.hasThumb);
4416
- if (!b64) {
4417
- hfImageNotFoundRef.current.set(entry.id, Date.now());
4418
- setHfMissingImages((prev) => {
4419
- if (prev.find((e) => e.id === entry.id)) return prev;
4420
- return [...prev, { id: entry.id, filename: entry.filename, mimeType: entry.mimeType, timestamp: entry.timestamp }];
4421
- });
4422
- continue;
4423
- }
4424
- const prefix = `data:${entry.mimeType || "image/jpeg"};base64,`;
4425
- setGalleryItems((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
4426
- setHistory((prev) => prev.map((g) => g.id === entry.id && !g.base64 ? { ...g, base64: prefix + b64 } : g));
4427
- } catch {
4428
- hfImageNotFoundRef.current.set(entry.id, Date.now());
4429
- }
4430
- }
4431
- })();
4432
4422
  }, [hfState]);
4433
- const [activePrompt, setActivePrompt] = useState20("");
4434
- const [isSynthesizing, setIsSynthesizing] = useState20(false);
4435
- const [activeGenerationsCount, setActiveGenerationsCount] = useState20(0);
4436
- const [currentResult, setCurrentResult] = useState20(null);
4437
- const [focusedNodeId, setFocusedNodeId] = useState20(null);
4438
- const [leftTab, setLeftTab] = useState20("prompt");
4439
- const [promptFeedback, setPromptFeedback] = useState20(null);
4440
- const [lastPromptPayload, setLastPromptPayload] = useState20(null);
4441
- const [isPromptTabGenerating, setIsPromptTabGenerating] = useState20(false);
4442
- const [activeTab, setActiveTab] = useState20("history");
4443
- const [mobileTab, setMobileTab] = useState20("stage");
4444
- const [middlePanel, setMiddlePanel] = useState20("stage");
4445
- const [recentLabItems, setRecentLabItems] = useState20([]);
4446
- const [aspectRatio, setAspectRatio] = useState20("1:1");
4447
- const [selectedModel, setSelectedModel] = useState20("\u{1F34C} Nano Banana Pro");
4448
- const [seed, setSeed] = useState20(Math.floor(Math.random() * 1e6));
4449
- const [seedMode, setSeedMode] = useState20("random");
4450
- const [isLeftCollapsed, setIsLeftCollapsed] = useState20(false);
4451
- const [isRightCollapsed, setIsRightCollapsed] = useState20(false);
4452
- const [leftPanelWidth, setLeftPanelWidth] = useState20(() => {
4423
+ useEffect7(() => {
4424
+ if (!hfState) return;
4425
+ const sortedMeta = [...hfState.metadata].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
4426
+ const skeletons = sortedMeta.map((m) => ({ id: m.id, prompt: m.prompt, timestamp: m.timestamp, status: "done", nodeId: m.id, tags: m.tags || [] }));
4427
+ const repIds = new Set(groupByPrompt(skeletons).slice(0, galleryVisibleCount).map((g) => g.representative.id));
4428
+ loadThumbnailsForEntries(sortedMeta.filter((e) => repIds.has(e.id)));
4429
+ }, [hfState, galleryVisibleCount, loadThumbnailsForEntries]);
4430
+ useEffect7(() => {
4431
+ if (!hfState) return;
4432
+ const sortedMeta = [...hfState.metadata].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
4433
+ loadThumbnailsForEntries(sortedMeta.slice(0, historyVisibleCount));
4434
+ }, [hfState, historyVisibleCount, loadThumbnailsForEntries]);
4435
+ const [activePrompt, setActivePrompt] = useState18("");
4436
+ const [isSynthesizing, setIsSynthesizing] = useState18(false);
4437
+ const [activeGenerationsCount, setActiveGenerationsCount] = useState18(0);
4438
+ const [currentResult, setCurrentResult] = useState18(null);
4439
+ const [focusedNodeId, setFocusedNodeId] = useState18(null);
4440
+ const [leftTab, setLeftTab] = useState18("prompt");
4441
+ const [promptFeedback, setPromptFeedback] = useState18(null);
4442
+ const [lastPromptPayload, setLastPromptPayload] = useState18(null);
4443
+ const [isPromptTabGenerating, setIsPromptTabGenerating] = useState18(false);
4444
+ const [activeTab, setActiveTab] = useState18("history");
4445
+ const [mobileTab, setMobileTab] = useState18("stage");
4446
+ const [middlePanel, setMiddlePanel] = useState18("stage");
4447
+ const [recentLabItems, setRecentLabItems] = useState18([]);
4448
+ const [aspectRatio, setAspectRatio] = useState18("1:1");
4449
+ const [selectedModel, setSelectedModel] = useState18("\u{1F34C} Nano Banana Pro");
4450
+ const [seed, setSeed] = useState18(Math.floor(Math.random() * 1e6));
4451
+ const [seedMode, setSeedMode] = useState18("random");
4452
+ const [imageCount, setImageCount] = useState18(() => {
4453
+ try {
4454
+ const v = parseInt(localStorage.getItem("aa-image-count") || "", 10);
4455
+ return v >= 1 && v <= 8 ? v : 4;
4456
+ } catch {
4457
+ return 4;
4458
+ }
4459
+ });
4460
+ const updateImageCount = (val) => {
4461
+ const n = Math.max(1, Math.min(8, parseInt(val, 10) || 4));
4462
+ setImageCount(n);
4463
+ try {
4464
+ localStorage.setItem("aa-image-count", String(n));
4465
+ } catch {
4466
+ }
4467
+ };
4468
+ const imageCountOptions = [
4469
+ { label: "1 Bild", value: "1" },
4470
+ { label: "2 Bilder", value: "2" },
4471
+ { label: "4 Bilder", value: "4" },
4472
+ { label: "8 Bilder", value: "8" }
4473
+ ];
4474
+ const [isLeftCollapsed, setIsLeftCollapsed] = useState18(false);
4475
+ const [isRightCollapsed, setIsRightCollapsed] = useState18(false);
4476
+ const [leftPanelWidth, setLeftPanelWidth] = useState18(() => {
4453
4477
  try {
4454
4478
  return parseInt(localStorage.getItem("aa-left-width") || "260", 10);
4455
4479
  } catch {
4456
4480
  return 260;
4457
4481
  }
4458
4482
  });
4459
- const [rightPanelWidth, setRightPanelWidth] = useState20(() => {
4483
+ const [rightPanelWidth, setRightPanelWidth] = useState18(() => {
4460
4484
  try {
4461
4485
  return parseInt(localStorage.getItem("aa-right-width") || "320", 10);
4462
4486
  } catch {
4463
4487
  return 320;
4464
4488
  }
4465
4489
  });
4466
- const [isPromptCollapsed, setIsPromptCollapsed] = useState20(false);
4467
- const [projectActionState, setProjectActionState] = useState20("idle");
4490
+ const [isPromptCollapsed, setIsPromptCollapsed] = useState18(false);
4491
+ const [projectActionState, setProjectActionState] = useState18("idle");
4468
4492
  const syncServerDataRef = useRef8(null);
4469
- const [workspaceTags, setWorkspaceTags] = useState20(null);
4470
- const [serverProjects, setServerProjects] = useState20([]);
4471
- const [isLoadingFromServer, setIsLoadingFromServer] = useState20(false);
4472
- const [highContrast, setHighContrast] = useState20(() => {
4493
+ const [workspaceTags, setWorkspaceTags] = useState18(null);
4494
+ const [serverProjects, setServerProjects] = useState18([]);
4495
+ const [isLoadingFromServer, setIsLoadingFromServer] = useState18(false);
4496
+ const [highContrast, setHighContrast] = useState18(() => {
4473
4497
  try {
4474
4498
  return localStorage.getItem("aa-contrast") === "high";
4475
4499
  } catch {
4476
4500
  return false;
4477
4501
  }
4478
4502
  });
4479
- const [activeReferenceId, setActiveReferenceId] = useState20(null);
4480
- const [activeReferenceThumbnail, setActiveReferenceThumbnail] = useState20(null);
4481
- const [isScanningImage, setIsScanningImage] = useState20(false);
4482
- const [touchStartX, setTouchStartX] = useState20(null);
4483
- const [isFullscreen, setIsFullscreen] = useState20(false);
4484
- const [zoomScale, setZoomScale] = useState20(1);
4485
- const [zoomOffset, setZoomOffset] = useState20({ x: 0, y: 0 });
4503
+ const [activeReferenceId, setActiveReferenceId] = useState18(null);
4504
+ const [activeReferenceThumbnail, setActiveReferenceThumbnail] = useState18(null);
4505
+ const [isScanningImage, setIsScanningImage] = useState18(false);
4506
+ const [touchStartX, setTouchStartX] = useState18(null);
4507
+ const [isFullscreen, setIsFullscreen] = useState18(false);
4508
+ const [zoomScale, setZoomScale] = useState18(1);
4509
+ const [zoomOffset, setZoomOffset] = useState18({ x: 0, y: 0 });
4486
4510
  const lastPinchDist = useRef8(null);
4487
4511
  const lastTapTime = useRef8(0);
4488
4512
  const dragStart = useRef8(null);
@@ -4638,7 +4662,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4638
4662
  const handleGallerySelect = useCallback3((g) => {
4639
4663
  setCurrentResult(g);
4640
4664
  setMobileTab("stage");
4641
- if (g.filename && hfToken && !g.fullBase64) {
4665
+ if (g.hasThumb && g.filename && hfToken && !g.fullBase64) {
4642
4666
  hfLoadImageAsBase64(g.id, hfToken, effectiveNamespace, g.filename, void 0, g.mimeType, false).then((b64) => {
4643
4667
  if (!b64) return;
4644
4668
  const full = `data:${g.mimeType || "image/jpeg"};base64,${b64}`;
@@ -4689,7 +4713,18 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4689
4713
  })();
4690
4714
  }, [currentResult?.id, currentResult?.prompt]);
4691
4715
  const hcStyle = highContrast ? { filter: "brightness(1.6) contrast(1.05)" } : void 0;
4692
- const isGenerating = activeGenerationsCount > 0;
4716
+ const runningBadge = activeGenerationsCount > 0 ? /* @__PURE__ */ jsxs21(
4717
+ "div",
4718
+ {
4719
+ className: "flex items-center gap-1 rounded-full bg-sky-500/15 border border-sky-400/30 px-2 shrink-0",
4720
+ style: { height: 24 },
4721
+ title: `${activeGenerationsCount} Generierung${activeGenerationsCount === 1 ? "" : "en"} l\xE4uft gerade`,
4722
+ children: [
4723
+ /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-sky-300", style: { fontSize: 14, lineHeight: 1 }, children: "autorenew" }),
4724
+ /* @__PURE__ */ jsx23("span", { className: "text-[11px] font-bold text-sky-300 tabular-nums", children: activeGenerationsCount })
4725
+ ]
4726
+ }
4727
+ ) : null;
4693
4728
  useKeyboardNavigation(history, currentResult, setCurrentResult);
4694
4729
  const getSubtreeFormat = useCallback3((nodeId, depth = 0) => {
4695
4730
  const node = nodes.find((n) => n.id === nodeId);
@@ -4762,6 +4797,15 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
4762
4797
  setActiveGenerationsCount((prev) => Math.max(0, prev - 1));
4763
4798
  }
4764
4799
  };
4800
+ const handleGenerateBatch = (customPrompt, useReferenceId, overrideNodeId, options = { silent: false }) => {
4801
+ const count = Math.max(1, Math.min(8, imageCount));
4802
+ return Promise.all(
4803
+ Array.from(
4804
+ { length: count },
4805
+ (_, i) => handleGenerateImage(customPrompt, useReferenceId, overrideNodeId, { silent: options.silent || i > 0 })
4806
+ )
4807
+ );
4808
+ };
4765
4809
  const handleSynthesizePrompt = async (nodeId, autoGenerate = false) => {
4766
4810
  setIsSynthesizing(true);
4767
4811
  try {
@@ -5224,7 +5268,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5224
5268
  onClick: async () => {
5225
5269
  setIsLoadingFromHF(true);
5226
5270
  try {
5227
- const { hfListProjects: hfListProjects2, hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-5BU5DVQ6.mjs");
5271
+ const { hfListProjects: hfListProjects2, hfDownloadProject: hfDownloadProject2 } = await import("./hfStateService-PHK6676C.mjs");
5228
5272
  const projects = await hfListProjects2(hfToken);
5229
5273
  if (projects.length > 0) {
5230
5274
  const file = await hfDownloadProject2(projects[0].path, hfToken);
@@ -5335,7 +5379,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5335
5379
  /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-2 px-3 border-b border-white/5 bg-black/30 shrink-0", style: { height: 52 }, children: [
5336
5380
  /* @__PURE__ */ jsx23(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
5337
5381
  /* @__PURE__ */ jsx23(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" }] }),
5382
+ /* @__PURE__ */ jsx23(CompactDropdown, { value: String(imageCount), displayValue: `${imageCount}\xD7`, onChange: updateImageCount, options: imageCountOptions }),
5338
5383
  /* @__PURE__ */ jsx23("div", { className: "flex-1" }),
5384
+ runningBadge,
5339
5385
  activeReferenceThumbnail ? /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-1 rounded-lg border border-white/20 bg-white/5 overflow-hidden mr-2", style: { height: 28 }, children: [
5340
5386
  /* @__PURE__ */ jsx23("img", { src: activeReferenceThumbnail, className: "h-full aspect-square object-cover" }),
5341
5387
  /* @__PURE__ */ jsx23("span", { className: "text-[10px] text-white/60 font-bold uppercase tracking-wide px-1", children: "Ref" }),
@@ -5357,20 +5403,17 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5357
5403
  ),
5358
5404
  activePrompt && !isSynthesizing && /* @__PURE__ */ jsx23("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__ */ jsx23("span", { className: "material-symbols-outlined text-[18px]", children: "close" }) })
5359
5405
  ] }) }),
5360
- /* @__PURE__ */ jsx23("div", { className: "px-3 pb-3 shrink-0", children: /* @__PURE__ */ jsx23(
5406
+ /* @__PURE__ */ jsx23("div", { className: "px-3 pb-3 shrink-0", children: /* @__PURE__ */ jsxs21(
5361
5407
  "button",
5362
5408
  {
5363
- onClick: () => handleGenerateImage(),
5364
- disabled: !activePrompt.trim() || isGenerating,
5409
+ onClick: () => handleGenerateBatch(),
5410
+ disabled: !activePrompt.trim(),
5365
5411
  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",
5366
- style: { height: 48, background: activePrompt.trim() && !isGenerating ? "#0284c7" : void 0, border: "1px solid rgba(255,255,255,0.1)" },
5367
- children: isGenerating ? /* @__PURE__ */ jsxs21(Fragment9, { children: [
5368
- /* @__PURE__ */ jsx23("div", { className: "w-4 h-4 border-t-2 border-white rounded-full animate-spin" }),
5369
- /* @__PURE__ */ jsx23("span", { children: "Generiere..." })
5370
- ] }) : /* @__PURE__ */ jsxs21(Fragment9, { children: [
5412
+ style: { height: 48, background: activePrompt.trim() ? "#0284c7" : void 0, border: "1px solid rgba(255,255,255,0.1)" },
5413
+ children: [
5371
5414
  /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-[20px]", children: "bolt" }),
5372
5415
  /* @__PURE__ */ jsx23("span", { children: "Generieren" })
5373
- ] })
5416
+ ]
5374
5417
  }
5375
5418
  ) }),
5376
5419
  /* @__PURE__ */ jsxs21("div", { className: "flex-1 min-h-0 px-3 pb-3 flex flex-col", children: [
@@ -5388,9 +5431,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5388
5431
  setTouchStartX(null);
5389
5432
  },
5390
5433
  children: [
5391
- currentResult?.status === "processing" && /* @__PURE__ */ jsxs21("div", { className: "flex flex-col items-center gap-3", children: [
5392
- /* @__PURE__ */ jsx23("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
5393
- /* @__PURE__ */ jsx23("span", { className: "text-[11px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
5434
+ currentResult?.status === "processing" && /* @__PURE__ */ jsxs21("div", { className: "flex flex-col items-center gap-3 opacity-40", children: [
5435
+ /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-[40px]", children: "hourglass_top" }),
5436
+ /* @__PURE__ */ jsx23("span", { className: "text-[11px] uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
5394
5437
  ] }),
5395
5438
  currentResult?.status === "error" && /* @__PURE__ */ jsxs21("div", { className: "p-6 text-center flex flex-col items-center gap-3", children: [
5396
5439
  /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-red-400 text-[36px]", children: "warning" }),
@@ -5463,7 +5506,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5463
5506
  /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-[18px] text-white/60", children: "replay" }),
5464
5507
  /* @__PURE__ */ jsx23("span", { className: "text-[12px] text-white/60", children: "Prompt" })
5465
5508
  ] }),
5466
- /* @__PURE__ */ jsxs21("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: [
5509
+ /* @__PURE__ */ jsxs21("button", { onClick: () => handleGenerateBatch(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: [
5467
5510
  /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-[18px] text-white/80", children: "auto_fix_high" }),
5468
5511
  /* @__PURE__ */ jsx23("span", { className: "text-[12px] text-white/80 font-bold", children: "Referenz" })
5469
5512
  ] }),
@@ -5480,7 +5523,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5480
5523
  hfToken && /* @__PURE__ */ jsx23("button", { onClick: () => refreshHF(), disabled: isHfRefreshing, className: "w-12 flex items-center justify-center text-white/20 active:text-white transition-colors disabled:opacity-30", children: /* @__PURE__ */ jsx23("span", { className: `material-symbols-outlined text-[20px]${isHfRefreshing ? " animate-spin" : ""}`, children: "sync" }) })
5481
5524
  ] }),
5482
5525
  /* @__PURE__ */ jsxs21("div", { className: "flex-1 overflow-hidden relative", children: [
5483
- activeTab === "history" && /* @__PURE__ */ jsx23(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
5526
+ activeTab === "history" && /* @__PURE__ */ jsx23(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)), visibleCount: historyVisibleCount, onLoadMore: () => setHistoryVisibleCount((c) => c + 20) }),
5484
5527
  activeTab === "gallery" && /* @__PURE__ */ jsx23(
5485
5528
  MediaLibrary,
5486
5529
  {
@@ -5493,9 +5536,11 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5493
5536
  onDelete: (id) => setGalleryItems((g) => g.filter((x) => x.id !== id)),
5494
5537
  onSelect: handleGallerySelect,
5495
5538
  onGenerateReference: (item) => {
5496
- handleGenerateImage(item.prompt || activePrompt, item.mediaId, void 0, { silent: true });
5539
+ handleGenerateBatch(item.prompt || activePrompt, item.mediaId, void 0, { silent: true });
5497
5540
  setMobileTab("stage");
5498
- }
5541
+ },
5542
+ visibleCount: galleryVisibleCount,
5543
+ onLoadMore: () => setGalleryVisibleCount((c) => c + 20)
5499
5544
  }
5500
5545
  ),
5501
5546
  activeTab === "inspect" && /* @__PURE__ */ jsx23(InspectPanel, { currentResult, history, onSelect: (g) => {
@@ -5567,7 +5612,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5567
5612
  }
5568
5613
  ) }),
5569
5614
  workspaceTags && /* @__PURE__ */ jsx23("div", { style: { display: leftTab === "prompt" && activeTab !== "setup" && activeTab !== "sync" && activeTab !== "hftest" ? "flex" : "none" }, className: "absolute inset-0 flex-col", children: /* @__PURE__ */ jsx23(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => {
5570
- handleGenerateImage(prompt);
5615
+ handleGenerateBatch(prompt);
5571
5616
  setMobileTab("stage");
5572
5617
  }, onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage }) }),
5573
5618
  activeTab === "setup" && /* @__PURE__ */ jsx23(SetupPanel, { onWorkspaceImport: handleWorkspaceImport, buildInfo }),
@@ -5647,7 +5692,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5647
5692
  /* @__PURE__ */ jsxs21("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: [
5648
5693
  /* @__PURE__ */ jsx23(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
5649
5694
  /* @__PURE__ */ jsx23(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" }] }),
5695
+ /* @__PURE__ */ jsx23(CompactDropdown, { value: String(imageCount), displayValue: `${imageCount}\xD7`, onChange: updateImageCount, options: imageCountOptions }),
5650
5696
  /* @__PURE__ */ jsx23("div", { style: { flex: 1 } }),
5697
+ runningBadge,
5651
5698
  /* @__PURE__ */ jsx23("button", { onClick: toggleContrast, style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: highContrast ? "light_mode" : "dark_mode" }) }),
5652
5699
  /* @__PURE__ */ jsx23("button", { onClick: () => setShowStart(true), style: { color: "rgba(255,255,255,0.2)", background: "none", border: "none", cursor: "pointer", padding: 4, lineHeight: 0 }, children: /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "apps" }) })
5653
5700
  ] }),
@@ -5663,22 +5710,19 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5663
5710
  ),
5664
5711
  activePrompt && /* @__PURE__ */ jsx23("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__ */ jsx23("span", { className: "material-symbols-outlined", style: { fontSize: 15 }, children: "close" }) })
5665
5712
  ] }) }),
5666
- /* @__PURE__ */ jsx23("div", { style: { padding: "0 12px 10px", flexShrink: 0 }, children: /* @__PURE__ */ jsx23(
5713
+ /* @__PURE__ */ jsx23("div", { style: { padding: "0 12px 10px", flexShrink: 0 }, children: /* @__PURE__ */ jsxs21(
5667
5714
  "button",
5668
5715
  {
5669
- onClick: () => handleGenerateImage(),
5670
- disabled: !activePrompt.trim() || isGenerating,
5671
- 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" },
5672
- children: isGenerating ? /* @__PURE__ */ jsxs21(Fragment9, { children: [
5673
- /* @__PURE__ */ jsx23("div", { style: { width: 14, height: 14, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
5674
- /* @__PURE__ */ jsx23("span", { children: "Generiere..." })
5675
- ] }) : /* @__PURE__ */ jsxs21(Fragment9, { children: [
5716
+ onClick: () => handleGenerateBatch(),
5717
+ disabled: !activePrompt.trim(),
5718
+ 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() ? "#0284c7" : "transparent", color: "#fff", cursor: activePrompt.trim() ? "pointer" : "default", opacity: !activePrompt.trim() ? 0.3 : 1, fontFamily: "inherit", transition: "background 0.2s" },
5719
+ children: [
5676
5720
  /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined", style: { fontSize: 18 }, children: "bolt" }),
5677
5721
  /* @__PURE__ */ jsx23("span", { children: "Generieren" })
5678
- ] })
5722
+ ]
5679
5723
  }
5680
5724
  ) }),
5681
- /* @__PURE__ */ jsx23("div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ jsx23(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }) })
5725
+ /* @__PURE__ */ jsx23("div", { style: { flex: 1, overflow: "hidden", position: "relative" }, children: /* @__PURE__ */ jsx23(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)), visibleCount: historyVisibleCount, onLoadMore: () => setHistoryVisibleCount((c) => c + 20) }) })
5682
5726
  ] }),
5683
5727
  /* @__PURE__ */ jsxs21("div", { style: { flex: 1, height: tlH, display: "flex", flexDirection: "column", background: "#0b0b0b" }, children: [
5684
5728
  /* @__PURE__ */ jsx23(
@@ -5694,9 +5738,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5694
5738
  setTouchStartX(null);
5695
5739
  },
5696
5740
  children: /* @__PURE__ */ jsxs21("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: [
5697
- currentResult?.status === "processing" && /* @__PURE__ */ jsxs21("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
5698
- /* @__PURE__ */ jsx23("div", { style: { width: 36, height: 36, borderTop: "2px solid #fff", borderRadius: "50%", animation: "spin 1s linear infinite" } }),
5699
- /* @__PURE__ */ jsx23("span", { style: { fontSize: 10, color: "rgba(255,255,255,0.4)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
5741
+ currentResult?.status === "processing" && /* @__PURE__ */ jsxs21("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 12, opacity: 0.4 }, children: [
5742
+ /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined", style: { fontSize: 36 }, children: "hourglass_top" }),
5743
+ /* @__PURE__ */ jsx23("span", { style: { fontSize: 10, color: "rgba(255,255,255,0.6)", textTransform: "uppercase", fontWeight: "bold", letterSpacing: "0.15em" }, children: "Erstelle Bild..." })
5700
5744
  ] }),
5701
5745
  currentResult?.status === "error" && /* @__PURE__ */ jsxs21("div", { style: { padding: 24, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 12 }, children: [
5702
5746
  /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined", style: { fontSize: 32, color: "#f87171" }, children: "warning" }),
@@ -5726,7 +5770,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5726
5770
  /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "replay" }),
5727
5771
  /* @__PURE__ */ jsx23("span", { children: "Prompt" })
5728
5772
  ] }),
5729
- /* @__PURE__ */ jsxs21("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: [
5773
+ /* @__PURE__ */ jsxs21("button", { onClick: () => handleGenerateBatch(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: [
5730
5774
  /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined", style: { fontSize: 16 }, children: "auto_fix_high" }),
5731
5775
  /* @__PURE__ */ jsx23("span", { children: "Referenz" })
5732
5776
  ] }),
@@ -5796,7 +5840,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5796
5840
  isGeneratingNodeId: (id) => isSynthesizing && focusedNodeId === id
5797
5841
  }
5798
5842
  ) }),
5799
- leftTab === "prompt" && workspaceTags && activeTab !== "tags" && /* @__PURE__ */ jsx23(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 })
5843
+ leftTab === "prompt" && workspaceTags && activeTab !== "tags" && /* @__PURE__ */ jsx23(PromptTab, { workspaceTags, onGenerate: handlePromptTabGenerate, isGenerating: isPromptTabGenerating, feedback: promptFeedback, promptResult: activePrompt || null, lastPayload: lastPromptPayload, onGenerateImage: (prompt) => handleGenerateBatch(prompt), onTagCreate: handleTagCreate, onTagUpdate: handleTagUpdate, onTagDelete: handleTagDelete, onScanImage: handleScanImage, isScanning: isScanningImage })
5800
5844
  ] })
5801
5845
  ] }),
5802
5846
  !isLeftCollapsed && /* @__PURE__ */ jsx23("div", { onMouseDown: startLeftResize, className: "w-1 shrink-0 cursor-col-resize hover:bg-white/20 active:bg-white/30 transition-colors", style: { background: "transparent" } }),
@@ -5804,7 +5848,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5804
5848
  /* @__PURE__ */ jsxs21("div", { className: "h-14 border-b border-white/5 flex items-center px-4 gap-2 justify-between shrink-0 bg-black/20", children: [
5805
5849
  /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-1.5", children: [
5806
5850
  /* @__PURE__ */ jsx23(CompactDropdown, { value: aspectRatio, onChange: setAspectRatio, options: [{ label: "1:1", value: "1:1" }, { label: "16:9", value: "16:9" }, { label: "9:16", value: "9:16" }] }),
5807
- /* @__PURE__ */ jsx23(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" }] })
5851
+ /* @__PURE__ */ jsx23(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" }] }),
5852
+ /* @__PURE__ */ jsx23(CompactDropdown, { value: String(imageCount), displayValue: `${imageCount}\xD7`, onChange: updateImageCount, options: imageCountOptions })
5808
5853
  ] }),
5809
5854
  /* @__PURE__ */ jsxs21("div", { className: "flex items-center gap-1 mx-auto", children: [
5810
5855
  /* @__PURE__ */ jsx23(
@@ -5834,7 +5879,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5834
5879
  /* @__PURE__ */ jsx23("span", { children: "Ref" })
5835
5880
  ] }),
5836
5881
  /* @__PURE__ */ jsx23("button", { onClick: () => setIsPromptCollapsed(!isPromptCollapsed), className: "text-white/40 hover:text-white transition-colors", children: /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined", children: isPromptCollapsed ? "expand_more" : "expand_less" }) }),
5837
- /* @__PURE__ */ jsx23(PillButton, { variant: "solid", icon: "bolt", loading: isGenerating, disabled: !activePrompt.trim(), onClick: () => handleGenerateImage(), children: "Generieren" })
5882
+ runningBadge,
5883
+ /* @__PURE__ */ jsx23(PillButton, { variant: "solid", icon: "bolt", disabled: !activePrompt.trim(), onClick: () => handleGenerateBatch(), children: "Generieren" })
5838
5884
  ] })
5839
5885
  ] }),
5840
5886
  /* @__PURE__ */ jsxs21("div", { className: "flex-1 flex flex-col overflow-hidden relative", children: [
@@ -5846,33 +5892,27 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5846
5892
  const frame = item.frames[0];
5847
5893
  if (frame?.base64) setCurrentResult(frameToGeneration(frame, item));
5848
5894
  } }) }) : /* @__PURE__ */ jsxs21("div", { className: "flex-1 overflow-hidden flex flex-col", children: [
5849
- /* @__PURE__ */ jsx23("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsxs21("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: [
5850
- isGenerating && currentResult?.status === "done" && /* @__PURE__ */ jsxs21("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: [
5851
- /* @__PURE__ */ jsx23("div", { className: "w-3 h-3 border-t-2 border-white rounded-full animate-spin" }),
5852
- /* @__PURE__ */ jsx23("span", { className: "text-[10px] text-white/60 uppercase font-bold tracking-widest", children: "Neue Referenz..." })
5895
+ /* @__PURE__ */ jsx23("div", { className: "flex-1 p-6 overflow-hidden flex items-center justify-center", children: /* @__PURE__ */ jsx23("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: currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs21("div", { className: "flex flex-col items-center gap-4 opacity-40", children: [
5896
+ /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-[40px]", children: "hourglass_top" }),
5897
+ /* @__PURE__ */ jsx23("span", { className: "text-[10px] uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
5898
+ ] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs21("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
5899
+ /* @__PURE__ */ jsx23("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
5900
+ /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-2", children: [
5901
+ /* @__PURE__ */ jsx23("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
5902
+ /* @__PURE__ */ jsx23("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
5853
5903
  ] }),
5854
- currentResult ? currentResult.status === "processing" ? /* @__PURE__ */ jsxs21("div", { className: "flex flex-col items-center gap-4", children: [
5855
- /* @__PURE__ */ jsx23("div", { className: "w-10 h-10 border-t-2 border-white rounded-full animate-spin" }),
5856
- /* @__PURE__ */ jsx23("span", { className: "text-[10px] text-white/40 uppercase font-bold tracking-widest", children: "Erstelle Bild..." })
5857
- ] }) : currentResult.status === "error" ? /* @__PURE__ */ jsxs21("div", { className: "p-10 text-center flex flex-col items-center gap-5 max-w-md", children: [
5858
- /* @__PURE__ */ jsx23("div", { className: "w-16 h-16 rounded-full bg-red-500/10 flex items-center justify-center", children: /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-red-500 text-[32px]", children: "warning" }) }),
5859
- /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-2", children: [
5860
- /* @__PURE__ */ jsx23("h3", { className: "text-[11px] font-bold uppercase tracking-widest text-red-400", children: "Generierungsfehler" }),
5861
- /* @__PURE__ */ jsx23("p", { className: "text-white/60 text-[12px] leading-relaxed", children: currentResult.error?.message })
5862
- ] }),
5863
- /* @__PURE__ */ jsx23(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
5864
- ] }) : /* @__PURE__ */ jsxs21("div", { className: "h-full w-full relative flex items-center justify-center", children: [
5865
- /* @__PURE__ */ jsx23("img", { src: currentResult.fullBase64 || currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
5866
- /* @__PURE__ */ jsxs21("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: [
5867
- /* @__PURE__ */ jsx23(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
5868
- /* @__PURE__ */ jsx23(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateImage(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
5869
- /* @__PURE__ */ jsx23(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
5870
- ] })
5871
- ] }) : /* @__PURE__ */ jsxs21("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
5872
- /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
5873
- /* @__PURE__ */ jsx23("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
5904
+ /* @__PURE__ */ jsx23(PillButton, { variant: "outline", icon: "refresh", onClick: () => handleGenerateImage(currentResult.prompt), children: "Erneut versuchen" })
5905
+ ] }) : /* @__PURE__ */ jsxs21("div", { className: "h-full w-full relative flex items-center justify-center", children: [
5906
+ /* @__PURE__ */ jsx23("img", { src: currentResult.fullBase64 || currentResult.base64, className: "max-h-full max-w-full object-contain rounded-xl shadow-2xl" }),
5907
+ /* @__PURE__ */ jsxs21("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: [
5908
+ /* @__PURE__ */ jsx23(PillButton, { variant: "outline", icon: "replay", onClick: () => setActivePrompt(currentResult.prompt || ""), children: "Prompt" }),
5909
+ /* @__PURE__ */ jsx23(PillButton, { variant: "solid", icon: "auto_fix_high", onClick: () => handleGenerateBatch(currentResult.prompt || activePrompt, currentResult.mediaId, void 0, { silent: true }), children: "Referenz" }),
5910
+ /* @__PURE__ */ jsx23(PillButton, { variant: "outline", icon: "download", onClick: handleDownloadSingle, children: "Speichern" })
5874
5911
  ] })
5875
- ] }) }),
5912
+ ] }) : /* @__PURE__ */ jsxs21("div", { className: "flex flex-col items-center gap-2 opacity-10", children: [
5913
+ /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-[100px]", children: "palette" }),
5914
+ /* @__PURE__ */ jsx23("span", { className: "text-[12px] font-bold uppercase tracking-[0.2em]", children: "Avatar Architect" })
5915
+ ] }) }) }),
5876
5916
  currentResult?.status === "done" && currentGroup.length > 1 && /* @__PURE__ */ jsx23("div", { className: "px-6 pb-4 shrink-0 flex gap-2 overflow-x-auto", style: { scrollbarWidth: "none" }, children: currentGroup.map((item) => /* @__PURE__ */ jsxs21("div", { style: { position: "relative", flexShrink: 0 }, children: [
5877
5917
  /* @__PURE__ */ jsx23(
5878
5918
  "div",
@@ -5954,7 +5994,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5954
5994
  /* @__PURE__ */ jsx23("span", { className: "material-symbols-outlined text-[40px] text-white/10 block mb-3", children: "label_off" }),
5955
5995
  /* @__PURE__ */ jsx23("p", { className: "text-[11px] text-white/20", children: "Erst Workspace importieren um Tags zu verwalten." })
5956
5996
  ] }) }),
5957
- activeTab === "history" && /* @__PURE__ */ jsx23(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)) }),
5997
+ activeTab === "history" && /* @__PURE__ */ jsx23(HistoryPanel, { history, currentResultId: currentResult?.id || null, onSelect: handleGallerySelect, onDelete: (id) => setHistory((h) => h.filter((x) => x.id !== id)), visibleCount: historyVisibleCount, onLoadMore: () => setHistoryVisibleCount((c) => c + 20) }),
5958
5998
  activeTab === "gallery" && /* @__PURE__ */ jsx23(
5959
5999
  MediaLibrary,
5960
6000
  {
@@ -5966,7 +6006,9 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
5966
6006
  },
5967
6007
  onDelete: (id) => setGalleryItems((g) => g.filter((x) => x.id !== id)),
5968
6008
  onSelect: handleGallerySelect,
5969
- onGenerateReference: (item) => handleGenerateImage(item.prompt || activePrompt, item.mediaId, void 0, { silent: true })
6009
+ onGenerateReference: (item) => handleGenerateBatch(item.prompt || activePrompt, item.mediaId, void 0, { silent: true }),
6010
+ visibleCount: galleryVisibleCount,
6011
+ onLoadMore: () => setGalleryVisibleCount((c) => c + 20)
5970
6012
  }
5971
6013
  ),
5972
6014
  activeTab === "inspect" && /* @__PURE__ */ jsx23(InspectPanel, { currentResult, history, onSelect: setCurrentResult }),
@@ -6002,7 +6044,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
6002
6044
  }
6003
6045
 
6004
6046
  // src/components/FaApp.tsx
6005
- import { useState as useState21, useEffect as useEffect8 } from "react";
6047
+ import { useState as useState19, useEffect as useEffect8 } from "react";
6006
6048
  import { jsx as jsx24 } from "react/jsx-runtime";
6007
6049
  function FaApp({
6008
6050
  onGenerateImage,
@@ -6022,7 +6064,7 @@ function FaApp({
6022
6064
  onServerDelete,
6023
6065
  buildInfo
6024
6066
  }) {
6025
- const [hfNamespace, setHfNamespace] = useState21(void 0);
6067
+ const [hfNamespace, setHfNamespace] = useState19(void 0);
6026
6068
  useEffect8(() => {
6027
6069
  if (!serverBaseUrl) return;
6028
6070
  fetch(`${serverBaseUrl}/api/status`).then((r) => r.json()).then((d) => {
@@ -6055,7 +6097,7 @@ function FaApp({
6055
6097
  }
6056
6098
 
6057
6099
  // src/index.ts
6058
- var LIB_VERSION = "2.0.56";
6100
+ var LIB_VERSION = "2.0.61";
6059
6101
  export {
6060
6102
  AvatarArchitectApp,
6061
6103
  CollapsibleCard,