tangled
alpha
login
or
join now
flo-bit.dev
/
blento
21
fork
atom
your personal website on atproto - mirror
blento.app
21
fork
atom
overview
issues
pulls
pipelines
add subscribe button, show upcoming or past events
Florian
1 week ago
2d0f550d
6bf9d2b4
+55
-16
1 changed file
expand all
collapse all
unified
split
src
routes
[[actor=actor]]
events
+page.svelte
+55
-16
src/routes/[[actor=actor]]/events/+page.svelte
···
2
2
import type { EventData } from '$lib/cards/social/EventCard';
3
3
import { getCDNImageBlobUrl } from '$lib/atproto';
4
4
import { user } from '$lib/atproto/auth.svelte';
5
5
-
import { Avatar as FoxAvatar, Badge, Button } from '@foxui/core';
5
5
+
import { Avatar as FoxAvatar, Badge, Button, toast } from '@foxui/core';
6
6
+
import { page } from '$app/state';
6
7
import Avatar from 'svelte-boring-avatars';
7
8
import * as TID from '@atcute/tid';
8
9
import { goto } from '$app/navigation';
···
78
79
}
79
80
80
81
let isOwner = $derived(user.isLoggedIn && user.did === did);
82
82
+
83
83
+
let showPast: boolean = $state(false);
84
84
+
let now = $derived(new Date());
85
85
+
let filteredEvents = $derived(
86
86
+
events.filter((e) => {
87
87
+
const endOrStart = e.endsAt || e.startsAt;
88
88
+
const eventDate = new Date(endOrStart);
89
89
+
return showPast ? eventDate < now : eventDate >= now;
90
90
+
})
91
91
+
);
81
92
</script>
82
93
83
94
<svelte:head>
···
96
107
<div class="mb-8 flex items-start justify-between">
97
108
<div>
98
109
<h1 class="text-base-900 dark:text-base-50 mb-2 text-2xl font-bold sm:text-3xl">
99
99
-
Upcoming events
110
110
+
{showPast ? 'Past' : 'Upcoming'} events
100
111
</h1>
101
112
<div class="mt-4 flex items-center gap-2">
102
113
<span class="text-base-500 dark:text-base-400 text-sm">Hosted by</span>
···
111
122
</a>
112
123
</div>
113
124
</div>
114
114
-
{#if isOwner}
125
125
+
<div class="flex flex-col items-end gap-2">
126
126
+
{#if isOwner}
127
127
+
<Button
128
128
+
variant="primary"
129
129
+
onclick={() => {
130
130
+
const rkey = TID.now();
131
131
+
const handle =
132
132
+
user.profile?.handle && user.profile.handle !== 'handle.invalid'
133
133
+
? user.profile.handle
134
134
+
: user.did;
135
135
+
goto(`/${handle}/events/${rkey}/edit`);
136
136
+
}}>New event</Button
137
137
+
>
138
138
+
{/if}
115
139
<Button
116
116
-
variant="primary"
117
117
-
onclick={() => {
118
118
-
const rkey = TID.now();
119
119
-
const handle =
120
120
-
user.profile?.handle && user.profile.handle !== 'handle.invalid'
121
121
-
? user.profile.handle
122
122
-
: user.did;
123
123
-
goto(`/${handle}/events/${rkey}/edit`);
124
124
-
}}>New event</Button
140
140
+
variant="secondary"
141
141
+
onclick={async () => {
142
142
+
const calendarUrl = `${page.url.origin}${page.url.pathname.replace(/\/$/, '')}/calendar`;
143
143
+
await navigator.clipboard.writeText(calendarUrl);
144
144
+
toast.success('Subscription link copied to clipboard');
145
145
+
}}>Subscribe</Button
125
146
>
126
126
-
{/if}
147
147
+
</div>
148
148
+
</div>
149
149
+
150
150
+
<!-- Toggle -->
151
151
+
<div class="mb-6 flex gap-1">
152
152
+
<button
153
153
+
class="rounded-xl px-3 py-1.5 text-sm font-medium transition-colors {!showPast
154
154
+
? 'bg-base-200 dark:bg-base-800 text-base-900 dark:text-base-50'
155
155
+
: 'text-base-500 dark:text-base-400 hover:text-base-700 dark:hover:text-base-200 cursor-pointer'}"
156
156
+
onclick={() => (showPast = false)}>Upcoming</button
157
157
+
>
158
158
+
<button
159
159
+
class="rounded-xl px-3 py-1.5 text-sm font-medium transition-colors {showPast
160
160
+
? 'bg-base-200 dark:bg-base-800 text-base-900 dark:text-base-50'
161
161
+
: 'text-base-500 dark:text-base-400 hover:text-base-700 dark:hover:text-base-200 cursor-pointer'}"
162
162
+
onclick={() => (showPast = true)}>Past</button
163
163
+
>
127
164
</div>
128
165
129
129
-
{#if events.length === 0}
130
130
-
<p class="text-base-500 dark:text-base-400 py-12 text-center">No events found.</p>
166
166
+
{#if filteredEvents.length === 0}
167
167
+
<p class="text-base-500 dark:text-base-400 py-12 text-center">
168
168
+
No {showPast ? 'past' : 'upcoming'} events.
169
169
+
</p>
131
170
{:else}
132
171
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
133
133
-
{#each events as event (event.rkey)}
172
172
+
{#each filteredEvents as event (event.rkey)}
134
173
{@const thumbnail = getThumbnail(event)}
135
174
{@const location = getLocationString(event.locations)}
136
175
{@const rkey = event.rkey}