feat: Add body and article font selection settings

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-01-02 22:11:28 +00:00
parent cf35bd53bf
commit e0f523cc1c
2 changed files with 71 additions and 2 deletions

View File

@@ -23,6 +23,8 @@ function App() {
const [settingsOpen, setSettingsOpen] = useState(false); const [settingsOpen, setSettingsOpen] = useState(false);
const defaultBodyFontSize = 1.0; const defaultBodyFontSize = 1.0;
const [bodyFontSize, setBodyFontSize] = useState(Number(localStorage.getItem('bodyFontSize')) || defaultBodyFontSize); const [bodyFontSize, setBodyFontSize] = useState(Number(localStorage.getItem('bodyFontSize')) || defaultBodyFontSize);
const [bodyFont, setBodyFont] = useState(localStorage.getItem('bodyFont') || 'Sans Serif');
const [articleFont, setArticleFont] = useState(localStorage.getItem('articleFont') || 'Apparatus SIL');
const updateCache = useCallback((key, value) => { const updateCache = useCallback((key, value) => {
cache.current[key] = value; cache.current[key] = value;
@@ -48,6 +50,16 @@ function App() {
localStorage.setItem('theme', 'red'); localStorage.setItem('theme', 'red');
}; };
const changeBodyFont = (font) => {
setBodyFont(font);
localStorage.setItem('bodyFont', font);
};
const changeArticleFont = (font) => {
setArticleFont(font);
localStorage.setItem('articleFont', font);
};
const changeBodyFontSize = (amount) => { const changeBodyFontSize = (amount) => {
const newSize = bodyFontSize + amount; const newSize = bodyFontSize + amount;
setBodyFontSize(parseFloat(newSize.toFixed(2))); setBodyFontSize(parseFloat(newSize.toFixed(2)));
@@ -112,6 +124,27 @@ function App() {
document.documentElement.style.fontSize = `${bodyFontSize}rem`; document.documentElement.style.fontSize = `${bodyFontSize}rem`;
}, [bodyFontSize]); }, [bodyFontSize]);
const fontMap = {
'Sans Serif': 'sans-serif',
'Serif': 'serif',
'Apparatus SIL': "'Apparatus SIL', sans-serif"
};
useEffect(() => {
document.body.style.fontFamily = fontMap[bodyFont];
}, [bodyFont]);
useEffect(() => {
const styleId = 'article-font-family-style';
let style = document.getElementById(styleId);
if (!style) {
style = document.createElement('style');
style.id = styleId;
document.head.appendChild(style);
}
style.innerHTML = `.story-text { font-family: ${fontMap[articleFont]} !important; }`;
}, [articleFont]);
const fullScreenAvailable = document.fullscreenEnabled || const fullScreenAvailable = document.fullscreenEnabled ||
document.mozFullscreenEnabled || document.mozFullscreenEnabled ||
@@ -138,6 +171,36 @@ function App() {
<button onClick={() => changeBodyFontSize(0.05)}>+</button> <button onClick={() => changeBodyFontSize(0.05)}>+</button>
<button onClick={resetBodyFontSize} disabled={!bodyFontSettingsChanged}>Reset</button> <button onClick={resetBodyFontSize} disabled={!bodyFontSettingsChanged}>Reset</button>
</div> </div>
<div className="setting-group">
<h4>Body Font</h4>
<div className="font-option">
<input className="checkbox" type="radio" id="body-sans-serif" name="body-font" value="Sans Serif" checked={bodyFont === 'Sans Serif'} onChange={() => changeBodyFont('Sans Serif')} />
<label htmlFor="body-sans-serif">Sans Serif *</label>
</div>
<div className="font-option">
<input className="checkbox" type="radio" id="body-serif" name="body-font" value="Serif" checked={bodyFont === 'Serif'} onChange={() => changeBodyFont('Serif')} />
<label htmlFor="body-serif">Serif</label>
</div>
<div className="font-option">
<input className="checkbox" type="radio" id="body-apparatus" name="body-font" value="Apparatus SIL" checked={bodyFont === 'Apparatus SIL'} onChange={() => changeBodyFont('Apparatus SIL')} />
<label htmlFor="body-apparatus">Apparatus SIL</label>
</div>
</div>
<div className="setting-group">
<h4>Article Font</h4>
<div className="font-option">
<input className="checkbox" type="radio" id="article-sans-serif" name="article-font" value="Sans Serif" checked={articleFont === 'Sans Serif'} onChange={() => changeArticleFont('Sans Serif')} />
<label htmlFor="article-sans-serif">Sans Serif</label>
</div>
<div className="font-option">
<input className="checkbox" type="radio" id="article-serif" name="article-font" value="Serif" checked={articleFont === 'Serif'} onChange={() => changeArticleFont('Serif')} />
<label htmlFor="article-serif">Serif</label>
</div>
<div className="font-option">
<input className="checkbox" type="radio" id="article-apparatus" name="article-font" value="Apparatus SIL" checked={articleFont === 'Apparatus SIL'} onChange={() => changeArticleFont('Apparatus SIL')} />
<label htmlFor="article-apparatus">Apparatus SIL *</label>
</div>
</div>
</div> </div>
</div> </div>
} }

View File

@@ -1,6 +1,7 @@
body { body {
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
font: 1rem/1.3 sans-serif; font-size: 1rem;
line-height: 1.3;
color: #000000; color: #000000;
word-break: break-word; word-break: break-word;
font-kerning: normal; font-kerning: normal;
@@ -198,7 +199,8 @@ span.source {
} }
.story-text { .story-text {
font: 1.2rem/1.5 'Apparatus SIL', sans-serif; font-size: 1.2rem;
line-height: 1.5;
margin-top: 1em; margin-top: 1em;
} }
@@ -478,3 +480,7 @@ button.comment {
text-align: center; text-align: center;
margin: 0 0.25rem; margin: 0 0.25rem;
} }
.modal-content .font-option {
margin-bottom: 0.25rem;
}