feat(settings): editor font size for chat input and code editor (#1325) (#2065)

* feat(settings): add editor font size setting for chat input and code editor

Adds an 'Editor font size' control in Settings > Appearance that sets an
absolute px font size for the chat input textarea and the in-app
CodeMirror editor. Mirrors the existing terminalFontSize lifecycle.

- New store field editorFontSize (default 13, clamp 9-32, step 1) in
  useUIStore with narrow selectors at each consumer.
- Persistence wired through appearanceAutoSave, desktop + runtime API
  types, and persistence.ts read/normalize.
- Settings UI row (NumberInput) with reset to 13, VisibleSetting union
  entry, OpenChamberPage registration, and search index entry
  appearance.editor-font-size.
- Applied as a post-zoom absolute override on the chat input textarea
  and on the CodeMirror theme's content rule, leaving gutter/line-number
  chrome at its existing hardcoded sizes (matches terminal scope).
- All 10 locales translated (en, es, fr, ja, ko, pl, pt-BR, uk, zh-CN,
  zh-TW); no English placeholders in non-English dictionaries.

Refs #1325

* fix(codemirror): use unitless lineHeight so it scales with editor font size

The & rule in the CodeMirror theme set lineHeight to 1.5rem (~24px),
which does not scale when editorFontSize is increased (e.g., 28-32px).
This causes overlapping lines at larger font sizes.

Change to unitless 1.5, which scales proportionally with whatever fontSize
resolves to (dynamic prop or --text-code fallback). Matches browser best
practice for proportional leading.

Review comment: https://github.com/openchamber/openchamber/pull/2065

---------

Co-authored-by: bashrusakh <bashrusakh@users.noreply.github.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Leonid
2026-07-11 14:45:27 +03:00
committed by GitHub
co-authored by bashrusakh Bohdan Triapitsyn
parent bfaf62e222
commit e0229917f8
23 changed files with 108 additions and 15 deletions
+1
View File
@@ -657,6 +657,7 @@ export interface SettingsPayload {
showSplitAssistantMessageActions?: boolean;
fontSize?: number;
terminalFontSize?: number;
editorFontSize?: number;
uiFont?: string;
monoFont?: string;
padding?: number;
@@ -31,6 +31,7 @@ type AppearanceSlice = {
sessionRetentionAction: 'archive' | 'delete';
fontSize: number;
terminalFontSize: number;
editorFontSize: number;
uiFont: UiFontOption;
monoFont: MonoFontOption;
padding: number;
@@ -72,6 +73,7 @@ export const startAppearanceAutoSave = (): void => {
sessionRetentionAction: useUIStore.getState().sessionRetentionAction,
fontSize: useUIStore.getState().fontSize,
terminalFontSize: useUIStore.getState().terminalFontSize,
editorFontSize: useUIStore.getState().editorFontSize,
uiFont: useUIStore.getState().uiFont,
monoFont: useUIStore.getState().monoFont,
padding: useUIStore.getState().padding,
@@ -125,6 +127,7 @@ export const startAppearanceAutoSave = (): void => {
sessionRetentionAction: state.sessionRetentionAction,
fontSize: state.fontSize,
terminalFontSize: state.terminalFontSize,
editorFontSize: state.editorFontSize,
uiFont: state.uiFont,
monoFont: state.monoFont,
padding: state.padding,
@@ -200,6 +203,9 @@ export const startAppearanceAutoSave = (): void => {
if (current.terminalFontSize !== previous.terminalFontSize) {
diff.terminalFontSize = current.terminalFontSize;
}
if (current.editorFontSize !== previous.editorFontSize) {
diff.editorFontSize = current.editorFontSize;
}
if (current.uiFont !== previous.uiFont) {
diff.uiFont = current.uiFont;
}
@@ -11,7 +11,7 @@ export function createFlexokiCodeMirrorTheme(
// When syntax colors are provided elsewhere (e.g. the Shiki decoration
// extension), pass `{ syntaxColors: false }` to keep only the editor UI theme
// (gutters, selection, cursor) and avoid a competing token color source.
options?: { syntaxColors?: boolean },
options?: { syntaxColors?: boolean; fontSize?: number },
): Extension {
const isDark = theme.metadata.variant === 'dark';
@@ -19,12 +19,14 @@ export function createFlexokiCodeMirrorTheme(
const highlights = theme.colors.syntax.highlights || {};
const tokens = theme.colors.syntax.tokens || {};
const contentFontSize = options?.fontSize ? `${options.fontSize}px` : 'var(--text-code)';
const ui = EditorView.theme({
'&': {
backgroundColor: 'var(--background)',
color: theme.colors.syntax.base.foreground,
fontSize: 'var(--text-code)',
lineHeight: '1.5rem',
fontSize: contentFontSize,
lineHeight: '1.5',
position: 'relative' as const,
},
'.cm-scroller': {
+1
View File
@@ -155,6 +155,7 @@ export type DesktopSettings = {
showSplitAssistantMessageActions?: boolean;
fontSize?: number;
terminalFontSize?: number;
editorFontSize?: number;
uiFont?: string;
monoFont?: string;
padding?: number;
@@ -1731,10 +1731,12 @@ export const settingsDict = {
'settings.openchamber.visual.field.fontSizePercentageAria': 'Font size percentage',
'settings.openchamber.visual.actions.resetFontSizeAria': 'Reset font size',
'settings.openchamber.visual.field.terminalFontSize': 'Terminal Font Size',
'settings.openchamber.visual.field.editorFontSize': 'Editor Font Size',
'settings.openchamber.visual.field.codeFont': 'Code Font',
'settings.openchamber.visual.field.selectCodeFontAria': 'Select code font',
'settings.openchamber.visual.actions.resetCodeFontAria': 'Reset code font',
'settings.openchamber.visual.actions.resetTerminalFontSizeAria': 'Reset terminal font size',
'settings.openchamber.visual.actions.resetEditorFontSizeAria': 'Reset editor font size',
'settings.openchamber.visual.field.spacingDensity': 'Spacing Density',
'settings.openchamber.visual.actions.resetSpacingAria': 'Reset spacing',
'settings.openchamber.visual.field.inputBarOffset': 'Input Bar Offset',
@@ -1698,10 +1698,12 @@ export const settingsDict = {
"settings.openchamber.visual.field.fontSizePercentageAria": "Porcentaje de tamaño de fuente",
"settings.openchamber.visual.actions.resetFontSizeAria": "Restablecer tamaño de fuente",
"settings.openchamber.visual.field.terminalFontSize": "Tamaño de fuente del terminal",
"settings.openchamber.visual.field.editorFontSize": "Tamaño de fuente del editor",
"settings.openchamber.visual.field.codeFont": "Fuente de código",
"settings.openchamber.visual.field.selectCodeFontAria": "Seleccionar fuente de código",
"settings.openchamber.visual.actions.resetCodeFontAria": "Restablecer fuente de código",
"settings.openchamber.visual.actions.resetTerminalFontSizeAria": "Restablecer tamaño de fuente del terminal",
"settings.openchamber.visual.actions.resetEditorFontSizeAria": "Restablecer tamaño de fuente del editor",
"settings.openchamber.visual.field.spacingDensity": "Densidad de espaciado",
"settings.openchamber.visual.actions.resetSpacingAria": "Restablecer espaciado",
"settings.openchamber.visual.field.inputBarOffset": "Desplazamiento de la barra de entrada",
@@ -1613,10 +1613,12 @@ export const settingsDict = {
'settings.openchamber.visual.field.fontSizePercentageAria': 'Pourcentage de taille de police',
'settings.openchamber.visual.actions.resetFontSizeAria': 'Réinitialiser la taille de la police',
'settings.openchamber.visual.field.terminalFontSize': 'Taille de la police du terminal',
'settings.openchamber.visual.field.editorFontSize': 'Taille de la police de l\'éditeur',
'settings.openchamber.visual.field.codeFont': 'Police de code',
'settings.openchamber.visual.field.selectCodeFontAria': 'Sélectionnez la police du code',
'settings.openchamber.visual.actions.resetCodeFontAria': 'Réinitialiser la police du code',
'settings.openchamber.visual.actions.resetTerminalFontSizeAria': 'Réinitialiser la taille de la police du terminal',
'settings.openchamber.visual.actions.resetEditorFontSizeAria': 'Réinitialiser la taille de la police de l\'éditeur',
'settings.openchamber.visual.field.spacingDensity': 'Densité d\'espacement',
'settings.openchamber.visual.actions.resetSpacingAria': 'Réinitialiser l\'espacement',
'settings.openchamber.visual.field.inputBarOffset': 'Décalage de la barre d\'entrée',
@@ -1731,10 +1731,12 @@ export const settingsDict = {
'settings.openchamber.visual.field.fontSizePercentageAria': 'フォントサイズの割合',
'settings.openchamber.visual.actions.resetFontSizeAria': 'フォントサイズをリセット',
'settings.openchamber.visual.field.terminalFontSize': 'ターミナルフォントサイズ',
'settings.openchamber.visual.field.editorFontSize': 'エディターフォントサイズ',
'settings.openchamber.visual.field.codeFont': 'コードフォント',
'settings.openchamber.visual.field.selectCodeFontAria': 'コードフォントを選択',
'settings.openchamber.visual.actions.resetCodeFontAria': 'コードフォントをリセット',
'settings.openchamber.visual.actions.resetTerminalFontSizeAria': 'ターミナルフォントサイズをリセット',
'settings.openchamber.visual.actions.resetEditorFontSizeAria': 'エディターフォントサイズをリセット',
'settings.openchamber.visual.field.spacingDensity': '間隔の密度',
'settings.openchamber.visual.actions.resetSpacingAria': '間隔をリセット',
'settings.openchamber.visual.field.inputBarOffset': '入力バーオフセット',
@@ -1698,10 +1698,12 @@ export const settingsDict = {
'settings.openchamber.visual.field.fontSizePercentageAria': '폰트 크기 비율',
'settings.openchamber.visual.actions.resetFontSizeAria': '폰트 크기 초기화',
'settings.openchamber.visual.field.terminalFontSize': '터미널 폰트 크기',
'settings.openchamber.visual.field.editorFontSize': '에디터 폰트 크기',
'settings.openchamber.visual.field.codeFont': '코드 폰트',
'settings.openchamber.visual.field.selectCodeFontAria': '코드 폰트 선택',
'settings.openchamber.visual.actions.resetCodeFontAria': '코드 폰트 초기화',
'settings.openchamber.visual.actions.resetTerminalFontSizeAria': '터미널 폰트 크기 초기화',
'settings.openchamber.visual.actions.resetEditorFontSizeAria': '에디터 폰트 크기 초기화',
'settings.openchamber.visual.field.spacingDensity': '간격 밀도',
'settings.openchamber.visual.actions.resetSpacingAria': '간격 초기화',
'settings.openchamber.visual.field.inputBarOffset': '입력 바 오프셋',
@@ -935,6 +935,7 @@ export const settingsDict = {
'settings.openchamber.visual.actions.resetInterfaceFontAria': 'Zresetuj czcionkę interfejsu',
'settings.openchamber.visual.actions.resetSpacingAria': 'Zresetuj odstępy',
'settings.openchamber.visual.actions.resetTerminalFontSizeAria': 'Zresetuj rozmiar czcionki terminala',
'settings.openchamber.visual.actions.resetEditorFontSizeAria': 'Zresetuj rozmiar czcionki edytora',
'settings.openchamber.visual.field.activityDefaultModeAria': 'Domyślny tryb aktywności: {option}',
'settings.openchamber.visual.field.bash': 'Bash',
'settings.openchamber.visual.field.codeFont': 'Czcionka kodu',
@@ -1004,6 +1005,7 @@ export const settingsDict = {
'settings.openchamber.visual.field.expandedEditorToolbarAria': 'Always show editor toolbar',
'settings.openchamber.visual.field.expandedEditorToolbar': 'Always show editor toolbar (docked under the file tabs)',
'settings.openchamber.visual.field.terminalFontSize': 'Rozmiar czcionki terminala',
'settings.openchamber.visual.field.editorFontSize': 'Rozmiar czcionki edytora',
'settings.openchamber.visual.field.terminalQuickKeys': 'Szybkie klawisze terminala',
'settings.openchamber.visual.field.terminalQuickKeysAria': 'Szybkie klawisze terminala',
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Pokaż Esc, Ctrl i strzałki w widoku terminala',
@@ -1698,10 +1698,12 @@ export const settingsDict = {
"settings.openchamber.visual.field.fontSizePercentageAria": "Porcentagem do tamanho base",
"settings.openchamber.visual.actions.resetFontSizeAria": "Redefinir tamanho base",
"settings.openchamber.visual.field.terminalFontSize": "Tamanho base do terminal",
"settings.openchamber.visual.field.editorFontSize": "Tamanho base do editor",
"settings.openchamber.visual.field.codeFont": "Fonte do código",
"settings.openchamber.visual.field.selectCodeFontAria": "Selecionar fonte do código",
"settings.openchamber.visual.actions.resetCodeFontAria": "Redefinir fonte do código",
"settings.openchamber.visual.actions.resetTerminalFontSizeAria": "Redefinir tamanho base do terminal",
"settings.openchamber.visual.actions.resetEditorFontSizeAria": "Redefinir tamanho base do editor",
"settings.openchamber.visual.field.spacingDensity": "Densidade de espaçamento",
"settings.openchamber.visual.actions.resetSpacingAria": "Redefinir espaçamento",
"settings.openchamber.visual.field.inputBarOffset": "Deslocamento da barra de entrada",
@@ -1698,10 +1698,12 @@ export const settingsDict = {
"settings.openchamber.visual.field.fontSizePercentageAria": "Розмір шрифту у відсотках",
"settings.openchamber.visual.actions.resetFontSizeAria": "Скинути розмір шрифту",
"settings.openchamber.visual.field.terminalFontSize": "Розмір шрифту терміналу",
"settings.openchamber.visual.field.editorFontSize": "Розмір шрифту редактора",
"settings.openchamber.visual.field.codeFont": "Шрифт коду",
"settings.openchamber.visual.field.selectCodeFontAria": "Вибрати шрифт коду",
"settings.openchamber.visual.actions.resetCodeFontAria": "Скинути шрифт коду",
"settings.openchamber.visual.actions.resetTerminalFontSizeAria": "Скинути розмір шрифту терміналу",
"settings.openchamber.visual.actions.resetEditorFontSizeAria": "Скинути розмір шрифту редактора",
"settings.openchamber.visual.field.spacingDensity": "Щільність інтервалу",
"settings.openchamber.visual.actions.resetSpacingAria": "Скинути інтервал",
"settings.openchamber.visual.field.inputBarOffset": "Зміщення панелі вводу",
@@ -1698,10 +1698,12 @@ export const settingsDict = {
'settings.openchamber.visual.field.fontSizePercentageAria': '字体大小百分比',
'settings.openchamber.visual.actions.resetFontSizeAria': '重置字体大小',
'settings.openchamber.visual.field.terminalFontSize': '终端字体大小',
'settings.openchamber.visual.field.editorFontSize': '编辑器字体大小',
'settings.openchamber.visual.field.codeFont': '代码字体',
'settings.openchamber.visual.field.selectCodeFontAria': '选择代码字体',
'settings.openchamber.visual.actions.resetCodeFontAria': '重置代码字体',
'settings.openchamber.visual.actions.resetTerminalFontSizeAria': '重置终端字体大小',
'settings.openchamber.visual.actions.resetEditorFontSizeAria': '重置编辑器字体大小',
'settings.openchamber.visual.field.spacingDensity': '间距密度',
'settings.openchamber.visual.actions.resetSpacingAria': '重置间距',
'settings.openchamber.visual.field.inputBarOffset': '输入栏偏移',
@@ -1609,10 +1609,12 @@
'settings.openchamber.visual.field.fontSizePercentageAria': '字體大小百分比',
'settings.openchamber.visual.actions.resetFontSizeAria': '重設字體大小',
'settings.openchamber.visual.field.terminalFontSize': '終端機字體大小',
'settings.openchamber.visual.field.editorFontSize': '編輯器字體大小',
'settings.openchamber.visual.field.codeFont': '程式碼字體',
'settings.openchamber.visual.field.selectCodeFontAria': '選擇程式碼字體',
'settings.openchamber.visual.actions.resetCodeFontAria': '重設程式碼字體',
'settings.openchamber.visual.actions.resetTerminalFontSizeAria': '重設終端機字體大小',
'settings.openchamber.visual.actions.resetEditorFontSizeAria': '重設編輯器字體大小',
'settings.openchamber.visual.field.spacingDensity': '間距密度',
'settings.openchamber.visual.actions.resetSpacingAria': '重設間距',
'settings.openchamber.visual.field.inputBarOffset': '輸入列偏移',
+6
View File
@@ -594,6 +594,9 @@ const applyDesktopUiPreferences = (settings: DesktopSettings) => {
if (typeof settings.terminalFontSize === 'number' && Number.isFinite(settings.terminalFontSize) && settings.terminalFontSize !== store.terminalFontSize) {
store.setTerminalFontSize(settings.terminalFontSize);
}
if (typeof settings.editorFontSize === 'number' && Number.isFinite(settings.editorFontSize) && settings.editorFontSize !== store.editorFontSize) {
store.setEditorFontSize(settings.editorFontSize);
}
if (isUiFontOption(settings.uiFont) && settings.uiFont !== store.uiFont) {
store.setUiFont(settings.uiFont);
}
@@ -1111,6 +1114,9 @@ const sanitizeWebSettings = (payload: unknown): DesktopSettings | null => {
if (typeof candidate.terminalFontSize === 'number' && Number.isFinite(candidate.terminalFontSize)) {
result.terminalFontSize = candidate.terminalFontSize;
}
if (typeof candidate.editorFontSize === 'number' && Number.isFinite(candidate.editorFontSize)) {
result.editorFontSize = candidate.editorFontSize;
}
if (isUiFontOption(candidate.uiFont)) {
result.uiFont = candidate.uiFont;
}
+6
View File
@@ -116,6 +116,12 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
titleKey: 'settings.openchamber.visual.field.terminalFontSize',
keywords: ['terminal', 'font', 'text size'],
},
{
id: 'appearance.editor-font-size',
page: 'appearance',
titleKey: 'settings.openchamber.visual.field.editorFontSize',
keywords: ['editor', 'font', 'text size', 'code'],
},
{
id: 'appearance.spacing-density',
page: 'appearance',