implement PWA support
Hunter
Friday, July 11th, 2025 at 3:57 PM
Binary files differ.
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>Web Workshop</title>
7 <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🛼</text></svg>">
8 + <link rel="manifest" href="manifest.json">
9 <script type="module">
10 import {EditorView, keymap, placeholder} from "https://esm.sh/@codemirror/view@6"
11 import {EditorState} from "https://esm.sh/@codemirror/state@6"
290
291 // Initialize when page loads
292 initializeCodeMirror();
293 +
294 + // Register service worker
295 + if ('serviceWorker' in navigator) {
296 + window.addEventListener('load', () => {
297 + navigator.serviceWorker.register('/sw.js')
298 + .then(registration => {
299 + console.log('SW registered: ', registration);
300 + })
301 + .catch(registrationError => {
302 + console.log('SW registration failed: ', registrationError);
303 + });
304 + });
305 + }
306 </script>
307 </body>
308 </html>
1 +{
2 + "name": "Web Workshop",
3 + "short_name": "WW",
4 + "description": "HTML editor and live preview tool",
5 + "start_url": "/",
6 + "display": "standalone",
7 + "background_color": "#16181b",
8 + "theme_color": "#16181b",
9 + "orientation": "any",
10 + "icons": [
11 + {
12 + "src": "images/rollerskate.png",
13 + "sizes": "160x160",
14 + "type": "image/png"
15 + },
16 + {
17 + "src": "images/rollerskate.png",
18 + "sizes": "192x192",
19 + "type": "image/png"
20 + }
21 + ]
22 +}
1 +const CACHE_NAME = 'web-workshop-v1';
2 +const urlsToCache = [
3 + '/',
4 + '/index.html',
5 + '/manifest.json'
6 +];
7 +
8 +// Function to discover and cache all files in directories
9 +async function cacheDirectoryFiles(cache, directories) {
10 + for (const dir of directories) {
11 + try {
12 + // Try to fetch directory listing
13 + const response = await fetch(dir);
14 + if (response.ok) {
15 + const html = await response.text();
16 + // Extract file links from directory listing
17 + const links = html.match(/href="([^"]*\.(png|jpg|jpeg|gif|svg|webp|html|css|js|json|txt|md))"/gi);
18 + if (links) {
19 + const files = links.map(link => {
20 + const match = link.match(/href="([^"]*)"/);
21 + return match ? dir + match[1] : null;
22 + }).filter(Boolean);
23 +
24 + // Cache each file
25 + for (const file of files) {
26 + try {
27 + await cache.add(file);
28 + } catch (e) {
29 + console.log(`Failed to cache ${file}:`, e);
30 + }
31 + }
32 + }
33 + }
34 + } catch (e) {
35 + console.log(`Failed to cache directory ${dir}:`, e);
36 + }
37 + }
38 +}
39 +
40 +// Install service worker and cache resources
41 +self.addEventListener('install', event => {
42 + event.waitUntil(
43 + caches.open(CACHE_NAME)
44 + .then(async cache => {
45 + // Cache core files
46 + await cache.addAll(urlsToCache);
47 + // Cache directory files
48 + await cacheDirectoryFiles(cache, ['/images/', '/pages/']);
49 + })
50 + .then(() => self.skipWaiting())
51 + );
52 +});
53 +
54 +// Activate service worker and clean up old caches
55 +self.addEventListener('activate', event => {
56 + event.waitUntil(
57 + caches.keys().then(cacheNames => {
58 + return Promise.all(
59 + cacheNames.map(cacheName => {
60 + if (cacheName !== CACHE_NAME) {
61 + return caches.delete(cacheName);
62 + }
63 + })
64 + );
65 + }).then(() => self.clients.claim())
66 + );
67 +});
68 +
69 +// Fetch strategy: Network first, then cache (for updates when online)
70 +self.addEventListener('fetch', event => {
71 + event.respondWith(
72 + fetch(event.request)
73 + .then(response => {
74 + // If we got a response, add it to the cache
75 + if (response.status === 200) {
76 + const responseClone = response.clone();
77 + caches.open(CACHE_NAME)
78 + .then(cache => cache.put(event.request, responseClone));
79 + }
80 + return response;
81 + })
82 + .catch(() => {
83 + // Network failed, try cache
84 + return caches.match(event.request)
85 + .then(response => {
86 + if (response) {
87 + return response;
88 + }
89 + // If not in cache and it's a navigation request, serve index.html
90 + if (event.request.mode === 'navigate') {
91 + return caches.match('/index.html');
92 + }
93 + throw new Error('No cached version available');
94 + });
95 + })
96 + );
97 +});