Add per-user page tone modes to reader
This commit is contained in:
1 parent
26d6cd59fc
commit
605fa5b9d8
8 files changed
+84
-2
No files matched your search
@@ -430,3 +430,9 @@ body.nobars #bot { transform: translateY(100%); opacity: 0; pointer-events: none
|
||||
.seg button { padding: 7px 10px; } #bot .btn { padding: 6px 10px; } .wide-only { display: none; }
|
||||
.clock-panel { bottom: calc(124px + env(safe-area-inset-bottom)); }
|
||||
}
|
||||
#canvas[data-page-tone="inverted"] .pg img { filter: invert(1); }
|
||||
#canvas[data-page-tone="sepia"] .pg img { filter: sepia(.8) brightness(.9); }
|
||||
#canvas[data-page-tone="dim"] .pg img { filter: brightness(.7); }
|
||||
#canvas[data-page-tone="extra-dim"] .pg img { filter: brightness(.45); }
|
||||
.page-tone { white-space: nowrap; }
|
||||
.page-tone:not([data-page-tone="original"]) { border-color: var(--accent); }
|
||||
@@ -38,6 +38,7 @@
|
||||
<button data-mode="page" title="One page at a time">Page</button>
|
||||
<button data-mode="book" title="Two pages side by side, like an open book">Book</button>
|
||||
</div>
|
||||
<button id="page-tone" class="btn page-tone" type="button" title="Change page colors; controls and theme stay the same" aria-label="Page tone: Original. Change page colors">Tone: Original</button>
|
||||
<button id="shift" class="btn" title="Page pairs look wrong? Shift them by one page">⇄<span class="wide-only"> Shift</span></button>
|
||||
<div class="seg zoom-controls" role="group" aria-label="Page zoom">
|
||||
<button id="zoomout" title="Zoom out 5%" aria-label="Zoom out 5%">−</button>
|
||||
|
||||
@@ -45,6 +45,36 @@
|
||||
const shift = new Set(D.progress && D.progress.v === D.version ? D.progress.shift : []);
|
||||
const zkey = () => (mode === 'flow' && ttb ? 'strip' : mode);
|
||||
const zoom = () => S.zoom[zkey()] || 1;
|
||||
const tones = [
|
||||
{ id: 'original', label: 'Original' },
|
||||
{ id: 'inverted', label: 'Inverted' },
|
||||
{ id: 'sepia', label: 'Sepia' },
|
||||
{ id: 'dim', label: 'Dim' },
|
||||
{ id: 'extra-dim', label: 'Extra dim' },
|
||||
];
|
||||
const toneButton = $('#page-tone');
|
||||
const toneName = id => tones.find(tone => tone.id === id)?.label || 'Original';
|
||||
function applyTone(id) {
|
||||
S.pageTone = tones.some(tone => tone.id === id) ? id : 'original';
|
||||
canvas.dataset.pageTone = S.pageTone;
|
||||
toneButton.dataset.pageTone = S.pageTone;
|
||||
toneButton.textContent = `Tone: ${toneName(S.pageTone)}`;
|
||||
toneButton.title = `Page images: ${toneName(S.pageTone)}. Click for the next tone; controls and theme stay unchanged.`;
|
||||
toneButton.setAttribute('aria-label', toneButton.title);
|
||||
}
|
||||
applyTone(S.pageTone);
|
||||
let savedTone = S.pageTone, toneSave = Promise.resolve(), toneChange = 0;
|
||||
function cycleTone() {
|
||||
const next = tones[(tones.findIndex(tone => tone.id === S.pageTone) + 1) % tones.length];
|
||||
applyTone(next.id);
|
||||
const change = ++toneChange;
|
||||
toneSave = toneSave.catch(() => {}).then(async () => {
|
||||
await api('api/settings', { pageTone: next.id });
|
||||
savedTone = next.id;
|
||||
}).catch(() => {
|
||||
if (change === toneChange) { applyTone(savedTone); toast('Could not save page tone'); }
|
||||
});
|
||||
}
|
||||
|
||||
const pr = D.progress;
|
||||
if (pr && !(pr.done && pr.p >= pr.n - 1)) {
|
||||
@@ -571,6 +601,7 @@
|
||||
ver.hidden = D.versions.length < 2;
|
||||
ver.onchange = () => { saveProgress(true); location.href = readUrl(D.manga.id, D.chapter.id, ver.value); };
|
||||
for (const b of modeBtns) b.onclick = () => { if (b.dataset.mode !== mode) setMode(b.dataset.mode, true); };
|
||||
toneButton.onclick = cycleTone;
|
||||
$('#shift').onclick = toggleShift;
|
||||
$('#zoomout').onclick = () => stepZoom(-1);
|
||||
$('#zoom').onclick = () => setZoom(1);
|
||||
|
||||
@@ -31,6 +31,13 @@
|
||||
h('option', { value: 'page' }, 'Always Page (one page at a time)'),
|
||||
h('option', { value: 'book' }, 'Always Book (two pages side by side)'));
|
||||
startMode.value = S.startMode;
|
||||
const tone = h('select', { onchange: e => save({ pageTone: e.target.value }) },
|
||||
h('option', { value: 'original' }, 'Original'),
|
||||
h('option', { value: 'inverted' }, 'Inverted'),
|
||||
h('option', { value: 'sepia' }, 'Sepia'),
|
||||
h('option', { value: 'dim' }, 'Dim (70% brightness)'),
|
||||
h('option', { value: 'extra-dim' }, 'Extra dim (45% brightness)'));
|
||||
tone.value = S.pageTone;
|
||||
const LABEL = { flow: 'Flow', page: 'Page', book: 'Book', strip: 'Webtoon flow' };
|
||||
const zooms = () => Object.keys(LABEL).map(k => `${LABEL[k]} ${Math.round((S.zoom[k] || 1) * 100)}%`).join(' · ');
|
||||
const zoomText = h('span', { class: 'muted' }, zooms());
|
||||
@@ -72,6 +79,8 @@
|
||||
check('skipCovers', 'Skip chapter cover pages'),
|
||||
check('flowPageGap', 'Show a gap between pages in Flow mode',
|
||||
'Turn this off for continuous webtoon artwork or text that crosses page edges.'),
|
||||
h('label', { class: 'field' }, h('span', {}, 'Page tone'), tone,
|
||||
h('div', { class: 'muted small' }, 'The reader button cycles through these choices. Only page artwork changes; the site theme and controls stay as they are.')),
|
||||
h('div', { class: 'field' }, h('span', {}, 'Page zoom'), zoomText, ' ',
|
||||
h('button', { class: 'btn small', onclick: async () => { await save({ zoom: {} }); zoomText.textContent = zooms(); } }, 'Reset to fit'),
|
||||
h('div', { class: 'muted small' }, '100% = the page fits the screen. Change it in the reader with Ctrl + mouse wheel, a pinch, or the + / - keys.'))));
|
||||
|
||||
Reference in new issue
Block a user