dsh-sidecard-ask 1.8.1 → 1.8.2
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/CHANGELOG.md +35 -0
- package/README.md +11 -5
- package/client.js +92 -21
- package/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.8.2
|
|
4
|
+
|
|
5
|
+
**主题:提问框底部的「作答位置」从"两枚看不出选中哪一侧的标签"改成一眼可辨的分段芯片;并把 1.8.1 之后写在本地、尚未提交的弹层对比度修补一并发布。**
|
|
6
|
+
|
|
7
|
+
起因是用户截图:弹层底部「作答位置 | 主对话 | 侧边卡片」两个选项长得几乎一样,看不出答案会去主对话还是侧边卡片。
|
|
8
|
+
|
|
9
|
+
- **选中态不可辨(用户反馈,已复现)**:旧选中态只有 `background: var(--dsw-alias-bg-layer-2)`,
|
|
10
|
+
叠在弹层 `--dsw-alias-bg-overlay` 上几乎是同色(本机皮肤下 `rgba(243,247,253,.95)` on
|
|
11
|
+
`rgba(248,251,255,.98)`),选中与未选中的差别只剩字重。
|
|
12
|
+
改法:`.dsa-seg` 变成带中灰描边(`rgba(127,127,127,.5)`)与内凹阴影的轨道;两个选项各带一枚 13px
|
|
13
|
+
内联 SVG 图标(气泡=主对话,带右轨的框=侧边卡片),**选中侧为品牌实底 + 白色 600 字 + 内白环 + 投影**,
|
|
14
|
+
未选侧为 `label-secondary` + 透明底;补 `:hover` 与 `:focus-visible`(品牌色 outline)。
|
|
15
|
+
组件抽成 `CarrierSeg`(client §9),带 `role="group"`、`aria-pressed`、`title` 说明;文案仍走 i18n。
|
|
16
|
+
- **深色主题里白字压品牌色只有 2.79:1(复核时发现的,非用户反馈)**:本机皮肤深色把
|
|
17
|
+
`--dsw-alias-brand-primary` 提亮到 `#5b9cf5`,白色 600 字在其上低于 4.5:1 正文下限、也低于 3:1 大字下限。
|
|
18
|
+
改法:`[data-ds-dark-theme]` 下选中侧改用深墨 `#0a1428`(实测 6.57:1);浅色保持白字
|
|
19
|
+
(`#2563c0` 上 5.79:1)。令牌值取自本机 `uiskin-theme`,对比度按 WCAG 相对亮度公式实算,不是目测。
|
|
20
|
+
- **弹层边框/阴影对比度修补(1.8.1 之后写在本地、未提交,本次一并发布)**:`.dsa-pop` 的 1px 边
|
|
21
|
+
改显式中灰 `rgba(127,127,127,.55)`(`border-l2` 落在弹层表面只量到 ≈1.3:1),阴影改两层衰减
|
|
22
|
+
`0 14px 36px rgba(0,0,0,.30), 0 3px 10px rgba(0,0,0,.14)`;`.dsa-pop` 内的次级文案改用
|
|
23
|
+
`label-primary` 并保留 `.78` 不透明度。
|
|
24
|
+
- 测试:contract 新增 **16** 项钉住这个控件(唯一 `.dsa-seg`、恰好两个按钮、恰好一个
|
|
25
|
+
`aria-pressed="true"`、每个选项带一枚内联 `svg`、`data-on` 只有一个真值、两个去向的标签不互换、
|
|
26
|
+
品牌实底规则与深色覆盖规则必须出现在样式表里)。**点击切换本身仍然不可测**:harness 的
|
|
27
|
+
`useState` 只回队列式 setter、不触发重渲染,注释里写明了原因,没有假装测过。
|
|
28
|
+
- 版本号三处同步到 1.8.2。
|
|
29
|
+
|
|
30
|
+
本机实测(四项均 exit 0):verify **57** / contract **972** / float-placement **38** / smoke **226**
|
|
31
|
+
= **1293 项全部通过**(1.8.1 为 1277,contract 956 → 972)。
|
|
32
|
+
|
|
33
|
+
> 未验证(如实记录):浅色/深色两张对比图(`design-preview/07-carrier-seg-{light,dark}.png`)是
|
|
34
|
+
> **离屏渲染**——无头 Edge 加载"从 `client.js` 抽取的真实 CSS + 本机皮肤真实令牌值"的静态页,
|
|
35
|
+
> 不是运行中 DSH 窗口的截图。真实页面里的点击手感、字体栅格化差异、弹层背后背景图的影响,
|
|
36
|
+
> 仍需刷新页面人工看一次。此前一轮口头汇报里说"新增 8 条"是数错了,实际新增 16 条。
|
|
37
|
+
|
|
3
38
|
## 1.8.1
|
|
4
39
|
|
|
5
40
|
**主题:对 1.8.0 交付做实证复核后的三项修正——1 个已复现的真实缺陷、1 处开关失效、1 条缺证据的声明。**
|
package/README.md
CHANGED
|
@@ -72,8 +72,10 @@ dsh-sidecard-ask/
|
|
|
72
72
|
├── README.md 本文件
|
|
73
73
|
├── CHANGELOG.md 版本变更记录
|
|
74
74
|
├── LICENSE MIT
|
|
75
|
-
├── design-preview/
|
|
76
|
-
│ 03-prototype-ac.html
|
|
75
|
+
├── design-preview/ 方案讨论资料,**不参与发布**:00–02 是手绘 SVG 示意图(非截图),
|
|
76
|
+
│ 03-prototype-ac.html 是可直接双击打开的可点按原型(自带近似色板,非真实观感),
|
|
77
|
+
│ 07-carrier-seg-{light,dark}.png 是 1.8.2 的离屏渲染对比图(无头 Edge + 真实 CSS
|
|
78
|
+
│ 与真实令牌值,仍非运行中窗口截图)
|
|
77
79
|
├── tools/
|
|
78
80
|
│ └── compat-probe.mjs DSH 版本能力探测(§7 矩阵的来源)
|
|
79
81
|
└── test/
|
|
@@ -515,6 +517,9 @@ node tools/compat-probe.mjs --json tools/.cache/matrix.json
|
|
|
515
517
|
2. 选区末端应浮出动作条:「💬 追问选中内容」按钮 + 「解释 / 翻译 / 总结 / 润色 / 纠错」芯片,
|
|
516
518
|
按钮带区域徽标(聊天区 / 任务区 / 跨区选择);**点任一芯片即跳过提问框直接在侧边卡片作答**;
|
|
517
519
|
3. 点主按钮后提问框出现(顶部同样有一排芯片),焦点在输入框,引文预览显示选中文本;
|
|
520
|
+
底部「作答位置」是两枚带内联图标的芯片(气泡=主对话,带右轨的框=侧边卡片):**选中侧为品牌实底 + 白字 600 + 内白环**,
|
|
521
|
+
未选侧只有描边;深色主题下选中侧改深墨字(品牌色在深色被提亮到 `#5b9cf5`,白字只有 2.79:1,深墨字 6.57:1);
|
|
522
|
+
控件带 `role="group"` 与 `aria-pressed`,键盘 Tab 可见品牌色焦点环;
|
|
518
523
|
4. 输入问题按 Enter → 提问框关闭,右下角出现卡片,状态先为「作答中…」并**逐字增长**;
|
|
519
524
|
5. 结束后状态变「已完成」;底部出现「改问 / 复制 / 继续追问 / 关闭」;答案里代码块的右上角有「⧉ 复制代码」;
|
|
520
525
|
6. 点「复制」→ 出现「已复制」提示;点「继续追问」→ 输入第二条问题(追加一轮),卡片内容**重置换行**后继续流式;
|
|
@@ -599,9 +604,10 @@ node test/smoke-test.mjs # 端到端:流式/截断/取消/持久化/失
|
|
|
599
604
|
```
|
|
600
605
|
|
|
601
606
|
四个脚本都以 `process.exitCode` 反映结果,失败会列出具体条目;测试会把 `DSH_HOME` 指向临时目录,不会污染真实配置。
|
|
602
|
-
当前规模(1.8.
|
|
603
|
-
smoke **226** 项 = **
|
|
604
|
-
|
|
607
|
+
当前规模(1.8.2 本机实测,四项均 exit 0):verify **57** 项 + contract **972** 项 + float-placement **38** 项 +
|
|
608
|
+
smoke **226** 项 = **1293 项全部通过**(1.8.1 为 1277 项,其中 contract 由 956 → 972:新增 16 项钉住提问框
|
|
609
|
+
「作答位置」分段芯片——唯一 `.dsa-seg`、两个按钮、恰好一个 `aria-pressed`、各带一枚内联图标、
|
|
610
|
+
品牌实底规则与深色覆盖规则;点击切换本身不可测,原因见 1.8.2 的 CHANGELOG)。
|
|
605
611
|
|
|
606
612
|
**真机探针(不属于四套自测)**:`.compat-report/scripts/composer-probe.mjs` 需要
|
|
607
613
|
`playwright-core` 与本机 Edge,对**真实 DSH 页面**回答 composer DOM / 哪条写入路径真能改变
|
package/client.js
CHANGED
|
@@ -47,7 +47,7 @@ window.__ModuleLoader__.load({
|
|
|
47
47
|
* the Host and the module's `api.version` both read it, so a report can
|
|
48
48
|
* never claim a generation the browser is not actually running.
|
|
49
49
|
*/
|
|
50
|
-
const CLIENT_VERSION = '1.8.
|
|
50
|
+
const CLIENT_VERSION = '1.8.2'
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Tab kind served by the DSH native right rail (also its implementation id).
|
|
@@ -1919,10 +1919,17 @@ window.__ModuleLoader__.load({
|
|
|
1919
1919
|
trigger drops its own fixed positioning, chips join the row directly. */
|
|
1920
1920
|
.dsa-trigger-embedded{position:static;box-shadow:0 2px 10px rgba(0,0,0,.18)}
|
|
1921
1921
|
.dsa-quickbar-chips{display:contents}
|
|
1922
|
+
/* Contrast pass, driven by a light-theme reference screenshot: every 1px edge
|
|
1923
|
+
inside the popover measured only ≈1.3–1.7:1 against the card surface, which
|
|
1924
|
+
is why the card read as a translucent sticker instead of a framed popover.
|
|
1925
|
+
The frame is therefore drawn explicitly here rather than through border-l2,
|
|
1926
|
+
which the host resolves below that level; mid grey is used instead of a
|
|
1927
|
+
black/white alpha so the stroke stays visible on both themes. The shadow is
|
|
1928
|
+
a two-layer falloff so the card lifts off the page as well. */
|
|
1922
1929
|
.dsa-pop{pointer-events:auto;position:fixed;width:min(420px, 92vw);display:flex;flex-direction:column;gap:8px;
|
|
1923
|
-
padding:12px;border-radius:12px;border:1px solid
|
|
1930
|
+
padding:12px;border-radius:12px;border:1px solid rgba(127,127,127,.55);
|
|
1924
1931
|
background:var(--dsw-alias-bg-overlay, #fff);color:var(--dsw-alias-label-primary, #111);
|
|
1925
|
-
box-shadow:0
|
|
1932
|
+
box-shadow:0 14px 36px rgba(0,0,0,.30),0 3px 10px rgba(0,0,0,.14);font-size:13px;line-height:19px}
|
|
1926
1933
|
.dsa-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
1927
1934
|
.dsa-title{font-weight:600;font-size:13px}
|
|
1928
1935
|
.dsa-quote{margin:0;padding:6px 8px;max-height:96px;overflow:auto;white-space:pre-wrap;word-break:break-word;
|
|
@@ -1946,11 +1953,43 @@ window.__ModuleLoader__.load({
|
|
|
1946
1953
|
/* Icon-only variant (the floating layer's collapse/hide controls): square and
|
|
1947
1954
|
quiet so the card title bar stays one line and the title keeps the weight. */
|
|
1948
1955
|
.dsa-btn-icon{padding:4px 7px;line-height:1;font-size:13px;color:var(--dsw-alias-label-secondary, #666)}
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1956
|
+
/* Segmented control (main chat / side card). These are the two destinations an
|
|
1957
|
+
answer can land in, so the pair has to read as a radio choice, not as two
|
|
1958
|
+
quiet labels: the group gets a recessed track with an explicit mid-grey edge
|
|
1959
|
+
(border-l1/l2 measured ≈1.3:1 against the popover surface and disappeared),
|
|
1960
|
+
each option carries a 13px label plus an inline glyph, and the selected side
|
|
1961
|
+
is a solid brand chip whose white 600-weight text cannot be confused with the
|
|
1962
|
+
unselected side. The inner white ring keeps the chip from flattening on the
|
|
1963
|
+
brand colour in either theme. */
|
|
1964
|
+
.dsa-seg{display:inline-flex;padding:3px;gap:3px;
|
|
1965
|
+
border:1px solid rgba(127,127,127,.5);border-radius:10px;
|
|
1966
|
+
background:var(--dsw-alias-bg-layer-1, rgba(127,127,127,.10));
|
|
1967
|
+
box-shadow:inset 0 1px 2px rgba(0,0,0,.10)}
|
|
1968
|
+
.dsa-seg button{display:inline-flex;align-items:center;gap:5px;padding:5px 12px;
|
|
1969
|
+
border:1px solid transparent;border-radius:7px;background:transparent;
|
|
1970
|
+
color:var(--dsw-alias-label-secondary, #666);font:inherit;font-size:13px;font-weight:500;
|
|
1971
|
+
line-height:18px;cursor:pointer;white-space:nowrap;
|
|
1972
|
+
transition:background .12s ease,color .12s ease,box-shadow .12s ease}
|
|
1973
|
+
.dsa-seg button svg{flex:none;opacity:.8}
|
|
1974
|
+
.dsa-seg button:hover{background:var(--dsw-alias-bg-layer-2, rgba(127,127,127,.16));
|
|
1975
|
+
color:var(--dsw-alias-label-primary, #222)}
|
|
1976
|
+
.dsa-seg button:hover svg{opacity:1}
|
|
1977
|
+
.dsa-seg button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary, #4c8dff);outline-offset:1px}
|
|
1978
|
+
.dsa-seg button[data-on="true"]{background:var(--dsw-alias-brand-primary, #4c8dff);
|
|
1979
|
+
border-color:var(--dsw-alias-brand-primary, #4c8dff);color:#fff;font-weight:600;
|
|
1980
|
+
box-shadow:0 1px 4px rgba(0,0,0,.22),inset 0 0 0 1px rgba(255,255,255,.22)}
|
|
1981
|
+
.dsa-seg button[data-on="true"] svg{opacity:1}
|
|
1982
|
+
.dsa-seg button[data-on="true"]:hover{background:var(--dsw-alias-brand-primary, #4c8dff);color:#fff}
|
|
1983
|
+
/* Dark themes lighten the brand accent (the local skin goes #2563c0 -> #5b9cf5),
|
|
1984
|
+
where white 600 text on the chip measures 2.79:1 — below the 4.5:1 floor for
|
|
1985
|
+
body text and below even the 3:1 large-text floor. Invert the on-brand label
|
|
1986
|
+
there instead of betting on one fixed foreground.
|
|
1987
|
+
DSH flags dark mode with [data-ds-dark-theme] on the root element. */
|
|
1988
|
+
html[data-ds-dark-theme] .dsa-seg button[data-on="true"],
|
|
1989
|
+
body[data-ds-dark-theme] .dsa-seg button[data-on="true"],
|
|
1990
|
+
html[data-ds-dark-theme] .dsa-seg button[data-on="true"]:hover,
|
|
1991
|
+
body[data-ds-dark-theme] .dsa-seg button[data-on="true"]:hover{
|
|
1992
|
+
color:#0a1428;text-shadow:0 1px 0 rgba(255,255,255,.25)}
|
|
1954
1993
|
.dsa-card{pointer-events:auto;display:flex;flex-direction:column;gap:8px;padding:12px;border-radius:12px;
|
|
1955
1994
|
border:1px solid var(--dsw-alias-border-l2, rgba(127,127,127,.35));
|
|
1956
1995
|
background:var(--dsw-alias-bg-overlay, #fff);color:var(--dsw-alias-label-primary, #111);
|
|
@@ -2014,6 +2053,13 @@ window.__ModuleLoader__.load({
|
|
|
2014
2053
|
.dsa-code{padding:0 4px;border-radius:4px;background:var(--dsw-alias-bg-layer-2, rgba(127,127,127,.12));
|
|
2015
2054
|
font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}
|
|
2016
2055
|
.dsa-muted{color:var(--dsw-alias-label-secondary, #666);font-size:11px;line-height:16px}
|
|
2056
|
+
/* Same contrast pass, applied to the popover's body copy: label-secondary
|
|
2057
|
+
measures ≈6:1 here and reads washed out at 11–13px. Secondary text inside
|
|
2058
|
+
.dsa-pop is re-derived from the primary label token instead, held one step
|
|
2059
|
+
quieter than the title through opacity so the hierarchy survives. */
|
|
2060
|
+
.dsa-pop .dsa-quote,
|
|
2061
|
+
.dsa-pop .dsa-muted{color:var(--dsw-alias-label-primary, #111)}
|
|
2062
|
+
.dsa-pop .dsa-muted{opacity:.78}
|
|
2017
2063
|
.dsa-error{color:var(--dsw-alias-state-error-primary, #c0392b);font-size:12px}
|
|
2018
2064
|
.dsa-toast{pointer-events:auto;position:fixed;left:50%;transform:translateX(-50%);bottom:24px;padding:6px 12px;
|
|
2019
2065
|
border-radius:999px;font-size:12px;background:var(--dsw-alias-bg-overlay, #222);
|
|
@@ -3260,6 +3306,43 @@ window.__ModuleLoader__.load({
|
|
|
3260
3306
|
}, h('span', null, action.label))))
|
|
3261
3307
|
}
|
|
3262
3308
|
|
|
3309
|
+
/** Where the answer should land: the main conversation, or an independent
|
|
3310
|
+
* side card. Rendered as a two-chip switch with an inline glyph per option
|
|
3311
|
+
* so the pair is scannable at a glance, and the selected chip is painted
|
|
3312
|
+
* with the brand fill (see .dsa-seg) instead of a whisper-grey tint. The
|
|
3313
|
+
* hint text moves into title/aria-label rather than a third line, because
|
|
3314
|
+
* the popover already has quote + chips + composer and a longer hint would
|
|
3315
|
+
* push the submit row out of view. */
|
|
3316
|
+
function CarrierSeg({ value, onChange }) {
|
|
3317
|
+
const glyph = path => h('svg', {
|
|
3318
|
+
viewBox: '0 0 16 16', width: 13, height: 13, 'aria-hidden': 'true', focusable: 'false',
|
|
3319
|
+
}, h('path', {
|
|
3320
|
+
d: path, fill: 'none', stroke: 'currentColor', strokeWidth: 1.3,
|
|
3321
|
+
strokeLinejoin: 'round', strokeLinecap: 'round',
|
|
3322
|
+
}))
|
|
3323
|
+
const options = [
|
|
3324
|
+
// speech balloon = the main conversation
|
|
3325
|
+
{ id: 'main', label: t('carrierMain'), hint: t('carrierMainHint'),
|
|
3326
|
+
icon: glyph('M2.5 3.5h11v8H8.4L5.2 14.3V11.5H2.5z') },
|
|
3327
|
+
// frame with a rail on the right = a card docked in the side panel
|
|
3328
|
+
{ id: 'side', label: t('carrierSide'), hint: t('carrierSideHint'),
|
|
3329
|
+
icon: glyph('M2.5 3.5h11v9h-11zM10 3.5v9') },
|
|
3330
|
+
]
|
|
3331
|
+
return h('div', {
|
|
3332
|
+
className: 'dsa-seg', role: 'group', 'aria-label': t('carrier'),
|
|
3333
|
+
}, options.map(option => {
|
|
3334
|
+
const on = value === option.id
|
|
3335
|
+
return h('button', {
|
|
3336
|
+
key: option.id,
|
|
3337
|
+
type: 'button',
|
|
3338
|
+
'data-on': String(on),
|
|
3339
|
+
'aria-pressed': String(on),
|
|
3340
|
+
title: option.hint,
|
|
3341
|
+
onClick: () => onChange(option.id),
|
|
3342
|
+
}, option.icon, option.label)
|
|
3343
|
+
}))
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3263
3346
|
/** The question popover. */
|
|
3264
3347
|
function AskPopover({ candidate, config, onClose, onSubmit, onQuick }) {
|
|
3265
3348
|
const [question, setQuestion] = React.useState('')
|
|
@@ -3341,19 +3424,7 @@ window.__ModuleLoader__.load({
|
|
|
3341
3424
|
}),
|
|
3342
3425
|
h('div', { className: 'dsa-row' },
|
|
3343
3426
|
h('span', { className: 'dsa-muted' }, t('carrier')),
|
|
3344
|
-
h(
|
|
3345
|
-
h('button', {
|
|
3346
|
-
type: 'button',
|
|
3347
|
-
'data-on': String(carrier === 'main'),
|
|
3348
|
-
title: t('carrierMainHint'),
|
|
3349
|
-
onClick: () => setCarrier('main'),
|
|
3350
|
-
}, t('carrierMain')),
|
|
3351
|
-
h('button', {
|
|
3352
|
-
type: 'button',
|
|
3353
|
-
'data-on': String(carrier === 'side'),
|
|
3354
|
-
title: t('carrierSideHint'),
|
|
3355
|
-
onClick: () => setCarrier('side'),
|
|
3356
|
-
}, t('carrierSide')))),
|
|
3427
|
+
h(CarrierSeg, { value: carrier, onChange: setCarrier })),
|
|
3357
3428
|
h('div', { className: 'dsa-row', style: { justifyContent: 'flex-end' } },
|
|
3358
3429
|
h('span', { className: 'dsa-muted', style: { marginRight: 'auto' } },
|
|
3359
3430
|
t('askShortcutHint', { key: config.shortcut })),
|
package/index.js
CHANGED
|
@@ -42,7 +42,7 @@ export const name = 'dsh-sidecard-ask'
|
|
|
42
42
|
export const inject = ['webServer']
|
|
43
43
|
|
|
44
44
|
/** Version of this plugin (kept in step with package.json by test/verify.mjs). */
|
|
45
|
-
export const PLUGIN_VERSION = '1.8.
|
|
45
|
+
export const PLUGIN_VERSION = '1.8.2'
|
|
46
46
|
|
|
47
47
|
/** Route prefix of the plugin's own API. */
|
|
48
48
|
export const ROUTE_PREFIX = '/sidecard-ask/api'
|