dsh-image-gen 0.7.0 → 0.8.5
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/README.en.md +418 -397
- package/README.md +418 -397
- package/README.zh-CN.md +3 -3
- package/lib/client.js +2931 -577
- package/lib/index.js +7701 -303
- package/lib/types/baoyu-compose.d.ts +61 -0
- package/lib/types/capabilities.d.ts +42 -0
- package/lib/types/client/gallery-store.d.ts +40 -1
- package/lib/types/client/gallery-view.d.ts +12 -0
- package/lib/types/client/image-result-node.d.ts +9 -17
- package/lib/types/client/index.d.ts +3 -1
- 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/multi-model-compare.d.ts +3 -1
- 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/tl-brand-theme.d.ts +7 -0
- package/lib/types/config.d.ts +21 -8
- 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 +20 -2
- package/lib/types/shared.d.ts +2 -0
- package/lib/types/studio-route.d.ts +2 -0
- package/lib/types/studio.d.ts +24 -0
- package/lib/types/subscription/manager.d.ts +2 -1
- package/lib/types/subscription/vendors/antigravity.d.ts +2 -2
- package/lib/types/subscription.d.ts +11 -1
- package/lib/types/xai-params.d.ts +5 -0
- package/package.json +139 -142
- package/skills/install-dsh-image-gen/SKILL.md +22 -22
- package/lib/client.js.map +0 -1
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. */
|
|
@@ -215,7 +217,7 @@ window.__ModuleLoader__.load({
|
|
|
215
217
|
const DEFAULT_SUBSCRIPTION_MODELS = {
|
|
216
218
|
"chatgpt-sub": "gpt-image-2.5-flare",
|
|
217
219
|
"grok-sub": "grok-imagine-image-2.0",
|
|
218
|
-
"google-sub": "gemini-3-
|
|
220
|
+
"google-sub": "gemini-3.1-flash-image"
|
|
219
221
|
};
|
|
220
222
|
const DEFAULT_MODELS = {
|
|
221
223
|
google: DEFAULT_GOOGLE_MODEL,
|
|
@@ -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",
|
|
@@ -1706,6 +1978,49 @@ window.__ModuleLoader__.load({
|
|
|
1706
1978
|
const active = configured.find((profile) => profile.provider === activeProvider);
|
|
1707
1979
|
return (active === void 0 ? configured : [active, ...configured.filter((profile) => profile.provider !== activeProvider)]).slice(0, 2).map((profile) => profile.provider);
|
|
1708
1980
|
}
|
|
1981
|
+
const RATIO_SORT_ORDER = [
|
|
1982
|
+
"auto",
|
|
1983
|
+
"1:1",
|
|
1984
|
+
"3:2",
|
|
1985
|
+
"2:3",
|
|
1986
|
+
"4:3",
|
|
1987
|
+
"3:4",
|
|
1988
|
+
"4:5",
|
|
1989
|
+
"5:4",
|
|
1990
|
+
"16:9",
|
|
1991
|
+
"9:16",
|
|
1992
|
+
"21:9"
|
|
1993
|
+
];
|
|
1994
|
+
const QUALITY_SORT_ORDER = [
|
|
1995
|
+
"auto",
|
|
1996
|
+
"standard",
|
|
1997
|
+
"1k",
|
|
1998
|
+
"1K",
|
|
1999
|
+
"2k",
|
|
2000
|
+
"2K",
|
|
2001
|
+
"3K",
|
|
2002
|
+
"4K",
|
|
2003
|
+
"low",
|
|
2004
|
+
"medium",
|
|
2005
|
+
"high",
|
|
2006
|
+
"xhigh",
|
|
2007
|
+
"max",
|
|
2008
|
+
"hd"
|
|
2009
|
+
];
|
|
2010
|
+
/** Union of every configured profile's options, for the shared comparison pickers. */
|
|
2011
|
+
function comparisonOptionUnion(profiles, key) {
|
|
2012
|
+
const sortOrder = key === "ratioOptions" ? RATIO_SORT_ORDER : QUALITY_SORT_ORDER;
|
|
2013
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2014
|
+
for (const profile of profiles) {
|
|
2015
|
+
if (!profile.configured) continue;
|
|
2016
|
+
for (const option of profile[key]) if (!seen.has(option.value)) seen.set(option.value, option);
|
|
2017
|
+
}
|
|
2018
|
+
const rank = (value) => {
|
|
2019
|
+
const index = sortOrder.indexOf(value);
|
|
2020
|
+
return index === -1 ? sortOrder.length : index;
|
|
2021
|
+
};
|
|
2022
|
+
return [...seen.values()].sort((a, b) => rank(a.value) - rank(b.value));
|
|
2023
|
+
}
|
|
1709
2024
|
//#endregion
|
|
1710
2025
|
//#region node_modules/.pnpm/@tldraw+utils@5.3.0/node_modules/@tldraw/utils/dist-esm/lib/version.mjs
|
|
1711
2026
|
const TLDRAW_LIBRARY_VERSION_KEY = "__TLDRAW_LIBRARY_VERSIONS__";
|
|
@@ -115760,6 +116075,24 @@ img.ProseMirror-separator {
|
|
|
115760
116075
|
}
|
|
115761
116076
|
});
|
|
115762
116077
|
}
|
|
116078
|
+
/**
|
|
116079
|
+
* Match tldraw's light/dark canvas to the DSH host theme. The host publishes
|
|
116080
|
+
* dark mode as the data-ds-dark-theme attribute on <body>; tldraw keeps its
|
|
116081
|
+
* own persisted user preference, so apply the host value now and observe
|
|
116082
|
+
* later flips. Returns the observer disposer.
|
|
116083
|
+
*/
|
|
116084
|
+
function syncTldrawThemeWithHost(editor) {
|
|
116085
|
+
const apply = () => {
|
|
116086
|
+
editor.user.updateUserPreferences({ colorScheme: document.body.hasAttribute("data-ds-dark-theme") ? "dark" : "light" });
|
|
116087
|
+
};
|
|
116088
|
+
apply();
|
|
116089
|
+
const observer = new MutationObserver(apply);
|
|
116090
|
+
observer.observe(document.body, {
|
|
116091
|
+
attributes: true,
|
|
116092
|
+
attributeFilter: ["data-ds-dark-theme"]
|
|
116093
|
+
});
|
|
116094
|
+
return () => observer.disconnect();
|
|
116095
|
+
}
|
|
115763
116096
|
//#endregion
|
|
115764
116097
|
//#region lib/types/client/tl/canvas-selection.js
|
|
115765
116098
|
/** Bound raster dimensions before exporting; large multi-image PNGs get a
|
|
@@ -116425,6 +116758,7 @@ img.ProseMirror-separator {
|
|
|
116425
116758
|
editor.run(() => editor.selectNone());
|
|
116426
116759
|
mountedEditors.add(editor);
|
|
116427
116760
|
applyBrandTheme(editor);
|
|
116761
|
+
const stopThemeSync = syncTldrawThemeWithHost(editor);
|
|
116428
116762
|
editor.updateInstanceState({ isGridMode: true });
|
|
116429
116763
|
console.info(`[dsh-image-gen] tldraw mounted (instance ${editor.id})`);
|
|
116430
116764
|
const stopLanding = registerTlLandingConsumer((items) => {
|
|
@@ -116460,6 +116794,7 @@ img.ProseMirror-separator {
|
|
|
116460
116794
|
mountedEditors.delete(editor);
|
|
116461
116795
|
mountedCanvases.delete(clear);
|
|
116462
116796
|
stopLanding();
|
|
116797
|
+
stopThemeSync();
|
|
116463
116798
|
stopSync();
|
|
116464
116799
|
retrySync.current = () => {};
|
|
116465
116800
|
};
|
|
@@ -116504,6 +116839,31 @@ img.ProseMirror-separator {
|
|
|
116504
116839
|
unconfigured: "未配置",
|
|
116505
116840
|
recent: "最近生成",
|
|
116506
116841
|
empty: "暂无生成历史",
|
|
116842
|
+
railTabRecent: "最新生成",
|
|
116843
|
+
railTabFavorites: "收藏",
|
|
116844
|
+
favImages: "收藏图片",
|
|
116845
|
+
favPrompts: "收藏提示词",
|
|
116846
|
+
favNewFolder: "新建文件夹",
|
|
116847
|
+
favFolderPlaceholder: "文件夹名称",
|
|
116848
|
+
favCreate: "创建",
|
|
116849
|
+
favCancel: "取消",
|
|
116850
|
+
favMoveTo: "移动到文件夹",
|
|
116851
|
+
favNoFolder: "未分组",
|
|
116852
|
+
favMove: "移动",
|
|
116853
|
+
favDeleteFolder: "删除文件夹",
|
|
116854
|
+
favEditPrompt: "编辑提示词",
|
|
116855
|
+
favUse: "使用",
|
|
116856
|
+
favSave: "保存",
|
|
116857
|
+
favEditPromptPlaceholder: "输入提示词内容…",
|
|
116858
|
+
favFolder: "所属文件夹",
|
|
116859
|
+
favEmptyImages: "在图片操作区点「收藏」后,图片会显示在这里",
|
|
116860
|
+
favEmptyPrompts: "点提示词输入框旁的「☆ 收藏」后,提示词会显示在这里",
|
|
116861
|
+
favoritePrompt: "收藏提示词",
|
|
116862
|
+
favActionShort: "收藏",
|
|
116863
|
+
favPromptSaved: "已收藏提示词",
|
|
116864
|
+
favPromptApplied: "已填入提示词",
|
|
116865
|
+
favRefApplied: "已加入参考图",
|
|
116866
|
+
favSaveFailed: "收藏失败,请重试",
|
|
116507
116867
|
generate: "文生图",
|
|
116508
116868
|
edit: "图生图",
|
|
116509
116869
|
reference: "参考图",
|
|
@@ -116517,6 +116877,8 @@ img.ProseMirror-separator {
|
|
|
116517
116877
|
model: "Model",
|
|
116518
116878
|
ratio: "比例",
|
|
116519
116879
|
quality: "清晰度",
|
|
116880
|
+
subscriptionParameterHint: "所选比例会自动补充到生成提示词中;实际尺寸和清晰度仍由 ChatGPT 决定,请以生成结果为准。",
|
|
116881
|
+
subscriptionRatioMismatch: "ChatGPT 订阅未按所选比例出图,请查看实际尺寸。",
|
|
116520
116882
|
start: "开始生成",
|
|
116521
116883
|
generating: "正在生成…",
|
|
116522
116884
|
cancelGenerate: "取消生成",
|
|
@@ -116560,6 +116922,8 @@ img.ProseMirror-separator {
|
|
|
116560
116922
|
infiniteCanvas: "无限画布",
|
|
116561
116923
|
loading: "正在读取图片…",
|
|
116562
116924
|
generationFailed: "生成失败",
|
|
116925
|
+
gatewayTimeout: "请求被反向代理中断(超时):请重试;反复出现需调大代理超时或换直连网络",
|
|
116926
|
+
requestFailed: "请求失败(HTTP {status})",
|
|
116563
116927
|
selectHistory: "从左侧选择一张图片,或在右侧开始新的生成。",
|
|
116564
116928
|
created: "生成时间",
|
|
116565
116929
|
elapsed: "耗时",
|
|
@@ -116567,6 +116931,7 @@ img.ProseMirror-separator {
|
|
|
116567
116931
|
output: "输出参数",
|
|
116568
116932
|
closeReference: "移除参考图",
|
|
116569
116933
|
uploadInvalid: "请选择有效的图片文件(最大 10MB)",
|
|
116934
|
+
uploadUnreadable: "部分图片读取失败,请重新选择后再试",
|
|
116570
116935
|
imageLoadFailed: "图片读取失败",
|
|
116571
116936
|
fullscreen: "大图全屏",
|
|
116572
116937
|
close: "关闭",
|
|
@@ -116613,6 +116978,31 @@ img.ProseMirror-separator {
|
|
|
116613
116978
|
unconfigured: "Not configured",
|
|
116614
116979
|
recent: "Recent generations",
|
|
116615
116980
|
empty: "No generated images yet",
|
|
116981
|
+
railTabRecent: "Latest",
|
|
116982
|
+
railTabFavorites: "Favorites",
|
|
116983
|
+
favImages: "Favorite images",
|
|
116984
|
+
favPrompts: "Favorite prompts",
|
|
116985
|
+
favNewFolder: "New folder",
|
|
116986
|
+
favFolderPlaceholder: "Folder name",
|
|
116987
|
+
favCreate: "Create",
|
|
116988
|
+
favCancel: "Cancel",
|
|
116989
|
+
favMoveTo: "Move to folder",
|
|
116990
|
+
favNoFolder: "Unfiled",
|
|
116991
|
+
favMove: "Move",
|
|
116992
|
+
favDeleteFolder: "Delete folder",
|
|
116993
|
+
favEditPrompt: "Edit prompt",
|
|
116994
|
+
favUse: "Use",
|
|
116995
|
+
favSave: "Save",
|
|
116996
|
+
favEditPromptPlaceholder: "Prompt text…",
|
|
116997
|
+
favFolder: "Folder",
|
|
116998
|
+
favEmptyImages: "Click Favorite on an image; favorited images appear here",
|
|
116999
|
+
favEmptyPrompts: "Click ☆ Save beside the prompt box",
|
|
117000
|
+
favoritePrompt: "Save prompt",
|
|
117001
|
+
favActionShort: "Save",
|
|
117002
|
+
favPromptSaved: "Prompt saved",
|
|
117003
|
+
favPromptApplied: "Prompt applied",
|
|
117004
|
+
favRefApplied: "Reference added",
|
|
117005
|
+
favSaveFailed: "Could not save; please retry",
|
|
116616
117006
|
generate: "Text to image",
|
|
116617
117007
|
edit: "Image to image",
|
|
116618
117008
|
reference: "Reference image",
|
|
@@ -116626,6 +117016,8 @@ img.ProseMirror-separator {
|
|
|
116626
117016
|
model: "Model",
|
|
116627
117017
|
ratio: "Aspect ratio",
|
|
116628
117018
|
quality: "Quality",
|
|
117019
|
+
subscriptionParameterHint: "The selected aspect ratio is automatically added to the generation prompt. ChatGPT still determines the final dimensions and quality; check the generated result.",
|
|
117020
|
+
subscriptionRatioMismatch: "ChatGPT subscription returned a different aspect ratio. Check the actual dimensions.",
|
|
116629
117021
|
start: "Generate",
|
|
116630
117022
|
generating: "Generating…",
|
|
116631
117023
|
cancelGenerate: "Cancel",
|
|
@@ -116669,6 +117061,8 @@ img.ProseMirror-separator {
|
|
|
116669
117061
|
infiniteCanvas: "Infinite canvas",
|
|
116670
117062
|
loading: "Loading image…",
|
|
116671
117063
|
generationFailed: "Generation failed",
|
|
117064
|
+
gatewayTimeout: "The reverse proxy cut the request (timeout): retry; if it repeats, raise the proxy timeout or use a direct network.",
|
|
117065
|
+
requestFailed: "Request failed (HTTP {status})",
|
|
116672
117066
|
selectHistory: "Select an image on the left, or start a new generation on the right.",
|
|
116673
117067
|
created: "Created",
|
|
116674
117068
|
elapsed: "Elapsed",
|
|
@@ -116676,6 +117070,7 @@ img.ProseMirror-separator {
|
|
|
116676
117070
|
output: "Output",
|
|
116677
117071
|
closeReference: "Remove reference",
|
|
116678
117072
|
uploadInvalid: "Choose a valid image file up to 10MB.",
|
|
117073
|
+
uploadUnreadable: "Some images could not be read; pick them again.",
|
|
116679
117074
|
imageLoadFailed: "Could not load image",
|
|
116680
117075
|
fullscreen: "Fullscreen",
|
|
116681
117076
|
close: "Close",
|
|
@@ -116719,17 +117114,28 @@ img.ProseMirror-separator {
|
|
|
116719
117114
|
};
|
|
116720
117115
|
/** localStorage flag remembering that the one-time infinite-canvas hint was dismissed. */
|
|
116721
117116
|
const INFINITE_CANVAS_HINT_KEY = "dsh-ig-infinite-canvas-hint-dismissed";
|
|
116722
|
-
const StudioView = ({ locale, credentialEvents, workspace, initialPrompt, initialCanvasSurface, showInfiniteCanvasHint, onInitialPromptApplied, onOpenInspiration }) => {
|
|
117117
|
+
const StudioView = ({ locale, credentialEvents, workspace, initialPrompt, initialReference, initialCanvasSurface, showInfiniteCanvasHint, onInitialPromptApplied, onInitialReferenceApplied, onOpenInspiration }) => {
|
|
116723
117118
|
const [lang, setLang] = (0, react.useState)(() => locale?.getSnapshot?.().active?.startsWith("en") ? "en" : "zh");
|
|
116724
117119
|
const [config, setConfig] = (0, react.useState)(null);
|
|
116725
117120
|
const [configLoading, setConfigLoading] = (0, react.useState)(true);
|
|
116726
117121
|
const [configError, setConfigError] = (0, react.useState)(null);
|
|
116727
117122
|
const [items, setItems] = (0, react.useState)([]);
|
|
117123
|
+
/** Which rail tab is showing: generation history or the favorites rail. */
|
|
117124
|
+
const [railTab, setRailTab] = (0, react.useState)("recent");
|
|
117125
|
+
const [favPrompts, setFavPrompts] = (0, react.useState)([]);
|
|
117126
|
+
const [favFolders, setFavFolders] = (0, react.useState)([]);
|
|
117127
|
+
const [activePromptFolder, setActivePromptFolder] = (0, react.useState)("");
|
|
117128
|
+
const [folderDraft, setFolderDraft] = (0, react.useState)(null);
|
|
117129
|
+
const [folderDraftName, setFolderDraftName] = (0, react.useState)("");
|
|
117130
|
+
const [editingPrompt, setEditingPrompt] = (0, react.useState)(null);
|
|
117131
|
+
const [editPromptText, setEditPromptText] = (0, react.useState)("");
|
|
117132
|
+
const [editPromptFolder, setEditPromptFolder] = (0, react.useState)("");
|
|
117133
|
+
const [movingFav, setMovingFav] = (0, react.useState)(null);
|
|
116728
117134
|
const [sidebarCollapsed, setSidebarCollapsed] = (0, react.useState)(false);
|
|
116729
117135
|
/** Manual-only collapse for the right generate form; the form stays put in
|
|
116730
117136
|
* narrow seats because it is the primary generation surface. Starts folded
|
|
116731
117137
|
* when the studio opens straight into the infinite canvas. */
|
|
116732
|
-
const [generateCollapsed, setGenerateCollapsed] = (0, react.useState)(initialCanvasSurface === "infinite");
|
|
117138
|
+
const [generateCollapsed, setGenerateCollapsed] = (0, react.useState)(initialCanvasSurface === "infinite" && initialPrompt === void 0);
|
|
116733
117139
|
/** Workbench root, observed so a narrow column (right sidebar) can fold the recent rail. */
|
|
116734
117140
|
const workbenchRootRef = (0, react.useRef)(null);
|
|
116735
117141
|
/** Set once the user toggles the rail by hand; auto-folding then stands down for this mount. */
|
|
@@ -116826,13 +117232,20 @@ img.ProseMirror-separator {
|
|
|
116826
117232
|
const maxReferences = comparisonEnabled ? comparisonProviders.includes("dashscope") ? 3 : 5 : provider === "dashscope" ? 3 : 5;
|
|
116827
117233
|
const referencesRef = (0, react.useRef)(references);
|
|
116828
117234
|
referencesRef.current = references;
|
|
116829
|
-
const comparisonSelectionsAllSubscription = comparisonEnabled && comparisonProviders.length > 0 && comparisonProviders.every((provider) => isSubscriptionProvider(provider));
|
|
116830
|
-
const singleProviderIsSubscription = !comparisonEnabled && isSubscriptionProvider(provider);
|
|
116831
117235
|
const t = (key, values) => {
|
|
116832
117236
|
let text = COPY$1[lang][key];
|
|
116833
117237
|
for (const [name, value] of Object.entries(values ?? {})) text = text.replace(`{${name}}`, value);
|
|
116834
117238
|
return text;
|
|
116835
117239
|
};
|
|
117240
|
+
/** Parse a studio response body; a gateway HTML error page (502/504 from a
|
|
117241
|
+
* reverse proxy) must surface as a readable message, not a JSON SyntaxError. */
|
|
117242
|
+
const readStudioBody = async (response) => {
|
|
117243
|
+
try {
|
|
117244
|
+
return await response.json();
|
|
117245
|
+
} catch {
|
|
117246
|
+
return { error: response.status === 502 || response.status === 504 ? t("gatewayTimeout") : t("requestFailed", { status: String(response.status) }) };
|
|
117247
|
+
}
|
|
117248
|
+
};
|
|
116836
117249
|
(0, react.useEffect)(() => locale?.subscribe?.(() => setLang(locale.getSnapshot().active?.startsWith("en") ? "en" : "zh")), [locale]);
|
|
116837
117250
|
const formStateRef = (0, react.useRef)({
|
|
116838
117251
|
provider,
|
|
@@ -116854,7 +117267,7 @@ img.ProseMirror-separator {
|
|
|
116854
117267
|
signal: controller.signal,
|
|
116855
117268
|
credentials: "same-origin"
|
|
116856
117269
|
});
|
|
116857
|
-
const payload = await response
|
|
117270
|
+
const payload = await readStudioBody(response);
|
|
116858
117271
|
if (!response.ok || !("providers" in payload)) throw new Error("error" in payload && payload.error ? payload.error : "Studio unavailable");
|
|
116859
117272
|
setConfig(payload);
|
|
116860
117273
|
if (silent) {
|
|
@@ -116900,6 +117313,20 @@ img.ProseMirror-separator {
|
|
|
116900
117313
|
unsubscribe();
|
|
116901
117314
|
};
|
|
116902
117315
|
}, []);
|
|
117316
|
+
(0, react.useEffect)(() => {
|
|
117317
|
+
let mounted = true;
|
|
117318
|
+
const load = () => void Promise.all([getFavoritePrompts(), getFavoriteFolders()]).then(([prompts, folders]) => {
|
|
117319
|
+
if (!mounted) return;
|
|
117320
|
+
setFavPrompts(prompts);
|
|
117321
|
+
setFavFolders(folders);
|
|
117322
|
+
});
|
|
117323
|
+
load();
|
|
117324
|
+
const unsubscribe = subscribeFavorites(load);
|
|
117325
|
+
return () => {
|
|
117326
|
+
mounted = false;
|
|
117327
|
+
unsubscribe();
|
|
117328
|
+
};
|
|
117329
|
+
}, []);
|
|
116903
117330
|
(0, react.useEffect)(() => {
|
|
116904
117331
|
return () => {
|
|
116905
117332
|
requestRef.current?.abort();
|
|
@@ -116967,6 +117394,8 @@ img.ProseMirror-separator {
|
|
|
116967
117394
|
ratio,
|
|
116968
117395
|
quality
|
|
116969
117396
|
]);
|
|
117397
|
+
const comparisonRatioOpts = (0, react.useMemo)(() => localizeRatioOptions(comparisonOptionUnion(comparisonProfiles, "ratioOptions"), lang), [comparisonProfiles, lang]);
|
|
117398
|
+
const comparisonQualityOpts = (0, react.useMemo)(() => localizeQualityOptions(comparisonOptionUnion(comparisonProfiles, "qualityOptions"), lang), [comparisonProfiles, lang]);
|
|
116970
117399
|
const applyProvider = (profile) => {
|
|
116971
117400
|
setProvider(profile.provider);
|
|
116972
117401
|
setModel(profile.model);
|
|
@@ -117024,7 +117453,65 @@ img.ProseMirror-separator {
|
|
|
117024
117453
|
};
|
|
117025
117454
|
};
|
|
117026
117455
|
const handleImageClick = () => {};
|
|
117027
|
-
|
|
117456
|
+
/** Keep the current prompt text in the favorites rail. */
|
|
117457
|
+
const handleFavoritePrompt = async () => {
|
|
117458
|
+
if (prompt.trim().length === 0) {
|
|
117459
|
+
setError(t("needPrompt"));
|
|
117460
|
+
return;
|
|
117461
|
+
}
|
|
117462
|
+
if (await saveFavoritePrompt(prompt)) {
|
|
117463
|
+
railToggledByUserRef.current = true;
|
|
117464
|
+
setSidebarCollapsed(false);
|
|
117465
|
+
setRailTab("favorites");
|
|
117466
|
+
flash(t("favPromptSaved"));
|
|
117467
|
+
} else setError(t("favSaveFailed"));
|
|
117468
|
+
};
|
|
117469
|
+
/** Turn one favorited gallery image back into a live reference (edit mode). */
|
|
117470
|
+
const applyFavoriteImage = async (item) => {
|
|
117471
|
+
const max = maxReferences;
|
|
117472
|
+
if (referencesRef.current.length >= max) {
|
|
117473
|
+
setError(t("maxReferencesExceeded", { max: String(max) }));
|
|
117474
|
+
return;
|
|
117475
|
+
}
|
|
117476
|
+
try {
|
|
117477
|
+
const blob = await fetchAttachmentBlob(item.attachment);
|
|
117478
|
+
const newItem = {
|
|
117479
|
+
id: `fav-${item.id}-${Date.now()}`,
|
|
117480
|
+
attachment: item.attachment,
|
|
117481
|
+
previewUrl: URL.createObjectURL(blob)
|
|
117482
|
+
};
|
|
117483
|
+
const next = [...referencesRef.current, newItem];
|
|
117484
|
+
setReferences(next);
|
|
117485
|
+
referencesRef.current = next;
|
|
117486
|
+
setMode("edit");
|
|
117487
|
+
setError(null);
|
|
117488
|
+
flash(t("favRefApplied"));
|
|
117489
|
+
} catch {
|
|
117490
|
+
setError(t("imageLoadFailed"));
|
|
117491
|
+
}
|
|
117492
|
+
};
|
|
117493
|
+
const createFavFolder = async () => {
|
|
117494
|
+
if (await addFavoriteFolder("prompt", folderDraftName) === null) {
|
|
117495
|
+
flash(t("favSaveFailed"));
|
|
117496
|
+
return;
|
|
117497
|
+
}
|
|
117498
|
+
setFolderDraft(null);
|
|
117499
|
+
setFolderDraftName("");
|
|
117500
|
+
};
|
|
117501
|
+
const openPromptEditor = (fav) => {
|
|
117502
|
+
setEditingPrompt(fav);
|
|
117503
|
+
setEditPromptText(fav.text);
|
|
117504
|
+
setEditPromptFolder(fav.folderId ?? "");
|
|
117505
|
+
};
|
|
117506
|
+
const doMoveFavorite = (folderId) => {
|
|
117507
|
+
if (movingFav === null) return;
|
|
117508
|
+
moveFavoritePrompt(movingFav.id, folderId);
|
|
117509
|
+
};
|
|
117510
|
+
const applyFavoritePrompt = (fav) => {
|
|
117511
|
+
setPrompt(fav.text);
|
|
117512
|
+
flash(t("favPromptApplied"));
|
|
117513
|
+
};
|
|
117514
|
+
const addReferenceFiles = async (fileList) => {
|
|
117028
117515
|
if (!fileList || fileList.length === 0) return;
|
|
117029
117516
|
const files = Array.from(fileList);
|
|
117030
117517
|
const validFiles = [];
|
|
@@ -117050,13 +117537,31 @@ img.ProseMirror-separator {
|
|
|
117050
117537
|
const toAdd = validFiles.slice(0, available);
|
|
117051
117538
|
if (validFiles.length > available) setError(t("maxReferencesExceeded", { max: String(maxReferences) }));
|
|
117052
117539
|
else setError(null);
|
|
117053
|
-
const
|
|
117540
|
+
const snapshotted = [];
|
|
117541
|
+
for (const file of toAdd) try {
|
|
117542
|
+
const bytes = await file.arrayBuffer();
|
|
117543
|
+
snapshotted.push(new File([bytes], file.name, {
|
|
117544
|
+
type: file.type,
|
|
117545
|
+
lastModified: file.lastModified
|
|
117546
|
+
}));
|
|
117547
|
+
} catch {
|
|
117548
|
+
setError(t("uploadUnreadable"));
|
|
117549
|
+
}
|
|
117550
|
+
const newItems = snapshotted.map((file, idx) => ({
|
|
117054
117551
|
id: `upload-${Date.now()}-${idx}-${Math.random().toString(36).slice(2, 7)}`,
|
|
117055
117552
|
file,
|
|
117056
117553
|
previewUrl: URL.createObjectURL(file)
|
|
117057
117554
|
}));
|
|
117058
117555
|
setReferences((prev) => [...prev, ...newItems]);
|
|
117059
117556
|
};
|
|
117557
|
+
const appliedReferenceRef = (0, react.useRef)(null);
|
|
117558
|
+
(0, react.useEffect)(() => {
|
|
117559
|
+
if (initialReference === void 0 || appliedReferenceRef.current === initialReference) return;
|
|
117560
|
+
appliedReferenceRef.current = initialReference;
|
|
117561
|
+
addReferenceFiles([initialReference]);
|
|
117562
|
+
setMode("edit");
|
|
117563
|
+
onInitialReferenceApplied?.();
|
|
117564
|
+
}, [initialReference, onInitialReferenceApplied]);
|
|
117060
117565
|
const removeReference = (id) => {
|
|
117061
117566
|
const target = referencesRef.current.find((item) => item.id === id);
|
|
117062
117567
|
if (target && target.previewUrl.startsWith("blob:")) URL.revokeObjectURL(target.previewUrl);
|
|
@@ -117188,7 +117693,7 @@ img.ProseMirror-separator {
|
|
|
117188
117693
|
...referencesPayload === void 0 ? {} : { references: referencesPayload }
|
|
117189
117694
|
})
|
|
117190
117695
|
});
|
|
117191
|
-
const payload = await response
|
|
117696
|
+
const payload = await readStudioBody(response);
|
|
117192
117697
|
if (!response.ok || !("attachment" in payload)) throw new Error("error" in payload && payload.error ? payload.error : `${target.profile.label}: ${t("generationFailed")}`);
|
|
117193
117698
|
return {
|
|
117194
117699
|
payload,
|
|
@@ -117232,6 +117737,7 @@ img.ProseMirror-separator {
|
|
|
117232
117737
|
success: String(successes.length),
|
|
117233
117738
|
failed: String(failed)
|
|
117234
117739
|
}));
|
|
117740
|
+
else if (galleryEntries.some(hasSubscriptionRatioMismatch)) flash(t("subscriptionRatioMismatch"));
|
|
117235
117741
|
return;
|
|
117236
117742
|
}
|
|
117237
117743
|
const response = await fetch(STUDIO_ROUTE, {
|
|
@@ -117251,7 +117757,7 @@ img.ProseMirror-separator {
|
|
|
117251
117757
|
...referencesPayload === void 0 ? {} : { references: referencesPayload }
|
|
117252
117758
|
})
|
|
117253
117759
|
});
|
|
117254
|
-
const payload = await response
|
|
117760
|
+
const payload = await readStudioBody(response);
|
|
117255
117761
|
if (!response.ok || !("attachment" in payload)) throw new Error("error" in payload && payload.error ? payload.error : t("generationFailed"));
|
|
117256
117762
|
const generatedList = Array.isArray(payload.items) && payload.items.length > 0 ? payload.items : [{
|
|
117257
117763
|
attachment: payload.attachment,
|
|
@@ -117295,6 +117801,7 @@ img.ProseMirror-separator {
|
|
|
117295
117801
|
success: String(generatedList.length),
|
|
117296
117802
|
failed: String(payload.failedCount)
|
|
117297
117803
|
}));
|
|
117804
|
+
else if (galleryEntries.some(hasSubscriptionRatioMismatch)) flash(t("subscriptionRatioMismatch"));
|
|
117298
117805
|
} catch (submitError) {
|
|
117299
117806
|
if (controller.signal.aborted) return;
|
|
117300
117807
|
setError(messageOf(submitError));
|
|
@@ -117323,8 +117830,8 @@ img.ProseMirror-separator {
|
|
|
117323
117830
|
selected,
|
|
117324
117831
|
selectedBatchItems
|
|
117325
117832
|
]);
|
|
117326
|
-
const saveButtonLabel = currentBatch !== null ? pendingGalleryItems.length > 0 ? t("saveSelected", { count: String(pendingGalleryItems.length) }) : selectedBatchItems.length === 0 ? t("saveSelected", { count: "0" }) : t("inGallery") :
|
|
117327
|
-
const saveSelectionComplete = currentBatch === null ?
|
|
117833
|
+
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");
|
|
117834
|
+
const saveSelectionComplete = currentBatch === null ? pendingGalleryItems.length === 0 : selectedBatchItems.length > 0 && pendingGalleryItems.length === 0;
|
|
117328
117835
|
const saveGalleryEntry = async (item) => {
|
|
117329
117836
|
let savedTo = item.savedTo;
|
|
117330
117837
|
const targetRoot = workspace?.path || config?.workspaceRoot;
|
|
@@ -117504,44 +118011,272 @@ img.ProseMirror-separator {
|
|
|
117504
118011
|
children: [
|
|
117505
118012
|
!sidebarCollapsed && (0, react_jsx_runtime.jsxs)("aside", {
|
|
117506
118013
|
className: "dsh-ig-recent-panel",
|
|
117507
|
-
children: [
|
|
117508
|
-
|
|
117509
|
-
|
|
117510
|
-
|
|
117511
|
-
|
|
117512
|
-
|
|
117513
|
-
|
|
117514
|
-
|
|
117515
|
-
|
|
117516
|
-
|
|
117517
|
-
|
|
118014
|
+
children: [
|
|
118015
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118016
|
+
className: "dsh-ig-panel-title",
|
|
118017
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
118018
|
+
style: {
|
|
118019
|
+
display: "flex",
|
|
118020
|
+
alignItems: "center",
|
|
118021
|
+
gap: "8px"
|
|
118022
|
+
},
|
|
118023
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: railTab === "recent" ? t("recent") : t("railTabFavorites") }), (0, react_jsx_runtime.jsx)("span", {
|
|
118024
|
+
className: "dsh-ig-count-badge",
|
|
118025
|
+
children: railTab === "recent" ? items.length : items.filter((item) => item.isFavorite).length + favPrompts.length
|
|
118026
|
+
})]
|
|
118027
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
118028
|
+
type: "button",
|
|
118029
|
+
className: "dsh-ig-collapse-btn",
|
|
118030
|
+
onClick: () => {
|
|
118031
|
+
railToggledByUserRef.current = true;
|
|
118032
|
+
setSidebarCollapsed(true);
|
|
118033
|
+
},
|
|
118034
|
+
title: t("collapseSidebar"),
|
|
118035
|
+
children: (0, react_jsx_runtime.jsx)(PanelLeftClose, { size: 15 })
|
|
117518
118036
|
})]
|
|
117519
|
-
}),
|
|
117520
|
-
|
|
117521
|
-
className: "dsh-ig-
|
|
117522
|
-
|
|
117523
|
-
|
|
117524
|
-
|
|
117525
|
-
|
|
117526
|
-
|
|
117527
|
-
|
|
117528
|
-
|
|
117529
|
-
|
|
117530
|
-
|
|
117531
|
-
|
|
117532
|
-
|
|
117533
|
-
|
|
117534
|
-
|
|
117535
|
-
|
|
117536
|
-
|
|
117537
|
-
|
|
117538
|
-
}
|
|
117539
|
-
|
|
117540
|
-
className: "dsh-ig-
|
|
117541
|
-
|
|
117542
|
-
|
|
117543
|
-
|
|
117544
|
-
|
|
118037
|
+
}),
|
|
118038
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118039
|
+
className: "dsh-ig-rail-tabs",
|
|
118040
|
+
role: "tablist",
|
|
118041
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
118042
|
+
type: "button",
|
|
118043
|
+
role: "tab",
|
|
118044
|
+
"aria-selected": railTab === "recent",
|
|
118045
|
+
className: `dsh-ig-rail-tab ${railTab === "recent" ? "is-active" : ""}`,
|
|
118046
|
+
onClick: () => setRailTab("recent"),
|
|
118047
|
+
children: t("railTabRecent")
|
|
118048
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
118049
|
+
type: "button",
|
|
118050
|
+
role: "tab",
|
|
118051
|
+
"aria-selected": railTab === "favorites",
|
|
118052
|
+
className: `dsh-ig-rail-tab ${railTab === "favorites" ? "is-active" : ""}`,
|
|
118053
|
+
onClick: () => setRailTab("favorites"),
|
|
118054
|
+
children: t("railTabFavorites")
|
|
118055
|
+
})]
|
|
118056
|
+
}),
|
|
118057
|
+
railTab === "recent" ? (0, react_jsx_runtime.jsxs)("div", {
|
|
118058
|
+
className: "dsh-ig-recent-scroll",
|
|
118059
|
+
children: [items.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
118060
|
+
className: "dsh-ig-recent-empty",
|
|
118061
|
+
children: [(0, react_jsx_runtime.jsx)(ImagePlus, { size: 22 }), (0, react_jsx_runtime.jsx)("span", { children: t("empty") })]
|
|
118062
|
+
}) : displayItems.map((item) => (0, react_jsx_runtime.jsx)(RecentItem, {
|
|
118063
|
+
item,
|
|
118064
|
+
active: selected?.id === item.id,
|
|
118065
|
+
onClick: () => selectItem(item)
|
|
118066
|
+
}, item.id)), items.length > visibleLimit && (0, react_jsx_runtime.jsx)("button", {
|
|
118067
|
+
type: "button",
|
|
118068
|
+
className: "dsh-ig-load-more",
|
|
118069
|
+
onClick: () => setVisibleLimit((l) => l + 30),
|
|
118070
|
+
children: t("loadMore", { n: String(items.length - visibleLimit) })
|
|
118071
|
+
})]
|
|
118072
|
+
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
118073
|
+
className: "dsh-ig-fav-scroll",
|
|
118074
|
+
children: [
|
|
118075
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
118076
|
+
className: "dsh-ig-fav-section-label",
|
|
118077
|
+
children: (0, react_jsx_runtime.jsx)("span", { children: t("favImages") })
|
|
118078
|
+
}),
|
|
118079
|
+
(() => {
|
|
118080
|
+
const list = items.filter((item) => item.isFavorite);
|
|
118081
|
+
if (list.length === 0) return (0, react_jsx_runtime.jsxs)("div", {
|
|
118082
|
+
className: "dsh-ig-fav-empty",
|
|
118083
|
+
children: [(0, react_jsx_runtime.jsx)(ImagePlus, { size: 18 }), (0, react_jsx_runtime.jsx)("span", { children: t("favEmptyImages") })]
|
|
118084
|
+
});
|
|
118085
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
118086
|
+
className: "dsh-ig-fav-grid",
|
|
118087
|
+
children: list.map((item) => (0, react_jsx_runtime.jsx)(RecentItem, {
|
|
118088
|
+
item,
|
|
118089
|
+
active: false,
|
|
118090
|
+
onClick: () => void applyFavoriteImage(item)
|
|
118091
|
+
}, item.id))
|
|
118092
|
+
});
|
|
118093
|
+
})(),
|
|
118094
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118095
|
+
className: "dsh-ig-fav-section-label",
|
|
118096
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("favPrompts") }), (0, react_jsx_runtime.jsx)("button", {
|
|
118097
|
+
type: "button",
|
|
118098
|
+
className: "dsh-ig-fav-folder-add",
|
|
118099
|
+
onClick: () => {
|
|
118100
|
+
setFolderDraft({ kind: "prompt" });
|
|
118101
|
+
setFolderDraftName("");
|
|
118102
|
+
},
|
|
118103
|
+
title: t("favNewFolder"),
|
|
118104
|
+
children: "+"
|
|
118105
|
+
})]
|
|
118106
|
+
}),
|
|
118107
|
+
(0, react_jsx_runtime.jsx)(FavoriteFolderBar, {
|
|
118108
|
+
folders: favFolders.filter((folder) => folder.kind === "prompt"),
|
|
118109
|
+
active: activePromptFolder,
|
|
118110
|
+
onSelect: (id) => setActivePromptFolder(id === activePromptFolder ? "" : id),
|
|
118111
|
+
onDelete: (id) => void deleteFavoriteFolder(id),
|
|
118112
|
+
deleteLabel: t("favDeleteFolder")
|
|
118113
|
+
}),
|
|
118114
|
+
folderDraft?.kind === "prompt" && (0, react_jsx_runtime.jsxs)("div", {
|
|
118115
|
+
className: "dsh-ig-fav-folder-draft",
|
|
118116
|
+
children: [
|
|
118117
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
118118
|
+
value: folderDraftName,
|
|
118119
|
+
placeholder: t("favFolderPlaceholder"),
|
|
118120
|
+
onChange: (e) => setFolderDraftName(e.target.value),
|
|
118121
|
+
onKeyDown: (e) => {
|
|
118122
|
+
if (e.key === "Enter") createFavFolder();
|
|
118123
|
+
}
|
|
118124
|
+
}),
|
|
118125
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118126
|
+
type: "button",
|
|
118127
|
+
onClick: () => void createFavFolder(),
|
|
118128
|
+
children: t("favCreate")
|
|
118129
|
+
}),
|
|
118130
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118131
|
+
type: "button",
|
|
118132
|
+
onClick: () => setFolderDraft(null),
|
|
118133
|
+
children: t("favCancel")
|
|
118134
|
+
})
|
|
118135
|
+
]
|
|
118136
|
+
}),
|
|
118137
|
+
(() => {
|
|
118138
|
+
const list = favPrompts.filter((fav) => activePromptFolder === "" || fav.folderId === activePromptFolder);
|
|
118139
|
+
if (list.length === 0) return (0, react_jsx_runtime.jsxs)("div", {
|
|
118140
|
+
className: "dsh-ig-fav-empty",
|
|
118141
|
+
children: [(0, react_jsx_runtime.jsx)(PencilLine, { size: 18 }), (0, react_jsx_runtime.jsx)("span", { children: t("favEmptyPrompts") })]
|
|
118142
|
+
});
|
|
118143
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
118144
|
+
className: "dsh-ig-fav-prompts",
|
|
118145
|
+
children: list.map((fav) => (0, react_jsx_runtime.jsxs)("div", {
|
|
118146
|
+
className: "dsh-ig-fav-prompt",
|
|
118147
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
118148
|
+
type: "button",
|
|
118149
|
+
className: "dsh-ig-fav-prompt-text",
|
|
118150
|
+
title: fav.text,
|
|
118151
|
+
onClick: () => openPromptEditor(fav),
|
|
118152
|
+
children: fav.text
|
|
118153
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
118154
|
+
type: "button",
|
|
118155
|
+
className: "dsh-ig-fav-del",
|
|
118156
|
+
title: t("remove"),
|
|
118157
|
+
onClick: () => void deleteFavoritePrompt(fav.id),
|
|
118158
|
+
children: (0, react_jsx_runtime.jsx)(X, { size: 11 })
|
|
118159
|
+
})]
|
|
118160
|
+
}, fav.id))
|
|
118161
|
+
});
|
|
118162
|
+
})()
|
|
118163
|
+
]
|
|
118164
|
+
})
|
|
118165
|
+
]
|
|
118166
|
+
}),
|
|
118167
|
+
(editingPrompt !== null || movingFav !== null) && (0, react_jsx_runtime.jsx)("div", {
|
|
118168
|
+
className: "dsh-ig-fav-dialog-wrap",
|
|
118169
|
+
onClick: () => {
|
|
118170
|
+
setEditingPrompt(null);
|
|
118171
|
+
setMovingFav(null);
|
|
118172
|
+
},
|
|
118173
|
+
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
118174
|
+
className: "dsh-ig-fav-dialog",
|
|
118175
|
+
onClick: (e) => e.stopPropagation(),
|
|
118176
|
+
children: [editingPrompt !== null && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
118177
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
118178
|
+
className: "dsh-ig-fav-dialog-title",
|
|
118179
|
+
children: t("favEditPrompt")
|
|
118180
|
+
}),
|
|
118181
|
+
(0, react_jsx_runtime.jsx)("textarea", {
|
|
118182
|
+
className: "dsh-ig-fav-dialog-textarea",
|
|
118183
|
+
value: editPromptText,
|
|
118184
|
+
placeholder: t("favEditPromptPlaceholder"),
|
|
118185
|
+
onChange: (e) => setEditPromptText(e.target.value),
|
|
118186
|
+
rows: 5
|
|
118187
|
+
}),
|
|
118188
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
118189
|
+
className: "dsh-ig-fav-dialog-folder-label",
|
|
118190
|
+
children: [t("favFolder"), (0, react_jsx_runtime.jsxs)("select", {
|
|
118191
|
+
value: editPromptFolder,
|
|
118192
|
+
onChange: (e) => setEditPromptFolder(e.target.value),
|
|
118193
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
118194
|
+
value: "",
|
|
118195
|
+
children: t("favNoFolder")
|
|
118196
|
+
}), favFolders.filter((folder) => folder.kind === "prompt").map((folder) => (0, react_jsx_runtime.jsx)("option", {
|
|
118197
|
+
value: folder.id,
|
|
118198
|
+
children: folder.name
|
|
118199
|
+
}, folder.id))]
|
|
118200
|
+
})]
|
|
118201
|
+
}),
|
|
118202
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118203
|
+
className: "dsh-ig-fav-dialog-actions",
|
|
118204
|
+
children: [
|
|
118205
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118206
|
+
type: "button",
|
|
118207
|
+
className: "is-primary",
|
|
118208
|
+
onClick: () => {
|
|
118209
|
+
updateFavoritePrompt(editingPrompt.id, editPromptText).then((ok) => {
|
|
118210
|
+
if (ok) moveFavoritePrompt(editingPrompt.id, editPromptFolder === "" ? void 0 : editPromptFolder);
|
|
118211
|
+
});
|
|
118212
|
+
setEditingPrompt(null);
|
|
118213
|
+
},
|
|
118214
|
+
children: t("favSave")
|
|
118215
|
+
}),
|
|
118216
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118217
|
+
type: "button",
|
|
118218
|
+
onClick: () => {
|
|
118219
|
+
applyFavoritePrompt({
|
|
118220
|
+
...editingPrompt,
|
|
118221
|
+
text: editPromptText
|
|
118222
|
+
});
|
|
118223
|
+
setEditingPrompt(null);
|
|
118224
|
+
},
|
|
118225
|
+
children: t("favUse")
|
|
118226
|
+
}),
|
|
118227
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118228
|
+
type: "button",
|
|
118229
|
+
onClick: () => {
|
|
118230
|
+
setMovingFav({
|
|
118231
|
+
kind: "prompt",
|
|
118232
|
+
id: editingPrompt.id,
|
|
118233
|
+
folderId: editingPrompt.folderId
|
|
118234
|
+
});
|
|
118235
|
+
setEditingPrompt(null);
|
|
118236
|
+
},
|
|
118237
|
+
children: t("favMove")
|
|
118238
|
+
}),
|
|
118239
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118240
|
+
type: "button",
|
|
118241
|
+
onClick: () => setEditingPrompt(null),
|
|
118242
|
+
children: t("favCancel")
|
|
118243
|
+
})
|
|
118244
|
+
]
|
|
118245
|
+
})
|
|
118246
|
+
] }), editingPrompt === null && movingFav !== null && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
118247
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
118248
|
+
className: "dsh-ig-fav-dialog-title",
|
|
118249
|
+
children: t("favMoveTo")
|
|
118250
|
+
}),
|
|
118251
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118252
|
+
className: "dsh-ig-fav-dialog-folders",
|
|
118253
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
118254
|
+
type: "button",
|
|
118255
|
+
onClick: () => {
|
|
118256
|
+
doMoveFavorite(void 0);
|
|
118257
|
+
setMovingFav(null);
|
|
118258
|
+
},
|
|
118259
|
+
children: t("favNoFolder")
|
|
118260
|
+
}), favFolders.filter((folder) => folder.kind === movingFav.kind).map((folder) => (0, react_jsx_runtime.jsx)("button", {
|
|
118261
|
+
type: "button",
|
|
118262
|
+
className: movingFav.folderId === folder.id ? "is-current" : "",
|
|
118263
|
+
onClick: () => {
|
|
118264
|
+
doMoveFavorite(folder.id);
|
|
118265
|
+
setMovingFav(null);
|
|
118266
|
+
},
|
|
118267
|
+
children: folder.name
|
|
118268
|
+
}, folder.id))]
|
|
118269
|
+
}),
|
|
118270
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
118271
|
+
className: "dsh-ig-fav-dialog-actions",
|
|
118272
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
118273
|
+
type: "button",
|
|
118274
|
+
onClick: () => setMovingFav(null),
|
|
118275
|
+
children: t("favCancel")
|
|
118276
|
+
})
|
|
118277
|
+
})
|
|
118278
|
+
] })]
|
|
118279
|
+
})
|
|
117545
118280
|
}),
|
|
117546
118281
|
(0, react_jsx_runtime.jsxs)("main", {
|
|
117547
118282
|
className: "dsh-ig-canvas-column",
|
|
@@ -117819,7 +118554,8 @@ img.ProseMirror-separator {
|
|
|
117819
118554
|
(0, react_jsx_runtime.jsx)("span", { children: formatRelativeTime$1(selected.createdAt, lang) }),
|
|
117820
118555
|
(0, react_jsx_runtime.jsx)("span", { children: selected.provider }),
|
|
117821
118556
|
(0, react_jsx_runtime.jsx)("span", { children: selected.model }),
|
|
117822
|
-
(0, react_jsx_runtime.jsx)("span", { children: selected.attachment.width && selected.attachment.height ? `${selected.attachment.width} × ${selected.attachment.height}` : "—" })
|
|
118557
|
+
(0, react_jsx_runtime.jsx)("span", { children: selected.provider === "chatgpt-sub" ? selected.output : selected.attachment.width && selected.attachment.height ? `${selected.attachment.width} × ${selected.attachment.height}` : "—" }),
|
|
118558
|
+
hasSubscriptionRatioMismatch(selected) && (0, react_jsx_runtime.jsx)("span", { children: t("subscriptionRatioMismatch") })
|
|
117823
118559
|
]
|
|
117824
118560
|
})
|
|
117825
118561
|
] })
|
|
@@ -117938,21 +118674,30 @@ img.ProseMirror-separator {
|
|
|
117938
118674
|
" ",
|
|
117939
118675
|
(0, react_jsx_runtime.jsx)("b", { children: "*" })
|
|
117940
118676
|
]
|
|
117941
|
-
}), (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
117942
|
-
|
|
117943
|
-
|
|
117944
|
-
|
|
117945
|
-
|
|
117946
|
-
|
|
117947
|
-
|
|
117948
|
-
|
|
117949
|
-
|
|
117950
|
-
|
|
118677
|
+
}), (0, react_jsx_runtime.jsxs)("span", { children: [
|
|
118678
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
118679
|
+
type: "button",
|
|
118680
|
+
className: "dsh-ig-find-inspiration",
|
|
118681
|
+
onClick: onOpenInspiration,
|
|
118682
|
+
children: [(0, react_jsx_runtime.jsx)(Sparkles, { size: 11 }), t("findInspiration")]
|
|
118683
|
+
}),
|
|
118684
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
118685
|
+
type: "button",
|
|
118686
|
+
className: "dsh-ig-fav-save-btn",
|
|
118687
|
+
onClick: () => void handleFavoritePrompt(),
|
|
118688
|
+
title: t("favoritePrompt"),
|
|
118689
|
+
children: [(0, react_jsx_runtime.jsx)(Star, { size: 12 }), t("favActionShort")]
|
|
118690
|
+
}),
|
|
118691
|
+
(0, react_jsx_runtime.jsx)("button", {
|
|
118692
|
+
type: "button",
|
|
118693
|
+
onClick: () => setPrompt(""),
|
|
118694
|
+
children: t("clear")
|
|
118695
|
+
})
|
|
118696
|
+
] })]
|
|
117951
118697
|
}),
|
|
117952
118698
|
(0, react_jsx_runtime.jsx)("textarea", {
|
|
117953
118699
|
id: "dsh-ig-prompt",
|
|
117954
118700
|
value: prompt,
|
|
117955
|
-
maxLength: 2e3,
|
|
117956
118701
|
onChange: (event) => setPrompt(event.target.value),
|
|
117957
118702
|
onKeyDown: (event) => {
|
|
117958
118703
|
if (event.nativeEvent.isComposing) return;
|
|
@@ -117963,7 +118708,7 @@ img.ProseMirror-separator {
|
|
|
117963
118708
|
},
|
|
117964
118709
|
placeholder: t("promptPlaceholder")
|
|
117965
118710
|
}),
|
|
117966
|
-
(0, react_jsx_runtime.
|
|
118711
|
+
(0, react_jsx_runtime.jsx)("small", { children: prompt.length })
|
|
117967
118712
|
]
|
|
117968
118713
|
}),
|
|
117969
118714
|
config === null ? configLoading ? (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -117994,82 +118739,70 @@ img.ProseMirror-separator {
|
|
|
117994
118739
|
onClick: () => toggleComparison(true),
|
|
117995
118740
|
children: [(0, react_jsx_runtime.jsx)(Copy, { size: 13 }), t("compareModels")]
|
|
117996
118741
|
})]
|
|
117997
|
-
}), comparisonEnabled ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
117998
|
-
|
|
117999
|
-
|
|
118000
|
-
|
|
118001
|
-
|
|
118002
|
-
|
|
118003
|
-
|
|
118004
|
-
|
|
118005
|
-
|
|
118006
|
-
|
|
118007
|
-
|
|
118008
|
-
|
|
118009
|
-
|
|
118010
|
-
|
|
118011
|
-
|
|
118012
|
-
|
|
118013
|
-
|
|
118014
|
-
|
|
118015
|
-
|
|
118016
|
-
|
|
118017
|
-
|
|
118018
|
-
|
|
118019
|
-
|
|
118020
|
-
|
|
118021
|
-
|
|
118022
|
-
|
|
118023
|
-
|
|
118024
|
-
|
|
118025
|
-
|
|
118026
|
-
|
|
118027
|
-
|
|
118028
|
-
|
|
118029
|
-
|
|
118030
|
-
|
|
118031
|
-
|
|
118032
|
-
|
|
118033
|
-
|
|
118034
|
-
|
|
118035
|
-
|
|
118036
|
-
|
|
118037
|
-
|
|
118038
|
-
|
|
118039
|
-
|
|
118040
|
-
|
|
118041
|
-
|
|
118042
|
-
|
|
118043
|
-
|
|
118044
|
-
|
|
118045
|
-
|
|
118046
|
-
|
|
118047
|
-
|
|
118048
|
-
|
|
118049
|
-
}
|
|
118050
|
-
|
|
118051
|
-
|
|
118052
|
-
|
|
118053
|
-
|
|
118054
|
-
|
|
118055
|
-
|
|
118056
|
-
|
|
118057
|
-
|
|
118058
|
-
|
|
118059
|
-
|
|
118060
|
-
|
|
118061
|
-
children: [(0, react_jsx_runtime.jsx)(FieldSelect, {
|
|
118062
|
-
label: t("ratio"),
|
|
118063
|
-
value: ratio,
|
|
118064
|
-
onChange: setRatio,
|
|
118065
|
-
options: comparisonRatioOptions(lang)
|
|
118066
|
-
}), (0, react_jsx_runtime.jsx)(FieldSelect, {
|
|
118067
|
-
label: t("quality"),
|
|
118068
|
-
value: quality,
|
|
118069
|
-
onChange: setQuality,
|
|
118070
|
-
options: comparisonQualityOptions(lang)
|
|
118071
|
-
})]
|
|
118072
|
-
})] }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
118742
|
+
}), comparisonEnabled ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
118743
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118744
|
+
className: "dsh-ig-compare-box",
|
|
118745
|
+
children: [
|
|
118746
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118747
|
+
className: "dsh-ig-compare-heading",
|
|
118748
|
+
children: [(0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)("strong", { children: t("compareSelect") }), (0, react_jsx_runtime.jsx)("small", { children: t("compareHint") })] }), (0, react_jsx_runtime.jsx)("span", { children: t("compareSelected", { count: String(comparisonTargets.length) }) })]
|
|
118749
|
+
}),
|
|
118750
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
118751
|
+
className: "dsh-ig-model-checks",
|
|
118752
|
+
children: comparisonProfiles.map((item) => {
|
|
118753
|
+
const target = comparisonTargets.find((candidate) => candidate.profile.provider === item.provider);
|
|
118754
|
+
return (0, react_jsx_runtime.jsxs)("button", {
|
|
118755
|
+
type: "button",
|
|
118756
|
+
className: target ? "is-selected" : "",
|
|
118757
|
+
"aria-pressed": Boolean(target),
|
|
118758
|
+
onClick: () => toggleComparisonProvider(item.provider),
|
|
118759
|
+
children: [
|
|
118760
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
118761
|
+
className: "dsh-ig-model-checkmark",
|
|
118762
|
+
children: target ? (0, react_jsx_runtime.jsx)(Check, { size: 12 }) : null
|
|
118763
|
+
}),
|
|
118764
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
118765
|
+
className: "dsh-ig-model-copy",
|
|
118766
|
+
children: [(0, react_jsx_runtime.jsx)("strong", { children: item.label }), (0, react_jsx_runtime.jsx)("small", {
|
|
118767
|
+
title: item.model,
|
|
118768
|
+
children: item.model
|
|
118769
|
+
})]
|
|
118770
|
+
}),
|
|
118771
|
+
target && (0, react_jsx_runtime.jsxs)("span", {
|
|
118772
|
+
className: "dsh-ig-model-settings",
|
|
118773
|
+
children: [
|
|
118774
|
+
target.ratio,
|
|
118775
|
+
" · ",
|
|
118776
|
+
target.quality,
|
|
118777
|
+
target.adjusted ? (0, react_jsx_runtime.jsx)("em", { children: t("compareAdjusted") }) : null
|
|
118778
|
+
]
|
|
118779
|
+
})
|
|
118780
|
+
]
|
|
118781
|
+
}, item.provider);
|
|
118782
|
+
})
|
|
118783
|
+
}),
|
|
118784
|
+
(0, react_jsx_runtime.jsx)("p", { children: t("compareParameterHint") })
|
|
118785
|
+
]
|
|
118786
|
+
}),
|
|
118787
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118788
|
+
className: "dsh-ig-field-grid",
|
|
118789
|
+
children: [(0, react_jsx_runtime.jsx)(FieldSelect, {
|
|
118790
|
+
label: t("ratio"),
|
|
118791
|
+
value: ratio,
|
|
118792
|
+
onChange: setRatio,
|
|
118793
|
+
options: comparisonRatioOpts
|
|
118794
|
+
}), (0, react_jsx_runtime.jsx)(FieldSelect, {
|
|
118795
|
+
label: t("quality"),
|
|
118796
|
+
value: quality,
|
|
118797
|
+
onChange: setQuality,
|
|
118798
|
+
options: comparisonQualityOpts
|
|
118799
|
+
})]
|
|
118800
|
+
}),
|
|
118801
|
+
comparisonTargets.some((target) => target.profile.provider === "chatgpt-sub") && (0, react_jsx_runtime.jsx)("div", {
|
|
118802
|
+
className: "dsh-ig-inline-note",
|
|
118803
|
+
children: t("subscriptionParameterHint")
|
|
118804
|
+
})
|
|
118805
|
+
] }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
118073
118806
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
118074
118807
|
className: "dsh-ig-field-grid",
|
|
118075
118808
|
children: [(0, react_jsx_runtime.jsx)(FieldSelect, {
|
|
@@ -118090,26 +118823,7 @@ img.ProseMirror-separator {
|
|
|
118090
118823
|
}]
|
|
118091
118824
|
})]
|
|
118092
118825
|
}),
|
|
118093
|
-
|
|
118094
|
-
className: "dsh-ig-field-grid",
|
|
118095
|
-
children: [(0, react_jsx_runtime.jsx)(FieldSelect, {
|
|
118096
|
-
label: t("ratio"),
|
|
118097
|
-
value: "auto",
|
|
118098
|
-
onChange: () => {},
|
|
118099
|
-
options: [{
|
|
118100
|
-
value: "auto",
|
|
118101
|
-
label: lang === "en" ? "Channel default" : "通道默认"
|
|
118102
|
-
}]
|
|
118103
|
-
}), (0, react_jsx_runtime.jsx)(FieldSelect, {
|
|
118104
|
-
label: t("quality"),
|
|
118105
|
-
value: "auto",
|
|
118106
|
-
onChange: () => {},
|
|
118107
|
-
options: [{
|
|
118108
|
-
value: "auto",
|
|
118109
|
-
label: lang === "en" ? "Channel default" : "通道默认"
|
|
118110
|
-
}]
|
|
118111
|
-
})]
|
|
118112
|
-
}) : (0, react_jsx_runtime.jsxs)("div", {
|
|
118826
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
118113
118827
|
className: "dsh-ig-field-grid",
|
|
118114
118828
|
children: [(0, react_jsx_runtime.jsx)(FieldSelect, {
|
|
118115
118829
|
label: t("ratio"),
|
|
@@ -118123,6 +118837,10 @@ img.ProseMirror-separator {
|
|
|
118123
118837
|
options: localizeQualityOptions(activeProfile?.qualityOptions ?? [], lang)
|
|
118124
118838
|
})]
|
|
118125
118839
|
}),
|
|
118840
|
+
provider === "chatgpt-sub" && (0, react_jsx_runtime.jsx)("div", {
|
|
118841
|
+
className: "dsh-ig-inline-note",
|
|
118842
|
+
children: t("subscriptionParameterHint")
|
|
118843
|
+
}),
|
|
118126
118844
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
118127
118845
|
className: "dsh-ig-field",
|
|
118128
118846
|
children: [(0, react_jsx_runtime.jsx)("label", { children: t("count") }), (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -118438,6 +119156,15 @@ img.ProseMirror-separator {
|
|
|
118438
119156
|
]
|
|
118439
119157
|
});
|
|
118440
119158
|
};
|
|
119159
|
+
function hasSubscriptionRatioMismatch(item) {
|
|
119160
|
+
if (item.provider !== "chatgpt-sub" || item.aspectRatio === "auto") return false;
|
|
119161
|
+
const width = item.attachment.width;
|
|
119162
|
+
const height = item.attachment.height;
|
|
119163
|
+
if (width === void 0 || height === void 0 || width <= 0 || height <= 0) return false;
|
|
119164
|
+
const parts = item.aspectRatio?.split(":").map(Number);
|
|
119165
|
+
if (parts === void 0 || parts.length !== 2 || !(parts[0] > 0) || !(parts[1] > 0)) return false;
|
|
119166
|
+
return Math.abs(width / height / (parts[0] / parts[1]) - 1) > .12;
|
|
119167
|
+
}
|
|
118441
119168
|
const FieldSelect = ({ label, value, options, onChange }) => (0, react_jsx_runtime.jsxs)("label", {
|
|
118442
119169
|
className: "dsh-ig-field-select",
|
|
118443
119170
|
children: [(0, react_jsx_runtime.jsx)("span", { children: label }), (0, react_jsx_runtime.jsx)("select", {
|
|
@@ -118474,6 +119201,14 @@ img.ProseMirror-separator {
|
|
|
118474
119201
|
zh: "3:4 竖向",
|
|
118475
119202
|
en: "3:4 Portrait"
|
|
118476
119203
|
},
|
|
119204
|
+
"4:5": {
|
|
119205
|
+
zh: "4:5 肖像",
|
|
119206
|
+
en: "4:5 Portrait"
|
|
119207
|
+
},
|
|
119208
|
+
"5:4": {
|
|
119209
|
+
zh: "5:4 横向",
|
|
119210
|
+
en: "5:4 Landscape"
|
|
119211
|
+
},
|
|
118477
119212
|
"16:9": {
|
|
118478
119213
|
zh: "16:9 宽屏",
|
|
118479
119214
|
en: "16:9 Widescreen"
|
|
@@ -118481,6 +119216,10 @@ img.ProseMirror-separator {
|
|
|
118481
119216
|
"9:16": {
|
|
118482
119217
|
zh: "9:16 竖屏",
|
|
118483
119218
|
en: "9:16 Portrait"
|
|
119219
|
+
},
|
|
119220
|
+
"21:9": {
|
|
119221
|
+
zh: "21:9 超宽",
|
|
119222
|
+
en: "21:9 Ultrawide"
|
|
118484
119223
|
}
|
|
118485
119224
|
};
|
|
118486
119225
|
const LOCALIZED_QUALITIES = {
|
|
@@ -118489,8 +119228,32 @@ img.ProseMirror-separator {
|
|
|
118489
119228
|
en: "Standard (Recommended)"
|
|
118490
119229
|
},
|
|
118491
119230
|
auto: {
|
|
118492
|
-
zh: "
|
|
118493
|
-
en: "
|
|
119231
|
+
zh: "自动",
|
|
119232
|
+
en: "Auto"
|
|
119233
|
+
},
|
|
119234
|
+
low: {
|
|
119235
|
+
zh: "低(快速)",
|
|
119236
|
+
en: "Low (Fast)"
|
|
119237
|
+
},
|
|
119238
|
+
medium: {
|
|
119239
|
+
zh: "中",
|
|
119240
|
+
en: "Medium"
|
|
119241
|
+
},
|
|
119242
|
+
high: {
|
|
119243
|
+
zh: "高",
|
|
119244
|
+
en: "High"
|
|
119245
|
+
},
|
|
119246
|
+
xhigh: {
|
|
119247
|
+
zh: "超高",
|
|
119248
|
+
en: "Extra High"
|
|
119249
|
+
},
|
|
119250
|
+
max: {
|
|
119251
|
+
zh: "最高",
|
|
119252
|
+
en: "Max"
|
|
119253
|
+
},
|
|
119254
|
+
hd: {
|
|
119255
|
+
zh: "高清",
|
|
119256
|
+
en: "HD"
|
|
118494
119257
|
}
|
|
118495
119258
|
};
|
|
118496
119259
|
function localizeRatioOptions(options, lang) {
|
|
@@ -118505,38 +119268,6 @@ img.ProseMirror-separator {
|
|
|
118505
119268
|
label: LOCALIZED_QUALITIES[opt.value]?.[lang] ?? opt.label
|
|
118506
119269
|
}));
|
|
118507
119270
|
}
|
|
118508
|
-
function comparisonRatioOptions(lang) {
|
|
118509
|
-
return [
|
|
118510
|
-
"1:1",
|
|
118511
|
-
"3:2",
|
|
118512
|
-
"2:3",
|
|
118513
|
-
"16:9",
|
|
118514
|
-
"9:16"
|
|
118515
|
-
].map((value) => ({
|
|
118516
|
-
value,
|
|
118517
|
-
label: LOCALIZED_RATIOS[value]?.[lang] ?? value
|
|
118518
|
-
}));
|
|
118519
|
-
}
|
|
118520
|
-
function comparisonQualityOptions(lang) {
|
|
118521
|
-
return [
|
|
118522
|
-
{
|
|
118523
|
-
value: "standard",
|
|
118524
|
-
label: lang === "zh" ? "标准" : "Standard"
|
|
118525
|
-
},
|
|
118526
|
-
{
|
|
118527
|
-
value: "1K",
|
|
118528
|
-
label: "1K"
|
|
118529
|
-
},
|
|
118530
|
-
{
|
|
118531
|
-
value: "2K",
|
|
118532
|
-
label: "2K"
|
|
118533
|
-
},
|
|
118534
|
-
{
|
|
118535
|
-
value: "4K",
|
|
118536
|
-
label: "4K"
|
|
118537
|
-
}
|
|
118538
|
-
];
|
|
118539
|
-
}
|
|
118540
119271
|
const RecentItem = ({ item, active, onClick }) => {
|
|
118541
119272
|
const [setRef, inView] = useInView();
|
|
118542
119273
|
const image = useAttachmentImage(item.attachment, inView);
|
|
@@ -118556,6 +119287,26 @@ img.ProseMirror-separator {
|
|
|
118556
119287
|
})
|
|
118557
119288
|
});
|
|
118558
119289
|
};
|
|
119290
|
+
const FavoriteFolderBar = ({ folders, active, onSelect, onDelete, deleteLabel }) => {
|
|
119291
|
+
if (folders.length === 0) return null;
|
|
119292
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
119293
|
+
className: "dsh-ig-fav-folders",
|
|
119294
|
+
children: folders.map((folder) => (0, react_jsx_runtime.jsxs)("span", {
|
|
119295
|
+
className: `dsh-ig-fav-folder-chip ${active === folder.id ? "is-active" : ""}`,
|
|
119296
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
119297
|
+
type: "button",
|
|
119298
|
+
onClick: () => onSelect(folder.id),
|
|
119299
|
+
children: folder.name
|
|
119300
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
119301
|
+
type: "button",
|
|
119302
|
+
className: "dsh-ig-fav-folder-del",
|
|
119303
|
+
title: deleteLabel,
|
|
119304
|
+
onClick: () => onDelete(folder.id),
|
|
119305
|
+
children: (0, react_jsx_runtime.jsx)(X, { size: 9 })
|
|
119306
|
+
})]
|
|
119307
|
+
}, folder.id))
|
|
119308
|
+
});
|
|
119309
|
+
};
|
|
118559
119310
|
function useInView() {
|
|
118560
119311
|
const [inView, setInView] = (0, react.useState)(false);
|
|
118561
119312
|
const observerRef = (0, react.useRef)(null);
|
|
@@ -118653,8 +119404,17 @@ img.ProseMirror-separator {
|
|
|
118653
119404
|
const MAX_BYTES = 188743680;
|
|
118654
119405
|
const pending = /* @__PURE__ */ new Map();
|
|
118655
119406
|
let cacheEpoch = 0;
|
|
118656
|
-
|
|
118657
|
-
|
|
119407
|
+
/**
|
|
119408
|
+
* Resolve the IndexedDB key for one image. `rev` (the source's imageRevision,
|
|
119409
|
+
* falling back to its version) namespaces the cache by image content: when a
|
|
119410
|
+
* source re-packages its images at stable case IDs, a bumped rev orphans the
|
|
119411
|
+
* old blobs instead of serving them forever.
|
|
119412
|
+
*/
|
|
119413
|
+
function cacheKey(sourceId, caseId, rev) {
|
|
119414
|
+
return rev === void 0 ? `${sourceId}:${caseId}` : `${sourceId}:${caseId}@${rev}`;
|
|
119415
|
+
}
|
|
119416
|
+
function fetchInspirationImage(sourceId, caseId, rev) {
|
|
119417
|
+
const key = cacheKey(sourceId, caseId, rev);
|
|
118658
119418
|
const existing = pending.get(key);
|
|
118659
119419
|
if (existing !== void 0) return existing;
|
|
118660
119420
|
const requestEpoch = cacheEpoch;
|
|
@@ -118677,8 +119437,8 @@ img.ProseMirror-separator {
|
|
|
118677
119437
|
pending.set(key, task);
|
|
118678
119438
|
return task;
|
|
118679
119439
|
}
|
|
118680
|
-
async function evictInspirationImage(sourceId, caseId) {
|
|
118681
|
-
const key =
|
|
119440
|
+
async function evictInspirationImage(sourceId, caseId, rev) {
|
|
119441
|
+
const key = cacheKey(sourceId, caseId, rev);
|
|
118682
119442
|
pending.delete(key);
|
|
118683
119443
|
const db = await openDatabase$1();
|
|
118684
119444
|
if (db === void 0) return;
|
|
@@ -118865,6 +119625,988 @@ img.ProseMirror-separator {
|
|
|
118865
119625
|
return Array.isArray(sources) && sources.length > 0 && sources.every((source) => typeof source === "object" && source !== null && Array.isArray(source.cases));
|
|
118866
119626
|
}
|
|
118867
119627
|
//#endregion
|
|
119628
|
+
//#region lib/types/inspiration/data/baoyu-compose.json
|
|
119629
|
+
var types = [
|
|
119630
|
+
{
|
|
119631
|
+
"id": "hero",
|
|
119632
|
+
"description": "Large visual impact, title overlay",
|
|
119633
|
+
"composition": "Large focal visual (60-70% area), title overlay on visual, dramatic composition"
|
|
119634
|
+
},
|
|
119635
|
+
{
|
|
119636
|
+
"id": "conceptual",
|
|
119637
|
+
"description": "Concept visualization, abstract core ideas",
|
|
119638
|
+
"composition": "Abstract shapes representing core concepts, information hierarchy, clean zones"
|
|
119639
|
+
},
|
|
119640
|
+
{
|
|
119641
|
+
"id": "typography",
|
|
119642
|
+
"description": "Text-focused layout, prominent title",
|
|
119643
|
+
"composition": "Title as primary element (40%+ area), minimal supporting visuals, strong hierarchy"
|
|
119644
|
+
},
|
|
119645
|
+
{
|
|
119646
|
+
"id": "metaphor",
|
|
119647
|
+
"description": "Visual metaphor, concrete expressing abstract",
|
|
119648
|
+
"composition": "Concrete object/scene representing abstract idea, symbolic elements, emotional resonance"
|
|
119649
|
+
},
|
|
119650
|
+
{
|
|
119651
|
+
"id": "scene",
|
|
119652
|
+
"description": "Atmospheric scene, narrative feel",
|
|
119653
|
+
"composition": "Atmospheric environment, narrative elements, mood-setting lighting and colors"
|
|
119654
|
+
},
|
|
119655
|
+
{
|
|
119656
|
+
"id": "minimal",
|
|
119657
|
+
"description": "Minimalist composition, generous whitespace",
|
|
119658
|
+
"composition": "Single focal element, generous whitespace (60%+), essential shapes only"
|
|
119659
|
+
}
|
|
119660
|
+
];
|
|
119661
|
+
var palettes = [
|
|
119662
|
+
{
|
|
119663
|
+
"id": "warm",
|
|
119664
|
+
"tagline": "Friendly, approachable, human-centered",
|
|
119665
|
+
"colors": [
|
|
119666
|
+
{
|
|
119667
|
+
"role": "Primary 1",
|
|
119668
|
+
"name": "Warm Orange",
|
|
119669
|
+
"hex": "#ed8936"
|
|
119670
|
+
},
|
|
119671
|
+
{
|
|
119672
|
+
"role": "Primary 2",
|
|
119673
|
+
"name": "Golden Yellow",
|
|
119674
|
+
"hex": "#f6ad55"
|
|
119675
|
+
},
|
|
119676
|
+
{
|
|
119677
|
+
"role": "Primary 3",
|
|
119678
|
+
"name": "Terracotta",
|
|
119679
|
+
"hex": "#c05621"
|
|
119680
|
+
},
|
|
119681
|
+
{
|
|
119682
|
+
"role": "Background",
|
|
119683
|
+
"name": "Cream",
|
|
119684
|
+
"hex": "#fffaf0"
|
|
119685
|
+
},
|
|
119686
|
+
{
|
|
119687
|
+
"role": "Background Alt",
|
|
119688
|
+
"name": "Soft Peach",
|
|
119689
|
+
"hex": "#fed7aa"
|
|
119690
|
+
},
|
|
119691
|
+
{
|
|
119692
|
+
"role": "Accent 1",
|
|
119693
|
+
"name": "Deep Brown",
|
|
119694
|
+
"hex": "#744210"
|
|
119695
|
+
},
|
|
119696
|
+
{
|
|
119697
|
+
"role": "Accent 2",
|
|
119698
|
+
"name": "Soft Red",
|
|
119699
|
+
"hex": "#e53e3e"
|
|
119700
|
+
}
|
|
119701
|
+
],
|
|
119702
|
+
"decorativeHints": [
|
|
119703
|
+
"Sun rays, warm lighting effects",
|
|
119704
|
+
"Rounded shapes, organic curves",
|
|
119705
|
+
"Hearts, smiling faces, friendly icons",
|
|
119706
|
+
"Warm gradient overlays"
|
|
119707
|
+
],
|
|
119708
|
+
"bestFor": ""
|
|
119709
|
+
},
|
|
119710
|
+
{
|
|
119711
|
+
"id": "cool",
|
|
119712
|
+
"tagline": "Technical, professional, precise",
|
|
119713
|
+
"colors": [
|
|
119714
|
+
{
|
|
119715
|
+
"role": "Primary 1",
|
|
119716
|
+
"name": "Engineering Blue",
|
|
119717
|
+
"hex": "#2563eb"
|
|
119718
|
+
},
|
|
119719
|
+
{
|
|
119720
|
+
"role": "Primary 2",
|
|
119721
|
+
"name": "Navy Blue",
|
|
119722
|
+
"hex": "#1e3a5f"
|
|
119723
|
+
},
|
|
119724
|
+
{
|
|
119725
|
+
"role": "Primary 3",
|
|
119726
|
+
"name": "Cyan",
|
|
119727
|
+
"hex": "#06b6d4"
|
|
119728
|
+
},
|
|
119729
|
+
{
|
|
119730
|
+
"role": "Background",
|
|
119731
|
+
"name": "Light Gray",
|
|
119732
|
+
"hex": "#f8f9fa"
|
|
119733
|
+
},
|
|
119734
|
+
{
|
|
119735
|
+
"role": "Background Alt",
|
|
119736
|
+
"name": "Blueprint Off-White",
|
|
119737
|
+
"hex": "#faf8f5"
|
|
119738
|
+
},
|
|
119739
|
+
{
|
|
119740
|
+
"role": "Accent 1",
|
|
119741
|
+
"name": "Amber",
|
|
119742
|
+
"hex": "#f59e0b"
|
|
119743
|
+
},
|
|
119744
|
+
{
|
|
119745
|
+
"role": "Accent 2",
|
|
119746
|
+
"name": "Light Blue",
|
|
119747
|
+
"hex": "#bfdbfe"
|
|
119748
|
+
}
|
|
119749
|
+
],
|
|
119750
|
+
"decorativeHints": [
|
|
119751
|
+
"Grid lines and alignment guides",
|
|
119752
|
+
"Dimension indicators and measurements",
|
|
119753
|
+
"Technical schematics and diagrams",
|
|
119754
|
+
"Geometric precision elements"
|
|
119755
|
+
],
|
|
119756
|
+
"bestFor": ""
|
|
119757
|
+
},
|
|
119758
|
+
{
|
|
119759
|
+
"id": "dark",
|
|
119760
|
+
"tagline": "Cinematic, premium, atmospheric",
|
|
119761
|
+
"colors": [
|
|
119762
|
+
{
|
|
119763
|
+
"role": "Primary 1",
|
|
119764
|
+
"name": "Electric Purple",
|
|
119765
|
+
"hex": "#8b5cf6"
|
|
119766
|
+
},
|
|
119767
|
+
{
|
|
119768
|
+
"role": "Primary 2",
|
|
119769
|
+
"name": "Cyan Blue",
|
|
119770
|
+
"hex": "#06b6d4"
|
|
119771
|
+
},
|
|
119772
|
+
{
|
|
119773
|
+
"role": "Primary 3",
|
|
119774
|
+
"name": "Magenta Pink",
|
|
119775
|
+
"hex": "#ec4899"
|
|
119776
|
+
},
|
|
119777
|
+
{
|
|
119778
|
+
"role": "Background",
|
|
119779
|
+
"name": "Deep Purple-Black",
|
|
119780
|
+
"hex": "#0a0a0a"
|
|
119781
|
+
},
|
|
119782
|
+
{
|
|
119783
|
+
"role": "Background Alt",
|
|
119784
|
+
"name": "Rich Navy",
|
|
119785
|
+
"hex": "#1a1a2e"
|
|
119786
|
+
},
|
|
119787
|
+
{
|
|
119788
|
+
"role": "Accent 1",
|
|
119789
|
+
"name": "Amber",
|
|
119790
|
+
"hex": "#f59e0b"
|
|
119791
|
+
},
|
|
119792
|
+
{
|
|
119793
|
+
"role": "Accent 2",
|
|
119794
|
+
"name": "Pure White",
|
|
119795
|
+
"hex": "#ffffff"
|
|
119796
|
+
}
|
|
119797
|
+
],
|
|
119798
|
+
"decorativeHints": [
|
|
119799
|
+
"Glowing accent elements and neon highlights",
|
|
119800
|
+
"Atmospheric fog or particle effects",
|
|
119801
|
+
"Silhouettes with backlit edges",
|
|
119802
|
+
"Subtle gradient backgrounds"
|
|
119803
|
+
],
|
|
119804
|
+
"bestFor": ""
|
|
119805
|
+
},
|
|
119806
|
+
{
|
|
119807
|
+
"id": "earth",
|
|
119808
|
+
"tagline": "Natural, organic, grounded",
|
|
119809
|
+
"colors": [
|
|
119810
|
+
{
|
|
119811
|
+
"role": "Primary 1",
|
|
119812
|
+
"name": "Forest Green",
|
|
119813
|
+
"hex": "#276749"
|
|
119814
|
+
},
|
|
119815
|
+
{
|
|
119816
|
+
"role": "Primary 2",
|
|
119817
|
+
"name": "Sage",
|
|
119818
|
+
"hex": "#9ae6b4"
|
|
119819
|
+
},
|
|
119820
|
+
{
|
|
119821
|
+
"role": "Primary 3",
|
|
119822
|
+
"name": "Earth Brown",
|
|
119823
|
+
"hex": "#744210"
|
|
119824
|
+
},
|
|
119825
|
+
{
|
|
119826
|
+
"role": "Background",
|
|
119827
|
+
"name": "Sand Beige",
|
|
119828
|
+
"hex": "#f5e6d3"
|
|
119829
|
+
},
|
|
119830
|
+
{
|
|
119831
|
+
"role": "Background Alt",
|
|
119832
|
+
"name": "Sky Blue",
|
|
119833
|
+
"hex": "#e0f2fe"
|
|
119834
|
+
},
|
|
119835
|
+
{
|
|
119836
|
+
"role": "Accent 1",
|
|
119837
|
+
"name": "Sunset Orange",
|
|
119838
|
+
"hex": "#ed8936"
|
|
119839
|
+
},
|
|
119840
|
+
{
|
|
119841
|
+
"role": "Accent 2",
|
|
119842
|
+
"name": "Water Blue",
|
|
119843
|
+
"hex": "#63b3ed"
|
|
119844
|
+
}
|
|
119845
|
+
],
|
|
119846
|
+
"decorativeHints": [
|
|
119847
|
+
"Leaves, trees, mountains, natural forms",
|
|
119848
|
+
"Sun, clouds, organic flowing lines",
|
|
119849
|
+
"Botanical illustrations",
|
|
119850
|
+
"Earthy textures and natural patterns"
|
|
119851
|
+
],
|
|
119852
|
+
"bestFor": ""
|
|
119853
|
+
},
|
|
119854
|
+
{
|
|
119855
|
+
"id": "elegant",
|
|
119856
|
+
"tagline": "Sophisticated, refined, understated luxury",
|
|
119857
|
+
"colors": [
|
|
119858
|
+
{
|
|
119859
|
+
"role": "Primary 1",
|
|
119860
|
+
"name": "Soft Coral",
|
|
119861
|
+
"hex": "#e8a598"
|
|
119862
|
+
},
|
|
119863
|
+
{
|
|
119864
|
+
"role": "Primary 2",
|
|
119865
|
+
"name": "Muted Teal",
|
|
119866
|
+
"hex": "#5b8a8a"
|
|
119867
|
+
},
|
|
119868
|
+
{
|
|
119869
|
+
"role": "Primary 3",
|
|
119870
|
+
"name": "Dusty Rose",
|
|
119871
|
+
"hex": "#d4a5a5"
|
|
119872
|
+
},
|
|
119873
|
+
{
|
|
119874
|
+
"role": "Background",
|
|
119875
|
+
"name": "Warm Cream",
|
|
119876
|
+
"hex": "#f5f0e6"
|
|
119877
|
+
},
|
|
119878
|
+
{
|
|
119879
|
+
"role": "Background Alt",
|
|
119880
|
+
"name": "Soft Beige",
|
|
119881
|
+
"hex": "#f0ebe0"
|
|
119882
|
+
},
|
|
119883
|
+
{
|
|
119884
|
+
"role": "Accent 1",
|
|
119885
|
+
"name": "Gold",
|
|
119886
|
+
"hex": "#c9a962"
|
|
119887
|
+
},
|
|
119888
|
+
{
|
|
119889
|
+
"role": "Accent 2",
|
|
119890
|
+
"name": "Copper",
|
|
119891
|
+
"hex": "#b87333"
|
|
119892
|
+
}
|
|
119893
|
+
],
|
|
119894
|
+
"decorativeHints": [
|
|
119895
|
+
"Delicate ornamental details",
|
|
119896
|
+
"Subtle gradients and soft transitions",
|
|
119897
|
+
"Refined geometric patterns",
|
|
119898
|
+
"Balanced, symmetrical compositions"
|
|
119899
|
+
],
|
|
119900
|
+
"bestFor": ""
|
|
119901
|
+
},
|
|
119902
|
+
{
|
|
119903
|
+
"id": "macaron",
|
|
119904
|
+
"tagline": "Soft macaron pastel color blocks on warm cream",
|
|
119905
|
+
"colors": [
|
|
119906
|
+
{
|
|
119907
|
+
"role": "Primary 1",
|
|
119908
|
+
"name": "Sky Blue",
|
|
119909
|
+
"hex": "#a8d8ea"
|
|
119910
|
+
},
|
|
119911
|
+
{
|
|
119912
|
+
"role": "Primary 2",
|
|
119913
|
+
"name": "Mint Green",
|
|
119914
|
+
"hex": "#b5e5cf"
|
|
119915
|
+
},
|
|
119916
|
+
{
|
|
119917
|
+
"role": "Primary 3",
|
|
119918
|
+
"name": "Lavender",
|
|
119919
|
+
"hex": "#d5c6e0"
|
|
119920
|
+
},
|
|
119921
|
+
{
|
|
119922
|
+
"role": "Background",
|
|
119923
|
+
"name": "Warm Cream",
|
|
119924
|
+
"hex": "#f5f0e8"
|
|
119925
|
+
},
|
|
119926
|
+
{
|
|
119927
|
+
"role": "Background Alt",
|
|
119928
|
+
"name": "Peach",
|
|
119929
|
+
"hex": "#ffd5c2"
|
|
119930
|
+
},
|
|
119931
|
+
{
|
|
119932
|
+
"role": "Accent 1",
|
|
119933
|
+
"name": "Coral Red",
|
|
119934
|
+
"hex": "#e8655a"
|
|
119935
|
+
},
|
|
119936
|
+
{
|
|
119937
|
+
"role": "Accent 2",
|
|
119938
|
+
"name": "Deep Charcoal",
|
|
119939
|
+
"hex": "#2d2d2d"
|
|
119940
|
+
}
|
|
119941
|
+
],
|
|
119942
|
+
"decorativeHints": [
|
|
119943
|
+
"Rounded pastel color blocks",
|
|
119944
|
+
"Subtle warm paper grain texture",
|
|
119945
|
+
"Soft shadows, no hard edges",
|
|
119946
|
+
"Gentle gradient transitions between zones"
|
|
119947
|
+
],
|
|
119948
|
+
"bestFor": ""
|
|
119949
|
+
},
|
|
119950
|
+
{
|
|
119951
|
+
"id": "mono",
|
|
119952
|
+
"tagline": "Clean, focused, essential",
|
|
119953
|
+
"colors": [
|
|
119954
|
+
{
|
|
119955
|
+
"role": "Primary 1",
|
|
119956
|
+
"name": "Pure Black",
|
|
119957
|
+
"hex": "#000000"
|
|
119958
|
+
},
|
|
119959
|
+
{
|
|
119960
|
+
"role": "Primary 2",
|
|
119961
|
+
"name": "Near Black",
|
|
119962
|
+
"hex": "#1f1f1f"
|
|
119963
|
+
},
|
|
119964
|
+
{
|
|
119965
|
+
"role": "Primary 3",
|
|
119966
|
+
"name": "Dark Gray",
|
|
119967
|
+
"hex": "#374151"
|
|
119968
|
+
},
|
|
119969
|
+
{
|
|
119970
|
+
"role": "Background",
|
|
119971
|
+
"name": "White",
|
|
119972
|
+
"hex": "#ffffff"
|
|
119973
|
+
},
|
|
119974
|
+
{
|
|
119975
|
+
"role": "Background Alt",
|
|
119976
|
+
"name": "Off-White",
|
|
119977
|
+
"hex": "#fafafa"
|
|
119978
|
+
},
|
|
119979
|
+
{
|
|
119980
|
+
"role": "Accent 2",
|
|
119981
|
+
"name": "Medium Gray",
|
|
119982
|
+
"hex": "#9ca3af"
|
|
119983
|
+
}
|
|
119984
|
+
],
|
|
119985
|
+
"decorativeHints": [
|
|
119986
|
+
"Maximum negative space",
|
|
119987
|
+
"Thin lines and minimal strokes",
|
|
119988
|
+
"Single focal point emphasis",
|
|
119989
|
+
"Stark contrast between elements"
|
|
119990
|
+
],
|
|
119991
|
+
"bestFor": ""
|
|
119992
|
+
},
|
|
119993
|
+
{
|
|
119994
|
+
"id": "pastel",
|
|
119995
|
+
"tagline": "Gentle, whimsical, soft",
|
|
119996
|
+
"colors": [
|
|
119997
|
+
{
|
|
119998
|
+
"role": "Primary 1",
|
|
119999
|
+
"name": "Soft Pink",
|
|
120000
|
+
"hex": "#ffb6c1"
|
|
120001
|
+
},
|
|
120002
|
+
{
|
|
120003
|
+
"role": "Primary 2",
|
|
120004
|
+
"name": "Mint",
|
|
120005
|
+
"hex": "#98d8c8"
|
|
120006
|
+
},
|
|
120007
|
+
{
|
|
120008
|
+
"role": "Primary 3",
|
|
120009
|
+
"name": "Lavender",
|
|
120010
|
+
"hex": "#c8a2c8"
|
|
120011
|
+
},
|
|
120012
|
+
{
|
|
120013
|
+
"role": "Background",
|
|
120014
|
+
"name": "White",
|
|
120015
|
+
"hex": "#ffffff"
|
|
120016
|
+
},
|
|
120017
|
+
{
|
|
120018
|
+
"role": "Background Alt",
|
|
120019
|
+
"name": "Light Cream",
|
|
120020
|
+
"hex": "#fff8e7"
|
|
120021
|
+
},
|
|
120022
|
+
{
|
|
120023
|
+
"role": "Accent 1",
|
|
120024
|
+
"name": "Butter Yellow",
|
|
120025
|
+
"hex": "#fffacd"
|
|
120026
|
+
},
|
|
120027
|
+
{
|
|
120028
|
+
"role": "Accent 2",
|
|
120029
|
+
"name": "Sky Blue",
|
|
120030
|
+
"hex": "#bee3f8"
|
|
120031
|
+
}
|
|
120032
|
+
],
|
|
120033
|
+
"decorativeHints": [
|
|
120034
|
+
"Cute rounded proportions",
|
|
120035
|
+
"Stars, sparkles, flowers, decorative flourishes",
|
|
120036
|
+
"Soft shadows and gentle highlights",
|
|
120037
|
+
"Storybook-style elements"
|
|
120038
|
+
],
|
|
120039
|
+
"bestFor": ""
|
|
120040
|
+
},
|
|
120041
|
+
{
|
|
120042
|
+
"id": "retro",
|
|
120043
|
+
"tagline": "Nostalgic, vintage, classic",
|
|
120044
|
+
"colors": [
|
|
120045
|
+
{
|
|
120046
|
+
"role": "Primary 1",
|
|
120047
|
+
"name": "Coral Red",
|
|
120048
|
+
"hex": "#e07a5f"
|
|
120049
|
+
},
|
|
120050
|
+
{
|
|
120051
|
+
"role": "Primary 2",
|
|
120052
|
+
"name": "Mint Green",
|
|
120053
|
+
"hex": "#81b29a"
|
|
120054
|
+
},
|
|
120055
|
+
{
|
|
120056
|
+
"role": "Primary 3",
|
|
120057
|
+
"name": "Mustard Yellow",
|
|
120058
|
+
"hex": "#f2cc8f"
|
|
120059
|
+
},
|
|
120060
|
+
{
|
|
120061
|
+
"role": "Primary 4",
|
|
120062
|
+
"name": "Dark Maroon",
|
|
120063
|
+
"hex": "#5d3a3a"
|
|
120064
|
+
},
|
|
120065
|
+
{
|
|
120066
|
+
"role": "Background",
|
|
120067
|
+
"name": "Cream Off-White",
|
|
120068
|
+
"hex": "#f5f0e6"
|
|
120069
|
+
},
|
|
120070
|
+
{
|
|
120071
|
+
"role": "Background Alt",
|
|
120072
|
+
"name": "Aged Paper",
|
|
120073
|
+
"hex": "#f5e6d3"
|
|
120074
|
+
},
|
|
120075
|
+
{
|
|
120076
|
+
"role": "Accent 1",
|
|
120077
|
+
"name": "Burnt Orange",
|
|
120078
|
+
"hex": "#d4764a"
|
|
120079
|
+
},
|
|
120080
|
+
{
|
|
120081
|
+
"role": "Accent 2",
|
|
120082
|
+
"name": "Rock Blue",
|
|
120083
|
+
"hex": "#577590"
|
|
120084
|
+
},
|
|
120085
|
+
{
|
|
120086
|
+
"role": "Accent 3",
|
|
120087
|
+
"name": "Vintage Gold",
|
|
120088
|
+
"hex": "#c9a227"
|
|
120089
|
+
},
|
|
120090
|
+
{
|
|
120091
|
+
"role": "Accent 4",
|
|
120092
|
+
"name": "Faded Teal",
|
|
120093
|
+
"hex": "#2f7373"
|
|
120094
|
+
}
|
|
120095
|
+
],
|
|
120096
|
+
"decorativeHints": [
|
|
120097
|
+
"Halftone dots and vintage badges",
|
|
120098
|
+
"Aged textures with subtle paper grain",
|
|
120099
|
+
"Sunburst/radiating lines for energy",
|
|
120100
|
+
"Pill-shaped clouds, small dots and stars",
|
|
120101
|
+
"Classic icons and retro motifs"
|
|
120102
|
+
],
|
|
120103
|
+
"bestFor": ""
|
|
120104
|
+
},
|
|
120105
|
+
{
|
|
120106
|
+
"id": "duotone",
|
|
120107
|
+
"tagline": "Dramatic, cinematic, two-color high contrast",
|
|
120108
|
+
"colors": [
|
|
120109
|
+
{
|
|
120110
|
+
"role": "Primary 1",
|
|
120111
|
+
"name": "Burnt Orange",
|
|
120112
|
+
"hex": "#e8751a"
|
|
120113
|
+
},
|
|
120114
|
+
{
|
|
120115
|
+
"role": "Primary 2",
|
|
120116
|
+
"name": "Deep Teal",
|
|
120117
|
+
"hex": "#0a6e6e"
|
|
120118
|
+
},
|
|
120119
|
+
{
|
|
120120
|
+
"role": "Background",
|
|
120121
|
+
"name": "Off-Black",
|
|
120122
|
+
"hex": "#121212"
|
|
120123
|
+
},
|
|
120124
|
+
{
|
|
120125
|
+
"role": "Background Alt",
|
|
120126
|
+
"name": "Dark Charcoal",
|
|
120127
|
+
"hex": "#1e1e1e"
|
|
120128
|
+
},
|
|
120129
|
+
{
|
|
120130
|
+
"role": "Accent 1",
|
|
120131
|
+
"name": "Warm Cream",
|
|
120132
|
+
"hex": "#f5e6d0"
|
|
120133
|
+
},
|
|
120134
|
+
{
|
|
120135
|
+
"role": "Accent 2",
|
|
120136
|
+
"name": "Amber Highlight",
|
|
120137
|
+
"hex": "#f4a623"
|
|
120138
|
+
}
|
|
120139
|
+
],
|
|
120140
|
+
"decorativeHints": [
|
|
120141
|
+
"Stark two-color separation across entire composition",
|
|
120142
|
+
"Halftone transitions between the two colors",
|
|
120143
|
+
"Silhouettes in one color against the other",
|
|
120144
|
+
"Minimal use of third color (only for small highlights)",
|
|
120145
|
+
"High contrast figure-ground relationships"
|
|
120146
|
+
],
|
|
120147
|
+
"bestFor": "",
|
|
120148
|
+
"pairs": [
|
|
120149
|
+
{
|
|
120150
|
+
"name": "Orange + Teal",
|
|
120151
|
+
"a": "#e8751a",
|
|
120152
|
+
"b": "#0a6e6e",
|
|
120153
|
+
"feel": "Cinematic, action"
|
|
120154
|
+
},
|
|
120155
|
+
{
|
|
120156
|
+
"name": "Red + Cream",
|
|
120157
|
+
"a": "#c0392b",
|
|
120158
|
+
"b": "#f5e6d0",
|
|
120159
|
+
"feel": "Bold, classic"
|
|
120160
|
+
},
|
|
120161
|
+
{
|
|
120162
|
+
"name": "Blue + Gold",
|
|
120163
|
+
"a": "#1a3a5c",
|
|
120164
|
+
"b": "#d4a843",
|
|
120165
|
+
"feel": "Prestigious, premium"
|
|
120166
|
+
},
|
|
120167
|
+
{
|
|
120168
|
+
"name": "Purple + Green",
|
|
120169
|
+
"a": "#6b3fa0",
|
|
120170
|
+
"b": "#2ecc71",
|
|
120171
|
+
"feel": "Futuristic, contrast"
|
|
120172
|
+
},
|
|
120173
|
+
{
|
|
120174
|
+
"name": "Magenta + Cyan",
|
|
120175
|
+
"a": "#c2185b",
|
|
120176
|
+
"b": "#00bcd4",
|
|
120177
|
+
"feel": "Vibrant, pop"
|
|
120178
|
+
},
|
|
120179
|
+
{
|
|
120180
|
+
"name": "Crimson + Navy",
|
|
120181
|
+
"a": "#dc143c",
|
|
120182
|
+
"b": "#0d1b2a",
|
|
120183
|
+
"feel": "Dramatic, noir"
|
|
120184
|
+
}
|
|
120185
|
+
]
|
|
120186
|
+
},
|
|
120187
|
+
{
|
|
120188
|
+
"id": "vivid",
|
|
120189
|
+
"tagline": "Energetic, bold, attention-grabbing",
|
|
120190
|
+
"colors": [
|
|
120191
|
+
{
|
|
120192
|
+
"role": "Primary 1",
|
|
120193
|
+
"name": "Bright Red",
|
|
120194
|
+
"hex": "#ef4444"
|
|
120195
|
+
},
|
|
120196
|
+
{
|
|
120197
|
+
"role": "Primary 2",
|
|
120198
|
+
"name": "Neon Green",
|
|
120199
|
+
"hex": "#22c55e"
|
|
120200
|
+
},
|
|
120201
|
+
{
|
|
120202
|
+
"role": "Primary 3",
|
|
120203
|
+
"name": "Electric Blue",
|
|
120204
|
+
"hex": "#3b82f6"
|
|
120205
|
+
},
|
|
120206
|
+
{
|
|
120207
|
+
"role": "Background",
|
|
120208
|
+
"name": "Light Blue",
|
|
120209
|
+
"hex": "#eff6ff"
|
|
120210
|
+
},
|
|
120211
|
+
{
|
|
120212
|
+
"role": "Background Alt",
|
|
120213
|
+
"name": "Soft Lavender",
|
|
120214
|
+
"hex": "#f5f3ff"
|
|
120215
|
+
},
|
|
120216
|
+
{
|
|
120217
|
+
"role": "Accent 1",
|
|
120218
|
+
"name": "Bright Orange",
|
|
120219
|
+
"hex": "#fb923c"
|
|
120220
|
+
},
|
|
120221
|
+
{
|
|
120222
|
+
"role": "Accent 2",
|
|
120223
|
+
"name": "Vivid Yellow",
|
|
120224
|
+
"hex": "#facc15"
|
|
120225
|
+
}
|
|
120226
|
+
],
|
|
120227
|
+
"decorativeHints": [
|
|
120228
|
+
"Dynamic diagonal lines and angles",
|
|
120229
|
+
"Bold geometric shapes and color blocks",
|
|
120230
|
+
"Dramatic lighting effects",
|
|
120231
|
+
"High-energy visual compositions"
|
|
120232
|
+
],
|
|
120233
|
+
"bestFor": ""
|
|
120234
|
+
}
|
|
120235
|
+
];
|
|
120236
|
+
var renderings = [
|
|
120237
|
+
{
|
|
120238
|
+
"id": "flat-vector",
|
|
120239
|
+
"tagline": "Clean, modern, geometric illustration",
|
|
120240
|
+
"lines": [
|
|
120241
|
+
"Clean outlines with uniform stroke weight",
|
|
120242
|
+
"Closed shapes (coloring-book style)",
|
|
120243
|
+
"Rounded line endings, avoid sharp corners",
|
|
120244
|
+
"Consistent stroke width throughout"
|
|
120245
|
+
],
|
|
120246
|
+
"texture": [
|
|
120247
|
+
"None: smooth, flat color fills only",
|
|
120248
|
+
"No gradients, shadows, or noise",
|
|
120249
|
+
"Solid color blocks"
|
|
120250
|
+
],
|
|
120251
|
+
"depth": [
|
|
120252
|
+
"Flat: no shadows, no perspective",
|
|
120253
|
+
"2D layering with overlap for depth illusion",
|
|
120254
|
+
"Optional 2.5D isometric layering (front/back occlusion, no atmospheric perspective)",
|
|
120255
|
+
"No 3D effects or bevels"
|
|
120256
|
+
],
|
|
120257
|
+
"elements": [
|
|
120258
|
+
"Geometric icons and simple shapes",
|
|
120259
|
+
"Bold outlined objects with clean fills",
|
|
120260
|
+
"Geometric simplification: complex objects → basic shapes (trees → lollipop/triangle, buildings → rectangles)",
|
|
120261
|
+
"\"Toy model\" aesthetic: cute, rounded proportions",
|
|
120262
|
+
"Decorative: dots, lines, sunbursts, pill-shaped clouds, small stars",
|
|
120263
|
+
"Isolated elements on clean backgrounds"
|
|
120264
|
+
]
|
|
120265
|
+
},
|
|
120266
|
+
{
|
|
120267
|
+
"id": "pixel",
|
|
120268
|
+
"tagline": "Retro 8-bit, nostalgic, chunky",
|
|
120269
|
+
"lines": [
|
|
120270
|
+
"Pixel grid alignment, no anti-aliasing",
|
|
120271
|
+
"Staircase edges on diagonals",
|
|
120272
|
+
"Single-pixel or double-pixel outlines",
|
|
120273
|
+
"Blocky, angular forms"
|
|
120274
|
+
],
|
|
120275
|
+
"texture": [
|
|
120276
|
+
"Dithering patterns for gradients",
|
|
120277
|
+
"No smooth transitions",
|
|
120278
|
+
"Cross-hatching with pixel precision",
|
|
120279
|
+
"Limited 16-32 color palette per scene"
|
|
120280
|
+
],
|
|
120281
|
+
"depth": [
|
|
120282
|
+
"None: flat pixel planes only",
|
|
120283
|
+
"Parallax layering (foreground/background)",
|
|
120284
|
+
"No perspective or 3D effects"
|
|
120285
|
+
],
|
|
120286
|
+
"elements": [
|
|
120287
|
+
"8-bit sprites and chunky shapes",
|
|
120288
|
+
"Simple iconography: stars, hearts, arrows",
|
|
120289
|
+
"Text bubbles with pixel borders",
|
|
120290
|
+
"Progress bars with chunky segments",
|
|
120291
|
+
"Retro gaming UI elements"
|
|
120292
|
+
]
|
|
120293
|
+
},
|
|
120294
|
+
{
|
|
120295
|
+
"id": "digital",
|
|
120296
|
+
"tagline": "Polished, precise, modern",
|
|
120297
|
+
"lines": [
|
|
120298
|
+
"Clean, precise, computer-perfect edges",
|
|
120299
|
+
"Consistent stroke weights",
|
|
120300
|
+
"Sharp corners where appropriate",
|
|
120301
|
+
"Anti-aliased smooth rendering"
|
|
120302
|
+
],
|
|
120303
|
+
"texture": [
|
|
120304
|
+
"Smooth surfaces with no visible texture",
|
|
120305
|
+
"Subtle gradients permitted (soft, controlled)",
|
|
120306
|
+
"Frosted glass and blur effects",
|
|
120307
|
+
"Clean shadows with consistent direction"
|
|
120308
|
+
],
|
|
120309
|
+
"depth": [
|
|
120310
|
+
"Subtle gradients and soft drop shadows",
|
|
120311
|
+
"Layered card-based layouts",
|
|
120312
|
+
"Light 3D effects (subtle, not realistic)",
|
|
120313
|
+
"Material Design-inspired elevation"
|
|
120314
|
+
],
|
|
120315
|
+
"elements": [
|
|
120316
|
+
"Polished icons and UI components",
|
|
120317
|
+
"Data visualizations: charts, graphs, metrics",
|
|
120318
|
+
"Card layouts and structured grids",
|
|
120319
|
+
"Tag chips, progress bars, status indicators",
|
|
120320
|
+
"Clean geometric shapes"
|
|
120321
|
+
]
|
|
120322
|
+
},
|
|
120323
|
+
{
|
|
120324
|
+
"id": "hand-drawn",
|
|
120325
|
+
"tagline": "Sketchy, organic, personal",
|
|
120326
|
+
"lines": [
|
|
120327
|
+
"Sketchy, organic, slightly imperfect strokes",
|
|
120328
|
+
"Variable line weight (thicker at pressure points)",
|
|
120329
|
+
"Wavy connectors and arrows",
|
|
120330
|
+
"Natural hand tremor visible"
|
|
120331
|
+
],
|
|
120332
|
+
"texture": [
|
|
120333
|
+
"Paper grain and subtle surface texture",
|
|
120334
|
+
"Pencil/pen/marker texture on strokes",
|
|
120335
|
+
"Casual fills with visible brush direction"
|
|
120336
|
+
],
|
|
120337
|
+
"depth": [
|
|
120338
|
+
"Minimal: light hand-drawn shadows or hatching",
|
|
120339
|
+
"No realistic depth or perspective",
|
|
120340
|
+
"Simple layering with overlap"
|
|
120341
|
+
],
|
|
120342
|
+
"elements": [
|
|
120343
|
+
"Doodles, organic shapes, hand-lettered labels",
|
|
120344
|
+
"Conceptual icons with sketchy quality",
|
|
120345
|
+
"Connection lines with hand-drawn wavy feel",
|
|
120346
|
+
"Stars, arrows, underlines, circles, checkmarks",
|
|
120347
|
+
"Stick figures and simple characters"
|
|
120348
|
+
]
|
|
120349
|
+
},
|
|
120350
|
+
{
|
|
120351
|
+
"id": "painterly",
|
|
120352
|
+
"tagline": "Soft, artistic, expressive",
|
|
120353
|
+
"lines": [
|
|
120354
|
+
"Soft brush strokes with variable opacity",
|
|
120355
|
+
"No hard outlines; edges defined by color transitions",
|
|
120356
|
+
"Organic flowing strokes with natural blending"
|
|
120357
|
+
],
|
|
120358
|
+
"texture": [
|
|
120359
|
+
"Visible paint or watercolor wash textures",
|
|
120360
|
+
"Color bleeds and wet-on-wet effects",
|
|
120361
|
+
"Paper texture showing through transparent areas",
|
|
120362
|
+
"Brush stroke patterns visible"
|
|
120363
|
+
],
|
|
120364
|
+
"depth": [
|
|
120365
|
+
"Soft edges with natural color blending",
|
|
120366
|
+
"Atmospheric depth through color fading",
|
|
120367
|
+
"Layered washes creating depth illusion"
|
|
120368
|
+
],
|
|
120369
|
+
"elements": [
|
|
120370
|
+
"Watercolor washes as backgrounds",
|
|
120371
|
+
"Natural elements: leaves, flowers, organic forms",
|
|
120372
|
+
"Soft gradients and color transitions",
|
|
120373
|
+
"Splatter and drip effects as accents",
|
|
120374
|
+
"Botanical and environmental motifs"
|
|
120375
|
+
]
|
|
120376
|
+
},
|
|
120377
|
+
{
|
|
120378
|
+
"id": "chalk",
|
|
120379
|
+
"tagline": "Educational, authentic, classroom",
|
|
120380
|
+
"lines": [
|
|
120381
|
+
"Imperfect chalk strokes with variable pressure",
|
|
120382
|
+
"Visible chalk texture and grain",
|
|
120383
|
+
"Slightly wobbly, hand-drawn quality",
|
|
120384
|
+
"Thick strokes for emphasis, thin for details"
|
|
120385
|
+
],
|
|
120386
|
+
"texture": [
|
|
120387
|
+
"Chalk dust effects around text and elements",
|
|
120388
|
+
"Board surface (dark, slightly worn)",
|
|
120389
|
+
"Eraser smudges and residue",
|
|
120390
|
+
"Grainy chalk quality on all elements"
|
|
120391
|
+
],
|
|
120392
|
+
"depth": [
|
|
120393
|
+
"None: flat chalk drawings on board surface",
|
|
120394
|
+
"Layering through erasure and redrawing",
|
|
120395
|
+
"No shadows or perspective"
|
|
120396
|
+
],
|
|
120397
|
+
"elements": [
|
|
120398
|
+
"Chalk doodles: stars, arrows, underlines",
|
|
120399
|
+
"Mathematical formulas and diagrams",
|
|
120400
|
+
"Stick figures and simple icons",
|
|
120401
|
+
"Connection lines with chalk feel",
|
|
120402
|
+
"Checkmarks, circles, boxes for lists",
|
|
120403
|
+
"Wooden frame border optional"
|
|
120404
|
+
]
|
|
120405
|
+
},
|
|
120406
|
+
{
|
|
120407
|
+
"id": "screen-print",
|
|
120408
|
+
"tagline": "Bold, limited-color poster art with print texture",
|
|
120409
|
+
"lines": [
|
|
120410
|
+
"Clean, sharp edges between color blocks",
|
|
120411
|
+
"No outlines — shapes defined by color boundaries",
|
|
120412
|
+
"Stencil-cut quality, bold silhouettes",
|
|
120413
|
+
"Geometric shapes with precise registration"
|
|
120414
|
+
],
|
|
120415
|
+
"texture": [
|
|
120416
|
+
"Halftone dot patterns within color fills",
|
|
120417
|
+
"Slight color layer misregistration (offset between print layers)",
|
|
120418
|
+
"Paper grain texture beneath colors",
|
|
120419
|
+
"Risograph / screen print imperfections (ink spread, dot gain)"
|
|
120420
|
+
],
|
|
120421
|
+
"depth": [
|
|
120422
|
+
"Flat color planes layered front to back",
|
|
120423
|
+
"Depth through silhouette overlap and color layering",
|
|
120424
|
+
"No gradients — tonal variation via halftone density",
|
|
120425
|
+
"Negative space as active compositional element"
|
|
120426
|
+
],
|
|
120427
|
+
"elements": [
|
|
120428
|
+
"Bold silhouettes and symbolic shapes",
|
|
120429
|
+
"Geometric framing (circles, arches, triangles)",
|
|
120430
|
+
"Figure-ground inversion (negative space forms secondary image)",
|
|
120431
|
+
"Limited icon vocabulary: key props, symbolic objects",
|
|
120432
|
+
"Typography integrated as design element, not overlay",
|
|
120433
|
+
"Vintage poster border treatments"
|
|
120434
|
+
]
|
|
120435
|
+
}
|
|
120436
|
+
];
|
|
120437
|
+
var textLevels = [
|
|
120438
|
+
{
|
|
120439
|
+
"id": "none",
|
|
120440
|
+
"area": "85% visual area"
|
|
120441
|
+
},
|
|
120442
|
+
{
|
|
120443
|
+
"id": "title-only",
|
|
120444
|
+
"area": "85% visual area"
|
|
120445
|
+
},
|
|
120446
|
+
{
|
|
120447
|
+
"id": "title-subtitle",
|
|
120448
|
+
"area": "75% visual area"
|
|
120449
|
+
},
|
|
120450
|
+
{
|
|
120451
|
+
"id": "text-rich",
|
|
120452
|
+
"area": "60% visual area"
|
|
120453
|
+
}
|
|
120454
|
+
];
|
|
120455
|
+
var moods = [
|
|
120456
|
+
{
|
|
120457
|
+
"id": "subtle",
|
|
120458
|
+
"application": "Use low contrast, muted colors, light visual weight, calm aesthetic"
|
|
120459
|
+
},
|
|
120460
|
+
{
|
|
120461
|
+
"id": "balanced",
|
|
120462
|
+
"application": "Use medium contrast, normal saturation, balanced visual weight"
|
|
120463
|
+
},
|
|
120464
|
+
{
|
|
120465
|
+
"id": "bold",
|
|
120466
|
+
"application": "Use high contrast, vivid saturated colors, heavy visual weight, dynamic energy"
|
|
120467
|
+
}
|
|
120468
|
+
];
|
|
120469
|
+
//#endregion
|
|
120470
|
+
//#region lib/types/baoyu-compose.js
|
|
120471
|
+
/**
|
|
120472
|
+
* Dimension-composition prompt assembly for the inspiration composer tab.
|
|
120473
|
+
* Data is generated by scripts/build-baoyu-compose.mjs from JimLiu/baoyu-skills
|
|
120474
|
+
* (baoyu-cover-image skill, MIT license).
|
|
120475
|
+
*/
|
|
120476
|
+
/** Pseudo inspiration source id that switches the view into composer mode. */
|
|
120477
|
+
const BAOYU_COMPOSER_SOURCE_ID = "baoyu-compose";
|
|
120478
|
+
const BAOYU_TYPES = types;
|
|
120479
|
+
const BAOYU_PALETTES = palettes;
|
|
120480
|
+
const BAOYU_RENDERINGS = renderings;
|
|
120481
|
+
const BAOYU_TEXT_LEVELS = textLevels;
|
|
120482
|
+
const BAOYU_MOODS = moods;
|
|
120483
|
+
/** Chinese labels for every dimension option id, shown when the UI language is zh. */
|
|
120484
|
+
const BAOYU_LABELS_ZH = {
|
|
120485
|
+
hero: "主视觉大图",
|
|
120486
|
+
conceptual: "概念抽象",
|
|
120487
|
+
typography: "文字主导",
|
|
120488
|
+
metaphor: "隐喻象征",
|
|
120489
|
+
scene: "氛围场景",
|
|
120490
|
+
minimal: "极简留白",
|
|
120491
|
+
warm: "暖色",
|
|
120492
|
+
cool: "冷色",
|
|
120493
|
+
dark: "暗色",
|
|
120494
|
+
earth: "大地色",
|
|
120495
|
+
elegant: "优雅",
|
|
120496
|
+
macaron: "马卡龙",
|
|
120497
|
+
mono: "单色",
|
|
120498
|
+
pastel: "粉彩",
|
|
120499
|
+
retro: "复古",
|
|
120500
|
+
duotone: "双色调",
|
|
120501
|
+
vivid: "高饱和",
|
|
120502
|
+
"flat-vector": "扁平矢量",
|
|
120503
|
+
pixel: "像素风",
|
|
120504
|
+
digital: "数字插画",
|
|
120505
|
+
"hand-drawn": "手绘",
|
|
120506
|
+
painterly: "绘画感",
|
|
120507
|
+
chalk: "粉笔",
|
|
120508
|
+
"screen-print": "丝网印刷",
|
|
120509
|
+
none: "无文字",
|
|
120510
|
+
"title-only": "仅标题",
|
|
120511
|
+
"title-subtitle": "标题+副标题",
|
|
120512
|
+
"text-rich": "丰富文字",
|
|
120513
|
+
subtle: "含蓄",
|
|
120514
|
+
balanced: "均衡",
|
|
120515
|
+
bold: "强烈"
|
|
120516
|
+
};
|
|
120517
|
+
const BAOYU_DEFAULT_SELECTION = {
|
|
120518
|
+
type: "metaphor",
|
|
120519
|
+
palette: "warm",
|
|
120520
|
+
rendering: "flat-vector",
|
|
120521
|
+
text: "title-only",
|
|
120522
|
+
mood: "balanced",
|
|
120523
|
+
title: ""
|
|
120524
|
+
};
|
|
120525
|
+
function palette(id) {
|
|
120526
|
+
return BAOYU_PALETTES.find((item) => item.id === id);
|
|
120527
|
+
}
|
|
120528
|
+
function rendering(id) {
|
|
120529
|
+
return BAOYU_RENDERINGS.find((item) => item.id === id);
|
|
120530
|
+
}
|
|
120531
|
+
function typeOf(id) {
|
|
120532
|
+
return BAOYU_TYPES.find((item) => item.id === id);
|
|
120533
|
+
}
|
|
120534
|
+
function moodOf(id) {
|
|
120535
|
+
return BAOYU_MOODS.find((item) => item.id === id);
|
|
120536
|
+
}
|
|
120537
|
+
function textLevel(id) {
|
|
120538
|
+
return BAOYU_TEXT_LEVELS.find((item) => item.id === id);
|
|
120539
|
+
}
|
|
120540
|
+
/** Assemble the five-dimension selection into one generate_image-ready prompt. */
|
|
120541
|
+
function composeBaoyuPrompt(selection) {
|
|
120542
|
+
const chosenType = typeOf(selection.type);
|
|
120543
|
+
const chosenPalette = palette(selection.palette);
|
|
120544
|
+
const chosenRendering = rendering(selection.rendering);
|
|
120545
|
+
const chosenText = textLevel(selection.text);
|
|
120546
|
+
const chosenMood = moodOf(selection.mood);
|
|
120547
|
+
if (chosenType === void 0 || chosenPalette === void 0 || chosenRendering === void 0 || chosenText === void 0 || chosenMood === void 0) throw new Error("invalid-baoyu-selection");
|
|
120548
|
+
const title = selection.title.trim();
|
|
120549
|
+
if (selection.text !== "none" && title === "") throw new Error("baoyu-title-required");
|
|
120550
|
+
const primary = chosenPalette.colors.filter((color) => color.role.startsWith("Primary"));
|
|
120551
|
+
const background = chosenPalette.colors.filter((color) => color.role.startsWith("Background"));
|
|
120552
|
+
const accent = chosenPalette.colors.filter((color) => color.role.startsWith("Accent"));
|
|
120553
|
+
const swatch = (colors) => colors.map((color) => `${color.name} ${color.hex}`).join(", ");
|
|
120554
|
+
const textElements = selection.text === "none" ? "No text elements; the full area stays visual." : [
|
|
120555
|
+
`Title: "${title}"`,
|
|
120556
|
+
...selection.text === "title-subtitle" || selection.text === "text-rich" ? ["Subtitle: derive one short supporting line from the title"] : [],
|
|
120557
|
+
...selection.text === "text-rich" ? ["Tags: derive 2-3 keyword badges from the title"] : []
|
|
120558
|
+
].join("\n");
|
|
120559
|
+
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("; ")}`;
|
|
120560
|
+
return [
|
|
120561
|
+
"Cover image.",
|
|
120562
|
+
"",
|
|
120563
|
+
"# Visual Design",
|
|
120564
|
+
`- Type: ${chosenType.id} — ${chosenType.composition}`,
|
|
120565
|
+
`- Palette: ${chosenPalette.id} (${chosenPalette.tagline})`,
|
|
120566
|
+
`- Rendering: ${chosenRendering.id} — ${chosenRendering.tagline}`,
|
|
120567
|
+
`- Text level: ${chosenText.id} (${chosenText.area})`,
|
|
120568
|
+
`- Mood: ${chosenMood.id} — ${chosenMood.application}`,
|
|
120569
|
+
"",
|
|
120570
|
+
"# Text Elements",
|
|
120571
|
+
textElements,
|
|
120572
|
+
"",
|
|
120573
|
+
"# Composition",
|
|
120574
|
+
`- Type composition: ${chosenType.composition}`,
|
|
120575
|
+
"- 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.",
|
|
120576
|
+
`- Decorative: ${chosenPalette.decorativeHints.join("; ")}`,
|
|
120577
|
+
"",
|
|
120578
|
+
"# Color Scheme",
|
|
120579
|
+
`- Primary: ${swatch(primary)}`,
|
|
120580
|
+
`- Background: ${swatch(background)}`,
|
|
120581
|
+
`- Accent: ${swatch(accent)}${pairNote}`,
|
|
120582
|
+
`- Mood adjustment: ${chosenMood.application}`,
|
|
120583
|
+
"- 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.",
|
|
120584
|
+
"",
|
|
120585
|
+
`# Rendering Notes (${chosenRendering.id})`,
|
|
120586
|
+
`- Lines: ${chosenRendering.lines.join("; ")}`,
|
|
120587
|
+
`- Texture: ${chosenRendering.texture.join("; ")}`,
|
|
120588
|
+
`- Depth: ${chosenRendering.depth.join("; ")}`,
|
|
120589
|
+
`- Elements: ${chosenRendering.elements.join("; ")}`,
|
|
120590
|
+
"",
|
|
120591
|
+
"# Core Principles",
|
|
120592
|
+
"- Ample whitespace, highlight the core message, avoid cluttered layouts.",
|
|
120593
|
+
"- Simplified silhouettes for any characters — no realistic human faces or bodies.",
|
|
120594
|
+
"- Icon-based vocabulary: represent concepts with simple, recognizable icons."
|
|
120595
|
+
].join("\n");
|
|
120596
|
+
}
|
|
120597
|
+
/** Randomize every visual dimension, keeping the current title text. */
|
|
120598
|
+
function randomBaoyuSelection(current) {
|
|
120599
|
+
const pick = (items) => items[Math.floor(Math.random() * items.length)];
|
|
120600
|
+
return {
|
|
120601
|
+
type: pick(BAOYU_TYPES).id,
|
|
120602
|
+
palette: pick(BAOYU_PALETTES).id,
|
|
120603
|
+
rendering: pick(BAOYU_RENDERINGS).id,
|
|
120604
|
+
text: pick(BAOYU_TEXT_LEVELS).id,
|
|
120605
|
+
mood: pick(BAOYU_MOODS).id,
|
|
120606
|
+
title: current.title
|
|
120607
|
+
};
|
|
120608
|
+
}
|
|
120609
|
+
//#endregion
|
|
118868
120610
|
//#region lib/types/client/inspiration-view.js
|
|
118869
120611
|
const FAVORITES_STORAGE_KEY = "dsh-ig-inspiration-favorites";
|
|
118870
120612
|
function loadInspirationFavorites() {
|
|
@@ -118956,6 +120698,7 @@ img.ProseMirror-separator {
|
|
|
118956
120698
|
allCategories: "全部分类",
|
|
118957
120699
|
allStyles: "全部风格",
|
|
118958
120700
|
allScenes: "全部场景",
|
|
120701
|
+
categoryNav: "分类导航",
|
|
118959
120702
|
search: "搜索案例、Prompt、风格…",
|
|
118960
120703
|
results: "找到 {count} 个案例",
|
|
118961
120704
|
noResults: "没有匹配的素材,换个关键词或筛选条件试试。",
|
|
@@ -118965,6 +120708,9 @@ img.ProseMirror-separator {
|
|
|
118965
120708
|
copied: "已复制",
|
|
118966
120709
|
use: "使用这个 Prompt",
|
|
118967
120710
|
source: "查看原来源",
|
|
120711
|
+
useReference: "提示词 + 参考图",
|
|
120712
|
+
referenceLoading: "获取参考图中…",
|
|
120713
|
+
referenceFailed: "参考图获取失败,请重试",
|
|
118968
120714
|
loading: "正在读取素材库…",
|
|
118969
120715
|
loadFailed: "素材库读取失败,请稍后重试。",
|
|
118970
120716
|
copyFailed: "复制失败",
|
|
@@ -118979,7 +120725,21 @@ img.ProseMirror-separator {
|
|
|
118979
120725
|
favorite: "收藏",
|
|
118980
120726
|
favorited: "已收藏",
|
|
118981
120727
|
zoomHint: "点击放大查看",
|
|
118982
|
-
close: "关闭"
|
|
120728
|
+
close: "关闭",
|
|
120729
|
+
composeTab: "宝玉维度组合",
|
|
120730
|
+
composeHint: "五个维度自由拼接封面 Prompt,数据源自宝玉封图 skill(JimLiu/baoyu-skills,MIT)。",
|
|
120731
|
+
composeType: "类型",
|
|
120732
|
+
composePalette: "色板",
|
|
120733
|
+
composeRendering: "渲染",
|
|
120734
|
+
composeText: "文字",
|
|
120735
|
+
composeMood: "情绪",
|
|
120736
|
+
composeTitleLabel: "标题文字",
|
|
120737
|
+
composeTitlePlaceholder: "输入封面标题(文字层级含标题时必填)",
|
|
120738
|
+
composeTitleRequired: "该文字层级需要先填写标题。",
|
|
120739
|
+
composeRandomize: "随机组合",
|
|
120740
|
+
composeUse: "用此 Prompt 去生成",
|
|
120741
|
+
composeCombos: "共 {count} 种组合",
|
|
120742
|
+
composePreview: "拼接结果预览"
|
|
118983
120743
|
},
|
|
118984
120744
|
en: {
|
|
118985
120745
|
kicker: "Prompt inspiration",
|
|
@@ -118999,6 +120759,7 @@ img.ProseMirror-separator {
|
|
|
118999
120759
|
allCategories: "All categories",
|
|
119000
120760
|
allStyles: "All styles",
|
|
119001
120761
|
allScenes: "All scenes",
|
|
120762
|
+
categoryNav: "Categories",
|
|
119002
120763
|
search: "Search examples, prompts, styles…",
|
|
119003
120764
|
results: "{count} examples",
|
|
119004
120765
|
noResults: "No matching examples. Try another keyword or filter.",
|
|
@@ -119008,6 +120769,9 @@ img.ProseMirror-separator {
|
|
|
119008
120769
|
copied: "Copied",
|
|
119009
120770
|
use: "Use this prompt",
|
|
119010
120771
|
source: "View source",
|
|
120772
|
+
useReference: "Prompt + reference",
|
|
120773
|
+
referenceLoading: "Fetching image…",
|
|
120774
|
+
referenceFailed: "Failed to load the reference image",
|
|
119011
120775
|
loading: "Loading inspiration…",
|
|
119012
120776
|
loadFailed: "Could not load the inspiration library.",
|
|
119013
120777
|
copyFailed: "Failed to copy",
|
|
@@ -119022,12 +120786,28 @@ img.ProseMirror-separator {
|
|
|
119022
120786
|
favorite: "Favorite",
|
|
119023
120787
|
favorited: "Favorited",
|
|
119024
120788
|
zoomHint: "Click to zoom in",
|
|
119025
|
-
close: "Close"
|
|
119026
|
-
|
|
119027
|
-
|
|
119028
|
-
|
|
120789
|
+
close: "Close",
|
|
120790
|
+
composeTab: "Baoyu Composer",
|
|
120791
|
+
composeHint: "Stitch a cover prompt from five dimensions, based on the baoyu cover-image skill (JimLiu/baoyu-skills, MIT).",
|
|
120792
|
+
composeType: "Type",
|
|
120793
|
+
composePalette: "Palette",
|
|
120794
|
+
composeRendering: "Rendering",
|
|
120795
|
+
composeText: "Text",
|
|
120796
|
+
composeMood: "Mood",
|
|
120797
|
+
composeTitleLabel: "Title text",
|
|
120798
|
+
composeTitlePlaceholder: "Cover title (required when the text level includes a title)",
|
|
120799
|
+
composeTitleRequired: "This text level needs a title first.",
|
|
120800
|
+
composeRandomize: "Randomize",
|
|
120801
|
+
composeUse: "Generate with this prompt",
|
|
120802
|
+
composeCombos: "{count} combinations",
|
|
120803
|
+
composePreview: "Composed prompt preview"
|
|
120804
|
+
}
|
|
120805
|
+
};
|
|
120806
|
+
const InspirationView = ({ locale, onUsePrompt, onUseReference }) => {
|
|
119029
120807
|
const [language, setLanguage] = (0, react.useState)(() => locale?.getSnapshot?.().active?.startsWith("en") ? "en" : "zh");
|
|
119030
120808
|
const [catalog, setCatalog] = (0, react.useState)(null);
|
|
120809
|
+
const [activeSourceId, setActiveSourceId] = (0, react.useState)("");
|
|
120810
|
+
const [baoyuSelection, setBaoyuSelection] = (0, react.useState)(BAOYU_DEFAULT_SELECTION);
|
|
119031
120811
|
const [catalogError, setCatalogError] = (0, react.useState)(false);
|
|
119032
120812
|
const [search, setSearch] = (0, react.useState)("");
|
|
119033
120813
|
const [category, setCategory] = (0, react.useState)("");
|
|
@@ -119043,8 +120823,12 @@ img.ProseMirror-separator {
|
|
|
119043
120823
|
const [onlyFavorites, setOnlyFavorites] = (0, react.useState)(false);
|
|
119044
120824
|
const [lightboxCase, setLightboxCase] = (0, react.useState)(null);
|
|
119045
120825
|
const [toast, setToast] = (0, react.useState)(null);
|
|
120826
|
+
const [referenceBusy, setReferenceBusy] = (0, react.useState)(false);
|
|
120827
|
+
const [pendingJump, setPendingJump] = (0, react.useState)("");
|
|
120828
|
+
const [activeCategory, setActiveCategory] = (0, react.useState)("");
|
|
119046
120829
|
const toastTimerRef = (0, react.useRef)(null);
|
|
119047
120830
|
const sentinelRef = (0, react.useRef)(null);
|
|
120831
|
+
const listRef = (0, react.useRef)(null);
|
|
119048
120832
|
(0, react.useEffect)(() => {
|
|
119049
120833
|
if (!locale?.subscribe) return;
|
|
119050
120834
|
return locale.subscribe(() => setLanguage(locale.getSnapshot?.().active?.startsWith("en") ? "en" : "zh"));
|
|
@@ -119114,7 +120898,33 @@ img.ProseMirror-separator {
|
|
|
119114
120898
|
mounted = false;
|
|
119115
120899
|
};
|
|
119116
120900
|
}, []);
|
|
119117
|
-
const source = catalog?.sources[0] ?? null;
|
|
120901
|
+
const source = catalog?.sources.find((candidate) => candidate.id === activeSourceId) ?? catalog?.sources[0] ?? null;
|
|
120902
|
+
const composerActive = activeSourceId === BAOYU_COMPOSER_SOURCE_ID;
|
|
120903
|
+
/** Switch the active library; each source owns its own category/style/scene vocabularies. */
|
|
120904
|
+
const switchSource = (id) => {
|
|
120905
|
+
if (id === activeSourceId) return;
|
|
120906
|
+
setActiveSourceId(id);
|
|
120907
|
+
setCategory("");
|
|
120908
|
+
setStyle("");
|
|
120909
|
+
setScene("");
|
|
120910
|
+
setOnlyFavorites(false);
|
|
120911
|
+
setSelected(null);
|
|
120912
|
+
setPendingJump("");
|
|
120913
|
+
setActiveCategory("");
|
|
120914
|
+
};
|
|
120915
|
+
const useSelectedReference = async () => {
|
|
120916
|
+
if (selected === null || source === null || onUseReference === void 0) return;
|
|
120917
|
+
setReferenceBusy(true);
|
|
120918
|
+
try {
|
|
120919
|
+
const blob = await fetchInspirationImage(source.id, selected.id, source.imageRevision ?? source.version);
|
|
120920
|
+
const ext = blob.type === "image/jpeg" ? "jpg" : blob.type.split("/")[1]?.replace(/[^a-z0-9]/gi, "") || "png";
|
|
120921
|
+
onUseReference(new File([blob], `inspiration-${selected.id}.${ext}`, { type: blob.type.startsWith("image/") ? blob.type : "image/webp" }), selected.prompt);
|
|
120922
|
+
} catch {
|
|
120923
|
+
showToast(t("referenceFailed"), true);
|
|
120924
|
+
} finally {
|
|
120925
|
+
setReferenceBusy(false);
|
|
120926
|
+
}
|
|
120927
|
+
};
|
|
119118
120928
|
const matchingCases = (0, react.useMemo)(() => {
|
|
119119
120929
|
if (source === null) return [];
|
|
119120
120930
|
const query = search.trim().toLowerCase();
|
|
@@ -119156,6 +120966,67 @@ img.ProseMirror-separator {
|
|
|
119156
120966
|
onlyFavorites
|
|
119157
120967
|
]);
|
|
119158
120968
|
const visibleCases = matchingCases.slice(0, visibleLimit);
|
|
120969
|
+
const categoryCounts = (0, react.useMemo)(() => {
|
|
120970
|
+
const counts = /* @__PURE__ */ new Map();
|
|
120971
|
+
for (const item of matchingCases) counts.set(item.category, (counts.get(item.category) ?? 0) + 1);
|
|
120972
|
+
return counts;
|
|
120973
|
+
}, [matchingCases]);
|
|
120974
|
+
const visibleGroups = (0, react.useMemo)(() => {
|
|
120975
|
+
if (source === null) return [];
|
|
120976
|
+
const byCategory = /* @__PURE__ */ new Map();
|
|
120977
|
+
for (const item of visibleCases) {
|
|
120978
|
+
const bucket = byCategory.get(item.category);
|
|
120979
|
+
if (bucket !== void 0) bucket.push(item);
|
|
120980
|
+
else byCategory.set(item.category, [item]);
|
|
120981
|
+
}
|
|
120982
|
+
return source.categories.flatMap((name) => {
|
|
120983
|
+
const items = byCategory.get(name);
|
|
120984
|
+
return items !== void 0 ? [{
|
|
120985
|
+
name,
|
|
120986
|
+
items
|
|
120987
|
+
}] : [];
|
|
120988
|
+
});
|
|
120989
|
+
}, [source, visibleCases]);
|
|
120990
|
+
const visibleGroupSignature = visibleGroups.map((group) => group.name).join("\0");
|
|
120991
|
+
const jumpToCategory = (name) => {
|
|
120992
|
+
if (category !== "") setCategory("");
|
|
120993
|
+
setPendingJump(name);
|
|
120994
|
+
};
|
|
120995
|
+
(0, react.useEffect)(() => {
|
|
120996
|
+
if (pendingJump === "") return;
|
|
120997
|
+
const index = matchingCases.findIndex((item) => item.category === pendingJump);
|
|
120998
|
+
if (index < 0) return;
|
|
120999
|
+
if (index >= visibleLimit) {
|
|
121000
|
+
setVisibleLimit(index + 60);
|
|
121001
|
+
return;
|
|
121002
|
+
}
|
|
121003
|
+
const raf = requestAnimationFrame(() => {
|
|
121004
|
+
document.getElementById(`dsh-ig-cat-${encodeURIComponent(pendingJump)}`)?.scrollIntoView({
|
|
121005
|
+
behavior: "smooth",
|
|
121006
|
+
block: "start"
|
|
121007
|
+
});
|
|
121008
|
+
setPendingJump("");
|
|
121009
|
+
});
|
|
121010
|
+
return () => cancelAnimationFrame(raf);
|
|
121011
|
+
}, [
|
|
121012
|
+
pendingJump,
|
|
121013
|
+
matchingCases,
|
|
121014
|
+
visibleLimit
|
|
121015
|
+
]);
|
|
121016
|
+
(0, react.useEffect)(() => {
|
|
121017
|
+
const root = listRef.current;
|
|
121018
|
+
if (root === null) return;
|
|
121019
|
+
const headers = Array.from(root.querySelectorAll(".dsh-ig-inspiration-group-head"));
|
|
121020
|
+
if (headers.length === 0) return;
|
|
121021
|
+
const categoryByTarget = /* @__PURE__ */ new Map();
|
|
121022
|
+
for (const header of headers) categoryByTarget.set(header, header.dataset.category ?? "");
|
|
121023
|
+
const observer = new IntersectionObserver((entries) => {
|
|
121024
|
+
const visible = entries.find((entry) => entry.isIntersecting);
|
|
121025
|
+
if (visible !== void 0) setActiveCategory(categoryByTarget.get(visible.target) ?? "");
|
|
121026
|
+
}, { rootMargin: "0px 0px -75% 0px" });
|
|
121027
|
+
for (const header of headers) observer.observe(header);
|
|
121028
|
+
return () => observer.disconnect();
|
|
121029
|
+
}, [visibleGroupSignature]);
|
|
119159
121030
|
(0, react.useEffect)(() => {
|
|
119160
121031
|
const el = sentinelRef.current;
|
|
119161
121032
|
if (!el) return;
|
|
@@ -119280,179 +121151,256 @@ img.ProseMirror-separator {
|
|
|
119280
121151
|
className: "dsh-ig-spin",
|
|
119281
121152
|
size: 23
|
|
119282
121153
|
}), (0, react_jsx_runtime.jsx)("span", { children: t("loading") })]
|
|
119283
|
-
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
119284
|
-
className: "dsh-ig-inspiration-
|
|
119285
|
-
|
|
119286
|
-
|
|
119287
|
-
|
|
119288
|
-
|
|
119289
|
-
|
|
119290
|
-
|
|
119291
|
-
|
|
119292
|
-
|
|
119293
|
-
|
|
119294
|
-
|
|
121154
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [catalog !== null ? (0, react_jsx_runtime.jsxs)("div", {
|
|
121155
|
+
className: "dsh-ig-inspiration-sources",
|
|
121156
|
+
role: "tablist",
|
|
121157
|
+
children: [catalog.sources.map((item) => (0, react_jsx_runtime.jsx)("button", {
|
|
121158
|
+
type: "button",
|
|
121159
|
+
role: "tab",
|
|
121160
|
+
"aria-selected": !composerActive && item.id === source?.id,
|
|
121161
|
+
className: `dsh-ig-inspiration-source-chip ${!composerActive && item.id === source?.id ? "is-active" : ""}`,
|
|
121162
|
+
onClick: () => switchSource(item.id),
|
|
121163
|
+
children: item.label
|
|
121164
|
+
}, item.id)), (0, react_jsx_runtime.jsxs)("button", {
|
|
121165
|
+
type: "button",
|
|
121166
|
+
role: "tab",
|
|
121167
|
+
"aria-selected": composerActive,
|
|
121168
|
+
className: `dsh-ig-inspiration-source-chip ${composerActive ? "is-active" : ""}`,
|
|
121169
|
+
onClick: () => switchSource(BAOYU_COMPOSER_SOURCE_ID),
|
|
121170
|
+
children: [(0, react_jsx_runtime.jsx)(Sparkles, { size: 11 }), t("composeTab")]
|
|
121171
|
+
})]
|
|
121172
|
+
}) : null, composerActive ? (0, react_jsx_runtime.jsx)(BaoyuComposerPanel, {
|
|
121173
|
+
language,
|
|
121174
|
+
selection: baoyuSelection,
|
|
121175
|
+
onChange: setBaoyuSelection,
|
|
121176
|
+
onUsePrompt
|
|
121177
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
121178
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121179
|
+
className: "dsh-ig-inspiration-toolbar",
|
|
121180
|
+
children: [
|
|
121181
|
+
(0, react_jsx_runtime.jsxs)("label", {
|
|
121182
|
+
className: "dsh-ig-inspiration-search",
|
|
121183
|
+
children: [(0, react_jsx_runtime.jsx)(Search, { size: 15 }), (0, react_jsx_runtime.jsx)("input", {
|
|
121184
|
+
value: search,
|
|
121185
|
+
onChange: (event) => setSearch(event.target.value),
|
|
121186
|
+
placeholder: t("search")
|
|
121187
|
+
})]
|
|
121188
|
+
}),
|
|
121189
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121190
|
+
type: "button",
|
|
121191
|
+
className: `dsh-ig-inspiration-fav-filter ${onlyFavorites ? "is-active" : ""}`,
|
|
121192
|
+
onClick: () => setOnlyFavorites((prev) => !prev),
|
|
121193
|
+
title: t("onlyFavorites"),
|
|
121194
|
+
children: [(0, react_jsx_runtime.jsx)(Star, {
|
|
121195
|
+
size: 14,
|
|
121196
|
+
className: onlyFavorites ? "fill-star" : ""
|
|
121197
|
+
}), (0, react_jsx_runtime.jsxs)("span", { children: [t("onlyFavorites"), favorites.size > 0 ? ` (${favorites.size})` : ""] })]
|
|
121198
|
+
}),
|
|
121199
|
+
(0, react_jsx_runtime.jsxs)("select", {
|
|
121200
|
+
value: category,
|
|
121201
|
+
onChange: (event) => setCategory(event.target.value),
|
|
121202
|
+
"aria-label": t("allCategories"),
|
|
121203
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
121204
|
+
value: "",
|
|
121205
|
+
children: t("allCategories")
|
|
121206
|
+
}), source.categories.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
121207
|
+
value: item,
|
|
121208
|
+
children: translateTag(item, language)
|
|
121209
|
+
}, item))]
|
|
121210
|
+
}),
|
|
121211
|
+
(0, react_jsx_runtime.jsxs)("select", {
|
|
121212
|
+
value: style,
|
|
121213
|
+
onChange: (event) => setStyle(event.target.value),
|
|
121214
|
+
"aria-label": t("allStyles"),
|
|
121215
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
121216
|
+
value: "",
|
|
121217
|
+
children: t("allStyles")
|
|
121218
|
+
}), source.styles.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
121219
|
+
value: item,
|
|
121220
|
+
children: translateTag(item, language)
|
|
121221
|
+
}, item))]
|
|
121222
|
+
}),
|
|
121223
|
+
(0, react_jsx_runtime.jsxs)("select", {
|
|
121224
|
+
value: scene,
|
|
121225
|
+
onChange: (event) => setScene(event.target.value),
|
|
121226
|
+
"aria-label": t("allScenes"),
|
|
121227
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
121228
|
+
value: "",
|
|
121229
|
+
children: t("allScenes")
|
|
121230
|
+
}), source.scenes.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
121231
|
+
value: item,
|
|
121232
|
+
children: translateTag(item, language)
|
|
121233
|
+
}, item))]
|
|
121234
|
+
})
|
|
121235
|
+
]
|
|
121236
|
+
}),
|
|
121237
|
+
(0, react_jsx_runtime.jsxs)("nav", {
|
|
121238
|
+
className: "dsh-ig-inspiration-catnav",
|
|
121239
|
+
"aria-label": t("categoryNav"),
|
|
121240
|
+
children: [(0, react_jsx_runtime.jsxs)("button", {
|
|
119295
121241
|
type: "button",
|
|
119296
|
-
className: `dsh-ig-inspiration-
|
|
119297
|
-
onClick: () =>
|
|
119298
|
-
|
|
119299
|
-
|
|
119300
|
-
|
|
119301
|
-
|
|
119302
|
-
|
|
119303
|
-
}),
|
|
119304
|
-
(0, react_jsx_runtime.jsxs)("select", {
|
|
119305
|
-
value: category,
|
|
119306
|
-
onChange: (event) => setCategory(event.target.value),
|
|
119307
|
-
"aria-label": t("allCategories"),
|
|
119308
|
-
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
119309
|
-
value: "",
|
|
119310
|
-
children: t("allCategories")
|
|
119311
|
-
}), source.categories.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
119312
|
-
value: item,
|
|
119313
|
-
children: translateTag(item, language)
|
|
119314
|
-
}, item))]
|
|
119315
|
-
}),
|
|
119316
|
-
(0, react_jsx_runtime.jsxs)("select", {
|
|
119317
|
-
value: style,
|
|
119318
|
-
onChange: (event) => setStyle(event.target.value),
|
|
119319
|
-
"aria-label": t("allStyles"),
|
|
119320
|
-
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
119321
|
-
value: "",
|
|
119322
|
-
children: t("allStyles")
|
|
119323
|
-
}), source.styles.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
119324
|
-
value: item,
|
|
119325
|
-
children: translateTag(item, language)
|
|
119326
|
-
}, item))]
|
|
119327
|
-
}),
|
|
119328
|
-
(0, react_jsx_runtime.jsxs)("select", {
|
|
119329
|
-
value: scene,
|
|
119330
|
-
onChange: (event) => setScene(event.target.value),
|
|
119331
|
-
"aria-label": t("allScenes"),
|
|
119332
|
-
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
119333
|
-
value: "",
|
|
119334
|
-
children: t("allScenes")
|
|
119335
|
-
}), source.scenes.map((item) => (0, react_jsx_runtime.jsx)("option", {
|
|
119336
|
-
value: item,
|
|
119337
|
-
children: translateTag(item, language)
|
|
119338
|
-
}, item))]
|
|
119339
|
-
})
|
|
119340
|
-
]
|
|
119341
|
-
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
119342
|
-
className: "dsh-ig-inspiration-layout",
|
|
119343
|
-
children: [(0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
119344
|
-
className: "dsh-ig-inspiration-summary",
|
|
119345
|
-
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) })]
|
|
119346
|
-
}), matchingCases.length === 0 ? (0, react_jsx_runtime.jsx)("div", {
|
|
119347
|
-
className: "dsh-ig-inspiration-empty",
|
|
119348
|
-
children: onlyFavorites ? t("noFavorites") : t("noResults")
|
|
119349
|
-
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
119350
|
-
className: "dsh-ig-inspiration-grid",
|
|
119351
|
-
children: visibleCases.map((item) => (0, react_jsx_runtime.jsx)(InspirationCard, {
|
|
119352
|
-
item,
|
|
119353
|
-
sourceId: source.id,
|
|
119354
|
-
selected: selected?.id === item.id,
|
|
119355
|
-
isFavorited: favorites.has(item.id),
|
|
119356
|
-
language,
|
|
119357
|
-
featuredLabel: t("featured"),
|
|
119358
|
-
retryLabel: t("retry"),
|
|
119359
|
-
onSelect: () => {
|
|
119360
|
-
setSelected(item);
|
|
119361
|
-
setCopied(false);
|
|
121242
|
+
className: `dsh-ig-inspiration-catnav-chip ${category === "" && activeCategory === "" ? "is-active" : ""}`,
|
|
121243
|
+
onClick: () => {
|
|
121244
|
+
if (category !== "") setCategory("");
|
|
121245
|
+
listRef.current?.scrollIntoView({
|
|
121246
|
+
behavior: "smooth",
|
|
121247
|
+
block: "start"
|
|
121248
|
+
});
|
|
119362
121249
|
},
|
|
119363
|
-
|
|
119364
|
-
},
|
|
119365
|
-
|
|
119366
|
-
|
|
119367
|
-
|
|
119368
|
-
|
|
119369
|
-
|
|
119370
|
-
|
|
119371
|
-
|
|
119372
|
-
|
|
119373
|
-
|
|
119374
|
-
|
|
119375
|
-
|
|
119376
|
-
|
|
119377
|
-
|
|
119378
|
-
|
|
119379
|
-
|
|
119380
|
-
className: "dsh-ig-inspiration-
|
|
119381
|
-
|
|
119382
|
-
|
|
119383
|
-
|
|
119384
|
-
|
|
119385
|
-
|
|
119386
|
-
|
|
119387
|
-
|
|
119388
|
-
children:
|
|
119389
|
-
|
|
119390
|
-
|
|
119391
|
-
|
|
119392
|
-
|
|
119393
|
-
|
|
119394
|
-
|
|
119395
|
-
|
|
119396
|
-
|
|
119397
|
-
|
|
119398
|
-
|
|
119399
|
-
|
|
119400
|
-
|
|
119401
|
-
|
|
119402
|
-
|
|
119403
|
-
|
|
119404
|
-
|
|
119405
|
-
|
|
119406
|
-
|
|
119407
|
-
|
|
119408
|
-
|
|
119409
|
-
|
|
119410
|
-
|
|
119411
|
-
})
|
|
119412
|
-
})
|
|
119413
|
-
|
|
119414
|
-
|
|
119415
|
-
|
|
119416
|
-
|
|
119417
|
-
|
|
119418
|
-
|
|
119419
|
-
|
|
119420
|
-
|
|
119421
|
-
|
|
119422
|
-
|
|
119423
|
-
|
|
119424
|
-
|
|
119425
|
-
|
|
119426
|
-
|
|
119427
|
-
|
|
121250
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("allCategories") }), (0, react_jsx_runtime.jsx)("em", { children: matchingCases.length })]
|
|
121251
|
+
}), source.categories.map((name) => {
|
|
121252
|
+
const count = categoryCounts.get(name) ?? 0;
|
|
121253
|
+
const isActive = category === name || category === "" && activeCategory === name;
|
|
121254
|
+
return (0, react_jsx_runtime.jsxs)("button", {
|
|
121255
|
+
type: "button",
|
|
121256
|
+
disabled: count === 0,
|
|
121257
|
+
"aria-current": isActive || void 0,
|
|
121258
|
+
className: `dsh-ig-inspiration-catnav-chip ${isActive ? "is-active" : ""}`,
|
|
121259
|
+
onClick: () => jumpToCategory(name),
|
|
121260
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: translateTag(name, language) }), (0, react_jsx_runtime.jsx)("em", { children: count })]
|
|
121261
|
+
}, name);
|
|
121262
|
+
})]
|
|
121263
|
+
}),
|
|
121264
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121265
|
+
className: "dsh-ig-inspiration-layout",
|
|
121266
|
+
children: [(0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
121267
|
+
className: "dsh-ig-inspiration-summary",
|
|
121268
|
+
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) })]
|
|
121269
|
+
}), matchingCases.length === 0 ? (0, react_jsx_runtime.jsx)("div", {
|
|
121270
|
+
className: "dsh-ig-inspiration-empty",
|
|
121271
|
+
children: onlyFavorites ? t("noFavorites") : t("noResults")
|
|
121272
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
|
|
121273
|
+
ref: listRef,
|
|
121274
|
+
className: "dsh-ig-inspiration-list",
|
|
121275
|
+
children: visibleGroups.map((group) => (0, react_jsx_runtime.jsxs)("section", {
|
|
121276
|
+
className: "dsh-ig-inspiration-group",
|
|
121277
|
+
children: [(0, react_jsx_runtime.jsxs)("h3", {
|
|
121278
|
+
id: `dsh-ig-cat-${encodeURIComponent(group.name)}`,
|
|
121279
|
+
"data-category": group.name,
|
|
121280
|
+
className: "dsh-ig-inspiration-group-head",
|
|
121281
|
+
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 })]
|
|
121282
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
121283
|
+
className: "dsh-ig-inspiration-grid",
|
|
121284
|
+
children: group.items.map((item) => (0, react_jsx_runtime.jsx)(InspirationCard, {
|
|
121285
|
+
item,
|
|
121286
|
+
sourceId: source.id,
|
|
121287
|
+
sourceRevision: source.imageRevision ?? source.version,
|
|
121288
|
+
selected: selected?.id === item.id,
|
|
121289
|
+
isFavorited: favorites.has(item.id),
|
|
121290
|
+
language,
|
|
121291
|
+
featuredLabel: t("featured"),
|
|
121292
|
+
retryLabel: t("retry"),
|
|
121293
|
+
onSelect: () => {
|
|
121294
|
+
setSelected(item);
|
|
121295
|
+
setCopied(false);
|
|
121296
|
+
},
|
|
121297
|
+
onToggleFavorite: () => toggleFavorite(item.id)
|
|
121298
|
+
}, item.id))
|
|
121299
|
+
})]
|
|
121300
|
+
}, group.name))
|
|
121301
|
+
}), visibleCases.length < matchingCases.length ? (0, react_jsx_runtime.jsx)("div", {
|
|
121302
|
+
ref: sentinelRef,
|
|
121303
|
+
style: {
|
|
121304
|
+
height: 32,
|
|
121305
|
+
margin: "16px 0"
|
|
121306
|
+
}
|
|
121307
|
+
}) : (0, react_jsx_runtime.jsx)("div", {
|
|
121308
|
+
className: "dsh-ig-inspiration-end-hint",
|
|
121309
|
+
children: t("allLoaded", { count: String(matchingCases.length) })
|
|
121310
|
+
})] })] }), (0, react_jsx_runtime.jsx)("aside", {
|
|
121311
|
+
className: "dsh-ig-inspiration-inspector",
|
|
121312
|
+
children: selected === null ? (0, react_jsx_runtime.jsxs)("div", {
|
|
121313
|
+
className: "dsh-ig-inspiration-inspector-empty",
|
|
121314
|
+
children: [(0, react_jsx_runtime.jsx)(Image$2, { size: 28 }), (0, react_jsx_runtime.jsx)("span", { children: t("selectHint") })]
|
|
121315
|
+
}) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
121316
|
+
className: "dsh-ig-inspiration-inspector-image",
|
|
121317
|
+
onClick: () => setLightboxCase({
|
|
121318
|
+
sourceId: source.id,
|
|
121319
|
+
caseId: selected.id,
|
|
121320
|
+
revision: source.imageRevision ?? source.version,
|
|
121321
|
+
title: selected.title,
|
|
121322
|
+
alt: selected.imageAlt
|
|
119428
121323
|
}),
|
|
119429
|
-
|
|
119430
|
-
|
|
119431
|
-
|
|
119432
|
-
|
|
119433
|
-
|
|
119434
|
-
|
|
119435
|
-
|
|
119436
|
-
|
|
119437
|
-
|
|
119438
|
-
|
|
119439
|
-
|
|
119440
|
-
|
|
119441
|
-
|
|
119442
|
-
|
|
119443
|
-
|
|
119444
|
-
|
|
121324
|
+
title: t("zoomHint"),
|
|
121325
|
+
children: [(0, react_jsx_runtime.jsx)(InspirationImage, {
|
|
121326
|
+
sourceId: source.id,
|
|
121327
|
+
caseId: selected.id,
|
|
121328
|
+
revision: source.imageRevision ?? source.version,
|
|
121329
|
+
alt: selected.imageAlt,
|
|
121330
|
+
retryLabel: t("retry")
|
|
121331
|
+
}), (0, react_jsx_runtime.jsxs)("span", {
|
|
121332
|
+
className: "dsh-ig-inspiration-inspector-zoom-hint",
|
|
121333
|
+
children: [(0, react_jsx_runtime.jsx)(Maximize2, { size: 11 }), t("zoomHint")]
|
|
121334
|
+
})]
|
|
121335
|
+
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
121336
|
+
className: "dsh-ig-inspiration-inspector-body",
|
|
121337
|
+
children: [
|
|
121338
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121339
|
+
className: "dsh-ig-inspiration-inspector-head",
|
|
121340
|
+
children: [(0, react_jsx_runtime.jsx)("h2", { children: selected.title }), (0, react_jsx_runtime.jsx)("button", {
|
|
119445
121341
|
type: "button",
|
|
119446
|
-
className:
|
|
119447
|
-
onClick: () =>
|
|
119448
|
-
|
|
119449
|
-
|
|
119450
|
-
|
|
119451
|
-
|
|
119452
|
-
|
|
119453
|
-
|
|
119454
|
-
|
|
119455
|
-
|
|
121342
|
+
className: `dsh-ig-inspiration-inspector-fav ${favorites.has(selected.id) ? "is-favorited" : ""}`,
|
|
121343
|
+
onClick: () => toggleFavorite(selected.id),
|
|
121344
|
+
title: favorites.has(selected.id) ? t("favorited") : t("favorite"),
|
|
121345
|
+
children: (0, react_jsx_runtime.jsx)(Star, {
|
|
121346
|
+
size: 15,
|
|
121347
|
+
className: favorites.has(selected.id) ? "fill-star" : ""
|
|
121348
|
+
})
|
|
121349
|
+
})]
|
|
121350
|
+
}),
|
|
121351
|
+
selected.sourceLabel && (0, react_jsx_runtime.jsx)("p", {
|
|
121352
|
+
className: "dsh-ig-inspiration-origin",
|
|
121353
|
+
children: selected.sourceLabel
|
|
121354
|
+
}),
|
|
121355
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121356
|
+
className: "dsh-ig-inspiration-tags",
|
|
121357
|
+
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))]
|
|
121358
|
+
}),
|
|
121359
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121360
|
+
className: "dsh-ig-inspiration-prompt-label",
|
|
121361
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: t("prompt") }), (0, react_jsx_runtime.jsx)("span", { children: selected.prompt.length })]
|
|
121362
|
+
}),
|
|
121363
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
121364
|
+
className: "dsh-ig-inspiration-prompt",
|
|
121365
|
+
children: selected.prompt
|
|
121366
|
+
}),
|
|
121367
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121368
|
+
className: "dsh-ig-inspiration-actions",
|
|
121369
|
+
children: [
|
|
121370
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121371
|
+
type: "button",
|
|
121372
|
+
onClick: () => void copyPrompt(),
|
|
121373
|
+
children: [copied ? (0, react_jsx_runtime.jsx)(Check, { size: 14 }) : (0, react_jsx_runtime.jsx)(Clipboard, { size: 14 }), copied ? t("copied") : t("copy")]
|
|
121374
|
+
}),
|
|
121375
|
+
selected.sourceUrl ?? selected.githubUrl ? (0, react_jsx_runtime.jsxs)("a", {
|
|
121376
|
+
className: "dsh-ig-inspiration-source-link",
|
|
121377
|
+
href: selected.sourceUrl ?? selected.githubUrl,
|
|
121378
|
+
target: "_blank",
|
|
121379
|
+
rel: "noreferrer",
|
|
121380
|
+
children: [(0, react_jsx_runtime.jsx)(ExternalLink, { size: 14 }), t("source")]
|
|
121381
|
+
}) : (0, react_jsx_runtime.jsx)("span", {}),
|
|
121382
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121383
|
+
type: "button",
|
|
121384
|
+
className: "dsh-ig-inspiration-use",
|
|
121385
|
+
onClick: () => onUsePrompt(selected.prompt),
|
|
121386
|
+
children: [(0, react_jsx_runtime.jsx)(Sparkles, { size: 14 }), t("use")]
|
|
121387
|
+
}),
|
|
121388
|
+
onUseReference !== void 0 ? (0, react_jsx_runtime.jsxs)("button", {
|
|
121389
|
+
type: "button",
|
|
121390
|
+
className: "dsh-ig-inspiration-use is-secondary",
|
|
121391
|
+
disabled: referenceBusy,
|
|
121392
|
+
onClick: () => {
|
|
121393
|
+
useSelectedReference();
|
|
121394
|
+
},
|
|
121395
|
+
children: [(0, react_jsx_runtime.jsx)(ImagePlus, { size: 14 }), referenceBusy ? t("referenceLoading") : t("useReference")]
|
|
121396
|
+
}) : null
|
|
121397
|
+
]
|
|
121398
|
+
})
|
|
121399
|
+
]
|
|
121400
|
+
})] })
|
|
121401
|
+
})]
|
|
121402
|
+
})
|
|
121403
|
+
] })] }),
|
|
119456
121404
|
lightboxCase !== null && (0, react_jsx_runtime.jsx)("div", {
|
|
119457
121405
|
className: "dsh-ig-inspiration-lightbox",
|
|
119458
121406
|
onClick: () => setLightboxCase(null),
|
|
@@ -119472,6 +121420,7 @@ img.ProseMirror-separator {
|
|
|
119472
121420
|
children: (0, react_jsx_runtime.jsx)(InspirationImage, {
|
|
119473
121421
|
sourceId: lightboxCase.sourceId,
|
|
119474
121422
|
caseId: lightboxCase.caseId,
|
|
121423
|
+
revision: lightboxCase.revision,
|
|
119475
121424
|
alt: lightboxCase.alt,
|
|
119476
121425
|
retryLabel: t("retry")
|
|
119477
121426
|
})
|
|
@@ -119524,7 +121473,155 @@ img.ProseMirror-separator {
|
|
|
119524
121473
|
]
|
|
119525
121474
|
});
|
|
119526
121475
|
};
|
|
119527
|
-
const
|
|
121476
|
+
const BaoyuComposerPanel = ({ language, selection, onChange, onUsePrompt }) => {
|
|
121477
|
+
const [copied, setCopied] = (0, react.useState)(false);
|
|
121478
|
+
const [copyFailed, setCopyFailed] = (0, react.useState)(false);
|
|
121479
|
+
const tr = (key, params) => {
|
|
121480
|
+
let text = COPY[language][key] ?? COPY.zh[key];
|
|
121481
|
+
if (params) for (const [k, v] of Object.entries(params)) text = text.replace(`{${k}}`, v);
|
|
121482
|
+
return text;
|
|
121483
|
+
};
|
|
121484
|
+
const label = (id) => language === "zh" ? BAOYU_LABELS_ZH[id] ?? id : id;
|
|
121485
|
+
const needsTitle = selection.text !== "none";
|
|
121486
|
+
const titleReady = !needsTitle || selection.title.trim() !== "";
|
|
121487
|
+
let prompt = "";
|
|
121488
|
+
if (titleReady) try {
|
|
121489
|
+
prompt = composeBaoyuPrompt(selection);
|
|
121490
|
+
} catch {
|
|
121491
|
+
prompt = "";
|
|
121492
|
+
}
|
|
121493
|
+
const combos = BAOYU_TYPES.length * BAOYU_PALETTES.length * BAOYU_RENDERINGS.length * BAOYU_TEXT_LEVELS.length * BAOYU_MOODS.length;
|
|
121494
|
+
const dimension = (name, key, options) => (0, react_jsx_runtime.jsxs)("div", {
|
|
121495
|
+
className: "dsh-ig-baoyu-dim",
|
|
121496
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
121497
|
+
className: "dsh-ig-baoyu-dim-head",
|
|
121498
|
+
children: name
|
|
121499
|
+
}), (0, react_jsx_runtime.jsx)("div", {
|
|
121500
|
+
className: "dsh-ig-baoyu-chips",
|
|
121501
|
+
children: options.map((option) => {
|
|
121502
|
+
const palette = key === "palette" ? BAOYU_PALETTES.find((item) => item.id === option.id) : void 0;
|
|
121503
|
+
return (0, react_jsx_runtime.jsxs)("button", {
|
|
121504
|
+
type: "button",
|
|
121505
|
+
className: `dsh-ig-baoyu-chip ${selection[key] === option.id ? "is-active" : ""}`,
|
|
121506
|
+
onClick: () => {
|
|
121507
|
+
onChange({
|
|
121508
|
+
...selection,
|
|
121509
|
+
[key]: option.id
|
|
121510
|
+
});
|
|
121511
|
+
setCopied(false);
|
|
121512
|
+
},
|
|
121513
|
+
title: language === "zh" ? palette?.tagline ?? option.id : option.id,
|
|
121514
|
+
children: [(0, react_jsx_runtime.jsx)("span", { children: label(option.id) }), palette !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
|
|
121515
|
+
className: "dsh-ig-baoyu-swatch",
|
|
121516
|
+
children: [
|
|
121517
|
+
palette.colors[0],
|
|
121518
|
+
palette.colors.find((color) => color.role === "Background"),
|
|
121519
|
+
palette.colors.find((color) => color.role === "Accent 1")
|
|
121520
|
+
].map((color, index) => color === void 0 ? null : (0, react_jsx_runtime.jsx)("i", { style: { background: color.hex } }, index))
|
|
121521
|
+
}) : null]
|
|
121522
|
+
}, option.id);
|
|
121523
|
+
})
|
|
121524
|
+
})]
|
|
121525
|
+
}, name);
|
|
121526
|
+
const copyPrompt = async () => {
|
|
121527
|
+
if (prompt === "") return;
|
|
121528
|
+
try {
|
|
121529
|
+
await navigator.clipboard.writeText(prompt);
|
|
121530
|
+
setCopied(true);
|
|
121531
|
+
setCopyFailed(false);
|
|
121532
|
+
} catch {
|
|
121533
|
+
setCopyFailed(true);
|
|
121534
|
+
}
|
|
121535
|
+
};
|
|
121536
|
+
return (0, react_jsx_runtime.jsxs)("div", {
|
|
121537
|
+
className: "dsh-ig-baoyu-panel",
|
|
121538
|
+
children: [
|
|
121539
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121540
|
+
className: "dsh-ig-baoyu-intro",
|
|
121541
|
+
children: [(0, react_jsx_runtime.jsx)("strong", {
|
|
121542
|
+
className: "dsh-ig-baoyu-combos",
|
|
121543
|
+
children: tr("composeCombos", { count: String(combos) })
|
|
121544
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
121545
|
+
className: "dsh-ig-baoyu-hint",
|
|
121546
|
+
children: tr("composeHint")
|
|
121547
|
+
})]
|
|
121548
|
+
}),
|
|
121549
|
+
dimension(tr("composeType"), "type", BAOYU_TYPES),
|
|
121550
|
+
dimension(tr("composePalette"), "palette", BAOYU_PALETTES),
|
|
121551
|
+
dimension(tr("composeRendering"), "rendering", BAOYU_RENDERINGS),
|
|
121552
|
+
dimension(tr("composeText"), "text", BAOYU_TEXT_LEVELS),
|
|
121553
|
+
dimension(tr("composeMood"), "mood", BAOYU_MOODS),
|
|
121554
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121555
|
+
className: "dsh-ig-baoyu-dim",
|
|
121556
|
+
children: [
|
|
121557
|
+
(0, react_jsx_runtime.jsx)("div", {
|
|
121558
|
+
className: "dsh-ig-baoyu-dim-head",
|
|
121559
|
+
children: tr("composeTitleLabel")
|
|
121560
|
+
}),
|
|
121561
|
+
(0, react_jsx_runtime.jsx)("input", {
|
|
121562
|
+
className: "dsh-ig-baoyu-title-input",
|
|
121563
|
+
value: selection.title,
|
|
121564
|
+
placeholder: tr("composeTitlePlaceholder"),
|
|
121565
|
+
disabled: selection.text === "none",
|
|
121566
|
+
onChange: (event) => {
|
|
121567
|
+
onChange({
|
|
121568
|
+
...selection,
|
|
121569
|
+
title: event.target.value
|
|
121570
|
+
});
|
|
121571
|
+
setCopied(false);
|
|
121572
|
+
}
|
|
121573
|
+
}),
|
|
121574
|
+
needsTitle && !titleReady ? (0, react_jsx_runtime.jsx)("div", {
|
|
121575
|
+
className: "dsh-ig-baoyu-required",
|
|
121576
|
+
children: tr("composeTitleRequired")
|
|
121577
|
+
}) : null
|
|
121578
|
+
]
|
|
121579
|
+
}),
|
|
121580
|
+
(0, react_jsx_runtime.jsxs)("div", {
|
|
121581
|
+
className: "dsh-ig-baoyu-actions",
|
|
121582
|
+
children: [
|
|
121583
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121584
|
+
type: "button",
|
|
121585
|
+
className: "dsh-ig-baoyu-btn",
|
|
121586
|
+
onClick: () => onChange(randomBaoyuSelection(selection)),
|
|
121587
|
+
children: [(0, react_jsx_runtime.jsx)(Shuffle, { size: 13 }), (0, react_jsx_runtime.jsx)("span", { children: tr("composeRandomize") })]
|
|
121588
|
+
}),
|
|
121589
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121590
|
+
type: "button",
|
|
121591
|
+
className: "dsh-ig-baoyu-btn",
|
|
121592
|
+
disabled: prompt === "",
|
|
121593
|
+
onClick: () => {
|
|
121594
|
+
copyPrompt();
|
|
121595
|
+
},
|
|
121596
|
+
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") })]
|
|
121597
|
+
}),
|
|
121598
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
121599
|
+
type: "button",
|
|
121600
|
+
className: "dsh-ig-baoyu-btn is-primary",
|
|
121601
|
+
disabled: prompt === "",
|
|
121602
|
+
onClick: () => onUsePrompt(prompt),
|
|
121603
|
+
children: [(0, react_jsx_runtime.jsx)(Sparkles, { size: 13 }), (0, react_jsx_runtime.jsx)("span", { children: tr("composeUse") })]
|
|
121604
|
+
}),
|
|
121605
|
+
copyFailed ? (0, react_jsx_runtime.jsx)("span", {
|
|
121606
|
+
className: "dsh-ig-baoyu-required",
|
|
121607
|
+
children: tr("copyFailed")
|
|
121608
|
+
}) : null
|
|
121609
|
+
]
|
|
121610
|
+
}),
|
|
121611
|
+
prompt !== "" ? (0, react_jsx_runtime.jsxs)("div", {
|
|
121612
|
+
className: "dsh-ig-baoyu-preview-block",
|
|
121613
|
+
children: [(0, react_jsx_runtime.jsx)("div", {
|
|
121614
|
+
className: "dsh-ig-baoyu-preview-head",
|
|
121615
|
+
children: tr("composePreview")
|
|
121616
|
+
}), (0, react_jsx_runtime.jsx)("pre", {
|
|
121617
|
+
className: "dsh-ig-baoyu-preview",
|
|
121618
|
+
children: prompt
|
|
121619
|
+
})]
|
|
121620
|
+
}) : null
|
|
121621
|
+
]
|
|
121622
|
+
});
|
|
121623
|
+
};
|
|
121624
|
+
const InspirationCard = ({ item, sourceId, sourceRevision, selected, isFavorited, language, featuredLabel, retryLabel, onSelect, onToggleFavorite }) => (0, react_jsx_runtime.jsxs)("button", {
|
|
119528
121625
|
type: "button",
|
|
119529
121626
|
className: `dsh-ig-inspiration-card ${selected ? "is-selected" : ""}`,
|
|
119530
121627
|
onClick: onSelect,
|
|
@@ -119551,6 +121648,7 @@ img.ProseMirror-separator {
|
|
|
119551
121648
|
(0, react_jsx_runtime.jsx)(InspirationImage, {
|
|
119552
121649
|
sourceId,
|
|
119553
121650
|
caseId: item.id,
|
|
121651
|
+
revision: sourceRevision,
|
|
119554
121652
|
alt: item.imageAlt,
|
|
119555
121653
|
retryLabel
|
|
119556
121654
|
})
|
|
@@ -119560,7 +121658,7 @@ img.ProseMirror-separator {
|
|
|
119560
121658
|
children: [(0, react_jsx_runtime.jsx)("strong", { children: item.title }), (0, react_jsx_runtime.jsx)("span", { children: translateTag(item.category, language) })]
|
|
119561
121659
|
})]
|
|
119562
121660
|
});
|
|
119563
|
-
const InspirationImage = ({ sourceId, caseId, alt, retryLabel = "Retry" }) => {
|
|
121661
|
+
const InspirationImage = ({ sourceId, caseId, revision, alt, retryLabel = "Retry" }) => {
|
|
119564
121662
|
const [node, setNode] = (0, react.useState)(null);
|
|
119565
121663
|
const [visible, setVisible] = (0, react.useState)(false);
|
|
119566
121664
|
const [url, setUrl] = (0, react.useState)(null);
|
|
@@ -119581,7 +121679,7 @@ img.ProseMirror-separator {
|
|
|
119581
121679
|
urlRef.current = null;
|
|
119582
121680
|
}
|
|
119583
121681
|
setUrl(null);
|
|
119584
|
-
fetchInspirationImage(sourceId, caseId).then((blob) => {
|
|
121682
|
+
fetchInspirationImage(sourceId, caseId, revision).then((blob) => {
|
|
119585
121683
|
if (!active) return;
|
|
119586
121684
|
const next = URL.createObjectURL(blob);
|
|
119587
121685
|
if (urlRef.current !== null) URL.revokeObjectURL(urlRef.current);
|
|
@@ -119596,7 +121694,8 @@ img.ProseMirror-separator {
|
|
|
119596
121694
|
}, [
|
|
119597
121695
|
visible,
|
|
119598
121696
|
sourceId,
|
|
119599
|
-
caseId
|
|
121697
|
+
caseId,
|
|
121698
|
+
revision
|
|
119600
121699
|
]);
|
|
119601
121700
|
(0, react.useEffect)(() => {
|
|
119602
121701
|
return () => {
|
|
@@ -119633,7 +121732,7 @@ img.ProseMirror-separator {
|
|
|
119633
121732
|
urlRef.current = null;
|
|
119634
121733
|
}
|
|
119635
121734
|
setUrl(null);
|
|
119636
|
-
evictInspirationImage(sourceId, caseId).then(() => fetchInspirationImage(sourceId, caseId)).then((blob) => {
|
|
121735
|
+
evictInspirationImage(sourceId, caseId, revision).then(() => fetchInspirationImage(sourceId, caseId, revision)).then((blob) => {
|
|
119637
121736
|
const next = URL.createObjectURL(blob);
|
|
119638
121737
|
if (urlRef.current !== null) URL.revokeObjectURL(urlRef.current);
|
|
119639
121738
|
urlRef.current = next;
|
|
@@ -119751,6 +121850,12 @@ img.ProseMirror-separator {
|
|
|
119751
121850
|
filterXAI: "xAI Grok",
|
|
119752
121851
|
filterZhipu: "智谱 GLM",
|
|
119753
121852
|
filterComfyUI: "本地 ComfyUI",
|
|
121853
|
+
filterImport: "导入",
|
|
121854
|
+
importImages: "导入图片",
|
|
121855
|
+
importAdded: "已导入 {count} 张图片",
|
|
121856
|
+
importPartial: "导入 {count} 张,{fail} 张失败",
|
|
121857
|
+
importFailed: "导入失败",
|
|
121858
|
+
importPickHint: "选择要导入的图片(PNG/JPG/WebP/GIF)",
|
|
119754
121859
|
filterAllModels: "全部模型",
|
|
119755
121860
|
filterAllRatios: "全部比例",
|
|
119756
121861
|
searchPlaceholder: "搜索 Prompt、标签…",
|
|
@@ -119847,6 +121952,12 @@ img.ProseMirror-separator {
|
|
|
119847
121952
|
filterXAI: "xAI Grok",
|
|
119848
121953
|
filterZhipu: "Zhipu GLM",
|
|
119849
121954
|
filterComfyUI: "Local ComfyUI",
|
|
121955
|
+
filterImport: "Imported",
|
|
121956
|
+
importImages: "Import images",
|
|
121957
|
+
importAdded: "Imported {count} images",
|
|
121958
|
+
importPartial: "Imported {count}, {fail} failed",
|
|
121959
|
+
importFailed: "Import failed",
|
|
121960
|
+
importPickHint: "Choose images to import (PNG/JPG/WebP/GIF)",
|
|
119850
121961
|
filterAllModels: "All Models",
|
|
119851
121962
|
filterAllRatios: "All Ratios",
|
|
119852
121963
|
searchPlaceholder: "Search prompt, tags…",
|
|
@@ -119929,6 +122040,19 @@ img.ProseMirror-separator {
|
|
|
119929
122040
|
}
|
|
119930
122041
|
};
|
|
119931
122042
|
/** Format human-readable relative time */
|
|
122043
|
+
/** Read a browser-picked file as base64 payload for the import route. */
|
|
122044
|
+
function readFileBase64(file) {
|
|
122045
|
+
return new Promise((resolve, reject) => {
|
|
122046
|
+
const reader = new FileReader();
|
|
122047
|
+
reader.onload = () => {
|
|
122048
|
+
const result = reader.result;
|
|
122049
|
+
if (typeof result === "string") resolve(result.slice(result.indexOf(",") + 1));
|
|
122050
|
+
else reject(/* @__PURE__ */ new Error("read-failed"));
|
|
122051
|
+
};
|
|
122052
|
+
reader.onerror = () => reject(/* @__PURE__ */ new Error("read-failed"));
|
|
122053
|
+
reader.readAsDataURL(file);
|
|
122054
|
+
});
|
|
122055
|
+
}
|
|
119932
122056
|
function formatRelativeTime(timestamp, t) {
|
|
119933
122057
|
const diff = Date.now() - timestamp;
|
|
119934
122058
|
if (diff < 6e4) return t("justNow");
|
|
@@ -119949,6 +122073,19 @@ img.ProseMirror-separator {
|
|
|
119949
122073
|
}
|
|
119950
122074
|
/** Extract standard aspect ratio for precise filtering */
|
|
119951
122075
|
function getItemRatio(item) {
|
|
122076
|
+
if (item.provider === "chatgpt-sub" && item.attachment.width && item.attachment.height) {
|
|
122077
|
+
const actual = item.attachment.width / item.attachment.height;
|
|
122078
|
+
for (const [label, value] of [
|
|
122079
|
+
["1:1", 1],
|
|
122080
|
+
["16:9", 16 / 9],
|
|
122081
|
+
["9:16", 9 / 16],
|
|
122082
|
+
["4:3", 4 / 3],
|
|
122083
|
+
["3:4", 3 / 4],
|
|
122084
|
+
["3:2", 3 / 2],
|
|
122085
|
+
["2:3", 2 / 3]
|
|
122086
|
+
]) if (Math.abs(actual / value - 1) < .08) return label;
|
|
122087
|
+
return "custom";
|
|
122088
|
+
}
|
|
119952
122089
|
if (item.aspectRatio && item.aspectRatio !== "custom") return item.aspectRatio;
|
|
119953
122090
|
if (item.output) {
|
|
119954
122091
|
const ratioMatch = item.output.match(/\b(1:1|16:9|9:16|4:3|3:4|3:2|2:3)\b/);
|
|
@@ -119987,6 +122124,7 @@ img.ProseMirror-separator {
|
|
|
119987
122124
|
const { locale, sessionId, useSessions, useWorkspaces, credentialEvents, inSidebar, defaultTab, initialCanvasSurface, useTabInfo } = props;
|
|
119988
122125
|
const [activeTab, setActiveTab] = (0, react.useState)(defaultTab ?? "gallery");
|
|
119989
122126
|
const [studioDraft, setStudioDraft] = (0, react.useState)(void 0);
|
|
122127
|
+
const [studioReference, setStudioReference] = (0, react.useState)(void 0);
|
|
119990
122128
|
const [items, setItems] = (0, react.useState)([]);
|
|
119991
122129
|
const [search, setSearch] = (0, react.useState)("");
|
|
119992
122130
|
const [selectedProvider, setSelectedProvider] = (0, react.useState)("all");
|
|
@@ -120101,11 +122239,80 @@ img.ProseMirror-separator {
|
|
|
120101
122239
|
setToast(null);
|
|
120102
122240
|
}, 2e3);
|
|
120103
122241
|
};
|
|
122242
|
+
const [importing, setImporting] = (0, react.useState)(false);
|
|
122243
|
+
const importInputRef = (0, react.useRef)(null);
|
|
122244
|
+
const importImages = async (files) => {
|
|
122245
|
+
if (files === null || files.length === 0 || importing) return;
|
|
122246
|
+
const all = Array.from(files);
|
|
122247
|
+
const picked = all.filter((file) => file.type.startsWith("image/")).slice(0, 8);
|
|
122248
|
+
if (picked.length === 0) {
|
|
122249
|
+
showToast(t("importFailed"));
|
|
122250
|
+
return;
|
|
122251
|
+
}
|
|
122252
|
+
setImporting(true);
|
|
122253
|
+
try {
|
|
122254
|
+
const reads = await Promise.allSettled(picked.map((file) => readFileBase64(file)));
|
|
122255
|
+
const images = reads.flatMap((read, index) => {
|
|
122256
|
+
if (read.status !== "fulfilled") return [];
|
|
122257
|
+
const file = picked[index];
|
|
122258
|
+
return [{
|
|
122259
|
+
data: read.value,
|
|
122260
|
+
mediaType: file.type,
|
|
122261
|
+
...file.name.length > 0 ? { name: file.name } : {}
|
|
122262
|
+
}];
|
|
122263
|
+
});
|
|
122264
|
+
const readFailures = reads.length - images.length;
|
|
122265
|
+
if (images.length === 0) {
|
|
122266
|
+
showToast(t("importFailed"));
|
|
122267
|
+
return;
|
|
122268
|
+
}
|
|
122269
|
+
const response = await fetch(IMPORT_ROUTE, {
|
|
122270
|
+
method: "POST",
|
|
122271
|
+
credentials: "same-origin",
|
|
122272
|
+
headers: { "content-type": "application/json" },
|
|
122273
|
+
body: JSON.stringify({ images })
|
|
122274
|
+
});
|
|
122275
|
+
if (!response.ok) throw new Error(`HTTP ${String(response.status)}`);
|
|
122276
|
+
const payload = await response.json();
|
|
122277
|
+
const imported = payload.images ?? [];
|
|
122278
|
+
let added = 0;
|
|
122279
|
+
let writeFailures = 0;
|
|
122280
|
+
for (const entry of imported) if (await saveGalleryItem({
|
|
122281
|
+
id: `import-${entry.attachment.attachmentId}-${crypto.randomUUID()}`,
|
|
122282
|
+
attachment: entry.attachment,
|
|
122283
|
+
prompt: "",
|
|
122284
|
+
provider: "import",
|
|
122285
|
+
model: "",
|
|
122286
|
+
createdAt: Date.now(),
|
|
122287
|
+
...activeWorkspace?.workspaceId ? { workspaceId: activeWorkspace.workspaceId } : {},
|
|
122288
|
+
...activeWorkspace?.path ? { workspacePath: activeWorkspace.path } : {},
|
|
122289
|
+
...currentSessionId ? { sessionId: currentSessionId } : {}
|
|
122290
|
+
})) added += 1;
|
|
122291
|
+
else writeFailures += 1;
|
|
122292
|
+
const failCount = (payload.failures ?? []).length + (all.length - picked.length) + readFailures + writeFailures;
|
|
122293
|
+
if (added === 0) showToast(t("importFailed"));
|
|
122294
|
+
else if (failCount > 0) showToast(t("importPartial", {
|
|
122295
|
+
count: String(added),
|
|
122296
|
+
fail: String(failCount)
|
|
122297
|
+
}));
|
|
122298
|
+
else showToast(t("importAdded", { count: String(added) }));
|
|
122299
|
+
} catch {
|
|
122300
|
+
showToast(t("importFailed"));
|
|
122301
|
+
} finally {
|
|
122302
|
+
setImporting(false);
|
|
122303
|
+
}
|
|
122304
|
+
};
|
|
120104
122305
|
const useInspirationPrompt = (0, react.useCallback)((prompt) => {
|
|
120105
122306
|
setStudioDraft(prompt);
|
|
120106
122307
|
setActiveTab("studio");
|
|
120107
122308
|
}, []);
|
|
122309
|
+
const useInspirationReference = (0, react.useCallback)((file, prompt) => {
|
|
122310
|
+
setStudioDraft(prompt);
|
|
122311
|
+
setStudioReference(file);
|
|
122312
|
+
setActiveTab("studio");
|
|
122313
|
+
}, []);
|
|
120108
122314
|
const clearStudioDraft = (0, react.useCallback)(() => setStudioDraft(void 0), []);
|
|
122315
|
+
const clearStudioReference = (0, react.useCallback)(() => setStudioReference(void 0), []);
|
|
120109
122316
|
(0, react.useEffect)(() => {
|
|
120110
122317
|
if (inSidebar) return void 0;
|
|
120111
122318
|
const seat = document.querySelector("[data-composer-seat]");
|
|
@@ -120655,6 +122862,10 @@ img.ProseMirror-separator {
|
|
|
120655
122862
|
(0, react_jsx_runtime.jsx)("option", {
|
|
120656
122863
|
value: "comfyui",
|
|
120657
122864
|
children: t("filterComfyUI")
|
|
122865
|
+
}),
|
|
122866
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
122867
|
+
value: "import",
|
|
122868
|
+
children: t("filterImport")
|
|
120658
122869
|
})
|
|
120659
122870
|
]
|
|
120660
122871
|
}),
|
|
@@ -120737,27 +122948,48 @@ img.ProseMirror-separator {
|
|
|
120737
122948
|
]
|
|
120738
122949
|
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
120739
122950
|
className: "dsh-ig-studio-toolbar-right",
|
|
120740
|
-
children: [
|
|
120741
|
-
|
|
120742
|
-
|
|
120743
|
-
|
|
120744
|
-
|
|
120745
|
-
|
|
120746
|
-
|
|
120747
|
-
|
|
120748
|
-
|
|
120749
|
-
|
|
120750
|
-
|
|
120751
|
-
|
|
120752
|
-
|
|
120753
|
-
|
|
120754
|
-
|
|
120755
|
-
|
|
120756
|
-
|
|
120757
|
-
|
|
120758
|
-
},
|
|
120759
|
-
|
|
120760
|
-
|
|
122951
|
+
children: [
|
|
122952
|
+
activeTab === "gallery" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("input", {
|
|
122953
|
+
ref: importInputRef,
|
|
122954
|
+
type: "file",
|
|
122955
|
+
accept: "image/png,image/jpeg,image/webp,image/gif",
|
|
122956
|
+
multiple: true,
|
|
122957
|
+
style: { display: "none" },
|
|
122958
|
+
onChange: (event) => {
|
|
122959
|
+
importImages(event.target.files);
|
|
122960
|
+
event.target.value = "";
|
|
122961
|
+
}
|
|
122962
|
+
}), (0, react_jsx_runtime.jsxs)("button", {
|
|
122963
|
+
type: "button",
|
|
122964
|
+
className: "dsh-ig-studio-btn",
|
|
122965
|
+
disabled: importing,
|
|
122966
|
+
title: t("importPickHint"),
|
|
122967
|
+
onClick: () => importInputRef.current?.click(),
|
|
122968
|
+
children: [(0, react_jsx_runtime.jsx)(Upload, { size: 13 }), (0, react_jsx_runtime.jsx)("span", { children: t("importImages") })]
|
|
122969
|
+
})] }),
|
|
122970
|
+
(0, react_jsx_runtime.jsxs)("select", {
|
|
122971
|
+
className: "dsh-ig-studio-select dsh-ig-studio-select-sort",
|
|
122972
|
+
value: sortBy,
|
|
122973
|
+
onChange: (e) => setSortBy(e.target.value),
|
|
122974
|
+
children: [(0, react_jsx_runtime.jsx)("option", {
|
|
122975
|
+
value: "newest",
|
|
122976
|
+
children: t("sortNewest")
|
|
122977
|
+
}), (0, react_jsx_runtime.jsx)("option", {
|
|
122978
|
+
value: "oldest",
|
|
122979
|
+
children: t("sortOldest")
|
|
122980
|
+
})]
|
|
122981
|
+
}),
|
|
122982
|
+
(0, react_jsx_runtime.jsxs)("button", {
|
|
122983
|
+
type: "button",
|
|
122984
|
+
className: `dsh-ig-studio-btn ${isManageMode ? "is-active" : ""}`,
|
|
122985
|
+
title: isManageMode ? t("exitManage") : t("manage"),
|
|
122986
|
+
onClick: () => {
|
|
122987
|
+
if (isManageMode) handleExitManage();
|
|
122988
|
+
else setIsManageMode(true);
|
|
122989
|
+
},
|
|
122990
|
+
children: [(0, react_jsx_runtime.jsx)(SquareCheckBig, { size: 13 }), (0, react_jsx_runtime.jsx)("span", { children: isManageMode ? t("exitManage") : t("manage") })]
|
|
122991
|
+
})
|
|
122992
|
+
]
|
|
120761
122993
|
})]
|
|
120762
122994
|
}),
|
|
120763
122995
|
(0, react_jsx_runtime.jsx)("div", {
|
|
@@ -120827,15 +123059,18 @@ img.ProseMirror-separator {
|
|
|
120827
123059
|
}, item.id))
|
|
120828
123060
|
}) : activeTab === "inspiration" ? (0, react_jsx_runtime.jsx)(InspirationView, {
|
|
120829
123061
|
locale,
|
|
120830
|
-
onUsePrompt: useInspirationPrompt
|
|
123062
|
+
onUsePrompt: useInspirationPrompt,
|
|
123063
|
+
onUseReference: useInspirationReference
|
|
120831
123064
|
}) : (0, react_jsx_runtime.jsx)(StudioView, {
|
|
120832
123065
|
locale,
|
|
120833
123066
|
credentialEvents,
|
|
120834
123067
|
workspace: activeWorkspace,
|
|
120835
123068
|
initialPrompt: studioDraft,
|
|
123069
|
+
initialReference: studioReference,
|
|
120836
123070
|
initialCanvasSurface,
|
|
120837
123071
|
showInfiniteCanvasHint: !inSidebar,
|
|
120838
123072
|
onInitialPromptApplied: clearStudioDraft,
|
|
123073
|
+
onInitialReferenceApplied: clearStudioReference,
|
|
120839
123074
|
onOpenInspiration: () => setActiveTab("inspiration")
|
|
120840
123075
|
})
|
|
120841
123076
|
}),
|
|
@@ -120995,7 +123230,7 @@ img.ProseMirror-separator {
|
|
|
120995
123230
|
children: [
|
|
120996
123231
|
(0, react_jsx_runtime.jsx)("span", {
|
|
120997
123232
|
className: "dsh-ig-tag",
|
|
120998
|
-
children: previewItem.provider
|
|
123233
|
+
children: previewItem.provider === "import" ? t("filterImport") : previewItem.provider
|
|
120999
123234
|
}),
|
|
121000
123235
|
previewItem.model && (0, react_jsx_runtime.jsx)("span", {
|
|
121001
123236
|
className: "dsh-ig-tag dsh-ig-tag-model",
|
|
@@ -121053,7 +123288,7 @@ img.ProseMirror-separator {
|
|
|
121053
123288
|
children: [
|
|
121054
123289
|
(0, react_jsx_runtime.jsx)("span", {
|
|
121055
123290
|
className: "dsh-ig-tag",
|
|
121056
|
-
children: previewItem.provider
|
|
123291
|
+
children: previewItem.provider === "import" ? t("filterImport") : previewItem.provider
|
|
121057
123292
|
}),
|
|
121058
123293
|
previewItem.model ? (0, react_jsx_runtime.jsx)("span", {
|
|
121059
123294
|
className: "dsh-ig-tag dsh-ig-tag-model",
|
|
@@ -121386,11 +123621,10 @@ img.ProseMirror-separator {
|
|
|
121386
123621
|
//#region lib/types/client/image-result-node.js
|
|
121387
123622
|
const IMAGE_RESULT_NODE_KIND = "dsh-image-result";
|
|
121388
123623
|
/**
|
|
121389
|
-
*
|
|
121390
|
-
*
|
|
121391
|
-
* Turn closes (only needed under the folding Compact transcript view).
|
|
123624
|
+
* Give each image Tool result its own Chat row at the event that produced it.
|
|
123625
|
+
* PTC (run_code) sub-calls already have their own stable sub-call identity.
|
|
121392
123626
|
*/
|
|
121393
|
-
function createImageResultDefinition(
|
|
123627
|
+
function createImageResultDefinition() {
|
|
121394
123628
|
return {
|
|
121395
123629
|
kind: IMAGE_RESULT_NODE_KIND,
|
|
121396
123630
|
target: "chat",
|
|
@@ -121398,77 +123632,52 @@ img.ProseMirror-separator {
|
|
|
121398
123632
|
if (event.type === "tool/ptc-dispatch") {
|
|
121399
123633
|
const subCallId = event.data.subCallId;
|
|
121400
123634
|
if (typeof subCallId !== "string" || subCallId === "") return null;
|
|
121401
|
-
return
|
|
123635
|
+
return imageResultsFromPtcDispatch(event).length === 0 ? null : {
|
|
121402
123636
|
id: `ptc:${subCallId}`,
|
|
121403
123637
|
role: "start"
|
|
121404
123638
|
};
|
|
121405
123639
|
}
|
|
121406
|
-
|
|
121407
|
-
|
|
121408
|
-
if (event.type === "turn/start") return {
|
|
121409
|
-
id: String(turn),
|
|
123640
|
+
if (event.type === "tool/result" && eventTurn(event) !== void 0 && imageResultsFromMeta(event.data.meta).length > 0) return {
|
|
123641
|
+
id: `result:${event.seq}`,
|
|
121410
123642
|
role: "start"
|
|
121411
123643
|
};
|
|
121412
|
-
if (event.type === "turn/end") return {
|
|
121413
|
-
id: String(turn),
|
|
121414
|
-
role: "update"
|
|
121415
|
-
};
|
|
121416
|
-
if (event.type === "assistant/message") return {
|
|
121417
|
-
id: String(turn),
|
|
121418
|
-
role: "update"
|
|
121419
|
-
};
|
|
121420
|
-
if (event.type === "tool/result" && imageResultFromMeta(event.data.meta) !== void 0) return {
|
|
121421
|
-
id: String(turn),
|
|
121422
|
-
role: "update"
|
|
121423
|
-
};
|
|
121424
123644
|
return null;
|
|
121425
123645
|
},
|
|
121426
123646
|
start: (_context, match) => {
|
|
121427
123647
|
if (match.event.type === "tool/ptc-dispatch") {
|
|
121428
|
-
const
|
|
121429
|
-
if (
|
|
121430
|
-
return { results:
|
|
123648
|
+
const results = imageResultsFromPtcDispatch(match.event);
|
|
123649
|
+
if (results.length === 0) throw new Error("dsh-image-result start requires a plugin image dispatch");
|
|
123650
|
+
return { results: results.map((result) => ({
|
|
121431
123651
|
...result,
|
|
121432
123652
|
seq: match.event.seq
|
|
121433
|
-
}
|
|
123653
|
+
})) };
|
|
121434
123654
|
}
|
|
121435
123655
|
const turn = eventTurn(match.event);
|
|
121436
|
-
|
|
123656
|
+
const results = match.event.type === "tool/result" ? imageResultsFromMeta(match.event.data.meta) : [];
|
|
123657
|
+
if (turn === void 0 || results.length === 0) throw new Error("dsh-image-result start requires an image Tool result");
|
|
121437
123658
|
return {
|
|
121438
123659
|
turn,
|
|
121439
|
-
results:
|
|
123660
|
+
results: results.map((result) => ({
|
|
123661
|
+
...result,
|
|
123662
|
+
seq: match.event.seq
|
|
123663
|
+
}))
|
|
121440
123664
|
};
|
|
121441
123665
|
},
|
|
121442
123666
|
update: (context, match) => {
|
|
121443
|
-
if (match.event.type
|
|
121444
|
-
|
|
121445
|
-
endSeq: match.event.seq
|
|
121446
|
-
};
|
|
121447
|
-
if (match.event.type === "assistant/message") return {
|
|
121448
|
-
...context.state,
|
|
121449
|
-
answerSeq: match.event.seq
|
|
121450
|
-
};
|
|
121451
|
-
if (match.event.type === "tool/ptc-dispatch") {
|
|
121452
|
-
const result = imageResultFromPtcDispatch(match.event);
|
|
121453
|
-
return result === void 0 ? context.state : appendResult(context.state, result, match.event.seq);
|
|
121454
|
-
}
|
|
121455
|
-
if (match.event.type !== "tool/result") return context.state;
|
|
121456
|
-
const result = imageResultFromMeta(match.event.data.meta);
|
|
121457
|
-
if (result === void 0) return context.state;
|
|
121458
|
-
return appendResult(context.state, result, match.event.seq);
|
|
123667
|
+
if (match.event.type !== "tool/ptc-dispatch") return context.state;
|
|
123668
|
+
return imageResultsFromPtcDispatch(match.event).reduce((state, result) => appendResult(state, result, match.event.seq), context.state);
|
|
121459
123669
|
},
|
|
121460
123670
|
buildViewNode: (context) => {
|
|
121461
123671
|
const state = context.state;
|
|
121462
|
-
const
|
|
121463
|
-
if (state === void 0 ||
|
|
121464
|
-
const location = context.matches.at(-1)?.location ?? context.start?.location ?? { kind: "unresolved" };
|
|
123672
|
+
const first = state?.results[0];
|
|
123673
|
+
if (state === void 0 || first === void 0) return null;
|
|
121465
123674
|
return {
|
|
121466
123675
|
key: context.key,
|
|
121467
123676
|
kind: IMAGE_RESULT_NODE_KIND,
|
|
121468
123677
|
id: context.id,
|
|
121469
123678
|
target: "chat",
|
|
121470
|
-
anchorSeq:
|
|
121471
|
-
location,
|
|
123679
|
+
anchorSeq: first.seq,
|
|
123680
|
+
location: { kind: "session" },
|
|
121472
123681
|
visibility: "visible",
|
|
121473
123682
|
data: {
|
|
121474
123683
|
...state.turn !== void 0 ? { turn: state.turn } : {},
|
|
@@ -121489,13 +123698,6 @@ img.ProseMirror-separator {
|
|
|
121489
123698
|
}]
|
|
121490
123699
|
};
|
|
121491
123700
|
}
|
|
121492
|
-
function compactTranscript(options) {
|
|
121493
|
-
try {
|
|
121494
|
-
return options.isCompactTranscript?.() ?? true;
|
|
121495
|
-
} catch {
|
|
121496
|
-
return true;
|
|
121497
|
-
}
|
|
121498
|
-
}
|
|
121499
123701
|
/** Parse the plugin-owned durable presentation metadata from a Tool result event. */
|
|
121500
123702
|
function imageResultFromMeta(value) {
|
|
121501
123703
|
const meta = record(value);
|
|
@@ -121512,12 +123714,26 @@ img.ProseMirror-separator {
|
|
|
121512
123714
|
...typeof meta.seed === "number" ? { seed: meta.seed } : {}
|
|
121513
123715
|
};
|
|
121514
123716
|
}
|
|
123717
|
+
/** Parse all successful images from either a single or batch Tool result. */
|
|
123718
|
+
function imageResultsFromMeta(value) {
|
|
123719
|
+
const meta = record(value);
|
|
123720
|
+
if (meta?.kind === "dsh-image-gen-batch" && Array.isArray(meta.images)) return meta.images.flatMap((image) => {
|
|
123721
|
+
const result = imageResultFromMeta(image);
|
|
123722
|
+
return result === void 0 ? [] : [result];
|
|
123723
|
+
});
|
|
123724
|
+
const result = imageResultFromMeta(value);
|
|
123725
|
+
return result === void 0 ? [] : [result];
|
|
123726
|
+
}
|
|
121515
123727
|
function eventTurn(event) {
|
|
121516
123728
|
const turn = event.data.turn;
|
|
121517
123729
|
return typeof turn === "number" && Number.isSafeInteger(turn) && turn >= 0 ? turn : void 0;
|
|
121518
123730
|
}
|
|
121519
123731
|
/** Plugin tools whose PTC (run_code) dispatch results are image results. */
|
|
121520
|
-
const PTC_IMAGE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
123732
|
+
const PTC_IMAGE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
123733
|
+
"generate_image",
|
|
123734
|
+
"generate_images",
|
|
123735
|
+
"edit_image"
|
|
123736
|
+
]);
|
|
121521
123737
|
/**
|
|
121522
123738
|
* Fixed summary text rendered by the tools' imageOutput(). PTC dispatch events
|
|
121523
123739
|
* carry no presentationMeta, so provider/model/output are recovered from this
|
|
@@ -121525,42 +123741,41 @@ img.ProseMirror-separator {
|
|
|
121525
123741
|
*/
|
|
121526
123742
|
const PTC_SUMMARY_PATTERN = /^(?:Generated|Edited) one image with ([^/\s]+)\/(\S+) \((.+)\)\. Attachment ID: /;
|
|
121527
123743
|
const PTC_SAVED_TO_PATTERN = / It was also saved to the workspace as (.+)\. (?:(?:Saving it to the workspace failed)|(?:It has no local file path)|(?:Respond to the user))/;
|
|
121528
|
-
/**
|
|
121529
|
-
|
|
121530
|
-
|
|
121531
|
-
* is rebuilt from the dispatch payload itself: the image content block for the
|
|
121532
|
-
* attachment, arguments for the prompt (and edit source ids), and the tool's
|
|
121533
|
-
* fixed-format summary text for provider/model/output. Returns undefined for
|
|
121534
|
-
* anything that is not a successful image result from our own image tools.
|
|
121535
|
-
*/
|
|
121536
|
-
function imageResultFromPtcDispatch(event) {
|
|
121537
|
-
if (event.type !== "tool/ptc-dispatch") return void 0;
|
|
123744
|
+
/** Pair each rendered image with its own summary, including batches with failed items. */
|
|
123745
|
+
function imageResultsFromPtcDispatch(event) {
|
|
123746
|
+
if (event.type !== "tool/ptc-dispatch") return [];
|
|
121538
123747
|
const data = event.data;
|
|
121539
|
-
if (data.isError === true) return
|
|
121540
|
-
if (typeof data.name !== "string" || !PTC_IMAGE_TOOL_NAMES.has(data.name)) return
|
|
123748
|
+
if (data.isError === true) return [];
|
|
123749
|
+
if (typeof data.name !== "string" || !PTC_IMAGE_TOOL_NAMES.has(data.name)) return [];
|
|
121541
123750
|
const content = Array.isArray(data.content) ? data.content : [];
|
|
121542
|
-
|
|
123751
|
+
const results = [];
|
|
121543
123752
|
let summaryText = "";
|
|
123753
|
+
const args = record(data.arguments);
|
|
123754
|
+
const sourceIds = sourceAttachmentIds(args);
|
|
121544
123755
|
for (const block of content) {
|
|
121545
123756
|
const candidate = record(block);
|
|
121546
123757
|
if (candidate === void 0) continue;
|
|
121547
|
-
if (candidate.type === "
|
|
121548
|
-
|
|
123758
|
+
if (candidate.type === "text" && typeof candidate.text === "string") {
|
|
123759
|
+
summaryText = candidate.text;
|
|
123760
|
+
continue;
|
|
123761
|
+
}
|
|
123762
|
+
if (candidate.type !== "image") continue;
|
|
123763
|
+
const attachment = imageAttachment(candidate.attachment);
|
|
123764
|
+
if (attachment === void 0) continue;
|
|
123765
|
+
const summary = PTC_SUMMARY_PATTERN.exec(summaryText);
|
|
123766
|
+
const savedTo = PTC_SAVED_TO_PATTERN.exec(summaryText)?.[1];
|
|
123767
|
+
const promptAt = data.name === "generate_images" ? summaryText.indexOf("\nImage prompt: ") : -1;
|
|
123768
|
+
results.push({
|
|
123769
|
+
attachment,
|
|
123770
|
+
prompt: promptAt < 0 ? stringValue(args?.prompt, "Generated Image") : summaryText.slice(promptAt + 15),
|
|
123771
|
+
provider: summary?.[1] ?? "",
|
|
123772
|
+
model: summary?.[2] ?? "",
|
|
123773
|
+
output: summary?.[3] ?? "",
|
|
123774
|
+
...savedTo !== void 0 ? { savedTo } : {},
|
|
123775
|
+
...sourceIds !== void 0 ? { sourceAttachmentIds: sourceIds } : {}
|
|
123776
|
+
});
|
|
121549
123777
|
}
|
|
121550
|
-
|
|
121551
|
-
const summary = PTC_SUMMARY_PATTERN.exec(summaryText);
|
|
121552
|
-
const savedTo = PTC_SAVED_TO_PATTERN.exec(summaryText)?.[1];
|
|
121553
|
-
const args = record(data.arguments);
|
|
121554
|
-
const sourceIds = sourceAttachmentIds(args);
|
|
121555
|
-
return {
|
|
121556
|
-
attachment,
|
|
121557
|
-
prompt: stringValue(args?.prompt, "Generated Image"),
|
|
121558
|
-
provider: summary?.[1] ?? "",
|
|
121559
|
-
model: summary?.[2] ?? "",
|
|
121560
|
-
output: summary?.[3] ?? "",
|
|
121561
|
-
...savedTo !== void 0 ? { savedTo } : {},
|
|
121562
|
-
...sourceIds !== void 0 ? { sourceAttachmentIds: sourceIds } : {}
|
|
121563
|
-
};
|
|
123778
|
+
return results;
|
|
121564
123779
|
}
|
|
121565
123780
|
/** Collect edit_image source attachment ids (single or list form) from dispatch arguments. */
|
|
121566
123781
|
function sourceAttachmentIds(args) {
|
|
@@ -121622,16 +123837,16 @@ img.ProseMirror-separator {
|
|
|
121622
123837
|
const isNew = event.seq > lastSeq;
|
|
121623
123838
|
lastSeq = Math.max(lastSeq, event.seq);
|
|
121624
123839
|
if (change.kind !== "append" || !isNew) continue;
|
|
121625
|
-
const
|
|
121626
|
-
if (
|
|
121627
|
-
pushTlLandingsLive(
|
|
123840
|
+
const results = event.type === "tool/result" ? imageResultsFromMeta(event.data.meta) : imageResultsFromPtcDispatch(event);
|
|
123841
|
+
if (results.length === 0) continue;
|
|
123842
|
+
pushTlLandingsLive(results.map((result) => ({
|
|
121628
123843
|
galleryId: String(result.attachment.attachmentId),
|
|
121629
123844
|
attachment: result.attachment,
|
|
121630
123845
|
fromConversation: true,
|
|
121631
123846
|
prompt: result.prompt,
|
|
121632
123847
|
provider: result.provider,
|
|
121633
123848
|
model: result.model
|
|
121634
|
-
}
|
|
123849
|
+
})));
|
|
121635
123850
|
}
|
|
121636
123851
|
});
|
|
121637
123852
|
};
|
|
@@ -121646,105 +123861,139 @@ img.ProseMirror-separator {
|
|
|
121646
123861
|
//#region lib/types/client/studio-style.js
|
|
121647
123862
|
const STUDIO_STYLE = `
|
|
121648
123863
|
.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}
|
|
121649
|
-
.dsh-ig-workbench{--ig-blue
|
|
123864
|
+
.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%)}
|
|
123865
|
+
body[data-ds-dark-theme] .dsh-ig-workbench{--ig-danger:#f08c8c;--ig-warn:#e5b76a}
|
|
121650
123866
|
.dsh-ig-workbench *{box-sizing:border-box}.dsh-ig-workbench button,.dsh-ig-workbench select,.dsh-ig-workbench textarea{font:inherit;color:inherit}
|
|
121651
|
-
.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(--
|
|
123867
|
+
.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}
|
|
121652
123868
|
.dsh-ig-workbench-grid.is-sidebar-collapsed{grid-template-columns:minmax(0,1fr) minmax(286px,340px)}
|
|
121653
123869
|
.dsh-ig-workbench-grid.is-generate-collapsed{grid-template-columns:minmax(190px,238px) minmax(0,1fr)}
|
|
121654
123870
|
.dsh-ig-workbench-grid.is-sidebar-collapsed.is-generate-collapsed{grid-template-columns:minmax(0,1fr)}
|
|
121655
|
-
.dsh-ig-recent-panel,.dsh-ig-generate-panel{min-width:0;min-height:0;overflow:hidden;background:
|
|
123871
|
+
.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)}
|
|
121656
123872
|
.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}
|
|
121657
|
-
.dsh-ig-count-badge{font-size:11px;min-width:22px;text-align:center;padding:2px 6px;border-radius:999px;background:var(--ig-soft);color
|
|
121658
|
-
.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
|
|
121659
|
-
.dsh-ig-collapse-btn:hover{border-color:var(--ig-line);background:var(--ig-soft);color:var(--
|
|
121660
|
-
.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
|
|
121661
|
-
.dsh-ig-
|
|
121662
|
-
.dsh-ig-
|
|
121663
|
-
.dsh-ig-
|
|
121664
|
-
.dsh-ig-
|
|
123873
|
+
.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}
|
|
123874
|
+
.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}
|
|
123875
|
+
.dsh-ig-collapse-btn:hover{border-color:var(--ig-line);background:var(--ig-soft);color:var(--ig-fg)}
|
|
123876
|
+
.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}
|
|
123877
|
+
.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)}
|
|
123878
|
+
.dsh-ig-fav-folders{display:flex;flex-wrap:wrap;gap:4px;margin:4px 0 6px}
|
|
123879
|
+
.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}
|
|
123880
|
+
.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)}
|
|
123881
|
+
.dsh-ig-fav-folder-chip>button:first-child{border:0;background:transparent;color:inherit;font-size:inherit;padding:0;cursor:pointer}
|
|
123882
|
+
.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)}
|
|
123883
|
+
.dsh-ig-fav-folder-draft{display:flex;gap:4px;margin:2px 0 6px}
|
|
123884
|
+
.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}
|
|
123885
|
+
.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}
|
|
123886
|
+
.dsh-ig-fav-folder-draft button:first-of-type{border-color:var(--ig-blue-line);color:var(--ig-blue)}
|
|
123887
|
+
.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)}
|
|
123888
|
+
.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}
|
|
123889
|
+
.dsh-ig-fav-dialog-title{font-size:12.5px;font-weight:600;color:var(--ig-fg)}
|
|
123890
|
+
.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}
|
|
123891
|
+
.dsh-ig-fav-dialog-folder-label{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--ig-fg-2)}
|
|
123892
|
+
.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}
|
|
123893
|
+
.dsh-ig-fav-dialog-actions{display:flex;gap:6px;justify-content:flex-end;flex-wrap:wrap}
|
|
123894
|
+
.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}
|
|
123895
|
+
.dsh-ig-fav-dialog-actions button.is-primary{border-color:var(--ig-blue);background:var(--ig-blue);color:#fff}
|
|
123896
|
+
.dsh-ig-fav-dialog-folders{display:flex;flex-direction:column;gap:4px}
|
|
123897
|
+
.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}
|
|
123898
|
+
.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)}
|
|
123899
|
+
.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}
|
|
123900
|
+
.dsh-ig-fav-prompt{position:relative;display:flex;align-items:flex-start;gap:2px}
|
|
123901
|
+
.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)}
|
|
123902
|
+
.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}
|
|
123903
|
+
.dsh-ig-rail-tabs{flex:none;display:flex;gap:4px;padding:4px 8px 6px;border-bottom:1px solid var(--ig-line)}
|
|
123904
|
+
.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}
|
|
123905
|
+
.dsh-ig-fav-scroll{flex:1 1 0;height:0;overflow-x:hidden;overflow-y:auto;min-height:0;padding:8px}
|
|
123906
|
+
.dsh-ig-fav-section-label{padding:4px 2px 6px;font-size:11px;font-weight:600;color:var(--ig-fg-3)}
|
|
123907
|
+
.dsh-ig-fav-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));gap:6px}
|
|
123908
|
+
.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}
|
|
123909
|
+
.dsh-ig-fav-prompts{display:flex;flex-direction:column;gap:4px}
|
|
123910
|
+
.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}
|
|
123911
|
+
.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)}
|
|
123912
|
+
.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)}
|
|
123913
|
+
.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))}
|
|
121665
123914
|
.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)}
|
|
121666
123915
|
.dsh-ig-canvas-toolbar-left,.dsh-ig-canvas-toolbar-right{display:flex;align-items:center;gap:6px;min-width:0}
|
|
121667
123916
|
.dsh-ig-canvas-toolbar-left{justify-self:start}
|
|
121668
123917
|
.dsh-ig-canvas-toolbar-right{justify-self:end}
|
|
121669
123918
|
.dsh-ig-canvas-toolbar-center{display:flex;align-items:center;justify-self:center;gap:6px;min-width:0}
|
|
121670
123919
|
.dsh-ig-toolbar-divider{width:1px;height:16px;background:var(--ig-line);flex-shrink:0;margin:0 2px}
|
|
121671
|
-
.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(--
|
|
121672
|
-
.dsh-ig-canvas-toolbar button:hover{border-color
|
|
121673
|
-
.dsh-ig-canvas-toolbar button.is-active{border-color
|
|
123920
|
+
.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}
|
|
123921
|
+
.dsh-ig-canvas-toolbar button:hover{border-color:var(--ig-blue-line);background:rgba(47,100,245,.05);color:var(--ig-blue)}
|
|
123922
|
+
.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}
|
|
121674
123923
|
.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)}
|
|
121675
|
-
.dsh-ig-zoom-display{font-size:11px;min-width:38px;text-align:center;color
|
|
121676
|
-
.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
|
|
123924
|
+
.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}
|
|
123925
|
+
.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)}
|
|
121677
123926
|
.dsh-ig-status-badge-wrap{position:relative;display:inline-flex;align-items:center}
|
|
121678
|
-
.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(--
|
|
121679
|
-
.dsh-ig-status-badge:hover{border-color
|
|
123927
|
+
.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}
|
|
123928
|
+
.dsh-ig-status-badge:hover{border-color:var(--ig-blue-line);background:rgba(47,100,245,.04)}
|
|
121680
123929
|
.dsh-ig-status-dot{width:7px;height:7px;min-width:7px;max-width:7px;border-radius:50%;flex-shrink:0;box-sizing:border-box}
|
|
121681
123930
|
.dsh-ig-status-dot.is-ready{background:#10b981;box-shadow:0 0 0 2px rgba(16,185,129,.2)}
|
|
121682
123931
|
.dsh-ig-status-dot.is-muted{background:#ef4444;box-shadow:0 0 0 2px rgba(239,68,68,.2)}
|
|
121683
|
-
.dsh-ig-status-text{font-size:11.5px;font-weight:500;color:var(--
|
|
121684
|
-
.dsh-ig-status-arrow{color
|
|
123932
|
+
.dsh-ig-status-text{font-size:11.5px;font-weight:500;color:var(--ig-fg);line-height:1}
|
|
123933
|
+
.dsh-ig-status-arrow{color:var(--ig-fg-cap);transition:transform .15s,color .15s}
|
|
121685
123934
|
.dsh-ig-status-badge-wrap:hover .dsh-ig-status-arrow{transform:rotate(180deg);color:var(--ig-blue)}
|
|
121686
|
-
.dsh-ig-status-popover{position:absolute;left:0;top:calc(100% + 6px);width:260px;background:var(--
|
|
123935
|
+
.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)}
|
|
121687
123936
|
.dsh-ig-status-badge-wrap:hover .dsh-ig-status-popover{opacity:1;pointer-events:auto;transform:translateY(0)}
|
|
121688
|
-
.dsh-ig-status-popover-title{display:flex;align-items:center;justify-content:space-between;font-size:10px;font-weight:650;color
|
|
123937
|
+
.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}
|
|
121689
123938
|
.dsh-ig-status-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}
|
|
121690
123939
|
.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}
|
|
121691
123940
|
.dsh-ig-status-list li.is-configured{background:rgba(16,185,129,.05);border:1px solid rgba(16,185,129,.12)}
|
|
121692
123941
|
.dsh-ig-status-list li.is-missing{background:rgba(239,68,68,.04);border:1px solid rgba(239,68,68,.12);opacity:.75}
|
|
121693
123942
|
.dsh-ig-status-item-name{display:flex;flex-direction:column;min-width:0}
|
|
121694
|
-
.dsh-ig-status-item-name strong{font-size:11.5px;font-weight:600;color:var(--
|
|
121695
|
-
.dsh-ig-status-item-name small{font-size:9.5px;color
|
|
123943
|
+
.dsh-ig-status-item-name strong{font-size:11.5px;font-weight:600;color:var(--ig-fg);line-height:16px}
|
|
123944
|
+
.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}
|
|
121696
123945
|
.dsh-ig-status-item-tag{font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;flex-shrink:0}
|
|
121697
123946
|
.is-configured .dsh-ig-status-item-tag{color:#059669;background:rgba(16,185,129,.14)}
|
|
121698
123947
|
.is-missing .dsh-ig-status-item-tag{color:#dc2626;background:rgba(239,68,68,.14)}
|
|
121699
123948
|
.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}
|
|
121700
123949
|
.dsh-ig-canvas.is-dragging,.dsh-ig-canvas.is-dragging *{cursor:grabbing!important}
|
|
121701
123950
|
.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}
|
|
121702
|
-
.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
|
|
121703
|
-
.dsh-ig-generating-state strong{font-size:15px;color:var(--
|
|
121704
|
-
.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(--
|
|
121705
|
-
.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(--
|
|
121706
|
-
.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
|
|
121707
|
-
.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
|
|
121708
|
-
.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
|
|
121709
|
-
.dsh-ig-upload{height:92px;border:1px dashed
|
|
123951
|
+
.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}
|
|
123952
|
+
.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}
|
|
123953
|
+
.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}
|
|
123954
|
+
.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)}
|
|
123955
|
+
.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)}
|
|
123956
|
+
.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)}
|
|
123957
|
+
.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}
|
|
123958
|
+
.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)}
|
|
121710
123959
|
.dsh-ig-reference-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(64px,1fr));gap:8px}
|
|
121711
|
-
.dsh-ig-reference-card{position:relative;aspect-ratio:1;border-radius:8px;overflow:hidden;background
|
|
123960
|
+
.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)}
|
|
121712
123961
|
.dsh-ig-reference-card img{width:100%;height:100%;object-fit:cover}
|
|
121713
123962
|
.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}
|
|
121714
123963
|
.dsh-ig-reference-card button:hover{background:#ef4444}
|
|
121715
|
-
.dsh-ig-reference-add{aspect-ratio:1;border:1px dashed
|
|
123964
|
+
.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}
|
|
121716
123965
|
.dsh-ig-reference-add:hover{border-color:var(--ig-blue);background:rgba(47,100,245,.05);color:var(--ig-blue)}
|
|
121717
|
-
.dsh-ig-reference-preview{position:relative;height:108px;border-radius:9px;overflow:hidden;background
|
|
121718
|
-
.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
|
|
121719
|
-
.dsh-ig-config-error{padding:14px;display:flex;flex-direction:column;align-items:center;gap:10px;background
|
|
123966
|
+
.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}
|
|
123967
|
+
.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)}
|
|
123968
|
+
.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)}
|
|
121720
123969
|
.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}
|
|
121721
123970
|
.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)}
|
|
121722
|
-
.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
|
|
123971
|
+
.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}
|
|
121723
123972
|
.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}
|
|
121724
|
-
.dsh-ig-workbench-modal-box{width:100%;max-width:380px;background:var(--
|
|
123973
|
+
.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}
|
|
121725
123974
|
.dsh-ig-workbench-modal-header{display:flex;align-items:center;gap:10px}
|
|
121726
123975
|
.dsh-ig-workbench-modal-header strong{font-size:14px;font-weight:650;color:#b91c1c}
|
|
121727
|
-
.dsh-ig-workbench-modal-desc{font-size:12px;line-height:18px;color
|
|
121728
|
-
.dsh-ig-workbench-modal-option{display:flex;align-items:center;gap:8px;font-size:11.5px;color
|
|
123976
|
+
.dsh-ig-workbench-modal-desc{font-size:12px;line-height:18px;color:var(--ig-fg-2);margin:0}
|
|
123977
|
+
.dsh-ig-workbench-modal-option{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--ig-fg-2);cursor:pointer}
|
|
121729
123978
|
.dsh-ig-workbench-modal-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:4px}
|
|
121730
123979
|
.dsh-ig-workbench-modal-actions button{height:32px;padding:0 14px;border-radius:7px;font-size:11.5px;font-weight:600;cursor:pointer}
|
|
121731
|
-
.dsh-ig-workbench-modal-cancel{border:1px solid var(--ig-line);background:var(--
|
|
121732
|
-
.dsh-ig-workbench-modal-cancel:hover{background
|
|
123980
|
+
.dsh-ig-workbench-modal-cancel{border:1px solid var(--ig-line);background:var(--ig-bg);color:var(--ig-fg-2)}
|
|
123981
|
+
.dsh-ig-workbench-modal-cancel:hover{background:var(--ig-soft)}
|
|
121733
123982
|
.dsh-ig-workbench-modal-danger{border:0;background:#dc2626;color:#fff}
|
|
121734
123983
|
.dsh-ig-workbench-modal-danger:hover{background:#b91c1c}
|
|
121735
123984
|
@keyframes dshIgPulse{50%{transform:scale(1.06);box-shadow:0 0 0 16px rgba(47,100,245,.025)}}
|
|
121736
123985
|
.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}
|
|
121737
123986
|
@keyframes dshIgFade{from{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%,0)}}
|
|
121738
123987
|
@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}}
|
|
121739
|
-
@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}}
|
|
123988
|
+
@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}}
|
|
121740
123989
|
@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}}
|
|
121741
123990
|
@media(prefers-reduced-motion:reduce){.dsh-ig-workbench *{scroll-behavior:auto!important;animation-duration:.01ms!important;transition-duration:.01ms!important}}
|
|
121742
|
-
.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
|
|
121743
|
-
.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(--
|
|
121744
|
-
.dsh-ig-workspace-filter-label:hover{border-color
|
|
123991
|
+
.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)}
|
|
123992
|
+
.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}
|
|
123993
|
+
.dsh-ig-workspace-filter-label:hover{border-color:var(--ig-blue-line);background:rgba(47,100,245,.04)}
|
|
121745
123994
|
.dsh-ig-workspace-checkbox{cursor:pointer;accent-color:#2f64f5;width:13.5px;height:13.5px;margin:0}
|
|
121746
123995
|
.dsh-ig-workspace-filter-text{font-weight:500;white-space:nowrap}
|
|
121747
|
-
.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
|
|
123996
|
+
.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}
|
|
121748
123997
|
.dsh-ig-canvas-cluster{display:grid;gap:16px;align-items:center;justify-content:center;user-select:none;pointer-events:auto;flex-shrink:0}
|
|
121749
123998
|
.dsh-ig-canvas-cluster[data-count="2"]{grid-template-columns:repeat(2,1fr);max-width:880px}
|
|
121750
123999
|
.dsh-ig-canvas-cluster[data-count="3"],.dsh-ig-canvas-cluster[data-count="4"]{grid-template-columns:repeat(2,1fr);max-width:760px}
|
|
@@ -121757,19 +124006,19 @@ img.ProseMirror-separator {
|
|
|
121757
124006
|
.dsh-ig-canvas-badge.is-model{max-width:calc(100% - 20px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
|
|
121758
124007
|
.dsh-ig-canvas-item.is-checked .dsh-ig-canvas-badge{background:var(--ig-blue)}
|
|
121759
124008
|
.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)}
|
|
121760
|
-
.dsh-ig-canvas-item-loading{width:260px;height:260px;display:flex;align-items:center;justify-content:center;background:
|
|
124009
|
+
.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)}
|
|
121761
124010
|
.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)}
|
|
121762
124011
|
.dsh-ig-lightbox-nav:hover{background:rgba(47,100,245,.85);transform:translateY(-50%) scale(1.08)}
|
|
121763
124012
|
.dsh-ig-lightbox-nav.is-prev{left:18px}
|
|
121764
124013
|
.dsh-ig-lightbox-nav.is-next{right:18px}
|
|
121765
124014
|
.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}
|
|
121766
124015
|
.dsh-ig-save-gallery-btn:hover{background:rgba(47,100,245,.12)!important}
|
|
121767
|
-
.dsh-ig-save-gallery-btn.is-saved{color
|
|
124016
|
+
.dsh-ig-save-gallery-btn.is-saved{color:var(--ig-fg-2)!important;border-color:var(--ig-line)!important;background:transparent!important}
|
|
121768
124017
|
|
|
121769
124018
|
/* tldraw infinite canvas surface (P0 spike) */
|
|
121770
124019
|
.dsh-ig-tl-canvas{position:relative;flex:1 1 0;height:0;min-height:0;overflow:hidden;isolation:isolate}
|
|
121771
|
-
.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(--
|
|
121772
|
-
.dsh-ig-canvas-sync-status[data-phase='error']{color
|
|
124020
|
+
.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}
|
|
124021
|
+
.dsh-ig-canvas-sync-status[data-phase='error']{color:var(--ig-danger);border-color:rgba(239,68,68,.4)}
|
|
121773
124022
|
.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}
|
|
121774
124023
|
|
|
121775
124024
|
/* ---- Right-sidebar seat variant (DSH 0.1.5 'sidebar.right.pane.tab') ----
|
|
@@ -121962,6 +124211,10 @@ img.ProseMirror-separator {
|
|
|
121962
124211
|
.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}
|
|
121963
124212
|
.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)}
|
|
121964
124213
|
.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}
|
|
124214
|
+
.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)}
|
|
124215
|
+
.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}
|
|
124216
|
+
.dsh-ig-inspiration-group{margin:0}
|
|
124217
|
+
.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)}
|
|
121965
124218
|
.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)}
|
|
121966
124219
|
.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}
|
|
121967
124220
|
.dsh-ig-inspiration-empty.is-catalog-error{display:flex;flex-direction:column;gap:12px;color:var(--inspiration-text)}
|
|
@@ -121985,7 +124238,37 @@ img.ProseMirror-separator {
|
|
|
121985
124238
|
.dsh-ig-inspiration-end-hint{display:flex;align-items:center;justify-content:center;padding:24px 0 16px;color:var(--inspiration-muted);font-size:12px}
|
|
121986
124239
|
.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)}
|
|
121987
124240
|
.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)}
|
|
124241
|
+
.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)}
|
|
124242
|
+
.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}
|
|
121988
124243
|
@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}}
|
|
124244
|
+
|
|
124245
|
+
.dsh-ig-inspiration-source-chip svg{flex-shrink:0}
|
|
124246
|
+
.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}
|
|
124247
|
+
.dsh-ig-baoyu-intro{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
|
|
124248
|
+
.dsh-ig-baoyu-combos{font-size:12px;color:var(--inspiration-blue)}
|
|
124249
|
+
.dsh-ig-baoyu-hint{font-size:11px;color:var(--inspiration-muted)}
|
|
124250
|
+
.dsh-ig-baoyu-dim{display:flex;flex-direction:column;gap:7px}
|
|
124251
|
+
.dsh-ig-baoyu-dim-head{font-size:11px;font-weight:650;color:var(--inspiration-muted);letter-spacing:.02em}
|
|
124252
|
+
.dsh-ig-baoyu-chips{display:flex;flex-wrap:wrap;gap:6px}
|
|
124253
|
+
.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}
|
|
124254
|
+
.dsh-ig-baoyu-chip:hover{border-color:rgba(47,100,245,.46);color:var(--inspiration-blue)}
|
|
124255
|
+
.dsh-ig-baoyu-chip.is-active{border-color:var(--inspiration-blue);background:rgba(47,100,245,.09);color:var(--inspiration-blue)}
|
|
124256
|
+
.dsh-ig-baoyu-swatch{display:inline-flex;gap:2px}
|
|
124257
|
+
.dsh-ig-baoyu-swatch i{width:9px;height:9px;border-radius:50%;border:1px solid rgba(15,23,42,.15);display:block}
|
|
124258
|
+
.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}
|
|
124259
|
+
.dsh-ig-baoyu-title-input:focus{outline:none;border-color:rgba(47,100,245,.55)}
|
|
124260
|
+
.dsh-ig-baoyu-title-input:disabled{opacity:.45}
|
|
124261
|
+
.dsh-ig-baoyu-required{color:#dc2626;font-size:11px}
|
|
124262
|
+
.dsh-ig-baoyu-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
124263
|
+
.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}
|
|
124264
|
+
.dsh-ig-baoyu-btn:hover{border-color:rgba(47,100,245,.46);color:var(--inspiration-blue)}
|
|
124265
|
+
.dsh-ig-baoyu-btn:disabled{opacity:.5;cursor:not-allowed}
|
|
124266
|
+
.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)}
|
|
124267
|
+
.dsh-ig-baoyu-btn.is-primary:hover{color:#fff;transform:translateY(-1px)}
|
|
124268
|
+
.dsh-ig-baoyu-btn.is-primary:disabled{opacity:.5;cursor:not-allowed;transform:none}
|
|
124269
|
+
.dsh-ig-baoyu-preview-block{display:flex;flex-direction:column;gap:6px}
|
|
124270
|
+
.dsh-ig-baoyu-preview-head{font-size:11px;font-weight:650;color:var(--inspiration-muted)}
|
|
124271
|
+
.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}
|
|
121989
124272
|
`;
|
|
121990
124273
|
//#endregion
|
|
121991
124274
|
//#region lib/types/client/conversation-image-revisions.js
|
|
@@ -122500,7 +124783,7 @@ img.ProseMirror-separator {
|
|
|
122500
124783
|
`;
|
|
122501
124784
|
//#endregion
|
|
122502
124785
|
//#region lib/types/client/index.js
|
|
122503
|
-
console.info(`[dsh-image-gen] canvas bundle 2026-09-
|
|
124786
|
+
console.info(`[dsh-image-gen] canvas bundle 2026-09-30T06:41:54.565Z`);
|
|
122504
124787
|
/** Right-sidebar tab-type registration id (DSH 0.1.5 `sidebarRightTabs`). */
|
|
122505
124788
|
const SIDEBAR_STUDIO_TAB_ID = "dsh-image-gen/studio";
|
|
122506
124789
|
/** The tab kind: a page type opened by kind, recognizing no resource address. */
|
|
@@ -122528,6 +124811,7 @@ img.ProseMirror-separator {
|
|
|
122528
124811
|
subBadgeUnknown: "状态未知",
|
|
122529
124812
|
subSectionTitle: "订阅生图",
|
|
122530
124813
|
subHint: "通过已登录的订阅账号生图,无需 API Key。登录在你的授权下进行,不会修改任何 API Key 或默认 Provider。",
|
|
124814
|
+
subProxyHint: "需要代理时,请在登录前开启代理软件的 TUN(虚拟网卡)模式。普通系统代理可能无法覆盖 DSH 后端请求,导致网页授权后登录失败。",
|
|
122531
124815
|
subAccountLabel: "账号",
|
|
122532
124816
|
subAccountEmail: "已登录:{email}",
|
|
122533
124817
|
subAccountNone: "未登录",
|
|
@@ -122562,6 +124846,9 @@ img.ProseMirror-separator {
|
|
|
122562
124846
|
clearKeyFailed: "清除 Key 失败",
|
|
122563
124847
|
saveKeyFailed: "保存 Key 失败",
|
|
122564
124848
|
saveKeyFirst: "请先保存 API Key,再拉取模型或测试连接。",
|
|
124849
|
+
saveEndpointFirst: "接口地址尚未保存,请先点击保存,再拉取模型或测试连接。",
|
|
124850
|
+
endpointRequired: "请填写接口地址并保存,再拉取模型或测试连接。",
|
|
124851
|
+
savedEndpointMissing: "未读取到已保存的接口地址,请保存后重试。",
|
|
122565
124852
|
clearKeyUnsupported: "当前版本 DSH 不支持在此清除 Key,请到凭据管理中删除。",
|
|
122566
124853
|
endpoint: "接口地址",
|
|
122567
124854
|
reset: "重置",
|
|
@@ -122572,7 +124859,8 @@ img.ProseMirror-separator {
|
|
|
122572
124859
|
editFormat: "图生图请求形态",
|
|
122573
124860
|
editFormatMultipart: "标准 multipart(OpenAI 官方)",
|
|
122574
124861
|
editFormatJsonImageUrlArray: "JSON images 数组(商汤等中转)",
|
|
122575
|
-
|
|
124862
|
+
editFormatFormReferenceImages: "multipart + reference_images JSON 数组(base64)",
|
|
124863
|
+
editFormatHint: "文生图不受影响。仅当中转站的图生图接口使用自有契约(如商汤 SenseNova 的 JSON images 数组,或要求 reference_images base64 数组的中转)时才需要切换。",
|
|
122576
124864
|
editExtra: "附加 JSON 字段",
|
|
122577
124865
|
editExtraPlaceholder: "{\"watermark\": false, \"prompt_extend\": true}",
|
|
122578
124866
|
editExtraHint: "仅 JSON 形态生效;会合并到请求体末尾,可覆盖默认字段。留空表示不附加。",
|
|
@@ -122672,6 +124960,7 @@ img.ProseMirror-separator {
|
|
|
122672
124960
|
subBadgeUnknown: "Unknown",
|
|
122673
124961
|
subSectionTitle: "Subscription generation",
|
|
122674
124962
|
subHint: "Generates through a logged-in subscription account; no API key needed. Signing in never changes any API key or the default provider.",
|
|
124963
|
+
subProxyHint: "If you need a proxy, enable TUN (virtual network adapter) mode before signing in. A system proxy alone may not cover DSH backend requests, causing sign-in to fail after browser authorization.",
|
|
122675
124964
|
subAccountLabel: "Account",
|
|
122676
124965
|
subAccountEmail: "Signed in: {email}",
|
|
122677
124966
|
subAccountNone: "Not signed in",
|
|
@@ -122706,6 +124995,9 @@ img.ProseMirror-separator {
|
|
|
122706
124995
|
clearKeyFailed: "Failed to clear key",
|
|
122707
124996
|
saveKeyFailed: "Failed to save the key",
|
|
122708
124997
|
saveKeyFirst: "Save the API key first, then fetch models or test the connection.",
|
|
124998
|
+
saveEndpointFirst: "The endpoint address has not been saved. Click Save before fetching models or testing the connection.",
|
|
124999
|
+
endpointRequired: "Enter and save an endpoint address before fetching models or testing the connection.",
|
|
125000
|
+
savedEndpointMissing: "No saved endpoint address was found. Save it and try again.",
|
|
122709
125001
|
clearKeyUnsupported: "This DSH build cannot clear keys here; remove it from credential management instead.",
|
|
122710
125002
|
endpoint: "Endpoint / Base URL",
|
|
122711
125003
|
reset: "Reset",
|
|
@@ -122716,7 +125008,8 @@ img.ProseMirror-separator {
|
|
|
122716
125008
|
editFormat: "Edit request format",
|
|
122717
125009
|
editFormatMultipart: "Standard multipart (official OpenAI)",
|
|
122718
125010
|
editFormatJsonImageUrlArray: "JSON images array (SenseNova etc.)",
|
|
122719
|
-
|
|
125011
|
+
editFormatFormReferenceImages: "Multipart with a reference_images JSON array (base64)",
|
|
125012
|
+
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.",
|
|
122720
125013
|
editExtra: "Extra JSON fields",
|
|
122721
125014
|
editExtraPlaceholder: "{\"watermark\": false, \"prompt_extend\": true}",
|
|
122722
125015
|
editExtraHint: "Only used with the JSON format; merged into the request body last and may override defaults. Leave empty for none.",
|
|
@@ -123115,11 +125408,6 @@ img.ProseMirror-separator {
|
|
|
123115
125408
|
const configForms = ctx.get("configForms");
|
|
123116
125409
|
const settingsScopeApi = configForms === void 0 ? ctx.get("settingsScope") : void 0;
|
|
123117
125410
|
const scope = configForms?.get("image-gen") ?? settingsScopeApi?.bind({ namespace: "image-generation" }) ?? degradedScope();
|
|
123118
|
-
const chatScope = configForms?.get("ui-chat") ?? settingsScopeApi?.bind({ namespace: "ui-chat" }) ?? degradedScope();
|
|
123119
|
-
const isCompactTranscript = () => {
|
|
123120
|
-
const mode = chatScope.getSnapshot().value?.transcriptView;
|
|
123121
|
-
return configForms === void 0 ? mode !== "normal" : mode !== "standard" && mode !== "detailed" && mode !== "verbose";
|
|
123122
|
-
};
|
|
123123
125411
|
const locale = ctx.get("locale");
|
|
123124
125412
|
const promotion = { enabled: false };
|
|
123125
125413
|
ctx.inject(["sessions"], (owner) => {
|
|
@@ -123147,7 +125435,7 @@ img.ProseMirror-separator {
|
|
|
123147
125435
|
if (uiConversation === void 0) throw new Error("dsh-image-gen: uiConversation has an incompatible interface");
|
|
123148
125436
|
promotion.enabled = true;
|
|
123149
125437
|
const ownerRegister = owner.slots.register.bind(owner.slots);
|
|
123150
|
-
owner.effect(() => uiConversation.events.register(createImageResultDefinition(
|
|
125438
|
+
owner.effect(() => uiConversation.events.register(createImageResultDefinition()), "dsh-image-gen: promoted image result node");
|
|
123151
125439
|
owner.slots.inject("conversation.chat.node", () => ownerRegister({
|
|
123152
125440
|
name: "conversation.chat.node",
|
|
123153
125441
|
key: IMAGE_RESULT_NODE_KIND,
|
|
@@ -123246,6 +125534,14 @@ img.ProseMirror-separator {
|
|
|
123246
125534
|
promoted: promotion.enabled
|
|
123247
125535
|
})
|
|
123248
125536
|
}, GeneratedImageCard));
|
|
125537
|
+
ctx.slots.inject("tool.call.toolview", () => register({
|
|
125538
|
+
name: "tool.call.toolview",
|
|
125539
|
+
key: "generate_images",
|
|
125540
|
+
inject: () => ({
|
|
125541
|
+
locale,
|
|
125542
|
+
promoted: promotion.enabled
|
|
125543
|
+
})
|
|
125544
|
+
}, GeneratedImagesCard));
|
|
123249
125545
|
ctx.slots.inject("tool.call.toolview", () => register({
|
|
123250
125546
|
name: "tool.call.toolview",
|
|
123251
125547
|
key: "edit_image",
|
|
@@ -123409,6 +125705,10 @@ img.ProseMirror-separator {
|
|
|
123409
125705
|
return "";
|
|
123410
125706
|
}
|
|
123411
125707
|
}
|
|
125708
|
+
/** Persisted or selected edit-format value → row state; unknown values fall back to standard multipart. */
|
|
125709
|
+
function parseEditFormat(value) {
|
|
125710
|
+
return value === "jsonImageUrlArray" || value === "formReferenceImages" ? value : "multipart";
|
|
125711
|
+
}
|
|
123412
125712
|
/** Build one row per provider from persisted settings, including ComfyUI extras. */
|
|
123413
125713
|
function rowsFromSettings(value) {
|
|
123414
125714
|
const rows = {};
|
|
@@ -123422,7 +125722,7 @@ img.ProseMirror-separator {
|
|
|
123422
125722
|
timeoutSeconds: Math.max(1, Math.round((value?.comfyuiTimeoutMs ?? 3e5) / 1e3))
|
|
123423
125723
|
} : {},
|
|
123424
125724
|
...provider === "openai-compat" ? {
|
|
123425
|
-
editFormat: value?.openaiCompatEditFormat
|
|
125725
|
+
editFormat: parseEditFormat(value?.openaiCompatEditFormat),
|
|
123426
125726
|
editExtraText: editExtraTextOf(value?.openaiCompatEditExtra)
|
|
123427
125727
|
} : {},
|
|
123428
125728
|
...provider === "seedream" ? {
|
|
@@ -123811,11 +126111,23 @@ img.ProseMirror-separator {
|
|
|
123811
126111
|
updateRow(provider, { saving: false });
|
|
123812
126112
|
}
|
|
123813
126113
|
};
|
|
126114
|
+
/** These actions use host settings, so drafts must be saved before making a request. */
|
|
126115
|
+
const providerActionBlockMessage = (provider) => {
|
|
126116
|
+
const row = rows[provider];
|
|
126117
|
+
if (row.keyInput.trim().length > 0) return t("saveKeyFirst");
|
|
126118
|
+
if (isSubscriptionProvider(provider)) return void 0;
|
|
126119
|
+
const address = row.baseURL.trim();
|
|
126120
|
+
if (address.length === 0) return t("endpointRequired");
|
|
126121
|
+
if (address !== baseURLOf(provider, props.scope.getSnapshot().value).trim()) return t("saveEndpointFirst");
|
|
126122
|
+
};
|
|
126123
|
+
/** Localize the host's missing-address error while preserving upstream details. */
|
|
126124
|
+
const providerErrorMessage = (message) => message === "Base URL is not configured" ? t("savedEndpointMissing") : message ?? t("testFailed");
|
|
123814
126125
|
/** Probe through the host route so the browser side never touches credential values. */
|
|
123815
126126
|
const testConnection = async (provider) => {
|
|
123816
|
-
|
|
126127
|
+
const blocked = providerActionBlockMessage(provider);
|
|
126128
|
+
if (blocked !== void 0) {
|
|
123817
126129
|
updateRow(provider, {
|
|
123818
|
-
message:
|
|
126130
|
+
message: blocked,
|
|
123819
126131
|
messageIsError: false,
|
|
123820
126132
|
testResult: void 0
|
|
123821
126133
|
});
|
|
@@ -123847,9 +126159,10 @@ img.ProseMirror-separator {
|
|
|
123847
126159
|
};
|
|
123848
126160
|
/** Pull the provider's image-capable model ids through the host route (Google and the OpenAI family). */
|
|
123849
126161
|
const fetchProviderModels = async (provider) => {
|
|
123850
|
-
|
|
126162
|
+
const blocked = providerActionBlockMessage(provider);
|
|
126163
|
+
if (blocked !== void 0) {
|
|
123851
126164
|
updateRow(provider, {
|
|
123852
|
-
modelFetchMessage:
|
|
126165
|
+
modelFetchMessage: blocked,
|
|
123853
126166
|
modelFetchIsError: false
|
|
123854
126167
|
});
|
|
123855
126168
|
return;
|
|
@@ -123886,7 +126199,7 @@ img.ProseMirror-separator {
|
|
|
123886
126199
|
modelFetchIsError: true
|
|
123887
126200
|
});
|
|
123888
126201
|
else updateRow(provider, {
|
|
123889
|
-
modelFetchMessage: payload.message
|
|
126202
|
+
modelFetchMessage: providerErrorMessage(payload.message),
|
|
123890
126203
|
modelFetchIsError: true
|
|
123891
126204
|
});
|
|
123892
126205
|
} catch (cause) {
|
|
@@ -123937,7 +126250,7 @@ img.ProseMirror-separator {
|
|
|
123937
126250
|
if (result.ok) return t("testOk");
|
|
123938
126251
|
if (result.reason === "missing-key") return t("badgeMissing");
|
|
123939
126252
|
if (result.reason === "unauthorized") return t("testUnauthorized");
|
|
123940
|
-
return `${t("testFailed")}${result.message !== void 0 && result.message.length > 0 ? `: ${result.message}` : ""}`;
|
|
126253
|
+
return `${t("testFailed")}${result.message !== void 0 && result.message.length > 0 ? `: ${providerErrorMessage(result.message)}` : ""}`;
|
|
123941
126254
|
};
|
|
123942
126255
|
const badgeOf = (provider) => {
|
|
123943
126256
|
if (provider === "comfyui") return {
|
|
@@ -124239,16 +126552,23 @@ img.ProseMirror-separator {
|
|
|
124239
126552
|
className: "dsh-ig-input",
|
|
124240
126553
|
value: row.editFormat,
|
|
124241
126554
|
onChange: (event) => {
|
|
124242
|
-
updateRow(provider, { editFormat: event.target.value
|
|
126555
|
+
updateRow(provider, { editFormat: parseEditFormat(event.target.value) });
|
|
124243
126556
|
},
|
|
124244
126557
|
disabled: !snapshot.writable,
|
|
124245
|
-
children: [
|
|
124246
|
-
|
|
124247
|
-
|
|
124248
|
-
|
|
124249
|
-
|
|
124250
|
-
|
|
124251
|
-
|
|
126558
|
+
children: [
|
|
126559
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
126560
|
+
value: "multipart",
|
|
126561
|
+
children: t("editFormatMultipart")
|
|
126562
|
+
}),
|
|
126563
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
126564
|
+
value: "jsonImageUrlArray",
|
|
126565
|
+
children: t("editFormatJsonImageUrlArray")
|
|
126566
|
+
}),
|
|
126567
|
+
(0, react_jsx_runtime.jsx)("option", {
|
|
126568
|
+
value: "formReferenceImages",
|
|
126569
|
+
children: t("editFormatFormReferenceImages")
|
|
126570
|
+
})
|
|
126571
|
+
]
|
|
124252
126572
|
}),
|
|
124253
126573
|
(0, react_jsx_runtime.jsx)("span", {
|
|
124254
126574
|
className: "dsh-ig-hint",
|
|
@@ -124597,13 +126917,21 @@ img.ProseMirror-separator {
|
|
|
124597
126917
|
children: [
|
|
124598
126918
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
124599
126919
|
className: "dsh-ig-field",
|
|
124600
|
-
children: [
|
|
124601
|
-
|
|
124602
|
-
|
|
124603
|
-
|
|
124604
|
-
|
|
124605
|
-
|
|
124606
|
-
|
|
126920
|
+
children: [
|
|
126921
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
126922
|
+
className: "dsh-ig-label",
|
|
126923
|
+
children: t("subSectionTitle")
|
|
126924
|
+
}),
|
|
126925
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
126926
|
+
className: "dsh-ig-hint",
|
|
126927
|
+
children: t("subHint")
|
|
126928
|
+
}),
|
|
126929
|
+
(0, react_jsx_runtime.jsx)("p", {
|
|
126930
|
+
className: "dsh-ig-hint",
|
|
126931
|
+
role: "note",
|
|
126932
|
+
children: t("subProxyHint")
|
|
126933
|
+
})
|
|
126934
|
+
]
|
|
124607
126935
|
}),
|
|
124608
126936
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
124609
126937
|
className: "dsh-ig-field",
|
|
@@ -124929,15 +127257,41 @@ img.ProseMirror-separator {
|
|
|
124929
127257
|
sessionId: props.sessionId
|
|
124930
127258
|
});
|
|
124931
127259
|
}
|
|
127260
|
+
/** Suppress the folded duplicate on modern hosts; render every image on legacy hosts. */
|
|
127261
|
+
function GeneratedImagesCard(props) {
|
|
127262
|
+
const block = props.block;
|
|
127263
|
+
let results = imageResultsFromMeta(block.meta ?? block.resultView?.meta);
|
|
127264
|
+
if (results.length === 0 && "kind" in block) results = ((block.resultView?.card === "generic" ? block.resultView.content : block.content) ?? []).flatMap((item) => item.type === "image" && item.attachment !== void 0 ? [{
|
|
127265
|
+
attachment: item.attachment,
|
|
127266
|
+
prompt: "Generated Image",
|
|
127267
|
+
provider: "",
|
|
127268
|
+
model: "",
|
|
127269
|
+
output: ""
|
|
127270
|
+
}] : []);
|
|
127271
|
+
if (props.promoted && results.length > 0) return (0, react_jsx_runtime.jsx)(PromotedResultNotice, { locale: props.locale });
|
|
127272
|
+
if (results.length === 0) {
|
|
127273
|
+
if (!("kind" in block)) return (0, react_jsx_runtime.jsx)(ImageResultCard, { locale: props.locale });
|
|
127274
|
+
const content = block.content ?? block.resultView?.content ?? [];
|
|
127275
|
+
return (0, react_jsx_runtime.jsx)("div", { children: content.filter((item) => item.type === "text").map((item, index) => (0, react_jsx_runtime.jsx)("p", { children: item.text }, index)) });
|
|
127276
|
+
}
|
|
127277
|
+
return (0, react_jsx_runtime.jsx)("div", {
|
|
127278
|
+
className: "dsh-ig-promoted-results",
|
|
127279
|
+
children: results.map((result, index) => (0, react_jsx_runtime.jsx)(ImageResultCard, {
|
|
127280
|
+
result,
|
|
127281
|
+
locale: props.locale,
|
|
127282
|
+
sessionId: props.sessionId
|
|
127283
|
+
}, `${result.attachment.attachmentId}:${index}`))
|
|
127284
|
+
});
|
|
127285
|
+
}
|
|
124932
127286
|
/** Render modern image artifacts as final conversation output instead of Tool process content. */
|
|
124933
127287
|
function PromotedImageResultNode(props) {
|
|
124934
127288
|
return (0, react_jsx_runtime.jsx)("div", {
|
|
124935
127289
|
className: "dsh-ig-promoted-results",
|
|
124936
|
-
children: props.node.data.results.map((result) => (0, react_jsx_runtime.jsx)(ImageResultCard, {
|
|
127290
|
+
children: props.node.data.results.map((result, index) => (0, react_jsx_runtime.jsx)(ImageResultCard, {
|
|
124937
127291
|
result,
|
|
124938
127292
|
locale: props.locale,
|
|
124939
127293
|
sessionId: props.sessionId
|
|
124940
|
-
}, result.attachment.attachmentId))
|
|
127294
|
+
}, `${result.attachment.attachmentId}:${index}`))
|
|
124941
127295
|
});
|
|
124942
127296
|
}
|
|
124943
127297
|
function PromotedResultNotice({ locale }) {
|
|
@@ -125404,7 +127758,6 @@ img.ProseMirror-separator {
|
|
|
125404
127758
|
(0, react_jsx_runtime.jsxs)("label", { children: [(0, react_jsx_runtime.jsx)("span", { children: t("prompt") }), (0, react_jsx_runtime.jsx)("textarea", {
|
|
125405
127759
|
ref: regenerateTextareaRef,
|
|
125406
127760
|
value: regeneratePrompt,
|
|
125407
|
-
maxLength: 2e3,
|
|
125408
127761
|
disabled: isRegenerating,
|
|
125409
127762
|
onChange: (event) => setRegeneratePrompt(event.target.value),
|
|
125410
127763
|
onKeyDown: (event) => {
|
|
@@ -125476,6 +127829,7 @@ img.ProseMirror-separator {
|
|
|
125476
127829
|
}
|
|
125477
127830
|
//#endregion
|
|
125478
127831
|
exports.GeneratedImageCard = GeneratedImageCard;
|
|
127832
|
+
exports.GeneratedImagesCard = GeneratedImagesCard;
|
|
125479
127833
|
exports.ImageGenerationSettingsCard = ImageGenerationSettingsCard;
|
|
125480
127834
|
exports.PromotedImageResultNode = PromotedImageResultNode;
|
|
125481
127835
|
exports.apply = apply;
|