@dickpy/dsh-imagegen 1.5.4 → 1.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/lib/client.js +1141 -508
- package/lib/client.js.map +1 -1
- package/lib/index.js +217 -170
- package/package.json +1 -1
- package/src/canvas-store.ts +15 -16
- package/src/client/CanvasWorkspace.tsx +333 -31
- package/src/client/ImageGenPanel.tsx +2737 -2679
- package/src/client/SettingsCard.tsx +14 -0
- package/src/client/canvas-workspace.module.css +144 -8
- package/src/client/locales.ts +82 -25
- package/src/client/panel.module.css +20 -26
- package/src/engine.ts +181 -146
- package/src/gallery-store.ts +13 -13
- package/src/generation-runtime.ts +2 -2
- package/src/history-store.ts +12 -12
- package/src/image-storage-path.ts +12 -0
- package/src/index.ts +5 -0
- package/src/protocol.ts +8 -2
- package/src/routes.ts +3 -0
- package/src/task-queue.ts +4 -5
|
@@ -33,6 +33,7 @@ export interface ImageGenSettings {
|
|
|
33
33
|
promptApiUrl?: string
|
|
34
34
|
promptApiKey?: string
|
|
35
35
|
promptModel?: string
|
|
36
|
+
localStoragePath?: string
|
|
36
37
|
storageEnabled?: boolean
|
|
37
38
|
storageEndpoint?: string
|
|
38
39
|
storageRegion?: string
|
|
@@ -55,6 +56,7 @@ export interface ImageGenSettingsCardState extends CardShell {
|
|
|
55
56
|
promptApiUrl: CardFieldState
|
|
56
57
|
promptApiKey: CardFieldState
|
|
57
58
|
promptModel: CardFieldState
|
|
59
|
+
localStoragePath: CardFieldState
|
|
58
60
|
storageEnabled: CardFieldState
|
|
59
61
|
storageEndpoint: CardFieldState
|
|
60
62
|
storageRegion: CardFieldState
|
|
@@ -98,6 +100,7 @@ export class ImageGenSettingsCardController {
|
|
|
98
100
|
textField('promptApiUrl'),
|
|
99
101
|
secretField('promptApiKey'),
|
|
100
102
|
textField('promptModel'),
|
|
103
|
+
textField('localStoragePath'),
|
|
101
104
|
booleanField('storageEnabled'),
|
|
102
105
|
textField('storageEndpoint'),
|
|
103
106
|
textField('storageRegion'),
|
|
@@ -124,6 +127,7 @@ export class ImageGenSettingsCardController {
|
|
|
124
127
|
promptApiUrl: this.form.field('promptApiUrl'),
|
|
125
128
|
promptApiKey: this.form.field('promptApiKey'),
|
|
126
129
|
promptModel: this.form.field('promptModel'),
|
|
130
|
+
localStoragePath: this.form.field('localStoragePath'),
|
|
127
131
|
storageEnabled: this.form.field('storageEnabled'),
|
|
128
132
|
storageEndpoint: this.form.field('storageEndpoint'),
|
|
129
133
|
storageRegion: this.form.field('storageRegion'),
|
|
@@ -475,6 +479,16 @@ export function ImageGenSettingsCard(props: ImageGenSettingsCardProps) {
|
|
|
475
479
|
<span aria-hidden="true">{storageOpen ? '⌃' : '⌄'}</span>
|
|
476
480
|
</button>
|
|
477
481
|
{storageOpen ? <div className={css.optionalContent}>
|
|
482
|
+
<ValueField
|
|
483
|
+
id="dsh-imagegen-settings-local-storage-path"
|
|
484
|
+
label={t('settings.localStoragePath')}
|
|
485
|
+
hint={t('settings.localStoragePathHint')}
|
|
486
|
+
placeholder="E:\\dsh-imagegen-data"
|
|
487
|
+
{...fieldProps}
|
|
488
|
+
{...state.localStoragePath}
|
|
489
|
+
onEdit={(text) => { props.edit('localStoragePath', text) }}
|
|
490
|
+
onReset={() => { props.resetField('localStoragePath') }}
|
|
491
|
+
/>
|
|
478
492
|
<BooleanField
|
|
479
493
|
id="dsh-imagegen-settings-storage-enabled"
|
|
480
494
|
label={t('settings.storageEnabled')}
|
|
@@ -142,6 +142,68 @@
|
|
|
142
142
|
|
|
143
143
|
.grid[data-mode="blank"] { background-image: none; }
|
|
144
144
|
|
|
145
|
+
.grid[data-mode="diagonal"] {
|
|
146
|
+
background-image: repeating-linear-gradient(45deg, color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent) 0 1px, transparent 1px 16px);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.grid[data-mode="checker"] {
|
|
150
|
+
background-image:
|
|
151
|
+
conic-gradient(color-mix(in srgb, var(--dsw-alias-label-primary) 7%, transparent) 90deg, transparent 90deg 180deg, color-mix(in srgb, var(--dsw-alias-label-primary) 7%, transparent) 180deg 270deg, transparent 270deg);
|
|
152
|
+
background-size: 48px 48px;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.grid[data-mode="image"] { background-image: none; }
|
|
156
|
+
|
|
157
|
+
.gridScrim {
|
|
158
|
+
position: absolute;
|
|
159
|
+
inset: 0;
|
|
160
|
+
background: var(--dsw-alias-bg-layer-1);
|
|
161
|
+
opacity: 0.6;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* ------------------------------------------------ background menu */
|
|
165
|
+
|
|
166
|
+
.backgroundMenu {
|
|
167
|
+
position: absolute;
|
|
168
|
+
transform: translate(-50%, -100%);
|
|
169
|
+
z-index: 45;
|
|
170
|
+
min-width: 168px;
|
|
171
|
+
padding: 5px;
|
|
172
|
+
border-radius: 11px;
|
|
173
|
+
border: 1px solid var(--dsw-alias-border-l1);
|
|
174
|
+
background: color-mix(in srgb, var(--dsw-alias-bg-layer-1) 96%, transparent);
|
|
175
|
+
box-shadow: 0 16px 40px rgb(15 23 42 / 20%);
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.backgroundMenu button {
|
|
181
|
+
display: flex;
|
|
182
|
+
align-items: center;
|
|
183
|
+
justify-content: space-between;
|
|
184
|
+
border: none;
|
|
185
|
+
border-radius: 7px;
|
|
186
|
+
background: transparent;
|
|
187
|
+
color: var(--dsw-alias-label-primary);
|
|
188
|
+
font-size: 12.5px;
|
|
189
|
+
padding: 7px 10px;
|
|
190
|
+
cursor: pointer;
|
|
191
|
+
text-align: left;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.backgroundMenu button:hover { background: var(--dsw-alias-interactive-bg-hover); }
|
|
195
|
+
|
|
196
|
+
.backgroundMenu button[data-active] {
|
|
197
|
+
color: var(--dsw-alias-brand-primary);
|
|
198
|
+
background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.backgroundMenuDivider {
|
|
202
|
+
height: 1px;
|
|
203
|
+
margin: 4px 6px;
|
|
204
|
+
background: var(--dsw-alias-border-l1);
|
|
205
|
+
}
|
|
206
|
+
|
|
145
207
|
.world {
|
|
146
208
|
position: absolute;
|
|
147
209
|
left: 0;
|
|
@@ -256,6 +318,33 @@
|
|
|
256
318
|
display: block;
|
|
257
319
|
}
|
|
258
320
|
|
|
321
|
+
.imageInfo {
|
|
322
|
+
position: absolute;
|
|
323
|
+
top: 6px;
|
|
324
|
+
z-index: 2;
|
|
325
|
+
padding: 3px 8px;
|
|
326
|
+
border-radius: 6px;
|
|
327
|
+
background: color-mix(in srgb, var(--dsw-alias-label-primary) 62%, transparent);
|
|
328
|
+
color: var(--dsw-alias-bg-layer-1);
|
|
329
|
+
font-size: 10.5px;
|
|
330
|
+
line-height: 1.4;
|
|
331
|
+
pointer-events: none;
|
|
332
|
+
backdrop-filter: blur(3px);
|
|
333
|
+
max-width: calc(100% - 90px);
|
|
334
|
+
overflow: hidden;
|
|
335
|
+
text-overflow: ellipsis;
|
|
336
|
+
white-space: nowrap;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.imageInfoLeft { left: 6px; font-weight: 600; }
|
|
340
|
+
|
|
341
|
+
.imageInfoRight {
|
|
342
|
+
right: 6px;
|
|
343
|
+
left: auto;
|
|
344
|
+
font-variant-numeric: tabular-nums;
|
|
345
|
+
opacity: 0.85;
|
|
346
|
+
}
|
|
347
|
+
|
|
259
348
|
.nodeState,
|
|
260
349
|
.nodeStateError {
|
|
261
350
|
display: flex;
|
|
@@ -343,7 +432,53 @@
|
|
|
343
432
|
backdrop-filter: blur(10px);
|
|
344
433
|
}
|
|
345
434
|
|
|
346
|
-
.dock .iconButton {
|
|
435
|
+
.dock .iconButton {
|
|
436
|
+
position: relative;
|
|
437
|
+
overflow: hidden;
|
|
438
|
+
width: 40px;
|
|
439
|
+
height: 40px;
|
|
440
|
+
border-radius: 11px;
|
|
441
|
+
transition: transform 0.18s cubic-bezier(0.34, 1.9, 0.64, 1), background 0.15s ease, color 0.15s ease, box-shadow 0.18s ease;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/* water-wave sheen sweeping across + gentle lift on hover */
|
|
445
|
+
.dock .iconButton::before {
|
|
446
|
+
content: '';
|
|
447
|
+
position: absolute;
|
|
448
|
+
top: -4px;
|
|
449
|
+
bottom: -4px;
|
|
450
|
+
left: -150%;
|
|
451
|
+
width: 65%;
|
|
452
|
+
background: linear-gradient(105deg, transparent, color-mix(in srgb, currentColor 26%, transparent), transparent);
|
|
453
|
+
transform: skewX(-18deg);
|
|
454
|
+
opacity: 0;
|
|
455
|
+
pointer-events: none;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.dock .iconButton:not(:disabled):hover {
|
|
459
|
+
transform: translateY(calc(-3px - var(--dock-lift, 0px)));
|
|
460
|
+
box-shadow: 0 6px 14px color-mix(in srgb, var(--dsw-alias-label-primary) 20%, transparent);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.dock .iconButton:not(:disabled):hover::before {
|
|
464
|
+
animation: dockShine 0.55s ease forwards;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.dock .iconButton:not(:disabled):active {
|
|
468
|
+
transform: translateY(-1px) scale(0.96);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
@keyframes dockShine {
|
|
472
|
+
0% { left: -150%; opacity: 1; }
|
|
473
|
+
100% { left: 170%; opacity: 1; }
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.dock .iconButton[data-active] {
|
|
477
|
+
background: var(--dsw-alias-label-primary);
|
|
478
|
+
color: var(--dsw-alias-bg-layer-1);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
.dock .iconButton[data-active]:hover { background: var(--dsw-alias-label-primary); color: var(--dsw-alias-bg-layer-1); }
|
|
347
482
|
|
|
348
483
|
.dockDivider {
|
|
349
484
|
width: 1px;
|
|
@@ -439,29 +574,30 @@
|
|
|
439
574
|
/* ------------------------------------------------------ config node */
|
|
440
575
|
|
|
441
576
|
.configNode {
|
|
442
|
-
padding: 0
|
|
577
|
+
padding: 0 14px 14px;
|
|
443
578
|
cursor: grab;
|
|
444
579
|
}
|
|
445
580
|
|
|
446
|
-
.configNode .nodeHeader { padding:
|
|
581
|
+
.configNode .nodeHeader { padding: 10px 2px 6px; font-size: 12px; }
|
|
447
582
|
|
|
448
583
|
.configLinks {
|
|
449
584
|
display: flex;
|
|
450
|
-
|
|
585
|
+
align-items: center;
|
|
586
|
+
margin: 4px 0 10px;
|
|
451
587
|
flex: none;
|
|
452
588
|
}
|
|
453
589
|
|
|
454
590
|
.configLinks .composerChip {
|
|
455
|
-
font-size:
|
|
456
|
-
padding:
|
|
591
|
+
font-size: 11px;
|
|
592
|
+
padding: 3px 10px;
|
|
457
593
|
}
|
|
458
594
|
|
|
459
595
|
.configHint {
|
|
460
596
|
flex: 1;
|
|
461
597
|
min-height: 0;
|
|
462
598
|
margin: 0;
|
|
463
|
-
font-size:
|
|
464
|
-
line-height: 1.
|
|
599
|
+
font-size: 11.5px;
|
|
600
|
+
line-height: 1.7;
|
|
465
601
|
color: var(--dsw-alias-label-tertiary);
|
|
466
602
|
overflow: auto;
|
|
467
603
|
}
|
package/src/client/locales.ts
CHANGED
|
@@ -31,7 +31,7 @@ export const zh = {
|
|
|
31
31
|
'canvas.untitled': '未命名画布',
|
|
32
32
|
'canvas.imageNode': '图片节点',
|
|
33
33
|
'canvas.textNode': '文本节点',
|
|
34
|
-
'canvas.fromGallery': '
|
|
34
|
+
'canvas.fromGallery': '素材库图片',
|
|
35
35
|
'canvas.fromHistory': '历史图片',
|
|
36
36
|
'canvas.project': '画布项目',
|
|
37
37
|
'canvas.newCanvas': '新建画布',
|
|
@@ -39,7 +39,15 @@ export const zh = {
|
|
|
39
39
|
'canvas.deleteCanvasConfirm': '再点一次确认删除',
|
|
40
40
|
'canvas.rename': '重命名画布',
|
|
41
41
|
'canvas.renameHint': '双击重命名',
|
|
42
|
-
'canvas.background': '
|
|
42
|
+
'canvas.background': '画布背景',
|
|
43
|
+
'canvas.backgroundDots': '点阵',
|
|
44
|
+
'canvas.backgroundLines': '网格线',
|
|
45
|
+
'canvas.backgroundDiagonal': '斜线',
|
|
46
|
+
'canvas.backgroundChecker': '棋盘格',
|
|
47
|
+
'canvas.backgroundBlank': '空白',
|
|
48
|
+
'canvas.backgroundUpload': '上传自定义背景…',
|
|
49
|
+
'canvas.backgroundRemove': '移除自定义背景',
|
|
50
|
+
'canvas.templateLibrary': '模板库(选择提示词生成文本+配置节点)',
|
|
43
51
|
'canvas.undo': '撤销 (Ctrl+Z)',
|
|
44
52
|
'canvas.redo': '重做 (Ctrl+Shift+Z)',
|
|
45
53
|
'canvas.saving': '保存中…',
|
|
@@ -60,6 +68,7 @@ export const zh = {
|
|
|
60
68
|
'canvas.generatingNode': '生成中…',
|
|
61
69
|
'canvas.generateFailed': '生成失败',
|
|
62
70
|
'canvas.retry': '重试',
|
|
71
|
+
'canvas.taskLost': '生成任务已丢失(服务重启),请重试',
|
|
63
72
|
'canvas.emptyImageNode': '点击上传图片',
|
|
64
73
|
'canvas.connectHint': '拖到其他节点建立连线',
|
|
65
74
|
'canvas.resizeHint': '拖动调整大小(图片锁定比例)',
|
|
@@ -88,7 +97,11 @@ export const zh = {
|
|
|
88
97
|
'canvas.close': '关闭',
|
|
89
98
|
'canvas.tabUpload': '上传',
|
|
90
99
|
'canvas.tabHistory': '历史记录',
|
|
91
|
-
'canvas.tabGallery': '
|
|
100
|
+
'canvas.tabGallery': '素材库',
|
|
101
|
+
'canvas.imageMenuUpload': '上传本地图片',
|
|
102
|
+
'canvas.imageMenuAssets': '从素材库选择',
|
|
103
|
+
'canvas.imageMenuHistory': '从历史记录选择',
|
|
104
|
+
'canvas.imageMenuGenerate': 'AI 生成新图',
|
|
92
105
|
'canvas.tabGenerate': 'AI 生成',
|
|
93
106
|
'canvas.dropHint': '图片拖动到此处即可添加',
|
|
94
107
|
'canvas.dropSub': '支持多选,PNG / JPG / WebP / GIF',
|
|
@@ -240,14 +253,18 @@ export const zh = {
|
|
|
240
253
|
'history.allModels': '全部模型',
|
|
241
254
|
'history.allRatios': '全部比例',
|
|
242
255
|
// gallery
|
|
243
|
-
'gallery.title': '
|
|
256
|
+
'gallery.title': '素材库',
|
|
244
257
|
'gallery.categories': '分类',
|
|
245
|
-
'gallery.all': '
|
|
258
|
+
'gallery.all': '全部素材',
|
|
259
|
+
'gallery.upload': '上传素材',
|
|
260
|
+
'gallery.uploadModel': '本地上传',
|
|
261
|
+
'gallery.uploaded': '素材已入库',
|
|
262
|
+
'gallery.uploadHint': '把本地图保存进素材库,画布随时可用',
|
|
246
263
|
'gallery.gpt': 'gpt-image-2',
|
|
247
264
|
'gallery.grok': 'grok-imagine-image',
|
|
248
265
|
'gallery.ratio': '画面比例',
|
|
249
266
|
'gallery.tags': '标签',
|
|
250
|
-
'gallery.filterHint': '
|
|
267
|
+
'gallery.filterHint': '按生成模式、模型和比例筛选素材',
|
|
251
268
|
'gallery.count': '· 共 {count} 幅',
|
|
252
269
|
'gallery.viewMode': '视图模式',
|
|
253
270
|
'gallery.masonry': '瀑布流',
|
|
@@ -269,16 +286,16 @@ export const zh = {
|
|
|
269
286
|
'gallery.downloadSelected': '下载所选',
|
|
270
287
|
'gallery.exportJson': '导出 JSON',
|
|
271
288
|
'gallery.select': '选择作品',
|
|
272
|
-
'gallery.add': '
|
|
273
|
-
'gallery.added': '
|
|
274
|
-
'gallery.already': '
|
|
275
|
-
'gallery.delete': '
|
|
289
|
+
'gallery.add': '加入素材库',
|
|
290
|
+
'gallery.added': '已加入素材库',
|
|
291
|
+
'gallery.already': '已在素材库中',
|
|
292
|
+
'gallery.delete': '移出素材库',
|
|
276
293
|
'gallery.openFolder': '打开文件夹',
|
|
277
|
-
'gallery.clear': '
|
|
294
|
+
'gallery.clear': '清空素材库',
|
|
278
295
|
'gallery.openFolderHint': '在系统的文件管理器中打开图片保存目录(~/.dsh/dsh-imagegen)',
|
|
279
|
-
'gallery.clearConfirm': '
|
|
280
|
-
'gallery.empty': '
|
|
281
|
-
'gallery.viewing': '
|
|
296
|
+
'gallery.clearConfirm': '确定要清空整个素材库吗?此操作不可撤销。',
|
|
297
|
+
'gallery.empty': '素材库还是空的,把喜欢的图片加入进来吧',
|
|
298
|
+
'gallery.viewing': '素材库 · {time}',
|
|
282
299
|
// preview
|
|
283
300
|
'preview.title': '图片预览',
|
|
284
301
|
'preview.open': '点击预览',
|
|
@@ -339,6 +356,8 @@ export const zh = {
|
|
|
339
356
|
'settings.removeModel': '移除模型',
|
|
340
357
|
'settings.optional': '可选',
|
|
341
358
|
'settings.moreOptions': '更多设置',
|
|
359
|
+
'settings.localStoragePath': '本地图片存储目录',
|
|
360
|
+
'settings.localStoragePathHint': '生成历史、素材库和无限画布图片统一保存到此目录;留空使用默认的 ~/.dsh/dsh-imagegen。',
|
|
342
361
|
'settings.storageTitle': '对象存储同步',
|
|
343
362
|
'settings.storageEnabled': '启用对象存储同步',
|
|
344
363
|
'settings.storageHint': '图片保存到本地后,异步上传一份到 S3 兼容对象存储(腾讯云 COS / 阿里云 OSS / 七牛云 S3 / MinIO / R2 等)',
|
|
@@ -352,8 +371,8 @@ export const zh = {
|
|
|
352
371
|
'settings.storageAccessKeyHint': 'S3 兼容密钥 ID(COS SecretId / OSS AccessKeyId / 七牛 AK)',
|
|
353
372
|
'settings.storageSecretKey': 'Secret Key',
|
|
354
373
|
'settings.storageSecretKeyHint': 'S3 兼容密钥,仅保存在本机设置文档',
|
|
355
|
-
'settings.storageSyncGallery': '
|
|
356
|
-
'settings.storageSyncGalleryHint': '
|
|
374
|
+
'settings.storageSyncGallery': '同步素材库图片',
|
|
375
|
+
'settings.storageSyncGalleryHint': '加入素材库的图片自动上传',
|
|
357
376
|
'settings.storageSyncHistory': '同步历史记录图片',
|
|
358
377
|
'settings.storageSyncHistoryHint': '所有生成结果也一并上传(数量可能较大)',
|
|
359
378
|
'settings.storageTest': '测试连接',
|
|
@@ -457,7 +476,7 @@ export const zh = {
|
|
|
457
476
|
'channels.statusIncomplete': '配置未完成',
|
|
458
477
|
'channels.edit': '编辑',
|
|
459
478
|
'channels.delete': '删除',
|
|
460
|
-
'channels.deleteConfirmTitle': '删除渠道「{name}
|
|
479
|
+
'channels.deleteConfirmTitle': '删除渠道「{name}」?该渠道的密钥将被移除;历史与素材库中的记录仍会保留。',
|
|
461
480
|
'channels.confirm': '确认删除',
|
|
462
481
|
'channels.cancel': '取消',
|
|
463
482
|
'channels.editorTitle': '渠道',
|
|
@@ -529,7 +548,15 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
529
548
|
'canvas.deleteCanvasConfirm': 'Click again to confirm',
|
|
530
549
|
'canvas.rename': 'Rename canvas',
|
|
531
550
|
'canvas.renameHint': 'Double-click to rename',
|
|
532
|
-
'canvas.background': '
|
|
551
|
+
'canvas.background': 'Canvas background',
|
|
552
|
+
'canvas.backgroundDots': 'Dots',
|
|
553
|
+
'canvas.backgroundLines': 'Grid lines',
|
|
554
|
+
'canvas.backgroundDiagonal': 'Diagonal',
|
|
555
|
+
'canvas.backgroundChecker': 'Checkerboard',
|
|
556
|
+
'canvas.backgroundBlank': 'Blank',
|
|
557
|
+
'canvas.backgroundUpload': 'Upload custom background…',
|
|
558
|
+
'canvas.backgroundRemove': 'Remove custom background',
|
|
559
|
+
'canvas.templateLibrary': 'Template library (pick a prompt to create text + config nodes)',
|
|
533
560
|
'canvas.undo': 'Undo (Ctrl+Z)',
|
|
534
561
|
'canvas.redo': 'Redo (Ctrl+Shift+Z)',
|
|
535
562
|
'canvas.saving': 'Saving…',
|
|
@@ -550,6 +577,7 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
550
577
|
'canvas.generatingNode': 'Generating…',
|
|
551
578
|
'canvas.generateFailed': 'Generation failed',
|
|
552
579
|
'canvas.retry': 'Retry',
|
|
580
|
+
'canvas.taskLost': 'Generation task lost (service restarted); please retry',
|
|
553
581
|
'canvas.emptyImageNode': 'Click to upload an image',
|
|
554
582
|
'canvas.connectHint': 'Drag onto another node to connect',
|
|
555
583
|
'canvas.resizeHint': 'Drag to resize (image ratio locked)',
|
|
@@ -578,7 +606,11 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
578
606
|
'canvas.close': 'Close',
|
|
579
607
|
'canvas.tabUpload': 'Upload',
|
|
580
608
|
'canvas.tabHistory': 'History',
|
|
581
|
-
'canvas.tabGallery': '
|
|
609
|
+
'canvas.tabGallery': 'Assets',
|
|
610
|
+
'canvas.imageMenuUpload': 'Upload local image',
|
|
611
|
+
'canvas.imageMenuAssets': 'Pick from assets',
|
|
612
|
+
'canvas.imageMenuHistory': 'Pick from history',
|
|
613
|
+
'canvas.imageMenuGenerate': 'Generate with AI',
|
|
582
614
|
'canvas.tabGenerate': 'AI generate',
|
|
583
615
|
'canvas.dropHint': 'Drop images here to add them',
|
|
584
616
|
'canvas.dropSub': 'Multiple files, PNG / JPG / WebP / GIF',
|
|
@@ -723,9 +755,13 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
723
755
|
'history.ratio': 'Ratio filter',
|
|
724
756
|
'history.allModels': 'All models',
|
|
725
757
|
'history.allRatios': 'All ratios',
|
|
726
|
-
'gallery.title': '
|
|
758
|
+
'gallery.title': 'Assets',
|
|
727
759
|
'gallery.categories': 'Categories',
|
|
728
|
-
'gallery.all': 'All
|
|
760
|
+
'gallery.all': 'All assets',
|
|
761
|
+
'gallery.upload': 'Upload',
|
|
762
|
+
'gallery.uploadModel': 'Local upload',
|
|
763
|
+
'gallery.uploaded': 'Asset saved',
|
|
764
|
+
'gallery.uploadHint': 'Save local images for reuse on the canvas',
|
|
729
765
|
'gallery.gpt': 'gpt-image-2',
|
|
730
766
|
'gallery.grok': 'grok-imagine-image',
|
|
731
767
|
'gallery.ratio': 'Aspect ratio',
|
|
@@ -818,6 +854,8 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
818
854
|
'settings.removeModel': 'Remove model',
|
|
819
855
|
'settings.optional': 'Optional',
|
|
820
856
|
'settings.moreOptions': 'More settings',
|
|
857
|
+
'settings.localStoragePath': 'Local image storage directory',
|
|
858
|
+
'settings.localStoragePathHint': 'History, assets and canvas images share this directory; leave empty for the default ~/.dsh/dsh-imagegen.',
|
|
821
859
|
'settings.storageTitle': 'Object storage sync',
|
|
822
860
|
'settings.storageEnabled': 'Enable object storage sync',
|
|
823
861
|
'settings.storageHint': 'After images land locally, mirror them to an S3-compatible store (Tencent COS / Alibaba OSS / Qiniu S3 / MinIO / R2 …)',
|
|
@@ -1011,7 +1049,15 @@ export const ru: Record<keyof typeof zh, string> = {
|
|
|
1011
1049
|
'canvas.deleteCanvasConfirm': 'Нажмите ещё раз для подтверждения',
|
|
1012
1050
|
'canvas.rename': 'Переименовать холст',
|
|
1013
1051
|
'canvas.renameHint': 'Двойной клик — переименовать',
|
|
1014
|
-
'canvas.background': '
|
|
1052
|
+
'canvas.background': 'Фон холста',
|
|
1053
|
+
'canvas.backgroundDots': 'Точки',
|
|
1054
|
+
'canvas.backgroundLines': 'Сетка',
|
|
1055
|
+
'canvas.backgroundDiagonal': 'Диагональ',
|
|
1056
|
+
'canvas.backgroundChecker': 'Шахматка',
|
|
1057
|
+
'canvas.backgroundBlank': 'Пустой',
|
|
1058
|
+
'canvas.backgroundUpload': 'Загрузить свой фон…',
|
|
1059
|
+
'canvas.backgroundRemove': 'Убрать свой фон',
|
|
1060
|
+
'canvas.templateLibrary': 'Библиотека шаблонов (выберите промпт — создадутся текстовый узел и узел конфигурации)',
|
|
1015
1061
|
'canvas.undo': 'Отменить (Ctrl+Z)',
|
|
1016
1062
|
'canvas.redo': 'Повторить (Ctrl+Shift+Z)',
|
|
1017
1063
|
'canvas.saving': 'Сохранение…',
|
|
@@ -1032,6 +1078,7 @@ export const ru: Record<keyof typeof zh, string> = {
|
|
|
1032
1078
|
'canvas.generatingNode': 'Генерация…',
|
|
1033
1079
|
'canvas.generateFailed': 'Не удалось создать изображение',
|
|
1034
1080
|
'canvas.retry': 'Повторить',
|
|
1081
|
+
'canvas.taskLost': 'Задача генерации потеряна (сервис перезапущен); повторите',
|
|
1035
1082
|
'canvas.emptyImageNode': 'Нажмите, чтобы загрузить изображение',
|
|
1036
1083
|
'canvas.connectHint': 'Потяните к другому узлу, чтобы соединить',
|
|
1037
1084
|
'canvas.resizeHint': 'Потяните, чтобы изменить размер (пропорции зафиксированы)',
|
|
@@ -1060,7 +1107,11 @@ export const ru: Record<keyof typeof zh, string> = {
|
|
|
1060
1107
|
'canvas.close': 'Закрыть',
|
|
1061
1108
|
'canvas.tabUpload': 'Загрузка',
|
|
1062
1109
|
'canvas.tabHistory': 'История',
|
|
1063
|
-
'canvas.tabGallery': '
|
|
1110
|
+
'canvas.tabGallery': 'Материалы',
|
|
1111
|
+
'canvas.imageMenuUpload': 'Загрузить локальное изображение',
|
|
1112
|
+
'canvas.imageMenuAssets': 'Выбрать из материалов',
|
|
1113
|
+
'canvas.imageMenuHistory': 'Выбрать из истории',
|
|
1114
|
+
'canvas.imageMenuGenerate': 'Создать через AI',
|
|
1064
1115
|
'canvas.tabGenerate': 'AI-генерация',
|
|
1065
1116
|
'canvas.dropHint': 'Перетащите изображения сюда',
|
|
1066
1117
|
'canvas.dropSub': 'Несколько файлов, PNG / JPG / WebP / GIF',
|
|
@@ -1205,9 +1256,13 @@ export const ru: Record<keyof typeof zh, string> = {
|
|
|
1205
1256
|
'history.ratio': 'Фильтр по пропорциям',
|
|
1206
1257
|
'history.allModels': 'Все модели',
|
|
1207
1258
|
'history.allRatios': 'Все пропорции',
|
|
1208
|
-
'gallery.title': '
|
|
1259
|
+
'gallery.title': 'Материалы',
|
|
1209
1260
|
'gallery.categories': 'Категории',
|
|
1210
|
-
'gallery.all': 'Все
|
|
1261
|
+
'gallery.all': 'Все материалы',
|
|
1262
|
+
'gallery.upload': 'Загрузить',
|
|
1263
|
+
'gallery.uploadModel': 'Локальный файл',
|
|
1264
|
+
'gallery.uploaded': 'Материал добавлен',
|
|
1265
|
+
'gallery.uploadHint': 'Сохраните локальные изображения для холста',
|
|
1211
1266
|
'gallery.gpt': 'gpt-image-2',
|
|
1212
1267
|
'gallery.grok': 'grok-imagine-image',
|
|
1213
1268
|
'gallery.ratio': 'Пропорции',
|
|
@@ -1300,6 +1355,8 @@ export const ru: Record<keyof typeof zh, string> = {
|
|
|
1300
1355
|
'settings.removeModel': 'Удалить модель',
|
|
1301
1356
|
'settings.optional': 'необязательно',
|
|
1302
1357
|
'settings.moreOptions': 'Дополнительно',
|
|
1358
|
+
'settings.localStoragePath': 'Локальная папка изображений',
|
|
1359
|
+
'settings.localStoragePathHint': 'История, материалы и холст используют эту папку; пусто — ~/.dsh/dsh-imagegen.',
|
|
1303
1360
|
'settings.storageTitle': 'Синхронизация с объектным хранилищем',
|
|
1304
1361
|
'settings.storageEnabled': 'Включить синхронизацию',
|
|
1305
1362
|
'settings.storageHint': 'После сохранения локально изображения выгружаются в S3-совместимое хранилище (Tencent COS / Alibaba OSS / Qiniu S3 / MinIO / R2…)',
|
|
@@ -488,26 +488,26 @@ html[data-dsh-imagegen-active] .sidebarHistoryHost {
|
|
|
488
488
|
flex: 1;
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
-
.generation {
|
|
492
|
-
display: flex;
|
|
493
|
-
width: 100%;
|
|
494
|
-
gap: 14px;
|
|
495
|
-
min-width: 0;
|
|
496
|
-
min-height: 0;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/* The canvas workspace owns the full generation surface. Keep the classic
|
|
500
|
-
config/result DOM mounted so switching tabs remains instantaneous, but hide
|
|
501
|
-
those siblings while the scene graph is active. */
|
|
502
|
-
.generation[data-workspace='canvas'] {
|
|
503
|
-
display: flex;
|
|
504
|
-
height: 100%;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
.generation[data-workspace='canvas'] > .config,
|
|
508
|
-
.generation[data-workspace='canvas'] > .canvas {
|
|
509
|
-
display: none !important;
|
|
510
|
-
}
|
|
491
|
+
.generation {
|
|
492
|
+
display: flex;
|
|
493
|
+
width: 100%;
|
|
494
|
+
gap: 14px;
|
|
495
|
+
min-width: 0;
|
|
496
|
+
min-height: 0;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/* The canvas workspace owns the full generation surface. Keep the classic
|
|
500
|
+
config/result DOM mounted so switching tabs remains instantaneous, but hide
|
|
501
|
+
those siblings while the scene graph is active. */
|
|
502
|
+
.generation[data-workspace='canvas'] {
|
|
503
|
+
display: flex;
|
|
504
|
+
height: 100%;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.generation[data-workspace='canvas'] > .config,
|
|
508
|
+
.generation[data-workspace='canvas'] > .canvas {
|
|
509
|
+
display: none !important;
|
|
510
|
+
}
|
|
511
511
|
|
|
512
512
|
.config {
|
|
513
513
|
display: flex;
|
|
@@ -2534,12 +2534,6 @@ html[data-dsh-imagegen-chat-collapsed] [data-dsh-imagegen-chat-resizer] {
|
|
|
2534
2534
|
}
|
|
2535
2535
|
|
|
2536
2536
|
/* --- gallery workspace -------------------------------------------------------- */
|
|
2537
|
-
.config[data-gallery='true'] .configScroll > *:not(:first-child),
|
|
2538
|
-
.config[data-gallery='true'] .footer,
|
|
2539
|
-
.canvas[data-gallery='true'] > .canvasState,
|
|
2540
|
-
.canvas[data-gallery='true'] > .canvasError,
|
|
2541
|
-
.canvas[data-gallery='true'] > .canvasBody,
|
|
2542
|
-
.studio:has(.config[data-gallery='true']) > .history { display: none; }
|
|
2543
2537
|
.config[data-gallery='true'] .configScroll { display: flex; flex: none; overflow: visible; order: 1; }
|
|
2544
2538
|
.config[data-gallery='true'] .galleryFilters { order: 2; flex: 1; min-height: 0; }
|
|
2545
2539
|
.galleryFilters { padding: 18px 14px; overflow-y: auto; overflow-x: hidden; }
|