Files
notas-online/web/sw.js
T
lgcosta f4d6361b62 fix(ui): paridade Firefox nos botões da toolbar — alturas fixas, sem inflar com métricas de emoji
Firefox calcula line-height:normal pelas métricas verticais da fonte do
conteúdo (Noto Color Emoji infla botões com ícone; glifos simples ficam
menores) → linha desalinhada/desproporcional, igual em Chrome.

- .btn: inline-flex + height 28px (small 22px) — conteúdo não afeta a caixa
- .segmented .seg: height 26px (container 28 com a borda); select da toolbar 28px
- .tag-chip 20px; .tree-menu/.ftree-act line-height 1
- resets ::-moz-focus-inner/-outer
- sw v13

Verificado com Firefox 159 headless e Chromium no mesmo harness e no app
real: alturas idênticas (28/26/22/20 desktop; 40/40/38 mobile via min-height).
2026-11-05 11:46:12 -03:00

80 lines
2.3 KiB
JavaScript

/* Service Worker do Notas — caches versionados.
* BUMP de CACHE em todo deploy que mude shell/assets (o activate limpa os antigos).
*/
const CACHE = 'notas-shell-v13';
const SHELL = [
'/',
'/css/app.css',
'/js/app.js',
'/manifest.webmanifest',
'/icons/icon-192.png',
'/icons/icon-512.png',
'/icons/maskable-192.png',
'/icons/maskable-512.png',
'/icons/monochrome-512.png',
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE)
.then((cache) => cache.addAll(SHELL))
.then(() => self.skipWaiting()),
);
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys()
.then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k))))
.then(() => self.clients.claim())
.then(() => self.clients.matchAll({ type: 'window' }))
.then((clients) => {
for (const client of clients) client.postMessage('notas:updated');
}),
);
});
self.addEventListener('message', (event) => {
if (event.data === 'notas:skip-waiting') self.skipWaiting();
});
self.addEventListener('fetch', (event) => {
const req = event.request;
const url = new URL(req.url);
// 1. API e SSE: NUNCA interceptar/cache — dados devem ser sempre frescos
// (interceptar SSE quebraria o stream de tempo real).
if (url.origin !== self.location.origin || url.pathname.startsWith('/api/')) return;
// 2. Navegação (abrir o app): network-first com fallback ao shell em cache (offline).
if (req.mode === 'navigate' || req.destination === 'document') {
event.respondWith(
fetch(req)
.then((resp) => {
const copy = resp.clone();
caches.open(CACHE).then((c) => c.put('/', copy));
return resp;
})
.catch(() => caches.match('/')),
);
return;
}
// 3. Estáticos (css/js/ícones/fontes): stale-while-revalidate —
// mostra o cache na hora e atualiza em background.
event.respondWith(
caches.match(req).then((hit) => {
const refresh = fetch(req)
.then((resp) => {
if (resp && resp.ok) {
const copy = resp.clone();
caches.open(CACHE).then((c) => c.put(req, copy));
}
return resp;
})
.catch(() => hit);
return hit || refresh;
}),
);
});