feat(a11y): add a Text size control and an OpenDyslexic font option (#4210)

* feat(a11y): add a Text size control and an OpenDyslexic font option

Text size: a Theme > Font & Layout control (Default / Larger) that scales the whole UI via CSS zoom, so the many hard-coded px sizes scale too (density only moves the root font-size). Stored globally so it persists across theme switches; applied early in the boot script to avoid a flash. OpenDyslexic: a dyslexia-friendly self-hosted font (SIL OFL 1.1), bundled as woff2 alongside Fira Code/Inter and wired into the Font select. Reuses the existing density/font pattern end to end; no new colours, spacing, or component styles.

* fix(a11y): keep modals on-screen at Larger text size

Inline vh heights on .modal-content overrode the ui-scale-125 max-height
compensation, so Cookbook (and the email/doc/skills/PDF modals) overflowed
the viewport at 125% — pushing the header and close button off-screen.
Let the compensation own those heights.

* fix(a11y): keep PDF export modal at its original 86vh on Default size
This commit is contained in:
Tom
2026-06-22 12:53:46 +01:00
committed by GitHub
parent d36879bd50
commit 91b4171b3f
12 changed files with 182 additions and 8 deletions
+16 -2
View File
@@ -76,7 +76,7 @@
}
// Apply font early
if (t && t.font) {
var fm = {mono:"'Fira Code', monospace",sans:"system-ui, -apple-system, 'Segoe UI', sans-serif",serif:"Georgia, 'Times New Roman', serif"};
var fm = {mono:"'Fira Code', monospace",sans:"system-ui, -apple-system, 'Segoe UI', sans-serif",serif:"Georgia, 'Times New Roman', serif",opendyslexic:"'OpenDyslexic', sans-serif"};
if (fm[t.font]) { s.setProperty('--font-family', fm[t.font]); }
else { s.setProperty('--font-family', "'" + t.font.replace(/'/g,'') + "', sans-serif"); }
}
@@ -84,6 +84,12 @@
if (t && t.density && t.density !== 'comfortable') {
document.documentElement.classList.add('density-' + t.density);
}
// Apply UI text-size scale early (global accessibility pref, independent
// of the active theme) so there's no flash on load.
try {
var _us = localStorage.getItem('odysseus-ui-scale');
if (_us && _us !== '100') document.documentElement.classList.add('ui-scale-' + _us);
} catch(e){}
// Apply background pattern on body once available
if (t && t.bgPattern && t.bgPattern !== 'none') {
document.addEventListener('DOMContentLoaded', function() {
@@ -581,6 +587,7 @@
<option value="mono">Monospace</option>
<option value="sans">Sans-serif</option>
<option value="serif">Serif</option>
<option value="opendyslexic">OpenDyslexic (dyslexia-friendly)</option>
</select>
</div>
<div class="theme-fd-group">
@@ -591,6 +598,13 @@
<option value="spacious">Spacious</option>
</select>
</div>
<div class="theme-fd-group">
<label class="theme-fd-label">Text size</label>
<select id="theme-text-size-select" class="theme-fd-select" aria-label="Text size">
<option value="100">Default</option>
<option value="125">Larger</option>
</select>
</div>
<div class="theme-fd-group" id="theme-frosted-group">
<label class="theme-fd-label" for="theme-frosted-toggle">Frosted</label>
<label class="admin-switch" style="margin-top:4px;">
@@ -1318,7 +1332,7 @@
<!-- Cookbook Modal -->
<div id="cookbook-modal" class="modal hidden">
<div class="modal-content" role="dialog" aria-label="Cookbook" style="width: min(780px, 92vw); height: 94vh; max-height: 94vh; background: var(--bg);">
<div class="modal-content" role="dialog" aria-label="Cookbook" style="width: min(780px, 92vw); background: var(--bg);">
<div class="modal-header">
<h4 style="margin:0;margin-right:auto"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:-2px;margin-right:6px"><path d="M12 7v14"/><path d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z"/></svg>Cookbook</h4>
<button class="close-btn" id="close-cookbook-modal" aria-label="Close cookbook"></button>