@dickpy/dsh-imagegen 1.0.7 → 1.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -12,7 +12,7 @@ window.__ModuleLoader__.load({
12
12
  let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
13
13
  //#region src/protocol.ts
14
14
  /** Published package version shared by the host updater and the client UI. */
15
- const PLUGIN_VERSION = "1.0.7";
15
+ const PLUGIN_VERSION = "1.0.19";
16
16
  /** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
17
17
  const SETTINGS_API = {
18
18
  describe: "/api/dsh-imagegen/settings/describe",
@@ -38,6 +38,29 @@ window.__ModuleLoader__.load({
38
38
  clear: "/api/dsh-imagegen/history/clear",
39
39
  image: "/api/dsh-imagegen/history/image"
40
40
  };
41
+ /**
42
+ * Same-origin route family for the user-curated gallery (favorites). Entries
43
+ * reuse the history wire shape and persist under ~/.dsh/dsh-imagegen/gallery/;
44
+ * unlike history there is no size cap 鈥?the user adds images on purpose.
45
+ */
46
+ const GALLERY_API = {
47
+ list: "/api/dsh-imagegen/gallery/list",
48
+ append: "/api/dsh-imagegen/gallery/append",
49
+ remove: "/api/dsh-imagegen/gallery/remove",
50
+ clear: "/api/dsh-imagegen/gallery/clear",
51
+ image: "/api/dsh-imagegen/gallery/image"
52
+ };
53
+ /**
54
+ * Same-origin route family for the bundled prompt-template library
55
+ * (awesome-gpt-image-2 mirror). The case list ships inside the package and is
56
+ * served by the host; reference images are proxied through the `image` prefix
57
+ * route and cached on disk so repeated views never hit the network again.
58
+ */
59
+ const TEMPLATES_API = {
60
+ list: "/api/dsh-imagegen/templates/list",
61
+ refresh: "/api/dsh-imagegen/templates/refresh",
62
+ image: "/api/dsh-imagegen/templates/image"
63
+ };
41
64
  //#endregion
42
65
  //#region src/client/api.ts
43
66
  /**
@@ -114,6 +137,54 @@ window.__ModuleLoader__.load({
114
137
  async historyClear() {
115
138
  return (await readEnvelope(await fetch(HISTORY_API.clear, { method: "POST" }))).entries;
116
139
  }
140
+ /** List the host-persisted gallery (newest first). */
141
+ async galleryList() {
142
+ return (await readEnvelope(await fetch(GALLERY_API.list, { method: "POST" }))).entries;
143
+ }
144
+ /** Append one image to the gallery. The host assigns the id and skips the
145
+ * append when a content-identical image is already in the gallery. */
146
+ async galleryAppend(entry) {
147
+ const body = await readEnvelope(await fetch(GALLERY_API.append, {
148
+ method: "POST",
149
+ headers: { "content-type": "application/json" },
150
+ body: JSON.stringify({ entry })
151
+ }));
152
+ return {
153
+ entries: body.entries,
154
+ added: body.added
155
+ };
156
+ }
157
+ /** Remove one gallery entry by id. */
158
+ async galleryRemove(id) {
159
+ return (await readEnvelope(await fetch(GALLERY_API.remove, {
160
+ method: "POST",
161
+ headers: { "content-type": "application/json" },
162
+ body: JSON.stringify({ id })
163
+ }))).entries;
164
+ }
165
+ /** Clear the entire gallery. */
166
+ async galleryClear() {
167
+ return (await readEnvelope(await fetch(GALLERY_API.clear, { method: "POST" }))).entries;
168
+ }
169
+ /** Fetch the prompt-template library (bundled snapshot or refreshed copy). */
170
+ async templatesList() {
171
+ const body = await readEnvelope(await fetch(TEMPLATES_API.list, { method: "POST" }));
172
+ return {
173
+ cases: body.cases,
174
+ total: body.total,
175
+ origin: body.origin,
176
+ repository: body.repository,
177
+ fetchedAt: body.fetchedAt
178
+ };
179
+ }
180
+ /** Re-download the template library from the upstream mirror (host-side). */
181
+ async templatesRefresh() {
182
+ const body = await readEnvelope(await fetch(TEMPLATES_API.refresh, { method: "POST" }));
183
+ return {
184
+ total: body.total,
185
+ fetchedAt: body.fetchedAt
186
+ };
187
+ }
117
188
  };
118
189
  //#endregion
119
190
  //#region src/client/controller.ts
@@ -155,9 +226,9 @@ window.__ModuleLoader__.load({
155
226
  */
156
227
  const zh = {
157
228
  "entry.label": "AI 生图",
158
- "entry.tooltip": "AI 生图面板(gpt-image-2)",
229
+ "entry.tooltip": "AI 生图面板(gpt-image-2 / grok-imagine-image)",
159
230
  "panel.title": "AI 生图",
160
- "panel.subtitle": "gpt-image-2 图像生成",
231
+ "panel.githubTip": "觉得好用或有建议?欢迎来 GitHub 提 issues、点个 star 支持一下!",
161
232
  "mode.text": "文生图",
162
233
  "mode.edit": "图生图",
163
234
  "prompt.placeholder": "描述你想要的画面,例如:一只戴着宇航员头盔的橘猫,在月球上举起望远镜,水彩风格,柔和光线…",
@@ -168,16 +239,18 @@ window.__ModuleLoader__.load({
168
239
  "params.count": "生成数量",
169
240
  "params.detail": "细节",
170
241
  "size.auto": "自动",
171
- "size.square": "1024×1024",
172
- "size.landscape": "1536×1024",
173
- "size.portrait": "1024×1536",
174
- "size.small": "512×512",
175
- "size.wide": "1792×1024",
176
- "size.tall": "1024×1792",
242
+ "size.square": "1:1 方图",
243
+ "size.portrait34": "3:4 标准竖图",
244
+ "size.landscape43": "4:3 标准横图",
245
+ "size.portrait916": "9:16 竖屏",
246
+ "size.portrait23": "2:3 竖图",
247
+ "size.landscape32": "3:2 横图",
248
+ "size.wide169": "16:9 宽屏",
249
+ "size.ultrawide21": "21:9 超宽屏",
177
250
  "quality.auto": "自动",
178
- "quality.low": "",
179
- "quality.medium": "",
180
- "quality.high": "",
251
+ "quality.1k": "1K",
252
+ "quality.2k": "2K",
253
+ "quality.4k": "4K",
181
254
  "count.one": "1 张",
182
255
  "count.two": "2 张",
183
256
  "count.three": "3 张",
@@ -209,6 +282,28 @@ window.__ModuleLoader__.load({
209
282
  "history.delete": "删除",
210
283
  "history.images": "张",
211
284
  "history.viewing": "历史 · {time}",
285
+ "gallery.title": "画廊",
286
+ "gallery.categories": "分类",
287
+ "gallery.all": "全部作品",
288
+ "gallery.gpt": "gpt-image-2",
289
+ "gallery.grok": "grok-imagine-image",
290
+ "gallery.ratio": "画面比例",
291
+ "gallery.filterHint": "按生成模式、模型和比例筛选画廊",
292
+ "gallery.count": "· 共 {count} 幅",
293
+ "gallery.viewMode": "视图模式",
294
+ "gallery.masonry": "瀑布流",
295
+ "gallery.grid": "整齐网格",
296
+ "gallery.sort": "排序",
297
+ "gallery.newest": "最新发布",
298
+ "gallery.oldest": "最早发布",
299
+ "gallery.untitled": "未命名作品",
300
+ "gallery.add": "加入画廊",
301
+ "gallery.added": "已加入画廊",
302
+ "gallery.already": "已在画廊中",
303
+ "gallery.delete": "移出画廊",
304
+ "gallery.clear": "清空画廊",
305
+ "gallery.empty": "画廊还是空的,把喜欢的图片加入进来吧",
306
+ "gallery.viewing": "画廊 · {time}",
212
307
  "preview.title": "图片预览",
213
308
  "preview.open": "点击预览",
214
309
  "preview.close": "关闭",
@@ -261,13 +356,40 @@ window.__ModuleLoader__.load({
261
356
  "settings.off": "关",
262
357
  "settings.overridden": "已覆盖",
263
358
  "settings.reset": "重置",
264
- "settings.invalidNumber": "请输入有效数字"
359
+ "settings.invalidNumber": "请输入有效数字",
360
+ "templates.open": "模板库",
361
+ "templates.title": "提示词模板库",
362
+ "templates.meta": "共 {count} 个模板 · {origin}",
363
+ "templates.origin.bundled": "内置快照",
364
+ "templates.origin.refreshed": "在线刷新",
365
+ "templates.search": "搜索模板标题或提示词…",
366
+ "templates.all": "全部",
367
+ "templates.close": "关闭",
368
+ "templates.back": "返回列表",
369
+ "templates.use": "使用此提示词",
370
+ "templates.copy": "复制提示词",
371
+ "templates.copied": "已复制",
372
+ "templates.refresh": "刷新模板库",
373
+ "templates.refreshing": "刷新中…",
374
+ "templates.refreshed": "已刷新,共 {count} 个模板",
375
+ "templates.refreshFailed": "刷新失败:{error}",
376
+ "templates.cacheAll": "缓存全部图片",
377
+ "templates.cacheAllHint": "通过本机代理把全部参考图缓存到本地磁盘,之后离线也能浏览",
378
+ "templates.caching": "缓存中 {done}/{total}…",
379
+ "templates.cached": "图片已全部缓存",
380
+ "templates.empty": "没有匹配的模板",
381
+ "templates.loading": "正在加载模板库…",
382
+ "templates.loadFailed": "模板库加载失败:{error}",
383
+ "templates.retry": "重试",
384
+ "templates.attribution": "模板与图片来自 awesome-gpt-image-2 项目,作者链接见各模板详情",
385
+ "templates.source": "来源:vibeui.top",
386
+ "templates.featured": "精选"
265
387
  };
266
388
  const en = {
267
389
  "entry.label": "AI Image",
268
- "entry.tooltip": "AI image generation studio (gpt-image-2)",
390
+ "entry.tooltip": "AI image generation studio (gpt-image-2 / grok-imagine-image)",
269
391
  "panel.title": "AI Image",
270
- "panel.subtitle": "gpt-image-2 image generation",
392
+ "panel.githubTip": "Like it or have suggestions? Head to GitHub to open issues and star us!",
271
393
  "mode.text": "Text to Image",
272
394
  "mode.edit": "Image to Image",
273
395
  "prompt.placeholder": "Describe the picture you want, e.g. an orange cat in an astronaut helmet raising a telescope on the moon, watercolor style, soft light…",
@@ -278,16 +400,18 @@ window.__ModuleLoader__.load({
278
400
  "params.count": "Count",
279
401
  "params.detail": "Detail",
280
402
  "size.auto": "Auto",
281
- "size.square": "1024×1024",
282
- "size.landscape": "1536×1024",
283
- "size.portrait": "1024×1536",
284
- "size.small": "512×512",
285
- "size.wide": "1792×1024",
286
- "size.tall": "1024×1792",
403
+ "size.square": "1:1 Square",
404
+ "size.portrait34": "3:4 Portrait",
405
+ "size.landscape43": "4:3 Landscape",
406
+ "size.portrait916": "9:16 Vertical",
407
+ "size.portrait23": "2:3 Portrait",
408
+ "size.landscape32": "3:2 Landscape",
409
+ "size.wide169": "16:9 Widescreen",
410
+ "size.ultrawide21": "21:9 Ultrawide",
287
411
  "quality.auto": "Auto",
288
- "quality.low": "Low",
289
- "quality.medium": "Medium",
290
- "quality.high": "High",
412
+ "quality.1k": "1K",
413
+ "quality.2k": "2K",
414
+ "quality.4k": "4K",
291
415
  "count.one": "1",
292
416
  "count.two": "2",
293
417
  "count.three": "3",
@@ -319,6 +443,28 @@ window.__ModuleLoader__.load({
319
443
  "history.delete": "Delete",
320
444
  "history.images": "images",
321
445
  "history.viewing": "History · {time}",
446
+ "gallery.title": "Gallery",
447
+ "gallery.categories": "Categories",
448
+ "gallery.all": "All works",
449
+ "gallery.gpt": "gpt-image-2",
450
+ "gallery.grok": "grok-imagine-image",
451
+ "gallery.ratio": "Aspect ratio",
452
+ "gallery.filterHint": "Filter by mode, model, and aspect ratio",
453
+ "gallery.count": "· {count} works",
454
+ "gallery.viewMode": "View mode",
455
+ "gallery.masonry": "Masonry",
456
+ "gallery.grid": "Grid",
457
+ "gallery.sort": "Sort",
458
+ "gallery.newest": "Newest",
459
+ "gallery.oldest": "Oldest",
460
+ "gallery.untitled": "Untitled work",
461
+ "gallery.add": "Add to gallery",
462
+ "gallery.added": "Added to gallery",
463
+ "gallery.already": "Already in gallery",
464
+ "gallery.delete": "Remove",
465
+ "gallery.clear": "Clear gallery",
466
+ "gallery.empty": "The gallery is empty — add images you like here",
467
+ "gallery.viewing": "Gallery · {time}",
322
468
  "preview.title": "Image preview",
323
469
  "preview.open": "Click to preview",
324
470
  "preview.close": "Close",
@@ -371,7 +517,34 @@ window.__ModuleLoader__.load({
371
517
  "settings.off": "Off",
372
518
  "settings.overridden": "Overridden",
373
519
  "settings.reset": "Reset",
374
- "settings.invalidNumber": "Enter a valid number"
520
+ "settings.invalidNumber": "Enter a valid number",
521
+ "templates.open": "Templates",
522
+ "templates.title": "Prompt Template Library",
523
+ "templates.meta": "{count} templates · {origin}",
524
+ "templates.origin.bundled": "bundled snapshot",
525
+ "templates.origin.refreshed": "refreshed online",
526
+ "templates.search": "Search template titles or prompts…",
527
+ "templates.all": "All",
528
+ "templates.close": "Close",
529
+ "templates.back": "Back to list",
530
+ "templates.use": "Use this prompt",
531
+ "templates.copy": "Copy prompt",
532
+ "templates.copied": "Copied",
533
+ "templates.refresh": "Refresh library",
534
+ "templates.refreshing": "Refreshing…",
535
+ "templates.refreshed": "Refreshed — {count} templates",
536
+ "templates.refreshFailed": "Refresh failed: {error}",
537
+ "templates.cacheAll": "Cache all images",
538
+ "templates.cacheAllHint": "Mirror every reference image to local disk through the host proxy, for offline browsing",
539
+ "templates.caching": "Caching {done}/{total}…",
540
+ "templates.cached": "All images cached",
541
+ "templates.empty": "No matching templates",
542
+ "templates.loading": "Loading the template library…",
543
+ "templates.loadFailed": "Failed to load the library: {error}",
544
+ "templates.retry": "Retry",
545
+ "templates.attribution": "Templates and images come from the awesome-gpt-image-2 project; author links are on each template",
546
+ "templates.source": "Source: vibeui.top",
547
+ "templates.featured": "Featured"
375
548
  };
376
549
  //#endregion
377
550
  //#region src/client/helpers.ts
@@ -398,8 +571,535 @@ window.__ModuleLoader__.load({
398
571
  return String(error);
399
572
  }
400
573
  //#endregion
574
+ //#region \0dsh-css:E:\dsh-plugin\src\client\templates.module.css.mjs
575
+ const css$2 = ".o0mAxG_overlay,.o0mAxG_overlay *,.o0mAxG_overlay :before,.o0mAxG_overlay :after{box-sizing:border-box}.o0mAxG_overlay{z-index:130;background:var(--dsw-alias-bg-mask-1);color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);justify-content:center;align-items:center;padding:28px;display:flex;position:fixed;inset:0}.o0mAxG_shell{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);border-radius:14px;flex-direction:column;width:min(1180px,100%);height:100%;max-height:100%;display:flex;overflow:hidden;box-shadow:0 18px 60px #00000047}.o0mAxG_header{flex:none;justify-content:space-between;align-items:center;gap:12px;padding:14px 18px 10px;display:flex}.o0mAxG_heading{align-items:baseline;gap:10px;min-width:0;display:flex}.o0mAxG_title{margin:0;font-size:15px;font-weight:650}.o0mAxG_meta{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px}.o0mAxG_headerActions{flex:none;align-items:center;gap:8px;display:inline-flex}.o0mAxG_close{width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:8px;justify-content:center;align-items:center;display:inline-flex}.o0mAxG_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.o0mAxG_toolbar{flex-direction:column;flex:none;gap:10px;padding:0 18px 12px;display:flex}.o0mAxG_search{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);width:100%;height:34px;color:var(--dsw-alias-label-primary);border-radius:9px;outline:none;padding:0 12px;font-family:inherit;font-size:13px}.o0mAxG_search:focus{border-color:var(--dsw-alias-brand-primary)}.o0mAxG_search::placeholder{color:var(--dsw-alias-label-dimmed)}.o0mAxG_categoryRow{flex-wrap:wrap;gap:6px;max-height:64px;display:flex;overflow-y:auto}.o0mAxG_categoryPill{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;border-radius:999px;padding:0 11px;font-family:inherit;font-size:12px}.o0mAxG_categoryPill:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}.o0mAxG_categoryPill[data-active]{border-color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-base)}.o0mAxG_notice{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);border-radius:9px;flex:none;margin:0 18px 10px;padding:8px 12px;font-size:12px}.o0mAxG_body{flex:1;min-height:0;padding:2px 18px 14px;overflow-y:auto}.o0mAxG_state{height:100%;min-height:220px;color:var(--dsw-alias-label-tertiary);flex-direction:column;justify-content:center;align-items:center;gap:12px;font-size:13px;display:flex}.o0mAxG_spinner{border:2px solid var(--dsw-alias-border-l2);border-top-color:var(--dsw-alias-brand-primary);border-radius:50%;width:26px;height:26px;animation:.9s linear infinite o0mAxG_dsh-imagegen-templates-spin}@keyframes o0mAxG_dsh-imagegen-templates-spin{to{transform:rotate(360deg)}}.o0mAxG_grid{grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px;display:grid}.o0mAxG_card{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);cursor:pointer;text-align:left;color:var(--dsw-alias-label-primary);border-radius:11px;flex-direction:column;gap:0;padding:0;font-family:inherit;transition:border-color .15s,transform .15s;display:flex;overflow:hidden}.o0mAxG_card:hover{border-color:var(--dsw-alias-brand-primary);transform:translateY(-1px)}.o0mAxG_thumbWrap{aspect-ratio:1;background:var(--dsw-alias-bg-layer-2);width:100%;display:block;position:relative}.o0mAxG_thumb{object-fit:cover;width:100%;height:100%;display:block}.o0mAxG_thumbPlaceholder{width:100%;height:100%;color:var(--dsw-alias-label-dimmed);justify-content:center;align-items:center;display:flex}.o0mAxG_featuredBadge{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-bg-base);border-radius:999px;padding:2px 8px;font-size:11px;font-weight:600;position:absolute;top:8px;left:8px}.o0mAxG_cardBody{flex-direction:column;gap:4px;min-width:0;padding:9px 11px 10px;display:flex}.o0mAxG_cardTitle{-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12.5px;font-weight:600;line-height:1.35;display:-webkit-box;overflow:hidden}.o0mAxG_cardMeta{min-width:0;color:var(--dsw-alias-label-tertiary);align-items:center;gap:6px;font-size:11px;display:flex}.o0mAxG_cardCategory{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 7px}.o0mAxG_cardSource{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.o0mAxG_footer{border-top:1px solid var(--dsw-alias-border-l1);flex:none;justify-content:space-between;align-items:center;gap:10px;padding:9px 18px;display:flex}.o0mAxG_attribution{color:var(--dsw-alias-label-dimmed);min-width:0;font-size:11.5px}.o0mAxG_sourceLink{color:var(--dsw-alias-brand-primary);white-space:nowrap;flex:none;font-size:11.5px;font-weight:600;text-decoration:none}.o0mAxG_sourceLink:hover{text-decoration:underline}.o0mAxG_detailOverlay{background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;padding:34px;display:flex;position:absolute;inset:0}.o0mAxG_detail{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);border-radius:14px;grid-template-rows:minmax(0,1fr);grid-template-columns:minmax(0,5fr) minmax(0,4fr);gap:0;width:min(980px,100%);max-height:100%;display:grid;overflow:hidden;box-shadow:0 18px 60px #00000052}.o0mAxG_detailMedia{background:var(--dsw-alias-bg-layer-2);justify-content:center;align-items:center;min-height:0;display:flex;overflow:hidden}.o0mAxG_detailImage{object-fit:contain;width:100%;height:100%;display:block}.o0mAxG_detailInfo{flex-direction:column;gap:10px;min-height:0;padding:18px;display:flex;overflow-y:auto}.o0mAxG_detailTitle{margin:0;font-size:15px;font-weight:650;line-height:1.4}.o0mAxG_detailMeta{color:var(--dsw-alias-label-tertiary);flex-wrap:wrap;align-items:center;gap:8px;font-size:12px;display:flex}.o0mAxG_detailLink{color:var(--dsw-alias-brand-primary);text-overflow:ellipsis;white-space:nowrap;text-decoration:none;overflow:hidden}.o0mAxG_detailLink:hover{text-decoration:underline}.o0mAxG_detailPrompt{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);min-height:0;color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;user-select:text;border-radius:10px;flex:1;margin:0;padding:12px;font-family:inherit;font-size:12.5px;line-height:1.6;overflow-y:auto}.o0mAxG_detailActions{background:var(--dsw-alias-bg-base);border-top:1px solid var(--dsw-alias-border-l1);flex:none;gap:8px;margin:0 -18px -18px;padding:12px 18px;display:flex;position:sticky;bottom:0}@media (width<=760px){.o0mAxG_detail{grid-template-rows:minmax(0,3fr) minmax(0,4fr);grid-template-columns:1fr}}";
576
+ const tagId$2 = "@dickpy/dsh-imagegen/templates.module.css";
577
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
578
+ const tag = document.createElement("style");
579
+ tag.dataset.plugin = "@dickpy/dsh-imagegen";
580
+ tag.dataset.pluginCss = tagId$2;
581
+ tag.textContent = css$2;
582
+ document.head.appendChild(tag);
583
+ }
584
+ var templates_module_css_default = {
585
+ "title": "o0mAxG_title",
586
+ "cardCategory": "o0mAxG_cardCategory",
587
+ "cardTitle": "o0mAxG_cardTitle",
588
+ "sourceLink": "o0mAxG_sourceLink",
589
+ "detailInfo": "o0mAxG_detailInfo",
590
+ "heading": "o0mAxG_heading",
591
+ "detailMeta": "o0mAxG_detailMeta",
592
+ "attribution": "o0mAxG_attribution",
593
+ "detailLink": "o0mAxG_detailLink",
594
+ "detailActions": "o0mAxG_detailActions",
595
+ "shell": "o0mAxG_shell",
596
+ "card": "o0mAxG_card",
597
+ "body": "o0mAxG_body",
598
+ "featuredBadge": "o0mAxG_featuredBadge",
599
+ "footer": "o0mAxG_footer",
600
+ "meta": "o0mAxG_meta",
601
+ "dsh-imagegen-templates-spin": "o0mAxG_dsh-imagegen-templates-spin",
602
+ "spinner": "o0mAxG_spinner",
603
+ "headerActions": "o0mAxG_headerActions",
604
+ "overlay": "o0mAxG_overlay",
605
+ "notice": "o0mAxG_notice",
606
+ "thumbWrap": "o0mAxG_thumbWrap",
607
+ "cardSource": "o0mAxG_cardSource",
608
+ "thumbPlaceholder": "o0mAxG_thumbPlaceholder",
609
+ "detailImage": "o0mAxG_detailImage",
610
+ "categoryRow": "o0mAxG_categoryRow",
611
+ "thumb": "o0mAxG_thumb",
612
+ "cardMeta": "o0mAxG_cardMeta",
613
+ "detailMedia": "o0mAxG_detailMedia",
614
+ "grid": "o0mAxG_grid",
615
+ "cardBody": "o0mAxG_cardBody",
616
+ "detail": "o0mAxG_detail",
617
+ "search": "o0mAxG_search",
618
+ "detailTitle": "o0mAxG_detailTitle",
619
+ "detailOverlay": "o0mAxG_detailOverlay",
620
+ "header": "o0mAxG_header",
621
+ "categoryPill": "o0mAxG_categoryPill",
622
+ "toolbar": "o0mAxG_toolbar",
623
+ "close": "o0mAxG_close",
624
+ "state": "o0mAxG_state",
625
+ "detailPrompt": "o0mAxG_detailPrompt"
626
+ };
627
+ //#endregion
628
+ //#region src/client/TemplateLibrary.tsx
629
+ /**
630
+ * Prompt-template library overlay: a searchable, category-filtered gallery of
631
+ * the bundled awesome-gpt-image-2 cases. The case list is served by the host
632
+ * (bundled snapshot, optionally refreshed online); reference images load
633
+ * lazily through the host's caching proxy, so browsing progressively mirrors
634
+ * the gallery onto the local disk. Picking a template hands its prompt back
635
+ * to the studio form.
636
+ */
637
+ /** Concurrent image downloads while caching the whole gallery offline. */
638
+ const CACHE_ALL_CONCURRENCY = 4;
639
+ /** Same-origin URL of one case's reference image (host caching proxy). */
640
+ function imageUrlOf(item) {
641
+ return `${TEMPLATES_API.image}/${encodeURIComponent(item.image)}`;
642
+ }
643
+ /** A card thumbnail that falls back to a placeholder when the proxy 404s. */
644
+ function TemplateThumb(props) {
645
+ const [failed, setFailed] = (0, react.useState)(false);
646
+ if (props.item.image === "" || failed) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
647
+ className: templates_module_css_default.thumbPlaceholder,
648
+ "aria-hidden": "true",
649
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
650
+ viewBox: "0 0 24 24",
651
+ width: "26",
652
+ height: "26",
653
+ fill: "none",
654
+ stroke: "currentColor",
655
+ strokeWidth: "1.2",
656
+ strokeLinecap: "round",
657
+ strokeLinejoin: "round",
658
+ children: [
659
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
660
+ x: "3",
661
+ y: "3",
662
+ width: "18",
663
+ height: "18",
664
+ rx: "3"
665
+ }),
666
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
667
+ cx: "8.5",
668
+ cy: "8.5",
669
+ r: "1.5"
670
+ }),
671
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 15l-5-5L5 21" })
672
+ ]
673
+ })
674
+ });
675
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
676
+ className: templates_module_css_default.thumb,
677
+ src: imageUrlOf(props.item),
678
+ alt: props.item.title,
679
+ loading: "lazy",
680
+ onError: () => {
681
+ setFailed(true);
682
+ }
683
+ });
684
+ }
685
+ /** The template-library modal. Rendered through a portal above the studio. */
686
+ function TemplateLibrary(props) {
687
+ const { api, onUse, onClose } = props;
688
+ const [list, setList] = (0, react.useState)(null);
689
+ const [loadError, setLoadError] = (0, react.useState)(null);
690
+ const [query, setQuery] = (0, react.useState)("");
691
+ const [category, setCategory] = (0, react.useState)("");
692
+ const [selected, setSelected] = (0, react.useState)(null);
693
+ const [copied, setCopied] = (0, react.useState)(false);
694
+ const [refreshing, setRefreshing] = (0, react.useState)(false);
695
+ const [notice, setNotice] = (0, react.useState)(null);
696
+ const [cacheAll, setCacheAll] = (0, react.useState)({
697
+ running: false,
698
+ done: 0,
699
+ total: 0
700
+ });
701
+ const searchRef = (0, react.useRef)(null);
702
+ const load = () => {
703
+ api.templatesList().then((result) => {
704
+ setList(result);
705
+ setLoadError(null);
706
+ }).catch((caught) => {
707
+ setLoadError(errorMessage(caught));
708
+ });
709
+ };
710
+ (0, react.useEffect)(() => {
711
+ load();
712
+ searchRef.current?.focus();
713
+ }, []);
714
+ const categories = (0, react.useMemo)(() => {
715
+ if (list === null) return [];
716
+ const counts = /* @__PURE__ */ new Map();
717
+ for (const item of list.cases) {
718
+ const entry = counts.get(item.category) ?? {
719
+ label: item.categoryZh || item.category,
720
+ count: 0
721
+ };
722
+ entry.count += 1;
723
+ counts.set(item.category, entry);
724
+ }
725
+ return [...counts.entries()].map(([key, value]) => ({
726
+ key,
727
+ label: value.label,
728
+ count: value.count
729
+ }));
730
+ }, [list]);
731
+ const filtered = (0, react.useMemo)(() => {
732
+ if (list === null) return [];
733
+ const needle = query.trim().toLowerCase();
734
+ return list.cases.filter((item) => {
735
+ if (category !== "" && item.category !== category) return false;
736
+ if (needle === "") return true;
737
+ return item.title.toLowerCase().includes(needle) || item.prompt.toLowerCase().includes(needle) || item.sourceLabel.toLowerCase().includes(needle);
738
+ });
739
+ }, [
740
+ list,
741
+ query,
742
+ category
743
+ ]);
744
+ (0, react.useEffect)(() => {
745
+ const onKey = (event) => {
746
+ if (event.key !== "Escape") return;
747
+ event.stopPropagation();
748
+ if (selected !== null) setSelected(null);
749
+ else onClose();
750
+ };
751
+ window.addEventListener("keydown", onKey, true);
752
+ return () => window.removeEventListener("keydown", onKey, true);
753
+ }, [selected, onClose]);
754
+ const refresh = async () => {
755
+ if (refreshing) return;
756
+ setRefreshing(true);
757
+ setNotice(null);
758
+ try {
759
+ const result = await api.templatesRefresh();
760
+ const reloaded = await api.templatesList();
761
+ setList(reloaded);
762
+ setLoadError(null);
763
+ setNotice(tt("templates.refreshed", { count: result.total }));
764
+ } catch (caught) {
765
+ setNotice(tt("templates.refreshFailed", { error: errorMessage(caught) }));
766
+ } finally {
767
+ setRefreshing(false);
768
+ }
769
+ };
770
+ /** Mirror every reference image through the host cache (offline browsing). */
771
+ const cacheAllImages = async () => {
772
+ if (cacheAll.running || list === null) return;
773
+ const files = [...new Set(list.cases.map((item) => item.image).filter((name) => name !== ""))];
774
+ setCacheAll({
775
+ running: true,
776
+ done: 0,
777
+ total: files.length
778
+ });
779
+ let index = 0;
780
+ const worker = async () => {
781
+ while (index < files.length) {
782
+ const file = files[index];
783
+ index += 1;
784
+ try {
785
+ await fetch(`${TEMPLATES_API.image}/${encodeURIComponent(file)}`);
786
+ } catch {}
787
+ setCacheAll((current) => ({
788
+ ...current,
789
+ done: current.done + 1
790
+ }));
791
+ }
792
+ };
793
+ await Promise.all(Array.from({ length: CACHE_ALL_CONCURRENCY }, () => worker()));
794
+ setCacheAll({
795
+ running: false,
796
+ done: files.length,
797
+ total: files.length
798
+ });
799
+ };
800
+ const copyPrompt = async (text) => {
801
+ try {
802
+ if (navigator.clipboard?.writeText !== void 0) await navigator.clipboard.writeText(text);
803
+ else {
804
+ const textarea = document.createElement("textarea");
805
+ textarea.value = text;
806
+ textarea.style.position = "fixed";
807
+ textarea.style.opacity = "0";
808
+ document.body.appendChild(textarea);
809
+ textarea.select();
810
+ const copiedOk = document.execCommand("copy");
811
+ textarea.remove();
812
+ if (!copiedOk) throw new Error("copy failed");
813
+ }
814
+ setCopied(true);
815
+ window.setTimeout(() => {
816
+ setCopied(false);
817
+ }, 1800);
818
+ } catch {
819
+ setCopied(false);
820
+ }
821
+ };
822
+ const originLabel = list === null ? "" : tt(list.origin === "refreshed" ? "templates.origin.refreshed" : "templates.origin.bundled");
823
+ return (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
824
+ className: templates_module_css_default.overlay,
825
+ role: "dialog",
826
+ "aria-modal": "true",
827
+ "aria-label": tt("templates.title"),
828
+ onClick: onClose,
829
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
830
+ className: templates_module_css_default.shell,
831
+ onClick: (event) => {
832
+ event.stopPropagation();
833
+ },
834
+ children: [
835
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
836
+ className: templates_module_css_default.header,
837
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
838
+ className: templates_module_css_default.heading,
839
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
840
+ className: templates_module_css_default.title,
841
+ children: tt("templates.title")
842
+ }), list !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
843
+ className: templates_module_css_default.meta,
844
+ children: tt("templates.meta", {
845
+ count: list.total,
846
+ origin: originLabel
847
+ })
848
+ }) : null]
849
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
850
+ className: templates_module_css_default.headerActions,
851
+ children: [
852
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
853
+ variant: "outline",
854
+ size: "sm",
855
+ disabled: refreshing || cacheAll.running,
856
+ onClick: () => {
857
+ refresh();
858
+ },
859
+ children: refreshing ? tt("templates.refreshing") : tt("templates.refresh")
860
+ }),
861
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
862
+ variant: "outline",
863
+ size: "sm",
864
+ disabled: list === null || cacheAll.running,
865
+ title: tt("templates.cacheAllHint"),
866
+ onClick: () => {
867
+ cacheAllImages();
868
+ },
869
+ children: cacheAll.running ? tt("templates.caching", {
870
+ done: cacheAll.done,
871
+ total: cacheAll.total
872
+ }) : cacheAll.total > 0 && cacheAll.done === cacheAll.total ? tt("templates.cached") : tt("templates.cacheAll")
873
+ }),
874
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
875
+ type: "button",
876
+ className: templates_module_css_default.close,
877
+ "aria-label": tt("templates.close"),
878
+ title: tt("templates.close"),
879
+ onClick: onClose,
880
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
881
+ viewBox: "0 0 16 16",
882
+ width: "16",
883
+ height: "16",
884
+ fill: "none",
885
+ stroke: "currentColor",
886
+ strokeWidth: "1.6",
887
+ strokeLinecap: "round",
888
+ "aria-hidden": "true",
889
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4 4l8 8M12 4l-8 8" })
890
+ })
891
+ })
892
+ ]
893
+ })]
894
+ }),
895
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
896
+ className: templates_module_css_default.toolbar,
897
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
898
+ ref: searchRef,
899
+ type: "search",
900
+ className: templates_module_css_default.search,
901
+ placeholder: tt("templates.search"),
902
+ value: query,
903
+ onChange: (event) => {
904
+ setQuery(event.target.value);
905
+ }
906
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
907
+ className: templates_module_css_default.categoryRow,
908
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
909
+ type: "button",
910
+ className: templates_module_css_default.categoryPill,
911
+ "data-active": category === "" ? "" : void 0,
912
+ onClick: () => {
913
+ setCategory("");
914
+ },
915
+ children: [tt("templates.all"), list !== null ? ` ${list.total}` : ""]
916
+ }), categories.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
917
+ type: "button",
918
+ className: templates_module_css_default.categoryPill,
919
+ "data-active": category === entry.key ? "" : void 0,
920
+ onClick: () => {
921
+ setCategory(entry.key);
922
+ },
923
+ children: [
924
+ entry.label,
925
+ " ",
926
+ entry.count
927
+ ]
928
+ }, entry.key))]
929
+ })]
930
+ }),
931
+ notice !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
932
+ className: templates_module_css_default.notice,
933
+ role: "status",
934
+ children: notice
935
+ }) : null,
936
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
937
+ className: templates_module_css_default.body,
938
+ children: [
939
+ list === null && loadError === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
940
+ className: templates_module_css_default.state,
941
+ role: "status",
942
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: templates_module_css_default.spinner }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("templates.loading") })]
943
+ }) : null,
944
+ loadError !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
945
+ className: templates_module_css_default.state,
946
+ role: "alert",
947
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("templates.loadFailed", { error: loadError }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
948
+ variant: "outline",
949
+ size: "sm",
950
+ onClick: () => {
951
+ setLoadError(null);
952
+ setList(null);
953
+ load();
954
+ },
955
+ children: tt("templates.retry")
956
+ })]
957
+ }) : null,
958
+ list !== null && filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
959
+ className: templates_module_css_default.state,
960
+ children: tt("templates.empty")
961
+ }) : null,
962
+ list !== null && filtered.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
963
+ className: templates_module_css_default.grid,
964
+ children: filtered.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
965
+ type: "button",
966
+ className: templates_module_css_default.card,
967
+ onClick: () => {
968
+ setSelected(item);
969
+ setCopied(false);
970
+ },
971
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
972
+ className: templates_module_css_default.thumbWrap,
973
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TemplateThumb, { item }), item.featured ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
974
+ className: templates_module_css_default.featuredBadge,
975
+ children: tt("templates.featured")
976
+ }) : null]
977
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
978
+ className: templates_module_css_default.cardBody,
979
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
980
+ className: templates_module_css_default.cardTitle,
981
+ children: item.title
982
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
983
+ className: templates_module_css_default.cardMeta,
984
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
985
+ className: templates_module_css_default.cardCategory,
986
+ children: item.categoryZh || item.category
987
+ }), item.sourceLabel !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
988
+ className: templates_module_css_default.cardSource,
989
+ children: item.sourceLabel
990
+ }) : null]
991
+ })]
992
+ })]
993
+ }, item.id))
994
+ }) : null
995
+ ]
996
+ }),
997
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
998
+ className: templates_module_css_default.footer,
999
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1000
+ className: templates_module_css_default.attribution,
1001
+ children: tt("templates.attribution")
1002
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1003
+ className: templates_module_css_default.sourceLink,
1004
+ href: "https://vibeui.top/",
1005
+ target: "_blank",
1006
+ rel: "noreferrer",
1007
+ children: tt("templates.source")
1008
+ })]
1009
+ })
1010
+ ]
1011
+ }), selected !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1012
+ className: templates_module_css_default.detailOverlay,
1013
+ onClick: () => {
1014
+ setSelected(null);
1015
+ },
1016
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1017
+ className: templates_module_css_default.detail,
1018
+ onClick: (event) => {
1019
+ event.stopPropagation();
1020
+ },
1021
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1022
+ className: templates_module_css_default.detailMedia,
1023
+ children: selected.image !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1024
+ className: templates_module_css_default.detailImage,
1025
+ src: imageUrlOf(selected),
1026
+ alt: selected.title
1027
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1028
+ className: templates_module_css_default.thumbPlaceholder,
1029
+ "aria-hidden": "true"
1030
+ })
1031
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1032
+ className: templates_module_css_default.detailInfo,
1033
+ children: [
1034
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h4", {
1035
+ className: templates_module_css_default.detailTitle,
1036
+ children: selected.title
1037
+ }),
1038
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1039
+ className: templates_module_css_default.detailMeta,
1040
+ children: [
1041
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1042
+ className: templates_module_css_default.cardCategory,
1043
+ children: selected.categoryZh || selected.category
1044
+ }),
1045
+ selected.sourceUrl !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1046
+ className: templates_module_css_default.detailLink,
1047
+ href: selected.sourceUrl,
1048
+ target: "_blank",
1049
+ rel: "noreferrer",
1050
+ children: selected.sourceLabel || selected.sourceUrl
1051
+ }) : null,
1052
+ selected.githubUrl !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1053
+ className: templates_module_css_default.detailLink,
1054
+ href: selected.githubUrl,
1055
+ target: "_blank",
1056
+ rel: "noreferrer",
1057
+ children: "GitHub"
1058
+ }) : null
1059
+ ]
1060
+ }),
1061
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
1062
+ className: templates_module_css_default.detailPrompt,
1063
+ children: selected.prompt
1064
+ }),
1065
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1066
+ className: templates_module_css_default.detailActions,
1067
+ children: [
1068
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1069
+ variant: "primary",
1070
+ size: "md",
1071
+ onClick: () => {
1072
+ onUse(selected.prompt);
1073
+ },
1074
+ children: tt("templates.use")
1075
+ }),
1076
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1077
+ variant: "outline",
1078
+ size: "md",
1079
+ onClick: () => {
1080
+ copyPrompt(selected.prompt);
1081
+ },
1082
+ children: copied ? tt("templates.copied") : tt("templates.copy")
1083
+ }),
1084
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1085
+ variant: "outline",
1086
+ size: "md",
1087
+ onClick: () => {
1088
+ setSelected(null);
1089
+ },
1090
+ children: tt("templates.back")
1091
+ })
1092
+ ]
1093
+ })
1094
+ ]
1095
+ })]
1096
+ })
1097
+ }) : null]
1098
+ }), document.body);
1099
+ }
1100
+ //#endregion
401
1101
  //#region \0dsh-css:E:\dsh-plugin\src\client\panel.module.css.mjs
402
- const css$1 = "[data-pane=conversation]{position:relative}[data-dsh-imagegen-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0}html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-dsh-imagegen-view]{display:block}html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-imagegen-view]),html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-imagegen-view]){display:none!important}.Yvqh9W_entry{width:100%;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 12px;font-size:13px;display:flex}.Yvqh9W_entry:hover{background:var(--dsw-specific-sidebar-nav-item-hover);color:var(--dsw-alias-label-primary)}.Yvqh9W_entry[data-active]{background:var(--dsw-specific-sidebar-nav-item-active);color:var(--dsw-alias-label-primary);font-weight:600}.Yvqh9W_entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}.Yvqh9W_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] .Yvqh9W_entry{justify-content:center;width:100%;padding:0}[data-dsh-frame][data-sidebar-collapsed] .Yvqh9W_entryLabel{display:none}.Yvqh9W_view{overflow:hidden}.Yvqh9W_panel,.Yvqh9W_panel *,.Yvqh9W_panel :before,.Yvqh9W_panel :after{box-sizing:border-box}.Yvqh9W_panel{background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:10px;padding:14px 16px 16px;display:flex;overflow:hidden}.Yvqh9W_panelHeader{flex:none;justify-content:space-between;align-items:center;gap:12px;display:flex}.Yvqh9W_panelHeading{align-items:baseline;gap:10px;min-width:0;display:flex}.Yvqh9W_panelTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}.Yvqh9W_panelSubtitle{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;font-size:12px;overflow:hidden}.Yvqh9W_connectionStatus{border:1px solid var(--dsw-alias-label-error);height:28px;color:var(--dsw-alias-label-error);font:inherit;white-space:nowrap;background:0 0;border-radius:8px;flex:none;align-items:center;gap:6px;padding:0 10px;font-size:12px;line-height:1;display:inline-flex}.Yvqh9W_connectionStatus[data-connected=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.Yvqh9W_connectionDot{background:currentColor;border-radius:50%;width:6px;height:6px}.Yvqh9W_updateBanner{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-primary);overflow-wrap:anywhere;border-radius:10px;flex:none;justify-content:space-between;align-items:center;gap:12px;padding:7px 10px 7px 12px;font-size:12px;line-height:1.5;display:flex}.Yvqh9W_updateBanner[data-kind=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.Yvqh9W_updateText{min-width:0}.Yvqh9W_updateActions{flex:none;align-items:center;gap:10px;display:inline-flex}.Yvqh9W_updateRelease{color:inherit;text-underline-offset:2px;white-space:nowrap;text-decoration:underline}@media (width<=700px){.Yvqh9W_panelHeader{align-items:flex-start}.Yvqh9W_panelHeading{flex-direction:column;align-items:flex-start;gap:2px}.Yvqh9W_updateBanner{flex-direction:column;align-items:flex-start}.Yvqh9W_updateActions{justify-content:space-between;width:100%}}.Yvqh9W_studio{flex:1;gap:14px;min-width:0;min-height:0;display:flex}.Yvqh9W_config{flex-direction:column;flex:none;gap:12px;width:300px;min-width:260px;max-width:340px;height:100%;min-height:0;display:flex;overflow:hidden}.Yvqh9W_configScroll{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:12px;min-height:0;padding-right:2px;display:flex;overflow-y:auto}.Yvqh9W_configScroll::-webkit-scrollbar{width:8px}.Yvqh9W_configScroll::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Yvqh9W_canvas{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;flex:1;min-width:0;min-height:0;display:flex;position:relative;overflow:hidden}.Yvqh9W_history{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;flex:none;width:240px;min-width:200px;max-width:280px;min-height:0;display:flex;overflow:hidden}.Yvqh9W_historyHeader{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:10px 12px;display:flex}.Yvqh9W_historyTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.Yvqh9W_historyClear{font:inherit;color:var(--dsw-alias-label-tertiary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11.5px}.Yvqh9W_historyClear:hover{color:var(--dsw-alias-label-error);border-color:var(--dsw-alias-label-error)}.Yvqh9W_historyList{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:8px;min-height:0;padding:10px;display:flex;overflow-y:auto}.Yvqh9W_historyList::-webkit-scrollbar{width:8px}.Yvqh9W_historyList::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Yvqh9W_historyEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);flex:1;justify-content:center;align-items:center;padding:20px;font-size:12px;line-height:1.6;display:flex}.Yvqh9W_historyItem{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:10px;flex-direction:column;flex:none;gap:6px;padding:8px;display:flex}.Yvqh9W_historyItem:hover{border-color:var(--dsw-alias-border-l2)}.Yvqh9W_historyItem[data-active]{border-color:var(--dsw-alias-brand-primary)}.Yvqh9W_historyMain{font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:flex-start;gap:8px;min-width:0;padding:0;display:flex}.Yvqh9W_historyThumb{object-fit:cover;background:var(--dsw-alias-bg-base);border-radius:8px;flex:none;width:52px;height:52px}.Yvqh9W_historyThumbPlaceholder{background:var(--dsw-alias-bg-layer-3);border-radius:8px;flex:none;width:52px;height:52px}.Yvqh9W_historyInfo{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Yvqh9W_historyPrompt{color:var(--dsw-alias-label-primary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}.Yvqh9W_historyMeta{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.Yvqh9W_historyActions{justify-content:flex-end;gap:6px;display:flex}.Yvqh9W_historyAction{font:inherit;color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11.5px}.Yvqh9W_historyAction:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Yvqh9W_historyAction[data-danger]:hover{color:var(--dsw-alias-label-error);border-color:var(--dsw-alias-label-error)}.Yvqh9W_card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;flex:none;gap:10px;padding:12px;display:flex}.Yvqh9W_modeRow{align-items:center;gap:8px;display:flex}.Yvqh9W_modePill{flex:1;justify-content:center;height:28px;font-size:13px}.Yvqh9W_uploadBox{min-height:128px;color:var(--dsw-alias-label-secondary);border:1.5px dashed var(--dsw-alias-border-l2);cursor:pointer;font:inherit;text-align:center;background:0 0;border-radius:12px;flex-direction:column;justify-content:center;align-items:center;gap:6px;padding:16px;font-size:12.5px;display:flex}.Yvqh9W_uploadBox:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-interactive-bg-hover)}.Yvqh9W_uploadBox:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Yvqh9W_uploadIcon{color:var(--dsw-alias-label-tertiary);display:inline-flex}.Yvqh9W_uploadHint{color:var(--dsw-alias-label-tertiary);font-size:11px}.Yvqh9W_reference{flex-direction:column;gap:8px;display:flex}.Yvqh9W_referenceImage{object-fit:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:100%;max-height:176px}.Yvqh9W_referenceActions{gap:8px;display:flex}.Yvqh9W_hiddenFile{display:none}.Yvqh9W_prompt{width:100%;min-height:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);resize:vertical;box-sizing:border-box;border-radius:10px;outline:none;padding:10px 12px;font-family:inherit;font-size:13px;line-height:1.6}.Yvqh9W_prompt:focus-visible{border-color:var(--dsw-alias-brand-primary)}.Yvqh9W_prompt::placeholder{color:var(--dsw-alias-label-tertiary)}.Yvqh9W_promptFooter{justify-content:flex-end;margin-top:-6px;display:flex}.Yvqh9W_promptCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px}.Yvqh9W_paramGroup{flex-direction:column;gap:8px;display:flex}.Yvqh9W_paramLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.Yvqh9W_optionRow{flex-wrap:wrap;gap:6px;display:flex}.Yvqh9W_optionGrid{grid-template-columns:repeat(3,1fr);gap:6px;display:grid}.Yvqh9W_optionPill{justify-content:center}.Yvqh9W_paramHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45}.Yvqh9W_footer{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;flex:none;align-items:stretch;gap:8px;padding:10px 2px 0 0;display:flex}.Yvqh9W_modelWrap{flex-direction:column;gap:5px;min-width:0;display:flex}.Yvqh9W_modelLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.Yvqh9W_modelSelect{width:100%;height:36px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;border-radius:18px;outline:none;padding:0 12px;font-family:inherit;font-size:13px}.Yvqh9W_modelSelect:focus-visible{border-color:var(--dsw-alias-brand-primary)}.Yvqh9W_modelSelect:disabled{opacity:.55}.Yvqh9W_generateButton{width:100%}.Yvqh9W_generateInner{align-items:center;gap:7px;display:inline-flex}.Yvqh9W_canvasState{text-align:center;color:var(--dsw-alias-label-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px;display:flex}.Yvqh9W_canvasStateTitle{color:var(--dsw-alias-label-secondary);font-size:14px;font-weight:600}.Yvqh9W_canvasStateHint{max-width:380px;font-size:12px;line-height:1.6}.Yvqh9W_canvasEmptyIcon{color:var(--dsw-alias-label-tertiary);margin-bottom:4px;display:inline-flex}.Yvqh9W_canvasError{color:var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-label-error);overflow-wrap:anywhere;border-radius:10px;flex:none;margin:14px;padding:10px 14px;font-size:12.5px;line-height:1.6}.Yvqh9W_canvasBody{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:10px;min-height:0;padding:14px;display:flex;overflow-y:auto}.Yvqh9W_canvasBody::-webkit-scrollbar{width:8px}.Yvqh9W_canvasBody::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Yvqh9W_canvasMeta{color:var(--dsw-alias-label-tertiary);flex:none;align-items:center;gap:8px;font-size:12px;display:flex}.Yvqh9W_canvasHistoryTag{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px}.Yvqh9W_grid{flex:1;grid-template-rows:repeat(2,minmax(0,1fr));grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;min-height:0;display:grid}.Yvqh9W_grid[data-count=\"1\"] .Yvqh9W_imageCard{grid-area:1/1/3/3}.Yvqh9W_imageCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);cursor:zoom-in;border-radius:12px;flex-direction:column;min-height:0;margin:0;display:flex;position:relative;overflow:hidden}.Yvqh9W_imageCard:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Yvqh9W_image{object-fit:cover;background:var(--dsw-alias-bg-base);flex:1;width:100%;min-height:0;display:block}.Yvqh9W_imageCaption{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;border-top:1px solid var(--dsw-alias-border-l1);padding:7px 10px;font-size:11px;line-height:1.5;overflow:hidden}.Yvqh9W_download{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);opacity:0;backdrop-filter:blur(4px);border-radius:999px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;text-decoration:none;transition:opacity .12s;position:absolute;top:8px;right:8px}.Yvqh9W_imageCard:hover .Yvqh9W_download{opacity:1}.Yvqh9W_download:hover{background:var(--dsw-alias-bg-base)}.Yvqh9W_zoomHint{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);opacity:0;backdrop-filter:blur(4px);pointer-events:none;border-radius:999px;align-items:center;gap:5px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;transition:opacity .12s;display:inline-flex;position:absolute;bottom:8px;left:8px}.Yvqh9W_imageCard:hover .Yvqh9W_zoomHint{opacity:1}.Yvqh9W_spinner,.Yvqh9W_bigSpinner{border:2px solid;border-top-color:#0000;border-radius:50%;flex:none;animation:.8s linear infinite Yvqh9W_dshImageGenSpin;display:inline-block}.Yvqh9W_spinner{width:11px;height:11px}.Yvqh9W_bigSpinner{width:30px;height:30px;color:var(--dsw-alias-state-business-primary);border-width:3px;margin-bottom:6px}.Yvqh9W_lightbox{z-index:1000;backdrop-filter:blur(6px);background:#000000b8;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.Yvqh9W_lightboxClose{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:50%;justify-content:center;align-items:center;width:38px;height:38px;display:inline-flex;position:absolute;top:16px;right:16px}.Yvqh9W_lightboxClose:hover{background:#ffffff42}.Yvqh9W_lightboxNav{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:50%;justify-content:center;align-items:center;width:42px;height:42px;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.Yvqh9W_lightboxNav:hover{background:#ffffff42}.Yvqh9W_lightboxNav[data-dir=prev]{left:max(20px,50% - 640px)}.Yvqh9W_lightboxNav[data-dir=next]{right:max(20px,50% - 640px)}.Yvqh9W_lightboxFigure{flex-direction:column;gap:10px;width:min(1100px,100vw - 160px);max-width:min(1100px,100vw - 160px);height:min(820px,100vh - 48px);min-height:0;margin:0;display:flex}.Yvqh9W_lightboxStage{background:#ffffff0a;border-radius:10px;flex:1;min-height:0;position:relative;overflow:auto}.Yvqh9W_lightboxScaleFrame{justify-content:center;align-items:center;min-width:100%;min-height:100%;display:flex}.Yvqh9W_lightboxImage{object-fit:contain;border-radius:10px;max-width:100%;max-height:100%;display:block;box-shadow:0 24px 80px #00000080}.Yvqh9W_lightboxTools{justify-content:center;align-items:center;gap:6px;display:flex}.Yvqh9W_lightboxTool,.Yvqh9W_lightboxZoomLevel,.Yvqh9W_lightboxCopy{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;justify-content:center;align-items:center;display:inline-flex}.Yvqh9W_lightboxTool,.Yvqh9W_lightboxZoomLevel{height:32px}.Yvqh9W_lightboxTool{border-radius:50%;width:32px}.Yvqh9W_lightboxZoomLevel{min-width:58px;font:inherit;font-variant-numeric:tabular-nums;border-radius:999px;padding:0 9px;font-size:12px}.Yvqh9W_lightboxTool:hover,.Yvqh9W_lightboxZoomLevel:hover,.Yvqh9W_lightboxCopy:hover{background:#ffffff42}.Yvqh9W_lightboxCaptionRow{align-items:flex-start;gap:8px;min-width:0;display:flex}.Yvqh9W_lightboxCaption{color:#ffffffe6;-webkit-line-clamp:3;-webkit-box-orient:vertical;flex:1;min-width:0;font-size:12px;line-height:1.6;display:-webkit-box;overflow:hidden}.Yvqh9W_lightboxCopy{min-height:28px;font:inherit;white-space:nowrap;border-radius:999px;flex:none;gap:5px;padding:4px 9px;font-size:12px}.Yvqh9W_lightboxMeta{justify-content:space-between;align-items:center;gap:12px;display:flex}.Yvqh9W_lightboxIndex{color:#fffc;font-variant-numeric:tabular-nums;font-size:12px}.Yvqh9W_lightboxActions{align-items:center;gap:8px;display:inline-flex}.Yvqh9W_lightboxDownload,.Yvqh9W_lightboxEdit{font:inherit;color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:999px;padding:4px 14px;font-size:12.5px;font-weight:500;text-decoration:none}.Yvqh9W_lightboxDownload:hover,.Yvqh9W_lightboxEdit:hover{background:#ffffff42}.Yvqh9W_lightboxEdit{color:#fff;background:#ffffff24;border:1px solid #ffffff47;border-radius:999px}@media (width<=720px){.Yvqh9W_lightbox{padding:16px}.Yvqh9W_lightboxFigure{width:calc(100vw - 32px);max-width:none}.Yvqh9W_lightboxNav[data-dir=prev]{left:20px}.Yvqh9W_lightboxNav[data-dir=next]{right:20px}.Yvqh9W_lightboxCaptionRow,.Yvqh9W_lightboxMeta{flex-direction:column;align-items:stretch}.Yvqh9W_lightboxCopy,.Yvqh9W_lightboxActions{align-self:flex-end}}@keyframes Yvqh9W_dshImageGenSpin{to{transform:rotate(360deg)}}@media (prefers-reduced-motion:reduce){.Yvqh9W_download,.Yvqh9W_spinner,.Yvqh9W_bigSpinner{transition:none;animation-duration:1.5s}}";
1102
+ const css$1 = "[data-pane=conversation],[class*=centerCol]{position:relative}[data-dsh-imagegen-view]{z-index:60;background:var(--dsw-alias-bg-base);display:none;position:absolute;inset:0}html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-dsh-imagegen-view]{display:block}html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [data-pane=conversation]>:not([data-dsh-imagegen-view]),html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ssh-active]) [class*=centerCol]>:not([data-dsh-imagegen-view]){display:none!important}.Yvqh9W_entry{width:100%;height:32px;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:8px;align-items:center;gap:8px;padding:0 12px;font-size:13px;display:flex}.Yvqh9W_entry:hover{background:var(--dsw-specific-sidebar-nav-item-hover);color:var(--dsw-alias-label-primary)}.Yvqh9W_entry[data-active]{background:var(--dsw-specific-sidebar-nav-item-active);color:var(--dsw-alias-label-primary);font-weight:600}.Yvqh9W_entryIcon{flex:none;justify-content:center;align-items:center;display:inline-flex}.Yvqh9W_entryLabel{text-overflow:ellipsis;overflow:hidden}[data-dsh-frame][data-sidebar-collapsed] .Yvqh9W_entry{justify-content:center;width:100%;padding:0}[data-dsh-frame][data-sidebar-collapsed] .Yvqh9W_entryLabel{display:none}.Yvqh9W_view{overflow:hidden}.Yvqh9W_panel,.Yvqh9W_panel *,.Yvqh9W_panel :before,.Yvqh9W_panel :after{box-sizing:border-box}.Yvqh9W_panel{background:var(--dsw-alias-bg-base);min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family);flex-direction:column;gap:10px;padding:14px 16px 16px;display:flex;position:relative;overflow:hidden}.Yvqh9W_panelHeader{flex:none;justify-content:space-between;align-items:center;gap:12px;display:flex}.Yvqh9W_panelHeading{align-items:baseline;gap:10px;min-width:0;display:flex}.Yvqh9W_panelTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:16px;font-weight:700}.Yvqh9W_githubLink{width:22px;height:22px;color:var(--dsw-alias-label-secondary);border-radius:6px;flex:none;justify-content:center;align-items:center;text-decoration:none;transition:color .12s,background .12s;display:inline-flex}.Yvqh9W_githubLink:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.Yvqh9W_connectionStatus{border:1px solid var(--dsw-alias-label-error);height:28px;color:var(--dsw-alias-label-error);font:inherit;white-space:nowrap;background:0 0;border-radius:8px;flex:none;align-items:center;gap:6px;padding:0 10px;font-size:12px;line-height:1;display:inline-flex}.Yvqh9W_connectionStatus[data-connected=true]{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}.Yvqh9W_connectionDot{background:currentColor;border-radius:50%;width:6px;height:6px}.Yvqh9W_updateBanner{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-primary);overflow-wrap:anywhere;border-radius:10px;flex:none;justify-content:space-between;align-items:center;gap:12px;padding:7px 10px 7px 12px;font-size:12px;line-height:1.5;display:flex}.Yvqh9W_updateBanner[data-kind=ok]{color:var(--dsw-alias-state-success-primary);border-color:var(--dsw-alias-state-success-primary)}.Yvqh9W_updateText{min-width:0}.Yvqh9W_updateActions{flex:none;align-items:center;gap:10px;display:inline-flex}.Yvqh9W_updateRelease{color:inherit;text-underline-offset:2px;white-space:nowrap;text-decoration:underline}@media (width<=700px){.Yvqh9W_panelHeader{align-items:flex-start}.Yvqh9W_panelHeading{flex-direction:column;align-items:flex-start;gap:2px}.Yvqh9W_updateBanner{flex-direction:column;align-items:flex-start}.Yvqh9W_updateActions{justify-content:space-between;width:100%}}.Yvqh9W_studio{flex:1;gap:14px;min-width:0;min-height:0;display:flex}.Yvqh9W_config{flex-direction:column;flex:none;gap:12px;width:300px;min-width:260px;max-width:340px;height:100%;min-height:0;display:flex;overflow:hidden}.Yvqh9W_configScroll{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:12px;min-height:0;padding-right:2px;display:flex;overflow-y:auto}.Yvqh9W_configScroll::-webkit-scrollbar{width:8px}.Yvqh9W_configScroll::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Yvqh9W_canvas{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;flex:1;min-width:0;min-height:0;display:flex;position:relative;overflow:hidden}.Yvqh9W_history{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex-direction:column;flex:none;width:240px;min-width:200px;max-width:280px;min-height:0;display:flex;overflow:hidden}.Yvqh9W_historyHeader{border-bottom:1px solid var(--dsw-alias-border-l1);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:10px 12px;display:flex}.Yvqh9W_historyTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.Yvqh9W_historyClear{font:inherit;color:var(--dsw-alias-label-tertiary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11.5px}.Yvqh9W_historyClear:hover{color:var(--dsw-alias-label-error);border-color:var(--dsw-alias-label-error)}.Yvqh9W_historyList{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:8px;min-height:0;padding:10px;display:flex;overflow-y:auto}.Yvqh9W_historyList::-webkit-scrollbar{width:8px}.Yvqh9W_historyList::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Yvqh9W_historyEmpty{text-align:center;color:var(--dsw-alias-label-tertiary);flex:1;justify-content:center;align-items:center;padding:20px;font-size:12px;line-height:1.6;display:flex}.Yvqh9W_historyItem{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);border-radius:10px;flex-direction:column;flex:none;gap:6px;padding:8px;display:flex}.Yvqh9W_historyItem:hover{border-color:var(--dsw-alias-border-l2)}.Yvqh9W_historyItem[data-active]{border-color:var(--dsw-alias-brand-primary)}.Yvqh9W_historyMain{font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:flex-start;gap:8px;min-width:0;padding:0;display:flex}.Yvqh9W_historyThumb{object-fit:cover;background:var(--dsw-alias-bg-base);border-radius:8px;flex:none;width:52px;height:52px}.Yvqh9W_historyThumbPlaceholder{background:var(--dsw-alias-bg-layer-3);border-radius:8px;flex:none;width:52px;height:52px}.Yvqh9W_historyInfo{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.Yvqh9W_historyPrompt{color:var(--dsw-alias-label-primary);-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:12px;line-height:1.4;display:-webkit-box;overflow:hidden}.Yvqh9W_historyMeta{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.Yvqh9W_historyActions{justify-content:flex-end;gap:6px;display:flex}.Yvqh9W_historyAction{font:inherit;color:var(--dsw-alias-label-secondary);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11.5px}.Yvqh9W_historyAction:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.Yvqh9W_historyAction[data-danger]:hover{color:var(--dsw-alias-label-error);border-color:var(--dsw-alias-label-error)}.Yvqh9W_card{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:12px;flex-direction:column;flex:none;gap:10px;padding:12px;display:flex}.Yvqh9W_modeRow{align-items:center;gap:8px;display:flex}.Yvqh9W_modePill{flex:1;justify-content:center;height:28px;font-size:13px}.Yvqh9W_uploadBox{min-height:128px;color:var(--dsw-alias-label-secondary);border:1.5px dashed var(--dsw-alias-border-l2);cursor:pointer;font:inherit;text-align:center;background:0 0;border-radius:12px;flex-direction:column;justify-content:center;align-items:center;gap:6px;padding:16px;font-size:12.5px;display:flex}.Yvqh9W_uploadBox:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-interactive-bg-hover)}.Yvqh9W_uploadBox:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Yvqh9W_uploadIcon{color:var(--dsw-alias-label-tertiary);display:inline-flex}.Yvqh9W_uploadHint{color:var(--dsw-alias-label-tertiary);font-size:11px}.Yvqh9W_reference{flex-direction:column;gap:8px;display:flex}.Yvqh9W_referenceImage{object-fit:contain;background:var(--dsw-alias-bg-base);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:100%;max-height:176px}.Yvqh9W_referenceActions{gap:8px;display:flex}.Yvqh9W_hiddenFile{display:none}.Yvqh9W_prompt{width:100%;min-height:120px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);resize:vertical;box-sizing:border-box;border-radius:10px;outline:none;padding:10px 12px;font-family:inherit;font-size:13px;line-height:1.6}.Yvqh9W_prompt:focus-visible{border-color:var(--dsw-alias-brand-primary)}.Yvqh9W_prompt::placeholder{color:var(--dsw-alias-label-tertiary)}.Yvqh9W_promptFooter{justify-content:space-between;align-items:center;gap:8px;margin-top:-6px;display:flex}.Yvqh9W_templatesButton{border:1px solid var(--dsw-alias-brand-primary);background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 5%, transparent));height:26px;color:var(--dsw-alias-brand-primary);cursor:pointer;box-shadow:0 1px 0 color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent);border-radius:999px;align-items:center;gap:6px;padding:0 12px;font-family:inherit;font-size:12px;font-weight:600;transition:transform .12s,box-shadow .12s,background .12s;display:inline-flex}.Yvqh9W_templatesButton svg{flex:none}.Yvqh9W_templatesButton:hover{background:linear-gradient(135deg, color-mix(in srgb, var(--dsw-alias-brand-primary) 24%, transparent), color-mix(in srgb, var(--dsw-alias-brand-primary) 8%, transparent));color:var(--dsw-alias-brand-primary);box-shadow:0 2px 6px color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, transparent);transform:translateY(-1px)}.Yvqh9W_templatesButton:active{transform:translateY(0)}.Yvqh9W_promptCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px}.Yvqh9W_paramGroup{flex-direction:column;gap:8px;display:flex}.Yvqh9W_paramLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.Yvqh9W_optionRow{flex-wrap:wrap;gap:6px;display:flex}.Yvqh9W_optionGrid{grid-template-columns:repeat(3,1fr);gap:6px;display:grid}.Yvqh9W_optionPill{justify-content:center}.Yvqh9W_paramHint{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.45}.Yvqh9W_footer{border-top:1px solid var(--dsw-alias-border-l1);flex-direction:column;flex:none;align-items:stretch;gap:8px;padding:10px 2px 0 0;display:flex}.Yvqh9W_modelWrap{flex-direction:column;gap:5px;min-width:0;display:flex}.Yvqh9W_modelLabel{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:600}.Yvqh9W_modelSelect{width:100%;height:36px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;text-align:left;border-radius:18px;outline:none;justify-content:space-between;align-items:center;gap:8px;padding:0 12px;font-family:inherit;font-size:13px;display:flex}.Yvqh9W_modelSelect:focus-visible{border-color:var(--dsw-alias-brand-primary)}.Yvqh9W_modelSelect:disabled{opacity:.55;cursor:default}.Yvqh9W_modelMenu{min-width:0;display:block;position:relative}.Yvqh9W_modelMenuList{z-index:40;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;padding:4px;display:flex;position:absolute;bottom:calc(100% + 6px);left:0;right:0;overflow:hidden;box-shadow:0 -8px 24px #0000002e}.Yvqh9W_modelMenuItem{width:100%;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;text-align:left;white-space:nowrap;text-overflow:ellipsis;background:0 0;border:none;border-radius:8px;padding:7px 10px;font-size:13px;display:block;overflow:hidden}.Yvqh9W_modelMenuItem:hover{background:var(--dsw-alias-bg-hover)}.Yvqh9W_modelMenuItem[data-selected]{color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-1);font-weight:600}.Yvqh9W_generateButton{width:100%}.Yvqh9W_generateInner{align-items:center;gap:7px;display:inline-flex}.Yvqh9W_canvasState{text-align:center;color:var(--dsw-alias-label-tertiary);flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:24px;display:flex}.Yvqh9W_canvasStateTitle{color:var(--dsw-alias-label-secondary);font-size:14px;font-weight:600}.Yvqh9W_canvasStateHint{max-width:380px;font-size:12px;line-height:1.6}.Yvqh9W_canvasEmptyIcon{color:var(--dsw-alias-label-tertiary);margin-bottom:4px;display:inline-flex}.Yvqh9W_canvasError{color:var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-label-error);overflow-wrap:anywhere;border-radius:10px;flex:none;margin:14px;padding:10px 14px;font-size:12.5px;line-height:1.6}.Yvqh9W_canvasBody{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex-direction:column;flex:1;gap:10px;min-height:0;padding:14px;display:flex;overflow-y:auto}.Yvqh9W_canvasBody::-webkit-scrollbar{width:8px}.Yvqh9W_canvasBody::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Yvqh9W_canvasMeta{color:var(--dsw-alias-label-tertiary);flex:none;align-items:center;gap:8px;font-size:12px;display:flex}.Yvqh9W_canvasHistoryTag{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);white-space:nowrap;border-radius:999px;padding:1px 8px;font-size:11px}.Yvqh9W_grid{flex:1;grid-template-rows:repeat(2,minmax(0,1fr));grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;min-height:0;display:grid}.Yvqh9W_grid[data-count=\"1\"] .Yvqh9W_imageCard{grid-area:1/1/3/3}.Yvqh9W_imageCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);cursor:zoom-in;border-radius:12px;flex-direction:column;min-height:0;margin:0;display:flex;position:relative;overflow:hidden}.Yvqh9W_imageCard:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.Yvqh9W_image{object-fit:cover;background:var(--dsw-alias-bg-base);flex:1;width:100%;min-height:0;display:block}.Yvqh9W_imageCaption{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;border-top:1px solid var(--dsw-alias-border-l1);padding:7px 10px;font-size:11px;line-height:1.5;overflow:hidden}.Yvqh9W_download{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);opacity:0;backdrop-filter:blur(4px);border-radius:999px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;text-decoration:none;transition:opacity .12s;position:absolute;top:8px;right:8px}.Yvqh9W_imageCard:hover .Yvqh9W_download{opacity:1}.Yvqh9W_download:hover{background:var(--dsw-alias-bg-base)}.Yvqh9W_galleryAdd{font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;opacity:0;backdrop-filter:blur(4px);border-radius:999px;align-items:center;gap:5px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;transition:opacity .12s;display:inline-flex;position:absolute;top:8px;left:8px}.Yvqh9W_imageCard:hover .Yvqh9W_galleryAdd{opacity:1}.Yvqh9W_galleryAdd:hover{background:var(--dsw-alias-bg-base)}.Yvqh9W_galleryAdd:disabled{opacity:.4;cursor:default}.Yvqh9W_zoomHint{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);opacity:0;backdrop-filter:blur(4px);pointer-events:none;border-radius:999px;align-items:center;gap:5px;padding:2px 10px;font-size:12px;font-weight:500;line-height:20px;transition:opacity .12s;display:inline-flex;position:absolute;bottom:8px;left:8px}.Yvqh9W_imageCard:hover .Yvqh9W_zoomHint{opacity:1}.Yvqh9W_spinner,.Yvqh9W_bigSpinner{border:2px solid;border-top-color:#0000;border-radius:50%;flex:none;animation:.8s linear infinite Yvqh9W_dshImageGenSpin;display:inline-block}.Yvqh9W_spinner{width:11px;height:11px}.Yvqh9W_bigSpinner{width:30px;height:30px;color:var(--dsw-alias-state-business-primary);border-width:3px;margin-bottom:6px}.Yvqh9W_lightbox{z-index:1000;backdrop-filter:blur(6px);background:#000000b8;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.Yvqh9W_lightboxClose{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:50%;justify-content:center;align-items:center;width:38px;height:38px;display:inline-flex;position:absolute;top:16px;right:16px}.Yvqh9W_lightboxClose:hover{background:#ffffff42}.Yvqh9W_lightboxNav{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:50%;justify-content:center;align-items:center;width:42px;height:42px;display:inline-flex;position:absolute;top:50%;transform:translateY(-50%)}.Yvqh9W_lightboxNav:hover{background:#ffffff42}.Yvqh9W_lightboxNav[data-dir=prev]{left:max(20px,50% - 640px)}.Yvqh9W_lightboxNav[data-dir=next]{right:max(20px,50% - 640px)}.Yvqh9W_lightboxFigure{flex-direction:column;gap:10px;width:min(1100px,100vw - 160px);max-width:min(1100px,100vw - 160px);height:min(820px,100vh - 48px);min-height:0;margin:0;display:flex}.Yvqh9W_lightboxStage{background:#ffffff0a;border-radius:10px;flex:1;min-height:0;position:relative;overflow:auto}.Yvqh9W_lightboxScaleFrame{justify-content:center;align-items:center;min-width:100%;min-height:100%;display:flex}.Yvqh9W_lightboxImage{object-fit:contain;border-radius:10px;max-width:100%;max-height:100%;display:block;box-shadow:0 24px 80px #00000080}.Yvqh9W_lightboxTools{justify-content:center;align-items:center;gap:6px;display:flex}.Yvqh9W_lightboxTool,.Yvqh9W_lightboxZoomLevel,.Yvqh9W_lightboxCopy{color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;justify-content:center;align-items:center;display:inline-flex}.Yvqh9W_lightboxTool,.Yvqh9W_lightboxZoomLevel{height:32px}.Yvqh9W_lightboxTool{border-radius:50%;width:32px}.Yvqh9W_lightboxZoomLevel{min-width:58px;font:inherit;font-variant-numeric:tabular-nums;border-radius:999px;padding:0 9px;font-size:12px}.Yvqh9W_lightboxTool:hover,.Yvqh9W_lightboxZoomLevel:hover,.Yvqh9W_lightboxCopy:hover{background:#ffffff42}.Yvqh9W_lightboxCaptionRow{align-items:flex-start;gap:8px;min-width:0;display:flex}.Yvqh9W_lightboxCaption{color:#ffffffe6;-webkit-line-clamp:3;-webkit-box-orient:vertical;flex:1;min-width:0;font-size:12px;line-height:1.6;display:-webkit-box;overflow:hidden}.Yvqh9W_lightboxCopy{min-height:28px;font:inherit;white-space:nowrap;border-radius:999px;flex:none;gap:5px;padding:4px 9px;font-size:12px}.Yvqh9W_lightboxMeta{justify-content:space-between;align-items:center;gap:12px;display:flex}.Yvqh9W_lightboxIndex{color:#fffc;font-variant-numeric:tabular-nums;font-size:12px}.Yvqh9W_lightboxActions{align-items:center;gap:8px;display:inline-flex}.Yvqh9W_lightboxDownload,.Yvqh9W_lightboxEdit{font:inherit;color:#fff;cursor:pointer;background:#ffffff24;border:1px solid #ffffff47;border-radius:999px;padding:4px 14px;font-size:12.5px;font-weight:500;text-decoration:none}.Yvqh9W_lightboxDownload:hover,.Yvqh9W_lightboxEdit:hover{background:#ffffff42}.Yvqh9W_lightboxEdit{color:#fff;background:#ffffff24;border:1px solid #ffffff47;border-radius:999px}@media (width<=720px){.Yvqh9W_lightbox{padding:16px}.Yvqh9W_lightboxFigure{width:calc(100vw - 32px);max-width:none}.Yvqh9W_lightboxNav[data-dir=prev]{left:20px}.Yvqh9W_lightboxNav[data-dir=next]{right:20px}.Yvqh9W_lightboxCaptionRow,.Yvqh9W_lightboxMeta{flex-direction:column;align-items:stretch}.Yvqh9W_lightboxCopy,.Yvqh9W_lightboxActions{align-self:flex-end}}@keyframes Yvqh9W_dshImageGenSpin{to{transform:rotate(360deg)}}.Yvqh9W_galleryToast{z-index:30;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-mask-1);border:1px solid var(--dsw-alias-border-l2);backdrop-filter:blur(6px);pointer-events:none;border-radius:999px;align-items:center;gap:7px;padding:6px 16px;font-size:13px;font-weight:500;animation:.16s ease-out Yvqh9W_dshImageGenToastIn;display:inline-flex;position:absolute;bottom:24px;left:50%;transform:translate(-50%);box-shadow:0 8px 24px #00000038}@keyframes Yvqh9W_dshImageGenToastIn{0%{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%)}}@media (prefers-reduced-motion:reduce){.Yvqh9W_download,.Yvqh9W_spinner,.Yvqh9W_bigSpinner{transition:none;animation-duration:1.5s}}.Yvqh9W_config[data-gallery=true] .Yvqh9W_configScroll>:not(:first-child),.Yvqh9W_config[data-gallery=true] .Yvqh9W_footer,.Yvqh9W_canvas[data-gallery=true]>.Yvqh9W_canvasState,.Yvqh9W_canvas[data-gallery=true]>.Yvqh9W_canvasError,.Yvqh9W_canvas[data-gallery=true]>.Yvqh9W_canvasBody,.Yvqh9W_studio:has(.Yvqh9W_config[data-gallery=true])>.Yvqh9W_history{display:none}.Yvqh9W_config[data-gallery=true] .Yvqh9W_configScroll{flex:none;order:1;display:flex;overflow:visible}.Yvqh9W_config[data-gallery=true] .Yvqh9W_galleryFilters{flex:1;order:2;min-height:0}.Yvqh9W_galleryFilters{padding:18px 14px;overflow:hidden auto}.Yvqh9W_galleryFilterHeading{color:var(--dsw-alias-label-tertiary);margin:0 4px 10px;font-size:12px;font-weight:600}.Yvqh9W_galleryFilter{width:100%;min-height:34px;color:var(--dsw-alias-label-secondary);cursor:pointer;text-align:left;background:0 0;border:0;border-radius:9px;justify-content:space-between;align-items:center;padding:0 10px;display:flex}.Yvqh9W_galleryFilter:hover,.Yvqh9W_galleryFilter[data-active]{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent)}.Yvqh9W_galleryFilterCount{min-width:20px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);text-align:center;border-radius:999px;padding:1px 6px;font-size:11px}.Yvqh9W_galleryFilterDivider{background:var(--dsw-alias-border-l1);height:1px;margin:18px 4px}.Yvqh9W_galleryRatioList{flex-wrap:wrap;gap:6px;display:flex}.Yvqh9W_galleryRatio{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;border:0;border-radius:999px;padding:6px 10px;font-size:12px}.Yvqh9W_galleryRatio[data-active]{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 13%, transparent)}.Yvqh9W_galleryFilterNote{color:var(--dsw-alias-label-quaternary);margin:20px 4px 0;font-size:11px;line-height:1.5}.Yvqh9W_galleryWorkspace{box-sizing:border-box;flex-direction:column;width:100%;min-width:0;height:100%;min-height:0;padding:22px 24px 26px;display:flex;position:absolute;inset:0;overflow:hidden}.Yvqh9W_galleryToolbar{flex:none;justify-content:space-between;align-items:center;gap:16px;min-width:0;margin-bottom:18px;display:flex}.Yvqh9W_galleryHeading{color:var(--dsw-alias-label-primary);margin:0;font-size:20px;font-weight:700;display:inline}.Yvqh9W_galleryCount{color:var(--dsw-alias-label-tertiary);margin-left:8px;font-size:13px}.Yvqh9W_galleryToolbarActions{flex-wrap:wrap;align-items:center;gap:10px;min-width:0;display:flex}.Yvqh9W_galleryViewToggle{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:9px;padding:3px;display:flex}.Yvqh9W_galleryViewToggle button,.Yvqh9W_gallerySort,.Yvqh9W_galleryClear{min-height:30px;color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;border-radius:7px;padding:0 10px;font-size:12px}.Yvqh9W_galleryViewToggle button[data-active],.Yvqh9W_galleryViewToggle button:hover,.Yvqh9W_gallerySort:hover,.Yvqh9W_galleryClear:hover{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent)}.Yvqh9W_gallerySort{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1)}.Yvqh9W_galleryClear{border:1px solid var(--dsw-alias-border-l1)}.Yvqh9W_galleryMasonry{box-sizing:border-box;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--dsw-alias-border-l2) transparent;flex:auto;grid-template-columns:repeat(3,minmax(0,1fr));grid-auto-rows:max-content;align-content:start;gap:16px;width:100%;min-width:0;max-width:100%;height:0;min-height:0;padding:2px 8px 16px 2px;display:grid;overflow:hidden scroll}.Yvqh9W_galleryMasonry::-webkit-scrollbar{width:8px}.Yvqh9W_galleryMasonry::-webkit-scrollbar-thumb{background:var(--dsw-alias-border-l2);border-radius:999px}.Yvqh9W_galleryCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-1);border-radius:14px;width:100%;margin:0;display:block;overflow:hidden;box-shadow:0 5px 18px #18203612}.Yvqh9W_galleryImageButton{background:var(--dsw-alias-bg-base);cursor:zoom-in;border:0;width:100%;padding:0;display:block;position:relative}.Yvqh9W_galleryImage{aspect-ratio:4/3;object-fit:cover;width:100%;display:block}.Yvqh9W_galleryMasonry[data-view=masonry] .Yvqh9W_galleryCard:nth-child(3n+1) .Yvqh9W_galleryImage{aspect-ratio:4/5}.Yvqh9W_galleryMasonry[data-view=masonry] .Yvqh9W_galleryCard:nth-child(3n+2) .Yvqh9W_galleryImage{aspect-ratio:4/3}.Yvqh9W_galleryMasonry[data-view=masonry] .Yvqh9W_galleryCard:nth-child(3n) .Yvqh9W_galleryImage{aspect-ratio:3/4}.Yvqh9W_galleryBadge{color:#fff;backdrop-filter:blur(4px);background:#121724c2;border-radius:999px;padding:4px 9px;font-size:11px;position:absolute;top:10px;left:10px}.Yvqh9W_galleryCardFooter{align-items:center;gap:9px;min-width:0;padding:10px 12px;display:flex}.Yvqh9W_galleryAvatar{color:#fff;background:var(--dsw-alias-brand-primary);border-radius:50%;flex:none;place-items:center;width:27px;height:27px;font-size:12px;font-weight:700;display:grid}.Yvqh9W_galleryCardInfo{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.Yvqh9W_galleryCardInfo strong,.Yvqh9W_galleryCardInfo small{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.Yvqh9W_galleryCardInfo strong{color:var(--dsw-alias-label-primary);font-size:12px}.Yvqh9W_galleryCardInfo small{color:var(--dsw-alias-label-tertiary);font-size:10px}.Yvqh9W_galleryRemove{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:50%;flex:none;padding:0;font-size:18px}.Yvqh9W_galleryRemove:hover{color:var(--dsw-alias-state-error);background:var(--dsw-alias-bg-layer-2)}@media (width<=1100px){.Yvqh9W_galleryMasonry{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (width<=760px){.Yvqh9W_studio{flex-direction:column;overflow:auto}.Yvqh9W_config{width:auto;max-width:none;height:auto;min-height:0}.Yvqh9W_config[data-gallery=true]{flex:none}.Yvqh9W_canvas{min-height:560px}.Yvqh9W_galleryToolbar{flex-direction:column;align-items:flex-start}.Yvqh9W_galleryToolbarActions{flex-wrap:wrap;width:100%}.Yvqh9W_galleryMasonry{grid-template-columns:1fr}}";
403
1103
  const tagId$1 = "@dickpy/dsh-imagegen/panel.module.css";
404
1104
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
405
1105
  const tag = document.createElement("style");
@@ -409,100 +1109,132 @@ window.__ModuleLoader__.load({
409
1109
  document.head.appendChild(tag);
410
1110
  }
411
1111
  var panel_module_css_default = {
412
- "panel": "Yvqh9W_panel",
413
- "panelHeader": "Yvqh9W_panelHeader",
1112
+ "galleryWorkspace": "Yvqh9W_galleryWorkspace",
1113
+ "galleryClear": "Yvqh9W_galleryClear",
1114
+ "generateInner": "Yvqh9W_generateInner",
1115
+ "galleryAdd": "Yvqh9W_galleryAdd",
1116
+ "lightboxScaleFrame": "Yvqh9W_lightboxScaleFrame",
1117
+ "panelTitle": "Yvqh9W_panelTitle",
1118
+ "modeRow": "Yvqh9W_modeRow",
1119
+ "generateButton": "Yvqh9W_generateButton",
1120
+ "panelHeading": "Yvqh9W_panelHeading",
1121
+ "historyThumb": "Yvqh9W_historyThumb",
1122
+ "canvasHistoryTag": "Yvqh9W_canvasHistoryTag",
1123
+ "galleryViewToggle": "Yvqh9W_galleryViewToggle",
1124
+ "configScroll": "Yvqh9W_configScroll",
414
1125
  "reference": "Yvqh9W_reference",
415
- "updateBanner": "Yvqh9W_updateBanner",
416
- "lightboxDownload": "Yvqh9W_lightboxDownload",
417
- "updateText": "Yvqh9W_updateText",
418
- "studio": "Yvqh9W_studio",
419
- "hiddenFile": "Yvqh9W_hiddenFile",
420
- "uploadHint": "Yvqh9W_uploadHint",
421
- "referenceActions": "Yvqh9W_referenceActions",
422
- "paramLabel": "Yvqh9W_paramLabel",
423
- "entryLabel": "Yvqh9W_entryLabel",
424
1126
  "imageCaption": "Yvqh9W_imageCaption",
425
- "panelTitle": "Yvqh9W_panelTitle",
426
- "historyHeader": "Yvqh9W_historyHeader",
427
- "card": "Yvqh9W_card",
1127
+ "historyActions": "Yvqh9W_historyActions",
1128
+ "galleryImageButton": "Yvqh9W_galleryImageButton",
1129
+ "lightboxIndex": "Yvqh9W_lightboxIndex",
1130
+ "canvasBody": "Yvqh9W_canvasBody",
1131
+ "galleryAvatar": "Yvqh9W_galleryAvatar",
428
1132
  "optionGrid": "Yvqh9W_optionGrid",
429
- "historyList": "Yvqh9W_historyList",
430
- "historyItem": "Yvqh9W_historyItem",
431
1133
  "footer": "Yvqh9W_footer",
432
- "updateActions": "Yvqh9W_updateActions",
433
1134
  "modelLabel": "Yvqh9W_modelLabel",
434
- "config": "Yvqh9W_config",
1135
+ "bigSpinner": "Yvqh9W_bigSpinner",
1136
+ "galleryFilterCount": "Yvqh9W_galleryFilterCount",
1137
+ "galleryRatioList": "Yvqh9W_galleryRatioList",
1138
+ "galleryRatio": "Yvqh9W_galleryRatio",
1139
+ "canvasError": "Yvqh9W_canvasError",
1140
+ "historyEmpty": "Yvqh9W_historyEmpty",
1141
+ "githubLink": "Yvqh9W_githubLink",
1142
+ "imageCard": "Yvqh9W_imageCard",
1143
+ "updateText": "Yvqh9W_updateText",
435
1144
  "canvasStateTitle": "Yvqh9W_canvasStateTitle",
1145
+ "modelMenu": "Yvqh9W_modelMenu",
1146
+ "prompt": "Yvqh9W_prompt",
1147
+ "uploadIcon": "Yvqh9W_uploadIcon",
1148
+ "canvas": "Yvqh9W_canvas",
1149
+ "galleryImage": "Yvqh9W_galleryImage",
1150
+ "entry": "Yvqh9W_entry",
1151
+ "updateRelease": "Yvqh9W_updateRelease",
436
1152
  "dshImageGenSpin": "Yvqh9W_dshImageGenSpin",
437
- "spinner": "Yvqh9W_spinner",
438
- "historyEmpty": "Yvqh9W_historyEmpty",
439
- "canvasBody": "Yvqh9W_canvasBody",
1153
+ "lightboxDownload": "Yvqh9W_lightboxDownload",
1154
+ "galleryCardFooter": "Yvqh9W_galleryCardFooter",
1155
+ "download": "Yvqh9W_download",
1156
+ "historyTitle": "Yvqh9W_historyTitle",
1157
+ "modelMenuList": "Yvqh9W_modelMenuList",
440
1158
  "canvasMeta": "Yvqh9W_canvasMeta",
441
- "image": "Yvqh9W_image",
442
- "lightboxScaleFrame": "Yvqh9W_lightboxScaleFrame",
443
- "canvas": "Yvqh9W_canvas",
444
- "lightboxTools": "Yvqh9W_lightboxTools",
445
- "lightboxTool": "Yvqh9W_lightboxTool",
446
- "paramGroup": "Yvqh9W_paramGroup",
447
- "canvasStateHint": "Yvqh9W_canvasStateHint",
1159
+ "galleryFilters": "Yvqh9W_galleryFilters",
1160
+ "updateActions": "Yvqh9W_updateActions",
448
1161
  "historyClear": "Yvqh9W_historyClear",
449
- "historyMain": "Yvqh9W_historyMain",
450
- "grid": "Yvqh9W_grid",
1162
+ "galleryToolbarActions": "Yvqh9W_galleryToolbarActions",
451
1163
  "lightboxFigure": "Yvqh9W_lightboxFigure",
452
- "lightboxCopy": "Yvqh9W_lightboxCopy",
453
- "lightboxCaptionRow": "Yvqh9W_lightboxCaptionRow",
454
- "lightboxCaption": "Yvqh9W_lightboxCaption",
455
- "lightboxActions": "Yvqh9W_lightboxActions",
456
- "generateButton": "Yvqh9W_generateButton",
1164
+ "panel": "Yvqh9W_panel",
1165
+ "referenceImage": "Yvqh9W_referenceImage",
1166
+ "historyMain": "Yvqh9W_historyMain",
1167
+ "zoomHint": "Yvqh9W_zoomHint",
457
1168
  "lightboxEdit": "Yvqh9W_lightboxEdit",
458
- "lightboxNav": "Yvqh9W_lightboxNav",
1169
+ "galleryToolbar": "Yvqh9W_galleryToolbar",
1170
+ "galleryCard": "Yvqh9W_galleryCard",
1171
+ "historyItem": "Yvqh9W_historyItem",
1172
+ "studio": "Yvqh9W_studio",
1173
+ "galleryFilterHeading": "Yvqh9W_galleryFilterHeading",
1174
+ "historyHeader": "Yvqh9W_historyHeader",
1175
+ "paramLabel": "Yvqh9W_paramLabel",
459
1176
  "historyAction": "Yvqh9W_historyAction",
460
- "canvasError": "Yvqh9W_canvasError",
461
- "lightboxMeta": "Yvqh9W_lightboxMeta",
462
- "history": "Yvqh9W_history",
1177
+ "galleryCardInfo": "Yvqh9W_galleryCardInfo",
1178
+ "lightboxCaptionRow": "Yvqh9W_lightboxCaptionRow",
463
1179
  "promptCount": "Yvqh9W_promptCount",
464
- "historyTitle": "Yvqh9W_historyTitle",
465
- "historyThumbPlaceholder": "Yvqh9W_historyThumbPlaceholder",
466
- "prompt": "Yvqh9W_prompt",
467
- "historyMeta": "Yvqh9W_historyMeta",
468
- "modePill": "Yvqh9W_modePill",
469
- "entry": "Yvqh9W_entry",
470
- "generateInner": "Yvqh9W_generateInner",
471
- "zoomHint": "Yvqh9W_zoomHint",
1180
+ "historyList": "Yvqh9W_historyList",
1181
+ "config": "Yvqh9W_config",
1182
+ "galleryBadge": "Yvqh9W_galleryBadge",
1183
+ "modelWrap": "Yvqh9W_modelWrap",
1184
+ "canvasState": "Yvqh9W_canvasState",
1185
+ "historyInfo": "Yvqh9W_historyInfo",
1186
+ "image": "Yvqh9W_image",
1187
+ "lightboxImage": "Yvqh9W_lightboxImage",
1188
+ "lightboxClose": "Yvqh9W_lightboxClose",
1189
+ "promptFooter": "Yvqh9W_promptFooter",
1190
+ "galleryFilterNote": "Yvqh9W_galleryFilterNote",
1191
+ "galleryHeading": "Yvqh9W_galleryHeading",
1192
+ "history": "Yvqh9W_history",
1193
+ "historyPrompt": "Yvqh9W_historyPrompt",
472
1194
  "lightboxZoomLevel": "Yvqh9W_lightboxZoomLevel",
473
- "lightboxIndex": "Yvqh9W_lightboxIndex",
1195
+ "galleryCount": "Yvqh9W_galleryCount",
1196
+ "galleryFilterDivider": "Yvqh9W_galleryFilterDivider",
1197
+ "modePill": "Yvqh9W_modePill",
1198
+ "grid": "Yvqh9W_grid",
1199
+ "updateBanner": "Yvqh9W_updateBanner",
1200
+ "optionPill": "Yvqh9W_optionPill",
1201
+ "galleryToast": "Yvqh9W_galleryToast",
1202
+ "dshImageGenToastIn": "Yvqh9W_dshImageGenToastIn",
1203
+ "optionRow": "Yvqh9W_optionRow",
1204
+ "referenceActions": "Yvqh9W_referenceActions",
1205
+ "panelHeader": "Yvqh9W_panelHeader",
1206
+ "paramGroup": "Yvqh9W_paramGroup",
474
1207
  "paramHint": "Yvqh9W_paramHint",
1208
+ "card": "Yvqh9W_card",
1209
+ "historyThumbPlaceholder": "Yvqh9W_historyThumbPlaceholder",
1210
+ "entryLabel": "Yvqh9W_entryLabel",
1211
+ "uploadHint": "Yvqh9W_uploadHint",
1212
+ "modelSelect": "Yvqh9W_modelSelect",
1213
+ "canvasEmptyIcon": "Yvqh9W_canvasEmptyIcon",
475
1214
  "lightbox": "Yvqh9W_lightbox",
476
- "lightboxImage": "Yvqh9W_lightboxImage",
477
- "connectionStatus": "Yvqh9W_connectionStatus",
478
- "referenceImage": "Yvqh9W_referenceImage",
479
- "promptFooter": "Yvqh9W_promptFooter",
1215
+ "lightboxStage": "Yvqh9W_lightboxStage",
1216
+ "lightboxMeta": "Yvqh9W_lightboxMeta",
1217
+ "entryIcon": "Yvqh9W_entryIcon",
1218
+ "hiddenFile": "Yvqh9W_hiddenFile",
1219
+ "galleryMasonry": "Yvqh9W_galleryMasonry",
480
1220
  "connectionDot": "Yvqh9W_connectionDot",
481
- "historyInfo": "Yvqh9W_historyInfo",
482
- "uploadBox": "Yvqh9W_uploadBox",
483
- "canvasEmptyIcon": "Yvqh9W_canvasEmptyIcon",
1221
+ "lightboxNav": "Yvqh9W_lightboxNav",
1222
+ "galleryRemove": "Yvqh9W_galleryRemove",
1223
+ "gallerySort": "Yvqh9W_gallerySort",
1224
+ "historyMeta": "Yvqh9W_historyMeta",
1225
+ "lightboxCopy": "Yvqh9W_lightboxCopy",
1226
+ "spinner": "Yvqh9W_spinner",
1227
+ "lightboxCaption": "Yvqh9W_lightboxCaption",
1228
+ "galleryFilter": "Yvqh9W_galleryFilter",
484
1229
  "view": "Yvqh9W_view",
485
- "entryIcon": "Yvqh9W_entryIcon",
486
- "lightboxClose": "Yvqh9W_lightboxClose",
487
- "download": "Yvqh9W_download",
488
- "modelSelect": "Yvqh9W_modelSelect",
489
- "historyPrompt": "Yvqh9W_historyPrompt",
490
- "uploadIcon": "Yvqh9W_uploadIcon",
491
- "canvasHistoryTag": "Yvqh9W_canvasHistoryTag",
492
- "historyActions": "Yvqh9W_historyActions",
493
- "panelHeading": "Yvqh9W_panelHeading",
494
- "panelSubtitle": "Yvqh9W_panelSubtitle",
495
- "historyThumb": "Yvqh9W_historyThumb",
496
- "modeRow": "Yvqh9W_modeRow",
497
- "canvasState": "Yvqh9W_canvasState",
498
- "configScroll": "Yvqh9W_configScroll",
499
- "modelWrap": "Yvqh9W_modelWrap",
500
- "lightboxStage": "Yvqh9W_lightboxStage",
501
- "optionRow": "Yvqh9W_optionRow",
502
- "updateRelease": "Yvqh9W_updateRelease",
503
- "imageCard": "Yvqh9W_imageCard",
504
- "optionPill": "Yvqh9W_optionPill",
505
- "bigSpinner": "Yvqh9W_bigSpinner"
1230
+ "connectionStatus": "Yvqh9W_connectionStatus",
1231
+ "lightboxTools": "Yvqh9W_lightboxTools",
1232
+ "uploadBox": "Yvqh9W_uploadBox",
1233
+ "lightboxTool": "Yvqh9W_lightboxTool",
1234
+ "canvasStateHint": "Yvqh9W_canvasStateHint",
1235
+ "templatesButton": "Yvqh9W_templatesButton",
1236
+ "lightboxActions": "Yvqh9W_lightboxActions",
1237
+ "modelMenuItem": "Yvqh9W_modelMenuItem"
506
1238
  };
507
1239
  //#endregion
508
1240
  //#region src/client/ImageGenPanel.tsx
@@ -515,34 +1247,44 @@ window.__ModuleLoader__.load({
515
1247
  * Controls ride the system UI primitives (@deepseek-ai/dsh-client-ui-primitives,
516
1248
  * a platform module) so the studio matches the dsh shell look by construction.
517
1249
  */
518
- /** The model dropdown offers exactly the plugin's namesake model. */
519
- const MODELS = ["gpt-image-2"];
520
- /** All size options for gpt-image-2. */
1250
+ /** Models offered by the dropdown. Anything OpenAI-compatible that answers
1251
+ * /images/generations (+ /images/edits) works; grok-imagine-image is handled
1252
+ * specially host-side (JSON /images/edits, aspect_ratio, b64_json). */
1253
+ const MODELS = ["gpt-image-2", "grok-imagine-image"];
1254
+ /** Size options, presented as aspect ratios (auto = let the model decide).
1255
+ * The host maps each ratio onto the model's own vocabulary: aspect_ratio for
1256
+ * Grok Imagine, the closest pixel size for OpenAI-compatible endpoints. */
521
1257
  const SIZES = [
522
1258
  "auto",
523
- "1024x1024",
524
- "1536x1024",
525
- "1024x1536",
526
- "512x512",
527
- "1792x1024",
528
- "1024x1792"
1259
+ "1:1",
1260
+ "3:4",
1261
+ "4:3",
1262
+ "9:16",
1263
+ "2:3",
1264
+ "3:2",
1265
+ "16:9",
1266
+ "21:9"
529
1267
  ];
530
1268
  /** Size option keys in the locale dictionary. */
531
1269
  const SIZE_KEYS = {
532
1270
  auto: "size.auto",
533
- "1024x1024": "size.square",
534
- "1536x1024": "size.landscape",
535
- "1024x1536": "size.portrait",
536
- "512x512": "size.small",
537
- "1792x1024": "size.wide",
538
- "1024x1792": "size.tall"
1271
+ "1:1": "size.square",
1272
+ "3:4": "size.portrait34",
1273
+ "4:3": "size.landscape43",
1274
+ "9:16": "size.portrait916",
1275
+ "2:3": "size.portrait23",
1276
+ "3:2": "size.landscape32",
1277
+ "16:9": "size.wide169",
1278
+ "21:9": "size.ultrawide21"
539
1279
  };
540
- /** Quality options. */
1280
+ /** Quality options, shown as output-resolution tiers (auto = let the model
1281
+ * decide). The host maps them: resolution for Grok, quality level for
1282
+ * OpenAI-compatible endpoints (1k→low, 2k→medium, 4k→high). */
541
1283
  const QUALITIES = [
542
1284
  "auto",
543
- "low",
544
- "medium",
545
- "high"
1285
+ "1k",
1286
+ "2k",
1287
+ "4k"
546
1288
  ];
547
1289
  /** Detail options ('' = omit the passthrough). */
548
1290
  const DETAILS = [
@@ -555,6 +1297,32 @@ window.__ModuleLoader__.load({
555
1297
  const PREVIEW_SCALE_MIN = .5;
556
1298
  const PREVIEW_SCALE_MAX = 3;
557
1299
  const PREVIEW_SCALE_STEP = .25;
1300
+ /** Legacy pixel sizes saved by older versions, mapped onto the current
1301
+ * aspect-ratio vocabulary so restoring old history entries still works. */
1302
+ const LEGACY_SIZE_TO_RATIO = {
1303
+ "512x512": "1:1",
1304
+ "1024x1024": "1:1",
1305
+ "1536x1024": "3:2",
1306
+ "1024x1536": "2:3",
1307
+ "1792x1024": "16:9",
1308
+ "1024x1792": "9:16"
1309
+ };
1310
+ /** Legacy quality levels saved by older versions, mapped onto resolution. */
1311
+ const LEGACY_QUALITY_TO_RES = {
1312
+ low: "1k",
1313
+ medium: "2k",
1314
+ high: "4k"
1315
+ };
1316
+ /** Normalize a saved size value into a current dropdown option. */
1317
+ function normalizeSize(value) {
1318
+ if (SIZES.includes(value)) return value;
1319
+ return LEGACY_SIZE_TO_RATIO[value] ?? "auto";
1320
+ }
1321
+ /** Normalize a saved quality value into a current dropdown option. */
1322
+ function normalizeQuality(value) {
1323
+ if (QUALITIES.includes(value)) return value;
1324
+ return LEGACY_QUALITY_TO_RES[value] ?? "auto";
1325
+ }
558
1326
  function clampPreviewScale(scale) {
559
1327
  return Math.min(PREVIEW_SCALE_MAX, Math.max(PREVIEW_SCALE_MIN, scale));
560
1328
  }
@@ -626,13 +1394,14 @@ window.__ModuleLoader__.load({
626
1394
  const configured = (config?.apiUrl ?? "").trim() !== "";
627
1395
  const keySet = useKeySet(scope);
628
1396
  const connected = enabled && configured && keySet;
629
- const [mode, setMode] = (0, react.useState)("text");
1397
+ const [tab, setTab] = (0, react.useState)("text");
630
1398
  const [prompt, setPrompt] = (0, react.useState)("");
631
1399
  const [size, setSize] = (0, react.useState)("auto");
632
1400
  const [quality, setQuality] = (0, react.useState)("auto");
633
1401
  const [count, setCount] = (0, react.useState)(1);
634
1402
  const [detail, setDetail] = (0, react.useState)("");
635
1403
  const [model, setModel] = (0, react.useState)(MODELS[0]);
1404
+ const [modelOpen, setModelOpen] = (0, react.useState)(false);
636
1405
  const [refImage, setRefImage] = (0, react.useState)(null);
637
1406
  const [images, setImages] = (0, react.useState)([]);
638
1407
  const [error, setError] = (0, react.useState)(null);
@@ -640,6 +1409,14 @@ window.__ModuleLoader__.load({
640
1409
  const [startedAt, setStartedAt] = (0, react.useState)(null);
641
1410
  const [history, setHistory] = (0, react.useState)([]);
642
1411
  const [viewingHistoryId, setViewingHistoryId] = (0, react.useState)(null);
1412
+ const [gallery, setGallery] = (0, react.useState)([]);
1413
+ const [galleryViewingId, setGalleryViewingId] = (0, react.useState)(null);
1414
+ const [galleryAdding, setGalleryAdding] = (0, react.useState)(false);
1415
+ const [galleryMessage, setGalleryMessage] = (0, react.useState)(null);
1416
+ const [galleryFilter, setGalleryFilter] = (0, react.useState)("all");
1417
+ const [galleryRatio, setGalleryRatio] = (0, react.useState)("all");
1418
+ const [galleryView, setGalleryView] = (0, react.useState)("masonry");
1419
+ const [gallerySort, setGallerySort] = (0, react.useState)("newest");
643
1420
  const [preview, setPreview] = (0, react.useState)(null);
644
1421
  const [previewScale, setPreviewScale] = (0, react.useState)(1);
645
1422
  const [promptCopied, setPromptCopied] = (0, react.useState)(false);
@@ -647,18 +1424,42 @@ window.__ModuleLoader__.load({
647
1424
  const [updating, setUpdating] = (0, react.useState)(false);
648
1425
  const [updateMessage, setUpdateMessage] = (0, react.useState)(null);
649
1426
  const [updateResult, setUpdateResult] = (0, react.useState)(null);
1427
+ const [libraryOpen, setLibraryOpen] = (0, react.useState)(false);
650
1428
  const fileInput = (0, react.useRef)(null);
651
1429
  const previewStage = (0, react.useRef)(null);
652
1430
  const elapsed = useElapsed(generating, startedAt);
1431
+ const filteredGallery = gallery.filter((entry) => {
1432
+ if (galleryFilter === "all") return true;
1433
+ if (galleryFilter === "text" || galleryFilter === "edit") return entry.mode === galleryFilter;
1434
+ return entry.model === galleryFilter;
1435
+ }).filter((entry) => galleryRatio === "all" || normalizeSize(entry.size) === galleryRatio).slice().sort((a, b) => gallerySort === "newest" ? b.createdAt - a.createdAt : a.createdAt - b.createdAt);
653
1436
  (0, react.useEffect)(() => {
654
1437
  let disposed = false;
655
1438
  api.historyList().then((entries) => {
656
1439
  if (!disposed) setHistory(entries);
657
1440
  }).catch(() => {});
1441
+ api.galleryList().then((entries) => {
1442
+ if (!disposed) setGallery(entries);
1443
+ }).catch(() => {});
658
1444
  return () => {
659
1445
  disposed = true;
660
1446
  };
661
1447
  }, [api]);
1448
+ const modelMenuRef = (0, react.useRef)(null);
1449
+ (0, react.useEffect)(() => {
1450
+ if (!modelOpen) return;
1451
+ const onPointer = (event) => {
1452
+ const target = event.target;
1453
+ if (target instanceof Node && modelMenuRef.current?.contains(target)) return;
1454
+ setModelOpen(false);
1455
+ };
1456
+ document.addEventListener("mousedown", onPointer);
1457
+ document.addEventListener("focusin", onPointer);
1458
+ return () => {
1459
+ document.removeEventListener("mousedown", onPointer);
1460
+ document.removeEventListener("focusin", onPointer);
1461
+ };
1462
+ }, [modelOpen]);
662
1463
  (0, react.useEffect)(() => {
663
1464
  let disposed = false;
664
1465
  api.updateCheck().then((info) => {
@@ -715,20 +1516,20 @@ window.__ModuleLoader__.load({
715
1516
  setError(tt("prompt.required"));
716
1517
  return;
717
1518
  }
718
- if (mode === "edit" && refImage === null) {
1519
+ if (tab === "edit" && refImage === null) {
719
1520
  setError(tt("edit.required"));
720
1521
  return;
721
1522
  }
722
1523
  const request = {
723
- mode,
1524
+ mode: tab === "gallery" ? "text" : tab,
724
1525
  model,
725
1526
  prompt: promptText,
726
1527
  size,
727
1528
  quality,
728
1529
  n: count,
729
1530
  detail,
730
- ...mode === "edit" && refImage !== null ? { image: refImage.dataUrl } : {},
731
- ...mode === "edit" && refImage !== null ? { refName: refImage.name } : {}
1531
+ ...tab === "edit" && refImage !== null ? { image: refImage.dataUrl } : {},
1532
+ ...tab === "edit" && refImage !== null ? { refName: refImage.name } : {}
732
1533
  };
733
1534
  setGenerating(true);
734
1535
  setError(null);
@@ -738,6 +1539,7 @@ window.__ModuleLoader__.load({
738
1539
  const result = await api.generate(request);
739
1540
  setImages(result.images);
740
1541
  setViewingHistoryId(null);
1542
+ setGalleryViewingId(null);
741
1543
  if (result.history !== void 0) setHistory(result.history);
742
1544
  if (result.historyError !== void 0) setError(result.historyError);
743
1545
  } catch (caught) {
@@ -803,6 +1605,7 @@ window.__ModuleLoader__.load({
803
1605
  setImages(await historyImagesToGenerated(entry.images));
804
1606
  setError(null);
805
1607
  setViewingHistoryId(entry.id);
1608
+ setGalleryViewingId(null);
806
1609
  } catch (caught) {
807
1610
  setError(errorMessage(caught));
808
1611
  }
@@ -811,10 +1614,10 @@ window.__ModuleLoader__.load({
811
1614
  const restoreHistoryEntry = async (entry) => {
812
1615
  try {
813
1616
  const restored = await historyImagesToGenerated(entry.images);
814
- setMode(entry.mode);
1617
+ setTab(entry.mode);
815
1618
  setPrompt(entry.prompt);
816
- setSize(SIZES.includes(entry.size) ? entry.size : "auto");
817
- setQuality(QUALITIES.includes(entry.quality) ? entry.quality : "auto");
1619
+ setSize(normalizeSize(entry.size));
1620
+ setQuality(normalizeQuality(entry.quality));
818
1621
  setDetail(DETAILS.includes(entry.detail) ? entry.detail : "");
819
1622
  setCount(entry.n >= 1 && entry.n <= 4 ? entry.n : 1);
820
1623
  setModel(MODELS.includes(entry.model) ? entry.model : MODELS[0]);
@@ -822,6 +1625,7 @@ window.__ModuleLoader__.load({
822
1625
  setImages(restored);
823
1626
  setError(null);
824
1627
  setViewingHistoryId(entry.id);
1628
+ setGalleryViewingId(null);
825
1629
  } catch (caught) {
826
1630
  setError(errorMessage(caught));
827
1631
  }
@@ -842,8 +1646,111 @@ window.__ModuleLoader__.load({
842
1646
  setHistory(await api.historyClear());
843
1647
  } catch {}
844
1648
  };
1649
+ /** Add one generated image to the gallery (host deduplicates by content).
1650
+ * `entry` makes the action available from a history/gallery list item (its
1651
+ * metadata + first image are saved); otherwise the current form state is
1652
+ * used. */
1653
+ const addToGallery = async (image, entry) => {
1654
+ if (galleryAdding || tab === "gallery") return;
1655
+ const source = entry ?? viewingEntry ?? {
1656
+ mode: tab === "edit" ? "edit" : "text",
1657
+ model,
1658
+ prompt: prompt.trim(),
1659
+ size,
1660
+ quality,
1661
+ detail,
1662
+ ...refImage !== null ? { refName: refImage.name } : {}
1663
+ };
1664
+ setGalleryAdding(true);
1665
+ try {
1666
+ const result = await api.galleryAppend({
1667
+ id: "",
1668
+ createdAt: Date.now(),
1669
+ mode: source.mode,
1670
+ model: source.model,
1671
+ prompt: source.prompt,
1672
+ size: source.size,
1673
+ quality: source.quality,
1674
+ detail: source.detail,
1675
+ n: 1,
1676
+ images: [image],
1677
+ ...source.refName === void 0 ? {} : { refName: source.refName }
1678
+ });
1679
+ setGallery(result.entries);
1680
+ setGalleryMessage(result.added ? tt("gallery.added") : tt("gallery.already"));
1681
+ window.setTimeout(() => {
1682
+ setGalleryMessage(null);
1683
+ }, 2200);
1684
+ } catch (caught) {
1685
+ setError(errorMessage(caught));
1686
+ } finally {
1687
+ setGalleryAdding(false);
1688
+ }
1689
+ };
1690
+ /** Add one history entry's first image to the gallery (fetches it from the
1691
+ * history image route, then delegates to addToGallery). */
1692
+ const addHistoryEntryToGallery = async (entry) => {
1693
+ if (galleryAdding || entry.images.length === 0) return;
1694
+ try {
1695
+ const [image] = await historyImagesToGenerated(entry.images.slice(0, 1));
1696
+ if (image === void 0) return;
1697
+ await addToGallery(image, entry);
1698
+ } catch (caught) {
1699
+ setError(errorMessage(caught));
1700
+ }
1701
+ };
1702
+ /** View a gallery image in the canvas. */
1703
+ const viewGalleryEntry = async (entry) => {
1704
+ try {
1705
+ const restored = await historyImagesToGenerated(entry.images);
1706
+ setImages(restored);
1707
+ setError(null);
1708
+ setViewingHistoryId(null);
1709
+ setGalleryViewingId(entry.id);
1710
+ if (restored.length > 0) openPreview(restored, 0);
1711
+ } catch (caught) {
1712
+ setError(errorMessage(caught));
1713
+ }
1714
+ };
1715
+ /** Restore a gallery entry's parameters (and its images) into the form. */
1716
+ const restoreGalleryEntry = async (entry) => {
1717
+ try {
1718
+ const restored = await historyImagesToGenerated(entry.images);
1719
+ setTab(entry.mode);
1720
+ setPrompt(entry.prompt);
1721
+ setSize(normalizeSize(entry.size));
1722
+ setQuality(normalizeQuality(entry.quality));
1723
+ setDetail(DETAILS.includes(entry.detail) ? entry.detail : "");
1724
+ setCount(entry.n >= 1 && entry.n <= 4 ? entry.n : 1);
1725
+ setModel(MODELS.includes(entry.model) ? entry.model : MODELS[0]);
1726
+ setRefImage(null);
1727
+ setImages(restored);
1728
+ setError(null);
1729
+ setViewingHistoryId(null);
1730
+ setGalleryViewingId(null);
1731
+ } catch (caught) {
1732
+ setError(errorMessage(caught));
1733
+ }
1734
+ };
1735
+ /** Remove one gallery entry. */
1736
+ const deleteGalleryEntry = async (id) => {
1737
+ setGallery(gallery.filter((entry) => entry.id !== id));
1738
+ if (galleryViewingId === id) setGalleryViewingId(null);
1739
+ try {
1740
+ setGallery(await api.galleryRemove(id));
1741
+ } catch {}
1742
+ };
1743
+ /** Remove every gallery entry. */
1744
+ const clearGalleryAll = async () => {
1745
+ setGallery([]);
1746
+ setGalleryViewingId(null);
1747
+ try {
1748
+ setGallery(await api.galleryClear());
1749
+ } catch {}
1750
+ };
845
1751
  const generateDisabled = generating || !enabled || !configured;
846
1752
  const viewingEntry = viewingHistoryId === null ? null : history.find((entry) => entry.id === viewingHistoryId) ?? null;
1753
+ const viewingGalleryEntry = galleryViewingId === null ? null : gallery.find((entry) => entry.id === galleryViewingId) ?? null;
847
1754
  const previewImage = preview === null ? null : preview.images[preview.index] ?? null;
848
1755
  const previewFrameScale = Math.max(1, previewScale);
849
1756
  const previewImageScale = previewScale / previewFrameScale;
@@ -871,7 +1778,7 @@ window.__ModuleLoader__.load({
871
1778
  };
872
1779
  const addPreviewToEdit = () => {
873
1780
  if (previewImage === null || preview === null) return;
874
- setMode("edit");
1781
+ setTab("edit");
875
1782
  setRefImage({
876
1783
  dataUrl: srcOf(previewImage),
877
1784
  name: `dsh-image-${preview.index + 1}.${extensionOf(previewImage.mime)}`
@@ -890,9 +1797,21 @@ window.__ModuleLoader__.load({
890
1797
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
891
1798
  className: panel_module_css_default.panelTitle,
892
1799
  children: tt("panel.title")
893
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
894
- className: panel_module_css_default.panelSubtitle,
895
- children: tt("panel.subtitle")
1800
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1801
+ className: panel_module_css_default.githubLink,
1802
+ href: "https://github.com/dickpy/dsh-imagegen",
1803
+ target: "_blank",
1804
+ rel: "noreferrer",
1805
+ title: tt("panel.githubTip"),
1806
+ "aria-label": tt("panel.githubTip"),
1807
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1808
+ viewBox: "0 0 16 16",
1809
+ width: "15",
1810
+ height: "15",
1811
+ fill: "currentColor",
1812
+ "aria-hidden": "true",
1813
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8z" })
1814
+ })
896
1815
  })]
897
1816
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
898
1817
  type: "button",
@@ -935,249 +1854,501 @@ window.__ModuleLoader__.load({
935
1854
  children: [
936
1855
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
937
1856
  className: panel_module_css_default.config,
938
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
939
- className: panel_module_css_default.configScroll,
940
- children: [
941
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
942
- className: panel_module_css_default.card,
943
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
944
- className: panel_module_css_default.modeRow,
945
- role: "tablist",
946
- "aria-label": tt("panel.title"),
947
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
948
- active: mode === "text",
949
- onClick: () => {
950
- setMode("text");
951
- },
952
- className: panel_module_css_default.modePill,
953
- children: tt("mode.text")
954
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
955
- active: mode === "edit",
956
- onClick: () => {
957
- setMode("edit");
958
- },
959
- className: panel_module_css_default.modePill,
960
- children: tt("mode.edit")
961
- })]
962
- })
963
- }),
964
- mode === "edit" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
965
- className: panel_module_css_default.card,
966
- children: [refImage === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1857
+ "data-gallery": tab === "gallery" ? "true" : void 0,
1858
+ children: [
1859
+ tab === "gallery" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1860
+ className: panel_module_css_default.galleryFilters,
1861
+ children: [
1862
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1863
+ className: panel_module_css_default.galleryFilterHeading,
1864
+ children: tt("gallery.categories")
1865
+ }),
1866
+ [
1867
+ ["all", "gallery.all"],
1868
+ ["text", "mode.text"],
1869
+ ["edit", "mode.edit"],
1870
+ ["gpt-image-2", "gallery.gpt"],
1871
+ ["grok-imagine-image", "gallery.grok"]
1872
+ ].map(([value, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
967
1873
  type: "button",
968
- className: panel_module_css_default.uploadBox,
1874
+ className: panel_module_css_default.galleryFilter,
1875
+ "data-active": galleryFilter === value ? "" : void 0,
969
1876
  onClick: () => {
970
- fileInput.current?.click();
971
- },
972
- onDragOver: (event) => {
973
- event.preventDefault();
974
- },
975
- onDrop: (event) => {
976
- event.preventDefault();
977
- acceptFile(event.dataTransfer.files?.[0]);
1877
+ setGalleryFilter(value);
978
1878
  },
1879
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt(label) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1880
+ className: panel_module_css_default.galleryFilterCount,
1881
+ children: gallery.filter((entry) => value === "all" || value === "text" || value === "edit" ? value === "all" ? true : entry.mode === value : entry.model === value).length
1882
+ })]
1883
+ }, value)),
1884
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: panel_module_css_default.galleryFilterDivider }),
1885
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1886
+ className: panel_module_css_default.galleryFilterHeading,
1887
+ children: tt("gallery.ratio")
1888
+ }),
1889
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1890
+ className: panel_module_css_default.galleryRatioList,
979
1891
  children: [
980
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
981
- className: panel_module_css_default.uploadIcon,
982
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1892
+ "all",
1893
+ "1:1",
1894
+ "3:4",
1895
+ "4:3",
1896
+ "16:9"
1897
+ ].map((ratio) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1898
+ type: "button",
1899
+ className: panel_module_css_default.galleryRatio,
1900
+ "data-active": galleryRatio === ratio ? "" : void 0,
1901
+ onClick: () => {
1902
+ setGalleryRatio(ratio);
1903
+ },
1904
+ children: ratio === "all" ? tt("gallery.all") : ratio
1905
+ }, ratio))
1906
+ }),
1907
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1908
+ className: panel_module_css_default.galleryFilterNote,
1909
+ children: tt("gallery.filterHint")
1910
+ })
1911
+ ]
1912
+ }) : null,
1913
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1914
+ className: panel_module_css_default.configScroll,
1915
+ children: [
1916
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
1917
+ className: panel_module_css_default.card,
1918
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1919
+ className: panel_module_css_default.modeRow,
1920
+ role: "tablist",
1921
+ "aria-label": tt("panel.title"),
1922
+ children: [
1923
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1924
+ active: tab === "text",
1925
+ onClick: () => {
1926
+ setTab("text");
1927
+ },
1928
+ className: panel_module_css_default.modePill,
1929
+ children: tt("mode.text")
1930
+ }),
1931
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1932
+ active: tab === "edit",
1933
+ onClick: () => {
1934
+ setTab("edit");
1935
+ },
1936
+ className: panel_module_css_default.modePill,
1937
+ children: tt("mode.edit")
1938
+ }),
1939
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1940
+ active: tab === "gallery",
1941
+ onClick: () => {
1942
+ setTab("gallery");
1943
+ },
1944
+ className: panel_module_css_default.modePill,
1945
+ children: tt("gallery.title")
1946
+ })
1947
+ ]
1948
+ })
1949
+ }),
1950
+ tab === "edit" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1951
+ className: panel_module_css_default.card,
1952
+ children: [refImage === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1953
+ type: "button",
1954
+ className: panel_module_css_default.uploadBox,
1955
+ onClick: () => {
1956
+ fileInput.current?.click();
1957
+ },
1958
+ onDragOver: (event) => {
1959
+ event.preventDefault();
1960
+ },
1961
+ onDrop: (event) => {
1962
+ event.preventDefault();
1963
+ acceptFile(event.dataTransfer.files?.[0]);
1964
+ },
1965
+ children: [
1966
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1967
+ className: panel_module_css_default.uploadIcon,
1968
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1969
+ viewBox: "0 0 16 16",
1970
+ width: "18",
1971
+ height: "18",
1972
+ fill: "none",
1973
+ stroke: "currentColor",
1974
+ strokeWidth: "1.3",
1975
+ strokeLinecap: "round",
1976
+ strokeLinejoin: "round",
1977
+ "aria-hidden": "true",
1978
+ children: [
1979
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 10.5V3" }),
1980
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M5 5.5l3-3 3 3" }),
1981
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 9v3.5h11V9" })
1982
+ ]
1983
+ })
1984
+ }),
1985
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("edit.upload") }),
1986
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1987
+ className: panel_module_css_default.uploadHint,
1988
+ children: tt("edit.uploadHint")
1989
+ })
1990
+ ]
1991
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1992
+ className: panel_module_css_default.reference,
1993
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1994
+ className: panel_module_css_default.referenceImage,
1995
+ src: refImage.dataUrl,
1996
+ alt: refImage.name
1997
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1998
+ className: panel_module_css_default.referenceActions,
1999
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2000
+ variant: "outline",
2001
+ size: "sm",
2002
+ onClick: () => {
2003
+ fileInput.current?.click();
2004
+ },
2005
+ children: tt("edit.change")
2006
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2007
+ variant: "outline",
2008
+ size: "sm",
2009
+ onClick: () => {
2010
+ setRefImage(null);
2011
+ },
2012
+ children: tt("edit.remove")
2013
+ })]
2014
+ })]
2015
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2016
+ ref: fileInput,
2017
+ type: "file",
2018
+ accept: "image/png,image/jpeg,image/webp,image/gif",
2019
+ className: panel_module_css_default.hiddenFile,
2020
+ onChange: (event) => {
2021
+ acceptFile(event.target.files?.[0]);
2022
+ event.target.value = "";
2023
+ }
2024
+ })]
2025
+ }) : null,
2026
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2027
+ className: panel_module_css_default.card,
2028
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
2029
+ className: panel_module_css_default.prompt,
2030
+ value: prompt,
2031
+ maxLength: PROMPT_MAX,
2032
+ placeholder: tt("prompt.placeholder"),
2033
+ onChange: (event) => {
2034
+ setPrompt(event.target.value);
2035
+ }
2036
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2037
+ className: panel_module_css_default.promptFooter,
2038
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2039
+ type: "button",
2040
+ className: panel_module_css_default.templatesButton,
2041
+ title: tt("templates.title"),
2042
+ onClick: () => {
2043
+ setLibraryOpen(true);
2044
+ },
2045
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
983
2046
  viewBox: "0 0 16 16",
984
- width: "18",
985
- height: "18",
2047
+ width: "12",
2048
+ height: "12",
986
2049
  fill: "none",
987
2050
  stroke: "currentColor",
988
- strokeWidth: "1.3",
2051
+ strokeWidth: "1.4",
989
2052
  strokeLinecap: "round",
990
2053
  strokeLinejoin: "round",
991
2054
  "aria-hidden": "true",
2055
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 3.5h11M2.5 8h11M2.5 12.5h7" })
2056
+ }), tt("templates.open")]
2057
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2058
+ className: panel_module_css_default.promptCount,
2059
+ children: tt("prompt.count", { count: prompt.length })
2060
+ })]
2061
+ })]
2062
+ }),
2063
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2064
+ className: panel_module_css_default.card,
2065
+ children: [
2066
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2067
+ className: panel_module_css_default.paramGroup,
2068
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2069
+ className: panel_module_css_default.paramLabel,
2070
+ children: tt("params.size")
2071
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2072
+ className: panel_module_css_default.optionGrid,
2073
+ children: SIZES.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
2074
+ active: size === option,
2075
+ onClick: () => {
2076
+ setSize(option);
2077
+ },
2078
+ className: panel_module_css_default.optionPill,
2079
+ children: tt(SIZE_KEYS[option] ?? "size.auto")
2080
+ }, option))
2081
+ })]
2082
+ }),
2083
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2084
+ className: panel_module_css_default.paramGroup,
2085
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2086
+ className: panel_module_css_default.paramLabel,
2087
+ children: tt("params.quality")
2088
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2089
+ className: panel_module_css_default.optionRow,
2090
+ children: QUALITIES.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
2091
+ active: quality === option,
2092
+ onClick: () => {
2093
+ setQuality(option);
2094
+ },
2095
+ className: panel_module_css_default.optionPill,
2096
+ children: tt(`quality.${option}`)
2097
+ }, option))
2098
+ })]
2099
+ }),
2100
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2101
+ className: panel_module_css_default.paramGroup,
2102
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2103
+ className: panel_module_css_default.paramLabel,
2104
+ children: tt("params.count")
2105
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2106
+ className: panel_module_css_default.optionRow,
992
2107
  children: [
993
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 10.5V3" }),
994
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M5 5.5l3-3 3 3" }),
995
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 9v3.5h11V9" })
996
- ]
997
- })
2108
+ 1,
2109
+ 2,
2110
+ 3,
2111
+ 4
2112
+ ].map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
2113
+ active: count === option,
2114
+ onClick: () => {
2115
+ setCount(option);
2116
+ },
2117
+ className: panel_module_css_default.optionPill,
2118
+ children: tt(`count.${option === 1 ? "one" : option === 2 ? "two" : option === 3 ? "three" : "four"}`)
2119
+ }, option))
2120
+ })]
998
2121
  }),
999
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("edit.upload") }),
1000
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1001
- className: panel_module_css_default.uploadHint,
1002
- children: tt("edit.uploadHint")
2122
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2123
+ className: panel_module_css_default.paramGroup,
2124
+ children: [
2125
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2126
+ className: panel_module_css_default.paramLabel,
2127
+ children: tt("params.detail")
2128
+ }),
2129
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2130
+ className: panel_module_css_default.optionRow,
2131
+ children: DETAILS.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
2132
+ active: detail === option,
2133
+ onClick: () => {
2134
+ setDetail(option);
2135
+ },
2136
+ className: panel_module_css_default.optionPill,
2137
+ children: tt(option === "" ? "detail.auto" : option === "standard" ? "detail.standard" : "detail.high")
2138
+ }, option === "" ? "auto" : option))
2139
+ }),
2140
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2141
+ className: panel_module_css_default.paramHint,
2142
+ children: tt("detail.hint")
2143
+ })
2144
+ ]
1003
2145
  })
1004
2146
  ]
1005
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1006
- className: panel_module_css_default.reference,
1007
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1008
- className: panel_module_css_default.referenceImage,
1009
- src: refImage.dataUrl,
1010
- alt: refImage.name
1011
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1012
- className: panel_module_css_default.referenceActions,
1013
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1014
- variant: "outline",
1015
- size: "sm",
1016
- onClick: () => {
1017
- fileInput.current?.click();
1018
- },
1019
- children: tt("edit.change")
1020
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1021
- variant: "outline",
1022
- size: "sm",
2147
+ })
2148
+ ]
2149
+ }),
2150
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2151
+ className: panel_module_css_default.footer,
2152
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2153
+ className: panel_module_css_default.modelWrap,
2154
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2155
+ className: panel_module_css_default.modelLabel,
2156
+ children: tt("model.label")
2157
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2158
+ ref: modelMenuRef,
2159
+ className: panel_module_css_default.modelMenu,
2160
+ "data-open": modelOpen ? "true" : "false",
2161
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2162
+ type: "button",
2163
+ className: panel_module_css_default.modelSelect,
2164
+ disabled: generating,
2165
+ "aria-haspopup": "listbox",
2166
+ "aria-expanded": modelOpen,
2167
+ onClick: () => {
2168
+ setModelOpen((open) => !open);
2169
+ },
2170
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2171
+ viewBox: "0 0 16 16",
2172
+ width: "12",
2173
+ height: "12",
2174
+ fill: "none",
2175
+ stroke: "currentColor",
2176
+ strokeWidth: "1.6",
2177
+ strokeLinecap: "round",
2178
+ strokeLinejoin: "round",
2179
+ "aria-hidden": "true",
2180
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 10.5L4 6h8z" })
2181
+ })]
2182
+ }), modelOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2183
+ className: panel_module_css_default.modelMenuList,
2184
+ role: "listbox",
2185
+ "aria-label": tt("model.label"),
2186
+ children: MODELS.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2187
+ type: "button",
2188
+ role: "option",
2189
+ "aria-selected": model === option,
2190
+ className: panel_module_css_default.modelMenuItem,
2191
+ "data-selected": model === option ? "" : void 0,
1023
2192
  onClick: () => {
1024
- setRefImage(null);
2193
+ setModel(option);
2194
+ setModelOpen(false);
1025
2195
  },
1026
- children: tt("edit.remove")
1027
- })]
1028
- })]
1029
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1030
- ref: fileInput,
1031
- type: "file",
1032
- accept: "image/png,image/jpeg,image/webp,image/gif",
1033
- className: panel_module_css_default.hiddenFile,
1034
- onChange: (event) => {
1035
- acceptFile(event.target.files?.[0]);
1036
- event.target.value = "";
1037
- }
1038
- })]
1039
- }) : null,
1040
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1041
- className: panel_module_css_default.card,
1042
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1043
- className: panel_module_css_default.prompt,
1044
- value: prompt,
1045
- maxLength: PROMPT_MAX,
1046
- placeholder: tt("prompt.placeholder"),
1047
- onChange: (event) => {
1048
- setPrompt(event.target.value);
1049
- }
1050
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1051
- className: panel_module_css_default.promptFooter,
1052
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1053
- className: panel_module_css_default.promptCount,
1054
- children: tt("prompt.count", { count: prompt.length })
1055
- })
2196
+ children: option
2197
+ }, option))
2198
+ }) : null]
1056
2199
  })]
1057
- }),
1058
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1059
- className: panel_module_css_default.card,
1060
- children: [
1061
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1062
- className: panel_module_css_default.paramGroup,
1063
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1064
- className: panel_module_css_default.paramLabel,
1065
- children: tt("params.size")
1066
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1067
- className: panel_module_css_default.optionGrid,
1068
- children: SIZES.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1069
- active: size === option,
2200
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2201
+ variant: "primary",
2202
+ size: "md",
2203
+ className: panel_module_css_default.generateButton,
2204
+ disabled: generateDisabled,
2205
+ onClick: () => {
2206
+ handleGenerate();
2207
+ },
2208
+ children: generating ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2209
+ className: panel_module_css_default.generateInner,
2210
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: panel_module_css_default.spinner }), tt("generating")]
2211
+ }) : tt("generate")
2212
+ })]
2213
+ })
2214
+ ]
2215
+ }),
2216
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2217
+ className: panel_module_css_default.canvas,
2218
+ "data-gallery": tab === "gallery" ? "true" : void 0,
2219
+ children: [
2220
+ tab === "gallery" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2221
+ className: panel_module_css_default.galleryWorkspace,
2222
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2223
+ className: panel_module_css_default.galleryToolbar,
2224
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2225
+ className: panel_module_css_default.galleryHeading,
2226
+ children: tt("gallery.all")
2227
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2228
+ className: panel_module_css_default.galleryCount,
2229
+ children: tt("gallery.count", { count: filteredGallery.length })
2230
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2231
+ className: panel_module_css_default.galleryToolbarActions,
2232
+ children: [
2233
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2234
+ className: panel_module_css_default.galleryViewToggle,
2235
+ role: "group",
2236
+ "aria-label": tt("gallery.viewMode"),
2237
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2238
+ type: "button",
2239
+ "data-active": galleryView === "masonry" ? "" : void 0,
1070
2240
  onClick: () => {
1071
- setSize(option);
2241
+ setGalleryView("masonry");
1072
2242
  },
1073
- className: panel_module_css_default.optionPill,
1074
- children: tt(SIZE_KEYS[option] ?? "size.auto")
1075
- }, option))
1076
- })]
1077
- }),
1078
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1079
- className: panel_module_css_default.paramGroup,
1080
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1081
- className: panel_module_css_default.paramLabel,
1082
- children: tt("params.quality")
1083
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1084
- className: panel_module_css_default.optionRow,
1085
- children: QUALITIES.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1086
- active: quality === option,
2243
+ title: tt("gallery.masonry"),
2244
+ children: [
2245
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2246
+ "aria-hidden": "true",
2247
+ children: "▦"
2248
+ }),
2249
+ " ",
2250
+ tt("gallery.masonry")
2251
+ ]
2252
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2253
+ type: "button",
2254
+ "data-active": galleryView === "grid" ? "" : void 0,
1087
2255
  onClick: () => {
1088
- setQuality(option);
2256
+ setGalleryView("grid");
1089
2257
  },
1090
- className: panel_module_css_default.optionPill,
1091
- children: tt(`quality.${option}`)
1092
- }, option))
1093
- })]
1094
- }),
1095
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1096
- className: panel_module_css_default.paramGroup,
1097
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1098
- className: panel_module_css_default.paramLabel,
1099
- children: tt("params.count")
1100
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1101
- className: panel_module_css_default.optionRow,
2258
+ title: tt("gallery.grid"),
2259
+ children: [
2260
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2261
+ "aria-hidden": "true",
2262
+ children: "▤"
2263
+ }),
2264
+ " ",
2265
+ tt("gallery.grid")
2266
+ ]
2267
+ })]
2268
+ }),
2269
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2270
+ className: panel_module_css_default.gallerySort,
2271
+ value: gallerySort,
2272
+ onChange: (event) => {
2273
+ setGallerySort(event.target.value);
2274
+ },
2275
+ "aria-label": tt("gallery.sort"),
2276
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2277
+ value: "newest",
2278
+ children: tt("gallery.newest")
2279
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2280
+ value: "oldest",
2281
+ children: tt("gallery.oldest")
2282
+ })]
2283
+ }),
2284
+ gallery.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2285
+ type: "button",
2286
+ className: panel_module_css_default.galleryClear,
2287
+ onClick: () => {
2288
+ clearGalleryAll();
2289
+ },
2290
+ children: tt("gallery.clear")
2291
+ }) : null
2292
+ ]
2293
+ })]
2294
+ }), filteredGallery.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2295
+ className: panel_module_css_default.historyEmpty,
2296
+ children: tt("gallery.empty")
2297
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2298
+ className: panel_module_css_default.galleryMasonry,
2299
+ "data-view": galleryView,
2300
+ children: filteredGallery.map((entry) => {
2301
+ const image = entry.images[0];
2302
+ if (image === void 0) return null;
2303
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
2304
+ className: panel_module_css_default.galleryCard,
2305
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2306
+ type: "button",
2307
+ className: panel_module_css_default.galleryImageButton,
2308
+ onClick: () => {
2309
+ viewGalleryEntry(entry);
2310
+ },
2311
+ title: tt("preview.open"),
2312
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
2313
+ className: panel_module_css_default.galleryImage,
2314
+ src: image.url,
2315
+ alt: entry.prompt
2316
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2317
+ className: panel_module_css_default.galleryBadge,
2318
+ children: entry.mode === "edit" ? tt("mode.edit") : tt("mode.text")
2319
+ })]
2320
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2321
+ className: panel_module_css_default.galleryCardFooter,
1102
2322
  children: [
1103
- 1,
1104
- 2,
1105
- 3,
1106
- 4
1107
- ].map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1108
- active: count === option,
1109
- onClick: () => {
1110
- setCount(option);
1111
- },
1112
- className: panel_module_css_default.optionPill,
1113
- children: tt(`count.${option === 1 ? "one" : option === 2 ? "two" : option === 3 ? "three" : "four"}`)
1114
- }, option))
1115
- })]
1116
- }),
1117
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1118
- className: panel_module_css_default.paramGroup,
1119
- children: [
1120
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1121
- className: panel_module_css_default.paramLabel,
1122
- children: tt("params.detail")
1123
- }),
1124
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1125
- className: panel_module_css_default.optionRow,
1126
- children: DETAILS.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1127
- active: detail === option,
2323
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2324
+ className: panel_module_css_default.galleryAvatar,
2325
+ children: entry.model.startsWith("grok") ? "G" : "D"
2326
+ }),
2327
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2328
+ className: panel_module_css_default.galleryCardInfo,
2329
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: entry.prompt || tt("gallery.untitled") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("small", { children: [
2330
+ entry.model,
2331
+ " · ",
2332
+ normalizeSize(entry.size),
2333
+ " · ",
2334
+ formatTime(entry.createdAt)
2335
+ ] })]
2336
+ }),
2337
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2338
+ type: "button",
2339
+ className: panel_module_css_default.galleryRemove,
1128
2340
  onClick: () => {
1129
- setDetail(option);
2341
+ deleteGalleryEntry(entry.id);
1130
2342
  },
1131
- className: panel_module_css_default.optionPill,
1132
- children: tt(option === "" ? "detail.auto" : option === "standard" ? "detail.standard" : "detail.high")
1133
- }, option === "" ? "auto" : option))
1134
- }),
1135
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1136
- className: panel_module_css_default.paramHint,
1137
- children: tt("detail.hint")
1138
- })
1139
- ]
1140
- })
1141
- ]
1142
- })
1143
- ]
1144
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1145
- className: panel_module_css_default.footer,
1146
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1147
- className: panel_module_css_default.modelWrap,
1148
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1149
- className: panel_module_css_default.modelLabel,
1150
- children: tt("model.label")
1151
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
1152
- className: panel_module_css_default.modelSelect,
1153
- value: model,
1154
- disabled: generating,
1155
- onChange: (event) => {
1156
- setModel(event.target.value);
1157
- },
1158
- children: MODELS.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1159
- value: option,
1160
- children: option
1161
- }, option))
2343
+ title: tt("gallery.delete"),
2344
+ children: "×"
2345
+ })
2346
+ ]
2347
+ })]
2348
+ }, entry.id);
2349
+ })
1162
2350
  })]
1163
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1164
- variant: "primary",
1165
- size: "md",
1166
- className: panel_module_css_default.generateButton,
1167
- disabled: generateDisabled,
1168
- onClick: () => {
1169
- handleGenerate();
1170
- },
1171
- children: generating ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1172
- className: panel_module_css_default.generateInner,
1173
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: panel_module_css_default.spinner }), tt("generating")]
1174
- }) : tt("generate")
1175
- })]
1176
- })]
1177
- }),
1178
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1179
- className: panel_module_css_default.canvas,
1180
- children: [
2351
+ }) : null,
1181
2352
  generating ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1182
2353
  className: panel_module_css_default.canvasState,
1183
2354
  role: "status",
@@ -1244,9 +2415,9 @@ window.__ModuleLoader__.load({
1244
2415
  className: panel_module_css_default.canvasBody,
1245
2416
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1246
2417
  className: panel_module_css_default.canvasMeta,
1247
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("canvas.images", { count: images.length }) }), viewingEntry !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2418
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("canvas.images", { count: images.length }) }), viewingEntry !== null || viewingGalleryEntry !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1248
2419
  className: panel_module_css_default.canvasHistoryTag,
1249
- children: tt("history.viewing", { time: formatTime(viewingEntry.createdAt) })
2420
+ children: viewingEntry !== null ? tt("history.viewing", { time: formatTime(viewingEntry.createdAt) }) : tt("gallery.viewing", { time: formatTime(viewingGalleryEntry.createdAt) })
1250
2421
  }) : null]
1251
2422
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1252
2423
  className: panel_module_css_default.grid,
@@ -1299,6 +2470,34 @@ window.__ModuleLoader__.load({
1299
2470
  ]
1300
2471
  }), tt("preview.open")]
1301
2472
  }),
2473
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2474
+ type: "button",
2475
+ className: panel_module_css_default.galleryAdd,
2476
+ title: tt("gallery.add"),
2477
+ disabled: galleryAdding,
2478
+ onClick: (event) => {
2479
+ event.stopPropagation();
2480
+ addToGallery(image);
2481
+ },
2482
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
2483
+ viewBox: "0 0 16 16",
2484
+ width: "12",
2485
+ height: "12",
2486
+ fill: "none",
2487
+ stroke: "currentColor",
2488
+ strokeWidth: "1.6",
2489
+ strokeLinecap: "round",
2490
+ strokeLinejoin: "round",
2491
+ "aria-hidden": "true",
2492
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
2493
+ x: "2.5",
2494
+ y: "3",
2495
+ width: "11",
2496
+ height: "10",
2497
+ rx: "1.5"
2498
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 5.8v4.4M5.8 8h4.4" })]
2499
+ }), tt("gallery.add")]
2500
+ }),
1302
2501
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1303
2502
  className: panel_module_css_default.download,
1304
2503
  href: srcOf(image),
@@ -1314,7 +2513,75 @@ window.__ModuleLoader__.load({
1314
2513
  }) : null
1315
2514
  ]
1316
2515
  }),
1317
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
2516
+ tab === "gallery" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
2517
+ className: panel_module_css_default.history,
2518
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2519
+ className: panel_module_css_default.historyHeader,
2520
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2521
+ className: panel_module_css_default.historyTitle,
2522
+ children: tt("gallery.title")
2523
+ }), gallery.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2524
+ type: "button",
2525
+ className: panel_module_css_default.historyClear,
2526
+ onClick: () => {
2527
+ clearGalleryAll();
2528
+ },
2529
+ children: tt("gallery.clear")
2530
+ }) : null]
2531
+ }), gallery.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2532
+ className: panel_module_css_default.historyEmpty,
2533
+ children: tt("gallery.empty")
2534
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2535
+ className: panel_module_css_default.historyList,
2536
+ children: gallery.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2537
+ className: panel_module_css_default.historyItem,
2538
+ "data-active": entry.id === galleryViewingId ? "" : void 0,
2539
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2540
+ type: "button",
2541
+ className: panel_module_css_default.historyMain,
2542
+ onClick: () => {
2543
+ viewGalleryEntry(entry);
2544
+ },
2545
+ children: [entry.images.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
2546
+ className: panel_module_css_default.historyThumb,
2547
+ src: entry.images[0].url,
2548
+ alt: ""
2549
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: panel_module_css_default.historyThumbPlaceholder }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2550
+ className: panel_module_css_default.historyInfo,
2551
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2552
+ className: panel_module_css_default.historyPrompt,
2553
+ children: entry.prompt
2554
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2555
+ className: panel_module_css_default.historyMeta,
2556
+ children: [
2557
+ tt(`mode.${entry.mode === "edit" ? "edit" : "text"}`),
2558
+ " · ",
2559
+ formatTime(entry.createdAt)
2560
+ ]
2561
+ })]
2562
+ })]
2563
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2564
+ className: panel_module_css_default.historyActions,
2565
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2566
+ type: "button",
2567
+ className: panel_module_css_default.historyAction,
2568
+ onClick: () => {
2569
+ restoreGalleryEntry(entry);
2570
+ },
2571
+ children: tt("history.restore")
2572
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2573
+ type: "button",
2574
+ className: panel_module_css_default.historyAction,
2575
+ "data-danger": true,
2576
+ onClick: () => {
2577
+ deleteGalleryEntry(entry.id);
2578
+ },
2579
+ children: tt("gallery.delete")
2580
+ })]
2581
+ })]
2582
+ }, entry.id))
2583
+ })]
2584
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
1318
2585
  className: panel_module_css_default.history,
1319
2586
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
1320
2587
  className: panel_module_css_default.historyHeader,
@@ -1367,28 +2634,53 @@ window.__ModuleLoader__.load({
1367
2634
  })]
1368
2635
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1369
2636
  className: panel_module_css_default.historyActions,
1370
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1371
- type: "button",
1372
- className: panel_module_css_default.historyAction,
1373
- onClick: () => {
1374
- restoreHistoryEntry(entry);
1375
- },
1376
- children: tt("history.restore")
1377
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1378
- type: "button",
1379
- className: panel_module_css_default.historyAction,
1380
- "data-danger": true,
1381
- onClick: () => {
1382
- deleteHistoryEntry(entry.id);
1383
- },
1384
- children: tt("history.delete")
1385
- })]
2637
+ children: [
2638
+ entry.images.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2639
+ type: "button",
2640
+ className: panel_module_css_default.historyAction,
2641
+ disabled: galleryAdding,
2642
+ title: tt("gallery.add"),
2643
+ onClick: () => {
2644
+ addHistoryEntryToGallery(entry);
2645
+ },
2646
+ children: tt("gallery.add")
2647
+ }) : null,
2648
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2649
+ type: "button",
2650
+ className: panel_module_css_default.historyAction,
2651
+ onClick: () => {
2652
+ restoreHistoryEntry(entry);
2653
+ },
2654
+ children: tt("history.restore")
2655
+ }),
2656
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2657
+ type: "button",
2658
+ className: panel_module_css_default.historyAction,
2659
+ "data-danger": true,
2660
+ onClick: () => {
2661
+ deleteHistoryEntry(entry.id);
2662
+ },
2663
+ children: tt("history.delete")
2664
+ })
2665
+ ]
1386
2666
  })]
1387
2667
  }, entry.id))
1388
2668
  })]
1389
2669
  })
1390
2670
  ]
1391
2671
  }),
2672
+ libraryOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TemplateLibrary, {
2673
+ api,
2674
+ onClose: () => {
2675
+ setLibraryOpen(false);
2676
+ },
2677
+ onUse: (text) => {
2678
+ setTab("text");
2679
+ setPrompt(text);
2680
+ setError(null);
2681
+ setLibraryOpen(false);
2682
+ }
2683
+ }) : null,
1392
2684
  preview !== null && previewImage !== null ? (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1393
2685
  className: panel_module_css_default.lightbox,
1394
2686
  role: "dialog",
@@ -1607,23 +2899,57 @@ window.__ModuleLoader__.load({
1607
2899
  })
1608
2900
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1609
2901
  className: panel_module_css_default.lightboxActions,
1610
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1611
- type: "button",
1612
- className: panel_module_css_default.lightboxEdit,
1613
- onClick: addPreviewToEdit,
1614
- children: tt("preview.addToEdit")
1615
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1616
- className: panel_module_css_default.lightboxDownload,
1617
- href: srcOf(previewImage),
1618
- download: `dsh-image-${preview.index + 1}.${extensionOf(previewImage.mime)}`,
1619
- children: tt("download")
1620
- })]
2902
+ children: [
2903
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2904
+ type: "button",
2905
+ className: panel_module_css_default.lightboxEdit,
2906
+ disabled: galleryAdding,
2907
+ onClick: () => {
2908
+ addToGallery(previewImage);
2909
+ },
2910
+ children: tt("gallery.add")
2911
+ }),
2912
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2913
+ type: "button",
2914
+ className: panel_module_css_default.lightboxEdit,
2915
+ onClick: addPreviewToEdit,
2916
+ children: tt("preview.addToEdit")
2917
+ }),
2918
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2919
+ className: panel_module_css_default.lightboxDownload,
2920
+ href: srcOf(previewImage),
2921
+ download: `dsh-image-${preview.index + 1}.${extensionOf(previewImage.mime)}`,
2922
+ children: tt("download")
2923
+ })
2924
+ ]
1621
2925
  })]
1622
2926
  })
1623
2927
  ]
1624
2928
  })
1625
2929
  ]
1626
- }), document.body) : null
2930
+ }), document.body) : null,
2931
+ galleryMessage !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2932
+ className: panel_module_css_default.galleryToast,
2933
+ role: "status",
2934
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
2935
+ viewBox: "0 0 16 16",
2936
+ width: "14",
2937
+ height: "14",
2938
+ fill: "none",
2939
+ stroke: "currentColor",
2940
+ strokeWidth: "1.6",
2941
+ strokeLinecap: "round",
2942
+ strokeLinejoin: "round",
2943
+ "aria-hidden": "true",
2944
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
2945
+ x: "2.5",
2946
+ y: "3",
2947
+ width: "11",
2948
+ height: "10",
2949
+ rx: "1.5"
2950
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 5.8v4.4M5.8 8h4.4" })]
2951
+ }), galleryMessage]
2952
+ }) : null
1627
2953
  ]
1628
2954
  });
1629
2955
  }
@@ -1643,13 +2969,18 @@ window.__ModuleLoader__.load({
1643
2969
  *
1644
2970
  * The `conversation` slot is single-occupant (ui-conversation) and external
1645
2971
  * plugins cannot declare slots, so the panel takes over the center column at
1646
- * the DOM level: a container is appended inside the `[data-pane="conversation"]`
1647
- * grid item (an extra trailing child React never manages), and a stylesheet
1648
- * rule hides the conversation content while the panel is active. Toggling is
1649
- * a data attribute on <html> — no React involvement, so the conversation
1650
- * subtree underneath stays mounted and stateful.
2972
+ * the DOM level: a container is appended inside the conversation grid item
2973
+ * (an extra trailing child React never manages), and a stylesheet rule hides
2974
+ * the conversation content while the panel is active. Toggling is a data
2975
+ * attribute on <html> — no React involvement, so the conversation subtree
2976
+ * underneath stays mounted and stateful.
2977
+ *
2978
+ * Shell compatibility: the center column is `[data-pane="conversation"]` on
2979
+ * legacy shells and `[class*="centerCol"]` on the rc.6+ AppFrame layout (the
2980
+ * same dual selector the dsh-ssh / task-board panels use); both are queried
2981
+ * and both get the `position: relative` base in panel.module.css.
1651
2982
  */
1652
- const CONVERSATION_COLUMN_SELECTOR = "[data-pane=\"conversation\"]";
2983
+ const CONVERSATION_COLUMN_SELECTOR = "[data-pane=\"conversation\"], [class*=\"centerCol\"]";
1653
2984
  const ACTIVE_ATTR = "data-dsh-imagegen-active";
1654
2985
  /** Sibling panels' activation attributes, removed when this panel opens. */
1655
2986
  const OTHER_ACTIVE_ATTRS = ["data-dsh-taskboard-active", "data-dsh-ssh-active"];
@@ -2100,34 +3431,34 @@ window.__ModuleLoader__.load({
2100
3431
  document.head.appendChild(tag);
2101
3432
  }
2102
3433
  var settings_card_module_css_default = {
2103
- "notExposed": "i1cc5G_notExposed",
2104
3434
  "chevron": "i1cc5G_chevron",
2105
- "label": "i1cc5G_label",
2106
- "headText": "i1cc5G_headText",
2107
- "select": "i1cc5G_select",
2108
- "inputInvalid": "i1cc5G_inputInvalid",
2109
- "invalid": "i1cc5G_invalid",
2110
- "description": "i1cc5G_description",
2111
- "footer": "i1cc5G_footer",
3435
+ "reset": "i1cc5G_reset",
3436
+ "failed": "i1cc5G_failed",
3437
+ "readOnly": "i1cc5G_readOnly",
3438
+ "head": "i1cc5G_head",
3439
+ "versionValue": "i1cc5G_versionValue",
3440
+ "hint": "i1cc5G_hint",
2112
3441
  "discard": "i1cc5G_discard",
3442
+ "notExposed": "i1cc5G_notExposed",
3443
+ "header": "i1cc5G_header",
2113
3444
  "save": "i1cc5G_save",
2114
- "name": "i1cc5G_name",
2115
- "hint": "i1cc5G_hint",
2116
- "versionValue": "i1cc5G_versionValue",
2117
- "readOnly": "i1cc5G_readOnly",
2118
- "badges": "i1cc5G_badges",
2119
- "reset": "i1cc5G_reset",
2120
- "badge": "i1cc5G_badge",
2121
3445
  "card": "i1cc5G_card",
3446
+ "pending": "i1cc5G_pending",
3447
+ "name": "i1cc5G_name",
2122
3448
  "input": "i1cc5G_input",
2123
- "head": "i1cc5G_head",
2124
3449
  "body": "i1cc5G_body",
2125
- "field": "i1cc5G_field",
2126
- "pending": "i1cc5G_pending",
2127
- "failed": "i1cc5G_failed",
3450
+ "headText": "i1cc5G_headText",
3451
+ "label": "i1cc5G_label",
3452
+ "badge": "i1cc5G_badge",
3453
+ "badges": "i1cc5G_badges",
3454
+ "inputInvalid": "i1cc5G_inputInvalid",
2128
3455
  "chevronOpen": "i1cc5G_chevronOpen",
2129
- "header": "i1cc5G_header",
3456
+ "footer": "i1cc5G_footer",
3457
+ "field": "i1cc5G_field",
3458
+ "select": "i1cc5G_select",
3459
+ "description": "i1cc5G_description",
2130
3460
  "versionRow": "i1cc5G_versionRow",
3461
+ "invalid": "i1cc5G_invalid",
2131
3462
  "versionLabel": "i1cc5G_versionLabel"
2132
3463
  };
2133
3464
  //#endregion