feat(appearance): add system font preference - #1038
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughChangesThe settings UI now controls a persisted system-font preference. Theme context synchronizes the preference with the root class and localStorage. CSS variables and Tailwind font definitions apply the selected font stack. System Font Preference
Sequence Diagram(s)sequenceDiagram
participant User
participant AppearanceSettingsTab
participant SettingsController
participant ThemeProvider
participant LocalStorage
participant DocumentRoot
User->>AppearanceSettingsTab: Toggle system font
AppearanceSettingsTab->>SettingsController: onUseSystemFontChange(value)
SettingsController->>ThemeProvider: setUseSystemFont(value)
ThemeProvider->>LocalStorage: Save preference
ThemeProvider->>DocumentRoot: Toggle system-font class
DocumentRoot->>User: Apply system font variables
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/contexts/ThemeContext.jsx (1)
96-97: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueMemoize the context value to prevent unnecessary re-renders.
The context
valueobject is recreated on every render ofThemeProvider, forcing all context consumers to re-render even if the state hasn't changed. Consider memoizing the value and thetoggleDarkModefunction.⚡ Proposed refactor
- const toggleDarkMode = () => { - setIsDarkMode(prev => !prev); - }; + const toggleDarkMode = useCallback(() => { + setIsDarkMode(prev => !prev); + }, []); - const value = { - isDarkMode, - toggleDarkMode, - useSystemFont, - setUseSystemFont, - }; + const value = useMemo(() => ({ + isDarkMode, + toggleDarkMode, + useSystemFont, + setUseSystemFont, + }), [isDarkMode, toggleDarkMode, useSystemFont]);(Ensure
useMemoanduseCallbackare imported from'react')🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/contexts/ThemeContext.jsx` around lines 96 - 97, Update ThemeProvider to memoize the context value with useMemo and memoize toggleDarkMode with useCallback, ensuring both React hooks are imported and their dependency arrays include all referenced state and functions. Keep the existing context fields and behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/contexts/ThemeContext.jsx`:
- Around line 67-71: Move the `system-font` class initialization from the
`useEffect` in `ThemeContext` to the bootstrap or initial render path so it is
applied before first paint, while preserving the existing `useSystemFont`
preference and localStorage behavior. Keep the effect only for subsequent
preference changes if needed.
In `@src/index.css`:
- Around line 46-47: Quote the specified font family names in both affected
declarations: update BlinkMacSystemFont, Roboto, and Arial in src/index.css
lines 46-47 and 78-82, and also quote Georgia and Cambria in lines 46-47.
Preserve all existing fallback order and values.
---
Nitpick comments:
In `@src/contexts/ThemeContext.jsx`:
- Around line 96-97: Update ThemeProvider to memoize the context value with
useMemo and memoize toggleDarkMode with useCallback, ensuring both React hooks
are imported and their dependency arrays include all referenced state and
functions. Keep the existing context fields and behavior unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: fba3d9b2-6b85-4c6e-b0ec-cc9287154244
📒 Files selected for processing (7)
src/components/settings/hooks/useSettingsController.tssrc/components/settings/view/Settings.tsxsrc/components/settings/view/tabs/AppearanceSettingsTab.tsxsrc/contexts/ThemeContext.jsxsrc/i18n/locales/en/settings.jsonsrc/index.csstailwind.config.js
| useEffect(() => { | ||
| document.documentElement.classList.toggle('system-font', useSystemFont); | ||
| localStorage.setItem('useSystemFont', String(useSystemFont)); | ||
| }, [useSystemFont]); | ||
|
|
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check for inline theme initialization scripts in HTML files.
rg "localStorage\.getItem" -g "*.html" -C 2Repository: siteboon/claudecodeui
Length of output: 159
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- files ---'
git ls-files | rg '(^|/)(index\.html|ThemeContext\.jsx|ThemeContext\.[jt]sx|main\.[jt]sx|App\.[jt]sx)$'
echo
echo '--- search for theme bootstrap/localStorage in html/jsx ---'
rg -n "localStorage\.getItem|system-font|ThemeContext|document\.documentElement\.classList\.toggle|classList\.add|classList\.remove" src . -g '*.html' -g '*.js' -g '*.jsx' -g '*.ts' -g '*.tsx'
echo
echo '--- candidate html files ---'
fd -a -t f 'index.html|*.html' .Repository: siteboon/claudecodeui
Length of output: 18963
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Read the theme context around the relevant effect.
FILE='src/contexts/ThemeContext.jsx'
wc -l "$FILE"
sed -n '1,140p' "$FILE"
# If there is an index.html, inspect it for inline scripts.
if git ls-files | rg -q '(^|/)index\.html$'; then
HTML=$(git ls-files | rg '(^|/)index\.html$' | head -n 1)
echo
echo "--- $HTML ---"
cat -n "$HTML"
fiRepository: siteboon/claudecodeui
Length of output: 4049
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- tracked html and theme files ---'
git ls-files | rg '(^|/)(index\.html|.*ThemeContext\.jsx|main\.[jt]sx|App\.[jt]sx)$' || true
echo
echo '--- ThemeContext.jsx ---'
sed -n '1,120p' src/contexts/ThemeContext.jsx
echo
echo '--- html files containing theme/bootstrap terms ---'
rg -n "localStorage\.getItem|system-font|theme" --glob '*.html' . || trueRepository: siteboon/claudecodeui
Length of output: 3946
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- root index.html ---'
cat -n index.html | sed -n '1,220p'
echo
echo '--- any inline scripts in HTML files ---'
rg -n "<script|localStorage|getItem|matchMedia|theme|system-font" index.html electron/launcher/index.html public/api-docs.html -C 3Repository: siteboon/claudecodeui
Length of output: 6308
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
for p in [Path('index.html'), Path('electron/launcher/index.html')]:
if p.exists():
text = p.read_text()
print(f'--- {p} script tags ---')
for i, line in enumerate(text.splitlines(), 1):
if '<script' in line or 'theme' in line.lower() or 'system-font' in line.lower():
print(f'{i}: {line}')
PYRepository: siteboon/claudecodeui
Length of output: 441
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo '--- root index.html ---'
cat -n index.html | sed -n '1,220p'
echo
echo '--- root and launcher HTML theme-related lines ---'
rg -n "<script|localStorage|getItem|matchMedia|theme|system-font" index.html electron/launcher/index.html -C 3Repository: siteboon/claudecodeui
Length of output: 3930
Apply system-font before first paint.
useEffect runs after hydration, so users who prefer the system font can see a brief font flash on load. Initialize this class in the bootstrap/initial render path instead.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/contexts/ThemeContext.jsx` around lines 67 - 71, Move the `system-font`
class initialization from the `useEffect` in `ThemeContext` to the bootstrap or
initial render path so it is applied before first paint, while preserving the
existing `useSystemFont` preference and localStorage behavior. Keep the effect
only for subsequent preference changes if needed.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main.jsx`:
- Around line 12-16: Guard all localStorage reads and writes in ThemeContext,
including state initialization and effect persistence, so unavailable or blocked
storage cannot crash the app. Update the relevant ThemeContext symbols to catch
storage failures or reuse centralized safe getItem/setItem helpers, while
preserving the existing font preference behavior when storage is available.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d9b54375-3cf7-4ad8-916a-c2b95398cc45
📒 Files selected for processing (3)
src/contexts/ThemeContext.jsxsrc/index.csssrc/main.jsx
🚧 Files skipped from review as they are similar to previous changes (2)
- src/contexts/ThemeContext.jsx
- src/index.css
|
Hey @sudo-eugene, can you address the coderabbit comments? |
|
@blackmammoth done |
What changed
CloudCLI now offers a persistent Use system font option under Appearance → Typography. Enabling it replaces both Encode Sans in the general interface and Merriweather in chat and reading views with the device's native system font; disabling it restores the existing typography.
Why
The current font choices are applied globally, leaving users who prefer their platform's native typography without a consistent alternative. A single preference covers both font layers so the interface does not end up with a mixture of system and bundled fonts.
The switch changes shared font variables rather than replacing individual component classes. This keeps the existing typography as the default, applies the preference to current and future views that use the shared font definitions, and avoids maintaining separate font overrides throughout the component tree.
What this enables
Users can match CloudCLI's typography to their operating system for a more native and personally readable interface, with their choice retained across reloads.
Screenshots
Before
After
Test plan
npm run typechecknpm run lint(passes with the repository's existing warnings)npm run build(passes with the repository's existing CSS and bundle-size warnings)Summary by CodeRabbit