dsh-fonttune 0.1.4 → 0.1.5
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.en.md +10 -0
- package/CHANGELOG.md +10 -0
- package/README.en.md +5 -4
- package/README.md +5 -4
- package/lib/client.js +149 -45
- package/lib/index.js +13 -3
- package/lib/shared.cjs +81 -9
- package/package.json +2 -2
package/CHANGELOG.en.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to **dsh-fonttune** are documented here. Chinese version: [CHANGELOG.md](CHANGELOG.md).
|
|
4
4
|
|
|
5
|
+
## [0.1.5] - 2026-09-15
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Code font weight**: weight is split into **two independent axes** — "Body font weight" for text and interface copy (headings included), and "Code font weight" for code blocks, inline code, tool code bodies and terminal output only. The single slider used to press on both chains, so moving body always dragged code with it; now each moves on its own. The field is `weightCode` (300–600, 0 = leave alone), sitting next to the existing `weight`, whose meaning narrows to "body and interface text".
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **Card layout**: the weight sliders moved into the group they belong to — body font → body size offset → body weight → code font → code size offset → code weight — and the two are labelled separately ("Body font weight" / "Code font weight"). The card description now reads "Body and code fonts, a size and a weight for each, and a West/CJK split".
|
|
12
|
+
- **Code no longer follows the body weight**: weight has no token chain to ride (measured on rc.2 — **zero** `font-weight: var(--dsw-font-…)` usages; the theme writes literal weights in its own class rules), which is why the body axis is a blanket `body, body *` `!important` rule. The code axis now appends a scoped rule **after** it that wins either on specificity (`[class*=…]`) or on source order (`pre` ties with `body *`); the selector covers `pre` / `code` / `kbd` / `samp` / `var` / `tt` / `textarea` / `.cm-editor` **and their descendants** (the blanket rule matches every element, so a highlighted `<span>` inside a `<pre>` has to be named too), plus `[class*="code" i]` and `[class*="terminal" i]` for the tool code bodies and the terminal, which are plain `div`s. **The rule is written even when the code weight is unset** (value `normal`), otherwise the blanket rule would pull code onto the body weight; after upgrading, body-weight behaviour is unchanged and code returns to DSH's own weight.
|
|
13
|
+
- **Compatibility table** now lists 0.1.5 as the latest version.
|
|
14
|
+
|
|
5
15
|
## [0.1.4] - 2026-09-15
|
|
6
16
|
|
|
7
17
|
### Added
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
**dsh-fonttune** 的重要变更都记录在这里。英文版见 [CHANGELOG.en.md](CHANGELOG.en.md)。
|
|
4
4
|
|
|
5
|
+
## [0.1.5] - 2026-09-15
|
|
6
|
+
|
|
7
|
+
### 新增
|
|
8
|
+
- **代码字重**:字重从「一个全局偏移」拆成**两个互不影响的轴**——「正文字重」覆盖正文与界面文字(含标题),「代码字重」只覆盖代码块、行内代码、工具代码块与终端输出。原来那一个滑块同时压两条链路,调正文必然带动代码;现在各调各的。字段为 `weightCode`(300~600,0 = 不动),与既有的 `weight` 并列;`weight` 语义收敛为「正文与界面文字」。
|
|
9
|
+
|
|
10
|
+
### 变更
|
|
11
|
+
- **卡片布局**:字重滑块同样移进对应字体那一组——正文字体 → 正文字号偏移 → 正文字重 → 代码字体 → 代码字号偏移 → 代码字重;两处文案分开(「正文字重」/「代码字重」),卡片描述改为「正文与代码字体、各自的字号与字重、中西文分栏」。
|
|
12
|
+
- **代码轴不再被正文字重带着走**:字重没有可依附的 token 链(rc.2 实测**零处** `font-weight: var(--dsw-font-…)`——主题是在自己的类规则里写字面量),所以正文轴一直是 `body, body *` 的全量 `!important` 规则。代码轴现在在这条规则**之后**追加一条作用域规则,靠更高特异性(`[class*=…]`)或更靠后的同特异性(`pre` 与 `body *` 同分)取胜;选择器覆盖 `pre` / `code` / `kbd` / `samp` / `var` / `tt` / `textarea` / `.cm-editor` **及其后代**(全量规则命中每一个元素,所以 `<pre>` 里高亮用的 `<span>` 也必须点名),再加 `[class*="code" i]` 与 `[class*="terminal" i]` 覆盖工具代码块与终端这类没有语义标签的纯 `div`。**代码字重未设置时也会写这条规则**(值 `normal`),否则全量规则会把代码一起拽到正文字重上;旧配置升级后正文字重行为不变、代码回到 DSH 原值。
|
|
13
|
+
- **兼容表**改列 0.1.5 为最新版本。
|
|
14
|
+
|
|
5
15
|
## [0.1.4] - 2026-09-15
|
|
6
16
|
|
|
7
17
|
### 新增
|
package/README.en.md
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
> [中文](README.md) | **English**
|
|
4
4
|
|
|
5
|
-
**Font plugin for DeepSeek Harness (DSH)**: set the body and code font families, a font
|
|
5
|
+
**Font plugin for DeepSeek Harness (DSH)**: set the body and code font families, a font size and a font weight for each, and pick fonts per **Western / CJK** slot. Everything lives in the native card under **Settings → Plugins → Plugin configuration** and applies immediately.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
9
|
- **Body / code fonts** — two independent fallback lists, Latin families first and CJK after; leaving one empty keeps DSH's own stack untouched
|
|
10
10
|
- **Body font-size offset** — -3 ~ +6 px for text and interface sizes, stacked on top of DSH's own font-size setting rather than replacing it; every size step scales together with its line height
|
|
11
11
|
- **Code font-size offset** — -3 ~ +6 px for code blocks and inline code, **independent** of the body offset: moving one never moves the other
|
|
12
|
-
- **
|
|
12
|
+
- **Body font weight** — any integer from 300 to 600, overriding the weight of text and interface copy including headings; unset or 400 keeps DSH's own weight
|
|
13
|
+
- **Code font weight** — any integer from 300 to 600 for code blocks, inline code and terminal output only; unset or 400 keeps DSH's own weight and keeps code out of the body weight
|
|
13
14
|
- **West / CJK split (simple mode)** — a switch at the top of the card: simple mode gives just a Western and a CJK single-pick slot (one pair for body, one for code), advanced mode is the full stack editor; both views share one stack, so toggling never changes the order you set up
|
|
14
15
|
- **Font picker panel** — four preset groups (monospace / CJK / Latin / generic), plus an "installed on this machine" group on Chromium; a name that is not in the list can be created with "use xxx"
|
|
15
16
|
- **Drag to reorder** — selected families are a chip list you can drag, with earlier / later buttons kept for keyboard and touch
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
|
|
20
21
|
| Plugin version | Supported DSH versions |
|
|
21
22
|
| --- | --- |
|
|
22
|
-
| **0.1.
|
|
23
|
+
| **0.1.5** (latest) | 0.1.5-rc.2 |
|
|
23
24
|
|
|
24
25
|
`engines.dsh` requires **0.1.5-rc.2** or newer, and the compatibility declaration lists only the **latest release of the 0.1.5 line**: it carries every fix in that line, which makes it the most stable build of the major version, while older builds of the same major version stay compatible per semantic versioning. Earlier or newer DSH versions are untested and not declared. On install or update, the DSH market runs a host-compatibility preflight against `engines.dsh`, `dsh.compatibility.dshReleases` and `peerDependencies` in `package.json`.
|
|
25
26
|
|
|
@@ -49,7 +50,7 @@ Restart DSH once afterwards and open the Web UI; changing settings needs no rest
|
|
|
49
50
|
|
|
50
51
|
- **Open the settings** — Settings → Plugins → Plugin configuration → expand the "Font tune" card
|
|
51
52
|
- **Pick fonts** — in simple mode click the four slots (Body · Western, Body · CJK, Code · Western, Code · CJK); in advanced mode use "Add font" and the chip editor to maintain the full fallback list
|
|
52
|
-
- **Tune sizes** — each
|
|
53
|
+
- **Tune sizes and weights** — each slider sits under the thing it changes: body font → body size offset → body weight → code font → code size offset → code weight. Drag and release to apply. Changed fields are marked and can be reset individually, with "Reset all" at the bottom of the card
|
|
53
54
|
- **Preview** — the mixed-script and code preview at the bottom of the card renders with the current configuration
|
|
54
55
|
- Settings are stored in DSH's settings document (`settings.yaml`), so they travel with your configuration
|
|
55
56
|
|
package/README.md
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
> [English](README.en.md) | **中文**
|
|
4
4
|
|
|
5
|
-
**DeepSeek Harness(DSH
|
|
5
|
+
**DeepSeek Harness(DSH)字体插件**:设置正文与代码的字体族、各自独立的字号与字重,并按「西文 / 中文」分栏挑字体;配置入口是 **设置 → 插件 → 插件配置** 里的原生卡片,改完即时生效。
|
|
6
6
|
|
|
7
7
|
## 功能
|
|
8
8
|
|
|
9
9
|
- **正文 / 代码字体** —— 两套独立的字体回退列表,拉丁字体在前、中文字体在后;留空表示完全沿用 DSH 的字体栈
|
|
10
10
|
- **正文字号偏移** —— -3 ~ +6 px,作用于正文与界面文字;与 DSH 自己的「字号大小」叠加而不是覆盖,每一档字号连同它的行高一起等比缩放
|
|
11
11
|
- **代码字号偏移** —— -3 ~ +6 px,**独立**作用于代码块与行内代码:调正文不会带动代码,调代码也不会带动正文
|
|
12
|
-
-
|
|
12
|
+
- **正文字重** —— 300 ~ 600 任意整数,覆盖正文与界面文字的粗细(含标题);未设置或 400 表示沿用 DSH 原本的字重
|
|
13
|
+
- **代码字重** —— 300 ~ 600 任意整数,只覆盖代码块、行内代码与终端输出;未设置或 400 表示代码保持 DSH 原样,也就是**不被正文字重带着走**
|
|
13
14
|
- **西文 / 中文分栏(简单模式)** —— 卡片顶部一个开关:简单模式只给「西文」「中文」两个单选格(正文/代码各一对),高级模式是完整的字体栈编辑器;两种模式共用同一条栈,来回切换不会改动已排好的顺序
|
|
14
15
|
- **选字体面板** —— 内置 等宽 / 中文(CJK)/ 拉丁 / 通用 四组预设,Chromium 下再补上「本机已安装」分组;搜索不到的名字可以直接「使用 xxx」新建
|
|
15
16
|
- **拖拽排序** —— 已选字体是 chip 列表,可拖动调整回退顺序,同时保留前移 / 后移按钮(键盘与触屏可用)
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
|
|
20
21
|
| 插件版本 | 支持的 DSH 版本 |
|
|
21
22
|
| --- | --- |
|
|
22
|
-
| **0.1.
|
|
23
|
+
| **0.1.5**(最新) | 0.1.5-rc.2 |
|
|
23
24
|
|
|
24
25
|
`engines.dsh` 下限为 **0.1.5-rc.2**,兼容声明只列 **0.1.5 线的最新版本**:它包含这条线的全部修复,是同一大版本里最稳的一版,而同一大版本内的旧版本按语义化版本约定向上兼容。更早或更新的 DSH 未经验证,不作声明。安装或更新时,DSH 市场会依据 `package.json` 里的 `engines.dsh`、`dsh.compatibility.dshReleases` 与 `peerDependencies` 做宿主兼容预检。
|
|
25
26
|
|
|
@@ -49,7 +50,7 @@ dsh plugin --profile web add <插件目录路径>
|
|
|
49
50
|
|
|
50
51
|
- **打开设置** —— 设置 → 插件 → 插件配置 → 展开「字体增强」卡片
|
|
51
52
|
- **换字体** —— 简单模式下点「正文 · 西文字体」「正文 · 中文字体」「代码 · 西文字体」「代码 · 中文字体」四个格子选字体;高级模式下用「添加字体」与 chips 编辑器维护完整回退列表
|
|
52
|
-
-
|
|
53
|
+
- **调整字号与字重** —— 滑块就在它作用的对象下面:正文字体 → 正文字号偏移 → 正文字重 → 代码字体 → 代码字号偏移 → 代码字重。拖动松手即生效;改过的字段标「已修改」并可单独重置,卡片底部有「全部重置」
|
|
53
54
|
- **预览** —— 卡片底部的中英混排与代码预览用当前配置渲染
|
|
54
55
|
- 设置保存在 DSH 的设置文档里(`settings.yaml`),跟随配置走
|
|
55
56
|
|
package/lib/client.js
CHANGED
|
@@ -38,9 +38,12 @@ var SIZE_FIELD = "sizeOffset";
|
|
|
38
38
|
/** Field carrying the code font-size offset in px (0 = leave DSH alone). */
|
|
39
39
|
var CODE_SIZE_FIELD = "sizeOffsetCode";
|
|
40
40
|
|
|
41
|
-
/** Field carrying the
|
|
41
|
+
/** Field carrying the body/UI font weight (0 = leave DSH alone). */
|
|
42
42
|
var WEIGHT_FIELD = "weight";
|
|
43
43
|
|
|
44
|
+
/** Field carrying the code font weight (0 = leave DSH alone). */
|
|
45
|
+
var CODE_WEIGHT_FIELD = "weightCode";
|
|
46
|
+
|
|
44
47
|
/** Allowed font-size offset range. The upper bound stays under a 2x scale. */
|
|
45
48
|
var SIZE_MIN = -3;
|
|
46
49
|
var SIZE_MAX = 6;
|
|
@@ -66,6 +69,7 @@ var DEFAULTS = {
|
|
|
66
69
|
sizeOffset: 0,
|
|
67
70
|
sizeOffsetCode: 0,
|
|
68
71
|
weight: WEIGHT_UNSET,
|
|
72
|
+
weightCode: WEIGHT_UNSET,
|
|
69
73
|
};
|
|
70
74
|
|
|
71
75
|
/**
|
|
@@ -156,18 +160,15 @@ function normalizeConfig(value) {
|
|
|
156
160
|
var source = value !== null && typeof value === "object" ? value : {};
|
|
157
161
|
var size = clampOffset(source[SIZE_FIELD]);
|
|
158
162
|
var codeSize = clampOffset(source[CODE_SIZE_FIELD]);
|
|
159
|
-
var weight =
|
|
160
|
-
|
|
161
|
-
weight = Math.round(weight);
|
|
162
|
-
if (weight !== WEIGHT_UNSET) {
|
|
163
|
-
weight = Math.min(WEIGHT_MAX, Math.max(WEIGHT_MIN, weight));
|
|
164
|
-
}
|
|
163
|
+
var weight = clampWeight(source[WEIGHT_FIELD]);
|
|
164
|
+
var codeWeight = clampWeight(source[CODE_WEIGHT_FIELD]);
|
|
165
165
|
var config = {};
|
|
166
166
|
config[SANS_FIELD] = sanitize(source[SANS_FIELD]).slice(0, MAX_STACK_LENGTH);
|
|
167
167
|
config[MONO_FIELD] = sanitize(source[MONO_FIELD]).slice(0, MAX_STACK_LENGTH);
|
|
168
168
|
config[SIZE_FIELD] = size;
|
|
169
169
|
config[CODE_SIZE_FIELD] = codeSize;
|
|
170
170
|
config[WEIGHT_FIELD] = weight;
|
|
171
|
+
config[CODE_WEIGHT_FIELD] = codeWeight;
|
|
171
172
|
return config;
|
|
172
173
|
}
|
|
173
174
|
|
|
@@ -182,6 +183,19 @@ function clampOffset(value) {
|
|
|
182
183
|
return Math.round(Math.min(SIZE_MAX, Math.max(SIZE_MIN, size)));
|
|
183
184
|
}
|
|
184
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Clamp one weight to the allowed range, keeping 0 as "do not touch".
|
|
188
|
+
* @param {unknown} value - candidate weight.
|
|
189
|
+
* @returns {number} the weight the stylesheet may use.
|
|
190
|
+
*/
|
|
191
|
+
function clampWeight(value) {
|
|
192
|
+
var weight = Number(value);
|
|
193
|
+
if (!isFinite(weight)) return WEIGHT_UNSET;
|
|
194
|
+
weight = Math.round(weight);
|
|
195
|
+
if (weight === WEIGHT_UNSET) return WEIGHT_UNSET;
|
|
196
|
+
return Math.min(WEIGHT_MAX, Math.max(WEIGHT_MIN, weight));
|
|
197
|
+
}
|
|
198
|
+
|
|
185
199
|
/**
|
|
186
200
|
* Format a family list as a CSS font-family value.
|
|
187
201
|
* @param {readonly string[]} families - family names in precedence order.
|
|
@@ -385,7 +399,8 @@ function isDormant(config) {
|
|
|
385
399
|
config[MONO_FIELD] === "" &&
|
|
386
400
|
config[SIZE_FIELD] === 0 &&
|
|
387
401
|
config[CODE_SIZE_FIELD] === 0 &&
|
|
388
|
-
config[WEIGHT_FIELD] === WEIGHT_UNSET
|
|
402
|
+
config[WEIGHT_FIELD] === WEIGHT_UNSET &&
|
|
403
|
+
config[CODE_WEIGHT_FIELD] === WEIGHT_UNSET
|
|
389
404
|
);
|
|
390
405
|
}
|
|
391
406
|
|
|
@@ -415,7 +430,14 @@ function isDormant(config) {
|
|
|
415
430
|
* what the shipped stylesheets use), which is why those are re-declared too,
|
|
416
431
|
* not just their `-font-size` / `-line-height` parts.
|
|
417
432
|
*
|
|
418
|
-
*
|
|
433
|
+
* Weight has no token chain to ride: no shipped rule reads a `-font-weight`
|
|
434
|
+
* token (measured — zero `font-weight: var(--dsw-font-…)` in rc.2), the theme
|
|
435
|
+
* writes literal weights on its own class rules, and that is exactly why the
|
|
436
|
+
* body axis has to be a blanket `!important` rule. The code axis is therefore a
|
|
437
|
+
* selector-scoped `!important` rule placed after it, which wins on specificity
|
|
438
|
+
* (`[class*=…]`) or on source order (`pre, …` ties with `body *`).
|
|
439
|
+
*
|
|
440
|
+
* @param {{sans: string, mono: string, sizeOffset: number, sizeOffsetCode: number, weight: number, weightCode: number}} config - normalized config.
|
|
419
441
|
* @param {Record<string, string>} [baseTokens] - token name to untouched value.
|
|
420
442
|
* @returns {string} declarations for one `<style>` element ("" when dormant).
|
|
421
443
|
*/
|
|
@@ -426,6 +448,7 @@ function buildFontCss(config, baseTokens) {
|
|
|
426
448
|
var offset = normalized[SIZE_FIELD];
|
|
427
449
|
var codeOffset = normalized[CODE_SIZE_FIELD];
|
|
428
450
|
var weight = normalized[WEIGHT_FIELD];
|
|
451
|
+
var codeWeight = normalized[CODE_WEIGHT_FIELD];
|
|
429
452
|
if (isDormant(normalized)) return "";
|
|
430
453
|
var declarations = [];
|
|
431
454
|
|
|
@@ -464,9 +487,54 @@ function buildFontCss(config, baseTokens) {
|
|
|
464
487
|
// a static one rounds to its own nearest step by itself.
|
|
465
488
|
declarations.push(bodyAndDescendants("font-weight:" + weight + " !important"));
|
|
466
489
|
}
|
|
490
|
+
if (codeWeight !== WEIGHT_UNSET) {
|
|
491
|
+
declarations.push(CODE_SELECTOR + "{font-weight:" + codeWeight + " !important}");
|
|
492
|
+
} else if (weight !== WEIGHT_UNSET) {
|
|
493
|
+
// The body axis is a blanket `body, body *` rule, so code would inherit the
|
|
494
|
+
// body weight unless it is explicitly taken back out. `normal` is what DSH
|
|
495
|
+
// itself computes there (the code `font` shorthands carry no weight), so an
|
|
496
|
+
// unset code weight means "code stays exactly as DSH shipped it".
|
|
497
|
+
declarations.push(CODE_SELECTOR + "{font-weight:normal !important}");
|
|
498
|
+
}
|
|
467
499
|
return declarations.join("\n");
|
|
468
500
|
}
|
|
469
501
|
|
|
502
|
+
/**
|
|
503
|
+
* What counts as code text for the weight axis.
|
|
504
|
+
*
|
|
505
|
+
* There is no token to hook here (see `buildFontCss`), so the code axis has to
|
|
506
|
+
* name the elements. Two layers, both measured against rc.2:
|
|
507
|
+
*
|
|
508
|
+
* 1. The tags DSH's own stylesheets size with a code token: markdown `pre` /
|
|
509
|
+
* inline `code`, the tool card's `:where(pre)` block, form controls, and the
|
|
510
|
+
* CodeMirror editor. Their descendants are listed too, because the blanket
|
|
511
|
+
* body rule matches EVERY element — a `<span>` inside a highlighted block
|
|
512
|
+
* would otherwise be pulled back to the body weight.
|
|
513
|
+
* 2. Containers that only a class name identifies: the terminal and tool-code
|
|
514
|
+
* bodies are plain `div`s (`…_terminal`, `…_codeBody`, `md-code-block`).
|
|
515
|
+
*
|
|
516
|
+
* The `i` flag keeps a casing change in a future DSH from silently dropping the
|
|
517
|
+
* rule, and an unmatched token/class simply means that surface follows the body
|
|
518
|
+
* axis — the same degradation as an unknown token name on the size axes.
|
|
519
|
+
*/
|
|
520
|
+
var CODE_SELECTOR = [
|
|
521
|
+
"pre",
|
|
522
|
+
"code",
|
|
523
|
+
"kbd",
|
|
524
|
+
"samp",
|
|
525
|
+
"var",
|
|
526
|
+
"tt",
|
|
527
|
+
"textarea",
|
|
528
|
+
".cm-editor",
|
|
529
|
+
".dfp-previewCode",
|
|
530
|
+
'[class*="code" i]',
|
|
531
|
+
'[class*="terminal" i]',
|
|
532
|
+
]
|
|
533
|
+
.map(function (selector) {
|
|
534
|
+
return selector + "," + selector + " *";
|
|
535
|
+
})
|
|
536
|
+
.join(",");
|
|
537
|
+
|
|
470
538
|
/**
|
|
471
539
|
* Values a ratio may multiply: a number with a unit, a bare number, or an
|
|
472
540
|
* expression. A keyword (`unset`, `inherit`) or an unrecognized shape is left
|
|
@@ -810,6 +878,7 @@ var shared = {
|
|
|
810
878
|
SIZE_FIELD: SIZE_FIELD,
|
|
811
879
|
CODE_SIZE_FIELD: CODE_SIZE_FIELD,
|
|
812
880
|
WEIGHT_FIELD: WEIGHT_FIELD,
|
|
881
|
+
CODE_WEIGHT_FIELD: CODE_WEIGHT_FIELD,
|
|
813
882
|
SIZE_MIN: SIZE_MIN,
|
|
814
883
|
SIZE_MAX: SIZE_MAX,
|
|
815
884
|
WEIGHT_MIN: WEIGHT_MIN,
|
|
@@ -827,6 +896,9 @@ var shared = {
|
|
|
827
896
|
sanitizeFamily: sanitizeFamily,
|
|
828
897
|
quoteFamily: quoteFamily,
|
|
829
898
|
normalizeConfig: normalizeConfig,
|
|
899
|
+
clampOffset: clampOffset,
|
|
900
|
+
clampWeight: clampWeight,
|
|
901
|
+
CODE_SELECTOR: CODE_SELECTOR,
|
|
830
902
|
formatStack: formatStack,
|
|
831
903
|
parseStack: parseStack,
|
|
832
904
|
scaleFor: scaleFor,
|
|
@@ -891,6 +963,7 @@ var MONO_FIELD = shared.MONO_FIELD;
|
|
|
891
963
|
var SIZE_FIELD = shared.SIZE_FIELD;
|
|
892
964
|
var CODE_SIZE_FIELD = shared.CODE_SIZE_FIELD;
|
|
893
965
|
var WEIGHT_FIELD = shared.WEIGHT_FIELD;
|
|
966
|
+
var CODE_WEIGHT_FIELD = shared.CODE_WEIGHT_FIELD;
|
|
894
967
|
var SIZE_MIN = shared.SIZE_MIN;
|
|
895
968
|
var SIZE_MAX = shared.SIZE_MAX;
|
|
896
969
|
var WEIGHT_MIN = shared.WEIGHT_MIN;
|
|
@@ -940,7 +1013,7 @@ var DICTS = {
|
|
|
940
1013
|
en: {
|
|
941
1014
|
"card.title": "Font tune",
|
|
942
1015
|
"card.description":
|
|
943
|
-
"Body and code fonts, a size
|
|
1016
|
+
"Body and code fonts, a size and a weight for each, and a West/CJK split",
|
|
944
1017
|
"card.expand": "Expand",
|
|
945
1018
|
"card.collapse": "Collapse",
|
|
946
1019
|
"card.resetAll": "Reset all",
|
|
@@ -1000,8 +1073,12 @@ var DICTS = {
|
|
|
1000
1073
|
"Adds {offset} to code blocks and inline code only; the body offset does not reach them. 0 keeps DSH's sizes.",
|
|
1001
1074
|
"size.unit": "px",
|
|
1002
1075
|
|
|
1003
|
-
"weight.
|
|
1004
|
-
"weight.
|
|
1076
|
+
"weight.bodyLabel": "Body font weight",
|
|
1077
|
+
"weight.bodyHint":
|
|
1078
|
+
"Overrides the weight of text and interface copy, headings included. Code keeps its own weight. Default weight is 400.",
|
|
1079
|
+
"weight.codeLabel": "Code font weight",
|
|
1080
|
+
"weight.codeHint":
|
|
1081
|
+
"Overrides code blocks, inline code and terminal output only. 400 or unset keeps DSH's own weight and takes code out of the body weight.",
|
|
1005
1082
|
"weight.unset": "Unset",
|
|
1006
1083
|
|
|
1007
1084
|
"preview.label": "Preview",
|
|
@@ -1016,7 +1093,7 @@ var DICTS = {
|
|
|
1016
1093
|
},
|
|
1017
1094
|
zh: {
|
|
1018
1095
|
"card.title": "字体增强",
|
|
1019
|
-
"card.description": "
|
|
1096
|
+
"card.description": "正文与代码字体、各自的字号与字重、中西文分栏",
|
|
1020
1097
|
"card.expand": "展开",
|
|
1021
1098
|
"card.collapse": "收起",
|
|
1022
1099
|
"card.resetAll": "全部重置",
|
|
@@ -1074,8 +1151,12 @@ var DICTS = {
|
|
|
1074
1151
|
"只作用于代码块与行内代码,与正文字号互不影响;0 表示保持原样。",
|
|
1075
1152
|
"size.unit": "px",
|
|
1076
1153
|
|
|
1077
|
-
"weight.
|
|
1078
|
-
"weight.
|
|
1154
|
+
"weight.bodyLabel": "正文字重",
|
|
1155
|
+
"weight.bodyHint":
|
|
1156
|
+
"覆盖正文与界面文字的粗细(含标题);代码不受它影响。默认字重为400。",
|
|
1157
|
+
"weight.codeLabel": "代码字重",
|
|
1158
|
+
"weight.codeHint":
|
|
1159
|
+
"只覆盖代码块、行内代码与终端输出;400 或未设置表示保持 DSH 原样,也就是不被正文字重带着走。",
|
|
1079
1160
|
"weight.unset": "未设置",
|
|
1080
1161
|
|
|
1081
1162
|
"preview.label": "预览",
|
|
@@ -2272,6 +2353,7 @@ function FontCard(props) {
|
|
|
2272
2353
|
var offset = config[SIZE_FIELD];
|
|
2273
2354
|
var codeOffset = config[CODE_SIZE_FIELD];
|
|
2274
2355
|
var weight = config[WEIGHT_FIELD];
|
|
2356
|
+
var codeWeight = config[CODE_WEIGHT_FIELD];
|
|
2275
2357
|
var offsetText = offset > 0 ? "+" + offset : String(offset);
|
|
2276
2358
|
var codeOffsetText = codeOffset > 0 ? "+" + codeOffset : String(codeOffset);
|
|
2277
2359
|
|
|
@@ -2312,6 +2394,43 @@ function FontCard(props) {
|
|
|
2312
2394
|
);
|
|
2313
2395
|
};
|
|
2314
2396
|
|
|
2397
|
+
/**
|
|
2398
|
+
* One weight slider, under the family it reweights.
|
|
2399
|
+
* @param {object} props - field, label keys and current value.
|
|
2400
|
+
* @returns {object} the field shell wrapping the slider.
|
|
2401
|
+
*/
|
|
2402
|
+
var weightField = function (props) {
|
|
2403
|
+
return h(
|
|
2404
|
+
FieldShell,
|
|
2405
|
+
{
|
|
2406
|
+
t: t,
|
|
2407
|
+
label: t(props.labelKey),
|
|
2408
|
+
hint: t(props.hintKey),
|
|
2409
|
+
overridden: overridden(props.field) && props.value !== WEIGHT_UNSET,
|
|
2410
|
+
disabled: !writable,
|
|
2411
|
+
onReset: function () {
|
|
2412
|
+
resetField(props.field);
|
|
2413
|
+
},
|
|
2414
|
+
},
|
|
2415
|
+
h(NumberSlider, {
|
|
2416
|
+
min: WEIGHT_MIN,
|
|
2417
|
+
max: WEIGHT_MAX,
|
|
2418
|
+
value: props.value === WEIGHT_UNSET ? NEUTRAL_WEIGHT : props.value,
|
|
2419
|
+
disabled: !writable,
|
|
2420
|
+
label: t(props.labelKey),
|
|
2421
|
+
readout: props.value === WEIGHT_UNSET ? t("weight.unset") : String(props.value),
|
|
2422
|
+
minLabel: String(WEIGHT_MIN),
|
|
2423
|
+
maxLabel: String(WEIGHT_MAX),
|
|
2424
|
+
onChange: function (value) {
|
|
2425
|
+
// 400 is DSH's own body weight, so choosing it means "leave the axis
|
|
2426
|
+
// alone" rather than "write 400 on every element".
|
|
2427
|
+
if (value === NEUTRAL_WEIGHT) resetField(props.field);
|
|
2428
|
+
else setField(props.field, value);
|
|
2429
|
+
},
|
|
2430
|
+
})
|
|
2431
|
+
);
|
|
2432
|
+
};
|
|
2433
|
+
|
|
2315
2434
|
return h(
|
|
2316
2435
|
"li",
|
|
2317
2436
|
{ className: "dfp-card" + (open ? " dfp-cardOpen" : "") },
|
|
@@ -2427,6 +2546,13 @@ function FontCard(props) {
|
|
|
2427
2546
|
text: offsetText,
|
|
2428
2547
|
}),
|
|
2429
2548
|
|
|
2549
|
+
weightField({
|
|
2550
|
+
field: WEIGHT_FIELD,
|
|
2551
|
+
labelKey: "weight.bodyLabel",
|
|
2552
|
+
hintKey: "weight.bodyHint",
|
|
2553
|
+
value: weight,
|
|
2554
|
+
}),
|
|
2555
|
+
|
|
2430
2556
|
view === "simple"
|
|
2431
2557
|
? h(SimpleFamilyField, {
|
|
2432
2558
|
t: t,
|
|
@@ -2476,35 +2602,12 @@ function FontCard(props) {
|
|
|
2476
2602
|
text: codeOffsetText,
|
|
2477
2603
|
}),
|
|
2478
2604
|
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
overridden: overridden(WEIGHT_FIELD) && weight !== WEIGHT_UNSET,
|
|
2486
|
-
disabled: !writable,
|
|
2487
|
-
onReset: function () {
|
|
2488
|
-
resetField(WEIGHT_FIELD);
|
|
2489
|
-
},
|
|
2490
|
-
},
|
|
2491
|
-
h(NumberSlider, {
|
|
2492
|
-
min: WEIGHT_MIN,
|
|
2493
|
-
max: WEIGHT_MAX,
|
|
2494
|
-
value: weight === WEIGHT_UNSET ? NEUTRAL_WEIGHT : weight,
|
|
2495
|
-
disabled: !writable,
|
|
2496
|
-
label: t("weight.label"),
|
|
2497
|
-
readout: weight === WEIGHT_UNSET ? t("weight.unset") : String(weight),
|
|
2498
|
-
minLabel: String(WEIGHT_MIN),
|
|
2499
|
-
maxLabel: String(WEIGHT_MAX),
|
|
2500
|
-
onChange: function (value) {
|
|
2501
|
-
// 400 is DSH's own body weight, so choosing it means "leave the
|
|
2502
|
-
// axis alone" rather than "write 400 on every element".
|
|
2503
|
-
if (value === NEUTRAL_WEIGHT) resetField(WEIGHT_FIELD);
|
|
2504
|
-
else setField(WEIGHT_FIELD, value);
|
|
2505
|
-
},
|
|
2506
|
-
})
|
|
2507
|
-
),
|
|
2605
|
+
weightField({
|
|
2606
|
+
field: CODE_WEIGHT_FIELD,
|
|
2607
|
+
labelKey: "weight.codeLabel",
|
|
2608
|
+
hintKey: "weight.codeHint",
|
|
2609
|
+
value: codeWeight,
|
|
2610
|
+
}),
|
|
2508
2611
|
|
|
2509
2612
|
h(
|
|
2510
2613
|
"div",
|
|
@@ -2537,7 +2640,7 @@ function FontCard(props) {
|
|
|
2537
2640
|
h(
|
|
2538
2641
|
"div",
|
|
2539
2642
|
{
|
|
2540
|
-
className: "dfp-previewText",
|
|
2643
|
+
className: "dfp-previewText dfp-previewCode",
|
|
2541
2644
|
style:
|
|
2542
2645
|
config[MONO_FIELD] === ""
|
|
2543
2646
|
? undefined
|
|
@@ -2563,6 +2666,7 @@ function FontCard(props) {
|
|
|
2563
2666
|
resetField(SIZE_FIELD);
|
|
2564
2667
|
resetField(CODE_SIZE_FIELD);
|
|
2565
2668
|
resetField(WEIGHT_FIELD);
|
|
2669
|
+
resetField(CODE_WEIGHT_FIELD);
|
|
2566
2670
|
},
|
|
2567
2671
|
},
|
|
2568
2672
|
t("card.resetAll")
|
package/lib/index.js
CHANGED
|
@@ -23,6 +23,7 @@ import shared from "./shared.cjs";
|
|
|
23
23
|
const {
|
|
24
24
|
buildFontCss,
|
|
25
25
|
CODE_SIZE_FIELD,
|
|
26
|
+
CODE_WEIGHT_FIELD,
|
|
26
27
|
FALLBACK_TOKENS,
|
|
27
28
|
MONO_FIELD,
|
|
28
29
|
NAMESPACE,
|
|
@@ -53,8 +54,9 @@ const MAX_STACK = 200;
|
|
|
53
54
|
*
|
|
54
55
|
* Every field defaults to "leave DSH alone": an empty stack injects no family
|
|
55
56
|
* rule, a zero offset injects no size rule on either axis, and a zero weight
|
|
56
|
-
* injects no weight rule
|
|
57
|
-
* the
|
|
57
|
+
* injects no weight rule (an unset CODE weight still writes the rule that keeps
|
|
58
|
+
* code out of the body weight). Installing the plugin therefore changes nothing
|
|
59
|
+
* until the user asks for something.
|
|
58
60
|
*/
|
|
59
61
|
export const Config = z.object({
|
|
60
62
|
[SANS_FIELD]: z
|
|
@@ -91,7 +93,15 @@ export const Config = z.object({
|
|
|
91
93
|
.max(WEIGHT_MAX)
|
|
92
94
|
.default(WEIGHT_UNSET)
|
|
93
95
|
.description(
|
|
94
|
-
`
|
|
96
|
+
`Body/UI font weight (${WEIGHT_MIN}..${WEIGHT_MAX}, ${WEIGHT_UNSET} keeps DSH's own weights; code is not affected)`
|
|
97
|
+
),
|
|
98
|
+
[CODE_WEIGHT_FIELD]: z
|
|
99
|
+
.number()
|
|
100
|
+
.min(WEIGHT_UNSET)
|
|
101
|
+
.max(WEIGHT_MAX)
|
|
102
|
+
.default(WEIGHT_UNSET)
|
|
103
|
+
.description(
|
|
104
|
+
`Code font weight (${WEIGHT_MIN}..${WEIGHT_MAX}, ${WEIGHT_UNSET} keeps DSH's own weights; independent of the body weight)`
|
|
95
105
|
),
|
|
96
106
|
});
|
|
97
107
|
|
package/lib/shared.cjs
CHANGED
|
@@ -29,9 +29,12 @@ var SIZE_FIELD = "sizeOffset";
|
|
|
29
29
|
/** Field carrying the code font-size offset in px (0 = leave DSH alone). */
|
|
30
30
|
var CODE_SIZE_FIELD = "sizeOffsetCode";
|
|
31
31
|
|
|
32
|
-
/** Field carrying the
|
|
32
|
+
/** Field carrying the body/UI font weight (0 = leave DSH alone). */
|
|
33
33
|
var WEIGHT_FIELD = "weight";
|
|
34
34
|
|
|
35
|
+
/** Field carrying the code font weight (0 = leave DSH alone). */
|
|
36
|
+
var CODE_WEIGHT_FIELD = "weightCode";
|
|
37
|
+
|
|
35
38
|
/** Allowed font-size offset range. The upper bound stays under a 2x scale. */
|
|
36
39
|
var SIZE_MIN = -3;
|
|
37
40
|
var SIZE_MAX = 6;
|
|
@@ -57,6 +60,7 @@ var DEFAULTS = {
|
|
|
57
60
|
sizeOffset: 0,
|
|
58
61
|
sizeOffsetCode: 0,
|
|
59
62
|
weight: WEIGHT_UNSET,
|
|
63
|
+
weightCode: WEIGHT_UNSET,
|
|
60
64
|
};
|
|
61
65
|
|
|
62
66
|
/**
|
|
@@ -147,18 +151,15 @@ function normalizeConfig(value) {
|
|
|
147
151
|
var source = value !== null && typeof value === "object" ? value : {};
|
|
148
152
|
var size = clampOffset(source[SIZE_FIELD]);
|
|
149
153
|
var codeSize = clampOffset(source[CODE_SIZE_FIELD]);
|
|
150
|
-
var weight =
|
|
151
|
-
|
|
152
|
-
weight = Math.round(weight);
|
|
153
|
-
if (weight !== WEIGHT_UNSET) {
|
|
154
|
-
weight = Math.min(WEIGHT_MAX, Math.max(WEIGHT_MIN, weight));
|
|
155
|
-
}
|
|
154
|
+
var weight = clampWeight(source[WEIGHT_FIELD]);
|
|
155
|
+
var codeWeight = clampWeight(source[CODE_WEIGHT_FIELD]);
|
|
156
156
|
var config = {};
|
|
157
157
|
config[SANS_FIELD] = sanitize(source[SANS_FIELD]).slice(0, MAX_STACK_LENGTH);
|
|
158
158
|
config[MONO_FIELD] = sanitize(source[MONO_FIELD]).slice(0, MAX_STACK_LENGTH);
|
|
159
159
|
config[SIZE_FIELD] = size;
|
|
160
160
|
config[CODE_SIZE_FIELD] = codeSize;
|
|
161
161
|
config[WEIGHT_FIELD] = weight;
|
|
162
|
+
config[CODE_WEIGHT_FIELD] = codeWeight;
|
|
162
163
|
return config;
|
|
163
164
|
}
|
|
164
165
|
|
|
@@ -173,6 +174,19 @@ function clampOffset(value) {
|
|
|
173
174
|
return Math.round(Math.min(SIZE_MAX, Math.max(SIZE_MIN, size)));
|
|
174
175
|
}
|
|
175
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Clamp one weight to the allowed range, keeping 0 as "do not touch".
|
|
179
|
+
* @param {unknown} value - candidate weight.
|
|
180
|
+
* @returns {number} the weight the stylesheet may use.
|
|
181
|
+
*/
|
|
182
|
+
function clampWeight(value) {
|
|
183
|
+
var weight = Number(value);
|
|
184
|
+
if (!isFinite(weight)) return WEIGHT_UNSET;
|
|
185
|
+
weight = Math.round(weight);
|
|
186
|
+
if (weight === WEIGHT_UNSET) return WEIGHT_UNSET;
|
|
187
|
+
return Math.min(WEIGHT_MAX, Math.max(WEIGHT_MIN, weight));
|
|
188
|
+
}
|
|
189
|
+
|
|
176
190
|
/**
|
|
177
191
|
* Format a family list as a CSS font-family value.
|
|
178
192
|
* @param {readonly string[]} families - family names in precedence order.
|
|
@@ -376,7 +390,8 @@ function isDormant(config) {
|
|
|
376
390
|
config[MONO_FIELD] === "" &&
|
|
377
391
|
config[SIZE_FIELD] === 0 &&
|
|
378
392
|
config[CODE_SIZE_FIELD] === 0 &&
|
|
379
|
-
config[WEIGHT_FIELD] === WEIGHT_UNSET
|
|
393
|
+
config[WEIGHT_FIELD] === WEIGHT_UNSET &&
|
|
394
|
+
config[CODE_WEIGHT_FIELD] === WEIGHT_UNSET
|
|
380
395
|
);
|
|
381
396
|
}
|
|
382
397
|
|
|
@@ -406,7 +421,14 @@ function isDormant(config) {
|
|
|
406
421
|
* what the shipped stylesheets use), which is why those are re-declared too,
|
|
407
422
|
* not just their `-font-size` / `-line-height` parts.
|
|
408
423
|
*
|
|
409
|
-
*
|
|
424
|
+
* Weight has no token chain to ride: no shipped rule reads a `-font-weight`
|
|
425
|
+
* token (measured — zero `font-weight: var(--dsw-font-…)` in rc.2), the theme
|
|
426
|
+
* writes literal weights on its own class rules, and that is exactly why the
|
|
427
|
+
* body axis has to be a blanket `!important` rule. The code axis is therefore a
|
|
428
|
+
* selector-scoped `!important` rule placed after it, which wins on specificity
|
|
429
|
+
* (`[class*=…]`) or on source order (`pre, …` ties with `body *`).
|
|
430
|
+
*
|
|
431
|
+
* @param {{sans: string, mono: string, sizeOffset: number, sizeOffsetCode: number, weight: number, weightCode: number}} config - normalized config.
|
|
410
432
|
* @param {Record<string, string>} [baseTokens] - token name to untouched value.
|
|
411
433
|
* @returns {string} declarations for one `<style>` element ("" when dormant).
|
|
412
434
|
*/
|
|
@@ -417,6 +439,7 @@ function buildFontCss(config, baseTokens) {
|
|
|
417
439
|
var offset = normalized[SIZE_FIELD];
|
|
418
440
|
var codeOffset = normalized[CODE_SIZE_FIELD];
|
|
419
441
|
var weight = normalized[WEIGHT_FIELD];
|
|
442
|
+
var codeWeight = normalized[CODE_WEIGHT_FIELD];
|
|
420
443
|
if (isDormant(normalized)) return "";
|
|
421
444
|
var declarations = [];
|
|
422
445
|
|
|
@@ -455,9 +478,54 @@ function buildFontCss(config, baseTokens) {
|
|
|
455
478
|
// a static one rounds to its own nearest step by itself.
|
|
456
479
|
declarations.push(bodyAndDescendants("font-weight:" + weight + " !important"));
|
|
457
480
|
}
|
|
481
|
+
if (codeWeight !== WEIGHT_UNSET) {
|
|
482
|
+
declarations.push(CODE_SELECTOR + "{font-weight:" + codeWeight + " !important}");
|
|
483
|
+
} else if (weight !== WEIGHT_UNSET) {
|
|
484
|
+
// The body axis is a blanket `body, body *` rule, so code would inherit the
|
|
485
|
+
// body weight unless it is explicitly taken back out. `normal` is what DSH
|
|
486
|
+
// itself computes there (the code `font` shorthands carry no weight), so an
|
|
487
|
+
// unset code weight means "code stays exactly as DSH shipped it".
|
|
488
|
+
declarations.push(CODE_SELECTOR + "{font-weight:normal !important}");
|
|
489
|
+
}
|
|
458
490
|
return declarations.join("\n");
|
|
459
491
|
}
|
|
460
492
|
|
|
493
|
+
/**
|
|
494
|
+
* What counts as code text for the weight axis.
|
|
495
|
+
*
|
|
496
|
+
* There is no token to hook here (see `buildFontCss`), so the code axis has to
|
|
497
|
+
* name the elements. Two layers, both measured against rc.2:
|
|
498
|
+
*
|
|
499
|
+
* 1. The tags DSH's own stylesheets size with a code token: markdown `pre` /
|
|
500
|
+
* inline `code`, the tool card's `:where(pre)` block, form controls, and the
|
|
501
|
+
* CodeMirror editor. Their descendants are listed too, because the blanket
|
|
502
|
+
* body rule matches EVERY element — a `<span>` inside a highlighted block
|
|
503
|
+
* would otherwise be pulled back to the body weight.
|
|
504
|
+
* 2. Containers that only a class name identifies: the terminal and tool-code
|
|
505
|
+
* bodies are plain `div`s (`…_terminal`, `…_codeBody`, `md-code-block`).
|
|
506
|
+
*
|
|
507
|
+
* The `i` flag keeps a casing change in a future DSH from silently dropping the
|
|
508
|
+
* rule, and an unmatched token/class simply means that surface follows the body
|
|
509
|
+
* axis — the same degradation as an unknown token name on the size axes.
|
|
510
|
+
*/
|
|
511
|
+
var CODE_SELECTOR = [
|
|
512
|
+
"pre",
|
|
513
|
+
"code",
|
|
514
|
+
"kbd",
|
|
515
|
+
"samp",
|
|
516
|
+
"var",
|
|
517
|
+
"tt",
|
|
518
|
+
"textarea",
|
|
519
|
+
".cm-editor",
|
|
520
|
+
".dfp-previewCode",
|
|
521
|
+
'[class*="code" i]',
|
|
522
|
+
'[class*="terminal" i]',
|
|
523
|
+
]
|
|
524
|
+
.map(function (selector) {
|
|
525
|
+
return selector + "," + selector + " *";
|
|
526
|
+
})
|
|
527
|
+
.join(",");
|
|
528
|
+
|
|
461
529
|
/**
|
|
462
530
|
* Values a ratio may multiply: a number with a unit, a bare number, or an
|
|
463
531
|
* expression. A keyword (`unset`, `inherit`) or an unrecognized shape is left
|
|
@@ -801,6 +869,7 @@ var shared = {
|
|
|
801
869
|
SIZE_FIELD: SIZE_FIELD,
|
|
802
870
|
CODE_SIZE_FIELD: CODE_SIZE_FIELD,
|
|
803
871
|
WEIGHT_FIELD: WEIGHT_FIELD,
|
|
872
|
+
CODE_WEIGHT_FIELD: CODE_WEIGHT_FIELD,
|
|
804
873
|
SIZE_MIN: SIZE_MIN,
|
|
805
874
|
SIZE_MAX: SIZE_MAX,
|
|
806
875
|
WEIGHT_MIN: WEIGHT_MIN,
|
|
@@ -818,6 +887,9 @@ var shared = {
|
|
|
818
887
|
sanitizeFamily: sanitizeFamily,
|
|
819
888
|
quoteFamily: quoteFamily,
|
|
820
889
|
normalizeConfig: normalizeConfig,
|
|
890
|
+
clampOffset: clampOffset,
|
|
891
|
+
clampWeight: clampWeight,
|
|
892
|
+
CODE_SELECTOR: CODE_SELECTOR,
|
|
821
893
|
formatStack: formatStack,
|
|
822
894
|
parseStack: parseStack,
|
|
823
895
|
scaleFor: scaleFor,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-fonttune",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Font plugin for the DeepSeek Harness Web GUI: body and code font families, a separate font
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Font plugin for the DeepSeek Harness Web GUI: body and code font families, a separate font size and weight for each, and a West/CJK split picker.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|