@dickpy/dsh-imagegen 1.0.20 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -11,8 +11,6 @@ window.__ModuleLoader__.load({
11
11
  let react_jsx_runtime = require("react/jsx-runtime");
12
12
  let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
13
13
  //#region src/protocol.ts
14
- /** Published package version shared by the host updater and the client UI. */
15
- const PLUGIN_VERSION = "1.0.20";
16
14
  /** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
17
15
  const SETTINGS_API = {
18
16
  describe: "/api/dsh-imagegen/settings/describe",
@@ -20,6 +18,20 @@ window.__ModuleLoader__.load({
20
18
  };
21
19
  /** The image-generation proxy route. */
22
20
  const GENERATE_API = "/api/dsh-imagegen/generate";
21
+ /** Host-mediated OpenAI-compatible prompt enhancement endpoints. */
22
+ const PROMPT_ENHANCE_API = {
23
+ models: "/api/dsh-imagegen/prompt-enhance/models",
24
+ enhance: "/api/dsh-imagegen/prompt-enhance"
25
+ };
26
+ /** Host-mediated candidate discovery for the configured image API. */
27
+ const IMAGE_MODEL_API = { models: "/api/dsh-imagegen/image-models" };
28
+ /** Host-resident generation queue endpoints. */
29
+ const TASK_API = {
30
+ submit: "/api/dsh-imagegen/tasks/submit",
31
+ list: "/api/dsh-imagegen/tasks/list",
32
+ cancel: "/api/dsh-imagegen/tasks/cancel",
33
+ retry: "/api/dsh-imagegen/tasks/retry"
34
+ };
23
35
  /** Host-mediated GitHub Release update routes. */
24
36
  const UPDATE_API = {
25
37
  check: "/api/dsh-imagegen/update/check",
@@ -48,6 +60,7 @@ window.__ModuleLoader__.load({
48
60
  append: "/api/dsh-imagegen/gallery/append",
49
61
  remove: "/api/dsh-imagegen/gallery/remove",
50
62
  clear: "/api/dsh-imagegen/gallery/clear",
63
+ tags: "/api/dsh-imagegen/gallery/tags",
51
64
  image: "/api/dsh-imagegen/gallery/image"
52
65
  };
53
66
  /**
@@ -121,6 +134,38 @@ window.__ModuleLoader__.load({
121
134
  ...body.historyError === void 0 ? {} : { historyError: body.historyError }
122
135
  };
123
136
  }
137
+ /** Ask the configured chat model to expand a concise image prompt. */
138
+ async enhancePrompt(prompt) {
139
+ return (await readEnvelope(await fetch(PROMPT_ENHANCE_API.enhance, {
140
+ method: "POST",
141
+ headers: { "content-type": "application/json" },
142
+ body: JSON.stringify({ prompt })
143
+ }))).prompt;
144
+ }
145
+ async taskSubmit(request) {
146
+ return (await readEnvelope(await fetch(TASK_API.submit, {
147
+ method: "POST",
148
+ headers: { "content-type": "application/json" },
149
+ body: JSON.stringify(request)
150
+ }))).task;
151
+ }
152
+ async taskList() {
153
+ return (await readEnvelope(await fetch(TASK_API.list, { method: "POST" }))).tasks;
154
+ }
155
+ async taskCancel(id) {
156
+ return (await readEnvelope(await fetch(TASK_API.cancel, {
157
+ method: "POST",
158
+ headers: { "content-type": "application/json" },
159
+ body: JSON.stringify({ id })
160
+ }))).task;
161
+ }
162
+ async taskRetry(id) {
163
+ return (await readEnvelope(await fetch(TASK_API.retry, {
164
+ method: "POST",
165
+ headers: { "content-type": "application/json" },
166
+ body: JSON.stringify({ id })
167
+ }))).task;
168
+ }
124
169
  /** List the host-persisted history (newest first). */
125
170
  async historyList() {
126
171
  return (await readEnvelope(await fetch(HISTORY_API.list, { method: "POST" }))).entries;
@@ -166,6 +211,16 @@ window.__ModuleLoader__.load({
166
211
  async galleryClear() {
167
212
  return (await readEnvelope(await fetch(GALLERY_API.clear, { method: "POST" }))).entries;
168
213
  }
214
+ async gallerySetTags(id, tags) {
215
+ return (await readEnvelope(await fetch(GALLERY_API.tags, {
216
+ method: "POST",
217
+ headers: { "content-type": "application/json" },
218
+ body: JSON.stringify({
219
+ id,
220
+ tags
221
+ })
222
+ }))).entries;
223
+ }
169
224
  /** Fetch the prompt-template library (bundled snapshot or refreshed copy). */
170
225
  async templatesList() {
171
226
  const body = await readEnvelope(await fetch(TEMPLATES_API.list, { method: "POST" }));
@@ -233,7 +288,20 @@ window.__ModuleLoader__.load({
233
288
  "mode.edit": "图生图",
234
289
  "prompt.placeholder": "描述你想要的画面,例如:一只戴着宇航员头盔的橘猫,在月球上举起望远镜,水彩风格,柔和光线…",
235
290
  "prompt.required": "请输入提示词",
236
- "prompt.count": "{count}/2000",
291
+ "prompt.count": "{count}",
292
+ "prompt.enhance": "增强",
293
+ "prompt.enhancing": "增强中…",
294
+ "prompt.enhanceHint": "使用已配置的对话模型扩写提示词",
295
+ "prompt.configTitle": "请先配置提示词增强模型",
296
+ "prompt.configHint": "已打开设置。进入「插件 → AI 生图」,填写或复用 API 地址和密钥,选择对话模型并保存。",
297
+ "tasks.title": "生成任务",
298
+ "tasks.queued": "排队中",
299
+ "tasks.running": "生成中",
300
+ "tasks.completed": "已完成",
301
+ "tasks.failed": "失败",
302
+ "tasks.cancelled": "已取消",
303
+ "tasks.cancel": "取消",
304
+ "tasks.retry": "重试",
237
305
  "params.size": "尺寸",
238
306
  "params.quality": "清晰度",
239
307
  "params.count": "生成数量",
@@ -260,6 +328,11 @@ window.__ModuleLoader__.load({
260
328
  "detail.high": "高清",
261
329
  "detail.hint": "透传参数,部分 gpt-image-2 网关支持;官方接口请保持「自动」",
262
330
  "model.label": "模型",
331
+ "compare.enable": "多模型对比",
332
+ "compare.models": "参与对比的模型",
333
+ "compare.title": "多模型结果对比",
334
+ "compare.fullscreen": "全屏对比",
335
+ "compare.selectRequired": "请至少选择一个对比模型",
263
336
  "generate": "开始生成",
264
337
  "generating": "生成中…",
265
338
  "edit.upload": "点击或拖拽上传参考图片",
@@ -282,12 +355,18 @@ window.__ModuleLoader__.load({
282
355
  "history.delete": "删除",
283
356
  "history.images": "张",
284
357
  "history.viewing": "历史 · {time}",
358
+ "history.search": "搜索提示词或模型…",
359
+ "history.model": "模型筛选",
360
+ "history.ratio": "比例筛选",
361
+ "history.allModels": "全部模型",
362
+ "history.allRatios": "全部比例",
285
363
  "gallery.title": "画廊",
286
364
  "gallery.categories": "分类",
287
365
  "gallery.all": "全部作品",
288
366
  "gallery.gpt": "gpt-image-2",
289
367
  "gallery.grok": "grok-imagine-image",
290
368
  "gallery.ratio": "画面比例",
369
+ "gallery.tags": "标签",
291
370
  "gallery.filterHint": "按生成模式、模型和比例筛选画廊",
292
371
  "gallery.count": "· 共 {count} 幅",
293
372
  "gallery.viewMode": "视图模式",
@@ -297,6 +376,19 @@ window.__ModuleLoader__.load({
297
376
  "gallery.newest": "最新发布",
298
377
  "gallery.oldest": "最早发布",
299
378
  "gallery.untitled": "未命名作品",
379
+ "gallery.search": "搜索作品或模型…",
380
+ "gallery.tagsPlaceholder": "标签,用逗号分隔",
381
+ "gallery.tagsApply": "添加标签",
382
+ "gallery.editTags": "编辑标签",
383
+ "gallery.tagsEditShort": "编辑",
384
+ "gallery.tagsSave": "保存",
385
+ "gallery.tagsCancel": "取消",
386
+ "gallery.selected": "已选 {count} 项",
387
+ "gallery.selectionDone": "完成选择",
388
+ "gallery.selectionClear": "取消选择",
389
+ "gallery.downloadSelected": "下载所选",
390
+ "gallery.exportJson": "导出 JSON",
391
+ "gallery.select": "选择作品",
300
392
  "gallery.add": "加入画廊",
301
393
  "gallery.added": "已加入画廊",
302
394
  "gallery.already": "已在画廊中",
@@ -319,6 +411,12 @@ window.__ModuleLoader__.load({
319
411
  "preview.copied": "已复制",
320
412
  "preview.addToEdit": "添加到图生图",
321
413
  "config.missing": "尚未配置 API:请前往「设置 → 插件 → 可配置」为 AI 生图填写 api_url 与 api_key。",
414
+ "config.generationTitle": "请先配置生图 API",
415
+ "config.generationHint": "已自动打开 DSH「设置 → 插件 → AI 生图」。填写生图 API 地址与 API 密钥,保存后即可开始生成。",
416
+ "config.enhancementTitle": "请先配置提示词增强模型",
417
+ "config.enhancementHint": "已自动打开 DSH「设置 → 插件 → AI 生图」。填写或复用对话 API 地址和密钥,选择对话模型并保存。",
418
+ "config.disabledTitle": "AI 生图插件已停用",
419
+ "config.disabledHint": "已自动打开 DSH「设置 → 插件 → AI 生图」。开启「启用插件」后即可生成图片。",
322
420
  "config.configured": "已连接 {url}",
323
421
  "config.disabled": "插件已停用,请在设置中重新启用。",
324
422
  "connection.connected": "已连接",
@@ -338,8 +436,39 @@ window.__ModuleLoader__.load({
338
436
  "settings.apiKeyHint": "Bearer 密钥,明文存于本机设置文档;界面只显示是否已设置",
339
437
  "settings.apiKeySet": "已保存密钥;输入新值可更换,点击「清除」可删除",
340
438
  "settings.apiKeyClear": "清除",
439
+ "settings.imageModelsTitle": "生图模型",
440
+ "settings.imageModelsHint": "保存 API 地址和密钥后检测候选模型;请只选择实际支持生图的项。",
441
+ "settings.imageModels": "允许使用的生图模型",
442
+ "settings.imageModelsManualHint": "一行一个模型;API 未提供 /models 时可手动填写。面板和 Agent 只能使用此列表。",
443
+ "settings.imageModelsFetch": "检测可用模型",
444
+ "settings.imageModelsLoading": "检测中…",
445
+ "settings.imageModelsCandidates": "检测到的候选模型(勾选后保存)",
446
+ "settings.addModel": "+ 手动添加",
447
+ "settings.cancelAddModel": "收起添加",
448
+ "settings.addModelPlaceholder": "输入模型名称,例如 qwen-image",
449
+ "settings.addModelConfirm": "添加",
450
+ "settings.removeModel": "移除模型",
451
+ "settings.optional": "可选",
452
+ "settings.moreOptions": "更多设置",
453
+ "settings.promptEnhanceTitle": "提示词增强模型",
454
+ "settings.promptEnhanceHint": "用于将简短描述扩写为更完整的生图提示词;留空的地址和密钥会复用生图配置。",
455
+ "settings.promptApiUrl": "对话 API 地址(可选)",
456
+ "settings.promptApiUrlHint": "OpenAI 兼容基址;留空则复用图像 API 地址。",
457
+ "settings.promptApiKey": "对话 API 密钥(可选)",
458
+ "settings.promptApiKeyHint": "留空则复用图像 API 密钥。",
459
+ "settings.promptModel": "对话模型",
460
+ "settings.promptModelHint": "选择或填写支持 /chat/completions 的模型。",
461
+ "settings.promptModelDetectionHint": "默认复用生图 API;检测后点选一个模型即可。",
462
+ "settings.promptModelsFetch": "获取可用模型",
463
+ "settings.promptModelsLoading": "正在获取…",
464
+ "settings.promptModelsSelect": "选择一个模型",
465
+ "settings.promptModelsCandidates": "检测到的候选对话模型",
466
+ "settings.addPromptModelPlaceholder": "输入对话模型名称,例如 gpt-4.1-mini",
467
+ "settings.promptApiAdvanced": "使用独立对话 API(可选)",
341
468
  "settings.announceToAgent": "向 Agent 播报本插件",
342
469
  "settings.announceToAgentHint": "开启后,本插件的存在与能力会写入每个 Agent 的系统提示词",
470
+ "settings.allowAgentImageGeneration": "允许 Agent 调用生图",
471
+ "settings.allowAgentImageGenerationHint": "默认开启。关闭后,Agent 无法提交、查询或取消生图任务;侧边栏工作台不受影响。",
343
472
  "settings.enabled": "启用插件",
344
473
  "settings.enabledHint": "关闭后生图面板不可用(设置卡片始终可用)",
345
474
  "settings.save": "保存",
@@ -394,7 +523,20 @@ window.__ModuleLoader__.load({
394
523
  "mode.edit": "Image to Image",
395
524
  "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…",
396
525
  "prompt.required": "Enter a prompt first",
397
- "prompt.count": "{count}/2000",
526
+ "prompt.count": "{count}",
527
+ "prompt.enhance": "Enhance",
528
+ "prompt.enhancing": "Enhancing…",
529
+ "prompt.enhanceHint": "Expand the prompt with the configured chat model",
530
+ "prompt.configTitle": "Configure a prompt enhancement model first",
531
+ "prompt.configHint": "Settings has opened. Go to Plugins → AI Image, configure or reuse an API URL and key, choose a chat model, then save.",
532
+ "tasks.title": "Generation tasks",
533
+ "tasks.queued": "Queued",
534
+ "tasks.running": "Generating",
535
+ "tasks.completed": "Completed",
536
+ "tasks.failed": "Failed",
537
+ "tasks.cancelled": "Cancelled",
538
+ "tasks.cancel": "Cancel",
539
+ "tasks.retry": "Retry",
398
540
  "params.size": "Size",
399
541
  "params.quality": "Quality",
400
542
  "params.count": "Count",
@@ -421,6 +563,11 @@ window.__ModuleLoader__.load({
421
563
  "detail.high": "High",
422
564
  "detail.hint": "Passthrough parameter supported by some gpt-image-2 gateways; keep \"Auto\" for official endpoints",
423
565
  "model.label": "Model",
566
+ "compare.enable": "Multi-model comparison",
567
+ "compare.models": "Models to compare",
568
+ "compare.title": "Multi-model comparison",
569
+ "compare.fullscreen": "Fullscreen comparison",
570
+ "compare.selectRequired": "Select at least one model",
424
571
  "generate": "Generate",
425
572
  "generating": "Generating…",
426
573
  "edit.upload": "Click or drag to upload a reference image",
@@ -443,12 +590,18 @@ window.__ModuleLoader__.load({
443
590
  "history.delete": "Delete",
444
591
  "history.images": "images",
445
592
  "history.viewing": "History · {time}",
593
+ "history.search": "Search prompt or model…",
594
+ "history.model": "Model filter",
595
+ "history.ratio": "Ratio filter",
596
+ "history.allModels": "All models",
597
+ "history.allRatios": "All ratios",
446
598
  "gallery.title": "Gallery",
447
599
  "gallery.categories": "Categories",
448
600
  "gallery.all": "All works",
449
601
  "gallery.gpt": "gpt-image-2",
450
602
  "gallery.grok": "grok-imagine-image",
451
603
  "gallery.ratio": "Aspect ratio",
604
+ "gallery.tags": "Tags",
452
605
  "gallery.filterHint": "Filter by mode, model, and aspect ratio",
453
606
  "gallery.count": "· {count} works",
454
607
  "gallery.viewMode": "View mode",
@@ -458,6 +611,19 @@ window.__ModuleLoader__.load({
458
611
  "gallery.newest": "Newest",
459
612
  "gallery.oldest": "Oldest",
460
613
  "gallery.untitled": "Untitled work",
614
+ "gallery.search": "Search works or models…",
615
+ "gallery.tagsPlaceholder": "Tags, comma separated",
616
+ "gallery.tagsApply": "Add tags",
617
+ "gallery.editTags": "Edit tags",
618
+ "gallery.tagsEditShort": "Edit",
619
+ "gallery.tagsSave": "Save",
620
+ "gallery.tagsCancel": "Cancel",
621
+ "gallery.selected": "{count} selected",
622
+ "gallery.selectionDone": "Done selecting",
623
+ "gallery.selectionClear": "Clear selection",
624
+ "gallery.downloadSelected": "Download selected",
625
+ "gallery.exportJson": "Export JSON",
626
+ "gallery.select": "Select work",
461
627
  "gallery.add": "Add to gallery",
462
628
  "gallery.added": "Added to gallery",
463
629
  "gallery.already": "Already in gallery",
@@ -480,6 +646,12 @@ window.__ModuleLoader__.load({
480
646
  "preview.copied": "Copied",
481
647
  "preview.addToEdit": "Add to image to image",
482
648
  "config.missing": "API not configured: open \"Settings → Plugins → Configurable\" and fill in api_url and api_key for AI Image.",
649
+ "config.generationTitle": "Configure the image API first",
650
+ "config.generationHint": "DSH Settings → Plugins → AI Image has opened. Enter the image API URL and API key, then save before generating.",
651
+ "config.enhancementTitle": "Configure a prompt enhancement model first",
652
+ "config.enhancementHint": "DSH Settings → Plugins → AI Image has opened. Configure or reuse a chat API URL and key, choose a chat model, then save.",
653
+ "config.disabledTitle": "The AI Image plugin is disabled",
654
+ "config.disabledHint": "DSH Settings → Plugins → AI Image has opened. Enable the plugin, then generate images.",
483
655
  "config.configured": "Connected to {url}",
484
656
  "config.disabled": "The plugin is disabled — re-enable it in Settings.",
485
657
  "connection.connected": "Connected",
@@ -499,8 +671,39 @@ window.__ModuleLoader__.load({
499
671
  "settings.apiKeyHint": "Bearer key, stored in plaintext in the local settings document; the UI only shows whether it is set",
500
672
  "settings.apiKeySet": "A key is stored; type a new value to replace it, or click \"Clear\" to remove it",
501
673
  "settings.apiKeyClear": "Clear",
674
+ "settings.imageModelsTitle": "Image generation models",
675
+ "settings.imageModelsHint": "Save the API URL and key, then detect candidate models. Select only models that actually support image generation.",
676
+ "settings.imageModels": "Allowed image models",
677
+ "settings.imageModelsManualHint": "One model per line. Add models manually when the API does not provide /models. The panel and Agent can use only this list.",
678
+ "settings.imageModelsFetch": "Detect available models",
679
+ "settings.imageModelsLoading": "Detecting…",
680
+ "settings.imageModelsCandidates": "Detected candidate models (select, then save)",
681
+ "settings.addModel": "+ Add manually",
682
+ "settings.cancelAddModel": "Hide add",
683
+ "settings.addModelPlaceholder": "Enter a model name, e.g. qwen-image",
684
+ "settings.addModelConfirm": "Add",
685
+ "settings.removeModel": "Remove model",
686
+ "settings.optional": "Optional",
687
+ "settings.moreOptions": "More settings",
688
+ "settings.promptEnhanceTitle": "Prompt enhancement model",
689
+ "settings.promptEnhanceHint": "Expands short requests into complete image prompts. Blank URL and key reuse the image API configuration.",
690
+ "settings.promptApiUrl": "Chat API URL (optional)",
691
+ "settings.promptApiUrlHint": "OpenAI-compatible base URL. Leave blank to reuse the image API URL.",
692
+ "settings.promptApiKey": "Chat API key (optional)",
693
+ "settings.promptApiKeyHint": "Leave blank to reuse the image API key.",
694
+ "settings.promptModel": "Chat model",
695
+ "settings.promptModelHint": "Select or enter a model supporting /chat/completions.",
696
+ "settings.promptModelDetectionHint": "Uses the image API by default. Detect and select one model.",
697
+ "settings.promptModelsFetch": "Fetch available models",
698
+ "settings.promptModelsLoading": "Fetching…",
699
+ "settings.promptModelsSelect": "Select a model",
700
+ "settings.promptModelsCandidates": "Detected chat model candidates",
701
+ "settings.addPromptModelPlaceholder": "Enter a chat model name, e.g. gpt-4.1-mini",
702
+ "settings.promptApiAdvanced": "Use a separate chat API (optional)",
502
703
  "settings.announceToAgent": "Announce this plugin to agents",
503
704
  "settings.announceToAgentHint": "When on, the plugin presence and capabilities are written into every agent system prompt",
705
+ "settings.allowAgentImageGeneration": "Allow agents to generate images",
706
+ "settings.allowAgentImageGenerationHint": "On by default. When off, agents cannot submit, query, or cancel image tasks; the sidebar studio remains available.",
504
707
  "settings.enabled": "Enable plugin",
505
708
  "settings.enabledHint": "When off, the generation studio is unavailable (this card stays available)",
506
709
  "settings.save": "Save",
@@ -582,47 +785,47 @@ window.__ModuleLoader__.load({
582
785
  document.head.appendChild(tag);
583
786
  }
584
787
  var templates_module_css_default = {
585
- "detailActions": "o0mAxG_detailActions",
586
- "headerActions": "o0mAxG_headerActions",
587
- "categoryPill": "o0mAxG_categoryPill",
588
- "spinner": "o0mAxG_spinner",
589
- "detailMeta": "o0mAxG_detailMeta",
590
- "state": "o0mAxG_state",
591
- "detail": "o0mAxG_detail",
592
- "detailImage": "o0mAxG_detailImage",
593
- "title": "o0mAxG_title",
594
- "heading": "o0mAxG_heading",
595
- "cardTitle": "o0mAxG_cardTitle",
596
- "detailTitle": "o0mAxG_detailTitle",
788
+ "categoryRow": "o0mAxG_categoryRow",
789
+ "header": "o0mAxG_header",
790
+ "thumbPlaceholder": "o0mAxG_thumbPlaceholder",
597
791
  "dsh-imagegen-templates-spin": "o0mAxG_dsh-imagegen-templates-spin",
598
- "meta": "o0mAxG_meta",
599
792
  "detailInfo": "o0mAxG_detailInfo",
600
- "body": "o0mAxG_body",
601
- "grid": "o0mAxG_grid",
602
- "thumbPlaceholder": "o0mAxG_thumbPlaceholder",
793
+ "card": "o0mAxG_card",
794
+ "detailLink": "o0mAxG_detailLink",
795
+ "detailPrompt": "o0mAxG_detailPrompt",
796
+ "thumb": "o0mAxG_thumb",
797
+ "cardCategory": "o0mAxG_cardCategory",
603
798
  "detailMedia": "o0mAxG_detailMedia",
799
+ "detailActions": "o0mAxG_detailActions",
800
+ "title": "o0mAxG_title",
801
+ "heading": "o0mAxG_heading",
604
802
  "overlay": "o0mAxG_overlay",
605
- "categoryRow": "o0mAxG_categoryRow",
803
+ "headerActions": "o0mAxG_headerActions",
606
804
  "cardSource": "o0mAxG_cardSource",
607
- "header": "o0mAxG_header",
608
- "footer": "o0mAxG_footer",
609
- "close": "o0mAxG_close",
610
- "card": "o0mAxG_card",
611
805
  "sourceLink": "o0mAxG_sourceLink",
612
- "cardBody": "o0mAxG_cardBody",
613
- "detailLink": "o0mAxG_detailLink",
806
+ "meta": "o0mAxG_meta",
807
+ "search": "o0mAxG_search",
614
808
  "notice": "o0mAxG_notice",
809
+ "categoryPill": "o0mAxG_categoryPill",
810
+ "cardTitle": "o0mAxG_cardTitle",
811
+ "featuredBadge": "o0mAxG_featuredBadge",
812
+ "spinner": "o0mAxG_spinner",
813
+ "cardMeta": "o0mAxG_cardMeta",
814
+ "body": "o0mAxG_body",
815
+ "close": "o0mAxG_close",
816
+ "footer": "o0mAxG_footer",
615
817
  "attribution": "o0mAxG_attribution",
818
+ "detailOverlay": "o0mAxG_detailOverlay",
819
+ "detailImage": "o0mAxG_detailImage",
820
+ "grid": "o0mAxG_grid",
821
+ "detailTitle": "o0mAxG_detailTitle",
822
+ "detailMeta": "o0mAxG_detailMeta",
823
+ "cardBody": "o0mAxG_cardBody",
824
+ "toolbar": "o0mAxG_toolbar",
616
825
  "shell": "o0mAxG_shell",
826
+ "state": "o0mAxG_state",
617
827
  "thumbWrap": "o0mAxG_thumbWrap",
618
- "toolbar": "o0mAxG_toolbar",
619
- "search": "o0mAxG_search",
620
- "thumb": "o0mAxG_thumb",
621
- "cardMeta": "o0mAxG_cardMeta",
622
- "detailOverlay": "o0mAxG_detailOverlay",
623
- "featuredBadge": "o0mAxG_featuredBadge",
624
- "cardCategory": "o0mAxG_cardCategory",
625
- "detailPrompt": "o0mAxG_detailPrompt"
828
+ "detail": "o0mAxG_detail"
626
829
  };
627
830
  //#endregion
628
831
  //#region src/client/TemplateLibrary.tsx
@@ -1098,8 +1301,27 @@ window.__ModuleLoader__.load({
1098
1301
  }), document.body);
1099
1302
  }
1100
1303
  //#endregion
1304
+ //#region src/image-models.ts
1305
+ /**
1306
+ * Image-model configuration shared by the host, panel, and Agent tools.
1307
+ * `/models` exposes candidates only: the configured list is the explicit
1308
+ * allow-list because OpenAI-compatible gateways rarely advertise modalities.
1309
+ */
1310
+ const DEFAULT_IMAGE_MODELS = ["gpt-image-2", "grok-imagine-image"];
1311
+ /** Normalize user-entered model identifiers and retain a usable legacy default. */
1312
+ function normalizeImageModels(value) {
1313
+ const candidates = Array.isArray(value) ? value : [];
1314
+ const unique = /* @__PURE__ */ new Set();
1315
+ for (const candidate of candidates) {
1316
+ if (typeof candidate !== "string") continue;
1317
+ const model = candidate.trim();
1318
+ if (model !== "") unique.add(model);
1319
+ }
1320
+ return unique.size > 0 ? [...unique] : [...DEFAULT_IMAGE_MODELS];
1321
+ }
1322
+ //#endregion
1101
1323
  //#region \0dsh-css:E:\dsh-plugin\src\client\panel.module.css.mjs
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}}";
1324
+ 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_taskTray{z-index:6;border:1px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-bg-layer-1) 92%, transparent);backdrop-filter:blur(10px);border-radius:9px;width:min(360px,100% - 24px);position:absolute;top:12px;right:12px;overflow:hidden;box-shadow:0 8px 24px #0000001f}.Yvqh9W_taskTrayHeader{color:var(--dsw-alias-label-primary);border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;padding:8px 10px;font-size:12px;font-weight:600;display:flex}.Yvqh9W_taskRow{border-top:1px solid var(--dsw-alias-border-l1);grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:7px;padding:7px 10px;display:grid}.Yvqh9W_taskRow:first-of-type{border-top:0}.Yvqh9W_taskStatus{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px}.Yvqh9W_taskRow[data-status=running] .Yvqh9W_taskStatus{color:var(--dsw-alias-brand-primary)}.Yvqh9W_taskRow[data-status=failed] .Yvqh9W_taskStatus{color:var(--dsw-alias-label-error)}.Yvqh9W_taskPrompt{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.Yvqh9W_taskRow button{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;font:inherit;border:0;border-radius:5px;padding:2px 7px;font-size:11px}.Yvqh9W_taskRow button:hover{color:var(--dsw-alias-brand-primary)}.Yvqh9W_configGuide{z-index:1100;background:#00000059;place-items:center;padding:20px;display:grid;position:fixed;inset:0}.Yvqh9W_configGuideBody{border:1px solid var(--dsw-alias-border-l2);width:min(360px,100%);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border-radius:10px;flex-direction:column;gap:12px;padding:18px;display:flex;box-shadow:0 14px 40px #0003}.Yvqh9W_configGuideBody span{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55}.Yvqh9W_configGuideBody button{min-height:30px;color:var(--dsw-alias-bg-layer-1);background:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;border:0;border-radius:7px;align-self:flex-end;padding:0 12px;font-size:12px}.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_historyFilters{border-bottom:1px solid var(--dsw-alias-border-l1);grid-template-columns:1fr 1fr;gap:6px;padding:8px 10px;display:grid}.Yvqh9W_historySearch,.Yvqh9W_historyFilters select,.Yvqh9W_gallerySearch{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);min-width:0;min-height:29px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;border-radius:7px;padding:0 8px;font-size:11px}.Yvqh9W_historySearch{grid-column:1/-1}.Yvqh9W_gallerySearch{width:156px}.Yvqh9W_galleryTagInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:130px;min-height:29px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;border-radius:7px;padding:0 8px;font-size:11px}.Yvqh9W_galleryBulkButton{border:1px solid var(--dsw-alias-border-l2);min-height:29px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);cursor:pointer;font:inherit;border-radius:7px;padding:0 8px;font-size:11px}.Yvqh9W_galleryBulkButton:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.Yvqh9W_galleryBulkButton:disabled{opacity:.45;cursor:default}.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_enhanceButton{border:1px solid var(--dsw-alias-border-l2);height:26px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);font:inherit;cursor:pointer;border-radius:999px;margin-left:auto;padding:0 11px;font-size:12px}.Yvqh9W_enhanceButton:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.Yvqh9W_enhanceButton:disabled{opacity:.5;cursor:default}.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_galleryTagFilterList{flex-wrap:wrap;gap:6px;display:flex}.Yvqh9W_galleryTagFilter{border:1px solid var(--dsw-alias-border-l1);min-width:0;max-width:100%;min-height:27px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;font:inherit;border-radius:6px;align-items:center;gap:5px;padding:0 8px;font-size:11px;display:inline-flex}.Yvqh9W_galleryTagFilter span:first-child{text-overflow:ellipsis;white-space:nowrap;max-width:112px;overflow:hidden}.Yvqh9W_galleryTagFilter span:last-child{color:var(--dsw-alias-label-tertiary);font-size:10px}.Yvqh9W_galleryTagFilter:hover,.Yvqh9W_galleryTagFilter[data-active]{color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, 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_gallerySelectMode,.Yvqh9W_galleryBulkButton,.Yvqh9W_gallerySelectionClear{border:1px solid var(--dsw-alias-border-l1);min-height:30px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);cursor:pointer;font:inherit;border-radius:7px;padding:0 10px;font-size:12px}.Yvqh9W_gallerySelectMode:hover,.Yvqh9W_gallerySelectMode[data-active],.Yvqh9W_galleryBulkButton:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 38%, var(--dsw-alias-border-l1));background:color-mix(in srgb, var(--dsw-alias-brand-primary) 11%, transparent)}.Yvqh9W_galleryBulkButton:disabled{cursor:not-allowed;opacity:.45}.Yvqh9W_gallerySelectionBar{border:1px solid color-mix(in srgb, var(--dsw-alias-brand-primary) 35%, var(--dsw-alias-border-l1));background:color-mix(in srgb, var(--dsw-alias-brand-primary) 7%, var(--dsw-alias-bg-layer-1));border-radius:9px;flex:none;align-items:center;gap:10px;min-width:0;margin:-4px 0 16px;padding:10px 12px;display:flex}.Yvqh9W_gallerySelectionBar strong{color:var(--dsw-alias-brand-primary);flex:none;font-size:12px}.Yvqh9W_gallerySelectionClear{margin-left:auto}.Yvqh9W_gallerySelectionClear:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.Yvqh9W_galleryTagInput,.Yvqh9W_gallerySearch{border:1px solid var(--dsw-alias-border-l1);min-width:0;height:30px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);font:inherit;border-radius:7px;outline:none;padding:0 10px;font-size:12px}.Yvqh9W_galleryTagInput{flex:190px}.Yvqh9W_galleryTagInput:focus,.Yvqh9W_gallerySearch:focus{border-color:var(--dsw-alias-brand-primary)}.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_compareControl{flex-direction:column;gap:6px;margin:0 0 10px;display:flex}.Yvqh9W_compareToggle,.Yvqh9W_compareModelChoices label{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;font-size:12px;display:flex}.Yvqh9W_compareToggle input,.Yvqh9W_compareModelChoices input{accent-color:var(--dsw-alias-brand-primary)}.Yvqh9W_compareModelChoices{flex-wrap:wrap;gap:6px;display:flex}.Yvqh9W_compareModelChoices label{border:1px solid var(--dsw-alias-border-l1);border-radius:5px;padding:4px 6px;font-size:10px}.Yvqh9W_comparisonBoard{z-index:4;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;flex-direction:column;display:flex;position:absolute;inset:126px 14px 14px;overflow:hidden;box-shadow:0 8px 24px #0000001f}.Yvqh9W_comparisonBoard>header{border-bottom:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;padding:10px 12px;display:flex}.Yvqh9W_comparisonBoard>header div{align-items:baseline;gap:7px;display:flex}.Yvqh9W_comparisonBoard>header strong{color:var(--dsw-alias-label-primary);font-size:13px}.Yvqh9W_comparisonBoard>header span{color:var(--dsw-alias-label-tertiary);font-size:11px}.Yvqh9W_comparisonBoard>header button{border:1px solid var(--dsw-alias-border-l1);min-height:28px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);cursor:pointer;font:inherit;border-radius:5px;padding:0 9px;font-size:11px}.Yvqh9W_comparisonGrid{flex:1;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px;padding:12px;display:grid;overflow:auto}.Yvqh9W_comparisonGrid article{flex-direction:column;gap:7px;min-width:0;display:flex}.Yvqh9W_comparisonGrid article>strong{color:var(--dsw-alias-label-primary);font-size:12px}.Yvqh9W_comparisonGrid article>span{min-height:160px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);place-items:center;font-size:12px;display:grid}.Yvqh9W_comparisonGrid img{object-fit:contain;background:var(--dsw-alias-bg-base);width:100%;min-height:160px;max-height:calc(100vh - 260px);display:block}.Yvqh9W_comparisonFullscreen{z-index:1200;background:#000000eb;padding:54px 24px 24px;position:fixed;inset:0;overflow:auto}.Yvqh9W_comparisonFullscreenGrid{grid-template-columns:repeat(auto-fit,minmax(300px,1fr));align-items:start;gap:18px;min-height:100%;display:grid}.Yvqh9W_comparisonFullscreen figure{min-width:0;margin:0}.Yvqh9W_comparisonFullscreen figcaption{color:#fff;margin-bottom:8px;font-size:13px;font-weight:600}.Yvqh9W_comparisonFullscreen img{background:#111;width:100%;margin-bottom:10px;display:block}.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;position:relative;overflow:hidden;box-shadow:0 5px 18px #18203612}.Yvqh9W_galleryCard[data-selected]{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent), 0 5px 18px #18203612}.Yvqh9W_gallerySelect{z-index:2;cursor:pointer;background:#00000094;border:1px solid #ffffffbf;border-radius:7px;place-items:center;width:26px;height:26px;display:grid;position:absolute;top:9px;right:9px}.Yvqh9W_gallerySelect input{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer;margin:0}.Yvqh9W_galleryImageButton{background:var(--dsw-alias-bg-base);cursor:zoom-in;border:0;width:100%;padding:0;display:block;position:relative}.Yvqh9W_galleryImageButton[data-selecting]{cursor:pointer}.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_galleryTags{flex-wrap:wrap;gap:4px;margin-top:4px;display:flex}.Yvqh9W_galleryTags button{max-width:96px;min-height:19px;color:var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 10%, transparent);cursor:pointer;font:inherit;text-overflow:ellipsis;white-space:nowrap;border:0;border-radius:4px;padding:1px 6px;font-size:10px;line-height:1.35;overflow:hidden}.Yvqh9W_galleryTags button:hover{background:color-mix(in srgb, var(--dsw-alias-brand-primary) 17%, transparent)}.Yvqh9W_galleryTags .Yvqh9W_galleryTagEdit{color:var(--dsw-alias-label-tertiary);background:0 0;flex:none}.Yvqh9W_galleryTagEditor{align-items:center;gap:6px;padding:0 12px 10px 48px;display:flex}.Yvqh9W_galleryTagEditor input{border:1px solid var(--dsw-alias-border-l2);min-width:0;height:27px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);font:inherit;border-radius:6px;outline:none;flex:1;padding:0 8px;font-size:11px}.Yvqh9W_galleryTagEditor input:focus{border-color:var(--dsw-alias-brand-primary)}.Yvqh9W_galleryTagEditor button{border:1px solid var(--dsw-alias-border-l2);height:27px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);cursor:pointer;font:inherit;border-radius:6px;padding:0 8px;font-size:11px}.Yvqh9W_galleryTagEditor button[type=submit]{color:var(--dsw-alias-brand-primary)}.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}}";
1103
1325
  const tagId$1 = "@dickpy/dsh-imagegen/panel.module.css";
1104
1326
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
1105
1327
  const tag = document.createElement("style");
@@ -1109,132 +1331,161 @@ window.__ModuleLoader__.load({
1109
1331
  document.head.appendChild(tag);
1110
1332
  }
1111
1333
  var panel_module_css_default = {
1112
- "config": "Yvqh9W_config",
1113
- "generateInner": "Yvqh9W_generateInner",
1114
- "panelHeader": "Yvqh9W_panelHeader",
1334
+ "compareToggle": "Yvqh9W_compareToggle",
1335
+ "panelTitle": "Yvqh9W_panelTitle",
1336
+ "taskStatus": "Yvqh9W_taskStatus",
1337
+ "galleryTagInput": "Yvqh9W_galleryTagInput",
1338
+ "canvas": "Yvqh9W_canvas",
1339
+ "history": "Yvqh9W_history",
1115
1340
  "lightboxTools": "Yvqh9W_lightboxTools",
1116
- "lightbox": "Yvqh9W_lightbox",
1117
- "hiddenFile": "Yvqh9W_hiddenFile",
1341
+ "taskPrompt": "Yvqh9W_taskPrompt",
1342
+ "galleryRatio": "Yvqh9W_galleryRatio",
1343
+ "updateBanner": "Yvqh9W_updateBanner",
1344
+ "canvasMeta": "Yvqh9W_canvasMeta",
1345
+ "historyThumbPlaceholder": "Yvqh9W_historyThumbPlaceholder",
1346
+ "historyFilters": "Yvqh9W_historyFilters",
1347
+ "historyList": "Yvqh9W_historyList",
1348
+ "uploadBox": "Yvqh9W_uploadBox",
1349
+ "updateActions": "Yvqh9W_updateActions",
1350
+ "lightboxTool": "Yvqh9W_lightboxTool",
1351
+ "lightboxDownload": "Yvqh9W_lightboxDownload",
1352
+ "comparisonFullscreenGrid": "Yvqh9W_comparisonFullscreenGrid",
1353
+ "connectionStatus": "Yvqh9W_connectionStatus",
1354
+ "panelHeading": "Yvqh9W_panelHeading",
1355
+ "gallerySearch": "Yvqh9W_gallerySearch",
1356
+ "bigSpinner": "Yvqh9W_bigSpinner",
1357
+ "canvasEmptyIcon": "Yvqh9W_canvasEmptyIcon",
1358
+ "imageCaption": "Yvqh9W_imageCaption",
1359
+ "entryLabel": "Yvqh9W_entryLabel",
1360
+ "config": "Yvqh9W_config",
1361
+ "configGuideBody": "Yvqh9W_configGuideBody",
1362
+ "historyTitle": "Yvqh9W_historyTitle",
1363
+ "galleryFilter": "Yvqh9W_galleryFilter",
1364
+ "galleryFilterCount": "Yvqh9W_galleryFilterCount",
1365
+ "galleryTagEditor": "Yvqh9W_galleryTagEditor",
1366
+ "historyAction": "Yvqh9W_historyAction",
1118
1367
  "galleryRemove": "Yvqh9W_galleryRemove",
1119
- "promptCount": "Yvqh9W_promptCount",
1120
- "lightboxCaptionRow": "Yvqh9W_lightboxCaptionRow",
1368
+ "lightboxClose": "Yvqh9W_lightboxClose",
1369
+ "modelMenuList": "Yvqh9W_modelMenuList",
1370
+ "modePill": "Yvqh9W_modePill",
1121
1371
  "zoomHint": "Yvqh9W_zoomHint",
1122
- "galleryRatio": "Yvqh9W_galleryRatio",
1123
- "modelSelect": "Yvqh9W_modelSelect",
1124
- "galleryRatioList": "Yvqh9W_galleryRatioList",
1125
- "historyHeader": "Yvqh9W_historyHeader",
1372
+ "taskRow": "Yvqh9W_taskRow",
1373
+ "referenceImage": "Yvqh9W_referenceImage",
1126
1374
  "galleryWorkspace": "Yvqh9W_galleryWorkspace",
1127
- "canvasState": "Yvqh9W_canvasState",
1128
- "entry": "Yvqh9W_entry",
1129
- "gallerySort": "Yvqh9W_gallerySort",
1375
+ "panel": "Yvqh9W_panel",
1376
+ "connectionDot": "Yvqh9W_connectionDot",
1130
1377
  "galleryImage": "Yvqh9W_galleryImage",
1131
- "paramLabel": "Yvqh9W_paramLabel",
1132
- "grid": "Yvqh9W_grid",
1133
- "canvasEmptyIcon": "Yvqh9W_canvasEmptyIcon",
1134
- "lightboxTool": "Yvqh9W_lightboxTool",
1135
- "galleryFilters": "Yvqh9W_galleryFilters",
1136
- "reference": "Yvqh9W_reference",
1137
- "optionGrid": "Yvqh9W_optionGrid",
1138
- "configScroll": "Yvqh9W_configScroll",
1378
+ "image": "Yvqh9W_image",
1379
+ "galleryTagFilter": "Yvqh9W_galleryTagFilter",
1380
+ "galleryCard": "Yvqh9W_galleryCard",
1381
+ "historyPrompt": "Yvqh9W_historyPrompt",
1382
+ "historyHeader": "Yvqh9W_historyHeader",
1383
+ "modelLabel": "Yvqh9W_modelLabel",
1384
+ "canvasState": "Yvqh9W_canvasState",
1385
+ "dshImageGenSpin": "Yvqh9W_dshImageGenSpin",
1386
+ "historyItem": "Yvqh9W_historyItem",
1387
+ "historyInfo": "Yvqh9W_historyInfo",
1388
+ "taskTrayHeader": "Yvqh9W_taskTrayHeader",
1139
1389
  "uploadIcon": "Yvqh9W_uploadIcon",
1140
- "historyTitle": "Yvqh9W_historyTitle",
1141
- "lightboxActions": "Yvqh9W_lightboxActions",
1142
- "view": "Yvqh9W_view",
1143
- "historyEmpty": "Yvqh9W_historyEmpty",
1144
- "card": "Yvqh9W_card",
1145
- "galleryToolbarActions": "Yvqh9W_galleryToolbarActions",
1146
- "lightboxCaption": "Yvqh9W_lightboxCaption",
1147
- "spinner": "Yvqh9W_spinner",
1148
- "canvasMeta": "Yvqh9W_canvasMeta",
1149
- "paramHint": "Yvqh9W_paramHint",
1390
+ "paramLabel": "Yvqh9W_paramLabel",
1391
+ "modelMenu": "Yvqh9W_modelMenu",
1150
1392
  "canvasStateTitle": "Yvqh9W_canvasStateTitle",
1151
- "footer": "Yvqh9W_footer",
1393
+ "historyEmpty": "Yvqh9W_historyEmpty",
1394
+ "canvasBody": "Yvqh9W_canvasBody",
1395
+ "canvasHistoryTag": "Yvqh9W_canvasHistoryTag",
1152
1396
  "galleryCount": "Yvqh9W_galleryCount",
1153
- "historyThumbPlaceholder": "Yvqh9W_historyThumbPlaceholder",
1154
- "galleryAdd": "Yvqh9W_galleryAdd",
1397
+ "gallerySelectionClear": "Yvqh9W_gallerySelectionClear",
1155
1398
  "historyActions": "Yvqh9W_historyActions",
1156
- "historyItem": "Yvqh9W_historyItem",
1157
- "galleryFilterNote": "Yvqh9W_galleryFilterNote",
1158
- "uploadHint": "Yvqh9W_uploadHint",
1159
- "modelMenuList": "Yvqh9W_modelMenuList",
1160
- "galleryClear": "Yvqh9W_galleryClear",
1399
+ "galleryTags": "Yvqh9W_galleryTags",
1400
+ "hiddenFile": "Yvqh9W_hiddenFile",
1401
+ "lightboxIndex": "Yvqh9W_lightboxIndex",
1402
+ "modeRow": "Yvqh9W_modeRow",
1161
1403
  "githubLink": "Yvqh9W_githubLink",
1162
- "lightboxFigure": "Yvqh9W_lightboxFigure",
1404
+ "download": "Yvqh9W_download",
1405
+ "view": "Yvqh9W_view",
1406
+ "galleryTagFilterList": "Yvqh9W_galleryTagFilterList",
1407
+ "lightbox": "Yvqh9W_lightbox",
1408
+ "galleryToolbarActions": "Yvqh9W_galleryToolbarActions",
1409
+ "spinner": "Yvqh9W_spinner",
1410
+ "lightboxEdit": "Yvqh9W_lightboxEdit",
1411
+ "comparisonGrid": "Yvqh9W_comparisonGrid",
1412
+ "galleryAvatar": "Yvqh9W_galleryAvatar",
1413
+ "grid": "Yvqh9W_grid",
1414
+ "modelWrap": "Yvqh9W_modelWrap",
1415
+ "comparisonFullscreen": "Yvqh9W_comparisonFullscreen",
1416
+ "modelMenuItem": "Yvqh9W_modelMenuItem",
1417
+ "compareControl": "Yvqh9W_compareControl",
1418
+ "updateText": "Yvqh9W_updateText",
1419
+ "footer": "Yvqh9W_footer",
1420
+ "lightboxActions": "Yvqh9W_lightboxActions",
1421
+ "lightboxMeta": "Yvqh9W_lightboxMeta",
1422
+ "prompt": "Yvqh9W_prompt",
1423
+ "optionPill": "Yvqh9W_optionPill",
1424
+ "galleryViewToggle": "Yvqh9W_galleryViewToggle",
1425
+ "imageCard": "Yvqh9W_imageCard",
1426
+ "compareModelChoices": "Yvqh9W_compareModelChoices",
1163
1427
  "galleryImageButton": "Yvqh9W_galleryImageButton",
1164
- "history": "Yvqh9W_history",
1165
- "imageCaption": "Yvqh9W_imageCaption",
1166
- "modelLabel": "Yvqh9W_modelLabel",
1167
- "dshImageGenSpin": "Yvqh9W_dshImageGenSpin",
1428
+ "comparisonBoard": "Yvqh9W_comparisonBoard",
1429
+ "paramHint": "Yvqh9W_paramHint",
1430
+ "uploadHint": "Yvqh9W_uploadHint",
1431
+ "optionRow": "Yvqh9W_optionRow",
1432
+ "optionGrid": "Yvqh9W_optionGrid",
1433
+ "lightboxNav": "Yvqh9W_lightboxNav",
1434
+ "galleryCardInfo": "Yvqh9W_galleryCardInfo",
1435
+ "reference": "Yvqh9W_reference",
1168
1436
  "historyClear": "Yvqh9W_historyClear",
1169
- "lightboxImage": "Yvqh9W_lightboxImage",
1170
- "image": "Yvqh9W_image",
1437
+ "lightboxScaleFrame": "Yvqh9W_lightboxScaleFrame",
1438
+ "galleryFilterHeading": "Yvqh9W_galleryFilterHeading",
1171
1439
  "galleryFilterDivider": "Yvqh9W_galleryFilterDivider",
1172
- "updateBanner": "Yvqh9W_updateBanner",
1173
- "connectionStatus": "Yvqh9W_connectionStatus",
1174
- "modelMenuItem": "Yvqh9W_modelMenuItem",
1175
- "galleryAvatar": "Yvqh9W_galleryAvatar",
1176
- "updateRelease": "Yvqh9W_updateRelease",
1177
- "studio": "Yvqh9W_studio",
1178
- "uploadBox": "Yvqh9W_uploadBox",
1179
- "historyMeta": "Yvqh9W_historyMeta",
1440
+ "historyThumb": "Yvqh9W_historyThumb",
1441
+ "lightboxFigure": "Yvqh9W_lightboxFigure",
1442
+ "gallerySelect": "Yvqh9W_gallerySelect",
1443
+ "galleryBadge": "Yvqh9W_galleryBadge",
1444
+ "galleryRatioList": "Yvqh9W_galleryRatioList",
1445
+ "entryIcon": "Yvqh9W_entryIcon",
1446
+ "lightboxCaptionRow": "Yvqh9W_lightboxCaptionRow",
1447
+ "lightboxImage": "Yvqh9W_lightboxImage",
1448
+ "galleryHeading": "Yvqh9W_galleryHeading",
1449
+ "panelHeader": "Yvqh9W_panelHeader",
1450
+ "generateInner": "Yvqh9W_generateInner",
1451
+ "galleryCardFooter": "Yvqh9W_galleryCardFooter",
1452
+ "galleryTagEdit": "Yvqh9W_galleryTagEdit",
1453
+ "configScroll": "Yvqh9W_configScroll",
1454
+ "referenceActions": "Yvqh9W_referenceActions",
1455
+ "canvasStateHint": "Yvqh9W_canvasStateHint",
1456
+ "galleryAdd": "Yvqh9W_galleryAdd",
1180
1457
  "generateButton": "Yvqh9W_generateButton",
1181
- "connectionDot": "Yvqh9W_connectionDot",
1182
- "panelHeading": "Yvqh9W_panelHeading",
1183
- "galleryViewToggle": "Yvqh9W_galleryViewToggle",
1184
- "modePill": "Yvqh9W_modePill",
1185
- "galleryToolbar": "Yvqh9W_galleryToolbar",
1186
- "historyPrompt": "Yvqh9W_historyPrompt",
1187
1458
  "galleryToast": "Yvqh9W_galleryToast",
1188
- "canvasStateHint": "Yvqh9W_canvasStateHint",
1459
+ "canvasError": "Yvqh9W_canvasError",
1460
+ "lightboxZoomLevel": "Yvqh9W_lightboxZoomLevel",
1461
+ "gallerySelectionBar": "Yvqh9W_gallerySelectionBar",
1189
1462
  "galleryMasonry": "Yvqh9W_galleryMasonry",
1190
- "paramGroup": "Yvqh9W_paramGroup",
1191
- "download": "Yvqh9W_download",
1192
- "templatesButton": "Yvqh9W_templatesButton",
1463
+ "galleryFilters": "Yvqh9W_galleryFilters",
1464
+ "lightboxCopy": "Yvqh9W_lightboxCopy",
1193
1465
  "lightboxStage": "Yvqh9W_lightboxStage",
1194
- "galleryFilter": "Yvqh9W_galleryFilter",
1195
- "referenceActions": "Yvqh9W_referenceActions",
1466
+ "card": "Yvqh9W_card",
1467
+ "taskTray": "Yvqh9W_taskTray",
1468
+ "galleryBulkButton": "Yvqh9W_galleryBulkButton",
1469
+ "promptCount": "Yvqh9W_promptCount",
1470
+ "modelSelect": "Yvqh9W_modelSelect",
1471
+ "lightboxCaption": "Yvqh9W_lightboxCaption",
1472
+ "updateRelease": "Yvqh9W_updateRelease",
1473
+ "historySearch": "Yvqh9W_historySearch",
1474
+ "galleryToolbar": "Yvqh9W_galleryToolbar",
1196
1475
  "dshImageGenToastIn": "Yvqh9W_dshImageGenToastIn",
1197
- "imageCard": "Yvqh9W_imageCard",
1198
- "entryIcon": "Yvqh9W_entryIcon",
1199
- "canvas": "Yvqh9W_canvas",
1200
- "galleryHeading": "Yvqh9W_galleryHeading",
1201
- "entryLabel": "Yvqh9W_entryLabel",
1202
- "updateActions": "Yvqh9W_updateActions",
1203
- "modelMenu": "Yvqh9W_modelMenu",
1204
- "historyInfo": "Yvqh9W_historyInfo",
1205
- "canvasBody": "Yvqh9W_canvasBody",
1206
- "galleryBadge": "Yvqh9W_galleryBadge",
1207
- "lightboxEdit": "Yvqh9W_lightboxEdit",
1208
- "bigSpinner": "Yvqh9W_bigSpinner",
1209
- "modelWrap": "Yvqh9W_modelWrap",
1210
- "referenceImage": "Yvqh9W_referenceImage",
1211
- "lightboxClose": "Yvqh9W_lightboxClose",
1476
+ "paramGroup": "Yvqh9W_paramGroup",
1477
+ "galleryFilterNote": "Yvqh9W_galleryFilterNote",
1478
+ "enhanceButton": "Yvqh9W_enhanceButton",
1479
+ "gallerySelectMode": "Yvqh9W_gallerySelectMode",
1480
+ "configGuide": "Yvqh9W_configGuide",
1481
+ "studio": "Yvqh9W_studio",
1482
+ "templatesButton": "Yvqh9W_templatesButton",
1483
+ "gallerySort": "Yvqh9W_gallerySort",
1212
1484
  "historyMain": "Yvqh9W_historyMain",
1213
- "lightboxZoomLevel": "Yvqh9W_lightboxZoomLevel",
1214
- "lightboxCopy": "Yvqh9W_lightboxCopy",
1215
- "prompt": "Yvqh9W_prompt",
1216
- "panelTitle": "Yvqh9W_panelTitle",
1217
- "optionRow": "Yvqh9W_optionRow",
1218
- "canvasError": "Yvqh9W_canvasError",
1219
- "canvasHistoryTag": "Yvqh9W_canvasHistoryTag",
1220
- "historyThumb": "Yvqh9W_historyThumb",
1221
- "historyList": "Yvqh9W_historyList",
1222
- "lightboxMeta": "Yvqh9W_lightboxMeta",
1223
- "galleryFilterHeading": "Yvqh9W_galleryFilterHeading",
1224
- "optionPill": "Yvqh9W_optionPill",
1225
- "panel": "Yvqh9W_panel",
1226
- "galleryCardInfo": "Yvqh9W_galleryCardInfo",
1227
- "lightboxNav": "Yvqh9W_lightboxNav",
1228
- "lightboxScaleFrame": "Yvqh9W_lightboxScaleFrame",
1229
- "galleryCardFooter": "Yvqh9W_galleryCardFooter",
1230
- "lightboxIndex": "Yvqh9W_lightboxIndex",
1231
- "lightboxDownload": "Yvqh9W_lightboxDownload",
1232
- "galleryFilterCount": "Yvqh9W_galleryFilterCount",
1233
- "promptFooter": "Yvqh9W_promptFooter",
1234
- "updateText": "Yvqh9W_updateText",
1235
- "galleryCard": "Yvqh9W_galleryCard",
1236
- "modeRow": "Yvqh9W_modeRow",
1237
- "historyAction": "Yvqh9W_historyAction"
1485
+ "galleryClear": "Yvqh9W_galleryClear",
1486
+ "entry": "Yvqh9W_entry",
1487
+ "historyMeta": "Yvqh9W_historyMeta",
1488
+ "promptFooter": "Yvqh9W_promptFooter"
1238
1489
  };
1239
1490
  //#endregion
1240
1491
  //#region src/client/ImageGenPanel.tsx
@@ -1247,10 +1498,6 @@ window.__ModuleLoader__.load({
1247
1498
  * Controls ride the system UI primitives (@deepseek-ai/dsh-client-ui-primitives,
1248
1499
  * a platform module) so the studio matches the dsh shell look by construction.
1249
1500
  */
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
1501
  /** Size options, presented as aspect ratios (auto = let the model decide).
1255
1502
  * The host maps each ratio onto the model's own vocabulary: aspect_ratio for
1256
1503
  * Grok Imagine, the closest pixel size for OpenAI-compatible endpoints. */
@@ -1292,7 +1539,6 @@ window.__ModuleLoader__.load({
1292
1539
  "standard",
1293
1540
  "high"
1294
1541
  ];
1295
- const PROMPT_MAX = 2e3;
1296
1542
  const REF_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
1297
1543
  const PREVIEW_SCALE_MIN = .5;
1298
1544
  const PREVIEW_SCALE_MAX = 3;
@@ -1334,13 +1580,13 @@ window.__ModuleLoader__.load({
1334
1580
  }), [scope]);
1335
1581
  return value;
1336
1582
  }
1337
- /** Track the redacted api-key presence bit exposed by the settings bridge. */
1338
- function useKeySet(scope) {
1339
- const [keySet, setKeySet] = (0, react.useState)(scope.getKeySetSnapshot());
1340
- (0, react.useEffect)(() => scope.subscribeKeySet(() => {
1341
- setKeySet(scope.getKeySetSnapshot());
1342
- }), [scope]);
1343
- return keySet;
1583
+ /** Track one redacted secret field without exposing its value to the panel. */
1584
+ function useSecretSet(scope, field) {
1585
+ const [isSet, setIsSet] = (0, react.useState)(scope.getSecretSetSnapshot(field));
1586
+ (0, react.useEffect)(() => scope.subscribeSecretSets(() => {
1587
+ setIsSet(scope.getSecretSetSnapshot(field));
1588
+ }), [field, scope]);
1589
+ return isSet;
1344
1590
  }
1345
1591
  /** Tick a seconds counter while `running`. */
1346
1592
  function useElapsed(running, startedAt) {
@@ -1392,20 +1638,26 @@ window.__ModuleLoader__.load({
1392
1638
  const config = useConfig(scope);
1393
1639
  const enabled = config?.enabled ?? true;
1394
1640
  const configured = (config?.apiUrl ?? "").trim() !== "";
1395
- const keySet = useKeySet(scope);
1396
- const connected = enabled && configured && keySet;
1641
+ const apiKeySet = useSecretSet(scope, "apiKey");
1642
+ const promptKeySet = useSecretSet(scope, "promptApiKey");
1643
+ const connected = enabled && configured && apiKeySet;
1644
+ const imageModels = normalizeImageModels(config?.imageModels);
1397
1645
  const [tab, setTab] = (0, react.useState)("text");
1398
1646
  const [prompt, setPrompt] = (0, react.useState)("");
1399
1647
  const [size, setSize] = (0, react.useState)("auto");
1400
1648
  const [quality, setQuality] = (0, react.useState)("auto");
1401
1649
  const [count, setCount] = (0, react.useState)(1);
1402
1650
  const [detail, setDetail] = (0, react.useState)("");
1403
- const [model, setModel] = (0, react.useState)(MODELS[0]);
1651
+ const [model, setModel] = (0, react.useState)(DEFAULT_IMAGE_MODELS[0]);
1652
+ const [compareEnabled, setCompareEnabled] = (0, react.useState)(false);
1653
+ const [compareModels, setCompareModels] = (0, react.useState)([...DEFAULT_IMAGE_MODELS]);
1404
1654
  const [modelOpen, setModelOpen] = (0, react.useState)(false);
1405
1655
  const [refImage, setRefImage] = (0, react.useState)(null);
1406
1656
  const [images, setImages] = (0, react.useState)([]);
1407
1657
  const [error, setError] = (0, react.useState)(null);
1408
1658
  const [generating, setGenerating] = (0, react.useState)(false);
1659
+ const [enhancing, setEnhancing] = (0, react.useState)(false);
1660
+ const [configGuide, setConfigGuide] = (0, react.useState)(null);
1409
1661
  const [startedAt, setStartedAt] = (0, react.useState)(null);
1410
1662
  const [history, setHistory] = (0, react.useState)([]);
1411
1663
  const [viewingHistoryId, setViewingHistoryId] = (0, react.useState)(null);
@@ -1415,8 +1667,18 @@ window.__ModuleLoader__.load({
1415
1667
  const [galleryMessage, setGalleryMessage] = (0, react.useState)(null);
1416
1668
  const [galleryFilter, setGalleryFilter] = (0, react.useState)("all");
1417
1669
  const [galleryRatio, setGalleryRatio] = (0, react.useState)("all");
1670
+ const [galleryTagFilter, setGalleryTagFilter] = (0, react.useState)(null);
1418
1671
  const [galleryView, setGalleryView] = (0, react.useState)("masonry");
1419
1672
  const [gallerySort, setGallerySort] = (0, react.useState)("newest");
1673
+ const [galleryQuery, setGalleryQuery] = (0, react.useState)("");
1674
+ const [galleryTagInput, setGalleryTagInput] = (0, react.useState)("");
1675
+ const [editingGalleryTagsId, setEditingGalleryTagsId] = (0, react.useState)(null);
1676
+ const [galleryTagEditInput, setGalleryTagEditInput] = (0, react.useState)("");
1677
+ const [selectedGalleryIds, setSelectedGalleryIds] = (0, react.useState)(/* @__PURE__ */ new Set());
1678
+ const [gallerySelecting, setGallerySelecting] = (0, react.useState)(false);
1679
+ const [historyQuery, setHistoryQuery] = (0, react.useState)("");
1680
+ const [historyModelFilter, setHistoryModelFilter] = (0, react.useState)("all");
1681
+ const [historyRatioFilter, setHistoryRatioFilter] = (0, react.useState)("all");
1420
1682
  const [preview, setPreview] = (0, react.useState)(null);
1421
1683
  const [previewScale, setPreviewScale] = (0, react.useState)(1);
1422
1684
  const [promptCopied, setPromptCopied] = (0, react.useState)(false);
@@ -1425,14 +1687,30 @@ window.__ModuleLoader__.load({
1425
1687
  const [updateMessage, setUpdateMessage] = (0, react.useState)(null);
1426
1688
  const [updateResult, setUpdateResult] = (0, react.useState)(null);
1427
1689
  const [libraryOpen, setLibraryOpen] = (0, react.useState)(false);
1690
+ const [tasks, setTasks] = (0, react.useState)([]);
1691
+ const [comparison, setComparison] = (0, react.useState)(null);
1692
+ const [comparisonFullscreen, setComparisonFullscreen] = (0, react.useState)(false);
1428
1693
  const fileInput = (0, react.useRef)(null);
1429
1694
  const previewStage = (0, react.useRef)(null);
1430
1695
  const elapsed = useElapsed(generating, startedAt);
1696
+ (0, react.useEffect)(() => {
1697
+ setModel((previous) => imageModels.includes(previous) ? previous : imageModels[0]);
1698
+ setCompareModels((previous) => {
1699
+ const retained = previous.filter((candidate) => imageModels.includes(candidate));
1700
+ return retained.length > 0 ? retained : [imageModels[0]];
1701
+ });
1702
+ }, [imageModels.join("\0")]);
1431
1703
  const filteredGallery = gallery.filter((entry) => {
1432
1704
  if (galleryFilter === "all") return true;
1433
1705
  if (galleryFilter === "text" || galleryFilter === "edit") return entry.mode === galleryFilter;
1434
1706
  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);
1707
+ }).filter((entry) => galleryRatio === "all" || normalizeSize(entry.size) === galleryRatio).filter((entry) => galleryTagFilter === null || (entry.tags ?? []).includes(galleryTagFilter)).filter((entry) => galleryQuery.trim() === "" || `${entry.prompt} ${entry.model} ${(entry.tags ?? []).join(" ")}`.toLocaleLowerCase().includes(galleryQuery.trim().toLocaleLowerCase())).slice().sort((a, b) => gallerySort === "newest" ? b.createdAt - a.createdAt : a.createdAt - b.createdAt);
1708
+ const galleryTagOptions = [...new Set(gallery.flatMap((entry) => entry.tags ?? []))].sort((a, b) => a.localeCompare(b));
1709
+ const galleryModels = [.../* @__PURE__ */ new Set([...imageModels, ...gallery.map((entry) => entry.model)])];
1710
+ const filteredHistory = history.filter((entry) => {
1711
+ const query = historyQuery.trim().toLocaleLowerCase();
1712
+ return (query === "" || `${entry.prompt} ${entry.model}`.toLocaleLowerCase().includes(query)) && (historyModelFilter === "all" || entry.model === historyModelFilter) && (historyRatioFilter === "all" || normalizeSize(entry.size) === historyRatioFilter);
1713
+ });
1436
1714
  (0, react.useEffect)(() => {
1437
1715
  let disposed = false;
1438
1716
  api.historyList().then((entries) => {
@@ -1445,6 +1723,29 @@ window.__ModuleLoader__.load({
1445
1723
  disposed = true;
1446
1724
  };
1447
1725
  }, [api]);
1726
+ (0, react.useEffect)(() => {
1727
+ let disposed = false;
1728
+ const refresh = () => {
1729
+ api.taskList().then((next) => {
1730
+ if (disposed) return;
1731
+ setTasks((previous) => {
1732
+ const completed = next.find((task) => task.status === "completed" && !previous.some((old) => old.id === task.id && old.status === "completed") && !comparison?.taskIds.includes(task.id));
1733
+ if (completed?.result !== void 0) {
1734
+ setImages(completed.result.images);
1735
+ if (completed.result.history !== void 0) setHistory(completed.result.history);
1736
+ setError(completed.result.historyError ?? null);
1737
+ }
1738
+ return next;
1739
+ });
1740
+ }).catch(() => {});
1741
+ };
1742
+ refresh();
1743
+ const timer = window.setInterval(refresh, 1500);
1744
+ return () => {
1745
+ disposed = true;
1746
+ window.clearInterval(timer);
1747
+ };
1748
+ }, [api, comparison]);
1448
1749
  const modelMenuRef = (0, react.useRef)(null);
1449
1750
  (0, react.useEffect)(() => {
1450
1751
  if (!modelOpen) return;
@@ -1485,6 +1786,36 @@ window.__ModuleLoader__.load({
1485
1786
  setUpdating(false);
1486
1787
  }
1487
1788
  };
1789
+ const openSettingsGuide = (kind) => {
1790
+ setConfigGuide(kind);
1791
+ const openPluginSettings = () => {
1792
+ Array.from(document.querySelectorAll("button")).find((button) => /^(插件|Plugins)$/.test(button.textContent?.trim() ?? ""))?.click();
1793
+ window.setTimeout(() => {
1794
+ const imageGenButton = Array.from(document.querySelectorAll("button")).find((button) => /dsh-imagegen/i.test(button.textContent ?? ""));
1795
+ if (imageGenButton?.getAttribute("aria-expanded") !== "true") imageGenButton?.click();
1796
+ }, 0);
1797
+ };
1798
+ const settingsButton = Array.from(document.querySelectorAll("button")).find((button) => /^(设置|Settings)$/.test(button.textContent?.trim() ?? ""));
1799
+ if (settingsButton?.getAttribute("aria-expanded") !== "true") settingsButton?.click();
1800
+ window.setTimeout(openPluginSettings, 0);
1801
+ };
1802
+ const enhanceCurrentPrompt = async () => {
1803
+ if (prompt.trim() === "" || enhancing) return;
1804
+ const promptEndpointConfigured = (config?.promptApiUrl ?? "").trim() !== "" || configured;
1805
+ if ((config?.promptModel ?? "").trim() === "" || !promptEndpointConfigured || !promptKeySet && !apiKeySet) {
1806
+ openSettingsGuide("enhancement");
1807
+ return;
1808
+ }
1809
+ setEnhancing(true);
1810
+ setError(null);
1811
+ try {
1812
+ setPrompt(await api.enhancePrompt(prompt));
1813
+ } catch (caught) {
1814
+ setError(errorMessage(caught));
1815
+ } finally {
1816
+ setEnhancing(false);
1817
+ }
1818
+ };
1488
1819
  /** Read an uploaded reference image into a data URL. */
1489
1820
  const acceptFile = (file) => {
1490
1821
  if (file === void 0) return;
@@ -1511,6 +1842,14 @@ window.__ModuleLoader__.load({
1511
1842
  /** Run one generation. */
1512
1843
  const handleGenerate = async () => {
1513
1844
  if (generating) return;
1845
+ if (!enabled) {
1846
+ openSettingsGuide("disabled");
1847
+ return;
1848
+ }
1849
+ if (!configured || !apiKeySet) {
1850
+ openSettingsGuide("generation");
1851
+ return;
1852
+ }
1514
1853
  const promptText = prompt.trim();
1515
1854
  if (promptText === "") {
1516
1855
  setError(tt("prompt.required"));
@@ -1522,7 +1861,7 @@ window.__ModuleLoader__.load({
1522
1861
  }
1523
1862
  const request = {
1524
1863
  mode: tab === "gallery" ? "text" : tab,
1525
- model,
1864
+ model: imageModels.includes(model) ? model : imageModels[0],
1526
1865
  prompt: promptText,
1527
1866
  size,
1528
1867
  quality,
@@ -1531,22 +1870,24 @@ window.__ModuleLoader__.load({
1531
1870
  ...tab === "edit" && refImage !== null ? { image: refImage.dataUrl } : {},
1532
1871
  ...tab === "edit" && refImage !== null ? { refName: refImage.name } : {}
1533
1872
  };
1534
- setGenerating(true);
1535
1873
  setError(null);
1536
- setImages([]);
1537
- setStartedAt(Date.now());
1538
1874
  try {
1539
- const result = await api.generate(request);
1540
- setImages(result.images);
1541
- setViewingHistoryId(null);
1542
- setGalleryViewingId(null);
1543
- if (result.history !== void 0) setHistory(result.history);
1544
- if (result.historyError !== void 0) setError(result.historyError);
1875
+ const targetModels = (compareEnabled ? compareModels : [request.model]).filter((candidate) => imageModels.includes(candidate));
1876
+ if (targetModels.length === 0) {
1877
+ setError(tt("compare.selectRequired"));
1878
+ return;
1879
+ }
1880
+ const submitted = await Promise.all(targetModels.map((targetModel) => api.taskSubmit({
1881
+ ...request,
1882
+ model: targetModel
1883
+ })));
1884
+ setTasks((previous) => [...submitted, ...previous.filter((item) => !submitted.some((task) => task.id === item.id))]);
1885
+ setComparison(targetModels.length > 1 ? {
1886
+ taskIds: submitted.map((task) => task.id),
1887
+ prompt: promptText
1888
+ } : null);
1545
1889
  } catch (caught) {
1546
1890
  setError(errorMessage(caught));
1547
- } finally {
1548
- setGenerating(false);
1549
- setStartedAt(null);
1550
1891
  }
1551
1892
  };
1552
1893
  /** Open the full-screen image preview at a given index. */
@@ -1620,7 +1961,7 @@ window.__ModuleLoader__.load({
1620
1961
  setQuality(normalizeQuality(entry.quality));
1621
1962
  setDetail(DETAILS.includes(entry.detail) ? entry.detail : "");
1622
1963
  setCount(entry.n >= 1 && entry.n <= 4 ? entry.n : 1);
1623
- setModel(MODELS.includes(entry.model) ? entry.model : MODELS[0]);
1964
+ setModel(imageModels.includes(entry.model) ? entry.model : imageModels[0]);
1624
1965
  setRefImage(null);
1625
1966
  setImages(restored);
1626
1967
  setError(null);
@@ -1722,7 +2063,7 @@ window.__ModuleLoader__.load({
1722
2063
  setQuality(normalizeQuality(entry.quality));
1723
2064
  setDetail(DETAILS.includes(entry.detail) ? entry.detail : "");
1724
2065
  setCount(entry.n >= 1 && entry.n <= 4 ? entry.n : 1);
1725
- setModel(MODELS.includes(entry.model) ? entry.model : MODELS[0]);
2066
+ setModel(imageModels.includes(entry.model) ? entry.model : imageModels[0]);
1726
2067
  setRefImage(null);
1727
2068
  setImages(restored);
1728
2069
  setError(null);
@@ -1748,10 +2089,73 @@ window.__ModuleLoader__.load({
1748
2089
  setGallery(await api.galleryClear());
1749
2090
  } catch {}
1750
2091
  };
1751
- const generateDisabled = generating || !enabled || !configured;
2092
+ const applyGalleryTags = async () => {
2093
+ const tags = galleryTagInput.split(",").map((tag) => tag.trim()).filter(Boolean);
2094
+ if (tags.length === 0 || selectedGalleryIds.size === 0) return;
2095
+ try {
2096
+ let next = gallery;
2097
+ for (const id of selectedGalleryIds) {
2098
+ const existing = next.find((entry) => entry.id === id)?.tags ?? [];
2099
+ next = await api.gallerySetTags(id, [...existing, ...tags]);
2100
+ }
2101
+ setGallery(next);
2102
+ setGalleryTagInput("");
2103
+ } catch (caught) {
2104
+ setError(errorMessage(caught));
2105
+ }
2106
+ };
2107
+ const startEditingGalleryTags = (entry) => {
2108
+ setEditingGalleryTagsId(entry.id);
2109
+ setGalleryTagEditInput((entry.tags ?? []).join(", "));
2110
+ };
2111
+ const saveGalleryTags = async (id) => {
2112
+ const tags = galleryTagEditInput.split(",").map((tag) => tag.trim()).filter(Boolean);
2113
+ try {
2114
+ setGallery(await api.gallerySetTags(id, tags));
2115
+ setEditingGalleryTagsId(null);
2116
+ setGalleryTagEditInput("");
2117
+ } catch (caught) {
2118
+ setError(errorMessage(caught));
2119
+ }
2120
+ };
2121
+ const toggleGallerySelection = (id) => {
2122
+ setSelectedGalleryIds((previous) => {
2123
+ const next = new Set(previous);
2124
+ if (next.has(id)) next.delete(id);
2125
+ else next.add(id);
2126
+ return next;
2127
+ });
2128
+ };
2129
+ const clearGallerySelection = () => {
2130
+ setSelectedGalleryIds(/* @__PURE__ */ new Set());
2131
+ setGallerySelecting(false);
2132
+ };
2133
+ const exportGalleryJson = () => {
2134
+ const entries = gallery.filter((entry) => selectedGalleryIds.has(entry.id));
2135
+ const blob = new Blob([JSON.stringify(entries, null, 2)], { type: "application/json" });
2136
+ const url = URL.createObjectURL(blob);
2137
+ const anchor = document.createElement("a");
2138
+ anchor.href = url;
2139
+ anchor.download = `dsh-imagegen-gallery-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`;
2140
+ anchor.click();
2141
+ URL.revokeObjectURL(url);
2142
+ };
2143
+ const downloadGalleryImages = () => {
2144
+ gallery.filter((entry) => selectedGalleryIds.has(entry.id)).forEach((entry, index) => {
2145
+ const image = entry.images[0];
2146
+ if (image === void 0) return;
2147
+ const anchor = document.createElement("a");
2148
+ anchor.href = image.url;
2149
+ anchor.download = `dsh-gallery-${index + 1}.${extensionOf(image.mime)}`;
2150
+ anchor.click();
2151
+ });
2152
+ };
2153
+ const generateDisabled = generating;
1752
2154
  const viewingEntry = viewingHistoryId === null ? null : history.find((entry) => entry.id === viewingHistoryId) ?? null;
1753
2155
  const viewingGalleryEntry = galleryViewingId === null ? null : gallery.find((entry) => entry.id === galleryViewingId) ?? null;
1754
2156
  const previewImage = preview === null ? null : preview.images[preview.index] ?? null;
2157
+ const comparisonTasks = comparison === null ? [] : comparison.taskIds.map((id) => tasks.find((task) => task.id === id)).filter((task) => task !== void 0);
2158
+ const comparisonResults = comparisonTasks.filter((task) => task.status === "completed" && task.result !== void 0);
1755
2159
  const previewFrameScale = Math.max(1, previewScale);
1756
2160
  const previewImageScale = previewScale / previewFrameScale;
1757
2161
  const copyPreviewPrompt = async (text) => {
@@ -1864,11 +2268,10 @@ window.__ModuleLoader__.load({
1864
2268
  children: tt("gallery.categories")
1865
2269
  }),
1866
2270
  [
1867
- ["all", "gallery.all"],
1868
- ["text", "mode.text"],
1869
- ["edit", "mode.edit"],
1870
- ["gpt-image-2", "gallery.gpt"],
1871
- ["grok-imagine-image", "gallery.grok"]
2271
+ ["all", tt("gallery.all")],
2272
+ ["text", tt("mode.text")],
2273
+ ["edit", tt("mode.edit")],
2274
+ ...galleryModels.map((value) => [value, value])
1872
2275
  ].map(([value, label]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1873
2276
  type: "button",
1874
2277
  className: panel_module_css_default.galleryFilter,
@@ -1876,7 +2279,7 @@ window.__ModuleLoader__.load({
1876
2279
  onClick: () => {
1877
2280
  setGalleryFilter(value);
1878
2281
  },
1879
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt(label) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2282
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1880
2283
  className: panel_module_css_default.galleryFilterCount,
1881
2284
  children: gallery.filter((entry) => value === "all" || value === "text" || value === "edit" ? value === "all" ? true : entry.mode === value : entry.model === value).length
1882
2285
  })]
@@ -1904,6 +2307,25 @@ window.__ModuleLoader__.load({
1904
2307
  children: ratio === "all" ? tt("gallery.all") : ratio
1905
2308
  }, ratio))
1906
2309
  }),
2310
+ galleryTagOptions.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2311
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: panel_module_css_default.galleryFilterDivider }),
2312
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2313
+ className: panel_module_css_default.galleryFilterHeading,
2314
+ children: tt("gallery.tags")
2315
+ }),
2316
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2317
+ className: panel_module_css_default.galleryTagFilterList,
2318
+ children: galleryTagOptions.map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2319
+ type: "button",
2320
+ className: panel_module_css_default.galleryTagFilter,
2321
+ "data-active": galleryTagFilter === tag ? "" : void 0,
2322
+ onClick: () => {
2323
+ setGalleryTagFilter((previous) => previous === tag ? null : tag);
2324
+ },
2325
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tag }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: gallery.filter((entry) => (entry.tags ?? []).includes(tag)).length })]
2326
+ }, tag))
2327
+ })
2328
+ ] }) : null,
1907
2329
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1908
2330
  className: panel_module_css_default.galleryFilterNote,
1909
2331
  children: tt("gallery.filterHint")
@@ -2028,36 +2450,48 @@ window.__ModuleLoader__.load({
2028
2450
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
2029
2451
  className: panel_module_css_default.prompt,
2030
2452
  value: prompt,
2031
- maxLength: PROMPT_MAX,
2032
2453
  placeholder: tt("prompt.placeholder"),
2033
2454
  onChange: (event) => {
2034
2455
  setPrompt(event.target.value);
2035
2456
  }
2036
2457
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2037
2458
  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", {
2046
- viewBox: "0 0 16 16",
2047
- width: "12",
2048
- height: "12",
2049
- fill: "none",
2050
- stroke: "currentColor",
2051
- strokeWidth: "1.4",
2052
- strokeLinecap: "round",
2053
- strokeLinejoin: "round",
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
- })]
2459
+ children: [
2460
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2461
+ type: "button",
2462
+ className: panel_module_css_default.templatesButton,
2463
+ title: tt("templates.title"),
2464
+ onClick: () => {
2465
+ setLibraryOpen(true);
2466
+ },
2467
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2468
+ viewBox: "0 0 16 16",
2469
+ width: "12",
2470
+ height: "12",
2471
+ fill: "none",
2472
+ stroke: "currentColor",
2473
+ strokeWidth: "1.4",
2474
+ strokeLinecap: "round",
2475
+ strokeLinejoin: "round",
2476
+ "aria-hidden": "true",
2477
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.5 3.5h11M2.5 8h11M2.5 12.5h7" })
2478
+ }), tt("templates.open")]
2479
+ }),
2480
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2481
+ type: "button",
2482
+ className: panel_module_css_default.enhanceButton,
2483
+ disabled: prompt.trim() === "" || enhancing,
2484
+ title: tt("prompt.enhanceHint"),
2485
+ onClick: () => {
2486
+ enhanceCurrentPrompt();
2487
+ },
2488
+ children: enhancing ? tt("prompt.enhancing") : tt("prompt.enhance")
2489
+ }),
2490
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2491
+ className: panel_module_css_default.promptCount,
2492
+ children: tt("prompt.count", { count: prompt.length })
2493
+ })
2494
+ ]
2061
2495
  })]
2062
2496
  }),
2063
2497
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
@@ -2149,67 +2583,94 @@ window.__ModuleLoader__.load({
2149
2583
  }),
2150
2584
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2151
2585
  className: panel_module_css_default.footer,
2152
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2153
- className: panel_module_css_default.modelWrap,
2154
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2155
- className: panel_module_css_default.modelLabel,
2156
- children: tt("model.label")
2157
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2158
- ref: modelMenuRef,
2159
- className: panel_module_css_default.modelMenu,
2160
- "data-open": modelOpen ? "true" : "false",
2161
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2162
- type: "button",
2163
- className: panel_module_css_default.modelSelect,
2164
- disabled: generating,
2165
- "aria-haspopup": "listbox",
2166
- "aria-expanded": modelOpen,
2167
- onClick: () => {
2168
- setModelOpen((open) => !open);
2169
- },
2170
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2171
- viewBox: "0 0 16 16",
2172
- width: "12",
2173
- height: "12",
2174
- fill: "none",
2175
- stroke: "currentColor",
2176
- strokeWidth: "1.6",
2177
- strokeLinecap: "round",
2178
- strokeLinejoin: "round",
2179
- "aria-hidden": "true",
2180
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 10.5L4 6h8z" })
2181
- })]
2182
- }), modelOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2183
- className: panel_module_css_default.modelMenuList,
2184
- role: "listbox",
2185
- "aria-label": tt("model.label"),
2186
- children: MODELS.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2586
+ children: [
2587
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2588
+ className: panel_module_css_default.modelWrap,
2589
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2590
+ className: panel_module_css_default.modelLabel,
2591
+ children: tt("model.label")
2592
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2593
+ ref: modelMenuRef,
2594
+ className: panel_module_css_default.modelMenu,
2595
+ "data-open": modelOpen ? "true" : "false",
2596
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2187
2597
  type: "button",
2188
- role: "option",
2189
- "aria-selected": model === option,
2190
- className: panel_module_css_default.modelMenuItem,
2191
- "data-selected": model === option ? "" : void 0,
2598
+ className: panel_module_css_default.modelSelect,
2599
+ disabled: generating,
2600
+ "aria-haspopup": "listbox",
2601
+ "aria-expanded": modelOpen,
2192
2602
  onClick: () => {
2193
- setModel(option);
2194
- setModelOpen(false);
2603
+ setModelOpen((open) => !open);
2195
2604
  },
2196
- children: option
2197
- }, option))
2605
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
2606
+ viewBox: "0 0 16 16",
2607
+ width: "12",
2608
+ height: "12",
2609
+ fill: "none",
2610
+ stroke: "currentColor",
2611
+ strokeWidth: "1.6",
2612
+ strokeLinecap: "round",
2613
+ strokeLinejoin: "round",
2614
+ "aria-hidden": "true",
2615
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 10.5L4 6h8z" })
2616
+ })]
2617
+ }), modelOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2618
+ className: panel_module_css_default.modelMenuList,
2619
+ role: "listbox",
2620
+ "aria-label": tt("model.label"),
2621
+ children: imageModels.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2622
+ type: "button",
2623
+ role: "option",
2624
+ "aria-selected": model === option,
2625
+ className: panel_module_css_default.modelMenuItem,
2626
+ "data-selected": model === option ? "" : void 0,
2627
+ onClick: () => {
2628
+ setModel(option);
2629
+ setModelOpen(false);
2630
+ },
2631
+ children: option
2632
+ }, option))
2633
+ }) : null]
2634
+ })]
2635
+ }),
2636
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2637
+ className: panel_module_css_default.compareControl,
2638
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2639
+ className: panel_module_css_default.compareToggle,
2640
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2641
+ type: "checkbox",
2642
+ checked: compareEnabled,
2643
+ onChange: (event) => {
2644
+ setCompareEnabled(event.target.checked);
2645
+ }
2646
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt("compare.enable") })]
2647
+ }), compareEnabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2648
+ className: panel_module_css_default.compareModelChoices,
2649
+ role: "group",
2650
+ "aria-label": tt("compare.models"),
2651
+ children: imageModels.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2652
+ type: "checkbox",
2653
+ checked: compareModels.includes(option),
2654
+ onChange: () => {
2655
+ setCompareModels((previous) => previous.includes(option) ? previous.filter((value) => value !== option) : [...previous, option]);
2656
+ }
2657
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: option })] }, option))
2198
2658
  }) : null]
2199
- })]
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
- })]
2659
+ }),
2660
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2661
+ variant: "primary",
2662
+ size: "md",
2663
+ className: panel_module_css_default.generateButton,
2664
+ disabled: generateDisabled,
2665
+ onClick: () => {
2666
+ handleGenerate();
2667
+ },
2668
+ children: generating ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2669
+ className: panel_module_css_default.generateInner,
2670
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: panel_module_css_default.spinner }), tt("generating")]
2671
+ }) : tt("generate")
2672
+ })
2673
+ ]
2213
2674
  })
2214
2675
  ]
2215
2676
  }),
@@ -2219,134 +2680,329 @@ window.__ModuleLoader__.load({
2219
2680
  children: [
2220
2681
  tab === "gallery" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2221
2682
  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", {
2683
+ children: [
2684
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2685
+ className: panel_module_css_default.galleryToolbar,
2686
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
2687
+ className: panel_module_css_default.galleryHeading,
2688
+ children: tt("gallery.all")
2689
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2690
+ className: panel_module_css_default.galleryCount,
2691
+ children: tt("gallery.count", { count: filteredGallery.length })
2692
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2693
+ className: panel_module_css_default.galleryToolbarActions,
2694
+ children: [
2695
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2696
+ className: panel_module_css_default.gallerySearch,
2697
+ value: galleryQuery,
2698
+ onChange: (event) => {
2699
+ setGalleryQuery(event.target.value);
2700
+ },
2701
+ placeholder: tt("gallery.search"),
2702
+ "aria-label": tt("gallery.search")
2703
+ }),
2704
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2238
2705
  type: "button",
2239
- "data-active": galleryView === "masonry" ? "" : void 0,
2706
+ className: panel_module_css_default.gallerySelectMode,
2707
+ "data-active": gallerySelecting ? "" : void 0,
2708
+ "aria-pressed": gallerySelecting,
2240
2709
  onClick: () => {
2241
- setGalleryView("masonry");
2710
+ setGallerySelecting((previous) => !previous);
2242
2711
  },
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", {
2712
+ children: gallerySelecting ? tt("gallery.selectionDone") : tt("gallery.select")
2713
+ }),
2714
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2715
+ className: panel_module_css_default.galleryViewToggle,
2716
+ role: "group",
2717
+ "aria-label": tt("gallery.viewMode"),
2718
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2719
+ type: "button",
2720
+ "data-active": galleryView === "masonry" ? "" : void 0,
2721
+ onClick: () => {
2722
+ setGalleryView("masonry");
2723
+ },
2724
+ title: tt("gallery.masonry"),
2725
+ children: [
2726
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2727
+ "aria-hidden": "true",
2728
+ children: "▦"
2729
+ }),
2730
+ " ",
2731
+ tt("gallery.masonry")
2732
+ ]
2733
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2734
+ type: "button",
2735
+ "data-active": galleryView === "grid" ? "" : void 0,
2736
+ onClick: () => {
2737
+ setGalleryView("grid");
2738
+ },
2739
+ title: tt("gallery.grid"),
2740
+ children: [
2741
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2742
+ "aria-hidden": "true",
2743
+ children: "▤"
2744
+ }),
2745
+ " ",
2746
+ tt("gallery.grid")
2747
+ ]
2748
+ })]
2749
+ }),
2750
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2751
+ className: panel_module_css_default.gallerySort,
2752
+ value: gallerySort,
2753
+ onChange: (event) => {
2754
+ setGallerySort(event.target.value);
2755
+ },
2756
+ "aria-label": tt("gallery.sort"),
2757
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2758
+ value: "newest",
2759
+ children: tt("gallery.newest")
2760
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2761
+ value: "oldest",
2762
+ children: tt("gallery.oldest")
2763
+ })]
2764
+ }),
2765
+ gallery.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2253
2766
  type: "button",
2254
- "data-active": galleryView === "grid" ? "" : void 0,
2767
+ className: panel_module_css_default.galleryClear,
2255
2768
  onClick: () => {
2256
- setGalleryView("grid");
2769
+ clearGalleryAll();
2257
2770
  },
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,
2771
+ children: tt("gallery.clear")
2772
+ }) : null
2773
+ ]
2774
+ })]
2775
+ }),
2776
+ selectedGalleryIds.size > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2777
+ className: panel_module_css_default.gallerySelectionBar,
2778
+ "aria-label": tt("gallery.selected", { count: selectedGalleryIds.size }),
2779
+ children: [
2780
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: tt("gallery.selected", { count: selectedGalleryIds.size }) }),
2781
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2782
+ className: panel_module_css_default.galleryTagInput,
2783
+ value: galleryTagInput,
2272
2784
  onChange: (event) => {
2273
- setGallerySort(event.target.value);
2785
+ setGalleryTagInput(event.target.value);
2274
2786
  },
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
- })]
2787
+ placeholder: tt("gallery.tagsPlaceholder"),
2788
+ "aria-label": tt("gallery.tagsPlaceholder")
2283
2789
  }),
2284
- gallery.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2790
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2285
2791
  type: "button",
2286
- className: panel_module_css_default.galleryClear,
2792
+ className: panel_module_css_default.galleryBulkButton,
2793
+ disabled: galleryTagInput.trim() === "",
2287
2794
  onClick: () => {
2288
- clearGalleryAll();
2795
+ applyGalleryTags();
2289
2796
  },
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", {
2797
+ children: tt("gallery.tagsApply")
2798
+ }),
2799
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2306
2800
  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,
2801
+ className: panel_module_css_default.galleryBulkButton,
2802
+ onClick: downloadGalleryImages,
2803
+ children: tt("gallery.downloadSelected")
2804
+ }),
2805
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2806
+ type: "button",
2807
+ className: panel_module_css_default.galleryBulkButton,
2808
+ onClick: exportGalleryJson,
2809
+ children: tt("gallery.exportJson")
2810
+ }),
2811
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2812
+ type: "button",
2813
+ className: panel_module_css_default.gallerySelectionClear,
2814
+ onClick: clearGallerySelection,
2815
+ children: tt("gallery.selectionClear")
2816
+ })
2817
+ ]
2818
+ }) : null,
2819
+ filteredGallery.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2820
+ className: panel_module_css_default.historyEmpty,
2821
+ children: tt("gallery.empty")
2822
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2823
+ className: panel_module_css_default.galleryMasonry,
2824
+ "data-view": galleryView,
2825
+ children: filteredGallery.map((entry) => {
2826
+ const image = entry.images[0];
2827
+ if (image === void 0) return null;
2828
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
2829
+ className: panel_module_css_default.galleryCard,
2830
+ "data-selected": selectedGalleryIds.has(entry.id) ? "" : void 0,
2322
2831
  children: [
2323
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2324
- className: panel_module_css_default.galleryAvatar,
2325
- children: entry.model.startsWith("grok") ? "G" : "D"
2832
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
2833
+ className: panel_module_css_default.gallerySelect,
2834
+ title: tt("gallery.select"),
2835
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2836
+ type: "checkbox",
2837
+ checked: selectedGalleryIds.has(entry.id),
2838
+ onChange: () => {
2839
+ setGallerySelecting(true);
2840
+ toggleGallerySelection(entry.id);
2841
+ }
2842
+ })
2326
2843
  }),
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", {
2844
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2338
2845
  type: "button",
2339
- className: panel_module_css_default.galleryRemove,
2846
+ className: panel_module_css_default.galleryImageButton,
2847
+ "data-selecting": gallerySelecting ? "" : void 0,
2340
2848
  onClick: () => {
2341
- deleteGalleryEntry(entry.id);
2849
+ if (gallerySelecting) toggleGallerySelection(entry.id);
2850
+ else viewGalleryEntry(entry);
2342
2851
  },
2343
- title: tt("gallery.delete"),
2344
- children: "×"
2345
- })
2852
+ title: gallerySelecting ? tt("gallery.select") : tt("preview.open"),
2853
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
2854
+ className: panel_module_css_default.galleryImage,
2855
+ src: image.url,
2856
+ alt: entry.prompt
2857
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2858
+ className: panel_module_css_default.galleryBadge,
2859
+ children: entry.mode === "edit" ? tt("mode.edit") : tt("mode.text")
2860
+ })]
2861
+ }),
2862
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2863
+ className: panel_module_css_default.galleryCardFooter,
2864
+ children: [
2865
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2866
+ className: panel_module_css_default.galleryAvatar,
2867
+ children: entry.model.startsWith("grok") ? "G" : "D"
2868
+ }),
2869
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2870
+ className: panel_module_css_default.galleryCardInfo,
2871
+ children: [
2872
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: entry.prompt || tt("gallery.untitled") }),
2873
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("small", { children: [
2874
+ entry.model,
2875
+ " · ",
2876
+ normalizeSize(entry.size),
2877
+ " · ",
2878
+ formatTime(entry.createdAt)
2879
+ ] }),
2880
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2881
+ className: panel_module_css_default.galleryTags,
2882
+ children: [(entry.tags ?? []).map((tag) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2883
+ type: "button",
2884
+ onClick: () => {
2885
+ setGalleryTagFilter(tag);
2886
+ },
2887
+ children: tag
2888
+ }, tag)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2889
+ type: "button",
2890
+ className: panel_module_css_default.galleryTagEdit,
2891
+ onClick: () => {
2892
+ startEditingGalleryTags(entry);
2893
+ },
2894
+ title: tt("gallery.editTags"),
2895
+ children: tt("gallery.tagsEditShort")
2896
+ })]
2897
+ })
2898
+ ]
2899
+ }),
2900
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2901
+ type: "button",
2902
+ className: panel_module_css_default.galleryRemove,
2903
+ onClick: () => {
2904
+ deleteGalleryEntry(entry.id);
2905
+ },
2906
+ title: tt("gallery.delete"),
2907
+ children: "×"
2908
+ })
2909
+ ]
2910
+ }),
2911
+ editingGalleryTagsId === entry.id ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
2912
+ className: panel_module_css_default.galleryTagEditor,
2913
+ onSubmit: (event) => {
2914
+ event.preventDefault();
2915
+ saveGalleryTags(entry.id);
2916
+ },
2917
+ children: [
2918
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2919
+ value: galleryTagEditInput,
2920
+ onChange: (event) => {
2921
+ setGalleryTagEditInput(event.target.value);
2922
+ },
2923
+ placeholder: tt("gallery.tagsPlaceholder"),
2924
+ "aria-label": tt("gallery.tagsPlaceholder"),
2925
+ autoFocus: true
2926
+ }),
2927
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2928
+ type: "submit",
2929
+ children: tt("gallery.tagsSave")
2930
+ }),
2931
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2932
+ type: "button",
2933
+ onClick: () => {
2934
+ setEditingGalleryTagsId(null);
2935
+ setGalleryTagEditInput("");
2936
+ },
2937
+ children: tt("gallery.tagsCancel")
2938
+ })
2939
+ ]
2940
+ }) : null
2346
2941
  ]
2347
- })]
2348
- }, entry.id);
2942
+ }, entry.id);
2943
+ })
2349
2944
  })
2945
+ ]
2946
+ }) : null,
2947
+ tab !== "gallery" && tasks.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2948
+ className: panel_module_css_default.taskTray,
2949
+ "aria-label": tt("tasks.title"),
2950
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2951
+ className: panel_module_css_default.taskTrayHeader,
2952
+ children: [
2953
+ tt("tasks.title"),
2954
+ " ",
2955
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tasks.filter((task) => task.status === "queued" || task.status === "running").length })
2956
+ ]
2957
+ }), tasks.slice(0, 5).map((task) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2958
+ className: panel_module_css_default.taskRow,
2959
+ "data-status": task.status,
2960
+ children: [
2961
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2962
+ className: panel_module_css_default.taskStatus,
2963
+ children: tt(`tasks.${task.status}`)
2964
+ }),
2965
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2966
+ className: panel_module_css_default.taskPrompt,
2967
+ children: task.request.prompt
2968
+ }),
2969
+ task.status === "queued" || task.status === "running" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2970
+ type: "button",
2971
+ onClick: () => {
2972
+ api.taskCancel(task.id);
2973
+ },
2974
+ children: tt("tasks.cancel")
2975
+ }) : null,
2976
+ task.status === "failed" || task.status === "cancelled" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2977
+ type: "button",
2978
+ onClick: () => {
2979
+ api.taskRetry(task.id);
2980
+ },
2981
+ children: tt("tasks.retry")
2982
+ }) : null
2983
+ ]
2984
+ }, task.id))]
2985
+ }) : null,
2986
+ tab !== "gallery" && comparison !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
2987
+ className: panel_module_css_default.comparisonBoard,
2988
+ "aria-label": tt("compare.title"),
2989
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: tt("compare.title") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
2990
+ comparisonResults.length,
2991
+ " / ",
2992
+ comparisonTasks.length
2993
+ ] })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2994
+ type: "button",
2995
+ disabled: comparisonResults.length === 0,
2996
+ onClick: () => {
2997
+ setComparisonFullscreen(true);
2998
+ },
2999
+ children: tt("compare.fullscreen")
3000
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3001
+ className: panel_module_css_default.comparisonGrid,
3002
+ children: comparisonTasks.map((task) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: task.request.model }), task.result?.images[0] !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
3003
+ src: srcOf(task.result.images[0]),
3004
+ alt: task.request.model
3005
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt(`tasks.${task.status}`) })] }, task.id))
2350
3006
  })]
2351
3007
  }) : null,
2352
3008
  generating ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -2571,101 +3227,146 @@ window.__ModuleLoader__.load({
2571
3227
  children: tt("history.restore")
2572
3228
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2573
3229
  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", {
2585
- className: panel_module_css_default.history,
2586
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
2587
- className: panel_module_css_default.historyHeader,
2588
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2589
- className: panel_module_css_default.historyTitle,
2590
- children: tt("history.title")
2591
- }), history.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2592
- type: "button",
2593
- className: panel_module_css_default.historyClear,
2594
- onClick: () => {
2595
- clearHistory();
2596
- },
2597
- children: tt("history.clear")
2598
- }) : null]
2599
- }), history.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2600
- className: panel_module_css_default.historyEmpty,
2601
- children: tt("history.empty")
2602
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2603
- className: panel_module_css_default.historyList,
2604
- children: history.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2605
- className: panel_module_css_default.historyItem,
2606
- "data-active": entry.id === viewingHistoryId ? "" : void 0,
2607
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2608
- type: "button",
2609
- className: panel_module_css_default.historyMain,
2610
- onClick: () => {
2611
- viewHistoryEntry(entry);
2612
- },
2613
- children: [entry.images.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
2614
- className: panel_module_css_default.historyThumb,
2615
- src: entry.images[0].url,
2616
- alt: ""
2617
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: panel_module_css_default.historyThumbPlaceholder }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2618
- className: panel_module_css_default.historyInfo,
2619
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2620
- className: panel_module_css_default.historyPrompt,
2621
- children: entry.prompt
2622
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2623
- className: panel_module_css_default.historyMeta,
2624
- children: [
2625
- tt(`mode.${entry.mode === "edit" ? "edit" : "text"}`),
2626
- " · ",
2627
- formatTime(entry.createdAt),
2628
- " · ",
2629
- entry.images.length,
2630
- " ",
2631
- tt("history.images")
2632
- ]
2633
- })]
2634
- })]
2635
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2636
- className: panel_module_css_default.historyActions,
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
- ]
3230
+ className: panel_module_css_default.historyAction,
3231
+ "data-danger": true,
3232
+ onClick: () => {
3233
+ deleteGalleryEntry(entry.id);
3234
+ },
3235
+ children: tt("gallery.delete")
3236
+ })]
2666
3237
  })]
2667
3238
  }, entry.id))
2668
3239
  })]
3240
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("aside", {
3241
+ className: panel_module_css_default.history,
3242
+ children: [
3243
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
3244
+ className: panel_module_css_default.historyHeader,
3245
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3246
+ className: panel_module_css_default.historyTitle,
3247
+ children: tt("history.title")
3248
+ }), history.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3249
+ type: "button",
3250
+ className: panel_module_css_default.historyClear,
3251
+ onClick: () => {
3252
+ clearHistory();
3253
+ },
3254
+ children: tt("history.clear")
3255
+ }) : null]
3256
+ }),
3257
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3258
+ className: panel_module_css_default.historyFilters,
3259
+ children: [
3260
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3261
+ className: panel_module_css_default.historySearch,
3262
+ value: historyQuery,
3263
+ onChange: (event) => {
3264
+ setHistoryQuery(event.target.value);
3265
+ },
3266
+ placeholder: tt("history.search"),
3267
+ "aria-label": tt("history.search")
3268
+ }),
3269
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3270
+ value: historyModelFilter,
3271
+ onChange: (event) => {
3272
+ setHistoryModelFilter(event.target.value);
3273
+ },
3274
+ "aria-label": tt("history.model"),
3275
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3276
+ value: "all",
3277
+ children: tt("history.allModels")
3278
+ }), [...new Set(history.map((entry) => entry.model))].map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3279
+ value: option,
3280
+ children: option
3281
+ }, option))]
3282
+ }),
3283
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3284
+ value: historyRatioFilter,
3285
+ onChange: (event) => {
3286
+ setHistoryRatioFilter(event.target.value);
3287
+ },
3288
+ "aria-label": tt("history.ratio"),
3289
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3290
+ value: "all",
3291
+ children: tt("history.allRatios")
3292
+ }), [...new Set(history.map((entry) => normalizeSize(entry.size)))].map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3293
+ value: option,
3294
+ children: option
3295
+ }, option))]
3296
+ })
3297
+ ]
3298
+ }),
3299
+ filteredHistory.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3300
+ className: panel_module_css_default.historyEmpty,
3301
+ children: tt("history.empty")
3302
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3303
+ className: panel_module_css_default.historyList,
3304
+ children: filteredHistory.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3305
+ className: panel_module_css_default.historyItem,
3306
+ "data-active": entry.id === viewingHistoryId ? "" : void 0,
3307
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3308
+ type: "button",
3309
+ className: panel_module_css_default.historyMain,
3310
+ onClick: () => {
3311
+ viewHistoryEntry(entry);
3312
+ },
3313
+ children: [entry.images.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
3314
+ className: panel_module_css_default.historyThumb,
3315
+ src: entry.images[0].url,
3316
+ alt: ""
3317
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: panel_module_css_default.historyThumbPlaceholder }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3318
+ className: panel_module_css_default.historyInfo,
3319
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3320
+ className: panel_module_css_default.historyPrompt,
3321
+ children: entry.prompt
3322
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3323
+ className: panel_module_css_default.historyMeta,
3324
+ children: [
3325
+ tt(`mode.${entry.mode === "edit" ? "edit" : "text"}`),
3326
+ " · ",
3327
+ formatTime(entry.createdAt),
3328
+ " · ",
3329
+ entry.images.length,
3330
+ " ",
3331
+ tt("history.images")
3332
+ ]
3333
+ })]
3334
+ })]
3335
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3336
+ className: panel_module_css_default.historyActions,
3337
+ children: [
3338
+ entry.images.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3339
+ type: "button",
3340
+ className: panel_module_css_default.historyAction,
3341
+ disabled: galleryAdding,
3342
+ title: tt("gallery.add"),
3343
+ onClick: () => {
3344
+ addHistoryEntryToGallery(entry);
3345
+ },
3346
+ children: tt("gallery.add")
3347
+ }) : null,
3348
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3349
+ type: "button",
3350
+ className: panel_module_css_default.historyAction,
3351
+ onClick: () => {
3352
+ restoreHistoryEntry(entry);
3353
+ },
3354
+ children: tt("history.restore")
3355
+ }),
3356
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3357
+ type: "button",
3358
+ className: panel_module_css_default.historyAction,
3359
+ "data-danger": true,
3360
+ onClick: () => {
3361
+ deleteHistoryEntry(entry.id);
3362
+ },
3363
+ children: tt("history.delete")
3364
+ })
3365
+ ]
3366
+ })]
3367
+ }, entry.id))
3368
+ })
3369
+ ]
2669
3370
  })
2670
3371
  ]
2671
3372
  }),
@@ -2681,6 +3382,53 @@ window.__ModuleLoader__.load({
2681
3382
  setLibraryOpen(false);
2682
3383
  }
2683
3384
  }) : null,
3385
+ configGuide !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3386
+ className: panel_module_css_default.configGuide,
3387
+ role: "dialog",
3388
+ "aria-modal": "true",
3389
+ "aria-label": tt(`config.${configGuide}Title`),
3390
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3391
+ className: panel_module_css_default.configGuideBody,
3392
+ children: [
3393
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: tt(`config.${configGuide}Title`) }),
3394
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tt(`config.${configGuide}Hint`) }),
3395
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3396
+ type: "button",
3397
+ onClick: () => {
3398
+ setConfigGuide(null);
3399
+ },
3400
+ children: tt("preview.close")
3401
+ })
3402
+ ]
3403
+ })
3404
+ }) : null,
3405
+ comparisonFullscreen && comparison !== null ? (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3406
+ className: panel_module_css_default.comparisonFullscreen,
3407
+ role: "dialog",
3408
+ "aria-modal": "true",
3409
+ "aria-label": tt("compare.title"),
3410
+ onClick: () => {
3411
+ setComparisonFullscreen(false);
3412
+ },
3413
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3414
+ type: "button",
3415
+ className: panel_module_css_default.lightboxClose,
3416
+ "aria-label": tt("preview.close"),
3417
+ onClick: () => {
3418
+ setComparisonFullscreen(false);
3419
+ },
3420
+ children: "×"
3421
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3422
+ className: panel_module_css_default.comparisonFullscreenGrid,
3423
+ onClick: (event) => {
3424
+ event.stopPropagation();
3425
+ },
3426
+ children: comparisonResults.map((task) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("figure", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("figcaption", { children: task.request.model }), task.result.images.map((image, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
3427
+ src: srcOf(image),
3428
+ alt: task.request.model
3429
+ }, index))] }, task.id))
3430
+ })]
3431
+ }), document.body) : null,
2684
3432
  preview !== null && previewImage !== null ? (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2685
3433
  className: panel_module_css_default.lightbox,
2686
3434
  role: "dialog",
@@ -3192,6 +3940,20 @@ window.__ModuleLoader__.load({
3192
3940
  }
3193
3941
  };
3194
3942
  }
3943
+ /** A newline/comma-separated model list, persisted as a normalized string array. */
3944
+ function stringListField(field) {
3945
+ return {
3946
+ field,
3947
+ format: (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string").join("\n") : "",
3948
+ parse: (text) => {
3949
+ const values = [...new Set(text.split(/[\n,]/).map((item) => item.trim()).filter(Boolean))];
3950
+ return values.length === 0 ? { kind: "clear" } : {
3951
+ kind: "set",
3952
+ value: values
3953
+ };
3954
+ }
3955
+ };
3956
+ }
3195
3957
  /** A boolean field, edited through true/false draft text. */
3196
3958
  function booleanField(field) {
3197
3959
  return {
@@ -3421,7 +4183,7 @@ window.__ModuleLoader__.load({
3421
4183
  };
3422
4184
  //#endregion
3423
4185
  //#region \0dsh-css:E:\dsh-plugin\src\client\settings-card.module.css.mjs
3424
- const css = ".i1cc5G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.i1cc5G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.i1cc5G_card:has(.i1cc5G_body){background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.i1cc5G_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.i1cc5G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.i1cc5G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.i1cc5G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.i1cc5G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.i1cc5G_chevron,.i1cc5G_chevronOpen{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.i1cc5G_chevronOpen{transform:rotate(180deg)}.i1cc5G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.i1cc5G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.i1cc5G_versionRow{border-bottom:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.i1cc5G_versionLabel{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}.i1cc5G_versionValue{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-family-mono,monospace);border-radius:999px;padding:1px 8px;font-size:12px;line-height:1.5}.i1cc5G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.i1cc5G_field+.i1cc5G_field{border-top:1px solid var(--dsw-alias-border-l2)}.i1cc5G_head{align-items:center;gap:8px;display:flex}.i1cc5G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.i1cc5G_badges{align-items:center;gap:8px;display:inline-flex}.i1cc5G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.i1cc5G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.i1cc5G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.i1cc5G_reset:disabled{cursor:default;opacity:.5}.i1cc5G_input,.i1cc5G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;outline:none;padding:0 12px;font-size:13px;line-height:1.5}.i1cc5G_input:focus-visible,.i1cc5G_select:focus-visible{border-color:var(--dsw-alias-brand-primary)}.i1cc5G_input:disabled,.i1cc5G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.i1cc5G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;outline:none;padding:0 12px;font-size:13px;line-height:1.5}.i1cc5G_hint,.i1cc5G_invalid{margin:0;font-size:12px;line-height:1.5}.i1cc5G_hint{color:var(--dsw-alias-label-tertiary)}.i1cc5G_invalid{color:var(--dsw-alias-label-error)}.i1cc5G_readOnly,.i1cc5G_notExposed{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.i1cc5G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.i1cc5G_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.i1cc5G_discard,.i1cc5G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.i1cc5G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.i1cc5G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.i1cc5G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.i1cc5G_discard:disabled,.i1cc5G_save:disabled{opacity:.4;cursor:default}.i1cc5G_discard:focus-visible,.i1cc5G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}@media (prefers-reduced-motion:reduce){.i1cc5G_card,.i1cc5G_chevron,.i1cc5G_chevronOpen{transition:none}}";
4186
+ const css = ".i1cc5G_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;transition:border-color .16s,background .16s}.i1cc5G_card:hover{border-color:var(--dsw-alias-label-dimmed)}.i1cc5G_card:has(.i1cc5G_body){background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.i1cc5G_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.i1cc5G_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.i1cc5G_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.i1cc5G_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.i1cc5G_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.i1cc5G_chevron,.i1cc5G_chevronOpen{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.i1cc5G_chevronOpen{transform:rotate(180deg)}.i1cc5G_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.i1cc5G_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.i1cc5G_versionRow{border-bottom:1px solid var(--dsw-alias-border-l2);justify-content:space-between;align-items:center;gap:12px;padding:12px 0;display:flex}.i1cc5G_versionLabel{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}.i1cc5G_versionValue{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-family-mono,monospace);border-radius:999px;padding:1px 8px;font-size:12px;line-height:1.5}.i1cc5G_field{flex-direction:column;gap:6px;padding:12px 0;display:flex}.i1cc5G_field+.i1cc5G_field{border-top:1px solid var(--dsw-alias-border-l2)}.i1cc5G_head{align-items:center;gap:8px;display:flex}.i1cc5G_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.i1cc5G_badges{align-items:center;gap:8px;display:inline-flex}.i1cc5G_badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.i1cc5G_reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}.i1cc5G_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.i1cc5G_reset:disabled{cursor:default;opacity:.5}.i1cc5G_input,.i1cc5G_select{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;outline:none;padding:0 12px;font-size:13px;line-height:1.5}.i1cc5G_input:focus-visible,.i1cc5G_select:focus-visible{border-color:var(--dsw-alias-brand-primary)}.i1cc5G_input:disabled,.i1cc5G_select:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.i1cc5G_inputInvalid{border:1px solid var(--dsw-alias-label-error);background:var(--dsw-alias-bg-layer-3);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;outline:none;padding:0 12px;font-size:13px;line-height:1.5}.i1cc5G_textarea,.i1cc5G_textareaInvalid{resize:vertical;background:var(--dsw-alias-bg-layer-3);min-height:70px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;outline:none;padding:8px 12px;font-size:13px;line-height:1.5}.i1cc5G_textarea{border:1px solid var(--dsw-alias-border-l2)}.i1cc5G_textareaInvalid{border:1px solid var(--dsw-alias-label-error)}.i1cc5G_textarea:focus-visible{border-color:var(--dsw-alias-brand-primary)}.i1cc5G_textarea:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.i1cc5G_hint,.i1cc5G_invalid{margin:0;font-size:12px;line-height:1.5}.i1cc5G_hint{color:var(--dsw-alias-label-tertiary)}.i1cc5G_invalid{color:var(--dsw-alias-label-error)}.i1cc5G_readOnly,.i1cc5G_notExposed{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.i1cc5G_sectionDivider{background:var(--dsw-alias-border-l2);height:1px;margin:18px 0 14px}.i1cc5G_sectionTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:14px;line-height:1.4}.i1cc5G_sectionHint{color:var(--dsw-alias-label-tertiary);margin:-4px 0 2px;font-size:12px;line-height:1.5}.i1cc5G_modelSection{padding:2px 0 14px}.i1cc5G_sectionHeader{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.i1cc5G_sectionHeader .i1cc5G_sectionHint{max-width:430px}.i1cc5G_modelSummary{flex-wrap:wrap;align-items:center;gap:6px;margin-top:12px;display:flex}.i1cc5G_modelChip{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);max-width:100%;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family-mono,monospace);border-radius:6px;align-items:center;gap:5px;padding:3px 5px 3px 8px;font-size:12px;line-height:1.5;display:inline-flex}.i1cc5G_modelChip>span{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.i1cc5G_modelChip button{appearance:none;width:18px;height:18px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:0;border-radius:4px;padding:0;line-height:18px}.i1cc5G_modelChip button:hover:not(:disabled){color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-module-platform)}.i1cc5G_modelChip button:disabled{cursor:default;opacity:.45}.i1cc5G_addModel{appearance:none;border:1px dashed var(--dsw-alias-border-l2);min-height:28px;color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border-radius:6px;padding:0 9px;font-size:12px}.i1cc5G_addModel:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.i1cc5G_addModel:disabled{opacity:.45;cursor:default}.i1cc5G_manualModelRow{gap:8px;margin-top:10px;display:flex}.i1cc5G_manualModelRow .i1cc5G_input{flex:1;min-width:0}.i1cc5G_disclosure{appearance:none;border:0;border-top:1px solid var(--dsw-alias-border-l2);width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;align-items:center;gap:8px;padding:13px 0;font-size:13px;font-weight:500;display:flex}.i1cc5G_disclosure>span:nth-child(2){color:var(--dsw-alias-label-tertiary);margin-left:auto;font-size:12px;font-weight:400}.i1cc5G_disclosure>span:last-child{color:var(--dsw-alias-label-tertiary)}.i1cc5G_disclosure:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.i1cc5G_optionalContent{padding:0 0 8px}.i1cc5G_inlineDisclosure{appearance:none;color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border:0;align-items:center;gap:6px;margin-top:12px;padding:0;font-size:12px;display:inline-flex}.i1cc5G_inlineDisclosure:hover{color:var(--dsw-alias-label-primary)}.i1cc5G_modelFetchRow{align-items:center;gap:8px;display:flex}.i1cc5G_modelFetch,.i1cc5G_modelChoices{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);min-height:32px;color:var(--dsw-alias-label-secondary);font:inherit;border-radius:7px;font-size:12px}.i1cc5G_modelFetch{cursor:pointer;padding:0 10px}.i1cc5G_modelFetch:hover:not(:disabled){color:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}.i1cc5G_modelFetch:disabled{opacity:.5;cursor:default}.i1cc5G_modelChoices{flex:1;min-width:0;padding:0 8px}.i1cc5G_modelCandidateList{flex-wrap:wrap;gap:6px 10px;margin-top:10px;display:flex}.i1cc5G_modelCandidateLabel{width:100%;color:var(--dsw-alias-label-tertiary);font-size:12px}.i1cc5G_modelCandidate{appearance:none;min-width:0;color:var(--dsw-alias-label-secondary);cursor:pointer;background:var(--dsw-alias-bg-layer-3);font-size:12px;line-height:1.5;font:inherit;border:1px solid #0000;border-radius:5px;align-items:center;gap:5px;padding:3px 6px;display:inline-flex}.i1cc5G_modelCandidate input{margin:0}.i1cc5G_modelCandidate[data-selected]{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary)}.i1cc5G_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.i1cc5G_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.i1cc5G_discard,.i1cc5G_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.i1cc5G_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.i1cc5G_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.i1cc5G_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.i1cc5G_discard:disabled,.i1cc5G_save:disabled{opacity:.4;cursor:default}.i1cc5G_discard:focus-visible,.i1cc5G_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}@media (prefers-reduced-motion:reduce){.i1cc5G_card,.i1cc5G_chevron,.i1cc5G_chevronOpen{transition:none}}";
3425
4187
  const tagId = "@dickpy/dsh-imagegen/settings-card.module.css";
3426
4188
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
3427
4189
  const tag = document.createElement("style");
@@ -3431,35 +4193,55 @@ window.__ModuleLoader__.load({
3431
4193
  document.head.appendChild(tag);
3432
4194
  }
3433
4195
  var settings_card_module_css_default = {
3434
- "headText": "i1cc5G_headText",
4196
+ "manualModelRow": "i1cc5G_manualModelRow",
4197
+ "modelFetchRow": "i1cc5G_modelFetchRow",
4198
+ "modelFetch": "i1cc5G_modelFetch",
4199
+ "chevronOpen": "i1cc5G_chevronOpen",
3435
4200
  "name": "i1cc5G_name",
3436
- "readOnly": "i1cc5G_readOnly",
4201
+ "badges": "i1cc5G_badges",
4202
+ "textarea": "i1cc5G_textarea",
3437
4203
  "input": "i1cc5G_input",
3438
- "footer": "i1cc5G_footer",
3439
- "versionValue": "i1cc5G_versionValue",
3440
- "reset": "i1cc5G_reset",
3441
- "select": "i1cc5G_select",
3442
- "field": "i1cc5G_field",
3443
- "body": "i1cc5G_body",
3444
- "chevron": "i1cc5G_chevron",
3445
- "pending": "i1cc5G_pending",
3446
- "save": "i1cc5G_save",
3447
- "card": "i1cc5G_card",
4204
+ "sectionHint": "i1cc5G_sectionHint",
4205
+ "modelSection": "i1cc5G_modelSection",
4206
+ "sectionDivider": "i1cc5G_sectionDivider",
4207
+ "optionalContent": "i1cc5G_optionalContent",
3448
4208
  "head": "i1cc5G_head",
4209
+ "select": "i1cc5G_select",
4210
+ "sectionTitle": "i1cc5G_sectionTitle",
4211
+ "label": "i1cc5G_label",
3449
4212
  "failed": "i1cc5G_failed",
4213
+ "addModel": "i1cc5G_addModel",
3450
4214
  "versionRow": "i1cc5G_versionRow",
3451
- "badge": "i1cc5G_badge",
4215
+ "discard": "i1cc5G_discard",
4216
+ "reset": "i1cc5G_reset",
4217
+ "field": "i1cc5G_field",
3452
4218
  "hint": "i1cc5G_hint",
3453
- "header": "i1cc5G_header",
3454
- "versionLabel": "i1cc5G_versionLabel",
3455
- "label": "i1cc5G_label",
4219
+ "modelCandidate": "i1cc5G_modelCandidate",
4220
+ "save": "i1cc5G_save",
4221
+ "description": "i1cc5G_description",
4222
+ "chevron": "i1cc5G_chevron",
4223
+ "headText": "i1cc5G_headText",
4224
+ "card": "i1cc5G_card",
4225
+ "modelCandidateLabel": "i1cc5G_modelCandidateLabel",
4226
+ "footer": "i1cc5G_footer",
4227
+ "modelSummary": "i1cc5G_modelSummary",
4228
+ "modelChoices": "i1cc5G_modelChoices",
4229
+ "notExposed": "i1cc5G_notExposed",
4230
+ "modelCandidateList": "i1cc5G_modelCandidateList",
4231
+ "pending": "i1cc5G_pending",
3456
4232
  "invalid": "i1cc5G_invalid",
3457
4233
  "inputInvalid": "i1cc5G_inputInvalid",
3458
- "chevronOpen": "i1cc5G_chevronOpen",
3459
- "notExposed": "i1cc5G_notExposed",
3460
- "badges": "i1cc5G_badges",
3461
- "description": "i1cc5G_description",
3462
- "discard": "i1cc5G_discard"
4234
+ "body": "i1cc5G_body",
4235
+ "disclosure": "i1cc5G_disclosure",
4236
+ "readOnly": "i1cc5G_readOnly",
4237
+ "versionLabel": "i1cc5G_versionLabel",
4238
+ "badge": "i1cc5G_badge",
4239
+ "versionValue": "i1cc5G_versionValue",
4240
+ "sectionHeader": "i1cc5G_sectionHeader",
4241
+ "header": "i1cc5G_header",
4242
+ "modelChip": "i1cc5G_modelChip",
4243
+ "textareaInvalid": "i1cc5G_textareaInvalid",
4244
+ "inlineDisclosure": "i1cc5G_inlineDisclosure"
3463
4245
  };
3464
4246
  //#endregion
3465
4247
  //#region src/client/SettingsCard.tsx
@@ -3480,8 +4262,13 @@ window.__ModuleLoader__.load({
3480
4262
  this.form = new CardForm(scope, [
3481
4263
  booleanField("enabled"),
3482
4264
  booleanField("announceToAgent"),
4265
+ booleanField("allowAgentImageGeneration"),
3483
4266
  textField("apiUrl"),
3484
- secretField("apiKey")
4267
+ secretField("apiKey"),
4268
+ stringListField("imageModels"),
4269
+ textField("promptApiUrl"),
4270
+ secretField("promptApiKey"),
4271
+ textField("promptModel")
3485
4272
  ], { secretSettled: () => this.scope.getKeySetSnapshot() });
3486
4273
  }
3487
4274
  projection() {
@@ -3489,8 +4276,13 @@ window.__ModuleLoader__.load({
3489
4276
  ...this.form.shell(),
3490
4277
  enabled: this.form.field("enabled"),
3491
4278
  announceToAgent: this.form.field("announceToAgent"),
4279
+ allowAgentImageGeneration: this.form.field("allowAgentImageGeneration"),
3492
4280
  apiUrl: this.form.field("apiUrl"),
3493
- apiKey: this.form.field("apiKey")
4281
+ apiKey: this.form.field("apiKey"),
4282
+ imageModels: this.form.field("imageModels"),
4283
+ promptApiUrl: this.form.field("promptApiUrl"),
4284
+ promptApiKey: this.form.field("promptApiKey"),
4285
+ promptModel: this.form.field("promptModel")
3494
4286
  };
3495
4287
  }
3496
4288
  /**
@@ -3522,6 +4314,19 @@ window.__ModuleLoader__.load({
3522
4314
  const state = props.useImageGenSettingsCard((snapshot) => snapshot);
3523
4315
  const keySet = props.useImageGenKeySet((snapshot) => snapshot);
3524
4316
  const [open, setOpen] = (0, react.useState)(false);
4317
+ const [promptModels, setPromptModels] = (0, react.useState)([]);
4318
+ const [loadingPromptModels, setLoadingPromptModels] = (0, react.useState)(false);
4319
+ const [promptModelsError, setPromptModelsError] = (0, react.useState)(null);
4320
+ const [imageModelCandidates, setImageModelCandidates] = (0, react.useState)([]);
4321
+ const [loadingImageModels, setLoadingImageModels] = (0, react.useState)(false);
4322
+ const [imageModelsError, setImageModelsError] = (0, react.useState)(null);
4323
+ const [manualModelsOpen, setManualModelsOpen] = (0, react.useState)(false);
4324
+ const [manualModel, setManualModel] = (0, react.useState)("");
4325
+ const [enhancementOpen, setEnhancementOpen] = (0, react.useState)(false);
4326
+ const [manualPromptModelOpen, setManualPromptModelOpen] = (0, react.useState)(false);
4327
+ const [manualPromptModel, setManualPromptModel] = (0, react.useState)("");
4328
+ const [promptApiOpen, setPromptApiOpen] = (0, react.useState)(false);
4329
+ const [moreOpen, setMoreOpen] = (0, react.useState)(false);
3525
4330
  if (!state.available) return null;
3526
4331
  const title = t("settings.title");
3527
4332
  const blocked = !state.dirty || state.invalid || state.saving;
@@ -3602,15 +4407,19 @@ window.__ModuleLoader__.load({
3602
4407
  role: "status",
3603
4408
  children: t("settings.readOnly")
3604
4409
  }) : null,
3605
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3606
- className: settings_card_module_css_default.versionRow,
3607
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3608
- className: settings_card_module_css_default.versionLabel,
3609
- children: t("settings.currentVersion")
3610
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("code", {
3611
- className: settings_card_module_css_default.versionValue,
3612
- children: ["v", PLUGIN_VERSION]
3613
- })]
4410
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
4411
+ id: "dsh-imagegen-settings-apiurl",
4412
+ label: t("settings.apiUrl"),
4413
+ hint: t("settings.apiUrlHint"),
4414
+ placeholder: "https://api.openai.com/v1",
4415
+ ...fieldProps,
4416
+ ...state.apiUrl,
4417
+ onEdit: (text) => {
4418
+ props.edit("apiUrl", text);
4419
+ },
4420
+ onReset: () => {
4421
+ props.resetField("apiUrl");
4422
+ }
3614
4423
  }),
3615
4424
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
3616
4425
  id: "dsh-imagegen-settings-apikey",
@@ -3633,52 +4442,355 @@ window.__ModuleLoader__.load({
3633
4442
  },
3634
4443
  canClear: keySet
3635
4444
  }),
3636
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
3637
- id: "dsh-imagegen-settings-apiurl",
3638
- label: t("settings.apiUrl"),
3639
- hint: t("settings.apiUrlHint"),
3640
- placeholder: "https://api.openai.com/v1",
3641
- ...fieldProps,
3642
- ...state.apiUrl,
3643
- onEdit: (text) => {
3644
- props.edit("apiUrl", text);
3645
- },
3646
- onReset: () => {
3647
- props.resetField("apiUrl");
3648
- }
4445
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: settings_card_module_css_default.sectionDivider }),
4446
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4447
+ className: settings_card_module_css_default.modelSection,
4448
+ "aria-label": t("settings.imageModelsTitle"),
4449
+ children: [
4450
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4451
+ className: settings_card_module_css_default.sectionHeader,
4452
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
4453
+ className: settings_card_module_css_default.sectionTitle,
4454
+ children: t("settings.imageModelsTitle")
4455
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4456
+ className: settings_card_module_css_default.sectionHint,
4457
+ children: t("settings.imageModelsHint")
4458
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4459
+ type: "button",
4460
+ className: settings_card_module_css_default.modelFetch,
4461
+ disabled: disabled || loadingImageModels,
4462
+ onClick: () => {
4463
+ setLoadingImageModels(true);
4464
+ setImageModelsError(null);
4465
+ fetch(IMAGE_MODEL_API.models, { method: "POST" }).then(async (response) => {
4466
+ const body = await response.json();
4467
+ if (!response.ok || body.ok !== true) throw new Error(body.message ?? `HTTP ${response.status}`);
4468
+ setImageModelCandidates(body.models ?? []);
4469
+ }).catch((error) => {
4470
+ setImageModelsError(error instanceof Error ? error.message : String(error));
4471
+ }).finally(() => {
4472
+ setLoadingImageModels(false);
4473
+ });
4474
+ },
4475
+ children: loadingImageModels ? t("settings.imageModelsLoading") : t("settings.imageModelsFetch")
4476
+ })]
4477
+ }),
4478
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4479
+ className: settings_card_module_css_default.modelSummary,
4480
+ children: [splitModels(state.imageModels.text).map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4481
+ className: settings_card_module_css_default.modelChip,
4482
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4483
+ type: "button",
4484
+ disabled,
4485
+ "aria-label": `${t("settings.removeModel")}: ${model}`,
4486
+ onClick: () => {
4487
+ props.edit("imageModels", splitModels(state.imageModels.text).filter((value) => value !== model).join("\n"));
4488
+ },
4489
+ children: "×"
4490
+ })]
4491
+ }, model)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4492
+ type: "button",
4493
+ className: settings_card_module_css_default.addModel,
4494
+ disabled,
4495
+ onClick: () => {
4496
+ setManualModelsOpen((open) => !open);
4497
+ },
4498
+ children: manualModelsOpen ? t("settings.cancelAddModel") : t("settings.addModel")
4499
+ })]
4500
+ }),
4501
+ manualModelsOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4502
+ className: settings_card_module_css_default.manualModelRow,
4503
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4504
+ className: settings_card_module_css_default.input,
4505
+ value: manualModel,
4506
+ placeholder: t("settings.addModelPlaceholder"),
4507
+ disabled,
4508
+ onChange: (event) => {
4509
+ setManualModel(event.target.value);
4510
+ },
4511
+ onKeyDown: (event) => {
4512
+ if (event.key !== "Enter") return;
4513
+ event.preventDefault();
4514
+ const next = manualModel.trim();
4515
+ if (next === "") return;
4516
+ props.edit("imageModels", [...splitModels(state.imageModels.text), next].join("\n"));
4517
+ setManualModel("");
4518
+ }
4519
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4520
+ type: "button",
4521
+ className: settings_card_module_css_default.addModel,
4522
+ disabled: disabled || manualModel.trim() === "",
4523
+ onClick: () => {
4524
+ props.edit("imageModels", [...splitModels(state.imageModels.text), manualModel.trim()].join("\n"));
4525
+ setManualModel("");
4526
+ },
4527
+ children: t("settings.addModelConfirm")
4528
+ })]
4529
+ }) : null,
4530
+ imageModelCandidates.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4531
+ className: settings_card_module_css_default.modelCandidateList,
4532
+ role: "group",
4533
+ "aria-label": t("settings.imageModelsCandidates"),
4534
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4535
+ className: settings_card_module_css_default.modelCandidateLabel,
4536
+ children: t("settings.imageModelsCandidates")
4537
+ }), imageModelCandidates.map((candidate) => {
4538
+ const selected = splitModels(state.imageModels.text).includes(candidate);
4539
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
4540
+ className: settings_card_module_css_default.modelCandidate,
4541
+ "data-selected": selected ? "" : void 0,
4542
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4543
+ type: "checkbox",
4544
+ checked: selected,
4545
+ disabled,
4546
+ onChange: () => {
4547
+ const selectedModels = splitModels(state.imageModels.text);
4548
+ const next = selected ? selectedModels.filter((model) => model !== candidate) : [...selectedModels, candidate];
4549
+ props.edit("imageModels", next.join("\n"));
4550
+ }
4551
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: candidate })]
4552
+ }, candidate);
4553
+ })]
4554
+ }) : null,
4555
+ imageModelsError !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4556
+ className: settings_card_module_css_default.failed,
4557
+ role: "status",
4558
+ children: imageModelsError
4559
+ }) : null
4560
+ ]
3649
4561
  }),
3650
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
3651
- id: "dsh-imagegen-settings-enabled",
3652
- label: t("settings.enabled"),
3653
- hint: t("settings.enabledHint"),
3654
- inheritLabel: t("settings.inherit"),
3655
- onLabel: t("settings.on"),
3656
- offLabel: t("settings.off"),
3657
- ...fieldProps,
3658
- ...state.enabled,
3659
- onEdit: (text) => {
3660
- props.edit("enabled", text);
4562
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4563
+ type: "button",
4564
+ className: settings_card_module_css_default.disclosure,
4565
+ "aria-expanded": enhancementOpen,
4566
+ onClick: () => {
4567
+ setEnhancementOpen((open) => !open);
3661
4568
  },
3662
- onReset: () => {
3663
- props.resetField("enabled");
3664
- }
4569
+ children: [
4570
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("settings.promptEnhanceTitle") }),
4571
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("settings.optional") }),
4572
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4573
+ "aria-hidden": "true",
4574
+ children: enhancementOpen ? "⌃" : "⌄"
4575
+ })
4576
+ ]
3665
4577
  }),
3666
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
3667
- id: "dsh-imagegen-settings-announce",
3668
- label: t("settings.announceToAgent"),
3669
- hint: t("settings.announceToAgentHint"),
3670
- inheritLabel: t("settings.inherit"),
3671
- onLabel: t("settings.on"),
3672
- offLabel: t("settings.off"),
3673
- ...fieldProps,
3674
- ...state.announceToAgent,
3675
- onEdit: (text) => {
3676
- props.edit("announceToAgent", text);
4578
+ enhancementOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4579
+ className: settings_card_module_css_default.optionalContent,
4580
+ "aria-label": t("settings.promptEnhanceTitle"),
4581
+ children: [
4582
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4583
+ className: settings_card_module_css_default.sectionHint,
4584
+ children: t("settings.promptEnhanceHint")
4585
+ }),
4586
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4587
+ className: settings_card_module_css_default.sectionHeader,
4588
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
4589
+ className: settings_card_module_css_default.sectionTitle,
4590
+ children: t("settings.promptModel")
4591
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4592
+ className: settings_card_module_css_default.sectionHint,
4593
+ children: t("settings.promptModelDetectionHint")
4594
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4595
+ type: "button",
4596
+ className: settings_card_module_css_default.modelFetch,
4597
+ disabled: disabled || loadingPromptModels,
4598
+ onClick: () => {
4599
+ setLoadingPromptModels(true);
4600
+ setPromptModelsError(null);
4601
+ fetch(PROMPT_ENHANCE_API.models, { method: "POST" }).then(async (response) => {
4602
+ const body = await response.json();
4603
+ if (!response.ok || body.ok !== true) throw new Error(body.message ?? `HTTP ${response.status}`);
4604
+ setPromptModels(body.models ?? []);
4605
+ }).catch((error) => {
4606
+ setPromptModelsError(error instanceof Error ? error.message : String(error));
4607
+ }).finally(() => {
4608
+ setLoadingPromptModels(false);
4609
+ });
4610
+ },
4611
+ children: loadingPromptModels ? t("settings.promptModelsLoading") : t("settings.promptModelsFetch")
4612
+ })]
4613
+ }),
4614
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4615
+ className: settings_card_module_css_default.modelSummary,
4616
+ children: [state.promptModel.text.trim() !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4617
+ className: settings_card_module_css_default.modelChip,
4618
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: state.promptModel.text }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4619
+ type: "button",
4620
+ disabled,
4621
+ "aria-label": `${t("settings.removeModel")}: ${state.promptModel.text}`,
4622
+ onClick: () => {
4623
+ props.edit("promptModel", "");
4624
+ },
4625
+ children: "×"
4626
+ })]
4627
+ }) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4628
+ type: "button",
4629
+ className: settings_card_module_css_default.addModel,
4630
+ disabled,
4631
+ onClick: () => {
4632
+ setManualPromptModelOpen((open) => !open);
4633
+ },
4634
+ children: manualPromptModelOpen ? t("settings.cancelAddModel") : t("settings.addModel")
4635
+ })]
4636
+ }),
4637
+ manualPromptModelOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4638
+ className: settings_card_module_css_default.manualModelRow,
4639
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4640
+ className: settings_card_module_css_default.input,
4641
+ value: manualPromptModel,
4642
+ placeholder: t("settings.addPromptModelPlaceholder"),
4643
+ disabled,
4644
+ onChange: (event) => {
4645
+ setManualPromptModel(event.target.value);
4646
+ }
4647
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4648
+ type: "button",
4649
+ className: settings_card_module_css_default.addModel,
4650
+ disabled: disabled || manualPromptModel.trim() === "",
4651
+ onClick: () => {
4652
+ props.edit("promptModel", manualPromptModel);
4653
+ setManualPromptModel("");
4654
+ },
4655
+ children: t("settings.addModelConfirm")
4656
+ })]
4657
+ }) : null,
4658
+ promptModels.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4659
+ className: settings_card_module_css_default.modelCandidateList,
4660
+ role: "radiogroup",
4661
+ "aria-label": t("settings.promptModelsCandidates"),
4662
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4663
+ className: settings_card_module_css_default.modelCandidateLabel,
4664
+ children: t("settings.promptModelsCandidates")
4665
+ }), promptModels.map((candidate) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4666
+ type: "button",
4667
+ role: "radio",
4668
+ className: settings_card_module_css_default.modelCandidate,
4669
+ "aria-checked": state.promptModel.text === candidate,
4670
+ "data-selected": state.promptModel.text === candidate ? "" : void 0,
4671
+ disabled,
4672
+ onClick: () => {
4673
+ props.edit("promptModel", candidate);
4674
+ },
4675
+ children: candidate
4676
+ }, candidate))]
4677
+ }) : null,
4678
+ promptModelsError !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4679
+ className: settings_card_module_css_default.failed,
4680
+ role: "status",
4681
+ children: promptModelsError
4682
+ }) : null,
4683
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4684
+ type: "button",
4685
+ className: settings_card_module_css_default.inlineDisclosure,
4686
+ "aria-expanded": promptApiOpen,
4687
+ onClick: () => {
4688
+ setPromptApiOpen((open) => !open);
4689
+ },
4690
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("settings.promptApiAdvanced") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4691
+ "aria-hidden": "true",
4692
+ children: promptApiOpen ? "⌃" : "⌄"
4693
+ })]
4694
+ }),
4695
+ promptApiOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4696
+ className: settings_card_module_css_default.optionalContent,
4697
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
4698
+ id: "dsh-imagegen-settings-prompt-apiurl",
4699
+ label: t("settings.promptApiUrl"),
4700
+ hint: t("settings.promptApiUrlHint"),
4701
+ placeholder: "https://api.openai.com/v1",
4702
+ ...fieldProps,
4703
+ ...state.promptApiUrl,
4704
+ onEdit: (text) => {
4705
+ props.edit("promptApiUrl", text);
4706
+ },
4707
+ onReset: () => {
4708
+ props.resetField("promptApiUrl");
4709
+ }
4710
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ValueField, {
4711
+ id: "dsh-imagegen-settings-prompt-apikey",
4712
+ label: t("settings.promptApiKey"),
4713
+ hint: t("settings.promptApiKeyHint"),
4714
+ placeholder: "sk-…",
4715
+ secret: true,
4716
+ ...fieldProps,
4717
+ ...state.promptApiKey,
4718
+ overridden: false,
4719
+ onEdit: (text) => {
4720
+ props.edit("promptApiKey", text);
4721
+ },
4722
+ onReset: () => {
4723
+ props.resetField("promptApiKey");
4724
+ }
4725
+ })]
4726
+ }) : null
4727
+ ]
4728
+ }) : null,
4729
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4730
+ type: "button",
4731
+ className: settings_card_module_css_default.disclosure,
4732
+ "aria-expanded": moreOpen,
4733
+ onClick: () => {
4734
+ setMoreOpen((open) => !open);
3677
4735
  },
3678
- onReset: () => {
3679
- props.resetField("announceToAgent");
3680
- }
4736
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("settings.moreOptions") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4737
+ "aria-hidden": "true",
4738
+ children: moreOpen ? "⌃" : "⌄"
4739
+ })]
3681
4740
  }),
4741
+ moreOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4742
+ className: settings_card_module_css_default.optionalContent,
4743
+ children: [
4744
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
4745
+ id: "dsh-imagegen-settings-enabled",
4746
+ label: t("settings.enabled"),
4747
+ hint: t("settings.enabledHint"),
4748
+ inheritLabel: t("settings.inherit"),
4749
+ onLabel: t("settings.on"),
4750
+ offLabel: t("settings.off"),
4751
+ ...fieldProps,
4752
+ ...state.enabled,
4753
+ onEdit: (text) => {
4754
+ props.edit("enabled", text);
4755
+ },
4756
+ onReset: () => {
4757
+ props.resetField("enabled");
4758
+ }
4759
+ }),
4760
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
4761
+ id: "dsh-imagegen-settings-announce",
4762
+ label: t("settings.announceToAgent"),
4763
+ hint: t("settings.announceToAgentHint"),
4764
+ inheritLabel: t("settings.inherit"),
4765
+ onLabel: t("settings.on"),
4766
+ offLabel: t("settings.off"),
4767
+ ...fieldProps,
4768
+ ...state.announceToAgent,
4769
+ onEdit: (text) => {
4770
+ props.edit("announceToAgent", text);
4771
+ },
4772
+ onReset: () => {
4773
+ props.resetField("announceToAgent");
4774
+ }
4775
+ }),
4776
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BooleanField, {
4777
+ id: "dsh-imagegen-settings-agent-generation",
4778
+ label: t("settings.allowAgentImageGeneration"),
4779
+ hint: t("settings.allowAgentImageGenerationHint"),
4780
+ inheritLabel: t("settings.inherit"),
4781
+ onLabel: t("settings.on"),
4782
+ offLabel: t("settings.off"),
4783
+ ...fieldProps,
4784
+ ...state.allowAgentImageGeneration,
4785
+ onEdit: (text) => {
4786
+ props.edit("allowAgentImageGeneration", text);
4787
+ },
4788
+ onReset: () => {
4789
+ props.resetField("allowAgentImageGeneration");
4790
+ }
4791
+ })
4792
+ ]
4793
+ }) : null,
3682
4794
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3683
4795
  className: settings_card_module_css_default.footer,
3684
4796
  children: [
@@ -3742,7 +4854,17 @@ window.__ModuleLoader__.load({
3742
4854
  }) : null
3743
4855
  ]
3744
4856
  }),
3745
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4857
+ props.multiline === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
4858
+ id: props.id,
4859
+ className: props.invalid ? settings_card_module_css_default.textareaInvalid : settings_card_module_css_default.textarea,
4860
+ ...props.invalid ? { "aria-invalid": true } : {},
4861
+ value: props.text,
4862
+ placeholder: props.placeholder ?? "",
4863
+ disabled: props.disabled,
4864
+ onChange: (event) => {
4865
+ props.onEdit(event.target.value);
4866
+ }
4867
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3746
4868
  id: props.id,
3747
4869
  className: props.invalid ? settings_card_module_css_default.inputInvalid : settings_card_module_css_default.input,
3748
4870
  type: props.secret === true ? "password" : "text",
@@ -3762,6 +4884,9 @@ window.__ModuleLoader__.load({
3762
4884
  ]
3763
4885
  });
3764
4886
  }
4887
+ function splitModels(value) {
4888
+ return [...new Set(value.split(/[\n,]/).map((model) => model.trim()).filter(Boolean))];
4889
+ }
3765
4890
  /** A staged boolean field: 继承 / 开 / 关. */
3766
4891
  function BooleanField(props) {
3767
4892
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -3868,6 +4993,8 @@ window.__ModuleLoader__.load({
3868
4993
  store;
3869
4994
  /** Whether the namespace currently holds a stored secret (e.g. apiKey). */
3870
4995
  keySet;
4996
+ /** Individual secret presence bits, keyed by the settings field name. */
4997
+ secretSets;
3871
4998
  tail = Promise.resolve();
3872
4999
  disposed = false;
3873
5000
  constructor(api, spec) {
@@ -3883,6 +5010,7 @@ window.__ModuleLoader__.load({
3883
5010
  mode: "host"
3884
5011
  });
3885
5012
  this.keySet = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(false);
5013
+ this.secretSets = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({});
3886
5014
  }
3887
5015
  getSnapshot() {
3888
5016
  return this.store.getSnapshot();
@@ -3895,6 +5023,14 @@ window.__ModuleLoader__.load({
3895
5023
  subscribeKeySet(listener) {
3896
5024
  return this.keySet.subscribe(listener);
3897
5025
  }
5026
+ /** Whether a specific secret field currently has a stored value. */
5027
+ getSecretSetSnapshot(field) {
5028
+ return this.secretSets.getSnapshot()[field] === true;
5029
+ }
5030
+ /** Observe changes to individual secret-field presence bits. */
5031
+ subscribeSecretSets(listener) {
5032
+ return this.secretSets.subscribe(listener);
5033
+ }
3898
5034
  subscribe(listener) {
3899
5035
  return this.store.subscribe(listener);
3900
5036
  }
@@ -3952,6 +5088,7 @@ window.__ModuleLoader__.load({
3952
5088
  draft.writable = writable === true;
3953
5089
  });
3954
5090
  this.keySet.set(false);
5091
+ this.secretSets.set({});
3955
5092
  return;
3956
5093
  }
3957
5094
  this.accept(view, writable);
@@ -3984,7 +5121,9 @@ window.__ModuleLoader__.load({
3984
5121
  draft.status = "ready";
3985
5122
  draft.value = view.value;
3986
5123
  });
3987
- this.keySet.set(Array.isArray(view.secrets) && view.secrets.some((secret) => secret.set));
5124
+ const secretSets = Object.fromEntries((view.secrets ?? []).map((secret) => [secret.path.join("."), secret.set]));
5125
+ this.keySet.set(Object.values(secretSets).some(Boolean));
5126
+ this.secretSets.set(secretSets);
3988
5127
  }
3989
5128
  };
3990
5129
  /**