Add crew designator to events
Distinguish between events for attendees to see and events that are meant only for the crew.
This commit is contained in:
parent
40c25f8990
commit
db8393c3a9
3 changed files with 96 additions and 20 deletions
|
@ -62,9 +62,10 @@
|
||||||
v-for="row, index in locationRows.get(location.id)"
|
v-for="row, index in locationRows.get(location.id)"
|
||||||
:key="index"
|
:key="index"
|
||||||
:colSpan="row.span"
|
:colSpan="row.span"
|
||||||
:class='{"event": row.slots.size }'
|
:class='{"event": row.slots.size, "crew": row.crew }'
|
||||||
|
:title="row.title"
|
||||||
>
|
>
|
||||||
{{ [...row.slots].map(slot => eventBySlotId.get(slot.id)!.name).join(", ") }}
|
{{ row.title }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -310,16 +311,20 @@ function padStretch(stretch: Stretch, timezone: string): Stretch {
|
||||||
}
|
}
|
||||||
|
|
||||||
function tableElementsFromStretches(
|
function tableElementsFromStretches(
|
||||||
stretches: Iterable<Stretch>, locations: ScheduleLocation[], timezone: string,
|
stretches: Iterable<Stretch>,
|
||||||
|
events: ScheduleEvent[],
|
||||||
|
locations: ScheduleLocation[],
|
||||||
|
timezone: string,
|
||||||
) {
|
) {
|
||||||
type Col = { minutes?: number };
|
type Col = { minutes?: number };
|
||||||
type DayHead = { span: number, content?: string }
|
type DayHead = { span: number, content?: string }
|
||||||
type HourHead = { span: number, content?: string }
|
type HourHead = { span: number, content?: string }
|
||||||
type LocationCell = { span: number, slots: Set<TimeSlot> }
|
type LocationCell = { span: number, slots: Set<TimeSlot>, title: string, crew?: boolean }
|
||||||
const columnGroups: { className?: string, cols: Col[] }[] = [];
|
const columnGroups: { className?: string, cols: Col[] }[] = [];
|
||||||
const dayHeaders: DayHead[] = [];
|
const dayHeaders: DayHead[] = [];
|
||||||
const hourHeaders: HourHead[]= [];
|
const hourHeaders: HourHead[]= [];
|
||||||
const locationRows = new Map<string, LocationCell[]>(locations.map(location => [location.id, []]));
|
const locationRows = new Map<string, LocationCell[]>(locations.map(location => [location.id, []]));
|
||||||
|
const eventBySlotId = new Map(events.flatMap(event => event.slots.map(slot => [slot.id, event])));
|
||||||
|
|
||||||
function startColumnGroup(className?: string) {
|
function startColumnGroup(className?: string) {
|
||||||
columnGroups.push({ className, cols: []})
|
columnGroups.push({ className, cols: []})
|
||||||
|
@ -331,7 +336,13 @@ function tableElementsFromStretches(
|
||||||
hourHeaders.push({ span: 0, content })
|
hourHeaders.push({ span: 0, content })
|
||||||
}
|
}
|
||||||
function startLocation(id: string, slots = new Set<TimeSlot>()) {
|
function startLocation(id: string, slots = new Set<TimeSlot>()) {
|
||||||
locationRows.get(id)!.push({ span: 0, slots });
|
const rows = locationRows.get(id)!;
|
||||||
|
if (rows.length) {
|
||||||
|
const row = rows[rows.length - 1];
|
||||||
|
row.title = [...row.slots].map(slot => eventBySlotId.get(slot.id)!.name).join(", ");
|
||||||
|
row.crew = [...row.slots].every(slot => eventBySlotId.get(slot.id)!.crew);
|
||||||
|
}
|
||||||
|
rows.push({ span: 0, slots, title: "" });
|
||||||
}
|
}
|
||||||
function pushColumn(minutes?: number) {
|
function pushColumn(minutes?: number) {
|
||||||
columnGroups[columnGroups.length - 1].cols.push({ minutes })
|
columnGroups[columnGroups.length - 1].cols.push({ minutes })
|
||||||
|
@ -414,6 +425,7 @@ function tableElementsFromStretches(
|
||||||
dayHeaders: dayHeaders.filter(day => day.span),
|
dayHeaders: dayHeaders.filter(day => day.span),
|
||||||
hourHeaders: hourHeaders.filter(hour => hour.span),
|
hourHeaders: hourHeaders.filter(hour => hour.span),
|
||||||
locationRows: new Map([...locationRows].map(([id, cells]) => [id, cells.filter(cell => cell.span)])),
|
locationRows: new Map([...locationRows].map(([id, cells]) => [id, cells.filter(cell => cell.span)])),
|
||||||
|
eventBySlotId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,16 +443,14 @@ const timezone = computed({
|
||||||
set: (value: string) => { debugTimezone.value = value },
|
set: (value: string) => { debugTimezone.value = value },
|
||||||
});
|
});
|
||||||
|
|
||||||
const elements = computed(() => tableElementsFromStretches(stretches.value, schedule.value.locations, timezone.value));
|
const elements = computed(() => tableElementsFromStretches(
|
||||||
|
stretches.value, schedule.value.events, schedule.value.locations, timezone.value
|
||||||
|
));
|
||||||
const columnGroups = computed(() => elements.value.columnGroups);
|
const columnGroups = computed(() => elements.value.columnGroups);
|
||||||
const dayHeaders = computed(() => elements.value.dayHeaders);
|
const dayHeaders = computed(() => elements.value.dayHeaders);
|
||||||
const hourHeaders = computed(() => elements.value.hourHeaders);
|
const hourHeaders = computed(() => elements.value.hourHeaders);
|
||||||
const locationRows = computed(() => elements.value.locationRows);
|
const locationRows = computed(() => elements.value.locationRows);
|
||||||
const eventBySlotId = computed(() => new Map(
|
const eventBySlotId = computed(() => elements.value.eventBySlotId);
|
||||||
schedule.value.events.flatMap(
|
|
||||||
event => event.slots.map(slot => [slot.id, event])
|
|
||||||
)
|
|
||||||
));
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -472,6 +482,9 @@ const eventBySlotId = computed(() => new Map(
|
||||||
}
|
}
|
||||||
|
|
||||||
.timetable :is(td, th) {
|
.timetable :is(td, th) {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: pre;
|
||||||
|
text-overflow: ellipsis;
|
||||||
padding: 0.1rem;
|
padding: 0.1rem;
|
||||||
border-top: 1px solid var(--foreground);
|
border-top: 1px solid var(--foreground);
|
||||||
border-right: 1px solid var(--foreground);
|
border-right: 1px solid var(--foreground);
|
||||||
|
@ -490,4 +503,7 @@ const eventBySlotId = computed(() => new Map(
|
||||||
.event {
|
.event {
|
||||||
background-color: color-mix(in oklab, var(--background), rgb(255, 125, 50) 60%);
|
background-color: color-mix(in oklab, var(--background), rgb(255, 125, 50) 60%);
|
||||||
}
|
}
|
||||||
|
.event.crew {
|
||||||
|
background-color: color-mix(in oklab, var(--background), rgb(127, 127, 127) 60%);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -32,16 +32,27 @@ const events = [
|
||||||
"d1 12:00 4h clubhouse",
|
"d1 12:00 4h clubhouse",
|
||||||
"d2 12:00 4h clubhouse",
|
"d2 12:00 4h clubhouse",
|
||||||
"d3 12:00 4h clubhouse",
|
"d3 12:00 4h clubhouse",
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
|
{ name: "Arcade Setup", crew: true, slots: ["d1 11:00 1h clubhouse"], },
|
||||||
{
|
{
|
||||||
name: "Bonfire Stories",
|
name: "Bonfire Stories",
|
||||||
description: "Share your stories as we sit cosily around the campfire.",
|
description: "Share your stories as we sit cosily around the campfire.",
|
||||||
slots: ["d2 18:00 2h campfire"]
|
slots: ["d2 18:00 2h campfire"],
|
||||||
|
},
|
||||||
|
{ name: "Stage Rigging", crew: true, slots: ["d1 11:00 7h30m stage"]},
|
||||||
|
{
|
||||||
|
name: "Reconfigure for DJ",
|
||||||
|
crew: true,
|
||||||
|
slots: [
|
||||||
|
"d2 19:00 1h stage",
|
||||||
|
"d3 18:45 1h15m stage",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{ name: "DJ Alpha", slots: ["d2 20:00 2h stage"] },
|
{ name: "DJ Alpha", slots: ["d2 20:00 2h stage"] },
|
||||||
{ name: "DJ Bravo", slots: ["d3 20:00 2h stage"] },
|
{ name: "DJ Bravo", slots: ["d3 20:00 2h stage"] },
|
||||||
{ name: "DJ Charlie", slots: ["d3 22:00 2h stage"] },
|
{ name: "DJ Charlie", slots: ["d3 22:00 2h stage"] },
|
||||||
|
{ name: "Prepare Fursuit Games", crew: true, slots: ["d4 17:00 1h clubhouse"] },
|
||||||
{
|
{
|
||||||
name: "Fursuit Games",
|
name: "Fursuit Games",
|
||||||
description: "Playful time for the suiters.",
|
description: "Playful time for the suiters.",
|
||||||
|
@ -50,6 +61,8 @@ const events = [
|
||||||
{ name: "Fishing Trip", slots: ["d3 12:00 3h30m outside"]},
|
{ name: "Fishing Trip", slots: ["d3 12:00 3h30m outside"]},
|
||||||
{ name: "Opening", slots: ["d1 18:30 1h30m stage"]},
|
{ name: "Opening", slots: ["d1 18:30 1h30m stage"]},
|
||||||
{ name: "Closing", slots: ["d5 16:00 1h stage"]},
|
{ name: "Closing", slots: ["d5 16:00 1h stage"]},
|
||||||
|
{ name: "Stage Teardown", crew: true, slots: ["d5 17:00 4h stage"]},
|
||||||
|
{ name: "Setup Board Games", crew: true, slots: ["d1 11:30 30m summerhouse"]},
|
||||||
{
|
{
|
||||||
name: "Board Games",
|
name: "Board Games",
|
||||||
slots: [
|
slots: [
|
||||||
|
@ -57,9 +70,18 @@ const events = [
|
||||||
"d2 12:00 4h summerhouse",
|
"d2 12:00 4h summerhouse",
|
||||||
"d3 12:00 4h summerhouse",
|
"d3 12:00 4h summerhouse",
|
||||||
"d4 12:00 4h summerhouse",
|
"d4 12:00 4h summerhouse",
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
|
{ name: "Teardown Board Games", crew: true, slots: ["d4 16:00 30m summerhouse"]},
|
||||||
{ name: "📷meet", slots: ["d3 19:00 1h10m summerhouse"]},
|
{ name: "📷meet", slots: ["d3 19:00 1h10m summerhouse"]},
|
||||||
|
{
|
||||||
|
name: "Prepare Karaoke",
|
||||||
|
crew: true,
|
||||||
|
slots: [
|
||||||
|
"d3 20:00 1h clubhouse",
|
||||||
|
"d4 20:00 1h clubhouse",
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Karaoke",
|
name: "Karaoke",
|
||||||
slots: [
|
slots: [
|
||||||
|
@ -68,9 +90,21 @@ const events = [
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ name: "Dance", slots: ["d1 20:00 3h stage"]},
|
{ name: "Dance", slots: ["d1 20:00 3h stage"]},
|
||||||
|
{ name: "Prepare Charity Auction", crew: true, slots: ["d4 10:00 3h stage"]},
|
||||||
{ name: "Charity Auction", slots: ["d4 13:00 2h stage"]},
|
{ name: "Charity Auction", slots: ["d4 13:00 2h stage"]},
|
||||||
|
{ name: "Tournament Preparation", crew: true, slots: ["d2 15:00 2h stage"]},
|
||||||
{ name: "Tournament", slots: ["d2 17:00 2h stage"]},
|
{ name: "Tournament", slots: ["d2 17:00 2h stage"]},
|
||||||
{ name: "Canoe Trip", slots: ["d4 11:00 4h30m outside"]},
|
{ name: "Canoe Trip", slots: ["d4 11:00 4h30m outside"]},
|
||||||
|
{
|
||||||
|
name: "Dinner Preparations",
|
||||||
|
crew: true,
|
||||||
|
slots: [
|
||||||
|
"d1 14:00 2h campfire",
|
||||||
|
"d2 14:00 2h campfire",
|
||||||
|
"d3 14:00 2h campfire",
|
||||||
|
"d4 14:00 2h campfire",
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Dinner",
|
name: "Dinner",
|
||||||
slots: [
|
slots: [
|
||||||
|
@ -80,10 +114,24 @@ const events = [
|
||||||
"d4 16:00 1h campfire",
|
"d4 16:00 1h campfire",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Dinner Cleanup",
|
||||||
|
crew: true,
|
||||||
|
slots: [
|
||||||
|
"d1 17:00 1h campfire",
|
||||||
|
"d2 17:00 1h campfire",
|
||||||
|
"d3 17:00 1h campfire",
|
||||||
|
"d4 17:00 1h campfire",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ name: "Prepare Film Night", crew: true, slots: ["d4 19:00 2h stage"]},
|
||||||
{ name: "Film Night", slots: ["d4 21:00 2h stage"]},
|
{ name: "Film Night", slots: ["d4 21:00 2h stage"]},
|
||||||
{ name: "Photo", slots: ["d3 18:00 45m stage"]},
|
{ name: "Prepare Group Photo", crew: true, slots: ["d3 17:00 1h stage"]},
|
||||||
|
{ name: "Group Photo", slots: ["d3 18:00 45m stage"]},
|
||||||
|
{ name: "Setup Artist Alley", crew: true, slots: ["d4 10:00 2h clubhouse"]},
|
||||||
{ name: "Artist Alley", slots: ["d4 12:00 4h clubhouse"]},
|
{ name: "Artist Alley", slots: ["d4 12:00 4h clubhouse"]},
|
||||||
{ name: "Feedback Panel", slots: ["d5 18:00 4h clubhouse"]},
|
{ name: "Teardown Artist Alley", crew: true, slots: ["d4 16:00 1h clubhouse"]},
|
||||||
|
{ name: "Feedback Panel", slots: ["d5 18:00 1h clubhouse"]},
|
||||||
];
|
];
|
||||||
|
|
||||||
function toId(name: string) {
|
function toId(name: string) {
|
||||||
|
@ -94,7 +142,7 @@ function toIso(date: Date) {
|
||||||
return date.toISOString().replace(":00.000Z", "Z");
|
return date.toISOString().replace(":00.000Z", "Z");
|
||||||
}
|
}
|
||||||
|
|
||||||
function toSlot(origin: Date, id: string, shorthand: string, index: number): TimeSlot {
|
function toSlot(origin: Date, id: string, shorthand: string, index: number, counts: Map<string, number>): TimeSlot {
|
||||||
const [day, start, duration, location] = shorthand.split(" ");
|
const [day, start, duration, location] = shorthand.split(" ");
|
||||||
const [startHours, startMinutes] = start.split(":").map(time => parseInt(time, 10));
|
const [startHours, startMinutes] = start.split(":").map(time => parseInt(time, 10));
|
||||||
const dayNumber = parseInt(day.slice(1));
|
const dayNumber = parseInt(day.slice(1));
|
||||||
|
@ -113,6 +161,7 @@ function toSlot(origin: Date, id: string, shorthand: string, index: number): Tim
|
||||||
start: toIso(startDate),
|
start: toIso(startDate),
|
||||||
end: toIso(endDate),
|
end: toIso(endDate),
|
||||||
locations: [location],
|
locations: [location],
|
||||||
|
interested: counts.get(`${id}-${index}`),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,13 +174,22 @@ export function generateDemoSchedule(): Schedule {
|
||||||
origin.setUTCSeconds(0);
|
origin.setUTCSeconds(0);
|
||||||
origin.setUTCMilliseconds(0);
|
origin.setUTCMilliseconds(0);
|
||||||
|
|
||||||
|
const counts = new Map<string, number>()
|
||||||
|
for (const account of generateDemoAccounts()) {
|
||||||
|
for (const id of account.interestedIds ?? []) {
|
||||||
|
counts.set(id, (counts.get(id) ?? 0) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
events: events.map(
|
events: events.map(
|
||||||
({ name, description, slots }) => ({
|
({ name, crew, description, slots }) => ({
|
||||||
id: toId(name),
|
id: toId(name),
|
||||||
name,
|
name,
|
||||||
|
crew,
|
||||||
description,
|
description,
|
||||||
slots: slots.map((shorthand, index) => toSlot(origin, toId(name), shorthand, index))
|
interested: counts.get(toId(name)),
|
||||||
|
slots: slots.map((shorthand, index) => toSlot(origin, toId(name), shorthand, index, counts))
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
locations: locations.map(
|
locations: locations.map(
|
||||||
|
@ -178,6 +236,7 @@ export function generateDemoAccounts(): Account[] {
|
||||||
|
|
||||||
// These have a much higher probability of being in someone's interested list.
|
// These have a much higher probability of being in someone's interested list.
|
||||||
const desiredEvent = ["opening", "closing", "fursuit-games"];
|
const desiredEvent = ["opening", "closing", "fursuit-games"];
|
||||||
|
const nonCrewEvents = events.filter(event => !event.crew);
|
||||||
|
|
||||||
for (const account of accounts) {
|
for (const account of accounts) {
|
||||||
const interestedIds: string[] = [];
|
const interestedIds: string[] = [];
|
||||||
|
@ -189,7 +248,7 @@ export function generateDemoAccounts(): Account[] {
|
||||||
|
|
||||||
const eventsToAdd = Math.floor(random() * 10);
|
const eventsToAdd = Math.floor(random() * 10);
|
||||||
while (interestedIds.length < eventsToAdd) {
|
while (interestedIds.length < eventsToAdd) {
|
||||||
const event = events[Math.floor(random() * events.length)];
|
const event = nonCrewEvents[Math.floor(random() * nonCrewEvents.length)];
|
||||||
const eventId = toId(event.name);
|
const eventId = toId(event.name);
|
||||||
if (interestedIds.some(id => id.replace(/-\d+$/, "") === eventId)) {
|
if (interestedIds.some(id => id.replace(/-\d+$/, "") === eventId)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
1
shared/types/schedule.d.ts
vendored
1
shared/types/schedule.d.ts
vendored
|
@ -1,6 +1,7 @@
|
||||||
export interface ScheduleEvent {
|
export interface ScheduleEvent {
|
||||||
name: string,
|
name: string,
|
||||||
id: string,
|
id: string,
|
||||||
|
crew?: boolean,
|
||||||
host?: string,
|
host?: string,
|
||||||
cancelled?: boolean,
|
cancelled?: boolean,
|
||||||
description?: string,
|
description?: string,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue