Skip to content

feat(web): add UI font family preference to appearance settings#1803

Open
TaoXieSZ wants to merge 3 commits into
MoonshotAI:mainfrom
TaoXieSZ:feat/web-ui-font-family
Open

feat(web): add UI font family preference to appearance settings#1803
TaoXieSZ wants to merge 3 commits into
MoonshotAI:mainfrom
TaoXieSZ:feat/web-ui-font-family

Conversation

@TaoXieSZ

@TaoXieSZ TaoXieSZ commented Jul 17, 2026

Copy link
Copy Markdown

Related Issue

Resolve #1797

Problem

See linked issue. In short: the web settings dialog exposes color scheme, accent, and font size, but the font family is pinned — UI/reading text to the Inter-first stack (--font-ui), code to the JetBrains Mono stack (--font-mono). Users who prefer the native platform font, a serif reading face, or their own coding font (e.g. Maple Mono NF CN) have no way to change it.

What changed

Two preferences in Appearance settings, in both the desktop SettingsDialog and the mobile MobileSettingsSheet:

  • Font (UI/reading): Default (Inter), System (platform UI stack), Serif (reading-oriented stack), Custom
  • Code font: Default (JetBrains Mono), System (platform monospace), Custom

Custom reveals a free-text input accepting any locally installed font name (comma-separated fallbacks supported; CSS generic keywords pass through unquoted). The input is sanitized into a CSS font-family list with the default stack appended, so a typo'd or uninstalled name degrades to the default face instead of the browser's generic fallback.

Mechanically: each choice persists in localStorage and is mirrored onto <html data-ui-font-family> / <html data-code-font-family>, which remap the --font-ui / --font-mono tokens in style.css. --font-display and --sans follow --font-ui, and the legacy --mono alias now forwards to --font-mono, so every surface (chat Markdown, composer, diffs, file preview, sidebar) picks the preference up with no component-level changes. All alternate stacks use locally installed fonts only — no extra webfont downloads, consistent with the self-hosted/local-first font strategy.

Also: new keys in both en and zh theme locales; the design-system view (DesignSystemView.vue §02) documents the preferences and the new tokens; a pure-logic test covers the custom-name sanitizing/quoting (test/custom-font.test.ts).

Known limitation: the xterm terminal keeps its fixed literal JetBrains Mono stack — xterm's fontFamily option cannot resolve CSS variables, so following the preference there needs a JS-side rebuild and is left as a follow-up.

Verification

  • pnpm --filter @moonshot-ai/kimi-web check:style — no new findings (baseline unchanged)
  • pnpm --filter @moonshot-ai/kimi-web typecheck (vue-tsc) — clean
  • pnpm --filter @moonshot-ai/kimi-web test — 608/608 pass (9 new assertions for the custom-name helper)
  • pnpm --filter @moonshot-ai/kimi-web build — succeeds
  • pnpm exec oxlint on the touched files — 0 errors
  • Manual browser verification against a local kap-server serving the production bundle: presets and custom names apply app-wide (chrome + reading text; code surfaces for the code font) in light/dark schemes and both locales; choices persist in localStorage across reloads; a nonexistent custom name falls back to the default stack; the terminal is unaffected as documented.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works. (test/custom-font.test.ts covers the custom font-name sanitizing/quoting; the CSS-variable wiring itself is verified manually as listed above.)
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update. (The docs site does not cover the web UI's appearance settings today.)

The web settings exposed color scheme, accent, and font size, but the
font family was pinned to the Inter-first stack. Add a Font preference
(desktop SettingsDialog + mobile MobileSettingsSheet) with Default
(Inter), System (platform UI stack), and Serif (reading-oriented stack)
faces. The choice persists in localStorage, mirrors onto
<html data-ui-font-family>, and remaps the --font-ui token, so UI and
reading text switch with zero component changes while --font-mono stays
put. Both alternate stacks use locally installed fonts only, so nothing
extra is downloaded. Documents the new tokens in the design-system view.
@changeset-bot

changeset-bot Bot commented Jul 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7e6c11d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Extend the font preference work based on user feedback on the linked
issue. The UI font gains a Custom option whose free-text input accepts
any locally installed font name (comma-separated fallbacks supported,
generic keywords passed through unquoted), and a parallel Code font
preference (Default / System / Custom) remaps --font-mono the same way,
with the legacy --mono alias now forwarding to it so diffs, file
previews, and composer code follow. Custom values are sanitized into a
CSS font-family list with the default stack appended, so a typo'd or
uninstalled name degrades to the default face instead of the browser's
generic fallback. The xterm terminal keeps its fixed literal stack
(xterm cannot resolve CSS variables); following the preference there is
left as a follow-up.
@TaoXieSZ

Copy link
Copy Markdown
Author

Scope update: this PR initially shipped presets only (Default / System / Serif for the UI font). Following user feedback on #1797 asking for freely selectable fonts (e.g. Maple Mono NF CN), the second commit adds a Custom option with a free-text input for any locally installed font name, plus a parallel Code font preference (Default / System / Custom) that remaps --font-mono — the legacy --mono alias forwards to it, so diffs, file preview, and composer code follow too. The xterm terminal intentionally keeps its fixed literal stack (it cannot resolve CSS variables); making it follow the preference is a possible follow-up. PR description updated to match.

Typing a font name by hand was the roughest edge of the custom option.
The browser cannot enumerate installed fonts, so probe a curated
candidate list (popular CJK + Latin UI faces, popular coding monos)
with the canvas measureText trick and offer only the detected ones in a
Select. A stored name that is not detected stays as an extra option so
the current value always renders, and the dropdown's last entry keeps a
manual text input for faces outside the candidate list.
@TaoXieSZ

Copy link
Copy Markdown
Author

UX follow-up: the Custom option now offers a dropdown of locally installed fonts instead of requiring the name to be typed. Since the web platform cannot enumerate installed fonts, we probe a curated candidate list (popular CJK + Latin UI faces in UI_FONT_CANDIDATES, popular coding monos in CODE_FONT_CANDIDATES) using the canvas measureText width trick — only faces that actually resolve appear in the select (e.g. Maple Mono NF CN shows up when installed). A previously stored name that is not detected stays as an extra option so the current value always renders, and the dropdown's last entry (Enter manually…) keeps the free-text input for faces outside the candidate list. Verified in-browser: on a machine with Maple Mono NF CN installed it appears in the code-font dropdown, selects cleanly, and applies with the default mono stack appended as fallback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[web] Support switching the UI font family

1 participant