Terminal Settings
Configure global terminal appearance
@@ -1469,15 +1480,15 @@ export function TerminalView() {
{/* Default Font Size */}
-
-
+
+
{terminalState.defaultFontSize}px
setTerminalDefaultFontSize(value)}
onValueCommit={() => {
@@ -1488,37 +1499,79 @@ export function TerminalView() {
/>
+ {/* Default Run Script */}
+
+
+
setTerminalDefaultRunScript(e.target.value)}
+ placeholder="e.g., claude"
+ className="h-7 text-xs"
+ />
+
+ Command to run when creating a new terminal
+
+
+
{/* Font Family */}
-
-
+
+
+ {/* Scrollback */}
+
+
+
+
+ {(terminalState.scrollbackLines / 1000).toFixed(0)}k lines
+
+
+
setTerminalScrollbackLines(value)}
+ onValueCommit={() => {
+ toast.info('Scrollback changed', {
+ description: 'Restart terminal for changes to take effect',
+ });
+ }}
+ />
{/* Line Height */}
-
-
+
+
{terminalState.lineHeight.toFixed(1)}
@@ -1536,18 +1589,21 @@ export function TerminalView() {
/>
- {/* Default Run Script */}
-
-
-
setTerminalDefaultRunScript(e.target.value)}
- placeholder="e.g., claude, npm run dev"
- className="h-8 text-sm"
+ {/* Screen Reader */}
+
+
+
+
Enable accessibility mode
+
+
{
+ setTerminalScreenReaderMode(checked);
+ toast.info(checked ? 'Screen reader enabled' : 'Screen reader disabled', {
+ description: 'Restart terminal for changes to take effect',
+ });
+ }}
/>
-
- Command to run when opening new terminals
-
diff --git a/apps/ui/src/components/views/terminal-view/terminal-panel.tsx b/apps/ui/src/components/views/terminal-view/terminal-panel.tsx
index 24a91f46..481ee6b4 100644
--- a/apps/ui/src/components/views/terminal-view/terminal-panel.tsx
+++ b/apps/ui/src/components/views/terminal-view/terminal-panel.tsx
@@ -30,6 +30,13 @@ import { Slider } from '@/components/ui/slider';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import { Switch } from '@/components/ui/switch';
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select';
import { useDraggable, useDroppable } from '@dnd-kit/core';
import { useAppStore, DEFAULT_KEYBOARD_SHORTCUTS, type KeyboardShortcuts } from '@/store/app-store';
import { useShallow } from 'zustand/react/shallow';
@@ -38,7 +45,9 @@ import {
getTerminalTheme,
TERMINAL_FONT_OPTIONS,
DEFAULT_TERMINAL_FONT,
+ getTerminalFontFamily,
} from '@/config/terminal-themes';
+import { DEFAULT_FONT_VALUE } from '@/config/ui-font-options';
import { toast } from 'sonner';
import { getElectronAPI } from '@/lib/electron';
import { getApiKey, getSessionToken, getServerUrlSync } from '@/lib/http-api-client';
@@ -567,7 +576,7 @@ export function TerminalPanel({
// Get settings from store (read at initialization time)
const terminalSettings = useAppStore.getState().terminalState;
const screenReaderEnabled = terminalSettings.screenReaderMode;
- const terminalFontFamily = terminalSettings.fontFamily || DEFAULT_TERMINAL_FONT;
+ const terminalFontFamily = getTerminalFontFamily(terminalSettings.fontFamily);
const terminalScrollback = terminalSettings.scrollbackLines || 5000;
const terminalLineHeight = terminalSettings.lineHeight || 1.0;
@@ -1269,7 +1278,7 @@ export function TerminalPanel({
useEffect(() => {
if (xtermRef.current && isTerminalReady) {
- xtermRef.current.options.fontFamily = fontFamily;
+ xtermRef.current.options.fontFamily = getTerminalFontFamily(fontFamily);
fitAddonRef.current?.fit();
}
}, [fontFamily, isTerminalReady]);
@@ -1902,22 +1911,33 @@ export function TerminalPanel({
- {
- setTerminalFontFamily(e.target.value);
+ {
+ setTerminalFontFamily(value);
toast.info('Font family changed', {
description: 'Restart terminal for changes to take effect',
});
}}
- className="w-full h-7 text-xs bg-background border border-input rounded-md px-2"
>
- {TERMINAL_FONT_OPTIONS.map((font) => (
-
- ))}
-
+
+
+
+
+ {TERMINAL_FONT_OPTIONS.map((option) => (
+
+
+ {option.label}
+
+
+ ))}
+
+
diff --git a/apps/ui/src/config/terminal-themes.ts b/apps/ui/src/config/terminal-themes.ts
index e23feba3..4573bc01 100644
--- a/apps/ui/src/config/terminal-themes.ts
+++ b/apps/ui/src/config/terminal-themes.ts
@@ -4,6 +4,11 @@
*/
import type { ThemeMode } from '@/store/app-store';
+import {
+ UI_MONO_FONT_OPTIONS,
+ DEFAULT_FONT_VALUE,
+ type UIFontOption,
+} from '@/config/ui-font-options';
export interface TerminalTheme {
background: string;
@@ -37,27 +42,44 @@ export interface TerminalTheme {
/**
* Terminal font options for user selection
- * These are monospace fonts commonly available on different platforms
+ *
+ * Uses the same fonts as UI_MONO_FONT_OPTIONS for consistency across the app.
+ * All fonts listed here are bundled with the app via @fontsource packages
+ * or are system fonts with appropriate fallbacks.
*/
-export interface TerminalFontOption {
- value: string;
- label: string;
-}
-export const TERMINAL_FONT_OPTIONS: TerminalFontOption[] = [
- { value: "Menlo, Monaco, 'Courier New', monospace", label: 'Menlo / Monaco' },
- { value: "'SF Mono', Menlo, Monaco, monospace", label: 'SF Mono' },
- { value: "'JetBrains Mono', monospace", label: 'JetBrains Mono' },
- { value: "'Fira Code', monospace", label: 'Fira Code' },
- { value: "'Source Code Pro', monospace", label: 'Source Code Pro' },
- { value: "Consolas, 'Courier New', monospace", label: 'Consolas' },
- { value: "'Ubuntu Mono', monospace", label: 'Ubuntu Mono' },
-];
+// Re-export for backwards compatibility
+export type TerminalFontOption = UIFontOption;
/**
- * Default terminal font family (first option)
+ * Terminal font options - reuses UI_MONO_FONT_OPTIONS with terminal-specific default
+ *
+ * The 'default' value means "use the default terminal font" (Menlo/Monaco)
*/
-export const DEFAULT_TERMINAL_FONT = TERMINAL_FONT_OPTIONS[0].value;
+export const TERMINAL_FONT_OPTIONS: readonly UIFontOption[] = UI_MONO_FONT_OPTIONS.map((option) => {
+ // Replace the UI default label with terminal-specific default
+ if (option.value === DEFAULT_FONT_VALUE) {
+ return { value: option.value, label: 'Default (Menlo / Monaco)' };
+ }
+ return option;
+});
+
+/**
+ * Default terminal font family
+ * Uses the DEFAULT_FONT_VALUE sentinel which maps to Menlo/Monaco
+ */
+export const DEFAULT_TERMINAL_FONT = DEFAULT_FONT_VALUE;
+
+/**
+ * Get the actual font family CSS value for terminal
+ * Converts DEFAULT_FONT_VALUE to the actual Menlo/Monaco font stack
+ */
+export function getTerminalFontFamily(fontValue: string | undefined): string {
+ if (!fontValue || fontValue === DEFAULT_FONT_VALUE) {
+ return "Menlo, Monaco, 'Courier New', monospace";
+ }
+ return fontValue;
+}
// Dark theme (default)
const darkTheme: TerminalTheme = {
diff --git a/apps/ui/src/hooks/use-settings-migration.ts b/apps/ui/src/hooks/use-settings-migration.ts
index 5789886b..07119b85 100644
--- a/apps/ui/src/hooks/use-settings-migration.ts
+++ b/apps/ui/src/hooks/use-settings-migration.ts
@@ -600,6 +600,13 @@ export function hydrateStoreFromSettings(settings: GlobalSettings): void {
worktreePanelCollapsed: settings.worktreePanelCollapsed ?? false,
lastProjectDir: settings.lastProjectDir ?? '',
recentFolders: settings.recentFolders ?? [],
+ // Terminal font (nested in terminalState)
+ ...(settings.terminalFontFamily && {
+ terminalState: {
+ ...current.terminalState,
+ fontFamily: settings.terminalFontFamily,
+ },
+ }),
});
// Hydrate setup wizard state from global settings (API-backed)
@@ -653,6 +660,7 @@ function buildSettingsUpdateFromStore(): Record {
worktreePanelCollapsed: state.worktreePanelCollapsed,
lastProjectDir: state.lastProjectDir,
recentFolders: state.recentFolders,
+ terminalFontFamily: state.terminalState.fontFamily,
};
}
diff --git a/apps/ui/src/hooks/use-settings-sync.ts b/apps/ui/src/hooks/use-settings-sync.ts
index 763c2bb0..c9430684 100644
--- a/apps/ui/src/hooks/use-settings-sync.ts
+++ b/apps/ui/src/hooks/use-settings-sync.ts
@@ -35,6 +35,7 @@ const SETTINGS_FIELDS_TO_SYNC = [
'theme',
'fontFamilySans',
'fontFamilyMono',
+ 'terminalFontFamily', // Maps to terminalState.fontFamily
'sidebarOpen',
'chatHistoryOpen',
'maxConcurrency',
@@ -159,6 +160,9 @@ export function useSettingsSync(): SettingsSyncState {
if (field === 'currentProjectId') {
// Special handling: extract ID from currentProject object
updates[field] = appState.currentProject?.id ?? null;
+ } else if (field === 'terminalFontFamily') {
+ // Special handling: map terminalState.fontFamily to terminalFontFamily
+ updates[field] = appState.terminalState.fontFamily;
} else {
updates[field] = appState[field as keyof typeof appState];
}
@@ -260,6 +264,8 @@ export function useSettingsSync(): SettingsSyncState {
for (const field of SETTINGS_FIELDS_TO_SYNC) {
if (field === 'currentProjectId') {
updates[field] = appState.currentProject?.id ?? null;
+ } else if (field === 'terminalFontFamily') {
+ updates[field] = appState.terminalState.fontFamily;
} else {
updates[field] = appState[field as keyof typeof appState];
}
@@ -322,6 +328,12 @@ export function useSettingsSync(): SettingsSyncState {
changed = true;
break;
}
+ } else if (field === 'terminalFontFamily') {
+ // Special handling: compare terminalState.fontFamily
+ if (newState.terminalState.fontFamily !== prevState.terminalState.fontFamily) {
+ changed = true;
+ break;
+ }
} else {
const key = field as keyof typeof newState;
if (newState[key] !== prevState[key]) {
@@ -403,6 +415,8 @@ export async function forceSyncSettingsToServer(): Promise {
for (const field of SETTINGS_FIELDS_TO_SYNC) {
if (field === 'currentProjectId') {
updates[field] = appState.currentProject?.id ?? null;
+ } else if (field === 'terminalFontFamily') {
+ updates[field] = appState.terminalState.fontFamily;
} else {
updates[field] = appState[field as keyof typeof appState];
}
@@ -505,6 +519,13 @@ export async function refreshSettingsFromServer(): Promise {
worktreePanelCollapsed: serverSettings.worktreePanelCollapsed ?? false,
lastProjectDir: serverSettings.lastProjectDir ?? '',
recentFolders: serverSettings.recentFolders ?? [],
+ // Terminal font (nested in terminalState)
+ ...(serverSettings.terminalFontFamily && {
+ terminalState: {
+ ...currentAppState.terminalState,
+ fontFamily: serverSettings.terminalFontFamily,
+ },
+ }),
});
// Also refresh setup wizard state
diff --git a/apps/ui/src/styles/global.css b/apps/ui/src/styles/global.css
index e0159e25..a8a6e53a 100644
--- a/apps/ui/src/styles/global.css
+++ b/apps/ui/src/styles/global.css
@@ -880,6 +880,11 @@
background: var(--muted-foreground);
}
+/* Terminal padding for better readability */
+.xterm {
+ padding: 12px 16px;
+}
+
/* ========================================
DEPENDENCY GRAPH STYLES
Theme-aware styling for React Flow graph
diff --git a/libs/types/src/settings.ts b/libs/types/src/settings.ts
index 1ccc2026..a48504a8 100644
--- a/libs/types/src/settings.ts
+++ b/libs/types/src/settings.ts
@@ -472,6 +472,8 @@ export interface GlobalSettings {
fontFamilySans?: string;
/** Global Code/Mono font family (undefined = use default Geist Mono) */
fontFamilyMono?: string;
+ /** Terminal font family (undefined = use default Menlo/Monaco) */
+ terminalFontFamily?: string;
// UI State Preferences
/** Whether sidebar is currently open */