From 7ee44622ee2de09e7720ac8f85409be41c8c93f0 Mon Sep 17 00:00:00 2001 From: mrwnslz Date: Mon, 28 Sep 2026 20:25:59 +0200 Subject: [PATCH] Reader: Schriftgewicht einstellbar (SW v47) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neuer Regler im Einstellungs-Panel, 200-800: bei Source Serif 4 (variabel) in 25er-Schritten, bei Systemschriften in 100ern. null behält das Gewicht aus dem Stylesheet. --reader-weight erlaubt alten WebViews ohne variable Schriften, einen statischen Schnitt zu wählen. "Kein Fett" erbt jetzt das eingestellte Gewicht statt fest normal. Co-Authored-By: Claude Opus 5.5 --- static/css/app.css | 2 +- static/js/app.js | 52 ++++++++++++++++++++++++++++++++++++++++++++-- static/js/sw.js | 2 +- 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/static/css/app.css b/static/css/app.css index 5b200a9..fd2bcc6 100644 --- a/static/css/app.css +++ b/static/css/app.css @@ -2130,7 +2130,7 @@ body.reader-immersive.reader-show-bottom .reader-overlay { bottom: var(--bar-h) .footnote-popover-close { position:absolute; top:4px; right:6px; background:none; border:none; color:inherit; opacity:0.5; cursor:pointer; font-size:14px; padding:2px 4px; line-height:1; } /* Highlight marks */ -.reader-no-bold * { font-weight: normal !important; } +.reader-no-bold * { font-weight: inherit !important; } .reader-content img { max-width: 100%; height: auto; display: block; } /* color:inherit overrides the browser's UA-default `mark { color: black }` — without it, highlighted text abruptly flips to black regardless of the diff --git a/static/js/app.js b/static/js/app.js index 64a27d3..cf513db 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -3254,7 +3254,7 @@ async function _syncPendingAnnotations() { // Reader settings let readerSettings = { fontSize: 16, lineHeight: 1.8, maxWidth: 65, theme: 'dark', - fontFamily: 'serif', noBold: false, + fontFamily: 'serif', noBold: false, fontWeight: null, pdfZoom: 100, pdfInverted: false, pdfPaginated: false, pdfSpread: false }; let readerSettingsPanelOpen = false; let currentPdfDoc = null; @@ -5026,7 +5026,7 @@ function jumpToTocEntry(href) { function loadReaderSettings(bookId) { // Reset to defaults, then apply per-book overrides Object.assign(readerSettings, { fontSize: 16, lineHeight: 1.8, maxWidth: 65, theme: 'dark', - fontFamily: 'serif', noBold: false, + fontFamily: 'serif', noBold: false, fontWeight: null, pdfZoom: 100, pdfInverted: false, pdfPaginated: false, pdfSpread: false }); try { const saved = JSON.parse(localStorage.getItem(`diora_reader_settings_${bookId}`) || '{}'); @@ -5060,6 +5060,16 @@ function applyReaderSettings(isPdf) { }; contentEl.style.fontFamily = fontMap[readerSettings.fontFamily] || fontMap.serif; contentEl.classList.toggle('reader-no-bold', !!readerSettings.noBold); + // Weight: null keeps the stylesheet's. --reader-weight lets old WebViews + // without variable-font support (which drop weights like 425) pick a + // static cut instead. + contentEl.style.fontWeight = ''; + if (readerSettings.fontWeight) { + contentEl.style.fontWeight = String(readerSettings.fontWeight); + contentEl.style.setProperty('--reader-weight', String(readerSettings.fontWeight)); + } else { + contentEl.style.removeProperty('--reader-weight'); + } if (_currentPositionAnchor && currentBookId) { _suppressScrollJumpDetect(); requestAnimationFrame(() => restoreFromAnchor($('reader-content'), _currentPositionAnchor)); @@ -5083,6 +5093,19 @@ function applyReaderSettings(isPdf) { if (isPdf && markerModeActive) toggleMarkerMode(); } +// Font weight slider: the variable Source Serif 4 takes any weight, the +// system fonts only their fixed cuts (multiples of 100). +function _readerWeightStep() { + return readerSettings.fontFamily === 'serif' ? 25 : 100; +} + +function _readerWeight() { + const step = _readerWeightStep(); + const w = readerSettings.fontWeight + || parseInt(getComputedStyle($('reader-content')).fontWeight, 10) || 400; + return Math.round(w / step) * step; +} + function toggleSettingsPanel() { const overlay = $('reader-overlay'); const contentEl = $('reader-content'); @@ -5108,6 +5131,7 @@ function toggleSettingsPanel() { + @@ -5187,12 +5211,36 @@ function toggleSettingsPanel() { saveReaderSettings(); }); + const weightRange = panel.querySelector('#rs-weight'); + const weightVal = panel.querySelector('#rs-weight-val'); + weightRange.addEventListener('input', () => { + readerSettings.fontWeight = parseInt(weightRange.value, 10); + weightVal.textContent = readerSettings.fontWeight; + applyReaderSettings(false); + saveReaderSettings(); + }); + panel.querySelector('#rs-weight-minus').addEventListener('click', () => { + weightRange.value = Math.max(+weightRange.min, parseInt(weightRange.value, 10) - +weightRange.step); + weightRange.dispatchEvent(new Event('input')); + }); + panel.querySelector('#rs-weight-plus').addEventListener('click', () => { + weightRange.value = Math.min(+weightRange.max, parseInt(weightRange.value, 10) + +weightRange.step); + weightRange.dispatchEvent(new Event('input')); + }); + panel.querySelectorAll('[data-rs-font]').forEach(btn => { btn.addEventListener('click', () => { readerSettings.fontFamily = btn.dataset.rsFont; panel.querySelectorAll('[data-rs-font]').forEach(b => b.classList.toggle('active', b === btn)); + // The system fonts only have cuts at multiples of 100. + weightRange.step = _readerWeightStep(); + if (readerSettings.fontWeight) { + readerSettings.fontWeight = Math.round(readerSettings.fontWeight / weightRange.step) * weightRange.step; + } applyReaderSettings(false); saveReaderSettings(); + weightRange.value = _readerWeight(); + weightVal.textContent = _readerWeight(); }); }); diff --git a/static/js/sw.js b/static/js/sw.js index 24a7b9c..2b72b57 100644 --- a/static/js/sw.js +++ b/static/js/sw.js @@ -2,7 +2,7 @@ * diora service worker — caches the app shell for offline use. */ -const CACHE = 'diora-v46'; +const CACHE = 'diora-v47'; const PODCAST_CACHE = 'diora-podcast-v1'; const SHELL = [ '/static/css/app.css',