Skip to content

feat: implement local font picker and storage functionality#5

Open
Zingzy wants to merge 1 commit into
millionco:mainfrom
Zingzy:feat/local-fonts
Open

feat: implement local font picker and storage functionality#5
Zingzy wants to merge 1 commit into
millionco:mainfrom
Zingzy:feat/local-fonts

Conversation

@Zingzy
Copy link
Copy Markdown

@Zingzy Zingzy commented May 5, 2026

Summary

Adds support for picking any locally-installed font as the terminal font, including Nerd Fonts.

A new "Local Font" entry in the Font dropdown opens a side popover that lists every font installed on the user's system (via the Local Font Access API). The list is searchable and each row is rendered in its own family for live preview. Picking a font applies it immediately to xterm.js, persists to localStorage, and shows a "Local" badge next to the family name in the trigger.

Browsers without the API (Firefox/Safari) — or users who deny the permission prompt — fall back to a manual text input where they can type any installed font family name. Either way, the chain falls back to ui-monospace if the chosen font isn't installed, so nothing crashes.

Why

Nerd Fonts (and other custom mono fonts like Operator Mono, MonoLisa) are too large to bundle or fetch over the wire — patched glyph files run ~5 MB per weight. Every native terminal (iTerm2, kitty, Alacritty, wezterm, VS Code) takes the same stance: install once, use everywhere. localterm now matches that pattern instead of trying to be a font CDN.

image

Note

Medium Risk
Adds a new font-selection path that queries the browser Local Font Access API and persists user input to localStorage, affecting terminal rendering and settings UI flows. Risk is mainly around browser support/permission failure modes and ensuring xterm.js font updates remain stable.

Overview
Enables selecting a locally installed font family as the terminal font via a new Local Font entry in the Font dropdown, including a side popover picker that queries window.queryLocalFonts, supports search, previews each family, and falls back to a manual text input when unsupported or permission is denied.

Persists the chosen local family in localStorage (new TERMINAL_LOCAL_FONT_FAMILY_STORAGE_KEY), threads it through SettingsMenuTerminal, and extends terminal-fonts to include a reserved LOCAL_FONT_ID plus helpers (buildLocalFont, updated findTerminalFontById) so xterm receives the synthesized fontFamily.

Updates SettingsSelect to support per-item onSelect (used to open the picker) and improves long-label truncation/scrolling, with new unit tests covering picker behavior, settings integration, font registry, and storage round-trips.

Reviewed by Cursor Bugbot for commit a6373c7. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI review requested due to automatic review settings May 5, 2026 19:37
@vercel
Copy link
Copy Markdown

vercel Bot commented May 5, 2026

@Zingzy is attempting to deploy a commit to the Million Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds terminal support for user-selected local fonts, so the app can use system-installed monospace fonts (including Nerd Fonts) without bundling them. This extends the terminal settings flow, font registry, and persistence utilities to support a reserved “Local Font” option alongside the existing bundled/Google fonts.

Changes:

  • Added local-font modeling and persistence (localStorage) for a user-provided font family.
  • Added a local font picker UI with Local Font Access API support plus manual-entry fallback.
  • Expanded tests for font registry behavior, local font picker behavior, settings-menu flow, and storage round-tripping.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
apps/terminal/tests/utils/store-terminal-local-font-family.test.ts Tests storage/load behavior for persisted local font family values.
apps/terminal/tests/lib/terminal-fonts.test.ts Tests local-font registry entries and synthesized local font handling.
apps/terminal/tests/components/settings-menu.test.tsx Adds coverage for opening the local-font flow from terminal settings.
apps/terminal/tests/components/local-font-picker.test.tsx Tests Local Font Access API path, filtering, selection, and fallback behavior.
apps/terminal/src/utils/store-terminal-local-font-family.ts Persists trimmed local font family values to storage.
apps/terminal/src/utils/query-local-fonts.ts Wraps Local Font Access API support detection and family enumeration.
apps/terminal/src/utils/load-stored-terminal-local-font-family.ts Loads and sanitizes the stored local font family.
apps/terminal/src/lib/terminal-fonts.ts Adds reserved local-font entry and logic for synthesizing a local font definition.
apps/terminal/src/lib/constants.ts Introduces constants for local-font storage and picker layout.
apps/terminal/src/components/terminal.tsx Wires local font state into terminal initialization, updates, and persistence.
apps/terminal/src/components/settings-select.tsx Extends select items with per-item click handling for the local-font entry.
apps/terminal/src/components/settings-menu.tsx Integrates the Local Font option and launches the side picker from settings.
apps/terminal/src/components/local-font-picker.tsx Implements the searchable local font picker and manual-entry fallback UI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +50 to +57
useEffect(() => {
if (!isLocalFontsApiSupported()) {
setLoadState({ kind: "unsupported" });
return;
}
if (cachedLocalFontFamilies) return;
let cancelled = false;
queryLocalFontFamilies()
Comment on lines +105 to +109
return {
id: font.id,
label: buildLocalLabel(localFontFamily, isActive),
itemStyle,
onSelect: openLocalPicker,
Comment on lines +283 to +289
<div className="relative">
<LocalFontPicker
open={isLocalPickerOpen}
onOpenChange={setIsLocalPickerOpen}
selectedFamily={localFontFamily}
onSelect={onLocalFontFamilyChange}
/>
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.

2 participants