An interface font and a reading font in Settings (#359)

The font chosen before is the interface's, under the same cookie, so a
choice already made stays as it was. The reading font, ipx_rfont, sets
an item's title and text and is the interface's until chosen. Text read
in a serif gets a line height of 1.75 for 1.65, whichever setting put
it there. Each face's stack is a custom property, used by both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 01:35:02 +00:00
parent 75afaa291c
commit 4249393f2a
7 changed files with 82 additions and 13 deletions

View File

@@ -448,9 +448,13 @@ async function prefsModal(){
<select id="smode">${Object.entries(MODES).map(([k,t])=>
`<option value="${k}"${theme.mode===k?' selected':''}>${esc(t)}</option>`).join('')}</select>
<span class="hint">Auto follows your system's light/dark setting.</span></div>
<div class="field"><label for="sfont">Font</label>
<div class="field"><label for="sfont">Interface font</label>
<select id="sfont">${Object.entries(FONTS).map(([k,t])=>
`<option value="${k}"${font===k?' selected':''}>${esc(t)}</option>`).join('')}</select></div>
<div class="field"><label for="srfont">Reading font</label>
<select id="srfont" aria-describedby="srfonthint">${Object.entries(READING_FONTS).map(([k,t])=>
`<option value="${k}"${readingFont===k?' selected':''}>${esc(t)}</option>`).join('')}</select>
<span class="hint" id="srfonthint">For an item's title and text.</span></div>
<div class="field"><label>DeadAir</label>
<span class="hint" id="sdeadsaved">${deadSavedText(S.me)}</span></div>
<div class="field"><label>Subscriptions</label>
@@ -492,6 +496,7 @@ async function prefsModal(){
$<HTMLSelectElement>('#stheme').onchange=(e: Event)=>setTheme((e.target as HTMLSelectElement).value,undefined,true);
$<HTMLSelectElement>('#smode').onchange=(e: Event)=>setTheme(undefined,(e.target as HTMLSelectElement).value,true);
$<HTMLSelectElement>('#sfont').onchange=(e: Event)=>setFont((e.target as HTMLSelectElement).value,true);
$<HTMLSelectElement>('#srfont').onchange=(e: Event)=>setReadingFont((e.target as HTMLSelectElement).value,true);
$<HTMLButtonElement>('#gopml').onclick=opmlModal;
drawTokens();
$<HTMLButtonElement>('#tokadd').onclick=async()=>{

View File

@@ -60,7 +60,11 @@ const FONTS: Record<string, string> = {
atkinson: 'Atkinson Hyperlegible', lexend: 'Lexend', literata: 'Literata', source: 'Source Serif',
dyslexic: 'OpenDyslexic', serif: "Serif (your device's)", mono: 'Monospace',
};
let font = 'theme';
// The reading font is an item's title and text; the same as the interface's until one is chosen.
const READING_FONTS: Record<string, string> = {
same: 'Same as the interface', ...Object.fromEntries(Object.entries(FONTS).filter(([k]) => k !== 'theme')),
};
let font = 'theme', readingFont = 'same';
function setFont(name = font, save = false){
font = FONTS[name] ? name : 'theme';
@@ -69,7 +73,15 @@ function setFont(name = font, save = false){
const sel = $<HTMLSelectElement>('#sfont'); if(sel) sel.value = font;
if(save) document.cookie = `ipx_font=${font}; Path=/; Max-Age=31536000; SameSite=Lax`;
}
function setReadingFont(name = readingFont, save = false){
readingFont = READING_FONTS[name] ? name : 'same';
const root = document.documentElement;
if(readingFont === 'same') delete root.dataset.rfont; else root.dataset.rfont = readingFont;
const sel = $<HTMLSelectElement>('#srfont'); if(sel) sel.value = readingFont;
if(save) document.cookie = `ipx_rfont=${readingFont}; Path=/; Max-Age=31536000; SameSite=Lax`;
}
setFont(document.documentElement.dataset.font);
setReadingFont(document.documentElement.dataset.rfont);
systemDark?.addEventListener?.('change', () => { if(theme.mode === 'auto') setTheme(); });
(() => {