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>
|
||||
</thead>
|
||||
<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">
|
||||
<tr v-if="locationRows.has(location.id)">
|
||||
<th>{{ location.name }}</th>
|
||||
|
@ -364,7 +378,8 @@ function tableElementsFromStretches(
|
|||
type HourHead = { span: number, isBreak: boolean, isDayShift: boolean, content?: string }
|
||||
type LocationCell = { span: number, slots: Set<ClientScheduleEventSlot>, title: string, crew?: boolean }
|
||||
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 hourHeaders: HourHead[]= [];
|
||||
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])));
|
||||
let totalColumns = 0;
|
||||
|
||||
function startColumnGroup(className?: string) {
|
||||
columnGroups.push({ className, cols: []})
|
||||
function startColumnGroup(start: number, end: number, width: number, className?: string) {
|
||||
columnGroups.push({ start, end, width, className, cols: []})
|
||||
}
|
||||
function startDay(isBreak: boolean, content?: string) {
|
||||
dayHeaders.push({ span: 0, isBreak, content })
|
||||
|
@ -414,13 +429,12 @@ function tableElementsFromStretches(
|
|||
}
|
||||
}
|
||||
|
||||
let first = true;
|
||||
let lastStretch: Stretch | undefined;
|
||||
for (let stretch of stretches) {
|
||||
stretch = padStretch(stretch, timezone);
|
||||
const startDate = DateTime.fromMillis(stretch.start, { zone: timezone, locale: accountStore.activeLocale });
|
||||
if (first) {
|
||||
first = false;
|
||||
startColumnGroup();
|
||||
if (!lastStretch) {
|
||||
startColumnGroup(stretch.start, stretch.end, (stretch.end - stretch.start) / oneHourMs);
|
||||
startDay(false, startDate.toFormat("yyyy-LL-dd"));
|
||||
startHour(false, startDate.toFormat("HH:mm"));
|
||||
for(const location of locations.values()) {
|
||||
|
@ -430,7 +444,7 @@ function tableElementsFromStretches(
|
|||
startRole(role.id);
|
||||
}
|
||||
} else {
|
||||
startColumnGroup("break");
|
||||
startColumnGroup(lastStretch.end, stretch.start, 1, "break");
|
||||
const dayName = startDate.toFormat("yyyy-LL-dd");
|
||||
const lastDayHeader = dayHeaders[dayHeaders.length - 1]
|
||||
const sameDay = dayName === lastDayHeader.content && lastDayHeader.span;
|
||||
|
@ -445,7 +459,7 @@ function tableElementsFromStretches(
|
|||
}
|
||||
pushColumn();
|
||||
|
||||
startColumnGroup();
|
||||
startColumnGroup(stretch.start, stretch.end, (stretch.end - stretch.start) / oneHourMs);
|
||||
if (!sameDay)
|
||||
startDay(false, dayName);
|
||||
startHour(false, startDate.toFormat("HH:mm"));
|
||||
|
@ -499,6 +513,8 @@ function tableElementsFromStretches(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastStretch = stretch;
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -565,6 +581,28 @@ const dayHeaders = computed(() => elements.value.dayHeaders);
|
|||
const hourHeaders = computed(() => elements.value.hourHeaders);
|
||||
const locationRows = computed(() => elements.value.locationRows);
|
||||
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>
|
||||
|
||||
<style scoped>
|
||||
|
@ -595,7 +633,7 @@ const roleRows = computed(() => elements.value.roleRows);
|
|||
left: 0;
|
||||
}
|
||||
|
||||
.timetable :is(td, th) {
|
||||
.timetable tr:not(.overlay) :is(td, th) {
|
||||
overflow: hidden;
|
||||
white-space: pre;
|
||||
text-overflow: ellipsis;
|
||||
|
@ -610,6 +648,30 @@ const roleRows = computed(() => elements.value.roleRows);
|
|||
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 {
|
||||
background-color: color-mix(in oklab, var(--background), rgb(50, 50, 255) 60%);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue