atmo.rsvp
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

switch embeds to blento

Florian 3569eef6 7fa47dbb

+94 -12
+49 -5
src/app.d.ts
··· 4 4 import type { Client } from '@atcute/client'; 5 5 import type { Did } from '@atcute/lexicons'; 6 6 7 - interface AtmoEmbedSDK { 8 - getParams(): { base: string; accent: string; dark: boolean; did: string | null }; 7 + interface BlentoSession { 8 + did: string; 9 + handle?: string; 10 + displayName?: string; 11 + avatar?: string; 12 + } 13 + 14 + interface BlentoBlobRef { 15 + $type: 'blob'; 16 + ref: { $link: string }; 17 + mimeType: string; 18 + size: number; 19 + } 20 + 21 + type BlentoWrite = 22 + | { $type: 'create'; collection: string; rkey?: string; value: Record<string, unknown> } 23 + | { $type: 'update'; collection: string; rkey: string; value: Record<string, unknown> } 24 + | { $type: 'delete'; collection: string; rkey: string }; 25 + 26 + interface Blento { 27 + ready: Promise<void>; 28 + getTheme(): { base: string | null; accent: string | null; dark: boolean }; 29 + getSession(): BlentoSession | null; 30 + on(event: 'session', cb: (session: BlentoSession | null) => void): () => void; 9 31 createRecord(opts: { 10 32 collection: string; 11 33 rkey?: string; 12 34 record: Record<string, unknown>; 13 - }): Promise<{ uri: string }>; 14 - deleteRecord(opts: { collection: string; rkey: string }): Promise<void>; 35 + }): Promise<{ uri: string; cid?: string }>; 36 + putRecord(opts: { 37 + collection: string; 38 + rkey: string; 39 + record: Record<string, unknown>; 40 + }): Promise<{ uri: string; cid?: string }>; 41 + deleteRecord(opts: { collection: string; rkey: string }): Promise<{ ok: boolean }>; 42 + applyWrites(opts: { 43 + writes: BlentoWrite[]; 44 + validate?: boolean; 45 + }): Promise<{ results: Array<{ uri?: string; cid?: string }> }>; 46 + uploadBlob(blob: Blob, opts?: { mimeType?: string }): Promise<BlentoBlobRef>; 47 + notifyResize(heightPx: number): void; 48 + notifyNavigate(url: string): void; 49 + promptLogin(): void; 15 50 } 16 51 52 + type BlentoErrorCode = 53 + | 'no_session' 54 + | 'user_cancelled' 55 + | 'rate_limited' 56 + | 'pds_error' 57 + | 'unsupported' 58 + | 'invalid_request' 59 + | 'unknown'; 60 + 17 61 declare global { 18 62 interface Window { 19 - AtmoEmbed?: AtmoEmbedSDK; 63 + Blento?: Blento; 20 64 } 21 65 namespace App { 22 66 // interface Error {}
+45 -7
src/routes/embed/p/[actor]/e/[rkey]/+page.svelte
··· 1 1 <script lang="ts"> 2 - import { untrack } from 'svelte'; 2 + import { onMount, untrack } from 'svelte'; 3 3 import { resolve } from '$app/paths'; 4 4 import Avatar from 'svelte-boring-avatars'; 5 5 import { notifyContrailOfUpdate } from '$lib/contrail'; ··· 10 10 let rsvpRkey: string | null = $state(untrack(() => data.viewerRsvpRkey)); 11 11 let submitting = $state(false); 12 12 13 + onMount(() => { 14 + if (!window.Blento) return; 15 + let cancelled = false; 16 + let unsubscribe: (() => void) | undefined; 17 + (async () => { 18 + try { 19 + await window.Blento!.ready; 20 + } catch { 21 + return; 22 + } 23 + if (cancelled) return; 24 + unsubscribe = window.Blento!.on('session', (s) => { 25 + if (s && !data.viewerDid) { 26 + const url = new URL(window.location.href); 27 + url.searchParams.set('did', s.did); 28 + window.location.href = url.toString(); 29 + } 30 + }); 31 + })(); 32 + return () => { 33 + cancelled = true; 34 + unsubscribe?.(); 35 + }; 36 + }); 37 + 38 + function handleLogin() { 39 + window.Blento?.promptLogin(); 40 + } 41 + 13 42 let eventUrl = $derived(`https://atmo.rsvp/p/${data.actorDid}/e/${data.rkey}`); 14 43 15 44 let startDate = $derived(new Date(data.eventData.startsAt)); ··· 50 79 51 80 52 81 async function submitRsvp(status: 'going' | 'interested') { 53 - if (!window.AtmoEmbed || !data.viewerDid) return; 82 + if (!window.Blento || !data.viewerDid) return; 54 83 submitting = true; 55 84 try { 56 - const result = await window.AtmoEmbed.createRecord({ 85 + await window.Blento.ready; 86 + const result = await window.Blento.createRecord({ 57 87 collection: 'community.lexicon.calendar.rsvp', 58 88 record: { 59 89 $type: 'community.lexicon.calendar.rsvp', ··· 80 110 } 81 111 82 112 async function cancelRsvp() { 83 - if (!window.AtmoEmbed || !rsvpRkey || !data.viewerDid) return; 113 + if (!window.Blento || !rsvpRkey || !data.viewerDid) return; 84 114 submitting = true; 85 115 const rsvpUri = `at://${data.viewerDid}/community.lexicon.calendar.rsvp/${rsvpRkey}`; 86 116 try { 87 - await window.AtmoEmbed.deleteRecord({ 117 + await window.Blento.ready; 118 + await window.Blento.deleteRecord({ 88 119 collection: 'community.lexicon.calendar.rsvp', 89 120 rkey: rsvpRkey 90 121 }); ··· 108 139 var a = p.get('accent'); if (a) h.classList.add(a); 109 140 if (p.get('dark') === '1') h.classList.add('dark'); 110 141 </script> 111 - <script src="https://atmo.social/embed-sdk.js"></script> 142 + <script src="https://blento.app/embed/v0/sdk.js"></script> 112 143 </svelte:head> 113 144 114 145 <div class="@container bg-base-200 dark:bg-base-950/50 text-base-900 dark:text-base-50 flex h-full items-center gap-4.5 overflow-hidden px-5 py-3 @sm:gap-5 @sm:px-6 @sm:py-4 @lg:gap-8 @lg:px-8 @lg:py-6"> ··· 148 179 </a> 149 180 150 181 <!-- RSVP --> 151 - {#if data.viewerDid} 182 + {#if !data.viewerDid} 183 + <div class="mt-2 @sm:mt-3 @lg:mt-4"> 184 + <button 185 + onclick={handleLogin} 186 + class="bg-accent-600 hover:bg-accent-700 w-full cursor-pointer rounded-md px-2.5 py-1 text-[11px] font-medium text-white transition-colors @sm:rounded-lg @sm:px-4 @sm:py-1.5 @sm:text-sm @lg:px-5 @lg:py-2 @lg:text-base" 187 + >Log in to RSVP</button> 188 + </div> 189 + {:else} 152 190 <div class="border-base-300 dark:border-base-800 bg-base-100 dark:bg-base-900/50 mt-2 flex flex-col justify-center rounded-lg border px-2 py-2 @sm:mt-3 @sm:rounded-xl @sm:px-3 @sm:py-3 @lg:mt-4 @lg:rounded-2xl @lg:px-4 @lg:py-4"> 153 191 {#if rsvpStatus === 'going'} 154 192 <div class="flex items-center justify-between">