Compare commits
3
Commits
2f89dd90e5
...
v1.0.11
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2b6dba8f7 | ||
|
|
304525cb50 | ||
|
|
0aa6b43e4b |
@@ -2,6 +2,15 @@
|
||||
|
||||
版本说明按倒序排列。提交信息遵循 [CONTRIBUTING.md](CONTRIBUTING.md) 的单行规范,因此每次改动"为什么这样改、影响面是什么"记在这里,而不是提交信息里。
|
||||
|
||||
## v1.0.11
|
||||
|
||||
- 修复:**轻弹窗的标题、状态图标与右侧两个按钮不在同一条中线上**——「查看」和 ✕ 比标题低 3px。卡片用 `align-items:flex-start` 让三个子块取**顶边**对齐,而标题的行盒高 22px、两个按钮是 28px 的命中区:顶边一样高时,两条中线自然差 `(28 - 22) / 2 = 3px`。状态图标本来就是 22px 高,所以只有按钮看起来往下掉。
|
||||
- 现在弹窗的第一行是**一条共享的中线带** `--dsn-toast-line`(22px):卡片行高、状态图标高度、标题行高、按钮行都取它。`.dsn-toast-actions` 一直在用 `align-items:center`,于是 28px 的按钮改成在这条带子**内居中**,高出带子的 3px 由卡片 12px 的内边距吸收。
|
||||
- 没有改用「把标题行加到 28px 让两者自然同高」的做法:那会让卡片长高 6px、描述行跟着往下挪。现在**卡片尺寸一点没变**(单行标题 68px、标题换行 88px,都与原来一致),只是两个按钮上移 3px;按钮的 28px 命中区、hover 底色、焦点环都不动。
|
||||
- 新增回归测试 1 条(`tests/unit/styles.test.js`):钉住「四处共用同一条 `--dsn-toast-line`、按钮行必须是这条带子而不是它自身的内容高度、两个按钮仍是 28px」。把 `height:var(--dsn-toast-line)` 删掉、或换成 `min-height`,测试都会直接失败。
|
||||
- 这次改动是用无头浏览器加载**真实样式表与真实 DOM**实测的,不是目测:调整前标题中线 23px、「查看」与 ✕ 26px,调整后四者都是 23px(单行标题与标题换行两种情况都量过)。
|
||||
- 行为未改:位置、尺寸、自动关闭时间、hover 暂停、`Esc` / ✕ 关闭、同屏 3 条、深色 / 浅色跟随都不变。
|
||||
|
||||
## v1.0.10
|
||||
|
||||
- 新增:**应用内轻弹窗的自动关闭时间可以在插件页设置**(3 / 6 / 10 / 30 秒,或**永不**)。原来固定 6 秒,现在:
|
||||
|
||||
@@ -61,10 +61,10 @@ DeepSeek Harness(DSH)插件:会话**需要你注意**时提醒你——窗
|
||||
在 DSH 的 **插件 → 添加插件** 的上方输入框里填:
|
||||
|
||||
```text
|
||||
https://gitea.iwake.top/dsh-plugin/session-notify.git#v1.0.10
|
||||
https://gitea.iwake.top/dsh-plugin/session-notify.git#v1.0.11
|
||||
```
|
||||
|
||||
`#` 后面跟标签或提交,用来锁定版本;不写则取默认分支。跟随 1.x 最新版可以写 `#semver:^1.0.10`。仓库是公开的,不需要凭据,也不用改「安装源」。
|
||||
`#` 后面跟标签或提交,用来锁定版本;不写则取默认分支。跟随 1.x 最新版可以写 `#semver:^1.0.11`。仓库是公开的,不需要凭据,也不用改「安装源」。
|
||||
|
||||
### 本地路径安装
|
||||
|
||||
|
||||
@@ -943,16 +943,16 @@ function seatTranslator(props, fallback) {
|
||||
var CSS = `
|
||||
.dsn-stack{position:fixed;top:40px;right:24px;z-index:1100;display:flex;flex-direction:column;align-items:flex-end;gap:8px;pointer-events:none}
|
||||
@media (max-width:520px){.dsn-stack{right:12px}}
|
||||
.dsn-toast{box-sizing:border-box;pointer-events:auto;display:flex;align-items:flex-start;gap:10px;width:max-content;max-width:min(420px,calc(100vw - 48px));padding:12px 12px 12px 16px;border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-layer-2);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);font-size:14px;line-height:22px;animation:dsn-toast-in var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-out)}
|
||||
.dsn-toast{--dsn-toast-line:22px;box-sizing:border-box;pointer-events:auto;display:flex;align-items:flex-start;gap:10px;width:max-content;max-width:min(420px,calc(100vw - 48px));padding:12px 12px 12px 16px;border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-layer-2);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);font-size:14px;line-height:var(--dsn-toast-line);animation:dsn-toast-in var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-out)}
|
||||
@keyframes dsn-toast-in{from{opacity:0;transform:translateX(8px)}to{opacity:1;transform:translateX(0)}}
|
||||
@media (prefers-reduced-motion: reduce){.dsn-toast{animation:none}}
|
||||
.dsn-toast-icon{display:grid;place-items:center;flex:none;height:22px;color:var(--dsw-alias-state-warn-label)}
|
||||
.dsn-toast-icon{display:grid;place-items:center;flex:none;height:var(--dsn-toast-line);color:var(--dsw-alias-state-warn-label)}
|
||||
.dsn-toast-icon.is-completion{color:var(--dsw-alias-state-success-primary)}
|
||||
.dsn-toast-icon.is-question{color:var(--dsw-alias-state-business-primary)}
|
||||
.dsn-toast-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
|
||||
.dsn-toast-title{color:var(--dsw-alias-label-primary);font-weight:500;font-size:14px;line-height:22px}
|
||||
.dsn-toast-title{color:var(--dsw-alias-label-primary);font-weight:500;font-size:14px;line-height:var(--dsn-toast-line)}
|
||||
.dsn-toast-desc{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px;overflow-wrap:break-word}
|
||||
.dsn-toast-actions{display:flex;align-items:center;gap:2px;flex:none}
|
||||
.dsn-toast-actions{display:flex;align-items:center;gap:2px;flex:none;height:var(--dsn-toast-line)}
|
||||
.dsn-toast-action{display:inline-flex;align-items:center;height:28px;padding:0 8px;border:0;border-radius:var(--dsw-radius-sm);background:none;color:var(--dsw-alias-state-business-primary);font:inherit;font-size:13px;line-height:20px;cursor:pointer}
|
||||
.dsn-toast-action:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
||||
.dsn-toast-action:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@dsh-plugin/session-notify",
|
||||
"version": "1.0.10",
|
||||
"version": "1.0.11",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "会话完成、需要授权、需要回答时提醒你:窗口不在前台用系统通知,窗口在前台用应用内轻弹窗。",
|
||||
|
||||
+14
-6
@@ -12,6 +12,14 @@
|
||||
* tokens. It deliberately does NOT use `--dsw-alias-toast-bg`, which is a fixed
|
||||
* dark slate (#353638 in light mode) and would read as a black slab on a light
|
||||
* page.
|
||||
* - The popup's first line is ONE band, `--dsn-toast-line`: the state glyph and
|
||||
* the title's line box are exactly that tall, and the two controls — 28px, so
|
||||
* taller than the band — are centred on it instead of being top-aligned with
|
||||
* the card. That is why `.dsn-toast-actions` carries a `height` smaller than its
|
||||
* own buttons: with the row's own height the card's `align-items:flex-start`
|
||||
* would line the controls' top edge up with the text's, and a 28px control
|
||||
* against a 22px line box sits 3px low. Height here is a centre line, not a
|
||||
* boundary, and the card's padding absorbs the overflow.
|
||||
* - The settings page is a reading order, not a form dump: a lede that says how
|
||||
* alerts travel, then one group per concern. Inside a group a title introduces
|
||||
* a list whose rows put the subject on the left and the single control on the
|
||||
@@ -22,8 +30,8 @@
|
||||
* artwork colors — and those are theme-aware state tokens too.
|
||||
*
|
||||
* A plugin must not import a Harness Client package, so the declarations are
|
||||
* this package's own text. `tests/unit/styles.test.js` holds both invariants:
|
||||
* tokens only, and no theme-fixed color.
|
||||
* this package's own text. `tests/unit/styles.test.js` holds these invariants:
|
||||
* tokens only, no theme-fixed color, and one centre line for the popup's first row.
|
||||
*
|
||||
* @module @dsh-plugin/session-notify/client/ui/styles
|
||||
*/
|
||||
@@ -31,16 +39,16 @@
|
||||
export const CSS = `
|
||||
.dsn-stack{position:fixed;top:40px;right:24px;z-index:1100;display:flex;flex-direction:column;align-items:flex-end;gap:8px;pointer-events:none}
|
||||
@media (max-width:520px){.dsn-stack{right:12px}}
|
||||
.dsn-toast{box-sizing:border-box;pointer-events:auto;display:flex;align-items:flex-start;gap:10px;width:max-content;max-width:min(420px,calc(100vw - 48px));padding:12px 12px 12px 16px;border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-layer-2);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);font-size:14px;line-height:22px;animation:dsn-toast-in var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-out)}
|
||||
.dsn-toast{--dsn-toast-line:22px;box-sizing:border-box;pointer-events:auto;display:flex;align-items:flex-start;gap:10px;width:max-content;max-width:min(420px,calc(100vw - 48px));padding:12px 12px 12px 16px;border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-layer-2);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);font-size:14px;line-height:var(--dsn-toast-line);animation:dsn-toast-in var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-out)}
|
||||
@keyframes dsn-toast-in{from{opacity:0;transform:translateX(8px)}to{opacity:1;transform:translateX(0)}}
|
||||
@media (prefers-reduced-motion: reduce){.dsn-toast{animation:none}}
|
||||
.dsn-toast-icon{display:grid;place-items:center;flex:none;height:22px;color:var(--dsw-alias-state-warn-label)}
|
||||
.dsn-toast-icon{display:grid;place-items:center;flex:none;height:var(--dsn-toast-line);color:var(--dsw-alias-state-warn-label)}
|
||||
.dsn-toast-icon.is-completion{color:var(--dsw-alias-state-success-primary)}
|
||||
.dsn-toast-icon.is-question{color:var(--dsw-alias-state-business-primary)}
|
||||
.dsn-toast-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
|
||||
.dsn-toast-title{color:var(--dsw-alias-label-primary);font-weight:500;font-size:14px;line-height:22px}
|
||||
.dsn-toast-title{color:var(--dsw-alias-label-primary);font-weight:500;font-size:14px;line-height:var(--dsn-toast-line)}
|
||||
.dsn-toast-desc{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px;overflow-wrap:break-word}
|
||||
.dsn-toast-actions{display:flex;align-items:center;gap:2px;flex:none}
|
||||
.dsn-toast-actions{display:flex;align-items:center;gap:2px;flex:none;height:var(--dsn-toast-line)}
|
||||
.dsn-toast-action{display:inline-flex;align-items:center;height:28px;padding:0 8px;border:0;border-radius:var(--dsw-radius-sm);background:none;color:var(--dsw-alias-state-business-primary);font:inherit;font-size:13px;line-height:20px;cursor:pointer}
|
||||
.dsn-toast-action:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
||||
.dsn-toast-action:focus-visible{outline:var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}
|
||||
|
||||
@@ -64,6 +64,27 @@ test('the three popup glyphs stay distinguishable through state tokens', () => {
|
||||
assert.ok(CSS.includes('.dsn-toast-icon.is-question{color:var(--dsw-alias-state-business-primary)}'))
|
||||
})
|
||||
|
||||
test('the popup first line is one band, because top-aligning it was the 3px bug', () => {
|
||||
const rule = (name) => CSS.match(new RegExp(`\\.${name}\\{([^}]*)\\}`))?.[1] ?? ''
|
||||
|
||||
// The band is the title's line box. A control is 28px and the line box 22px, so
|
||||
// top-aligning them (which `align-items:flex-start` alone did) drops the two
|
||||
// buttons 3px below the text they sit next to.
|
||||
assert.equal(/--dsn-toast-line:(\d+px)/.exec(rule('dsn-toast'))?.[1], '22px', 'the popup must declare its first-line band')
|
||||
for (const name of ['dsn-toast', 'dsn-toast-title', 'dsn-toast-icon', 'dsn-toast-actions']) {
|
||||
assert.ok(rule(name).includes('var(--dsn-toast-line)'), `.${name} must take its first-line height from the band`)
|
||||
}
|
||||
|
||||
// The actions row has to BE the band and centre its contents on it; stretching
|
||||
// it to its own content would put the controls back to top-aligned.
|
||||
const actions = rule('dsn-toast-actions')
|
||||
assert.ok(actions.includes('height:var(--dsn-toast-line)'), 'the actions row must be the band, not its buttons')
|
||||
assert.ok(actions.includes('align-items:center'), 'the controls must centre on the band')
|
||||
for (const control of ['dsn-toast-action', 'dsn-toast-close']) {
|
||||
assert.ok(rule(control).includes('height:28px'), `.${control} must keep its own 28px hit area`)
|
||||
}
|
||||
})
|
||||
|
||||
test('every class the components render has a rule, so nothing falls back to defaults', () => {
|
||||
// Guards the redesign: a renamed class that the sheet no longer styles would
|
||||
// render as an unstyled block instead of failing loudly.
|
||||
|
||||
Reference in New Issue
Block a user