blob: 638910e04abf8eacf1a05c6bf3fe561cdf32dc23 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
<script setup lang="ts">
import { Radio } from 'lucide-vue-next';
import EventListing from '~/components/EventListing.vue';
import Panel from '~/components/Panel.vue';
import { type Event } from '~/stores/schedule';
definePageMeta({
middleware: ['logged-in', 'conference-selected']
})
const favouritesStore = useFavouritesStore();
const scheduleStore = useScheduleStore();
const showAllHappeningNow = ref(false);
const showAllUpcoming = ref(false);
const timer = ref();
const refreshKey = ref(0);
const todayEvents = computed(() => {
return scheduleStore.events.filter((event) => isToday(new Date(event.start)));
});
const happeningNow = computed(() => {
refreshKey.value;
return todayEvents.value.filter((event) => isEventHappeningNow(event));
});
const favouritesHappeningNow = computed(() => {
refreshKey.value;
return happeningNow.value.filter((event) => favouritesStore.isFavourite(event));
});
const upcomingToday = computed(() => {
refreshKey.value;
return todayEvents.value.filter((event) => !isEventHappeningNow(event) && isInFuture(event));
});
const favouritesUpcomingToday = computed(() => {
refreshKey.value;
return upcomingToday.value.filter((event) => favouritesStore.isFavourite(event));
});
onMounted(() => {
timer.value = setInterval(() => {
refreshKey.value++;
}, 1000);
});
function isEventHappeningNow(event: Event): boolean {
const now = new Date();
return event.start <= now && event.end >= now;
}
function isInFuture(event: Event): boolean {
return event.start > new Date();
}
function isToday(date: Date): boolean {
const today = new Date();
return date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear();
}
</script>
<template>
<div v-if="scheduleStore.status === 'pending'" class="loading">
<span class="loading-text">
<Spinner color="var(--color-text-muted)" />Updating schedule...
</span>
</div>
<Panel kind="emphasis" class="ongoing" v-if="happeningNow.length > 0" title="Now" :icon="Radio">
<ul class="events-list">
<li v-for="event in showAllHappeningNow ? happeningNow : favouritesHappeningNow" :key="event.id">
<EventListing :event="event" />
</li>
<span class="other" v-if="!showAllHappeningNow && happeningNow.length != favouritesHappeningNow.length">{{ happeningNow.length }} other events happening right now</span>
</ul>
<template #actions>
<div class="actions">
<span class="status" v-if="!showAllHappeningNow">Showing only agenda items</span>
<Button @click="showAllHappeningNow = !showAllHappeningNow" :kind="showAllHappeningNow ? 'secondary' : 'primary'">
{{ showAllHappeningNow ? 'Show only agenda items' : 'Show all' }}
</Button>
</div>
</template>
</Panel>
<Panel class="upcoming" v-if="upcomingToday.length > 0" title="Upcoming">
<ul class="events-list">
<li v-for="event in showAllUpcoming ? upcomingToday : favouritesUpcomingToday" :key="event.id">
<EventListing :event="event" :show-relative-time="true" />
</li>
<span class="other" v-if="!showAllUpcoming">{{ upcomingToday.length }} other upcoming events today</span>
</ul>
<template #actions>
<div class="actions">
<span class="status" v-if="!showAllUpcoming">Showing only agenda items</span>
<Button @click="showAllUpcoming = !showAllUpcoming" :kind="showAllUpcoming ? 'secondary' : 'primary'">
{{ showAllUpcoming ? 'Show only agenda items' : 'Show all' }}
</Button>
</div>
</template>
</Panel>
<Panel kind="error" v-if="todayEvents.length === 0">
<span>There are no more events today</span>
</Panel>
</template>
<style scoped>
ul.events-list {
list-style: none;
margin: 0;
padding: 0;
display: grid;
margin-top: -1rem;
}
ul.events-list > .other {
font-style: italic;
}
ul.events-list > li {
border-bottom: 1px solid var(--color-hover);
}
ul.events-list > li:last-of-type {
border-bottom: none;
}
div.actions {
display: flex;
align-items: center;
gap: 1rem;
}
div.actions > span.status {
color: var(--color-text);
font-style: italic;
font-size: var(--text-small);
}
@media (max-width: 800px) {
div.actions > span.status {
display: none;
}
}
</style>
|