dsh-claude-style 0.10.3 → 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 +32 -0
- package/README.en.md +4 -0
- package/README.md +4 -0
- package/docs/architecture.md +14 -6
- 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/index.js +2 -1
- package/host/routes.js +4 -1
- package/lib/client.js +427 -166
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
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
|
+
|
|
5
37
|
## [0.10.3] - 2026-10-01
|
|
6
38
|
|
|
7
39
|
[中文](#cn-0.10.3) | [English](#en-0.10.3)
|
package/README.en.md
CHANGED
|
@@ -76,6 +76,10 @@ The settings page's Brand mark row switches between the Claude and DeepSeek pale
|
|
|
76
76
|
| Anthropic Sans Web Text | Interface / UI | [`fonts/AnthropicSansWebText.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/AnthropicSansWebText.ttf) |
|
|
77
77
|
| Anthropic Serif Web Text | Conversation body / Markdown | [`fonts/AnthropicSerifWebText.ttf`](https://github.com/Nwflower/dsh-claude-style/raw/main/fonts/AnthropicSerifWebText.ttf) |
|
|
78
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.
|
|
79
83
|
|
|
80
84
|
To enable the Anthropic fonts, choose one of the following:
|
|
81
85
|
|
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/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 多主题
|
|
@@ -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,12 +266,19 @@
|
|
|
265
266
|
## D27. 会话数字收进上下文弹层
|
|
266
267
|
|
|
267
268
|
- **决定**:
|
|
268
|
-
- 宿主画在输入卡片下方的统计行(轮次与步数 · tok/s、总 tokens · 缓存命中)与它的两张明细面板一起隐藏(`features/composer/inline-bar.css`):输入行只剩右端的上下文计量环,数字进它自己的那个弹层。行仍留在文档里,只为让「性能与用量」这一档(详细 / 简洁)的结构还读得出来——详细档给出宿主那两组所有的行,简洁档只给四个数字:总用时(模型用时加工具调用用时,宿主没有这个合计,用皮肤自己的文案)、首 token
|
|
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')` 重新量。
|
|
273
|
-
- 追加的块带 `data-dsh-claude-context-stats
|
|
274
|
+
- 追加的块带 `data-dsh-claude-context-stats`;投影还没有应答时,详细档按两个真实小标题、简洁档按无标题 2×2 网格占住数字要用的高度(占位条按真实行的 37px 排),宿主重绘面板把它抹掉时下一轮刷新重画。占位只保留 `STATS_SKELETON_MS`(2 秒):宿主不提供这两个投影单元时,块退场而不是长期立着占位条。
|
|
274
275
|
- **理由**:会话的所有数字只留一个去处,输入行只剩右端那只计量环;面板本体、开合与关合都还是宿主的。读投影让插件画的是数据,不是别人渲染出来的文字——既不重复渲染,也能随会话实时更新。
|
|
275
276
|
- **代价**:依赖宿主两个投影单元的键名与值形状、`chat` 命名空间的键、会话面上的 `projections.faceOf`,以及统计行的结构(据此判断详细 / 简洁)。宿主不装这两个投影单元时,面板里没有这两组数字(那时宿主的胶囊同样没有数据)。弹层的左右位置另依赖宿主的放置方式与计量环的现状;宿主改从右缘放下弹层、或给面板一个固定宽度时,这段接管要跟着核对。
|
|
276
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.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
|
|
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.
|
package/host/index.js
CHANGED
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* are NOT in the npm package (they remain Anthropic's property), but a
|
|
18
18
|
* user who drops them into this package's `fonts/` directory gets the
|
|
19
19
|
* same zero-install treatment; a missing file simply 404s and the stack
|
|
20
|
-
* falls back to a system-installed copy
|
|
20
|
+
* falls back to a system-installed copy, then to the look-alike faces
|
|
21
|
+
* this package does ship (Inter, Noto Serif — SIL OFL).
|
|
21
22
|
* 3. Resolve the OS user once for the browser half. The username route answers
|
|
22
23
|
* a single GET and the browser caches it; it runs the host's own request
|
|
23
24
|
* fence first — see refusalOf() in routes.js.
|
package/host/routes.js
CHANGED
|
@@ -24,7 +24,8 @@ const COPY_FILE = 'model-descriptions.json'
|
|
|
24
24
|
* Webfonts this plugin serves under `${ROUTE_PREFIX}/fonts/`, mapped to their
|
|
25
25
|
* content type. The table is a whitelist: the filename is the whole request
|
|
26
26
|
* contract, so nothing below the package's `fonts/` directory is reachable
|
|
27
|
-
* and no path traversal is possible. The JetBrains Mono files
|
|
27
|
+
* and no path traversal is possible. The JetBrains Mono files and the two
|
|
28
|
+
* look-alike faces behind the Anthropic ones (Inter, Noto Serif) ship in the
|
|
28
29
|
* npm package; the Anthropic faces do not (copyright) — their entries exist so
|
|
29
30
|
* a user-supplied copy in `fonts/` is served, and readFileSync's ENOENT turns
|
|
30
31
|
* into a 404 the browser half's font stacks fall back from.
|
|
@@ -34,6 +35,8 @@ const FONT_FILES = {
|
|
|
34
35
|
'JetBrainsMonoItalicVariable.ttf': 'font/ttf',
|
|
35
36
|
'AnthropicSansWebText.ttf': 'font/ttf',
|
|
36
37
|
'AnthropicSerifWebText.ttf': 'font/ttf',
|
|
38
|
+
'InterVariable.woff2': 'font/woff2',
|
|
39
|
+
'NotoSerifVariable.woff2': 'font/woff2',
|
|
37
40
|
}
|
|
38
41
|
/**
|
|
39
42
|
* Deepy's animation sheets, served under `${ROUTE_PREFIX}/deepy/` from the
|
package/lib/client.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* - src/assets/brand/*.svg Brand marks (inlined as CSS url() data URIs at build time)
|
|
9
9
|
* * - src/constants.js
|
|
10
10
|
* - src/core/host.js
|
|
11
|
+
* - src/core/desktop-band.js
|
|
11
12
|
* - src/core/prefs.js
|
|
12
13
|
* - src/core/model-copy.js
|
|
13
14
|
* - src/core/i18n.js
|
|
@@ -499,15 +500,15 @@ window.__ModuleLoader__.load({
|
|
|
499
500
|
/** Wordmark aspect ratio; scripts/build.mjs sizes the sidebar word height from it (geometry lives in src/assets/claude-word.svg). */
|
|
500
501
|
const CLAUDE_WORD_ASPECT = 512.22 / 121.54
|
|
501
502
|
|
|
502
|
-
const SANS = "'Anthropic Sans Web Text','Noto Sans SC','Source Han Sans SC',-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Hiragino Sans GB','Microsoft YaHei','Helvetica Neue',Helvetica,Arial,sans-serif"
|
|
503
|
-
const SERIF = "'Anthropic Serif Web Text',Georgia,'Times New Roman','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif"
|
|
503
|
+
const SANS = "'Anthropic Sans Web Text','Claude Style Inter','Noto Sans SC','Source Han Sans SC',-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Hiragino Sans GB','Microsoft YaHei','Helvetica Neue',Helvetica,Arial,sans-serif"
|
|
504
|
+
const SERIF = "'Anthropic Serif Web Text','Claude Style Noto Serif',Georgia,'Times New Roman','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif"
|
|
504
505
|
/**
|
|
505
506
|
* Conversation prose: Claude sets Latin text in the serif face and lets
|
|
506
507
|
* Chinese fall through to a sans CJK — the serif Latin faces carry no CJK
|
|
507
508
|
* glyphs, so the stack leads with serif and names the sans CJK families
|
|
508
509
|
* after it. UI chrome keeps SANS; only markdown prose uses this.
|
|
509
510
|
*/
|
|
510
|
-
const PROSE = "'Anthropic Serif Web Text',Georgia,'Times New Roman','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif"
|
|
511
|
+
const PROSE = "'Anthropic Serif Web Text','Claude Style Noto Serif',Georgia,'Times New Roman','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif"
|
|
511
512
|
const MONO = "'JetBrains Mono','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',ui-monospace,'SF Mono','Fira Code',Consolas,'Liberation Mono',Menlo,Courier,monospace"
|
|
512
513
|
|
|
513
514
|
// ============================================================================
|
|
@@ -517,9 +518,9 @@ window.__ModuleLoader__.load({
|
|
|
517
518
|
"/* --- 2.1 Design Tokens (Dark Base & Light Overrides) --- */",
|
|
518
519
|
"/* ---------- typography tokens: theme-independent ---------- */",
|
|
519
520
|
"body[data-dsh-claude-style] {",
|
|
520
|
-
" --dsw-font-family: 'Anthropic Sans Web Text','Noto Sans SC','Source Han Sans SC',-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Hiragino Sans GB','Microsoft YaHei','Helvetica Neue',Helvetica,Arial,sans-serif;",
|
|
521
|
-
" --dsw-font-serif: 'Anthropic Serif Web Text',Georgia,'Times New Roman','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;",
|
|
522
|
-
" --dsw-font-prose: 'Anthropic Serif Web Text',Georgia,'Times New Roman','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;",
|
|
521
|
+
" --dsw-font-family: 'Anthropic Sans Web Text','Claude Style Inter','Noto Sans SC','Source Han Sans SC',-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Hiragino Sans GB','Microsoft YaHei','Helvetica Neue',Helvetica,Arial,sans-serif;",
|
|
522
|
+
" --dsw-font-serif: 'Anthropic Serif Web Text','Claude Style Noto Serif',Georgia,'Times New Roman','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;",
|
|
523
|
+
" --dsw-font-prose: 'Anthropic Serif Web Text','Claude Style Noto Serif',Georgia,'Times New Roman','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif;",
|
|
523
524
|
" --dsw-font-code: 'JetBrains Mono','Noto Sans SC','Source Han Sans SC','PingFang SC','Hiragino Sans GB','Microsoft YaHei',ui-monospace,'SF Mono','Fira Code',Consolas,'Liberation Mono',Menlo,Courier,monospace;",
|
|
524
525
|
" /* Claude's lockup is drawn in Anthropic's serif, so its rows take the same face:",
|
|
525
526
|
" the wordmark and the rest of the label then read as one piece of lettering.",
|
|
@@ -918,6 +919,33 @@ window.__ModuleLoader__.load({
|
|
|
918
919
|
" font-display: swap;",
|
|
919
920
|
"}",
|
|
920
921
|
"",
|
|
922
|
+
"/* The look-alikes the stacks name right after the Anthropic faces, for an",
|
|
923
|
+
" install that has neither the files nor a system copy. Both ship in the",
|
|
924
|
+
" package (SIL OFL 1.1), cut to exactly the characters the Anthropic faces",
|
|
925
|
+
" cover, so text the Anthropic faces would not draw falls through to the same",
|
|
926
|
+
" CJK and system fonts as before. Inter matches Anthropic Sans in x-height,",
|
|
927
|
+
" cap height and lowercase width to within 0.01 em; Noto Serif does the same",
|
|
928
|
+
" for Anthropic Serif, so switching between a face and its look-alike does",
|
|
929
|
+
" not rewrap text. Both carry real weights, roman only — the Anthropic faces",
|
|
930
|
+
" have no italic either, so emphasis is slanted the same way in both. The",
|
|
931
|
+
" family names are the skin's own: a plugin that asks for 'Inter' or",
|
|
932
|
+
" 'Noto Serif' still gets its own copy, not these cut-down files. */",
|
|
933
|
+
"@font-face {",
|
|
934
|
+
" font-family: 'Claude Style Inter';",
|
|
935
|
+
" src: url('/dsh-claude-style/fonts/InterVariable.woff2') format('woff2');",
|
|
936
|
+
" font-weight: 100 900;",
|
|
937
|
+
" font-style: normal;",
|
|
938
|
+
" font-display: swap;",
|
|
939
|
+
"}",
|
|
940
|
+
"",
|
|
941
|
+
"@font-face {",
|
|
942
|
+
" font-family: 'Claude Style Noto Serif';",
|
|
943
|
+
" src: url('/dsh-claude-style/fonts/NotoSerifVariable.woff2') format('woff2');",
|
|
944
|
+
" font-weight: 100 900;",
|
|
945
|
+
" font-style: normal;",
|
|
946
|
+
" font-display: swap;",
|
|
947
|
+
"}",
|
|
948
|
+
"",
|
|
921
949
|
"/* ---------- typography: serif display + sans UI + mono code ---------- */",
|
|
922
950
|
"body[data-dsh-claude-style] {",
|
|
923
951
|
" font-family: var(--dsw-font-family);",
|
|
@@ -1361,15 +1389,15 @@ window.__ModuleLoader__.load({
|
|
|
1361
1389
|
" color: var(--dsh-claude-link-hover);",
|
|
1362
1390
|
"}",
|
|
1363
1391
|
"",
|
|
1364
|
-
"body[data-dsh-claude-style] button[class*=\"brand\"] {",
|
|
1392
|
+
"body[data-dsh-claude-style] button[class*=\"brand\"]:not([class*=\"dsh-claude\"]) {",
|
|
1365
1393
|
" color: var(--dsw-alias-brand-primary);",
|
|
1366
1394
|
"}",
|
|
1367
1395
|
"",
|
|
1368
1396
|
"/* The baked-in wordmark \"HARNESS\" badge (a pill rect + its letter paths)",
|
|
1369
1397
|
" looks crowded next to the whale + wordmark. Hide the badge entirely so",
|
|
1370
1398
|
" the brand reads as a clean whale + wordmark on the clay pill. */",
|
|
1371
|
-
"body[data-dsh-claude-style] button[class*=\"brand\"] rect[fill=\"currentColor\"],",
|
|
1372
|
-
"body[data-dsh-claude-style] button[class*=\"brand\"] path[fill*=\"label-primary-inverted\"] {",
|
|
1399
|
+
"body[data-dsh-claude-style] button[class*=\"brand\"]:not([class*=\"dsh-claude\"]) rect[fill=\"currentColor\"],",
|
|
1400
|
+
"body[data-dsh-claude-style] button[class*=\"brand\"]:not([class*=\"dsh-claude\"]) path[fill*=\"label-primary-inverted\"] {",
|
|
1373
1401
|
" display: none;",
|
|
1374
1402
|
"}",
|
|
1375
1403
|
"",
|
|
@@ -1393,25 +1421,48 @@ window.__ModuleLoader__.load({
|
|
|
1393
1421
|
" the canvas. That pill also carried a 9999px radius, and together with the",
|
|
1394
1422
|
" button overflow:hidden its arc clipped the leading edge of the mark — so",
|
|
1395
1423
|
" the radius goes as well. Adaptive logo color: espresso on light, ivory",
|
|
1396
|
-
" on dark (--dsh-claude-logo-ink; the DeepSeek brand's own blue under it).
|
|
1397
|
-
"
|
|
1398
|
-
"
|
|
1424
|
+
" on dark (--dsh-claude-logo-ink; the DeepSeek brand's own blue under it).",
|
|
1425
|
+
" Every \"brand\" rule in this file excludes the skin's own controls",
|
|
1426
|
+
" (:not([class*=\"dsh-claude\"])): the settings page's brand cards carry the",
|
|
1427
|
+
" same substring and draw their own border and background. */",
|
|
1428
|
+
"body[data-dsh-claude-style]:not([data-ds-dark-theme]) button[class*=\"brand\"]:not([class*=\"dsh-claude\"]),",
|
|
1429
|
+
"body[data-dsh-claude-style][data-ds-dark-theme] button[class*=\"brand\"]:not([class*=\"dsh-claude\"]) {",
|
|
1399
1430
|
" background: transparent !important;",
|
|
1400
1431
|
" border: none;",
|
|
1401
1432
|
" border-radius: 0;",
|
|
1402
1433
|
"}",
|
|
1403
1434
|
"",
|
|
1404
|
-
"body[data-dsh-claude-style]:not([data-ds-dark-theme]) button[class*=\"brand\"] {",
|
|
1435
|
+
"body[data-dsh-claude-style]:not([data-ds-dark-theme]) button[class*=\"brand\"]:not([class*=\"dsh-claude\"]) {",
|
|
1405
1436
|
" color: var(--dsh-claude-logo-ink) !important;",
|
|
1406
1437
|
"}",
|
|
1407
1438
|
"",
|
|
1408
|
-
"body[data-dsh-claude-style][data-ds-dark-theme] button[class*=\"brand\"] {",
|
|
1439
|
+
"body[data-dsh-claude-style][data-ds-dark-theme] button[class*=\"brand\"]:not([class*=\"dsh-claude\"]) {",
|
|
1409
1440
|
" color: var(--dsh-claude-logo-ink) !important;",
|
|
1410
1441
|
"}",
|
|
1411
1442
|
"",
|
|
1412
|
-
"/* badges: full pill
|
|
1413
|
-
"
|
|
1443
|
+
"/* Host badges and tags: full pill. Each is named by its own CSS-module class",
|
|
1444
|
+
" (docs/architecture.md D3) — trajectory step tags, the trajectory table's kind",
|
|
1445
|
+
" tag, the custom-model row tag, the recommended-option badge in a question,",
|
|
1446
|
+
" the plugin install attempt badge, the shortcut key caps — so a plugin's own",
|
|
1447
|
+
" badge or tag keeps the shape it draws. The host's Tag primitive is a round",
|
|
1448
|
+
" pill already. corner-shape: round goes with the pill radius: the host's",
|
|
1449
|
+
" corner-shape sheet gives every element a superellipse, which squares off a",
|
|
1450
|
+
" pill's ends. */",
|
|
1451
|
+
"body[data-dsh-claude-style] :is(",
|
|
1452
|
+
" [class*=\"_tagSystem\"],",
|
|
1453
|
+
" [class*=\"_tagUser\"],",
|
|
1454
|
+
" [class*=\"_tagContext\"],",
|
|
1455
|
+
" [class*=\"_tagMessage\"],",
|
|
1456
|
+
" [class*=\"_tagTool\"],",
|
|
1457
|
+
" [class*=\"_tagSubtool\"],",
|
|
1458
|
+
" [class*=\"_kindTag\"]:not([class*=\"_kindTagIcon\"], [class*=\"_kindTagLabel\"]),",
|
|
1459
|
+
" [class*=\"_rowTag\"],",
|
|
1460
|
+
" [class*=\"_optionLine\"] > [class*=\"_badge\"],",
|
|
1461
|
+
" [class*=\"_attemptBadge\"],",
|
|
1462
|
+
" [class*=\"_keyBadge\"]",
|
|
1463
|
+
") {",
|
|
1414
1464
|
" border-radius: 9999px;",
|
|
1465
|
+
" corner-shape: round;",
|
|
1415
1466
|
"}",
|
|
1416
1467
|
"",
|
|
1417
1468
|
"/* ---------- chrome details ---------- */",
|
|
@@ -1708,7 +1759,10 @@ window.__ModuleLoader__.load({
|
|
|
1708
1759
|
" the titlebar, horizontally centred in the window — the same row the host",
|
|
1709
1760
|
" gives the collapsed sidebar's new-session button. The measured",
|
|
1710
1761
|
" --dsh-view-tabs-shift is not written in this mode, so the base transform",
|
|
1711
|
-
" gives way.
|
|
1762
|
+
" gives way.",
|
|
1763
|
+
" macOS has no such block: its shell leaves the frame unpadded, so the",
|
|
1764
|
+
" conversation header draws its first row inside the strip and the measured",
|
|
1765
|
+
" shift seats the tabs on the row beneath it (view-tabs.js). */",
|
|
1712
1766
|
"body[data-dsh-claude-style][data-dsh-titlebar-tabs] [data-dsh-view-tabs] {",
|
|
1713
1767
|
" position: fixed !important;",
|
|
1714
1768
|
" top: calc(var(--dsh-windows-titlebar-height, 40px) / 2) !important;",
|
|
@@ -2545,9 +2599,13 @@ window.__ModuleLoader__.load({
|
|
|
2545
2599
|
"}",
|
|
2546
2600
|
"",
|
|
2547
2601
|
"/* @composer-gate */",
|
|
2548
|
-
"/* Model trigger in
|
|
2549
|
-
"
|
|
2550
|
-
"
|
|
2602
|
+
"/* Model trigger in the host's contract slot: the skin's own button, and the",
|
|
2603
|
+
" host's trigger when the picker preference hands the seat back. Both are",
|
|
2604
|
+
" named by their exact place in the seat, so a menu another plugin nests",
|
|
2605
|
+
" inside the seat keeps its own layout, and the seat root the picker hides is",
|
|
2606
|
+
" never matched — a display here would outrank the hide rule below. */",
|
|
2607
|
+
"body[data-dsh-claude-style][data-dsh-claude-composer-active] [data-composer-card][data-composer-variant=\"inline\"] [data-slot=\"conversation.input.model\"] > [class*=\"_root\"] > [class*=\"_trigger\"],",
|
|
2608
|
+
"body[data-dsh-claude-style][data-dsh-claude-composer-active] [data-composer-card][data-composer-variant=\"inline\"] [data-slot=\"conversation.input.model\"] > .dsh-claude-model-btn {",
|
|
2551
2609
|
" display: inline-flex !important;",
|
|
2552
2610
|
" align-items: center !important;",
|
|
2553
2611
|
" font-size: 13px !important;",
|
|
@@ -3554,16 +3612,23 @@ window.__ModuleLoader__.load({
|
|
|
3554
3612
|
" visibility: hidden !important;",
|
|
3555
3613
|
" pointer-events: none !important;",
|
|
3556
3614
|
"}",
|
|
3557
|
-
"/* The desktop shell's sidebar column starts under its 40px titlebar,
|
|
3558
|
-
" left the brand a titlebar's height lower than on the web; the row rises
|
|
3559
|
-
" 10px — as far as it goes with the 32px box still wholly below the titlebar,",
|
|
3560
|
-
" where the column's top edge would cut it.
|
|
3615
|
+
"/* The Windows desktop shell's sidebar column starts under its 40px titlebar,",
|
|
3616
|
+
" which left the brand a titlebar's height lower than on the web; the row rises",
|
|
3617
|
+
" by 10px — as far as it goes with the 32px box still wholly below the titlebar,",
|
|
3618
|
+
" where the column's top edge would cut it. macOS takes no offset: the host pads",
|
|
3619
|
+
" nothing around the traffic lights, and its own `_topStrip + _logoRow` margin",
|
|
3620
|
+
" (-12px) already seats the row's content at the 48px it declares for",
|
|
3621
|
+
" --dsh-frame-top-clearance; -10px would override that margin and move the row",
|
|
3622
|
+
" 2px down. */",
|
|
3561
3623
|
"html[data-windows-titlebar] body[data-dsh-claude-style] [data-slot=\"sidebar\"] [class*=\"_logoRow\"] {",
|
|
3562
3624
|
" margin-top: -10px !important;",
|
|
3563
3625
|
"}",
|
|
3564
|
-
"/*
|
|
3565
|
-
"
|
|
3566
|
-
"
|
|
3626
|
+
"/* On both desktop shells the host's toggle takes no cell in the row: macOS",
|
|
3627
|
+
" renders it inside its own 52px `_topStrip`, Windows fixes it into the caption",
|
|
3628
|
+
" overlay. The row keeps a single column there — a second, empty one would",
|
|
3629
|
+
" still cost the brand and the box the host logo row's 8px gap. */",
|
|
3630
|
+
"html[data-windows-titlebar] body[data-dsh-claude-style] [data-dsh-claude-search-row],",
|
|
3631
|
+
"html[data-platform=darwin] body[data-dsh-claude-style] [data-dsh-claude-search-row] {",
|
|
3567
3632
|
" grid-template-columns: minmax(0, 1fr) !important;",
|
|
3568
3633
|
"}",
|
|
3569
3634
|
"/* The host's own sidebar search stays mounted, since its shortcut (Ctrl+K)",
|
|
@@ -4741,27 +4806,40 @@ window.__ModuleLoader__.load({
|
|
|
4741
4806
|
" color: var(--dsh-ban-text);",
|
|
4742
4807
|
"}",
|
|
4743
4808
|
"",
|
|
4744
|
-
"/* ---------- Desktop caption
|
|
4745
|
-
"/*
|
|
4746
|
-
"
|
|
4747
|
-
"
|
|
4748
|
-
" --
|
|
4749
|
-
"
|
|
4750
|
-
"
|
|
4751
|
-
"
|
|
4752
|
-
"
|
|
4753
|
-
"
|
|
4754
|
-
"
|
|
4755
|
-
"
|
|
4809
|
+
"/* ---------- Desktop caption strip: the bar rides the native titlebar row ---------- */",
|
|
4810
|
+
"/* Both desktop platforms hand the top of the window to a NATIVE layer, and",
|
|
4811
|
+
" ban-screen.js stamps data-dsh-ban-titlebar on the overlay once per open",
|
|
4812
|
+
" whenever the shared desktopBand() reports a strip, together with the strip's",
|
|
4813
|
+
" height (--dsh-ban-caption-height) and the width its window controls occupy",
|
|
4814
|
+
" (--dsh-ban-caption-controls) and the end those controls take",
|
|
4815
|
+
" (data-dsh-ban-controls). So the bar stops drawing its own three window buttons",
|
|
4816
|
+
" — the strip already shows a cluster — and moves its content up onto the strip,",
|
|
4817
|
+
" clear of that cluster: Windows draws its caption buttons at the RIGHT end and",
|
|
4818
|
+
" macOS draws its traffic lights at the LEFT, which is the one thing the two",
|
|
4819
|
+
" platforms lay out differently. The Windows shell paints its strip with the",
|
|
4820
|
+
" colour it measures off --dsw-specific-sidebar-fill, so the overlay lends it",
|
|
4821
|
+
" the page's canvas colour while it is open (holdCaptionFill), which is what",
|
|
4822
|
+
" lets the lockup and Sign out read as that row's own content the way Claude's",
|
|
4823
|
+
" titlebar carries them; macOS paints the strip as the vibrancy sidebar, which",
|
|
4824
|
+
" no token of ours reaches.",
|
|
4825
|
+
" The strip has to keep moving the window, so the bar claims the DRAG region for",
|
|
4756
4826
|
" itself and only the one control inside it opts out: the overlay covers the",
|
|
4757
|
-
" host's own
|
|
4758
|
-
"
|
|
4827
|
+
" host's own drag regions (the Windows frame's `.frame::before` strip, and on",
|
|
4828
|
+
" macOS the elements the host marks `data-window-drag`), and a drag region the",
|
|
4829
|
+
" pointer cannot reach is no region at all. */",
|
|
4759
4830
|
"body[data-dsh-claude-style] .dsh-claude-ban[data-dsh-ban-titlebar] .dsh-claude-ban-bar {",
|
|
4760
|
-
" height: var(--dsh-ban-caption-height,
|
|
4831
|
+
" height: var(--dsh-ban-caption-height, 40px) !important;",
|
|
4761
4832
|
" padding: 0 calc(var(--dsh-ban-caption-controls, 140px) + 10px) 0 44px !important;",
|
|
4762
4833
|
" -webkit-app-region: drag;",
|
|
4763
4834
|
"}",
|
|
4764
4835
|
"",
|
|
4836
|
+
"/* macOS: the traffic lights sit at the LEFT end of the strip, so the bar keeps",
|
|
4837
|
+
" its own leading inset clear of them and gives the trailing end back to the",
|
|
4838
|
+
" row. */",
|
|
4839
|
+
"body[data-dsh-claude-style] .dsh-claude-ban[data-dsh-ban-titlebar][data-dsh-ban-controls=\"left\"] .dsh-claude-ban-bar {",
|
|
4840
|
+
" padding: 0 10px 0 calc(var(--dsh-ban-caption-controls, 88px) + 10px) !important;",
|
|
4841
|
+
"}",
|
|
4842
|
+
"",
|
|
4765
4843
|
"/* The lockup sits a touch below the row's midline: the wordmark's ink fills its",
|
|
4766
4844
|
" whole 21px box, so centring it beside the platform's 10px-tall caption glyphs",
|
|
4767
4845
|
" leaves it reading high. */",
|
|
@@ -4779,11 +4857,11 @@ window.__ModuleLoader__.load({
|
|
|
4779
4857
|
"}",
|
|
4780
4858
|
"",
|
|
4781
4859
|
"body[data-dsh-claude-style] .dsh-claude-ban[data-dsh-ban-titlebar] .dsh-claude-ban-scroll {",
|
|
4782
|
-
" inset: calc(var(--dsh-ban-caption-height,
|
|
4860
|
+
" inset: calc(var(--dsh-ban-caption-height, 40px) + 6px) 0 0 0;",
|
|
4783
4861
|
"}",
|
|
4784
4862
|
"",
|
|
4785
4863
|
"body[data-dsh-claude-style] .dsh-claude-ban[data-dsh-ban-titlebar] .dsh-claude-ban-toast {",
|
|
4786
|
-
" top: calc(var(--dsh-ban-caption-height,
|
|
4864
|
+
" top: calc(var(--dsh-ban-caption-height, 40px) + 16px);",
|
|
4787
4865
|
"}",
|
|
4788
4866
|
"",
|
|
4789
4867
|
"/* ---------- account_banned toast ---------- */",
|
|
@@ -6096,10 +6174,11 @@ window.__ModuleLoader__.load({
|
|
|
6096
6174
|
"}",
|
|
6097
6175
|
"",
|
|
6098
6176
|
"/* ---------- Claude Code layout: settings page ---------- */",
|
|
6099
|
-
"/* The skin's own page in the settings dialog
|
|
6100
|
-
" composer permission picker's classes
|
|
6101
|
-
" `.dsh-claude-segment`), so the two are literally one
|
|
6102
|
-
" lookalikes;
|
|
6177
|
+
"/* The skin's own page in the settings dialog and on the plugin page. Its",
|
|
6178
|
+
" segmented controls reuse the composer permission picker's classes",
|
|
6179
|
+
" (`.dsh-claude-segments` / `.dsh-claude-segment`), so the two are literally one",
|
|
6180
|
+
" control rather than two lookalikes; the row shell, the switch and the brand",
|
|
6181
|
+
" cards are new here. */",
|
|
6103
6182
|
"body[data-dsh-claude-style] .dsh-claude-settings {",
|
|
6104
6183
|
" display: flex;",
|
|
6105
6184
|
" flex-direction: column;",
|
|
@@ -6130,6 +6209,77 @@ window.__ModuleLoader__.load({
|
|
|
6130
6209
|
" min-width: 0;",
|
|
6131
6210
|
"}",
|
|
6132
6211
|
"",
|
|
6212
|
+
"/* A block row stacks its control under the text across the row's full width —",
|
|
6213
|
+
" the brand picker's cards need more room than an inline control slot gives. */",
|
|
6214
|
+
"body[data-dsh-claude-style] .dsh-claude-settings-row-block {",
|
|
6215
|
+
" flex-direction: column;",
|
|
6216
|
+
" align-items: stretch;",
|
|
6217
|
+
"}",
|
|
6218
|
+
"",
|
|
6219
|
+
"/* The brand picker: one card per brand, the brand's mark above its name. The",
|
|
6220
|
+
" marks are the same assets the sidebar and hero paint — Claude's clay",
|
|
6221
|
+
" starburst, DeepSeek's whale in brand blue — inlined as CSS data URIs, so",
|
|
6222
|
+
" they read in full colour on either theme. A new brand adds one option in",
|
|
6223
|
+
" settings.js and one [data-brand] rule here. */",
|
|
6224
|
+
"body[data-dsh-claude-style] .dsh-claude-brand-picker {",
|
|
6225
|
+
" display: grid;",
|
|
6226
|
+
" grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));",
|
|
6227
|
+
" gap: 8px;",
|
|
6228
|
+
"}",
|
|
6229
|
+
"",
|
|
6230
|
+
"body[data-dsh-claude-style] .dsh-claude-brand-card {",
|
|
6231
|
+
" appearance: none;",
|
|
6232
|
+
" margin: 0;",
|
|
6233
|
+
" display: flex;",
|
|
6234
|
+
" flex-direction: column;",
|
|
6235
|
+
" align-items: center;",
|
|
6236
|
+
" gap: 8px;",
|
|
6237
|
+
" padding: 14px 12px 10px;",
|
|
6238
|
+
" box-sizing: border-box;",
|
|
6239
|
+
" border: 1px solid var(--dsw-alias-border-l1);",
|
|
6240
|
+
" border-radius: 12px;",
|
|
6241
|
+
" background: var(--dsw-alias-bg-layer-1);",
|
|
6242
|
+
" color: var(--dsw-alias-label-primary);",
|
|
6243
|
+
" font: inherit;",
|
|
6244
|
+
" cursor: pointer;",
|
|
6245
|
+
" transition: border-color .12s ease;",
|
|
6246
|
+
"}",
|
|
6247
|
+
"",
|
|
6248
|
+
"body[data-dsh-claude-style] .dsh-claude-brand-card:hover {",
|
|
6249
|
+
" border-color: var(--dsw-alias-border-l2);",
|
|
6250
|
+
"}",
|
|
6251
|
+
"",
|
|
6252
|
+
"body[data-dsh-claude-style] .dsh-claude-brand-card:focus-visible {",
|
|
6253
|
+
" outline: 2px solid var(--dsw-alias-brand-primary, #d97757);",
|
|
6254
|
+
" outline-offset: 1px;",
|
|
6255
|
+
"}",
|
|
6256
|
+
"",
|
|
6257
|
+
"body[data-dsh-claude-style] .dsh-claude-brand-card[data-active] {",
|
|
6258
|
+
" border-color: var(--dsw-alias-brand-primary, #d97757);",
|
|
6259
|
+
"}",
|
|
6260
|
+
"",
|
|
6261
|
+
"body[data-dsh-claude-style] .dsh-claude-brand-card-logo {",
|
|
6262
|
+
" width: 32px;",
|
|
6263
|
+
" height: 32px;",
|
|
6264
|
+
" background-position: center;",
|
|
6265
|
+
" background-repeat: no-repeat;",
|
|
6266
|
+
" background-size: contain;",
|
|
6267
|
+
"}",
|
|
6268
|
+
"",
|
|
6269
|
+
"body[data-dsh-claude-style] .dsh-claude-brand-card-logo[data-brand=\"claude\"] {",
|
|
6270
|
+
" background-image: url(\"data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%20148.09%20148.18'%3E%3Cg%20transform%3D'translate(-75.96%2C-223.53)'%3E%3Cpath%20fill%3D'%23D97757'%20d%3D'm%20105.01%2C322.07%2029.14%2C-16.35%200.49%2C-1.42%20-0.49%2C-0.79%20h%20-1.42%20l%20-4.87%2C-0.3%20-16.65%2C-0.45%20-14.44%2C-0.6%20-13.99%2C-0.75%20-3.52%2C-0.75%20-3.3%2C-4.35%200.34%2C-2.17%202.96%2C-1.99%204.24%2C0.37%209.37%2C0.64%2014.06%2C0.97%2010.2%2C0.6%2015.11%2C1.57%20h%202.4%20l%200.34%2C-0.97%20-0.82%2C-0.6%20-0.64%2C-0.6%20-14.55%2C-9.86%20-15.75%2C-10.42%20-8.25%2C-6%20-4.46%2C-3.04%20-2.25%2C-2.85%20-0.97%2C-6.22%204.05%2C-4.46%205.44%2C0.37%201.39%2C0.37%205.51%2C4.24%2011.77%2C9.11%2015.37%2C11.32%202.25%2C1.87%200.9%2C-0.64%200.11%2C-0.45%20-1.01%2C-1.69%20-8.36%2C-15.11%20-8.92%2C-15.37%20-3.97%2C-6.37%20-1.05%2C-3.82%20c%20-0.37%2C-1.57%20-0.64%2C-2.89%20-0.64%2C-4.5%20l%204.61%2C-6.26%202.55%2C-0.82%206.15%2C0.82%202.59%2C2.25%203.82%2C8.74%206.19%2C13.76%209.6%2C18.71%202.81%2C5.55%201.5%2C5.14%200.56%2C1.57%20h%200.97%20v%20-0.9%20l%200.79%2C-10.54%201.46%2C-12.94%201.42%2C-16.65%200.49%2C-4.69%202.32%2C-5.62%204.61%2C-3.04%203.6%2C1.72%202.96%2C4.24%20-0.41%2C2.74%20-1.76%2C11.44%20-3.45%2C17.92%20-2.25%2C12%20h%201.31%20l%201.5%2C-1.5%206.07%2C-8.06%2010.2%2C-12.75%204.5%2C-5.06%205.25%2C-5.59%203.37%2C-2.66%20h%206.37%20l%204.69%2C6.97%20-2.1%2C7.2%20-6.56%2C8.32%20-5.44%2C7.05%20-7.8%2C10.5%20-4.87%2C8.4%200.45%2C0.67%201.16%2C-0.11%2017.62%2C-3.75%209.52%2C-1.72%2011.36%2C-1.95%205.14%2C2.4%200.56%2C2.44%20-2.02%2C4.99%20-12.15%2C3%20-14.25%2C2.85%20-21.22%2C5.02%20-0.26%2C0.19%200.3%2C0.37%209.56%2C0.9%204.09%2C0.22%20h%2010.01%20l%2018.64%2C1.39%204.87%2C3.22%202.92%2C3.94%20-0.49%2C3%20-7.5%2C3.82%20-10.12%2C-2.4%20-23.62%2C-5.62%20-8.1%2C-2.02%20h%20-1.12%20v%200.67%20l%206.75%2C6.6%2012.37%2C11.17%2015.49%2C14.4%200.79%2C3.56%20-1.99%2C2.81%20-2.1%2C-0.3%20-13.61%2C-10.24%20-5.25%2C-4.61%20-11.89%2C-10.01%20h%20-0.79%20v%201.05%20l%202.74%2C4.01%2014.47%2C21.75%200.75%2C6.67%20-1.05%2C2.17%20-3.75%2C1.31%20-4.12%2C-0.75%20-8.47%2C-11.89%20-8.74%2C-13.39%20-7.05%2C-12%20-0.86%2C0.49%20-4.16%2C44.81%20-1.95%2C2.29%20-4.5%2C1.72%20-3.75%2C-2.85%20-1.99%2C-4.61%201.99%2C-9.11%202.4%2C-11.89%201.95%2C-9.45%201.76%2C-11.74%201.05%2C-3.9%20-0.07%2C-0.26%20-0.86%2C0.11%20-8.85%2C12.15%20-13.46%2C18.19%20-10.65%2C11.4%20-2.55%2C1.01%20-4.42%2C-2.29%200.41%2C-4.09%202.47%2C-3.64%2014.74%2C-18.75%208.89%2C-11.62%205.74%2C-6.71%20-0.04%2C-0.97%20h%20-0.34%20l%20-39.15%2C25.42%20-6.97%2C0.9%20-3%2C-2.81%200.37%2C-4.61%201.42%2C-1.5%2011.77%2C-8.1%20-0.04%2C0.04%20z'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E\");",
|
|
6271
|
+
"}",
|
|
6272
|
+
"",
|
|
6273
|
+
"body[data-dsh-claude-style] .dsh-claude-brand-card-logo[data-brand=\"deepseek\"] {",
|
|
6274
|
+
" background-image: url(\"data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2023.16%2017.04'%3E%3Cpath%20fill%3D'%234D6BFE'%20d%3D'M22.9168%201.43018C22.6713%201.31018%2022.5658%201.53918%2022.4223%201.65519C22.3733%201.69269%2022.3318%201.74169%2022.2903%201.78669C21.9317%202.1697%2021.5127%202.42121%2020.9657%202.39121C20.1657%202.34621%2019.4827%202.59771%2018.8787%203.20973C18.7502%202.45521%2018.3236%202.0047%2017.6746%201.71569C17.3351%201.56568%2016.9916%201.41518%2016.7536%201.08867C16.5876%200.856163%2016.5421%200.597155%2016.4591%200.341647C16.4061%200.187643%2016.3536%200.0301382%2016.1761%200.00363739C15.9836%20-0.0263635%2015.9081%200.135141%2015.8326%200.270145C15.5306%200.822162%2015.4136%201.43018%2015.4251%202.0462C15.4516%203.43174%2016.0366%204.53527%2017.1991%205.3203C17.3311%205.4103%2017.3651%205.5003%2017.3236%205.63181C17.2441%205.90231%2017.1501%206.16482%2017.0671%206.43533C17.0141%206.60784%2016.9351%206.64584%2016.7501%206.57033C16.1121%206.30383%2015.5611%205.90931%2015.074%205.4328C14.2475%204.63328%2013.5%203.75075%2012.568%203.05973C12.349%202.89822%2012.13%202.74822%2011.9034%202.60522C10.9524%201.68169%2012.028%200.923165%2012.277%200.833162C12.5375%200.739159%2012.3675%200.41615%2011.5259%200.42015C10.6844%200.42365%209.91439%200.705658%208.93286%201.08117C8.78935%201.13767%208.63835%201.17867%208.48384%201.21267C7.59332%201.04367%206.66829%201.00617%205.70226%201.11517C3.88321%201.31768%202.43016%202.1777%201.36213%203.64575C0.0790928%205.4103%20-0.222916%207.41536%200.146595%209.50642C0.535106%2011.7105%201.66014%2013.535%203.38869%2014.9616C5.18125%2016.4406%207.24581%2017.1657%209.60138%2017.0266C11.0319%2016.9441%2012.6245%2016.7526%2014.421%2015.2321C14.874%2015.4576%2015.3496%2015.5476%2016.1381%2015.6151C16.7456%2015.6716%2017.3306%2015.5851%2017.7836%2015.4911C18.4931%2015.3411%2018.4441%2014.6841%2018.1876%2014.5636C16.1081%2013.595%2016.5646%2013.9891%2016.1496%2013.67C17.2061%2012.42%2018.8202%2010.1979%2019.3182%207.17235C19.3672%206.83834%2019.4297%206.36783%2019.4222%206.09732C19.4182%205.93231%2019.4562%205.86831%2019.6447%205.84931C20.1657%205.78931%2020.6712%205.64681%2021.1357%205.3913C22.4833%204.65528%2023.0268%203.44624%2023.1548%201.9972C23.1738%201.77569%2023.1508%201.54668%2022.9168%201.43018ZM11.1749%2014.4736C9.15936%2012.889%208.18184%2012.3675%207.77832%2012.39C7.40081%2012.4125%207.46881%2012.8445%207.55182%2013.126C7.63882%2013.404%207.75182%2013.5955%207.91033%2013.8396C8.01983%2014.0011%208.09533%2014.2411%207.80083%2014.4216C7.15181%2014.8231%206.02327%2014.2866%205.97027%2014.2601C4.65673%2013.4865%203.5587%2012.4655%202.78467%2011.069C2.03715%209.72493%201.60314%208.28289%201.53164%206.74384C1.51264%206.37233%201.62214%206.24082%201.99215%206.17332C2.47916%206.08332%202.98118%206.06432%203.46769%206.13582C5.52476%206.43633%207.27581%207.35586%208.74385%208.8129C9.58188%209.64243%2010.2159%2010.634%2010.8689%2011.6025C11.5634%2012.631%2012.3105%2013.611%2013.262%2014.4146C13.598%2014.6961%2013.866%2014.9101%2014.1225%2015.0681C13.349%2015.1546%2012.058%2015.1731%2011.1749%2014.4746L11.1749%2014.4736ZM12.141%208.25988C12.141%208.09488%2012.273%207.96338%2012.439%207.96338C12.4765%207.96338%2012.5105%207.97088%2012.541%207.98188C12.5825%207.99688%2012.6205%208.01938%2012.6505%208.05338C12.7035%208.10588%2012.7335%208.18088%2012.7335%208.25988C12.7335%208.42489%2012.6015%208.55639%2012.4355%208.55639C12.2695%208.55639%2012.141%208.42489%2012.141%208.25988ZM15.1415%209.79893C14.949%209.87793%2014.7565%209.94544%2014.5715%209.95294C14.2845%209.96794%2013.9715%209.85143%2013.8015%209.70893C13.5375%209.48742%2013.3485%209.36342%2013.2695%208.97691C13.2355%208.8119%2013.2545%208.55639%2013.2845%208.40989C13.3525%208.09438%2013.277%207.89187%2013.0545%207.70787C12.8735%207.55786%2012.643%207.51636%2012.39%207.51636C12.2955%207.51636%2012.209%207.47486%2012.1445%207.44136C12.039%207.38886%2011.9519%207.25735%2012.035%207.09585C12.0615%207.04335%2012.19%206.91584%2012.22%206.89334C12.5635%206.69784%2012.9595%206.76184%2013.326%206.90834C13.6655%207.04735%2013.9225%207.30236%2014.292%207.66287C14.6695%208.09838%2014.7375%208.21838%2014.9525%208.54539C15.1225%208.8009%2015.277%209.06341%2015.3831%209.36392C15.4471%209.55142%2015.3641%209.70493%2015.1415%209.79893Z'%2F%3E%3C%2Fsvg%3E\");",
|
|
6275
|
+
"}",
|
|
6276
|
+
"",
|
|
6277
|
+
"body[data-dsh-claude-style] .dsh-claude-brand-card-name {",
|
|
6278
|
+
" font-size: 13px;",
|
|
6279
|
+
" font-weight: 600;",
|
|
6280
|
+
" line-height: 1.5;",
|
|
6281
|
+
"}",
|
|
6282
|
+
"",
|
|
6133
6283
|
"body[data-dsh-claude-style] .dsh-claude-settings-row-title {",
|
|
6134
6284
|
" font-size: 13px;",
|
|
6135
6285
|
" font-weight: 600;",
|
|
@@ -7076,7 +7226,7 @@ window.__ModuleLoader__.load({
|
|
|
7076
7226
|
// ============================================================================
|
|
7077
7227
|
// 构建编号(由 scripts/build.mjs 按产物内容生成) (Build id)
|
|
7078
7228
|
// ============================================================================
|
|
7079
|
-
var BUILD_ID = '
|
|
7229
|
+
var BUILD_ID = '9b6e5ae9a898'
|
|
7080
7230
|
|
|
7081
7231
|
// ============================================================================
|
|
7082
7232
|
// Deepy 帧图内容戳(由 scripts/build.mjs 按帧图字节生成) (Deepy sheet stamps)
|
|
@@ -7377,6 +7527,95 @@ window.__ModuleLoader__.load({
|
|
|
7377
7527
|
accountAvatar = ''
|
|
7378
7528
|
}
|
|
7379
7529
|
|
|
7530
|
+
/** macOS: the clearance the traffic lights need, read off the host's own leading seat. */
|
|
7531
|
+
const MAC_TRAFFIC_LIGHTS = 88
|
|
7532
|
+
/** macOS: the strip height the host declares, used when the token is absent. */
|
|
7533
|
+
const MAC_BAND_HEIGHT = 48
|
|
7534
|
+
/** Windows: the three caption buttons at their standard size, used when the overlay cannot measure them. */
|
|
7535
|
+
const WIN_CAPTION_CONTROLS = 140
|
|
7536
|
+
/** Windows: the strip height the host declares, used when the token is absent. */
|
|
7537
|
+
const WIN_BAND_HEIGHT = 40
|
|
7538
|
+
|
|
7539
|
+
/**
|
|
7540
|
+
* The host's declared caption-strip height, or `fallback` when the host
|
|
7541
|
+
* declares none.
|
|
7542
|
+
*
|
|
7543
|
+
* `--dsh-frame-top-clearance` is the host's own name for the strip, and the
|
|
7544
|
+
* one token both desktop platforms set: 48px under
|
|
7545
|
+
* `html[data-platform=darwin]`, and `var(--dsh-windows-titlebar-height)`
|
|
7546
|
+
* under `html[data-windows-titlebar]`. It is read through the computed
|
|
7547
|
+
* style, so that alias chain resolves to a length.
|
|
7548
|
+
*
|
|
7549
|
+
* @param fallback - the height to answer with when the token is absent.
|
|
7550
|
+
* @returns the height in CSS pixels.
|
|
7551
|
+
*/
|
|
7552
|
+
function bandHeight(fallback) {
|
|
7553
|
+
const declared = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--dsh-frame-top-clearance'))
|
|
7554
|
+
return isFinite(declared) && declared > 0 ? Math.round(declared) : fallback
|
|
7555
|
+
}
|
|
7556
|
+
|
|
7557
|
+
/**
|
|
7558
|
+
* The desktop shell's native caption strip, resolved in one place.
|
|
7559
|
+
*
|
|
7560
|
+
* Both desktop platforms hand the top of the window to a native layer, and
|
|
7561
|
+
* every consumer of that strip asks the same three questions: whether it
|
|
7562
|
+
* exists, how tall it is, and which end the platform's window controls take.
|
|
7563
|
+
* The platforms answer differently, so the answers are resolved here once.
|
|
7564
|
+
*
|
|
7565
|
+
* - Marker. Windows marks `<html>` with `data-windows-titlebar`; macOS
|
|
7566
|
+
* marks it `data-platform="darwin"`. The shell's preload writes both.
|
|
7567
|
+
* - Controls. Windows draws its three caption buttons at the right end and
|
|
7568
|
+
* publishes their box through the Window Controls Overlay API; macOS
|
|
7569
|
+
* draws its traffic lights at the left, at (16, 18) — the shell's own
|
|
7570
|
+
* `trafficLightPosition` — and publishes no measurement. The host's own
|
|
7571
|
+
* leading seat starts at 88px, the clearance those lights need.
|
|
7572
|
+
* - Fullscreen. A fullscreen macOS window hides its traffic lights, and
|
|
7573
|
+
* the host zeroes `--dsh-frame-chrome-top` with them, so that platform
|
|
7574
|
+
* answers null. Windows keeps the answer it gave before this module
|
|
7575
|
+
* existed: its frame holds both the strip and its padding in fullscreen,
|
|
7576
|
+
* and the Window Controls Overlay API's own visibility is the authority
|
|
7577
|
+
* there.
|
|
7578
|
+
*
|
|
7579
|
+
* Windows' answers are the ones the caption-band code computed before this
|
|
7580
|
+
* module existed, the Window Controls Overlay API included, so that
|
|
7581
|
+
* platform's behaviour is unchanged.
|
|
7582
|
+
*
|
|
7583
|
+
* @returns {{ platform: 'win32' | 'darwin', height: number, controls: { side: 'left' | 'right', size: number } } | null}
|
|
7584
|
+
* the strip, or null when the page owns its whole surface.
|
|
7585
|
+
*/
|
|
7586
|
+
function desktopBand() {
|
|
7587
|
+
const root = document.documentElement
|
|
7588
|
+
if (root.hasAttribute('data-windows-titlebar')) {
|
|
7589
|
+
const overlay = navigator.windowControlsOverlay
|
|
7590
|
+
if (!overlay || overlay.visible !== true) return null
|
|
7591
|
+
const rect = typeof overlay.getTitlebarAreaRect === 'function' ? overlay.getTitlebarAreaRect() : null
|
|
7592
|
+
if (rect && rect.width > 0 && rect.height > 0) {
|
|
7593
|
+
return {
|
|
7594
|
+
platform: 'win32',
|
|
7595
|
+
height: Math.round(rect.height),
|
|
7596
|
+
controls: { side: 'right', size: Math.max(0, Math.round(window.innerWidth - rect.right)) },
|
|
7597
|
+
}
|
|
7598
|
+
}
|
|
7599
|
+
// The API is present and visible with no measurement yet: the declared
|
|
7600
|
+
// caption height, and Windows' three caption buttons at their standard
|
|
7601
|
+
// size.
|
|
7602
|
+
return {
|
|
7603
|
+
platform: 'win32',
|
|
7604
|
+
height: bandHeight(WIN_BAND_HEIGHT),
|
|
7605
|
+
controls: { side: 'right', size: WIN_CAPTION_CONTROLS },
|
|
7606
|
+
}
|
|
7607
|
+
}
|
|
7608
|
+
if (root.dataset.platform === 'darwin') {
|
|
7609
|
+
if (root.hasAttribute('data-fullscreen')) return null
|
|
7610
|
+
return {
|
|
7611
|
+
platform: 'darwin',
|
|
7612
|
+
height: bandHeight(MAC_BAND_HEIGHT),
|
|
7613
|
+
controls: { side: 'left', size: MAC_TRAFFIC_LIGHTS },
|
|
7614
|
+
}
|
|
7615
|
+
}
|
|
7616
|
+
return null
|
|
7617
|
+
}
|
|
7618
|
+
|
|
7380
7619
|
/**
|
|
7381
7620
|
* Skin preferences.
|
|
7382
7621
|
*
|
|
@@ -8974,9 +9213,8 @@ window.__ModuleLoader__.load({
|
|
|
8974
9213
|
const STATS_SKELETON_MS = 2000
|
|
8975
9214
|
/** Rows of each section the placeholder reserves (a session's usual count). */
|
|
8976
9215
|
const STATS_SKELETON_ROWS = 4
|
|
8977
|
-
/** The same, for the compact block:
|
|
8978
|
-
const
|
|
8979
|
-
const COMPACT_SKELETON_USAGE_ROWS = 1
|
|
9216
|
+
/** The same, for the compact block: four items in a single 2x2 grid. */
|
|
9217
|
+
const COMPACT_SKELETON_ITEMS = 4
|
|
8980
9218
|
|
|
8981
9219
|
/** The custom property the stylesheet reads to line the panel up with the meter. */
|
|
8982
9220
|
const CONTEXT_PANEL_LEFT = '--dsh-claude-context-panel-left'
|
|
@@ -9209,8 +9447,25 @@ window.__ModuleLoader__.load({
|
|
|
9209
9447
|
function sessionStatsSections(chat, compact) {
|
|
9210
9448
|
const sections = []
|
|
9211
9449
|
const stats = statsValue('sessionStats')
|
|
9450
|
+
if (compact) {
|
|
9451
|
+
const rows = []
|
|
9452
|
+
if (stats !== undefined && stats !== null) {
|
|
9453
|
+
const timeRows = statsTimeRows(stats, chat, true)
|
|
9454
|
+
for (let i = 0; i < timeRows.length; i++) rows.push(timeRows[i])
|
|
9455
|
+
}
|
|
9456
|
+
const usage = statsValue('tokenUsage')
|
|
9457
|
+
if (usage !== undefined && usage !== null) {
|
|
9458
|
+
const billed = usage.uncachedInputTokens + usage.cacheReadTokens + usage.cacheWriteTokens
|
|
9459
|
+
if (billed > 0 || usage.outputTokens > 0) {
|
|
9460
|
+
const hit = sessionStatsCacheHit(usage.cacheReadTokens, billed)
|
|
9461
|
+
if (hit !== null) rows.push({ label: chat('message.turnUsage.cacheHit'), value: `${hit}%` })
|
|
9462
|
+
}
|
|
9463
|
+
}
|
|
9464
|
+
if (rows.length > 0) sections.push({ title: '', rows })
|
|
9465
|
+
return sections
|
|
9466
|
+
}
|
|
9212
9467
|
if (stats !== undefined && stats !== null) {
|
|
9213
|
-
const rows = statsTimeRows(stats, chat,
|
|
9468
|
+
const rows = statsTimeRows(stats, chat, false)
|
|
9214
9469
|
if (rows.length > 0) sections.push({ title: chat('stats.dialog.title'), rows })
|
|
9215
9470
|
}
|
|
9216
9471
|
const usage = statsValue('tokenUsage')
|
|
@@ -9220,14 +9475,12 @@ window.__ModuleLoader__.load({
|
|
|
9220
9475
|
const rows = []
|
|
9221
9476
|
const hit = sessionStatsCacheHit(usage.cacheReadTokens, billed)
|
|
9222
9477
|
if (hit !== null) rows.push({ label: chat('message.turnUsage.cacheHit'), value: `${hit}%` })
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
rows.push({ label: chat('message.turnUsage.cacheWrite'), value: sessionStatsTokens(usage.cacheWriteTokens, chat) })
|
|
9228
|
-
}
|
|
9229
|
-
rows.push({ label: chat('message.turnUsage.output'), value: sessionStatsTokens(usage.outputTokens, chat) })
|
|
9478
|
+
rows.push({ label: chat('message.turnUsage.input'), value: sessionStatsTokens(usage.uncachedInputTokens, chat) })
|
|
9479
|
+
rows.push({ label: chat('message.turnUsage.cacheRead'), value: sessionStatsTokens(usage.cacheReadTokens, chat) })
|
|
9480
|
+
if (usage.cacheWriteTokens !== 0) {
|
|
9481
|
+
rows.push({ label: chat('message.turnUsage.cacheWrite'), value: sessionStatsTokens(usage.cacheWriteTokens, chat) })
|
|
9230
9482
|
}
|
|
9483
|
+
rows.push({ label: chat('message.turnUsage.output'), value: sessionStatsTokens(usage.outputTokens, chat) })
|
|
9231
9484
|
if (rows.length > 0) sections.push({ title: chat('stats.dialog.usageTitle'), rows })
|
|
9232
9485
|
}
|
|
9233
9486
|
}
|
|
@@ -9331,17 +9584,25 @@ window.__ModuleLoader__.load({
|
|
|
9331
9584
|
renderContextStats()
|
|
9332
9585
|
}, STATS_SKELETON_MS - held)
|
|
9333
9586
|
}
|
|
9334
|
-
const titles = [chat('stats.dialog.title'), chat('stats.dialog.usageTitle')]
|
|
9335
|
-
const counts = compact ? [COMPACT_SKELETON_ROWS, COMPACT_SKELETON_USAGE_ROWS] : [STATS_SKELETON_ROWS, STATS_SKELETON_ROWS]
|
|
9336
9587
|
let signature = compact ? 'skeleton-compact' : 'skeleton'
|
|
9337
9588
|
let html = ''
|
|
9338
|
-
|
|
9339
|
-
|
|
9340
|
-
|
|
9341
|
-
for (let r = 0; r < counts[i]; r++) {
|
|
9589
|
+
if (compact) {
|
|
9590
|
+
html += '<div class="dsh-claude-context-stats-grid">'
|
|
9591
|
+
for (let r = 0; r < COMPACT_SKELETON_ITEMS; r++) {
|
|
9342
9592
|
html += '<div class="dsh-claude-context-stats-item"><span class="dsh-claude-context-stats-skeleton-label"></span><span class="dsh-claude-context-stats-skeleton-value"></span></div>'
|
|
9343
9593
|
}
|
|
9344
9594
|
html += '</div>'
|
|
9595
|
+
} else {
|
|
9596
|
+
const titles = [chat('stats.dialog.title'), chat('stats.dialog.usageTitle')]
|
|
9597
|
+
const counts = [STATS_SKELETON_ROWS, STATS_SKELETON_ROWS]
|
|
9598
|
+
for (let i = 0; i < titles.length; i++) {
|
|
9599
|
+
signature += `\u0001${titles[i]}`
|
|
9600
|
+
html += `<div class="dsh-claude-context-stats-section">${statsEscape(titles[i])}</div><div class="dsh-claude-context-stats-grid">`
|
|
9601
|
+
for (let r = 0; r < counts[i]; r++) {
|
|
9602
|
+
html += '<div class="dsh-claude-context-stats-item"><span class="dsh-claude-context-stats-skeleton-label"></span><span class="dsh-claude-context-stats-skeleton-value"></span></div>'
|
|
9603
|
+
}
|
|
9604
|
+
html += '</div>'
|
|
9605
|
+
}
|
|
9345
9606
|
}
|
|
9346
9607
|
const block = ensureContextBlock(panel)
|
|
9347
9608
|
if (signature === blockSignature && block.childElementCount > 0) return
|
|
@@ -9373,11 +9634,14 @@ window.__ModuleLoader__.load({
|
|
|
9373
9634
|
}
|
|
9374
9635
|
stopSkeleton()
|
|
9375
9636
|
let html = ''
|
|
9376
|
-
let signature = ''
|
|
9637
|
+
let signature = compact ? 'compact' : ''
|
|
9377
9638
|
for (let sIndex = 0; sIndex < sections.length; sIndex++) {
|
|
9378
9639
|
const section = sections[sIndex]
|
|
9379
|
-
|
|
9380
|
-
|
|
9640
|
+
if (section.title) {
|
|
9641
|
+
signature += `\u0001${section.title}`
|
|
9642
|
+
html += `<div class="dsh-claude-context-stats-section">${statsEscape(section.title)}</div>`
|
|
9643
|
+
}
|
|
9644
|
+
html += '<div class="dsh-claude-context-stats-grid">'
|
|
9381
9645
|
for (let r = 0; r < section.rows.length; r++) {
|
|
9382
9646
|
const row = section.rows[r]
|
|
9383
9647
|
signature += `\u0001${row.label}\u0002${row.value}`
|
|
@@ -14763,14 +15027,8 @@ window.__ModuleLoader__.load({
|
|
|
14763
15027
|
*/
|
|
14764
15028
|
function installBanScreen(ctx, ui) {
|
|
14765
15029
|
let banRoot = null
|
|
14766
|
-
/** Whether the open overlay has lent its canvas colour to the caption band. */
|
|
15030
|
+
/** Whether the open overlay has lent its canvas colour to the Windows caption band. */
|
|
14767
15031
|
let captionFillHeld = false
|
|
14768
|
-
/**
|
|
14769
|
-
* The width the Desktop's window buttons occupy when the Window Controls
|
|
14770
|
-
* Overlay API is there but carries no measurement yet: Windows' three
|
|
14771
|
-
* caption buttons at their standard size. A fallback only.
|
|
14772
|
-
*/
|
|
14773
|
-
const CAPTION_CONTROLS_FALLBACK = 140
|
|
14774
15032
|
|
|
14775
15033
|
// A client hot reload drops a generation's disposals without running them,
|
|
14776
15034
|
// so an overlay left open across one keeps its node — and the caption fill
|
|
@@ -14794,54 +15052,17 @@ window.__ModuleLoader__.load({
|
|
|
14794
15052
|
}
|
|
14795
15053
|
|
|
14796
15054
|
/**
|
|
14797
|
-
*
|
|
14798
|
-
*
|
|
14799
|
-
* Windows titlebar mode (`html[data-windows-titlebar]`) hands the top
|
|
14800
|
-
* `--dsh-windows-titlebar-height` pixels to a NATIVE layer: the shell
|
|
14801
|
-
* paints it with the colour it measures off `--dsw-specific-sidebar-fill`
|
|
14802
|
-
* and draws the three window buttons at its right end, and no page
|
|
14803
|
-
* content can cover it. Two things follow for this overlay — the band
|
|
14804
|
-
* already shows a window cluster, so the page must not draw its own
|
|
14805
|
-
* (that is the duplicate the Desktop showed), and the lockup and Sign out
|
|
14806
|
-
* can ride the caption row only while the band carries the page's own
|
|
14807
|
-
* canvas colour (holdCaptionFill).
|
|
14808
|
-
*
|
|
14809
|
-
* The band's height and the width its buttons occupy come from the Window
|
|
14810
|
-
* Controls Overlay API, so they follow the platform's own metrics rather
|
|
14811
|
-
* than a constant; a window whose overlay is hidden (fullscreen) has no
|
|
14812
|
-
* band and keeps the shipped layout.
|
|
14813
|
-
*
|
|
14814
|
-
* @returns `{ height, controls }` in CSS pixels, or null.
|
|
14815
|
-
*/
|
|
14816
|
-
function captionMetrics() {
|
|
14817
|
-
if (!document.documentElement.hasAttribute('data-windows-titlebar')) return null
|
|
14818
|
-
const overlay = navigator.windowControlsOverlay
|
|
14819
|
-
if (!overlay || overlay.visible !== true) return null
|
|
14820
|
-
const rect = typeof overlay.getTitlebarAreaRect === 'function' ? overlay.getTitlebarAreaRect() : null
|
|
14821
|
-
if (rect && rect.width > 0 && rect.height > 0) {
|
|
14822
|
-
return {
|
|
14823
|
-
height: Math.round(rect.height),
|
|
14824
|
-
controls: Math.max(0, Math.round(window.innerWidth - rect.right)),
|
|
14825
|
-
}
|
|
14826
|
-
}
|
|
14827
|
-
// The API is there but has no measurement yet: the declared caption
|
|
14828
|
-
// height and Windows' three caption buttons at their standard size.
|
|
14829
|
-
const declared = parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--dsh-windows-titlebar-height'))
|
|
14830
|
-
return {
|
|
14831
|
-
height: isFinite(declared) && declared > 0 ? Math.round(declared) : 40,
|
|
14832
|
-
controls: CAPTION_CONTROLS_FALLBACK,
|
|
14833
|
-
}
|
|
14834
|
-
}
|
|
14835
|
-
|
|
14836
|
-
/**
|
|
14837
|
-
* Lend the page's canvas colour to the caption band while the overlay is
|
|
14838
|
-
* open.
|
|
15055
|
+
* Lend the page's canvas colour to the Windows caption band while the
|
|
15056
|
+
* overlay is open.
|
|
14839
15057
|
*
|
|
14840
|
-
* The Desktop measures `--dsw-specific-sidebar-fill` off a probe
|
|
14841
|
-
* `<body>` and repaints the band whenever `<body>`'s style
|
|
14842
|
-
* changes, so an inline value here reaches the band and
|
|
14843
|
-
* gives the theme's own colour back.
|
|
14844
|
-
*
|
|
15058
|
+
* The Windows Desktop measures `--dsw-specific-sidebar-fill` off a probe
|
|
15059
|
+
* inside `<body>` and repaints the band whenever `<body>`'s style
|
|
15060
|
+
* attribute changes, so an inline value here reaches the band and
|
|
15061
|
+
* `closeBanScreen` gives the theme's own colour back. macOS paints its
|
|
15062
|
+
* strip from its own metrics and reads no such token, which is why this
|
|
15063
|
+
* is only ever called for `win32` (openBanScreen). Nothing else is
|
|
15064
|
+
* visible while the page is up — it covers the sidebar whose fill this
|
|
15065
|
+
* token names.
|
|
14845
15066
|
*/
|
|
14846
15067
|
function holdCaptionFill() {
|
|
14847
15068
|
if (banRoot === null) return
|
|
@@ -15033,17 +15254,27 @@ window.__ModuleLoader__.load({
|
|
|
15033
15254
|
banRoot = root
|
|
15034
15255
|
document.body.appendChild(root)
|
|
15035
15256
|
|
|
15036
|
-
// On the Desktop the bar rides the native caption
|
|
15037
|
-
//
|
|
15038
|
-
//
|
|
15039
|
-
//
|
|
15040
|
-
//
|
|
15041
|
-
|
|
15042
|
-
|
|
15257
|
+
// On the Desktop the bar rides the native caption strip, whose shape
|
|
15258
|
+
// the shared desktopBand() resolves once for every consumer: Windows
|
|
15259
|
+
// marks `<html>` with `data-windows-titlebar` and draws its three
|
|
15260
|
+
// caption buttons at the right end, macOS marks it
|
|
15261
|
+
// `data-platform="darwin"` and draws its traffic lights at the left.
|
|
15262
|
+
// When a strip is reported the page's own window cluster goes (the
|
|
15263
|
+
// strip already draws one) and the lockup and Sign out are laid into
|
|
15264
|
+
// that row — on Windows only after the band has taken the page's canvas
|
|
15265
|
+
// colour, which is what makes them read as the row's own content. A
|
|
15266
|
+
// null band means the platform publishes no strip: Windows answers
|
|
15267
|
+
// through the Window Controls Overlay API, which reports itself hidden
|
|
15268
|
+
// while the window is fullscreen, and on macOS the shell hides the
|
|
15269
|
+
// traffic lights. All of it is decided here, once per open: the strip
|
|
15270
|
+
// cannot appear or vanish while the page is up.
|
|
15271
|
+
const band = desktopBand()
|
|
15272
|
+
if (band !== null) {
|
|
15043
15273
|
root.setAttribute('data-dsh-ban-titlebar', '')
|
|
15044
|
-
root.
|
|
15045
|
-
root.style.setProperty('--dsh-ban-caption-
|
|
15046
|
-
|
|
15274
|
+
root.setAttribute('data-dsh-ban-controls', band.controls.side)
|
|
15275
|
+
root.style.setProperty('--dsh-ban-caption-height', `${band.height}px`)
|
|
15276
|
+
root.style.setProperty('--dsh-ban-caption-controls', `${band.controls.size}px`)
|
|
15277
|
+
if (band.platform === 'win32') holdCaptionFill()
|
|
15047
15278
|
}
|
|
15048
15279
|
}
|
|
15049
15280
|
|
|
@@ -16851,6 +17082,14 @@ window.__ModuleLoader__.load({
|
|
|
16851
17082
|
* marker onto <body> so the stylesheet can switch, and skips the measured
|
|
16852
17083
|
* shift entirely there.
|
|
16853
17084
|
*
|
|
17085
|
+
* macOS keeps the measured path. Its shell hands the top of the window to
|
|
17086
|
+
* the traffic lights and pads no content around them: the host sets
|
|
17087
|
+
* `--dsh-frame-top-clearance: 48px` under `html[data-platform=darwin]` and
|
|
17088
|
+
* leaves `--dsh-frame-chrome-top` at 0, so the conversation header keeps its
|
|
17089
|
+
* own top inset and draws its first row inside that strip. A fixed strip
|
|
17090
|
+
* would land on the title and the header actions; the measured shift already
|
|
17091
|
+
* seats it on the row beneath the strip.
|
|
17092
|
+
*
|
|
16854
17093
|
* The strip itself is stamped `data-dsh-view-tabs`, and every strip rule in
|
|
16855
17094
|
* view-tabs.css keys on that attribute. Finding the strip is a query this pass
|
|
16856
17095
|
* runs once; as a stylesheet selector (`header:has(tabs) tabs`) it made the
|
|
@@ -19589,24 +19828,27 @@ window.__ModuleLoader__.load({
|
|
|
19589
19828
|
}
|
|
19590
19829
|
|
|
19591
19830
|
/**
|
|
19592
|
-
* The skin's settings page, mounted by
|
|
19831
|
+
* The skin's settings page, mounted by every seat this host declares.
|
|
19593
19832
|
*
|
|
19594
|
-
*
|
|
19595
|
-
*
|
|
19596
|
-
*
|
|
19597
|
-
*
|
|
19598
|
-
*
|
|
19599
|
-
*
|
|
19600
|
-
*
|
|
19833
|
+
* Two seats render it: the `plugins.bundle.config` entry on the plugin
|
|
19834
|
+
* page (0.1.7+, keyed by the package name) and the full-page
|
|
19835
|
+
* `settings.section` tab in the settings dialog. An older host declares
|
|
19836
|
+
* only the latter; a newer one gets both, and since both render the same
|
|
19837
|
+
* component against the same prefs store, two live instances stay in
|
|
19838
|
+
* step. Neither seat hands the component a store: it reads and writes the
|
|
19839
|
+
* skin preferences through src/core/prefs.js, which owns the host round
|
|
19840
|
+
* trip, and follows changes the same way the rest of the skin does.
|
|
19601
19841
|
*
|
|
19602
19842
|
* Copy comes from the model copy document's `settings` block, so the page
|
|
19603
19843
|
* follows the shell language like every other string the skin paints. The
|
|
19604
19844
|
* English literals here are the fallback for a failed fetch.
|
|
19605
19845
|
*
|
|
19606
|
-
*
|
|
19846
|
+
* The segmented controls reuse the shared `.dsh-claude-segments` /
|
|
19607
19847
|
* `.dsh-claude-segment` classes and sliding highlight — the same control the
|
|
19608
19848
|
* composer's permission picker uses — so the two read as one design instead
|
|
19609
|
-
* of two lookalikes.
|
|
19849
|
+
* of two lookalikes. The brand choice is the exception: brands are
|
|
19850
|
+
* presets, not sibling tiers of one setting, so they render as a grid of
|
|
19851
|
+
* large cards, each carrying the brand's own mark.
|
|
19610
19852
|
*/
|
|
19611
19853
|
/**
|
|
19612
19854
|
* The quick-provider popover (src/features/settings/quick-providers.js). The settings
|
|
@@ -19744,9 +19986,11 @@ window.__ModuleLoader__.load({
|
|
|
19744
19986
|
React.createElement('span', { className: 'dsh-claude-settings-switch-knob' }),
|
|
19745
19987
|
)
|
|
19746
19988
|
|
|
19747
|
-
|
|
19989
|
+
// A block row stacks its control under the text across the row's full
|
|
19990
|
+
// width; the inline form keeps text left and control right.
|
|
19991
|
+
const row = (key, title, description, control, block) => React.createElement(
|
|
19748
19992
|
'div',
|
|
19749
|
-
{ className: 'dsh-claude-settings-row', key },
|
|
19993
|
+
{ className: block ? 'dsh-claude-settings-row dsh-claude-settings-row-block' : 'dsh-claude-settings-row', key },
|
|
19750
19994
|
React.createElement(
|
|
19751
19995
|
'div',
|
|
19752
19996
|
{ className: 'dsh-claude-settings-row-text' },
|
|
@@ -19825,7 +20069,28 @@ window.__ModuleLoader__.load({
|
|
|
19825
20069
|
'brand',
|
|
19826
20070
|
settingsCopy('brandTitle', 'Brand mark'),
|
|
19827
20071
|
settingsCopy('brandDesc', 'The brand mark in the sidebar and on the home page. DeepSeek keeps the host\'s own DeepSeek mark in DeepSeek blue, turns the whole palette blue (a sky-tinted white in light, a blue-black in dark) and puts Deepy the pixel whale on the composer in place of the crab.'),
|
|
19828
|
-
|
|
20072
|
+
// One card per brand: the brand's own mark above its name, the
|
|
20073
|
+
// active card outlined in the brand accent. The stylesheet picks the
|
|
20074
|
+
// mark off the logo's data-brand, so a new brand is one option here
|
|
20075
|
+
// plus one rule in settings.css.
|
|
20076
|
+
React.createElement(
|
|
20077
|
+
'div',
|
|
20078
|
+
{ className: 'dsh-claude-brand-picker', role: 'group' },
|
|
20079
|
+
brandOptions.map(option => React.createElement(
|
|
20080
|
+
'button',
|
|
20081
|
+
{
|
|
20082
|
+
key: option.value,
|
|
20083
|
+
type: 'button',
|
|
20084
|
+
className: 'dsh-claude-brand-card',
|
|
20085
|
+
'data-active': option.value === prefs.brand ? '' : undefined,
|
|
20086
|
+
'aria-pressed': option.value === prefs.brand ? 'true' : 'false',
|
|
20087
|
+
onClick: () => { if (option.value !== prefs.brand) write({ brand: option.value }) },
|
|
20088
|
+
},
|
|
20089
|
+
React.createElement('span', { className: 'dsh-claude-brand-card-logo', 'data-brand': option.value }),
|
|
20090
|
+
React.createElement('span', { className: 'dsh-claude-brand-card-name' }, option.label),
|
|
20091
|
+
)),
|
|
20092
|
+
),
|
|
20093
|
+
true,
|
|
19829
20094
|
),
|
|
19830
20095
|
row(
|
|
19831
20096
|
'motion',
|
|
@@ -19986,26 +20251,22 @@ window.__ModuleLoader__.load({
|
|
|
19986
20251
|
},
|
|
19987
20252
|
ClaudeStyleBundleConfig,
|
|
19988
20253
|
)), 'dsh-claude-style: plugin page')
|
|
19989
|
-
// The full-page section
|
|
19990
|
-
//
|
|
19991
|
-
//
|
|
19992
|
-
//
|
|
19993
|
-
//
|
|
19994
|
-
|
|
19995
|
-
|
|
19996
|
-
|
|
19997
|
-
|
|
19998
|
-
|
|
19999
|
-
|
|
20000
|
-
|
|
20001
|
-
|
|
20002
|
-
|
|
20003
|
-
|
|
20004
|
-
|
|
20005
|
-
},
|
|
20006
|
-
ClaudeStyleSettingsSection,
|
|
20007
|
-
)
|
|
20008
|
-
}), 'dsh-claude-style: settings section')
|
|
20254
|
+
// The full-page section registers on every host that declares the
|
|
20255
|
+
// slot. On an older host it is the only seat; on 0.1.7+ the same page
|
|
20256
|
+
// also renders on the plugin page, and this tab keeps a route to it
|
|
20257
|
+
// inside the settings dialog. Two live instances share the prefs
|
|
20258
|
+
// store, so a change in one shows in the other.
|
|
20259
|
+
scope.effect(() => slots.inject(SETTINGS_SECTION_SLOT, () => slots.register(
|
|
20260
|
+
{
|
|
20261
|
+
name: SETTINGS_SECTION_SLOT,
|
|
20262
|
+
id: 'claude-style',
|
|
20263
|
+
order: 22,
|
|
20264
|
+
// A function, so the navigation entry localizes once the copy
|
|
20265
|
+
// document has arrived; the literal is the pre-fetch fallback.
|
|
20266
|
+
label() { return settingsCopy('title', 'Claude Style') },
|
|
20267
|
+
},
|
|
20268
|
+
ClaudeStyleSettingsSection,
|
|
20269
|
+
)), 'dsh-claude-style: settings section')
|
|
20009
20270
|
})
|
|
20010
20271
|
return () => {
|
|
20011
20272
|
if (ui && ui.settingsNav) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-claude-style",
|
|
3
3
|
"description": "Claude Code Desktop theme for DeepSeek Harness (dsh) web GUI — visual & interaction overhaul",
|
|
4
|
-
"version": "0.10.
|
|
4
|
+
"version": "0.10.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "host/index.js",
|
|
7
7
|
"icon": "lib/claude-mark.svg",
|
|
@@ -44,7 +44,11 @@
|
|
|
44
44
|
"fonts/JetBrainsMonoVariable.ttf",
|
|
45
45
|
"fonts/JetBrainsMonoItalicVariable.ttf",
|
|
46
46
|
"fonts/OFL.txt",
|
|
47
|
-
"fonts/AUTHORS.txt"
|
|
47
|
+
"fonts/AUTHORS.txt",
|
|
48
|
+
"fonts/InterVariable.woff2",
|
|
49
|
+
"fonts/OFL-Inter.txt",
|
|
50
|
+
"fonts/NotoSerifVariable.woff2",
|
|
51
|
+
"fonts/OFL-NotoSerif.txt"
|
|
48
52
|
],
|
|
49
53
|
"keywords": [
|
|
50
54
|
"dsh",
|