Make the app work better on iPhone and iPad
Build and Push Docker Image / build-and-push (push) Successful in 7m32s

- Text fields are at least 16px on touch screens (stops iOS zooming on focus)
- Chapter swipe ignores sheets, fields, sliders, sideways-scrolling rows and text selection
- vh -> dvh for sheets, palette and dialogs
- Bigger tap targets for small links, chips and the logo; no double-tap delay
- No tap flash or landscape text inflation

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-06 13:08:07 -04:00
1 parent bdb04cdedc
commit d29a66f984
12 files changed
+99 -14

No files matched your search

+12
View File
@@ -0,0 +1,12 @@
// Swiping sideways on the reading page turns the chapter. It shouldn't when the finger is on something that has its
// own sideways gesture: a sheet, a form field, or a row that scrolls sideways.
const OWN_GESTURE = 'input, textarea, select, [role="dialog"], [role="slider"], [data-no-swipe]';
export function swipeAllowedFrom(target) {
if (!target?.closest) return true;
if (target.closest(OWN_GESTURE)) return false;
for (let el = target; el && el !== document.body; el = el.parentElement) {
if (el.scrollWidth > el.clientWidth + 1 && /(auto|scroll)/.test(getComputedStyle(el).overflowX)) return false;
}
return true;
}
+26
View File
@@ -0,0 +1,26 @@
import { afterEach, expect, test } from 'vitest';
import { swipeAllowedFrom } from './swipe.js';
afterEach(() => { document.body.innerHTML = ''; });
const mount = (html) => { document.body.innerHTML = html; return document.body.firstElementChild; };
test('swiping on plain text is allowed', () => {
const root = mount('<div><p id="t">verse</p></div>');
expect(swipeAllowedFrom(root.querySelector('#t'))).toBe(true);
expect(swipeAllowedFrom(null)).toBe(true);
});
test('sheets, fields and sliders keep their own sideways gestures', () => {
const root = mount('<div><div role="dialog"><button id="a">x</button></div><input id="b"><div data-no-swipe><span id="c"></span></div></div>');
expect(swipeAllowedFrom(root.querySelector('#a'))).toBe(false);
expect(swipeAllowedFrom(root.querySelector('#b'))).toBe(false);
expect(swipeAllowedFrom(root.querySelector('#c'))).toBe(false);
});
test('a row that scrolls sideways is left alone', () => {
const root = mount('<div id="row" style="overflow-x:auto"><span id="s"></span></div>');
const row = root;
Object.defineProperty(row, 'scrollWidth', { value: 500, configurable: true });
Object.defineProperty(row, 'clientWidth', { value: 200, configurable: true });
expect(swipeAllowedFrom(row.querySelector('#s'))).toBe(false);
});