diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2025-11-08 16:28:10 -0500 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2025-11-08 16:28:10 -0500 |
| commit | fc6914831743f6d683c59adb367479defe6f8b3a (patch) | |
| tree | 5b997adac55f47b52f30022013b8ec3b2c10bcc5 /ui/routes/(swatch) | |
| parent | 0ef69c7d256380e660edc45ace7f1d6151226340 (diff) | |
| parent | 6bab5b4405c9adafb2ce76540595a62eea80acc0 (diff) | |
Integrate the prototype push notification support.
We're going to move forwards with this for now, as low-utility as it is, so that we can more easily iterate on it in a real-world environment (hi.grimoire.ca).
Diffstat (limited to 'ui/routes/(swatch)')
| -rw-r--r-- | ui/routes/(swatch)/.swatch/+page.svelte | 1 | ||||
| -rw-r--r-- | ui/routes/(swatch)/.swatch/PushSubscription/+page.svelte | 79 |
2 files changed, 80 insertions, 0 deletions
diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte index 5334438..c1969e5 100644 --- a/ui/routes/(swatch)/.swatch/+page.svelte +++ b/ui/routes/(swatch)/.swatch/+page.svelte @@ -19,5 +19,6 @@ <li><a href="MessageRun">MessageRun</a></li> <li><a href="MessageInput">MessageInput</a></li> <li><a href="Message">Message</a></li> + <li><a href="PushSubscription">PushSubscription</a></li> <li><a href="swatch/EventLog">swatch/EventLog</a></li> </ul> diff --git a/ui/routes/(swatch)/.swatch/PushSubscription/+page.svelte b/ui/routes/(swatch)/.swatch/PushSubscription/+page.svelte new file mode 100644 index 0000000..3d564a3 --- /dev/null +++ b/ui/routes/(swatch)/.swatch/PushSubscription/+page.svelte @@ -0,0 +1,79 @@ +<script> + import { DateTime } from 'luxon'; + + import PushSubscription from '$lib/components/PushSubscription.svelte'; + import { makeDeriver } from '$lib/swatch/derive.js'; + import EventLog from '$lib/components/swatch/EventLog.svelte'; + import EventCapture from '$lib/swatch/event-capture.svelte.js'; + import * as json from '$lib/swatch/json.js'; + + function fromBase64(str) { + if (str.trim().length === 0) { + return null; + } + const bytes = Uint8Array.fromBase64(str, { alphabet: 'base64url' }); + return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength); + } + + const base64Deriver = makeDeriver(fromBase64); + + // This is a "real" key, but it's not a key that's in use anywhere. I generated it for this + // purpose. -o + const testVapidKey = + 'BJXUH-WxM8BoxntTsrLufxc2Zlbwk-A1wsF01-ykUyh9pSUZG1Ymk3R-FOxJTGApQeJWIYTW9j-1sLQFIL8cGBU='; + + let vapidInput = $state(''); + let vapid = $derived(base64Deriver(vapidInput)); + + // See <> for schema. This is an approximation of the browser subscription object. + const testSubscription = json.encode({ + endpoint: 'https://push.example.com/1234', + expirationTime: performance.now() + 86400 /* sec */ * 1000 /* millisec */, + options: { + userVisibleOnly: true, + applicationServerKey: null, + }, + }); + + let subscriptionInput = $state(''); + let subscription = $derived(json.decode(subscriptionInput)); + + let capture = $state(new EventCapture()); + const subscribe = capture.on('subscribe'); + const ping = capture.on('ping'); +</script> + +<h1><code>PushSubscription</code></h1> + +<nav><p><a href=".">Back to swatches</a></p></nav> + +<h2>properties</h2> + +<div class="component-properties"> + <label>vapid key <input type="text" bind:value={vapidInput} /></label> + <div class="suggestion"> + interesting values: + <button onclick={() => (vapidInput = '')}>(none)</button> + <button onclick={() => (vapidInput = testVapidKey)}>test key</button> + </div> + + <label + ><p>subscription (json)</p> + <textarea bind:value={subscriptionInput}></textarea> + <div class="suggestion"> + interesting values: + <button onclick={() => (subscriptionInput = '')}>(none)</button> + <button onclick={() => (subscriptionInput = testSubscription)}>example</button> + </div> + </label> +</div> + +<h2>rendered</h2> + +<div class="component-preview"> + <PushSubscription {vapid} {subscription} {subscribe} {ping} /> +</div> + +<h2>events</h2> + +<EventLog events={capture.events} clear={capture.clear.bind(capture)} /> |
