From 54c0bc35bef0fb8b91d9d1ff1fedd7a157a2e0c6 Mon Sep 17 00:00:00 2001 From: Dominik Murar <79326595+dominik-murar@users.noreply.github.com> Date: Fri, 30 Oct 2026 11:04:23 +0100 Subject: [PATCH 1/4] feat(web): choose a separate font for chat messages Adds a Chat font (family and size) to Typography, shown with the other separate fonts. It applies to user and assistant messages and the new-thread heading; the rest of the UI keeps the interface font. Co-Authored-By: Claude Opus 5.5 --- .../settings/DesktopClientSettings.test.ts | 2 + apps/web/src/appInit.tsx | 4 ++ apps/web/src/appearanceFonts.ts | 17 ++++++++ apps/web/src/components/NoProjectsHero.tsx | 4 +- .../src/components/chat/DraftHeroHeadline.tsx | 2 +- .../chat/DraftHeroProjectHeading.tsx | 6 ++- .../components/chat/TimelineAssistantRows.tsx | 1 + .../chat/TimelineUserMessageRow.tsx | 2 +- .../src/components/chat/TriageDraftHero.tsx | 2 +- .../settings/SettingsFontPreviews.tsx | 12 ++++++ .../settings/SettingsPanels.logic.ts | 6 +++ .../components/settings/SettingsPanels.tsx | 2 + .../TypographySettings.browser.test.tsx | 1 + .../settings/TypographySettings.tsx | 43 ++++++++++++++++++- .../src/components/settings/settingsSearch.ts | 7 +++ apps/web/src/index.css | 23 ++++++++++ packages/contracts/src/settings.ts | 14 ++++++ 17 files changed, 141 insertions(+), 7 deletions(-) diff --git a/apps/desktop/src/settings/DesktopClientSettings.test.ts b/apps/desktop/src/settings/DesktopClientSettings.test.ts index ec5062f9105bf..50bf186d52662 100644 --- a/apps/desktop/src/settings/DesktopClientSettings.test.ts +++ b/apps/desktop/src/settings/DesktopClientSettings.test.ts @@ -39,10 +39,12 @@ const clientSettings: ClientSettings = { diffLayout: "stacked", environmentIdentificationMode: "artwork", favorites: [], + fontFamilyChat: "", fontFamilyCode: "", fontFamilyComposer: "", fontFamilySans: "", fontFamilyTerminal: "", + fontSizeChat: 14, fontSizeCode: 13, fontSizeInterface: 16, fontSizePrompt: 14, diff --git a/apps/web/src/appInit.tsx b/apps/web/src/appInit.tsx index b9312858e334b..f9b8ab4f87797 100644 --- a/apps/web/src/appInit.tsx +++ b/apps/web/src/appInit.tsx @@ -83,8 +83,10 @@ function startClientAppearance(): void { previous?.fontFamilySans !== settings.fontFamilySans || previous.fontFamilyCode !== settings.fontFamilyCode || previous.fontFamilyComposer !== settings.fontFamilyComposer || + previous.fontFamilyChat !== settings.fontFamilyChat || previous.fontSizeInterface !== settings.fontSizeInterface || previous.fontSizePrompt !== settings.fontSizePrompt || + previous.fontSizeChat !== settings.fontSizeChat || previous.fontSizeCode !== settings.fontSizeCode || previous.fontSmoothing !== settings.fontSmoothing ) { @@ -92,8 +94,10 @@ function startClientAppearance(): void { sans: settings.fontFamilySans, code: settings.fontFamilyCode, composer: settings.fontFamilyComposer, + chat: settings.fontFamilyChat, sizeInterface: settings.fontSizeInterface, sizePrompt: settings.fontSizePrompt, + sizeChat: settings.fontSizeChat, sizeCode: settings.fontSizeCode, smoothing: settings.fontSmoothing, }); diff --git a/apps/web/src/appearanceFonts.ts b/apps/web/src/appearanceFonts.ts index 48f8e5955e7e1..5bd4bf29ff83b 100644 --- a/apps/web/src/appearanceFonts.ts +++ b/apps/web/src/appearanceFonts.ts @@ -1,10 +1,13 @@ import { + DEFAULT_CHAT_FONT_SIZE, DEFAULT_CODE_FONT_SIZE, DEFAULT_INTERFACE_FONT_SIZE, DEFAULT_PROMPT_FONT_SIZE, + MAX_CHAT_FONT_SIZE, MAX_CODE_FONT_SIZE, MAX_INTERFACE_FONT_SIZE, MAX_PROMPT_FONT_SIZE, + MIN_CHAT_FONT_SIZE, MIN_CODE_FONT_SIZE, MIN_INTERFACE_FONT_SIZE, MIN_PROMPT_FONT_SIZE, @@ -62,8 +65,10 @@ export interface AppearanceFontPreferences { readonly sans: string; readonly code: string; readonly composer: string; + readonly chat: string; readonly sizeInterface: number; readonly sizePrompt: number; + readonly sizeChat: number; readonly sizeCode: number; readonly smoothing: boolean; } @@ -77,6 +82,7 @@ export function applyAppearanceFontVariables( ["--font-sans", preferences.sans, DEFAULT_SANS_FONT_STACK], ["--font-mono", preferences.code, DEFAULT_CODE_FONT_STACK], ["--font-composer", preferences.composer, "var(--font-sans)"], + ["--font-chat", preferences.chat, "var(--font-sans)"], ]; for (const [variable, custom, fallback] of families) { const list = cssFontFamilies(custom); @@ -89,6 +95,13 @@ export function applyAppearanceFontVariables( root.style.fontSize = `${clampInterfaceFontSize(preferences.sizeInterface)}px`; root.style.setProperty("--font-size-prompt", `${clampPromptFontSize(preferences.sizePrompt)}px`); + const chat = clampChatFontSize(preferences.sizeChat); + // The default leaves messages on their rem size, so they keep following the interface size. + if (chat === DEFAULT_CHAT_FONT_SIZE) { + root.style.removeProperty("--font-size-chat"); + } else { + root.style.setProperty("--font-size-chat", `${chat}px`); + } const code = clampCodeFontSize(preferences.sizeCode); root.style.setProperty("--font-size-code", `${code}px`); root.style.setProperty("--diffs-font-size", `${code}px`); @@ -118,6 +131,10 @@ function clampPromptFontSize(value: number): number { return clampFontSize(value, MIN_PROMPT_FONT_SIZE, MAX_PROMPT_FONT_SIZE, DEFAULT_PROMPT_FONT_SIZE); } +function clampChatFontSize(value: number): number { + return clampFontSize(value, MIN_CHAT_FONT_SIZE, MAX_CHAT_FONT_SIZE, DEFAULT_CHAT_FONT_SIZE); +} + function clampCodeFontSize(value: number): number { return clampFontSize(value, MIN_CODE_FONT_SIZE, MAX_CODE_FONT_SIZE, DEFAULT_CODE_FONT_SIZE); } diff --git a/apps/web/src/components/NoProjectsHero.tsx b/apps/web/src/components/NoProjectsHero.tsx index e6ebe6536c519..e3b80ec490a34 100644 --- a/apps/web/src/components/NoProjectsHero.tsx +++ b/apps/web/src/components/NoProjectsHero.tsx @@ -28,7 +28,9 @@ export function NoProjectsHero() {
- What should we work on? + + What should we work on? + {scratchTargetEnvironmentId === null ? "Add a project to start your first thread." diff --git a/apps/web/src/components/chat/DraftHeroHeadline.tsx b/apps/web/src/components/chat/DraftHeroHeadline.tsx index d2e259692204b..56b5f868c75ef 100644 --- a/apps/web/src/components/chat/DraftHeroHeadline.tsx +++ b/apps/web/src/components/chat/DraftHeroHeadline.tsx @@ -387,7 +387,7 @@ export function DraftHeroHeadline({ {projectSelector} ) : ( -

+

{isScratchDraft ? ( <>What should we work on? ) : canChooseProject ? ( diff --git a/apps/web/src/components/chat/DraftHeroProjectHeading.tsx b/apps/web/src/components/chat/DraftHeroProjectHeading.tsx index d5db58f503afe..f0cc1ccebdd51 100644 --- a/apps/web/src/components/chat/DraftHeroProjectHeading.tsx +++ b/apps/web/src/components/chat/DraftHeroProjectHeading.tsx @@ -30,7 +30,11 @@ export function DraftHeroProjectHeading({ }, []); return ( -
+