diff options
| author | Adam Soltys <[email protected]> | 2024-04-11 13:35:06 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2024-04-11 13:35:06 -0700 |
| commit | 9d55044d4321233f6ffdbada737bccb5894a0f2a (patch) | |
| tree | eadaa34e2c9e4e61184d4d0634cdbab3b4ac5d67 | |
| parent | c92dce530d00edad2447daba619514f50418f0ac (diff) | |
| download | coinos-ui-9d55044d4321233f6ffdbada737bccb5894a0f2a.tar.gz coinos-ui-9d55044d4321233f6ffdbada737bccb5894a0f2a.zip | |
service worker for pwa
| -rwxr-xr-x | bun.lockb | bin | 120851 -> 120851 bytes | |||
| -rw-r--r-- | src/app.html | 1 | ||||
| -rw-r--r-- | src/locales/en.json | 2 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/(profile)/+layout.svelte | 6 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/(profile)/+page.svelte | 28 | ||||
| -rw-r--r-- | src/routes/+layout.svelte | 17 | ||||
| -rw-r--r-- | src/service-worker.js | 83 | ||||
| -rw-r--r-- | static/home.png | bin | 0 -> 260144 bytes | |||
| -rw-r--r-- | static/manifest.webmanifest | 66 | ||||
| -rw-r--r-- | static/receive.png | bin | 0 -> 247776 bytes | |||
| -rw-r--r-- | static/screenshot.png | bin | 219558 -> 0 bytes | |||
| -rw-r--r-- | svelte.config.js | 3 |
12 files changed, 188 insertions, 18 deletions
| Binary files differ diff --git a/src/app.html b/src/app.html index 9d7e2fdb..728900ed 100644 --- a/src/app.html +++ b/src/app.html @@ -9,6 +9,7 @@ /> <meta name="description" content="The easiest raysway to get started with bitcoin" /> <meta name="keywords" content="open source bitcoin lightning web wallet" /> + <meta name="theme-color" content="#fff"/> <link rel="manifest" href="/manifest.webmanifest" /> %sveltekit.head% </head> diff --git a/src/locales/en.json b/src/locales/en.json index f29c8d29..93affb7f 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -155,7 +155,7 @@ "subheader": "Latest Updates" }, "user": { - "details": "Details", + "info": "Info", "noMessages": "You have not sent or received any messages yet", "profilePage": "Profile page", "nostrPubkey": "Nostr pubkey", diff --git a/src/routes/(app)/[username]/(profile)/+layout.svelte b/src/routes/(app)/[username]/(profile)/+layout.svelte index 5752491b..11e33dbf 100644 --- a/src/routes/(app)/[username]/(profile)/+layout.svelte +++ b/src/routes/(app)/[username]/(profile)/+layout.svelte @@ -168,14 +168,16 @@ </a> {/if} + {#if user.username !== subject.username} <button type="button" on:click={toggleDetails} class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex justify-center w-full" > - <Icon icon="edit" style="w-8 mr-2" /> - <div class="mt-1">{$t("user.details")}</div> + <Icon icon="profile" style="w-8 mr-2" /> + <div class="mt-1">{$t("user.info")}</div> </button> + {/if} {#if user?.admin && user.username !== subject.username} <form class="w-full flex" on:submit|preventDefault={reset}> diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index f0ab743a..9443c063 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -102,6 +102,21 @@ let reset = () => (dragDisabled = user?.username !== subject?.username || window.innerWidth < 768); + + let installPrompt; + onMount(() => { + if (!browser) return; + window.addEventListener("beforeinstallprompt", (event) => { + event.preventDefault(); + installPrompt = event; + }); + }); + + let install = async () => { + if (!installPrompt) return; + await installPrompt.prompt(); + installPrompt = null; + }; </script> <svelte:window on:resize={reset} /> @@ -148,18 +163,17 @@ </button> </a> - <a href={`/${user.username}/items/create`} class="contents"> + {#if installPrompt} <button - class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex bg-primary grow basis-full" + class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex bg-black text-white grow basis-full fixed bottom-16" + on:click={install} > <div class="mx-auto flex gap-2"> - <Icon icon="plus" style="w-8 mx-auto" /> - <div class="my-auto text-xl whitespace-nowrap"> - {$t("items.add")} - </div> + <Icon icon="save" style="w-8 mx-auto invert" /> + <div class="my-auto text-xl whitespace-nowrap">Install app</div> </div> </button> - </a> + {/if} </div> {/if} diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 545018ed..43e573ef 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -2,6 +2,23 @@ import { PUBLIC_DOMAIN } from "$env/static/public"; import "../app.css"; import { loading, t } from "$lib/translations"; + import { onMount } from "svelte"; + import { dev } from "$app/environment"; + + onMount(() => { + if ("serviceWorker" in navigator) { + navigator.serviceWorker + .register("/service-worker.js", { + type: dev ? "module" : "classic", + }) + .then((registration) => { + console.log("SW registered: ", registration); + }) + .catch((registrationError) => { + console.log("SW registration failed: ", registrationError); + }); + } + }); export let data; let { pathname } = data; diff --git a/src/service-worker.js b/src/service-worker.js new file mode 100644 index 00000000..a95ff268 --- /dev/null +++ b/src/service-worker.js @@ -0,0 +1,83 @@ +/// <reference types="@sveltejs/kit" /> +import { build, files, version } from "$service-worker"; + +// Create a unique cache name for this deployment +const CACHE = `cache-${version}`; + +const ASSETS = [ + ...build, // the app itself + ...files, // everything in `static` +]; + +self.addEventListener("install", (event) => { + console.log("SW installed"); + + // Create a new cache and add all files to it + async function addFilesToCache() { + const cache = await caches.open(CACHE); + await cache.addAll(ASSETS); + } + + event.waitUntil(addFilesToCache()); +}); + +self.addEventListener("activate", (event) => { + // Remove previous cached data from disk + async function deleteOldCaches() { + for (const key of await caches.keys()) { + if (key !== CACHE) await caches.delete(key); + } + } + + event.waitUntil(deleteOldCaches()); +}); + +self.addEventListener("fetch", (event) => { + console.log("FETCH") + // ignore POST requests etc + if (event.request.method !== "GET") return; + + async function respond() { + const url = new URL(event.request.url); + const cache = await caches.open(CACHE); + + // `build`/`files` can always be served from the cache + if (ASSETS.includes(url.pathname)) { + const response = await cache.match(url.pathname); + + if (response) { + return response; + } + } + + // for everything else, try the network first, but + // fall back to the cache if we're offline + try { + const response = await fetch(event.request); + + // if we're offline, fetch can return a value that is not a Response + // instead of throwing - and we can't pass this non-Response to respondWith + if (!(response instanceof Response)) { + throw new Error("invalid response from fetch"); + } + + if (response.status === 200) { + cache.put(event.request, response.clone()); + } + + return response; + } catch (err) { + const response = await cache.match(event.request); + + if (response) { + return response; + } + + // if there's no cache, then just error out + // as there is nothing we can do to respond to this request + throw err; + } + } + + event.respondWith(respond()); +}); diff --git a/static/home.png b/static/home.png Binary files differnew file mode 100644 index 00000000..e6ba1b85 --- /dev/null +++ b/static/home.png diff --git a/static/manifest.webmanifest b/static/manifest.webmanifest index d09b8090..15f55603 100644 --- a/static/manifest.webmanifest +++ b/static/manifest.webmanifest @@ -11,30 +11,80 @@ { "src": "/icon-192x192.png", "sizes": "192x192", - "type": "image/png" + "type": "image/png", + "purpose": "maskable" }, { "src": "/icon-256x256.png", "sizes": "256x256", - "type": "image/png" + "type": "image/png", + "purpose": "maskable" }, { "src": "/icon-384x384.png", "sizes": "384x384", - "type": "image/png" + "type": "image/png", + "purpose": "maskable" }, { "src": "/icon-512x512.png", "sizes": "512x512", - "type": "image/png" + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "/icon-192x192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icon-256x256.png", + "sizes": "256x256", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icon-384x384.png", + "sizes": "384x384", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/icon-512x512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" } ], "screenshots": [ { - "src": "/screenshot.png", - "sizes": "632x701", - "type": "image/gif", - "label": "Homepage" + "src": "/home.png", + "sizes": "801x920", + "type": "image/png", + "label": "Homepage", + "form_factor": "wide" + }, + { + "src": "/receive.png", + "sizes": "801x920", + "type": "image/png", + "label": "Receive", + "form_factor": "wide" + }, + { + "src": "/home.png", + "sizes": "801x920", + "type": "image/png", + "label": "Homepage", + "form_factor": "narrow" + }, + { + "src": "/receive.png", + "sizes": "801x920", + "type": "image/png", + "label": "Receive", + "form_factor": "narrow" } ], "protocol_handlers": [ diff --git a/static/receive.png b/static/receive.png Binary files differnew file mode 100644 index 00000000..8151e52c --- /dev/null +++ b/static/receive.png diff --git a/static/screenshot.png b/static/screenshot.png Binary files differdeleted file mode 100644 index e10fbd19..00000000 --- a/static/screenshot.png +++ /dev/null diff --git a/svelte.config.js b/svelte.config.js index bc89e810..ccd77e7d 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -17,6 +17,9 @@ const config = { crawl: false, entries: [], }, + serviceWorker: { + register: false + } }, onwarn: (warning, handler) => { if (warning.code.includes("caption") || warning.filename.includes("Toast")) |
