dsh-claude-style 0.10.2 → 0.10.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/CHANGELOG.md +72 -0
- package/README.en.md +27 -49
- package/README.md +4 -0
- package/docs/STYLE.md +31 -9
- package/docs/architecture.md +22 -13
- package/fonts/InterVariable.woff2 +0 -0
- package/fonts/NotoSerifVariable.woff2 +0 -0
- package/fonts/OFL-Inter.txt +93 -0
- package/fonts/OFL-NotoSerif.txt +93 -0
- package/host/hdsl.js +80 -0
- package/host/index.js +13 -878
- package/host/routes.js +619 -0
- package/host/settings.js +224 -0
- package/lib/client.js +897 -445
- package/lib/model-descriptions.json +4 -0
- package/package.json +8 -3
- package/docs/claude-conversation-dark.png +0 -0
- package/docs/claude-conversation-light.png +0 -0
- package/docs/claude-home-dark.png +0 -0
- package/docs/claude-home-light.png +0 -0
- package/docs/deepseek-conversation-dark.png +0 -0
- package/docs/deepseek-conversation-light.png +0 -0
- package/docs/deepseek-home-dark.png +0 -0
- package/docs/deepseek-home-light.png +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,78 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `dsh-claude-style` are documented here, newest first.
|
|
4
4
|
|
|
5
|
+
## [0.10.4] - 2026-10-03
|
|
6
|
+
|
|
7
|
+
[中文](#cn-0.10.4) | [English](#en-0.10.4)
|
|
8
|
+
|
|
9
|
+
<h3 id="cn-0.10.4">体验优化</h3>
|
|
10
|
+
|
|
11
|
+
- **没有 Anthropic 字体时,界面与正文换成外观相近的字体**:没有把 Anthropic Sans / Serif 装进系统或放进插件 `fonts/` 目录时,界面以前落到 Segoe UI、苹方这类系统字体,对话正文落到 Georgia,字形和排版都和原样差得远。现在插件自带 Inter 与 Noto Serif(SIL OFL 1.1)代替两款 Anthropic 字体,它们的字高、字宽与原字体相差不到百分之二,换字体时文字不会重新换行,粗体用的是字体本身的字重。两款字体只含 Anthropic 字体覆盖的拉丁字符,中文照旧使用系统中文字体;npm 包因此大约增加 214 KB。已经启用 Anthropic 字体的环境不受影响。
|
|
12
|
+
- **品牌标识改为大卡片选择**:设置页的品牌选项由分段小按钮改为一排大卡片,每张卡片放对应的品牌标识(Claude 的陶土星芒、DeepSeek 的蓝鲸),当前品牌的卡片带品牌色描边;后续新增品牌只需添一张卡片。
|
|
13
|
+
- **设置页同时出现在设置对话框与插件页**:0.1.7 起这页只显示在插件页内。现在设置对话框恢复「Claude Style」标签页,两处渲染同一份页面、共用同一份偏好存储,一边改动另一边即时跟上;旧版宿主不受影响,仍只有设置对话框一处。
|
|
14
|
+
|
|
15
|
+
### 问题修复
|
|
16
|
+
|
|
17
|
+
- **简洁用量模式下的统计弹层不再出现空置半行与多余分组**:宿主「性能与用量」设置选为简洁时,上下文弹层以前把四个数字拆在「会话统计」和「Token 用量」两个小标题下,三项指标占两行、一项指标占一行,各自留下一处空白格。现在简洁模式下移除分组小标题,总用时、首 token 平均、输出速度与缓存命中四个指标合并为整齐的 2×2 排版。
|
|
18
|
+
- **其他插件放进输入框的模型菜单恢复上下排列**:同时启用 `dsh-thinking-effort` 这类自带模型菜单的插件时,菜单里的各个供应商分组以前被挤成一行横排。现在分组按原样上下排列。
|
|
19
|
+
- **macOS 桌面端的封号彩蛋页不再重复出现窗口按钮**:macOS 桌面壳的窗口左上角是系统画的三个红黄绿按钮,彩蛋页以前又画了一套最小化 / 还原 / 关闭,页面上于是出现两排按钮。现在这页不画自己那套,星芒标与字标、「退出登录」直接排进系统标题栏那一行,并让开左侧的三个按钮;按住这一行的空白处仍然可以拖动窗口。
|
|
20
|
+
- **其他插件的弹层与标签保持原有的形状**:其他插件的元素只要类名里带 `badge` 或 `tag`,以前都会被改成胶囊圆角。额度插件的弹层因此变成四角极圆的方圆形,标题和底部按钮被切掉一角,弹层里各段的分隔线也弯成弧形。现在胶囊圆角只用在宿主自己的徽标与标签上(轨迹标签、自定义模型行的标签、提问里的「推荐」、快捷键按键等),而且两端是正圆弧,不再略方。
|
|
21
|
+
|
|
22
|
+
<h3 id="en-0.10.4">Improvements</h3>
|
|
23
|
+
|
|
24
|
+
- **Without the Anthropic fonts, the interface and conversation text use close look-alikes**: when Anthropic Sans and Serif were neither installed on the system nor dropped into the plugin's `fonts/` directory, the interface used to fall back to system fonts such as Segoe UI or PingFang and the conversation body to Georgia, far from the intended letterforms and layout. The plugin now ships Inter and Noto Serif (SIL OFL 1.1) in their place; their letter heights and widths are within two percent of the Anthropic fonts, so text does not rewrap when one replaces the other, and bold text uses the fonts' own weights. Both carry only the Latin characters the Anthropic fonts cover, so Chinese text keeps using the system's Chinese fonts; the npm package grows by about 214 KB. Setups that already have the Anthropic fonts are unaffected.
|
|
25
|
+
- **The brand choice is now a row of large cards**: the settings page's brand option changes from small segments to large cards, each carrying the brand's own mark (Claude's clay starburst, DeepSeek's blue whale) with the active card outlined in the brand accent; a new brand is one more card.
|
|
26
|
+
- **The settings page now shows in both the settings dialog and the plugin page**: since 0.1.7 it lived only on the plugin page. The settings dialog keeps its "Claude Style" tab again — both render the same page against the same preference store, so a change in one appears in the other at once. Older hosts are unaffected and keep the dialog tab as the only seat.
|
|
27
|
+
|
|
28
|
+
### Bug Fixes
|
|
29
|
+
|
|
30
|
+
- **The stats popover under compact usage no longer shows half-empty rows and redundant groups**: when the host's performance and usage setting was set to compact, the context popover previously split the four figures under "Session statistics" and "Token usage" headings, leaving awkward empty slots in two separate grids. The compact mode now removes the section headings and places total time, average TTFT, output speed, and cache hit share together into a clean 2x2 layout.
|
|
31
|
+
- **A model menu another plugin puts in the composer stacks its groups again**: with a plugin that brings its own model menu, such as `dsh-thinking-effort`, the menu's provider groups used to be squeezed into one horizontal row. They stack top to bottom as the plugin draws them now.
|
|
32
|
+
- **The account-hold page on the macOS Desktop no longer draws a second set of window buttons**: the top-left of a macOS Desktop window belongs to the system, which paints the three red-yellow-green buttons; the page used to draw its own minimize, maximize and close as well, so the window showed two rows of buttons. It draws none of its own now — the starburst and wordmark and the Sign out button take their place in the titlebar row, clear of the three buttons on the left, and the window is still dragged by the empty part of that row.
|
|
33
|
+
- **Other plugins' popovers and tags keep their own shape**: any element of another plugin whose class name contained `badge` or `tag` used to be turned into a pill. A quota plugin's popover became a squarish blob with very round corners, its title and bottom buttons clipped at the corners and the dividers between its sections bent into arcs. The pill radius now applies only to the host's own badges and tags (trajectory tags, the custom model row tag, the Recommended mark in a question, shortcut key caps and the like), and their ends are true round arcs instead of slightly squared ones.
|
|
34
|
+
|
|
35
|
+
**Full Changelog**: [v0.10.3...v0.10.4](https://github.com/Nwflower/dsh-claude-style/compare/v0.10.3...v0.10.4)
|
|
36
|
+
|
|
37
|
+
## [0.10.3] - 2026-10-01
|
|
38
|
+
|
|
39
|
+
[中文](#cn-0.10.3) | [English](#en-0.10.3)
|
|
40
|
+
|
|
41
|
+
<h3 id="cn-0.10.3">体验优化</h3>
|
|
42
|
+
|
|
43
|
+
- **上下文弹层与计量环右缘对齐**:宿主把弹层从计量环的左缘往下放,输入行右端按这个位置只够把它挤到窗口右缘,和圆环错开一截。现在弹层的右缘与计量环的右缘齐平,窗口宽度变化、页面滚动与弹层自身高度变化时都重新量。
|
|
44
|
+
- **用量面板的数字与模型列表写法统一**:概览页「Token 总量」一格与热力图提示原来写「1.0M」「2.00B」「963.6K」,现在与模型列表一样写「1M」「2B」「963.6k」——最多一位小数、整数不带 `.0`、`k` 小写,单位按四舍五入后的值取,刚过百万的读数不再出现「1000k」。轮次状态行的输出 tokens 也走这一套写法。
|
|
45
|
+
- **首页工作区弹层改到控件正上方**:hero 行的工作区与预设两个弹层原来贴在控件右侧、底边与控件齐平;现在与输入框上的模型、推理档位弹层同一种摆法,与控件右缘对齐、在控件上方留 6px 展开,上方空间不够时翻到控件下方。快捷供应商弹层一直与触发控件右缘对齐,却从左下角放大展开,现在与模型弹层一样从右下角展开。
|
|
46
|
+
- **「性能与用量」选简洁档时,上下文弹层里仍有四个数字**:以前简洁档下弹层里只有宿主自己的上下文明细,会话的用时与速度一概看不到。现在简洁档补上总用时(模型用时加工具调用用时)、首 token 平均、输出速度与缓存命中比例;详细档给出宿主那两组全部的行,与之前一致。
|
|
47
|
+
|
|
48
|
+
### 问题修复
|
|
49
|
+
|
|
50
|
+
- **推理档位触发控件收起后不再回来**:切到不带档位的模型再切回来,或离开再回到带输入框的页面,模型名右边只剩一块空位,档位名与可点的控件都看不见了。现在触发器重建后回到模型名旁边,档位照常可选。
|
|
51
|
+
- **输入框下方那一行里上下文计量环偏高**:同一行里模型名、推理档位与权限控件的中心都在一条线上,只有计量环与它的读数高出 2 像素。现在计量环与这一行其余控件同线。
|
|
52
|
+
|
|
53
|
+
### 其他变更
|
|
54
|
+
|
|
55
|
+
- **两份 README 改成同一套骨架**:英文版删去功能清单与「停用与卸载」两节,小鲸鱼 Deepy 的八张动图移进预览一节,安装步骤两份都读作插件页、终端、插件市场三步。0.10.2 条目里提到的「特点」一节随这次改动不再存在。
|
|
56
|
+
- **发行包不再包含 README 截图**:`package.json` 的 `files` 只带 `docs/STYLE.md` 与 `docs/architecture.md` 两篇文档,八张截图留在仓库里。npm 包解包体积由 3.24 MiB 降到 2.47 MiB,下载体积由 1.89 MB 降到 1.07 MB;GitHub 与 npm 页面上的 README 图片照常显示。
|
|
57
|
+
|
|
58
|
+
<h3 id="en-0.10.3">Improvements</h3>
|
|
59
|
+
|
|
60
|
+
- **The context popover now lines its right edge up with the meter**: the host hangs the panel from the meter's LEFT edge, and at the end of the composer row that position only fits by parking the panel against the window's right margin, well clear of the ring. The panel's right edge now sits on the ring's, re-read on window resizes, page scrolls and changes to the panel's own height.
|
|
61
|
+
- **The usage panel's numbers now read the way the model list writes them**: the Overview tab's Total tokens cell and the heat grid's tips used "1.0M", "2.00B" and "963.6K"; they now print "1M", "2B" and "963.6k" like the model list — one decimal at most, a whole number without its ".0", a lowercase k, and the unit picked on the rounded value, so a count just past a million never reads "1000k". The turn status line's output tokens print through the same formatter.
|
|
62
|
+
- **The home page's workspace popover now opens over its control**: the hero row's workspace and preset cards used to sit beside their control, bottom-aligned with it; they now take the placement the composer's model and effort popovers use — right-aligned with the control and opening 6px above it, flipping below when the viewport leaves no room. The quick-provider popover, which has always been right-aligned with its trigger, scaled in from its bottom-left corner; it now grows from the bottom-right one, like the model picker.
|
|
63
|
+
- **The context popover keeps four figures under the compact "performance & usage" row**: with the compact row the popover used to carry the host's context rows and nothing about the session. It now adds the total time (the model's time plus the tool calls'), the first-token average, the output speed and the cache-hit share; the detailed row keeps the host's whole set, exactly as before.
|
|
64
|
+
|
|
65
|
+
### Bug Fixes
|
|
66
|
+
|
|
67
|
+
- **The reasoning-effort control no longer stayed away once taken down**: switching to a model without levels and back, or leaving a page with the input area and returning, left an empty slot beside the model name — no level name, nothing to click. The trigger now returns beside the model name, and the levels are selectable again.
|
|
68
|
+
- **The context meter rode high in the composer's control row**: the model name, the effort level and the permission control shared one centre line while the ring and its reading sat 2px above it. The meter now sits on the same line as the rest of the row.
|
|
69
|
+
|
|
70
|
+
### Chores
|
|
71
|
+
|
|
72
|
+
- **Both READMEs now share one skeleton**: the English one drops its feature list and its "Disabling and uninstalling" section, Deepy's eight GIFs move into the preview, and installation reads as three steps — plugin page, terminal, plugin market — in both languages. The "Features" section the 0.10.2 entry names no longer exists as of this change.
|
|
73
|
+
- **The npm package no longer carries the README screenshots**: `package.json`'s `files` now ships only the two documents under `docs/` (`STYLE.md` and `architecture.md`), leaving the eight screenshots in the repository. The unpacked package drops from 3.24 MiB to 2.47 MiB and the tarball from 1.89 MB to 1.07 MB, while the README keeps showing its images on GitHub and npm.
|
|
74
|
+
|
|
75
|
+
**Full Changelog**: [v0.10.2...v0.10.3](https://github.com/Nwflower/dsh-claude-style/compare/v0.10.2...v0.10.3)
|
|
76
|
+
|
|
5
77
|
## [0.10.2] - 2026-09-30
|
|
6
78
|
|
|
7
79
|
[中文](#cn-0.10.2) | [English](#en-0.10.2)
|
package/README.en.md
CHANGED
|
@@ -49,6 +49,21 @@ The settings page's Brand mark row switches between the Claude and DeepSeek pale
|
|
|
49
49
|
</table>
|
|
50
50
|
|
|
51
51
|
> Light mode is a white with a touch of sky blue, `#F7FAFF`, with the sidebar at `#F3F7FE`; dark mode is a blue-black `#13161D`. The accent is DeepSeek's brand blue `#4D6BFE`, and Deepy the pixel whale stands on the composer on the home page and in conversations alike.
|
|
52
|
+
>
|
|
53
|
+
> <table>
|
|
54
|
+
> <tr>
|
|
55
|
+
> <td align="center" width="25%"><img src="./showcase/gifs/idle.gif" width="120" alt="Idle" /><br />Idle</td>
|
|
56
|
+
> <td align="center" width="25%"><img src="./showcase/gifs/thinking.gif" width="120" alt="Thinking" /><br />Thinking</td>
|
|
57
|
+
> <td align="center" width="25%"><img src="./showcase/gifs/typing.gif" width="120" alt="Answering and calling tools" /><br />Answering and calling tools</td>
|
|
58
|
+
> <td align="center" width="25%"><img src="./showcase/gifs/conducting.gif" width="120" alt="Conducting subagents" /><br />Conducting subagents</td>
|
|
59
|
+
> </tr>
|
|
60
|
+
> <tr>
|
|
61
|
+
> <td align="center" width="25%"><img src="./showcase/gifs/notification.gif" width="120" alt="Waiting on you" /><br />Waiting on you</td>
|
|
62
|
+
> <td align="center" width="25%"><img src="./showcase/gifs/error.gif" width="120" alt="Failed" /><br />Failed</td>
|
|
63
|
+
> <td align="center" width="25%"><img src="./showcase/gifs/happy.gif" width="120" alt="Finished" /><br />Finished</td>
|
|
64
|
+
> <td align="center" width="25%"><img src="./showcase/gifs/sleeping.gif" width="120" alt="Asleep" /><br />Asleep</td>
|
|
65
|
+
> </tr>
|
|
66
|
+
> </table>
|
|
52
67
|
|
|
53
68
|
> The workspaces, sessions, usage figures and nickname in the screenshots are sample data.
|
|
54
69
|
|
|
@@ -61,6 +76,10 @@ The settings page's Brand mark row switches between the Claude and DeepSeek pale
|
|
|
61
76
|
| Anthropic Sans Web Text | Interface / UI | [`fonts/AnthropicSansWebText.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/AnthropicSansWebText.ttf) |
|
|
62
77
|
| Anthropic Serif Web Text | Conversation body / Markdown | [`fonts/AnthropicSerifWebText.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/AnthropicSerifWebText.ttf) |
|
|
63
78
|
| JetBrains Mono Variable | Code / code blocks | [`fonts/JetBrainsMonoVariable.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/JetBrainsMonoVariable.ttf), [`fonts/JetBrainsMonoItalicVariable.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/JetBrainsMonoItalicVariable.ttf) |
|
|
79
|
+
| Inter | Interface when Anthropic Sans is absent | [`fonts/InterVariable.woff2`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/InterVariable.woff2) |
|
|
80
|
+
| Noto Serif | Conversation body when Anthropic Serif is absent | [`fonts/NotoSerifVariable.woff2`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/NotoSerifVariable.woff2) |
|
|
81
|
+
|
|
82
|
+
JetBrains Mono, Inter and Noto Serif are licensed under the SIL Open Font License 1.1 and ship with the npm package; nothing to set up. Inter and Noto Serif nearly match the two Anthropic fonts in letter height and width, so without the Anthropic fonts they stand in and the interface and conversation text keep their layout. Both carry only the Latin characters the Anthropic fonts cover; Chinese text keeps using the system's Chinese fonts.
|
|
64
83
|
|
|
65
84
|
To enable the Anthropic fonts, choose one of the following:
|
|
66
85
|
|
|
@@ -72,63 +91,22 @@ To enable the Anthropic fonts, choose one of the following:
|
|
|
72
91
|
|
|
73
92
|
## Installation
|
|
74
93
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
1. From a terminal:
|
|
94
|
+
1. From the official plugin page, add the plugin below and it installs.
|
|
78
95
|
|
|
79
|
-
```bash
|
|
80
|
-
dsh plugin --profile web add dsh-claude-style # npm package (recommended)
|
|
81
|
-
dsh plugin --profile web add Nwflower/dsh-claude-style # GitHub source
|
|
82
96
|
```
|
|
83
|
-
|
|
84
|
-
2. From the [plugin market](https://github.com/dsh-market/dsh-market)
|
|
85
|
-
|
|
86
|
-
Keep only one theme enabled at a time. After installation, **restart `dsh web`** and refresh the page.
|
|
87
|
-
|
|
88
|
-
## Features
|
|
89
|
-
|
|
90
|
-
1. **Theme** — applies globally the moment it is installed, with nothing to configure. Light mode uses ivory `#FCFCFB`, dark mode warm black `#141413`, and both share the same ember orange `#D97757` action accent; light/dark follows the system color mode. The settings page's Brand mark row offers DeepSeek / Claude: DeepSeek turns the whole palette blue — the accent becomes DeepSeek's brand blue `#4D6BFE` (buttons, switches, checks, links and the status line follow), the yellowish ivory light canvas gives way to a white carrying only a hint of sky blue, `#FAFBFF` (sidebar `#F7F9FF`, with the raised layers, segmented-control plates, table headers and scrollbars stepped back in the same measure), the warm-black dark canvas to a blue-black `#13161D`, the hairlines and grey inks turn cool and user bubbles take a touch of blue; the sidebar and the home page keep the host's own DeepSeek whale and wordmark, painted DeepSeek blue, and the account row's picture without an avatar and a running turn's status line take DeepSeek's whale mark as well. The choice used to be labelled "Off", and a value stored under that name reads as DeepSeek; the third choice this row once carried, Anthropic, is gone, and a value stored as `anthropic` reads as Claude, whose marks and palette it shared. The settings page also carries an **Animation** row — Follow the system (Windows' own "show animations" setting decides), Reduced (every animation holds its still frame, whatever the system says) and Always (they play, whatever the system says); the background-work ring turns in every setting, since a still ring reads as broken rather than as calm.
|
|
91
|
-
2. **Composer** — the input box is rebuilt from the ground up: a permission segmented control (Read / Edit / Auto / Yolo) with its tier list under it, a model trigger carrying the vendor lockup, and the toolbar laid out on a single line with the send and stop buttons unified into 7px rounded rectangles. The session's numbers are no longer a sentence on that line: the two host pills behind it are hidden, and their detail (model time, tool-call time, average time to first token, output speed, and the token-usage rows) is appended to the context meter's popover — read from the host's own session projections, so it matches what the host itself would show and follows the session while the popover stays open. That popover opens on hover and folds away when the pointer leaves, arriving with the same short fade and rise as the skin's own cards; while the numbers are still on their way, a placeholder holds their height so it never opens short and grows. The model trigger and the meter share the same font size and color. The permission tiers come from the host's own catalog: a deployment draws exactly the tiers it configures, and a tier a third-party plugin registers (the auto mode plugin's `auto-mode`, say) appears in the list and takes the Auto slot; the list stays text-only, so a tier's declared glyph is not drawn. Switching tiers slides the highlight from the old tier to the new one, and every segmented control on the settings page does the same.
|
|
92
|
-
3. **Model picker** — a new two-level popover. The first level lists the official service plus the quick providers selected in settings; "More models" opens a second level grouped by provider. Every row carries its vendor lockup and a description, and the footer holds the reasoning-effort slider (stepless — it snaps to the nearest level on release) together with the "More models" entry. The second level aligns its bottom edge with the first, providers already shown on the first level are not repeated, and models without thinking support get no slider. Hovering opens the popover after a 100 ms dwell and closes it after 150 ms; the gap between the two cards does not count as leaving.
|
|
93
|
-
4. **Workspace** — the sidebar's "Workspace" heading becomes an **Active / Archived** segmented control. Active keeps the host's session tree, while Archived is the skin's own flat list (title, time, and per-row unarchive and delete icon buttons). A refused delete raises the host's Toast with the reason: a conversation still held open by the app asks for a restart first, and every other refusal names the reason. Rows match the host's session rows measurement for measurement (row x=12 / width 251 / height 28 / title x=36), and they rest in the same grey: an archived title darkens only while the pointer is on its row or the keyboard focus is in it. Switching between the two views slides the highlight from one segment to the other.
|
|
94
|
-
5. **Sidebar** — the New session and Plugins rows take Claude's real shape: no background at rest, a background on hover, the "+" of New session set inside a circular chip, and both icons rotating 90° clockwise on hover (four-fold symmetric glyphs, so they land back on themselves). The account drawer remains as it was. On the desktop the ban-screen easter egg rides the window's own titlebar row: its lockup and Sign out sit in that row beneath the system's window buttons (which the page draws no second copy of), the row takes the page's own canvas colour, and the window is still dragged by it. On the desktop the brand row sits 10px higher than the host draws it, level with the web build. While the pointer is over the sidebar, the brand mark at its top left fades into a search box (the collapsed rail has none); pressing it, or the host's search shortcut (Ctrl+K on the desktop, Ctrl+Alt+K on the web), fades in a search palette near the top of the window, and the Workspace heading's own search icon is gone: it searches past sessions (by title, workspace name and what was said in them: every message between you and the model counts, a few Chinese characters from the middle of a sentence match, case does not matter, and the matching line shows under the row with the match in bold; the first time the palette opens after the host starts, every session is read once, which takes a dozen seconds or so), projects, plugins, the skills the current session offers and keyboard shortcuts, with All / Sessions / Projects / Plugins / Skills / Shortcuts across the top, and with the box empty it lists the five most recent sessions and the New session, Plugins, Settings and Keyboard shortcuts actions. ↑↓ moves, Enter opens, Tab and Shift+Tab switch the category, Esc closes; a session opens, a project starts a new session in that workspace, a plugin opens its details on the plugins page, a skill puts `/name ` at the head of the current session's input, and a shortcut opens the host's shortcut list filtered to that entry.
|
|
95
|
-
6. **Account area** — the nickname and the picture each follow one fixed order. Nickname: the custom nickname → the signed-in account's name → the HDSL launcher's account name → the last probed system user → the freshly probed system user → `User`. Picture: the signed-in account's avatar → the HDSL launcher's avatar → the Claude mark. The account profile is fetched from the server only at startup, on hot reload, and on sign-in and sign-out — never polled. The HDSL contract is read once by the host half and forwarded over two read-only routes (`GET /dsh-claude-style/hdsl` for the metadata, `GET /dsh-claude-style/hdsl-skin.png` for the avatar image; neither carries the avatar file's absolute path, and both sit behind the host's request fence). A contract version that is missing or unknown voids the whole group, and a deleted avatar file falls back to the mark. What the launcher publishes is a skin sheet rather than a finished avatar, so that picture is cropped into the head first — the face's 8×8 texel block inset by 1/18 of the box with the hat layer over the whole box, drawn square so no rounding shaves its pixels. The account popover remains the host's own: the host's account row is the entry point, and the popover lists the account header, the other plugins' footer entries, and the host's own Settings / Feedback / Sign out, each keeping its original copy, order, and click behavior. On hosts without an account area (Web), the plugin builds a popover with the same look. The card takes the main canvas's fill (ivory in light mode, sky white under the DeepSeek brand) and spans the sidebar's width. Without an avatar the picture is the brand mark: the Claude mark under the Claude brand, DeepSeek's whale under the DeepSeek brand.
|
|
96
|
-
7. **Conversation views** — in the desktop Windows titlebar mode, the Conversation / Trajectory control sits centered and always visible on the titlebar row (the same row as the New session button). On wide windows with a short title it stays on the title's row; otherwise it keeps its own row below the title. Switching views slides the highlight from the old tab to the new one. For running, stopped and failed turns the status line follows the end of the turn's work (the footer and queued messages sit below it) and looks like Claude Code's: while running, a turning spark, then elapsed time · output tokens · what the model is doing (waiting for the model, thinking, thought for N s, writing, preparing a tool call, running tools); once stopped or failed, a still spark and "Stopped / Failed · duration · output tokens". Under the DeepSeek brand the spark is DeepSeek's whale mark, which sways as it swims while the turn runs. A turn that finishes normally keeps the host's own look and place.
|
|
97
|
-
8. **Home layouts** — the new-conversation page comes in two layouts, Studio by default and switchable in the settings page at any time: **Classic** is the centered headline over the composer card, the headline drawn from a pool of greetings for the time of day (a few each for morning, midday, afternoon, evening and night, plus a few for any hour) and redrawn each time the new-conversation page comes back; **Studio** pins the greeting to the top left as one fixed line ("What's up next, <user>?"), docks the composer in the conversation's single-line form at the window's bottom edge with a row of hairline context chips above it, and sets the greeting and a 480px usage panel against the composer's left edge: an Overview tab with six stat cells (sessions, messages, total tokens, active days, peak hour, favorite model) and a twenty-six-week per-day heat grid of square cells in equal columns, a Models tab stacking each day's per-model tokens into one bar over a ranked model list (swatch, name, input and output, share; past six rows it folds behind a "show more" row, and the open list folds back with "show less"), and All / 30d / 7d range pills at the top right, which the peak hour and the multiplier line follow too; once the picked range's total passes one book, a multiplier line appears under the grid, naming one of sixty-five books (Tao Te Ching to In Search of Lost Time) drawn afresh each time the new-conversation page comes back. The numbers are rolled up by the plugin's host half: with `dsh-cost-meter` installed it reads that plugin's ledger cache directly (read-only — their file is never written), and without it the host half folds the local session logs itself, caching per log by size and modification time. Both sources answer each model's four buckets and each day's per-model tokens, with one model served by several providers counted as one row; the ledger keeps no hours, so the peak hour is always folded per day from the local session logs; when the roll-up cannot answer, the panel falls back to the projection block each host session row carries. The panel draws its skeleton first and does not shift when the numbers land. Before a workspace is picked (a fresh start, no session yet), the usage panel and the Read / Edit / Auto / Yolo permission segments still show; the segments rest on the preset a new session starts in, and pressing them opens the workspace picker, the same as pressing the input box, whose dashed "pick a workspace" ring now outlines the single-line input box alone. When the window is too short for the whole panel, the panel scrolls between the greeting and the composer with its bottom edge fading out, and the page no longer runs past the window. The workspace picker is drawn as Claude Code's folder menu: a narrow card of plain text rows set closer together, with no folder glyph in front of each folder and no plus sign on "Add workspace…"; the current workspace keeps the accent check.
|
|
98
|
-
9. **The pixel crab** — in the Studio layout, Claude Code's pixel crab stands on the new-conversation composer card's top edge, near its right end (the Classic layout has none). When it is clicked or the pointer leaves it (and on its own every half minute or so while the page is open), it plays Claude Code's fishing routine, frame for frame from Claude Code's own animation: a blink, the rod raised and cast down past the card's edge, a hop into a side-on stance for a spell of fishing, and the rod reeled in as it turns back — about three and a half seconds. With reduced motion requested (Windows' "Show animations in Windows" turned off, for one), it moves only when clicked.
|
|
99
|
-
10. **Deepy the pixel whale** — under the DeepSeek brand the crab gives way to Deepy, a pixel whale drawn on a 52×52 grid whose every frame comes from the Deepy theme pack's animations, 50 ms a frame. On the home page (both layouts) it stands on the composer card's top edge near its right end; in a conversation it stands on top of the whole input area (the composer card together with the todo, queue and goal cards above it), and while you are asked to approve something, answer a question or review a plan it stands on the panel that takes the card's place. Only the main conversation carries it; the sidebar's subagent chats do not. What it does follows the agent's work: between jobs it breathes, flicks its tail and blinks, and every half minute or so looks around or spouts water; while the model reasons or has not started answering, a thought cloud floats over it; while the model writes an answer or calls tools it types at a keyboard, puts on headphones when two sessions work at once and a hard hat from three; while subagents run it wears headphones for one and conducts a squad of little whale clones with its tail for two or more; a context compaction has it inhale the fragments; while you are asked for something it rings an exclamation bell; a failed tool call or a failed turn gives it a fright, smoke and dizzy stars; a turn or a compaction that finishes gets a flip and confetti (a finish that comes right after a failure is celebrated once the fright has played out). On the home page it reads the whole workspace: how many sessions are working picks the animation, a session waiting on you rings the bell, and one finishing in the background is celebrated. After a minute with no work and no pointer movement or key press it puts on a nightcap and falls asleep, and wakes with a start at the next one. Clicking its face or its tail pokes it into a jelly wobble, four quick clicks tickle it, and pressing it and pulling lifts it into a dangle until you let go. With reduced motion requested, each state holds one frame, and it moves only when clicked. The frames weigh about 0.4 MB, so they stay out of the page script: the plugin's host half serves them over a public route, `GET /dsh-claude-style/deepy/<animation>.png`, and the browser fetches an animation's frames the first time it plays. Against a host half that predates the route (the plugin updated without restarting the host), the frames do not load, the whale stays away and the console says so once.
|
|
100
|
-
|
|
101
|
-
<table>
|
|
102
|
-
<tr>
|
|
103
|
-
<td align="center" width="25%"><img src="./showcase/gifs/idle.gif" width="120" alt="Idle" /><br />Idle</td>
|
|
104
|
-
<td align="center" width="25%"><img src="./showcase/gifs/thinking.gif" width="120" alt="Thinking" /><br />Thinking</td>
|
|
105
|
-
<td align="center" width="25%"><img src="./showcase/gifs/typing.gif" width="120" alt="Answering and calling tools" /><br />Answering and calling tools</td>
|
|
106
|
-
<td align="center" width="25%"><img src="./showcase/gifs/conducting.gif" width="120" alt="Conducting subagents" /><br />Conducting subagents</td>
|
|
107
|
-
</tr>
|
|
108
|
-
<tr>
|
|
109
|
-
<td align="center" width="25%"><img src="./showcase/gifs/notification.gif" width="120" alt="Waiting on you" /><br />Waiting on you</td>
|
|
110
|
-
<td align="center" width="25%"><img src="./showcase/gifs/error.gif" width="120" alt="Failed" /><br />Failed</td>
|
|
111
|
-
<td align="center" width="25%"><img src="./showcase/gifs/happy.gif" width="120" alt="Finished" /><br />Finished</td>
|
|
112
|
-
<td align="center" width="25%"><img src="./showcase/gifs/sleeping.gif" width="120" alt="Asleep" /><br />Asleep</td>
|
|
113
|
-
</tr>
|
|
114
|
-
</table>
|
|
115
|
-
|
|
116
|
-
## Disabling and uninstalling
|
|
117
|
-
|
|
118
|
-
To pause the theme without uninstalling it, add the following to the profile's `cordis.patch.yml` (`~/.dsh/profiles/web/cordis.patch.yml`):
|
|
119
|
-
|
|
120
|
-
```yaml
|
|
121
|
-
- id: ui-skin-claude-style
|
|
122
|
-
disabled: true
|
|
97
|
+
dsh-claude-style
|
|
123
98
|
```
|
|
124
99
|
|
|
125
|
-
|
|
100
|
+
2. From a terminal:
|
|
126
101
|
|
|
127
102
|
```bash
|
|
128
|
-
dsh plugin --profile web
|
|
103
|
+
dsh plugin --profile web add dsh-claude-style # npm package (recommended)
|
|
104
|
+
dsh plugin --profile web add Nwflower/dsh-claude-style # GitHub source
|
|
129
105
|
```
|
|
130
106
|
|
|
131
|
-
|
|
107
|
+
3. From the [plugin market](https://github.com/dsh-market/dsh-market)
|
|
108
|
+
|
|
109
|
+
Keep only one theme enabled at a time. dsh ≥ 0.1.7 is required, and a restart of DeepSeek Harness brings the full feature set.
|
|
132
110
|
|
|
133
111
|
## Documentation
|
|
134
112
|
|
package/README.md
CHANGED
|
@@ -78,6 +78,10 @@
|
|
|
78
78
|
| Anthropic Sans Web Text | 界面 / UI | [`fonts/AnthropicSansWebText.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/AnthropicSansWebText.ttf) |
|
|
79
79
|
| Anthropic Serif Web Text | 对话正文 / Markdown | [`fonts/AnthropicSerifWebText.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/AnthropicSerifWebText.ttf) |
|
|
80
80
|
| JetBrains Mono Variable | 代码 / 代码块 | [`fonts/JetBrainsMonoVariable.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/JetBrainsMonoVariable.ttf)、[`fonts/JetBrainsMonoItalicVariable.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/JetBrainsMonoItalicVariable.ttf) |
|
|
81
|
+
| Inter | 没有 Anthropic Sans 时的界面字体 | [`fonts/InterVariable.woff2`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/InterVariable.woff2) |
|
|
82
|
+
| Noto Serif | 没有 Anthropic Serif 时的正文字体 | [`fonts/NotoSerifVariable.woff2`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/NotoSerifVariable.woff2) |
|
|
83
|
+
|
|
84
|
+
JetBrains Mono、Inter 与 Noto Serif 采用 SIL Open Font License 1.1,随 npm 包分发,无需任何操作。Inter 与 Noto Serif 的字高、字宽与两款 Anthropic 字体几乎一致,没有启用 Anthropic 字体时由它们代替,界面与正文的排版不会因此变样;两者只含 Anthropic 字体覆盖的拉丁字符,中文照旧使用系统中文字体。
|
|
81
85
|
|
|
82
86
|
Anthropic 字体启用(二选一):
|
|
83
87
|
|
package/docs/STYLE.md
CHANGED
|
@@ -173,7 +173,7 @@ the shell itself. What it carries is described under "Context popover" below.
|
|
|
173
173
|
| radius | 12px |
|
|
174
174
|
| shadow | `0 8px 30px rgba(20,20,19,.12), 0 2px 8px rgba(20,20,19,.06)`; dark `rgba(0,0,0,.5)` / `rgba(0,0,0,.3)` |
|
|
175
175
|
| padding | 6px |
|
|
176
|
-
| layout | flex column, `gap: 6px
|
|
176
|
+
| layout | flex column, `gap: 6px`; a list body stacks its rows 3px apart |
|
|
177
177
|
| z-index | 99999, above the host's own menus (1100) |
|
|
178
178
|
| open | `opacity 0 → 1`, `translateY(4px) scale(.98) → none`, `.15s ease`, origin on the anchor's side |
|
|
179
179
|
|
|
@@ -238,12 +238,24 @@ on that stamp, so it plays on the card the reader will actually see.
|
|
|
238
238
|
The context meter's popover is the host's own panel: the skin opens it by
|
|
239
239
|
pressing the host's trigger (hover, with the shared 100 ms dwell and close
|
|
240
240
|
grace, gated on the "open popovers on hover" preference; a click still works),
|
|
241
|
-
and paints nothing of its shell
|
|
241
|
+
and paints nothing of its shell or its dismissal. It mounts
|
|
242
242
|
instead of toggling `data-open`, so the feature stamps the panel and it takes
|
|
243
243
|
the cards' own short rise as a one-shot animation — same 4px, same `scale(.98)`,
|
|
244
244
|
same 0.15s — and a surface the skin opens arrives the same way wherever it is
|
|
245
245
|
the host's.
|
|
246
246
|
|
|
247
|
+
Its horizontal place is the one thing the skin takes over. ui-chat hangs the
|
|
248
|
+
panel from the anchor's LEFT edge and only then clamps it into the viewport
|
|
249
|
+
(`useStatDialog`, align `start`), so a trigger at the end of the composer row
|
|
250
|
+
leaves the panel against the window's right margin instead of under the ring.
|
|
251
|
+
`features/permissions/session-stats.js` reads the meter's right edge and the
|
|
252
|
+
panel's own layout width — `offsetWidth`, not its rect: the entrance scales the
|
|
253
|
+
box, and a transformed rect is two per cent narrower than the one that settles —
|
|
254
|
+
and writes `--dsh-claude-context-panel-left` with the mark that turns it on;
|
|
255
|
+
`features/composer/inline-bar.css` reads it with `!important`, which outranks the
|
|
256
|
+
host's inline value. The reading is re-taken when the panel's box changes (a
|
|
257
|
+
`ResizeObserver`) and when the viewport moves (`reposition('viewport')`).
|
|
258
|
+
|
|
247
259
|
What the skin appends to it is the session's numbers
|
|
248
260
|
(`features/permissions/session-stats.js`), read from the host's `sessionStats`
|
|
249
261
|
and `tokenUsage` projections — the same durable whole-log values the host's own
|
|
@@ -254,6 +266,14 @@ two surfaces read the same words; the host's small formatting rules
|
|
|
254
266
|
`formatCacheHitPercent`) are mirrored so the figures match character for
|
|
255
267
|
character.
|
|
256
268
|
|
|
269
|
+
Which figures appear follows the host's statistics row. Its detailed form gets
|
|
270
|
+
the whole list. Its compact form carries only the output speed and the cache-hit
|
|
271
|
+
share on the composer line, so the block keeps the four that row leaves out —
|
|
272
|
+
the total time, the first-token average, the output speed and the cache-hit
|
|
273
|
+
share. The total is the one figure the host has no word for (its dialog names
|
|
274
|
+
the model's time and the tool calls' separately): it is their sum, labelled from
|
|
275
|
+
the skin's own copy (`contextTotalTime`).
|
|
276
|
+
|
|
257
277
|
The block: a 1px `var(--dsw-alias-border-l1)` rule and 10px above it, then per
|
|
258
278
|
section an 11px / 16px heading at 600 in `label-tertiary` and a two-column grid
|
|
259
279
|
(6px by 10px). A row is a stack: 12px / 16px label in `label-tertiary` over a
|
|
@@ -274,13 +294,15 @@ z-index 1000 and 100000) and now follows the table above. The hero row's pickers
|
|
|
274
294
|
two ways that CSS cannot change: it mounts instead of toggling a `data-open`
|
|
275
295
|
attribute, so it takes the same fade/scale as a one-shot `0.15s` animation; and
|
|
276
296
|
the host places it *below* its trigger, which is where the composer sits — so
|
|
277
|
-
`src/features/hero-menu/hero-menu.js` re-places it
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
297
|
+
`src/features/hero-menu/hero-menu.js` re-places it on the trigger the way the
|
|
298
|
+
skin's own composer pickers sit: right-aligned with the trigger and opening
|
|
299
|
+
upward by the same 6px air, flipping below only when the viewport leaves no room
|
|
300
|
+
above, and clamped to the 8px viewport margin (`POPOVER_MARGIN`). The host
|
|
301
|
+
re-runs its own placement from its anchor geometry on every frame while the card
|
|
302
|
+
is open, so the position is handed over in two custom properties on the card
|
|
303
|
+
(`--dsh-claude-hero-menu-x` / `--dsh-claude-hero-menu-y`, written by the same
|
|
304
|
+
pass that stamps it) which `features/hero-menu/hero-menu.css` reads with
|
|
305
|
+
`!important`; that declaration outranks the host's plain inline value.
|
|
284
306
|
|
|
285
307
|
## Search · 搜索
|
|
286
308
|
|
package/docs/architecture.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
按主题:
|
|
12
12
|
|
|
13
13
|
- 构建与源码:D1 拼接构建 · D5 模型文案是数据 · D18 源码布局与共用部件层 · D4 输入框样式门控
|
|
14
|
-
- 宿主边界:D2 只做浏览器半边 · D3 宿主选择器纪律 · D19 宿主契约与构建编号 · D10 设置传输 · D11 私有路由与字符串安全
|
|
14
|
+
- 宿主边界:D2 只做浏览器半边 · D3 宿主选择器纪律 · D19 宿主契约与构建编号 · D10 设置传输 · D11 私有路由与字符串安全 · D28 桌面标题带的一处读取
|
|
15
15
|
- 运行时:D6 单一调度器 · D13 功能契约 · D12 快速失败与功能隔离 · D9 样式性能
|
|
16
16
|
- 功能:D14 账号表面 · D15 HDSL 契约 · D16 弹层基准 · D17 权限档位 · D20 滑动高亮 · D21 已归档列表 · D22 搜索面板 · D23 轮次状态行 · D24 小鲸鱼 Deepy · D25 封号彩蛋页的桌面顶栏 · D26 动画效果偏好 · D27 会话数字收进上下文弹层
|
|
17
17
|
- 分发:D7 行为层与皮肤同包 · D8 多主题
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
## D1. 零构建工具链:构建期逐字拼接成单文件
|
|
22
22
|
|
|
23
23
|
- **决定**:`scripts/build.mjs` 按 `FRAGMENTS` / `STYLE_FILES` 的顺序把 `src/` 下的 JS 片段与样式表拼成 `lib/client.js`。所有片段共用一个工厂作用域:不写 import/export,顶层名字在整个产物里唯一;React 由构建头部经加载器 `require('react')` 取得,其他宿主包在用到它的功能里直接 `require`。片段用现代语法(`const` / `let`、箭头函数、可选链),基础缩进 4 空格。品牌 SVG、螃蟹的帧条 PNG 与厂商锁定标在构建时内联,字体、模型文案与小鲸鱼的帧图(D24,构建时复制到 `lib/deepy/`)走宿主半边的路由。
|
|
24
|
-
- **构建检查**:`src/` 下每个 `.js` / `.css` 都在两份清单里;`%%TOKEN%%` 全部替换;输入框样式门控(D4);`:has()` 位置(D9);产物能被 `vm.Script` 解析;模型文案文档校验(D5);小鲸鱼的帧图与 `DEEPY_SHEETS` 表一一对应、每行的帧数、裁切框与静止帧合法(D24
|
|
25
|
-
- **理由**:DSH 的插件加载器没有相对 require,也没有资产 URL
|
|
24
|
+
- **构建检查**:`src/` 下每个 `.js` / `.css` 都在两份清单里;`%%TOKEN%%` 全部替换;输入框样式门控(D4);`:has()` 位置(D9);产物能被 `vm.Script` 解析;模型文案文档校验(D5);小鲸鱼的帧图与 `DEEPY_SHEETS` 表一一对应、每行的帧数、裁切框与静止帧合法(D24);`src/entry.js` 的 FEATURES 表与 `FEATURE_MAINS` 登记的功能主文件双向对上、`src/features/` 下每个目录都有安装项(`checkFeatureRegistry`)。产物写入构建编号(D19)。
|
|
25
|
+
- **理由**:DSH 的插件加载器没有相对 require,也没有资产 URL,打包器产出的分块与资产引用无处安放。加载器另有包内异步分包(`require.async('./client.<名字>.js')`),评估后不采用:产物 gzip 后约 288 KiB,首帧解析成本可忽略;大负载已按 D5 与 D24 在产物外按需加载(模型文案、帧图,字体走宿主路由);改用分包要让构建发出带 `__ModuleLoader__.load` 注册的多个文件、让桩宿主扮分包加载,并把共享作用域的片段在分包边界上显式导出,而收益只是省下一次本来就快的解析;这条管线目前只有官方包在用,第三方插件包的分包资源没有公开契约(D2)。
|
|
26
26
|
- **代价**:顶层名字共用一个作用域,靠命名约定避免冲突(D18);没有按需裁剪,产物体积靠自律控制。
|
|
27
|
-
- **重审条件**:加载器原生支持 ES module 相对导入与资产 URL
|
|
27
|
+
- **重审条件**:加载器原生支持 ES module 相对导入与资产 URL;或引擎把插件包的异步分包写进公开契约,且产物 gzip 后超过约 1 MiB 时,重新评估分包。
|
|
28
28
|
|
|
29
29
|
## D2. 只做浏览器半边的皮肤,不改宿主
|
|
30
30
|
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
|
|
66
66
|
## D6. 单一调度器
|
|
67
67
|
|
|
68
|
-
- **决定**:`src/core/scheduler.js`
|
|
68
|
+
- **决定**:`src/core/scheduler.js` 持有唯一常驻的 MutationObserver(`<body>` 子树,属性只看 `aria-label` / `aria-selected`),用 requestAnimationFrame 把变化合并成每帧一次刷新,按功能顺序调用各功能的 `sync()`。常驻的指针、键盘、焦点、滚动与尺寸监听也只注册在这里,经功能句柄上的钩子分发(D13)。例外只有两类,两处都要随自己的开合或状态撤下:弹层开着期间的指针与按键(模型选择器、快捷供应商、推理推条、hero 菜单、权限弹层各自在打开时挂、关闭或卸载时摘);调度器看不了、又不得喂给任何一轮刷新的状态——跟随窗口焦点的文本选区(`features/selection`,窗口事件需要捕获阶段)、主题翻转的 `data-ds-dark-theme`(`features/theme-flip` 自己盯,只影响自己的抑制标记)、分段控件的尺寸变化(`shared/sliding-pill.js`)。指针移动只经 `onActivity` 告诉功能「读者在」,钩子只记下时刻,一次扫过不触发刷新。键盘路径只认用户的按键:皮肤自己代发的键盘事件带标记(账号表面对宿主菜单派发的 Escape 带 `__dshHostMenuEscape`),调度器见到标记即跳过——那次代发只送达宿主的菜单,不得顺带触发全局 Esc 路由。刷新状态在调度器开头声明:订阅偏好时,已就绪的设置表单会同步通知并触发 `schedule()`。
|
|
69
69
|
- **理由**:各功能自挂观察者与监听会互相干扰、重复扫描、难以卸载干净。
|
|
70
70
|
- **代价**:每个 `sync()` 必须能快速提前返回,并且只在值变化时写 DOM(同值写入也会让元素样式失效);页面持续变化时每帧都有一次刷新,其开销见 D9。
|
|
71
71
|
|
|
@@ -169,14 +169,14 @@
|
|
|
169
169
|
## D18. 源码按功能归档,共用部件单独成层
|
|
170
170
|
|
|
171
171
|
- **决定**:
|
|
172
|
-
- `src/core/`:宿主访问、偏好、模型文案、i18n、调度器。`src/shared/`:多个功能共用的部件,JS 与 CSS 放在一起——`dom.js`(`buildElement`、`createStamp`)、`notify.js`(`notifyAll`)、`popover.js` / `popover.css`(定位、悬停意图、弹层登记表、卡片外壳与行,D16)、`sliding-pill.js` / `sliding-pill.css`(D20)。`src/theme/`:不属于任何功能的全局外观。`src/features/<功能>/`:一个功能的安装器、拆出的工厂与样式表放在一起,主文件以功能命名。`host
|
|
172
|
+
- `src/core/`:宿主访问、偏好、模型文案、i18n、调度器。`src/shared/`:多个功能共用的部件,JS 与 CSS 放在一起——`dom.js`(`buildElement`、`createStamp`)、`notify.js`(`notifyAll`)、`popover.js` / `popover.css`(定位、悬停意图、弹层登记表、卡片外壳与行,D16)、`sliding-pill.js` / `sliding-pill.css`(D20)。`src/theme/`:不属于任何功能的全局外观。`src/features/<功能>/`:一个功能的安装器、拆出的工厂与样式表放在一起,主文件以功能命名。`host/`:手写的宿主半边,入口 `index.js` 只做装配,私有路由(`routes.js`)、HDSL 契约(`hdsl.js`)与设置形式(`settings.js`)各自成模块。`lib/`:只放构建产物。
|
|
173
173
|
- 拼接顺序:共用样式表排在所有功能样式表之前,功能自己的规则在同优先级时后出现、取胜。
|
|
174
174
|
- 共用:同一段 DOM 查询或同一种写法出现第 3 次时收进 `shared/`(宿主访问收进 `core/host.js`);功能之间不借用类名,共用外观用中性类名。
|
|
175
175
|
- 文件大小:片段接近 750 行时,在它的功能目录里按职责拆出工厂(D13),不按行数机械切分。
|
|
176
176
|
- 搬动与逻辑改动分开提交:搬动提交里只有位置与路径变化,并用构建产物逐行比对确认。
|
|
177
177
|
- **理由**:一个功能的 JS 与样式放在一起,读代码时只需看一个目录;共用写法只有一份,改动不会漏改。
|
|
178
178
|
- **代价**:路径更深;新文件要登记到构建清单(构建会拒绝漏登的文件)。
|
|
179
|
-
- **重审条件**:D1
|
|
179
|
+
- **重审条件**:D1 的重审条件成立时,改为真正的模块导入(含按需分包)。
|
|
180
180
|
|
|
181
181
|
## D19. 宿主契约与构建编号
|
|
182
182
|
|
|
@@ -245,11 +245,12 @@
|
|
|
245
245
|
## D25. 封号彩蛋页在桌面端骑在系统标题栏那一行上
|
|
246
246
|
|
|
247
247
|
- **决定**:
|
|
248
|
-
-
|
|
249
|
-
-
|
|
248
|
+
- 两个桌面平台都把窗口最上面一条交给系统层,彩蛋页因此不再画自己那套最小化 / 还原 / 关闭,顶栏改骑在这条横带上:`ban-screen.js` 打开时问一次 `desktopBand()`(D28),把横带高度与窗口控件占用的宽度写成 `--dsh-ban-caption-height` / `--dsh-ban-caption-controls`,把控件所在的一端写成 `data-dsh-ban-controls`,并给浮层打 `data-dsh-ban-titlebar`;样式表据此把字标与「退出登录」排进这一行,并按控件所在的一端让出那一段宽度——Windows 的三个窗口按钮在右端,macOS 的三个红黄绿按钮在左端。
|
|
249
|
+
- Windows 的横带要跟着页面走:浮层打开期间把页面自己的 `--dsh-ban-canvas` 写到 `<body>` 的 `--dsw-specific-sidebar-fill` 上——桌面壳的探针读的正是这个令牌,`<body>` 的 style 一变它就重画横带——关闭时撤掉。这一步只在 Windows 调用:macOS 的横带由系统自己的半透明材质画出,页面写不到它。
|
|
250
|
+
- 这一行是窗口的拖拽区,浮层盖住了宿主自己的拖拽区(Windows 的 `.frame::before` 横条,以及 macOS 上宿主标了 `data-window-drag` 的那些元素),所以顶栏自己声明 `-webkit-app-region: drag`,里面只有「退出登录」一个控件写 `no-drag`。
|
|
250
251
|
- 这页画的始终是 Claude 自己的星芒加字标,与品牌偏好无关(它复刻的是 Claude 的一页)。
|
|
251
252
|
- **理由**:桌面端的系统标题栏是原生层,页面既盖不住也画不上;把这一行接过来,整窗浮层才像一整个窗口,而不是窗口里嵌了一页。
|
|
252
|
-
- **代价**:依赖 `
|
|
253
|
+
- **代价**:依赖 `data-windows-titlebar` 与 `data-platform="darwin"`、`--dsh-frame-top-clearance`、Windows 的 `--dsw-specific-sidebar-fill` 探针与 Window Controls Overlay API 的现状;桌面壳不再量这些时横带保持主题色,页面顶端的字标会被横带盖住。
|
|
253
254
|
- **重审条件**:宿主或桌面壳给出整窗浮层的插槽,或允许浮层隐藏标题栏时,改用那个。
|
|
254
255
|
|
|
255
256
|
## D26. 动画效果偏好:一处解析,两处读同一个值
|
|
@@ -265,11 +266,19 @@
|
|
|
265
266
|
## D27. 会话数字收进上下文弹层
|
|
266
267
|
|
|
267
268
|
- **决定**:
|
|
268
|
-
- 宿主画在输入卡片下方的统计行(轮次与步数 · tok/s、总 tokens · 缓存命中)与它的两张明细面板一起隐藏(`features/composer/inline-bar.css`):输入行只剩右端的上下文计量环,数字进它自己的那个弹层。行仍留在文档里,只为让「性能与用量」这一档(详细 /
|
|
269
|
+
- 宿主画在输入卡片下方的统计行(轮次与步数 · tok/s、总 tokens · 缓存命中)与它的两张明细面板一起隐藏(`features/composer/inline-bar.css`):输入行只剩右端的上下文计量环,数字进它自己的那个弹层。行仍留在文档里,只为让「性能与用量」这一档(详细 / 简洁)的结构还读得出来——详细档给出宿主那两组所有的行,简洁档只给四个数字:总用时(模型用时加工具调用用时,宿主没有这个合计,用皮肤自己的文案)、首 token 平均、输出速度与缓存命中,不带分组小标题,直接排成 2×2 网格。
|
|
269
270
|
- 数字按**数据**读,不读渲染结果:`sessionStats` 与 `tokenUsage` 是宿主在整份日志上折出来的会话投影,会话面交出它们的按 key 读取面(`session.projections.faceOf`,也就是宿主自己 `useProjection` 走的那个座位;`features/permissions/session-stats.js` 经 `sessions.binding(id)` 取)。面板打开时按当前值填,订阅到新帧就地重写:不再按胶囊、不再等宿主的对话框挂载。
|
|
270
271
|
- **文字与格式向宿主对齐**:标签、时长模板与分词符都取自宿主的 `chat` 语言命名空间(`locale.bind('chat')`);宿主在原始数值之上做的四条格式规则(`formatDuration`、`formatTokensPerSecond`、`formatExactTokens`、`formatCacheHitPercent`)在皮肤里各写一份,函数名对着来源,输出与宿主自己的显示逐字符相同。
|
|
271
272
|
- 面板靠结构辨认(非模态、带 `dl`),开合靠按宿主的触发按钮(`aria-expanded` 是权威);悬停进出走共享的停留与宽限,并跟随「悬停打开弹层」偏好,指针停在面板里时不收起。既然面板是宿主挂载的,皮肤给它打 `data-dsh-claude-context-panel` 并让它取卡片那套一次性入场(同一个 4px、同一个 0.15 秒)——同一个动作在哪个控件上都以同样的方式出现。
|
|
272
|
-
-
|
|
273
|
+
- 面板的左右位置由皮肤重写:宿主从定位点的左缘放下弹层(`useStatDialog` 的 `align: 'start'`),输入行右端按这个位置只够把它挤到窗口右缘,离计量环很远。皮肤量出计量环的右缘与弹层自己的布局宽度(入场动画把盒子缩到 0.98,量矩形会少两个百分点,所以读 `offsetWidth`),写成 `--dsh-claude-context-panel-left` 并同时打上 `data-dsh-claude-context-aligned`,样式表用 `!important` 读取——与 hero 菜单同一套交接。盒子变化时由 ResizeObserver、视口移动时由 `reposition('viewport')` 重新量。
|
|
274
|
+
- 追加的块带 `data-dsh-claude-context-stats`;投影还没有应答时,详细档按两个真实小标题、简洁档按无标题 2×2 网格占住数字要用的高度(占位条按真实行的 37px 排),宿主重绘面板把它抹掉时下一轮刷新重画。占位只保留 `STATS_SKELETON_MS`(2 秒):宿主不提供这两个投影单元时,块退场而不是长期立着占位条。
|
|
273
275
|
- **理由**:会话的所有数字只留一个去处,输入行只剩右端那只计量环;面板本体、开合与关合都还是宿主的。读投影让插件画的是数据,不是别人渲染出来的文字——既不重复渲染,也能随会话实时更新。
|
|
274
|
-
- **代价**:依赖宿主两个投影单元的键名与值形状、`chat` 命名空间的键、会话面上的 `projections.faceOf`,以及统计行的结构(据此判断详细 /
|
|
276
|
+
- **代价**:依赖宿主两个投影单元的键名与值形状、`chat` 命名空间的键、会话面上的 `projections.faceOf`,以及统计行的结构(据此判断详细 / 简洁)。宿主不装这两个投影单元时,面板里没有这两组数字(那时宿主的胶囊同样没有数据)。弹层的左右位置另依赖宿主的放置方式与计量环的现状;宿主改从右缘放下弹层、或给面板一个固定宽度时,这段接管要跟着核对。
|
|
275
277
|
- **重审条件**:宿主把这些数字放进它自己的面板,或给统计行一个可悬挂的插槽时,改回宿主的。
|
|
278
|
+
|
|
279
|
+
## D28. 桌面标题带只在一处读取
|
|
280
|
+
|
|
281
|
+
- **决定**:`src/core/desktop-band.js` 的 `desktopBand()` 是皮肤读取桌面标题带的唯一入口,一次回答三个问题:这条横带在不在、多高、窗口控件占哪一端,返回值形如 `{ platform, height, controls: { side, size } }`,没有横带时返回 `null`。判据全部取宿主自己的契约:标记用 `data-windows-titlebar` 与 `data-platform="darwin"`,高度用 `--dsh-frame-top-clearance`(宿主在两个平台都写它,Windows 上它是 `--dsh-windows-titlebar-height` 的别名,读取时经计算样式把别名解开),Windows 的控件宽度仍以 Window Controls Overlay API 为准、取不到量值时回落到 140px,macOS 的控件在左端、宽度取宿主自己的 leading seat 起点 88px。macOS 全屏时窗口控件收起,这里答 `null`;Windows 的答案与引入这个模块之前逐字相同,`data-fullscreen` 不参与那个平台的分支。
|
|
282
|
+
- **理由**:封号彩蛋页是第一个读者;判据若写在每个读者里,两个平台的三处分歧就要在每一处重复一遍。集中之后 Windows 的行为不变,macOS 拿到的是同一套答案换成本平台的量值。
|
|
283
|
+
- **代价**:多一个片段,每次调用多一次 `getComputedStyle` 读取;`--dsh-frame-top-clearance` 缺席时回落到模块内的常数(macOS 48px、Windows 40px)。
|
|
284
|
+
- **重审条件**:宿主给出统一的标题带插槽或平台无关的度量接口时,改读宿主的接口。
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright 2020 The Inter Project Authors (https://github.com/rsms/inter)
|
|
2
|
+
|
|
3
|
+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
|
4
|
+
This license is copied below, and is also available with a FAQ at:
|
|
5
|
+
https://scripts.sil.org/OFL
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
-----------------------------------------------------------
|
|
9
|
+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
|
10
|
+
-----------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
PREAMBLE
|
|
13
|
+
The goals of the Open Font License (OFL) are to stimulate worldwide
|
|
14
|
+
development of collaborative font projects, to support the font creation
|
|
15
|
+
efforts of academic and linguistic communities, and to provide a free and
|
|
16
|
+
open framework in which fonts may be shared and improved in partnership
|
|
17
|
+
with others.
|
|
18
|
+
|
|
19
|
+
The OFL allows the licensed fonts to be used, studied, modified and
|
|
20
|
+
redistributed freely as long as they are not sold by themselves. The
|
|
21
|
+
fonts, including any derivative works, can be bundled, embedded,
|
|
22
|
+
redistributed and/or sold with any software provided that any reserved
|
|
23
|
+
names are not used by derivative works. The fonts and derivatives,
|
|
24
|
+
however, cannot be released under any other type of license. The
|
|
25
|
+
requirement for fonts to remain under this license does not apply
|
|
26
|
+
to any document created using the fonts or their derivatives.
|
|
27
|
+
|
|
28
|
+
DEFINITIONS
|
|
29
|
+
"Font Software" refers to the set of files released by the Copyright
|
|
30
|
+
Holder(s) under this license and clearly marked as such. This may
|
|
31
|
+
include source files, build scripts and documentation.
|
|
32
|
+
|
|
33
|
+
"Reserved Font Name" refers to any names specified as such after the
|
|
34
|
+
copyright statement(s).
|
|
35
|
+
|
|
36
|
+
"Original Version" refers to the collection of Font Software components as
|
|
37
|
+
distributed by the Copyright Holder(s).
|
|
38
|
+
|
|
39
|
+
"Modified Version" refers to any derivative made by adding to, deleting,
|
|
40
|
+
or substituting -- in part or in whole -- any of the components of the
|
|
41
|
+
Original Version, by changing formats or by porting the Font Software to a
|
|
42
|
+
new environment.
|
|
43
|
+
|
|
44
|
+
"Author" refers to any designer, engineer, programmer, technical
|
|
45
|
+
writer or other person who contributed to the Font Software.
|
|
46
|
+
|
|
47
|
+
PERMISSION & CONDITIONS
|
|
48
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
49
|
+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
|
50
|
+
redistribute, and sell modified and unmodified copies of the Font
|
|
51
|
+
Software, subject to the following conditions:
|
|
52
|
+
|
|
53
|
+
1) Neither the Font Software nor any of its individual components,
|
|
54
|
+
in Original or Modified Versions, may be sold by itself.
|
|
55
|
+
|
|
56
|
+
2) Original or Modified Versions of the Font Software may be bundled,
|
|
57
|
+
redistributed and/or sold with any software, provided that each copy
|
|
58
|
+
contains the above copyright notice and this license. These can be
|
|
59
|
+
included either as stand-alone text files, human-readable headers or
|
|
60
|
+
in the appropriate machine-readable metadata fields within text or
|
|
61
|
+
binary files as long as those fields can be easily viewed by the user.
|
|
62
|
+
|
|
63
|
+
3) No Modified Version of the Font Software may use the Reserved Font
|
|
64
|
+
Name(s) unless explicit written permission is granted by the corresponding
|
|
65
|
+
Copyright Holder. This restriction only applies to the primary font name as
|
|
66
|
+
presented to the users.
|
|
67
|
+
|
|
68
|
+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
|
69
|
+
Software shall not be used to promote, endorse or advertise any
|
|
70
|
+
Modified Version, except to acknowledge the contribution(s) of the
|
|
71
|
+
Copyright Holder(s) and the Author(s) or with their explicit written
|
|
72
|
+
permission.
|
|
73
|
+
|
|
74
|
+
5) The Font Software, modified or unmodified, in part or in whole,
|
|
75
|
+
must be distributed entirely under this license, and must not be
|
|
76
|
+
distributed under any other license. The requirement for fonts to
|
|
77
|
+
remain under this license does not apply to any document created
|
|
78
|
+
using the Font Software.
|
|
79
|
+
|
|
80
|
+
TERMINATION
|
|
81
|
+
This license becomes null and void if any of the above conditions are
|
|
82
|
+
not met.
|
|
83
|
+
|
|
84
|
+
DISCLAIMER
|
|
85
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
|
88
|
+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
|
89
|
+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
90
|
+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
|
91
|
+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
92
|
+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
|
93
|
+
OTHER DEALINGS IN THE FONT SOFTWARE.
|