@nonamelego/dsh-catppuccin 0.6.7 → 0.7.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/README.en.md CHANGED
@@ -224,9 +224,14 @@ installing, launch `dsh --profile dsh-tui` and pick the theme with `/theme` —
224
224
  2. Open **Settings** and pick **Catppuccin** in the left nav (its own section, after the official ones).
225
225
  3. Under **Theme**, pick a flavour:
226
226
  **Latte** (light), **Frappé**, **Macchiato** or **Mocha** (dark).
227
- 4. Choosing **Follow system** reverts to the official theme — it restores the preference
227
+ 4. Turn on **Follow system light/dark**: Latte on light, your chosen flavour (Mocha by default)
228
+ on dark, switching with the Windows light/dark setting — the native title bar and window
229
+ buttons follow too. The dark end is picked separately (Frappé / Macchiato / Mocha).
230
+ 5. Choosing **Turn off (official theme)** reverts to the official theme — it restores the preference
228
231
  you had before enabling Catppuccin (light / dark / follow system) instead of forcing a reset.
229
232
 
233
+ > "Follow system" used to name step 5; since 0.7.0 the two are separate controls, as above.
234
+
230
235
  > **Second entrance**: open this plugin's own card on the **Plugins** page and the middle of
231
236
  > its detail page shows the **same settings** (Catppuccin theme / Glass / Check for updates /
232
237
  > Feedback & support) — both read and write one set of preferences, so either place works.
package/README.md CHANGED
@@ -197,9 +197,14 @@ dsh plugin --profile dsh-tui add https://github.com/NoNameLeGo/dsh-catppuccin-th
197
197
  2. 打开 **设置**,在左侧导航里点 **Catppuccin**(官方各节之后的独立分区)。
198
198
  3. 在 **主题** 区域选择风味:
199
199
  **Latte**(浅色)、**Frappé**、**Macchiato** 或 **Mocha**(深色)。
200
- 4. 选择 **跟随系统** 则回退到官方主题——会还原你启用 Catppuccin 之前
200
+ 4. 打开 **跟随系统深色/浅色**:浅色时用 **Latte**、深色时用你选的风味(默认 **Mocha**),
201
+ 随 Windows 的深浅色设置自动切换——原生标题栏和窗口按钮也会一起变。
202
+ 深色端可单独选 Frappé / Macchiato / Mocha。
203
+ 5. 选择 **关闭(官方主题)** 则回退到官方主题——会还原你启用 Catppuccin 之前
201
204
  的官方偏好(浅色 / 深色 / 跟随系统),而不是强制重置。
202
205
 
206
+ > 「跟随系统」一词以前指第 5 步的「关闭」,0.7.0 起两个功能分开命名,见上。
207
+
203
208
  > **另一处入口**:在 **插件页**(Plugins)点开本插件自己的卡片,中间会出现**同一组设置**
204
209
  > (Catppuccin 主题 / 玻璃质感 / 检查更新 / 反馈与支持)——两处读写的是同一份偏好,改哪边都一样。
205
210
  > 该区域由宿主(≥ `0.2.0-rc.2` 的插件详情页)提供,更旧的版本上没有。
@@ -340,11 +345,14 @@ console.table({ backdropFilter: cs.backdropFilter, background: cs.backgroundColo
340
345
  | DSH | `>=0.1.7-rc.1`(设置页消费官方 `dsh-client-ui-primitives` 的 `SegmentedControl`,该导出自 `0.1.7-alpha.1` 起才有;旧的 `settingsScope` 通道代码保留,但 0.1.5 / 0.1.6 宿主不再声明支持) |
341
346
  | Node.js | `>=20` |
342
347
  | Profile | `web`(Web GUI 与两个桌面壳都启动 web 界面,共用本插件);桌面端默认 profile 名为 `desktop`(已声明) |
343
- | 已验证的具体版本 | `0.2.1-rc.2`:官方桌面壳真机验收——插件正常启动、token 逐项生效、玻璃配方完整,**改设置真写回 `cordis.patch.yml`(修复前不写)**、重启后从文档采纳回来([审计](docs/desktop-0.2.1-adaptation-audit.md));`0.2.0-rc.2`:官方桌面壳自带运行时的启动级 e2e(19/19)、真机桌面窗口像素与标题栏取色链路、`configForms` 落盘([审计](docs/desktop-0.2.0-adaptation-audit.md));`0.1.7-rc.1`:真实 profile 上完成安装、启动、改设置落盘与重启恢复([证据](docs/issue-15-settings-seam-0.1.7.md));`0.1.7-rc.2`:启动级 e2e 与玻璃层的真页采样(issue #16 / #17);`0.1.5-rc.1`:按 CI 口径复跑的启动级 e2e(**历史记录**,已低于当前兼容下限) |
344
-
345
- `package.json` 的 `dsh.compatibility`(`dsh` / `dshReleases` / `dshOperations`)**只声明当前支持的三条**:
346
- `0.1.7-rc.1` / `0.2.0-rc.2` / `0.2.1-rc.2`(兼容下限 `>=0.1.7-rc.1`);更早的 `0.1.5-rc.*`
347
- 与 `0.1.7-alpha.*` 是**当时**的验证记录,不在声明内。
348
+ | 已验证的具体版本 | `0.2.1-rc.5`:官方桌面壳真机验收——启动正常、token 逐项生效、玻璃配方完整(顶栏 / 输入卡 / dock / 菜单 / 设置壳逐面实测),`--dsw-*` 全表与前端构建产物**逐字节不变**([审计](docs/issue-0.2.1-rc.5-adaptation-audit.md));`0.2.1-rc.3`:三个新 More 菜单自动继承玻璃、视图标签行与 `-95/107` 滚动补偿不冲突([审计](docs/issue-0.2.1-rc.3-adaptation-audit.md));`0.2.1-rc.2`:官方桌面壳真机验收——插件正常启动、token 逐项生效、玻璃配方完整,**改设置真写回 `cordis.patch.yml`(修复前不写)**、重启后从文档采纳回来([审计](docs/desktop-0.2.1-adaptation-audit.md));`0.2.0-rc.2`:官方桌面壳自带运行时的启动级 e2e(19/19)、真机桌面窗口像素与标题栏取色链路、`configForms` 落盘([审计](docs/desktop-0.2.0-adaptation-audit.md));`0.1.7-rc.1`:真实 profile 上完成安装、启动、改设置落盘与重启恢复([证据](docs/issue-15-settings-seam-0.1.7.md));`0.1.7-rc.2`:启动级 e2e 与玻璃层的真页采样(issue #16 / #17);`0.1.5-rc.1`:按 CI 口径复跑的启动级 e2e(**历史记录**,已低于当前兼容下限) |
349
+
350
+ `package.json` 的 `dsh.compatibility`(`dsh` / `dshReleases` / `dshOperations`)声明清单以文件为准,
351
+ 当前是 `0.1.7-rc.1` / `0.2.0-rc.2` / `0.2.1-rc.2` / `0.2.1-rc.3` / `0.2.1-rc.5`(兼容下限 `>=0.1.7-rc.1`);
352
+ 更早的 `0.1.5-rc.*` 与 `0.1.7-alpha.*` 是**当时**的验证记录,不在声明内。
353
+ ⚠️ 商铺按「上游最新三版」窗口判定(`latest` / `next` / `alpha` 里版本号最高的那个往下数三版),
354
+ **窗口内至少命中一条**才不会显示「兼容未声明」——所以上游每发一版都要跟,见
355
+ `docs/issue-0.2.1-rc.5-adaptation-audit.md` §6.1。
348
356
 
349
357
  色彩覆盖以 `dsh-v0.2.0-rc.2` 的 `design-platform.css` 为基线:每方案 190 个 `--dsw-*` token(static 77 /
350
358
  alias 101 / specific 11 / 非三族 1)全覆盖,含 0.2.0 新增的 17 个 alias。
package/lib/client.js CHANGED
@@ -52,7 +52,7 @@ window.__ModuleLoader__.load({
52
52
  }
53
53
  //#endregion
54
54
  //#region \0dsh-css:/home/runner/work/dsh-catppuccin-theme/dsh-catppuccin-theme/src/client/CatppuccinRow.module.css.mjs
55
- const css$2 = ".AfSEaq_cubes{flex-wrap:wrap;gap:8px;display:flex}.AfSEaq_cube{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-xl);color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;flex-direction:column;flex:118px;justify-content:center;align-items:flex-start;gap:2px;padding:12px 14px;font-size:13px;line-height:20px;display:flex}.AfSEaq_cube:hover:not(.AfSEaq_selected){background:var(--dsw-alias-interactive-bg-hover)}.AfSEaq_cube:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.AfSEaq_selected{background:var(--dsw-alias-bg-module-platform);border-color:var(--dsw-static-neutral-bluish-400)}.AfSEaq_cubeHead{align-items:center;gap:6px;display:inline-flex}.AfSEaq_swatch{border-radius:3px;flex:none;width:12px;height:12px}.AfSEaq_subtitle{color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:14px}.AfSEaq_shikiRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.AfSEaq_shikiLabel{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.AfSEaq_codePreview{flex-direction:column;gap:6px;margin-top:2px;display:flex}.AfSEaq_codeSample{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-markdown-code-block,var(--dsw-alias-bg-layer-2));color:var(--shiki-foreground,var(--dsw-alias-label-primary));white-space:pre;margin:0;padding:8px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;line-height:18px;overflow:auto}.AfSEaq_tokKeyword{color:var(--shiki-token-keyword,var(--dsw-static-blue-500))}.AfSEaq_tokFunction{color:var(--shiki-token-function,var(--dsw-static-amber-500))}.AfSEaq_tokParameter{color:var(--shiki-token-parameter,var(--dsw-alias-label-primary))}.AfSEaq_tokString{color:var(--shiki-token-string,var(--dsw-static-green-500))}.AfSEaq_tokPunct{color:var(--shiki-token-punctuation,var(--dsw-alias-label-secondary))}.AfSEaq_tokComment{color:var(--shiki-token-comment,var(--dsw-alias-label-tertiary))}.AfSEaq_overrides{flex-direction:column;gap:6px;display:flex}.AfSEaq_overrideRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.AfSEaq_overrideInput{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm);height:28px;color:var(--dsw-alias-label-primary);font:inherit;background:0 0;flex:200px;padding:0 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px}.AfSEaq_overrideInput:focus-visible{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary) 35%, transparent);outline:none}.AfSEaq_overrideValue{flex:140px}.AfSEaq_hint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.AfSEaq_selfStart{align-self:flex-start}";
55
+ const css$2 = ".AfSEaq_cubes{flex-wrap:wrap;gap:8px;display:flex}.AfSEaq_cube{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-xl);color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;flex-direction:column;flex:118px;justify-content:center;align-items:flex-start;gap:2px;padding:12px 14px;font-size:13px;line-height:20px;display:flex}.AfSEaq_cube:hover:not(.AfSEaq_selected){background:var(--dsw-alias-interactive-bg-hover)}.AfSEaq_cube:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.AfSEaq_selected{background:var(--dsw-alias-bg-module-platform);border-color:var(--dsw-static-neutral-bluish-400)}.AfSEaq_cubeHead{align-items:center;gap:6px;display:inline-flex}.AfSEaq_swatch{border-radius:3px;flex:none;width:12px;height:12px}.AfSEaq_subtitle{color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:14px}.AfSEaq_shikiRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.AfSEaq_followRow{flex-direction:column;gap:6px;display:flex}.AfSEaq_followHead{align-items:center;gap:10px;display:flex}.AfSEaq_followLabel{color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}.AfSEaq_shikiLabel{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.AfSEaq_codePreview{flex-direction:column;gap:6px;margin-top:2px;display:flex}.AfSEaq_codeSample{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-markdown-code-block,var(--dsw-alias-bg-layer-2));color:var(--shiki-foreground,var(--dsw-alias-label-primary));white-space:pre;margin:0;padding:8px 10px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;line-height:18px;overflow:auto}.AfSEaq_tokKeyword{color:var(--shiki-token-keyword,var(--dsw-static-blue-500))}.AfSEaq_tokFunction{color:var(--shiki-token-function,var(--dsw-static-amber-500))}.AfSEaq_tokParameter{color:var(--shiki-token-parameter,var(--dsw-alias-label-primary))}.AfSEaq_tokString{color:var(--shiki-token-string,var(--dsw-static-green-500))}.AfSEaq_tokPunct{color:var(--shiki-token-punctuation,var(--dsw-alias-label-secondary))}.AfSEaq_tokComment{color:var(--shiki-token-comment,var(--dsw-alias-label-tertiary))}.AfSEaq_overrides{flex-direction:column;gap:6px;display:flex}.AfSEaq_overrideRow{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.AfSEaq_overrideInput{border:.5px solid var(--dsw-alias-border-l3);border-radius:var(--dsw-radius-sm);height:28px;color:var(--dsw-alias-label-primary);font:inherit;background:0 0;flex:200px;padding:0 8px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px}.AfSEaq_overrideInput:focus-visible{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-state-business-primary) 35%, transparent);outline:none}.AfSEaq_overrideValue{flex:140px}.AfSEaq_hint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.AfSEaq_selfStart{align-self:flex-start}";
56
56
  const tagId$2 = "@nonamelego/dsh-catppuccin/CatppuccinRow.module.css";
57
57
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
58
58
  const tag = document.createElement("style");
@@ -67,6 +67,9 @@ window.__ModuleLoader__.load({
67
67
  "cube": "AfSEaq_cube",
68
68
  "cubeHead": "AfSEaq_cubeHead",
69
69
  "cubes": "AfSEaq_cubes",
70
+ "followHead": "AfSEaq_followHead",
71
+ "followLabel": "AfSEaq_followLabel",
72
+ "followRow": "AfSEaq_followRow",
70
73
  "hint": "AfSEaq_hint",
71
74
  "overrideInput": "AfSEaq_overrideInput",
72
75
  "overrideRow": "AfSEaq_overrideRow",
@@ -89,9 +92,11 @@ window.__ModuleLoader__.load({
89
92
  //#region src/client/CatppuccinRow.tsx
90
93
  /**
91
94
  * Catppuccin flavour row — the first row of the plugin's own settings page
92
- * (issue #27) and of the plugin detail card. It lists the four flavour themes
93
- * plus a "follow system" (off) choice. Selecting a flavour calls the injected
94
- * `select`, which switches the official ThemeRuntime and persists the choice.
95
+ * (issue #27) and of the plugin detail card. It lists the four flavour themes,
96
+ * a "follow the OS light/dark scheme" switch (issue #36 — NOT the same thing as
97
+ * the "off" cube, which hands the UI back to the official theme) and the
98
+ * "off" cube itself. Selecting a flavour calls the injected `select`, which
99
+ * switches the official ThemeRuntime and persists the choice.
95
100
  * The row subscribes to `theme/change` so the highlighted flavour tracks the
96
101
  * live preference.
97
102
  *
@@ -126,8 +131,10 @@ window.__ModuleLoader__.load({
126
131
  * @param props - composed slot props.
127
132
  * @returns the row element tree.
128
133
  */
129
- function CatppuccinRow({ t, themes, current, subscribe, select, overrides, setOverrides, shikiStyle, setShikiStyle, subscribePrefs }) {
134
+ function CatppuccinRow({ t, themes, current, subscribe, select, followAvailable, followSystem, setFollowSystem, followDark, setFollowDark, overrides, setOverrides, shikiStyle, setShikiStyle, subscribePrefs }) {
130
135
  const choice = (0, react.useSyncExternalStore)(subscribe, current);
136
+ const following = (0, react.useSyncExternalStore)(subscribePrefs, followSystem);
137
+ const darkEnd = (0, react.useSyncExternalStore)(subscribePrefs, followDark);
131
138
  const overrideMap = (0, react.useSyncExternalStore)(subscribePrefs, overrides);
132
139
  const style = (0, react.useSyncExternalStore)(subscribePrefs, shikiStyle);
133
140
  const [overridesOpen, setOverridesOpen] = (0, react.useState)(false);
@@ -250,6 +257,47 @@ window.__ModuleLoader__.load({
250
257
  })
251
258
  }, "off")]
252
259
  }),
260
+ followAvailable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
261
+ className: CatppuccinRow_module_css_default.followRow,
262
+ "data-catppuccin-follow": "",
263
+ children: [
264
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
265
+ className: CatppuccinRow_module_css_default.followHead,
266
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {
267
+ checked: following,
268
+ onChange: (next) => {
269
+ setFollowSystem(next);
270
+ },
271
+ label: t("row.follow")
272
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
273
+ className: CatppuccinRow_module_css_default.followLabel,
274
+ children: t("row.follow")
275
+ })]
276
+ }),
277
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
278
+ className: CatppuccinRow_module_css_default.hint,
279
+ children: t("row.followHint")
280
+ }),
281
+ following && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
282
+ className: CatppuccinRow_module_css_default.shikiRow,
283
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
284
+ className: CatppuccinRow_module_css_default.shikiLabel,
285
+ children: t("row.followDark")
286
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedControl, {
287
+ id: "catppuccin-follow-dark",
288
+ label: t("row.followDark"),
289
+ value: darkEnd,
290
+ options: themes.filter((flavor) => flavor.id !== "catppuccin-latte").map((flavor) => ({
291
+ value: flavor.id,
292
+ label: flavor.label
293
+ })),
294
+ onChange: (next) => {
295
+ setFollowDark(next);
296
+ }
297
+ })]
298
+ })
299
+ ]
300
+ }),
253
301
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
254
302
  className: CatppuccinRow_module_css_default.shikiRow,
255
303
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
@@ -577,6 +625,21 @@ window.__ModuleLoader__.load({
577
625
  "catppuccin-macchiato",
578
626
  "catppuccin-mocha"
579
627
  ];
628
+ /**
629
+ * The LIGHT end of "follow the OS" (issue #36). Latte is the only light
630
+ * flavour Catppuccin ships, so the light half is a constant instead of a
631
+ * setting — a picker here would offer exactly one real option.
632
+ */
633
+ const FOLLOW_LIGHT_FLAVOR = "catppuccin-latte";
634
+ /** The flavours the follow mode may use for its DARK end. Only the three dark
635
+ * flavours: Latte here would paint a light palette into the dark half. */
636
+ const FOLLOW_DARK_FLAVORS = [
637
+ "catppuccin-frappe",
638
+ "catppuccin-macchiato",
639
+ "catppuccin-mocha"
640
+ ];
641
+ /** Shipped follow-mode dark end: Mocha, Catppuccin's most common dark pick. */
642
+ const DEFAULT_FOLLOW_DARK = "catppuccin-mocha";
580
643
  /** Shipped glass defaults — the single source of truth; the client glass layer
581
644
  * (`src/client/glass/glass-layer.ts`) derives its knob defaults from here. */
582
645
  const DEFAULT_GLASS = {
@@ -599,6 +662,8 @@ window.__ModuleLoader__.load({
599
662
  return {
600
663
  version: 1,
601
664
  flavor: "off",
665
+ followSystem: false,
666
+ followDark: DEFAULT_FOLLOW_DARK,
602
667
  glass: { ...DEFAULT_GLASS },
603
668
  autoCheck: true,
604
669
  updateChannel: DEFAULT_UPDATE_CHANNEL,
@@ -650,6 +715,10 @@ window.__ModuleLoader__.load({
650
715
  const flavor = raw.flavor;
651
716
  if (typeof flavor === "string" && CATPPUCCIN_THEME_IDS.includes(flavor)) state.flavor = flavor;
652
717
  else if (flavor === "off") state.flavor = "off";
718
+ const followDark = raw.followDark;
719
+ state.followDark = typeof followDark === "string" && FOLLOW_DARK_FLAVORS.includes(followDark) ? followDark : DEFAULT_FOLLOW_DARK;
720
+ state.followSystem = raw.followSystem === true;
721
+ if (state.flavor === "off") state.followSystem = false;
653
722
  const glass = typeof raw.glass === "object" && raw.glass !== null ? raw.glass : {};
654
723
  state.glass.enabled = glass.enabled === true;
655
724
  state.glass.mode = glass.mode === "compat" ? "compat" : "mica";
@@ -671,12 +740,14 @@ window.__ModuleLoader__.load({
671
740
  * "no durable state yet" apart from "an explicit default choice". */
672
741
  function isDefaultState(state) {
673
742
  const expected = defaultState();
674
- return state.flavor === expected.flavor && state.glass.enabled === expected.glass.enabled && state.glass.mode === expected.glass.mode && state.glass.blur === expected.glass.blur && state.glass.frost === expected.glass.frost && state.glass.brightness === expected.glass.brightness && state.glass.gap === expected.glass.gap && state.glass.glowStrength === expected.glass.glowStrength && state.glass.glowSize === expected.glass.glowSize && state.glass.glow === expected.glass.glow && state.autoCheck === expected.autoCheck && state.updateChannel === expected.updateChannel && Object.keys(state.overrides).length === 0 && state.shikiStyle === expected.shikiStyle;
743
+ return state.flavor === expected.flavor && state.followSystem === expected.followSystem && state.followDark === expected.followDark && state.glass.enabled === expected.glass.enabled && state.glass.mode === expected.glass.mode && state.glass.blur === expected.glass.blur && state.glass.frost === expected.glass.frost && state.glass.brightness === expected.glass.brightness && state.glass.gap === expected.glass.gap && state.glass.glowStrength === expected.glass.glowStrength && state.glass.glowSize === expected.glass.glowSize && state.glass.glow === expected.glass.glow && state.autoCheck === expected.autoCheck && state.updateChannel === expected.updateChannel && Object.keys(state.overrides).length === 0 && state.shikiStyle === expected.shikiStyle;
675
744
  }
676
745
  /** Drop the synthetic `version` field: full state → settings-document section. */
677
746
  function settingsSectionFromState(state) {
678
747
  return {
679
748
  flavor: state.flavor,
749
+ followSystem: state.followSystem,
750
+ followDark: state.followDark,
680
751
  glass: { ...state.glass },
681
752
  autoCheck: state.autoCheck,
682
753
  updateChannel: state.updateChannel,
@@ -699,7 +770,7 @@ window.__ModuleLoader__.load({
699
770
  /** Whether two settings sections are field-for-field equal (used to skip
700
771
  * redundant mirror writes and to recognize the Host echoing our own write). */
701
772
  function settingsSectionsEqual(a, b) {
702
- return a.flavor === b.flavor && a.glass.enabled === b.glass.enabled && a.glass.mode === b.glass.mode && a.glass.blur === b.glass.blur && a.glass.frost === b.glass.frost && a.glass.brightness === b.glass.brightness && a.glass.gap === b.glass.gap && a.glass.glowStrength === b.glass.glowStrength && a.glass.glowSize === b.glass.glowSize && a.glass.glow === b.glass.glow && a.autoCheck === b.autoCheck && a.updateChannel === b.updateChannel && a.shikiStyle === b.shikiStyle && sameOverrides(a.overrides, b.overrides);
773
+ return a.flavor === b.flavor && a.followSystem === b.followSystem && a.followDark === b.followDark && a.glass.enabled === b.glass.enabled && a.glass.mode === b.glass.mode && a.glass.blur === b.glass.blur && a.glass.frost === b.glass.frost && a.glass.brightness === b.glass.brightness && a.glass.gap === b.glass.gap && a.glass.glowStrength === b.glass.glowStrength && a.glass.glowSize === b.glass.glowSize && a.glass.glow === b.glass.glow && a.autoCheck === b.autoCheck && a.updateChannel === b.updateChannel && a.shikiStyle === b.shikiStyle && sameOverrides(a.overrides, b.overrides);
703
774
  }
704
775
  /**
705
776
  * Replay the local changes a window made BEFORE the durable channel became
@@ -754,6 +825,8 @@ window.__ModuleLoader__.load({
754
825
  }
755
826
  };
756
827
  carry("flavor");
828
+ carry("followSystem");
829
+ carry("followDark");
757
830
  carryGlass("enabled");
758
831
  carryGlass("mode");
759
832
  carryGlass("blur");
@@ -2211,7 +2284,10 @@ window.__ModuleLoader__.load({
2211
2284
  "page.title": "Catppuccin 外观设置",
2212
2285
  "row.title": "Catppuccin 主题",
2213
2286
  "row.description": "Latte / Frappé / Macchiato / Mocha 四款配色,一键切换。",
2214
- "row.off": "跟随系统",
2287
+ "row.off": "关闭(官方主题)",
2288
+ "row.follow": "跟随系统深色/浅色",
2289
+ "row.followHint": "浅色时用 Latte,深色时用下方选中的风味;跟随 Windows 的深浅色设置切换,原生标题栏与窗口按钮一起变。深色端默认 Mocha。",
2290
+ "row.followDark": "深色端风味",
2215
2291
  "row.helpLabel": "关于 Catppuccin 主题",
2216
2292
  "row.help": "Catppuccin 社区出品的四款配色:Latte(浅色)、Frappé / Macchiato / Mocha(深色)。选择后立即生效并持久保存。",
2217
2293
  "row.shikiStyle": "代码高亮风格",
@@ -2306,7 +2382,10 @@ window.__ModuleLoader__.load({
2306
2382
  "page.title": "Catppuccin appearance",
2307
2383
  "row.title": "Catppuccin theme",
2308
2384
  "row.description": "Latte / Frappé / Macchiato / Mocha, one click away.",
2309
- "row.off": "Follow system",
2385
+ "row.off": "Turn off (official theme)",
2386
+ "row.follow": "Follow system light/dark",
2387
+ "row.followHint": "Latte on light, the flavour picked below on dark; switches with the Windows light/dark setting, native title bar and window buttons included. The dark end defaults to Mocha.",
2388
+ "row.followDark": "Dark-end flavour",
2310
2389
  "row.helpLabel": "About the Catppuccin theme",
2311
2390
  "row.help": "Four palettes from the Catppuccin community: Latte (light), Frappé / Macchiato / Mocha (dark). Applies instantly and persists.",
2312
2391
  "row.shikiStyle": "Code highlight style",
@@ -2401,7 +2480,10 @@ window.__ModuleLoader__.load({
2401
2480
  "page.title": "Catppuccin 外観設定",
2402
2481
  "row.title": "Catppuccin テーマ",
2403
2482
  "row.description": "Latte / Frappé / Macchiato / Mocha の4色をワンクリックで切替。",
2404
- "row.off": "システムに従う",
2483
+ "row.off": "オフ(標準テーマ)",
2484
+ "row.follow": "システムのライト/ダークに追従",
2485
+ "row.followHint": "ライトは Latte、ダークは下で選んだフレーバー。Windows のライト/ダーク設定に合わせて切り替わり、ネイティブのタイトルバーとウィンドウボタンも追従します。ダーク側の既定は Mocha。",
2486
+ "row.followDark": "ダーク側のフレーバー",
2405
2487
  "row.helpLabel": "Catppuccin テーマについて",
2406
2488
  "row.help": "Catppuccin コミュニティの4色: Latte(ライト)、Frappé / Macchiato / Mocha(ダーク)。選択直後に反映され、保存されます。",
2407
2489
  "row.shikiStyle": "コードハイライト",
@@ -2496,7 +2578,10 @@ window.__ModuleLoader__.load({
2496
2578
  "page.title": "Catppuccin 모양 설정",
2497
2579
  "row.title": "Catppuccin 테마",
2498
2580
  "row.description": "Latte / Frappé / Macchiato / Mocha 네 가지 배색, 한 번의 클릭으로 전환.",
2499
- "row.off": "시스템 팔로우",
2581
+ "row.off": "끄기(기본 테마)",
2582
+ "row.follow": "시스템 밝기/어둡기 따르기",
2583
+ "row.followHint": "밝을 때는 Latte, 어두울 때는 아래에서 고른 플레이버. Windows 밝기 설정에 따라 전환되며 기본 제목 표시줄과 창 버튼도 함께 바뀝니다. 어두운 쪽 기본값은 Mocha.",
2584
+ "row.followDark": "어두운 쪽 플레이버",
2500
2585
  "row.helpLabel": "Catppuccin 테마 정보",
2501
2586
  "row.help": "Catppuccin 커뮤니티의 네 가지 배색: Latte(밝음), Frappé / Macchiato / Mocha(어두움). 선택 즉시 적용되고 저장됩니다.",
2502
2587
  "row.shikiStyle": "코드 하이라이트",
@@ -2591,7 +2676,10 @@ window.__ModuleLoader__.load({
2591
2676
  "page.title": "Aspecto de Catppuccin",
2592
2677
  "row.title": "Tema Catppuccin",
2593
2678
  "row.description": "Latte / Frappé / Macchiato / Mocha, a un clic.",
2594
- "row.off": "Seguir al sistema",
2679
+ "row.off": "Desactivar (tema oficial)",
2680
+ "row.follow": "Seguir el modo claro/oscuro del sistema",
2681
+ "row.followHint": "Latte en claro y el sabor elegido abajo en oscuro; cambia con el ajuste de Windows, incluidos la barra de título nativa y los botones de la ventana. El extremo oscuro es Mocha por defecto.",
2682
+ "row.followDark": "Sabor del extremo oscuro",
2595
2683
  "row.helpLabel": "Acerca del tema Catppuccin",
2596
2684
  "row.help": "Cuatro paletas de la comunidad Catppuccin: Latte (claro), Frappé / Macchiato / Mocha (oscuro). Se aplican al instante y se guardan.",
2597
2685
  "row.shikiStyle": "Estilo de resaltado",
@@ -2686,7 +2774,10 @@ window.__ModuleLoader__.load({
2686
2774
  "page.title": "Apparence Catppuccin",
2687
2775
  "row.title": "Thème Catppuccin",
2688
2776
  "row.description": "Latte / Frappé / Macchiato / Mocha, en un clic.",
2689
- "row.off": "Suivre le système",
2777
+ "row.off": "Désactiver (thème officiel)",
2778
+ "row.follow": "Suivre le clair/sombre du système",
2779
+ "row.followHint": "Latte en clair, la saveur choisie ci-dessous en sombre ; bascule avec le réglage Windows, barre de titre native et boutons de fenêtre compris. L’extrémité sombre est Mocha par défaut.",
2780
+ "row.followDark": "Saveur de l’extrémité sombre",
2690
2781
  "row.helpLabel": "À propos du thème Catppuccin",
2691
2782
  "row.help": "Quatre palettes de la communauté Catppuccin : Latte (clair), Frappé / Macchiato / Mocha (sombre). Application immédiate et persistante.",
2692
2783
  "row.shikiStyle": "Style de coloration",
@@ -2781,7 +2872,10 @@ window.__ModuleLoader__.load({
2781
2872
  "page.title": "Catppuccin-Darstellung",
2782
2873
  "row.title": "Catppuccin-Design",
2783
2874
  "row.description": "Latte / Frappé / Macchiato / Mocha, mit einem Klick.",
2784
- "row.off": "System folgen",
2875
+ "row.off": "Aus (offizielles Theme)",
2876
+ "row.follow": "System-Hell/Dunkel folgen",
2877
+ "row.followHint": "Latte bei Hell, die unten gewählte Variante bei Dunkel; wechselt mit der Windows-Einstellung, inklusive nativer Titelleiste und Fensterknöpfe. Das dunkle Ende ist standardmäßig Mocha.",
2878
+ "row.followDark": "Variante fürs dunkle Ende",
2785
2879
  "row.helpLabel": "Über das Catppuccin-Design",
2786
2880
  "row.help": "Vier Paletten der Catppuccin-Community: Latte (hell), Frappé / Macchiato / Mocha (dunkel). Wirkt sofort und wird gespeichert.",
2787
2881
  "row.shikiStyle": "Code-Hervorhebung",
@@ -4002,6 +4096,16 @@ window.__ModuleLoader__.load({
4002
4096
  path: ["flavor"],
4003
4097
  value: section.flavor
4004
4098
  },
4099
+ {
4100
+ op: "set",
4101
+ path: ["followSystem"],
4102
+ value: section.followSystem
4103
+ },
4104
+ {
4105
+ op: "set",
4106
+ path: ["followDark"],
4107
+ value: section.followDark
4108
+ },
4005
4109
  {
4006
4110
  op: "set",
4007
4111
  path: ["glass", "enabled"],
@@ -4193,6 +4297,10 @@ window.__ModuleLoader__.load({
4193
4297
  const OVERRIDES_KEY = "dsh.catppuccin.overrides";
4194
4298
  /** localStorage key carrying the shiki style preference (item M). */
4195
4299
  const SHIKI_STYLE_KEY = "dsh.catppuccin.shikiStyle";
4300
+ /** localStorage key carrying the follow-the-OS flag (issue #36). */
4301
+ const FOLLOW_SYSTEM_KEY = "dsh.catppuccin.followSystem";
4302
+ /** localStorage key carrying the follow-mode dark half (issue #36). */
4303
+ const FOLLOW_DARK_KEY = "dsh.catppuccin.followDark";
4196
4304
  /** Accepted flavour values — the four registered theme ids plus `off`. These
4197
4305
  * MUST stay in sync with the registered themes (guarded by
4198
4306
  * tests/palettes.spec.ts) because the persisted value is the theme id. */
@@ -4337,6 +4445,35 @@ window.__ModuleLoader__.load({
4337
4445
  localStorage.setItem(SHIKI_STYLE_KEY, value);
4338
4446
  } catch {}
4339
4447
  }
4448
+ /** Read the persisted follow-the-OS flag (issue #36; absent means off). */
4449
+ function readFollowSystem() {
4450
+ try {
4451
+ return localStorage.getItem(FOLLOW_SYSTEM_KEY) === "true";
4452
+ } catch {
4453
+ return false;
4454
+ }
4455
+ }
4456
+ /** Persist the follow-the-OS flag. */
4457
+ function writeFollowSystem(value) {
4458
+ try {
4459
+ localStorage.setItem(FOLLOW_SYSTEM_KEY, String(value));
4460
+ } catch {}
4461
+ }
4462
+ /** Read the follow-mode dark half (only the three dark flavours are legal). */
4463
+ function readFollowDark() {
4464
+ try {
4465
+ const raw = localStorage.getItem(FOLLOW_DARK_KEY);
4466
+ return raw !== null && FOLLOW_DARK_FLAVORS.includes(raw) ? raw : DEFAULT_FOLLOW_DARK;
4467
+ } catch {
4468
+ return DEFAULT_FOLLOW_DARK;
4469
+ }
4470
+ }
4471
+ /** Persist the follow-mode dark half. */
4472
+ function writeFollowDark(value) {
4473
+ try {
4474
+ localStorage.setItem(FOLLOW_DARK_KEY, value);
4475
+ } catch {}
4476
+ }
4340
4477
  /**
4341
4478
  * Does this host ship the menu blur that makes a translucent menu surface work?
4342
4479
  *
@@ -4490,6 +4627,8 @@ window.__ModuleLoader__.load({
4490
4627
  const buildLocalState = () => ({
4491
4628
  version: 1,
4492
4629
  flavor: readFlavor(),
4630
+ followSystem: readFollowSystem() && readFlavor() !== "off",
4631
+ followDark: readFollowDark(),
4493
4632
  glass: glass.getRemoteState(),
4494
4633
  autoCheck: readAutoCheck(),
4495
4634
  updateChannel: readUpdateChannel(),
@@ -4506,7 +4645,99 @@ window.__ModuleLoader__.load({
4506
4645
  conflictCount += 1;
4507
4646
  for (const listener of conflictListeners) listener();
4508
4647
  };
4648
+ const FOLLOW_LAYER_SOURCE = PACKAGE_NAME;
4649
+ /** Disposer of the currently stacked follow layer (`undefined` = no layer). */
4650
+ let followLayerDispose;
4651
+ /** Content signature of the stacked layer, so a no-op refresh does not
4652
+ * republish (every `overrideTokens` call emits `theme/change`). */
4653
+ let followLayerSignature;
4654
+ /** Theme-id → shiki/flavour key ("catppuccin-latte" → "latte"). */
4655
+ const flavorKey = (flavor) => flavor.themeId.replace("catppuccin-", "");
4656
+ /** Whether this host serves `overrideTokens` at all. Hosts before that API
4657
+ * cannot follow the OS; the row hides the control instead of offering a
4658
+ * switch that would do nothing. */
4659
+ const followSupported = () => typeof theme.overrideTokens === "function";
4660
+ /** Follow mode is wanted AND possible. `off` always wins: turning the plugin
4661
+ * off must not leave a layer painting Catppuccin tokens. */
4662
+ const followWanted = () => followSupported() && readFollowSystem() && readFlavor() !== "off";
4663
+ /**
4664
+ * The two halves of the follow layer.
4665
+ *
4666
+ * Precedence per token mirrors `registerThemeFor`: flavour tokens < shiki <
4667
+ * host-shape menu patch < user overrides (later wins). A user override is
4668
+ * scheme-agnostic by contract, so the SAME value goes into both halves.
4669
+ * A token present in only one flavour falls back to the other half's value so
4670
+ * every entry stays a well-formed `{ light, dark }` pair (`overrideTokens`
4671
+ * throws on a bare string).
4672
+ * @returns the layer, or null when a flavour table is missing.
4673
+ */
4674
+ const followLayerTokens = () => {
4675
+ const light = flavorInfo(FOLLOW_LIGHT_FLAVOR);
4676
+ const dark = flavorInfo(readFollowDark());
4677
+ if (light === void 0 || dark === void 0) return null;
4678
+ const shiki = readShikiStyle();
4679
+ const lightShiki = SHIKI_TOKENS[flavorKey(light)][shiki];
4680
+ const darkShiki = SHIKI_TOKENS[flavorKey(dark)][shiki];
4681
+ const menu = menuSurfaceFor(hostHasMenuBlur());
4682
+ const overrides = readOverrides();
4683
+ const names = /* @__PURE__ */ new Set([
4684
+ ...Object.keys(light.tokens),
4685
+ ...Object.keys(dark.tokens),
4686
+ ...Object.keys(lightShiki),
4687
+ ...Object.keys(darkShiki),
4688
+ ...Object.keys(menu),
4689
+ ...Object.keys(overrides)
4690
+ ]);
4691
+ const pairs = {};
4692
+ for (const name of names) {
4693
+ const lightValue = overrides[name] ?? menu[name] ?? lightShiki[name] ?? light.tokens[name];
4694
+ const darkValue = overrides[name] ?? menu[name] ?? darkShiki[name] ?? dark.tokens[name];
4695
+ if (lightValue === void 0 && darkValue === void 0) continue;
4696
+ pairs[name] = {
4697
+ light: lightValue ?? darkValue,
4698
+ dark: darkValue ?? lightValue
4699
+ };
4700
+ }
4701
+ return pairs;
4702
+ };
4703
+ /** Remove the follow layer (idempotent). */
4704
+ const disposeFollowLayer = () => {
4705
+ if (followLayerDispose === void 0) return;
4706
+ followLayerDispose();
4707
+ followLayerDispose = void 0;
4708
+ followLayerSignature = void 0;
4709
+ };
4710
+ /**
4711
+ * Stack (or refresh, or retire) the follow layer.
4712
+ *
4713
+ * MUST be called outside a `theme/change` dispatch: `overrideTokens`
4714
+ * publishes, and a synchronous publish from inside a dispatch lets the
4715
+ * presenter apply the OUTER (stale) snapshot last — the issue #10 trap, same
4716
+ * reason `scheduleRestore` defers.
4717
+ */
4718
+ const syncFollowLayer = () => {
4719
+ if (!followWanted()) {
4720
+ disposeFollowLayer();
4721
+ return;
4722
+ }
4723
+ const tokens = followLayerTokens();
4724
+ if (tokens === null) {
4725
+ disposeFollowLayer();
4726
+ return;
4727
+ }
4728
+ const signature = JSON.stringify(tokens);
4729
+ if (followLayerDispose !== void 0 && signature === followLayerSignature) return;
4730
+ const dispose = theme.overrideTokens(FOLLOW_LAYER_SOURCE, tokens);
4731
+ followLayerDispose?.();
4732
+ followLayerDispose = dispose;
4733
+ followLayerSignature = signature;
4734
+ };
4509
4735
  const reapplyThemePrefs = () => {
4736
+ if (followWanted()) {
4737
+ syncFollowLayer();
4738
+ return;
4739
+ }
4740
+ disposeFollowLayer();
4510
4741
  const active = theme.getTheme().preference;
4511
4742
  const flavor = flavorInfo(active);
4512
4743
  if (flavor === void 0) return;
@@ -4591,6 +4822,28 @@ window.__ModuleLoader__.load({
4591
4822
  applyRestoredPreference = (id) => {
4592
4823
  commitTheme(id, false);
4593
4824
  };
4825
+ let followSyncPending = false;
4826
+ const scheduleFollowSync = () => {
4827
+ if (followSyncPending) return;
4828
+ followSyncPending = true;
4829
+ queueMicrotask(() => {
4830
+ followSyncPending = false;
4831
+ if (!followWanted()) {
4832
+ disposeFollowLayer();
4833
+ return;
4834
+ }
4835
+ syncFollowLayer();
4836
+ const preference = theme.getTheme().preference;
4837
+ if (preference === "system") {
4838
+ clearBootPalette();
4839
+ return;
4840
+ }
4841
+ if (builtinPickWins(preference, liveBuiltinPick)) return;
4842
+ try {
4843
+ commitTheme("system", false);
4844
+ } catch {}
4845
+ });
4846
+ };
4594
4847
  let restorePending = false;
4595
4848
  let pendingDesired;
4596
4849
  const scheduleRestore = (desired) => {
@@ -4614,8 +4867,14 @@ window.__ModuleLoader__.load({
4614
4867
  });
4615
4868
  };
4616
4869
  const applyDesired = () => {
4617
- rememberBuiltinPreference(theme.getTheme().preference);
4870
+ const follow = followWanted();
4871
+ if (!follow) rememberBuiltinPreference(theme.getTheme().preference);
4618
4872
  const desired = readFlavor();
4873
+ if (follow) {
4874
+ scheduleFollowSync();
4875
+ return;
4876
+ }
4877
+ if (followLayerDispose !== void 0) scheduleFollowSync();
4619
4878
  if (desired === "off") {
4620
4879
  const preference = theme.getTheme().preference;
4621
4880
  if (readExplicitFlavorOff()) {
@@ -4635,7 +4894,17 @@ window.__ModuleLoader__.load({
4635
4894
  applyDesired();
4636
4895
  const disposer = ctx.on("theme/change", applyDesired);
4637
4896
  const onStorage = (event) => {
4897
+ if (event.key === "dsh.catppuccin.followSystem" || event.key === "dsh.catppuccin.followDark") {
4898
+ emitPrefs();
4899
+ applyDesired();
4900
+ return;
4901
+ }
4638
4902
  if (event.key !== "dsh.catppuccin.flavor") return;
4903
+ if (followWanted()) {
4904
+ emitPrefs();
4905
+ applyDesired();
4906
+ return;
4907
+ }
4639
4908
  const next = readFlavor();
4640
4909
  if (next !== "off") {
4641
4910
  ensureThemeRegistered(next);
@@ -4765,11 +5034,48 @@ window.__ModuleLoader__.load({
4765
5034
  accent: flavor.accent
4766
5035
  })),
4767
5036
  current: () => {
5037
+ if (readFollowSystem() && readFlavor() !== "off") return readFlavor();
4768
5038
  const pref = theme.getTheme().preference;
4769
5039
  return flavorFromThemeId(pref);
4770
5040
  },
4771
5041
  subscribe: (listener) => ctx.on("theme/change", listener),
5042
+ followAvailable: followSupported(),
5043
+ followSystem: () => readFollowSystem(),
5044
+ setFollowSystem: (enabled) => {
5045
+ if (!followSupported()) return;
5046
+ if (enabled) {
5047
+ if (readFlavor() === "off") writeFlavor(readFollowDark());
5048
+ writeFollowSystem(true);
5049
+ syncFollowLayer();
5050
+ try {
5051
+ if (applyRestoredPreference !== void 0) applyRestoredPreference("system");
5052
+ else theme.setTheme("system");
5053
+ } catch {}
5054
+ } else {
5055
+ writeFollowSystem(false);
5056
+ disposeFollowLayer();
5057
+ const target = readFlavor();
5058
+ if (target !== "off") try {
5059
+ if (applyRestoredPreference !== void 0) applyRestoredPreference(target);
5060
+ else theme.setTheme(target);
5061
+ } catch {}
5062
+ }
5063
+ emitPrefs();
5064
+ queuePersist();
5065
+ },
5066
+ followDark: () => readFollowDark(),
5067
+ setFollowDark: (dark) => {
5068
+ if (!FOLLOW_DARK_FLAVORS.includes(dark)) return;
5069
+ writeFollowDark(dark);
5070
+ if (followWanted()) syncFollowLayer();
5071
+ emitPrefs();
5072
+ queuePersist();
5073
+ },
4772
5074
  select: (choice) => {
5075
+ if (readFollowSystem()) {
5076
+ writeFollowSystem(false);
5077
+ disposeFollowLayer();
5078
+ }
4773
5079
  if (choice === "off") {
4774
5080
  writeFlavor("off");
4775
5081
  try {
@@ -4935,6 +5241,8 @@ window.__ModuleLoader__.load({
4935
5241
  exports.AUTO_CHECK_KEY = AUTO_CHECK_KEY;
4936
5242
  exports.CATPPUCCIN_FLAVOR_VALUES = CATPPUCCIN_FLAVOR_VALUES;
4937
5243
  exports.FLAVOR_STORAGE_KEY = FLAVOR_STORAGE_KEY;
5244
+ exports.FOLLOW_DARK_KEY = FOLLOW_DARK_KEY;
5245
+ exports.FOLLOW_SYSTEM_KEY = FOLLOW_SYSTEM_KEY;
4938
5246
  exports.NS = NS;
4939
5247
  exports.OVERRIDES_KEY = OVERRIDES_KEY;
4940
5248
  exports.RESTORE_STORAGE_KEY = RESTORE_STORAGE_KEY;
@@ -4951,6 +5259,8 @@ window.__ModuleLoader__.load({
4951
5259
  exports.readAutoCheck = readAutoCheck;
4952
5260
  exports.readExplicitFlavorOff = readExplicitFlavorOff;
4953
5261
  exports.readFlavor = readFlavor;
5262
+ exports.readFollowDark = readFollowDark;
5263
+ exports.readFollowSystem = readFollowSystem;
4954
5264
  exports.readOverrides = readOverrides;
4955
5265
  exports.readRestoredPreference = readRestoredPreference;
4956
5266
  exports.readShikiStyle = readShikiStyle;
@@ -4958,6 +5268,8 @@ window.__ModuleLoader__.load({
4958
5268
  exports.rememberBuiltinPreference = rememberBuiltinPreference;
4959
5269
  exports.writeAutoCheck = writeAutoCheck;
4960
5270
  exports.writeFlavor = writeFlavor;
5271
+ exports.writeFollowDark = writeFollowDark;
5272
+ exports.writeFollowSystem = writeFollowSystem;
4961
5273
  exports.writeOverrides = writeOverrides;
4962
5274
  exports.writeShikiStyle = writeShikiStyle;
4963
5275
  exports.writeUpdateChannel = writeUpdateChannel;