Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
316c001
feat(web): configurable font families under Settings → Appearance
StiensWout Jul 31, 2026
3aaf1b3
feat(web): font dropdowns with availability filtering and surface pre…
StiensWout Jul 31, 2026
dc3ebeb
fix(web): make code and terminal font previews follow the selection
StiensWout Jul 31, 2026
80612c4
fix(web): reliable font availability probing and theme-consistent pre…
StiensWout Jul 31, 2026
0d7b5f5
test(desktop): add font-family keys to the client settings fixture
StiensWout Jul 31, 2026
a31d2bc
fix(web): route body and code font-family through the theme tokens
StiensWout Jul 31, 2026
d423e00
fix(web): survive async settings hydration and group font dropdowns
StiensWout Jul 31, 2026
bec7059
feat(web): unified font catalog per dropdown and draft-committed cust…
StiensWout Jul 31, 2026
47b1e92
fix(web): route shadow-root code surfaces through the appearance font…
StiensWout Jul 31, 2026
df68214
fix(web): include font settings in restore defaults and align compose…
StiensWout Jul 31, 2026
1218240
refactor(web): scope font settings to the prompt textarea and terminal
StiensWout Jul 31, 2026
eadee77
fix(web): commit an explicit clear of the custom font input
StiensWout Jul 31, 2026
4e4cf0f
fix(web): plainer copy for the font settings rows
StiensWout Jul 31, 2026
d932f98
feat(web): restore all four font settings with a calmer custom input
StiensWout Jul 31, 2026
61df965
fix(web): polish pass on font settings
StiensWout Aug 1, 2026
2e35470
fix(web): stop the custom-font shift and normalize apparent font size
StiensWout Aug 1, 2026
9001d78
fix(web): start the custom font field empty
StiensWout Aug 1, 2026
3bafffd
fix(web): plainer font setting descriptions
StiensWout Aug 1, 2026
1a3481a
fix(web): cap the size correction for faces with unusual proportions
StiensWout Aug 1, 2026
ddb3b48
docs(web): correct the size-adjust docblock after clamping
StiensWout Aug 1, 2026
04c529a
feat(web): font size sliders instead of automatic size normalization
StiensWout Aug 1, 2026
162d5b4
feat(web): collapse the composer context strip to icons when text out…
StiensWout Aug 1, 2026
ed70fa4
fix(web): keep proportional fonts out of the grid surfaces, collapse …
StiensWout Aug 1, 2026
2977bae
fix(web): refuse proportional faces in the terminal grid
StiensWout Aug 1, 2026
c299943
feat(web): slide the terminal font size with the canvas width
StiensWout Aug 1, 2026
0fcaa3b
fix(web): truncate the context strip before collapsing, measure conte…
StiensWout Aug 1, 2026
7580c5d
feat(web): animate the context strip label collapse
StiensWout Aug 1, 2026
c2677c2
fix(web): consume the code size token, stop focus theft, gate termina…
StiensWout Aug 1, 2026
805813e
fix(web): include the environment label in the collapse, gate the cod…
StiensWout Aug 1, 2026
5ce99c2
fix(web): commit slider steps reliably, scope pre sizing, measure nes…
StiensWout Aug 1, 2026
a6f5f65
fix(web): apply the prompt-size floor only on touch devices
StiensWout Aug 1, 2026
a0ac88f
Merge remote-tracking branch 'origin/main' into agent/web-appearance-…
juliusmarminge Aug 4, 2026
a7b35a2
feat(web): render the font previews with the real surfaces
juliusmarminge Aug 4, 2026
62daf23
feat(web): inline font rows and system-wide font pickers
juliusmarminge Aug 4, 2026
4b728a7
fix(web): title the fonts section Typography and move word wrap into it
juliusmarminge Aug 4, 2026
dd9700f
fix(web): register the font rows in settings search
juliusmarminge Aug 4, 2026
df2e7b3
feat(web): say what the Default font resolves to
juliusmarminge Aug 4, 2026
8a5e436
feat(web): start font rows as inputs, upgrade to the picker on discovery
juliusmarminge Aug 4, 2026
6e1d025
feat(web): font smoothing toggle, system default fonts
juliusmarminge Aug 4, 2026
c3a46f7
feat(web): seed the prompt preview with skill and file-tag pills
juliusmarminge Aug 4, 2026
71b4e7e
fix(web): un-invert font smoothing to match Cursor and Codex
juliusmarminge Aug 4, 2026
1e1e89c
feat(web): name the face a default stack actually renders
juliusmarminge Aug 4, 2026
c1ef13d
fix(web): scale composer pills with the prompt font size
juliusmarminge Aug 4, 2026
8e13a97
feat(web): fold typography overrides behind an Advanced switch
juliusmarminge Aug 4, 2026
deb9252
fix(review): address font picker and typography review feedback
juliusmarminge Aug 4, 2026
aeef720
feat(web): show the font picker immediately when permission is granted
juliusmarminge Aug 4, 2026
67599b2
fix(web): parse the diff preview patch per mount
juliusmarminge Aug 4, 2026
284ea9f
fix(web): render the diff preview statically
juliusmarminge Aug 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/desktop/src/preview/BrowserSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ const ALLOWED_PREVIEW_PERMISSIONS: ReadonlySet<string> = new Set([
"clipboard-sanitized-write",
"notifications",
"geolocation",
// Deliberately NOT local-fonts: preview sessions run untrusted web content,
// and silently granting it would hand every page the user's installed-font
// fingerprint (and font file bytes via FontData.blob()). The app's own font
// picker runs in the main window session, which is unaffected by this list.
]);

export class BrowserSessionPartitionDerivationError extends Schema.TaggedErrorClass<BrowserSessionPartitionDerivationError>()(
Expand Down
9 changes: 9 additions & 0 deletions apps/desktop/src/settings/DesktopClientSettings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ const clientSettings: ClientSettings = {
diffIgnoreWhitespace: true,
environmentIdentificationMode: "artwork",
favorites: [],
fontFamilyCode: "",
fontFamilyComposer: "",
fontFamilySans: "",
fontFamilyTerminal: "",
fontSizeCode: 13,
fontSizeInterface: 16,
fontSizePrompt: 14,
fontSizeTerminal: 12,
fontSmoothing: true,
glassOpacity: 80,
providerModelPreferences: {},
sidebarAutoSettleAfterDays: 3,
Expand Down
9 changes: 1 addition & 8 deletions apps/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,7 @@
body {
background: #ffffff;
color: #262626;
font-family:
"DM Sans Variable",
"DM Sans",
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
system-ui,
sans-serif;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
}

html.dark body {
Expand Down
2 changes: 0 additions & 2 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@
"@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@effect/atom-react": "catalog:",
"@fontsource-variable/dm-sans": "^5.2.8",
"@fontsource/jetbrains-mono": "^5.2.8",
"@formkit/auto-animate": "^0.9.0",
"@legendapp/list": "3.2.0",
"@lexical/react": "^0.41.0",
Expand Down
71 changes: 71 additions & 0 deletions apps/web/src/appearanceFonts.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { describe, expect, it } from "vite-plus/test";

import {
clampCodeFontSize,
clampInterfaceFontSize,
clampPromptFontSize,
DEFAULT_CODE_FONT_STACK,
DEFAULT_SANS_FONT_STACK,
appearanceFontStack,
cssFontFamilies,
resolveDefaultFamilyLabel,
} from "./appearanceFonts";

describe("cssFontFamilies", () => {
it("returns null for effectively empty input", () => {
expect(cssFontFamilies("")).toBeNull();
expect(cssFontFamilies(" ")).toBeNull();
expect(cssFontFamilies(" , , ")).toBeNull();
});

it("quotes names with spaces and keeps single idents bare", () => {
expect(cssFontFamilies("Fira Code")).toBe('"Fira Code"');
expect(cssFontFamilies("monospace")).toBe("monospace");
expect(cssFontFamilies('"Comic Mono"')).toBe('"Comic Mono"');
});

it("normalizes comma-separated lists and strips embedded quotes", () => {
expect(cssFontFamilies(" Fira Code , Menlo ")).toBe('"Fira Code", Menlo');
expect(cssFontFamilies('Bad"Name')).toBe('"BadName"');
});

it("quotes names that are not single CSS idents", () => {
expect(cssFontFamilies("3270 Nerd Font")).toBe('"3270 Nerd Font"');
expect(cssFontFamilies("M+ 1m")).toBe('"M+ 1m"');
});
});

describe("resolveDefaultFamilyLabel", () => {
it("skips generic keywords and returns null for a stack of only generics", () => {
expect(resolveDefaultFamilyLabel("system-ui, sans-serif")).toBeNull();
expect(resolveDefaultFamilyLabel("ui-monospace, monospace")).toBeNull();
});
});

describe("appearanceFontStack", () => {
it("prepends the custom family to the default stack", () => {
expect(appearanceFontStack("Fira Code", DEFAULT_CODE_FONT_STACK)).toBe(
`"Fira Code", ${DEFAULT_CODE_FONT_STACK}`,
);
});

it("falls back to the default stack when unset", () => {
expect(appearanceFontStack("", DEFAULT_SANS_FONT_STACK)).toBe(DEFAULT_SANS_FONT_STACK);
});
});

describe("font size clamping", () => {
it("keeps sizes inside the ranges the UI can absorb", () => {
expect(clampInterfaceFontSize(16)).toBe(16);
expect(clampInterfaceFontSize(2)).toBe(12);
expect(clampInterfaceFontSize(96)).toBe(20);
expect(clampPromptFontSize(40)).toBe(20);
expect(clampCodeFontSize(1)).toBe(10);
});

it("rounds fractional values and falls back for unusable input", () => {
expect(clampCodeFontSize(13.4)).toBe(13);
expect(clampInterfaceFontSize(Number.NaN)).toBe(16);
expect(clampPromptFontSize(Number.POSITIVE_INFINITY)).toBe(14);
});
});
Loading
Loading