@atmo-dev/kit 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.md +94 -1
  2. package/dist/components/ExternalEmbed.svelte +174 -0
  3. package/dist/components/ExternalEmbed.svelte.d.ts +8 -0
  4. package/dist/components/GrainAlbumPicker.svelte +218 -0
  5. package/dist/components/GrainAlbumPicker.svelte.d.ts +14 -0
  6. package/dist/components/GrainAlbumView.svelte +94 -0
  7. package/dist/components/GrainAlbumView.svelte.d.ts +10 -0
  8. package/dist/components/NestedComments.svelte +20 -10
  9. package/dist/components/NestedComments.svelte.d.ts +2 -0
  10. package/dist/components/PhotoGrid.svelte +53 -0
  11. package/dist/components/PhotoGrid.svelte.d.ts +9 -0
  12. package/dist/components/PhotoLightbox.svelte +332 -0
  13. package/dist/components/PhotoLightbox.svelte.d.ts +12 -0
  14. package/dist/components/PostContent.svelte +78 -20
  15. package/dist/components/PostContent.svelte.d.ts +5 -0
  16. package/dist/components/StreamplacePicker.svelte +94 -0
  17. package/dist/components/StreamplacePicker.svelte.d.ts +12 -0
  18. package/dist/events/DatePicker.svelte +222 -0
  19. package/dist/events/DatePicker.svelte.d.ts +12 -0
  20. package/dist/events/DateTimePicker.svelte +112 -0
  21. package/dist/events/DateTimePicker.svelte.d.ts +10 -0
  22. package/dist/events/EventAttendees.svelte +199 -0
  23. package/dist/events/EventAttendees.svelte.d.ts +19 -0
  24. package/dist/events/EventCard.svelte +148 -0
  25. package/dist/events/EventCard.svelte.d.ts +8 -0
  26. package/dist/events/EventComments.svelte +98 -0
  27. package/dist/events/EventComments.svelte.d.ts +8 -0
  28. package/dist/events/EventEditor.svelte +540 -0
  29. package/dist/events/EventEditor.svelte.d.ts +18 -0
  30. package/dist/events/EventRsvp.svelte +178 -0
  31. package/dist/events/EventRsvp.svelte.d.ts +16 -0
  32. package/dist/events/EventView.svelte +488 -0
  33. package/dist/events/EventView.svelte.d.ts +23 -0
  34. package/dist/events/ImageDropper.svelte +66 -0
  35. package/dist/events/ImageDropper.svelte.d.ts +7 -0
  36. package/dist/events/Map.svelte +36 -0
  37. package/dist/events/Map.svelte.d.ts +8 -0
  38. package/dist/events/PostToBlueskyModal.svelte +246 -0
  39. package/dist/events/PostToBlueskyModal.svelte.d.ts +22 -0
  40. package/dist/events/ShareModal.svelte +174 -0
  41. package/dist/events/ShareModal.svelte.d.ts +23 -0
  42. package/dist/events/StarterPackButton.svelte +72 -0
  43. package/dist/events/StarterPackButton.svelte.d.ts +10 -0
  44. package/dist/events/ThemeApply.svelte +30 -0
  45. package/dist/events/ThemeApply.svelte.d.ts +7 -0
  46. package/dist/events/ThemeBackground.svelte +33 -0
  47. package/dist/events/ThemeBackground.svelte.d.ts +7 -0
  48. package/dist/events/ThemePicker.svelte +104 -0
  49. package/dist/events/ThemePicker.svelte.d.ts +7 -0
  50. package/dist/events/ThumbnailPresets.svelte +71 -0
  51. package/dist/events/ThumbnailPresets.svelte.d.ts +11 -0
  52. package/dist/events/TimePicker.svelte +117 -0
  53. package/dist/events/TimePicker.svelte.d.ts +10 -0
  54. package/dist/events/TimezonePicker.svelte +67 -0
  55. package/dist/events/TimezonePicker.svelte.d.ts +6 -0
  56. package/dist/events/VodPlayer.svelte +154 -0
  57. package/dist/events/VodPlayer.svelte.d.ts +14 -0
  58. package/dist/events/VodTranscript.svelte +75 -0
  59. package/dist/events/VodTranscript.svelte.d.ts +8 -0
  60. package/dist/events/atproto-helpers.d.ts +21 -0
  61. package/dist/events/atproto-helpers.js +61 -0
  62. package/dist/events/cal/helper.d.ts +1 -0
  63. package/dist/events/cal/helper.js +20 -0
  64. package/dist/events/cal/ical.d.ts +22 -0
  65. package/dist/events/cal/ical.js +188 -0
  66. package/dist/events/cal/sanitize.d.ts +3 -0
  67. package/dist/events/cal/sanitize.js +25 -0
  68. package/dist/events/conference.d.ts +65 -0
  69. package/dist/events/conference.js +61 -0
  70. package/dist/events/contrail.d.ts +49 -0
  71. package/dist/events/contrail.js +12 -0
  72. package/dist/events/date-format.d.ts +22 -0
  73. package/dist/events/date-format.js +43 -0
  74. package/dist/events/editor/LinkedRecordsPicker.svelte +104 -0
  75. package/dist/events/editor/LinkedRecordsPicker.svelte.d.ts +12 -0
  76. package/dist/events/editor/LinksSection.svelte +154 -0
  77. package/dist/events/editor/LinksSection.svelte.d.ts +13 -0
  78. package/dist/events/editor/LocationSection.svelte +163 -0
  79. package/dist/events/editor/LocationSection.svelte.d.ts +8 -0
  80. package/dist/events/editor/RecurringModal.svelte +313 -0
  81. package/dist/events/editor/RecurringModal.svelte.d.ts +30 -0
  82. package/dist/events/editor/ThemeSection.svelte +24 -0
  83. package/dist/events/editor/ThemeSection.svelte.d.ts +7 -0
  84. package/dist/events/editor/ThumbnailSection.svelte +181 -0
  85. package/dist/events/editor/ThumbnailSection.svelte.d.ts +13 -0
  86. package/dist/events/editor/adapter.d.ts +73 -0
  87. package/dist/events/editor/adapter.js +9 -0
  88. package/dist/events/editor/location.d.ts +16 -0
  89. package/dist/events/editor/location.js +50 -0
  90. package/dist/events/editor/save.d.ts +43 -0
  91. package/dist/events/editor/save.js +168 -0
  92. package/dist/events/editor/types.d.ts +39 -0
  93. package/dist/events/editor/types.js +9 -0
  94. package/dist/events/event-media.d.ts +4 -0
  95. package/dist/events/event-media.js +4 -0
  96. package/dist/events/event-types.d.ts +79 -0
  97. package/dist/events/event-types.js +11 -0
  98. package/dist/events/event-view/AddToCalendarButton.svelte +31 -0
  99. package/dist/events/event-view/AddToCalendarButton.svelte.d.ts +9 -0
  100. package/dist/events/event-view/EventBadges.svelte +20 -0
  101. package/dist/events/event-view/EventBadges.svelte.d.ts +7 -0
  102. package/dist/events/event-view/EventDateBlock.svelte +43 -0
  103. package/dist/events/event-view/EventDateBlock.svelte.d.ts +7 -0
  104. package/dist/events/event-view/EventHostedBy.svelte +61 -0
  105. package/dist/events/event-view/EventHostedBy.svelte.d.ts +16 -0
  106. package/dist/events/event-view/EventLinksList.svelte +24 -0
  107. package/dist/events/event-view/EventLinksList.svelte.d.ts +9 -0
  108. package/dist/events/event-view/EventLocationBlock.svelte +62 -0
  109. package/dist/events/event-view/EventLocationBlock.svelte.d.ts +7 -0
  110. package/dist/events/event-view/EventLocationMap.svelte +66 -0
  111. package/dist/events/event-view/EventLocationMap.svelte.d.ts +7 -0
  112. package/dist/events/event-view/ExternalRsvpNotice.svelte +34 -0
  113. package/dist/events/event-view/ExternalRsvpNotice.svelte.d.ts +6 -0
  114. package/dist/events/event-view/StreamPlacePlayer.svelte +209 -0
  115. package/dist/events/event-view/StreamPlacePlayer.svelte.d.ts +8 -0
  116. package/dist/events/event-view/format.d.ts +10 -0
  117. package/dist/events/event-view/format.js +112 -0
  118. package/dist/events/event-view/locations.d.ts +36 -0
  119. package/dist/events/event-view/locations.js +243 -0
  120. package/dist/events/event-view/plyr-icons.d.ts +3 -0
  121. package/dist/events/event-view/plyr-icons.js +46 -0
  122. package/dist/events/linked-records.d.ts +18 -0
  123. package/dist/events/linked-records.js +11 -0
  124. package/dist/events/profile-url.d.ts +3 -0
  125. package/dist/events/profile-url.js +11 -0
  126. package/dist/events/schedule/ConferenceTimetable.svelte +340 -0
  127. package/dist/events/schedule/ConferenceTimetable.svelte.d.ts +22 -0
  128. package/dist/events/schedule/DaySchedule.svelte +298 -0
  129. package/dist/events/schedule/DaySchedule.svelte.d.ts +26 -0
  130. package/dist/events/schedule/ScheduleEventCell.svelte +166 -0
  131. package/dist/events/schedule/ScheduleEventCell.svelte.d.ts +25 -0
  132. package/dist/events/schedule/schedule-utils.d.ts +44 -0
  133. package/dist/events/schedule/schedule-utils.js +166 -0
  134. package/dist/events/starter-pack-url.d.ts +3 -0
  135. package/dist/events/starter-pack-url.js +16 -0
  136. package/dist/events/theme.d.ts +9 -0
  137. package/dist/events/theme.js +36 -0
  138. package/dist/events/themes/Blobs.svelte +64 -0
  139. package/dist/events/themes/Blobs.svelte.d.ts +18 -0
  140. package/dist/events/themes/Butterflies.svelte +183 -0
  141. package/dist/events/themes/Butterflies.svelte.d.ts +3 -0
  142. package/dist/events/themes/Fireflies.svelte +134 -0
  143. package/dist/events/themes/Fireflies.svelte.d.ts +3 -0
  144. package/dist/events/themes/Kaleidoscope.svelte +183 -0
  145. package/dist/events/themes/Kaleidoscope.svelte.d.ts +3 -0
  146. package/dist/events/themes/Matrix.svelte +153 -0
  147. package/dist/events/themes/Matrix.svelte.d.ts +3 -0
  148. package/dist/events/themes/Stars.svelte +98 -0
  149. package/dist/events/themes/Stars.svelte.d.ts +3 -0
  150. package/dist/events/thumbnails/designs.d.ts +18 -0
  151. package/dist/events/thumbnails/designs.js +316 -0
  152. package/dist/events/view-data.d.ts +38 -0
  153. package/dist/events/view-data.js +1 -0
  154. package/dist/events-data.d.ts +15 -0
  155. package/dist/events-data.js +9 -0
  156. package/dist/events-editor.d.ts +2 -0
  157. package/dist/events-editor.js +2 -0
  158. package/dist/events.d.ts +19 -0
  159. package/dist/events.js +17 -0
  160. package/dist/grain/types.d.ts +41 -0
  161. package/dist/grain/types.js +1 -0
  162. package/dist/grain/urls.d.ts +7 -0
  163. package/dist/grain/urls.js +74 -0
  164. package/dist/grain/xrpc.d.ts +3 -0
  165. package/dist/grain/xrpc.js +129 -0
  166. package/dist/grain.d.ts +3 -0
  167. package/dist/grain.js +2 -0
  168. package/dist/index.d.ts +16 -0
  169. package/dist/index.js +9 -0
  170. package/dist/media.d.ts +10 -0
  171. package/dist/media.js +1 -0
  172. package/dist/social/external-embeds.d.ts +39 -0
  173. package/dist/social/external-embeds.js +107 -0
  174. package/dist/social/posts.d.ts +59 -17
  175. package/dist/social/posts.js +99 -12
  176. package/dist/social.d.ts +2 -0
  177. package/dist/social.js +1 -0
  178. package/dist/streamplace.d.ts +6 -0
  179. package/dist/streamplace.js +1 -0
  180. package/package.json +58 -4
@@ -0,0 +1,148 @@
1
+ <script lang="ts">
2
+ import { getCDNImageBlobUrl } from './atproto-helpers.js';
3
+ import { getEventThumbnail } from './event-media.js';
4
+ import { eventUrl, isEventOngoing, type FlatEventRecord } from './contrail.js';
5
+ import Avatar from 'svelte-boring-avatars';
6
+ import { Badge, Icon } from '../index.js';
7
+ import { CalendarDays, MapPin } from '@sketchyicons/svelte';
8
+ import { getLocations, getLocationSummary } from './event-view/locations.js';
9
+
10
+ let {
11
+ event,
12
+ actor
13
+ }: {
14
+ event: FlatEventRecord;
15
+ actor?: string;
16
+ } = $props();
17
+
18
+ function formatDateTime(dateStr: string): string {
19
+ return new Date(dateStr).toLocaleDateString('en-US', {
20
+ weekday: 'short',
21
+ month: 'short',
22
+ day: 'numeric',
23
+ hour: 'numeric',
24
+ minute: '2-digit'
25
+ });
26
+ }
27
+
28
+ /**
29
+ * What a card says about an event ALREADY UNDER WAY: when it finishes, not when
30
+ * it began. A "Live" badge beside "Wed, Jul 1" reads as a bug, and in a list
31
+ * sorted by finishing time the start dates look shuffled. Day and weekday are
32
+ * dropped when it ends today, since the only thing a reader wants then is how
33
+ * long they have left.
34
+ */
35
+ function formatEndsAt(endsAt: string): string {
36
+ const end = new Date(endsAt);
37
+ const now = new Date();
38
+ const endsToday = end.toDateString() === now.toDateString();
39
+ // Carry the YEAR when it is not this one. Long-running events are exactly
40
+ // what this band surfaces — a year-long journey ending 2027-07-04 rendered
41
+ // as "Ends Sun, Jul 4", which reads as a date three days ago.
42
+ const endsThisYear = end.getFullYear() === now.getFullYear();
43
+ return end.toLocaleTimeString('en-US', {
44
+ ...(endsToday
45
+ ? {}
46
+ : {
47
+ weekday: 'short',
48
+ month: 'short',
49
+ day: 'numeric',
50
+ ...(endsThisYear ? {} : { year: 'numeric' })
51
+ }),
52
+ hour: 'numeric',
53
+ minute: '2-digit'
54
+ });
55
+ }
56
+
57
+ function getModeLabel(mode: string | undefined): string | undefined {
58
+ if (!mode) return undefined;
59
+ if (mode.includes('virtual')) return 'Virtual';
60
+ if (mode.includes('hybrid')) return 'Hybrid';
61
+ if (mode.includes('inperson')) return 'In-Person';
62
+ return 'Event';
63
+ }
64
+
65
+ function getThumbnail(event: FlatEventRecord): { url: string; alt: string } | null {
66
+ const media = getEventThumbnail(event.media);
67
+ if (media?.content) {
68
+ const url = getCDNImageBlobUrl({ did: event.did, blob: media.content });
69
+ if (url) return { url, alt: media.alt || event.name };
70
+ }
71
+
72
+ const banner = event.media?.find((m) => m.role === 'header');
73
+ if (banner?.content) {
74
+ const url = getCDNImageBlobUrl({ did: event.did, blob: banner.content });
75
+ if (url) return { url, alt: banner.alt || event.name };
76
+ }
77
+
78
+ return null;
79
+ }
80
+
81
+ let thumbnail = $derived(getThumbnail(event));
82
+ let location = $derived(getLocationSummary(getLocations(event.locations)));
83
+ let mode = $derived(getModeLabel(event.mode));
84
+ let isOngoing = $derived(isEventOngoing(event.startsAt, event.endsAt));
85
+ </script>
86
+
87
+ <a
88
+ href={eventUrl(event, actor)}
89
+ class="group grid grid-cols-[5rem_minmax(0,1fr)] gap-3 rounded-ui outline-offset-4 transition-colors focus-visible:outline-2 focus-visible:outline-focus sm:grid-cols-[6rem_minmax(0,1fr)] sm:gap-3.5"
90
+ >
91
+ <div class="w-full">
92
+ {#if thumbnail}
93
+ <img
94
+ src={thumbnail.url}
95
+ alt={thumbnail.alt}
96
+ loading="lazy"
97
+ class="block aspect-square w-full rounded-[14px_12px_15px_13px] border border-line object-cover"
98
+ />
99
+ {:else}
100
+ <div
101
+ class="aspect-square w-full overflow-hidden rounded-[14px_12px_15px_13px] border border-line [&>svg]:h-full [&>svg]:w-full"
102
+ >
103
+ <Avatar
104
+ size={96}
105
+ name={event.rkey}
106
+ variant="marble"
107
+ colors={['#92A1C6', '#146A7C', '#F0AB3D', '#C271B4', '#C20D90']}
108
+ square
109
+ />
110
+ </div>
111
+ {/if}
112
+ </div>
113
+
114
+ <div class="min-w-0 self-center">
115
+ <p class="flex items-center gap-1.5 text-xs font-medium text-muted">
116
+ <Icon img={CalendarDays} size={14} class="shrink-0" />
117
+ {#if isOngoing && event.endsAt}
118
+ Ends {formatEndsAt(event.endsAt)}
119
+ {:else}
120
+ {formatDateTime(event.startsAt)}
121
+ {/if}
122
+ {#if isOngoing}
123
+ <Badge class="gap-1 px-1.5 py-0 text-[10px]">
124
+ <span class="size-1.5 animate-pulse rounded-full bg-accent-500"></span>
125
+ Live
126
+ </Badge>
127
+ {/if}
128
+ </p>
129
+ <h3
130
+ class="mt-0.5 flex items-start gap-1.5 text-sm leading-snug font-semibold text-base-900 transition-colors group-hover:text-base-700 sm:text-base dark:text-base-50 dark:group-hover:text-base-200"
131
+ >
132
+ <span class="line-clamp-2">{event.name}</span>
133
+ </h3>
134
+ {#if location || mode}
135
+ <p class="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted">
136
+ {#if location}
137
+ <span class="inline-flex max-w-full min-w-0 items-center gap-1.5" title={location}>
138
+ <Icon img={MapPin} size={14} class="shrink-0" />
139
+ <span class="truncate">{location}</span>
140
+ </span>
141
+ {/if}
142
+ {#if mode}
143
+ <Badge variant="outline" class="shrink-0 px-1.5 py-0 text-[10px]">{mode}</Badge>
144
+ {/if}
145
+ </p>
146
+ {/if}
147
+ </div>
148
+ </a>
@@ -0,0 +1,8 @@
1
+ import { type FlatEventRecord } from './contrail.js';
2
+ type $$ComponentProps = {
3
+ event: FlatEventRecord;
4
+ actor?: string;
5
+ };
6
+ declare const EventCard: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type EventCard = ReturnType<typeof EventCard>;
8
+ export default EventCard;
@@ -0,0 +1,98 @@
1
+ <script lang="ts">
2
+ import { NestedComments, blueskyPostToPostData, type PostData } from '../index.js';
3
+
4
+ import { socialClientInfo, socialPostUrl, type PreferredSocialClient } from '../social.js';
5
+
6
+ let {
7
+ postUri,
8
+ socialClient
9
+ }: {
10
+ postUri: string;
11
+ socialClient?: PreferredSocialClient | null;
12
+ } = $props();
13
+
14
+ let comments = $state<PostData[]>([]);
15
+ let loading = $state(true);
16
+ let errorMessage = $state<string | null>(null);
17
+
18
+ function threadToComments(replies: unknown[]): PostData[] {
19
+ return (replies as Array<{ $type?: string; post?: unknown; replies?: unknown[] }>)
20
+ .filter((r) => r.$type === 'app.bsky.feed.defs#threadViewPost' && r.post)
21
+ .map((r) => {
22
+ const postData = blueskyPostToPostData(
23
+ r.post as Parameters<typeof blueskyPostToPostData>[0]
24
+ );
25
+ if (r.replies?.length) {
26
+ postData.replies = threadToComments(r.replies);
27
+ }
28
+ return postData;
29
+ });
30
+ }
31
+
32
+ async function loadThread(uri: string, signal: AbortSignal) {
33
+ loading = true;
34
+ errorMessage = null;
35
+ try {
36
+ const res = await fetch(
37
+ `https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=${encodeURIComponent(uri)}&depth=6`,
38
+ { signal }
39
+ );
40
+ if (!res.ok) throw new Error(`Failed to load thread (${res.status})`);
41
+ const data = (await res.json()) as { thread?: { replies?: unknown[] } };
42
+ const thread = data.thread;
43
+ if (!signal.aborted)
44
+ comments = thread?.replies?.length ? threadToComments(thread.replies) : [];
45
+ } catch (err) {
46
+ if (signal.aborted) return;
47
+ console.error('EventComments: load failed', err);
48
+ errorMessage = err instanceof Error ? err.message : 'Failed to load comments';
49
+ comments = [];
50
+ } finally {
51
+ if (!signal.aborted) loading = false;
52
+ }
53
+ }
54
+
55
+ // Only a new thread URI should refetch; changing the viewer's client just changes links.
56
+ let threadUri = $derived(postUri);
57
+ $effect(() => {
58
+ const controller = new AbortController();
59
+ if (threadUri) loadThread(threadUri, controller.signal);
60
+ return () => controller.abort();
61
+ });
62
+
63
+ let replyUrl = $derived(socialPostUrl(postUri, socialClient));
64
+ let clientLabel = $derived(socialClientInfo(socialClient).label);
65
+ </script>
66
+
67
+ <div>
68
+ {#if replyUrl}
69
+ <div class="mb-4 text-sm">
70
+ <a
71
+ href={replyUrl}
72
+ target="_blank"
73
+ rel="noopener noreferrer"
74
+ class="font-medium text-accent-600 hover:text-accent-700 dark:text-accent-400 dark:hover:text-accent-300"
75
+ >
76
+ Add a comment on {clientLabel} &rarr;
77
+ </a>
78
+ </div>
79
+ {/if}
80
+
81
+ {#if loading}
82
+ <p class="text-sm text-muted">Loading comments…</p>
83
+ {:else if errorMessage}
84
+ <p class="text-sm text-muted">{errorMessage}</p>
85
+ {:else if comments.length === 0}
86
+ <p class="text-sm text-muted">No comments yet.</p>
87
+ {:else}
88
+ <div class="not-prose comments-no-divider">
89
+ <NestedComments {comments} {socialClient} />
90
+ </div>
91
+ {/if}
92
+ </div>
93
+
94
+ <style>
95
+ .comments-no-divider :global(> div) {
96
+ border-top-width: 0;
97
+ }
98
+ </style>
@@ -0,0 +1,8 @@
1
+ import { type PreferredSocialClient } from '../social.js';
2
+ type $$ComponentProps = {
3
+ postUri: string;
4
+ socialClient?: PreferredSocialClient | null;
5
+ };
6
+ declare const EventComments: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type EventComments = ReturnType<typeof EventComments>;
8
+ export default EventComments;