@dickpy/dsh-imagegen 1.2.0 → 1.2.1

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/index.js CHANGED
@@ -17,7 +17,7 @@ import { defineTool } from "@deepseek-ai/dsh-tools";
17
17
  /** Settings namespace this plugin owns (host settings seam + bridge). */
18
18
  const IMAGEGEN_SETTINGS_NAMESPACE = "dsh-imagegen";
19
19
  /** Published package version shared by the host updater and the client UI. */
20
- const PLUGIN_VERSION = "1.2.0";
20
+ const PLUGIN_VERSION = "1.2.1";
21
21
  /** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
22
22
  const SETTINGS_API = {
23
23
  describe: "/api/dsh-imagegen/settings/describe",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dickpy/dsh-imagegen",
3
3
  "description": "AI 鐢熷浘 (image generation) plugin for the dsh web GUI: text-to-image and image-to-image through a configurable OpenAI-compatible endpoint (gpt-image-2 / grok-imagine-image / dall-e-3, with native xAI Grok Imagine request shaping), with a settings card for api_url / api_key and a sidebar entry opening a split-pane generation studio.",
4
- "version": "1.2.0",
4
+ "version": "1.2.1",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -213,6 +213,7 @@ export function ImageGenPanel(props: {
213
213
  const [updateResult, setUpdateResult] = useState<'success' | 'failed' | null>(null)
214
214
  const [libraryOpen, setLibraryOpen] = useState(false)
215
215
  const [tasks, setTasks] = useState<GenerationTask[]>([])
216
+ const [taskTrayOpen, setTaskTrayOpen] = useState(false)
216
217
  const [comparison, setComparison] = useState<ComparisonSession | null>(null)
217
218
  const [comparisonFullscreen, setComparisonFullscreen] = useState(false)
218
219
  const fileInput = useRef<HTMLInputElement>(null)
@@ -1152,16 +1153,25 @@ export function ImageGenPanel(props: {
1152
1153
  </div>
1153
1154
  ) : null}
1154
1155
  {tab !== 'gallery' && tasks.length > 0 ? (
1155
- <section className={css.taskTray} aria-label={tt('tasks.title')}>
1156
- <header className={css.taskTrayHeader}>{tt('tasks.title')} <span>{tasks.filter(task => task.status === 'queued' || task.status === 'running').length}</span></header>
1157
- {tasks.slice(0, 5).map(task => (
1158
- <div key={task.id} className={css.taskRow} data-status={task.status}>
1159
- <span className={css.taskStatus}>{tt(`tasks.${task.status}` as never)}</span>
1160
- <span className={css.taskPrompt}>{task.request.prompt}</span>
1161
- {(task.status === 'queued' || task.status === 'running') ? <button type="button" onClick={() => { void api.taskCancel(task.id) }}>{tt('tasks.cancel')}</button> : null}
1162
- {task.status === 'failed' || task.status === 'cancelled' ? <button type="button" onClick={() => { void api.taskRetry(task.id) }}>{tt('tasks.retry')}</button> : null}
1163
- </div>
1164
- ))}
1156
+ <section className={css.taskTray} data-open={taskTrayOpen ? 'true' : 'false'} aria-label={tt('tasks.title')}>
1157
+ <header className={css.taskTrayHeader}>
1158
+ <button type="button" className={css.taskTrayToggle} aria-expanded={taskTrayOpen} onClick={() => { setTaskTrayOpen(open => !open) }}>
1159
+ <span>{tt('tasks.title')}</span>
1160
+ <span className={css.taskTrayCount}>{tasks.filter(task => task.status === 'queued' || task.status === 'running').length}</span>
1161
+ <span className={css.taskTrayChevron} aria-hidden="true">{taskTrayOpen ? '⌃' : '⌄'}</span>
1162
+ </button>
1163
+ {taskTrayOpen ? <button type="button" className={css.taskTrayClose} aria-label={tt('preview.close')} onClick={() => { setTaskTrayOpen(false) }}>×</button> : null}
1164
+ </header>
1165
+ <div className={css.taskRows}>
1166
+ {tasks.slice(0, 5).map(task => (
1167
+ <div key={task.id} className={css.taskRow} data-status={task.status}>
1168
+ <span className={css.taskStatus}>{tt(`tasks.${task.status}` as never)}</span>
1169
+ <span className={css.taskPrompt}>{task.request.prompt}</span>
1170
+ {(task.status === 'queued' || task.status === 'running') ? <button type="button" onClick={() => { void api.taskCancel(task.id) }}>{tt('tasks.cancel')}</button> : null}
1171
+ {task.status === 'failed' || task.status === 'cancelled' ? <button type="button" onClick={() => { void api.taskRetry(task.id) }}>{tt('tasks.retry')}</button> : null}
1172
+ </div>
1173
+ ))}
1174
+ </div>
1165
1175
  </section>
1166
1176
  ) : null}
1167
1177
  {tab !== 'gallery' && comparison !== null ? (
@@ -325,6 +325,9 @@ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ss
325
325
  top: 12px;
326
326
  right: 12px;
327
327
  width: min(360px, calc(100% - 24px));
328
+ max-height: calc(100% - 24px);
329
+ display: flex;
330
+ flex-direction: column;
328
331
  overflow: hidden;
329
332
  border: 1px solid var(--dsw-alias-border-l2);
330
333
  border-radius: 9px;
@@ -333,7 +336,18 @@ html[data-dsh-imagegen-active]:not([data-dsh-taskboard-active]):not([data-dsh-ss
333
336
  backdrop-filter: blur(10px);
334
337
  }
335
338
 
336
- .taskTrayHeader { display: flex; justify-content: space-between; padding: 8px 10px; color: var(--dsw-alias-label-primary); font-size: 12px; font-weight: 600; border-bottom: 1px solid var(--dsw-alias-border-l1); }
339
+ .taskTray[data-open='false'] { width: auto; max-width: calc(100% - 24px); }
340
+ .taskTrayHeader { display: flex; align-items: stretch; min-height: 34px; color: var(--dsw-alias-label-primary); font-size: 12px; font-weight: 600; border-bottom: 1px solid var(--dsw-alias-border-l1); }
341
+ .taskTray[data-open='false'] .taskTrayHeader { border-bottom: 0; }
342
+ .taskTrayToggle { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; padding: 8px 10px; border: 0; color: inherit; background: transparent; cursor: pointer; font: inherit; font-size: inherit; font-weight: inherit; text-align: left; }
343
+ .taskTrayToggle:hover { background: var(--dsw-alias-bg-layer-2); }
344
+ .taskTrayCount { min-width: 18px; padding: 1px 5px; border-radius: 999px; color: var(--dsw-alias-label-secondary); background: var(--dsw-alias-bg-layer-2); font-size: 11px; font-weight: 500; text-align: center; }
345
+ .taskTrayChevron { margin-left: auto; color: var(--dsw-alias-label-tertiary); font-size: 12px; font-weight: 400; }
346
+ .taskTrayClose { width: 32px; border: 0; border-left: 1px solid var(--dsw-alias-border-l1); color: var(--dsw-alias-label-tertiary); background: transparent; cursor: pointer; font: inherit; font-size: 17px; }
347
+ .taskTrayClose:hover { color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-2); }
348
+ .taskTray[data-open='false'] .taskTrayToggle { min-height: 34px; }
349
+ .taskRows { min-height: 0; overflow-y: auto; }
350
+ .taskTray[data-open='false'] .taskRows { display: none; }
337
351
  .taskRow { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 7px; align-items: center; padding: 7px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }
338
352
  .taskRow:first-of-type { border-top: 0; }
339
353
  .taskStatus { color: var(--dsw-alias-label-tertiary); font-size: 11px; white-space: nowrap; }
package/src/protocol.ts CHANGED
@@ -8,7 +8,7 @@
8
8
  export const IMAGEGEN_SETTINGS_NAMESPACE = 'dsh-imagegen'
9
9
 
10
10
  /** Published package version shared by the host updater and the client UI. */
11
- export const PLUGIN_VERSION = '1.2.0'
11
+ export const PLUGIN_VERSION = '1.2.1'
12
12
 
13
13
  /** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
14
14
  export const SETTINGS_API = {