dsh-web-icon-indicator 0.1.0 → 0.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 ADDED
@@ -0,0 +1,533 @@
1
+ /**
2
+ * Browser half of dsh-web-icon-indicator (dsh.client bundle, ModuleLoader
3
+ * factory format — hand-written, no build step).
4
+ *
5
+ * Registers one card into the shared "plugin configuration" surface
6
+ * (`settings.plugin.item`, keyed by the `web-icon-indicator` settings
7
+ * namespace). The card binds the namespace's settings scope, stages edits
8
+ * locally, and writes them through `scope.set` / `scope.unset` (validated and
9
+ * persisted host-side into the profile's settings.yaml).
10
+ *
11
+ * The tab that dispatches this slot (`dsh-client-ui-settings-plugins`) only
12
+ * renders the card while the host serves the namespace, so this bundle is
13
+ * inert on deployments that do not compose the host plugin.
14
+ */
15
+ window.__ModuleLoader__.load({
16
+ id: "dsh-web-icon-indicator",
17
+ factory: (require) => {
18
+ var module = { exports: {} };
19
+ var exports = module.exports;
20
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
21
+
22
+ var React = require("react");
23
+ var useState = React.useState;
24
+ var useSyncExternalStore = React.useSyncExternalStore;
25
+ var createElement = React.createElement;
26
+ // Official UI primitives (same source the shell's own plugin cards use,
27
+ // e.g. dsh-client-ui-settings-plugins): the standard collapse chevron.
28
+ var primitives = require("@deepseek-ai/dsh-client-ui-primitives");
29
+
30
+ /** Settings namespace owned by the host plugin (must match lib/index.js). */
31
+ var NS = "web-icon-indicator";
32
+ var LOCALE = "dsh-web-icon-indicator";
33
+ var STATE_NAMES = ["idle", "running", "asking", "done"];
34
+ var EFFECT_NAMES = ["static", "blink", "breath", "rainbow", "heartbeat", "bounce"];
35
+ var TOP_NUMBERS = ["askingHoldMs", "doneHoldMs"];
36
+
37
+ /** Cordis fiber services this browser plugin injects. */
38
+ var inject = ["slots", "settingsScope", "locale"];
39
+
40
+ // ---------------------------------------------------------------------------
41
+ // Locale copy
42
+ // ---------------------------------------------------------------------------
43
+ var en = {
44
+ title: "Favicon indicator",
45
+ description: "How the browser tab favicon reflects session state.",
46
+ expand: "Show settings",
47
+ collapse: "Hide settings",
48
+ askingHoldMs: "Asking hold (ms)",
49
+ askingHoldMsHint: "Minimum visibility of the asking icon before it settles.",
50
+ doneHoldMs: "Done hold (ms)",
51
+ doneHoldMsHint: "How long the done icon stays before returning to idle.",
52
+ stateLabel: "State",
53
+ effect: "Effect",
54
+ effectHint: "Animation for this state.",
55
+ colors: "Colors",
56
+ colorsHint: "Comma-separated hex colors; the first is the primary color.",
57
+ speed: "Cycle (ms)",
58
+ speedHint: "Per-state cycle length; blank keeps the current value.",
59
+ unsaved: "Unsaved",
60
+ readOnly: "This deployment stores settings read-only.",
61
+ save: "Save",
62
+ saving: "Saving…",
63
+ discard: "Discard",
64
+ resetAll: "Reset to defaults",
65
+ saveFailed: "The deployment did not accept these values; they were left for you to correct.",
66
+ invalidNumber: "Enter a number, or leave blank to use the default.",
67
+ invalidColors: "Enter hex colors like #FACC15, separated by commas.",
68
+ };
69
+ var zh = {
70
+ title: "标签页图标指示器",
71
+ description: "浏览器标签页图标如何反映会话状态。",
72
+ expand: "展开设置",
73
+ collapse: "收起设置",
74
+ askingHoldMs: "提问驻留(毫秒)",
75
+ askingHoldMsHint: "提问图标的最短可见时长。",
76
+ doneHoldMs: "完成驻留(毫秒)",
77
+ doneHoldMsHint: "完成图标停留多久后回到待机。",
78
+ stateLabel: "状态",
79
+ effect: "特效",
80
+ effectHint: "该状态的动画效果。",
81
+ colors: "颜色",
82
+ colorsHint: "逗号分隔的十六进制颜色;第一个为主色。",
83
+ speed: "周期(毫秒)",
84
+ speedHint: "该状态的动画周期;留空保持当前值。",
85
+ unsaved: "未保存",
86
+ readOnly: "本部署的设置为只读。",
87
+ save: "保存",
88
+ saving: "保存中…",
89
+ discard: "放弃修改",
90
+ resetAll: "恢复默认",
91
+ saveFailed: "本部署没有接受这些值,已保留供你修改。",
92
+ invalidNumber: "请填数字;留空表示使用默认值。",
93
+ invalidColors: "请输入 #FACC15 形式的十六进制颜色,用逗号分隔。",
94
+ };
95
+
96
+ // ---------------------------------------------------------------------------
97
+ // Small field primitives (inline styles on the shell's design tokens)
98
+ // ---------------------------------------------------------------------------
99
+ var styles = {
100
+ card: { border: "1px solid var(--dsw-alias-border-l2)", background: "var(--dsw-alias-bg-layer-3)", borderRadius: 12, padding: "14px 16px", margin: 0 },
101
+ header: { appearance: "none", width: "100%", font: "inherit", color: "inherit", textAlign: "left", cursor: "pointer", background: "0 0", border: "0", borderRadius: 12, display: "flex", alignItems: "center", gap: 12, padding: 0 },
102
+ body: { borderTop: "1px solid var(--dsw-alias-border-l2)", marginTop: 12, paddingTop: 4 },
103
+ headText: { display: "flex", flexDirection: "column", gap: 4, flex: 1, minWidth: 0 },
104
+ name: { display: "block", color: "var(--dsw-alias-label-primary)", fontSize: 15, fontWeight: 600, lineHeight: "1.4", margin: 0 },
105
+ description: { display: "block", color: "var(--dsw-alias-label-tertiary)", fontSize: 13, lineHeight: "1.5", margin: 0 },
106
+ chevron: { color: "var(--dsw-alias-label-tertiary)", flex: "none", fontSize: 14, lineHeight: 1, transition: "transform .16s" },
107
+ chevronOpen: { transform: "rotate(180deg)" },
108
+ field: { display: "flex", flexDirection: "column", gap: 6, padding: "12px 0" },
109
+ fieldBorder: { borderTop: "1px solid var(--dsw-alias-border-l2)" },
110
+ label: { color: "var(--dsw-alias-label-primary)", fontSize: 13, fontWeight: 500, lineHeight: "1.5" },
111
+ hint: { color: "var(--dsw-alias-label-tertiary)", fontSize: 12, lineHeight: "1.5", margin: 0 },
112
+ invalidText: { color: "var(--dsw-alias-label-error)", fontSize: 12, lineHeight: "1.5", margin: 0 },
113
+ select: { border: "1px solid var(--dsw-alias-border-l2)", background: "var(--dsw-alias-bg-layer-3)", height: 34, borderRadius: 8, padding: "0 8px", fontSize: 13, fontFamily: "inherit", color: "var(--dsw-alias-label-primary)" },
114
+ group: { borderTop: "1px solid var(--dsw-alias-border-l2)", marginTop: 4, paddingTop: 4 },
115
+ groupTitle: { color: "var(--dsw-alias-label-secondary)", fontSize: 12, fontWeight: 600, textTransform: "uppercase", letterSpacing: ".04em", margin: "10px 0 0" },
116
+ badges: { display: "inline-flex", alignItems: "center", gap: 8 },
117
+ badge: { whiteSpace: "nowrap", background: "var(--dsw-alias-bg-module-platform)", color: "var(--dsw-alias-label-secondary)", borderRadius: 999, padding: "1px 8px", fontSize: 11, fontWeight: 500, lineHeight: "17px" },
118
+ footer: { borderTop: "1px solid var(--dsw-alias-border-l2)", display: "flex", justifyContent: "flex-end", alignItems: "center", gap: 8, padding: "12px 0 4px" },
119
+ failed: { minWidth: 0, color: "var(--dsw-alias-label-error)", flex: 1, margin: 0, fontSize: 12, lineHeight: "1.5" },
120
+ };
121
+
122
+ // Layout shim for primitives.Input inside the card: make the wrapper fill
123
+ // the field row and the inner <input> flex. Primitives components carry no
124
+ // CSS-module hooks for us (the bundle has no build step), so one guarded
125
+ // style tag mirrors what the official cards' stylesheets do.
126
+ var FORM_CSS_TAG = "dsh-web-icon-indicator/form.css";
127
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(FORM_CSS_TAG) + "]") === null) {
128
+ var cssTag = document.createElement("style");
129
+ cssTag.dataset.plugin = "dsh-web-icon-indicator";
130
+ cssTag.dataset.pluginCss = FORM_CSS_TAG;
131
+ cssTag.textContent = ".dsh-wii-input{display:flex;align-items:center;width:100%}.dsh-wii-input>input{flex:1;min-width:0}";
132
+ document.head.appendChild(cssTag);
133
+ }
134
+
135
+ function fieldStyle(separated) {
136
+ return separated ? Object.assign({}, styles.field, styles.fieldBorder) : styles.field;
137
+ }
138
+
139
+ /** Style handed to primitives.Input (spread onto the inner <input>): full width + invalid border. */
140
+ function inputStyle(invalid) {
141
+ return Object.assign({ width: "100%" }, invalid ? { borderColor: "var(--dsw-alias-label-error)" } : {});
142
+ }
143
+
144
+ function LabeledField(props) {
145
+ // props: { label, hint, invalidLabel, children }
146
+ return createElement(
147
+ "div",
148
+ { style: fieldStyle(props.separated) },
149
+ createElement("label", { style: styles.label }, props.label),
150
+ props.children,
151
+ createElement("p", { style: props.invalid ? styles.invalidText : styles.hint }, props.invalid ? props.invalidLabel : props.hint)
152
+ );
153
+ }
154
+
155
+ function NumberInput(props) {
156
+ // props: { id, value, onChange, invalid, disabled, invalidLabel, hint, label }
157
+ return createElement(
158
+ LabeledField,
159
+ { label: props.label, hint: props.hint, invalid: props.invalid, invalidLabel: props.invalidLabel, separated: props.separated },
160
+ createElement(primitives.Input, {
161
+ id: props.id,
162
+ type: "text",
163
+ inputMode: "numeric",
164
+ className: "dsh-wii-input",
165
+ style: inputStyle(props.invalid),
166
+ disabled: props.disabled,
167
+ value: props.value,
168
+ onChange: function (event) { props.onChange(event.target.value); },
169
+ })
170
+ );
171
+ }
172
+
173
+ function TextInput(props) {
174
+ return createElement(
175
+ LabeledField,
176
+ { label: props.label, hint: props.hint, invalid: props.invalid, invalidLabel: props.invalidLabel, separated: props.separated },
177
+ createElement(primitives.Input, {
178
+ id: props.id,
179
+ type: "text",
180
+ className: "dsh-wii-input",
181
+ style: inputStyle(props.invalid),
182
+ disabled: props.disabled,
183
+ value: props.value,
184
+ placeholder: props.placeholder || "",
185
+ onChange: function (event) { props.onChange(event.target.value); },
186
+ })
187
+ );
188
+ }
189
+
190
+ function SelectInput(props) {
191
+ // props: { id, value, options, onChange, disabled }
192
+ return createElement(
193
+ "select",
194
+ {
195
+ id: props.id,
196
+ style: styles.select,
197
+ disabled: props.disabled,
198
+ value: props.value,
199
+ onChange: function (event) { props.onChange(event.target.value); },
200
+ },
201
+ props.options.map(function (option) {
202
+ return createElement("option", { key: option, value: option }, option);
203
+ })
204
+ );
205
+ }
206
+
207
+ // ---------------------------------------------------------------------------
208
+ // Form model
209
+ // ---------------------------------------------------------------------------
210
+ function formatNumber(value) {
211
+ return typeof value === "number" && Number.isFinite(value) ? String(value) : "";
212
+ }
213
+
214
+ function formatColors(colors) {
215
+ return Array.isArray(colors) && colors.length > 0 ? colors.join(", ") : "";
216
+ }
217
+
218
+ /** Parse a comma/space separated list of #hex colors; null when malformed. */
219
+ function parseColors(text) {
220
+ var parts = String(text).split(/[\s,]+/).filter(function (part) { return part.length > 0; });
221
+ if (parts.length === 0) return null;
222
+ var colors = [];
223
+ for (var i = 0; i < parts.length; i += 1) {
224
+ var candidate = parts[i].trim();
225
+ if (!/^#[0-9a-fA-F]{3,6}$/.test(candidate)) return null;
226
+ colors.push(candidate);
227
+ }
228
+ return colors;
229
+ }
230
+
231
+ function isValidNumber(text, min) {
232
+ var trimmed = text.trim();
233
+ if (trimmed === "") return { kind: "clear" };
234
+ var parsed = Number(trimmed);
235
+ if (!Number.isFinite(parsed) || parsed < min) return null;
236
+ return { kind: "set", value: parsed };
237
+ }
238
+
239
+ /** Subscribe a React component to the scope's snapshot store. */
240
+ function useScopeSnapshot(scope) {
241
+ return useSyncExternalStore(
242
+ function (listener) { return scope.subscribe(listener); },
243
+ function () { return scope.getSnapshot(); },
244
+ function () { return scope.getSnapshot(); }
245
+ );
246
+ }
247
+
248
+ // ---------------------------------------------------------------------------
249
+ // The card
250
+ // ---------------------------------------------------------------------------
251
+ function IconConfigCard(props) {
252
+ var scope = props.scope;
253
+ var t = props.t;
254
+ var snapshot = useScopeSnapshot(scope);
255
+ var ready = snapshot !== null && snapshot.status === "ready" && snapshot.value !== void 0;
256
+ var value = ready ? snapshot.value : null;
257
+ var writable = ready && snapshot.writable !== false;
258
+ var userLayer = ready ? snapshot.user : void 0;
259
+ var userHas = function (key) { return userLayer !== void 0 && Object.prototype.hasOwnProperty.call(userLayer, key); };
260
+
261
+ var draftState = useState({});
262
+ var drafts = draftState[0];
263
+ var setDrafts = draftState[1];
264
+ var failedState = useState(null);
265
+ var failed = failedState[0];
266
+ var setFailed = failedState[1];
267
+ var savingState = useState(false);
268
+ var saving = savingState[0];
269
+ var setSaving = savingState[1];
270
+ var openState = useState(false);
271
+ var open = openState[0];
272
+ var setOpen = openState[1];
273
+
274
+ if (!ready || value === null) return null;
275
+
276
+ var edit = function (key, text) {
277
+ var next = Object.assign({}, drafts);
278
+ next[key] = text;
279
+ setDrafts(next);
280
+ setFailed(null);
281
+ };
282
+ var discard = function () {
283
+ if (Object.keys(drafts).length === 0 && failed === null) return;
284
+ setDrafts({});
285
+ setFailed(null);
286
+ };
287
+
288
+ var stateOf = function (name) {
289
+ return (value.states || {})[name] || {};
290
+ };
291
+ var fieldValue = function (key) {
292
+ return Object.prototype.hasOwnProperty.call(drafts, key) ? drafts[key] : formatNumber(value[key]);
293
+ };
294
+ var stateFieldValue = function (name, kind) {
295
+ var key = "states." + name + "." + kind;
296
+ if (Object.prototype.hasOwnProperty.call(drafts, key)) return drafts[key];
297
+ var state = stateOf(name);
298
+ if (kind === "effect") return state.effect || "static";
299
+ if (kind === "colors") return formatColors(state.colors);
300
+ return formatNumber(state.speed);
301
+ };
302
+
303
+ var dirty = Object.keys(drafts).length > 0;
304
+
305
+ var save = function () {
306
+ if (!writable || saving || !dirty) return;
307
+ var ops = [];
308
+ var i;
309
+ var key;
310
+ // Top-level numbers: draft absent → untouched; blank → clear (unset).
311
+ for (i = 0; i < TOP_NUMBERS.length; i += 1) {
312
+ key = TOP_NUMBERS[i];
313
+ if (!Object.prototype.hasOwnProperty.call(drafts, key)) continue;
314
+ var parsed = isValidNumber(drafts[key], 0);
315
+ if (parsed === null) { setFailed("invalidNumber"); return; }
316
+ if (parsed.kind === "clear") { if (userHas(key)) ops.push({ op: "unset", field: key }); }
317
+ else if (parsed.value !== value[key]) ops.push({ op: "set", field: key, value: parsed.value });
318
+ }
319
+ // Per-state visuals: rebuild the whole `states` object from the resolved
320
+ // values with the drafts applied (deep-merged over the user layer).
321
+ var statesDirty = false;
322
+ var nextStates = {};
323
+ for (i = 0; i < STATE_NAMES.length; i += 1) {
324
+ var name = STATE_NAMES[i];
325
+ var effKey = "states." + name + ".effect";
326
+ var colKey = "states." + name + ".colors";
327
+ var spdKey = "states." + name + ".speed";
328
+ var hasEff = Object.prototype.hasOwnProperty.call(drafts, effKey);
329
+ var hasCol = Object.prototype.hasOwnProperty.call(drafts, colKey);
330
+ var hasSpd = Object.prototype.hasOwnProperty.call(drafts, spdKey);
331
+ if (!hasEff && !hasCol && !hasSpd) continue;
332
+ statesDirty = true;
333
+ var current = stateOf(name);
334
+ var effect = hasEff ? drafts[effKey] : current.effect || "static";
335
+ var colors = current.colors;
336
+ if (hasCol) {
337
+ var parsedColors = parseColors(drafts[colKey]);
338
+ if (parsedColors === null) { setFailed("invalidColors"); return; }
339
+ colors = parsedColors;
340
+ }
341
+ var speed = current.speed;
342
+ if (hasSpd) {
343
+ var speedParse = isValidNumber(drafts[spdKey], 1);
344
+ if (speedParse === null) { setFailed("invalidNumber"); return; }
345
+ speed = speedParse.kind === "clear" ? void 0 : speedParse.value;
346
+ }
347
+ var next = { effect: effect, colors: colors };
348
+ if (speed !== void 0) next.speed = speed;
349
+ nextStates[name] = next;
350
+ }
351
+ if (statesDirty) ops.push({ op: "set", field: "states", value: nextStates });
352
+
353
+ if (ops.length === 0) return;
354
+ setSaving(true);
355
+ setFailed(null);
356
+ var run = Promise.resolve();
357
+ var ok = true;
358
+ for (i = 0; i < ops.length; i += 1) {
359
+ (function (op) {
360
+ run = run.then(function () {
361
+ if (!ok) return;
362
+ if (op.op === "set") return scope.set(op.field, op.value);
363
+ return scope.unset(op.field);
364
+ }).then(void 0, function () { ok = false; });
365
+ })(ops[i]);
366
+ }
367
+ run.then(function () {
368
+ setSaving(false);
369
+ if (ok) { setDrafts({}); setFailed(null); }
370
+ else setFailed("saveFailed");
371
+ });
372
+ };
373
+
374
+ var resetAll = function () {
375
+ if (!writable || saving) return;
376
+ setSaving(true);
377
+ Promise.all([
378
+ scope.unset("askingHoldMs"),
379
+ scope.unset("doneHoldMs"),
380
+ scope.unset("states"),
381
+ ]).then(function () {
382
+ setSaving(false);
383
+ setDrafts({});
384
+ setFailed(null);
385
+ }, function () {
386
+ setSaving(false);
387
+ setFailed("saveFailed");
388
+ });
389
+ };
390
+
391
+ var disabled = !writable || saving;
392
+
393
+ return createElement(
394
+ "div",
395
+ { style: styles.card },
396
+ createElement(
397
+ "button",
398
+ {
399
+ type: "button",
400
+ style: styles.header,
401
+ "aria-expanded": open,
402
+ "aria-label": t(open ? "collapse" : "expand") + ": " + t("title"),
403
+ onClick: function () { setOpen(!open); },
404
+ },
405
+ createElement(
406
+ "span",
407
+ { style: styles.headText },
408
+ createElement("span", { style: styles.name }, t("title")),
409
+ createElement("span", { style: styles.description }, t("description"))
410
+ ),
411
+ dirty ? createElement("span", { style: styles.badge }, t("unsaved")) : null,
412
+ createElement(
413
+ "span",
414
+ { style: Object.assign({}, styles.chevron, open ? styles.chevronOpen : {}) },
415
+ createElement(primitives.IconChevronDownOutline14, {})
416
+ )
417
+ ),
418
+ open ? createElement(
419
+ "div",
420
+ { style: styles.body },
421
+ !writable ? createElement("p", { style: styles.hint }, t("readOnly")) : null,
422
+ createElement(NumberInput, {
423
+ id: "plugin-config-icon-asking-hold",
424
+ label: t("askingHoldMs"),
425
+ hint: t("askingHoldMsHint"),
426
+ invalidLabel: t("invalidNumber"),
427
+ invalid: failed === "invalidNumber",
428
+ disabled: disabled,
429
+ separated: true,
430
+ value: fieldValue("askingHoldMs"),
431
+ onChange: function (text) { edit("askingHoldMs", text); },
432
+ }),
433
+ createElement(NumberInput, {
434
+ id: "plugin-config-icon-done-hold",
435
+ label: t("doneHoldMs"),
436
+ hint: t("doneHoldMsHint"),
437
+ invalidLabel: t("invalidNumber"),
438
+ invalid: failed === "invalidNumber",
439
+ disabled: disabled,
440
+ separated: true,
441
+ value: fieldValue("doneHoldMs"),
442
+ onChange: function (text) { edit("doneHoldMs", text); },
443
+ }),
444
+ STATE_NAMES.map(function (name, index) {
445
+ return createElement(
446
+ "div",
447
+ { key: name, style: styles.group },
448
+ createElement("p", { style: styles.groupTitle }, t("stateLabel") + ": " + name),
449
+ createElement(
450
+ LabeledField,
451
+ { label: t("effect"), hint: t("effectHint"), invalid: false, invalidLabel: "", separated: true },
452
+ createElement(SelectInput, {
453
+ id: "plugin-config-icon-" + name + "-effect",
454
+ options: EFFECT_NAMES,
455
+ disabled: disabled,
456
+ value: stateFieldValue(name, "effect"),
457
+ onChange: function (text) { edit("states." + name + ".effect", text); },
458
+ })
459
+ ),
460
+ createElement(TextInput, {
461
+ id: "plugin-config-icon-" + name + "-colors",
462
+ label: t("colors"),
463
+ hint: t("colorsHint"),
464
+ invalidLabel: t("invalidColors"),
465
+ invalid: failed === "invalidColors",
466
+ disabled: disabled,
467
+ value: stateFieldValue(name, "colors"),
468
+ onChange: function (text) { edit("states." + name + ".colors", text); },
469
+ }),
470
+ createElement(NumberInput, {
471
+ id: "plugin-config-icon-" + name + "-speed",
472
+ label: t("speed"),
473
+ hint: t("speedHint"),
474
+ invalidLabel: t("invalidNumber"),
475
+ invalid: failed === "invalidNumber",
476
+ disabled: disabled,
477
+ separated: true,
478
+ value: stateFieldValue(name, "speed"),
479
+ onChange: function (text) { edit("states." + name + ".speed", text); },
480
+ })
481
+ );
482
+ }),
483
+ createElement(
484
+ "div",
485
+ { style: styles.footer },
486
+ failed !== null ? createElement("p", { style: styles.failed, role: "status" }, t(failed)) : null,
487
+ createElement(
488
+ primitives.Button,
489
+ { variant: "outline", disabled: !writable || saving, onClick: resetAll },
490
+ t("resetAll")
491
+ ),
492
+ createElement(
493
+ primitives.Button,
494
+ { variant: "outline", disabled: !dirty || saving, onClick: discard },
495
+ t("discard")
496
+ ),
497
+ createElement(
498
+ primitives.Button,
499
+ { variant: "primary", disabled: !dirty || saving || !writable, onClick: save },
500
+ t(saving ? "saving" : "save")
501
+ )
502
+ )
503
+ ) : null
504
+ );
505
+ }
506
+
507
+ // ---------------------------------------------------------------------------
508
+ // Plugin entry
509
+ // ---------------------------------------------------------------------------
510
+ function apply(ctx) {
511
+ var t = ctx.locale.bind(LOCALE);
512
+ ctx.effect(function () {
513
+ return ctx.locale.register(LOCALE, { zh: zh, en: en });
514
+ }, "dsh-web-icon-indicator: settings card dictionaries");
515
+ var scope = ctx.settingsScope.bind({ namespace: NS });
516
+ ctx.slots.inject("settings.plugin.item", function () {
517
+ return ctx.slots.register(
518
+ {
519
+ name: "settings.plugin.item",
520
+ key: NS,
521
+ locale: LOCALE,
522
+ inject: function () { return { scope: scope, t: t }; },
523
+ },
524
+ IconConfigCard
525
+ );
526
+ });
527
+ }
528
+
529
+ exports.apply = apply;
530
+ exports.inject = inject;
531
+ return module.exports;
532
+ },
533
+ });