owltide/components/CardEvent.vue
Hornwitser a32a49b281
All checks were successful
/ build (push) Successful in 1m35s
/ deploy (push) Successful in 16s
Add UI for setting cancelled status
Add indications in event cards, event slot cards and the timetable for
an event or event slot being cancelled by striking it through and
dimming the text colour.  And a checkbox in the event and event slot
list to edit the cancelled status.  And a diff entry for the cancelled
status on events and event slots.
2025-09-21 23:15:10 +02:00

137 lines
3.2 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
<section
class="event"
:class="{ cancelled: event.cancelled }"
>
<h3>{{ event.name }}</h3>
<p v-if=event.host>
Host: {{ event.host }}
</p>
<div v-if="event.notice" class="notice preWrap">
<div class="noticeIcon">
</div>
<p>
{{ event.notice }}
</p>
</div>
<div
v-if="descriptionHtml"
class="flow"
v-html="descriptionHtml"
/>
<p v-if="event.interested">
{{ event.interested }} interested
</p>
<p v-if="accountStore.valid">
<button
class="interested"
:class="{ active: accountStore.interestedEventIds.has(event.id) }"
@click="toggle('event', event.id, [...event.slots.keys()])"
>
{{ accountStore.interestedEventIds.has(event.id) ? "✔ interested" : "🔔 interested?" }}
</button>
</p>
<h4>Timeslots</h4>
<ul>
<li
v-for="slot in event.slots.values()"
:key="slot.id"
class="slot"
:class="{ cancelled: slot.cancelled }"
>
{{ formatTime(slot.start) }} - {{ formatTime(slot.end) }}
<button
v-if="accountStore.valid && event.slots.size > 1"
class="interested"
:disabled="accountStore.interestedEventIds.has(event.id)"
:class="{ active: accountStore.interestedEventIds.has(event.id) || accountStore.interestedEventSlotIds.has(slot.id) }"
@click="toggle('slot', slot.id)"
>
{{ accountStore.interestedEventIds.has(event.id) || accountStore.interestedEventSlotIds.has(slot.id) ? "✔ interested" : "🔔 interested?" }}
</button>
<template v-if="slot.interested">
({{ slot.interested }} interested)
</template>
<p v-if="slot.assigned.size">
Crew:
{{ [...slot.assigned].map(id => usersStore.users.get(id)?.name).join(", ") }}
</p>
</li>
</ul>
</section>
</template>
<script lang="ts" setup>
import { micromark } from 'micromark';
import { DateTime } from '~/shared/utils/luxon';
const props = defineProps<{
event: ClientScheduleEvent
}>()
const descriptionHtml = computed(() => {
if (props.event.description) {
return micromark(props.event.description);
}
});
const accountStore = useAccountStore();
const usersStore = useUsersStore();
function formatTime(time: DateTime) {
return time.toFormat("yyyy-LL-dd HH:mm");
}
async function toggle(type: "event" | "slot", id: number, slotIds?: number[]) {
await accountStore.toggleInterestedId(type, id, slotIds);
}
</script>
<style scoped>
.event {
background: color-mix(in oklab, var(--background), grey 20%);
padding: 0.5rem;
border-radius: 0.5rem;
}
.event.cancelled>*, .slot.cancelled {
text-decoration: line-through;
color: grey;
}
.event h3 {
margin: 0;
}
.event + .event {
margin-block-start: 0.5rem;
}
.event .notice {
text-decoration: none;
color: CanvasText;
display: flex;
width: fit-content;
gap: 0.5rem;
padding: 0.5rem;
margin-block: 0.5rem;
border-radius: 0.25rem;
border: 1px solid color-mix(in oklab, CanvasText, orange 50%);
background-color: color-mix(in oklab, Canvas, orange 40%);
}
.noticeIcon {
flex: 0 0 auto;
align-self: center;
font-size: 1rem;
}
button {
padding-inline: 0.2em;
}
button.active {
color: color-mix(in oklab, var(--foreground), green 50%);
}
</style>