npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@citisen/dsh-font

v0.3.1

Published

DeepSeek Harness plugin: customize the Web GUI fonts (interface family, code family, and two font-size axes) from Settings

Readme

dsh-font

English | 中文

dsh 起不来怎么办

你正在看的报错就是这三行 ——

Failed to load plugins
web boot: 3 entries did not activate
@citisen/dsh-font: pending (waiting for service: settingsScope)

「启用的条目却始终不激活」在 dsh 里算启动失败而不是警告:它会拒绝完成启动,而不是少个插件 照常起来。三条出路,从快到慢,三条都在 dsh 起不来的情况下可用。本插件在 profile 里的行是 id: ui-font,对应 name: '@citisen/dsh-font'。

1. 禁用它 —— 在 profile 自己的补丁层里加一条 ($DSH_HOME/profiles/web/cordis.patch.yml,这一层在所有 bundle 层之后应用):

- id: ui-font
  disabled: true

不用敲命令、不用联网、不用装东西;删掉这两行它就回来了。dsh --profile web --dump-config 会打印组装后的树 —— 每个行的 id 和包名,不管它属于谁 —— 补丁生效时这一行会带 disabled: true;它不加载任何插件,所以 dsh 起不来时也能用。

2. 只影响这一次启动,什么都不改 —— 把同样两行写进你自己的文件,当叠加层传进去:

dsh --profile web --patch ./no-font.yml web

3. 卸载它 —— 一条命令同时摘掉依赖和 bundle 层(dsh.profile.bundles 会按已安装状态自动 对齐)。它只是转发给 profile 目录里的 pnpm,不组装 profile,所以 dsh 起不来时也能跑:

dsh plugin --profile web remove @citisen/dsh-font

需要 PATH 上有 pnpm。没有的话,就手工从 $DSH_HOME/profiles/web/package.json 的 dsh.profile.bundles(以及对应的 dependencies)里删掉包名。

或者先要一个能用的 dsh:用官方模板起一个干净的 profile,它不带你装的任何 bundle:

dsh --profile rescue --from-default-profile web

兼容性

本构建在两条 dsh 线上都能跑:0.1.5-rc.x 系列(也就是当前的 latest 和 next),以及 0.1.7-alpha.1 —— 后者的设置模型它同样会说。两条线上,这份插件的 section 都叫同一个名字 ui-font:0.1.7 线按 Loader 条目 id 定位设置,而本 bundle 的补丁正是以这个名字插入条目; 0.1.5 线则把同一个名字注册为设置命名空间。

| 它读什么 | 0.1.5-rc.x | 0.1.7-alpha.1 | | --- | --- | --- | | 那份持久 section | settingsScope.bind({ namespace: 'ui-font' }) | configForms.get('ui-font'),读条目自己的 Config | | 宿主契约 | settings.register('ui-font', schema) | 导出的 Config,字段标记为 .volatile() |

两者都是可选绑定,所以两条服务都不提供的 dsh 也照样激活:插件不会一直 pending(那会直接 阻断启动),也不会在激活时抛错。它按出厂默认值工作,而你在设置行上第一次动开关时,它会告诉你为 什么存不下来。0.2.2 及更早的版本要求 0.1.5 那条服务,所以在 0.1.7-alpha.1 上被报成「未激活」的条目;0.2.3 两条线的设置都会说,0.2.4 起还不再借用设计系统的图标。

最后这条值得单独说清楚,因为它正是移植设置时最容易藏住的故障。设计系统的图标导出按笔画粗细命名, 而名字在两条 dsh 线之间改过(0.1.5-rc.x 是 IconChevronDownOutline14,0.1.7 是 IconChevronDownOutlineRegular)。名字没了的图标不会渲染成"缺一张图",而是以 undefined 顶替 组件类型,于是 React 在渲染这一行时抛 "Element type is invalid",整个字体行直接从设置页面上 消失,只留一条控制台报错。这一行现在一个图标都不借、也不自己画(只有文字框、数字框和一个 按钮),也正因如此,它的客户端 bundle 只向 shell 要 react 和 @deepseek-ai/dsh-client-store。

0.3.1:会话正文字号这一项去掉了

对话正文、标题与表格的字号重新完全归 dsh 自带的 设置 → 外观 → 字号大小:0.3.1 起本插件 不再写 --dsh-content-font-size,也不再重新推导那条 Markdown 阶梯。设置行里因此少了一个字段, contentFontSize 也从 schema 里移除 —— 所以如果你在旧版本里设过它,请把这一行从 $DSH_HOME/settings.yaml 或 profile 的 cordis.patch.yml 里删掉:dsh 会用条目自己的 schema 校验这个 section,多一个不认识的键就会整段拒绝。

0.1.7 改名时丢掉的设置

dsh 0.1.7 会把旧的 $DSH_HOME/settings.yaml 导入一次 —— 每个 section 写进同名条目 —— 并把文件 改名为 settings.yaml.imported。在 0.2.4 之前,本插件的条目叫 font,于是 ui-font 这个 section 无处可去,只留在改名后的文件里。现在名字对上了,dsh 自己的导入就能把 这些值放回去:

  1. 把 $DSH_HOME/settings.yaml.imported 复制成 $DSH_HOME/settings.yaml(是复制不是移动 —— 导入跑之前,那个文件是唯一的记录),并且只保留条目现在仍然声明的键:dsh 会用条目自己的 schema 校验这个 section,只要有一个不认识的键就整段拒绝,所以上面表格没列出的键都要删掉。
  2. 用你平时用的 profile 启动一次 dsh 0.1.7。凡是现在有条目对应的 section —— 包括 ui-font —— 都会写进那个 profile 的 Cordis patch。
  3. dsh 仍然不认的 section 会被报告出来,并继续留在 settings.yaml.imported 里;所以在你把需要 的东西取出来之前,别删那个文件。

在设置里自定义 DeepSeek Harness Web 界面字体:界面字体与代码字体两条字体栈(各带自己的字重),以及两条互相独立的字号轴(界面缩放与代码字号)。

这是一个第三方 dsh profile bundle(插件包)。它是一个「双面」包:Node 半边负责持久化的设置命名空间与首屏绘制前的样式注入,浏览器半边负责实际绘制并注册设置项。

需要 dsh 0.1.5-rc.1 或更新的 0.1.5-rc.x;它用到 settings.general.item 插槽、settingsScope 服务以及 ctx.theme.overrideTokens,这些在 latest 与 next 两条发布通道里都已具备。

功能

在 设置 → 通用 中新增一个 字体 行:两个字体查询字段,每个字段在输入框右侧紧跟一个自己的字号数字框。

| 字段 | 作用 | 取值 | | --- | --- | --- | | 界面字体 | --dsw-font-family,所有非代码的界面文字 | 字体查询:字体族,可带字重 | | 界面字号 | --dsw-font-family 那侧的数字框:按比例缩放所有写死的界面文字尺寸 | 75 – 150(百分比),整数即可 | | 代码字体 | --ds-font-family-code,代码块、行内代码、等宽文本 | 字体查询 | | 代码字号 | --ds-font-family-code 那侧的数字框:代码块与行内代码的字号 | 10 – 20 px |

字号不是滑块,而是一个原生数字框:可以直接输入,也可以用上下方向键或浏览器自带的微调箭头;单位(% / px)就写在框里。只有完整且在范围内的数值才会写入——打到一半的 1(本来要打 125)不是一条指令,因此既不会写坏设置,也不会被重新渲染掉;而离开这个框时,框里会恢复成实际保存的值,被拒绝的数字不会留在屏幕上装作已经生效。

会话正文字号不在这里。 对话正文、标题与表格的字号一直由 dsh 自带的 设置 → 外观 → 字号大小(ui-theme 命名空间)负责;0.3.1 去掉了这一行原本提供的第二个入口,本插件也不再写 --dsh-content-font-size。

两个字体框都是一门小型字体查询语言的编辑器,而不是普通输入框:整条字体栈就是一段可以逐字编辑的文本,带语法高亮、自动换行,以及一份来自本机实际字体的补全列表。字重写在查询里面、紧挨着它所属的字体族,所以换字体和换字重是同一处的同一次编辑:

Geist Mono medium, "Zhuque Fangsong (technical preview)", monospace
└─────┬────┘ └──┬─┘
    字体族      字重
  • 顺序就是文本的顺序。 浏览器能解析到的第一个字体族生效,排序靠编辑文本完成:剪切粘贴,或把光标放进某个词条按 Alt+↑/↓。没有需要拖动的胶囊了。
  • 这段文字归你。 插件不会改写它:不加引号、不重排、不整理,也不会把清空的框重新填满。新字体就落在光标处——因为你是在那里打的字;把某个字体放到最前面,要么自己敲 Inter, ,要么在词条开头从补全列表里选。
  • 列表认识你机器上的字体。 它补全字体族、通用族,以及某个字体族实际拥有的字重(从它的字面读取)。本机字体读取不可用或被拒绝时,会退回"探测到的常用字体"名单,并在行上方说明一次;任何名字始终可以手写,目录从不自称完整。
  • 输入框永远是同一个等宽字体。 高亮层和真正的 textarea 共用一个盒子,而 textarea 没法给不同的字符串设不同字体,所以这个框统一使用一套系统等宽字体、字重固定 400、并关闭连字与字距调整——无论查询里写的是什么字体。带连字的字体(Fira Code 的 ->)会在高亮层画成一个字形、在输入框里画成两个,合成字重也会两边不一致。框下那行读数用的是这条轴自己的字体,所以你选的字体在那里仍然看得见。
  • 设置跟着每一次按键走。 文字归编辑器自己所有,所以没有"提交"这一步:查询边打边解析、边写入,框下的读数也随之更新。Tab(或点击)才会接受高亮的那条补全——那是唯一会替换文本的情况,因为"选中一条建议"本身就是这个意思。Enter 同样会接受高亮的补全,除此之外绝不改动文本。
  • 写错只标出来,不改。 本机没有的字体族、字体族没有的字面、没闭合的引号、多出来的词,都会在框下分别以警告色或错误色标出,文本保持你写的样子。空输入框什么都不写并说明这一点:已保存的字体栈仍在生效,要回到出厂值按「恢复默认」。

所有取值都通过宿主设置文档持久化($DSH_HOME/settings.yaml,命名空间 ui-font),因此重启后依然生效,并且对指向同一台宿主的所有浏览器共享。

界面字号 与 代码字号 是两条独立的轴:放大界面可以让周围的控件更好读,而消息正文一个字都不动;调大代码字号也不会把对话正文顶开——会话正文只认 dsh 自带的那条设置。

如何选字重:Geist Mono medium

CSS 没法把字重写进 font-family —— font-family: "Geist Mono" 500, monospace 本身就是非法声明,整条字体栈会被丢弃。所以这门查询语言把字重写成一个词,紧跟在它所属的字体族后面,插件再把这一对还原成真正生效的两条声明:

Geist Mono medium, monospace   →   font-family: "Geist Mono", monospace
                               →   font-weight: 500

Thin、ExtraLight、Light、Book、Regular、Medium、SemiBold、Bold、ExtraBold、Black 以及常见别名(Hairline、DemiBold、UltraBold 等)都能识别,大小写不敏感。字重属于整条轴而不是某一个字体族,所以写在哪里都算数,但只算一次;规范形式把它写在第一个字体族(也就是生效的那个)后面。

出厂字重是隐含的:某条轴停在出厂的 400 时,文本里不会出现任何字重词——每个字体族后面都跟一个 regular 是谁也没要求的噪音,而对界面轴来说 400 本来就等于"不做覆盖"。只有真正选了字重,这个词才会出现;把它删掉就回到 400。这条轴当前到底是多少,永远写在输入框下面那一行(界面字重: 常规 400(出厂值,未覆盖)),所以省掉那个词并没有藏起任何信息。

字重是一个封闭列表而不是任意数字:所选字体族没有的字重会被浏览器合成(伪粗体),把伪粗体当成正常选项提供,比不提供更糟。在能读到字面的机器上(Local Font Access API 会报告每个字面),补全列表只给这个字体族真正拥有的字重,缺哪个会在框下点出来:

Geist Mono 在本机没有 700 这个字面(bold),浏览器会合成

把字重词删掉不会悄悄重置任何东西:这条轴保持它被设成的值,输入框下面那行会写出来;等下次行组件按存储值重建时,那个词也会回来。要回到出厂字重,从列表里选它那一档(常规 400)——选中是一条指令,所以即使它的文本只是字体族名,也会把值设成 400。

有一处刻意的例外:如果你输入的内容本身就是本机上的字体族,末尾那个词会被当成名字的一部分。Book Antiqua、Franklin Gothic Medium 都是真实存在的字体族,把它们当成"字体族 + 字重"处理会静默改错。代价是:真正两者皆是的名字(真有一个字体族叫 Geist Mono Medium)也会被当作名字。判断依据就是补全列表给出的那份字体目录。想明确表达"这就是名字",加引号即可:"Book Antiqua" 永远是名字本身。

界面字重是可选覆盖

代码区域没有需要保留的字重层级,所以它的字重就是查询里写的那个数。界面则只有一条规则:

/* --dsh-font-ui-weight: 500 */
html body { font-weight: 500 }

会跟着变的是继承字重的那部分文字;设计系统自己写死字重的东西——标题、表头、按钮,以及用 font: 简写整体声明过的对话正文——不受影响,因为它们自己的规则仍然胜出。对话正文的字号与行高由 dsh 自带的字号设置驱动,本插件不再覆盖那条 Markdown 阶梯,所以界面字重也不会去改写它。出厂的 400 不产生任何规则,所以未改动的安装画出来的就是设计系统原本的样子。

这门查询语言

query  := entry ("," entry)*
entry  := family | weight
family := '"' … '"' | "'" … "'" | word (space word)*
weight := thin | extralight | light | book | regular | roman | medium |
          demibold | semibold | bold | extrabold | black | heavy | …

语法就是 CSS font-family 列表,加上列表本身装不下的那一样东西。只有未加引号词条的最后一个词可能是字重,而且整个词条本身不是已收录的字体族时才成立。单独一个 medium 也表示"只设字重、不改字体族"。引号里的逗号不是分隔符,所以 "Foo, Bar" 是一个字体族。

解析器刻意宽容——这段文字是人手敲的,不是生成的——凡是放不下的东西都按原样保留并在框下报告,而不是悄悄丢掉:没闭合的引号、引号后面多出来的词、写了两次的字重、本机目录里没有的字体族、这个字体族没有的字面。框下同时会写出当前生效的字体族,也就是浏览器真正能用上的第一个。

安装

dsh plugin --profile web add @citisen/dsh-font

直接从 GitHub 安装(同一个包,不走 registry):

dsh plugin --profile web add github:citisen/dsh-font

然后重启 Web 界面:

dsh --profile web

dsh plugin 会在 profile 目录里转发给 pnpm,然后对 dsh.profile.bundles 做一次对账:由于本包声明了 dsh.bundle,安装时会自动把它追加为一个 profile 层,无需手工修改 cordis.patch.yml。

这两条路径都在全新 profile 上实测过:这一行会进入最终 entry 列表,浏览器 roster 也能解析到客户端 bundle。装完后可以用 node scripts/verify-profile.mjs <profile> 自己确认。

从本地目录安装

在 Windows 上,如果 profile 和代码目录位于不同盘符,dsh plugin --profile web add <路径> 不可靠——pnpm 会把跨盘符的目录链接解析成一个不存在的路径,随后对账会认为该包没有声明 dsh.bundle,于是不把它写进 bundles。这时请自己建立链接:

cd "$DSH_HOME/profiles/web"
pnpm add "D:/path/to/dsh-font"          # 写入依赖
# pnpm 建立的链接指向 <profile>/D:/path/to/dsh-font,该路径不存在,需要修复:
cmd /c rmdir node_modules\dsh-font
cmd /c mklink /J node_modules\dsh-font D:\path\to\dsh-font
# 再手工把 "dsh-font" 加进 package.json 的 dsh.profile.bundles

用 node scripts/verify-profile.mjs 校验结果;只要这一行没进最终的 entry 列表,它就会直接报错。

实现原理

修改代码前请先读这一节;两个半边解决的是不同的问题,这个划分是有意的。

为什么字体族走 theme 服务

设计系统只在 :root 声明了这两个字体变量:

:root{--dsw-font-family:…;--ds-font-family-code:…}

界面上几乎所有排版 token 都经由 var(--dsw-font-family) 解析(--dsw-font-base-16、--dsw-font-xs-13、整条 Markdown 字号阶梯……),shell 自己的 body 规则也读取它,所以覆盖这两个变量就等于重新指向整个界面。

但最直观的写法——在 documentElement 上设自定义属性——活不下来。ui-layout 的 ThemePresenter 掌管 document.body.style,每次主题变化时它会把所有不是自己写的自定义属性删掉,再重新写入当前 token 集合。外部设置的属性会在用户第一次切换浅色/深色时消失。

所以浏览器半边把字体叠加到 theme 上:

ctx.theme.overrideTokens('dsh-font', {
  '--dsw-font-family': { light: uiFontFamily, dark: uiFontFamily },
  '--ds-font-family-code': { light: codeFontFamily, dark: codeFontFamily },
})

这个覆盖层会被折进当前快照,presenter 随后会把它写出去,并在每次调色板变化时继续写。{ light, dark } 这一对是强制的:overrideTokens 对裸字符串会抛出带解释的错误,因为单一取值在另一套调色板下会不可读。

为什么字号走样式表

设计系统里没有界面字号变量。每个组件都写死 11、12、13、14、16、20、24 px 之一,而 --dsw-font-* 是一套固定阶梯(--dsw-font-xs-13 就是 13px,没有变量可调)。代码字号同样烘焙在复合 token 里。

因此插件为每个内置尺寸生成一个工具类:

.dsh-font-size-14{font-size:calc(14px * var(--dsh-font-ui-scale,1)) !important}

并把对应的类逐个盖章到元素上——在元素还没有盖章时用 getComputedStyle 量出它的内置尺寸。MutationObserver 会在界面挂载新节点时补盖。

之所以逐元素盖章而不是用通配规则,正是为了让两条字号轴互不影响:html body * 这种覆盖会继承进会话区域并与 dsh 自己的正文字号复合叠加,而且还会改掉那些本来不该缩放的装饰性尺寸(文件类型图标里内嵌的 SVG 文字标签)。逐元素测量还意味着插件不需要知道任何组件的类名,因此能扛住界面重构。

正文字号不再由本插件负责

--dsh-content-font-size 是在 body 上的内联自定义属性,由 ui-layout 依据兄弟命名空间 ui-theme 写入(也就是 设置 → 外观 → 字号大小)。内联声明无论有没有 !important 都压过样式表,所以想接管它就必须写到完全相同的位置——本插件以前就是这么做的,现在不再写它,也不再重新推导那条 Markdown 阶梯。对话正文的字号与行高重新完全归 dsh 自带那条设置所有;本插件只留下界面缩放与代码字号两条轴,它们各自作用在自己的区域里,互不复合。

代码字重写在哪里

设计系统里完全没有字重 token——界面上每一处 font: 都是字面量,代码那条阶梯写死就是 400。所以字重没法像字体族那样搭在字体 token 上,它分两层生效:

/* 三个代码 token 在各自的 font: 简写里带上它…… */
--dsw-font-markdown-code: var(--dsh-font-code-weight,400) var(--dsh-font-code-size,12px) / … ;

/* ……而直接用代码字体族写死的地方,按结构匹配 */
html body pre, html body code, html body [class*="code" i] {
  font-family: var(--ds-font-family-code) !important;
  font-weight: var(--dsh-font-code-weight,400) !important;
}

第二条规则的存在,是因为界面上大多数代码根本不读 token:工具 I/O 卡片和终端输出是在组件样式表里用 font-family: var(--ds-font-family-code) 加上自己的字面量字重写死的,除了覆盖元素本身没有别的地方可改。!important 正是为了压过 font: 500 12px/18px …。这条规则刻意不是通配规则:周围标签仍保留出厂的字重层级。

界面字重写在哪里

界面字重是可选的:出厂值 400 不产生任何规则,所以未改动的安装画出来的就是设计系统原本的样子。设成别的值时就只有一条规则:

/* 会继承字重的界面文字整体移动 */
html body { font-weight: 500 }

标题、表头这类在设计系统里写死了自己字重的地方不动,用 font: 简写整体声明过的对话正文也不动——对话正文的字号与行高归 dsh 自带那条设置,本插件不再重新声明那条阶梯,也就不会顺手改写它的字重。

首屏绘制前

Node 半边响应 webserver/index-inject,注入一段内联 <script>,在 shell 挂载之前就装好样式表并设好字体族与字重变量,因此第一帧就已经是用户的字体。它在渲染时读取同一个 ui-font 设置段;当设置服务缺失时回退到 schema 默认值。

开发

npm run build     # src/client.js -> lib/client.js
npm run check     # 发布闸门:产物同步 + host/client 校验
npm run check:all # 再加上 profile 组合校验(需要本机有 dsh)
npm run verify    # 只跑校验脚本
npm run watch     # 保存即重建,配合 dsh-client-hmr

浏览器半边的唯一真源是 src/client.js。它为了可读性写成 ES module,但 DSH 的客户端 bundle 是传统脚本(classic script),只允许通过 window.__ModuleLoader__ 注册一个惰性 CommonJS 工厂——因此 scripts/build-client.mjs 负责套上这层外壳,并把静态 import 改写成 require 调用。这个转换刻意做得很窄,遇到无法改写的写法会直接让构建失败,因为没有打包器能替你发现问题。

浏览器半边只允许向 shell 索取它注入模块表的那九个模块(react、react/jsx-runtime、react-dom、react-dom/client、@deepseek-ai/cordis、@deepseek-ai/dsh-client-store、@deepseek-ai/dsh-client-ui-slots、@deepseek-ai/dsh-client-ui-primitives、@deepseek-ai/dsh-client-ui-dockkit)。其它依赖一律编译进 bundle:库走 VENDORED 映射,本插件自己的 src/font-grammar.js 走 LOCAL_MODULES——它被直接拼进 src/client.js 的作用域,因此两者共用同一份常量。另一条有文档的路子是 dsh.client.external,但它需要第二个客户端 bundle、第二个 roster 行,以及宿主的配合;而且宿主会静默忽略 supplier 不是活跃插件行的条目。构建会强制检查每个 specifier 走的是哪条路。

verify-profile.mjs 需要本机有 dsh 安装和已初始化的 profile,所以在两者都不存在时会跳过(exit 0)——干净的 CI runner 上没有 dsh。设 DSH_REQUIRE=1 可以把「跳过」变成失败。

要在运行中的宿主上迭代浏览器半边,开一个 watcher,让 dsh-client-hmr 热替换插件——它每 500 ms 轮询一次客户端 bundle,因此保存后的重建无需刷新页面即可生效:

# 终端 1
npm run watch

# 终端 2
dsh --profile web

刷新页面总能拿到新组合的图,所以 watcher 只是便利,不是必需。

发布

发布先由 GitHub Actions 通过 npm trusted publishing 完成暂存(stage),再由维护者审批,因此本仓库里没有 NPM_TOKEN,也不应该出现。逐步流程见 RELEASING.md;一次性配置以及这套机制防不住什么见 PUBLISHING.md。

包结构

| 路径 | 作用 | | --- | --- | | lib/index.js | Node 半边:设置命名空间、首屏绘制前的注入。由 loader 加载。 | | lib/client.js | 浏览器半边,由 src/client.js 生成。由 /plugins/@citisen/dsh-font/client.js 提供。 | | src/client.js | 浏览器半边源码。 | | src/font-grammar.js | 字体查询语法,作为一份 @citisen/litearea grammar。会被拼进 src/client.js。 | | cordis.patch.yml | 本 bundle 贡献的 profile 层。 | | scripts/ | 构建与校验脚本。 | | .github/workflows/stage.yml | 唯一发布路径的 CI 半边。 | | PUBLISHING.md | trusted publishing 一次性配置,以及这套机制防不住什么。 | | RELEASING.md | 改完代码之后怎么发布的完整流程。 | | package.json | 声明 dsh.bundle(profile 层)与 dsh.client(浏览器节点)。 |

已知限制

  • 只处理写死的尺寸。 界面缩放只作用于样式表里以 px 写死的文字,刻意不动展示级大字号和装饰性字形尺寸,因此 150% 并不等于整个界面的等比 1.5 倍。
  • 会话正文字号归 dsh 自带的外观设置。 对话正文、标题与表格的字号由 设置 → 外观 → 字号大小 决定,本插件不参与;界面缩放只动界面本身,代码字号只动代码区域。
  • 字体不会被安装。 只有浏览器或操作系统能解析到的字体名才会生效;插件不打包也不下载 webfont,因此写错名字只会静默回退到列表末尾的通用字体。
  • 逐元素盖章的开销与 DOM 规模成正比。 缩放扫描对每个元素只测量一次并缓存结果,之后按 DOM 变化增量盖章,因此开销有界——但在超长会话里并非免费。
  • 代码字重不能按区域分别设置。 它一次作用于所有代码区域,覆盖范围是 pre、code 以及类名里带 code 的元素——因此组件自己在代码块里设的字重(语法高亮、加粗的 diff 行)同样会被覆盖。界面字重同理,只是范围相反:只有会继承字重的那部分界面文字跟着变,设计系统写死字重的标签、按钮保持原样。字体族没有的字重浏览器仍会合成,封闭列表和"本机没有这个字面"的提示只是把它挡在选择之外。
  • 查询语言是本插件自己的约定,不是 CSS。 它只存在于这一行的两个字体框里,存储的仍然是合法的 CSS font-family 列表加上一个 font-weight 数字,所以关掉插件不会有残留。末尾的词算字重还是算名字的一部分,由已加载的字体目录决定,所以本身就以字重词结尾的真实字体族(Book Antiqua、Franklin Gothic Medium)只有在目录里确实列出了这一整名时才会保持原样——这两个词都在探测列表里,因此正常都能保住;而列表之外的同类名字在拒绝字体权限提示时可能被拆开,用引号可以明确表达"这是名字"。
  • 界面字重只动会继承它的文字。 只有一条 html body { font-weight: … }:设计系统写死字重的标题、表头、按钮,以及用 font: 简写整体声明的对话正文,都保持原来的字重。
  • 输入框不等于设置值。 存储的是插件对查询的序列化结果(加了引号、字重词落在生效字体族后面);框里显示的是你的文本,只要这一行还在就原样保留。重新加载页面时会用两个存储值重建输入框,所以你删掉的字重词可能又出现,拼写也可能和你写的不一样。
  • 设置项只有中英两种文案,与官方内置的语言对一致。

许可证

MIT