diff --git a/clients/app/src/jsMain/kotlin/main.kt b/clients/app/src/jsMain/kotlin/main.kt index 97bc0d9f..c2baff13 100644 --- a/clients/app/src/jsMain/kotlin/main.kt +++ b/clients/app/src/jsMain/kotlin/main.kt @@ -2,10 +2,12 @@ import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.window.ComposeViewport import at.mocode.clients.app.App import kotlinx.browser.document +import org.w3c.dom.HTMLElement @OptIn(ExperimentalComposeUiApi::class) fun main() { - ComposeViewport(document.getElementById("ComposeTarget")!!) { + val root = document.getElementById("ComposeTarget") as HTMLElement + ComposeViewport(root) { App() } } diff --git a/clients/app/src/jsMain/resources/icons/icon-192.png b/clients/app/src/jsMain/resources/icons/icon-192.png new file mode 100644 index 00000000..03fc0c72 Binary files /dev/null and b/clients/app/src/jsMain/resources/icons/icon-192.png differ diff --git a/clients/app/src/jsMain/resources/icons/icon-512.png b/clients/app/src/jsMain/resources/icons/icon-512.png new file mode 100644 index 00000000..16994d9c Binary files /dev/null and b/clients/app/src/jsMain/resources/icons/icon-512.png differ diff --git a/clients/app/src/jsMain/resources/index.html b/clients/app/src/jsMain/resources/index.html index 37eed833..637b1320 100644 --- a/clients/app/src/jsMain/resources/index.html +++ b/clients/app/src/jsMain/resources/index.html @@ -13,7 +13,7 @@ diff --git a/clients/app/src/jsMain/resources/sw.js b/clients/app/src/jsMain/resources/sw.js index a43af350..33f7a113 100644 --- a/clients/app/src/jsMain/resources/sw.js +++ b/clients/app/src/jsMain/resources/sw.js @@ -23,14 +23,30 @@ self.addEventListener('activate', (event) => { self.addEventListener('fetch', (event) => { const req = event.request; + const url = new URL(req.url); + + const isHttp = url.protocol === 'http:' || url.protocol === 'https:'; + const sameOrigin = url.origin === self.location.origin; + const isExtension = url.protocol === 'chrome-extension:'; + const isHotUpdate = url.pathname.includes('hot-update'); + + // Ignore non-GET, cross-origin, browser extensions, and HMR/hot-update requests + if (req.method !== 'GET' || !isHttp || !sameOrigin || isExtension || isHotUpdate) { + return; // Let the browser handle it + } + if (req.mode === 'navigate') { // Network-first for navigation event.respondWith( - fetch(req).then((resp) => { - const copy = resp.clone(); - caches.open(CACHE_NAME).then((cache) => cache.put('/', copy)); - return resp; - }).catch(() => caches.match('/index.html')) + fetch(req) + .then((resp) => { + if (resp && resp.status === 200 && resp.type === 'basic') { + const copy = resp.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put('/index.html', copy)).catch(() => {}); + } + return resp; + }) + .catch(() => caches.match('/index.html')) ); return; } @@ -39,11 +55,15 @@ self.addEventListener('fetch', (event) => { event.respondWith( caches.match(req).then((cached) => { if (cached) return cached; - return fetch(req).then((resp) => { - const copy = resp.clone(); - caches.open(CACHE_NAME).then((cache) => cache.put(req, copy)); - return resp; - }); + return fetch(req) + .then((resp) => { + if (resp && resp.status === 200 && resp.type === 'basic') { + const copy = resp.clone(); + caches.open(CACHE_NAME).then((cache) => cache.put(req, copy)).catch(() => {}); + } + return resp; + }) + .catch(() => caches.match(req)); }) ); });