dsh-claude-style 0.3.1 → 0.4.0
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 +57 -0
- package/README.en.md +2 -9
- package/README.md +2 -15
- package/docs/STYLE.md +83 -32
- package/docs/architecture.md +7 -8
- package/lib/client.js +1152 -1502
- package/lib/index.js +41 -22
- package/lib/model-descriptions.json +271 -211
- package/package.json +1 -1
- package/lib/icons/providers/ClaudeApi.png +0 -0
- package/lib/icons/providers/README.md +0 -13
- package/lib/icons/providers/TeamoRouter-icon-dark.png +0 -0
- package/lib/icons/providers/a6-icon.png +0 -0
- package/lib/icons/providers/aicodemirror.svg +0 -19
- package/lib/icons/providers/aicoding.svg +0 -20
- package/lib/icons/providers/aihubmix-color.svg +0 -1
- package/lib/icons/providers/algocode.svg +0 -51
- package/lib/icons/providers/alibaba.svg +0 -1
- package/lib/icons/providers/amuxapi-icon.svg +0 -13
- package/lib/icons/providers/anthropic.svg +0 -1
- package/lib/icons/providers/apikeyfun.png +0 -0
- package/lib/icons/providers/apinebula_icon.png +0 -0
- package/lib/icons/providers/atlascloud_icon.png +0 -0
- package/lib/icons/providers/aws.svg +0 -1
- package/lib/icons/providers/azure.svg +0 -1
- package/lib/icons/providers/baidu.svg +0 -1
- package/lib/icons/providers/bailian.svg +0 -1
- package/lib/icons/providers/bytedance.svg +0 -1
- package/lib/icons/providers/byteplus.png +0 -0
- package/lib/icons/providers/catcoder.svg +0 -1
- package/lib/icons/providers/ccsub.svg +0 -4
- package/lib/icons/providers/chatglm.svg +0 -1
- package/lib/icons/providers/cherryin.png +0 -0
- package/lib/icons/providers/claude.svg +0 -1
- package/lib/icons/providers/claudecn.png +0 -0
- package/lib/icons/providers/claw.svg +0 -22
- package/lib/icons/providers/cloudflare.svg +0 -1
- package/lib/icons/providers/code0.png +0 -0
- package/lib/icons/providers/cohere.svg +0 -1
- package/lib/icons/providers/copilot.svg +0 -1
- package/lib/icons/providers/crazyrouter.svg +0 -1
- package/lib/icons/providers/cubence.svg +0 -9
- package/lib/icons/providers/deepseek.svg +0 -1
- package/lib/icons/providers/doubao.svg +0 -1
- package/lib/icons/providers/eflowcode.png +0 -0
- package/lib/icons/providers/etok.png +0 -0
- package/lib/icons/providers/fenno-icon.webp +0 -0
- package/lib/icons/providers/gemini.svg +0 -1
- package/lib/icons/providers/gemma.svg +0 -1
- package/lib/icons/providers/github.svg +0 -1
- package/lib/icons/providers/githubcopilot.svg +0 -1
- package/lib/icons/providers/google.svg +0 -1
- package/lib/icons/providers/googlecloud.svg +0 -1
- package/lib/icons/providers/grok.svg +0 -1
- package/lib/icons/providers/hermes.png +0 -0
- package/lib/icons/providers/huawei.svg +0 -1
- package/lib/icons/providers/huggingface.svg +0 -1
- package/lib/icons/providers/hunyuan.svg +0 -1
- package/lib/icons/providers/huoshan.png +0 -0
- package/lib/icons/providers/kimi.svg +0 -1
- package/lib/icons/providers/lioncc.svg +0 -6
- package/lib/icons/providers/longcat-color.svg +0 -1
- package/lib/icons/providers/mcp.svg +0 -1
- package/lib/icons/providers/meta.svg +0 -1
- package/lib/icons/providers/micu.svg +0 -23
- package/lib/icons/providers/midjourney.svg +0 -1
- package/lib/icons/providers/minimax.svg +0 -1
- package/lib/icons/providers/mistral.svg +0 -1
- package/lib/icons/providers/modelscope-color.svg +0 -1
- package/lib/icons/providers/nekocode-icon.png +0 -0
- package/lib/icons/providers/newapi.svg +0 -1
- package/lib/icons/providers/notion.svg +0 -1
- package/lib/icons/providers/novita.svg +0 -11
- package/lib/icons/providers/nvidia.svg +0 -1
- package/lib/icons/providers/ollama.svg +0 -1
- package/lib/icons/providers/openai.svg +0 -1
- package/lib/icons/providers/opencode-logo-light.svg +0 -1
- package/lib/icons/providers/openrouter.svg +0 -1
- package/lib/icons/providers/packycode.svg +0 -1
- package/lib/icons/providers/palm.svg +0 -1
- package/lib/icons/providers/pateway.jpg +0 -0
- package/lib/icons/providers/perplexity.svg +0 -1
- package/lib/icons/providers/pipellm.png +0 -0
- package/lib/icons/providers/ppio.svg +0 -1
- package/lib/icons/providers/qianwenai.svg +0 -1
- package/lib/icons/providers/qiniu.png +0 -0
- package/lib/icons/providers/qwen.svg +0 -1
- package/lib/icons/providers/qwencloud.svg +0 -1
- package/lib/icons/providers/rc.svg +0 -1
- package/lib/icons/providers/relaxcode.png +0 -0
- package/lib/icons/providers/runapi.jpg +0 -0
- package/lib/icons/providers/shengsuanyun.svg +0 -4
- package/lib/icons/providers/siliconflow.svg +0 -1
- package/lib/icons/providers/sssaicode.svg +0 -73
- package/lib/icons/providers/stability.svg +0 -1
- package/lib/icons/providers/stepfun.svg +0 -10
- package/lib/icons/providers/subrouter.svg +0 -30
- package/lib/icons/providers/sudocode-us.png +0 -0
- package/lib/icons/providers/sudocode.png +0 -0
- package/lib/icons/providers/tencent.svg +0 -1
- package/lib/icons/providers/ucloud.svg +0 -1
- package/lib/icons/providers/unity2.png +0 -0
- package/lib/icons/providers/vercel.svg +0 -1
- package/lib/icons/providers/wenxin.svg +0 -1
- package/lib/icons/providers/xai.svg +0 -1
- package/lib/icons/providers/xiaomimimo.svg +0 -1
- package/lib/icons/providers/xycai-icon.png +0 -0
- package/lib/icons/providers/yi.svg +0 -1
- package/lib/icons/providers/zeroone.svg +0 -1
- package/lib/icons/providers/zetaapi-icon.png +0 -0
- package/lib/icons/providers/zhipu.svg +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,63 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.4.0] - 2026-09-21
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **设置页新增「快捷供应商」多选弹层,一级弹层改按供应商分组**:勾选的供应商,其模型会直接列在模型选择器的一级弹层里;不同供应商之间一条横线,供应商名以 11px 小字**领在横线前面**(同一行,线被名字挤短——不是另加一条整行横线,也不是名字压在线上),官方来源不标名字、第一组前面也不画线。名字用 `--dsw-alias-label-caption`,比横线本身的 `--dsw-alias-border-l1` 深一档——那个色当文字读不出来。新碎片 `src/overrides/quick-providers.js` 负责那个多选弹层——它复用权限弹层的卡片与行样式,但因为是设置控件而非接管,所以只点击展开(悬停设置行不该弹出菜单)、勾选后不关闭。卡片挂到 `<body>` 而不是设置行里:对话框会裁剪并可能 transform 自己的子树,`position: fixed` 的卡片在里头会以对话框为参照系。
|
|
9
|
+
- **当前席位那行不再把供应商写在括号里**:供应商改由它自己的一条横线承载(与分组同一套语汇);当前席位不在已列出的供应商里时,会在列表末尾(分隔线**之上**,分隔线只负责把模型列表与推理等级/更多模型分开)补一条横线加它那一行。二级弹层的高度也从写死的 540px 上限改成只受视口约束,随内容自适应。
|
|
10
|
+
- **设置页新增「重做模型选择器」开关(默认开)**:关掉后不再接管输入框的模型席位与两级弹层,交回宿主自己的模型菜单——只影响弹层,输入区其余改动照旧。它与「对话框样式改动范围」是两个独立开关。
|
|
11
|
+
- **首页对话框的目录选择器与预设弹层改用皮肤自己的弹层样式**:这两个控件由宿主共享的菜单原语渲染,卡片 portal 到 `<body>` 且自身没有任何标记,CSS 无法把它与宿主其它菜单区分开。所以新增 `src/overrides/hero-menu.js`:hero 行的触发器(工作区 chip / 预设 seat,含无会话时由卡片自身当触发器的那种)报告 `aria-expanded="true"` 时,给 `<body>` 里那张卡片打上 `data-dsh-claude-hero-menu`;新增的 `components/hero-menu.css`(composer 门控)据此把它重绘成皮肤的弹层语言——12px 卡片、32px 行、6px 行圆角、hover 面、陶烬橙选中勾。宿主其它菜单(侧栏行菜单、设置页权限行、子菜单)保持原样。
|
|
12
|
+
- **`docs/STYLE.md` 新增「Popovers · 多选一弹层」规范**:把这类弹层的卡片 / 行 / 标题 / 分隔 / 页脚度量列成表,并记下宿主两族类名的哈希方向相反(原语是 `_<local>_<hash>_<n>`,client-ui 包是 `<hash>_<local>`,子串匹配要各取最长稳定片段),以及四处既有弹层尚未对齐的具体位置。
|
|
13
|
+
- **hero 弹层的位置改为从按钮旁边弹出**:宿主把卡片放在触发器**下方**,而那正是输入框所在的位置——弹层会盖住输入区和里面的控件。现在由 `src/overrides/hero-menu.js` 把它挪到触发器**旁边**:底边与触发器对齐、向上生长进 hero 的空白区,视口不够时翻到左侧,两边都按 12px 边距夹紧;定位用 `important` 内联写入盖过宿主自己的那一次写入,并在滚动/缩放时经 scheduler 的视口钩子重算。卡片是宿主挂载而非切 `data-open`,所以规范里的展开过渡在这里落成一次性的 0.15s 动画。
|
|
14
|
+
|
|
15
|
+
- **首页的目录/预设弹层现在也受「自动弹出弹层」管辖**:这两个是宿主自己的菜单,只会点击打开;现在 `hero-menu.js` 用委托的 `mouseover`/`mouseout` 驱动宿主那个点击处理器——`全部` 档下悬停触发器即展开、移开即收起(跨过触发器与卡片之间那 6px 间隙不会误关),点击打开的菜单则不受悬停影响。悬停只在「对话框重绘」对该页面生效时启用,与样式门控一致。
|
|
16
|
+
- **设置里的「快捷供应商」清单排除官方服务,已下线的供应商也能清掉**:官方服务**始终**列在一级弹层最前面,不在多选清单里——它出现在清单里只会让人以为它能被「取消」,读取时也会把存储里残留的官方 id 归一掉(宿主与浏览器半边各一次)。反过来,一个曾经勾选、后来从目录消失的供应商 id 会带着「已移除」的弱化标记留在清单里——它还是「勾选」状态,取消勾选即从存储清除,否则那种残留 id 会永远隐形地躺在存储里、既看不见也删不掉。
|
|
17
|
+
- **对话框获得焦点时收起对话区的弹层**:`focusin` 一旦落在对话卡片里,权限、模型(两级)、会话统计、账户抽屉、首页 hero 菜单与设置里的快捷供应商弹层全部关闭——一个弹层悬在刚点进来的输入区上方会很碍事,而焦点的语义正好是「用户开始在这里干活」。注册在调度器的 document 级监听器上,随其它监听器一起装卸。
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- **一级弹层的滚动区只剩模型列表,分隔线与「推理程度 / 更多模型」钉在滚动区外**:此前整个一级弹层共用一个滚动容器,模型很多时「推理程度」「更多模型」两行会跟着滚出视野——现在弹层拆成上下两段:模型列表在上段滚动,分隔线、推理程度、更多模型在下段**不进滚动区**,始终停在卡片底部。一级弹层的高度也改成随内容自适应(只受视口约束,与二级弹层同一上限),短列表不再撑出一张空高卡片。
|
|
21
|
+
- **「自动弹出弹层」从开关改成三档(关闭 / 仅账号区 / 全部,默认全部)**:原来只有开与关,也没说清范围;现在三档把它写明——「仅账号区」只让侧栏账户弹层悬停展开,「全部」再加上权限、模型、会话统计与首页的目录/预设。旧的布尔值在读取时归一到新档位(`true` → 全部,`false` → 关闭),浏览器半边与宿主半边各做一次归一,宿主写路径的白名单也接受新的字符串值。
|
|
22
|
+
- **四处弹层的度量统一到规范**:账户抽屉与会话统计此前是 8px 行圆角、2px / 4px 卡片间距、8px 内边距、260px 最小宽度、z-index 1000 / 100000,权限弹层是 220px 最小宽度——现在全部对齐「Popovers · 多选一弹层」:6px 内边距、6px 间距、`min-height: 32px` 的行、`2px 7px` 行内边距、6px 行圆角、248px 最小宽度、z-index 99999。顺带修掉权限弹层把行高写死成 `height: 32px` 而内容本就是两行的隐患(改 `min-height`),并给会话统计补上缺失的 `transform-origin`。
|
|
23
|
+
- **清掉一批开发期痕迹,行为无变化**:删除从未被调用的 `applyBrand`(它连同注释一直被打进 bundle)、`modelBrand` 一个未使用的参数、`model-brand.js` 开头讲文件来历的注释,以及架构文档里指向某次提交与某个已删除计划文档的引用;`docs/STYLE.md` 中与 `AGENTS.md` 重复的模型文案规则与选择器纪律改为指向后者,并修掉那里一处断了主语的句子、README 里过期的锁定标数量与 Star History 图。
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **开发时热重载会让账号区和模型席位重复渲染**:客户端的 HMR 在刷新时丢掉旧 fiber 的清理(不执行 dispose),于是前一代渲染的账户按钮/模型席位和它们的弹层还留在 DOM 里,新一代从零开始又插了一份——账户区因此出现过两次(且旧的那份带着过期的用户名)。权限弹层没这个问题,因为它是 DOM 幂等的:每次先清掉同名节点再造。修复方式是把账户区与模型席位也改成 DOM 幂等:更新前先清扫上一代的同名节点(`body > .dsh-claude-model-popover` 与 `.dsh-claude-account-*` 各自的清扫在各自的 update 里),旧闭包泄漏的监听器/观察器/定时器无法从插件侧释放,只在开发模式下有成本,属可接受的余量。
|
|
27
|
+
|
|
28
|
+
## [0.3.2] - 2026-09-21
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **会话统计弹层现在跟随「自动弹出弹层」设置**:账户、模型、权限三个弹层都检查了 `readPrefs().autoPopover`,只有会话统计那个漏了——`bindStatsHover` 无条件在 `mouseenter` 打开弹层,于是它无视开关、永远悬停即弹。现在与那三个对齐:关掉开关后悬停不再弹出,点击仍可打开宿主自己的统计对话框。
|
|
32
|
+
- **「更多模型」弹层再收紧**:列间距 6 → 4px、分组间距 6 → 4px、分组标题上边距 6 → 4px(上一轮已把行内边距 4 → 3px)。
|
|
33
|
+
- **锁定标不再回退到供应商,用不到的标一并删掉**:此前「没有规则认领的模型」会退回它所在 provider 的锁定标,于是 OpenCode 转售的 `LongCat-2.0` 戴上 OpenCode 自己的标——那不是缺一个标,而是给了一个错的标。现在没有规则命中就不画标(`modelBrand` 不再回退),`brands.providers` 随之清空,vendoring 的品牌集合只剩规则真正用到的那些:**43 → 25 个锁定标**,产物 **756 KB → 649 KB**(−107 KB)。
|
|
34
|
+
- **新增 `longcat` 品牌与 `mimo` → `xiaomimimo` 规则**:OpenCode 转售的 `MiMo V2.5 Pro` 此前解析不到(没有 `mimo` 规则,于是落到 provider),现在命中;LongCat 用 Lobe 的 `longcat` 图标。
|
|
35
|
+
- **OpenAI 的标在暖黑画布上不可见**:手工提供的 ChatGPT SVG 把颜色写在 `style="fill:#000000"` 里,而内联 style **优先于**呈现属性,所以 `fill="currentColor"` 的包装不生效——标是黑的,暖黑上等于没有。现在 vendoring 会清掉本地资产里带 fill 的内联 style,再补 `currentColor`。
|
|
36
|
+
- **「更多模型」弹层收紧、同供应商内按 id 升序**:行内边距 4px → 3px;每个 provider 的模型按 id 升序排(目录自己的顺序是 provider 返回的顺序,不可预期),排序在副本上做,不动宿主的快照。
|
|
37
|
+
- **锁定标的七处修正**:(1) **Meta 的锁定标向左漂移**——`compose_lockup` 的 viewBox 左右边界只取了字标簇,而图标画在字标左侧,于是它落到元素框外、压向前一列;现在边界取整件墨迹,只有大写带仍取自字标簇(viewBox 左边界 38.3 → 2.0)。(2) **混元标的一部分被染黑**——`recolour_illegible` 会把任何在象牙白上读不出的填充换成 `currentColor`,而混元图标里那块浅色高光并非主导色,因此被误伤;现在只换**按墨迹面积加权的主导色**(Kimi 的白 K 是主导 → 仍换 ✓,它的蓝点保留 ✓,混元的 `#ECECEE` 保留 ✓)。(3) **`hy-mt2-*` 三个混元模型解析不到品牌**——规则 `hy\d` 不匹配 `hy-mt2`,放宽为 `hy(\d|-?mt)`。(4) **新增 Gemma 品牌**(Lobe 有 `gemma` 图标):Gemma 是 Google 的开放模型线,此前落到 `google`,而 Google 没有锁定标、行里就是空的;现在有自己的 ✓。(5) **Gemini 标与字标之间空隙过大**——字标定位改用**图标墨迹**的右边缘;Lobe 的 24 单位盒子里留白很多(Gemini 星芒远窄于盒子),按盒子定位就多出一大截空隙。(6) **新增 Nano Banana 品牌**(Lobe 的 id 是 `nanobanana`,词覆写为 `Nano Banana` 才与目录名对得上)。(7) **Claude 行改用 Anthropic Serif 排其余文字**——那枚锁定标本身是衬线体,标签此前是无衬线,两截字形不同;`@font-face` 与宿主路由白名单本就存在,所以只加了一个字体 token 与一条 `[data-brand='claude']` 规则。
|
|
38
|
+
- **模型行改用厂商锁定标:图标与字标合成一件图形,随包的自建字标全部删掉**:起因是「引入自建字体」这条路——每接一个厂商的字标都要单独弄一枚资产、自己裁 viewBox 对齐大写带。Lobe 的 React 包有一个 `Combine` 变体(`<Qwen.Combine/>`),但**静态资产包里没有 `-combine` 文件**:它是运行时把「图标」和「文字变体」拼起来的,所以合成得自己做,而**规则不用自己发明**——每个图标 `es/<Icon>/style.js` 里的 `TEXT_MULTIPLE`(字标 ÷ 图标)与 `SPACE_MULTIPLE`(间距)就是 Lobe 自己发布的合成比例,`es/toc.js` 给品牌色与变体清单。产出 `src/assets/icons/combine/<厂商>.svg`:viewBox 高度归一化为「字标的大写带」(所以样式表一条 `height: 1cap` 管住全部 43 个),内部三组——亮色画布显彩色图标、暗色画布显单色图标(`currentColor`;Lobe 自己用品牌色染,但 `#000` 在暖黑上会消失)、字标两份共用。厂商自己的词也由 Lobe 的 `TITLE` 带出(`moonshot` 画的是 `MoonshotAI`、`zai` 是 `zai`,从品牌 id 推不出来)。渲染规则:名称里以该厂商词开头就替换掉那个词(连分隔符一起),名称里没有该词(Kimi 官方目录只叫 `K3`)就把锁定标领在开头;该行不再另起前置图标。
|
|
39
|
+
**顺带瘦身**:删掉 `assets/icons/lobe/`(41 个厂商标)、`assets/icons/wordmarks/`(3 个自建字标)、`fetch-lobe-icons.mjs`,以及 `PROVIDER_ICONS`(157 KB 的供应商图标 markup)与 `PROVIDER_ICON_URL_KEYS`——供应商行不再显示图标后,最大的一块正好变成死重量;`providerIconName()` 改为只吃 id 集合 `PROVIDER_ICON_KEYS`,元数据保留(品牌解析靠它)。产物 711 KB → 739 KB(锁定标本身 235 KB,净 +28 KB)。
|
|
40
|
+
- **Claude 行改画 Claude 自己的锁定标**:原先 `claude` 规则指向 `anthropic`,行里画的是「Anthropic」字标,而名称里那个词是「Claude」——字标必须和它替换的词对得上(Grok 行画 Grok 而不是 xAI,同一个道理)。`anthropic` 仍留作 `anthropic` 路由的兜底。
|
|
41
|
+
- **新增 `gemma` 与 `nano-?banana` 两条家族规则**:这两个品牌在 `brands.models` 里有锁定标,`families` 里却没有文案规则,于是模型行一路掉到档位规则上(Gemma 会显示成「轻量档…」这类通用话术)。现在两条各有官网口径的一行。
|
|
42
|
+
- **新增 Claude Fable 与 Mythos 两条家族规则**:Anthropic 的模型线现在是 Mythos / Fable / Opus / Sonnet / Haiku,而 `families` 里只有 opus / sonnet / haiku 三条,Fable 与 Mythos 会掉到兜底的「Anthropic Claude 模型。」。两条各用官网自己的定位句(Fable 用 anthropic.com/claude/fable 的 tagline,Mythos 用它的受众与访问限制)。
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
- **抽出 `model-brand.js`**:`model-picker.js` 已达 737/750 行,撞上仓库的体量停止线,所以先把「这一行/这个分组属于哪个厂商」整块(含共用的元素工厂 `modelEl` 与五个品牌函数)搬进新碎片,再落上面的字标功能。产物侧用行多重集比对证明这是纯搬移——旧 `lib/client.js` 8717 个非空行 vs 新 8729,差异只有新碎片的横幅与构建的碎片清单;`model-picker.js` 737 → 636 行。
|
|
46
|
+
- **厂商字标扫描改为预置数组,并补上分项计时探针**:`.debug/wordmark-cost.cjs` 量出每行标签构建里扫描词表约占 0.5µs(50 行一次渲染约 25ms),改为加载时构建成数组后整行成本从约 0.78µs 降到约 0.72µs。同一批量具还带出 `scripts/probe-timing.cjs`:在真实浏览器里分项计时——启动长任务与插件资源、模型目录就绪、选择器打开延迟、行构成、锁定标 markup 的 `innerHTML` 解析成本、JS 堆——把「哪一段慢」从推测变成测量。
|
|
47
|
+
- **模型简介全部按厂商官网口径重写**:19 条精确条目与 54 条家族规则的文案此前多为转述与推测,现逐条对着官网的发布页 / 模型文档页 / 价格页重写(DeepSeek、Anthropic、OpenAI、Google、Z.ai、Moonshot、阿里、阶跃、MiniMax、xAI、字节、百度、Mistral,以及 Meta、Inception、Cohere、微软、AWS、Perplexity、Motif、Apodex 等十余家),把可核对的事实写进文案——参数量与激活参数、上下文与输出上限、许可证、吞吐与单价。家族规则照旧不写最高级、不写版本相关数字:调研素材里带进来的「1M 上下文」这类数字已从家族文案剔除,否则会把同一家族的旧版一起误标。
|
|
48
|
+
- **文案改为「按线映射」,不再按版本钉死**:DeepSeek 的三条旧版精确条目(V4 Flash、V4 Flash Vision Exp、V4 Pro)与 V3.2 条目一并删除,改为按名字模式映射——所有 Flash 共用一句、所有 Pro 共用一句(官网小标题「性能比肩顶级闭源模型」)、其余共用一句(V4.1 发布标题「更强、更快、更普惠」)。理由是模型会迭代:给某个版本写的描述会被下一代继承,给「已退场版本」写的描述又会挂在当前版本上,而线级文案没有这个问题(已记入 `docs/architecture.md` D5)。
|
|
49
|
+
- **去掉我们自己加的档位前缀**:此前多条家族与档位文案以「旗舰档:」「主力档:」「轻量档:」「高能力档:」「中端档:」开头——那是我们的定位话术,不是模型自己的说法。现在要么用厂商自己的定位句,要么直接说它做什么。例:Claude Fable 线写官网 tagline「新一代智能,专为解决最艰深的知识工作和编程难题」,而不是「顶级档位:新一代智能,专为解决最艰深的知识工作和编程难题」。
|
|
50
|
+
- **描述不再重复模型名与产品线名**:行里已经写着模型名,文案再以「X 系列:」「X 档:」「模型名:」开头就是同一句话说两遍。共改 50 条——16 条精确条目 + 32 条家族规则 + 2 条档位规则。例:GLM 家族规则从「智谱的开源大模型系列:覆盖对话、编程与智能体,支持思考模式与函数调用。」改成「覆盖对话、编程与智能体,支持思考模式与函数调用。」;Kimi K3 从「全球首个开源 3T 级模型:2.8T 参数、1M 上下文、原生多模态。」改成官网模型页标题去掉模型名之后的那半句「面向编程与知识工作的 2.8T 开源模型。」;Mistral Large 3、文心 5.0、ERNIE 等条目的「…:」结构改为逗号并列,事实一个不丢。DeepSeek 的三条线级文案按指定保持不变(DeepSeek 官网没有 per-model 模型页,`/news/*` 的标题是动词句,形状对不上)。
|
|
51
|
+
- **只剩规格的条目补上用途**:删掉标签后有几条只剩参数与价格(`gpt-5.4` 一度只剩「105 万 token 上下文、原生电脑操作。」),读起来不知道它是干什么用的。这些条目按 Kimi 那种「面向…的…」形状,把官网模型卡的用途句并回句首,共 10 条:`gpt-5.4`、`gemini-3.8-flash`、`glm-5.3`、`glm-5.3-flash`、`glm-5.3-flashx`、`kimi-for-coding-highspeed`、`qwen3.8-max`、`step-5-preview`、`step-3.7-flash`、`gpt-oss`。官网 tagline 不如现有事实句的(Codex「The same powerful coding agent—now in ChatGPT」、Gemma、Nano Banana)没有替换。
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
- **几处已经过时或张冠李戴的模型说法**:(1) DeepSeek V4 Flash 与 V4 Flash Vision Exp 已下线、V4 Pro 已公告退场(旧模型名现由 V4.1 Flash 提供服务并按 Flash 价计费),这三条不再逐版本描述,改由线级映射给出文案;(2) Grok 4.5 的「最强」在 4.6 发布后已不成立,改为它自身的事实并注明有更新版本;(3) 文心 5.0 的「预训练成本极低」实为 ERNIE 5.1 的说法,换成官网确有的 2.4 万亿参数 / 每 token 激活约 3% / 128K 上下文;(4) `kimi-for-coding` 的官方名是 Kimi K2.7 Code,文案改按官方命名。
|
|
55
|
+
- **插件加载即崩(皮肤全崩)**:上一版把 `WORDMARK_SVGS` 从产物里删了,却没删 `model-brand.js` 里读它的那个**加载期 IIFE** → `ReferenceError: WORDMARK_SVGS is not defined` → 客户端半边整个加载失败。构建的语法门禁抓不到这类「引用一个已不存在的全局」——语法完全合法,跑起来才抛。补了 `.debug/bundle-load-check.cjs`:用桩跑一遍产物工厂,正反两次对照都验过(把引用注回去即 `FAIL factory runs`)。
|
|
56
|
+
- **锁定标占位但不显示**:源文件把 `fill="currentColor"` 与 `fill-rule="evenodd"` 放在**根 `<svg>` 上**、内部路径靠继承,而 vendoring 只取了内部内容 → 属性丢失、形状无填充(彩色层因为 `fill` 写在每条路径上反而正常,于是现象是「彩色图标在、字标不在」)。现在把根的绘制属性重新包一层 `<g>`,并去掉会变成 hover 提示的 `<title>`。
|
|
57
|
+
- **一级弹层「当前模型」那行的供应商、以及两级都显示模型描述**:三处相关调整。(1) 那行原先显示 `供应商id/模型id`,上一版按「外显名而非 id」改成了只显示模型名,把供应商整个丢了——现在格式定为 `模型 (供应商)`,两侧都是外显名(模型取目录里的 name,供应商取 `group.name`,目录没给名字时退回 id)。**带字标的模型同样带供应商**:字标只说明厂商,没说明这个席位由哪个 provider 提供,所以 `[KiMi]K3 (opencode)` 才是完整信息;供应商放在模型之后而不是之前,因为字标正站在标签开头。(2) 「更多模型」是每个 provider 的完整目录,描述行在那里只是噪声,改为只在第一级显示。(3) 一级那行补上描述——它和官方列表里的行一样是「读」的行,描述正是把模型区分开的东西。
|
|
58
|
+
- **冷启动后模型选择器要等几秒才有内容**:宿主的模型目录是每个 Host generation 一次 RPC(`remote.session.modelCatalog()`),而它**只在宿主自己菜单的 `show()` 里发起**——本皮肤把宿主的模型席位藏了起来,那个菜单永远不会打开,于是整趟往返都压在第一次打开选择器上(冷启动时是数秒的「正在加载模型…」)。现在插件在会话一解析出来就 `load()` 预热(`warmModelCatalog()`,每次安装只发一次、失败交给 store 的错误面),把这趟等待挪进用户本来就在等的启动过程;触发器的模型名标签读的也是同一份目录,所以它一起提前出来了。目录的 load 是共享在途且宿主侧缓存的,因此选择器自己那次 `load()` 变成空操作,而不是第二个请求。
|
|
59
|
+
- **Grok 行显示的是 xAI 的标识**:`brands.models` 里的 `{ "match": "grok", "brand": "xai" }` 把模型行指到了公司标识上——xAI 是公司、Grok 是模型线,所以 Grok 行该显示 Grok 自己的标记(provider 分组标题仍显示 xAI 的,因为 provider 只从 `providers` 解析,与模型行互不影响)。标识本来就在仓库里:`src/assets/icons/providers/grok.svg`(cc-switch 供应商集,路径数据与 Lobe 的 `grok.svg` 完全一致,只是带着 `<title>`/`style`/em 宽高),而选择器优先用 cc-switch 图标、缺失才回退 Lobe,所以这一处不必重新抓图,改映射即可。规则补了一条 note 说明这个分工。
|
|
60
|
+
- **一级弹层里「当前模型」那行显示的是 `供应商id/模型id`**:当选中模型不在官方服务上时,一级弹层会在官方列表下面补一行显示当前席位——但它直接把 `group.id + '/' + model.id` 当标签写了出来,于是那一行是 `openrouter/anthropic-claude-4.5` 这种 id 串,而它上下每一行都是模型的外显名。现在这行与其他行同一套标签逻辑(`buildModelName`,含厂商字标),只在目录没给名字时才退回 id;同时补上了行的 `data-brand`,所以它和列表里对应的那一行穿同一件厂商标记与字体。变更签名(判断是否需要重绘)仍然只比对 id——那是每轮 pass 都要算的热路径,而目录的名字在一次会话内是稳定的。
|
|
61
|
+
|
|
5
62
|
## [0.3.1] - 2026-09-21
|
|
6
63
|
|
|
7
64
|
### Added
|
package/README.en.md
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
**A Claude Code Desktop theme for the DeepSeek Harness (DSH) web client — the warm ivory editorial canvas, the clay ember accent, and the Claude Code interaction model rebuilt on DSH.**
|
|
5
5
|
|
|
6
|
-
> **Coffee and Claude time?**
|
|
7
|
-
|
|
8
6
|
[](README.en.md) [](README.md)
|
|
9
7
|
|
|
10
8
|
[](https://github.com/Nwflower/dsh-claude-style)
|
|
@@ -57,9 +55,9 @@ Only one theme should be active at a time. After installing, **restart `dsh web`
|
|
|
57
55
|
|
|
58
56
|
1. **Theme** — applies the whole canvas automatically after install; no configuration needed. Light and dark follow the system color scheme.
|
|
59
57
|
2. **Permission segments** — the composer gets a Read | Edit | Auto segmented control replacing the shipped access-mode menu: read-only, workspace write, and full access (Auto is switched through the shipped risk-confirmation dialog).
|
|
60
|
-
3. **Model picker** — the composer's model seat becomes a two-level Claude-style menu: the first level
|
|
58
|
+
3. **Model picker** (can be switched off in Settings to hand the menu back to the host) — the composer's model seat becomes a two-level Claude-style menu: the first level **always leads with the official service**, followed by the models of the **quick providers** picked in Settings — one rule between providers, the provider's name leading it in small text on the same row so the rule is shortened by it (the official source is not named and is never listed in Settings; a provider removed from the catalog stays in the list marked "Removed" and can be unchecked to clear it) — then a divider, the reasoning-effort row and "More models"; both levels are sized by their content and capped by the viewport, the first level scrolls its model list only while the divider and the two drill rows stay pinned below the scroll area, and the second opens beside it. Model descriptions appear on the first level only; a current seat that none of the listed providers carries gets a row of its own at the end of the list, above the divider, under a provider rule of its own; the "More models" level is every provider's full catalog and lists names alone. Every model row carries its **vendor's lockup** — the mark and the vendor's wordmark composed into one piece of art, drawn in place of the vendor's name inside the label (`[DeepSeek whale + wordmark] V4.1-Flash`); a name that never spells the vendor (Kimi's own catalog calls the model `K3`) leads with the lockup instead. The "More models" group headers carry the provider's name alone, no mark. The artwork is [Lobe Icons](https://lobehub.com/icons) (MIT), composed before the build into one `<svg>` per vendor (no React dependency). The mark's size and the gap after it are **global constants**, not Lobe's per-icon `TEXT_MULTIPLE`/`SPACE_MULTIPLE` — those ratios are relative to each wordmark's own box, which made every vendor's mark a different size and every gap a different width; the brand colours and variant list come from `es/toc.js`. The colour artwork draws on the ivory canvas, with any fill that cannot be read there swapped to `currentColor` (Kimi's white K would vanish, its blue dot stays); the warm black canvas gets the mono layer in the theme's text colour. A few vendors override the lockup in `brands.lockups`: the two halves may come from different icons (Hunyuan's mark with Tencent's wordmark), the word it stands in for may be spelled differently (`Step` for `step-*`, also `MiMo` and `GLM`), and a wordmark may be cropped (GLM-V drops its `-V`, ChatGPT keeps only `GPT`); hand-provided artwork lives in `src/assets/icons/`, beside the generated `combine/` directory. A wordmark has to match the word it stands in for: Claude rows draw Claude's and Grok rows draw Grok's, not their parent companies' — and Claude's remaining text is set in Anthropic Serif, because that lockup is serif lettering. Hidden text keeps the full vendor name in the accessibility tree, so a screen reader still hears "Kimi K3" rather than "K3".
|
|
61
59
|
4. **Brand switch** — Settings (`Ctrl+,`) → **Claude Style**: the sidebar brand flips between the Claude starburst + the official Claude wordmark and Anthropic (`A\` + ANTHROPIC wordmark); the hero mark follows the choice with the clay fill. The choice persists in the browser; `claude` is the default.
|
|
62
|
-
5. **Account drawer** — the sidebar footer button opens a hover popover with quick access to Settings (`Ctrl+,`) and plugin management; the username row at its top is an easter egg: it opens Claude's own "Your account is on hold" page (a purely local reproduction that touches no real state — click any control on it, or press `Esc`, to leave; it deliberately stays put when the window loses focus, so you can switch away and read it). That page's language is its own setting (**Account-hold easter egg language**, Chinese/English, English by default).
|
|
60
|
+
5. **Account drawer** — the sidebar footer button opens a hover popover (the **Open popovers on hover** setting picks Off / Account only / All) with quick access to Settings (`Ctrl+,`) and plugin management; the username row at its top is an easter egg: it opens Claude's own "Your account is on hold" page (a purely local reproduction that touches no real state — click any control on it, or press `Esc`, to leave; it deliberately stays put when the window loses focus, so you can switch away and read it). That page's language is its own setting (**Account-hold easter egg language**, Chinese/English, English by default).
|
|
63
61
|
6. **Status polish** — thinking turns pick one of Claude Code's 185 spinner verbs per turn; the workspace loading state uses a Fluent-style circular indicator.
|
|
64
62
|
|
|
65
63
|
## Disable & Uninstall
|
|
@@ -86,12 +84,7 @@ Then restart `dsh web`; remove hand-added rows for this theme from `cordis.patch
|
|
|
86
84
|
| [Design Tokens](docs/STYLE.md) | Palette, typography, shapes, plus the bundle source layout and host-selector discipline |
|
|
87
85
|
| [Changelog](CHANGELOG.md) | Version history |
|
|
88
86
|
| [Contributing](CONTRIBUTING.md) | How to build from `src/`, commit rules, and the screenshot/regression tooling |
|
|
89
|
-
| [AGENTS.md](AGENTS.md) | Development guide for AI assistants: build commands, fragment rules, host-selector discipline, and the release flow (Chinese) |
|
|
90
87
|
|
|
91
88
|
## Related Links
|
|
92
89
|
|
|
93
90
|
> Running several themes side by side? Recommended: [dsh-skin-manager](https://github.com/xiaoyangcheng84-svg/dsh-skin-manager) — switch all installed themes from its Settings page.
|
|
94
|
-
|
|
95
|
-
## Star History
|
|
96
|
-
|
|
97
|
-
[](https://www.star-history.com/?type=date&repos=Nwflower%2Fdsh-claude-style)
|
package/README.md
CHANGED
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
<div align="center">
|
|
6
6
|
|
|
7
|
-
> **Coffee and Claude time?**
|
|
8
|
-
|
|
9
7
|
[](README.en.md) [](README.md)
|
|
10
8
|
|
|
11
9
|
[](https://github.com/Nwflower/dsh-claude-style)
|
|
@@ -58,9 +56,9 @@ dsh plugin --profile web add Nwflower/dsh-claude-style # GitHub 源
|
|
|
58
56
|
|
|
59
57
|
1. **主题** —— 安装即全局生效,无需配置;亮暗跟随系统颜色模式。
|
|
60
58
|
2. **权限分段** —— 输入框以 Read | Edit | Auto 三段式控制器替换原生的访问模式菜单:只读、工作区写入与完全权限(Auto 经宿主的安全确认弹窗切换)。
|
|
61
|
-
3.
|
|
59
|
+
3. **模型选择器**(可在设置里关闭,交回系统自己的模型菜单)—— 输入框的模型席位换成 Claude 风格的两级弹层:一级**始终以官方服务打头**,后面跟着设置里勾选的**快捷供应商**的模型——不同供应商之间一条横线,供应商名以小字领在横线前面(同一行、把线挤短;官方来源不标名,也不在设置清单里;从目录消失的供应商带「已移除」标记留在清单里,取消勾选即可清除)——再加分隔线、推理等级与「更多模型」;两级弹层高度都随内容自适应(只受视口约束),一级只滚动模型列表,分隔线与两个操作行**钉在滚动区外**始终可见,二级在右侧展开。模型描述只出现在第一级;当前席位不在上面列出的供应商里时,会在列表末尾(分隔线之上)补一行,同样带一条供应商横线;二级「更多模型」是各 provider 的完整目录,只列名称。每个模型行显示**所属厂商的锁定标**——图标与厂商字标合成的一件图形,直接替换名称里的厂商名(`[DeepSeek 鲸鱼+字标] V4.1-Flash`);名称里没有厂商词的(Kimi 官方目录只叫 `K3`)则锁定标领在开头。「更多模型」的分组标题只显示 provider 名称,不带图标。图形取自 [Lobe Icons](https://lobehub.com/icons)(MIT),在构建前的 vendoring 阶段按厂商各合成一个 `<svg>`,不含 React 依赖。图标高度与间距是**全局常数**——不逐家采用 Lobe 的 `TEXT_MULTIPLE`/`SPACE_MULTIPLE`,那套比例是相对各家字标盒子的,会让图标大小与间距逐家漂移;品牌色与变体清单取自 `es/toc.js`。亮色画布用彩色原图,其中在象牙白上读不出来的填充换成 `currentColor`(Kimi 的白 K 会消失、而它的蓝点保留);暖黑画布换成单色、跟随主题文字色。少数厂商在 `brands.lockups` 里覆写:图标与字标可来自不同图标(混元的标 + Tencent 的字标)、匹配词可指定(`step-*` 用 `Step`,另有 `MiMo`、`GLM`)、字标可裁掉多余部分(GLM-V 截掉 `-V`、ChatGPT 只留 `GPT`);手工提供的资产放 `src/assets/icons/`(与生成的 `combine/` 同级)。字标要和它替换的词对得上:Claude 行画 Claude 的、Grok 行画 Grok 的,而不是各自母公司的;Claude 行的其余文字用 Anthropic Serif 排(那枚锁定标本身就是衬线体)。名称里另有视觉隐藏的厂商名,屏读听到的仍是「Kimi K3」而不是「K3」。
|
|
62
60
|
4. **品牌切换** —— 设置(`Ctrl+,`)→ **Claude Style**:侧栏品牌在 Claude(官方星芒 + Claude 字标)与 Anthropic(`A\` + ANTHROPIC 字标)之间切换,新会话页标识随所选品牌保持陶烬橙星芒;选择保存在浏览器本地,默认 Claude。
|
|
63
|
-
5. **账户抽屉** ——
|
|
61
|
+
5. **账户抽屉** —— 侧栏底栏的账户按钮悬停展开弹层(设置里「自动弹出弹层」可选关闭 / 仅账号区 / 全部),一键打开设置(`Ctrl+,`)与管理插件;弹层顶部那条用户名横条是个彩蛋:点开会看到 Claude 官方的「账户已暂停」页(纯本地复刻,不碰任何真实状态,点页面上任意按钮或按 `Esc` 退出;切走窗口**不会**关,方便你切出去照着它看)。这页的语言在设置里单独选(**封号彩蛋语言**,中文/英文,默认英文)。
|
|
64
62
|
6. **状态细节** —— 思考状态每轮从 Claude Code 的 185 个思考动词随机抽取一个稳定展示;工作区运行中状态使用 Fluent 风格的圆形加载动画。
|
|
65
63
|
|
|
66
64
|
## 停用与卸载
|
|
@@ -87,18 +85,7 @@ dsh plugin --profile web remove dsh-claude-style # 卸载
|
|
|
87
85
|
| [设计令牌](docs/STYLE.md) | 调色板、字体、形状,源码结构与宿主选择器纪律(英文) |
|
|
88
86
|
| [更新日志](CHANGELOG.md) | 版本历史 |
|
|
89
87
|
| [贡献指南](CONTRIBUTING.md) | 如何从 `src/` 构建、提交规范与截图/回归工具(英文) |
|
|
90
|
-
| [AGENTS.md](AGENTS.md) | AI 助手的开发指南:构建命令、碎片规则、宿主选择器纪律与发布流程 |
|
|
91
88
|
|
|
92
89
|
## 友链
|
|
93
90
|
|
|
94
91
|
> 同时启用多个主题?推荐 [dsh-skin-manager](https://github.com/xiaoyangcheng84-svg/dsh-skin-manager),在其设置页一键切换所有已安装主题。
|
|
95
|
-
|
|
96
|
-
## Star History
|
|
97
|
-
|
|
98
|
-
<a href="https://www.star-history.com/?type=date&repos=Nwflower%2Fdsh-claude-style">
|
|
99
|
-
<picture>
|
|
100
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=Nwflower/dsh-claude-style&type=date&theme=dark&legend=top-left" />
|
|
101
|
-
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=Nwflower/dsh-claude-style&type=date&legend=top-left" />
|
|
102
|
-
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=Nwflower/dsh-claude-style&type=date&legend=top-left" />
|
|
103
|
-
</picture>
|
|
104
|
-
</a>
|
package/docs/STYLE.md
CHANGED
|
@@ -94,6 +94,74 @@ empty wash above and below the text. The skin sets `line-height: 1.2` on inline
|
|
|
94
94
|
code (27px → 22px, with the 1px padding as the visible inset); lower values
|
|
95
95
|
start clipping descenders. The fill, hairline, radius and size are unchanged.
|
|
96
96
|
|
|
97
|
+
## Popovers · 多选一弹层
|
|
98
|
+
|
|
99
|
+
Every single-choice popover in the skin — the permission menu, the model picker,
|
|
100
|
+
the account drawer, the session-stats card, and the host's own menu primitive
|
|
101
|
+
under the hero row's workspace and preset pickers — is meant to start from one
|
|
102
|
+
recipe. New popovers take it rather than inventing a card.
|
|
103
|
+
|
|
104
|
+
**Card**
|
|
105
|
+
|
|
106
|
+
| Property | Value |
|
|
107
|
+
|---|---|
|
|
108
|
+
| background | `var(--dsw-alias-bg-overlay)`; dark `#1e1e1d` |
|
|
109
|
+
| border | `1px solid var(--dsw-alias-border-l1)`; dark `#2e2c29` |
|
|
110
|
+
| radius | 12px |
|
|
111
|
+
| 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)` |
|
|
112
|
+
| padding | 6px |
|
|
113
|
+
| layout | flex column, `gap: 6px` |
|
|
114
|
+
| z-index | 99999, above the host's own menus (1100) |
|
|
115
|
+
| open | `opacity 0 → 1`, `translateY(4px) scale(.98) → none`, `.15s ease`, origin on the anchor's side |
|
|
116
|
+
|
|
117
|
+
**Row**
|
|
118
|
+
|
|
119
|
+
| Property | Value |
|
|
120
|
+
|---|---|
|
|
121
|
+
| min-height | 32px — a floor, not a cap: a two-line row grows |
|
|
122
|
+
| padding | `2px 7px` |
|
|
123
|
+
| radius | 6px |
|
|
124
|
+
| text | 13px / 20px, `var(--dsw-alias-label-primary)` |
|
|
125
|
+
| hover | `var(--dsh-claude-hover-bg, rgba(0, 0, 0, .08))` |
|
|
126
|
+
| icon | 16px, `var(--dsw-alias-label-secondary)` |
|
|
127
|
+
| two-line row | name 13px / 16px at 500; description 11px / 14px in `label-tertiary` |
|
|
128
|
+
| current row | trailing `IconCheckOutline16` in `var(--dsw-alias-brand-primary)` — the accent is what marks the choice |
|
|
129
|
+
| disabled | `opacity: .4`, `cursor: not-allowed` |
|
|
130
|
+
|
|
131
|
+
**Heading, separator, footer**
|
|
132
|
+
|
|
133
|
+
- heading row: 11px / 16px at 600, `letter-spacing: .04em`, uppercase, `label-tertiary`, `padding: 6px 7px 2px`
|
|
134
|
+
- separator: 1px `var(--dsw-alias-border-l1)`, `margin: 2px 4px`
|
|
135
|
+
- pinned footer: `margin-top` / `padding-top` 4px, `1px solid var(--dsw-alias-border-l1)` above
|
|
136
|
+
|
|
137
|
+
**Host surfaces**
|
|
138
|
+
|
|
139
|
+
The host's dropdown menus are one shared primitive (primitives' `Menu`), and its
|
|
140
|
+
two class-name families hash in opposite directions: the primitive ships inside
|
|
141
|
+
the web shell as `_<local>_<hash>_<n>` (`_itemWrap_1nxmc_92`,
|
|
142
|
+
`_itemLabel_1nxmc_174`), while the client-ui packages hash as `<hash>_<local>`
|
|
143
|
+
(`daogkW_itemName`, `p_FcLG_cardWorkspaceTrigger`). A substring matcher therefore
|
|
144
|
+
takes the longest stable piece of whichever family it targets — `_itemWrap_`,
|
|
145
|
+
`_itemLabel_`, `_viewport_` on one side, `_itemName`, `_itemDesc` on the other —
|
|
146
|
+
never the bare local name.
|
|
147
|
+
|
|
148
|
+
The hero row's two pickers are that primitive, portaled to `<body>` with no
|
|
149
|
+
marker of their own. `src/overrides/hero-menu.js` stamps the open card with
|
|
150
|
+
`data-dsh-claude-hero-menu` and `components/hero-menu.css` restyles it; the
|
|
151
|
+
host's other menus (sidebar row menus, the settings permission row, submenus)
|
|
152
|
+
keep the host's own design on purpose. What that replaces: a 20px radius card
|
|
153
|
+
with 4px padding, 40px rows at 10px radius, and 14px text.
|
|
154
|
+
|
|
155
|
+
**All five are aligned**: the account drawer and the stats card were the outliers
|
|
156
|
+
(8px row radius, 2px and 4px card gap, 8px padding, 220 / 260px min-width,
|
|
157
|
+
z-index 1000 and 100000) and now follow the table above. The hero row's pickers are the host's own menu primitive, which differs in
|
|
158
|
+
two ways that CSS cannot change: it mounts instead of toggling a `data-open`
|
|
159
|
+
attribute, so it takes the same fade/scale as a one-shot `0.15s` animation; and
|
|
160
|
+
the host places it *below* its trigger, which is where the composer sits — so
|
|
161
|
+
`src/overrides/hero-menu.js` re-places it beside the trigger (bottom-aligned,
|
|
162
|
+
growing upward into the empty hero space, flipping left when the viewport is
|
|
163
|
+
tight) with an `important` inline write that outranks the host's own.
|
|
164
|
+
|
|
97
165
|
## Implementation notes
|
|
98
166
|
|
|
99
167
|
- Every rule is scoped under `body[data-dsh-claude-style]`.
|
|
@@ -109,8 +177,8 @@ assembles the bundle:
|
|
|
109
177
|
|---|---|
|
|
110
178
|
| `src/constants.js` | constants, spinner verbs, shared token values (evaluated at build time to fill `%%TOKEN%%` placeholders) |
|
|
111
179
|
| `src/assets/brand/*.svg` | brand marks, inlined as CSS `url()` data URIs at build time (the loader exposes no asset URLs) |
|
|
112
|
-
| `src/assets/icons/
|
|
113
|
-
| `src/assets/icons
|
|
180
|
+
| `src/assets/icons/combine/*.svg` | vendor lockups (Lobe Icons mark + wordmark composed into one SVG, MIT), inlined as JS markup tables at build time; bound to models by `model-descriptions.json` → `brands` |
|
|
181
|
+
| `src/assets/icons/*.svg` | hand-provided lockup artwork (e.g. ChatGPT), which the vendoring step prefers over anything fetched; `brands.lockups` may also point a brand's two halves at different Lobe icons or crop a wordmark |
|
|
114
182
|
| `src/styles/tokens.css` | design tokens (dark base + ivory light) |
|
|
115
183
|
| `src/styles/typography.css` | serif display / sans UI / mono code, editorial markdown |
|
|
116
184
|
| `src/styles/chrome.css` | canvas, hairlines, clay accent, chrome details |
|
|
@@ -122,6 +190,7 @@ assembles the bundle:
|
|
|
122
190
|
| `src/styles/components/account-footer.css` | account row and floating popover |
|
|
123
191
|
| `src/styles/components/ban-screen.css` | the account-hold easter egg (full-window overlay) |
|
|
124
192
|
| `src/styles/components/model-picker.css` | model picker popovers |
|
|
193
|
+
| `src/styles/components/hero-menu.css` | the host's menu primitive under the hero row's workspace/preset pickers (composer-gated) |
|
|
125
194
|
| `src/styles/components/footer-takeover.css` | host footer takeover rules |
|
|
126
195
|
| `src/styles/components/third-party.css` | agy-link repair rules |
|
|
127
196
|
| `src/styles/components/settings.css` | settings page section |
|
|
@@ -133,6 +202,7 @@ assembles the bundle:
|
|
|
133
202
|
| `src/overrides/copy.js` | composer/copy rewrites installer |
|
|
134
203
|
| `src/overrides/permissions.js` | permission segments/popover installer |
|
|
135
204
|
| `src/overrides/model-picker.js` | model picker installer |
|
|
205
|
+
| `src/overrides/hero-menu.js` | stamps the host menu card the hero row's pickers open |
|
|
136
206
|
| `src/overrides/account-footer.js` | account footer/popover installer |
|
|
137
207
|
| `src/overrides/ban-screen.js` | account-hold easter egg installer |
|
|
138
208
|
| `src/overrides/scheduler.js` | scheduler, observers, subscriptions, teardown |
|
|
@@ -141,36 +211,17 @@ assembles the bundle:
|
|
|
141
211
|
| `src/entry.js` | `apply()` orchestrator + exports |
|
|
142
212
|
| `src/model-descriptions.json` | model copy (picker labels + per-model descriptions); validated at build time and **copied** to `lib/`, not inlined |
|
|
143
213
|
|
|
144
|
-
Fragments share one factory scope at runtime
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
`
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
one line in the language the shell's own `locale` service reports, falling back
|
|
156
|
-
to the document's `fallback` locale. Lookup descends exact → family → tier →
|
|
157
|
-
the catalog's own text; family rules are ordered and must stay anchored (the
|
|
158
|
-
`flash` rule is scoped to `deepseek`, or another vendor's flash tier inherits
|
|
159
|
-
DeepSeek's copy).
|
|
160
|
-
|
|
161
|
-
The same document carries the picker's **brand marks** under `brands`:
|
|
162
|
-
`brands.providers` maps a provider route id to a vendored mark (the level-2
|
|
163
|
-
group header), and `brands.models` is an ordered, anchored rule list matching a
|
|
164
|
-
model id (the row's vendor — the vendor that made the model, not the aggregator
|
|
165
|
-
reselling it, with the provider's mark as the fallback). Both name ids vendored
|
|
166
|
-
in `src/assets/icons/lobe/`, and the build fails on an id that is not there, so the
|
|
167
|
-
binding cannot drift. The marks are the **mono** Lobe Icons glyphs
|
|
168
|
-
(`fill="currentColor"`), stamped into the row as markup: the theme's own text
|
|
169
|
-
colour paints them, which keeps them legible on both canvases and keeps the
|
|
170
|
-
palette to its single clay accent. Full-colour variants are deliberately not
|
|
171
|
-
used — a third of the vendors ship no colour version (OpenAI, Anthropic, xAI,
|
|
172
|
-
Moonshot, Z.ai, Vercel, Groq), and several brand colours are near-black on the
|
|
173
|
-
`#141413` canvas.
|
|
214
|
+
Fragments share one factory scope at runtime — no `import`/`export`, 4-space
|
|
215
|
+
base indent; the build rejects unsubstituted `%%TOKENS%%` and refuses to emit a
|
|
216
|
+
bundle that fails to parse. The hard rules for fragments, model copy and host
|
|
217
|
+
selectors live in `AGENTS.md` (the selector section below is the detail page it
|
|
218
|
+
points to); the reasoning behind them is in `docs/architecture.md` (D1, D3, D5).
|
|
219
|
+
|
|
220
|
+
Model copy is the one thing that does **not** go into the bundle: the build
|
|
221
|
+
copies `src/model-descriptions.json` to `lib/` and the host half serves it, so
|
|
222
|
+
the table grows without a rebuild. The picker's brand bindings ride the same
|
|
223
|
+
document under `brands`; the note inside the file explains why a model no rule
|
|
224
|
+
claims draws no lockup at all.
|
|
174
225
|
|
|
175
226
|
### Host selector discipline · 宿主选择器纪律
|
|
176
227
|
|
package/docs/architecture.md
CHANGED
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
## D5. 模型文案是数据,不进 bundle
|
|
42
42
|
|
|
43
43
|
- **背景**:模型目录日新月异,文案更新不应要求改 JS 发版。
|
|
44
|
-
- **决定**:`src/model-descriptions.json` 构建期校验后复制到 `lib/`,浏览器首次绘制选择器时经宿主路由 fetch;查找按 精确条目 → 家族规则 → 档位规则 → 目录自带文本
|
|
44
|
+
- **决定**:`src/model-descriptions.json` 构建期校验后复制到 `lib/`,浏览器首次绘制选择器时经宿主路由 fetch;查找按 精确条目 → 家族规则 → 档位规则 → 目录自带文本 逐级降级;不写「最强/旗舰」等最高级(钉住版本的精确条目除外)。两条附加纪律:**文案是「线」的文案,不是「版本」的文案**——同一条产品线(如 DeepSeek 的 Flash / Pro)按名字模式映射到同一句,版本迭代与退场都不改这句话,因为过时版本会命中同一条规则,给某个版本写的描述最终会挂在别的版本上;**不写我们自己加的档位前缀**(「旗舰档:」「顶级档位:」),文案要么是厂商自己的定位句,要么直接说它做什么——前缀是我们的定位话术,会随产品线换代变成假话;**描述也不重复模型名**——行里已经写着模型名,文案再以「X 系列:」「X 档:」开头就是重复,只写后半句(Kimi K3 那条就是官网模型页标题去掉「Kimi K3:」之后的部分)。
|
|
45
45
|
- **代价**:首次绘制选择器有一次异步 fetch;文案体系有学习成本。
|
|
46
46
|
- **重审条件**:宿主模型目录 API 直接提供本地化文案时。
|
|
47
47
|
|
|
@@ -52,23 +52,22 @@
|
|
|
52
52
|
- **代价**:每个 sync 必须有廉价的 early-out;新增 override 要接入同一调度器而不是自立门户。
|
|
53
53
|
- **已知代价与对策**:流式输出期间每帧一次全量 pass 是性能热点,见 D9。
|
|
54
54
|
|
|
55
|
-
## D7. UI
|
|
55
|
+
## D7. UI 行为优化内置在本插件,不拆独立插件
|
|
56
56
|
|
|
57
57
|
- **背景**:模型选择器、权限分段、账户抽屉等「UI 优化」与皮肤共享同一套宿主锚点(选择器纪律)、同一调度器(D6)、同一 popover 工具与 teardown。
|
|
58
58
|
- **决定**:行为层(`src/overrides/`)与皮肤层(`src/styles/`、tokens、品牌资产)在源码内保持分离,但发布为同一个包。不想要 Claude 皮肤的用户用设置里的品牌切换回到接近宿主的观感。
|
|
59
59
|
- **代价**:包名与主题绑定,「只用 UI 优化不要皮」的诉求没有独立入口。
|
|
60
60
|
- **重审条件**:出现第二个真实消费者(另一个主题包或宿主官方)需要复用 overrides 层时,把 overrides 抽成独立包,皮肤包依赖它。
|
|
61
61
|
|
|
62
|
-
## D8.
|
|
62
|
+
## D8. 多主题走「单仓库构建期分包」
|
|
63
63
|
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
- **触发条件(重要)**:仅当新主题有**行为分叉**(不同的 DOM override、不同的 composer 结构)才动手。若只是换色板与 logo,先用现有品牌切换机制(settings.js)在包内消化,不提前改造。
|
|
64
|
+
- **背景与决定**:做第二个主题时,多合一会让包名(claude)名不副实,分仓库会让共享机制(build.mjs、scheduler、popover-utils、选择器纪律)多处漂移,抽 npm 运行时公共包则违反 D1。所以届时把本仓库改为单仓库多主题:共享碎片留仓库级 `src/`,主题私有碎片(tokens、品牌资产、copy、主题特有 overrides)收进 `themes/<name>/`,`build.mjs` 参数化 `--theme`,每个主题产出自包含单文件、各自发 npm 包;`dsh-claude-style` 包名不动。具体改造步骤到立项时再写。
|
|
65
|
+
- **触发条件**:仅当新主题有**行为分叉**(不同的 DOM override、不同的 composer 结构)才动手。若只是换色板与 logo,先用现有品牌切换机制(settings.js)在包内消化,不提前改造。
|
|
67
66
|
- **代价**:改造时 build.mjs 与目录布局有一次性手术;两个主题之后共享碎片的改动需要双主题回归。
|
|
68
67
|
|
|
69
|
-
## D9. composer 的 :has() 分支改 JS
|
|
68
|
+
## D9. composer 的 :has() 分支改 JS 写属性
|
|
70
69
|
|
|
71
70
|
- **背景**:皮肤在流式输出期间的渲染压力主要来自两处:D6 的每帧全量 pass,以及 CSS 中约 70 处对 DOM 结构敏感的 `:has()`(绝大多数是 `[class*="composerStack"]` 上的 hero/inline 分支)——每次 DOM 变更都触发昂贵的选择器重算。
|
|
72
71
|
- **决定**:把「结构感知」从 CSS 移到 JS:`permissions.js` 的 `syncSegments()` 在 scheduler 每轮 pass 里为 composerStack 祖先写 `data-composer-variant="hero|inline"` 属性(observer 的 attributeFilter 不含 data-*,不会反触发;写前比较旧值防抖动;同轮去重避免多卡命中同一 stack 反复写),CSS 改为读属性。交互敏感的 `:has()`(`:hover`、`:focus-within`)与低频的 dialog `:has()` 保留。
|
|
73
|
-
-
|
|
72
|
+
- **落地**:已执行完毕。仍未消除的结构感知 `:has()` 只剩 placeholder 那条(`card` 上的 `:not(:has([data-composer-placeholder]))`):`copy.js` 本就管理 placeholder,可在它的 sync 里同步写 `data-has-placeholder` 再改 CSS,属可选的后续优化。
|
|
74
73
|
- **重审条件**:实测证明 :has() 不再是热点,或宿主提供 hero/inline 的稳定属性契约。
|