@dickpy/dsh-imagegen 1.5.2 → 1.5.4
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 +23 -2
- package/lib/client.js +5803 -1942
- package/lib/client.js.map +1 -1
- package/lib/index.js +1151 -33
- package/package.json +1 -1
- package/src/canvas-store.ts +376 -0
- package/src/client/CanvasWorkspace.tsx +1569 -0
- package/src/client/ImageGenPanel.tsx +164 -96
- package/src/client/SettingsCard.tsx +182 -4
- package/src/client/api.ts +48 -1
- package/src/client/canvas-workspace.module.css +929 -0
- package/src/client/helpers.ts +71 -33
- package/src/client/index.ts +59 -7
- package/src/client/locales.ts +1452 -772
- package/src/client/panel.module.css +83 -33
- package/src/client/use-language.ts +14 -0
- package/src/engine.ts +302 -12
- package/src/gallery-store.ts +5 -0
- package/src/generation-runtime.ts +1 -0
- package/src/history-store.ts +5 -0
- package/src/index.ts +71 -4
- package/src/model-catalog.ts +10 -1
- package/src/presets.ts +15 -0
- package/src/protocol.ts +121 -1
- package/src/routes.ts +231 -1
- package/src/storage-sync.ts +105 -0
package/src/client/helpers.ts
CHANGED
|
@@ -1,33 +1,71 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared panel helpers: the active-dictionary pick
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Shared panel helpers: the active-dictionary pick bound to the dsh-imagegen
|
|
3
|
+
* interpolator, the plugin locale that follows the DSH interface language
|
|
4
|
+
* (bridged in client/index.ts from ctx.locale — the plugin ships zh / en / ru
|
|
5
|
+
* and registers itself as a DSH language pack for Русский), plus a small
|
|
6
|
+
* error-message extractor. All copy stays in the locale dictionaries.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { en, ru, zh, type ImageGenKey } from './locales.ts'
|
|
10
|
+
|
|
11
|
+
/** Template values accepted by the interpolator. */
|
|
12
|
+
export type TranslateValues = Record<string, string | number>
|
|
13
|
+
|
|
14
|
+
/** Languages with a shipped dictionary. */
|
|
15
|
+
export type ImageGenLanguage = 'zh' | 'en' | 'ru'
|
|
16
|
+
|
|
17
|
+
const DICTIONARIES: Record<ImageGenLanguage, Record<string, string>> = { zh, en, ru }
|
|
18
|
+
|
|
19
|
+
/** The active DSH locale mapped onto our dictionary (module-level, one value per app). */
|
|
20
|
+
let activeLocale: ImageGenLanguage = 'zh'
|
|
21
|
+
|
|
22
|
+
/** Bumped on every locale change; useSyncExternalStore version. */
|
|
23
|
+
let languageVersion = 0
|
|
24
|
+
|
|
25
|
+
const languageListeners = new Set<() => void>()
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Adopt the DSH interface language. Unknown ids (future language packs)
|
|
29
|
+
* resolve to English — the same per-key fallback convention the host locale
|
|
30
|
+
* chain uses.
|
|
31
|
+
*/
|
|
32
|
+
export function applyHostLocale(id: unknown): void {
|
|
33
|
+
const next: ImageGenLanguage = id === 'zh' || id === 'ru' ? id : 'en'
|
|
34
|
+
if (next === activeLocale) return
|
|
35
|
+
activeLocale = next
|
|
36
|
+
languageVersion += 1
|
|
37
|
+
for (const listener of [...languageListeners]) listener()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Monotonic version of the active locale (external-store snapshot). */
|
|
41
|
+
export function getImageGenLanguageVersion(): number {
|
|
42
|
+
return languageVersion
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Observe locale changes; returns the unsubscriber. */
|
|
46
|
+
export function subscribeImageGenLanguage(listener: () => void): () => void {
|
|
47
|
+
languageListeners.add(listener)
|
|
48
|
+
return () => { languageListeners.delete(listener) }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Active dictionary for the current DSH language. */
|
|
52
|
+
export function dictionary(): Record<string, string> {
|
|
53
|
+
return DICTIONARIES[activeLocale]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Translate a key with optional {name} template params (current language). */
|
|
57
|
+
export function tt(key: ImageGenKey, values?: TranslateValues): string {
|
|
58
|
+
const text = dictionary()[key] ?? key
|
|
59
|
+
if (values === undefined) return text
|
|
60
|
+
let rendered = text
|
|
61
|
+
for (const [name, value] of Object.entries(values)) {
|
|
62
|
+
rendered = rendered.replaceAll(`{${name}}`, String(value))
|
|
63
|
+
}
|
|
64
|
+
return rendered
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Human-readable error text from an unknown thrown value. */
|
|
68
|
+
export function errorMessage(error: unknown): string {
|
|
69
|
+
if (error instanceof Error) return error.message
|
|
70
|
+
return String(error)
|
|
71
|
+
}
|
package/src/client/index.ts
CHANGED
|
@@ -11,18 +11,18 @@
|
|
|
11
11
|
* whole boot when a plugin apply throws, and an external plugin must not take
|
|
12
12
|
* the GUI down.
|
|
13
13
|
*/
|
|
14
|
-
import type { Context as ClientContext } from '@deepseek-ai/cordis'
|
|
15
|
-
import type { ISessions } from '@deepseek-ai/dsh-api-session-controller/client'
|
|
14
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis'
|
|
15
|
+
import type { ISessions } from '@deepseek-ai/dsh-api-session-controller/client'
|
|
16
16
|
import type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client'
|
|
17
17
|
// Type-only: pulls the locale plugin's Context merge (ctx.locale).
|
|
18
|
-
import type {} from '@deepseek-ai/dsh-client-locale/client'
|
|
19
|
-
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
|
|
20
|
-
// Type-only: pulls the LocaleNamespaceMap merge table.
|
|
18
|
+
import type {} from '@deepseek-ai/dsh-client-locale/client'
|
|
19
|
+
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
|
|
20
|
+
// Type-only: pulls the LocaleNamespaceMap merge table.
|
|
21
21
|
import type {} from '@deepseek-ai/dsh-client-ui-slots'
|
|
22
22
|
import { ImageGenApi } from './api.ts'
|
|
23
23
|
import { ImageGenController } from './controller.ts'
|
|
24
|
-
import { tt } from './helpers.ts'
|
|
25
|
-
import { en, zh, type ImageGenKey } from './locales.ts'
|
|
24
|
+
import { tt, applyHostLocale } from './helpers.ts'
|
|
25
|
+
import { en, ru, zh, type ImageGenKey } from './locales.ts'
|
|
26
26
|
import { mountPanel } from './mount.tsx'
|
|
27
27
|
import { mountSidebarEntry } from './sidebar-entry.ts'
|
|
28
28
|
import { ImageGenSettingsCard, ImageGenSettingsCardController } from './SettingsCard.tsx'
|
|
@@ -68,7 +68,39 @@ export const inject = ['slots', 'locale', 'connection', 'sessions', 'conversatio
|
|
|
68
68
|
* @param ctx - client root context (services: slots, locale, connection).
|
|
69
69
|
*/
|
|
70
70
|
export function apply(ctx: ClientContext): void {
|
|
71
|
+
// The host locale service only knows zh/en dictionaries (its type is
|
|
72
|
+
// fixed); ru rides the untyped single-locale registration instead.
|
|
71
73
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-imagegen: dictionaries')
|
|
74
|
+
// Russian ships as a language pack: the dictionary lands in this plugin's
|
|
75
|
+
// namespace, and Русский joins the shared DSH language catalog (Settings →
|
|
76
|
+
// General → Language) with per-key fallback to English for host copy.
|
|
77
|
+
// Registration order/aggregation between register(NS, 'ru', …) and
|
|
78
|
+
// addLanguage differs across host builds and a duplicate throws — these
|
|
79
|
+
// surfaces must degrade silently, never fail the GUI boot.
|
|
80
|
+
ctx.effect(() => {
|
|
81
|
+
try {
|
|
82
|
+
return ctx.locale.register(NS, 'ru', ru)
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.warn('[dsh-imagegen] ru dictionary not registered:', error)
|
|
85
|
+
return () => {}
|
|
86
|
+
}
|
|
87
|
+
}, 'dsh-imagegen: ru dictionary')
|
|
88
|
+
ctx.effect(() => {
|
|
89
|
+
try {
|
|
90
|
+
if (ctx.locale.getLocale().locales.some(locale => locale.id === 'ru')) return () => {}
|
|
91
|
+
return ctx.locale.addLanguage({ id: 'ru', label: 'Русский', fallback: 'en' })
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.warn('[dsh-imagegen] ru language not added to the catalog:', error)
|
|
94
|
+
return () => {}
|
|
95
|
+
}
|
|
96
|
+
}, 'dsh-imagegen: ru language pack')
|
|
97
|
+
// Every plugin surface renders through tt(); bridge DSH locale switches
|
|
98
|
+
// into it so the whole plugin follows the interface language.
|
|
99
|
+
ctx.effect(() => {
|
|
100
|
+
const applyLocale = (): void => { applyHostLocale(ctx.locale.getLocale().active) }
|
|
101
|
+
applyLocale()
|
|
102
|
+
return ctx.locale.subscribe(applyLocale)
|
|
103
|
+
}, 'dsh-imagegen: follow host locale')
|
|
72
104
|
registerImageToolviews(ctx)
|
|
73
105
|
|
|
74
106
|
const connection = ctx.get('connection') as ConnectionHandle | undefined
|
|
@@ -119,6 +151,26 @@ export function apply(ctx: ClientContext): void {
|
|
|
119
151
|
tt('entry.tooltip'),
|
|
120
152
|
))
|
|
121
153
|
disposers.push(mountPanel(controller, api, scope, { sessions, conversation }))
|
|
154
|
+
// The imperative sidebar tabs render their labels once; relabel them on
|
|
155
|
+
// every DSH language switch so the entry follows the interface too.
|
|
156
|
+
disposers.push(ctx.locale.subscribe(() => {
|
|
157
|
+
const root = document.querySelector('[data-dsh-imagegen-sidebar-root]')
|
|
158
|
+
if (root === null) return
|
|
159
|
+
const labels: Array<[string, string, string]> = [
|
|
160
|
+
['new-session', tt('entry.newSession'), tt('entry.newSessionTooltip')],
|
|
161
|
+
['image', tt('entry.image'), tt('entry.tooltip')],
|
|
162
|
+
]
|
|
163
|
+
for (const [tab, label, tooltip] of labels) {
|
|
164
|
+
const button = root.querySelector<HTMLButtonElement>(`[data-dsh-imagegen-tab="${tab}"]`)
|
|
165
|
+
if (button === null) continue
|
|
166
|
+
button.setAttribute('aria-label', label)
|
|
167
|
+
button.setAttribute('title', tooltip)
|
|
168
|
+
const labelSpan = button.querySelector('span:nth-child(2)')
|
|
169
|
+
if (labelSpan !== null) labelSpan.textContent = label
|
|
170
|
+
}
|
|
171
|
+
const tablist = root.querySelector<HTMLDivElement>('[role="tablist"][data-dsh-imagegen-session-tabs]')
|
|
172
|
+
tablist?.setAttribute('aria-label', tt('entry.tooltip'))
|
|
173
|
+
}))
|
|
122
174
|
} catch (error) {
|
|
123
175
|
// DOM failures degrade the studio, never the GUI.
|
|
124
176
|
console.warn('[dsh-imagegen] mount failed:', error)
|