diff --git a/index.html b/index.html
index 5760d3e..bb31b0d 100644
--- a/index.html
+++ b/index.html
@@ -10,7 +10,6 @@
-
@@ -69,6 +68,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -89,6 +103,20 @@
rel="stylesheet">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/manifest.webmanifest b/manifest.webmanifest
new file mode 100644
index 0000000..ca470a5
--- /dev/null
+++ b/manifest.webmanifest
@@ -0,0 +1,28 @@
+{
+ "name": "RADICAL - The Underground Parliament",
+ "short_name": "RADICAL",
+ "description": "Australia's direct democracy movement. Share policy ideas, vote on proposals, take back control.",
+ "start_url": "/?source=pwa",
+ "display": "standalone",
+ "background_color": "#000000",
+ "theme_color": "#ff0099",
+ "orientation": "portrait-primary",
+ "icons": [
+ {
+ "src": "https://radical.omar-c29.workers.dev/memes/favicon.jpg",
+ "sizes": "192x192",
+ "type": "image/jpeg"
+ },
+ {
+ "src": "https://radical.omar-c29.workers.dev/memes/favicon.jpg",
+ "sizes": "512x512",
+ "type": "image/jpeg"
+ },
+ {
+ "src": "https://radical.omar-c29.workers.dev/memes/favicon.jpg",
+ "sizes": "512x512",
+ "type": "image/jpeg",
+ "purpose": "maskable"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/service-worker.js b/service-worker.js
new file mode 100644
index 0000000..bf3c400
--- /dev/null
+++ b/service-worker.js
@@ -0,0 +1,72 @@
+// Service Worker for RADICAL PWA
+
+const CACHE_NAME = 'radical-cache-v1';
+const urlsToCache = [
+ '/',
+ '/styles.css',
+ 'https://radical.omar-c29.workers.dev/memes/favicon.jpg',
+ 'https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@300;400;500;600;700&display=swap'
+];
+
+// Install event - cache essential resources
+self.addEventListener('install', event => {
+ event.waitUntil(
+ caches.open(CACHE_NAME)
+ .then(cache => {
+ console.log('Cache opened');
+ return cache.addAll(urlsToCache);
+ })
+ );
+});
+
+// Fetch event - serve from cache when possible
+self.addEventListener('fetch', event => {
+ event.respondWith(
+ caches.match(event.request)
+ .then(response => {
+ // Return cached response if found
+ if (response) {
+ return response;
+ }
+
+ // Clone the request - request can only be used once
+ const fetchRequest = event.request.clone();
+
+ return fetch(fetchRequest).then(response => {
+ // Check if valid response
+ if (!response || response.status !== 200 || response.type !== 'basic') {
+ return response;
+ }
+
+ // Clone the response - response can only be used once
+ const responseToCache = response.clone();
+
+ caches.open(CACHE_NAME).then(cache => {
+ // Don't cache API responses
+ if (!event.request.url.includes('/api/')) {
+ cache.put(event.request, responseToCache);
+ }
+ });
+
+ return response;
+ });
+ })
+ );
+});
+
+// Activate event - clean up old caches
+self.addEventListener('activate', event => {
+ const cacheWhitelist = [CACHE_NAME];
+
+ event.waitUntil(
+ caches.keys().then(cacheNames => {
+ return Promise.all(
+ cacheNames.map(cacheName => {
+ if (cacheWhitelist.indexOf(cacheName) === -1) {
+ return caches.delete(cacheName);
+ }
+ })
+ );
+ })
+ );
+});
\ No newline at end of file