v0.8.4 full refresh

This commit is contained in:
2026-03-13 10:02:04 -04:00
parent 33b5f2ee4d
commit a02facff1a
9 changed files with 73 additions and 24 deletions

View File

@@ -14,25 +14,72 @@ if ('serviceWorker' in navigator) {
// Disable pull-to-refresh in PWA standalone mode to prevent viewport shift bug.
// The CSS overscroll-behavior-y:none handles most browsers; this catches the rest.
// ─── Touch gesture handler ───────────────────────────────────────────────────
// Handles two behaviours in one unified listener set to avoid conflicts:
//
// 1. PINCH → font scale only (not viewport zoom).
// viewport has user-scalable=no so the browser never zooms the layout.
// We intercept the pinch and adjust --font-scale on <html> instead,
// which scales only text (rem-based font sizes). Persisted to localStorage.
// On first launch, html { font-size: 100% } inherits the Android system
// font size as the 1rem baseline automatically.
//
// 2. PULL-TO-REFRESH → blocked in PWA standalone mode only.
(function () {
const LS_KEY = 'jama_font_scale';
const MIN_SCALE = 0.8;
const MAX_SCALE = 2.0;
const isStandalone = window.matchMedia('(display-mode: standalone)').matches
|| window.navigator.standalone === true;
if (!isStandalone) return;
let startY = 0;
document.addEventListener('touchstart', e => {
startY = e.touches[0].clientY;
// Restore saved font scale on launch
const saved = parseFloat(localStorage.getItem(LS_KEY));
let currentScale = (saved >= MIN_SCALE && saved <= MAX_SCALE) ? saved : 1.0;
document.documentElement.style.setProperty('--font-scale', currentScale);
let pinchStartDist = null;
let pinchStartScale = currentScale;
let singleStartY = 0;
function getTouchDist(e) {
const dx = e.touches[0].clientX - e.touches[1].clientX;
const dy = e.touches[0].clientY - e.touches[1].clientY;
return Math.sqrt(dx * dx + dy * dy);
}
document.addEventListener('touchstart', function (e) {
if (e.touches.length === 2) {
pinchStartDist = getTouchDist(e);
pinchStartScale = currentScale;
} else if (e.touches.length === 1) {
singleStartY = e.touches[0].clientY;
}
}, { passive: true });
document.addEventListener('touchmove', e => {
// Only block downward pull at the very top of the document
const dy = e.touches[0].clientY - startY;
if (dy > 0 && (document.documentElement.scrollTop === 0 || document.body.scrollTop === 0)) {
document.addEventListener('touchmove', function (e) {
if (e.touches.length === 2 && pinchStartDist !== null) {
// Two-finger pinch: scale fonts, not viewport
e.preventDefault();
const ratio = getTouchDist(e) / pinchStartDist;
const newScale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, pinchStartScale * ratio));
currentScale = Math.round(newScale * 100) / 100;
document.documentElement.style.setProperty('--font-scale', currentScale);
} else if (e.touches.length === 1 && isStandalone) {
// Single finger: block pull-to-refresh at top of page
const dy = e.touches[0].clientY - singleStartY;
if (dy > 0 && document.documentElement.scrollTop === 0 && document.body.scrollTop === 0) {
e.preventDefault();
}
}
}, { passive: false });
document.addEventListener('touchend', function (e) {
if (e.touches.length < 2 && pinchStartDist !== null) {
pinchStartDist = null;
localStorage.setItem(LS_KEY, currentScale);
}
}, { passive: true });
})();
// Clear badge count when user focuses the app