@goodandready/dsh-tts 0.3.3 → 0.3.5

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.
Files changed (2) hide show
  1. package/lib/client.js +54 -34
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -29,33 +29,31 @@ window.__ModuleLoader__.load({
29
29
  '.dts-wrap{display:flex;flex-direction:column;gap:22px;padding:4px 0;max-width:720px}' +
30
30
  '.dts-block{display:flex;flex-direction:column;gap:10px}' +
31
31
  '.dts-h{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary)}' +
32
- '.dts-sub{font-size:12px;color:var(--dsw-alias-label-secondary)}' +
32
+ // Единый вид карточки «Настройки плагинов»: значения из канона
33
+ // (issue #19), цвета только переменными темы.
34
+ '.dts-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none}' +
35
+ '.dts-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 16px}' +
36
+ '.dts-headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}' +
37
+ '.dts-title{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}' +
38
+ '.dts-sub{color:var(--dsw-alias-label-secondary);font-size:13px}' +
39
+ '.dts-chev{margin-left:auto;color:var(--dsw-alias-label-secondary);flex:none;transition:transform .16s}' +
40
+ '.dts-chevOpen{transform:rotate(180deg)}' +
41
+ '.dts-body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}' +
42
+ '.dts-field{display:flex;flex-direction:column;gap:6px;padding:12px 0}' +
43
+ '.dts-input{height:34px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px}' +
44
+ '.dts-foot{border-top:1px solid var(--dsw-alias-border-l2);display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px}' +
45
+ '.dts-save{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}' +
46
+ // Помощники внутренней формы (цепочка провайдеров).
33
47
  '.dts-entry{display:flex;flex-direction:column;gap:8px;padding:10px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px}' +
34
48
  '.dts-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}' +
35
- '.dts-row select,.dts-row input,.dts-field input,.dts-field select{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);border-radius:6px;padding:6px 8px;font-size:13px}' +
36
49
  '.dts-row .dts-model{flex:1;min-width:120px}' +
37
50
  '.dts-row .dts-key{flex:1;min-width:180px}' +
38
- '.dts-field{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--dsw-alias-label-secondary)}' +
39
51
  '.dts-mini{border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-primary);border-radius:6px;width:28px;height:28px;cursor:pointer;flex:none}' +
40
- '.dts-save{background:var(--dsw-alias-brand-primary);color:#fff;border:none;border-radius:6px;padding:7px 14px;font-size:13px;cursor:pointer}' +
41
52
  '.dts-ok{font-size:12px;color:var(--dsw-alias-state-success-primary)}' +
42
53
  '.dts-bad{font-size:12px;color:var(--dsw-alias-state-error-primary)}' +
43
54
  '.dts-badge{font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);white-space:nowrap}' +
44
55
  '.dts-badge-on{color:var(--dsw-alias-state-success-primary);border-color:currentColor}' +
45
- '.dts-link{background:none;border:none;color:var(--dsw-alias-label-secondary);cursor:pointer;font-size:12px;padding:0}' +
46
- // Карточка во вкладке «Настройки плагинов» — как у соседних
47
- // плагинов: li в списке ядра, шапка со сбросом темы, шеврон.
48
- '.dts-card{list-style:none;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;transition:border-color .16s,background .16s}' +
49
- '.dts-card:hover{border-color:var(--dsw-alias-label-dimmed)}' +
50
- '.dts-cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}' +
51
- '.dts-cardHead{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}' +
52
- '.dts-cardHead:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}' +
53
- '.dts-headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}' +
54
- '.dts-name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}' +
55
- '.dts-descr{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}' +
56
- '.dts-chev{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}' +
57
- '.dts-chevOpen{transform:rotate(180deg)}' +
58
- '.dts-cardBody{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding:16px 0 8px}'
56
+ '.dts-link{background:none;border:none;color:var(--dsw-alias-label-secondary);cursor:pointer;font-size:12px;padding:0}'
59
57
 
60
58
  const setCssId = 'dsh-tts/settings.module.css'
61
59
  if (typeof document !== 'undefined' && !document.querySelector('style[data-plugin-css="' + setCssId + '"]')) {
@@ -278,15 +276,16 @@ window.__ModuleLoader__.load({
278
276
  return React.createElement('div', { className: 'dts-entry', key: i },
279
277
  React.createElement('div', { className: 'dts-row' },
280
278
  React.createElement('select', {
279
+ className: 'dts-input',
281
280
  value: row.provider, disabled: !props.writable,
282
281
  onChange: (e) => change(i, { provider: e.target.value }),
283
282
  }, PROVIDERS.map((p) => React.createElement('option', { key: p, value: p }, p))),
284
283
  React.createElement('input', {
285
- className: 'dts-model', value: row.model || '', disabled: !props.writable,
284
+ className: 'dts-model dts-input', value: row.model || '', disabled: !props.writable,
286
285
  placeholder: MODEL_HINT[row.provider] || '', onChange: (e) => change(i, { model: e.target.value }),
287
286
  }),
288
287
  React.createElement('input', {
289
- className: 'dts-model', value: row.voice || '', disabled: !props.writable,
288
+ className: 'dts-model dts-input', value: row.voice || '', disabled: !props.writable,
290
289
  placeholder: 'voice', onChange: (e) => change(i, { voice: e.target.value }),
291
290
  }),
292
291
  React.createElement('button', { type: 'button', className: 'dts-mini', title: t('up'), disabled: !props.writable, onClick: () => move(i, -1) }, '\u2191'),
@@ -295,7 +294,7 @@ window.__ModuleLoader__.load({
295
294
  ),
296
295
  cloud ? React.createElement('div', { className: 'dts-row' },
297
296
  React.createElement('input', {
298
- className: 'dts-key', type: 'password', autoComplete: 'off',
297
+ className: 'dts-key dts-input', type: 'password', autoComplete: 'off',
299
298
  value: draft, disabled: !props.writable || !cred.writable,
300
299
  placeholder: cred.configured ? 'leave blank to keep' : 'paste API key',
301
300
  onChange: (e) => props.onDraft(row.provider, e.target.value),
@@ -514,6 +513,7 @@ window.__ModuleLoader__.load({
514
513
  const numberField = (key, label, hint, step) => React.createElement('label', { className: 'dts-field' }, label,
515
514
  React.createElement('input', {
516
515
  type: 'number', step: step || 1,
516
+ className: 'dts-input',
517
517
  value: draft && draft[key] !== undefined ? draft[key] : '', disabled: !writable,
518
518
  onChange: (e) => setTop(key, Number(e.target.value)),
519
519
  }),
@@ -521,14 +521,17 @@ window.__ModuleLoader__.load({
521
521
 
522
522
  const textField = (key, label, hint) => React.createElement('label', { className: 'dts-field' }, label,
523
523
  React.createElement('input', {
524
+ className: 'dts-input',
524
525
  value: draft && draft[key] !== undefined ? draft[key] : '', disabled: !writable,
525
526
  onChange: (e) => setTop(key, e.target.value),
526
527
  }),
527
528
  React.createElement('span', { className: 'dts-sub' }, hint))
528
529
 
530
+ // В карточке заголовок рисует шапка — свой блок не дублируем.
531
+ const titleLine = props && props.compact ? null : React.createElement('div', { className: 'dts-h' }, t('title'))
529
532
  return React.createElement('div', { className: 'dts-wrap' },
530
533
  React.createElement('div', { className: 'dts-block' },
531
- React.createElement('div', { className: 'dts-h' }, t('title')),
534
+ titleLine,
532
535
  React.createElement('label', { className: 'dts-row' },
533
536
  React.createElement('input', {
534
537
  type: 'checkbox', checked: !!(draft && draft.speakReplies), disabled: !writable,
@@ -572,7 +575,7 @@ window.__ModuleLoader__.load({
572
575
  textField('edgeBin', t('edgeBin'), t('edgeHint')),
573
576
  textField('azureRegion', t('azureRegion'), t('azureHint')),
574
577
  ),
575
- React.createElement('div', { className: 'dts-row' },
578
+ React.createElement('div', { className: 'dts-foot' },
576
579
  React.createElement('button', { type: 'button', className: 'dts-save', disabled: !writable, onClick: save }, t('save')),
577
580
  saved ? React.createElement('span', { className: 'dts-ok' }, t('saved')) : null,
578
581
  err ? React.createElement('span', { className: 'dts-bad' }, err) : null,
@@ -581,23 +584,22 @@ window.__ModuleLoader__.load({
581
584
  }
582
585
 
583
586
 
584
- // Карточка во вкладке «Настройки плагинов» — та же структура, что у
585
- // ядра и соседних плагинов: li в списке, шапка-кнопка со сбросом
586
- // темы (иначе браузерный стиль кнопки красит её фирменным акцентом),
587
- // шеврон, тело с формой.
587
+ // Карточка во вкладке «Настройки плагинов» — разметка и стили по
588
+ // единому канону (issue #19): li в списке ядра, шапка со сбросом темы,
589
+ // тело с чертой-разделителем. Шеврон — наш, ядро его не даёт.
588
590
  function TtsCard(props) {
589
591
  const t = (props && props.t) || ((key) => key)
590
592
  const [open, setOpen] = React.useState(false)
591
- return React.createElement('li', { className: 'dts-card' + (open ? ' dts-cardOpen' : '') },
593
+ return React.createElement('li', { className: 'dts-card' },
592
594
  React.createElement('button', {
593
595
  type: 'button',
594
- className: 'dts-cardHead',
596
+ className: 'dts-head',
595
597
  onClick: () => setOpen(!open),
596
598
  'aria-expanded': open,
597
599
  },
598
600
  React.createElement('div', { className: 'dts-headText' },
599
- React.createElement('div', { className: 'dts-name' }, t('title')),
600
- React.createElement('div', { className: 'dts-descr' }, t('cardHint')),
601
+ React.createElement('div', { className: 'dts-title' }, t('title')),
602
+ React.createElement('div', { className: 'dts-sub' }, t('cardHint')),
601
603
  ),
602
604
  React.createElement('svg', {
603
605
  className: 'dts-chev' + (open ? ' dts-chevOpen' : ''),
@@ -609,8 +611,8 @@ window.__ModuleLoader__.load({
609
611
  }),
610
612
  ),
611
613
  ),
612
- open ? React.createElement('div', { className: 'dts-cardBody' },
613
- React.createElement(TtsSection, props),
614
+ open ? React.createElement('div', { className: 'dts-body' },
615
+ React.createElement(TtsSection, Object.assign({}, props, { compact: true })),
614
616
  ) : null,
615
617
  )
616
618
  }
@@ -644,7 +646,25 @@ window.__ModuleLoader__.load({
644
646
  }
645
647
 
646
648
  function registerSettings(ctx) {
647
- ctx.effect(() => ctx.locale.register(NS, { en, ru }), 'dsh-tts: словари')
649
+ // Язык может принести не только плагин: словарные пакеты объявляют
650
+ // русский для чужих пространств. Ядро на повторное объявление той же
651
+ // пары «пространство + язык» бросает исключение, и незащищённый вызов
652
+ // уносил с собой весь плагин — в интерфейсе это выглядело как «Failed to
653
+ // load plugins» с перечнем ни в чём не повинных соседей.
654
+ //
655
+ // Поэтому каждый язык объявляется отдельно и по-хорошему: заняли до нас —
656
+ // уступаем, свой английский при этом всё равно встаёт на место.
657
+ const addLocale = (locale, dictionary) => {
658
+ try {
659
+ return ctx.locale.register(NS, locale, dictionary)
660
+ } catch (alreadyTaken) {
661
+ return () => {}
662
+ }
663
+ }
664
+ ctx.effect(() => {
665
+ const undo = [addLocale('en', en), addLocale('ru', ru)]
666
+ return () => { for (const off of undo) off() }
667
+ }, 'dsh-tts: словари')
648
668
  // Подпись раздела рисует боковой список, а не наш компонент: props.t
649
669
  // туда не доходит, поэтому берём переводчик, привязанный к namespace.
650
670
  const t = ctx.locale.bind(NS)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-tts",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Text-to-speech for DeepSeek Harness: speak agent replies in the Web UI with a provider fallback chain (OpenAI, ElevenLabs, Google, Azure, Groq, Deepgram, OpenRouter, Edge, Piper, eSpeak).",
5
5
  "license": "MIT",
6
6
  "type": "module",