From 3ab8cdcc37ac39e62bc5691b1dc4bae3798e5cf7 Mon Sep 17 00:00:00 2001 From: 0x1d Date: Sat, 15 Nov 2025 13:59:57 +0100 Subject: [PATCH] feat: minimal pwa --- public/app.js | 16 +++++++++ public/icon-192.png | Bin 0 -> 19063 bytes public/icon-512.png | Bin 0 -> 22622 bytes public/icon.svg | 22 ++++++++++++ public/index.html | 9 ++++- public/manifest.json | 25 +++++++++++++ public/sw.js | 82 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 public/icon-192.png create mode 100644 public/icon-512.png create mode 100644 public/icon.svg create mode 100644 public/manifest.json create mode 100644 public/sw.js diff --git a/public/app.js b/public/app.js index f9850e9..c18a97c 100644 --- a/public/app.js +++ b/public/app.js @@ -31,8 +31,24 @@ document.addEventListener('DOMContentLoaded', () => { setupMobileAddLink(); setupLayoutToggle(); applyLayout(currentLayout); + registerServiceWorker(); }); +// Register service worker for PWA +function registerServiceWorker() { + if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker.register('/sw.js') + .then((registration) => { + console.log('Service Worker registered successfully:', registration.scope); + }) + .catch((error) => { + console.log('Service Worker registration failed:', error); + }); + }); + } +} + // Event listeners function setupEventListeners() { linkForm.addEventListener('submit', handleAddLink); diff --git a/public/icon-192.png b/public/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..f6a451b6081d7ad081bc459ea77db1052facfa1b GIT binary patch literal 19063 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 literal 0 HcmV?d00001 diff --git a/public/icon-512.png b/public/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..aa0cb9718491c6152ce39e80fe07e72fcb8ffce4 GIT binary patch literal 22622 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�&Xu96)etfoNg{~2`>(8NEg_{w60z!!MDpw1)04WRi|uvrK~ zMDcyV6OIWT%UcD^l6VQCh>QXSJNQ7q7x-u3!B;Vzdoh||5d#_o{>>(ew5a351itIx zp?e`DQOLZ+z4m{GLzlU~{GVafrIgYCGc2}lY~Y(su_Nn$2e@@Tz6>6a*^-L|P~^=@bHE%wmVT zJ_iWyWQfpObBzCYHG|D(eS3mDyDtdp-!ssEgPcG;!{t8wy~?xKf;$B;IFJ=7A=w_# zwCty~f&9re?wynXP7vM*tXjDa`jOq(wNnS1rmARgVAsY37d*MEL)a+_T8$a*T6j%5 zH3KINOmZov^7q!&P6QzW`CF$aQrz-H{Jw1uVH35L-8*zj(my+M;tzw z5(w+e`ZXn*{B|Y@y3AXLwtiy5OXb%T_3tr{Ar;WBBoYotPblBVBOUnLMLF0^J;mKf zcS&D55@W~k+qu=Grvz1kW+l6%H|ZIFwgN`}n{?K#&r81+4EMVf{qF@yy>Q)jc4&y` zsRHQ>|5C4Gm8z1z=5#XtZ1S%;={Su*FT-7yjmZiPi2h6S$YXI=&|N&m_ND%Z296c( z=jVPatS%wfzY(R=FaiZlIF^BKCDuk%}i z3Uvf8gumzg8+=q!mA*zU9O-*${$5#i8VCM1yeMt4pMbJ=}`<{}{J#&+L7E)$+ zEx->XA|xU%AS^5(EPh>BL`qCtN?4RnNJvUZ$S|zg?>_*y?ai$%-SGnmcHWf*0LOo? jaL@X-h0{Hg+YWoci0v*?VRG9Jz(ALj)Xrxq7~lUNhx!UH literal 0 HcmV?d00001 diff --git a/public/icon.svg b/public/icon.svg new file mode 100644 index 0000000..55e6374 --- /dev/null +++ b/public/icon.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/index.html b/public/index.html index f30d0b0..660ca68 100644 --- a/public/index.html +++ b/public/index.html @@ -2,8 +2,15 @@ - + + + + + + LinkDing - Your Link Collection + + diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 0000000..65a9c66 --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,25 @@ +{ + "name": "LinkDing", + "short_name": "LinkDing", + "description": "Your Link Collection", + "start_url": "/", + "display": "fullscreen", + "background_color": "#0f172a", + "theme_color": "#6366f1", + "orientation": "portrait-primary", + "icons": [ + { + "src": "/icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any maskable" + }, + { + "src": "/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any maskable" + } + ] +} + diff --git a/public/sw.js b/public/sw.js new file mode 100644 index 0000000..262b65e --- /dev/null +++ b/public/sw.js @@ -0,0 +1,82 @@ +const CACHE_NAME = 'linkding-v1'; +const urlsToCache = [ + '/', + '/index.html', + '/styles.css', + '/app.js', + '/manifest.json', + '/icon-192.png', + '/icon-512.png' +]; + +// Install event - cache resources +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME) + .then((cache) => { + console.log('Opened cache'); + return cache.addAll(urlsToCache); + }) + .catch((error) => { + console.error('Cache install failed:', error); + }) + ); + self.skipWaiting(); +}); + +// Activate event - clean up old caches +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys().then((cacheNames) => { + return Promise.all( + cacheNames.map((cacheName) => { + if (cacheName !== CACHE_NAME) { + console.log('Deleting old cache:', cacheName); + return caches.delete(cacheName); + } + }) + ); + }) + ); + return self.clients.claim(); +}); + +// Fetch event - serve from cache, fallback to network +self.addEventListener('fetch', (event) => { + // API requests - always fetch from network, don't cache + if (event.request.url.includes('/api/')) { + event.respondWith(fetch(event.request)); + return; + } + + // Static assets - cache first, then network + event.respondWith( + caches.match(event.request) + .then((response) => { + // Return cached version or fetch from network + return response || fetch(event.request).then((response) => { + // Don't cache non-successful responses + if (!response || response.status !== 200 || response.type !== 'basic') { + return response; + } + + // Clone the response + const responseToCache = response.clone(); + + caches.open(CACHE_NAME) + .then((cache) => { + cache.put(event.request, responseToCache); + }); + + return response; + }); + }) + .catch(() => { + // If both cache and network fail, return offline page if available + if (event.request.destination === 'document') { + return caches.match('/index.html'); + } + }) + ); +}); +