your personal website on atproto - mirror blento.app

event stuff

Florian 50224195 043df1e8

+66 -145
+13 -13
src/lib/cards/social/EventCard/CreateEventCardModal.svelte
··· 2 import { Alert, Button, Input, Subheading } from '@foxui/core'; 3 import Modal from '$lib/components/modal/Modal.svelte'; 4 import type { CreationModalComponentProps } from '../../types'; 5 6 const EVENT_COLLECTION = 'community.lexicon.calendar.event'; 7 ··· 38 throw new Error('Invalid URL format'); 39 } 40 41 - // Validate the event exists by fetching it 42 - const response = await fetch( 43 - `https://smokesignal.events/xrpc/community.lexicon.calendar.GetEvent?repository=${encodeURIComponent(parsed.did)}&record_key=${encodeURIComponent(parsed.rkey)}` 44 - ); 45 46 - if (!response.ok) { 47 throw new Error('Event not found'); 48 } 49 ··· 55 errorMessage = 56 err instanceof Error && err.message === 'Event not found' 57 ? "Couldn't find that event. Please check the URL and try again." 58 - : 'Invalid URL. Please enter a valid smokesignal.events URL or AT URI.'; 59 return false; 60 } finally { 61 isValidating = false; ··· 70 }} 71 class="flex flex-col gap-2" 72 > 73 - <Subheading>Enter a Smoke Signal event URL</Subheading> 74 <Input 75 bind:value={eventUrl} 76 - placeholder="https://smokesignal.events/did:.../..." 77 class="mt-4" 78 /> 79 ··· 82 {/if} 83 84 <p class="text-base-500 dark:text-base-400 mt-2 text-xs"> 85 - Paste a URL from <a 86 - href="https://smokesignal.events" 87 - class="text-accent-800 dark:text-accent-300" 88 - target="_blank">smokesignal.events</a 89 - > or an AT URI for a calendar event. 90 </p> 91 92 <div class="mt-4 flex justify-end gap-2">
··· 2 import { Alert, Button, Input, Subheading } from '@foxui/core'; 3 import Modal from '$lib/components/modal/Modal.svelte'; 4 import type { CreationModalComponentProps } from '../../types'; 5 + import { getRecord } from '$lib/atproto/methods'; 6 + import type { Did } from '@atcute/lexicons'; 7 8 const EVENT_COLLECTION = 'community.lexicon.calendar.event'; 9 ··· 40 throw new Error('Invalid URL format'); 41 } 42 43 + // Validate the event exists by fetching the record directly 44 + const record = await getRecord({ 45 + did: parsed.did as Did, 46 + collection: EVENT_COLLECTION, 47 + rkey: parsed.rkey 48 + }); 49 50 + if (!record?.value) { 51 throw new Error('Event not found'); 52 } 53 ··· 59 errorMessage = 60 err instanceof Error && err.message === 'Event not found' 61 ? "Couldn't find that event. Please check the URL and try again." 62 + : 'Invalid URL. Please enter a valid event AT URI or smokesignal.events URL.'; 63 return false; 64 } finally { 65 isValidating = false; ··· 74 }} 75 class="flex flex-col gap-2" 76 > 77 + <Subheading>Enter an event URL</Subheading> 78 <Input 79 bind:value={eventUrl} 80 + placeholder="at://did:.../community.lexicon.calendar.event/..." 81 class="mt-4" 82 /> 83 ··· 86 {/if} 87 88 <p class="text-base-500 dark:text-base-400 mt-2 text-xs"> 89 + Paste an AT URI for a calendar event or a smokesignal.events URL. 90 </p> 91 92 <div class="mt-4 flex justify-end gap-2">
+4 -53
src/lib/cards/social/EventCard/EventCard.svelte
··· 91 } 92 93 let eventUrl = $derived(() => { 94 - if (eventData?.url) return eventData.url; 95 if (parsedUri) { 96 - return `https://smokesignal.events/${parsedUri.repo}/${parsedUri.rkey}`; 97 } 98 return '#'; 99 }); ··· 144 </div> 145 146 {#if isMobile() ? item.mobileW > 4 : item.w > 2} 147 - <Button href={eventUrl()} target="_blank" rel="noopener noreferrer" class="z-50" 148 - >View event</Button 149 - > 150 {/if} 151 </div> 152 ··· 211 {eventData.description} 212 </p> 213 {/if} 214 - 215 - {#if (eventData.countGoing !== undefined || eventData.countInterested !== undefined) && ((isMobile() && item.mobileH >= 4) || (!isMobile() && item.h >= 3))} 216 - <div 217 - class="text-base-600 dark:text-base-400 accent:text-base-800 flex flex-wrap gap-3 text-xs" 218 - > 219 - {#if eventData.countGoing !== undefined} 220 - <div class="flex items-center gap-1"> 221 - <svg 222 - xmlns="http://www.w3.org/2000/svg" 223 - fill="none" 224 - viewBox="0 0 24 24" 225 - stroke-width="1.5" 226 - stroke="currentColor" 227 - class="size-4" 228 - > 229 - <path 230 - stroke-linecap="round" 231 - stroke-linejoin="round" 232 - d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" 233 - /> 234 - </svg> 235 - <span>{eventData.countGoing} going</span> 236 - </div> 237 - {/if} 238 - {#if eventData.countInterested !== undefined} 239 - <div class="flex items-center gap-1"> 240 - <svg 241 - xmlns="http://www.w3.org/2000/svg" 242 - fill="none" 243 - viewBox="0 0 24 24" 244 - stroke-width="1.5" 245 - stroke="currentColor" 246 - class="size-4" 247 - > 248 - <path 249 - stroke-linecap="round" 250 - stroke-linejoin="round" 251 - d="M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z" 252 - /> 253 - </svg> 254 - <span>{eventData.countInterested} interested</span> 255 - </div> 256 - {/if} 257 - </div> 258 - {/if} 259 </div> 260 261 {#if showImage} ··· 267 268 <a 269 href={eventUrl()} 270 - class="absolute inset-0 h-full w-full" 271 target="_blank" 272 - rel="noopener noreferrer" 273 use:qrOverlay={{ 274 context: { 275 title: eventData?.name ?? '' 276 } 277 }} 278 > 279 - <span class="sr-only">View event on smokesignal.events</span> 280 </a> 281 {:else if isLoaded} 282 <div class="flex h-full w-full items-center justify-center">
··· 91 } 92 93 let eventUrl = $derived(() => { 94 if (parsedUri) { 95 + return `/${parsedUri.repo}/events/${parsedUri.rkey}`; 96 } 97 return '#'; 98 }); ··· 143 </div> 144 145 {#if isMobile() ? item.mobileW > 4 : item.w > 2} 146 + <Button href={eventUrl()} target="_blank" class="z-50">View event</Button> 147 {/if} 148 </div> 149 ··· 208 {eventData.description} 209 </p> 210 {/if} 211 </div> 212 213 {#if showImage} ··· 219 220 <a 221 href={eventUrl()} 222 target="_blank" 223 + class="absolute inset-0 h-full w-full" 224 use:qrOverlay={{ 225 context: { 226 title: eventData?.name ?? '' 227 } 228 }} 229 > 230 + <span class="sr-only">View event</span> 231 </a> 232 {:else if isLoaded} 233 <div class="flex h-full w-full items-center justify-center">
+11 -11
src/lib/cards/social/EventCard/index.ts
··· 1 - import { parseUri } from '$lib/atproto'; 2 import type { CardDefinition } from '../../types'; 3 import CreateEventCardModal from './CreateEventCardModal.svelte'; 4 import EventCard from './EventCard.svelte'; 5 6 const EVENT_COLLECTION = 'community.lexicon.calendar.event'; 7 ··· 39 uri: string; 40 name?: string; 41 }>; 42 - countGoing?: number; 43 - countInterested?: number; 44 - url: string; 45 }; 46 47 export const EventCardDefinition = { ··· 66 if (!parsedUri || !parsedUri.rkey || !parsedUri.repo) continue; 67 68 try { 69 - const response = await fetch( 70 - `https://smokesignal.events/xrpc/community.lexicon.calendar.GetEvent?repository=${encodeURIComponent(parsedUri.repo)}&record_key=${encodeURIComponent(parsedUri.rkey)}` 71 - ); 72 73 - if (response.ok) { 74 - const data = await response.json(); 75 - eventDataMap[item.id] = data as EventData; 76 } 77 } catch (error) { 78 console.error('Failed to fetch event data:', error); ··· 118 119 name: 'Event', 120 121 - keywords: ['calendar', 'meetup', 'schedule', 'date', 'rsvp'], 122 groups: ['Social'], 123 icon: `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-4"><path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5" /></svg>` 124 } as CardDefinition & { type: 'event' };
··· 1 + import { parseUri, getRecord } from '$lib/atproto'; 2 import type { CardDefinition } from '../../types'; 3 import CreateEventCardModal from './CreateEventCardModal.svelte'; 4 import EventCard from './EventCard.svelte'; 5 + import type { Did } from '@atcute/lexicons'; 6 7 const EVENT_COLLECTION = 'community.lexicon.calendar.event'; 8 ··· 40 uri: string; 41 name?: string; 42 }>; 43 + url?: string; 44 }; 45 46 export const EventCardDefinition = { ··· 65 if (!parsedUri || !parsedUri.rkey || !parsedUri.repo) continue; 66 67 try { 68 + const record = await getRecord({ 69 + did: parsedUri.repo as Did, 70 + collection: EVENT_COLLECTION, 71 + rkey: parsedUri.rkey 72 + }); 73 74 + if (record?.value) { 75 + eventDataMap[item.id] = record.value as EventData; 76 } 77 } catch (error) { 78 console.error('Failed to fetch event data:', error); ··· 118 119 name: 'Event', 120 121 + keywords: ['calendar', 'meetup', 'schedule', 'date', 'rsvp', 'smokesignal'], 122 groups: ['Social'], 123 icon: `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-4"><path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5" /></svg>` 124 } as CardDefinition & { type: 'event' };
+11 -11
src/routes/[[actor=actor]]/e/+page.server.ts src/routes/[[actor=actor]]/events/+page.server.ts
··· 1 import { error } from '@sveltejs/kit'; 2 import type { EventData } from '$lib/cards/social/EventCard'; 3 - import { getBlentoOrBskyProfile } from '$lib/atproto/methods.js'; 4 import { createCache, type CachedProfile } from '$lib/cache'; 5 import type { Did } from '@atcute/lexicons'; 6 import { getActor } from '$lib/actor.js'; ··· 15 } 16 17 try { 18 - const [eventsResponse, hostProfile] = await Promise.all([ 19 - fetch( 20 - `https://smokesignal.events/xrpc/community.lexicon.calendar.searchEvents?repository=${encodeURIComponent(did)}&query=upcoming` 21 - ), 22 cache 23 ? cache.getProfile(did as Did).catch(() => null) 24 : getBlentoOrBskyProfile({ did: did as Did }) ··· 35 .catch(() => null) 36 ]); 37 38 - if (!eventsResponse.ok) { 39 - throw error(404, 'Events not found'); 40 - } 41 - 42 - const data: { results: EventData[] } = await eventsResponse.json(); 43 - const events = data.results; 44 45 return { 46 events,
··· 1 import { error } from '@sveltejs/kit'; 2 import type { EventData } from '$lib/cards/social/EventCard'; 3 + import { getBlentoOrBskyProfile, listRecords } from '$lib/atproto/methods.js'; 4 import { createCache, type CachedProfile } from '$lib/cache'; 5 import type { Did } from '@atcute/lexicons'; 6 import { getActor } from '$lib/actor.js'; ··· 15 } 16 17 try { 18 + const [records, hostProfile] = await Promise.all([ 19 + listRecords({ 20 + did: did as Did, 21 + collection: 'community.lexicon.calendar.event', 22 + limit: 100 23 + }), 24 cache 25 ? cache.getProfile(did as Did).catch(() => null) 26 : getBlentoOrBskyProfile({ did: did as Did }) ··· 37 .catch(() => null) 38 ]); 39 40 + const events = records.map((r) => ({ 41 + ...(r.value as EventData), 42 + rkey: r.uri.split('/').pop() as string 43 + })); 44 45 return { 46 events,
+4 -14
src/routes/[[actor=actor]]/e/+page.svelte src/routes/[[actor=actor]]/events/+page.svelte
··· 6 7 let { data } = $props(); 8 9 - let events: EventData[] = $derived(data.events); 10 let did: string = $derived(data.did); 11 let hostProfile = $derived(data.hostProfile); 12 ··· 74 return { url, alt: media.alt || event.name }; 75 } 76 77 - function getRkey(event: EventData): string { 78 - return event.url.split('/').pop() || ''; 79 - } 80 - 81 let actorPrefix = $derived(data.hostProfile?.handle ? `/${data.hostProfile.handle}` : `/${did}`); 82 </script> 83 ··· 98 <h1 class="text-base-900 dark:text-base-50 mb-2 text-2xl font-bold sm:text-3xl"> 99 Upcoming events 100 </h1> 101 - <div class="flex items-center gap-2 mt-4"> 102 <span class="text-base-500 dark:text-base-400 text-sm">Hosted by</span> 103 <a 104 href={hostUrl} ··· 116 <p class="text-base-500 dark:text-base-400 py-12 text-center">No events found.</p> 117 {:else} 118 <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"> 119 - {#each events as event (event.url)} 120 {@const thumbnail = getThumbnail(event)} 121 {@const location = getLocationString(event.locations)} 122 - {@const rkey = getRkey(event)} 123 <a 124 href="{actorPrefix}/e/{rkey}" 125 class="border-base-200 dark:border-base-800 hover:border-base-300 dark:hover:border-base-700 group block overflow-hidden rounded-xl border transition-colors" ··· 168 <span class="text-base-500 dark:text-base-400 truncate text-xs">{location}</span> 169 {/if} 170 </div> 171 - 172 - {#if event.countGoing && event.countGoing > 0} 173 - <p class="text-base-500 dark:text-base-400 mt-2 text-xs"> 174 - {event.countGoing} going 175 - </p> 176 - {/if} 177 </div> 178 </a> 179 {/each}
··· 6 7 let { data } = $props(); 8 9 + let events: (EventData & { rkey: string })[] = $derived(data.events); 10 let did: string = $derived(data.did); 11 let hostProfile = $derived(data.hostProfile); 12 ··· 74 return { url, alt: media.alt || event.name }; 75 } 76 77 let actorPrefix = $derived(data.hostProfile?.handle ? `/${data.hostProfile.handle}` : `/${did}`); 78 </script> 79 ··· 94 <h1 class="text-base-900 dark:text-base-50 mb-2 text-2xl font-bold sm:text-3xl"> 95 Upcoming events 96 </h1> 97 + <div class="mt-4 flex items-center gap-2"> 98 <span class="text-base-500 dark:text-base-400 text-sm">Hosted by</span> 99 <a 100 href={hostUrl} ··· 112 <p class="text-base-500 dark:text-base-400 py-12 text-center">No events found.</p> 113 {:else} 114 <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"> 115 + {#each events as event (event.rkey)} 116 {@const thumbnail = getThumbnail(event)} 117 {@const location = getLocationString(event.locations)} 118 + {@const rkey = event.rkey} 119 <a 120 href="{actorPrefix}/e/{rkey}" 121 class="border-base-200 dark:border-base-800 hover:border-base-300 dark:hover:border-base-700 group block overflow-hidden rounded-xl border transition-colors" ··· 164 <span class="text-base-500 dark:text-base-400 truncate text-xs">{location}</span> 165 {/if} 166 </div> 167 </div> 168 </a> 169 {/each}
+12 -17
src/routes/[[actor=actor]]/e/[rkey]/+page.server.ts src/routes/[[actor=actor]]/events/[rkey]/+page.server.ts
··· 1 import { error } from '@sveltejs/kit'; 2 import type { EventData } from '$lib/cards/social/EventCard'; 3 - import { getBlentoOrBskyProfile, getRecord, resolveHandle } from '$lib/atproto/methods.js'; 4 - import { isHandle } from '@atcute/lexicons/syntax'; 5 import { createCache, type CachedProfile } from '$lib/cache'; 6 - import type { ActorIdentifier, Did } from '@atcute/lexicons'; 7 - import { env as publicEnv } from '$env/dynamic/public'; 8 import { getActor } from '$lib/actor'; 9 10 export async function load({ params, platform, request }) { ··· 19 } 20 21 try { 22 - const [eventResponse, hostProfile, eventRecord] = await Promise.all([ 23 - fetch( 24 - `https://smokesignal.events/xrpc/community.lexicon.calendar.GetEvent?repository=${encodeURIComponent(did)}&record_key=${encodeURIComponent(rkey)}` 25 - ), 26 cache 27 ? cache.getProfile(did as Did).catch(() => null) 28 : getBlentoOrBskyProfile({ did: did as Did }) ··· 36 url: p.url 37 }) 38 ) 39 - .catch(() => null), 40 - getRecord({ 41 - did: did as Did, 42 - collection: 'community.lexicon.calendar.event', 43 - rkey 44 - }).catch(() => null) 45 ]); 46 47 - if (!eventResponse.ok) { 48 throw error(404, 'Event not found'); 49 } 50 51 - const eventData: EventData = await eventResponse.json(); 52 53 return { 54 eventData, 55 did, 56 rkey, 57 hostProfile: hostProfile ?? null, 58 - eventCid: (eventRecord?.cid as string) ?? null 59 }; 60 } catch (e) { 61 if (e && typeof e === 'object' && 'status' in e) throw e;
··· 1 import { error } from '@sveltejs/kit'; 2 import type { EventData } from '$lib/cards/social/EventCard'; 3 + import { getBlentoOrBskyProfile, getRecord } from '$lib/atproto/methods.js'; 4 import { createCache, type CachedProfile } from '$lib/cache'; 5 + import type { Did } from '@atcute/lexicons'; 6 import { getActor } from '$lib/actor'; 7 8 export async function load({ params, platform, request }) { ··· 17 } 18 19 try { 20 + const [eventRecord, hostProfile] = await Promise.all([ 21 + getRecord({ 22 + did: did as Did, 23 + collection: 'community.lexicon.calendar.event', 24 + rkey 25 + }), 26 cache 27 ? cache.getProfile(did as Did).catch(() => null) 28 : getBlentoOrBskyProfile({ did: did as Did }) ··· 36 url: p.url 37 }) 38 ) 39 + .catch(() => null) 40 ]); 41 42 + if (!eventRecord?.value) { 43 throw error(404, 'Event not found'); 44 } 45 46 + const eventData: EventData = eventRecord.value as EventData; 47 48 return { 49 eventData, 50 did, 51 rkey, 52 hostProfile: hostProfile ?? null, 53 + eventCid: (eventRecord.cid as string) ?? null 54 }; 55 } catch (e) { 56 if (e && typeof e === 'object' && 'status' in e) throw e;
+2 -16
src/routes/[[actor=actor]]/e/[rkey]/+page.svelte src/routes/[[actor=actor]]/events/[rkey]/+page.svelte
··· 88 return { url, alt: media.alt || eventData.name }; 89 }); 90 91 - let eventUrl = $derived(eventData.url || `https://smokesignal.events/${did}/${rkey}`); 92 let eventUri = $derived(`at://${did}/community.lexicon.calendar.event/${rkey}`); 93 94 let ogImageUrl = $derived(`${page.url.origin}${page.url.pathname}/og.png`); ··· 247 </a> 248 </div> 249 250 - {#if (eventData.countGoing && eventData.countGoing > 0) || (eventData.countInterested && eventData.countInterested > 0)} 251 - <!-- Counts --> 252 - <div 253 - class="text-base-900 dark:text-base-100 order-4 space-y-2.5 text-base font-medium md:order-0 md:col-start-1" 254 - > 255 - {#if eventData.countGoing && eventData.countGoing > 0} 256 - <p>{eventData.countGoing} Going</p> 257 - {/if} 258 - {#if eventData.countInterested && eventData.countInterested > 0} 259 - <p>{eventData.countInterested} Interested</p> 260 - {/if} 261 - </div> 262 - {/if} 263 - 264 {#if eventData.uris && eventData.uris.length > 0} 265 <!-- Links --> 266 <div class="order-5 md:order-0 md:col-start-1"> ··· 300 301 <!-- View on Smoke Signal link --> 302 <a 303 - href={eventUrl} 304 target="_blank" 305 rel="noopener noreferrer" 306 class="text-base-500 dark:text-base-400 hover:text-base-700 dark:hover:text-base-200 order-6 inline-flex items-center gap-1.5 text-sm transition-colors md:order-0 md:col-start-2"
··· 88 return { url, alt: media.alt || eventData.name }; 89 }); 90 91 + let smokesignalUrl = $derived(`https://smokesignal.events/${did}/${rkey}`); 92 let eventUri = $derived(`at://${did}/community.lexicon.calendar.event/${rkey}`); 93 94 let ogImageUrl = $derived(`${page.url.origin}${page.url.pathname}/og.png`); ··· 247 </a> 248 </div> 249 250 {#if eventData.uris && eventData.uris.length > 0} 251 <!-- Links --> 252 <div class="order-5 md:order-0 md:col-start-1"> ··· 286 287 <!-- View on Smoke Signal link --> 288 <a 289 + href={smokesignalUrl} 290 target="_blank" 291 rel="noopener noreferrer" 292 class="text-base-500 dark:text-base-400 hover:text-base-700 dark:hover:text-base-200 order-6 inline-flex items-center gap-1.5 text-sm transition-colors md:order-0 md:col-start-2"
src/routes/[[actor=actor]]/e/[rkey]/EventRsvp.svelte src/routes/[[actor=actor]]/events/[rkey]/EventRsvp.svelte
+9 -9
src/routes/[[actor=actor]]/e/[rkey]/og.png/+server.ts src/routes/[[actor=actor]]/events/[rkey]/og.png/+server.ts
··· 1 - import { getCDNImageBlobUrl, resolveHandle } from '$lib/atproto/methods.js'; 2 - import { env as publicEnv } from '$env/dynamic/public'; 3 4 - import type { ActorIdentifier } from '@atcute/lexicons'; 5 - import { isHandle } from '@atcute/lexicons/syntax'; 6 import type { EventData } from '$lib/cards/social/EventCard'; 7 import { ImageResponse } from '@ethercorps/sveltekit-og'; 8 import { error } from '@sveltejs/kit'; ··· 29 let eventData: EventData; 30 31 try { 32 - const eventResponse = await fetch( 33 - `https://smokesignal.events/xrpc/community.lexicon.calendar.GetEvent?repository=${encodeURIComponent(did)}&record_key=${encodeURIComponent(rkey)}` 34 - ); 35 36 - if (!eventResponse.ok) { 37 throw error(404, 'Event not found'); 38 } 39 40 - eventData = await eventResponse.json(); 41 } catch (e) { 42 if (e && typeof e === 'object' && 'status' in e) throw e; 43 throw error(404, 'Event not found');
··· 1 + import { getCDNImageBlobUrl, getRecord } from '$lib/atproto/methods.js'; 2 3 + import type { Did } from '@atcute/lexicons'; 4 import type { EventData } from '$lib/cards/social/EventCard'; 5 import { ImageResponse } from '@ethercorps/sveltekit-og'; 6 import { error } from '@sveltejs/kit'; ··· 27 let eventData: EventData; 28 29 try { 30 + const eventRecord = await getRecord({ 31 + did: did as Did, 32 + collection: 'community.lexicon.calendar.event', 33 + rkey 34 + }); 35 36 + if (!eventRecord?.value) { 37 throw error(404, 'Event not found'); 38 } 39 40 + eventData = eventRecord.value as EventData; 41 } catch (e) { 42 if (e && typeof e === 'object' && 'status' in e) throw e; 43 throw error(404, 'Event not found');
-1
src/routes/[[actor=actor]]/e/[rkey]/og.png/EventOgImage.svelte src/routes/[[actor=actor]]/events/[rkey]/og.png/EventOgImage.svelte
··· 58 </svg> 59 <span class="ml-3 text-2xl text-neutral-300">{dateStr}</span> 60 </div> 61 - 62 </div> 63 </div>
··· 58 </svg> 59 <span class="ml-3 text-2xl text-neutral-300">{dateStr}</span> 60 </div> 61 </div> 62 </div>