Offline edits that send when back online, books saved on the device, and keyboard access for dialogs and Bible verses; roadmap

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-27 11:36:32 -04:00
1 parent 275ef2009f
commit 95ade02bf2
11 files changed
+96 -18

No files matched your search

+8 -2
View File
@@ -1,5 +1,5 @@
// App-shell cache only; Seafile/API traffic always goes to the network.
const CACHE = 'hub-v119';
const CACHE = 'hub-v122';
const KEEP = /^hub-(offline|share|who|data-)/; // caches that outlive a new version
const SHARE = 'hub-share'; // files shared into the app from other apps, held until the person picks a folder
const SHELL = ['/icon.svg', '/manifest.webmanifest', '/icons/icon-192.png', '/icons/apple-touch-icon.png'];
@@ -35,7 +35,7 @@ async function offlineAudio(req) {
}
// Saved data for offline use: the lists a person is likely to want with no signal (tasks, notes, recipes, calendar, contacts, chores). Network first; when the network fails the last
// copy is used. Kept per person (the page tells us who is signed in), so a shared tablet never shows one person's data to another. Reading only: changes need a connection.
const DATA_OK = /^\/api\/(tasks(\/(upcoming|summary|lists|due))?|notes|recipes(\/(r\/[\w-]+|shopping))?|cal\/(events|list)|contacts|chores(\/\w+)?|bible\/(state))\/?$/;
const DATA_OK = /^\/api\/(read\/(list|book\/\w+\/notes)|tasks(\/(upcoming|summary|lists|due))?|notes|recipes(\/(r\/[\w-]+|shopping))?|cal\/(events|list)|contacts|chores(\/\w+)?|bible\/(state))\/?$/;
const whoNow = async () => { try { const r = await (await caches.open('hub-who')).match('/who'); return r ? await r.text() : ''; } catch { return ''; } };
self.addEventListener('message', e => {
const d = e.data || {}; if (d.type !== 'who') return;
@@ -54,6 +54,11 @@ async function dataFirstNetwork(req) {
throw err;
}
}
// A book saved on this device (see reader.js): answered from the saved copy whatever the address's query, otherwise the network as normal.
async function offlineBook(req) {
const hit = await (await caches.open('hub-offline')).match(req.url, { ignoreSearch: true });
return hit || fetch(req);
}
// Share target: other apps send files here (POST); keep them and open the app, which asks where to put them.
async function takeShare(request) {
try {
@@ -68,6 +73,7 @@ self.addEventListener('fetch', e => {
const u = new URL(e.request.url);
if (e.request.method === 'POST' && u.origin === location.origin && u.pathname === '/share-target') return e.respondWith(takeShare(e.request));
if (e.request.method === 'GET' && u.origin === location.origin && /^\/api\/podcast\/podcasts\/[^/]+\/file$/.test(u.pathname)) return e.respondWith(offlineAudio(e.request));
if (e.request.method === 'GET' && u.origin === location.origin && /^\/api\/read\/book\/\w+\/(file|cover)$/.test(u.pathname)) return e.respondWith(offlineBook(e.request)); // (books saved on this device)
if (e.request.method === 'GET' && u.origin === location.origin && /^\/plex\/library\/parts\//.test(u.pathname)) return e.respondWith(offlineAudio(e.request)); // (albums saved on this device)
if (e.request.method === 'GET' && u.origin === location.origin && DATA_OK.test(u.pathname)) return e.respondWith(dataFirstNetwork(e.request));
if (e.request.method !== 'GET' || u.origin !== location.origin || u.pathname.startsWith('/sf/') || u.pathname.startsWith('/plex/') || u.pathname.startsWith('/api/')) return;