@atmo-dev/events-ui 0.1.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 (113) hide show
  1. package/dist/DatePicker.svelte +231 -0
  2. package/dist/DatePicker.svelte.d.ts +11 -0
  3. package/dist/DateTimePicker.svelte +101 -0
  4. package/dist/DateTimePicker.svelte.d.ts +9 -0
  5. package/dist/EventAttendees.svelte +203 -0
  6. package/dist/EventAttendees.svelte.d.ts +13 -0
  7. package/dist/EventCard.svelte +131 -0
  8. package/dist/EventCard.svelte.d.ts +8 -0
  9. package/dist/EventComments.svelte +99 -0
  10. package/dist/EventComments.svelte.d.ts +6 -0
  11. package/dist/EventEditor.svelte +589 -0
  12. package/dist/EventEditor.svelte.d.ts +20 -0
  13. package/dist/EventRsvp.svelte +237 -0
  14. package/dist/EventRsvp.svelte.d.ts +17 -0
  15. package/dist/EventView.svelte +433 -0
  16. package/dist/EventView.svelte.d.ts +16 -0
  17. package/dist/ImageDropper.svelte +66 -0
  18. package/dist/ImageDropper.svelte.d.ts +7 -0
  19. package/dist/Map.svelte +27 -0
  20. package/dist/Map.svelte.d.ts +8 -0
  21. package/dist/PostToBlueskyModal.svelte +244 -0
  22. package/dist/PostToBlueskyModal.svelte.d.ts +22 -0
  23. package/dist/ShareModal.svelte +160 -0
  24. package/dist/ShareModal.svelte.d.ts +23 -0
  25. package/dist/ThemeApply.svelte +50 -0
  26. package/dist/ThemeApply.svelte.d.ts +7 -0
  27. package/dist/ThemeBackground.svelte +33 -0
  28. package/dist/ThemeBackground.svelte.d.ts +7 -0
  29. package/dist/ThemePicker.svelte +102 -0
  30. package/dist/ThemePicker.svelte.d.ts +7 -0
  31. package/dist/ThumbnailPresets.svelte +68 -0
  32. package/dist/ThumbnailPresets.svelte.d.ts +11 -0
  33. package/dist/TimePicker.svelte +188 -0
  34. package/dist/TimePicker.svelte.d.ts +9 -0
  35. package/dist/TimezonePicker.svelte +132 -0
  36. package/dist/TimezonePicker.svelte.d.ts +6 -0
  37. package/dist/VodPlayer.svelte +137 -0
  38. package/dist/VodPlayer.svelte.d.ts +14 -0
  39. package/dist/VodTranscript.svelte +72 -0
  40. package/dist/VodTranscript.svelte.d.ts +8 -0
  41. package/dist/atproto-helpers.d.ts +21 -0
  42. package/dist/atproto-helpers.js +61 -0
  43. package/dist/cal/helper.d.ts +1 -0
  44. package/dist/cal/helper.js +20 -0
  45. package/dist/cal/ical.d.ts +22 -0
  46. package/dist/cal/ical.js +188 -0
  47. package/dist/cal/sanitize.d.ts +3 -0
  48. package/dist/cal/sanitize.js +25 -0
  49. package/dist/contrail.d.ts +54 -0
  50. package/dist/contrail.js +22 -0
  51. package/dist/date-format.d.ts +22 -0
  52. package/dist/date-format.js +43 -0
  53. package/dist/editor/LinksSection.svelte +144 -0
  54. package/dist/editor/LinksSection.svelte.d.ts +10 -0
  55. package/dist/editor/LocationSection.svelte +215 -0
  56. package/dist/editor/LocationSection.svelte.d.ts +8 -0
  57. package/dist/editor/RecurringModal.svelte +270 -0
  58. package/dist/editor/RecurringModal.svelte.d.ts +30 -0
  59. package/dist/editor/ThemeSection.svelte +39 -0
  60. package/dist/editor/ThemeSection.svelte.d.ts +7 -0
  61. package/dist/editor/ThumbnailSection.svelte +219 -0
  62. package/dist/editor/ThumbnailSection.svelte.d.ts +13 -0
  63. package/dist/editor/adapter.d.ts +98 -0
  64. package/dist/editor/adapter.js +9 -0
  65. package/dist/editor/save.d.ts +42 -0
  66. package/dist/editor/save.js +154 -0
  67. package/dist/editor/types.d.ts +39 -0
  68. package/dist/editor/types.js +9 -0
  69. package/dist/event-types.d.ts +70 -0
  70. package/dist/event-types.js +11 -0
  71. package/dist/event-view/AddToCalendarButton.svelte +42 -0
  72. package/dist/event-view/AddToCalendarButton.svelte.d.ts +9 -0
  73. package/dist/event-view/EventBadges.svelte +20 -0
  74. package/dist/event-view/EventBadges.svelte.d.ts +7 -0
  75. package/dist/event-view/EventDateBlock.svelte +43 -0
  76. package/dist/event-view/EventDateBlock.svelte.d.ts +7 -0
  77. package/dist/event-view/EventHostedBy.svelte +63 -0
  78. package/dist/event-view/EventHostedBy.svelte.d.ts +16 -0
  79. package/dist/event-view/EventLinksList.svelte +37 -0
  80. package/dist/event-view/EventLinksList.svelte.d.ts +9 -0
  81. package/dist/event-view/EventLocationBlock.svelte +48 -0
  82. package/dist/event-view/EventLocationBlock.svelte.d.ts +7 -0
  83. package/dist/event-view/EventLocationMap.svelte +72 -0
  84. package/dist/event-view/EventLocationMap.svelte.d.ts +8 -0
  85. package/dist/event-view/ExternalRsvpNotice.svelte +44 -0
  86. package/dist/event-view/ExternalRsvpNotice.svelte.d.ts +6 -0
  87. package/dist/event-view/InviteShareFlow.svelte +177 -0
  88. package/dist/event-view/InviteShareFlow.svelte.d.ts +15 -0
  89. package/dist/event-view/StreamPlacePlayer.svelte +222 -0
  90. package/dist/event-view/StreamPlacePlayer.svelte.d.ts +8 -0
  91. package/dist/event-view/format.d.ts +26 -0
  92. package/dist/event-view/format.js +145 -0
  93. package/dist/index.d.ts +18 -0
  94. package/dist/index.js +18 -0
  95. package/dist/profile-url.d.ts +1 -0
  96. package/dist/profile-url.js +7 -0
  97. package/dist/theme.d.ts +9 -0
  98. package/dist/theme.js +22 -0
  99. package/dist/themes/Blobs.svelte +35 -0
  100. package/dist/themes/Blobs.svelte.d.ts +26 -0
  101. package/dist/themes/Butterflies.svelte +185 -0
  102. package/dist/themes/Butterflies.svelte.d.ts +3 -0
  103. package/dist/themes/Fireflies.svelte +134 -0
  104. package/dist/themes/Fireflies.svelte.d.ts +3 -0
  105. package/dist/themes/Kaleidoscope.svelte +177 -0
  106. package/dist/themes/Kaleidoscope.svelte.d.ts +3 -0
  107. package/dist/themes/Matrix.svelte +150 -0
  108. package/dist/themes/Matrix.svelte.d.ts +3 -0
  109. package/dist/themes/Stars.svelte +98 -0
  110. package/dist/themes/Stars.svelte.d.ts +3 -0
  111. package/dist/thumbnails/designs.d.ts +18 -0
  112. package/dist/thumbnails/designs.js +316 -0
  113. package/package.json +95 -0
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Structural shape of a `community.lexicon.calendar.event` record, plus the
3
+ * extensions atmo adds (timezone, media, facets, theme, bskyPostRef).
4
+ *
5
+ * Defined permissively so consumers using project-local generated lexicon
6
+ * types can still pass their records into our components without type
7
+ * gymnastics. Components inspect specific fields and `$type` strings as
8
+ * needed; rich variant unions live in the consumer's lexicon types if they
9
+ * want them.
10
+ */
11
+ export type EventLocationVariant = {
12
+ $type: string;
13
+ [key: string]: unknown;
14
+ };
15
+ export type EventStatus = string;
16
+ export type EventMode = string;
17
+ export interface EventLexiconMain {
18
+ $type?: 'community.lexicon.calendar.event';
19
+ createdAt: string;
20
+ name: string;
21
+ description?: string;
22
+ startsAt?: string;
23
+ endsAt?: string;
24
+ locations?: EventLocationVariant[];
25
+ mode?: EventMode;
26
+ status?: EventStatus;
27
+ }
28
+ export type EventData = EventLexiconMain & {
29
+ startsAt: string;
30
+ timezone?: string;
31
+ /** Atmo stores URIs as objects with optional names rather than bare strings. */
32
+ uris?: Array<{
33
+ uri: string;
34
+ name?: string;
35
+ }>;
36
+ media?: Array<{
37
+ role: string;
38
+ alt?: string;
39
+ content: {
40
+ $type: 'blob';
41
+ ref: {
42
+ $link: string;
43
+ };
44
+ };
45
+ [key: string]: unknown;
46
+ }>;
47
+ facets?: Array<{
48
+ index: {
49
+ byteStart: number;
50
+ byteEnd: number;
51
+ };
52
+ features: Array<{
53
+ $type: string;
54
+ did?: string;
55
+ uri?: string;
56
+ tag?: string;
57
+ }>;
58
+ }>;
59
+ additionalData?: Record<string, unknown>;
60
+ theme?: {
61
+ name: string;
62
+ accentColor: string;
63
+ baseColor: string;
64
+ };
65
+ bskyPostRef?: {
66
+ uri: string;
67
+ cid: string;
68
+ showComments: boolean;
69
+ };
70
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Structural shape of a `community.lexicon.calendar.event` record, plus the
3
+ * extensions atmo adds (timezone, media, facets, theme, bskyPostRef).
4
+ *
5
+ * Defined permissively so consumers using project-local generated lexicon
6
+ * types can still pass their records into our components without type
7
+ * gymnastics. Components inspect specific fields and `$type` strings as
8
+ * needed; rich variant unions live in the consumer's lexicon types if they
9
+ * want them.
10
+ */
11
+ export {};
@@ -0,0 +1,42 @@
1
+ <script lang="ts">
2
+ import { generateICalEvent } from '../cal/ical.js';
3
+ import type { FlatEventRecord } from '../contrail.js';
4
+
5
+ let {
6
+ eventData,
7
+ eventUri,
8
+ pageHref
9
+ }: { eventData: FlatEventRecord; eventUri: string; pageHref: string } = $props();
10
+
11
+ function downloadIcs() {
12
+ const ical = generateICalEvent(eventData, eventUri, pageHref);
13
+ const blob = new Blob([ical], { type: 'text/calendar;charset=utf-8' });
14
+ const url = URL.createObjectURL(blob);
15
+ const a = document.createElement('a');
16
+ a.href = url;
17
+ a.download = `${eventData.name.replace(/[^a-zA-Z0-9]/g, '-')}.ics`;
18
+ a.click();
19
+ URL.revokeObjectURL(url);
20
+ }
21
+ </script>
22
+
23
+ <button
24
+ onclick={downloadIcs}
25
+ class="text-base-700 dark:text-base-300 hover:text-base-900 dark:hover:text-base-100 flex cursor-pointer items-center gap-2 text-sm font-medium transition-colors"
26
+ >
27
+ <svg
28
+ xmlns="http://www.w3.org/2000/svg"
29
+ fill="none"
30
+ viewBox="0 0 24 24"
31
+ stroke-width="1.5"
32
+ stroke="currentColor"
33
+ class="size-4"
34
+ >
35
+ <path
36
+ stroke-linecap="round"
37
+ stroke-linejoin="round"
38
+ 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"
39
+ />
40
+ </svg>
41
+ Add to Calendar
42
+ </button>
@@ -0,0 +1,9 @@
1
+ import type { FlatEventRecord } from '../contrail.js';
2
+ type $$ComponentProps = {
3
+ eventData: FlatEventRecord;
4
+ eventUri: string;
5
+ pageHref: string;
6
+ };
7
+ declare const AddToCalendarButton: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type AddToCalendarButton = ReturnType<typeof AddToCalendarButton>;
9
+ export default AddToCalendarButton;
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import { Badge } from '@foxui/core';
3
+ import { getModeColor, getModeLabel } from './format';
4
+
5
+ let { mode, isOngoing }: { mode?: string; isOngoing: boolean } = $props();
6
+ </script>
7
+
8
+ {#if mode || isOngoing}
9
+ <div class="mb-8 flex items-center gap-2">
10
+ {#if isOngoing}
11
+ <Badge size="md" variant="primary">
12
+ <span class="bg-accent-500 mr-1 inline-block size-1.5 animate-pulse rounded-full"></span>
13
+ Live
14
+ </Badge>
15
+ {/if}
16
+ {#if mode}
17
+ <Badge size="md" variant="primary" class={getModeColor(mode)}>{getModeLabel(mode)}</Badge>
18
+ {/if}
19
+ </div>
20
+ {/if}
@@ -0,0 +1,7 @@
1
+ type $$ComponentProps = {
2
+ mode?: string;
3
+ isOngoing: boolean;
4
+ };
5
+ declare const EventBadges: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type EventBadges = ReturnType<typeof EventBadges>;
7
+ export default EventBadges;
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ import { Badge } from '@foxui/core';
3
+ import { formatDay, formatFullDate, formatMonth, formatTime, formatWeekday } from './format';
4
+
5
+ let { startDate, endDate }: { startDate: Date; endDate: Date | null } = $props();
6
+
7
+ let isSameDay = $derived(
8
+ endDate &&
9
+ startDate.getFullYear() === endDate.getFullYear() &&
10
+ startDate.getMonth() === endDate.getMonth() &&
11
+ startDate.getDate() === endDate.getDate()
12
+ );
13
+ </script>
14
+
15
+ <div class="mb-4 flex items-center gap-4">
16
+ <div
17
+ class="border-base-200 dark:border-base-700 bg-base-100 dark:bg-base-950/30 flex size-12 shrink-0 flex-col items-center justify-center overflow-hidden rounded-xl border"
18
+ >
19
+ <span class="text-base-500 dark:text-base-400 text-[9px] leading-none font-semibold">
20
+ {formatMonth(startDate)}
21
+ </span>
22
+ <span class="text-base-900 dark:text-base-50 text-lg leading-tight font-bold">
23
+ {formatDay(startDate)}
24
+ </span>
25
+ </div>
26
+ <div>
27
+ <p class="text-base-900 dark:text-base-50 font-semibold">
28
+ {formatWeekday(startDate)}, {formatFullDate(startDate)}
29
+ {#if endDate && !isSameDay}
30
+ - {formatWeekday(endDate)}, {formatFullDate(endDate)}
31
+ {/if}
32
+ </p>
33
+ <p class="text-base-500 dark:text-base-400 flex flex-wrap items-center gap-2 text-sm">
34
+ <span>
35
+ {formatTime(startDate)}
36
+ {#if endDate && isSameDay}
37
+ - {formatTime(endDate)}
38
+ {/if}
39
+ </span>
40
+ <Badge size="sm" variant="secondary">local time</Badge>
41
+ </p>
42
+ </div>
43
+ </div>
@@ -0,0 +1,7 @@
1
+ type $$ComponentProps = {
2
+ startDate: Date;
3
+ endDate: Date | null;
4
+ };
5
+ declare const EventDateBlock: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type EventDateBlock = ReturnType<typeof EventDateBlock>;
7
+ export default EventDateBlock;
@@ -0,0 +1,63 @@
1
+ <script lang="ts">
2
+ import { Avatar as FoxAvatar } from '@foxui/core';
3
+ import type { HostProfile } from '../contrail.js';
4
+
5
+ type Speaker = { id?: string; handle?: string; name: string; avatar?: string };
6
+
7
+ let {
8
+ hostProfile,
9
+ hostUrl,
10
+ did,
11
+ speakers = []
12
+ }: {
13
+ hostProfile: HostProfile | null | undefined;
14
+ hostUrl: string;
15
+ did: string;
16
+ speakers?: Speaker[];
17
+ } = $props();
18
+ </script>
19
+
20
+ <div>
21
+ <p class="text-base-500 dark:text-base-400 mb-3 text-xs font-semibold tracking-wider uppercase">
22
+ Hosted By
23
+ </p>
24
+ <a
25
+ href={hostUrl}
26
+ class="text-base-900 dark:text-base-100 flex items-center gap-2.5 font-medium transition-opacity hover:opacity-80"
27
+ >
28
+ <FoxAvatar
29
+ src={hostProfile?.avatar}
30
+ alt={hostProfile?.displayName || hostProfile?.handle || did}
31
+ class="size-8 shrink-0"
32
+ />
33
+ <span class="truncate text-sm">
34
+ {hostProfile?.displayName || hostProfile?.handle || did}
35
+ </span>
36
+ </a>
37
+ </div>
38
+
39
+ {#if speakers.length > 0}
40
+ <div>
41
+ <p class="text-base-500 dark:text-base-400 mb-3 text-xs font-semibold tracking-wider uppercase">
42
+ Speakers
43
+ </p>
44
+ <div class="space-y-2">
45
+ {#each speakers as speaker, i (speaker.id || i)}
46
+ {#if speaker.handle}
47
+ <a
48
+ href="/p/{speaker.handle}"
49
+ class="text-base-900 dark:text-base-100 flex items-center gap-2.5 font-medium transition-opacity hover:opacity-80"
50
+ >
51
+ <FoxAvatar src={speaker.avatar} alt={speaker.name} class="size-8 shrink-0" />
52
+ <span class="truncate text-sm">{speaker.name}</span>
53
+ </a>
54
+ {:else}
55
+ <div class="text-base-900 dark:text-base-100 flex items-center gap-2.5 font-medium">
56
+ <FoxAvatar alt={speaker.name} class="size-8 shrink-0" />
57
+ <span class="truncate text-sm">{speaker.name}</span>
58
+ </div>
59
+ {/if}
60
+ {/each}
61
+ </div>
62
+ </div>
63
+ {/if}
@@ -0,0 +1,16 @@
1
+ import type { HostProfile } from '../contrail.js';
2
+ type Speaker = {
3
+ id?: string;
4
+ handle?: string;
5
+ name: string;
6
+ avatar?: string;
7
+ };
8
+ type $$ComponentProps = {
9
+ hostProfile: HostProfile | null | undefined;
10
+ hostUrl: string;
11
+ did: string;
12
+ speakers?: Speaker[];
13
+ };
14
+ declare const EventHostedBy: import("svelte").Component<$$ComponentProps, {}, "">;
15
+ type EventHostedBy = ReturnType<typeof EventHostedBy>;
16
+ export default EventHostedBy;
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ let { uris = [] }: { uris?: Array<{ uri: string; name?: string }> } = $props();
3
+ </script>
4
+
5
+ {#if uris.length > 0}
6
+ <div>
7
+ <p class="text-base-500 dark:text-base-400 mb-4 text-xs font-semibold tracking-wider uppercase">
8
+ Links
9
+ </p>
10
+ <div class="space-y-3">
11
+ {#each uris as link (link.name + link.uri)}
12
+ <a
13
+ href={link.uri}
14
+ target="_blank"
15
+ rel="noopener noreferrer"
16
+ class="text-base-700 dark:text-base-300 hover:text-base-900 dark:hover:text-base-100 flex items-center gap-1.5 text-sm transition-colors"
17
+ >
18
+ <svg
19
+ xmlns="http://www.w3.org/2000/svg"
20
+ fill="none"
21
+ viewBox="0 0 24 24"
22
+ stroke-width="1.5"
23
+ stroke="currentColor"
24
+ class="size-3.5 shrink-0"
25
+ >
26
+ <path
27
+ stroke-linecap="round"
28
+ stroke-linejoin="round"
29
+ d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244"
30
+ />
31
+ </svg>
32
+ <span class="truncate">{link.name || link.uri.replace(/^https?:\/\//, '')}</span>
33
+ </a>
34
+ {/each}
35
+ </div>
36
+ </div>
37
+ {/if}
@@ -0,0 +1,9 @@
1
+ type $$ComponentProps = {
2
+ uris?: Array<{
3
+ uri: string;
4
+ name?: string;
5
+ }>;
6
+ };
7
+ declare const EventLinksList: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type EventLinksList = ReturnType<typeof EventLinksList>;
9
+ export default EventLinksList;
@@ -0,0 +1,48 @@
1
+ <script lang="ts">
2
+ import type { LocationData } from './format';
3
+
4
+ let { locationData }: { locationData: LocationData | null } = $props();
5
+ </script>
6
+
7
+ {#if locationData}
8
+ <a
9
+ href={locationData.googleMapsUrl}
10
+ target="_blank"
11
+ rel="noopener noreferrer"
12
+ class="mb-6 flex items-center gap-4 transition-opacity hover:opacity-80"
13
+ >
14
+ <div
15
+ class="border-base-200 dark:border-base-700 bg-base-100 dark:bg-base-950/30 flex size-12 shrink-0 items-center justify-center rounded-xl border"
16
+ >
17
+ <svg
18
+ xmlns="http://www.w3.org/2000/svg"
19
+ fill="none"
20
+ viewBox="0 0 24 24"
21
+ stroke-width="1.5"
22
+ stroke="currentColor"
23
+ class="text-base-900 dark:text-base-200 size-5"
24
+ >
25
+ <path
26
+ stroke-linecap="round"
27
+ stroke-linejoin="round"
28
+ d="M15 10.5a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
29
+ />
30
+ <path
31
+ stroke-linecap="round"
32
+ stroke-linejoin="round"
33
+ d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1 1 15 0Z"
34
+ />
35
+ </svg>
36
+ </div>
37
+ <div>
38
+ {#if locationData.name}
39
+ <p class="text-base-900 dark:text-base-50 font-semibold">{locationData.name}</p>
40
+ <p class="text-base-500 dark:text-base-400 text-sm">{locationData.shortAddress}</p>
41
+ {:else}
42
+ <p class="text-base-900 dark:text-base-50 font-semibold">
43
+ {locationData.shortAddress}
44
+ </p>
45
+ {/if}
46
+ </div>
47
+ </a>
48
+ {/if}
@@ -0,0 +1,7 @@
1
+ import type { LocationData } from './format';
2
+ type $$ComponentProps = {
3
+ locationData: LocationData | null;
4
+ };
5
+ declare const EventLocationBlock: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type EventLocationBlock = ReturnType<typeof EventLocationBlock>;
7
+ export default EventLocationBlock;
@@ -0,0 +1,72 @@
1
+ <script lang="ts">
2
+ import { Badge } from '@foxui/core';
3
+ import Map from '../Map.svelte';
4
+ import type { LocationData, GeoLocation } from './format';
5
+
6
+ let {
7
+ locationData,
8
+ geoLocation
9
+ }: {
10
+ locationData: LocationData | null;
11
+ geoLocation: GeoLocation | null;
12
+ } = $props();
13
+
14
+ let copied = $state(false);
15
+
16
+ async function copyCoords() {
17
+ if (!geoLocation) return;
18
+ const text = `${geoLocation.lat.toFixed(5)}, ${geoLocation.lng.toFixed(5)}`;
19
+ try {
20
+ await navigator.clipboard.writeText(text);
21
+ copied = true;
22
+ setTimeout(() => (copied = false), 2000);
23
+ } catch {}
24
+ }
25
+ </script>
26
+
27
+ {#if geoLocation && locationData}
28
+ <div class="mt-8 mb-8">
29
+ <div class="mb-3 flex items-baseline gap-2">
30
+ <p class="text-base-500 dark:text-base-400 text-xs font-semibold tracking-wider uppercase">
31
+ Location:
32
+ </p>
33
+ <button
34
+ type="button"
35
+ onclick={copyCoords}
36
+ class="ml-auto cursor-pointer transition-opacity active:opacity-60"
37
+ title="Copy coordinates"
38
+ aria-label="Copy coordinates"
39
+ >
40
+ <Badge size="sm" variant="secondary" class="font-mono">
41
+ {copied
42
+ ? 'Copied!'
43
+ : `${geoLocation.lat.toFixed(5)}, ${geoLocation.lng.toFixed(5)}`}
44
+ </Badge>
45
+ </button>
46
+ </div>
47
+ <div class="h-64 w-full overflow-hidden rounded-xl">
48
+ <Map lat={geoLocation.lat} lng={geoLocation.lng} />
49
+ </div>
50
+ <p class="text-base-700 dark:text-base-200 mt-3 text-sm">{locationData.fullString}</p>
51
+ <p class="text-base-500 dark:text-base-400 mt-1 text-xs">
52
+ Open in
53
+ <a
54
+ href={geoLocation.googleMapsUrl}
55
+ target="_blank"
56
+ rel="noopener noreferrer"
57
+ class="text-base-700 dark:text-base-300 hover:underline"
58
+ >
59
+ Google Maps
60
+ </a>
61
+ |
62
+ <a
63
+ href={geoLocation.osmUrl}
64
+ target="_blank"
65
+ rel="noopener noreferrer"
66
+ class="text-base-700 dark:text-base-300 hover:underline"
67
+ >
68
+ OpenStreetMap
69
+ </a>
70
+ </p>
71
+ </div>
72
+ {/if}
@@ -0,0 +1,8 @@
1
+ import type { LocationData, GeoLocation } from './format';
2
+ type $$ComponentProps = {
3
+ locationData: LocationData | null;
4
+ geoLocation: GeoLocation | null;
5
+ };
6
+ declare const EventLocationMap: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type EventLocationMap = ReturnType<typeof EventLocationMap>;
8
+ export default EventLocationMap;
@@ -0,0 +1,44 @@
1
+ <script lang="ts">
2
+ import { Button } from '@foxui/core';
3
+
4
+ // Shown in place of the RSVP controls for imported events whose host opted out
5
+ // of atmo RSVPs (additionalData.externalSource.rsvpMode === 'external_only').
6
+ // Directs attendees to the original event page instead.
7
+ let { url }: { url: string } = $props();
8
+
9
+ let host = $derived.by(() => {
10
+ try {
11
+ return new URL(url).hostname.replace(/^www\./, '');
12
+ } catch {
13
+ return null;
14
+ }
15
+ });
16
+ </script>
17
+
18
+ <div
19
+ class="border-base-200 dark:border-base-800 bg-base-100 dark:bg-base-950/50 mt-8 mb-2 flex flex-col gap-3 rounded-2xl border p-4 sm:flex-row sm:items-center sm:justify-between"
20
+ >
21
+ <div class="min-w-0">
22
+ <p class="text-base-900 dark:text-base-50 text-sm font-semibold">RSVP on the original page</p>
23
+ <p class="text-base-600 dark:text-base-400 mt-0.5 text-xs">
24
+ {host
25
+ ? `This event is hosted on ${host}. Head there to RSVP.`
26
+ : 'This event is hosted elsewhere. Open the original page to RSVP.'}
27
+ </p>
28
+ </div>
29
+ <Button href={url} target="_blank" rel="noopener noreferrer" class="shrink-0">
30
+ {host ? `RSVP on ${host}` : 'Open original event'}
31
+ <svg
32
+ xmlns="http://www.w3.org/2000/svg"
33
+ viewBox="0 0 20 20"
34
+ fill="currentColor"
35
+ aria-hidden="true"
36
+ >
37
+ <path
38
+ fill-rule="evenodd"
39
+ d="M5.22 14.78a.75.75 0 0 0 1.06 0l7.22-7.22v5.69a.75.75 0 0 0 1.5 0v-7.5a.75.75 0 0 0-.75-.75h-7.5a.75.75 0 0 0 0 1.5h5.69l-7.22 7.22a.75.75 0 0 0 0 1.06Z"
40
+ clip-rule="evenodd"
41
+ />
42
+ </svg>
43
+ </Button>
44
+ </div>
@@ -0,0 +1,6 @@
1
+ type $$ComponentProps = {
2
+ url: string;
3
+ };
4
+ declare const ExternalRsvpNotice: import("svelte").Component<$$ComponentProps, {}, "">;
5
+ type ExternalRsvpNotice = ReturnType<typeof ExternalRsvpNotice>;
6
+ export default ExternalRsvpNotice;