Add line indicating now to Timetable
Add a red vertical line indicated the current time and date in the timetable with the label "now" on top of it.
This commit is contained in:
parent
bea8e77742
commit
ebf7bdcc9c
1 changed files with 72 additions and 10 deletions
|
@ -68,6 +68,20 @@
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr class="overlay">
|
||||||
|
<th></th>
|
||||||
|
<td :colSpan="totalColumns">
|
||||||
|
<div
|
||||||
|
v-if="nowOffset !== undefined"
|
||||||
|
class="now"
|
||||||
|
:style="` --now-offset: ${nowOffset}`"
|
||||||
|
>
|
||||||
|
<div class="label">
|
||||||
|
now
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<template v-for="location in schedule.locations.values()" :key="location.id">
|
<template v-for="location in schedule.locations.values()" :key="location.id">
|
||||||
<tr v-if="locationRows.has(location.id)">
|
<tr v-if="locationRows.has(location.id)">
|
||||||
<th>{{ location.name }}</th>
|
<th>{{ location.name }}</th>
|
||||||
|
@ -364,7 +378,8 @@ function tableElementsFromStretches(
|
||||||
type HourHead = { span: number, isBreak: boolean, isDayShift: boolean, content?: string }
|
type HourHead = { span: number, isBreak: boolean, isDayShift: boolean, content?: string }
|
||||||
type LocationCell = { span: number, slots: Set<ClientScheduleEventSlot>, title: string, crew?: boolean }
|
type LocationCell = { span: number, slots: Set<ClientScheduleEventSlot>, title: string, crew?: boolean }
|
||||||
type RoleCell = { span: number, slots: Set<ClientScheduleShiftSlot>, title: string };
|
type RoleCell = { span: number, slots: Set<ClientScheduleShiftSlot>, title: string };
|
||||||
const columnGroups: { className?: string, cols: Col[] }[] = [];
|
type ColumnGroup = { start: number, end: number, width: number, className?: string, cols: Col[] };
|
||||||
|
const columnGroups: ColumnGroup[] = [];
|
||||||
const dayHeaders: DayHead[] = [];
|
const dayHeaders: DayHead[] = [];
|
||||||
const hourHeaders: HourHead[]= [];
|
const hourHeaders: HourHead[]= [];
|
||||||
const locationRows = new Map<number, LocationCell[]>([...locations.keys()].map(id => [id, []]));
|
const locationRows = new Map<number, LocationCell[]>([...locations.keys()].map(id => [id, []]));
|
||||||
|
@ -373,8 +388,8 @@ function tableElementsFromStretches(
|
||||||
const shiftBySlotId = new Map([...shifts.values()].flatMap?.(shift => [...shift.slots.values()].map(slot =>[slot.id, shift])));
|
const shiftBySlotId = new Map([...shifts.values()].flatMap?.(shift => [...shift.slots.values()].map(slot =>[slot.id, shift])));
|
||||||
let totalColumns = 0;
|
let totalColumns = 0;
|
||||||
|
|
||||||
function startColumnGroup(className?: string) {
|
function startColumnGroup(start: number, end: number, width: number, className?: string) {
|
||||||
columnGroups.push({ className, cols: []})
|
columnGroups.push({ start, end, width, className, cols: []})
|
||||||
}
|
}
|
||||||
function startDay(isBreak: boolean, content?: string) {
|
function startDay(isBreak: boolean, content?: string) {
|
||||||
dayHeaders.push({ span: 0, isBreak, content })
|
dayHeaders.push({ span: 0, isBreak, content })
|
||||||
|
@ -414,13 +429,12 @@ function tableElementsFromStretches(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let first = true;
|
let lastStretch: Stretch | undefined;
|
||||||
for (let stretch of stretches) {
|
for (let stretch of stretches) {
|
||||||
stretch = padStretch(stretch, timezone);
|
stretch = padStretch(stretch, timezone);
|
||||||
const startDate = DateTime.fromMillis(stretch.start, { zone: timezone, locale: accountStore.activeLocale });
|
const startDate = DateTime.fromMillis(stretch.start, { zone: timezone, locale: accountStore.activeLocale });
|
||||||
if (first) {
|
if (!lastStretch) {
|
||||||
first = false;
|
startColumnGroup(stretch.start, stretch.end, (stretch.end - stretch.start) / oneHourMs);
|
||||||
startColumnGroup();
|
|
||||||
startDay(false, startDate.toFormat("yyyy-LL-dd"));
|
startDay(false, startDate.toFormat("yyyy-LL-dd"));
|
||||||
startHour(false, startDate.toFormat("HH:mm"));
|
startHour(false, startDate.toFormat("HH:mm"));
|
||||||
for(const location of locations.values()) {
|
for(const location of locations.values()) {
|
||||||
|
@ -430,7 +444,7 @@ function tableElementsFromStretches(
|
||||||
startRole(role.id);
|
startRole(role.id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
startColumnGroup("break");
|
startColumnGroup(lastStretch.end, stretch.start, 1, "break");
|
||||||
const dayName = startDate.toFormat("yyyy-LL-dd");
|
const dayName = startDate.toFormat("yyyy-LL-dd");
|
||||||
const lastDayHeader = dayHeaders[dayHeaders.length - 1]
|
const lastDayHeader = dayHeaders[dayHeaders.length - 1]
|
||||||
const sameDay = dayName === lastDayHeader.content && lastDayHeader.span;
|
const sameDay = dayName === lastDayHeader.content && lastDayHeader.span;
|
||||||
|
@ -445,7 +459,7 @@ function tableElementsFromStretches(
|
||||||
}
|
}
|
||||||
pushColumn();
|
pushColumn();
|
||||||
|
|
||||||
startColumnGroup();
|
startColumnGroup(stretch.start, stretch.end, (stretch.end - stretch.start) / oneHourMs);
|
||||||
if (!sameDay)
|
if (!sameDay)
|
||||||
startDay(false, dayName);
|
startDay(false, dayName);
|
||||||
startHour(false, startDate.toFormat("HH:mm"));
|
startHour(false, startDate.toFormat("HH:mm"));
|
||||||
|
@ -499,6 +513,8 @@ function tableElementsFromStretches(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastStretch = stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -565,6 +581,28 @@ 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 roleRows = computed(() => elements.value.roleRows);
|
const roleRows = computed(() => elements.value.roleRows);
|
||||||
|
|
||||||
|
const now = useState(() => Math.round(Date.now() / oneMinMs) * oneMinMs);
|
||||||
|
const interval = ref<any>();
|
||||||
|
onMounted(() => {
|
||||||
|
interval.value = setInterval(() => {
|
||||||
|
const newNow = Math.round(Date.now() / oneMinMs) * oneMinMs;
|
||||||
|
if (now.value !== newNow)
|
||||||
|
now.value = newNow;
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(interval.value);
|
||||||
|
});
|
||||||
|
const nowOffset = computed(() => {
|
||||||
|
let offset = 0;
|
||||||
|
for (let group of columnGroups.value) {
|
||||||
|
if (group.start <= now.value && now.value < group.end) {
|
||||||
|
return offset + (now.value - group.start) / (group.end - group.start) * group.width;
|
||||||
|
}
|
||||||
|
offset += group.width;
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -595,7 +633,7 @@ const roleRows = computed(() => elements.value.roleRows);
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timetable :is(td, th) {
|
.timetable tr:not(.overlay) :is(td, th) {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
@ -610,6 +648,30 @@ const roleRows = computed(() => elements.value.roleRows);
|
||||||
border-bottom: 1px solid var(--foreground);
|
border-bottom: 1px solid var(--foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.timetable tbody {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.timetable tr.overlay .now {
|
||||||
|
background-color: #f008;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: calc(var(--row-header-width) + var(--cell-size) * var(--now-offset) - 1px);
|
||||||
|
bottom: 0;
|
||||||
|
width: 2px;
|
||||||
|
scroll-margin-inline-start: calc(var(--row-header-width) + 2rem);
|
||||||
|
}
|
||||||
|
.now .label {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
color: white;
|
||||||
|
background: red;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
font-size: 0.5rem;
|
||||||
|
line-height: 1.1;
|
||||||
|
padding-inline: 0.1rem;
|
||||||
|
translate: calc(-50% + 0.5px) -50%;
|
||||||
|
}
|
||||||
|
|
||||||
colgroup.break {
|
colgroup.break {
|
||||||
background-color: color-mix(in oklab, var(--background), rgb(50, 50, 255) 60%);
|
background-color: color-mix(in oklab, var(--background), rgb(50, 50, 255) 60%);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue