From 911199b21a777744097806991940a69ed987ad9a Mon Sep 17 00:00:00 2001 From: Armando Vaquera <263793884+proyectoauraorg@users.noreply.github.com> Date: Sat, 23 May 2026 18:56:57 -0600 Subject: [PATCH 1/4] feat(settings): add configurable chat font size (#157) The Zoo Code chat font could not be sized independently of VS Code's UI zoom. Adds an optional chatFontSize setting (px, 8-32) surfaced as a slider with a 'Use VS Code default' reset in the UI settings section. When unset the appearance is unchanged: the --zoo-chat-font-size CSS var defaults to --vscode-font-size, and the webview text scale derives from it. When set, the value is applied to the document root and persisted via the generic updateSettings path (nullish + null-on-reset, matching allowedMaxRequests). Includes init-vs-user-edit webview tests and full i18n for all 18 locales. Closes #157 --- packages/types/src/global-settings.ts | 5 ++ packages/types/src/vscode-extension-host.ts | 1 + src/core/webview/ClineProvider.ts | 3 ++ .../src/components/settings/SettingsView.tsx | 3 ++ .../src/components/settings/UISettings.tsx | 47 ++++++++++++++++ .../settings/__tests__/UISettings.spec.tsx | 46 ++++++++++++++++ .../src/context/ExtensionStateContext.tsx | 14 +++++ .../__tests__/ExtensionStateContext.spec.tsx | 53 +++++++++++++++++++ webview-ui/src/i18n/locales/ca/settings.json | 5 ++ webview-ui/src/i18n/locales/de/settings.json | 5 ++ webview-ui/src/i18n/locales/en/settings.json | 5 ++ webview-ui/src/i18n/locales/es/settings.json | 5 ++ webview-ui/src/i18n/locales/fr/settings.json | 5 ++ webview-ui/src/i18n/locales/hi/settings.json | 5 ++ webview-ui/src/i18n/locales/id/settings.json | 5 ++ webview-ui/src/i18n/locales/it/settings.json | 5 ++ webview-ui/src/i18n/locales/ja/settings.json | 5 ++ webview-ui/src/i18n/locales/ko/settings.json | 5 ++ webview-ui/src/i18n/locales/nl/settings.json | 5 ++ webview-ui/src/i18n/locales/pl/settings.json | 5 ++ .../src/i18n/locales/pt-BR/settings.json | 5 ++ webview-ui/src/i18n/locales/ru/settings.json | 5 ++ webview-ui/src/i18n/locales/tr/settings.json | 5 ++ webview-ui/src/i18n/locales/vi/settings.json | 5 ++ .../src/i18n/locales/zh-CN/settings.json | 5 ++ .../src/i18n/locales/zh-TW/settings.json | 5 ++ webview-ui/src/index.css | 15 ++++-- 27 files changed, 273 insertions(+), 4 deletions(-) diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 3a5a99eb98..b9e896eebd 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -201,6 +201,11 @@ export const globalSettingsSchema = z.object({ includeTaskHistoryInEnhance: z.boolean().optional(), historyPreviewCollapsed: z.boolean().optional(), reasoningBlockCollapsed: z.boolean().optional(), + /** + * Font size (in pixels) for the Zoo Code chat/webview UI. + * When unset (or `null`), the webview inherits VS Code's `--vscode-font-size`. + */ + chatFontSize: z.number().int().min(8).max(32).nullish(), /** * Controls the keyboard behavior for sending messages in the chat input. * - "send": Enter sends message, Shift+Enter creates newline (default) diff --git a/packages/types/src/vscode-extension-host.ts b/packages/types/src/vscode-extension-host.ts index c09f22aed7..990715ab8e 100644 --- a/packages/types/src/vscode-extension-host.ts +++ b/packages/types/src/vscode-extension-host.ts @@ -293,6 +293,7 @@ export type ExtensionState = Pick< | "openRouterImageGenerationSelectedModel" | "includeTaskHistoryInEnhance" | "reasoningBlockCollapsed" + | "chatFontSize" | "enterBehavior" | "includeCurrentTime" | "includeCurrentCost" diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 3f5af94cae..94bae24e46 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2071,6 +2071,7 @@ export class ClineProvider maxTotalImageSize, historyPreviewCollapsed, reasoningBlockCollapsed, + chatFontSize, enterBehavior, cloudUserInfo, cloudIsAuthenticated, @@ -2229,6 +2230,7 @@ export class ClineProvider settingsImportedAt: this.settingsImportedAt, historyPreviewCollapsed: historyPreviewCollapsed ?? false, reasoningBlockCollapsed: reasoningBlockCollapsed ?? true, + chatFontSize, enterBehavior: enterBehavior ?? "send", cloudUserInfo, cloudIsAuthenticated: cloudIsAuthenticated ?? false, @@ -2428,6 +2430,7 @@ export class ClineProvider maxTotalImageSize: stateValues.maxTotalImageSize ?? 20, historyPreviewCollapsed: stateValues.historyPreviewCollapsed ?? false, reasoningBlockCollapsed: stateValues.reasoningBlockCollapsed ?? true, + chatFontSize: stateValues.chatFontSize, enterBehavior: stateValues.enterBehavior ?? "send", cloudUserInfo, cloudIsAuthenticated, diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 47e087615e..8197c858a7 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -199,6 +199,7 @@ const SettingsView = forwardRef(({ onDone, t openRouterImageApiKey, openRouterImageGenerationSelectedModel, reasoningBlockCollapsed, + chatFontSize, enterBehavior, includeCurrentTime, includeCurrentCost, @@ -412,6 +413,7 @@ const SettingsView = forwardRef(({ onDone, t followupAutoApproveTimeoutMs, includeTaskHistoryInEnhance: includeTaskHistoryInEnhance ?? true, reasoningBlockCollapsed: reasoningBlockCollapsed ?? true, + chatFontSize: chatFontSize ?? null, enterBehavior: enterBehavior ?? "send", includeCurrentTime: includeCurrentTime ?? true, includeCurrentCost: includeCurrentCost ?? true, @@ -892,6 +894,7 @@ const SettingsView = forwardRef(({ onDone, t )} diff --git a/webview-ui/src/components/settings/UISettings.tsx b/webview-ui/src/components/settings/UISettings.tsx index a3488dc59e..49dbba347b 100644 --- a/webview-ui/src/components/settings/UISettings.tsx +++ b/webview-ui/src/components/settings/UISettings.tsx @@ -7,17 +7,24 @@ import { SetCachedStateField } from "./types" import { SectionHeader } from "./SectionHeader" import { Section } from "./Section" import { SearchableSetting } from "./SearchableSetting" +import { Slider, Button } from "../ui" import { ExtensionStateContextType } from "@/context/ExtensionStateContext" +export const CHAT_FONT_SIZE_MIN = 8 +export const CHAT_FONT_SIZE_MAX = 32 +export const CHAT_FONT_SIZE_DEFAULT = 13 + interface UISettingsProps extends HTMLAttributes { reasoningBlockCollapsed: boolean enterBehavior: "send" | "newline" + chatFontSize?: number setCachedStateField: SetCachedStateField } export const UISettings = ({ reasoningBlockCollapsed, enterBehavior, + chatFontSize, setCachedStateField, ...props }: UISettingsProps) => { @@ -48,6 +55,14 @@ export const UISettings = ({ }) } + const handleChatFontSizeChange = (value: number) => { + setCachedStateField("chatFontSize", value) + } + + const handleChatFontSizeReset = () => { + setCachedStateField("chatFontSize", undefined) + } + return (
{t("settings:sections.ui")} @@ -91,6 +106,38 @@ export const UISettings = ({
+ + {/* Chat Font Size Setting */} + +
+ +
+ handleChatFontSizeChange(value)} + data-testid="chat-font-size-slider" + /> + {chatFontSize ?? CHAT_FONT_SIZE_DEFAULT}px + +
+
+ {t("settings:ui.chatFontSize.description")} +
+
+
diff --git a/webview-ui/src/components/settings/__tests__/UISettings.spec.tsx b/webview-ui/src/components/settings/__tests__/UISettings.spec.tsx index 2a21a410b3..b5c7bc15c7 100644 --- a/webview-ui/src/components/settings/__tests__/UISettings.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/UISettings.spec.tsx @@ -41,4 +41,50 @@ describe("UISettings", () => { rerender() expect(checkbox.checked).toBe(true) }) + + describe("chat font size", () => { + it("shows the default font size when unset (init)", () => { + const { getByText, getByTestId } = render() + expect(getByTestId("chat-font-size-slider")).toBeTruthy() + // Default falls back to VS Code-equivalent default value. + expect(getByText("13px")).toBeTruthy() + }) + + it("shows the configured font size when set", () => { + const { getByText } = render() + expect(getByText("20px")).toBeTruthy() + }) + + it("persists a user-edited font size via setCachedStateField", () => { + const setCachedStateField = vi.fn() + const { getByTestId } = render( + , + ) + + const slider = getByTestId("chat-font-size-slider").querySelector('[role="slider"]') as HTMLElement + slider.focus() + fireEvent.keyDown(slider, { key: "ArrowRight" }) + + expect(setCachedStateField).toHaveBeenCalledWith("chatFontSize", 15) + }) + + it("disables reset when unset and clears the value on reset", () => { + const setCachedStateField = vi.fn() + const { getByTestId, rerender } = render( + , + ) + + const resetUnset = getByTestId("chat-font-size-reset") as HTMLButtonElement + expect(resetUnset.disabled).toBe(true) + + rerender( + , + ) + const resetSet = getByTestId("chat-font-size-reset") as HTMLButtonElement + expect(resetSet.disabled).toBe(false) + + fireEvent.click(resetSet) + expect(setCachedStateField).toHaveBeenCalledWith("chatFontSize", undefined) + }) + }) }) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index 10b49e3de0..476e7aebb5 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -124,6 +124,8 @@ export interface ExtensionStateContextType extends ExtensionState { togglePinnedApiConfig: (configName: string) => void setHistoryPreviewCollapsed: (value: boolean) => void setReasoningBlockCollapsed: (value: boolean) => void + chatFontSize?: number + setChatFontSize: (value: number | undefined) => void enterBehavior?: "send" | "newline" setEnterBehavior: (value: "send" | "newline") => void autoCondenseContext: boolean @@ -473,6 +475,17 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode vscode.postMessage({ type: "webviewDidLaunch" }) }, []) + // Apply the configurable chat font size as a CSS variable. When unset, the + // override is removed so the UI falls back to VS Code's `--vscode-font-size`. + useEffect(() => { + const root = document.documentElement + if (typeof state.chatFontSize === "number") { + root.style.setProperty("--zoo-chat-font-size", `${state.chatFontSize}px`) + } else { + root.style.removeProperty("--zoo-chat-font-size") + } + }, [state.chatFontSize]) + const contextValue: ExtensionStateContextType = { ...state, reasoningBlockCollapsed: state.reasoningBlockCollapsed ?? true, @@ -572,6 +585,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode setState((prevState) => ({ ...prevState, historyPreviewCollapsed: value })), setReasoningBlockCollapsed: (value) => setState((prevState) => ({ ...prevState, reasoningBlockCollapsed: value })), + setChatFontSize: (value) => setState((prevState) => ({ ...prevState, chatFontSize: value })), enterBehavior: state.enterBehavior ?? "send", setEnterBehavior: (value) => setState((prevState) => ({ ...prevState, enterBehavior: value })), setHasOpenedModeSelector: (value) => setState((prevState) => ({ ...prevState, hasOpenedModeSelector: value })), diff --git a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx index 2a5e74c40d..a795c08897 100644 --- a/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx +++ b/webview-ui/src/context/__tests__/ExtensionStateContext.spec.tsx @@ -29,6 +29,22 @@ const TestComponent = () => { ) } +const ChatFontSizeTestComponent = () => { + const { chatFontSize, setChatFontSize } = useExtensionState() + + return ( +
+
{JSON.stringify(chatFontSize ?? null)}
+ + +
+ ) +} + const ApiConfigTestComponent = () => { const { apiConfiguration, setApiConfiguration } = useExtensionState() @@ -92,6 +108,43 @@ describe("ExtensionStateContext", () => { expect(JSON.parse(screen.getByTestId("show-rooignored-files").textContent!)).toBe(false) }) + it("does not set the chat font-size CSS variable when unset (init)", () => { + document.documentElement.style.removeProperty("--zoo-chat-font-size") + + render( + + + , + ) + + expect(JSON.parse(screen.getByTestId("chat-font-size").textContent!)).toBe(null) + expect(document.documentElement.style.getPropertyValue("--zoo-chat-font-size")).toBe("") + }) + + it("applies the chat font-size CSS variable when set, and clears it on reset", () => { + document.documentElement.style.removeProperty("--zoo-chat-font-size") + + render( + + + , + ) + + act(() => { + screen.getByTestId("set-font-size-button").click() + }) + + expect(JSON.parse(screen.getByTestId("chat-font-size").textContent!)).toBe(20) + expect(document.documentElement.style.getPropertyValue("--zoo-chat-font-size")).toBe("20px") + + act(() => { + screen.getByTestId("reset-font-size-button").click() + }) + + expect(JSON.parse(screen.getByTestId("chat-font-size").textContent!)).toBe(null) + expect(document.documentElement.style.getPropertyValue("--zoo-chat-font-size")).toBe("") + }) + it("updates allowedCommands through setAllowedCommands", () => { render( diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 92ecfa7e73..20827758e2 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Requereix {{primaryMod}}+Intro per enviar missatges", "description": "Quan estigui activat, has de prémer {{primaryMod}}+Intro per enviar missatges en lloc de només Intro" + }, + "chatFontSize": { + "label": "Mida de lletra del xat", + "description": "Defineix la mida de la lletra (en píxels) del xat de Zoo Code. Deixa-ho al valor per defecte per coincidir amb la mida de lletra del VS Code.", + "reset": "Utilitza el valor per defecte del VS Code" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 5154d11039..49af834e3d 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "{{primaryMod}}+Enter zum Senden erfordern", "description": "Wenn aktiviert, musst du {{primaryMod}}+Enter drücken, um Nachrichten zu senden, anstatt nur Enter" + }, + "chatFontSize": { + "label": "Chat-Schriftgröße", + "description": "Lege die Schriftgröße (in Pixeln) für den Zoo Code-Chat fest. Belasse den Standardwert, um die Schriftgröße von VS Code zu übernehmen.", + "reset": "VS Code-Standard verwenden" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index a3c11be386..c14430f9b8 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -160,6 +160,11 @@ "requireCtrlEnterToSend": { "label": "Require {{primaryMod}}+Enter to send messages", "description": "When enabled, you must press {{primaryMod}}+Enter to send messages instead of just Enter" + }, + "chatFontSize": { + "label": "Chat font size", + "description": "Set the font size (in pixels) for the Zoo Code chat. Leave at the default to match VS Code's font size.", + "reset": "Use VS Code default" } }, "prompts": { diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 8ec3e29338..5eafedb3fb 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Requerir {{primaryMod}}+Enter para enviar mensajes", "description": "Cuando está activado, debes presionar {{primaryMod}}+Enter para enviar mensajes en lugar de solo Enter" + }, + "chatFontSize": { + "label": "Tamaño de fuente del chat", + "description": "Establece el tamaño de fuente (en píxeles) del chat de Zoo Code. Déjalo en el valor predeterminado para que coincida con el tamaño de fuente de VS Code.", + "reset": "Usar el valor predeterminado de VS Code" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index d746111a0a..7f6d92b317 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Exiger {{primaryMod}}+Entrée pour envoyer les messages", "description": "Lorsqu'activé, tu dois appuyer sur {{primaryMod}}+Entrée pour envoyer des messages au lieu de simplement Entrée" + }, + "chatFontSize": { + "label": "Taille de police du chat", + "description": "Définissez la taille de police (en pixels) du chat Zoo Code. Laissez la valeur par défaut pour correspondre à la taille de police de VS Code.", + "reset": "Utiliser la valeur par défaut de VS Code" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 9a77b69ee4..503cae1f1c 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "संदेश भेजने के लिए {{primaryMod}}+Enter की आवश्यकता है", "description": "जब सक्षम हो, तो आपको केवल Enter के बजाय संदेश भेजने के लिए {{primaryMod}}+Enter दबाना होगा" + }, + "chatFontSize": { + "label": "चैट फ़ॉन्ट आकार", + "description": "Zoo Code चैट के लिए फ़ॉन्ट आकार (पिक्सेल में) सेट करें। VS Code के फ़ॉन्ट आकार से मेल खाने के लिए डिफ़ॉल्ट पर छोड़ दें।", + "reset": "VS Code डिफ़ॉल्ट का उपयोग करें" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 41eae1b053..181dc0f748 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Memerlukan {{primaryMod}}+Enter untuk mengirim pesan", "description": "Ketika diaktifkan, kamu harus menekan {{primaryMod}}+Enter untuk mengirim pesan alih-alih hanya Enter" + }, + "chatFontSize": { + "label": "Ukuran font obrolan", + "description": "Atur ukuran font (dalam piksel) untuk obrolan Zoo Code. Biarkan pada nilai default agar sesuai dengan ukuran font VS Code.", + "reset": "Gunakan default VS Code" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 806fb44462..80be04f65c 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Richiedi {{primaryMod}}+Invio per inviare messaggi", "description": "Quando abilitato, devi premere {{primaryMod}}+Invio per inviare messaggi invece di solo Invio" + }, + "chatFontSize": { + "label": "Dimensione carattere della chat", + "description": "Imposta la dimensione del carattere (in pixel) per la chat di Zoo Code. Lascia il valore predefinito per adattarsi alla dimensione del carattere di VS Code.", + "reset": "Usa il valore predefinito di VS Code" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index b9a0976c42..f0dc3f782d 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "メッセージを送信するには{{primaryMod}}+Enterが必要", "description": "有効にすると、Enterだけでなく{{primaryMod}}+Enterを押してメッセージを送信する必要があります" + }, + "chatFontSize": { + "label": "チャットのフォントサイズ", + "description": "Zoo Code チャットのフォントサイズ(ピクセル単位)を設定します。VS Code のフォントサイズに合わせるには既定値のままにしてください。", + "reset": "VS Code の既定値を使用" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 3a88c9fbde..4f73144ae6 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "메시지를 보내려면 {{primaryMod}}+Enter가 필요", "description": "활성화하면 Enter만으로는 안 되고 {{primaryMod}}+Enter를 눌러야 메시지를 보낼 수 있습니다" + }, + "chatFontSize": { + "label": "채팅 글꼴 크기", + "description": "Zoo Code 채팅의 글꼴 크기(픽셀)를 설정합니다. VS Code 글꼴 크기에 맞추려면 기본값으로 두세요.", + "reset": "VS Code 기본값 사용" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index a91bb87de5..733de12b9b 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Vereist {{primaryMod}}+Enter om berichten te versturen", "description": "Wanneer ingeschakeld, moet je {{primaryMod}}+Enter indrukken om berichten te versturen in plaats van alleen Enter" + }, + "chatFontSize": { + "label": "Lettergrootte van chat", + "description": "Stel de lettergrootte (in pixels) in voor de Zoo Code-chat. Laat op de standaardwaarde staan om overeen te komen met de lettergrootte van VS Code.", + "reset": "VS Code-standaard gebruiken" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index f3751196d8..11c261ad1d 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Wymagaj {{primaryMod}}+Enter do wysyłania wiadomości", "description": "Po włączeniu musisz nacisnąć {{primaryMod}}+Enter, aby wysłać wiadomości, zamiast tylko Enter" + }, + "chatFontSize": { + "label": "Rozmiar czcionki czatu", + "description": "Ustaw rozmiar czcionki (w pikselach) dla czatu Zoo Code. Pozostaw wartość domyślną, aby dopasować ją do rozmiaru czcionki VS Code.", + "reset": "Użyj wartości domyślnej VS Code" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 05d3557f76..22160d1788 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Requer {{primaryMod}}+Enter para enviar mensagens", "description": "Quando ativado, você deve pressionar {{primaryMod}}+Enter para enviar mensagens em vez de apenas Enter" + }, + "chatFontSize": { + "label": "Tamanho da fonte do chat", + "description": "Defina o tamanho da fonte (em pixels) do chat do Zoo Code. Deixe no padrão para corresponder ao tamanho da fonte do VS Code.", + "reset": "Usar o padrão do VS Code" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 1aedb8a575..a878c389b5 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Требовать {{primaryMod}}+Enter для отправки сообщений", "description": "Если включено, необходимо нажать {{primaryMod}}+Enter для отправки сообщений вместо простого Enter" + }, + "chatFontSize": { + "label": "Размер шрифта чата", + "description": "Задайте размер шрифта (в пикселях) для чата Zoo Code. Оставьте значение по умолчанию, чтобы соответствовать размеру шрифта VS Code.", + "reset": "Использовать значение по умолчанию VS Code" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 22bd730488..f1a84c38bf 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Mesaj göndermek için {{primaryMod}}+Enter gerekli", "description": "Etkinleştirildiğinde, sadece Enter yerine mesaj göndermek için {{primaryMod}}+Enter'a basmalısınız" + }, + "chatFontSize": { + "label": "Sohbet yazı tipi boyutu", + "description": "Zoo Code sohbeti için yazı tipi boyutunu (piksel cinsinden) ayarlayın. VS Code yazı tipi boyutuyla eşleşmesi için varsayılan değerde bırakın.", + "reset": "VS Code varsayılanını kullan" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 0b09ae004b..92f4cbb7f3 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "Yêu cầu {{primaryMod}}+Enter để gửi tin nhắn", "description": "Khi được bật, bạn phải nhấn {{primaryMod}}+Enter để gửi tin nhắn thay vì chỉ nhấn Enter" + }, + "chatFontSize": { + "label": "Cỡ chữ trò chuyện", + "description": "Đặt cỡ chữ (tính bằng pixel) cho cuộc trò chuyện Zoo Code. Để ở giá trị mặc định để khớp với cỡ chữ của VS Code.", + "reset": "Dùng mặc định của VS Code" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index f58ea87f8c..5631f55179 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -960,6 +960,11 @@ "requireCtrlEnterToSend": { "label": "需要 {{primaryMod}}+Enter 发送消息", "description": "启用后,必须按 {{primaryMod}}+Enter 发送消息,而不仅仅是 Enter" + }, + "chatFontSize": { + "label": "聊天字体大小", + "description": "设置 Zoo Code 聊天的字体大小(以像素为单位)。保留默认值以匹配 VS Code 的字体大小。", + "reset": "使用 VS Code 默认值" } }, "skills": { diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index e4268280de..5d2b4634df 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -107,6 +107,11 @@ "requireCtrlEnterToSend": { "label": "需要 {{primaryMod}}+Enter 傳送訊息", "description": "啟用後,必須按 {{primaryMod}}+Enter 傳送訊息,而不只是 Enter" + }, + "chatFontSize": { + "label": "聊天字型大小", + "description": "設定 Zoo Code 聊天的字型大小(以像素為單位)。保留預設值以符合 VS Code 的字型大小。", + "reset": "使用 VS Code 預設值" } }, "prompts": { diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index ebb9a2fb90..9a142b07db 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -25,10 +25,10 @@ @theme { --font-display: var(--vscode-font-family); - --text-xs: calc(var(--vscode-font-size) * 0.85); - --text-sm: calc(var(--vscode-font-size) * 0.9); - --text-base: var(--vscode-font-size); - --text-lg: calc(var(--vscode-font-size) * 1.1); + --text-xs: calc(var(--zoo-chat-font-size) * 0.85); + --text-sm: calc(var(--zoo-chat-font-size) * 0.9); + --text-base: var(--zoo-chat-font-size); + --text-lg: calc(var(--zoo-chat-font-size) * 1.1); --color-background: var(--background); --color-foreground: var(--foreground); @@ -253,11 +253,18 @@ html { height: 100%; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + /* + * Base font size for the Zoo Code chat/webview UI. Defaults to VS Code's + * font size so appearance is unchanged unless the user configures the + * "Chat font size" setting, which overrides this variable at runtime. + */ + --zoo-chat-font-size: var(--vscode-font-size); } body { margin: 0; line-height: 1.25; + font-size: var(--zoo-chat-font-size); } body.scrollable, From 48b680d01811aa3448a929462f46d0d62da483c5 Mon Sep 17 00:00:00 2001 From: Armando Vaquera <263793884+proyectoauraorg@users.noreply.github.com> Date: Sat, 23 May 2026 19:20:52 -0600 Subject: [PATCH 2/4] fix(webview): normalize nullish chatFontSize in context value (#157) --- webview-ui/src/context/ExtensionStateContext.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/webview-ui/src/context/ExtensionStateContext.tsx b/webview-ui/src/context/ExtensionStateContext.tsx index 476e7aebb5..f81de054c7 100644 --- a/webview-ui/src/context/ExtensionStateContext.tsx +++ b/webview-ui/src/context/ExtensionStateContext.tsx @@ -488,6 +488,9 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode const contextValue: ExtensionStateContextType = { ...state, + // `chatFontSize` is persisted as nullish (null on reset); normalize null to + // undefined so it matches the context type and means "use VS Code default". + chatFontSize: state.chatFontSize ?? undefined, reasoningBlockCollapsed: state.reasoningBlockCollapsed ?? true, didHydrateState, showWelcome, From a046159073a234b3faf836352c0e54a7300ee0c1 Mon Sep 17 00:00:00 2001 From: Armando Vaquera <263793884+proyectoauraorg@users.noreply.github.com> Date: Sun, 24 May 2026 12:41:14 -0600 Subject: [PATCH 3/4] fix(settings): scope chat font size to the chat markdown surface (#157) --- .../src/components/common/MarkdownBlock.tsx | 2 +- .../settings/__tests__/SettingsView.spec.tsx | 31 +++++++++++++++++++ webview-ui/src/index.css | 16 +++++----- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/webview-ui/src/components/common/MarkdownBlock.tsx b/webview-ui/src/components/common/MarkdownBlock.tsx index 2553a5e558..7280cea77a 100644 --- a/webview-ui/src/components/common/MarkdownBlock.tsx +++ b/webview-ui/src/components/common/MarkdownBlock.tsx @@ -83,7 +83,7 @@ const StyledMarkdown = styled.div` "Helvetica Neue", sans-serif; - font-size: var(--vscode-font-size, 13px); + font-size: var(--zoo-chat-font-size, var(--vscode-font-size, 13px)); p, li, diff --git a/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx b/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx index 6fa34ebe81..2457c554b0 100644 --- a/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/SettingsView.spec.tsx @@ -412,6 +412,37 @@ describe("SettingsView - Sound Settings", () => { ) }) + it("saves the selected chat font size and persists null on reset", () => { + const { activateTab, getSettingsContent } = renderSettingsView() + + activateTab("ui") + + const content = getSettingsContent() + const slider = within(content).getByTestId("chat-font-size-slider") + + // Pick a size, then Save — the boundary should forward it to the host. + fireEvent.change(slider, { target: { value: "18" } }) + fireEvent.click(screen.getByTestId("save-button")) + + expect(vscode.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ + type: "updateSettings", + updatedSettings: expect.objectContaining({ chatFontSize: 18 }), + }), + ) + + // Reset clears the override; it is persisted as null (not undefined). + fireEvent.click(within(getSettingsContent()).getByTestId("chat-font-size-reset")) + fireEvent.click(screen.getByTestId("save-button")) + + expect(vscode.postMessage).toHaveBeenCalledWith( + expect.objectContaining({ + type: "updateSettings", + updatedSettings: expect.objectContaining({ chatFontSize: null }), + }), + ) + }) + it("shows tts slider when sound is enabled", () => { // Render once and get the activateTab helper const { activateTab, getSettingsContent } = renderSettingsView() diff --git a/webview-ui/src/index.css b/webview-ui/src/index.css index 9a142b07db..b93603f5a6 100644 --- a/webview-ui/src/index.css +++ b/webview-ui/src/index.css @@ -25,10 +25,10 @@ @theme { --font-display: var(--vscode-font-family); - --text-xs: calc(var(--zoo-chat-font-size) * 0.85); - --text-sm: calc(var(--zoo-chat-font-size) * 0.9); - --text-base: var(--zoo-chat-font-size); - --text-lg: calc(var(--zoo-chat-font-size) * 1.1); + --text-xs: calc(var(--vscode-font-size) * 0.85); + --text-sm: calc(var(--vscode-font-size) * 0.9); + --text-base: var(--vscode-font-size); + --text-lg: calc(var(--vscode-font-size) * 1.1); --color-background: var(--background); --color-foreground: var(--foreground); @@ -254,9 +254,10 @@ html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; /* - * Base font size for the Zoo Code chat/webview UI. Defaults to VS Code's - * font size so appearance is unchanged unless the user configures the - * "Chat font size" setting, which overrides this variable at runtime. + * Font size for the Zoo Code chat message surface (consumed by MarkdownBlock). + * Defaults to VS Code's font size so appearance is unchanged unless the user + * configures the "Chat font size" setting, which overrides this variable at + * runtime. Scoped to chat rendering so it does not resize settings/other UI. */ --zoo-chat-font-size: var(--vscode-font-size); } @@ -264,7 +265,6 @@ html { body { margin: 0; line-height: 1.25; - font-size: var(--zoo-chat-font-size); } body.scrollable, From e94e2609cea38d9e19b216fa490105aa6654086e Mon Sep 17 00:00:00 2001 From: Armando Vaquera <263793884+proyectoauraorg@users.noreply.github.com> Date: Wed, 27 May 2026 04:11:29 -0600 Subject: [PATCH 4/4] feat(settings): emit telemetry for chat font size changes (#157) The chat font size change/reset handlers now emit telemetry like the other UI settings handlers in this file (ui_settings_chat_font_size_changed with the value, and ui_settings_chat_font_size_reset). Covered by UISettings spec. --- webview-ui/src/components/settings/UISettings.tsx | 8 ++++++++ .../src/components/settings/__tests__/UISettings.spec.tsx | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/webview-ui/src/components/settings/UISettings.tsx b/webview-ui/src/components/settings/UISettings.tsx index 49dbba347b..3d67072a75 100644 --- a/webview-ui/src/components/settings/UISettings.tsx +++ b/webview-ui/src/components/settings/UISettings.tsx @@ -57,10 +57,18 @@ export const UISettings = ({ const handleChatFontSizeChange = (value: number) => { setCachedStateField("chatFontSize", value) + + // Track telemetry event + telemetryClient.capture("ui_settings_chat_font_size_changed", { + value, + }) } const handleChatFontSizeReset = () => { setCachedStateField("chatFontSize", undefined) + + // Track telemetry event + telemetryClient.capture("ui_settings_chat_font_size_reset") } return ( diff --git a/webview-ui/src/components/settings/__tests__/UISettings.spec.tsx b/webview-ui/src/components/settings/__tests__/UISettings.spec.tsx index b5c7bc15c7..618568daa0 100644 --- a/webview-ui/src/components/settings/__tests__/UISettings.spec.tsx +++ b/webview-ui/src/components/settings/__tests__/UISettings.spec.tsx @@ -1,6 +1,11 @@ import { render, fireEvent, waitFor } from "@testing-library/react" import { describe, it, expect, vi } from "vitest" import { UISettings } from "../UISettings" +import { telemetryClient } from "@/utils/TelemetryClient" + +vi.mock("@/utils/TelemetryClient", () => ({ + telemetryClient: { capture: vi.fn() }, +})) describe("UISettings", () => { const defaultProps = { @@ -66,6 +71,7 @@ describe("UISettings", () => { fireEvent.keyDown(slider, { key: "ArrowRight" }) expect(setCachedStateField).toHaveBeenCalledWith("chatFontSize", 15) + expect(telemetryClient.capture).toHaveBeenCalledWith("ui_settings_chat_font_size_changed", { value: 15 }) }) it("disables reset when unset and clears the value on reset", () => { @@ -85,6 +91,7 @@ describe("UISettings", () => { fireEvent.click(resetSet) expect(setCachedStateField).toHaveBeenCalledWith("chatFontSize", undefined) + expect(telemetryClient.capture).toHaveBeenCalledWith("ui_settings_chat_font_size_reset") }) }) })