feat: add UI font size adjustment with Ctrl+Mouse Wheel

- Add uiFontSize state management to ExtensionStateContext
- Implement Ctrl+Mouse Wheel event handler in App.tsx
- Add font size persistence to global settings
- Apply font size dynamically using CSS variables
- Support font size range from 50% to 200%

Fixes #7530
This commit is contained in:
Roo Code 2025-08-29 14:54:30 +00:00
parent 1d46bd1bbc
commit ebbfa6e50d
6 changed files with 62 additions and 0 deletions

View file

@ -148,6 +148,7 @@ export const globalSettingsSchema = z.object({
hasOpenedModeSelector: z.boolean().optional(),
lastModeExportPath: z.string().optional(),
lastModeImportPath: z.string().optional(),
uiFontSize: z.number().min(50).max(200).optional(), // UI font size as percentage (50-200%)
})
export type GlobalSettings = z.infer<typeof globalSettingsSchema>

View file

@ -2657,5 +2657,12 @@ export const webviewMessageHandler = async (
vscode.window.showWarningMessage(t("common:mdm.info.organization_requires_auth"))
break
}
case "uiFontSize": {
// Store the UI font size preference
const fontSize = message.value ?? 100
await updateGlobalState("uiFontSize", fontSize)
await provider.postStateToWebview()
break
}
}
}

View file

@ -326,6 +326,7 @@ export type ExtensionState = Pick<
marketplaceInstalledMetadata?: { project: Record<string, any>; global: Record<string, any> }
profileThresholds: Record<string, number>
hasOpenedModeSelector: boolean
uiFontSize?: number // UI font size as percentage (50-200%)
}
export interface ClineSayTool {

View file

@ -212,6 +212,7 @@ export interface WebviewMessage {
| "createCommand"
| "insertTextIntoTextarea"
| "showMdmAuthRequiredNotification"
| "uiFontSize"
text?: string
editedMessageContent?: string
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account"

View file

@ -74,6 +74,8 @@ const App = () => {
cloudApiUrl,
renderContext,
mdmCompliant,
uiFontSize,
setUiFontSize,
} = useExtensionState()
// Create a persistent state manager
@ -226,6 +228,43 @@ const App = () => {
}
}, [tab])
// Handle Ctrl + Mouse Wheel for font size adjustment
useEffect(() => {
const handleWheel = (e: WheelEvent) => {
// Check if Ctrl key is pressed (or Cmd on Mac)
if (e.ctrlKey || e.metaKey) {
e.preventDefault() // Prevent default browser zoom
const currentSize = uiFontSize || 100
const delta = e.deltaY > 0 ? -5 : 5 // Decrease on scroll down, increase on scroll up
const newSize = Math.min(200, Math.max(50, currentSize + delta)) // Clamp between 50% and 200%
if (newSize !== currentSize) {
setUiFontSize(newSize)
// Send message to extension to persist the setting
vscode.postMessage({ type: "uiFontSize", value: newSize })
}
}
}
// Add event listener with passive: false to allow preventDefault
window.addEventListener("wheel", handleWheel, { passive: false })
return () => {
window.removeEventListener("wheel", handleWheel)
}
}, [uiFontSize, setUiFontSize])
// Apply font size to the document
useEffect(() => {
if (uiFontSize) {
// Apply the font size as a CSS variable that can be used throughout the app
document.documentElement.style.setProperty("--ui-font-scale", `${uiFontSize / 100}`)
// Also apply a direct font-size to the body for immediate effect
document.documentElement.style.fontSize = `${uiFontSize}%`
}
}, [uiFontSize])
if (!didHydrateState) {
return null
}

View file

@ -151,6 +151,8 @@ export interface ExtensionStateContextType extends ExtensionState {
setMaxDiagnosticMessages: (value: number) => void
includeTaskHistoryInEnhance?: boolean
setIncludeTaskHistoryInEnhance: (value: boolean) => void
uiFontSize?: number
setUiFontSize: (value: number) => void
}
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
@ -239,6 +241,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
autoCondenseContext: true,
autoCondenseContextPercent: 100,
profileThresholds: {},
uiFontSize: 100, // Default UI font size as percentage (100 = 100% = normal size)
codebaseIndexConfig: {
codebaseIndexEnabled: true,
codebaseIndexQdrantUrl: "http://localhost:6333",
@ -271,6 +274,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
global: {},
})
const [includeTaskHistoryInEnhance, setIncludeTaskHistoryInEnhance] = useState(true)
const [, setUiFontSizeState] = useState(100) // Default to 100%
const setListApiConfigMeta = useCallback(
(value: ProviderSettingsEntry[]) => setState((prevState) => ({ ...prevState, listApiConfigMeta: value })),
@ -308,6 +312,10 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
if ((newState as any).includeTaskHistoryInEnhance !== undefined) {
setIncludeTaskHistoryInEnhance((newState as any).includeTaskHistoryInEnhance)
}
// Update uiFontSize if present in state message
if (newState.uiFontSize !== undefined) {
setUiFontSizeState(newState.uiFontSize)
}
// Handle marketplace data if present in state message
if (newState.marketplaceItems !== undefined) {
setMarketplaceItems(newState.marketplaceItems)
@ -524,6 +532,11 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
},
includeTaskHistoryInEnhance,
setIncludeTaskHistoryInEnhance,
uiFontSize: state.uiFontSize ?? 100,
setUiFontSize: (value) => {
setState((prevState) => ({ ...prevState, uiFontSize: value }))
setUiFontSizeState(value)
},
}
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>