your personal website on atproto - mirror blento.app
at fix-edit-button 124 lines 3.3 kB view raw
1import { parseUri } from '$lib/atproto'; 2import type { CardDefinition } from '../../types'; 3import CreateEventCardModal from './CreateEventCardModal.svelte'; 4import EventCard from './EventCard.svelte'; 5 6const EVENT_COLLECTION = 'community.lexicon.calendar.event'; 7 8export type EventData = { 9 mode: string; 10 name: string; 11 status: string; 12 startsAt: string; 13 endsAt?: string; 14 description?: string; 15 locations?: Array<{ 16 $type: string; 17 address?: { 18 locality?: string; 19 region?: string; 20 country?: string; 21 }; 22 }>; 23 media?: Array<{ 24 alt?: string; 25 role?: string; 26 content?: { 27 $type: 'blob'; 28 ref: { 29 $link: string; 30 }; 31 mimeType?: string; 32 }; 33 aspect_ratio?: { 34 width: number; 35 height: number; 36 }; 37 }>; 38 uris?: Array<{ 39 uri: string; 40 name?: string; 41 }>; 42 countGoing?: number; 43 countInterested?: number; 44 url: string; 45}; 46 47export const EventCardDefinition = { 48 type: 'event', 49 contentComponent: EventCard, 50 creationModalComponent: CreateEventCardModal, 51 createNew: (card) => { 52 card.w = 4; 53 card.h = 4; 54 card.mobileW = 8; 55 card.mobileH = 6; 56 }, 57 58 loadData: async (items) => { 59 const eventDataMap: Record<string, EventData> = {}; 60 61 for (const item of items) { 62 const uri = item.cardData?.uri; 63 if (!uri) continue; 64 65 const parsedUri = parseUri(uri); 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); 79 } 80 } 81 82 return eventDataMap; 83 }, 84 85 onUrlHandler: (url, item) => { 86 // Match smokesignal.events URLs: https://smokesignal.events/{did}/{rkey} 87 const smokesignalMatch = url.match(/^https?:\/\/smokesignal\.events\/(did:[^/]+)\/([^/?#]+)/); 88 if (smokesignalMatch) { 89 const [, did, rkey] = smokesignalMatch; 90 item.w = 4; 91 item.h = 4; 92 item.mobileW = 8; 93 item.mobileH = 6; 94 item.cardType = 'event'; 95 item.cardData.uri = `at://${did}/${EVENT_COLLECTION}/${rkey}`; 96 return item; 97 } 98 99 // Match AT URIs: at://{did}/community.lexicon.calendar.event/{rkey} 100 const atUriMatch = url.match(/^at:\/\/(did:[^/]+)\/([^/]+)\/([^/?#]+)/); 101 if (atUriMatch) { 102 const [, did, collection, rkey] = atUriMatch; 103 if (collection === EVENT_COLLECTION) { 104 item.w = 4; 105 item.h = 4; 106 item.mobileW = 8; 107 item.mobileH = 6; 108 item.cardType = 'event'; 109 item.cardData.uri = `at://${did}/${collection}/${rkey}`; 110 return item; 111 } 112 } 113 114 return null; 115 }, 116 117 urlHandlerPriority: 5, 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' };