@dickpy/dsh-imagegen 1.0.9 → 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.9";
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",
@@ -39,6 +39,18 @@ window.__ModuleLoader__.load({
39
39
  image: "/api/dsh-imagegen/history/image"
40
40
  };
41
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
+ /**
42
54
  * Same-origin route family for the bundled prompt-template library
43
55
  * (awesome-gpt-image-2 mirror). The case list ships inside the package and is
44
56
  * served by the host; reference images are proxied through the `image` prefix
@@ -125,6 +137,35 @@ window.__ModuleLoader__.load({
125
137
  async historyClear() {
126
138
  return (await readEnvelope(await fetch(HISTORY_API.clear, { method: "POST" }))).entries;
127
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
+ }
128
169
  /** Fetch the prompt-template library (bundled snapshot or refreshed copy). */
129
170
  async templatesList() {
130
171
  const body = await readEnvelope(await fetch(TEMPLATES_API.list, { method: "POST" }));
@@ -185,9 +226,9 @@ window.__ModuleLoader__.load({
185
226
  */
186
227
  const zh = {
187
228
  "entry.label": "AI 生图",
188
- "entry.tooltip": "AI 生图面板(gpt-image-2)",
229
+ "entry.tooltip": "AI 生图面板(gpt-image-2 / grok-imagine-image)",
189
230
  "panel.title": "AI 生图",
190
- "panel.subtitle": "gpt-image-2 图像生成",
231
+ "panel.githubTip": "觉得好用或有建议?欢迎来 GitHub 提 issues、点个 star 支持一下!",
191
232
  "mode.text": "文生图",
192
233
  "mode.edit": "图生图",
193
234
  "prompt.placeholder": "描述你想要的画面,例如:一只戴着宇航员头盔的橘猫,在月球上举起望远镜,水彩风格,柔和光线…",
@@ -198,16 +239,18 @@ window.__ModuleLoader__.load({
198
239
  "params.count": "生成数量",
199
240
  "params.detail": "细节",
200
241
  "size.auto": "自动",
201
- "size.square": "1024×1024",
202
- "size.landscape": "1536×1024",
203
- "size.portrait": "1024×1536",
204
- "size.small": "512×512",
205
- "size.wide": "1792×1024",
206
- "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 超宽屏",
207
250
  "quality.auto": "自动",
208
- "quality.low": "",
209
- "quality.medium": "",
210
- "quality.high": "",
251
+ "quality.1k": "1K",
252
+ "quality.2k": "2K",
253
+ "quality.4k": "4K",
211
254
  "count.one": "1 张",
212
255
  "count.two": "2 张",
213
256
  "count.three": "3 张",
@@ -239,6 +282,28 @@ window.__ModuleLoader__.load({
239
282
  "history.delete": "删除",
240
283
  "history.images": "张",
241
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}",
242
307
  "preview.title": "图片预览",
243
308
  "preview.open": "点击预览",
244
309
  "preview.close": "关闭",
@@ -322,9 +387,9 @@ window.__ModuleLoader__.load({
322
387
  };
323
388
  const en = {
324
389
  "entry.label": "AI Image",
325
- "entry.tooltip": "AI image generation studio (gpt-image-2)",
390
+ "entry.tooltip": "AI image generation studio (gpt-image-2 / grok-imagine-image)",
326
391
  "panel.title": "AI Image",
327
- "panel.subtitle": "gpt-image-2 image generation",
392
+ "panel.githubTip": "Like it or have suggestions? Head to GitHub to open issues and star us!",
328
393
  "mode.text": "Text to Image",
329
394
  "mode.edit": "Image to Image",
330
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…",
@@ -335,16 +400,18 @@ window.__ModuleLoader__.load({
335
400
  "params.count": "Count",
336
401
  "params.detail": "Detail",
337
402
  "size.auto": "Auto",
338
- "size.square": "1024×1024",
339
- "size.landscape": "1536×1024",
340
- "size.portrait": "1024×1536",
341
- "size.small": "512×512",
342
- "size.wide": "1792×1024",
343
- "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",
344
411
  "quality.auto": "Auto",
345
- "quality.low": "Low",
346
- "quality.medium": "Medium",
347
- "quality.high": "High",
412
+ "quality.1k": "1K",
413
+ "quality.2k": "2K",
414
+ "quality.4k": "4K",
348
415
  "count.one": "1",
349
416
  "count.two": "2",
350
417
  "count.three": "3",
@@ -376,6 +443,28 @@ window.__ModuleLoader__.load({
376
443
  "history.delete": "Delete",
377
444
  "history.images": "images",
378
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}",
379
468
  "preview.title": "Image preview",
380
469
  "preview.open": "Click to preview",
381
470
  "preview.close": "Close",
@@ -494,46 +583,46 @@ window.__ModuleLoader__.load({
494
583
  }
495
584
  var templates_module_css_default = {
496
585
  "title": "o0mAxG_title",
497
- "meta": "o0mAxG_meta",
498
- "cardBody": "o0mAxG_cardBody",
499
- "thumb": "o0mAxG_thumb",
500
- "cardSource": "o0mAxG_cardSource",
501
- "card": "o0mAxG_card",
502
- "detailActions": "o0mAxG_detailActions",
503
- "dsh-imagegen-templates-spin": "o0mAxG_dsh-imagegen-templates-spin",
586
+ "cardCategory": "o0mAxG_cardCategory",
587
+ "cardTitle": "o0mAxG_cardTitle",
504
588
  "sourceLink": "o0mAxG_sourceLink",
505
- "detailOverlay": "o0mAxG_detailOverlay",
506
- "thumbPlaceholder": "o0mAxG_thumbPlaceholder",
507
- "close": "o0mAxG_close",
508
- "detailMedia": "o0mAxG_detailMedia",
509
- "state": "o0mAxG_state",
510
- "toolbar": "o0mAxG_toolbar",
589
+ "detailInfo": "o0mAxG_detailInfo",
590
+ "heading": "o0mAxG_heading",
511
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",
512
598
  "featuredBadge": "o0mAxG_featuredBadge",
513
- "cardCategory": "o0mAxG_cardCategory",
599
+ "footer": "o0mAxG_footer",
600
+ "meta": "o0mAxG_meta",
601
+ "dsh-imagegen-templates-spin": "o0mAxG_dsh-imagegen-templates-spin",
514
602
  "spinner": "o0mAxG_spinner",
515
- "thumbWrap": "o0mAxG_thumbWrap",
516
- "detailTitle": "o0mAxG_detailTitle",
603
+ "headerActions": "o0mAxG_headerActions",
517
604
  "overlay": "o0mAxG_overlay",
518
- "categoryRow": "o0mAxG_categoryRow",
519
- "categoryPill": "o0mAxG_categoryPill",
520
605
  "notice": "o0mAxG_notice",
521
- "body": "o0mAxG_body",
522
- "detail": "o0mAxG_detail",
523
- "header": "o0mAxG_header",
524
- "attribution": "o0mAxG_attribution",
525
- "detailInfo": "o0mAxG_detailInfo",
526
- "footer": "o0mAxG_footer",
527
- "shell": "o0mAxG_shell",
528
- "detailPrompt": "o0mAxG_detailPrompt",
529
- "headerActions": "o0mAxG_headerActions",
530
- "heading": "o0mAxG_heading",
531
- "cardTitle": "o0mAxG_cardTitle",
532
- "cardMeta": "o0mAxG_cardMeta",
606
+ "thumbWrap": "o0mAxG_thumbWrap",
607
+ "cardSource": "o0mAxG_cardSource",
608
+ "thumbPlaceholder": "o0mAxG_thumbPlaceholder",
533
609
  "detailImage": "o0mAxG_detailImage",
534
- "search": "o0mAxG_search",
610
+ "categoryRow": "o0mAxG_categoryRow",
611
+ "thumb": "o0mAxG_thumb",
612
+ "cardMeta": "o0mAxG_cardMeta",
613
+ "detailMedia": "o0mAxG_detailMedia",
535
614
  "grid": "o0mAxG_grid",
536
- "detailLink": "o0mAxG_detailLink"
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"
537
626
  };
538
627
  //#endregion
539
628
  //#region src/client/TemplateLibrary.tsx
@@ -1010,7 +1099,7 @@ window.__ModuleLoader__.load({
1010
1099
  }
1011
1100
  //#endregion
1012
1101
  //#region \0dsh-css:E:\dsh-plugin\src\client\panel.module.css.mjs
1013
- 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: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;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}}";
1014
1103
  const tagId$1 = "@dickpy/dsh-imagegen/panel.module.css";
1015
1104
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
1016
1105
  const tag = document.createElement("style");
@@ -1020,101 +1109,132 @@ window.__ModuleLoader__.load({
1020
1109
  document.head.appendChild(tag);
1021
1110
  }
1022
1111
  var panel_module_css_default = {
1023
- "updateRelease": "Yvqh9W_updateRelease",
1024
- "canvasHistoryTag": "Yvqh9W_canvasHistoryTag",
1025
- "lightboxCaptionRow": "Yvqh9W_lightboxCaptionRow",
1026
- "panelHeading": "Yvqh9W_panelHeading",
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",
1027
1119
  "generateButton": "Yvqh9W_generateButton",
1028
- "historyHeader": "Yvqh9W_historyHeader",
1120
+ "panelHeading": "Yvqh9W_panelHeading",
1121
+ "historyThumb": "Yvqh9W_historyThumb",
1122
+ "canvasHistoryTag": "Yvqh9W_canvasHistoryTag",
1123
+ "galleryViewToggle": "Yvqh9W_galleryViewToggle",
1124
+ "configScroll": "Yvqh9W_configScroll",
1125
+ "reference": "Yvqh9W_reference",
1126
+ "imageCaption": "Yvqh9W_imageCaption",
1127
+ "historyActions": "Yvqh9W_historyActions",
1128
+ "galleryImageButton": "Yvqh9W_galleryImageButton",
1129
+ "lightboxIndex": "Yvqh9W_lightboxIndex",
1130
+ "canvasBody": "Yvqh9W_canvasBody",
1131
+ "galleryAvatar": "Yvqh9W_galleryAvatar",
1132
+ "optionGrid": "Yvqh9W_optionGrid",
1029
1133
  "footer": "Yvqh9W_footer",
1134
+ "modelLabel": "Yvqh9W_modelLabel",
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",
1030
1142
  "imageCard": "Yvqh9W_imageCard",
1031
- "spinner": "Yvqh9W_spinner",
1032
- "reference": "Yvqh9W_reference",
1033
- "panelHeader": "Yvqh9W_panelHeader",
1034
- "canvasStateHint": "Yvqh9W_canvasStateHint",
1035
- "historyInfo": "Yvqh9W_historyInfo",
1036
- "lightboxEdit": "Yvqh9W_lightboxEdit",
1037
- "promptCount": "Yvqh9W_promptCount",
1038
- "historyTitle": "Yvqh9W_historyTitle",
1039
- "uploadHint": "Yvqh9W_uploadHint",
1040
- "promptFooter": "Yvqh9W_promptFooter",
1143
+ "updateText": "Yvqh9W_updateText",
1144
+ "canvasStateTitle": "Yvqh9W_canvasStateTitle",
1145
+ "modelMenu": "Yvqh9W_modelMenu",
1041
1146
  "prompt": "Yvqh9W_prompt",
1042
- "modelSelect": "Yvqh9W_modelSelect",
1043
- "lightboxImage": "Yvqh9W_lightboxImage",
1044
- "download": "Yvqh9W_download",
1045
- "view": "Yvqh9W_view",
1046
- "optionGrid": "Yvqh9W_optionGrid",
1047
- "grid": "Yvqh9W_grid",
1048
- "entryLabel": "Yvqh9W_entryLabel",
1147
+ "uploadIcon": "Yvqh9W_uploadIcon",
1049
1148
  "canvas": "Yvqh9W_canvas",
1149
+ "galleryImage": "Yvqh9W_galleryImage",
1150
+ "entry": "Yvqh9W_entry",
1151
+ "updateRelease": "Yvqh9W_updateRelease",
1152
+ "dshImageGenSpin": "Yvqh9W_dshImageGenSpin",
1153
+ "lightboxDownload": "Yvqh9W_lightboxDownload",
1154
+ "galleryCardFooter": "Yvqh9W_galleryCardFooter",
1155
+ "download": "Yvqh9W_download",
1156
+ "historyTitle": "Yvqh9W_historyTitle",
1157
+ "modelMenuList": "Yvqh9W_modelMenuList",
1158
+ "canvasMeta": "Yvqh9W_canvasMeta",
1159
+ "galleryFilters": "Yvqh9W_galleryFilters",
1160
+ "updateActions": "Yvqh9W_updateActions",
1161
+ "historyClear": "Yvqh9W_historyClear",
1162
+ "galleryToolbarActions": "Yvqh9W_galleryToolbarActions",
1163
+ "lightboxFigure": "Yvqh9W_lightboxFigure",
1164
+ "panel": "Yvqh9W_panel",
1165
+ "referenceImage": "Yvqh9W_referenceImage",
1166
+ "historyMain": "Yvqh9W_historyMain",
1167
+ "zoomHint": "Yvqh9W_zoomHint",
1168
+ "lightboxEdit": "Yvqh9W_lightboxEdit",
1169
+ "galleryToolbar": "Yvqh9W_galleryToolbar",
1170
+ "galleryCard": "Yvqh9W_galleryCard",
1050
1171
  "historyItem": "Yvqh9W_historyItem",
1051
- "uploadIcon": "Yvqh9W_uploadIcon",
1052
- "entryIcon": "Yvqh9W_entryIcon",
1053
- "hiddenFile": "Yvqh9W_hiddenFile",
1054
- "lightboxCopy": "Yvqh9W_lightboxCopy",
1055
- "connectionStatus": "Yvqh9W_connectionStatus",
1056
- "modeRow": "Yvqh9W_modeRow",
1172
+ "studio": "Yvqh9W_studio",
1173
+ "galleryFilterHeading": "Yvqh9W_galleryFilterHeading",
1174
+ "historyHeader": "Yvqh9W_historyHeader",
1175
+ "paramLabel": "Yvqh9W_paramLabel",
1176
+ "historyAction": "Yvqh9W_historyAction",
1177
+ "galleryCardInfo": "Yvqh9W_galleryCardInfo",
1178
+ "lightboxCaptionRow": "Yvqh9W_lightboxCaptionRow",
1179
+ "promptCount": "Yvqh9W_promptCount",
1180
+ "historyList": "Yvqh9W_historyList",
1057
1181
  "config": "Yvqh9W_config",
1058
- "referenceImage": "Yvqh9W_referenceImage",
1182
+ "galleryBadge": "Yvqh9W_galleryBadge",
1059
1183
  "modelWrap": "Yvqh9W_modelWrap",
1060
- "historyActions": "Yvqh9W_historyActions",
1061
- "history": "Yvqh9W_history",
1062
- "paramLabel": "Yvqh9W_paramLabel",
1063
- "modelLabel": "Yvqh9W_modelLabel",
1064
- "templatesButton": "Yvqh9W_templatesButton",
1065
- "generateInner": "Yvqh9W_generateInner",
1066
- "paramGroup": "Yvqh9W_paramGroup",
1067
1184
  "canvasState": "Yvqh9W_canvasState",
1068
- "lightboxScaleFrame": "Yvqh9W_lightboxScaleFrame",
1069
- "historyList": "Yvqh9W_historyList",
1070
- "lightboxActions": "Yvqh9W_lightboxActions",
1071
- "lightboxMeta": "Yvqh9W_lightboxMeta",
1072
- "historyThumbPlaceholder": "Yvqh9W_historyThumbPlaceholder",
1073
- "canvasStateTitle": "Yvqh9W_canvasStateTitle",
1074
- "imageCaption": "Yvqh9W_imageCaption",
1075
- "canvasError": "Yvqh9W_canvasError",
1076
- "historyMain": "Yvqh9W_historyMain",
1185
+ "historyInfo": "Yvqh9W_historyInfo",
1077
1186
  "image": "Yvqh9W_image",
1078
- "lightboxStage": "Yvqh9W_lightboxStage",
1079
- "historyThumb": "Yvqh9W_historyThumb",
1080
- "lightbox": "Yvqh9W_lightbox",
1081
- "lightboxFigure": "Yvqh9W_lightboxFigure",
1082
- "historyClear": "Yvqh9W_historyClear",
1083
- "historyEmpty": "Yvqh9W_historyEmpty",
1187
+ "lightboxImage": "Yvqh9W_lightboxImage",
1188
+ "lightboxClose": "Yvqh9W_lightboxClose",
1189
+ "promptFooter": "Yvqh9W_promptFooter",
1190
+ "galleryFilterNote": "Yvqh9W_galleryFilterNote",
1191
+ "galleryHeading": "Yvqh9W_galleryHeading",
1192
+ "history": "Yvqh9W_history",
1084
1193
  "historyPrompt": "Yvqh9W_historyPrompt",
1085
- "historyAction": "Yvqh9W_historyAction",
1086
- "referenceActions": "Yvqh9W_referenceActions",
1087
- "updateActions": "Yvqh9W_updateActions",
1088
- "optionPill": "Yvqh9W_optionPill",
1089
- "card": "Yvqh9W_card",
1090
- "lightboxNav": "Yvqh9W_lightboxNav",
1091
- "connectionDot": "Yvqh9W_connectionDot",
1092
- "uploadBox": "Yvqh9W_uploadBox",
1093
- "panelSubtitle": "Yvqh9W_panelSubtitle",
1094
- "paramHint": "Yvqh9W_paramHint",
1095
- "optionRow": "Yvqh9W_optionRow",
1096
1194
  "lightboxZoomLevel": "Yvqh9W_lightboxZoomLevel",
1097
- "panelTitle": "Yvqh9W_panelTitle",
1098
- "lightboxIndex": "Yvqh9W_lightboxIndex",
1099
- "canvasEmptyIcon": "Yvqh9W_canvasEmptyIcon",
1100
- "entry": "Yvqh9W_entry",
1195
+ "galleryCount": "Yvqh9W_galleryCount",
1196
+ "galleryFilterDivider": "Yvqh9W_galleryFilterDivider",
1101
1197
  "modePill": "Yvqh9W_modePill",
1102
- "lightboxTool": "Yvqh9W_lightboxTool",
1103
- "lightboxDownload": "Yvqh9W_lightboxDownload",
1104
- "updateText": "Yvqh9W_updateText",
1198
+ "grid": "Yvqh9W_grid",
1105
1199
  "updateBanner": "Yvqh9W_updateBanner",
1106
- "studio": "Yvqh9W_studio",
1107
- "dshImageGenSpin": "Yvqh9W_dshImageGenSpin",
1108
- "canvasMeta": "Yvqh9W_canvasMeta",
1109
- "lightboxClose": "Yvqh9W_lightboxClose",
1110
- "lightboxTools": "Yvqh9W_lightboxTools",
1111
- "configScroll": "Yvqh9W_configScroll",
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",
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",
1214
+ "lightbox": "Yvqh9W_lightbox",
1215
+ "lightboxStage": "Yvqh9W_lightboxStage",
1216
+ "lightboxMeta": "Yvqh9W_lightboxMeta",
1217
+ "entryIcon": "Yvqh9W_entryIcon",
1218
+ "hiddenFile": "Yvqh9W_hiddenFile",
1219
+ "galleryMasonry": "Yvqh9W_galleryMasonry",
1220
+ "connectionDot": "Yvqh9W_connectionDot",
1221
+ "lightboxNav": "Yvqh9W_lightboxNav",
1222
+ "galleryRemove": "Yvqh9W_galleryRemove",
1223
+ "gallerySort": "Yvqh9W_gallerySort",
1112
1224
  "historyMeta": "Yvqh9W_historyMeta",
1113
- "canvasBody": "Yvqh9W_canvasBody",
1114
- "zoomHint": "Yvqh9W_zoomHint",
1115
- "bigSpinner": "Yvqh9W_bigSpinner",
1225
+ "lightboxCopy": "Yvqh9W_lightboxCopy",
1226
+ "spinner": "Yvqh9W_spinner",
1116
1227
  "lightboxCaption": "Yvqh9W_lightboxCaption",
1117
- "panel": "Yvqh9W_panel"
1228
+ "galleryFilter": "Yvqh9W_galleryFilter",
1229
+ "view": "Yvqh9W_view",
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"
1118
1238
  };
1119
1239
  //#endregion
1120
1240
  //#region src/client/ImageGenPanel.tsx
@@ -1127,34 +1247,44 @@ window.__ModuleLoader__.load({
1127
1247
  * Controls ride the system UI primitives (@deepseek-ai/dsh-client-ui-primitives,
1128
1248
  * a platform module) so the studio matches the dsh shell look by construction.
1129
1249
  */
1130
- /** The model dropdown offers exactly the plugin's namesake model. */
1131
- const MODELS = ["gpt-image-2"];
1132
- /** 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. */
1133
1257
  const SIZES = [
1134
1258
  "auto",
1135
- "1024x1024",
1136
- "1536x1024",
1137
- "1024x1536",
1138
- "512x512",
1139
- "1792x1024",
1140
- "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"
1141
1267
  ];
1142
1268
  /** Size option keys in the locale dictionary. */
1143
1269
  const SIZE_KEYS = {
1144
1270
  auto: "size.auto",
1145
- "1024x1024": "size.square",
1146
- "1536x1024": "size.landscape",
1147
- "1024x1536": "size.portrait",
1148
- "512x512": "size.small",
1149
- "1792x1024": "size.wide",
1150
- "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"
1151
1279
  };
1152
- /** 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). */
1153
1283
  const QUALITIES = [
1154
1284
  "auto",
1155
- "low",
1156
- "medium",
1157
- "high"
1285
+ "1k",
1286
+ "2k",
1287
+ "4k"
1158
1288
  ];
1159
1289
  /** Detail options ('' = omit the passthrough). */
1160
1290
  const DETAILS = [
@@ -1167,6 +1297,32 @@ window.__ModuleLoader__.load({
1167
1297
  const PREVIEW_SCALE_MIN = .5;
1168
1298
  const PREVIEW_SCALE_MAX = 3;
1169
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
+ }
1170
1326
  function clampPreviewScale(scale) {
1171
1327
  return Math.min(PREVIEW_SCALE_MAX, Math.max(PREVIEW_SCALE_MIN, scale));
1172
1328
  }
@@ -1238,13 +1394,14 @@ window.__ModuleLoader__.load({
1238
1394
  const configured = (config?.apiUrl ?? "").trim() !== "";
1239
1395
  const keySet = useKeySet(scope);
1240
1396
  const connected = enabled && configured && keySet;
1241
- const [mode, setMode] = (0, react.useState)("text");
1397
+ const [tab, setTab] = (0, react.useState)("text");
1242
1398
  const [prompt, setPrompt] = (0, react.useState)("");
1243
1399
  const [size, setSize] = (0, react.useState)("auto");
1244
1400
  const [quality, setQuality] = (0, react.useState)("auto");
1245
1401
  const [count, setCount] = (0, react.useState)(1);
1246
1402
  const [detail, setDetail] = (0, react.useState)("");
1247
1403
  const [model, setModel] = (0, react.useState)(MODELS[0]);
1404
+ const [modelOpen, setModelOpen] = (0, react.useState)(false);
1248
1405
  const [refImage, setRefImage] = (0, react.useState)(null);
1249
1406
  const [images, setImages] = (0, react.useState)([]);
1250
1407
  const [error, setError] = (0, react.useState)(null);
@@ -1252,6 +1409,14 @@ window.__ModuleLoader__.load({
1252
1409
  const [startedAt, setStartedAt] = (0, react.useState)(null);
1253
1410
  const [history, setHistory] = (0, react.useState)([]);
1254
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");
1255
1420
  const [preview, setPreview] = (0, react.useState)(null);
1256
1421
  const [previewScale, setPreviewScale] = (0, react.useState)(1);
1257
1422
  const [promptCopied, setPromptCopied] = (0, react.useState)(false);
@@ -1263,15 +1428,38 @@ window.__ModuleLoader__.load({
1263
1428
  const fileInput = (0, react.useRef)(null);
1264
1429
  const previewStage = (0, react.useRef)(null);
1265
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);
1266
1436
  (0, react.useEffect)(() => {
1267
1437
  let disposed = false;
1268
1438
  api.historyList().then((entries) => {
1269
1439
  if (!disposed) setHistory(entries);
1270
1440
  }).catch(() => {});
1441
+ api.galleryList().then((entries) => {
1442
+ if (!disposed) setGallery(entries);
1443
+ }).catch(() => {});
1271
1444
  return () => {
1272
1445
  disposed = true;
1273
1446
  };
1274
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]);
1275
1463
  (0, react.useEffect)(() => {
1276
1464
  let disposed = false;
1277
1465
  api.updateCheck().then((info) => {
@@ -1328,20 +1516,20 @@ window.__ModuleLoader__.load({
1328
1516
  setError(tt("prompt.required"));
1329
1517
  return;
1330
1518
  }
1331
- if (mode === "edit" && refImage === null) {
1519
+ if (tab === "edit" && refImage === null) {
1332
1520
  setError(tt("edit.required"));
1333
1521
  return;
1334
1522
  }
1335
1523
  const request = {
1336
- mode,
1524
+ mode: tab === "gallery" ? "text" : tab,
1337
1525
  model,
1338
1526
  prompt: promptText,
1339
1527
  size,
1340
1528
  quality,
1341
1529
  n: count,
1342
1530
  detail,
1343
- ...mode === "edit" && refImage !== null ? { image: refImage.dataUrl } : {},
1344
- ...mode === "edit" && refImage !== null ? { refName: refImage.name } : {}
1531
+ ...tab === "edit" && refImage !== null ? { image: refImage.dataUrl } : {},
1532
+ ...tab === "edit" && refImage !== null ? { refName: refImage.name } : {}
1345
1533
  };
1346
1534
  setGenerating(true);
1347
1535
  setError(null);
@@ -1351,6 +1539,7 @@ window.__ModuleLoader__.load({
1351
1539
  const result = await api.generate(request);
1352
1540
  setImages(result.images);
1353
1541
  setViewingHistoryId(null);
1542
+ setGalleryViewingId(null);
1354
1543
  if (result.history !== void 0) setHistory(result.history);
1355
1544
  if (result.historyError !== void 0) setError(result.historyError);
1356
1545
  } catch (caught) {
@@ -1416,6 +1605,7 @@ window.__ModuleLoader__.load({
1416
1605
  setImages(await historyImagesToGenerated(entry.images));
1417
1606
  setError(null);
1418
1607
  setViewingHistoryId(entry.id);
1608
+ setGalleryViewingId(null);
1419
1609
  } catch (caught) {
1420
1610
  setError(errorMessage(caught));
1421
1611
  }
@@ -1424,10 +1614,10 @@ window.__ModuleLoader__.load({
1424
1614
  const restoreHistoryEntry = async (entry) => {
1425
1615
  try {
1426
1616
  const restored = await historyImagesToGenerated(entry.images);
1427
- setMode(entry.mode);
1617
+ setTab(entry.mode);
1428
1618
  setPrompt(entry.prompt);
1429
- setSize(SIZES.includes(entry.size) ? entry.size : "auto");
1430
- setQuality(QUALITIES.includes(entry.quality) ? entry.quality : "auto");
1619
+ setSize(normalizeSize(entry.size));
1620
+ setQuality(normalizeQuality(entry.quality));
1431
1621
  setDetail(DETAILS.includes(entry.detail) ? entry.detail : "");
1432
1622
  setCount(entry.n >= 1 && entry.n <= 4 ? entry.n : 1);
1433
1623
  setModel(MODELS.includes(entry.model) ? entry.model : MODELS[0]);
@@ -1435,6 +1625,7 @@ window.__ModuleLoader__.load({
1435
1625
  setImages(restored);
1436
1626
  setError(null);
1437
1627
  setViewingHistoryId(entry.id);
1628
+ setGalleryViewingId(null);
1438
1629
  } catch (caught) {
1439
1630
  setError(errorMessage(caught));
1440
1631
  }
@@ -1455,18 +1646,121 @@ window.__ModuleLoader__.load({
1455
1646
  setHistory(await api.historyClear());
1456
1647
  } catch {}
1457
1648
  };
1458
- const generateDisabled = generating || !enabled || !configured;
1459
- const viewingEntry = viewingHistoryId === null ? null : history.find((entry) => entry.id === viewingHistoryId) ?? null;
1460
- const previewImage = preview === null ? null : preview.images[preview.index] ?? null;
1461
- const previewFrameScale = Math.max(1, previewScale);
1462
- const previewImageScale = previewScale / previewFrameScale;
1463
- const copyPreviewPrompt = async (text) => {
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);
1464
1665
  try {
1465
- if (navigator.clipboard?.writeText !== void 0) await navigator.clipboard.writeText(text);
1466
- else {
1467
- const textarea = document.createElement("textarea");
1468
- textarea.value = text;
1469
- textarea.style.position = "fixed";
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
+ };
1751
+ const generateDisabled = generating || !enabled || !configured;
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;
1754
+ const previewImage = preview === null ? null : preview.images[preview.index] ?? null;
1755
+ const previewFrameScale = Math.max(1, previewScale);
1756
+ const previewImageScale = previewScale / previewFrameScale;
1757
+ const copyPreviewPrompt = async (text) => {
1758
+ try {
1759
+ if (navigator.clipboard?.writeText !== void 0) await navigator.clipboard.writeText(text);
1760
+ else {
1761
+ const textarea = document.createElement("textarea");
1762
+ textarea.value = text;
1763
+ textarea.style.position = "fixed";
1470
1764
  textarea.style.opacity = "0";
1471
1765
  document.body.appendChild(textarea);
1472
1766
  textarea.select();
@@ -1484,7 +1778,7 @@ window.__ModuleLoader__.load({
1484
1778
  };
1485
1779
  const addPreviewToEdit = () => {
1486
1780
  if (previewImage === null || preview === null) return;
1487
- setMode("edit");
1781
+ setTab("edit");
1488
1782
  setRefImage({
1489
1783
  dataUrl: srcOf(previewImage),
1490
1784
  name: `dsh-image-${preview.index + 1}.${extensionOf(previewImage.mime)}`
@@ -1503,9 +1797,21 @@ window.__ModuleLoader__.load({
1503
1797
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
1504
1798
  className: panel_module_css_default.panelTitle,
1505
1799
  children: tt("panel.title")
1506
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1507
- className: panel_module_css_default.panelSubtitle,
1508
- 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
+ })
1509
1815
  })]
1510
1816
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1511
1817
  type: "button",
@@ -1548,268 +1854,501 @@ window.__ModuleLoader__.load({
1548
1854
  children: [
1549
1855
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
1550
1856
  className: panel_module_css_default.config,
1551
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1552
- className: panel_module_css_default.configScroll,
1553
- children: [
1554
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
1555
- className: panel_module_css_default.card,
1556
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1557
- className: panel_module_css_default.modeRow,
1558
- role: "tablist",
1559
- "aria-label": tt("panel.title"),
1560
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1561
- active: mode === "text",
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", {
1873
+ type: "button",
1874
+ className: panel_module_css_default.galleryFilter,
1875
+ "data-active": galleryFilter === value ? "" : void 0,
1876
+ onClick: () => {
1877
+ setGalleryFilter(value);
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,
1891
+ children: [
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,
1562
1901
  onClick: () => {
1563
- setMode("text");
1902
+ setGalleryRatio(ratio);
1564
1903
  },
1565
- className: panel_module_css_default.modePill,
1566
- children: tt("mode.text")
1567
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1568
- active: mode === "edit",
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,
1569
1955
  onClick: () => {
1570
- setMode("edit");
1956
+ fileInput.current?.click();
1571
1957
  },
1572
- className: panel_module_css_default.modePill,
1573
- children: tt("mode.edit")
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
+ }
1574
2024
  })]
1575
- })
1576
- }),
1577
- mode === "edit" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1578
- className: panel_module_css_default.card,
1579
- children: [refImage === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1580
- type: "button",
1581
- className: panel_module_css_default.uploadBox,
1582
- onClick: () => {
1583
- fileInput.current?.click();
1584
- },
1585
- onDragOver: (event) => {
1586
- event.preventDefault();
1587
- },
1588
- onDrop: (event) => {
1589
- event.preventDefault();
1590
- acceptFile(event.dataTransfer.files?.[0]);
1591
- },
1592
- children: [
1593
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1594
- className: panel_module_css_default.uploadIcon,
1595
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
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", {
1596
2046
  viewBox: "0 0 16 16",
1597
- width: "18",
1598
- height: "18",
2047
+ width: "12",
2048
+ height: "12",
1599
2049
  fill: "none",
1600
2050
  stroke: "currentColor",
1601
- strokeWidth: "1.3",
2051
+ strokeWidth: "1.4",
1602
2052
  strokeLinecap: "round",
1603
2053
  strokeLinejoin: "round",
1604
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,
1605
2107
  children: [
1606
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 10.5V3" }),
1607
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M5 5.5l3-3 3 3" }),
1608
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 9v3.5h11V9" })
1609
- ]
1610
- })
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
+ })]
1611
2121
  }),
1612
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("edit.upload") }),
1613
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1614
- className: panel_module_css_default.uploadHint,
1615
- 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
+ ]
1616
2145
  })
1617
2146
  ]
1618
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1619
- className: panel_module_css_default.reference,
1620
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1621
- className: panel_module_css_default.referenceImage,
1622
- src: refImage.dataUrl,
1623
- alt: refImage.name
1624
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1625
- className: panel_module_css_default.referenceActions,
1626
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1627
- variant: "outline",
1628
- size: "sm",
1629
- onClick: () => {
1630
- fileInput.current?.click();
1631
- },
1632
- children: tt("edit.change")
1633
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1634
- variant: "outline",
1635
- size: "sm",
1636
- onClick: () => {
1637
- setRefImage(null);
1638
- },
1639
- children: tt("edit.remove")
1640
- })]
1641
- })]
1642
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1643
- ref: fileInput,
1644
- type: "file",
1645
- accept: "image/png,image/jpeg,image/webp,image/gif",
1646
- className: panel_module_css_default.hiddenFile,
1647
- onChange: (event) => {
1648
- acceptFile(event.target.files?.[0]);
1649
- event.target.value = "";
1650
- }
1651
- })]
1652
- }) : null,
1653
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1654
- className: panel_module_css_default.card,
1655
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1656
- className: panel_module_css_default.prompt,
1657
- value: prompt,
1658
- maxLength: PROMPT_MAX,
1659
- placeholder: tt("prompt.placeholder"),
1660
- onChange: (event) => {
1661
- setPrompt(event.target.value);
1662
- }
1663
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1664
- className: panel_module_css_default.promptFooter,
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",
1665
2161
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1666
2162
  type: "button",
1667
- className: panel_module_css_default.templatesButton,
1668
- title: tt("templates.title"),
2163
+ className: panel_module_css_default.modelSelect,
2164
+ disabled: generating,
2165
+ "aria-haspopup": "listbox",
2166
+ "aria-expanded": modelOpen,
1669
2167
  onClick: () => {
1670
- setLibraryOpen(true);
2168
+ setModelOpen((open) => !open);
1671
2169
  },
1672
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2170
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1673
2171
  viewBox: "0 0 16 16",
1674
2172
  width: "12",
1675
2173
  height: "12",
1676
2174
  fill: "none",
1677
2175
  stroke: "currentColor",
1678
- strokeWidth: "1.4",
2176
+ strokeWidth: "1.6",
1679
2177
  strokeLinecap: "round",
1680
2178
  strokeLinejoin: "round",
1681
2179
  "aria-hidden": "true",
1682
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 3.5h11M2.5 8h11M2.5 12.5h7" })
1683
- }), tt("templates.open")]
1684
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1685
- className: panel_module_css_default.promptCount,
1686
- children: tt("prompt.count", { count: prompt.length })
1687
- })]
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,
2192
+ onClick: () => {
2193
+ setModel(option);
2194
+ setModelOpen(false);
2195
+ },
2196
+ children: option
2197
+ }, option))
2198
+ }) : null]
1688
2199
  })]
1689
- }),
1690
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1691
- className: panel_module_css_default.card,
1692
- children: [
1693
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1694
- className: panel_module_css_default.paramGroup,
1695
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1696
- className: panel_module_css_default.paramLabel,
1697
- children: tt("params.size")
1698
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1699
- className: panel_module_css_default.optionGrid,
1700
- children: SIZES.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1701
- 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,
1702
2240
  onClick: () => {
1703
- setSize(option);
2241
+ setGalleryView("masonry");
1704
2242
  },
1705
- className: panel_module_css_default.optionPill,
1706
- children: tt(SIZE_KEYS[option] ?? "size.auto")
1707
- }, option))
1708
- })]
1709
- }),
1710
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1711
- className: panel_module_css_default.paramGroup,
1712
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1713
- className: panel_module_css_default.paramLabel,
1714
- children: tt("params.quality")
1715
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1716
- className: panel_module_css_default.optionRow,
1717
- children: QUALITIES.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1718
- 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,
1719
2255
  onClick: () => {
1720
- setQuality(option);
2256
+ setGalleryView("grid");
1721
2257
  },
1722
- className: panel_module_css_default.optionPill,
1723
- children: tt(`quality.${option}`)
1724
- }, option))
1725
- })]
1726
- }),
1727
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1728
- className: panel_module_css_default.paramGroup,
1729
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1730
- className: panel_module_css_default.paramLabel,
1731
- children: tt("params.count")
1732
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1733
- 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,
1734
2322
  children: [
1735
- 1,
1736
- 2,
1737
- 3,
1738
- 4
1739
- ].map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1740
- active: count === option,
1741
- onClick: () => {
1742
- setCount(option);
1743
- },
1744
- className: panel_module_css_default.optionPill,
1745
- children: tt(`count.${option === 1 ? "one" : option === 2 ? "two" : option === 3 ? "three" : "four"}`)
1746
- }, option))
1747
- })]
1748
- }),
1749
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1750
- className: panel_module_css_default.paramGroup,
1751
- children: [
1752
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1753
- className: panel_module_css_default.paramLabel,
1754
- children: tt("params.detail")
1755
- }),
1756
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1757
- className: panel_module_css_default.optionRow,
1758
- children: DETAILS.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Pill, {
1759
- 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,
1760
2340
  onClick: () => {
1761
- setDetail(option);
2341
+ deleteGalleryEntry(entry.id);
1762
2342
  },
1763
- className: panel_module_css_default.optionPill,
1764
- children: tt(option === "" ? "detail.auto" : option === "standard" ? "detail.standard" : "detail.high")
1765
- }, option === "" ? "auto" : option))
1766
- }),
1767
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1768
- className: panel_module_css_default.paramHint,
1769
- children: tt("detail.hint")
1770
- })
1771
- ]
1772
- })
1773
- ]
1774
- })
1775
- ]
1776
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1777
- className: panel_module_css_default.footer,
1778
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1779
- className: panel_module_css_default.modelWrap,
1780
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1781
- className: panel_module_css_default.modelLabel,
1782
- children: tt("model.label")
1783
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("select", {
1784
- className: panel_module_css_default.modelSelect,
1785
- value: model,
1786
- disabled: generating,
1787
- onChange: (event) => {
1788
- setModel(event.target.value);
1789
- },
1790
- children: MODELS.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1791
- value: option,
1792
- children: option
1793
- }, option))
2343
+ title: tt("gallery.delete"),
2344
+ children: "×"
2345
+ })
2346
+ ]
2347
+ })]
2348
+ }, entry.id);
2349
+ })
1794
2350
  })]
1795
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1796
- variant: "primary",
1797
- size: "md",
1798
- className: panel_module_css_default.generateButton,
1799
- disabled: generateDisabled,
1800
- onClick: () => {
1801
- handleGenerate();
1802
- },
1803
- children: generating ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1804
- className: panel_module_css_default.generateInner,
1805
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: panel_module_css_default.spinner }), tt("generating")]
1806
- }) : tt("generate")
1807
- })]
1808
- })]
1809
- }),
1810
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
1811
- className: panel_module_css_default.canvas,
1812
- children: [
2351
+ }) : null,
1813
2352
  generating ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1814
2353
  className: panel_module_css_default.canvasState,
1815
2354
  role: "status",
@@ -1876,9 +2415,9 @@ window.__ModuleLoader__.load({
1876
2415
  className: panel_module_css_default.canvasBody,
1877
2416
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1878
2417
  className: panel_module_css_default.canvasMeta,
1879
- 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", {
1880
2419
  className: panel_module_css_default.canvasHistoryTag,
1881
- 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) })
1882
2421
  }) : null]
1883
2422
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1884
2423
  className: panel_module_css_default.grid,
@@ -1931,6 +2470,34 @@ window.__ModuleLoader__.load({
1931
2470
  ]
1932
2471
  }), tt("preview.open")]
1933
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
+ }),
1934
2501
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
1935
2502
  className: panel_module_css_default.download,
1936
2503
  href: srcOf(image),
@@ -1946,7 +2513,75 @@ window.__ModuleLoader__.load({
1946
2513
  }) : null
1947
2514
  ]
1948
2515
  }),
1949
- /* @__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", {
1950
2585
  className: panel_module_css_default.history,
1951
2586
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
1952
2587
  className: panel_module_css_default.historyHeader,
@@ -1999,22 +2634,35 @@ window.__ModuleLoader__.load({
1999
2634
  })]
2000
2635
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2001
2636
  className: panel_module_css_default.historyActions,
2002
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2003
- type: "button",
2004
- className: panel_module_css_default.historyAction,
2005
- onClick: () => {
2006
- restoreHistoryEntry(entry);
2007
- },
2008
- children: tt("history.restore")
2009
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2010
- type: "button",
2011
- className: panel_module_css_default.historyAction,
2012
- "data-danger": true,
2013
- onClick: () => {
2014
- deleteHistoryEntry(entry.id);
2015
- },
2016
- children: tt("history.delete")
2017
- })]
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
+ ]
2018
2666
  })]
2019
2667
  }, entry.id))
2020
2668
  })]
@@ -2027,7 +2675,7 @@ window.__ModuleLoader__.load({
2027
2675
  setLibraryOpen(false);
2028
2676
  },
2029
2677
  onUse: (text) => {
2030
- setMode("text");
2678
+ setTab("text");
2031
2679
  setPrompt(text);
2032
2680
  setError(null);
2033
2681
  setLibraryOpen(false);
@@ -2251,23 +2899,57 @@ window.__ModuleLoader__.load({
2251
2899
  })
2252
2900
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2253
2901
  className: panel_module_css_default.lightboxActions,
2254
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2255
- type: "button",
2256
- className: panel_module_css_default.lightboxEdit,
2257
- onClick: addPreviewToEdit,
2258
- children: tt("preview.addToEdit")
2259
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
2260
- className: panel_module_css_default.lightboxDownload,
2261
- href: srcOf(previewImage),
2262
- download: `dsh-image-${preview.index + 1}.${extensionOf(previewImage.mime)}`,
2263
- children: tt("download")
2264
- })]
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
+ ]
2265
2925
  })]
2266
2926
  })
2267
2927
  ]
2268
2928
  })
2269
2929
  ]
2270
- }), 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
2271
2953
  ]
2272
2954
  });
2273
2955
  }
@@ -2287,13 +2969,18 @@ window.__ModuleLoader__.load({
2287
2969
  *
2288
2970
  * The `conversation` slot is single-occupant (ui-conversation) and external
2289
2971
  * plugins cannot declare slots, so the panel takes over the center column at
2290
- * the DOM level: a container is appended inside the `[data-pane="conversation"]`
2291
- * grid item (an extra trailing child React never manages), and a stylesheet
2292
- * rule hides the conversation content while the panel is active. Toggling is
2293
- * a data attribute on <html> — no React involvement, so the conversation
2294
- * 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.
2295
2982
  */
2296
- const CONVERSATION_COLUMN_SELECTOR = "[data-pane=\"conversation\"]";
2983
+ const CONVERSATION_COLUMN_SELECTOR = "[data-pane=\"conversation\"], [class*=\"centerCol\"]";
2297
2984
  const ACTIVE_ATTR = "data-dsh-imagegen-active";
2298
2985
  /** Sibling panels' activation attributes, removed when this panel opens. */
2299
2986
  const OTHER_ACTIVE_ATTRS = ["data-dsh-taskboard-active", "data-dsh-ssh-active"];
@@ -2744,35 +3431,35 @@ window.__ModuleLoader__.load({
2744
3431
  document.head.appendChild(tag);
2745
3432
  }
2746
3433
  var settings_card_module_css_default = {
2747
- "pending": "i1cc5G_pending",
2748
- "save": "i1cc5G_save",
2749
- "card": "i1cc5G_card",
2750
- "inputInvalid": "i1cc5G_inputInvalid",
2751
- "versionValue": "i1cc5G_versionValue",
2752
- "description": "i1cc5G_description",
2753
- "versionRow": "i1cc5G_versionRow",
2754
- "head": "i1cc5G_head",
2755
- "header": "i1cc5G_header",
2756
- "name": "i1cc5G_name",
2757
- "failed": "i1cc5G_failed",
2758
- "notExposed": "i1cc5G_notExposed",
2759
3434
  "chevron": "i1cc5G_chevron",
2760
- "field": "i1cc5G_field",
3435
+ "reset": "i1cc5G_reset",
3436
+ "failed": "i1cc5G_failed",
3437
+ "readOnly": "i1cc5G_readOnly",
3438
+ "head": "i1cc5G_head",
3439
+ "versionValue": "i1cc5G_versionValue",
2761
3440
  "hint": "i1cc5G_hint",
2762
3441
  "discard": "i1cc5G_discard",
2763
- "badges": "i1cc5G_badges",
2764
- "select": "i1cc5G_select",
2765
- "readOnly": "i1cc5G_readOnly",
2766
- "footer": "i1cc5G_footer",
2767
- "chevronOpen": "i1cc5G_chevronOpen",
2768
- "invalid": "i1cc5G_invalid",
2769
- "body": "i1cc5G_body",
2770
- "versionLabel": "i1cc5G_versionLabel",
3442
+ "notExposed": "i1cc5G_notExposed",
3443
+ "header": "i1cc5G_header",
3444
+ "save": "i1cc5G_save",
3445
+ "card": "i1cc5G_card",
3446
+ "pending": "i1cc5G_pending",
3447
+ "name": "i1cc5G_name",
2771
3448
  "input": "i1cc5G_input",
2772
- "label": "i1cc5G_label",
3449
+ "body": "i1cc5G_body",
2773
3450
  "headText": "i1cc5G_headText",
3451
+ "label": "i1cc5G_label",
2774
3452
  "badge": "i1cc5G_badge",
2775
- "reset": "i1cc5G_reset"
3453
+ "badges": "i1cc5G_badges",
3454
+ "inputInvalid": "i1cc5G_inputInvalid",
3455
+ "chevronOpen": "i1cc5G_chevronOpen",
3456
+ "footer": "i1cc5G_footer",
3457
+ "field": "i1cc5G_field",
3458
+ "select": "i1cc5G_select",
3459
+ "description": "i1cc5G_description",
3460
+ "versionRow": "i1cc5G_versionRow",
3461
+ "invalid": "i1cc5G_invalid",
3462
+ "versionLabel": "i1cc5G_versionLabel"
2776
3463
  };
2777
3464
  //#endregion
2778
3465
  //#region src/client/SettingsCard.tsx