your personal website on atproto - mirror blento.app
at small-event-card-fixes 128 lines 3.4 kB view raw
1import { parseUri, getRecord } from '$lib/atproto'; 2import type { CardDefinition } from '../../types'; 3import CreateEventCardModal from './CreateEventCardModal.svelte'; 4import EventCard from './EventCard.svelte'; 5import type { Did } from '@atcute/lexicons'; 6 7const EVENT_COLLECTION = 'community.lexicon.calendar.event'; 8 9export type EventData = { 10 mode: string; 11 name: string; 12 status: string; 13 startsAt: string; 14 endsAt?: string; 15 description?: string; 16 locations?: Array<{ 17 $type: string; 18 address?: { 19 locality?: string; 20 region?: string; 21 country?: string; 22 }; 23 }>; 24 media?: Array<{ 25 alt?: string; 26 role?: string; 27 content?: { 28 $type: 'blob'; 29 ref: { 30 $link: string; 31 }; 32 mimeType?: string; 33 }; 34 aspect_ratio?: { 35 width: number; 36 height: number; 37 }; 38 }>; 39 facets?: Array<{ 40 index: { byteStart: number; byteEnd: number }; 41 features: Array<{ $type: string; [key: string]: unknown }>; 42 }>; 43 uris?: Array<{ 44 uri: string; 45 name?: string; 46 }>; 47 url?: string; 48}; 49 50export const EventCardDefinition = { 51 type: 'event', 52 contentComponent: EventCard, 53 creationModalComponent: CreateEventCardModal, 54 createNew: (card) => { 55 card.w = 4; 56 card.h = 4; 57 card.mobileW = 8; 58 card.mobileH = 6; 59 }, 60 61 loadData: async (items) => { 62 const eventDataMap: Record<string, EventData> = {}; 63 64 for (const item of items) { 65 const uri = item.cardData?.uri; 66 if (!uri) continue; 67 68 const parsedUri = parseUri(uri); 69 if (!parsedUri || !parsedUri.rkey || !parsedUri.repo) continue; 70 71 try { 72 const record = await getRecord({ 73 did: parsedUri.repo as Did, 74 collection: EVENT_COLLECTION, 75 rkey: parsedUri.rkey 76 }); 77 78 if (record?.value) { 79 eventDataMap[item.id] = record.value as EventData; 80 } 81 } catch (error) { 82 console.error('Failed to fetch event data:', error); 83 } 84 } 85 86 return eventDataMap; 87 }, 88 89 onUrlHandler: (url, item) => { 90 // Match smokesignal.events URLs: https://smokesignal.events/{did}/{rkey} 91 const smokesignalMatch = url.match(/^https?:\/\/smokesignal\.events\/(did:[^/]+)\/([^/?#]+)/); 92 if (smokesignalMatch) { 93 const [, did, rkey] = smokesignalMatch; 94 item.w = 4; 95 item.h = 4; 96 item.mobileW = 8; 97 item.mobileH = 6; 98 item.cardType = 'event'; 99 item.cardData.uri = `at://${did}/${EVENT_COLLECTION}/${rkey}`; 100 return item; 101 } 102 103 // Match AT URIs: at://{did}/community.lexicon.calendar.event/{rkey} 104 const atUriMatch = url.match(/^at:\/\/(did:[^/]+)\/([^/]+)\/([^/?#]+)/); 105 if (atUriMatch) { 106 const [, did, collection, rkey] = atUriMatch; 107 if (collection === EVENT_COLLECTION) { 108 item.w = 4; 109 item.h = 4; 110 item.mobileW = 8; 111 item.mobileH = 6; 112 item.cardType = 'event'; 113 item.cardData.uri = `at://${did}/${collection}/${rkey}`; 114 return item; 115 } 116 } 117 118 return null; 119 }, 120 121 urlHandlerPriority: 5, 122 123 name: 'Event', 124 125 keywords: ['calendar', 'meetup', 'schedule', 'date', 'rsvp', 'smokesignal'], 126 groups: ['Social'], 127 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>` 128} as CardDefinition & { type: 'event' };