dsh-image-gen 0.6.11 → 0.8.0
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/lib/client.js +2676 -359
- package/lib/client.js.map +1 -1
- package/lib/index.js +7867 -1176
- package/lib/types/baoyu-compose.d.ts +61 -0
- package/lib/types/client/gallery-store.d.ts +40 -1
- package/lib/types/client/gallery-view.d.ts +22 -0
- package/lib/types/client/index.d.ts +10 -3
- package/lib/types/client/inspiration-image-cache.d.ts +2 -2
- package/lib/types/client/inspiration-style.d.ts +1 -1
- package/lib/types/client/inspiration-view.d.ts +1 -0
- package/lib/types/client/settings-write.d.ts +4 -0
- package/lib/types/client/studio-style.d.ts +1 -1
- package/lib/types/client/studio-view.d.ts +3 -0
- package/lib/types/client/tl/studio-tl-canvas.d.ts +7 -0
- package/lib/types/client/tl/tl-brand-theme.d.ts +7 -0
- package/lib/types/config.d.ts +26 -7
- package/lib/types/import-route.d.ts +16 -0
- package/lib/types/index.d.ts +1 -0
- package/lib/types/inspiration.d.ts +40 -1
- package/lib/types/openai-compatible.d.ts +1 -1
- package/lib/types/shared.d.ts +8 -0
- package/lib/types/studio-route.d.ts +2 -0
- package/lib/types/studio.d.ts +24 -0
- package/package.json +20 -20
- package/lib/types/client/canvas/canvas-bridge.d.ts +0 -10
- package/lib/types/client/canvas/canvas-model.d.ts +0 -129
- package/lib/types/client/canvas/canvas-nodes.d.ts +0 -23
- package/lib/types/client/canvas/canvas-store.d.ts +0 -29
- package/lib/types/client/canvas/canvas-style.d.ts +0 -1
- package/lib/types/client/canvas/canvas-view.d.ts +0 -8
- package/lib/types/client/canvas/rf-base-css.d.ts +0 -2
- package/lib/types/client/studio-chat-panel.d.ts +0 -23
- package/lib/types/client/tl/diagram-landing.d.ts +0 -75
- package/lib/types/client/tl/diagram-layout.d.ts +0 -76
- package/lib/types/client/tl/diagram-measure.d.ts +0 -40
- package/lib/types/diagram.d.ts +0 -42
- package/lib/types/studio-chat.d.ts +0 -48
package/lib/client.js
CHANGED
|
@@ -75,6 +75,8 @@ window.__ModuleLoader__.load({
|
|
|
75
75
|
//#region lib/types/shared.js
|
|
76
76
|
/** Browser route used by the generated-image card. */
|
|
77
77
|
const IMAGE_ROUTE = "/plugins/dsh-image-gen/image";
|
|
78
|
+
/** Browser route that uploads user-picked images as DSH attachments. */
|
|
79
|
+
const IMPORT_ROUTE = "/plugins/dsh-image-gen/import";
|
|
78
80
|
/** Browser route used for deleting generated images and workspace files. */
|
|
79
81
|
const DELETE_ROUTE = "/plugins/dsh-image-gen/delete";
|
|
80
82
|
/** Same-origin route used by the browser image workbench. */
|
|
@@ -300,9 +302,11 @@ window.__ModuleLoader__.load({
|
|
|
300
302
|
//#endregion
|
|
301
303
|
//#region lib/types/client/gallery-store.js
|
|
302
304
|
const DB_NAME$2 = "dsh_image_gen_db";
|
|
303
|
-
const DB_VERSION =
|
|
305
|
+
const DB_VERSION = 4;
|
|
304
306
|
const STORE_NAME = "gallery_history";
|
|
305
307
|
const TOMBSTONE_STORE = "gallery_tombstones";
|
|
308
|
+
const FAV_PROMPT_STORE = "favorite_prompts";
|
|
309
|
+
const FAV_FOLDER_STORE = "favorite_folders";
|
|
306
310
|
let dbPromise = null;
|
|
307
311
|
let tombstonesCache = null;
|
|
308
312
|
function getDB() {
|
|
@@ -317,14 +321,25 @@ window.__ModuleLoader__.load({
|
|
|
317
321
|
const db = event.target.result;
|
|
318
322
|
if (!db.objectStoreNames.contains(STORE_NAME)) db.createObjectStore(STORE_NAME, { keyPath: "id" }).createIndex("createdAt", "createdAt", { unique: false });
|
|
319
323
|
if (!db.objectStoreNames.contains(TOMBSTONE_STORE)) db.createObjectStore(TOMBSTONE_STORE, { keyPath: "id" });
|
|
324
|
+
if (!db.objectStoreNames.contains(FAV_PROMPT_STORE)) db.createObjectStore(FAV_PROMPT_STORE, { keyPath: "id" });
|
|
325
|
+
if (!db.objectStoreNames.contains(FAV_FOLDER_STORE)) db.createObjectStore(FAV_FOLDER_STORE, { keyPath: "id" });
|
|
320
326
|
};
|
|
321
327
|
request.onsuccess = () => {
|
|
322
|
-
|
|
328
|
+
const db = request.result;
|
|
329
|
+
db.onversionchange = () => {
|
|
330
|
+
db.close();
|
|
331
|
+
dbPromise = null;
|
|
332
|
+
};
|
|
333
|
+
resolve(db);
|
|
323
334
|
};
|
|
324
335
|
request.onerror = () => {
|
|
325
336
|
dbPromise = null;
|
|
326
337
|
reject(request.error);
|
|
327
338
|
};
|
|
339
|
+
request.onblocked = () => {
|
|
340
|
+
dbPromise = null;
|
|
341
|
+
reject(/* @__PURE__ */ new Error("IndexedDB upgrade blocked. Close other open Studio tabs and retry."));
|
|
342
|
+
};
|
|
328
343
|
});
|
|
329
344
|
return dbPromise;
|
|
330
345
|
}
|
|
@@ -551,6 +566,7 @@ window.__ModuleLoader__.load({
|
|
|
551
566
|
*/
|
|
552
567
|
function isItemInWorkspace(item, workspace) {
|
|
553
568
|
if (!workspace || !workspace.workspaceId && !workspace.path && (!workspace.sessionIds || workspace.sessionIds.length === 0)) return true;
|
|
569
|
+
if (!item.workspaceId && !item.sessionId && !item.workspacePath && !item.savedTo) return true;
|
|
554
570
|
if (item.workspaceId && workspace.workspaceId && item.workspaceId === workspace.workspaceId) return true;
|
|
555
571
|
if (item.sessionId && Array.isArray(workspace.sessionIds) && workspace.sessionIds.includes(item.sessionId)) return true;
|
|
556
572
|
if (item.workspacePath && workspace.path) {
|
|
@@ -563,6 +579,234 @@ window.__ModuleLoader__.load({
|
|
|
563
579
|
}
|
|
564
580
|
return false;
|
|
565
581
|
}
|
|
582
|
+
const favoriteListeners = /* @__PURE__ */ new Set();
|
|
583
|
+
function notifyFavorites() {
|
|
584
|
+
for (const listener of favoriteListeners) try {
|
|
585
|
+
listener();
|
|
586
|
+
} catch (err) {
|
|
587
|
+
console.error("[dsh-image-gen] Favorites listener error:", err);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
/** Subscribe to favorites mutations (insert/delete). */
|
|
591
|
+
function subscribeFavorites(listener) {
|
|
592
|
+
favoriteListeners.add(listener);
|
|
593
|
+
return () => {
|
|
594
|
+
favoriteListeners.delete(listener);
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
/** Stable base36 id for a favorite prompt; identical trimmed text dedupes. */
|
|
598
|
+
function promptIdOf(text) {
|
|
599
|
+
let hash = 5381;
|
|
600
|
+
for (let i = 0; i < text.length; i++) hash = (hash << 5) + hash + text.charCodeAt(i) | 0;
|
|
601
|
+
return `p${(hash >>> 0).toString(36)}-${text.length.toString(36)}`;
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Collision-free prompt id. Distinct texts can share the djb2 hash and the
|
|
605
|
+
* length, which would silently overwrite an unrelated saved prompt; suffix
|
|
606
|
+
* until the id is free or already owned by the same text.
|
|
607
|
+
*/
|
|
608
|
+
async function uniquePromptId(db, text) {
|
|
609
|
+
const rows = await readAll(db, FAV_PROMPT_STORE);
|
|
610
|
+
const byId = new Map(rows.map((row) => [row.id, row]));
|
|
611
|
+
const base = promptIdOf(text);
|
|
612
|
+
let candidate = base;
|
|
613
|
+
let suffix = 1;
|
|
614
|
+
while (byId.has(candidate) && byId.get(candidate)?.text !== text) {
|
|
615
|
+
suffix++;
|
|
616
|
+
candidate = `${base}-${suffix}`;
|
|
617
|
+
}
|
|
618
|
+
return candidate;
|
|
619
|
+
}
|
|
620
|
+
function readAll(db, storeName) {
|
|
621
|
+
return new Promise((resolve, reject) => {
|
|
622
|
+
const req = db.transaction(storeName, "readonly").objectStore(storeName).openCursor();
|
|
623
|
+
const rows = [];
|
|
624
|
+
req.onsuccess = (event) => {
|
|
625
|
+
const cursor = event.target.result;
|
|
626
|
+
if (cursor) {
|
|
627
|
+
rows.push(cursor.value);
|
|
628
|
+
cursor.continue();
|
|
629
|
+
} else resolve(rows);
|
|
630
|
+
};
|
|
631
|
+
req.onerror = () => reject(req.error);
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Keep one prompt in the favorites rail; identical trimmed text overwrites
|
|
636
|
+
* (one record per distinct prompt).
|
|
637
|
+
* @returns false when the write failed.
|
|
638
|
+
*/
|
|
639
|
+
async function saveFavoritePrompt(text) {
|
|
640
|
+
const trimmed = text.trim();
|
|
641
|
+
if (trimmed.length === 0) return false;
|
|
642
|
+
try {
|
|
643
|
+
const db = await getDB();
|
|
644
|
+
const id = await uniquePromptId(db, trimmed);
|
|
645
|
+
await new Promise((resolve, reject) => {
|
|
646
|
+
const req = db.transaction(FAV_PROMPT_STORE, "readwrite").objectStore(FAV_PROMPT_STORE).put({
|
|
647
|
+
id,
|
|
648
|
+
text: trimmed,
|
|
649
|
+
addedAt: Date.now()
|
|
650
|
+
});
|
|
651
|
+
req.onsuccess = () => resolve();
|
|
652
|
+
req.onerror = () => reject(req.error);
|
|
653
|
+
});
|
|
654
|
+
notifyFavorites();
|
|
655
|
+
return true;
|
|
656
|
+
} catch (err) {
|
|
657
|
+
console.warn("[dsh-image-gen] Failed to save favorite prompt:", err);
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
/** Prompt favorites, newest first. */
|
|
662
|
+
async function getFavoritePrompts() {
|
|
663
|
+
try {
|
|
664
|
+
return (await readAll(await getDB(), FAV_PROMPT_STORE)).sort((a, b) => b.addedAt - a.addedAt);
|
|
665
|
+
} catch (err) {
|
|
666
|
+
console.warn("[dsh-image-gen] Failed to read favorite prompts:", err);
|
|
667
|
+
return [];
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/** Drop one prompt favorite. */
|
|
671
|
+
async function deleteFavoritePrompt(id) {
|
|
672
|
+
try {
|
|
673
|
+
const db = await getDB();
|
|
674
|
+
await new Promise((resolve, reject) => {
|
|
675
|
+
const req = db.transaction(FAV_PROMPT_STORE, "readwrite").objectStore(FAV_PROMPT_STORE).delete(id);
|
|
676
|
+
req.onsuccess = () => resolve();
|
|
677
|
+
req.onerror = () => reject(req.error);
|
|
678
|
+
});
|
|
679
|
+
notifyFavorites();
|
|
680
|
+
} catch (err) {
|
|
681
|
+
console.warn("[dsh-image-gen] Failed to delete favorite prompt:", err);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
function folderIdOf(kind, name) {
|
|
685
|
+
return `f-${kind}-${name.trim().toLowerCase().replace(/\s+/g, "-")}-${name.length.toString(36)}`;
|
|
686
|
+
}
|
|
687
|
+
/** Create a favorites folder; returns null when the name is empty or already used for the kind. */
|
|
688
|
+
async function addFavoriteFolder(kind, name) {
|
|
689
|
+
const trimmed = name.trim();
|
|
690
|
+
if (trimmed === "") return null;
|
|
691
|
+
try {
|
|
692
|
+
const db = await getDB();
|
|
693
|
+
if ((await readAll(db, FAV_FOLDER_STORE)).some((folder) => folder.kind === kind && folder.name === trimmed)) return null;
|
|
694
|
+
const folder = {
|
|
695
|
+
id: folderIdOf(kind, trimmed),
|
|
696
|
+
kind,
|
|
697
|
+
name: trimmed,
|
|
698
|
+
addedAt: Date.now()
|
|
699
|
+
};
|
|
700
|
+
await new Promise((resolve, reject) => {
|
|
701
|
+
const req = db.transaction(FAV_FOLDER_STORE, "readwrite").objectStore(FAV_FOLDER_STORE).put(folder);
|
|
702
|
+
req.onsuccess = () => resolve();
|
|
703
|
+
req.onerror = () => reject(req.error);
|
|
704
|
+
});
|
|
705
|
+
notifyFavorites();
|
|
706
|
+
return folder;
|
|
707
|
+
} catch (err) {
|
|
708
|
+
console.warn("[dsh-image-gen] Failed to add favorite folder:", err);
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
/** List all favorite folders. */
|
|
713
|
+
async function getFavoriteFolders() {
|
|
714
|
+
try {
|
|
715
|
+
return (await readAll(await getDB(), FAV_FOLDER_STORE)).sort((a, b) => a.addedAt - b.addedAt);
|
|
716
|
+
} catch (err) {
|
|
717
|
+
console.warn("[dsh-image-gen] Failed to read favorite folders:", err);
|
|
718
|
+
return [];
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
/** Delete a folder; member favorites survive and become unfiled. */
|
|
722
|
+
async function deleteFavoriteFolder(id) {
|
|
723
|
+
try {
|
|
724
|
+
const db = await getDB();
|
|
725
|
+
await new Promise((resolve, reject) => {
|
|
726
|
+
const tx = db.transaction(FAV_PROMPT_STORE, "readwrite");
|
|
727
|
+
const req = tx.objectStore(FAV_PROMPT_STORE).openCursor();
|
|
728
|
+
req.onsuccess = (event) => {
|
|
729
|
+
const cursor = event.target.result;
|
|
730
|
+
if (cursor) {
|
|
731
|
+
const row = cursor.value;
|
|
732
|
+
if (row.folderId === id) {
|
|
733
|
+
delete row.folderId;
|
|
734
|
+
cursor.update(row);
|
|
735
|
+
}
|
|
736
|
+
cursor.continue();
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
tx.oncomplete = () => resolve();
|
|
740
|
+
tx.onerror = () => reject(tx.error);
|
|
741
|
+
});
|
|
742
|
+
await new Promise((resolve, reject) => {
|
|
743
|
+
const req = db.transaction(FAV_FOLDER_STORE, "readwrite").objectStore(FAV_FOLDER_STORE).delete(id);
|
|
744
|
+
req.onsuccess = () => resolve();
|
|
745
|
+
req.onerror = () => reject(req.error);
|
|
746
|
+
});
|
|
747
|
+
notifyFavorites();
|
|
748
|
+
} catch (err) {
|
|
749
|
+
console.warn("[dsh-image-gen] Failed to delete favorite folder:", err);
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
async function moveFavorite(storeName, id, folderId) {
|
|
753
|
+
try {
|
|
754
|
+
const db = await getDB();
|
|
755
|
+
const ok = await new Promise((resolve, reject) => {
|
|
756
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
757
|
+
const req = tx.objectStore(storeName).get(id);
|
|
758
|
+
req.onsuccess = () => {
|
|
759
|
+
const row = req.result;
|
|
760
|
+
if (row === void 0) {
|
|
761
|
+
resolve(false);
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
if (folderId === void 0) delete row.folderId;
|
|
765
|
+
else row.folderId = folderId;
|
|
766
|
+
tx.objectStore(storeName).put(row);
|
|
767
|
+
resolve(true);
|
|
768
|
+
};
|
|
769
|
+
tx.onerror = () => reject(tx.error);
|
|
770
|
+
});
|
|
771
|
+
if (ok) notifyFavorites();
|
|
772
|
+
return ok;
|
|
773
|
+
} catch (err) {
|
|
774
|
+
console.warn("[dsh-image-gen] Failed to move favorite:", err);
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
/** File a favorite prompt into a folder (undefined unfiles it). */
|
|
779
|
+
function moveFavoritePrompt(id, folderId) {
|
|
780
|
+
return moveFavorite(FAV_PROMPT_STORE, id, folderId);
|
|
781
|
+
}
|
|
782
|
+
/** Rewrite a favorite prompt's text in place, keeping its id stable. */
|
|
783
|
+
async function updateFavoritePrompt(id, text) {
|
|
784
|
+
const trimmed = text.trim();
|
|
785
|
+
if (trimmed === "") return false;
|
|
786
|
+
try {
|
|
787
|
+
const db = await getDB();
|
|
788
|
+
const ok = await new Promise((resolve, reject) => {
|
|
789
|
+
const tx = db.transaction(FAV_PROMPT_STORE, "readwrite");
|
|
790
|
+
const req = tx.objectStore(FAV_PROMPT_STORE).get(id);
|
|
791
|
+
req.onsuccess = () => {
|
|
792
|
+
const row = req.result;
|
|
793
|
+
if (row === void 0) {
|
|
794
|
+
resolve(false);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
row.text = trimmed;
|
|
798
|
+
tx.objectStore(FAV_PROMPT_STORE).put(row);
|
|
799
|
+
resolve(true);
|
|
800
|
+
};
|
|
801
|
+
tx.onerror = () => reject(tx.error);
|
|
802
|
+
});
|
|
803
|
+
if (ok) notifyFavorites();
|
|
804
|
+
return ok;
|
|
805
|
+
} catch (err) {
|
|
806
|
+
console.warn("[dsh-image-gen] Failed to update favorite prompt:", err);
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
566
810
|
//#endregion
|
|
567
811
|
//#region node_modules/.pnpm/lucide-react@1.38.0_react@18.3.1/node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs
|
|
568
812
|
/**
|
|
@@ -1209,6 +1453,34 @@ window.__ModuleLoader__.load({
|
|
|
1209
1453
|
* This source code is licensed under the ISC license.
|
|
1210
1454
|
* See the LICENSE file in the root directory of this source tree.
|
|
1211
1455
|
*/
|
|
1456
|
+
const Shuffle = createLucideIcon("shuffle", [
|
|
1457
|
+
["path", {
|
|
1458
|
+
d: "m18 14 4 4-4 4",
|
|
1459
|
+
key: "10pe0f"
|
|
1460
|
+
}],
|
|
1461
|
+
["path", {
|
|
1462
|
+
d: "m18 2 4 4-4 4",
|
|
1463
|
+
key: "pucp1d"
|
|
1464
|
+
}],
|
|
1465
|
+
["path", {
|
|
1466
|
+
d: "M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22",
|
|
1467
|
+
key: "1ailkh"
|
|
1468
|
+
}],
|
|
1469
|
+
["path", {
|
|
1470
|
+
d: "M2 6h1.972a4 4 0 0 1 3.6 2.2",
|
|
1471
|
+
key: "km57vx"
|
|
1472
|
+
}],
|
|
1473
|
+
["path", {
|
|
1474
|
+
d: "M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45",
|
|
1475
|
+
key: "os18l9"
|
|
1476
|
+
}]
|
|
1477
|
+
]);
|
|
1478
|
+
/**
|
|
1479
|
+
* @license lucide-react v1.38.0 - ISC
|
|
1480
|
+
*
|
|
1481
|
+
* This source code is licensed under the ISC license.
|
|
1482
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1483
|
+
*/
|
|
1212
1484
|
const SlidersHorizontal = createLucideIcon("sliders-horizontal", [
|
|
1213
1485
|
["path", {
|
|
1214
1486
|
d: "M10 5H3",
|
|
@@ -115760,6 +116032,24 @@ img.ProseMirror-separator {
|
|
|
115760
116032
|
}
|
|
115761
116033
|
});
|
|
115762
116034
|
}
|
|
116035
|
+
/**
|
|
116036
|
+
* Match tldraw's light/dark canvas to the DSH host theme. The host publishes
|
|
116037
|
+
* dark mode as the data-ds-dark-theme attribute on <body>; tldraw keeps its
|
|
116038
|
+
* own persisted user preference, so apply the host value now and observe
|
|
116039
|
+
* later flips. Returns the observer disposer.
|
|
116040
|
+
*/
|
|
116041
|
+
function syncTldrawThemeWithHost(editor) {
|
|
116042
|
+
const apply = () => {
|
|
116043
|
+
editor.user.updateUserPreferences({ colorScheme: document.body.hasAttribute("data-ds-dark-theme") ? "dark" : "light" });
|
|
116044
|
+
};
|
|
116045
|
+
apply();
|
|
116046
|
+
const observer = new MutationObserver(apply);
|
|
116047
|
+
observer.observe(document.body, {
|
|
116048
|
+
attributes: true,
|
|
116049
|
+
attributeFilter: ["data-ds-dark-theme"]
|
|
116050
|
+
});
|
|
116051
|
+
return () => observer.disconnect();
|
|
116052
|
+
}
|
|
115763
116053
|
//#endregion
|
|
115764
116054
|
//#region lib/types/client/tl/canvas-selection.js
|
|
115765
116055
|
/** Bound raster dimensions before exporting; large multi-image PNGs get a
|
|
@@ -116227,6 +116517,7 @@ img.ProseMirror-separator {
|
|
|
116227
116517
|
const GRID_GAP = 40;
|
|
116228
116518
|
const GRID_COLS = 3;
|
|
116229
116519
|
const mountedCanvases = /* @__PURE__ */ new Set();
|
|
116520
|
+
const mountedEditors = /* @__PURE__ */ new Set();
|
|
116230
116521
|
/** Reset canvas-owned data only. Gallery records and host attachments are untouched. */
|
|
116231
116522
|
function clearStudioTlCanvases() {
|
|
116232
116523
|
if (mountedCanvases.size === 0) return false;
|
|
@@ -116236,6 +116527,17 @@ img.ProseMirror-separator {
|
|
|
116236
116527
|
return true;
|
|
116237
116528
|
}
|
|
116238
116529
|
/**
|
|
116530
|
+
* Cancel in-editor selection on every mounted canvas, keeping shapes and sync
|
|
116531
|
+
* untouched. Selection is interaction state tied to the surface: leaving the
|
|
116532
|
+
* studio page cancels it so a stale selection can neither resurface on return
|
|
116533
|
+
* nor linger in the host mirror.
|
|
116534
|
+
*/
|
|
116535
|
+
function deselectStudioTlCanvases() {
|
|
116536
|
+
if (mountedEditors.size === 0) return false;
|
|
116537
|
+
for (const editor of mountedEditors) editor.run(() => editor.selectNone());
|
|
116538
|
+
return true;
|
|
116539
|
+
}
|
|
116540
|
+
/**
|
|
116239
116541
|
* Dock the stock toolbar vertically along the left edge (Figma-style) instead
|
|
116240
116542
|
* of tldraw's signature bottom-center pill. It is still the same
|
|
116241
116543
|
* DefaultToolbar with the same tools and overflow handling — only the
|
|
@@ -116410,7 +116712,10 @@ img.ProseMirror-separator {
|
|
|
116410
116712
|
const retrySync = (0, react.useRef)(() => {});
|
|
116411
116713
|
const onMount = (0, react.useCallback)((editor) => {
|
|
116412
116714
|
let active = true;
|
|
116715
|
+
editor.run(() => editor.selectNone());
|
|
116716
|
+
mountedEditors.add(editor);
|
|
116413
116717
|
applyBrandTheme(editor);
|
|
116718
|
+
const stopThemeSync = syncTldrawThemeWithHost(editor);
|
|
116414
116719
|
editor.updateInstanceState({ isGridMode: true });
|
|
116415
116720
|
console.info(`[dsh-image-gen] tldraw mounted (instance ${editor.id})`);
|
|
116416
116721
|
const stopLanding = registerTlLandingConsumer((items) => {
|
|
@@ -116443,8 +116748,10 @@ img.ProseMirror-separator {
|
|
|
116443
116748
|
mountedCanvases.add(clear);
|
|
116444
116749
|
return () => {
|
|
116445
116750
|
active = false;
|
|
116751
|
+
mountedEditors.delete(editor);
|
|
116446
116752
|
mountedCanvases.delete(clear);
|
|
116447
116753
|
stopLanding();
|
|
116754
|
+
stopThemeSync();
|
|
116448
116755
|
stopSync();
|
|
116449
116756
|
retrySync.current = () => {};
|
|
116450
116757
|
};
|
|
@@ -116489,6 +116796,31 @@ img.ProseMirror-separator {
|
|
|
116489
116796
|
unconfigured: "未配置",
|
|
116490
116797
|
recent: "最近生成",
|
|
116491
116798
|
empty: "暂无生成历史",
|
|
116799
|
+
railTabRecent: "最新生成",
|
|
116800
|
+
railTabFavorites: "收藏",
|
|
116801
|
+
favImages: "收藏图片",
|
|
116802
|
+
favPrompts: "收藏提示词",
|
|
116803
|
+
favNewFolder: "新建文件夹",
|
|
116804
|
+
favFolderPlaceholder: "文件夹名称",
|
|
116805
|
+
favCreate: "创建",
|
|
116806
|
+
favCancel: "取消",
|
|
116807
|
+
favMoveTo: "移动到文件夹",
|
|
116808
|
+
favNoFolder: "未分组",
|
|
116809
|
+
favMove: "移动",
|
|
116810
|
+
favDeleteFolder: "删除文件夹",
|
|
116811
|
+
favEditPrompt: "编辑提示词",
|
|
116812
|
+
favUse: "使用",
|
|
116813
|
+
favSave: "保存",
|
|
116814
|
+
favEditPromptPlaceholder: "输入提示词内容…",
|
|
116815
|
+
favFolder: "所属文件夹",
|
|
116816
|
+
favEmptyImages: "在图片操作区点「收藏」后,图片会显示在这里",
|
|
116817
|
+
favEmptyPrompts: "点提示词输入框旁的「☆ 收藏」后,提示词会显示在这里",
|
|
116818
|
+
favoritePrompt: "收藏提示词",
|
|
116819
|
+
favActionShort: "收藏",
|
|
116820
|
+
favPromptSaved: "已收藏提示词",
|
|
116821
|
+
favPromptApplied: "已填入提示词",
|
|
116822
|
+
favRefApplied: "已加入参考图",
|
|
116823
|
+
favSaveFailed: "收藏失败,请重试",
|
|
116492
116824
|
generate: "文生图",
|
|
116493
116825
|
edit: "图生图",
|
|
116494
116826
|
reference: "参考图",
|
|
@@ -116545,6 +116877,8 @@ img.ProseMirror-separator {
|
|
|
116545
116877
|
infiniteCanvas: "无限画布",
|
|
116546
116878
|
loading: "正在读取图片…",
|
|
116547
116879
|
generationFailed: "生成失败",
|
|
116880
|
+
gatewayTimeout: "请求被反向代理中断(超时):请重试;反复出现需调大代理超时或换直连网络",
|
|
116881
|
+
requestFailed: "请求失败(HTTP {status})",
|
|
116548
116882
|
selectHistory: "从左侧选择一张图片,或在右侧开始新的生成。",
|
|
116549
116883
|
created: "生成时间",
|
|
116550
116884
|
elapsed: "耗时",
|
|
@@ -116552,6 +116886,7 @@ img.ProseMirror-separator {
|
|
|
116552
116886
|
output: "输出参数",
|
|
116553
116887
|
closeReference: "移除参考图",
|
|
116554
116888
|
uploadInvalid: "请选择有效的图片文件(最大 10MB)",
|
|
116889
|
+
uploadUnreadable: "部分图片读取失败,请重新选择后再试",
|
|
116555
116890
|
imageLoadFailed: "图片读取失败",
|
|
116556
116891
|
fullscreen: "大图全屏",
|
|
116557
116892
|
close: "关闭",
|
|
@@ -116598,6 +116933,31 @@ img.ProseMirror-separator {
|
|
|
116598
116933
|
unconfigured: "Not configured",
|
|
116599
116934
|
recent: "Recent generations",
|
|
116600
116935
|
empty: "No generated images yet",
|
|
116936
|
+
railTabRecent: "Latest",
|
|
116937
|
+
railTabFavorites: "Favorites",
|
|
116938
|
+
favImages: "Favorite images",
|
|
116939
|
+
favPrompts: "Favorite prompts",
|
|
116940
|
+
favNewFolder: "New folder",
|
|
116941
|
+
favFolderPlaceholder: "Folder name",
|
|
116942
|
+
favCreate: "Create",
|
|
116943
|
+
favCancel: "Cancel",
|
|
116944
|
+
favMoveTo: "Move to folder",
|
|
116945
|
+
favNoFolder: "Unfiled",
|
|
116946
|
+
favMove: "Move",
|
|
116947
|
+
favDeleteFolder: "Delete folder",
|
|
116948
|
+
favEditPrompt: "Edit prompt",
|
|
116949
|
+
favUse: "Use",
|
|
116950
|
+
favSave: "Save",
|
|
116951
|
+
favEditPromptPlaceholder: "Prompt text…",
|
|
116952
|
+
favFolder: "Folder",
|
|
116953
|
+
favEmptyImages: "Click Favorite on an image; favorited images appear here",
|
|
116954
|
+
favEmptyPrompts: "Click ☆ Save beside the prompt box",
|
|
116955
|
+
favoritePrompt: "Save prompt",
|
|
116956
|
+
favActionShort: "Save",
|
|
116957
|
+
favPromptSaved: "Prompt saved",
|
|
116958
|
+
favPromptApplied: "Prompt applied",
|
|
116959
|
+
favRefApplied: "Reference added",
|
|
116960
|
+
favSaveFailed: "Could not save; please retry",
|
|
116601
116961
|
generate: "Text to image",
|
|
116602
116962
|
edit: "Image to image",
|
|
116603
116963
|
reference: "Reference image",
|
|
@@ -116654,6 +117014,8 @@ img.ProseMirror-separator {
|
|
|
116654
117014
|
infiniteCanvas: "Infinite canvas",
|
|
116655
117015
|
loading: "Loading image…",
|
|
116656
117016
|
generationFailed: "Generation failed",
|
|
117017
|
+
gatewayTimeout: "The reverse proxy cut the request (timeout): retry; if it repeats, raise the proxy timeout or use a direct network.",
|
|
117018
|
+
requestFailed: "Request failed (HTTP {status})",
|
|
116657
117019
|
selectHistory: "Select an image on the left, or start a new generation on the right.",
|
|
116658
117020
|
created: "Created",
|
|
116659
117021
|
elapsed: "Elapsed",
|
|
@@ -116661,6 +117023,7 @@ img.ProseMirror-separator {
|
|
|
116661
117023
|
output: "Output",
|
|
116662
117024
|
closeReference: "Remove reference",
|
|
116663
117025
|
uploadInvalid: "Choose a valid image file up to 10MB.",
|
|
117026
|
+
uploadUnreadable: "Some images could not be read; pick them again.",
|
|
116664
117027
|
imageLoadFailed: "Could not load image",
|
|
116665
117028
|
fullscreen: "Fullscreen",
|
|
116666
117029
|
close: "Close",
|
|
@@ -116704,17 +117067,28 @@ img.ProseMirror-separator {
|
|
|
116704
117067
|
};
|
|
116705
117068
|
/** localStorage flag remembering that the one-time infinite-canvas hint was dismissed. */
|
|
116706
117069
|
const INFINITE_CANVAS_HINT_KEY = "dsh-ig-infinite-canvas-hint-dismissed";
|
|
116707
|
-
const StudioView = ({ locale, credentialEvents, workspace, initialPrompt, initialCanvasSurface, showInfiniteCanvasHint, onInitialPromptApplied, onOpenInspiration }) => {
|
|
117070
|
+
const StudioView = ({ locale, credentialEvents, workspace, initialPrompt, initialReference, initialCanvasSurface, showInfiniteCanvasHint, onInitialPromptApplied, onInitialReferenceApplied, onOpenInspiration }) => {
|
|
116708
117071
|
const [lang, setLang] = (0, react.useState)(() => locale?.getSnapshot?.().active?.startsWith("en") ? "en" : "zh");
|
|
116709
117072
|
const [config, setConfig] = (0, react.useState)(null);
|
|
116710
117073
|
const [configLoading, setConfigLoading] = (0, react.useState)(true);
|
|
116711
117074
|
const [configError, setConfigError] = (0, react.useState)(null);
|
|
116712
117075
|
const [items, setItems] = (0, react.useState)([]);
|
|
117076
|
+
/** Which rail tab is showing: generation history or the favorites rail. */
|
|
117077
|
+
const [railTab, setRailTab] = (0, react.useState)("recent");
|
|
117078
|
+
const [favPrompts, setFavPrompts] = (0, react.useState)([]);
|
|
117079
|
+
const [favFolders, setFavFolders] = (0, react.useState)([]);
|
|
117080
|
+
const [activePromptFolder, setActivePromptFolder] = (0, react.useState)("");
|
|
117081
|
+
const [folderDraft, setFolderDraft] = (0, react.useState)(null);
|
|
117082
|
+
const [folderDraftName, setFolderDraftName] = (0, react.useState)("");
|
|
117083
|
+
const [editingPrompt, setEditingPrompt] = (0, react.useState)(null);
|
|
117084
|
+
const [editPromptText, setEditPromptText] = (0, react.useState)("");
|
|
117085
|
+
const [editPromptFolder, setEditPromptFolder] = (0, react.useState)("");
|
|
117086
|
+
const [movingFav, setMovingFav] = (0, react.useState)(null);
|
|
116713
117087
|
const [sidebarCollapsed, setSidebarCollapsed] = (0, react.useState)(false);
|
|
116714
117088
|
/** Manual-only collapse for the right generate form; the form stays put in
|
|
116715
117089
|
* narrow seats because it is the primary generation surface. Starts folded
|
|
116716
117090
|
* when the studio opens straight into the infinite canvas. */
|
|
116717
|
-
const [generateCollapsed, setGenerateCollapsed] = (0, react.useState)(initialCanvasSurface === "infinite");
|
|
117091
|
+
const [generateCollapsed, setGenerateCollapsed] = (0, react.useState)(initialCanvasSurface === "infinite" && initialPrompt === void 0);
|
|
116718
117092
|
/** Workbench root, observed so a narrow column (right sidebar) can fold the recent rail. */
|
|
116719
117093
|
const workbenchRootRef = (0, react.useRef)(null);
|
|
116720
117094
|
/** Set once the user toggles the rail by hand; auto-folding then stands down for this mount. */
|
|
@@ -116818,6 +117192,15 @@ img.ProseMirror-separator {
|
|
|
116818
117192
|
for (const [name, value] of Object.entries(values ?? {})) text = text.replace(`{${name}}`, value);
|
|
116819
117193
|
return text;
|
|
116820
117194
|
};
|
|
117195
|
+
/** Parse a studio response body; a gateway HTML error page (502/504 from a
|
|
117196
|
+
* reverse proxy) must surface as a readable message, not a JSON SyntaxError. */
|
|
117197
|
+
const readStudioBody = async (response) => {
|
|
117198
|
+
try {
|
|
117199
|
+
return await response.json();
|
|
117200
|
+
} catch {
|
|
117201
|
+
return { error: response.status === 502 || response.status === 504 ? t("gatewayTimeout") : t("requestFailed", { status: String(response.status) }) };
|
|
117202
|
+
}
|
|
117203
|
+
};
|
|
116821
117204
|
(0, react.useEffect)(() => locale?.subscribe?.(() => setLang(locale.getSnapshot().active?.startsWith("en") ? "en" : "zh")), [locale]);
|
|
116822
117205
|
const formStateRef = (0, react.useRef)({
|
|
116823
117206
|
provider,
|
|
@@ -116839,7 +117222,7 @@ img.ProseMirror-separator {
|
|
|
116839
117222
|
signal: controller.signal,
|
|
116840
117223
|
credentials: "same-origin"
|
|
116841
117224
|
});
|
|
116842
|
-
const payload = await response
|
|
117225
|
+
const payload = await readStudioBody(response);
|
|
116843
117226
|
if (!response.ok || !("providers" in payload)) throw new Error("error" in payload && payload.error ? payload.error : "Studio unavailable");
|
|
116844
117227
|
setConfig(payload);
|
|
116845
117228
|
if (silent) {
|
|
@@ -116885,6 +117268,20 @@ img.ProseMirror-separator {
|
|
|
116885
117268
|
unsubscribe();
|
|
116886
117269
|
};
|
|
116887
117270
|
}, []);
|
|
117271
|
+
(0, react.useEffect)(() => {
|
|
117272
|
+
let mounted = true;
|
|
117273
|
+
const load = () => void Promise.all([getFavoritePrompts(), getFavoriteFolders()]).then(([prompts, folders]) => {
|
|
117274
|
+
if (!mounted) return;
|
|
117275
|
+
setFavPrompts(prompts);
|
|
117276
|
+
setFavFolders(folders);
|
|
117277
|
+
});
|
|
117278
|
+
load();
|
|
117279
|
+
const unsubscribe = subscribeFavorites(load);
|
|
117280
|
+
return () => {
|
|
117281
|
+
mounted = false;
|
|
117282
|
+
unsubscribe();
|
|
117283
|
+
};
|
|
117284
|
+
}, []);
|
|
116888
117285
|
(0, react.useEffect)(() => {
|
|
116889
117286
|
return () => {
|
|
116890
117287
|
requestRef.current?.abort();
|
|
@@ -117009,7 +117406,65 @@ img.ProseMirror-separator {
|
|
|
117009
117406
|
};
|
|
117010
117407
|
};
|
|
117011
117408
|
const handleImageClick = () => {};
|
|
117012
|
-
|
|
117409
|
+
/** Keep the current prompt text in the favorites rail. */
|
|
117410
|
+
const handleFavoritePrompt = async () => {
|
|
117411
|
+
if (prompt.trim().length === 0) {
|
|
117412
|
+
setError(t("needPrompt"));
|
|
117413
|
+
return;
|
|
117414
|
+
}
|
|
117415
|
+
if (await saveFavoritePrompt(prompt)) {
|
|
117416
|
+
railToggledByUserRef.current = true;
|
|
117417
|
+
setSidebarCollapsed(false);
|
|
117418
|
+
setRailTab("favorites");
|
|
117419
|
+
flash(t("favPromptSaved"));
|
|
117420
|
+
} else setError(t("favSaveFailed"));
|
|
117421
|
+
};
|
|
117422
|
+
/** Turn one favorited gallery image back into a live reference (edit mode). */
|
|
117423
|
+
const applyFavoriteImage = async (item) => {
|
|
117424
|
+
const max = maxReferences;
|
|
117425
|
+
if (referencesRef.current.length >= max) {
|
|
117426
|
+
setError(t("maxReferencesExceeded", { max: String(max) }));
|
|
117427
|
+
return;
|
|
117428
|
+
}
|
|
117429
|
+
try {
|
|
117430
|
+
const blob = await fetchAttachmentBlob(item.attachment);
|
|
117431
|
+
const newItem = {
|
|
117432
|
+
id: `fav-${item.id}-${Date.now()}`,
|
|
117433
|
+
attachment: item.attachment,
|
|
117434
|
+
previewUrl: URL.createObjectURL(blob)
|
|
117435
|
+
};
|
|
117436
|
+
const next = [...referencesRef.current, newItem];
|
|
117437
|
+
setReferences(next);
|
|
117438
|
+
referencesRef.current = next;
|
|
117439
|
+
setMode("edit");
|
|
117440
|
+
setError(null);
|
|
117441
|
+
flash(t("favRefApplied"));
|
|
117442
|
+
} catch {
|
|
117443
|
+
setError(t("imageLoadFailed"));
|
|
117444
|
+
}
|
|
117445
|
+
};
|
|
117446
|
+
const createFavFolder = async () => {
|
|
117447
|
+
if (await addFavoriteFolder("prompt", folderDraftName) === null) {
|
|
117448
|
+
flash(t("favSaveFailed"));
|
|
117449
|
+
return;
|
|
117450
|
+
}
|
|
117451
|
+
setFolderDraft(null);
|
|
117452
|
+
setFolderDraftName("");
|
|
117453
|
+
};
|
|
117454
|
+
const openPromptEditor = (fav) => {
|
|
117455
|
+
setEditingPrompt(fav);
|
|
117456
|
+
setEditPromptText(fav.text);
|
|
117457
|
+
setEditPromptFolder(fav.folderId ?? "");
|
|
117458
|
+
};
|
|
117459
|
+
const doMoveFavorite = (folderId) => {
|
|
117460
|
+
if (movingFav === null) return;
|
|
117461
|
+
moveFavoritePrompt(movingFav.id, folderId);
|
|
117462
|
+
};
|
|
117463
|
+
const applyFavoritePrompt = (fav) => {
|
|
117464
|
+
setPrompt(fav.text);
|
|
117465
|
+
flash(t("favPromptApplied"));
|
|
117466
|
+
};
|
|
117467
|
+
const addReferenceFiles = async (fileList) => {
|
|
117013
117468
|
if (!fileList || fileList.length === 0) return;
|
|
117014
117469
|
const files = Array.from(fileList);
|
|
117015
117470
|
const validFiles = [];
|
|
@@ -117035,13 +117490,31 @@ img.ProseMirror-separator {
|
|
|
117035
117490
|
const toAdd = validFiles.slice(0, available);
|
|
117036
117491
|
if (validFiles.length > available) setError(t("maxReferencesExceeded", { max: String(maxReferences) }));
|
|
117037
117492
|
else setError(null);
|
|
117038
|
-
const
|
|
117493
|
+
const snapshotted = [];
|
|
117494
|
+
for (const file of toAdd) try {
|
|
117495
|
+
const bytes = await file.arrayBuffer();
|
|
117496
|
+
snapshotted.push(new File([bytes], file.name, {
|
|
117497
|
+
type: file.type,
|
|
117498
|
+
lastModified: file.lastModified
|
|
117499
|
+
}));
|
|
117500
|
+
} catch {
|
|
117501
|
+
setError(t("uploadUnreadable"));
|
|
117502
|
+
}
|
|
117503
|
+
const newItems = snapshotted.map((file, idx) => ({
|
|
117039
117504
|
id: `upload-${Date.now()}-${idx}-${Math.random().toString(36).slice(2, 7)}`,
|
|
117040
117505
|
file,
|
|
117041
117506
|
previewUrl: URL.createObjectURL(file)
|
|
117042
117507
|
}));
|
|
117043
117508
|
setReferences((prev) => [...prev, ...newItems]);
|
|
117044
117509
|
};
|
|
117510
|
+
const appliedReferenceRef = (0, react.useRef)(null);
|
|
117511
|
+
(0, react.useEffect)(() => {
|
|
117512
|
+
if (initialReference === void 0 || appliedReferenceRef.current === initialReference) return;
|
|
117513
|
+
appliedReferenceRef.current = initialReference;
|
|
117514
|
+
addReferenceFiles([initialReference]);
|
|
117515
|
+
setMode("edit");
|
|
117516
|
+
onInitialReferenceApplied?.();
|
|
117517
|
+
}, [initialReference, onInitialReferenceApplied]);
|
|
117045
117518
|
const removeReference = (id) => {
|
|
117046
117519
|
const target = referencesRef.current.find((item) => item.id === id);
|
|
117047
117520
|
if (target && target.previewUrl.startsWith("blob:")) URL.revokeObjectURL(target.previewUrl);
|
|
@@ -117173,7 +117646,7 @@ img.ProseMirror-separator {
|
|
|
117173
117646
|
...referencesPayload === void 0 ? {} : { references: referencesPayload }
|
|
117174
117647
|
})
|
|
117175
117648
|
});
|
|
117176
|
-
const payload = await response
|
|
117649
|
+
const payload = await readStudioBody(response);
|
|
117177
117650
|
if (!response.ok || !("attachment" in payload)) throw new Error("error" in payload && payload.error ? payload.error : `${target.profile.label}: ${t("generationFailed")}`);
|
|
117178
117651
|
return {
|
|
117179
117652
|
payload,
|
|
@@ -117236,7 +117709,7 @@ img.ProseMirror-separator {
|
|
|
117236
117709
|
...referencesPayload === void 0 ? {} : { references: referencesPayload }
|
|
117237
117710
|
})
|
|
117238
117711
|
});
|
|
117239
|
-
const payload = await response
|
|
117712
|
+
const payload = await readStudioBody(response);
|
|
117240
117713
|
if (!response.ok || !("attachment" in payload)) throw new Error("error" in payload && payload.error ? payload.error : t("generationFailed"));
|
|
117241
117714
|
const generatedList = Array.isArray(payload.items) && payload.items.length > 0 ? payload.items : [{
|
|
117242
117715
|
attachment: payload.attachment,
|
|
@@ -117308,8 +117781,8 @@ img.ProseMirror-separator {
|
|
|
117308
117781
|
selected,
|
|
117309
117782
|
selectedBatchItems
|
|
117310
117783
|
]);
|
|
117311
|
-
const saveButtonLabel = currentBatch !== null ? pendingGalleryItems.length > 0 ? t("saveSelected", { count: String(pendingGalleryItems.length) }) : selectedBatchItems.length === 0 ? t("saveSelected", { count: "0" }) : t("inGallery") :
|
|
117312
|
-
const saveSelectionComplete = currentBatch === null ?
|
|
117784
|
+
const saveButtonLabel = currentBatch !== null ? pendingGalleryItems.length > 0 ? t("saveSelected", { count: String(pendingGalleryItems.length) }) : selectedBatchItems.length === 0 ? t("saveSelected", { count: "0" }) : t("inGallery") : pendingGalleryItems.length > 0 ? t("saveToGallery") : selected !== null ? t("inGallery") : t("saveToGallery");
|
|
117785
|
+
const saveSelectionComplete = currentBatch === null ? pendingGalleryItems.length === 0 : selectedBatchItems.length > 0 && pendingGalleryItems.length === 0;
|
|
117313
117786
|
const saveGalleryEntry = async (item) => {
|
|
117314
117787
|
let savedTo = item.savedTo;
|
|
117315
117788
|
const targetRoot = workspace?.path || config?.workspaceRoot;
|
|
@@ -117489,44 +117962,272 @@ img.ProseMirror-separator {
|
|
|
117489
117962
|
children: [
|
|
117490
117963
|
!sidebarCollapsed && (0, react_jsx_runtime.jsxs)("aside", {
|
|
117491
117964
|
className: "dsh-ig-recent-panel",
|
|
117492
|
-
children: [
|
|
117493
|
-
|
|
117494
|
-
|
|
117495
|
-
|
|
117496
|
-
|
|
117497
|
-
|
|
117498
|
-
|
|
117499
|
-
|
|
117500
|
-
|
|
117501
|
-
|
|
117502
|
-
|
|
117965
|
+
children: [
|
|
117966
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
117967
|
+
className: "dsh-ig-panel-title",
|
|
117968
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
117969
|
+
style: {
|
|
117970
|
+
display: "flex",
|
|
117971
|
+
alignItems: "center",
|
|
117972
|
+
gap: "8px"
|
|
117973
|
+
},
|
|
117974
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: railTab === "recent" ? t("recent") : t("railTabFavorites") }), (0, react_jsx_runtime.jsx)("span", {
|
|
117975
|
+
className: "dsh-ig-count-badge",
|
|
117976
|
+
children: railTab === "recent" ? items.length : items.filter((item) => item.isFavorite).length + favPrompts.length
|
|
117977
|
+
})]
|
|
117978
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
117979
|
+
type: "button",
|
|
117980
|
+
className: "dsh-ig-collapse-btn",
|
|
117981
|
+
onClick: () => {
|
|
117982
|
+
railToggledByUserRef.current = true;
|
|
117983
|
+
setSidebarCollapsed(true);
|
|
117984
|
+
},
|
|
117985
|
+
title: t("collapseSidebar"),
|
|
117986
|
+
children: (0, react_jsx_runtime.jsx)(PanelLeftClose, { size: 15 })
|
|
117503
117987
|
})]
|
|
117504
|
-
}),
|
|
117505
|
-
|
|
117506
|
-
className: "dsh-ig-
|
|
117507
|
-
|
|
117508
|
-
|
|
117509
|
-
|
|
117510
|
-
|
|
117511
|
-
|
|
117512
|
-
|
|
117513
|
-
|
|
117514
|
-
|
|
117515
|
-
|
|
117516
|
-
|
|
117517
|
-
|
|
117518
|
-
|
|
117519
|
-
|
|
117520
|
-
|
|
117521
|
-
|
|
117522
|
-
|
|
117523
|
-
}
|
|
117524
|
-
|
|
117525
|
-
className: "dsh-ig-
|
|
117526
|
-
|
|
117527
|
-
|
|
117528
|
-
|
|
117529
|
-
|
|
117988
|
+
}),
|
|
117989
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
117990
|
+
className: "dsh-ig-rail-tabs",
|
|
117991
|
+
role: "tablist",
|
|
117992
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
117993
|
+
type: "button",
|
|
117994
|
+
role: "tab",
|
|
117995
|
+
"aria-selected": railTab === "recent",
|
|
117996
|
+
className: `dsh-ig-rail-tab ${railTab === "recent" ? "is-active" : ""}`,
|
|
117997
|
+
onClick: () => setRailTab("recent"),
|
|
117998
|
+
children: t("railTabRecent")
|
|
117999
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
118000
|
+
type: "button",
|
|
118001
|
+
role: "tab",
|
|
118002
|
+
"aria-selected": railTab === "favorites",
|
|
118003
|
+
className: `dsh-ig-rail-tab ${railTab === "favorites" ? "is-active" : ""}`,
|
|
118004
|
+
onClick: () => setRailTab("favorites"),
|
|
118005
|
+
children: t("railTabFavorites")
|
|
118006
|
+
})]
|
|
118007
|
+
}),
|
|
118008
|
+
railTab === "recent" ? (0, react_jsx_runtime.jsxs)("div", {
|
|
118009
|
+
className: "dsh-ig-recent-scroll",
|
|
118010
|
+
children: [items.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
118011
|
+
className: "dsh-ig-recent-empty",
|
|
118012
|
+
children: [(0, react_jsx_runtime.jsx)(ImagePlus, { size: 22 }), (0, react_jsx_runtime.jsx)("span", { children: t("empty") })]
|
|
118013
|
+
}) : displayItems.map((item) => (0, react_jsx_runtime.jsx)(RecentItem, {
|
|
118014
|
+
item,
|
|
118015
|
+
active: selected?.id === item.id,
|
|
118016
|
+
onClick: () => selectItem(item)
|
|
118017
|
+
}, item.id)), items.length > visibleLimit && (0, react_jsx_runtime.jsx)("button", {
|
|
118018
|
+
type: "button",
|
|
118019
|
+
className: "dsh-ig-load-more",
|
|
118020
|
+
onClick: () => setVisibleLimit((l) => l + 30),
|
|
118021
|
+
children: t("loadMore", { n: String(items.length - visibleLimit) })
|
|
118022
|
+
})]
|
|
118023
|
+
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
118024
|
+
className: "dsh-ig-fav-scroll",
|
|
118025
|
+
children: [
|
|
118026
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
118027
|
+
className: "dsh-ig-fav-section-label",
|
|
118028
|
+
children: (0, react_jsx_runtime.jsx)("span", { children: t("favImages") })
|
|
118029
|
+
}),
|
|
118030
|
+
(() => {
|
|
118031
|
+
const list = items.filter((item) => item.isFavorite);
|
|
118032
|
+
if (list.length === 0) return (0, react_jsx_runtime.jsxs)("div", {
|
|
118033
|
+
className: "dsh-ig-fav-empty",
|
|
118034
|
+
children: [(0, react_jsx_runtime.jsx)(ImagePlus, { size: 18 }), (0, react_jsx_runtime.jsx)("span", { children: t("favEmptyImages") })]
|
|
118035
|
+
});
|
|
118036
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
118037
|
+
className: "dsh-ig-fav-grid",
|
|
118038
|
+
children: list.map((item) => (0, react_jsx_runtime.jsx)(RecentItem, {
|
|
118039
|
+
item,
|
|
118040
|
+
active: false,
|
|
118041
|
+
onClick: () => void applyFavoriteImage(item)
|
|
118042
|
+
}, item.id))
|
|
118043
|
+
});
|
|
118044
|
+
})(),
|
|
118045
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118046
|
+
className: "dsh-ig-fav-section-label",
|
|
118047
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("favPrompts") }), (0, react_jsx_runtime.jsx)("button", {
|
|
118048
|
+
type: "button",
|
|
118049
|
+
className: "dsh-ig-fav-folder-add",
|
|
118050
|
+
onClick: () => {
|
|
118051
|
+
setFolderDraft({ kind: "prompt" });
|
|
118052
|
+
setFolderDraftName("");
|
|
118053
|
+
},
|
|
118054
|
+
title: t("favNewFolder"),
|
|
118055
|
+
children: "+"
|
|
118056
|
+
})]
|
|
118057
|
+
}),
|
|
118058
|
+
(0, react_jsx_runtime.jsx)(FavoriteFolderBar, {
|
|
118059
|
+
folders: favFolders.filter((folder) => folder.kind === "prompt"),
|
|
118060
|
+
active: activePromptFolder,
|
|
118061
|
+
onSelect: (id) => setActivePromptFolder(id === activePromptFolder ? "" : id),
|
|
118062
|
+
onDelete: (id) => void deleteFavoriteFolder(id),
|
|
118063
|
+
deleteLabel: t("favDeleteFolder")
|
|
118064
|
+
}),
|
|
118065
|
+
folderDraft?.kind === "prompt" && (0, react_jsx_runtime.jsxs)("div", {
|
|
118066
|
+
className: "dsh-ig-fav-folder-draft",
|
|
118067
|
+
children: [
|
|
118068
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
118069
|
+
value: folderDraftName,
|
|
118070
|
+
placeholder: t("favFolderPlaceholder"),
|
|
118071
|
+
onChange: (e) => setFolderDraftName(e.target.value),
|
|
118072
|
+
onKeyDown: (e) => {
|
|
118073
|
+
if (e.key === "Enter") createFavFolder();
|
|
118074
|
+
}
|
|
118075
|
+
}),
|
|
118076
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118077
|
+
type: "button",
|
|
118078
|
+
onClick: () => void createFavFolder(),
|
|
118079
|
+
children: t("favCreate")
|
|
118080
|
+
}),
|
|
118081
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118082
|
+
type: "button",
|
|
118083
|
+
onClick: () => setFolderDraft(null),
|
|
118084
|
+
children: t("favCancel")
|
|
118085
|
+
})
|
|
118086
|
+
]
|
|
118087
|
+
}),
|
|
118088
|
+
(() => {
|
|
118089
|
+
const list = favPrompts.filter((fav) => activePromptFolder === "" || fav.folderId === activePromptFolder);
|
|
118090
|
+
if (list.length === 0) return (0, react_jsx_runtime.jsxs)("div", {
|
|
118091
|
+
className: "dsh-ig-fav-empty",
|
|
118092
|
+
children: [(0, react_jsx_runtime.jsx)(PencilLine, { size: 18 }), (0, react_jsx_runtime.jsx)("span", { children: t("favEmptyPrompts") })]
|
|
118093
|
+
});
|
|
118094
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
118095
|
+
className: "dsh-ig-fav-prompts",
|
|
118096
|
+
children: list.map((fav) => (0, react_jsx_runtime.jsxs)("div", {
|
|
118097
|
+
className: "dsh-ig-fav-prompt",
|
|
118098
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
118099
|
+
type: "button",
|
|
118100
|
+
className: "dsh-ig-fav-prompt-text",
|
|
118101
|
+
title: fav.text,
|
|
118102
|
+
onClick: () => openPromptEditor(fav),
|
|
118103
|
+
children: fav.text
|
|
118104
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
118105
|
+
type: "button",
|
|
118106
|
+
className: "dsh-ig-fav-del",
|
|
118107
|
+
title: t("remove"),
|
|
118108
|
+
onClick: () => void deleteFavoritePrompt(fav.id),
|
|
118109
|
+
children: (0, react_jsx_runtime.jsx)(X, { size: 11 })
|
|
118110
|
+
})]
|
|
118111
|
+
}, fav.id))
|
|
118112
|
+
});
|
|
118113
|
+
})()
|
|
118114
|
+
]
|
|
118115
|
+
})
|
|
118116
|
+
]
|
|
118117
|
+
}),
|
|
118118
|
+
(editingPrompt !== null || movingFav !== null) && (0, react_jsx_runtime.jsx)("div", {
|
|
118119
|
+
className: "dsh-ig-fav-dialog-wrap",
|
|
118120
|
+
onClick: () => {
|
|
118121
|
+
setEditingPrompt(null);
|
|
118122
|
+
setMovingFav(null);
|
|
118123
|
+
},
|
|
118124
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
118125
|
+
className: "dsh-ig-fav-dialog",
|
|
118126
|
+
onClick: (e) => e.stopPropagation(),
|
|
118127
|
+
children: [editingPrompt !== null && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
118128
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
118129
|
+
className: "dsh-ig-fav-dialog-title",
|
|
118130
|
+
children: t("favEditPrompt")
|
|
118131
|
+
}),
|
|
118132
|
+
(0, react_jsx_runtime.jsx)("textarea", {
|
|
118133
|
+
className: "dsh-ig-fav-dialog-textarea",
|
|
118134
|
+
value: editPromptText,
|
|
118135
|
+
placeholder: t("favEditPromptPlaceholder"),
|
|
118136
|
+
onChange: (e) => setEditPromptText(e.target.value),
|
|
118137
|
+
rows: 5
|
|
118138
|
+
}),
|
|
118139
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
118140
|
+
className: "dsh-ig-fav-dialog-folder-label",
|
|
118141
|
+
children: [t("favFolder"), (0, react_jsx_runtime.jsxs)("select", {
|
|
118142
|
+
value: editPromptFolder,
|
|
118143
|
+
onChange: (e) => setEditPromptFolder(e.target.value),
|
|
118144
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
118145
|
+
value: "",
|
|
118146
|
+
children: t("favNoFolder")
|
|
118147
|
+
}), favFolders.filter((folder) => folder.kind === "prompt").map((folder) => (0, react_jsx_runtime.jsx)("option", {
|
|
118148
|
+
value: folder.id,
|
|
118149
|
+
children: folder.name
|
|
118150
|
+
}, folder.id))]
|
|
118151
|
+
})]
|
|
118152
|
+
}),
|
|
118153
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118154
|
+
className: "dsh-ig-fav-dialog-actions",
|
|
118155
|
+
children: [
|
|
118156
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118157
|
+
type: "button",
|
|
118158
|
+
className: "is-primary",
|
|
118159
|
+
onClick: () => {
|
|
118160
|
+
updateFavoritePrompt(editingPrompt.id, editPromptText).then((ok) => {
|
|
118161
|
+
if (ok) moveFavoritePrompt(editingPrompt.id, editPromptFolder === "" ? void 0 : editPromptFolder);
|
|
118162
|
+
});
|
|
118163
|
+
setEditingPrompt(null);
|
|
118164
|
+
},
|
|
118165
|
+
children: t("favSave")
|
|
118166
|
+
}),
|
|
118167
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118168
|
+
type: "button",
|
|
118169
|
+
onClick: () => {
|
|
118170
|
+
applyFavoritePrompt({
|
|
118171
|
+
...editingPrompt,
|
|
118172
|
+
text: editPromptText
|
|
118173
|
+
});
|
|
118174
|
+
setEditingPrompt(null);
|
|
118175
|
+
},
|
|
118176
|
+
children: t("favUse")
|
|
118177
|
+
}),
|
|
118178
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118179
|
+
type: "button",
|
|
118180
|
+
onClick: () => {
|
|
118181
|
+
setMovingFav({
|
|
118182
|
+
kind: "prompt",
|
|
118183
|
+
id: editingPrompt.id,
|
|
118184
|
+
folderId: editingPrompt.folderId
|
|
118185
|
+
});
|
|
118186
|
+
setEditingPrompt(null);
|
|
118187
|
+
},
|
|
118188
|
+
children: t("favMove")
|
|
118189
|
+
}),
|
|
118190
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118191
|
+
type: "button",
|
|
118192
|
+
onClick: () => setEditingPrompt(null),
|
|
118193
|
+
children: t("favCancel")
|
|
118194
|
+
})
|
|
118195
|
+
]
|
|
118196
|
+
})
|
|
118197
|
+
] }), editingPrompt === null && movingFav !== null && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
118198
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
118199
|
+
className: "dsh-ig-fav-dialog-title",
|
|
118200
|
+
children: t("favMoveTo")
|
|
118201
|
+
}),
|
|
118202
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118203
|
+
className: "dsh-ig-fav-dialog-folders",
|
|
118204
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
118205
|
+
type: "button",
|
|
118206
|
+
onClick: () => {
|
|
118207
|
+
doMoveFavorite(void 0);
|
|
118208
|
+
setMovingFav(null);
|
|
118209
|
+
},
|
|
118210
|
+
children: t("favNoFolder")
|
|
118211
|
+
}), favFolders.filter((folder) => folder.kind === movingFav.kind).map((folder) => (0, react_jsx_runtime.jsx)("button", {
|
|
118212
|
+
type: "button",
|
|
118213
|
+
className: movingFav.folderId === folder.id ? "is-current" : "",
|
|
118214
|
+
onClick: () => {
|
|
118215
|
+
doMoveFavorite(folder.id);
|
|
118216
|
+
setMovingFav(null);
|
|
118217
|
+
},
|
|
118218
|
+
children: folder.name
|
|
118219
|
+
}, folder.id))]
|
|
118220
|
+
}),
|
|
118221
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
118222
|
+
className: "dsh-ig-fav-dialog-actions",
|
|
118223
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
118224
|
+
type: "button",
|
|
118225
|
+
onClick: () => setMovingFav(null),
|
|
118226
|
+
children: t("favCancel")
|
|
118227
|
+
})
|
|
118228
|
+
})
|
|
118229
|
+
] })]
|
|
118230
|
+
})
|
|
117530
118231
|
}),
|
|
117531
118232
|
(0, react_jsx_runtime.jsxs)("main", {
|
|
117532
118233
|
className: "dsh-ig-canvas-column",
|
|
@@ -117923,21 +118624,30 @@ img.ProseMirror-separator {
|
|
|
117923
118624
|
" ",
|
|
117924
118625
|
(0, react_jsx_runtime.jsx)("b", { children: "*" })
|
|
117925
118626
|
]
|
|
117926
|
-
}), (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
117927
|
-
|
|
117928
|
-
|
|
117929
|
-
|
|
117930
|
-
|
|
117931
|
-
|
|
117932
|
-
|
|
117933
|
-
|
|
117934
|
-
|
|
117935
|
-
|
|
118627
|
+
}), (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
118628
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
118629
|
+
type: "button",
|
|
118630
|
+
className: "dsh-ig-find-inspiration",
|
|
118631
|
+
onClick: onOpenInspiration,
|
|
118632
|
+
children: [(0, react_jsx_runtime.jsx)(Sparkles, { size: 11 }), t("findInspiration")]
|
|
118633
|
+
}),
|
|
118634
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
118635
|
+
type: "button",
|
|
118636
|
+
className: "dsh-ig-fav-save-btn",
|
|
118637
|
+
onClick: () => void handleFavoritePrompt(),
|
|
118638
|
+
title: t("favoritePrompt"),
|
|
118639
|
+
children: [(0, react_jsx_runtime.jsx)(Star, { size: 12 }), t("favActionShort")]
|
|
118640
|
+
}),
|
|
118641
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118642
|
+
type: "button",
|
|
118643
|
+
onClick: () => setPrompt(""),
|
|
118644
|
+
children: t("clear")
|
|
118645
|
+
})
|
|
118646
|
+
] })]
|
|
117936
118647
|
}),
|
|
117937
118648
|
(0, react_jsx_runtime.jsx)("textarea", {
|
|
117938
118649
|
id: "dsh-ig-prompt",
|
|
117939
118650
|
value: prompt,
|
|
117940
|
-
maxLength: 2e3,
|
|
117941
118651
|
onChange: (event) => setPrompt(event.target.value),
|
|
117942
118652
|
onKeyDown: (event) => {
|
|
117943
118653
|
if (event.nativeEvent.isComposing) return;
|
|
@@ -117948,7 +118658,7 @@ img.ProseMirror-separator {
|
|
|
117948
118658
|
},
|
|
117949
118659
|
placeholder: t("promptPlaceholder")
|
|
117950
118660
|
}),
|
|
117951
|
-
(0, react_jsx_runtime.
|
|
118661
|
+
(0, react_jsx_runtime.jsx)("small", { children: prompt.length })
|
|
117952
118662
|
]
|
|
117953
118663
|
}),
|
|
117954
118664
|
config === null ? configLoading ? (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -118541,6 +119251,26 @@ img.ProseMirror-separator {
|
|
|
118541
119251
|
})
|
|
118542
119252
|
});
|
|
118543
119253
|
};
|
|
119254
|
+
const FavoriteFolderBar = ({ folders, active, onSelect, onDelete, deleteLabel }) => {
|
|
119255
|
+
if (folders.length === 0) return null;
|
|
119256
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
119257
|
+
className: "dsh-ig-fav-folders",
|
|
119258
|
+
children: folders.map((folder) => (0, react_jsx_runtime.jsxs)("span", {
|
|
119259
|
+
className: `dsh-ig-fav-folder-chip ${active === folder.id ? "is-active" : ""}`,
|
|
119260
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
119261
|
+
type: "button",
|
|
119262
|
+
onClick: () => onSelect(folder.id),
|
|
119263
|
+
children: folder.name
|
|
119264
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
119265
|
+
type: "button",
|
|
119266
|
+
className: "dsh-ig-fav-folder-del",
|
|
119267
|
+
title: deleteLabel,
|
|
119268
|
+
onClick: () => onDelete(folder.id),
|
|
119269
|
+
children: (0, react_jsx_runtime.jsx)(X, { size: 9 })
|
|
119270
|
+
})]
|
|
119271
|
+
}, folder.id))
|
|
119272
|
+
});
|
|
119273
|
+
};
|
|
118544
119274
|
function useInView() {
|
|
118545
119275
|
const [inView, setInView] = (0, react.useState)(false);
|
|
118546
119276
|
const observerRef = (0, react.useRef)(null);
|
|
@@ -118638,8 +119368,17 @@ img.ProseMirror-separator {
|
|
|
118638
119368
|
const MAX_BYTES = 188743680;
|
|
118639
119369
|
const pending = /* @__PURE__ */ new Map();
|
|
118640
119370
|
let cacheEpoch = 0;
|
|
118641
|
-
|
|
118642
|
-
|
|
119371
|
+
/**
|
|
119372
|
+
* Resolve the IndexedDB key for one image. `rev` (the source's imageRevision,
|
|
119373
|
+
* falling back to its version) namespaces the cache by image content: when a
|
|
119374
|
+
* source re-packages its images at stable case IDs, a bumped rev orphans the
|
|
119375
|
+
* old blobs instead of serving them forever.
|
|
119376
|
+
*/
|
|
119377
|
+
function cacheKey(sourceId, caseId, rev) {
|
|
119378
|
+
return rev === void 0 ? `${sourceId}:${caseId}` : `${sourceId}:${caseId}@${rev}`;
|
|
119379
|
+
}
|
|
119380
|
+
function fetchInspirationImage(sourceId, caseId, rev) {
|
|
119381
|
+
const key = cacheKey(sourceId, caseId, rev);
|
|
118643
119382
|
const existing = pending.get(key);
|
|
118644
119383
|
if (existing !== void 0) return existing;
|
|
118645
119384
|
const requestEpoch = cacheEpoch;
|
|
@@ -118662,8 +119401,8 @@ img.ProseMirror-separator {
|
|
|
118662
119401
|
pending.set(key, task);
|
|
118663
119402
|
return task;
|
|
118664
119403
|
}
|
|
118665
|
-
async function evictInspirationImage(sourceId, caseId) {
|
|
118666
|
-
const key =
|
|
119404
|
+
async function evictInspirationImage(sourceId, caseId, rev) {
|
|
119405
|
+
const key = cacheKey(sourceId, caseId, rev);
|
|
118667
119406
|
pending.delete(key);
|
|
118668
119407
|
const db = await openDatabase$1();
|
|
118669
119408
|
if (db === void 0) return;
|
|
@@ -118850,6 +119589,988 @@ img.ProseMirror-separator {
|
|
|
118850
119589
|
return Array.isArray(sources) && sources.length > 0 && sources.every((source) => typeof source === "object" && source !== null && Array.isArray(source.cases));
|
|
118851
119590
|
}
|
|
118852
119591
|
//#endregion
|
|
119592
|
+
//#region lib/types/inspiration/data/baoyu-compose.json
|
|
119593
|
+
var types = [
|
|
119594
|
+
{
|
|
119595
|
+
"id": "hero",
|
|
119596
|
+
"description": "Large visual impact, title overlay",
|
|
119597
|
+
"composition": "Large focal visual (60-70% area), title overlay on visual, dramatic composition"
|
|
119598
|
+
},
|
|
119599
|
+
{
|
|
119600
|
+
"id": "conceptual",
|
|
119601
|
+
"description": "Concept visualization, abstract core ideas",
|
|
119602
|
+
"composition": "Abstract shapes representing core concepts, information hierarchy, clean zones"
|
|
119603
|
+
},
|
|
119604
|
+
{
|
|
119605
|
+
"id": "typography",
|
|
119606
|
+
"description": "Text-focused layout, prominent title",
|
|
119607
|
+
"composition": "Title as primary element (40%+ area), minimal supporting visuals, strong hierarchy"
|
|
119608
|
+
},
|
|
119609
|
+
{
|
|
119610
|
+
"id": "metaphor",
|
|
119611
|
+
"description": "Visual metaphor, concrete expressing abstract",
|
|
119612
|
+
"composition": "Concrete object/scene representing abstract idea, symbolic elements, emotional resonance"
|
|
119613
|
+
},
|
|
119614
|
+
{
|
|
119615
|
+
"id": "scene",
|
|
119616
|
+
"description": "Atmospheric scene, narrative feel",
|
|
119617
|
+
"composition": "Atmospheric environment, narrative elements, mood-setting lighting and colors"
|
|
119618
|
+
},
|
|
119619
|
+
{
|
|
119620
|
+
"id": "minimal",
|
|
119621
|
+
"description": "Minimalist composition, generous whitespace",
|
|
119622
|
+
"composition": "Single focal element, generous whitespace (60%+), essential shapes only"
|
|
119623
|
+
}
|
|
119624
|
+
];
|
|
119625
|
+
var palettes = [
|
|
119626
|
+
{
|
|
119627
|
+
"id": "warm",
|
|
119628
|
+
"tagline": "Friendly, approachable, human-centered",
|
|
119629
|
+
"colors": [
|
|
119630
|
+
{
|
|
119631
|
+
"role": "Primary 1",
|
|
119632
|
+
"name": "Warm Orange",
|
|
119633
|
+
"hex": "#ed8936"
|
|
119634
|
+
},
|
|
119635
|
+
{
|
|
119636
|
+
"role": "Primary 2",
|
|
119637
|
+
"name": "Golden Yellow",
|
|
119638
|
+
"hex": "#f6ad55"
|
|
119639
|
+
},
|
|
119640
|
+
{
|
|
119641
|
+
"role": "Primary 3",
|
|
119642
|
+
"name": "Terracotta",
|
|
119643
|
+
"hex": "#c05621"
|
|
119644
|
+
},
|
|
119645
|
+
{
|
|
119646
|
+
"role": "Background",
|
|
119647
|
+
"name": "Cream",
|
|
119648
|
+
"hex": "#fffaf0"
|
|
119649
|
+
},
|
|
119650
|
+
{
|
|
119651
|
+
"role": "Background Alt",
|
|
119652
|
+
"name": "Soft Peach",
|
|
119653
|
+
"hex": "#fed7aa"
|
|
119654
|
+
},
|
|
119655
|
+
{
|
|
119656
|
+
"role": "Accent 1",
|
|
119657
|
+
"name": "Deep Brown",
|
|
119658
|
+
"hex": "#744210"
|
|
119659
|
+
},
|
|
119660
|
+
{
|
|
119661
|
+
"role": "Accent 2",
|
|
119662
|
+
"name": "Soft Red",
|
|
119663
|
+
"hex": "#e53e3e"
|
|
119664
|
+
}
|
|
119665
|
+
],
|
|
119666
|
+
"decorativeHints": [
|
|
119667
|
+
"Sun rays, warm lighting effects",
|
|
119668
|
+
"Rounded shapes, organic curves",
|
|
119669
|
+
"Hearts, smiling faces, friendly icons",
|
|
119670
|
+
"Warm gradient overlays"
|
|
119671
|
+
],
|
|
119672
|
+
"bestFor": ""
|
|
119673
|
+
},
|
|
119674
|
+
{
|
|
119675
|
+
"id": "cool",
|
|
119676
|
+
"tagline": "Technical, professional, precise",
|
|
119677
|
+
"colors": [
|
|
119678
|
+
{
|
|
119679
|
+
"role": "Primary 1",
|
|
119680
|
+
"name": "Engineering Blue",
|
|
119681
|
+
"hex": "#2563eb"
|
|
119682
|
+
},
|
|
119683
|
+
{
|
|
119684
|
+
"role": "Primary 2",
|
|
119685
|
+
"name": "Navy Blue",
|
|
119686
|
+
"hex": "#1e3a5f"
|
|
119687
|
+
},
|
|
119688
|
+
{
|
|
119689
|
+
"role": "Primary 3",
|
|
119690
|
+
"name": "Cyan",
|
|
119691
|
+
"hex": "#06b6d4"
|
|
119692
|
+
},
|
|
119693
|
+
{
|
|
119694
|
+
"role": "Background",
|
|
119695
|
+
"name": "Light Gray",
|
|
119696
|
+
"hex": "#f8f9fa"
|
|
119697
|
+
},
|
|
119698
|
+
{
|
|
119699
|
+
"role": "Background Alt",
|
|
119700
|
+
"name": "Blueprint Off-White",
|
|
119701
|
+
"hex": "#faf8f5"
|
|
119702
|
+
},
|
|
119703
|
+
{
|
|
119704
|
+
"role": "Accent 1",
|
|
119705
|
+
"name": "Amber",
|
|
119706
|
+
"hex": "#f59e0b"
|
|
119707
|
+
},
|
|
119708
|
+
{
|
|
119709
|
+
"role": "Accent 2",
|
|
119710
|
+
"name": "Light Blue",
|
|
119711
|
+
"hex": "#bfdbfe"
|
|
119712
|
+
}
|
|
119713
|
+
],
|
|
119714
|
+
"decorativeHints": [
|
|
119715
|
+
"Grid lines and alignment guides",
|
|
119716
|
+
"Dimension indicators and measurements",
|
|
119717
|
+
"Technical schematics and diagrams",
|
|
119718
|
+
"Geometric precision elements"
|
|
119719
|
+
],
|
|
119720
|
+
"bestFor": ""
|
|
119721
|
+
},
|
|
119722
|
+
{
|
|
119723
|
+
"id": "dark",
|
|
119724
|
+
"tagline": "Cinematic, premium, atmospheric",
|
|
119725
|
+
"colors": [
|
|
119726
|
+
{
|
|
119727
|
+
"role": "Primary 1",
|
|
119728
|
+
"name": "Electric Purple",
|
|
119729
|
+
"hex": "#8b5cf6"
|
|
119730
|
+
},
|
|
119731
|
+
{
|
|
119732
|
+
"role": "Primary 2",
|
|
119733
|
+
"name": "Cyan Blue",
|
|
119734
|
+
"hex": "#06b6d4"
|
|
119735
|
+
},
|
|
119736
|
+
{
|
|
119737
|
+
"role": "Primary 3",
|
|
119738
|
+
"name": "Magenta Pink",
|
|
119739
|
+
"hex": "#ec4899"
|
|
119740
|
+
},
|
|
119741
|
+
{
|
|
119742
|
+
"role": "Background",
|
|
119743
|
+
"name": "Deep Purple-Black",
|
|
119744
|
+
"hex": "#0a0a0a"
|
|
119745
|
+
},
|
|
119746
|
+
{
|
|
119747
|
+
"role": "Background Alt",
|
|
119748
|
+
"name": "Rich Navy",
|
|
119749
|
+
"hex": "#1a1a2e"
|
|
119750
|
+
},
|
|
119751
|
+
{
|
|
119752
|
+
"role": "Accent 1",
|
|
119753
|
+
"name": "Amber",
|
|
119754
|
+
"hex": "#f59e0b"
|
|
119755
|
+
},
|
|
119756
|
+
{
|
|
119757
|
+
"role": "Accent 2",
|
|
119758
|
+
"name": "Pure White",
|
|
119759
|
+
"hex": "#ffffff"
|
|
119760
|
+
}
|
|
119761
|
+
],
|
|
119762
|
+
"decorativeHints": [
|
|
119763
|
+
"Glowing accent elements and neon highlights",
|
|
119764
|
+
"Atmospheric fog or particle effects",
|
|
119765
|
+
"Silhouettes with backlit edges",
|
|
119766
|
+
"Subtle gradient backgrounds"
|
|
119767
|
+
],
|
|
119768
|
+
"bestFor": ""
|
|
119769
|
+
},
|
|
119770
|
+
{
|
|
119771
|
+
"id": "earth",
|
|
119772
|
+
"tagline": "Natural, organic, grounded",
|
|
119773
|
+
"colors": [
|
|
119774
|
+
{
|
|
119775
|
+
"role": "Primary 1",
|
|
119776
|
+
"name": "Forest Green",
|
|
119777
|
+
"hex": "#276749"
|
|
119778
|
+
},
|
|
119779
|
+
{
|
|
119780
|
+
"role": "Primary 2",
|
|
119781
|
+
"name": "Sage",
|
|
119782
|
+
"hex": "#9ae6b4"
|
|
119783
|
+
},
|
|
119784
|
+
{
|
|
119785
|
+
"role": "Primary 3",
|
|
119786
|
+
"name": "Earth Brown",
|
|
119787
|
+
"hex": "#744210"
|
|
119788
|
+
},
|
|
119789
|
+
{
|
|
119790
|
+
"role": "Background",
|
|
119791
|
+
"name": "Sand Beige",
|
|
119792
|
+
"hex": "#f5e6d3"
|
|
119793
|
+
},
|
|
119794
|
+
{
|
|
119795
|
+
"role": "Background Alt",
|
|
119796
|
+
"name": "Sky Blue",
|
|
119797
|
+
"hex": "#e0f2fe"
|
|
119798
|
+
},
|
|
119799
|
+
{
|
|
119800
|
+
"role": "Accent 1",
|
|
119801
|
+
"name": "Sunset Orange",
|
|
119802
|
+
"hex": "#ed8936"
|
|
119803
|
+
},
|
|
119804
|
+
{
|
|
119805
|
+
"role": "Accent 2",
|
|
119806
|
+
"name": "Water Blue",
|
|
119807
|
+
"hex": "#63b3ed"
|
|
119808
|
+
}
|
|
119809
|
+
],
|
|
119810
|
+
"decorativeHints": [
|
|
119811
|
+
"Leaves, trees, mountains, natural forms",
|
|
119812
|
+
"Sun, clouds, organic flowing lines",
|
|
119813
|
+
"Botanical illustrations",
|
|
119814
|
+
"Earthy textures and natural patterns"
|
|
119815
|
+
],
|
|
119816
|
+
"bestFor": ""
|
|
119817
|
+
},
|
|
119818
|
+
{
|
|
119819
|
+
"id": "elegant",
|
|
119820
|
+
"tagline": "Sophisticated, refined, understated luxury",
|
|
119821
|
+
"colors": [
|
|
119822
|
+
{
|
|
119823
|
+
"role": "Primary 1",
|
|
119824
|
+
"name": "Soft Coral",
|
|
119825
|
+
"hex": "#e8a598"
|
|
119826
|
+
},
|
|
119827
|
+
{
|
|
119828
|
+
"role": "Primary 2",
|
|
119829
|
+
"name": "Muted Teal",
|
|
119830
|
+
"hex": "#5b8a8a"
|
|
119831
|
+
},
|
|
119832
|
+
{
|
|
119833
|
+
"role": "Primary 3",
|
|
119834
|
+
"name": "Dusty Rose",
|
|
119835
|
+
"hex": "#d4a5a5"
|
|
119836
|
+
},
|
|
119837
|
+
{
|
|
119838
|
+
"role": "Background",
|
|
119839
|
+
"name": "Warm Cream",
|
|
119840
|
+
"hex": "#f5f0e6"
|
|
119841
|
+
},
|
|
119842
|
+
{
|
|
119843
|
+
"role": "Background Alt",
|
|
119844
|
+
"name": "Soft Beige",
|
|
119845
|
+
"hex": "#f0ebe0"
|
|
119846
|
+
},
|
|
119847
|
+
{
|
|
119848
|
+
"role": "Accent 1",
|
|
119849
|
+
"name": "Gold",
|
|
119850
|
+
"hex": "#c9a962"
|
|
119851
|
+
},
|
|
119852
|
+
{
|
|
119853
|
+
"role": "Accent 2",
|
|
119854
|
+
"name": "Copper",
|
|
119855
|
+
"hex": "#b87333"
|
|
119856
|
+
}
|
|
119857
|
+
],
|
|
119858
|
+
"decorativeHints": [
|
|
119859
|
+
"Delicate ornamental details",
|
|
119860
|
+
"Subtle gradients and soft transitions",
|
|
119861
|
+
"Refined geometric patterns",
|
|
119862
|
+
"Balanced, symmetrical compositions"
|
|
119863
|
+
],
|
|
119864
|
+
"bestFor": ""
|
|
119865
|
+
},
|
|
119866
|
+
{
|
|
119867
|
+
"id": "macaron",
|
|
119868
|
+
"tagline": "Soft macaron pastel color blocks on warm cream",
|
|
119869
|
+
"colors": [
|
|
119870
|
+
{
|
|
119871
|
+
"role": "Primary 1",
|
|
119872
|
+
"name": "Sky Blue",
|
|
119873
|
+
"hex": "#a8d8ea"
|
|
119874
|
+
},
|
|
119875
|
+
{
|
|
119876
|
+
"role": "Primary 2",
|
|
119877
|
+
"name": "Mint Green",
|
|
119878
|
+
"hex": "#b5e5cf"
|
|
119879
|
+
},
|
|
119880
|
+
{
|
|
119881
|
+
"role": "Primary 3",
|
|
119882
|
+
"name": "Lavender",
|
|
119883
|
+
"hex": "#d5c6e0"
|
|
119884
|
+
},
|
|
119885
|
+
{
|
|
119886
|
+
"role": "Background",
|
|
119887
|
+
"name": "Warm Cream",
|
|
119888
|
+
"hex": "#f5f0e8"
|
|
119889
|
+
},
|
|
119890
|
+
{
|
|
119891
|
+
"role": "Background Alt",
|
|
119892
|
+
"name": "Peach",
|
|
119893
|
+
"hex": "#ffd5c2"
|
|
119894
|
+
},
|
|
119895
|
+
{
|
|
119896
|
+
"role": "Accent 1",
|
|
119897
|
+
"name": "Coral Red",
|
|
119898
|
+
"hex": "#e8655a"
|
|
119899
|
+
},
|
|
119900
|
+
{
|
|
119901
|
+
"role": "Accent 2",
|
|
119902
|
+
"name": "Deep Charcoal",
|
|
119903
|
+
"hex": "#2d2d2d"
|
|
119904
|
+
}
|
|
119905
|
+
],
|
|
119906
|
+
"decorativeHints": [
|
|
119907
|
+
"Rounded pastel color blocks",
|
|
119908
|
+
"Subtle warm paper grain texture",
|
|
119909
|
+
"Soft shadows, no hard edges",
|
|
119910
|
+
"Gentle gradient transitions between zones"
|
|
119911
|
+
],
|
|
119912
|
+
"bestFor": ""
|
|
119913
|
+
},
|
|
119914
|
+
{
|
|
119915
|
+
"id": "mono",
|
|
119916
|
+
"tagline": "Clean, focused, essential",
|
|
119917
|
+
"colors": [
|
|
119918
|
+
{
|
|
119919
|
+
"role": "Primary 1",
|
|
119920
|
+
"name": "Pure Black",
|
|
119921
|
+
"hex": "#000000"
|
|
119922
|
+
},
|
|
119923
|
+
{
|
|
119924
|
+
"role": "Primary 2",
|
|
119925
|
+
"name": "Near Black",
|
|
119926
|
+
"hex": "#1f1f1f"
|
|
119927
|
+
},
|
|
119928
|
+
{
|
|
119929
|
+
"role": "Primary 3",
|
|
119930
|
+
"name": "Dark Gray",
|
|
119931
|
+
"hex": "#374151"
|
|
119932
|
+
},
|
|
119933
|
+
{
|
|
119934
|
+
"role": "Background",
|
|
119935
|
+
"name": "White",
|
|
119936
|
+
"hex": "#ffffff"
|
|
119937
|
+
},
|
|
119938
|
+
{
|
|
119939
|
+
"role": "Background Alt",
|
|
119940
|
+
"name": "Off-White",
|
|
119941
|
+
"hex": "#fafafa"
|
|
119942
|
+
},
|
|
119943
|
+
{
|
|
119944
|
+
"role": "Accent 2",
|
|
119945
|
+
"name": "Medium Gray",
|
|
119946
|
+
"hex": "#9ca3af"
|
|
119947
|
+
}
|
|
119948
|
+
],
|
|
119949
|
+
"decorativeHints": [
|
|
119950
|
+
"Maximum negative space",
|
|
119951
|
+
"Thin lines and minimal strokes",
|
|
119952
|
+
"Single focal point emphasis",
|
|
119953
|
+
"Stark contrast between elements"
|
|
119954
|
+
],
|
|
119955
|
+
"bestFor": ""
|
|
119956
|
+
},
|
|
119957
|
+
{
|
|
119958
|
+
"id": "pastel",
|
|
119959
|
+
"tagline": "Gentle, whimsical, soft",
|
|
119960
|
+
"colors": [
|
|
119961
|
+
{
|
|
119962
|
+
"role": "Primary 1",
|
|
119963
|
+
"name": "Soft Pink",
|
|
119964
|
+
"hex": "#ffb6c1"
|
|
119965
|
+
},
|
|
119966
|
+
{
|
|
119967
|
+
"role": "Primary 2",
|
|
119968
|
+
"name": "Mint",
|
|
119969
|
+
"hex": "#98d8c8"
|
|
119970
|
+
},
|
|
119971
|
+
{
|
|
119972
|
+
"role": "Primary 3",
|
|
119973
|
+
"name": "Lavender",
|
|
119974
|
+
"hex": "#c8a2c8"
|
|
119975
|
+
},
|
|
119976
|
+
{
|
|
119977
|
+
"role": "Background",
|
|
119978
|
+
"name": "White",
|
|
119979
|
+
"hex": "#ffffff"
|
|
119980
|
+
},
|
|
119981
|
+
{
|
|
119982
|
+
"role": "Background Alt",
|
|
119983
|
+
"name": "Light Cream",
|
|
119984
|
+
"hex": "#fff8e7"
|
|
119985
|
+
},
|
|
119986
|
+
{
|
|
119987
|
+
"role": "Accent 1",
|
|
119988
|
+
"name": "Butter Yellow",
|
|
119989
|
+
"hex": "#fffacd"
|
|
119990
|
+
},
|
|
119991
|
+
{
|
|
119992
|
+
"role": "Accent 2",
|
|
119993
|
+
"name": "Sky Blue",
|
|
119994
|
+
"hex": "#bee3f8"
|
|
119995
|
+
}
|
|
119996
|
+
],
|
|
119997
|
+
"decorativeHints": [
|
|
119998
|
+
"Cute rounded proportions",
|
|
119999
|
+
"Stars, sparkles, flowers, decorative flourishes",
|
|
120000
|
+
"Soft shadows and gentle highlights",
|
|
120001
|
+
"Storybook-style elements"
|
|
120002
|
+
],
|
|
120003
|
+
"bestFor": ""
|
|
120004
|
+
},
|
|
120005
|
+
{
|
|
120006
|
+
"id": "retro",
|
|
120007
|
+
"tagline": "Nostalgic, vintage, classic",
|
|
120008
|
+
"colors": [
|
|
120009
|
+
{
|
|
120010
|
+
"role": "Primary 1",
|
|
120011
|
+
"name": "Coral Red",
|
|
120012
|
+
"hex": "#e07a5f"
|
|
120013
|
+
},
|
|
120014
|
+
{
|
|
120015
|
+
"role": "Primary 2",
|
|
120016
|
+
"name": "Mint Green",
|
|
120017
|
+
"hex": "#81b29a"
|
|
120018
|
+
},
|
|
120019
|
+
{
|
|
120020
|
+
"role": "Primary 3",
|
|
120021
|
+
"name": "Mustard Yellow",
|
|
120022
|
+
"hex": "#f2cc8f"
|
|
120023
|
+
},
|
|
120024
|
+
{
|
|
120025
|
+
"role": "Primary 4",
|
|
120026
|
+
"name": "Dark Maroon",
|
|
120027
|
+
"hex": "#5d3a3a"
|
|
120028
|
+
},
|
|
120029
|
+
{
|
|
120030
|
+
"role": "Background",
|
|
120031
|
+
"name": "Cream Off-White",
|
|
120032
|
+
"hex": "#f5f0e6"
|
|
120033
|
+
},
|
|
120034
|
+
{
|
|
120035
|
+
"role": "Background Alt",
|
|
120036
|
+
"name": "Aged Paper",
|
|
120037
|
+
"hex": "#f5e6d3"
|
|
120038
|
+
},
|
|
120039
|
+
{
|
|
120040
|
+
"role": "Accent 1",
|
|
120041
|
+
"name": "Burnt Orange",
|
|
120042
|
+
"hex": "#d4764a"
|
|
120043
|
+
},
|
|
120044
|
+
{
|
|
120045
|
+
"role": "Accent 2",
|
|
120046
|
+
"name": "Rock Blue",
|
|
120047
|
+
"hex": "#577590"
|
|
120048
|
+
},
|
|
120049
|
+
{
|
|
120050
|
+
"role": "Accent 3",
|
|
120051
|
+
"name": "Vintage Gold",
|
|
120052
|
+
"hex": "#c9a227"
|
|
120053
|
+
},
|
|
120054
|
+
{
|
|
120055
|
+
"role": "Accent 4",
|
|
120056
|
+
"name": "Faded Teal",
|
|
120057
|
+
"hex": "#2f7373"
|
|
120058
|
+
}
|
|
120059
|
+
],
|
|
120060
|
+
"decorativeHints": [
|
|
120061
|
+
"Halftone dots and vintage badges",
|
|
120062
|
+
"Aged textures with subtle paper grain",
|
|
120063
|
+
"Sunburst/radiating lines for energy",
|
|
120064
|
+
"Pill-shaped clouds, small dots and stars",
|
|
120065
|
+
"Classic icons and retro motifs"
|
|
120066
|
+
],
|
|
120067
|
+
"bestFor": ""
|
|
120068
|
+
},
|
|
120069
|
+
{
|
|
120070
|
+
"id": "duotone",
|
|
120071
|
+
"tagline": "Dramatic, cinematic, two-color high contrast",
|
|
120072
|
+
"colors": [
|
|
120073
|
+
{
|
|
120074
|
+
"role": "Primary 1",
|
|
120075
|
+
"name": "Burnt Orange",
|
|
120076
|
+
"hex": "#e8751a"
|
|
120077
|
+
},
|
|
120078
|
+
{
|
|
120079
|
+
"role": "Primary 2",
|
|
120080
|
+
"name": "Deep Teal",
|
|
120081
|
+
"hex": "#0a6e6e"
|
|
120082
|
+
},
|
|
120083
|
+
{
|
|
120084
|
+
"role": "Background",
|
|
120085
|
+
"name": "Off-Black",
|
|
120086
|
+
"hex": "#121212"
|
|
120087
|
+
},
|
|
120088
|
+
{
|
|
120089
|
+
"role": "Background Alt",
|
|
120090
|
+
"name": "Dark Charcoal",
|
|
120091
|
+
"hex": "#1e1e1e"
|
|
120092
|
+
},
|
|
120093
|
+
{
|
|
120094
|
+
"role": "Accent 1",
|
|
120095
|
+
"name": "Warm Cream",
|
|
120096
|
+
"hex": "#f5e6d0"
|
|
120097
|
+
},
|
|
120098
|
+
{
|
|
120099
|
+
"role": "Accent 2",
|
|
120100
|
+
"name": "Amber Highlight",
|
|
120101
|
+
"hex": "#f4a623"
|
|
120102
|
+
}
|
|
120103
|
+
],
|
|
120104
|
+
"decorativeHints": [
|
|
120105
|
+
"Stark two-color separation across entire composition",
|
|
120106
|
+
"Halftone transitions between the two colors",
|
|
120107
|
+
"Silhouettes in one color against the other",
|
|
120108
|
+
"Minimal use of third color (only for small highlights)",
|
|
120109
|
+
"High contrast figure-ground relationships"
|
|
120110
|
+
],
|
|
120111
|
+
"bestFor": "",
|
|
120112
|
+
"pairs": [
|
|
120113
|
+
{
|
|
120114
|
+
"name": "Orange + Teal",
|
|
120115
|
+
"a": "#e8751a",
|
|
120116
|
+
"b": "#0a6e6e",
|
|
120117
|
+
"feel": "Cinematic, action"
|
|
120118
|
+
},
|
|
120119
|
+
{
|
|
120120
|
+
"name": "Red + Cream",
|
|
120121
|
+
"a": "#c0392b",
|
|
120122
|
+
"b": "#f5e6d0",
|
|
120123
|
+
"feel": "Bold, classic"
|
|
120124
|
+
},
|
|
120125
|
+
{
|
|
120126
|
+
"name": "Blue + Gold",
|
|
120127
|
+
"a": "#1a3a5c",
|
|
120128
|
+
"b": "#d4a843",
|
|
120129
|
+
"feel": "Prestigious, premium"
|
|
120130
|
+
},
|
|
120131
|
+
{
|
|
120132
|
+
"name": "Purple + Green",
|
|
120133
|
+
"a": "#6b3fa0",
|
|
120134
|
+
"b": "#2ecc71",
|
|
120135
|
+
"feel": "Futuristic, contrast"
|
|
120136
|
+
},
|
|
120137
|
+
{
|
|
120138
|
+
"name": "Magenta + Cyan",
|
|
120139
|
+
"a": "#c2185b",
|
|
120140
|
+
"b": "#00bcd4",
|
|
120141
|
+
"feel": "Vibrant, pop"
|
|
120142
|
+
},
|
|
120143
|
+
{
|
|
120144
|
+
"name": "Crimson + Navy",
|
|
120145
|
+
"a": "#dc143c",
|
|
120146
|
+
"b": "#0d1b2a",
|
|
120147
|
+
"feel": "Dramatic, noir"
|
|
120148
|
+
}
|
|
120149
|
+
]
|
|
120150
|
+
},
|
|
120151
|
+
{
|
|
120152
|
+
"id": "vivid",
|
|
120153
|
+
"tagline": "Energetic, bold, attention-grabbing",
|
|
120154
|
+
"colors": [
|
|
120155
|
+
{
|
|
120156
|
+
"role": "Primary 1",
|
|
120157
|
+
"name": "Bright Red",
|
|
120158
|
+
"hex": "#ef4444"
|
|
120159
|
+
},
|
|
120160
|
+
{
|
|
120161
|
+
"role": "Primary 2",
|
|
120162
|
+
"name": "Neon Green",
|
|
120163
|
+
"hex": "#22c55e"
|
|
120164
|
+
},
|
|
120165
|
+
{
|
|
120166
|
+
"role": "Primary 3",
|
|
120167
|
+
"name": "Electric Blue",
|
|
120168
|
+
"hex": "#3b82f6"
|
|
120169
|
+
},
|
|
120170
|
+
{
|
|
120171
|
+
"role": "Background",
|
|
120172
|
+
"name": "Light Blue",
|
|
120173
|
+
"hex": "#eff6ff"
|
|
120174
|
+
},
|
|
120175
|
+
{
|
|
120176
|
+
"role": "Background Alt",
|
|
120177
|
+
"name": "Soft Lavender",
|
|
120178
|
+
"hex": "#f5f3ff"
|
|
120179
|
+
},
|
|
120180
|
+
{
|
|
120181
|
+
"role": "Accent 1",
|
|
120182
|
+
"name": "Bright Orange",
|
|
120183
|
+
"hex": "#fb923c"
|
|
120184
|
+
},
|
|
120185
|
+
{
|
|
120186
|
+
"role": "Accent 2",
|
|
120187
|
+
"name": "Vivid Yellow",
|
|
120188
|
+
"hex": "#facc15"
|
|
120189
|
+
}
|
|
120190
|
+
],
|
|
120191
|
+
"decorativeHints": [
|
|
120192
|
+
"Dynamic diagonal lines and angles",
|
|
120193
|
+
"Bold geometric shapes and color blocks",
|
|
120194
|
+
"Dramatic lighting effects",
|
|
120195
|
+
"High-energy visual compositions"
|
|
120196
|
+
],
|
|
120197
|
+
"bestFor": ""
|
|
120198
|
+
}
|
|
120199
|
+
];
|
|
120200
|
+
var renderings = [
|
|
120201
|
+
{
|
|
120202
|
+
"id": "flat-vector",
|
|
120203
|
+
"tagline": "Clean, modern, geometric illustration",
|
|
120204
|
+
"lines": [
|
|
120205
|
+
"Clean outlines with uniform stroke weight",
|
|
120206
|
+
"Closed shapes (coloring-book style)",
|
|
120207
|
+
"Rounded line endings, avoid sharp corners",
|
|
120208
|
+
"Consistent stroke width throughout"
|
|
120209
|
+
],
|
|
120210
|
+
"texture": [
|
|
120211
|
+
"None: smooth, flat color fills only",
|
|
120212
|
+
"No gradients, shadows, or noise",
|
|
120213
|
+
"Solid color blocks"
|
|
120214
|
+
],
|
|
120215
|
+
"depth": [
|
|
120216
|
+
"Flat: no shadows, no perspective",
|
|
120217
|
+
"2D layering with overlap for depth illusion",
|
|
120218
|
+
"Optional 2.5D isometric layering (front/back occlusion, no atmospheric perspective)",
|
|
120219
|
+
"No 3D effects or bevels"
|
|
120220
|
+
],
|
|
120221
|
+
"elements": [
|
|
120222
|
+
"Geometric icons and simple shapes",
|
|
120223
|
+
"Bold outlined objects with clean fills",
|
|
120224
|
+
"Geometric simplification: complex objects → basic shapes (trees → lollipop/triangle, buildings → rectangles)",
|
|
120225
|
+
"\"Toy model\" aesthetic: cute, rounded proportions",
|
|
120226
|
+
"Decorative: dots, lines, sunbursts, pill-shaped clouds, small stars",
|
|
120227
|
+
"Isolated elements on clean backgrounds"
|
|
120228
|
+
]
|
|
120229
|
+
},
|
|
120230
|
+
{
|
|
120231
|
+
"id": "pixel",
|
|
120232
|
+
"tagline": "Retro 8-bit, nostalgic, chunky",
|
|
120233
|
+
"lines": [
|
|
120234
|
+
"Pixel grid alignment, no anti-aliasing",
|
|
120235
|
+
"Staircase edges on diagonals",
|
|
120236
|
+
"Single-pixel or double-pixel outlines",
|
|
120237
|
+
"Blocky, angular forms"
|
|
120238
|
+
],
|
|
120239
|
+
"texture": [
|
|
120240
|
+
"Dithering patterns for gradients",
|
|
120241
|
+
"No smooth transitions",
|
|
120242
|
+
"Cross-hatching with pixel precision",
|
|
120243
|
+
"Limited 16-32 color palette per scene"
|
|
120244
|
+
],
|
|
120245
|
+
"depth": [
|
|
120246
|
+
"None: flat pixel planes only",
|
|
120247
|
+
"Parallax layering (foreground/background)",
|
|
120248
|
+
"No perspective or 3D effects"
|
|
120249
|
+
],
|
|
120250
|
+
"elements": [
|
|
120251
|
+
"8-bit sprites and chunky shapes",
|
|
120252
|
+
"Simple iconography: stars, hearts, arrows",
|
|
120253
|
+
"Text bubbles with pixel borders",
|
|
120254
|
+
"Progress bars with chunky segments",
|
|
120255
|
+
"Retro gaming UI elements"
|
|
120256
|
+
]
|
|
120257
|
+
},
|
|
120258
|
+
{
|
|
120259
|
+
"id": "digital",
|
|
120260
|
+
"tagline": "Polished, precise, modern",
|
|
120261
|
+
"lines": [
|
|
120262
|
+
"Clean, precise, computer-perfect edges",
|
|
120263
|
+
"Consistent stroke weights",
|
|
120264
|
+
"Sharp corners where appropriate",
|
|
120265
|
+
"Anti-aliased smooth rendering"
|
|
120266
|
+
],
|
|
120267
|
+
"texture": [
|
|
120268
|
+
"Smooth surfaces with no visible texture",
|
|
120269
|
+
"Subtle gradients permitted (soft, controlled)",
|
|
120270
|
+
"Frosted glass and blur effects",
|
|
120271
|
+
"Clean shadows with consistent direction"
|
|
120272
|
+
],
|
|
120273
|
+
"depth": [
|
|
120274
|
+
"Subtle gradients and soft drop shadows",
|
|
120275
|
+
"Layered card-based layouts",
|
|
120276
|
+
"Light 3D effects (subtle, not realistic)",
|
|
120277
|
+
"Material Design-inspired elevation"
|
|
120278
|
+
],
|
|
120279
|
+
"elements": [
|
|
120280
|
+
"Polished icons and UI components",
|
|
120281
|
+
"Data visualizations: charts, graphs, metrics",
|
|
120282
|
+
"Card layouts and structured grids",
|
|
120283
|
+
"Tag chips, progress bars, status indicators",
|
|
120284
|
+
"Clean geometric shapes"
|
|
120285
|
+
]
|
|
120286
|
+
},
|
|
120287
|
+
{
|
|
120288
|
+
"id": "hand-drawn",
|
|
120289
|
+
"tagline": "Sketchy, organic, personal",
|
|
120290
|
+
"lines": [
|
|
120291
|
+
"Sketchy, organic, slightly imperfect strokes",
|
|
120292
|
+
"Variable line weight (thicker at pressure points)",
|
|
120293
|
+
"Wavy connectors and arrows",
|
|
120294
|
+
"Natural hand tremor visible"
|
|
120295
|
+
],
|
|
120296
|
+
"texture": [
|
|
120297
|
+
"Paper grain and subtle surface texture",
|
|
120298
|
+
"Pencil/pen/marker texture on strokes",
|
|
120299
|
+
"Casual fills with visible brush direction"
|
|
120300
|
+
],
|
|
120301
|
+
"depth": [
|
|
120302
|
+
"Minimal: light hand-drawn shadows or hatching",
|
|
120303
|
+
"No realistic depth or perspective",
|
|
120304
|
+
"Simple layering with overlap"
|
|
120305
|
+
],
|
|
120306
|
+
"elements": [
|
|
120307
|
+
"Doodles, organic shapes, hand-lettered labels",
|
|
120308
|
+
"Conceptual icons with sketchy quality",
|
|
120309
|
+
"Connection lines with hand-drawn wavy feel",
|
|
120310
|
+
"Stars, arrows, underlines, circles, checkmarks",
|
|
120311
|
+
"Stick figures and simple characters"
|
|
120312
|
+
]
|
|
120313
|
+
},
|
|
120314
|
+
{
|
|
120315
|
+
"id": "painterly",
|
|
120316
|
+
"tagline": "Soft, artistic, expressive",
|
|
120317
|
+
"lines": [
|
|
120318
|
+
"Soft brush strokes with variable opacity",
|
|
120319
|
+
"No hard outlines; edges defined by color transitions",
|
|
120320
|
+
"Organic flowing strokes with natural blending"
|
|
120321
|
+
],
|
|
120322
|
+
"texture": [
|
|
120323
|
+
"Visible paint or watercolor wash textures",
|
|
120324
|
+
"Color bleeds and wet-on-wet effects",
|
|
120325
|
+
"Paper texture showing through transparent areas",
|
|
120326
|
+
"Brush stroke patterns visible"
|
|
120327
|
+
],
|
|
120328
|
+
"depth": [
|
|
120329
|
+
"Soft edges with natural color blending",
|
|
120330
|
+
"Atmospheric depth through color fading",
|
|
120331
|
+
"Layered washes creating depth illusion"
|
|
120332
|
+
],
|
|
120333
|
+
"elements": [
|
|
120334
|
+
"Watercolor washes as backgrounds",
|
|
120335
|
+
"Natural elements: leaves, flowers, organic forms",
|
|
120336
|
+
"Soft gradients and color transitions",
|
|
120337
|
+
"Splatter and drip effects as accents",
|
|
120338
|
+
"Botanical and environmental motifs"
|
|
120339
|
+
]
|
|
120340
|
+
},
|
|
120341
|
+
{
|
|
120342
|
+
"id": "chalk",
|
|
120343
|
+
"tagline": "Educational, authentic, classroom",
|
|
120344
|
+
"lines": [
|
|
120345
|
+
"Imperfect chalk strokes with variable pressure",
|
|
120346
|
+
"Visible chalk texture and grain",
|
|
120347
|
+
"Slightly wobbly, hand-drawn quality",
|
|
120348
|
+
"Thick strokes for emphasis, thin for details"
|
|
120349
|
+
],
|
|
120350
|
+
"texture": [
|
|
120351
|
+
"Chalk dust effects around text and elements",
|
|
120352
|
+
"Board surface (dark, slightly worn)",
|
|
120353
|
+
"Eraser smudges and residue",
|
|
120354
|
+
"Grainy chalk quality on all elements"
|
|
120355
|
+
],
|
|
120356
|
+
"depth": [
|
|
120357
|
+
"None: flat chalk drawings on board surface",
|
|
120358
|
+
"Layering through erasure and redrawing",
|
|
120359
|
+
"No shadows or perspective"
|
|
120360
|
+
],
|
|
120361
|
+
"elements": [
|
|
120362
|
+
"Chalk doodles: stars, arrows, underlines",
|
|
120363
|
+
"Mathematical formulas and diagrams",
|
|
120364
|
+
"Stick figures and simple icons",
|
|
120365
|
+
"Connection lines with chalk feel",
|
|
120366
|
+
"Checkmarks, circles, boxes for lists",
|
|
120367
|
+
"Wooden frame border optional"
|
|
120368
|
+
]
|
|
120369
|
+
},
|
|
120370
|
+
{
|
|
120371
|
+
"id": "screen-print",
|
|
120372
|
+
"tagline": "Bold, limited-color poster art with print texture",
|
|
120373
|
+
"lines": [
|
|
120374
|
+
"Clean, sharp edges between color blocks",
|
|
120375
|
+
"No outlines — shapes defined by color boundaries",
|
|
120376
|
+
"Stencil-cut quality, bold silhouettes",
|
|
120377
|
+
"Geometric shapes with precise registration"
|
|
120378
|
+
],
|
|
120379
|
+
"texture": [
|
|
120380
|
+
"Halftone dot patterns within color fills",
|
|
120381
|
+
"Slight color layer misregistration (offset between print layers)",
|
|
120382
|
+
"Paper grain texture beneath colors",
|
|
120383
|
+
"Risograph / screen print imperfections (ink spread, dot gain)"
|
|
120384
|
+
],
|
|
120385
|
+
"depth": [
|
|
120386
|
+
"Flat color planes layered front to back",
|
|
120387
|
+
"Depth through silhouette overlap and color layering",
|
|
120388
|
+
"No gradients — tonal variation via halftone density",
|
|
120389
|
+
"Negative space as active compositional element"
|
|
120390
|
+
],
|
|
120391
|
+
"elements": [
|
|
120392
|
+
"Bold silhouettes and symbolic shapes",
|
|
120393
|
+
"Geometric framing (circles, arches, triangles)",
|
|
120394
|
+
"Figure-ground inversion (negative space forms secondary image)",
|
|
120395
|
+
"Limited icon vocabulary: key props, symbolic objects",
|
|
120396
|
+
"Typography integrated as design element, not overlay",
|
|
120397
|
+
"Vintage poster border treatments"
|
|
120398
|
+
]
|
|
120399
|
+
}
|
|
120400
|
+
];
|
|
120401
|
+
var textLevels = [
|
|
120402
|
+
{
|
|
120403
|
+
"id": "none",
|
|
120404
|
+
"area": "85% visual area"
|
|
120405
|
+
},
|
|
120406
|
+
{
|
|
120407
|
+
"id": "title-only",
|
|
120408
|
+
"area": "85% visual area"
|
|
120409
|
+
},
|
|
120410
|
+
{
|
|
120411
|
+
"id": "title-subtitle",
|
|
120412
|
+
"area": "75% visual area"
|
|
120413
|
+
},
|
|
120414
|
+
{
|
|
120415
|
+
"id": "text-rich",
|
|
120416
|
+
"area": "60% visual area"
|
|
120417
|
+
}
|
|
120418
|
+
];
|
|
120419
|
+
var moods = [
|
|
120420
|
+
{
|
|
120421
|
+
"id": "subtle",
|
|
120422
|
+
"application": "Use low contrast, muted colors, light visual weight, calm aesthetic"
|
|
120423
|
+
},
|
|
120424
|
+
{
|
|
120425
|
+
"id": "balanced",
|
|
120426
|
+
"application": "Use medium contrast, normal saturation, balanced visual weight"
|
|
120427
|
+
},
|
|
120428
|
+
{
|
|
120429
|
+
"id": "bold",
|
|
120430
|
+
"application": "Use high contrast, vivid saturated colors, heavy visual weight, dynamic energy"
|
|
120431
|
+
}
|
|
120432
|
+
];
|
|
120433
|
+
//#endregion
|
|
120434
|
+
//#region lib/types/baoyu-compose.js
|
|
120435
|
+
/**
|
|
120436
|
+
* Dimension-composition prompt assembly for the inspiration composer tab.
|
|
120437
|
+
* Data is generated by scripts/build-baoyu-compose.mjs from JimLiu/baoyu-skills
|
|
120438
|
+
* (baoyu-cover-image skill, MIT license).
|
|
120439
|
+
*/
|
|
120440
|
+
/** Pseudo inspiration source id that switches the view into composer mode. */
|
|
120441
|
+
const BAOYU_COMPOSER_SOURCE_ID = "baoyu-compose";
|
|
120442
|
+
const BAOYU_TYPES = types;
|
|
120443
|
+
const BAOYU_PALETTES = palettes;
|
|
120444
|
+
const BAOYU_RENDERINGS = renderings;
|
|
120445
|
+
const BAOYU_TEXT_LEVELS = textLevels;
|
|
120446
|
+
const BAOYU_MOODS = moods;
|
|
120447
|
+
/** Chinese labels for every dimension option id, shown when the UI language is zh. */
|
|
120448
|
+
const BAOYU_LABELS_ZH = {
|
|
120449
|
+
hero: "主视觉大图",
|
|
120450
|
+
conceptual: "概念抽象",
|
|
120451
|
+
typography: "文字主导",
|
|
120452
|
+
metaphor: "隐喻象征",
|
|
120453
|
+
scene: "氛围场景",
|
|
120454
|
+
minimal: "极简留白",
|
|
120455
|
+
warm: "暖色",
|
|
120456
|
+
cool: "冷色",
|
|
120457
|
+
dark: "暗色",
|
|
120458
|
+
earth: "大地色",
|
|
120459
|
+
elegant: "优雅",
|
|
120460
|
+
macaron: "马卡龙",
|
|
120461
|
+
mono: "单色",
|
|
120462
|
+
pastel: "粉彩",
|
|
120463
|
+
retro: "复古",
|
|
120464
|
+
duotone: "双色调",
|
|
120465
|
+
vivid: "高饱和",
|
|
120466
|
+
"flat-vector": "扁平矢量",
|
|
120467
|
+
pixel: "像素风",
|
|
120468
|
+
digital: "数字插画",
|
|
120469
|
+
"hand-drawn": "手绘",
|
|
120470
|
+
painterly: "绘画感",
|
|
120471
|
+
chalk: "粉笔",
|
|
120472
|
+
"screen-print": "丝网印刷",
|
|
120473
|
+
none: "无文字",
|
|
120474
|
+
"title-only": "仅标题",
|
|
120475
|
+
"title-subtitle": "标题+副标题",
|
|
120476
|
+
"text-rich": "丰富文字",
|
|
120477
|
+
subtle: "含蓄",
|
|
120478
|
+
balanced: "均衡",
|
|
120479
|
+
bold: "强烈"
|
|
120480
|
+
};
|
|
120481
|
+
const BAOYU_DEFAULT_SELECTION = {
|
|
120482
|
+
type: "metaphor",
|
|
120483
|
+
palette: "warm",
|
|
120484
|
+
rendering: "flat-vector",
|
|
120485
|
+
text: "title-only",
|
|
120486
|
+
mood: "balanced",
|
|
120487
|
+
title: ""
|
|
120488
|
+
};
|
|
120489
|
+
function palette(id) {
|
|
120490
|
+
return BAOYU_PALETTES.find((item) => item.id === id);
|
|
120491
|
+
}
|
|
120492
|
+
function rendering(id) {
|
|
120493
|
+
return BAOYU_RENDERINGS.find((item) => item.id === id);
|
|
120494
|
+
}
|
|
120495
|
+
function typeOf(id) {
|
|
120496
|
+
return BAOYU_TYPES.find((item) => item.id === id);
|
|
120497
|
+
}
|
|
120498
|
+
function moodOf(id) {
|
|
120499
|
+
return BAOYU_MOODS.find((item) => item.id === id);
|
|
120500
|
+
}
|
|
120501
|
+
function textLevel(id) {
|
|
120502
|
+
return BAOYU_TEXT_LEVELS.find((item) => item.id === id);
|
|
120503
|
+
}
|
|
120504
|
+
/** Assemble the five-dimension selection into one generate_image-ready prompt. */
|
|
120505
|
+
function composeBaoyuPrompt(selection) {
|
|
120506
|
+
const chosenType = typeOf(selection.type);
|
|
120507
|
+
const chosenPalette = palette(selection.palette);
|
|
120508
|
+
const chosenRendering = rendering(selection.rendering);
|
|
120509
|
+
const chosenText = textLevel(selection.text);
|
|
120510
|
+
const chosenMood = moodOf(selection.mood);
|
|
120511
|
+
if (chosenType === void 0 || chosenPalette === void 0 || chosenRendering === void 0 || chosenText === void 0 || chosenMood === void 0) throw new Error("invalid-baoyu-selection");
|
|
120512
|
+
const title = selection.title.trim();
|
|
120513
|
+
if (selection.text !== "none" && title === "") throw new Error("baoyu-title-required");
|
|
120514
|
+
const primary = chosenPalette.colors.filter((color) => color.role.startsWith("Primary"));
|
|
120515
|
+
const background = chosenPalette.colors.filter((color) => color.role.startsWith("Background"));
|
|
120516
|
+
const accent = chosenPalette.colors.filter((color) => color.role.startsWith("Accent"));
|
|
120517
|
+
const swatch = (colors) => colors.map((color) => `${color.name} ${color.hex}`).join(", ");
|
|
120518
|
+
const textElements = selection.text === "none" ? "No text elements; the full area stays visual." : [
|
|
120519
|
+
`Title: "${title}"`,
|
|
120520
|
+
...selection.text === "title-subtitle" || selection.text === "text-rich" ? ["Subtitle: derive one short supporting line from the title"] : [],
|
|
120521
|
+
...selection.text === "text-rich" ? ["Tags: derive 2-3 keyword badges from the title"] : []
|
|
120522
|
+
].join("\n");
|
|
120523
|
+
const pairNote = chosenPalette.pairs === void 0 ? "" : `\n- Duotone pair: pick ONE dominant two-color pair from ${chosenPalette.pairs.map((pair) => `${pair.name} (${pair.a} + ${pair.b})`).join("; ")}`;
|
|
120524
|
+
return [
|
|
120525
|
+
"Cover image.",
|
|
120526
|
+
"",
|
|
120527
|
+
"# Visual Design",
|
|
120528
|
+
`- Type: ${chosenType.id} — ${chosenType.composition}`,
|
|
120529
|
+
`- Palette: ${chosenPalette.id} (${chosenPalette.tagline})`,
|
|
120530
|
+
`- Rendering: ${chosenRendering.id} — ${chosenRendering.tagline}`,
|
|
120531
|
+
`- Text level: ${chosenText.id} (${chosenText.area})`,
|
|
120532
|
+
`- Mood: ${chosenMood.id} — ${chosenMood.application}`,
|
|
120533
|
+
"",
|
|
120534
|
+
"# Text Elements",
|
|
120535
|
+
textElements,
|
|
120536
|
+
"",
|
|
120537
|
+
"# Composition",
|
|
120538
|
+
`- Type composition: ${chosenType.composition}`,
|
|
120539
|
+
"- Layout: generous whitespace (40-60% breathing room); one dominant focal point with 1-2 supporting elements plus decorative accents; main visual centered or slightly left, reserving the right side for the title when included.",
|
|
120540
|
+
`- Decorative: ${chosenPalette.decorativeHints.join("; ")}`,
|
|
120541
|
+
"",
|
|
120542
|
+
"# Color Scheme",
|
|
120543
|
+
`- Primary: ${swatch(primary)}`,
|
|
120544
|
+
`- Background: ${swatch(background)}`,
|
|
120545
|
+
`- Accent: ${swatch(accent)}${pairNote}`,
|
|
120546
|
+
`- Mood adjustment: ${chosenMood.application}`,
|
|
120547
|
+
"- Color constraint: Color values (#hex) and color names are rendering guidance only — do NOT display color names, hex codes, or palette labels as visible text in the image.",
|
|
120548
|
+
"",
|
|
120549
|
+
`# Rendering Notes (${chosenRendering.id})`,
|
|
120550
|
+
`- Lines: ${chosenRendering.lines.join("; ")}`,
|
|
120551
|
+
`- Texture: ${chosenRendering.texture.join("; ")}`,
|
|
120552
|
+
`- Depth: ${chosenRendering.depth.join("; ")}`,
|
|
120553
|
+
`- Elements: ${chosenRendering.elements.join("; ")}`,
|
|
120554
|
+
"",
|
|
120555
|
+
"# Core Principles",
|
|
120556
|
+
"- Ample whitespace, highlight the core message, avoid cluttered layouts.",
|
|
120557
|
+
"- Simplified silhouettes for any characters — no realistic human faces or bodies.",
|
|
120558
|
+
"- Icon-based vocabulary: represent concepts with simple, recognizable icons."
|
|
120559
|
+
].join("\n");
|
|
120560
|
+
}
|
|
120561
|
+
/** Randomize every visual dimension, keeping the current title text. */
|
|
120562
|
+
function randomBaoyuSelection(current) {
|
|
120563
|
+
const pick = (items) => items[Math.floor(Math.random() * items.length)];
|
|
120564
|
+
return {
|
|
120565
|
+
type: pick(BAOYU_TYPES).id,
|
|
120566
|
+
palette: pick(BAOYU_PALETTES).id,
|
|
120567
|
+
rendering: pick(BAOYU_RENDERINGS).id,
|
|
120568
|
+
text: pick(BAOYU_TEXT_LEVELS).id,
|
|
120569
|
+
mood: pick(BAOYU_MOODS).id,
|
|
120570
|
+
title: current.title
|
|
120571
|
+
};
|
|
120572
|
+
}
|
|
120573
|
+
//#endregion
|
|
118853
120574
|
//#region lib/types/client/inspiration-view.js
|
|
118854
120575
|
const FAVORITES_STORAGE_KEY = "dsh-ig-inspiration-favorites";
|
|
118855
120576
|
function loadInspirationFavorites() {
|
|
@@ -118941,6 +120662,7 @@ img.ProseMirror-separator {
|
|
|
118941
120662
|
allCategories: "全部分类",
|
|
118942
120663
|
allStyles: "全部风格",
|
|
118943
120664
|
allScenes: "全部场景",
|
|
120665
|
+
categoryNav: "分类导航",
|
|
118944
120666
|
search: "搜索案例、Prompt、风格…",
|
|
118945
120667
|
results: "找到 {count} 个案例",
|
|
118946
120668
|
noResults: "没有匹配的素材,换个关键词或筛选条件试试。",
|
|
@@ -118950,6 +120672,9 @@ img.ProseMirror-separator {
|
|
|
118950
120672
|
copied: "已复制",
|
|
118951
120673
|
use: "使用这个 Prompt",
|
|
118952
120674
|
source: "查看原来源",
|
|
120675
|
+
useReference: "提示词 + 参考图",
|
|
120676
|
+
referenceLoading: "获取参考图中…",
|
|
120677
|
+
referenceFailed: "参考图获取失败,请重试",
|
|
118953
120678
|
loading: "正在读取素材库…",
|
|
118954
120679
|
loadFailed: "素材库读取失败,请稍后重试。",
|
|
118955
120680
|
copyFailed: "复制失败",
|
|
@@ -118964,7 +120689,21 @@ img.ProseMirror-separator {
|
|
|
118964
120689
|
favorite: "收藏",
|
|
118965
120690
|
favorited: "已收藏",
|
|
118966
120691
|
zoomHint: "点击放大查看",
|
|
118967
|
-
close: "关闭"
|
|
120692
|
+
close: "关闭",
|
|
120693
|
+
composeTab: "宝玉维度组合",
|
|
120694
|
+
composeHint: "五个维度自由拼接封面 Prompt,数据源自宝玉封图 skill(JimLiu/baoyu-skills,MIT)。",
|
|
120695
|
+
composeType: "类型",
|
|
120696
|
+
composePalette: "色板",
|
|
120697
|
+
composeRendering: "渲染",
|
|
120698
|
+
composeText: "文字",
|
|
120699
|
+
composeMood: "情绪",
|
|
120700
|
+
composeTitleLabel: "标题文字",
|
|
120701
|
+
composeTitlePlaceholder: "输入封面标题(文字层级含标题时必填)",
|
|
120702
|
+
composeTitleRequired: "该文字层级需要先填写标题。",
|
|
120703
|
+
composeRandomize: "随机组合",
|
|
120704
|
+
composeUse: "用此 Prompt 去生成",
|
|
120705
|
+
composeCombos: "共 {count} 种组合",
|
|
120706
|
+
composePreview: "拼接结果预览"
|
|
118968
120707
|
},
|
|
118969
120708
|
en: {
|
|
118970
120709
|
kicker: "Prompt inspiration",
|
|
@@ -118984,6 +120723,7 @@ img.ProseMirror-separator {
|
|
|
118984
120723
|
allCategories: "All categories",
|
|
118985
120724
|
allStyles: "All styles",
|
|
118986
120725
|
allScenes: "All scenes",
|
|
120726
|
+
categoryNav: "Categories",
|
|
118987
120727
|
search: "Search examples, prompts, styles…",
|
|
118988
120728
|
results: "{count} examples",
|
|
118989
120729
|
noResults: "No matching examples. Try another keyword or filter.",
|
|
@@ -118993,6 +120733,9 @@ img.ProseMirror-separator {
|
|
|
118993
120733
|
copied: "Copied",
|
|
118994
120734
|
use: "Use this prompt",
|
|
118995
120735
|
source: "View source",
|
|
120736
|
+
useReference: "Prompt + reference",
|
|
120737
|
+
referenceLoading: "Fetching image…",
|
|
120738
|
+
referenceFailed: "Failed to load the reference image",
|
|
118996
120739
|
loading: "Loading inspiration…",
|
|
118997
120740
|
loadFailed: "Could not load the inspiration library.",
|
|
118998
120741
|
copyFailed: "Failed to copy",
|
|
@@ -119007,12 +120750,28 @@ img.ProseMirror-separator {
|
|
|
119007
120750
|
favorite: "Favorite",
|
|
119008
120751
|
favorited: "Favorited",
|
|
119009
120752
|
zoomHint: "Click to zoom in",
|
|
119010
|
-
close: "Close"
|
|
119011
|
-
|
|
119012
|
-
|
|
119013
|
-
|
|
120753
|
+
close: "Close",
|
|
120754
|
+
composeTab: "Baoyu Composer",
|
|
120755
|
+
composeHint: "Stitch a cover prompt from five dimensions, based on the baoyu cover-image skill (JimLiu/baoyu-skills, MIT).",
|
|
120756
|
+
composeType: "Type",
|
|
120757
|
+
composePalette: "Palette",
|
|
120758
|
+
composeRendering: "Rendering",
|
|
120759
|
+
composeText: "Text",
|
|
120760
|
+
composeMood: "Mood",
|
|
120761
|
+
composeTitleLabel: "Title text",
|
|
120762
|
+
composeTitlePlaceholder: "Cover title (required when the text level includes a title)",
|
|
120763
|
+
composeTitleRequired: "This text level needs a title first.",
|
|
120764
|
+
composeRandomize: "Randomize",
|
|
120765
|
+
composeUse: "Generate with this prompt",
|
|
120766
|
+
composeCombos: "{count} combinations",
|
|
120767
|
+
composePreview: "Composed prompt preview"
|
|
120768
|
+
}
|
|
120769
|
+
};
|
|
120770
|
+
const InspirationView = ({ locale, onUsePrompt, onUseReference }) => {
|
|
119014
120771
|
const [language, setLanguage] = (0, react.useState)(() => locale?.getSnapshot?.().active?.startsWith("en") ? "en" : "zh");
|
|
119015
120772
|
const [catalog, setCatalog] = (0, react.useState)(null);
|
|
120773
|
+
const [activeSourceId, setActiveSourceId] = (0, react.useState)("");
|
|
120774
|
+
const [baoyuSelection, setBaoyuSelection] = (0, react.useState)(BAOYU_DEFAULT_SELECTION);
|
|
119016
120775
|
const [catalogError, setCatalogError] = (0, react.useState)(false);
|
|
119017
120776
|
const [search, setSearch] = (0, react.useState)("");
|
|
119018
120777
|
const [category, setCategory] = (0, react.useState)("");
|
|
@@ -119028,8 +120787,12 @@ img.ProseMirror-separator {
|
|
|
119028
120787
|
const [onlyFavorites, setOnlyFavorites] = (0, react.useState)(false);
|
|
119029
120788
|
const [lightboxCase, setLightboxCase] = (0, react.useState)(null);
|
|
119030
120789
|
const [toast, setToast] = (0, react.useState)(null);
|
|
120790
|
+
const [referenceBusy, setReferenceBusy] = (0, react.useState)(false);
|
|
120791
|
+
const [pendingJump, setPendingJump] = (0, react.useState)("");
|
|
120792
|
+
const [activeCategory, setActiveCategory] = (0, react.useState)("");
|
|
119031
120793
|
const toastTimerRef = (0, react.useRef)(null);
|
|
119032
120794
|
const sentinelRef = (0, react.useRef)(null);
|
|
120795
|
+
const listRef = (0, react.useRef)(null);
|
|
119033
120796
|
(0, react.useEffect)(() => {
|
|
119034
120797
|
if (!locale?.subscribe) return;
|
|
119035
120798
|
return locale.subscribe(() => setLanguage(locale.getSnapshot?.().active?.startsWith("en") ? "en" : "zh"));
|
|
@@ -119099,7 +120862,33 @@ img.ProseMirror-separator {
|
|
|
119099
120862
|
mounted = false;
|
|
119100
120863
|
};
|
|
119101
120864
|
}, []);
|
|
119102
|
-
const source = catalog?.sources[0] ?? null;
|
|
120865
|
+
const source = catalog?.sources.find((candidate) => candidate.id === activeSourceId) ?? catalog?.sources[0] ?? null;
|
|
120866
|
+
const composerActive = activeSourceId === BAOYU_COMPOSER_SOURCE_ID;
|
|
120867
|
+
/** Switch the active library; each source owns its own category/style/scene vocabularies. */
|
|
120868
|
+
const switchSource = (id) => {
|
|
120869
|
+
if (id === activeSourceId) return;
|
|
120870
|
+
setActiveSourceId(id);
|
|
120871
|
+
setCategory("");
|
|
120872
|
+
setStyle("");
|
|
120873
|
+
setScene("");
|
|
120874
|
+
setOnlyFavorites(false);
|
|
120875
|
+
setSelected(null);
|
|
120876
|
+
setPendingJump("");
|
|
120877
|
+
setActiveCategory("");
|
|
120878
|
+
};
|
|
120879
|
+
const useSelectedReference = async () => {
|
|
120880
|
+
if (selected === null || source === null || onUseReference === void 0) return;
|
|
120881
|
+
setReferenceBusy(true);
|
|
120882
|
+
try {
|
|
120883
|
+
const blob = await fetchInspirationImage(source.id, selected.id, source.imageRevision ?? source.version);
|
|
120884
|
+
const ext = blob.type === "image/jpeg" ? "jpg" : blob.type.split("/")[1]?.replace(/[^a-z0-9]/gi, "") || "png";
|
|
120885
|
+
onUseReference(new File([blob], `inspiration-${selected.id}.${ext}`, { type: blob.type.startsWith("image/") ? blob.type : "image/webp" }), selected.prompt);
|
|
120886
|
+
} catch {
|
|
120887
|
+
showToast(t("referenceFailed"), true);
|
|
120888
|
+
} finally {
|
|
120889
|
+
setReferenceBusy(false);
|
|
120890
|
+
}
|
|
120891
|
+
};
|
|
119103
120892
|
const matchingCases = (0, react.useMemo)(() => {
|
|
119104
120893
|
if (source === null) return [];
|
|
119105
120894
|
const query = search.trim().toLowerCase();
|
|
@@ -119141,6 +120930,67 @@ img.ProseMirror-separator {
|
|
|
119141
120930
|
onlyFavorites
|
|
119142
120931
|
]);
|
|
119143
120932
|
const visibleCases = matchingCases.slice(0, visibleLimit);
|
|
120933
|
+
const categoryCounts = (0, react.useMemo)(() => {
|
|
120934
|
+
const counts = /* @__PURE__ */ new Map();
|
|
120935
|
+
for (const item of matchingCases) counts.set(item.category, (counts.get(item.category) ?? 0) + 1);
|
|
120936
|
+
return counts;
|
|
120937
|
+
}, [matchingCases]);
|
|
120938
|
+
const visibleGroups = (0, react.useMemo)(() => {
|
|
120939
|
+
if (source === null) return [];
|
|
120940
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
120941
|
+
for (const item of visibleCases) {
|
|
120942
|
+
const bucket = byCategory.get(item.category);
|
|
120943
|
+
if (bucket !== void 0) bucket.push(item);
|
|
120944
|
+
else byCategory.set(item.category, [item]);
|
|
120945
|
+
}
|
|
120946
|
+
return source.categories.flatMap((name) => {
|
|
120947
|
+
const items = byCategory.get(name);
|
|
120948
|
+
return items !== void 0 ? [{
|
|
120949
|
+
name,
|
|
120950
|
+
items
|
|
120951
|
+
}] : [];
|
|
120952
|
+
});
|
|
120953
|
+
}, [source, visibleCases]);
|
|
120954
|
+
const visibleGroupSignature = visibleGroups.map((group) => group.name).join("\0");
|
|
120955
|
+
const jumpToCategory = (name) => {
|
|
120956
|
+
if (category !== "") setCategory("");
|
|
120957
|
+
setPendingJump(name);
|
|
120958
|
+
};
|
|
120959
|
+
(0, react.useEffect)(() => {
|
|
120960
|
+
if (pendingJump === "") return;
|
|
120961
|
+
const index = matchingCases.findIndex((item) => item.category === pendingJump);
|
|
120962
|
+
if (index < 0) return;
|
|
120963
|
+
if (index >= visibleLimit) {
|
|
120964
|
+
setVisibleLimit(index + 60);
|
|
120965
|
+
return;
|
|
120966
|
+
}
|
|
120967
|
+
const raf = requestAnimationFrame(() => {
|
|
120968
|
+
document.getElementById(`dsh-ig-cat-${encodeURIComponent(pendingJump)}`)?.scrollIntoView({
|
|
120969
|
+
behavior: "smooth",
|
|
120970
|
+
block: "start"
|
|
120971
|
+
});
|
|
120972
|
+
setPendingJump("");
|
|
120973
|
+
});
|
|
120974
|
+
return () => cancelAnimationFrame(raf);
|
|
120975
|
+
}, [
|
|
120976
|
+
pendingJump,
|
|
120977
|
+
matchingCases,
|
|
120978
|
+
visibleLimit
|
|
120979
|
+
]);
|
|
120980
|
+
(0, react.useEffect)(() => {
|
|
120981
|
+
const root = listRef.current;
|
|
120982
|
+
if (root === null) return;
|
|
120983
|
+
const headers = Array.from(root.querySelectorAll(".dsh-ig-inspiration-group-head"));
|
|
120984
|
+
if (headers.length === 0) return;
|
|
120985
|
+
const categoryByTarget = /* @__PURE__ */ new Map();
|
|
120986
|
+
for (const header of headers) categoryByTarget.set(header, header.dataset.category ?? "");
|
|
120987
|
+
const observer = new IntersectionObserver((entries) => {
|
|
120988
|
+
const visible = entries.find((entry) => entry.isIntersecting);
|
|
120989
|
+
if (visible !== void 0) setActiveCategory(categoryByTarget.get(visible.target) ?? "");
|
|
120990
|
+
}, { rootMargin: "0px 0px -75% 0px" });
|
|
120991
|
+
for (const header of headers) observer.observe(header);
|
|
120992
|
+
return () => observer.disconnect();
|
|
120993
|
+
}, [visibleGroupSignature]);
|
|
119144
120994
|
(0, react.useEffect)(() => {
|
|
119145
120995
|
const el = sentinelRef.current;
|
|
119146
120996
|
if (!el) return;
|
|
@@ -119265,179 +121115,256 @@ img.ProseMirror-separator {
|
|
|
119265
121115
|
className: "dsh-ig-spin",
|
|
119266
121116
|
size: 23
|
|
119267
121117
|
}), (0, react_jsx_runtime.jsx)("span", { children: t("loading") })]
|
|
119268
|
-
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
119269
|
-
className: "dsh-ig-inspiration-
|
|
119270
|
-
|
|
119271
|
-
|
|
119272
|
-
|
|
119273
|
-
|
|
119274
|
-
|
|
119275
|
-
|
|
119276
|
-
|
|
119277
|
-
|
|
119278
|
-
|
|
119279
|
-
|
|
121118
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [catalog !== null ? (0, react_jsx_runtime.jsxs)("div", {
|
|
121119
|
+
className: "dsh-ig-inspiration-sources",
|
|
121120
|
+
role: "tablist",
|
|
121121
|
+
children: [catalog.sources.map((item) => (0, react_jsx_runtime.jsx)("button", {
|
|
121122
|
+
type: "button",
|
|
121123
|
+
role: "tab",
|
|
121124
|
+
"aria-selected": !composerActive && item.id === source?.id,
|
|
121125
|
+
className: `dsh-ig-inspiration-source-chip ${!composerActive && item.id === source?.id ? "is-active" : ""}`,
|
|
121126
|
+
onClick: () => switchSource(item.id),
|
|
121127
|
+
children: item.label
|
|
121128
|
+
}, item.id)), (0, react_jsx_runtime.jsxs)("button", {
|
|
121129
|
+
type: "button",
|
|
121130
|
+
role: "tab",
|
|
121131
|
+
"aria-selected": composerActive,
|
|
121132
|
+
className: `dsh-ig-inspiration-source-chip ${composerActive ? "is-active" : ""}`,
|
|
121133
|
+
onClick: () => switchSource(BAOYU_COMPOSER_SOURCE_ID),
|
|
121134
|
+
children: [(0, react_jsx_runtime.jsx)(Sparkles, { size: 11 }), t("composeTab")]
|
|
121135
|
+
})]
|
|
121136
|
+
}) : null, composerActive ? (0, react_jsx_runtime.jsx)(BaoyuComposerPanel, {
|
|
121137
|
+
language,
|
|
121138
|
+
selection: baoyuSelection,
|
|
121139
|
+
onChange: setBaoyuSelection,
|
|
121140
|
+
onUsePrompt
|
|
121141
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
121142
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121143
|
+
className: "dsh-ig-inspiration-toolbar",
|
|
121144
|
+
children: [
|
|
121145
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
121146
|
+
className: "dsh-ig-inspiration-search",
|
|
121147
|
+
children: [(0, react_jsx_runtime.jsx)(Search, { size: 15 }), (0, react_jsx_runtime.jsx)("input", {
|
|
121148
|
+
value: search,
|
|
121149
|
+
onChange: (event) => setSearch(event.target.value),
|
|
121150
|
+
placeholder: t("search")
|
|
121151
|
+
})]
|
|
121152
|
+
}),
|
|
121153
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121154
|
+
type: "button",
|
|
121155
|
+
className: `dsh-ig-inspiration-fav-filter ${onlyFavorites ? "is-active" : ""}`,
|
|
121156
|
+
onClick: () => setOnlyFavorites((prev) => !prev),
|
|
121157
|
+
title: t("onlyFavorites"),
|
|
121158
|
+
children: [(0, react_jsx_runtime.jsx)(Star, {
|
|
121159
|
+
size: 14,
|
|
121160
|
+
className: onlyFavorites ? "fill-star" : ""
|
|
121161
|
+
}), (0, react_jsx_runtime.jsxs)("span", { children: [t("onlyFavorites"), favorites.size > 0 ? ` (${favorites.size})` : ""] })]
|
|
121162
|
+
}),
|
|
121163
|
+
(0, react_jsx_runtime.jsxs)("select", {
|
|
121164
|
+
value: category,
|
|
121165
|
+
onChange: (event) => setCategory(event.target.value),
|
|
121166
|
+
"aria-label": t("allCategories"),
|
|
121167
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
121168
|
+
value: "",
|
|
121169
|
+
children: t("allCategories")
|
|
121170
|
+
}), source.categories.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
121171
|
+
value: item,
|
|
121172
|
+
children: translateTag(item, language)
|
|
121173
|
+
}, item))]
|
|
121174
|
+
}),
|
|
121175
|
+
(0, react_jsx_runtime.jsxs)("select", {
|
|
121176
|
+
value: style,
|
|
121177
|
+
onChange: (event) => setStyle(event.target.value),
|
|
121178
|
+
"aria-label": t("allStyles"),
|
|
121179
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
121180
|
+
value: "",
|
|
121181
|
+
children: t("allStyles")
|
|
121182
|
+
}), source.styles.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
121183
|
+
value: item,
|
|
121184
|
+
children: translateTag(item, language)
|
|
121185
|
+
}, item))]
|
|
121186
|
+
}),
|
|
121187
|
+
(0, react_jsx_runtime.jsxs)("select", {
|
|
121188
|
+
value: scene,
|
|
121189
|
+
onChange: (event) => setScene(event.target.value),
|
|
121190
|
+
"aria-label": t("allScenes"),
|
|
121191
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
121192
|
+
value: "",
|
|
121193
|
+
children: t("allScenes")
|
|
121194
|
+
}), source.scenes.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
121195
|
+
value: item,
|
|
121196
|
+
children: translateTag(item, language)
|
|
121197
|
+
}, item))]
|
|
121198
|
+
})
|
|
121199
|
+
]
|
|
121200
|
+
}),
|
|
121201
|
+
(0, react_jsx_runtime.jsxs)("nav", {
|
|
121202
|
+
className: "dsh-ig-inspiration-catnav",
|
|
121203
|
+
"aria-label": t("categoryNav"),
|
|
121204
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
119280
121205
|
type: "button",
|
|
119281
|
-
className: `dsh-ig-inspiration-
|
|
119282
|
-
onClick: () =>
|
|
119283
|
-
|
|
119284
|
-
|
|
119285
|
-
|
|
119286
|
-
|
|
119287
|
-
|
|
119288
|
-
}),
|
|
119289
|
-
(0, react_jsx_runtime.jsxs)("select", {
|
|
119290
|
-
value: category,
|
|
119291
|
-
onChange: (event) => setCategory(event.target.value),
|
|
119292
|
-
"aria-label": t("allCategories"),
|
|
119293
|
-
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
119294
|
-
value: "",
|
|
119295
|
-
children: t("allCategories")
|
|
119296
|
-
}), source.categories.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
119297
|
-
value: item,
|
|
119298
|
-
children: translateTag(item, language)
|
|
119299
|
-
}, item))]
|
|
119300
|
-
}),
|
|
119301
|
-
(0, react_jsx_runtime.jsxs)("select", {
|
|
119302
|
-
value: style,
|
|
119303
|
-
onChange: (event) => setStyle(event.target.value),
|
|
119304
|
-
"aria-label": t("allStyles"),
|
|
119305
|
-
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
119306
|
-
value: "",
|
|
119307
|
-
children: t("allStyles")
|
|
119308
|
-
}), source.styles.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
119309
|
-
value: item,
|
|
119310
|
-
children: translateTag(item, language)
|
|
119311
|
-
}, item))]
|
|
119312
|
-
}),
|
|
119313
|
-
(0, react_jsx_runtime.jsxs)("select", {
|
|
119314
|
-
value: scene,
|
|
119315
|
-
onChange: (event) => setScene(event.target.value),
|
|
119316
|
-
"aria-label": t("allScenes"),
|
|
119317
|
-
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
119318
|
-
value: "",
|
|
119319
|
-
children: t("allScenes")
|
|
119320
|
-
}), source.scenes.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
119321
|
-
value: item,
|
|
119322
|
-
children: translateTag(item, language)
|
|
119323
|
-
}, item))]
|
|
119324
|
-
})
|
|
119325
|
-
]
|
|
119326
|
-
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
119327
|
-
className: "dsh-ig-inspiration-layout",
|
|
119328
|
-
children: [(0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
119329
|
-
className: "dsh-ig-inspiration-summary",
|
|
119330
|
-
children: [(0, react_jsx_runtime.jsx)("strong", { children: t("results", { count: String(matchingCases.length) }) }), (0, react_jsx_runtime.jsx)("span", { children: source.version.slice(0, 8) })]
|
|
119331
|
-
}), matchingCases.length === 0 ? (0, react_jsx_runtime.jsx)("div", {
|
|
119332
|
-
className: "dsh-ig-inspiration-empty",
|
|
119333
|
-
children: onlyFavorites ? t("noFavorites") : t("noResults")
|
|
119334
|
-
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
119335
|
-
className: "dsh-ig-inspiration-grid",
|
|
119336
|
-
children: visibleCases.map((item) => (0, react_jsx_runtime.jsx)(InspirationCard, {
|
|
119337
|
-
item,
|
|
119338
|
-
sourceId: source.id,
|
|
119339
|
-
selected: selected?.id === item.id,
|
|
119340
|
-
isFavorited: favorites.has(item.id),
|
|
119341
|
-
language,
|
|
119342
|
-
featuredLabel: t("featured"),
|
|
119343
|
-
retryLabel: t("retry"),
|
|
119344
|
-
onSelect: () => {
|
|
119345
|
-
setSelected(item);
|
|
119346
|
-
setCopied(false);
|
|
121206
|
+
className: `dsh-ig-inspiration-catnav-chip ${category === "" && activeCategory === "" ? "is-active" : ""}`,
|
|
121207
|
+
onClick: () => {
|
|
121208
|
+
if (category !== "") setCategory("");
|
|
121209
|
+
listRef.current?.scrollIntoView({
|
|
121210
|
+
behavior: "smooth",
|
|
121211
|
+
block: "start"
|
|
121212
|
+
});
|
|
119347
121213
|
},
|
|
119348
|
-
|
|
119349
|
-
},
|
|
119350
|
-
|
|
119351
|
-
|
|
119352
|
-
|
|
119353
|
-
|
|
119354
|
-
|
|
119355
|
-
|
|
119356
|
-
|
|
119357
|
-
|
|
119358
|
-
|
|
119359
|
-
|
|
119360
|
-
|
|
119361
|
-
|
|
119362
|
-
|
|
119363
|
-
|
|
119364
|
-
|
|
119365
|
-
className: "dsh-ig-inspiration-
|
|
119366
|
-
|
|
119367
|
-
|
|
119368
|
-
|
|
119369
|
-
|
|
119370
|
-
|
|
119371
|
-
|
|
119372
|
-
|
|
119373
|
-
children:
|
|
119374
|
-
|
|
119375
|
-
|
|
119376
|
-
|
|
119377
|
-
|
|
119378
|
-
|
|
119379
|
-
|
|
119380
|
-
|
|
119381
|
-
|
|
119382
|
-
|
|
119383
|
-
|
|
119384
|
-
|
|
119385
|
-
|
|
119386
|
-
|
|
119387
|
-
|
|
119388
|
-
|
|
119389
|
-
|
|
119390
|
-
|
|
119391
|
-
|
|
119392
|
-
|
|
119393
|
-
|
|
119394
|
-
|
|
119395
|
-
|
|
119396
|
-
})
|
|
119397
|
-
})
|
|
119398
|
-
|
|
119399
|
-
|
|
119400
|
-
|
|
119401
|
-
|
|
119402
|
-
|
|
119403
|
-
|
|
119404
|
-
|
|
119405
|
-
|
|
119406
|
-
|
|
119407
|
-
|
|
119408
|
-
|
|
119409
|
-
|
|
119410
|
-
|
|
119411
|
-
|
|
119412
|
-
|
|
121214
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("allCategories") }), (0, react_jsx_runtime.jsx)("em", { children: matchingCases.length })]
|
|
121215
|
+
}), source.categories.map((name) => {
|
|
121216
|
+
const count = categoryCounts.get(name) ?? 0;
|
|
121217
|
+
const isActive = category === name || category === "" && activeCategory === name;
|
|
121218
|
+
return (0, react_jsx_runtime.jsxs)("button", {
|
|
121219
|
+
type: "button",
|
|
121220
|
+
disabled: count === 0,
|
|
121221
|
+
"aria-current": isActive || void 0,
|
|
121222
|
+
className: `dsh-ig-inspiration-catnav-chip ${isActive ? "is-active" : ""}`,
|
|
121223
|
+
onClick: () => jumpToCategory(name),
|
|
121224
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: translateTag(name, language) }), (0, react_jsx_runtime.jsx)("em", { children: count })]
|
|
121225
|
+
}, name);
|
|
121226
|
+
})]
|
|
121227
|
+
}),
|
|
121228
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121229
|
+
className: "dsh-ig-inspiration-layout",
|
|
121230
|
+
children: [(0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
121231
|
+
className: "dsh-ig-inspiration-summary",
|
|
121232
|
+
children: [(0, react_jsx_runtime.jsx)("strong", { children: t("results", { count: String(matchingCases.length) }) }), (0, react_jsx_runtime.jsx)("span", { children: source.version.slice(0, 8) })]
|
|
121233
|
+
}), matchingCases.length === 0 ? (0, react_jsx_runtime.jsx)("div", {
|
|
121234
|
+
className: "dsh-ig-inspiration-empty",
|
|
121235
|
+
children: onlyFavorites ? t("noFavorites") : t("noResults")
|
|
121236
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
121237
|
+
ref: listRef,
|
|
121238
|
+
className: "dsh-ig-inspiration-list",
|
|
121239
|
+
children: visibleGroups.map((group) => (0, react_jsx_runtime.jsxs)("section", {
|
|
121240
|
+
className: "dsh-ig-inspiration-group",
|
|
121241
|
+
children: [(0, react_jsx_runtime.jsxs)("h3", {
|
|
121242
|
+
id: `dsh-ig-cat-${encodeURIComponent(group.name)}`,
|
|
121243
|
+
"data-category": group.name,
|
|
121244
|
+
className: "dsh-ig-inspiration-group-head",
|
|
121245
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: translateTag(group.name, language) }), (0, react_jsx_runtime.jsx)("em", { children: categoryCounts.get(group.name) ?? group.items.length })]
|
|
121246
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
121247
|
+
className: "dsh-ig-inspiration-grid",
|
|
121248
|
+
children: group.items.map((item) => (0, react_jsx_runtime.jsx)(InspirationCard, {
|
|
121249
|
+
item,
|
|
121250
|
+
sourceId: source.id,
|
|
121251
|
+
sourceRevision: source.imageRevision ?? source.version,
|
|
121252
|
+
selected: selected?.id === item.id,
|
|
121253
|
+
isFavorited: favorites.has(item.id),
|
|
121254
|
+
language,
|
|
121255
|
+
featuredLabel: t("featured"),
|
|
121256
|
+
retryLabel: t("retry"),
|
|
121257
|
+
onSelect: () => {
|
|
121258
|
+
setSelected(item);
|
|
121259
|
+
setCopied(false);
|
|
121260
|
+
},
|
|
121261
|
+
onToggleFavorite: () => toggleFavorite(item.id)
|
|
121262
|
+
}, item.id))
|
|
121263
|
+
})]
|
|
121264
|
+
}, group.name))
|
|
121265
|
+
}), visibleCases.length < matchingCases.length ? (0, react_jsx_runtime.jsx)("div", {
|
|
121266
|
+
ref: sentinelRef,
|
|
121267
|
+
style: {
|
|
121268
|
+
height: 32,
|
|
121269
|
+
margin: "16px 0"
|
|
121270
|
+
}
|
|
121271
|
+
}) : (0, react_jsx_runtime.jsx)("div", {
|
|
121272
|
+
className: "dsh-ig-inspiration-end-hint",
|
|
121273
|
+
children: t("allLoaded", { count: String(matchingCases.length) })
|
|
121274
|
+
})] })] }), (0, react_jsx_runtime.jsx)("aside", {
|
|
121275
|
+
className: "dsh-ig-inspiration-inspector",
|
|
121276
|
+
children: selected === null ? (0, react_jsx_runtime.jsxs)("div", {
|
|
121277
|
+
className: "dsh-ig-inspiration-inspector-empty",
|
|
121278
|
+
children: [(0, react_jsx_runtime.jsx)(Image$2, { size: 28 }), (0, react_jsx_runtime.jsx)("span", { children: t("selectHint") })]
|
|
121279
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
121280
|
+
className: "dsh-ig-inspiration-inspector-image",
|
|
121281
|
+
onClick: () => setLightboxCase({
|
|
121282
|
+
sourceId: source.id,
|
|
121283
|
+
caseId: selected.id,
|
|
121284
|
+
revision: source.imageRevision ?? source.version,
|
|
121285
|
+
title: selected.title,
|
|
121286
|
+
alt: selected.imageAlt
|
|
119413
121287
|
}),
|
|
119414
|
-
|
|
119415
|
-
|
|
119416
|
-
|
|
119417
|
-
|
|
119418
|
-
|
|
119419
|
-
|
|
119420
|
-
|
|
119421
|
-
|
|
119422
|
-
|
|
119423
|
-
|
|
119424
|
-
|
|
119425
|
-
|
|
119426
|
-
|
|
119427
|
-
|
|
119428
|
-
|
|
119429
|
-
|
|
121288
|
+
title: t("zoomHint"),
|
|
121289
|
+
children: [(0, react_jsx_runtime.jsx)(InspirationImage, {
|
|
121290
|
+
sourceId: source.id,
|
|
121291
|
+
caseId: selected.id,
|
|
121292
|
+
revision: source.imageRevision ?? source.version,
|
|
121293
|
+
alt: selected.imageAlt,
|
|
121294
|
+
retryLabel: t("retry")
|
|
121295
|
+
}), (0, react_jsx_runtime.jsxs)("span", {
|
|
121296
|
+
className: "dsh-ig-inspiration-inspector-zoom-hint",
|
|
121297
|
+
children: [(0, react_jsx_runtime.jsx)(Maximize2, { size: 11 }), t("zoomHint")]
|
|
121298
|
+
})]
|
|
121299
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
121300
|
+
className: "dsh-ig-inspiration-inspector-body",
|
|
121301
|
+
children: [
|
|
121302
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121303
|
+
className: "dsh-ig-inspiration-inspector-head",
|
|
121304
|
+
children: [(0, react_jsx_runtime.jsx)("h2", { children: selected.title }), (0, react_jsx_runtime.jsx)("button", {
|
|
119430
121305
|
type: "button",
|
|
119431
|
-
className:
|
|
119432
|
-
onClick: () =>
|
|
119433
|
-
|
|
119434
|
-
|
|
119435
|
-
|
|
119436
|
-
|
|
119437
|
-
|
|
119438
|
-
|
|
119439
|
-
|
|
119440
|
-
|
|
121306
|
+
className: `dsh-ig-inspiration-inspector-fav ${favorites.has(selected.id) ? "is-favorited" : ""}`,
|
|
121307
|
+
onClick: () => toggleFavorite(selected.id),
|
|
121308
|
+
title: favorites.has(selected.id) ? t("favorited") : t("favorite"),
|
|
121309
|
+
children: (0, react_jsx_runtime.jsx)(Star, {
|
|
121310
|
+
size: 15,
|
|
121311
|
+
className: favorites.has(selected.id) ? "fill-star" : ""
|
|
121312
|
+
})
|
|
121313
|
+
})]
|
|
121314
|
+
}),
|
|
121315
|
+
selected.sourceLabel && (0, react_jsx_runtime.jsx)("p", {
|
|
121316
|
+
className: "dsh-ig-inspiration-origin",
|
|
121317
|
+
children: selected.sourceLabel
|
|
121318
|
+
}),
|
|
121319
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121320
|
+
className: "dsh-ig-inspiration-tags",
|
|
121321
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: translateTag(selected.category, language) }), selected.styles.slice(0, 3).map((item) => (0, react_jsx_runtime.jsx)("span", { children: translateTag(item, language) }, item))]
|
|
121322
|
+
}),
|
|
121323
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121324
|
+
className: "dsh-ig-inspiration-prompt-label",
|
|
121325
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("prompt") }), (0, react_jsx_runtime.jsx)("span", { children: selected.prompt.length })]
|
|
121326
|
+
}),
|
|
121327
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
121328
|
+
className: "dsh-ig-inspiration-prompt",
|
|
121329
|
+
children: selected.prompt
|
|
121330
|
+
}),
|
|
121331
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121332
|
+
className: "dsh-ig-inspiration-actions",
|
|
121333
|
+
children: [
|
|
121334
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121335
|
+
type: "button",
|
|
121336
|
+
onClick: () => void copyPrompt(),
|
|
121337
|
+
children: [copied ? (0, react_jsx_runtime.jsx)(Check, { size: 14 }) : (0, react_jsx_runtime.jsx)(Clipboard, { size: 14 }), copied ? t("copied") : t("copy")]
|
|
121338
|
+
}),
|
|
121339
|
+
selected.sourceUrl ?? selected.githubUrl ? (0, react_jsx_runtime.jsxs)("a", {
|
|
121340
|
+
className: "dsh-ig-inspiration-source-link",
|
|
121341
|
+
href: selected.sourceUrl ?? selected.githubUrl,
|
|
121342
|
+
target: "_blank",
|
|
121343
|
+
rel: "noreferrer",
|
|
121344
|
+
children: [(0, react_jsx_runtime.jsx)(ExternalLink, { size: 14 }), t("source")]
|
|
121345
|
+
}) : (0, react_jsx_runtime.jsx)("span", {}),
|
|
121346
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121347
|
+
type: "button",
|
|
121348
|
+
className: "dsh-ig-inspiration-use",
|
|
121349
|
+
onClick: () => onUsePrompt(selected.prompt),
|
|
121350
|
+
children: [(0, react_jsx_runtime.jsx)(Sparkles, { size: 14 }), t("use")]
|
|
121351
|
+
}),
|
|
121352
|
+
onUseReference !== void 0 ? (0, react_jsx_runtime.jsxs)("button", {
|
|
121353
|
+
type: "button",
|
|
121354
|
+
className: "dsh-ig-inspiration-use is-secondary",
|
|
121355
|
+
disabled: referenceBusy,
|
|
121356
|
+
onClick: () => {
|
|
121357
|
+
useSelectedReference();
|
|
121358
|
+
},
|
|
121359
|
+
children: [(0, react_jsx_runtime.jsx)(ImagePlus, { size: 14 }), referenceBusy ? t("referenceLoading") : t("useReference")]
|
|
121360
|
+
}) : null
|
|
121361
|
+
]
|
|
121362
|
+
})
|
|
121363
|
+
]
|
|
121364
|
+
})] })
|
|
121365
|
+
})]
|
|
121366
|
+
})
|
|
121367
|
+
] })] }),
|
|
119441
121368
|
lightboxCase !== null && (0, react_jsx_runtime.jsx)("div", {
|
|
119442
121369
|
className: "dsh-ig-inspiration-lightbox",
|
|
119443
121370
|
onClick: () => setLightboxCase(null),
|
|
@@ -119457,6 +121384,7 @@ img.ProseMirror-separator {
|
|
|
119457
121384
|
children: (0, react_jsx_runtime.jsx)(InspirationImage, {
|
|
119458
121385
|
sourceId: lightboxCase.sourceId,
|
|
119459
121386
|
caseId: lightboxCase.caseId,
|
|
121387
|
+
revision: lightboxCase.revision,
|
|
119460
121388
|
alt: lightboxCase.alt,
|
|
119461
121389
|
retryLabel: t("retry")
|
|
119462
121390
|
})
|
|
@@ -119509,7 +121437,155 @@ img.ProseMirror-separator {
|
|
|
119509
121437
|
]
|
|
119510
121438
|
});
|
|
119511
121439
|
};
|
|
119512
|
-
const
|
|
121440
|
+
const BaoyuComposerPanel = ({ language, selection, onChange, onUsePrompt }) => {
|
|
121441
|
+
const [copied, setCopied] = (0, react.useState)(false);
|
|
121442
|
+
const [copyFailed, setCopyFailed] = (0, react.useState)(false);
|
|
121443
|
+
const tr = (key, params) => {
|
|
121444
|
+
let text = COPY[language][key] ?? COPY.zh[key];
|
|
121445
|
+
if (params) for (const [k, v] of Object.entries(params)) text = text.replace(`{${k}}`, v);
|
|
121446
|
+
return text;
|
|
121447
|
+
};
|
|
121448
|
+
const label = (id) => language === "zh" ? BAOYU_LABELS_ZH[id] ?? id : id;
|
|
121449
|
+
const needsTitle = selection.text !== "none";
|
|
121450
|
+
const titleReady = !needsTitle || selection.title.trim() !== "";
|
|
121451
|
+
let prompt = "";
|
|
121452
|
+
if (titleReady) try {
|
|
121453
|
+
prompt = composeBaoyuPrompt(selection);
|
|
121454
|
+
} catch {
|
|
121455
|
+
prompt = "";
|
|
121456
|
+
}
|
|
121457
|
+
const combos = BAOYU_TYPES.length * BAOYU_PALETTES.length * BAOYU_RENDERINGS.length * BAOYU_TEXT_LEVELS.length * BAOYU_MOODS.length;
|
|
121458
|
+
const dimension = (name, key, options) => (0, react_jsx_runtime.jsxs)("div", {
|
|
121459
|
+
className: "dsh-ig-baoyu-dim",
|
|
121460
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
121461
|
+
className: "dsh-ig-baoyu-dim-head",
|
|
121462
|
+
children: name
|
|
121463
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
121464
|
+
className: "dsh-ig-baoyu-chips",
|
|
121465
|
+
children: options.map((option) => {
|
|
121466
|
+
const palette = key === "palette" ? BAOYU_PALETTES.find((item) => item.id === option.id) : void 0;
|
|
121467
|
+
return (0, react_jsx_runtime.jsxs)("button", {
|
|
121468
|
+
type: "button",
|
|
121469
|
+
className: `dsh-ig-baoyu-chip ${selection[key] === option.id ? "is-active" : ""}`,
|
|
121470
|
+
onClick: () => {
|
|
121471
|
+
onChange({
|
|
121472
|
+
...selection,
|
|
121473
|
+
[key]: option.id
|
|
121474
|
+
});
|
|
121475
|
+
setCopied(false);
|
|
121476
|
+
},
|
|
121477
|
+
title: language === "zh" ? palette?.tagline ?? option.id : option.id,
|
|
121478
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: label(option.id) }), palette !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
121479
|
+
className: "dsh-ig-baoyu-swatch",
|
|
121480
|
+
children: [
|
|
121481
|
+
palette.colors[0],
|
|
121482
|
+
palette.colors.find((color) => color.role === "Background"),
|
|
121483
|
+
palette.colors.find((color) => color.role === "Accent 1")
|
|
121484
|
+
].map((color, index) => color === void 0 ? null : (0, react_jsx_runtime.jsx)("i", { style: { background: color.hex } }, index))
|
|
121485
|
+
}) : null]
|
|
121486
|
+
}, option.id);
|
|
121487
|
+
})
|
|
121488
|
+
})]
|
|
121489
|
+
}, name);
|
|
121490
|
+
const copyPrompt = async () => {
|
|
121491
|
+
if (prompt === "") return;
|
|
121492
|
+
try {
|
|
121493
|
+
await navigator.clipboard.writeText(prompt);
|
|
121494
|
+
setCopied(true);
|
|
121495
|
+
setCopyFailed(false);
|
|
121496
|
+
} catch {
|
|
121497
|
+
setCopyFailed(true);
|
|
121498
|
+
}
|
|
121499
|
+
};
|
|
121500
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
121501
|
+
className: "dsh-ig-baoyu-panel",
|
|
121502
|
+
children: [
|
|
121503
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121504
|
+
className: "dsh-ig-baoyu-intro",
|
|
121505
|
+
children: [(0, react_jsx_runtime.jsx)("strong", {
|
|
121506
|
+
className: "dsh-ig-baoyu-combos",
|
|
121507
|
+
children: tr("composeCombos", { count: String(combos) })
|
|
121508
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
121509
|
+
className: "dsh-ig-baoyu-hint",
|
|
121510
|
+
children: tr("composeHint")
|
|
121511
|
+
})]
|
|
121512
|
+
}),
|
|
121513
|
+
dimension(tr("composeType"), "type", BAOYU_TYPES),
|
|
121514
|
+
dimension(tr("composePalette"), "palette", BAOYU_PALETTES),
|
|
121515
|
+
dimension(tr("composeRendering"), "rendering", BAOYU_RENDERINGS),
|
|
121516
|
+
dimension(tr("composeText"), "text", BAOYU_TEXT_LEVELS),
|
|
121517
|
+
dimension(tr("composeMood"), "mood", BAOYU_MOODS),
|
|
121518
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121519
|
+
className: "dsh-ig-baoyu-dim",
|
|
121520
|
+
children: [
|
|
121521
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
121522
|
+
className: "dsh-ig-baoyu-dim-head",
|
|
121523
|
+
children: tr("composeTitleLabel")
|
|
121524
|
+
}),
|
|
121525
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
121526
|
+
className: "dsh-ig-baoyu-title-input",
|
|
121527
|
+
value: selection.title,
|
|
121528
|
+
placeholder: tr("composeTitlePlaceholder"),
|
|
121529
|
+
disabled: selection.text === "none",
|
|
121530
|
+
onChange: (event) => {
|
|
121531
|
+
onChange({
|
|
121532
|
+
...selection,
|
|
121533
|
+
title: event.target.value
|
|
121534
|
+
});
|
|
121535
|
+
setCopied(false);
|
|
121536
|
+
}
|
|
121537
|
+
}),
|
|
121538
|
+
needsTitle && !titleReady ? (0, react_jsx_runtime.jsx)("div", {
|
|
121539
|
+
className: "dsh-ig-baoyu-required",
|
|
121540
|
+
children: tr("composeTitleRequired")
|
|
121541
|
+
}) : null
|
|
121542
|
+
]
|
|
121543
|
+
}),
|
|
121544
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121545
|
+
className: "dsh-ig-baoyu-actions",
|
|
121546
|
+
children: [
|
|
121547
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121548
|
+
type: "button",
|
|
121549
|
+
className: "dsh-ig-baoyu-btn",
|
|
121550
|
+
onClick: () => onChange(randomBaoyuSelection(selection)),
|
|
121551
|
+
children: [(0, react_jsx_runtime.jsx)(Shuffle, { size: 13 }), (0, react_jsx_runtime.jsx)("span", { children: tr("composeRandomize") })]
|
|
121552
|
+
}),
|
|
121553
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121554
|
+
type: "button",
|
|
121555
|
+
className: "dsh-ig-baoyu-btn",
|
|
121556
|
+
disabled: prompt === "",
|
|
121557
|
+
onClick: () => {
|
|
121558
|
+
copyPrompt();
|
|
121559
|
+
},
|
|
121560
|
+
children: [copied ? (0, react_jsx_runtime.jsx)(Check, { size: 13 }) : (0, react_jsx_runtime.jsx)(Clipboard, { size: 13 }), (0, react_jsx_runtime.jsx)("span", { children: copied ? tr("copied") : tr("copy") })]
|
|
121561
|
+
}),
|
|
121562
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121563
|
+
type: "button",
|
|
121564
|
+
className: "dsh-ig-baoyu-btn is-primary",
|
|
121565
|
+
disabled: prompt === "",
|
|
121566
|
+
onClick: () => onUsePrompt(prompt),
|
|
121567
|
+
children: [(0, react_jsx_runtime.jsx)(Sparkles, { size: 13 }), (0, react_jsx_runtime.jsx)("span", { children: tr("composeUse") })]
|
|
121568
|
+
}),
|
|
121569
|
+
copyFailed ? (0, react_jsx_runtime.jsx)("span", {
|
|
121570
|
+
className: "dsh-ig-baoyu-required",
|
|
121571
|
+
children: tr("copyFailed")
|
|
121572
|
+
}) : null
|
|
121573
|
+
]
|
|
121574
|
+
}),
|
|
121575
|
+
prompt !== "" ? (0, react_jsx_runtime.jsxs)("div", {
|
|
121576
|
+
className: "dsh-ig-baoyu-preview-block",
|
|
121577
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
121578
|
+
className: "dsh-ig-baoyu-preview-head",
|
|
121579
|
+
children: tr("composePreview")
|
|
121580
|
+
}), (0, react_jsx_runtime.jsx)("pre", {
|
|
121581
|
+
className: "dsh-ig-baoyu-preview",
|
|
121582
|
+
children: prompt
|
|
121583
|
+
})]
|
|
121584
|
+
}) : null
|
|
121585
|
+
]
|
|
121586
|
+
});
|
|
121587
|
+
};
|
|
121588
|
+
const InspirationCard = ({ item, sourceId, sourceRevision, selected, isFavorited, language, featuredLabel, retryLabel, onSelect, onToggleFavorite }) => (0, react_jsx_runtime.jsxs)("button", {
|
|
119513
121589
|
type: "button",
|
|
119514
121590
|
className: `dsh-ig-inspiration-card ${selected ? "is-selected" : ""}`,
|
|
119515
121591
|
onClick: onSelect,
|
|
@@ -119536,6 +121612,7 @@ img.ProseMirror-separator {
|
|
|
119536
121612
|
(0, react_jsx_runtime.jsx)(InspirationImage, {
|
|
119537
121613
|
sourceId,
|
|
119538
121614
|
caseId: item.id,
|
|
121615
|
+
revision: sourceRevision,
|
|
119539
121616
|
alt: item.imageAlt,
|
|
119540
121617
|
retryLabel
|
|
119541
121618
|
})
|
|
@@ -119545,7 +121622,7 @@ img.ProseMirror-separator {
|
|
|
119545
121622
|
children: [(0, react_jsx_runtime.jsx)("strong", { children: item.title }), (0, react_jsx_runtime.jsx)("span", { children: translateTag(item.category, language) })]
|
|
119546
121623
|
})]
|
|
119547
121624
|
});
|
|
119548
|
-
const InspirationImage = ({ sourceId, caseId, alt, retryLabel = "Retry" }) => {
|
|
121625
|
+
const InspirationImage = ({ sourceId, caseId, revision, alt, retryLabel = "Retry" }) => {
|
|
119549
121626
|
const [node, setNode] = (0, react.useState)(null);
|
|
119550
121627
|
const [visible, setVisible] = (0, react.useState)(false);
|
|
119551
121628
|
const [url, setUrl] = (0, react.useState)(null);
|
|
@@ -119566,7 +121643,7 @@ img.ProseMirror-separator {
|
|
|
119566
121643
|
urlRef.current = null;
|
|
119567
121644
|
}
|
|
119568
121645
|
setUrl(null);
|
|
119569
|
-
fetchInspirationImage(sourceId, caseId).then((blob) => {
|
|
121646
|
+
fetchInspirationImage(sourceId, caseId, revision).then((blob) => {
|
|
119570
121647
|
if (!active) return;
|
|
119571
121648
|
const next = URL.createObjectURL(blob);
|
|
119572
121649
|
if (urlRef.current !== null) URL.revokeObjectURL(urlRef.current);
|
|
@@ -119581,7 +121658,8 @@ img.ProseMirror-separator {
|
|
|
119581
121658
|
}, [
|
|
119582
121659
|
visible,
|
|
119583
121660
|
sourceId,
|
|
119584
|
-
caseId
|
|
121661
|
+
caseId,
|
|
121662
|
+
revision
|
|
119585
121663
|
]);
|
|
119586
121664
|
(0, react.useEffect)(() => {
|
|
119587
121665
|
return () => {
|
|
@@ -119618,7 +121696,7 @@ img.ProseMirror-separator {
|
|
|
119618
121696
|
urlRef.current = null;
|
|
119619
121697
|
}
|
|
119620
121698
|
setUrl(null);
|
|
119621
|
-
evictInspirationImage(sourceId, caseId).then(() => fetchInspirationImage(sourceId, caseId)).then((blob) => {
|
|
121699
|
+
evictInspirationImage(sourceId, caseId, revision).then(() => fetchInspirationImage(sourceId, caseId, revision)).then((blob) => {
|
|
119622
121700
|
const next = URL.createObjectURL(blob);
|
|
119623
121701
|
if (urlRef.current !== null) URL.revokeObjectURL(urlRef.current);
|
|
119624
121702
|
urlRef.current = next;
|
|
@@ -119736,6 +121814,12 @@ img.ProseMirror-separator {
|
|
|
119736
121814
|
filterXAI: "xAI Grok",
|
|
119737
121815
|
filterZhipu: "智谱 GLM",
|
|
119738
121816
|
filterComfyUI: "本地 ComfyUI",
|
|
121817
|
+
filterImport: "导入",
|
|
121818
|
+
importImages: "导入图片",
|
|
121819
|
+
importAdded: "已导入 {count} 张图片",
|
|
121820
|
+
importPartial: "导入 {count} 张,{fail} 张失败",
|
|
121821
|
+
importFailed: "导入失败",
|
|
121822
|
+
importPickHint: "选择要导入的图片(PNG/JPG/WebP/GIF)",
|
|
119739
121823
|
filterAllModels: "全部模型",
|
|
119740
121824
|
filterAllRatios: "全部比例",
|
|
119741
121825
|
searchPlaceholder: "搜索 Prompt、标签…",
|
|
@@ -119832,6 +121916,12 @@ img.ProseMirror-separator {
|
|
|
119832
121916
|
filterXAI: "xAI Grok",
|
|
119833
121917
|
filterZhipu: "Zhipu GLM",
|
|
119834
121918
|
filterComfyUI: "Local ComfyUI",
|
|
121919
|
+
filterImport: "Imported",
|
|
121920
|
+
importImages: "Import images",
|
|
121921
|
+
importAdded: "Imported {count} images",
|
|
121922
|
+
importPartial: "Imported {count}, {fail} failed",
|
|
121923
|
+
importFailed: "Import failed",
|
|
121924
|
+
importPickHint: "Choose images to import (PNG/JPG/WebP/GIF)",
|
|
119835
121925
|
filterAllModels: "All Models",
|
|
119836
121926
|
filterAllRatios: "All Ratios",
|
|
119837
121927
|
searchPlaceholder: "Search prompt, tags…",
|
|
@@ -119914,6 +122004,19 @@ img.ProseMirror-separator {
|
|
|
119914
122004
|
}
|
|
119915
122005
|
};
|
|
119916
122006
|
/** Format human-readable relative time */
|
|
122007
|
+
/** Read a browser-picked file as base64 payload for the import route. */
|
|
122008
|
+
function readFileBase64(file) {
|
|
122009
|
+
return new Promise((resolve, reject) => {
|
|
122010
|
+
const reader = new FileReader();
|
|
122011
|
+
reader.onload = () => {
|
|
122012
|
+
const result = reader.result;
|
|
122013
|
+
if (typeof result === "string") resolve(result.slice(result.indexOf(",") + 1));
|
|
122014
|
+
else reject(/* @__PURE__ */ new Error("read-failed"));
|
|
122015
|
+
};
|
|
122016
|
+
reader.onerror = () => reject(/* @__PURE__ */ new Error("read-failed"));
|
|
122017
|
+
reader.readAsDataURL(file);
|
|
122018
|
+
});
|
|
122019
|
+
}
|
|
119917
122020
|
function formatRelativeTime(timestamp, t) {
|
|
119918
122021
|
const diff = Date.now() - timestamp;
|
|
119919
122022
|
if (diff < 6e4) return t("justNow");
|
|
@@ -119969,9 +122072,10 @@ img.ProseMirror-separator {
|
|
|
119969
122072
|
return "1:1";
|
|
119970
122073
|
}
|
|
119971
122074
|
const GalleryViewTab = (props) => {
|
|
119972
|
-
const { locale, sessionId, useSessions, useWorkspaces, credentialEvents, inSidebar, defaultTab, initialCanvasSurface } = props;
|
|
122075
|
+
const { locale, sessionId, useSessions, useWorkspaces, credentialEvents, inSidebar, defaultTab, initialCanvasSurface, useTabInfo } = props;
|
|
119973
122076
|
const [activeTab, setActiveTab] = (0, react.useState)(defaultTab ?? "gallery");
|
|
119974
122077
|
const [studioDraft, setStudioDraft] = (0, react.useState)(void 0);
|
|
122078
|
+
const [studioReference, setStudioReference] = (0, react.useState)(void 0);
|
|
119975
122079
|
const [items, setItems] = (0, react.useState)([]);
|
|
119976
122080
|
const [search, setSearch] = (0, react.useState)("");
|
|
119977
122081
|
const [selectedProvider, setSelectedProvider] = (0, react.useState)("all");
|
|
@@ -119992,6 +122096,10 @@ img.ProseMirror-separator {
|
|
|
119992
122096
|
localStorage.setItem("dsh-ig-only-current-workspace", String(onlyCurrentWorkspace));
|
|
119993
122097
|
} catch {}
|
|
119994
122098
|
}, [onlyCurrentWorkspace]);
|
|
122099
|
+
const tabVisible = useTabInfo?.().tab?.visible;
|
|
122100
|
+
(0, react.useEffect)(() => {
|
|
122101
|
+
if (tabVisible === false) deselectStudioTlCanvases();
|
|
122102
|
+
}, [tabVisible]);
|
|
119995
122103
|
(0, react.useEffect)(() => {
|
|
119996
122104
|
let mounted = true;
|
|
119997
122105
|
fetch(STUDIO_ROUTE).then((res) => res.ok ? res.json() : null).then((data) => {
|
|
@@ -120082,11 +122190,80 @@ img.ProseMirror-separator {
|
|
|
120082
122190
|
setToast(null);
|
|
120083
122191
|
}, 2e3);
|
|
120084
122192
|
};
|
|
122193
|
+
const [importing, setImporting] = (0, react.useState)(false);
|
|
122194
|
+
const importInputRef = (0, react.useRef)(null);
|
|
122195
|
+
const importImages = async (files) => {
|
|
122196
|
+
if (files === null || files.length === 0 || importing) return;
|
|
122197
|
+
const all = Array.from(files);
|
|
122198
|
+
const picked = all.filter((file) => file.type.startsWith("image/")).slice(0, 8);
|
|
122199
|
+
if (picked.length === 0) {
|
|
122200
|
+
showToast(t("importFailed"));
|
|
122201
|
+
return;
|
|
122202
|
+
}
|
|
122203
|
+
setImporting(true);
|
|
122204
|
+
try {
|
|
122205
|
+
const reads = await Promise.allSettled(picked.map((file) => readFileBase64(file)));
|
|
122206
|
+
const images = reads.flatMap((read, index) => {
|
|
122207
|
+
if (read.status !== "fulfilled") return [];
|
|
122208
|
+
const file = picked[index];
|
|
122209
|
+
return [{
|
|
122210
|
+
data: read.value,
|
|
122211
|
+
mediaType: file.type,
|
|
122212
|
+
...file.name.length > 0 ? { name: file.name } : {}
|
|
122213
|
+
}];
|
|
122214
|
+
});
|
|
122215
|
+
const readFailures = reads.length - images.length;
|
|
122216
|
+
if (images.length === 0) {
|
|
122217
|
+
showToast(t("importFailed"));
|
|
122218
|
+
return;
|
|
122219
|
+
}
|
|
122220
|
+
const response = await fetch(IMPORT_ROUTE, {
|
|
122221
|
+
method: "POST",
|
|
122222
|
+
credentials: "same-origin",
|
|
122223
|
+
headers: { "content-type": "application/json" },
|
|
122224
|
+
body: JSON.stringify({ images })
|
|
122225
|
+
});
|
|
122226
|
+
if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
|
|
122227
|
+
const payload = await response.json();
|
|
122228
|
+
const imported = payload.images ?? [];
|
|
122229
|
+
let added = 0;
|
|
122230
|
+
let writeFailures = 0;
|
|
122231
|
+
for (const entry of imported) if (await saveGalleryItem({
|
|
122232
|
+
id: `import-${entry.attachment.attachmentId}-${crypto.randomUUID()}`,
|
|
122233
|
+
attachment: entry.attachment,
|
|
122234
|
+
prompt: "",
|
|
122235
|
+
provider: "import",
|
|
122236
|
+
model: "",
|
|
122237
|
+
createdAt: Date.now(),
|
|
122238
|
+
...activeWorkspace?.workspaceId ? { workspaceId: activeWorkspace.workspaceId } : {},
|
|
122239
|
+
...activeWorkspace?.path ? { workspacePath: activeWorkspace.path } : {},
|
|
122240
|
+
...currentSessionId ? { sessionId: currentSessionId } : {}
|
|
122241
|
+
})) added += 1;
|
|
122242
|
+
else writeFailures += 1;
|
|
122243
|
+
const failCount = (payload.failures ?? []).length + (all.length - picked.length) + readFailures + writeFailures;
|
|
122244
|
+
if (added === 0) showToast(t("importFailed"));
|
|
122245
|
+
else if (failCount > 0) showToast(t("importPartial", {
|
|
122246
|
+
count: String(added),
|
|
122247
|
+
fail: String(failCount)
|
|
122248
|
+
}));
|
|
122249
|
+
else showToast(t("importAdded", { count: String(added) }));
|
|
122250
|
+
} catch {
|
|
122251
|
+
showToast(t("importFailed"));
|
|
122252
|
+
} finally {
|
|
122253
|
+
setImporting(false);
|
|
122254
|
+
}
|
|
122255
|
+
};
|
|
120085
122256
|
const useInspirationPrompt = (0, react.useCallback)((prompt) => {
|
|
120086
122257
|
setStudioDraft(prompt);
|
|
120087
122258
|
setActiveTab("studio");
|
|
120088
122259
|
}, []);
|
|
122260
|
+
const useInspirationReference = (0, react.useCallback)((file, prompt) => {
|
|
122261
|
+
setStudioDraft(prompt);
|
|
122262
|
+
setStudioReference(file);
|
|
122263
|
+
setActiveTab("studio");
|
|
122264
|
+
}, []);
|
|
120089
122265
|
const clearStudioDraft = (0, react.useCallback)(() => setStudioDraft(void 0), []);
|
|
122266
|
+
const clearStudioReference = (0, react.useCallback)(() => setStudioReference(void 0), []);
|
|
120090
122267
|
(0, react.useEffect)(() => {
|
|
120091
122268
|
if (inSidebar) return void 0;
|
|
120092
122269
|
const seat = document.querySelector("[data-composer-seat]");
|
|
@@ -120636,6 +122813,10 @@ img.ProseMirror-separator {
|
|
|
120636
122813
|
(0, react_jsx_runtime.jsx)("option", {
|
|
120637
122814
|
value: "comfyui",
|
|
120638
122815
|
children: t("filterComfyUI")
|
|
122816
|
+
}),
|
|
122817
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
122818
|
+
value: "import",
|
|
122819
|
+
children: t("filterImport")
|
|
120639
122820
|
})
|
|
120640
122821
|
]
|
|
120641
122822
|
}),
|
|
@@ -120718,27 +122899,48 @@ img.ProseMirror-separator {
|
|
|
120718
122899
|
]
|
|
120719
122900
|
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
120720
122901
|
className: "dsh-ig-studio-toolbar-right",
|
|
120721
|
-
children: [
|
|
120722
|
-
|
|
120723
|
-
|
|
120724
|
-
|
|
120725
|
-
|
|
120726
|
-
|
|
120727
|
-
|
|
120728
|
-
|
|
120729
|
-
|
|
120730
|
-
|
|
120731
|
-
|
|
120732
|
-
|
|
120733
|
-
|
|
120734
|
-
|
|
120735
|
-
|
|
120736
|
-
|
|
120737
|
-
|
|
120738
|
-
|
|
120739
|
-
},
|
|
120740
|
-
|
|
120741
|
-
|
|
122902
|
+
children: [
|
|
122903
|
+
activeTab === "gallery" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("input", {
|
|
122904
|
+
ref: importInputRef,
|
|
122905
|
+
type: "file",
|
|
122906
|
+
accept: "image/png,image/jpeg,image/webp,image/gif",
|
|
122907
|
+
multiple: true,
|
|
122908
|
+
style: { display: "none" },
|
|
122909
|
+
onChange: (event) => {
|
|
122910
|
+
importImages(event.target.files);
|
|
122911
|
+
event.target.value = "";
|
|
122912
|
+
}
|
|
122913
|
+
}), (0, react_jsx_runtime.jsxs)("button", {
|
|
122914
|
+
type: "button",
|
|
122915
|
+
className: "dsh-ig-studio-btn",
|
|
122916
|
+
disabled: importing,
|
|
122917
|
+
title: t("importPickHint"),
|
|
122918
|
+
onClick: () => importInputRef.current?.click(),
|
|
122919
|
+
children: [(0, react_jsx_runtime.jsx)(Upload, { size: 13 }), (0, react_jsx_runtime.jsx)("span", { children: t("importImages") })]
|
|
122920
|
+
})] }),
|
|
122921
|
+
(0, react_jsx_runtime.jsxs)("select", {
|
|
122922
|
+
className: "dsh-ig-studio-select dsh-ig-studio-select-sort",
|
|
122923
|
+
value: sortBy,
|
|
122924
|
+
onChange: (e) => setSortBy(e.target.value),
|
|
122925
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
122926
|
+
value: "newest",
|
|
122927
|
+
children: t("sortNewest")
|
|
122928
|
+
}), (0, react_jsx_runtime.jsx)("option", {
|
|
122929
|
+
value: "oldest",
|
|
122930
|
+
children: t("sortOldest")
|
|
122931
|
+
})]
|
|
122932
|
+
}),
|
|
122933
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
122934
|
+
type: "button",
|
|
122935
|
+
className: `dsh-ig-studio-btn ${isManageMode ? "is-active" : ""}`,
|
|
122936
|
+
title: isManageMode ? t("exitManage") : t("manage"),
|
|
122937
|
+
onClick: () => {
|
|
122938
|
+
if (isManageMode) handleExitManage();
|
|
122939
|
+
else setIsManageMode(true);
|
|
122940
|
+
},
|
|
122941
|
+
children: [(0, react_jsx_runtime.jsx)(SquareCheckBig, { size: 13 }), (0, react_jsx_runtime.jsx)("span", { children: isManageMode ? t("exitManage") : t("manage") })]
|
|
122942
|
+
})
|
|
122943
|
+
]
|
|
120742
122944
|
})]
|
|
120743
122945
|
}),
|
|
120744
122946
|
(0, react_jsx_runtime.jsx)("div", {
|
|
@@ -120808,15 +123010,18 @@ img.ProseMirror-separator {
|
|
|
120808
123010
|
}, item.id))
|
|
120809
123011
|
}) : activeTab === "inspiration" ? (0, react_jsx_runtime.jsx)(InspirationView, {
|
|
120810
123012
|
locale,
|
|
120811
|
-
onUsePrompt: useInspirationPrompt
|
|
123013
|
+
onUsePrompt: useInspirationPrompt,
|
|
123014
|
+
onUseReference: useInspirationReference
|
|
120812
123015
|
}) : (0, react_jsx_runtime.jsx)(StudioView, {
|
|
120813
123016
|
locale,
|
|
120814
123017
|
credentialEvents,
|
|
120815
123018
|
workspace: activeWorkspace,
|
|
120816
123019
|
initialPrompt: studioDraft,
|
|
123020
|
+
initialReference: studioReference,
|
|
120817
123021
|
initialCanvasSurface,
|
|
120818
123022
|
showInfiniteCanvasHint: !inSidebar,
|
|
120819
123023
|
onInitialPromptApplied: clearStudioDraft,
|
|
123024
|
+
onInitialReferenceApplied: clearStudioReference,
|
|
120820
123025
|
onOpenInspiration: () => setActiveTab("inspiration")
|
|
120821
123026
|
})
|
|
120822
123027
|
}),
|
|
@@ -120976,7 +123181,7 @@ img.ProseMirror-separator {
|
|
|
120976
123181
|
children: [
|
|
120977
123182
|
(0, react_jsx_runtime.jsx)("span", {
|
|
120978
123183
|
className: "dsh-ig-tag",
|
|
120979
|
-
children: previewItem.provider
|
|
123184
|
+
children: previewItem.provider === "import" ? t("filterImport") : previewItem.provider
|
|
120980
123185
|
}),
|
|
120981
123186
|
previewItem.model && (0, react_jsx_runtime.jsx)("span", {
|
|
120982
123187
|
className: "dsh-ig-tag dsh-ig-tag-model",
|
|
@@ -121034,7 +123239,7 @@ img.ProseMirror-separator {
|
|
|
121034
123239
|
children: [
|
|
121035
123240
|
(0, react_jsx_runtime.jsx)("span", {
|
|
121036
123241
|
className: "dsh-ig-tag",
|
|
121037
|
-
children: previewItem.provider
|
|
123242
|
+
children: previewItem.provider === "import" ? t("filterImport") : previewItem.provider
|
|
121038
123243
|
}),
|
|
121039
123244
|
previewItem.model ? (0, react_jsx_runtime.jsx)("span", {
|
|
121040
123245
|
className: "dsh-ig-tag dsh-ig-tag-model",
|
|
@@ -121627,105 +123832,139 @@ img.ProseMirror-separator {
|
|
|
121627
123832
|
//#region lib/types/client/studio-style.js
|
|
121628
123833
|
const STUDIO_STYLE = `
|
|
121629
123834
|
.dsh-ig-gallery-page-body.is-workbench{flex:1 1 0;height:100%;min-height:0;padding:0;overflow:hidden;display:flex;flex-direction:column}
|
|
121630
|
-
.dsh-ig-workbench{--ig-blue
|
|
123835
|
+
.dsh-ig-workbench{--ig-blue:var(--dsw-alias-brand-primary-new-colorprimary-new-color,#2f64f5);--ig-blue-line:color-mix(in srgb,var(--ig-blue) 45%,transparent);--ig-line:var(--dsw-alias-border-l2,color-mix(in srgb,currentColor 11%,transparent));--ig-soft:color-mix(in srgb,currentColor 4%,transparent);--ig-fg:var(--dsw-alias-label-primary,var(--foreground,#182033));--ig-fg-2:var(--dsw-alias-label-secondary,#5a6478);--ig-fg-3:var(--dsw-alias-label-tertiary,#717b90);--ig-fg-cap:var(--dsw-alias-label-caption,#929bad);--ig-bg:var(--dsw-alias-bg-layer-1,var(--background,#fff));--ig-bg-panel:var(--dsw-alias-bg-layer-2,color-mix(in srgb,var(--background,#fff) 96%,#f5f7fb));--ig-bg-thumb:var(--dsw-alias-bg-skeleton,#eef1f7);--ig-danger:#b63737;--ig-warn:#8b671c;position:relative;display:flex;flex-direction:column;min-height:0;height:100%;overflow:hidden;padding:10px 12px 12px;color:var(--ig-fg);box-sizing:border-box;background:radial-gradient(circle at 60% -20%,rgba(63,104,246,.07),transparent 30%)}
|
|
123836
|
+
body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a}
|
|
121631
123837
|
.dsh-ig-workbench *{box-sizing:border-box}.dsh-ig-workbench button,.dsh-ig-workbench select,.dsh-ig-workbench textarea{font:inherit;color:inherit}
|
|
121632
|
-
.dsh-ig-workbench-grid{display:grid;grid-template-columns:minmax(190px,238px) minmax(0,1fr) minmax(286px,340px);grid-template-rows:minmax(0,1fr);min-height:0;height:0;flex:1 1 0;border:1px solid var(--ig-line);border-radius:12px;overflow:hidden;background:var(--
|
|
123838
|
+
.dsh-ig-workbench-grid{display:grid;grid-template-columns:minmax(190px,238px) minmax(0,1fr) minmax(286px,340px);grid-template-rows:minmax(0,1fr);min-height:0;height:0;flex:1 1 0;border:1px solid var(--ig-line);border-radius:12px;overflow:hidden;background:var(--ig-bg);box-shadow:0 12px 32px rgba(30,42,76,.05);transition:grid-template-columns .2s ease}
|
|
121633
123839
|
.dsh-ig-workbench-grid.is-sidebar-collapsed{grid-template-columns:minmax(0,1fr) minmax(286px,340px)}
|
|
121634
123840
|
.dsh-ig-workbench-grid.is-generate-collapsed{grid-template-columns:minmax(190px,238px) minmax(0,1fr)}
|
|
121635
123841
|
.dsh-ig-workbench-grid.is-sidebar-collapsed.is-generate-collapsed{grid-template-columns:minmax(0,1fr)}
|
|
121636
|
-
.dsh-ig-recent-panel,.dsh-ig-generate-panel{min-width:0;min-height:0;overflow:hidden;background:
|
|
123842
|
+
.dsh-ig-recent-panel,.dsh-ig-generate-panel{min-width:0;min-height:0;overflow:hidden;background:var(--ig-bg-panel)}.dsh-ig-recent-panel{display:flex;flex-direction:column;border-right:1px solid var(--ig-line)}
|
|
121637
123843
|
.dsh-ig-panel-title{height:48px;flex:0 0 48px;padding:0 12px 0 14px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--ig-line);font-size:13px;font-weight:650}
|
|
121638
|
-
.dsh-ig-count-badge{font-size:11px;min-width:22px;text-align:center;padding:2px 6px;border-radius:999px;background:var(--ig-soft);color
|
|
121639
|
-
.dsh-ig-collapse-btn{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:6px;background:transparent;color
|
|
121640
|
-
.dsh-ig-collapse-btn:hover{border-color:var(--ig-line);background:var(--ig-soft);color:var(--
|
|
121641
|
-
.dsh-ig-recent-scroll{flex:1 1 0;height:0;padding:8px;overflow-x:hidden;overflow-y:auto;min-height:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(78px,1fr));gap:6px;align-content:start}.dsh-ig-recent-empty{min-height:180px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:10px;color
|
|
121642
|
-
.dsh-ig-
|
|
121643
|
-
.dsh-ig-
|
|
121644
|
-
.dsh-ig-
|
|
121645
|
-
.dsh-ig-
|
|
123844
|
+
.dsh-ig-count-badge{font-size:11px;min-width:22px;text-align:center;padding:2px 6px;border-radius:999px;background:var(--ig-soft);color:var(--ig-fg-3);font-weight:500}
|
|
123845
|
+
.dsh-ig-collapse-btn{width:28px;height:28px;display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:6px;background:transparent;color:var(--ig-fg-3);cursor:pointer;transition:all .15s}
|
|
123846
|
+
.dsh-ig-collapse-btn:hover{border-color:var(--ig-line);background:var(--ig-soft);color:var(--ig-fg)}
|
|
123847
|
+
.dsh-ig-recent-scroll{flex:1 1 0;height:0;padding:8px;overflow-x:hidden;overflow-y:auto;min-height:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(78px,1fr));gap:6px;align-content:start}.dsh-ig-recent-empty{min-height:180px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:10px;color:var(--ig-fg-cap);text-align:center;font-size:12px;grid-column:1/-1}
|
|
123848
|
+
.dsh-ig-fav-folder-add{margin-left:auto;padding:0 5px;border:0;background:transparent;color:var(--ig-fg-3);font-size:12px;line-height:16px;cursor:pointer;border-radius:4px}.dsh-ig-fav-folder-add:hover{color:var(--ig-blue);background:var(--ig-bg-thumb)}
|
|
123849
|
+
.dsh-ig-fav-folders{display:flex;flex-wrap:wrap;gap:4px;margin:4px 0 6px}
|
|
123850
|
+
.dsh-ig-fav-folder-chip{display:inline-flex;align-items:center;gap:2px;padding:2px 6px;border:1px solid var(--ig-line);border-radius:999px;background:transparent;color:var(--ig-fg-3);font-size:10.5px}
|
|
123851
|
+
.dsh-ig-fav-folder-chip.is-active{border-color:var(--ig-blue-line);color:var(--ig-blue);background:color-mix(in srgb,var(--ig-blue) 10%,transparent)}
|
|
123852
|
+
.dsh-ig-fav-folder-chip>button:first-child{border:0;background:transparent;color:inherit;font-size:inherit;padding:0;cursor:pointer}
|
|
123853
|
+
.dsh-ig-fav-folder-del{border:0;background:transparent;color:var(--ig-fg-3);cursor:pointer;display:inline-flex;padding:0}.dsh-ig-fav-folder-del:hover{color:var(--ig-danger)}
|
|
123854
|
+
.dsh-ig-fav-folder-draft{display:flex;gap:4px;margin:2px 0 6px}
|
|
123855
|
+
.dsh-ig-fav-folder-draft input{flex:1;min-width:0;padding:3px 6px;border:1px solid var(--ig-line);border-radius:5px;background:var(--ig-bg);color:var(--ig-fg);font-size:11px}
|
|
123856
|
+
.dsh-ig-fav-folder-draft button{padding:3px 8px;border:1px solid var(--ig-line);border-radius:5px;background:transparent;color:var(--ig-fg-2);font-size:11px;cursor:pointer}
|
|
123857
|
+
.dsh-ig-fav-folder-draft button:first-of-type{border-color:var(--ig-blue-line);color:var(--ig-blue)}
|
|
123858
|
+
.dsh-ig-fav-dialog-wrap{position:fixed;inset:0;z-index:60;display:flex;align-items:center;justify-content:center;background:rgba(15,20,34,.45)}
|
|
123859
|
+
.dsh-ig-fav-dialog{width:min(420px,92vw);max-height:70vh;overflow:auto;padding:14px;border-radius:10px;background:var(--ig-bg-panel);border:1px solid var(--ig-line);box-shadow:0 12px 32px rgba(10,14,26,.25);display:flex;flex-direction:column;gap:10px}
|
|
123860
|
+
.dsh-ig-fav-dialog-title{font-size:12.5px;font-weight:600;color:var(--ig-fg)}
|
|
123861
|
+
.dsh-ig-fav-dialog-textarea{width:100%;resize:vertical;padding:8px;border:1px solid var(--ig-line);border-radius:6px;background:var(--ig-bg);color:var(--ig-fg);font-size:12px;line-height:1.5}
|
|
123862
|
+
.dsh-ig-fav-dialog-folder-label{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--ig-fg-2)}
|
|
123863
|
+
.dsh-ig-fav-dialog-folder-label select{flex:1;padding:4px 6px;border:1px solid var(--ig-line);border-radius:5px;background:var(--ig-bg);color:var(--ig-fg);font-size:11.5px}
|
|
123864
|
+
.dsh-ig-fav-dialog-actions{display:flex;gap:6px;justify-content:flex-end;flex-wrap:wrap}
|
|
123865
|
+
.dsh-ig-fav-dialog-actions button{padding:5px 12px;border:1px solid var(--ig-line);border-radius:6px;background:transparent;color:var(--ig-fg-2);font-size:12px;cursor:pointer}
|
|
123866
|
+
.dsh-ig-fav-dialog-actions button.is-primary{border-color:var(--ig-blue);background:var(--ig-blue);color:#fff}
|
|
123867
|
+
.dsh-ig-fav-dialog-folders{display:flex;flex-direction:column;gap:4px}
|
|
123868
|
+
.dsh-ig-fav-dialog-folders button{text-align:left;padding:6px 10px;border:1px solid var(--ig-line);border-radius:6px;background:transparent;color:var(--ig-fg-2);font-size:12px;cursor:pointer}
|
|
123869
|
+
.dsh-ig-fav-dialog-folders button:hover,.dsh-ig-fav-dialog-folders button.is-current{border-color:var(--ig-blue-line);color:var(--ig-blue);background:color-mix(in srgb,var(--ig-blue) 8%,transparent)}
|
|
123870
|
+
.dsh-ig-fav-del{position:absolute;top:-5px;right:-5px;width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;padding:0;border:1px solid var(--ig-line);border-radius:50%;background:var(--ig-bg);color:var(--ig-fg-3);cursor:pointer;z-index:2;opacity:0;pointer-events:none;transition:opacity .12s,color .15s,border-color .15s}.dsh-ig-fav-del:hover{color:#d5495c;border-color:#e6a3ad}.dsh-ig-fav-prompt:hover .dsh-ig-fav-del,.dsh-ig-fav-del:focus-visible{opacity:1;pointer-events:auto}.dsh-ig-fav-del:focus-visible{outline:2px solid var(--ig-blue);outline-offset:1px}
|
|
123871
|
+
.dsh-ig-fav-prompt{position:relative;display:flex;align-items:flex-start;gap:2px}
|
|
123872
|
+
.dsh-ig-fav-prompt-text{flex:1;min-width:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-align:left;padding:5px 8px;border:1px solid var(--ig-line);border-radius:6px;background:transparent;font-size:11px;line-height:1.45;color:var(--ig-fg);cursor:pointer;transition:all .15s}.dsh-ig-fav-prompt-text:hover{border-color:var(--ig-blue-line);background:var(--ig-soft)}
|
|
123873
|
+
.dsh-ig-fav-save-btn{display:inline-flex;align-items:center;justify-content:center;padding:2px 4px;border:0;background:transparent;color:var(--ig-fg-cap);cursor:pointer;transition:color .15s}.dsh-ig-fav-save-btn:hover{color:#e8a33d}
|
|
123874
|
+
.dsh-ig-rail-tabs{flex:none;display:flex;gap:4px;padding:4px 8px 6px;border-bottom:1px solid var(--ig-line)}
|
|
123875
|
+
.dsh-ig-rail-tab{flex:1;height:26px;display:inline-flex;align-items:center;justify-content:center;border:1px solid transparent;border-radius:6px;background:transparent;font-size:12px;color:var(--ig-fg-3);cursor:pointer;transition:all .15s}.dsh-ig-rail-tab:hover{background:var(--ig-soft);color:var(--ig-fg)}.dsh-ig-rail-tab.is-active{border-color:var(--ig-blue-line);background:var(--ig-soft);color:var(--ig-blue);font-weight:600}
|
|
123876
|
+
.dsh-ig-fav-scroll{flex:1 1 0;height:0;overflow-x:hidden;overflow-y:auto;min-height:0;padding:8px}
|
|
123877
|
+
.dsh-ig-fav-section-label{padding:4px 2px 6px;font-size:11px;font-weight:600;color:var(--ig-fg-3)}
|
|
123878
|
+
.dsh-ig-fav-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));gap:6px}
|
|
123879
|
+
.dsh-ig-fav-empty{min-height:64px;display:flex;flex-direction:column;justify-content:center;align-items:center;gap:8px;color:var(--ig-fg-cap);text-align:center;font-size:11px;border:1px dashed var(--ig-line);border-radius:8px;margin-bottom:8px;padding:8px}
|
|
123880
|
+
.dsh-ig-fav-prompts{display:flex;flex-direction:column;gap:4px}
|
|
123881
|
+
.dsh-ig-recent-item{position:relative;width:100%;aspect-ratio:1;align-self:start;padding:0;border:1px solid transparent;border-radius:8px;background:transparent;cursor:pointer;transition:border-color .16s,box-shadow .16s}.dsh-ig-recent-item:hover{border-color:var(--ig-blue-line);box-shadow:0 1px 4px rgba(30,42,76,.14)}.dsh-ig-recent-item.is-active{border-color:var(--ig-blue);box-shadow:0 0 0 2px rgba(47,100,245,.18)}.dsh-ig-recent-thumb{width:100%;height:100%;border-radius:7px;display:flex;align-items:center;justify-content:center;overflow:hidden;background:var(--ig-bg-thumb);color:var(--ig-fg-cap)}.dsh-ig-recent-thumb img{width:100%;height:100%;object-fit:cover}
|
|
123882
|
+
.dsh-ig-load-more{grid-column:1/-1;width:100%;height:32px;margin:4px 0 2px;display:flex;align-items:center;justify-content:center;border:1px dashed var(--ig-line);border-radius:7px;background:transparent;font-size:11px;color:var(--ig-fg-2);cursor:pointer;transition:background .15s,color .15s}.dsh-ig-load-more:hover{background:var(--ig-soft);color:var(--ig-blue);border-color:var(--ig-blue-line)}
|
|
123883
|
+
.dsh-ig-mini-btn{height:22px;padding:0 7px;display:inline-flex;align-items:center;gap:3px;border:1px solid var(--ig-line);border-radius:5px;background:var(--ig-bg);font-size:10.5px;font-weight:500;color:var(--ig-fg);cursor:pointer;transition:all .15s}.dsh-ig-mini-btn:hover{border-color:var(--ig-blue-line);color:var(--ig-blue);background:rgba(47,100,245,.06)}
|
|
123884
|
+
.dsh-ig-canvas-column{min-width:0;min-height:0;height:100%;overflow:hidden;display:flex;flex-direction:column;background:var(--dsw-alias-bg-layer-2,var(--ig-bg))}
|
|
121646
123885
|
.dsh-ig-canvas-toolbar{height:46px;flex:0 0 46px;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:8px;padding:0 14px;border-bottom:1px solid var(--ig-line)}
|
|
121647
123886
|
.dsh-ig-canvas-toolbar-left,.dsh-ig-canvas-toolbar-right{display:flex;align-items:center;gap:6px;min-width:0}
|
|
121648
123887
|
.dsh-ig-canvas-toolbar-left{justify-self:start}
|
|
121649
123888
|
.dsh-ig-canvas-toolbar-right{justify-self:end}
|
|
121650
123889
|
.dsh-ig-canvas-toolbar-center{display:flex;align-items:center;justify-self:center;gap:6px;min-width:0}
|
|
121651
123890
|
.dsh-ig-toolbar-divider{width:1px;height:16px;background:var(--ig-line);flex-shrink:0;margin:0 2px}
|
|
121652
|
-
.dsh-ig-canvas-toolbar button{height:30px;min-width:30px;padding:0 9px;display:inline-flex;align-items:center;justify-content:center;gap:5px;border:1px solid var(--ig-line);border-radius:7px;background:var(--
|
|
121653
|
-
.dsh-ig-canvas-toolbar button:hover{border-color
|
|
121654
|
-
.dsh-ig-canvas-toolbar button.is-active{border-color
|
|
123891
|
+
.dsh-ig-canvas-toolbar button{height:30px;min-width:30px;padding:0 9px;display:inline-flex;align-items:center;justify-content:center;gap:5px;border:1px solid var(--ig-line);border-radius:7px;background:var(--ig-bg);color:var(--ig-fg);font-size:11.5px;font-weight:500;cursor:pointer;transition:border-color .15s,background .15s,color .15s}
|
|
123892
|
+
.dsh-ig-canvas-toolbar button:hover{border-color:var(--ig-blue-line);background:rgba(47,100,245,.05);color:var(--ig-blue)}
|
|
123893
|
+
.dsh-ig-canvas-toolbar button.is-active{border-color:var(--ig-blue-line);background:rgba(47,100,245,.08);color:var(--ig-blue);font-weight:550}
|
|
121655
123894
|
.dsh-ig-canvas-toolbar-center button.is-active{border-color:var(--ig-blue);background:rgba(47,100,245,.09);color:var(--ig-blue);font-weight:600;box-shadow:inset 0 0 0 1px rgba(47,100,245,.28)}
|
|
121656
|
-
.dsh-ig-zoom-display{font-size:11px;min-width:38px;text-align:center;color
|
|
121657
|
-
.dsh-ig-canvas-hint{flex:0 0 auto;display:flex;align-items:flex-start;gap:8px;padding:7px 12px;border-bottom:1px solid rgba(47,100,245,.14);background:rgba(47,100,245,.055);color
|
|
123895
|
+
.dsh-ig-zoom-display{font-size:11px;min-width:38px;text-align:center;color:var(--ig-fg-2);user-select:none;font-variant-numeric:tabular-nums}
|
|
123896
|
+
.dsh-ig-canvas-hint{flex:0 0 auto;display:flex;align-items:flex-start;gap:8px;padding:7px 12px;border-bottom:1px solid rgba(47,100,245,.14);background:rgba(47,100,245,.055);color:var(--ig-fg-2);font-size:11.5px;line-height:17px}.dsh-ig-canvas-hint>svg:first-child{flex-shrink:0;color:var(--ig-blue);margin-top:1px}.dsh-ig-canvas-hint>span{flex:1 1 0;min-width:0}.dsh-ig-canvas-hint>button{flex-shrink:0;width:22px;height:22px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:5px;background:transparent;color:var(--ig-fg-cap);cursor:pointer;transition:background .15s,color .15s}.dsh-ig-canvas-hint>button:hover{background:rgba(47,100,245,.1);color:var(--ig-blue)}
|
|
121658
123897
|
.dsh-ig-status-badge-wrap{position:relative;display:inline-flex;align-items:center}
|
|
121659
|
-
.dsh-ig-status-badge{height:30px;display:inline-flex;align-items:center;gap:7px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--
|
|
121660
|
-
.dsh-ig-status-badge:hover{border-color
|
|
123898
|
+
.dsh-ig-status-badge{height:30px;display:inline-flex;align-items:center;gap:7px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--ig-bg);cursor:pointer;user-select:none;transition:border-color .15s,background .15s,box-shadow .15s}
|
|
123899
|
+
.dsh-ig-status-badge:hover{border-color:var(--ig-blue-line);background:rgba(47,100,245,.04)}
|
|
121661
123900
|
.dsh-ig-status-dot{width:7px;height:7px;min-width:7px;max-width:7px;border-radius:50%;flex-shrink:0;box-sizing:border-box}
|
|
121662
123901
|
.dsh-ig-status-dot.is-ready{background:#10b981;box-shadow:0 0 0 2px rgba(16,185,129,.2)}
|
|
121663
123902
|
.dsh-ig-status-dot.is-muted{background:#ef4444;box-shadow:0 0 0 2px rgba(239,68,68,.2)}
|
|
121664
|
-
.dsh-ig-status-text{font-size:11.5px;font-weight:500;color:var(--
|
|
121665
|
-
.dsh-ig-status-arrow{color
|
|
123903
|
+
.dsh-ig-status-text{font-size:11.5px;font-weight:500;color:var(--ig-fg);line-height:1}
|
|
123904
|
+
.dsh-ig-status-arrow{color:var(--ig-fg-cap);transition:transform .15s,color .15s}
|
|
121666
123905
|
.dsh-ig-status-badge-wrap:hover .dsh-ig-status-arrow{transform:rotate(180deg);color:var(--ig-blue)}
|
|
121667
|
-
.dsh-ig-status-popover{position:absolute;left:0;top:calc(100% + 6px);width:260px;background:var(--
|
|
123906
|
+
.dsh-ig-status-popover{position:absolute;left:0;top:calc(100% + 6px);width:260px;background:var(--ig-bg);border:1px solid var(--ig-line);border-radius:9px;box-shadow:0 12px 36px rgba(20,28,45,.14);padding:10px 12px;z-index:40;opacity:0;pointer-events:none;transform:translateY(4px);transition:opacity .15s cubic-bezier(.16,1,.3,1),transform .15s cubic-bezier(.16,1,.3,1)}
|
|
121668
123907
|
.dsh-ig-status-badge-wrap:hover .dsh-ig-status-popover{opacity:1;pointer-events:auto;transform:translateY(0)}
|
|
121669
|
-
.dsh-ig-status-popover-title{display:flex;align-items:center;justify-content:space-between;font-size:10px;font-weight:650;color
|
|
123908
|
+
.dsh-ig-status-popover-title{display:flex;align-items:center;justify-content:space-between;font-size:10px;font-weight:650;color:var(--ig-fg-cap);margin-bottom:8px;letter-spacing:.02em;text-transform:uppercase}
|
|
121670
123909
|
.dsh-ig-status-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}
|
|
121671
123910
|
.dsh-ig-status-list li{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 8px;border-radius:6px;transition:background .12s}
|
|
121672
123911
|
.dsh-ig-status-list li.is-configured{background:rgba(16,185,129,.05);border:1px solid rgba(16,185,129,.12)}
|
|
121673
123912
|
.dsh-ig-status-list li.is-missing{background:rgba(239,68,68,.04);border:1px solid rgba(239,68,68,.12);opacity:.75}
|
|
121674
123913
|
.dsh-ig-status-item-name{display:flex;flex-direction:column;min-width:0}
|
|
121675
|
-
.dsh-ig-status-item-name strong{font-size:11.5px;font-weight:600;color:var(--
|
|
121676
|
-
.dsh-ig-status-item-name small{font-size:9.5px;color
|
|
123914
|
+
.dsh-ig-status-item-name strong{font-size:11.5px;font-weight:600;color:var(--ig-fg);line-height:16px}
|
|
123915
|
+
.dsh-ig-status-item-name small{font-size:9.5px;color:var(--ig-fg-cap);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:145px;line-height:14px}
|
|
121677
123916
|
.dsh-ig-status-item-tag{font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;flex-shrink:0}
|
|
121678
123917
|
.is-configured .dsh-ig-status-item-tag{color:#059669;background:rgba(16,185,129,.14)}
|
|
121679
123918
|
.is-missing .dsh-ig-status-item-tag{color:#dc2626;background:rgba(239,68,68,.14)}
|
|
121680
123919
|
.dsh-ig-canvas{position:relative;flex:1 1 0;height:0;min-height:0;display:flex;align-items:center;justify-content:center;overflow:hidden;padding:24px;touch-action:none;user-select:none;cursor:grab;background-image:linear-gradient(45deg,rgba(114,128,156,.035) 25%,transparent 25%),linear-gradient(-45deg,rgba(114,128,156,.035) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(114,128,156,.035) 75%),linear-gradient(-45deg,transparent 75%,rgba(114,128,156,.035) 75%);background-size:24px 24px;background-position:0 0,0 12px,12px -12px,-12px 0}
|
|
121681
123920
|
.dsh-ig-canvas.is-dragging,.dsh-ig-canvas.is-dragging *{cursor:grabbing!important}
|
|
121682
123921
|
.dsh-ig-canvas img{display:block;max-width:100%;max-height:100%;width:auto;height:auto;border-radius:10px;box-shadow:0 14px 45px rgba(25,35,63,.18);user-select:none;-webkit-user-drag:none;pointer-events:auto}
|
|
121683
|
-
.dsh-ig-canvas-empty,.dsh-ig-generating-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px;color
|
|
121684
|
-
.dsh-ig-generating-state strong{font-size:15px;color:var(--
|
|
121685
|
-
.dsh-ig-result-strip{flex:0 0 auto;min-height:52px;padding:8px 14px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--ig-line)}.dsh-ig-result-strip>span{font-size:12px;font-weight:650}.dsh-ig-result-strip>div,.dsh-ig-result-actions>div{display:flex;gap:7px}.dsh-ig-result-strip button,.dsh-ig-result-actions button{height:32px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--
|
|
121686
|
-
.dsh-ig-generate-panel{height:100%;display:flex;flex-direction:column;border-left:1px solid var(--ig-line);overflow:hidden}.dsh-ig-generator-form{flex:1 1 0;height:0;padding:15px;display:flex;flex-direction:column;gap:15px;overflow-x:hidden;overflow-y:auto;min-height:0}.dsh-ig-mode-switch{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-ig-mode-switch button{height:39px;border:1px solid var(--ig-line);border-radius:8px;background:var(--
|
|
121687
|
-
.dsh-ig-field{position:relative;display:flex;flex-direction:column;gap:7px}.dsh-ig-field>label,.dsh-ig-field-label label{font-size:11.5px;font-weight:630}.dsh-ig-field>label span{font-weight:400;color
|
|
121688
|
-
.dsh-ig-generation-kind{display:grid;grid-template-columns:1fr 1fr;gap:4px;padding:3px;border:1px solid var(--ig-line);border-radius:9px;background:var(--ig-soft)}.dsh-ig-generation-kind button{height:31px;border:0;border-radius:6px;background:transparent;color
|
|
121689
|
-
.dsh-ig-compare-box{padding:10px;border:1px solid rgba(47,100,245,.2);border-radius:10px;background:linear-gradient(145deg,rgba(47,100,245,.055),rgba(99,102,241,.018));display:flex;flex-direction:column;gap:9px}.dsh-ig-compare-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.dsh-ig-compare-heading>div{min-width:0;display:flex;flex-direction:column;gap:2px}.dsh-ig-compare-heading strong{font-size:11.5px}.dsh-ig-compare-heading small{font-size:9.5px;color
|
|
121690
|
-
.dsh-ig-upload{height:92px;border:1px dashed
|
|
123922
|
+
.dsh-ig-canvas-empty,.dsh-ig-generating-state{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:12px;color:var(--ig-fg-cap);font-size:12px;padding:26px;cursor:default}
|
|
123923
|
+
.dsh-ig-generating-state strong{font-size:15px;color:var(--ig-fg)}.dsh-ig-generating-state span{font-size:11px}.dsh-ig-generation-orbit{width:66px;height:66px;border-radius:50%;display:grid;place-items:center;color:var(--ig-blue);background:rgba(47,100,245,.09);box-shadow:0 0 0 10px rgba(47,100,245,.035);animation:dshIgPulse 1.8s ease-in-out infinite}
|
|
123924
|
+
.dsh-ig-result-strip{flex:0 0 auto;min-height:52px;padding:8px 14px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--ig-line)}.dsh-ig-result-strip>span{font-size:12px;font-weight:650}.dsh-ig-result-strip>div,.dsh-ig-result-actions>div{display:flex;gap:7px}.dsh-ig-result-strip button,.dsh-ig-result-actions button{height:32px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line);border-radius:7px;background:var(--ig-bg);font-size:11px;cursor:pointer}.dsh-ig-result-strip button:hover,.dsh-ig-result-actions button:hover{border-color:var(--ig-blue-line);color:var(--ig-blue)}.dsh-ig-result-actions{flex:0 0 auto;min-height:54px;padding:8px 14px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--ig-line)}.dsh-ig-result-actions p{margin:0;min-width:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:11.5px;line-height:18px;color:var(--ig-fg-2)}.dsh-ig-result-meta{flex:0 0 auto;min-height:32px;padding:6px 14px;display:flex;gap:13px;align-items:center;flex-wrap:wrap;border-top:1px solid var(--ig-line);font-size:10px;color:var(--ig-fg-cap)}.dsh-ig-result-meta span+span:before{content:'·';margin-right:13px}
|
|
123925
|
+
.dsh-ig-generate-panel{height:100%;display:flex;flex-direction:column;border-left:1px solid var(--ig-line);overflow:hidden}.dsh-ig-generator-form{flex:1 1 0;height:0;padding:15px;display:flex;flex-direction:column;gap:15px;overflow-x:hidden;overflow-y:auto;min-height:0}.dsh-ig-mode-switch{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-ig-mode-switch button{height:39px;border:1px solid var(--ig-line);border-radius:8px;background:var(--ig-bg);display:flex;align-items:center;justify-content:center;gap:7px;font-size:12px;cursor:pointer}.dsh-ig-mode-switch button.is-active{border-color:var(--ig-blue-line);color:var(--ig-blue);background:rgba(47,100,245,.065);box-shadow:inset 0 0 0 1px rgba(47,100,245,.1)}
|
|
123926
|
+
.dsh-ig-field{position:relative;display:flex;flex-direction:column;gap:7px}.dsh-ig-field>label,.dsh-ig-field-label label{font-size:11.5px;font-weight:630}.dsh-ig-field>label span{font-weight:400;color:var(--ig-fg-cap)}.dsh-ig-field-label{display:flex;align-items:center;justify-content:space-between}.dsh-ig-field-label b{color:#e14d4d}.dsh-ig-field-label button{border:0;background:transparent;color:var(--ig-fg-3);font-size:10.5px;cursor:pointer}.dsh-ig-field textarea{width:100%;height:112px;padding:11px 12px 22px;resize:vertical;border:1px solid var(--ig-line);border-radius:9px;background:var(--ig-bg);font-size:12px;line-height:19px;outline:none}.dsh-ig-field textarea:focus{border-color:var(--ig-blue);box-shadow:0 0 0 3px rgba(47,100,245,.09)}.dsh-ig-field>small{position:absolute;right:9px;bottom:7px;color:var(--ig-fg-cap);font-size:9.5px}.dsh-ig-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:9px}.dsh-ig-field-select{display:flex;flex-direction:column;gap:6px;min-width:0}.dsh-ig-field-select>span{font-size:11px;font-weight:620}.dsh-ig-field-select select{width:100%;height:36px;padding:0 26px 0 9px;border:1px solid var(--ig-line);border-radius:8px;background:var(--ig-bg);font-size:11px;outline:none;text-overflow:ellipsis}.dsh-ig-field-select select:focus{border-color:var(--ig-blue)}.dsh-ig-count-row{display:grid;grid-template-columns:repeat(4,1fr);gap:6px}.dsh-ig-count-pill{height:34px;border:1px solid var(--ig-line);border-radius:7px;background:var(--ig-bg);font-size:12px;font-weight:600;color:var(--ig-fg-2);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .15s}.dsh-ig-count-pill:hover{border-color:var(--ig-blue-line);color:var(--ig-blue)}.dsh-ig-count-pill.is-active{border-color:var(--ig-blue);background:rgba(47,100,245,.08);color:var(--ig-blue);box-shadow:inset 0 0 0 1px var(--ig-blue)}
|
|
123927
|
+
.dsh-ig-generation-kind{display:grid;grid-template-columns:1fr 1fr;gap:4px;padding:3px;border:1px solid var(--ig-line);border-radius:9px;background:var(--ig-soft)}.dsh-ig-generation-kind button{height:31px;border:0;border-radius:6px;background:transparent;color:var(--ig-fg-3);font-size:11.5px;display:flex;align-items:center;justify-content:center;gap:6px;cursor:pointer;transition:background .15s,color .15s,box-shadow .15s}.dsh-ig-generation-kind button.is-active{background:var(--ig-bg);color:var(--ig-blue);font-weight:650;box-shadow:0 2px 8px rgba(30,42,76,.09)}
|
|
123928
|
+
.dsh-ig-compare-box{padding:10px;border:1px solid rgba(47,100,245,.2);border-radius:10px;background:linear-gradient(145deg,rgba(47,100,245,.055),rgba(99,102,241,.018));display:flex;flex-direction:column;gap:9px}.dsh-ig-compare-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.dsh-ig-compare-heading>div{min-width:0;display:flex;flex-direction:column;gap:2px}.dsh-ig-compare-heading strong{font-size:11.5px}.dsh-ig-compare-heading small{font-size:9.5px;color:var(--ig-fg-cap)}.dsh-ig-compare-heading>span{flex:none;padding:2px 6px;border-radius:999px;background:rgba(47,100,245,.11);color:var(--ig-blue);font-size:9.5px;font-weight:650}.dsh-ig-model-checks{display:flex;flex-direction:column;gap:6px}.dsh-ig-model-checks>button{min-height:43px;width:100%;padding:6px 7px;display:grid;grid-template-columns:18px minmax(0,1fr) auto;align-items:center;gap:7px;border:1px solid var(--ig-line);border-radius:8px;background:var(--ig-bg);text-align:left;cursor:pointer;transition:border-color .15s,background .15s,transform .15s}.dsh-ig-model-checks>button:hover{border-color:var(--ig-blue-line);transform:translateY(-1px)}.dsh-ig-model-checks>button.is-selected{border-color:var(--ig-blue-line);background:rgba(47,100,245,.055);box-shadow:inset 3px 0 0 var(--ig-blue)}.dsh-ig-model-checkmark{width:17px;height:17px;border:1px solid var(--ig-line);border-radius:5px;display:grid;place-items:center;color:#fff;background:var(--ig-bg)}.dsh-ig-model-checks>button.is-selected .dsh-ig-model-checkmark{border-color:var(--ig-blue);background:var(--ig-blue)}.dsh-ig-model-copy{display:flex;flex-direction:column;min-width:0}.dsh-ig-model-copy strong{font-size:11px;line-height:15px}.dsh-ig-model-copy small{max-width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ig-fg-cap);font-size:9.5px;line-height:14px}.dsh-ig-model-settings{display:flex;flex-direction:column;align-items:flex-end;gap:2px;color:var(--ig-fg-2);font-size:9.5px;white-space:nowrap}.dsh-ig-model-settings em{font-style:normal;color:var(--ig-warn);font-size:8.5px}.dsh-ig-compare-box>p{margin:0;color:var(--ig-fg-3);font-size:9.5px;line-height:14px}
|
|
123929
|
+
.dsh-ig-upload{height:92px;border:1px dashed var(--ig-line);border-radius:9px;background:color-mix(in srgb,var(--ig-bg) 55%,transparent);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;color:var(--ig-fg-3);cursor:pointer}.dsh-ig-upload strong{font-size:11px;font-weight:570}.dsh-ig-upload small{font-size:9.5px}.dsh-ig-upload:hover,.dsh-ig-upload.is-dragging{border-color:var(--ig-blue);background:rgba(47,100,245,.05);color:var(--ig-blue)}
|
|
121691
123930
|
.dsh-ig-reference-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));gap:8px}
|
|
121692
|
-
.dsh-ig-reference-card{position:relative;aspect-ratio:1;border-radius:8px;overflow:hidden;background
|
|
123931
|
+
.dsh-ig-reference-card{position:relative;aspect-ratio:1;border-radius:8px;overflow:hidden;background:var(--ig-bg-thumb);border:1px solid var(--ig-line)}
|
|
121693
123932
|
.dsh-ig-reference-card img{width:100%;height:100%;object-fit:cover}
|
|
121694
123933
|
.dsh-ig-reference-card button{position:absolute;right:4px;top:4px;width:18px;height:18px;border:0;border-radius:50%;display:grid;place-items:center;background:rgba(20,28,45,.75);color:#fff;cursor:pointer;padding:0;transition:background .15s}
|
|
121695
123934
|
.dsh-ig-reference-card button:hover{background:#ef4444}
|
|
121696
|
-
.dsh-ig-reference-add{aspect-ratio:1;border:1px dashed
|
|
123935
|
+
.dsh-ig-reference-add{aspect-ratio:1;border:1px dashed var(--ig-line);border-radius:8px;background:color-mix(in srgb,var(--ig-bg) 55%,transparent);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;color:var(--ig-fg-3);cursor:pointer;font-size:10px;transition:border-color .15s,color .15s,background .15s}
|
|
121697
123936
|
.dsh-ig-reference-add:hover{border-color:var(--ig-blue);background:rgba(47,100,245,.05);color:var(--ig-blue)}
|
|
121698
|
-
.dsh-ig-reference-preview{position:relative;height:108px;border-radius:9px;overflow:hidden;background
|
|
121699
|
-
.dsh-ig-inline-note,.dsh-ig-form-error{padding:9px 10px;border-radius:7px;font-size:10.5px;line-height:16px}.dsh-ig-inline-note{background
|
|
121700
|
-
.dsh-ig-config-error{padding:14px;display:flex;flex-direction:column;align-items:center;gap:10px;background
|
|
123937
|
+
.dsh-ig-reference-preview{position:relative;height:108px;border-radius:9px;overflow:hidden;background:var(--ig-bg-thumb)}.dsh-ig-reference-preview img{width:100%;height:100%;object-fit:contain}.dsh-ig-reference-preview button{position:absolute;right:7px;top:7px;width:25px;height:25px;border:0;border-radius:50%;display:grid;place-items:center;background:rgba(20,28,45,.72);color:#fff;cursor:pointer}
|
|
123938
|
+
.dsh-ig-inline-note,.dsh-ig-form-error{padding:9px 10px;border-radius:7px;font-size:10.5px;line-height:16px}.dsh-ig-inline-note{background:rgba(245,158,11,.1);color:var(--ig-warn);border:1px solid rgba(245,158,11,.35)}.dsh-ig-form-error{background:rgba(239,68,68,.08);color:var(--ig-danger);border:1px solid rgba(239,68,68,.3)}.dsh-ig-form-loading{height:70px;display:grid;place-items:center;color:var(--ig-blue)}
|
|
123939
|
+
.dsh-ig-config-error{padding:14px;display:flex;flex-direction:column;align-items:center;gap:10px;background:rgba(239,68,68,.07);border:1px solid rgba(239,68,68,.3);border-radius:8px;color:var(--ig-danger);font-size:11.5px;text-align:center}.dsh-ig-config-error p{margin:0;line-height:17px}.dsh-ig-config-error button{height:30px;display:inline-flex;align-items:center;gap:6px;padding:0 12px;border:1px solid rgba(239,68,68,.35);border-radius:6px;background:var(--ig-bg);color:var(--ig-danger);font-size:11.5px;font-weight:600;cursor:pointer}.dsh-ig-config-error button:hover{background:rgba(239,68,68,.12)}
|
|
121701
123940
|
.dsh-ig-generate-button{height:42px;flex:0 0 auto;border:0;border-radius:8px;background:linear-gradient(135deg,#386cf6,#2758e7);color:#fff!important;display:flex;align-items:center;justify-content:center;gap:8px;font-size:12px;font-weight:650;cursor:pointer;box-shadow:0 8px 18px rgba(47,100,245,.22);transition:transform .16s,box-shadow .16s}.dsh-ig-generate-button:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 10px 24px rgba(47,100,245,.28)}.dsh-ig-generate-button:disabled{opacity:.55;cursor:not-allowed;box-shadow:none}
|
|
121702
123941
|
.dsh-ig-generate-button.is-cancel{background:linear-gradient(135deg,#ef4444,#dc2626);box-shadow:0 8px 18px rgba(239,68,68,.25)}.dsh-ig-generate-button.is-cancel:hover{background:linear-gradient(135deg,#dc2626,#b91c1c);box-shadow:0 10px 24px rgba(239,68,68,.35)}
|
|
121703
|
-
.dsh-ig-details{padding:16px;margin:0;overflow:auto}.dsh-ig-details>div{padding:12px 0;border-bottom:1px solid var(--ig-line)}.dsh-ig-details dt{font-size:10.5px;color
|
|
123942
|
+
.dsh-ig-details{padding:16px;margin:0;overflow:auto}.dsh-ig-details>div{padding:12px 0;border-bottom:1px solid var(--ig-line)}.dsh-ig-details dt{font-size:10.5px;color:var(--ig-fg-cap);margin-bottom:5px}.dsh-ig-details dd{margin:0;font-size:11.5px;line-height:18px;word-break:break-word}.dsh-ig-details-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;height:220px;padding:20px;color:var(--ig-fg-cap);font-size:11px;text-align:center}
|
|
121704
123943
|
.dsh-ig-workbench-modal-backdrop{position:fixed;inset:0;background:rgba(15,23,42,.45);backdrop-filter:blur(3px);z-index:999;display:grid;place-items:center;padding:16px}
|
|
121705
|
-
.dsh-ig-workbench-modal-box{width:100%;max-width:380px;background:var(--
|
|
123944
|
+
.dsh-ig-workbench-modal-box{width:100%;max-width:380px;background:var(--ig-bg);border-radius:12px;padding:20px;box-shadow:0 20px 48px rgba(0,0,0,.22);display:flex;flex-direction:column;gap:14px}
|
|
121706
123945
|
.dsh-ig-workbench-modal-header{display:flex;align-items:center;gap:10px}
|
|
121707
123946
|
.dsh-ig-workbench-modal-header strong{font-size:14px;font-weight:650;color:#b91c1c}
|
|
121708
|
-
.dsh-ig-workbench-modal-desc{font-size:12px;line-height:18px;color
|
|
121709
|
-
.dsh-ig-workbench-modal-option{display:flex;align-items:center;gap:8px;font-size:11.5px;color
|
|
123947
|
+
.dsh-ig-workbench-modal-desc{font-size:12px;line-height:18px;color:var(--ig-fg-2);margin:0}
|
|
123948
|
+
.dsh-ig-workbench-modal-option{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--ig-fg-2);cursor:pointer}
|
|
121710
123949
|
.dsh-ig-workbench-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:4px}
|
|
121711
123950
|
.dsh-ig-workbench-modal-actions button{height:32px;padding:0 14px;border-radius:7px;font-size:11.5px;font-weight:600;cursor:pointer}
|
|
121712
|
-
.dsh-ig-workbench-modal-cancel{border:1px solid var(--ig-line);background:var(--
|
|
121713
|
-
.dsh-ig-workbench-modal-cancel:hover{background
|
|
123951
|
+
.dsh-ig-workbench-modal-cancel{border:1px solid var(--ig-line);background:var(--ig-bg);color:var(--ig-fg-2)}
|
|
123952
|
+
.dsh-ig-workbench-modal-cancel:hover{background:var(--ig-soft)}
|
|
121714
123953
|
.dsh-ig-workbench-modal-danger{border:0;background:#dc2626;color:#fff}
|
|
121715
123954
|
.dsh-ig-workbench-modal-danger:hover{background:#b91c1c}
|
|
121716
123955
|
@keyframes dshIgPulse{50%{transform:scale(1.06);box-shadow:0 0 0 16px rgba(47,100,245,.025)}}
|
|
121717
123956
|
.dsh-ig-workbench-toast{position:fixed;bottom:28px;left:50%;transform:translateX(-50%);background:rgba(15,23,42,0.88);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);color:#fff;padding:8px 18px;border-radius:10px;font-size:12.5px;font-weight:500;box-shadow:0 12px 32px rgba(0,0,0,0.3);z-index:99999;animation:dshIgFade .15s ease-out;pointer-events:none}
|
|
121718
123957
|
@keyframes dshIgFade{from{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%,0)}}
|
|
121719
123958
|
@media(max-width:1120px){.dsh-ig-workbench-grid{grid-template-columns:190px minmax(360px,1fr) 300px}.dsh-ig-result-actions button,.dsh-ig-result-strip button{padding:0 7px;font-size:10px;gap:4px}.dsh-ig-result-actions>div,.dsh-ig-result-strip>div{gap:5px}}
|
|
121720
|
-
@media(max-width:900px){.dsh-ig-gallery-page-body.is-workbench{height:auto;overflow:auto}.dsh-ig-workbench{height:auto;min-height:100%;overflow:visible;padding:12px}.dsh-ig-workbench-heading{height:auto;padding-bottom:12px;align-items:center}.dsh-ig-provider-quick>span{display:none}.dsh-ig-workbench-grid{height:auto;display:flex;flex:none;flex-direction:column;overflow:visible}.dsh-ig-recent-panel{height:auto;overflow:hidden;border-right:0;border-bottom:1px solid var(--ig-line)}.dsh-ig-recent-scroll{height:auto;display:flex;overflow-x:auto;overflow-y:hidden;padding:8px}.dsh-ig-recent-item{min-width:220px}.dsh-ig-canvas-column{height:auto;min-height:560px}.dsh-ig-generate-panel{height:auto;border-left:0;border-top:1px solid var(--ig-line);min-height:560px}.dsh-ig-generator-form{height:auto;overflow:visible}.dsh-ig-canvas{height:auto;min-height:360px}}
|
|
123959
|
+
@media(max-width:900px){.dsh-ig-gallery-page-body.is-workbench{height:auto;overflow:auto}.dsh-ig-workbench{height:auto;min-height:100%;overflow:visible;padding:12px}.dsh-ig-workbench-heading{height:auto;padding-bottom:12px;align-items:center}.dsh-ig-provider-quick>span{display:none}.dsh-ig-workbench-grid{height:auto;display:flex;flex:none;flex-direction:column;overflow:visible}.dsh-ig-recent-panel{height:auto;overflow:hidden;border-right:0;border-bottom:1px solid var(--ig-line)}.dsh-ig-recent-scroll{height:auto;display:flex;overflow-x:auto;overflow-y:hidden;padding:8px}.dsh-ig-fav-scroll{height:auto;flex:none;overflow:visible}.dsh-ig-recent-item{min-width:220px}.dsh-ig-canvas-column{height:auto;min-height:560px}.dsh-ig-generate-panel{height:auto;border-left:0;border-top:1px solid var(--ig-line);min-height:560px}.dsh-ig-generator-form{height:auto;overflow:visible}.dsh-ig-canvas{height:auto;min-height:360px}}
|
|
121721
123960
|
@media(max-width:560px){.dsh-ig-workbench-heading>div{display:block}.dsh-ig-workbench-heading h1{font-size:15px}.dsh-ig-provider-quick select{min-width:128px;max-width:150px}.dsh-ig-canvas{padding:12px;min-height:300px}.dsh-ig-result-strip,.dsh-ig-result-actions{align-items:flex-start;flex-direction:column}.dsh-ig-result-strip>div,.dsh-ig-result-actions>div{width:100%}.dsh-ig-result-strip button,.dsh-ig-result-actions button{flex:1;justify-content:center}.dsh-ig-result-actions button span{display:inline}.dsh-ig-field-grid{grid-template-columns:1fr}.dsh-ig-result-meta span+span:before{display:none}}
|
|
121722
123961
|
@media(prefers-reduced-motion:reduce){.dsh-ig-workbench *{scroll-behavior:auto!important;animation-duration:.01ms!important;transition-duration:.01ms!important}}
|
|
121723
|
-
.dsh-ig-field-label>span{display:flex;align-items:center;gap:5px}.dsh-ig-field-label .dsh-ig-find-inspiration{display:inline-flex;align-items:center;gap:3px;color:var(--ig-blue);font-weight:600}.dsh-ig-field-label .dsh-ig-find-inspiration:hover{color
|
|
121724
|
-
.dsh-ig-workspace-filter-label{height:30px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line,rgba(0,0,0,.1));border-radius:7px;background:var(--
|
|
121725
|
-
.dsh-ig-workspace-filter-label:hover{border-color
|
|
123962
|
+
.dsh-ig-field-label>span{display:flex;align-items:center;gap:5px}.dsh-ig-field-label .dsh-ig-find-inspiration{display:inline-flex;align-items:center;gap:3px;color:var(--ig-blue);font-weight:600}.dsh-ig-field-label .dsh-ig-find-inspiration:hover{color:color-mix(in srgb,var(--ig-blue) 78%,#fff)}
|
|
123963
|
+
.dsh-ig-workspace-filter-label{height:30px;display:inline-flex;align-items:center;gap:6px;padding:0 10px;border:1px solid var(--ig-line,rgba(0,0,0,.1));border-radius:7px;background:var(--ig-bg);font-size:11.5px;color:var(--ig-fg);cursor:pointer;user-select:none;transition:border-color .15s,background .15s}
|
|
123964
|
+
.dsh-ig-workspace-filter-label:hover{border-color:var(--ig-blue-line);background:rgba(47,100,245,.04)}
|
|
121726
123965
|
.dsh-ig-workspace-checkbox{cursor:pointer;accent-color:#2f64f5;width:13.5px;height:13.5px;margin:0}
|
|
121727
123966
|
.dsh-ig-workspace-filter-text{font-weight:500;white-space:nowrap}
|
|
121728
|
-
.dsh-ig-workspace-filter-badge{font-size:10px;font-weight:600;padding:1px 6px;border-radius:999px;background:color-mix(in srgb,currentColor 7%,transparent);color
|
|
123967
|
+
.dsh-ig-workspace-filter-badge{font-size:10px;font-weight:600;padding:1px 6px;border-radius:999px;background:color-mix(in srgb,currentColor 7%,transparent);color:var(--ig-fg-2);font-variant-numeric:tabular-nums}
|
|
121729
123968
|
.dsh-ig-canvas-cluster{display:grid;gap:16px;align-items:center;justify-content:center;user-select:none;pointer-events:auto;flex-shrink:0}
|
|
121730
123969
|
.dsh-ig-canvas-cluster[data-count="2"]{grid-template-columns:repeat(2,1fr);max-width:880px}
|
|
121731
123970
|
.dsh-ig-canvas-cluster[data-count="3"],.dsh-ig-canvas-cluster[data-count="4"]{grid-template-columns:repeat(2,1fr);max-width:760px}
|
|
@@ -121738,19 +123977,19 @@ img.ProseMirror-separator {
|
|
|
121738
123977
|
.dsh-ig-canvas-badge.is-model{max-width:calc(100% - 20px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
|
|
121739
123978
|
.dsh-ig-canvas-item.is-checked .dsh-ig-canvas-badge{background:var(--ig-blue)}
|
|
121740
123979
|
.dsh-ig-canvas-check{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1.5px solid rgba(255,255,255,.85);border-radius:50%;display:grid;place-items:center;background:rgba(15,23,42,.48);color:#fff;box-shadow:0 2px 8px rgba(15,23,42,.18);backdrop-filter:blur(4px);z-index:2;pointer-events:none}.dsh-ig-canvas-item.is-checked .dsh-ig-canvas-check{border-color:#fff;background:var(--ig-blue)}
|
|
121741
|
-
.dsh-ig-canvas-item-loading{width:260px;height:260px;display:flex;align-items:center;justify-content:center;background:
|
|
123980
|
+
.dsh-ig-canvas-item-loading{width:260px;height:260px;display:flex;align-items:center;justify-content:center;background:color-mix(in srgb,var(--ig-bg) 55%,transparent);border:1px solid var(--ig-line);border-radius:10px;color:var(--ig-fg-cap)}
|
|
121742
123981
|
.dsh-ig-lightbox-nav{position:absolute;top:50%;transform:translateY(-50%);width:42px;height:42px;border-radius:50%;border:0;background:rgba(15,23,42,.65);color:#fff;display:grid;place-items:center;cursor:pointer;transition:background .15s,transform .15s;z-index:10;backdrop-filter:blur(4px)}
|
|
121743
123982
|
.dsh-ig-lightbox-nav:hover{background:rgba(47,100,245,.85);transform:translateY(-50%) scale(1.08)}
|
|
121744
123983
|
.dsh-ig-lightbox-nav.is-prev{left:18px}
|
|
121745
123984
|
.dsh-ig-lightbox-nav.is-next{right:18px}
|
|
121746
123985
|
.dsh-ig-save-gallery-btn{color:var(--ig-blue)!important;border-color:rgba(47,100,245,.35)!important;background:rgba(47,100,245,.06)!important}
|
|
121747
123986
|
.dsh-ig-save-gallery-btn:hover{background:rgba(47,100,245,.12)!important}
|
|
121748
|
-
.dsh-ig-save-gallery-btn.is-saved{color
|
|
123987
|
+
.dsh-ig-save-gallery-btn.is-saved{color:var(--ig-fg-2)!important;border-color:var(--ig-line)!important;background:transparent!important}
|
|
121749
123988
|
|
|
121750
123989
|
/* tldraw infinite canvas surface (P0 spike) */
|
|
121751
123990
|
.dsh-ig-tl-canvas{position:relative;flex:1 1 0;height:0;min-height:0;overflow:hidden;isolation:isolate}
|
|
121752
|
-
.dsh-ig-canvas-sync-status{position:absolute;z-index:500;bottom:48px;left:60px;right:16px;display:flex;align-items:center;justify-content:center;gap:8px;max-width:560px;margin:auto;padding:7px 12px;border:1px solid var(--
|
|
121753
|
-
.dsh-ig-canvas-sync-status[data-phase='error']{color
|
|
123991
|
+
.dsh-ig-canvas-sync-status{position:absolute;z-index:500;bottom:48px;left:60px;right:16px;display:flex;align-items:center;justify-content:center;gap:8px;max-width:560px;margin:auto;padding:7px 12px;border:1px solid var(--ig-line);border-radius:10px;background:var(--ig-bg);color:var(--ig-fg-2);box-shadow:0 2px 8px #0001;font-size:12px;pointer-events:none}
|
|
123992
|
+
.dsh-ig-canvas-sync-status[data-phase='error']{color:var(--ig-danger);border-color:rgba(239,68,68,.4)}
|
|
121754
123993
|
.dsh-ig-canvas-sync-status button{pointer-events:auto;flex-shrink:0;border:1px solid currentColor;border-radius:6px;padding:3px 9px;background:transparent;color:inherit;cursor:pointer}
|
|
121755
123994
|
|
|
121756
123995
|
/* ---- Right-sidebar seat variant (DSH 0.1.5 'sidebar.right.pane.tab') ----
|
|
@@ -121943,6 +124182,10 @@ img.ProseMirror-separator {
|
|
|
121943
124182
|
.dsh-ig-inspiration-head{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;margin-bottom:18px}.dsh-ig-inspiration-head-actions{display:flex;align-items:center;gap:8px}.dsh-ig-inspiration-kicker{margin:0 0 4px;color:var(--inspiration-blue);font-size:11px;letter-spacing:.08em;font-weight:700;text-transform:uppercase}.dsh-ig-inspiration-head h1{margin:0;font-size:18px;letter-spacing:-.025em;line-height:1.25}.dsh-ig-inspiration-subtitle{margin:5px 0 0;color:var(--inspiration-muted);font-size:12px;line-height:1.5}.dsh-ig-inspiration-refresh,.dsh-ig-inspiration-clear-cache{height:32px;padding:0 11px;display:inline-flex;align-items:center;gap:6px;border:1px solid var(--inspiration-line);border-radius:7px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--inspiration-muted);font:inherit;font-size:12px;white-space:nowrap;cursor:pointer;transition:all .15s ease}.dsh-ig-inspiration-refresh:hover:not(:disabled){border-color:rgba(47,100,245,.42);color:var(--inspiration-blue);background:rgba(47,100,245,.04)}.dsh-ig-inspiration-clear-cache:hover:not(:disabled){border-color:rgba(239,68,68,.4);color:#ef4444;background:rgba(239,68,68,.04)}.dsh-ig-inspiration-refresh:disabled,.dsh-ig-inspiration-clear-cache:disabled{opacity:.55;cursor:wait}
|
|
121944
124183
|
.dsh-ig-inspiration-toolbar{display:grid;grid-template-columns:minmax(180px,1fr) auto repeat(3,minmax(110px,140px));gap:8px;padding:10px;border:1px solid var(--inspiration-line);border-radius:10px;background:color-mix(in srgb,var(--dsw-alias-bg-layer-1,#fff) 90%,#edf2ff);margin-bottom:16px}.dsh-ig-inspiration-search{min-width:0;position:relative}.dsh-ig-inspiration-search svg{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:#8995aa}.dsh-ig-inspiration-toolbar input,.dsh-ig-inspiration-toolbar select{width:100%;height:34px;box-sizing:border-box;border:1px solid transparent;border-radius:6px;background:var(--dsw-alias-bg-layer-1,#fff);color:inherit;padding:0 9px;font:inherit;font-size:12px;outline:none}.dsh-ig-inspiration-toolbar input{padding-left:31px}.dsh-ig-inspiration-toolbar input:focus,.dsh-ig-inspiration-toolbar select:focus{border-color:var(--inspiration-blue);box-shadow:0 0 0 3px rgba(47,100,245,.1)}
|
|
121945
124184
|
.dsh-ig-inspiration-fav-filter{height:34px;padding:0 12px;display:inline-flex;align-items:center;gap:6px;border:1px solid var(--inspiration-line);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--inspiration-muted);font:inherit;font-size:12px;cursor:pointer;white-space:nowrap;transition:all .15s ease}.dsh-ig-inspiration-fav-filter:hover{border-color:rgba(47,100,245,.4);color:var(--inspiration-blue)}.dsh-ig-inspiration-fav-filter.is-active{background:#eef3ff;border-color:var(--inspiration-blue);color:var(--inspiration-blue);font-weight:600}.fill-star{fill:currentColor}
|
|
124185
|
+
.dsh-ig-inspiration-catnav{position:sticky;top:0;z-index:6;display:flex;flex-wrap:wrap;gap:6px;margin:0 0 14px;padding:8px;border:1px solid var(--inspiration-line);border-radius:10px;background:color-mix(in srgb,var(--dsw-alias-bg-layer-1,#fff) 92%,#edf2ff);backdrop-filter:blur(8px)}
|
|
124186
|
+
.dsh-ig-inspiration-catnav-chip{height:26px;padding:0 11px;display:inline-flex;align-items:center;gap:6px;border:1px solid var(--inspiration-line);border-radius:999px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--inspiration-muted);font:inherit;font-size:11px;font-weight:600;cursor:pointer;white-space:nowrap;transition:all .15s ease}.dsh-ig-inspiration-catnav-chip em{font-style:normal;font-size:10px;opacity:.75}.dsh-ig-inspiration-catnav-chip:hover:not(:disabled){border-color:rgba(47,100,245,.46);color:var(--inspiration-blue)}.dsh-ig-inspiration-catnav-chip.is-active{border-color:var(--inspiration-blue);background:#eef3ff;color:var(--inspiration-blue)}.dsh-ig-inspiration-catnav-chip:disabled{opacity:.4;cursor:default}
|
|
124187
|
+
.dsh-ig-inspiration-group{margin:0}
|
|
124188
|
+
.dsh-ig-inspiration-group-head{position:sticky;top:48px;z-index:5;display:flex;align-items:center;gap:8px;margin:6px 0 10px;padding:7px 2px;font-size:12px;font-weight:700;letter-spacing:.02em;color:var(--inspiration-ink);background:color-mix(in srgb,var(--dsw-alias-bg-layer-1,#fff) 86%,transparent);backdrop-filter:blur(6px);scroll-margin-top:48px}.dsh-ig-inspiration-group-head em{font-style:normal;font-weight:600;font-size:10.5px;color:var(--inspiration-muted)}
|
|
121946
124189
|
.dsh-ig-inspiration-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(260px,310px);gap:18px;align-items:start}.dsh-ig-inspiration-summary{height:24px;display:flex;align-items:center;justify-content:space-between;color:var(--inspiration-muted);font-size:11.5px}.dsh-ig-inspiration-summary strong{color:inherit;font-weight:650}.dsh-ig-inspiration-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(185px,1fr));gap:12px}.dsh-ig-inspiration-card{position:relative;min-width:0;padding:0;border:1px solid var(--inspiration-line);border-radius:10px;overflow:hidden;background:var(--dsw-alias-bg-layer-1,#fff);text-align:left;cursor:pointer;transition:transform .16s ease,border-color .16s ease,box-shadow .16s ease;content-visibility:auto;contain-intrinsic-size:245px}.dsh-ig-inspiration-card:hover,.dsh-ig-inspiration-card.is-selected{border-color:rgba(47,100,245,.58);box-shadow:0 8px 22px rgba(37,62,123,.11)}.dsh-ig-inspiration-card:hover{transform:translateY(-2px)}.dsh-ig-inspiration-card.is-selected:after{content:'';position:absolute;inset:0;border:2px solid var(--inspiration-blue);border-radius:9px;pointer-events:none}.dsh-ig-inspiration-visual{aspect-ratio:1/1;position:relative;background:linear-gradient(135deg,#f0f4fc,#e3eafa);overflow:hidden}.dsh-ig-inspiration-visual img{width:100%;height:100%;object-fit:cover;display:block}.dsh-ig-inspiration-image-placeholder{height:100%;display:grid;place-items:center;color:#8a99b3}.dsh-ig-inspiration-image-placeholder.is-error{font-size:11px;padding:10px;text-align:center}.dsh-ig-inspiration-card-copy{padding:9px 10px 10px}.dsh-ig-inspiration-card-copy strong{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:17px}.dsh-ig-inspiration-card-copy span{display:block;margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--inspiration-muted);font-size:10.5px}.dsh-ig-inspiration-featured{position:absolute;top:8px;left:8px;display:inline-flex;align-items:center;gap:3px;padding:3px 6px;border-radius:999px;background:rgba(20,31,52,.72);backdrop-filter:blur(5px);color:#fff;font-size:10px;font-weight:600;z-index:1}.dsh-ig-inspiration-card-star{position:absolute;top:8px;right:8px;width:26px;height:26px;border-radius:50%;background:rgba(20,31,52,.6);backdrop-filter:blur(4px);border:none;color:#fff;display:grid;place-items:center;cursor:pointer;z-index:2;opacity:0;transition:opacity .15s,transform .15s}.dsh-ig-inspiration-card:hover .dsh-ig-inspiration-card-star,.dsh-ig-inspiration-card-star.is-favorited{opacity:1}.dsh-ig-inspiration-card-star.is-favorited{color:#f59e0b;background:rgba(20,31,52,.85)}.dsh-ig-inspiration-card-star:hover{transform:scale(1.15)}
|
|
121947
124190
|
.dsh-ig-inspiration-empty{min-height:310px;display:grid;place-items:center;padding:30px;text-align:center;color:var(--inspiration-muted);border:1px dashed var(--inspiration-line);border-radius:10px;font-size:12px}
|
|
121948
124191
|
.dsh-ig-inspiration-empty.is-catalog-error{display:flex;flex-direction:column;gap:12px;color:var(--inspiration-text)}
|
|
@@ -121966,7 +124209,37 @@ img.ProseMirror-separator {
|
|
|
121966
124209
|
.dsh-ig-inspiration-end-hint{display:flex;align-items:center;justify-content:center;padding:24px 0 16px;color:var(--inspiration-muted);font-size:12px}
|
|
121967
124210
|
.dsh-ig-inspiration-inspector{position:sticky;top:0;overflow:hidden;border:1px solid var(--inspiration-line);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#fff);box-shadow:0 9px 28px rgba(27,45,88,.06)}.dsh-ig-inspiration-inspector-empty{min-height:310px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:9px;padding:22px;color:var(--inspiration-muted);font-size:12px;text-align:center}.dsh-ig-inspiration-inspector-image{aspect-ratio:16/10;background:#f1f4fa;position:relative;cursor:zoom-in}.dsh-ig-inspiration-inspector-image img{width:100%;height:100%;object-fit:cover}.dsh-ig-inspiration-inspector-zoom-hint{position:absolute;bottom:8px;right:8px;display:inline-flex;align-items:center;gap:4px;padding:4px 8px;border-radius:6px;background:rgba(15,23,42,.75);backdrop-filter:blur(5px);color:#fff;font-size:10.5px;font-weight:500;opacity:0;transition:opacity .15s ease;pointer-events:none}.dsh-ig-inspiration-inspector-image:hover .dsh-ig-inspiration-inspector-zoom-hint{opacity:1}.dsh-ig-inspiration-inspector-body{padding:14px}.dsh-ig-inspiration-inspector-head{display:flex;align-items:flex-start;justify-content:space-between;gap:8px}.dsh-ig-inspiration-inspector-body h2{margin:0;font-size:14px;line-height:1.4;flex:1}.dsh-ig-inspiration-inspector-fav{width:30px;height:30px;flex-shrink:0;border:1px solid var(--inspiration-line);border-radius:7px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--inspiration-muted);display:grid;place-items:center;cursor:pointer;transition:all .15s ease}.dsh-ig-inspiration-inspector-fav:hover{border-color:rgba(245,158,11,.4);color:#f59e0b}.dsh-ig-inspiration-inspector-fav.is-favorited{color:#f59e0b;border-color:rgba(245,158,11,.5);background:rgba(245,158,11,.08)}.dsh-ig-inspiration-origin{margin:5px 0 12px;color:var(--inspiration-muted);font-size:11px}.dsh-ig-inspiration-tags{display:flex;flex-wrap:wrap;gap:5px;margin:0 0 12px}.dsh-ig-inspiration-tags span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:3px 6px;border-radius:4px;background:#eef3ff;color:#3e5fb8;font-size:10px}.dsh-ig-inspiration-prompt-label{display:flex;align-items:center;justify-content:space-between;margin:0 0 6px;color:var(--inspiration-muted);font-size:10.5px;font-weight:650}.dsh-ig-inspiration-prompt{max-height:155px;margin:0;padding:9px;overflow:auto;white-space:pre-wrap;border:1px solid var(--inspiration-line);border-radius:7px;background:color-mix(in srgb,var(--dsw-alias-bg-layer-2,#f8fafc) 90%,#e9efff);font-size:11px;line-height:1.55;color:#526078}.dsh-ig-inspiration-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:12px}.dsh-ig-inspiration-actions button,.dsh-ig-inspiration-source-link{height:34px;display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid var(--inspiration-line);border-radius:7px;background:var(--dsw-alias-bg-layer-1,#fff);color:#536075;font:inherit;font-size:11.5px;font-weight:600;cursor:pointer;text-decoration:none}.dsh-ig-inspiration-actions button:hover,.dsh-ig-inspiration-source-link:hover{border-color:rgba(47,100,245,.46);color:var(--inspiration-blue)}.dsh-ig-inspiration-actions .dsh-ig-inspiration-use{grid-column:1/-1;border-color:var(--inspiration-blue);background:linear-gradient(135deg,#386cf6,#2758e7);color:#fff;box-shadow:0 7px 15px rgba(47,100,245,.2)}.dsh-ig-inspiration-actions .dsh-ig-inspiration-use:hover{color:#fff;transform:translateY(-1px)}
|
|
121968
124211
|
.dsh-ig-inspiration-lightbox{position:fixed;inset:0;z-index:10000;background:rgba(8,12,22,.88);backdrop-filter:blur(8px);display:flex;align-items:center;justify-content:center;padding:24px;box-sizing:border-box}.dsh-ig-inspiration-lightbox-content{position:relative;max-width:90vw;max-height:90vh;display:flex;flex-direction:column;align-items:center}.dsh-ig-inspiration-lightbox-img-wrap{max-width:85vw;max-height:82vh;border-radius:10px;overflow:hidden;box-shadow:0 25px 60px rgba(0,0,0,.7);background:#05070d}.dsh-ig-inspiration-lightbox-img-wrap img{width:auto;height:auto;max-width:85vw;max-height:82vh;object-fit:contain;display:block}.dsh-ig-inspiration-lightbox-close{position:absolute;top:-16px;right:-16px;width:34px;height:34px;border-radius:50%;background:#1e293b;color:#fff;border:1px solid rgba(255,255,255,.2);cursor:pointer;display:grid;place-items:center;transition:background .15s,transform .15s;z-index:10}.dsh-ig-inspiration-lightbox-close:hover{background:#334155;transform:scale(1.1)}.dsh-ig-inspiration-lightbox-caption{margin-top:12px;color:rgba(255,255,255,.9);font-size:13px;font-weight:500;text-shadow:0 2px 4px rgba(0,0,0,.6)}
|
|
124212
|
+
.dsh-ig-inspiration-sources{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:10px}.dsh-ig-inspiration-source-chip{height:30px;padding:0 13px;display:inline-flex;align-items:center;border:1px solid var(--inspiration-line);border-radius:999px;background:var(--dsw-alias-bg-layer-1,#fff);color:var(--inspiration-muted);font:inherit;font-size:11.5px;font-weight:600;cursor:pointer;transition:all .15s ease}.dsh-ig-inspiration-source-chip:hover{border-color:rgba(47,100,245,.46);color:var(--inspiration-blue)}.dsh-ig-inspiration-source-chip.is-active{border-color:var(--inspiration-blue);background:linear-gradient(135deg,#386cf6,#2758e7);color:#fff;box-shadow:0 5px 12px rgba(47,100,245,.22)}
|
|
124213
|
+
.dsh-ig-inspiration-actions .dsh-ig-inspiration-use.is-secondary{grid-column:1/-1;border-color:rgba(47,100,245,.5);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--inspiration-blue);box-shadow:none}.dsh-ig-inspiration-actions .dsh-ig-inspiration-use.is-secondary:hover{color:#2758e7;transform:translateY(-1px)}.dsh-ig-inspiration-actions .dsh-ig-inspiration-use.is-secondary:disabled{opacity:.6;cursor:wait;transform:none}
|
|
121969
124214
|
@media(max-width:980px){.dsh-ig-inspiration-layout{grid-template-columns:1fr}.dsh-ig-inspiration-inspector{position:relative;top:auto}.dsh-ig-inspiration-inspector-empty{min-height:150px}.dsh-ig-inspiration-inspector-image{max-height:290px}.dsh-ig-inspiration-inspector-image img{object-fit:contain;background:#f1f4fa}}@media(max-width:700px){.dsh-ig-inspiration{padding:14px}.dsh-ig-inspiration-head{align-items:center}.dsh-ig-inspiration-toolbar{grid-template-columns:1fr 1fr}.dsh-ig-inspiration-search{grid-column:1/-1}.dsh-ig-inspiration-fav-filter{grid-column:1/-1}.dsh-ig-inspiration-grid{grid-template-columns:repeat(auto-fill,minmax(145px,1fr));gap:9px}}@media(max-width:420px){.dsh-ig-inspiration-toolbar{grid-template-columns:1fr}.dsh-ig-inspiration-search{grid-column:auto}}
|
|
124215
|
+
|
|
124216
|
+
.dsh-ig-inspiration-source-chip svg{flex-shrink:0}
|
|
124217
|
+
.dsh-ig-baoyu-panel{border:1px solid var(--inspiration-line);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#fff);padding:18px;display:flex;flex-direction:column;gap:14px}
|
|
124218
|
+
.dsh-ig-baoyu-intro{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
|
|
124219
|
+
.dsh-ig-baoyu-combos{font-size:12px;color:var(--inspiration-blue)}
|
|
124220
|
+
.dsh-ig-baoyu-hint{font-size:11px;color:var(--inspiration-muted)}
|
|
124221
|
+
.dsh-ig-baoyu-dim{display:flex;flex-direction:column;gap:7px}
|
|
124222
|
+
.dsh-ig-baoyu-dim-head{font-size:11px;font-weight:650;color:var(--inspiration-muted);letter-spacing:.02em}
|
|
124223
|
+
.dsh-ig-baoyu-chips{display:flex;flex-wrap:wrap;gap:6px}
|
|
124224
|
+
.dsh-ig-baoyu-chip{height:28px;padding:0 10px;display:inline-flex;align-items:center;gap:6px;border:1px solid var(--inspiration-line);border-radius:999px;background:var(--dsw-alias-bg-layer-1,#fff);color:#536075;font:inherit;font-size:11px;font-weight:600;cursor:pointer;transition:all .15s ease}
|
|
124225
|
+
.dsh-ig-baoyu-chip:hover{border-color:rgba(47,100,245,.46);color:var(--inspiration-blue)}
|
|
124226
|
+
.dsh-ig-baoyu-chip.is-active{border-color:var(--inspiration-blue);background:rgba(47,100,245,.09);color:var(--inspiration-blue)}
|
|
124227
|
+
.dsh-ig-baoyu-swatch{display:inline-flex;gap:2px}
|
|
124228
|
+
.dsh-ig-baoyu-swatch i{width:9px;height:9px;border-radius:50%;border:1px solid rgba(15,23,42,.15);display:block}
|
|
124229
|
+
.dsh-ig-baoyu-title-input{height:34px;flex:1;padding:0 11px;border:1px solid var(--inspiration-line);border-radius:7px;background:var(--dsw-alias-bg-layer-1,#fff);color:inherit;font:inherit;font-size:12px}
|
|
124230
|
+
.dsh-ig-baoyu-title-input:focus{outline:none;border-color:rgba(47,100,245,.55)}
|
|
124231
|
+
.dsh-ig-baoyu-title-input:disabled{opacity:.45}
|
|
124232
|
+
.dsh-ig-baoyu-required{color:#dc2626;font-size:11px}
|
|
124233
|
+
.dsh-ig-baoyu-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
124234
|
+
.dsh-ig-baoyu-btn{height:34px;padding:0 14px;display:inline-flex;align-items:center;gap:6px;border:1px solid var(--inspiration-line);border-radius:7px;background:var(--dsw-alias-bg-layer-1,#fff);color:#536075;font:inherit;font-size:11.5px;font-weight:600;cursor:pointer;transition:all .15s ease}
|
|
124235
|
+
.dsh-ig-baoyu-btn:hover{border-color:rgba(47,100,245,.46);color:var(--inspiration-blue)}
|
|
124236
|
+
.dsh-ig-baoyu-btn:disabled{opacity:.5;cursor:not-allowed}
|
|
124237
|
+
.dsh-ig-baoyu-btn.is-primary{border-color:var(--inspiration-blue);background:linear-gradient(135deg,#386cf6,#2758e7);color:#fff;box-shadow:0 7px 15px rgba(47,100,245,.2)}
|
|
124238
|
+
.dsh-ig-baoyu-btn.is-primary:hover{color:#fff;transform:translateY(-1px)}
|
|
124239
|
+
.dsh-ig-baoyu-btn.is-primary:disabled{opacity:.5;cursor:not-allowed;transform:none}
|
|
124240
|
+
.dsh-ig-baoyu-preview-block{display:flex;flex-direction:column;gap:6px}
|
|
124241
|
+
.dsh-ig-baoyu-preview-head{font-size:11px;font-weight:650;color:var(--inspiration-muted)}
|
|
124242
|
+
.dsh-ig-baoyu-preview{max-height:260px;margin:0;padding:12px;overflow:auto;white-space:pre-wrap;border:1px solid var(--inspiration-line);border-radius:7px;background:color-mix(in srgb,var(--dsw-alias-bg-layer-2,#f8fafc) 90%,#e9efff);font-size:11px;line-height:1.6;color:#526078}
|
|
121970
124243
|
`;
|
|
121971
124244
|
//#endregion
|
|
121972
124245
|
//#region lib/types/client/conversation-image-revisions.js
|
|
@@ -122038,6 +124311,12 @@ img.ProseMirror-separator {
|
|
|
122038
124311
|
return typeof candidate.attachmentId === "string" && (candidate.mediaType === "image/png" || candidate.mediaType === "image/jpeg" || candidate.mediaType === "image/webp" || candidate.mediaType === "image/gif") && typeof candidate.bytes === "number" && typeof candidate.width === "number" && typeof candidate.height === "number";
|
|
122039
124312
|
}
|
|
122040
124313
|
//#endregion
|
|
124314
|
+
//#region lib/types/client/settings-write.js
|
|
124315
|
+
/** DSH 0.1.7 resolves refused writes to false; older settings scopes resolve to void. */
|
|
124316
|
+
async function writeSetting(scope, field, value, rejectedMessage) {
|
|
124317
|
+
if (await scope.set(field, value) === false) throw new Error(rejectedMessage);
|
|
124318
|
+
}
|
|
124319
|
+
//#endregion
|
|
122041
124320
|
//#region lib/types/client/provider-pill.js
|
|
122042
124321
|
/**
|
|
122043
124322
|
* Composer tool-row pill: switch the default image provider without leaving
|
|
@@ -122058,7 +124337,8 @@ img.ProseMirror-separator {
|
|
|
122058
124337
|
subSignedOut: "未登录",
|
|
122059
124338
|
subStatusUnknown: "状态未知",
|
|
122060
124339
|
readOnly: "图像设置为只读,无法在此切换",
|
|
122061
|
-
switchFailed: "切换失败"
|
|
124340
|
+
switchFailed: "切换失败",
|
|
124341
|
+
writeRejected: "设置未保存,请重试"
|
|
122062
124342
|
},
|
|
122063
124343
|
en: {
|
|
122064
124344
|
pillLabel: "Image",
|
|
@@ -122072,7 +124352,8 @@ img.ProseMirror-separator {
|
|
|
122072
124352
|
subSignedOut: "Signed out",
|
|
122073
124353
|
subStatusUnknown: "Unknown",
|
|
122074
124354
|
readOnly: "Image settings are read-only; switch them in the config source",
|
|
122075
|
-
switchFailed: "Switch failed"
|
|
124355
|
+
switchFailed: "Switch failed",
|
|
124356
|
+
writeRejected: "Setting was not saved. Please try again"
|
|
122076
124357
|
}
|
|
122077
124358
|
};
|
|
122078
124359
|
/** Provider row names, per locale. Brand words stay untranslated; only the
|
|
@@ -122280,7 +124561,7 @@ img.ProseMirror-separator {
|
|
|
122280
124561
|
}
|
|
122281
124562
|
setError("");
|
|
122282
124563
|
setPending(provider);
|
|
122283
|
-
props.scope
|
|
124564
|
+
writeSetting(props.scope, "provider", provider, t("writeRejected")).then(() => {
|
|
122284
124565
|
setOpen(false);
|
|
122285
124566
|
}).catch((cause) => {
|
|
122286
124567
|
setError(cause instanceof Error ? cause.message : String(cause));
|
|
@@ -122473,7 +124754,7 @@ img.ProseMirror-separator {
|
|
|
122473
124754
|
`;
|
|
122474
124755
|
//#endregion
|
|
122475
124756
|
//#region lib/types/client/index.js
|
|
122476
|
-
console.info(`[dsh-image-gen] canvas bundle 2026-09-
|
|
124757
|
+
console.info(`[dsh-image-gen] canvas bundle 2026-09-28T16:41:08.496Z`);
|
|
122477
124758
|
/** Right-sidebar tab-type registration id (DSH 0.1.5 `sidebarRightTabs`). */
|
|
122478
124759
|
const SIDEBAR_STUDIO_TAB_ID = "dsh-image-gen/studio";
|
|
122479
124760
|
/** The tab kind: a page type opened by kind, recognizing no resource address. */
|
|
@@ -122545,7 +124826,8 @@ img.ProseMirror-separator {
|
|
|
122545
124826
|
editFormat: "图生图请求形态",
|
|
122546
124827
|
editFormatMultipart: "标准 multipart(OpenAI 官方)",
|
|
122547
124828
|
editFormatJsonImageUrlArray: "JSON images 数组(商汤等中转)",
|
|
122548
|
-
|
|
124829
|
+
editFormatFormReferenceImages: "multipart + reference_images JSON 数组(base64)",
|
|
124830
|
+
editFormatHint: "文生图不受影响。仅当中转站的图生图接口使用自有契约(如商汤 SenseNova 的 JSON images 数组,或要求 reference_images base64 数组的中转)时才需要切换。",
|
|
122549
124831
|
editExtra: "附加 JSON 字段",
|
|
122550
124832
|
editExtraPlaceholder: "{\"watermark\": false, \"prompt_extend\": true}",
|
|
122551
124833
|
editExtraHint: "仅 JSON 形态生效;会合并到请求体末尾,可覆盖默认字段。留空表示不附加。",
|
|
@@ -122598,6 +124880,7 @@ img.ProseMirror-separator {
|
|
|
122598
124880
|
saving: "保存中…",
|
|
122599
124881
|
save: "保存",
|
|
122600
124882
|
saved: "已保存",
|
|
124883
|
+
settingsWriteRejected: "有一项设置未能保存,请检查后重试。",
|
|
122601
124884
|
savedToPath: "已保存到",
|
|
122602
124885
|
generating: "正在生成图片…",
|
|
122603
124886
|
loading: "正在加载图片…",
|
|
@@ -122688,7 +124971,8 @@ img.ProseMirror-separator {
|
|
|
122688
124971
|
editFormat: "Edit request format",
|
|
122689
124972
|
editFormatMultipart: "Standard multipart (official OpenAI)",
|
|
122690
124973
|
editFormatJsonImageUrlArray: "JSON images array (SenseNova etc.)",
|
|
122691
|
-
|
|
124974
|
+
editFormatFormReferenceImages: "Multipart with a reference_images JSON array (base64)",
|
|
124975
|
+
editFormatHint: "Text-to-image is unaffected. Only switch when the relay runs image edits on its own contract (e.g. SenseNova's JSON images array, or a relay that takes reference_images as a base64 JSON array); size is pinned to \"auto\" in the JSON images format (the only value SenseNova's edits endpoint accepts) and can be overridden via extra fields.",
|
|
122692
124976
|
editExtra: "Extra JSON fields",
|
|
122693
124977
|
editExtraPlaceholder: "{\"watermark\": false, \"prompt_extend\": true}",
|
|
122694
124978
|
editExtraHint: "Only used with the JSON format; merged into the request body last and may override defaults. Leave empty for none.",
|
|
@@ -122741,6 +125025,7 @@ img.ProseMirror-separator {
|
|
|
122741
125025
|
saving: "Saving…",
|
|
122742
125026
|
save: "Save",
|
|
122743
125027
|
saved: "Saved",
|
|
125028
|
+
settingsWriteRejected: "A setting could not be saved. Please check and try again.",
|
|
122744
125029
|
savedToPath: "Saved to",
|
|
122745
125030
|
generating: "Generating image…",
|
|
122746
125031
|
loading: "Loading image…",
|
|
@@ -123057,19 +125342,40 @@ img.ProseMirror-separator {
|
|
|
123057
125342
|
:has(.dsh-ig-gallery-page:not(.dsh-ig-page-in-sidebar)) [class*="widthHandle"],
|
|
123058
125343
|
.root:has(.dsh-ig-gallery-page:not(.dsh-ig-page-in-sidebar)) [class*="widthHandle"]{display:none!important}
|
|
123059
125344
|
`;
|
|
123060
|
-
/**
|
|
125345
|
+
/**
|
|
125346
|
+
* Required browser services. The settings form reader is deliberately absent:
|
|
125347
|
+
* DSH 0.1.7 serves it as `configForms` (keyed by the Loader entry id) while
|
|
125348
|
+
* 0.1.5/0.1.6 expose `settingsScope` (keyed by the legacy namespace), so it is
|
|
125349
|
+
* probed at runtime in `apply`. A static inject of either name would park this
|
|
125350
|
+
* fiber forever on hosts from the other generation — the issue #55 failure.
|
|
125351
|
+
*/
|
|
123061
125352
|
const inject = [
|
|
123062
125353
|
"slots",
|
|
123063
125354
|
"connection",
|
|
123064
125355
|
"remote",
|
|
123065
|
-
"settingsScope",
|
|
123066
125356
|
"locale"
|
|
123067
125357
|
];
|
|
125358
|
+
/** Host with neither settings generation: reads empty, writes refuse, never throws. */
|
|
125359
|
+
function degradedScope() {
|
|
125360
|
+
return {
|
|
125361
|
+
getSnapshot: () => ({
|
|
125362
|
+
value: void 0,
|
|
125363
|
+
writable: false
|
|
125364
|
+
}),
|
|
125365
|
+
subscribe: () => () => {},
|
|
125366
|
+
set: async () => false
|
|
125367
|
+
};
|
|
125368
|
+
}
|
|
123068
125369
|
/** Mount the settings card, generated-image card, and native conversation gallery view. */
|
|
123069
125370
|
function apply(ctx) {
|
|
123070
|
-
const
|
|
123071
|
-
const
|
|
123072
|
-
const
|
|
125371
|
+
const configForms = ctx.get("configForms");
|
|
125372
|
+
const settingsScopeApi = configForms === void 0 ? ctx.get("settingsScope") : void 0;
|
|
125373
|
+
const scope = configForms?.get("image-gen") ?? settingsScopeApi?.bind({ namespace: "image-generation" }) ?? degradedScope();
|
|
125374
|
+
const chatScope = configForms?.get("ui-chat") ?? settingsScopeApi?.bind({ namespace: "ui-chat" }) ?? degradedScope();
|
|
125375
|
+
const isCompactTranscript = () => {
|
|
125376
|
+
const mode = chatScope.getSnapshot().value?.transcriptView;
|
|
125377
|
+
return configForms === void 0 ? mode !== "normal" : mode !== "standard" && mode !== "detailed" && mode !== "verbose";
|
|
125378
|
+
};
|
|
123073
125379
|
const locale = ctx.get("locale");
|
|
123074
125380
|
const promotion = { enabled: false };
|
|
123075
125381
|
ctx.inject(["sessions"], (owner) => {
|
|
@@ -123359,6 +125665,10 @@ img.ProseMirror-separator {
|
|
|
123359
125665
|
return "";
|
|
123360
125666
|
}
|
|
123361
125667
|
}
|
|
125668
|
+
/** Persisted or selected edit-format value → row state; unknown values fall back to standard multipart. */
|
|
125669
|
+
function parseEditFormat(value) {
|
|
125670
|
+
return value === "jsonImageUrlArray" || value === "formReferenceImages" ? value : "multipart";
|
|
125671
|
+
}
|
|
123362
125672
|
/** Build one row per provider from persisted settings, including ComfyUI extras. */
|
|
123363
125673
|
function rowsFromSettings(value) {
|
|
123364
125674
|
const rows = {};
|
|
@@ -123372,7 +125682,7 @@ img.ProseMirror-separator {
|
|
|
123372
125682
|
timeoutSeconds: Math.max(1, Math.round((value?.comfyuiTimeoutMs ?? 3e5) / 1e3))
|
|
123373
125683
|
} : {},
|
|
123374
125684
|
...provider === "openai-compat" ? {
|
|
123375
|
-
editFormat: value?.openaiCompatEditFormat
|
|
125685
|
+
editFormat: parseEditFormat(value?.openaiCompatEditFormat),
|
|
123376
125686
|
editExtraText: editExtraTextOf(value?.openaiCompatEditExtra)
|
|
123377
125687
|
} : {},
|
|
123378
125688
|
...provider === "seedream" ? {
|
|
@@ -123562,6 +125872,7 @@ img.ProseMirror-separator {
|
|
|
123562
125872
|
if (params) for (const [k, v] of Object.entries(params)) text = text.replace(`{${k}}`, v);
|
|
123563
125873
|
return text;
|
|
123564
125874
|
};
|
|
125875
|
+
const saveSetting = (field, value) => writeSetting(props.scope, field, value, t("settingsWriteRejected"));
|
|
123565
125876
|
const providerLabels = {
|
|
123566
125877
|
google: t("providerGoogle"),
|
|
123567
125878
|
openai: t("providerOpenAI"),
|
|
@@ -123673,7 +125984,7 @@ img.ProseMirror-separator {
|
|
|
123673
125984
|
setDefaultProvider(provider);
|
|
123674
125985
|
setProviderMessage("");
|
|
123675
125986
|
setProviderMessageIsError(false);
|
|
123676
|
-
|
|
125987
|
+
saveSetting("provider", provider).catch((cause) => {
|
|
123677
125988
|
setDefaultProvider(snapshot.value?.provider ?? "google");
|
|
123678
125989
|
setProviderMessage(cause instanceof Error ? cause.message : String(cause));
|
|
123679
125990
|
setProviderMessageIsError(true);
|
|
@@ -123699,12 +126010,12 @@ img.ProseMirror-separator {
|
|
|
123699
126010
|
}
|
|
123700
126011
|
if (new Set(entries.map((entry) => entry.name)).size !== entries.length) throw new Error(t("workflowDuplicateName"));
|
|
123701
126012
|
const activeEntry = entries.find((entry) => entry.name === row.activeWorkflow) ?? entries[0];
|
|
123702
|
-
await
|
|
123703
|
-
await
|
|
123704
|
-
await
|
|
123705
|
-
await
|
|
123706
|
-
await
|
|
123707
|
-
await
|
|
126013
|
+
await saveSetting("comfyuiBaseURL", row.baseURL);
|
|
126014
|
+
await saveSetting("comfyuiWorkflows", entries);
|
|
126015
|
+
await saveSetting("comfyuiActiveWorkflow", activeEntry === void 0 ? "" : activeEntry.name);
|
|
126016
|
+
await saveSetting("comfyuiWorkflowJson", activeEntry === void 0 ? "" : activeEntry.json);
|
|
126017
|
+
await saveSetting("comfyuiWorkflowName", activeEntry === void 0 ? "" : activeEntry.name);
|
|
126018
|
+
await saveSetting("comfyuiTimeoutMs", Math.max(1, Math.round(row.timeoutSeconds)) * 1e3);
|
|
123708
126019
|
} else if (isSubscriptionProvider(provider)) await Promise.resolve();
|
|
123709
126020
|
else {
|
|
123710
126021
|
let editExtra = {};
|
|
@@ -123721,16 +126032,16 @@ img.ProseMirror-separator {
|
|
|
123721
126032
|
editExtra = parsed;
|
|
123722
126033
|
}
|
|
123723
126034
|
}
|
|
123724
|
-
await
|
|
123725
|
-
await
|
|
126035
|
+
await saveSetting(modelFieldOf(provider), row.model);
|
|
126036
|
+
await saveSetting(baseURLFieldOf(provider), row.baseURL);
|
|
123726
126037
|
if (provider === "openai-compat") {
|
|
123727
|
-
await
|
|
123728
|
-
await
|
|
126038
|
+
await saveSetting("openaiCompatEditFormat", row.editFormat);
|
|
126039
|
+
await saveSetting("openaiCompatEditExtra", editExtra);
|
|
123729
126040
|
}
|
|
123730
126041
|
if (provider === "seedream") {
|
|
123731
|
-
await
|
|
123732
|
-
await
|
|
123733
|
-
await
|
|
126042
|
+
await saveSetting("seedreamOutputFormat", row.outputFormat);
|
|
126043
|
+
await saveSetting("seedreamWatermark", row.watermark);
|
|
126044
|
+
await saveSetting("seedreamBackground", row.background);
|
|
123734
126045
|
}
|
|
123735
126046
|
if (row.keyInput.trim().length > 0) {
|
|
123736
126047
|
const keyRef = cloudCredentialRef(provider);
|
|
@@ -124021,7 +126332,7 @@ img.ProseMirror-separator {
|
|
|
124021
126332
|
setSaveToWorkspace(next);
|
|
124022
126333
|
setWorkspaceMessage("");
|
|
124023
126334
|
setWorkspaceMessageIsError(false);
|
|
124024
|
-
|
|
126335
|
+
saveSetting("saveToWorkspace", next).catch((cause) => {
|
|
124025
126336
|
setSaveToWorkspace(snapshot.value?.saveToWorkspace ?? true);
|
|
124026
126337
|
setWorkspaceMessage(cause instanceof Error ? cause.message : String(cause));
|
|
124027
126338
|
setWorkspaceMessageIsError(true);
|
|
@@ -124033,7 +126344,7 @@ img.ProseMirror-separator {
|
|
|
124033
126344
|
if (next === (snapshot.value?.workspaceFolder ?? "dsh-image-gen")) return;
|
|
124034
126345
|
setWorkspaceMessage("");
|
|
124035
126346
|
setWorkspaceMessageIsError(false);
|
|
124036
|
-
|
|
126347
|
+
saveSetting("workspaceFolder", next).then(() => {
|
|
124037
126348
|
setWorkspaceMessage(t("saved"));
|
|
124038
126349
|
}).catch((cause) => {
|
|
124039
126350
|
setWorkspaceFolder(snapshot.value?.workspaceFolder ?? "dsh-image-gen");
|
|
@@ -124046,7 +126357,7 @@ img.ProseMirror-separator {
|
|
|
124046
126357
|
setShowPill(next);
|
|
124047
126358
|
setUiMessage("");
|
|
124048
126359
|
setUiMessageIsError(false);
|
|
124049
|
-
|
|
126360
|
+
saveSetting("showProviderPill", next).catch((cause) => {
|
|
124050
126361
|
setShowPill(snapshot.value?.showProviderPill === true);
|
|
124051
126362
|
setUiMessage(cause instanceof Error ? cause.message : String(cause));
|
|
124052
126363
|
setUiMessageIsError(true);
|
|
@@ -124188,16 +126499,23 @@ img.ProseMirror-separator {
|
|
|
124188
126499
|
className: "dsh-ig-input",
|
|
124189
126500
|
value: row.editFormat,
|
|
124190
126501
|
onChange: (event) => {
|
|
124191
|
-
updateRow(provider, { editFormat: event.target.value
|
|
126502
|
+
updateRow(provider, { editFormat: parseEditFormat(event.target.value) });
|
|
124192
126503
|
},
|
|
124193
126504
|
disabled: !snapshot.writable,
|
|
124194
|
-
children: [
|
|
124195
|
-
|
|
124196
|
-
|
|
124197
|
-
|
|
124198
|
-
|
|
124199
|
-
|
|
124200
|
-
|
|
126505
|
+
children: [
|
|
126506
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
126507
|
+
value: "multipart",
|
|
126508
|
+
children: t("editFormatMultipart")
|
|
126509
|
+
}),
|
|
126510
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
126511
|
+
value: "jsonImageUrlArray",
|
|
126512
|
+
children: t("editFormatJsonImageUrlArray")
|
|
126513
|
+
}),
|
|
126514
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
126515
|
+
value: "formReferenceImages",
|
|
126516
|
+
children: t("editFormatFormReferenceImages")
|
|
126517
|
+
})
|
|
126518
|
+
]
|
|
124201
126519
|
}),
|
|
124202
126520
|
(0, react_jsx_runtime.jsx)("span", {
|
|
124203
126521
|
className: "dsh-ig-hint",
|
|
@@ -125353,7 +127671,6 @@ img.ProseMirror-separator {
|
|
|
125353
127671
|
(0, react_jsx_runtime.jsxs)("label", { children: [(0, react_jsx_runtime.jsx)("span", { children: t("prompt") }), (0, react_jsx_runtime.jsx)("textarea", {
|
|
125354
127672
|
ref: regenerateTextareaRef,
|
|
125355
127673
|
value: regeneratePrompt,
|
|
125356
|
-
maxLength: 2e3,
|
|
125357
127674
|
disabled: isRegenerating,
|
|
125358
127675
|
onChange: (event) => setRegeneratePrompt(event.target.value),
|
|
125359
127676
|
onKeyDown: (event) => {
|