Web: redesign, logo, PWA, QR codes, Spotify guidance
- Album-art-tinted cards that crossfade on song change, equalizer bars, live avatar rings, drifting ambient colour, Space Grotesk display font, brand purple-to-blue gradient from the logo - Feed cards rise in and glide to new positions (motion); respects reduced-motion - New logo as nav mark, favicon and Apple touch icon - Installable PWA: manifest, maskable icons, small service worker (cached build assets + offline page), security headers - Show-QR-code on your own profile; centred profile header with stats - Settings explains connecting Spotify via Last.fm or ListenBrainz Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
// musicshare service worker.
|
||||
// Deliberately small: live data must always come from the network, so we only
|
||||
// cache Next.js's immutable build assets, and show an offline page when a
|
||||
// navigation fails. (Web push notifications will hook in here later.)
|
||||
const VERSION = 'v1';
|
||||
const STATIC_CACHE = `static-${VERSION}`;
|
||||
const OFFLINE_URL = '/offline.html';
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(caches.open(STATIC_CACHE).then((cache) => cache.addAll([OFFLINE_URL, '/icon-192.png'])));
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
caches
|
||||
.keys()
|
||||
.then((keys) => Promise.all(keys.filter((k) => k !== STATIC_CACHE).map((k) => caches.delete(k))))
|
||||
.then(() => self.clients.claim()),
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
const { request } = event;
|
||||
if (request.method !== 'GET') return;
|
||||
const url = new URL(request.url);
|
||||
if (url.origin !== self.location.origin) return; // API calls, artwork, etc.: straight to the network
|
||||
|
||||
// Hashed build assets never change: cache first.
|
||||
if (url.pathname.startsWith('/_next/static/')) {
|
||||
event.respondWith(
|
||||
caches.match(request).then(
|
||||
(hit) =>
|
||||
hit ||
|
||||
fetch(request).then((res) => {
|
||||
const copy = res.clone();
|
||||
caches.open(STATIC_CACHE).then((cache) => cache.put(request, copy));
|
||||
return res;
|
||||
}),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pages: always fresh; offline page if the network is gone.
|
||||
if (request.mode === 'navigate') {
|
||||
event.respondWith(fetch(request).catch(() => caches.match(OFFLINE_URL)));
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user