Shift hour display to be on the lines

The hour headers indicate the time on the left line of the cell, this
makes them confusing to read. Shift the displayed hour to be in the
middle of the left line of the cell so that it is clear which line is
the start of which hour.
This commit is contained in:
Hornwitser 2025-06-18 15:13:18 +02:00
parent a087172d39
commit bea8e77742

View file

@ -44,14 +44,26 @@
<thead>
<tr>
<th></th>
<th v-for="day, index in dayHeaders" :key="index" :colSpan="day.span">
<th
v-for="day, index in dayHeaders"
:key="index"
:colSpan="day.span"
:class="{ break: day.isBreak }"
>
{{ day.content }}
</th>
</tr>
<tr>
<tr class="hours">
<th>Location</th>
<th v-for="hour, index in hourHeaders" :key="index" :colSpan="hour.span">
{{ hour.content }}
<th
v-for="hour, index in hourHeaders"
:key="index"
:colSpan="hour.span"
:class="{ break: hour.isBreak, dayShift: hour.isDayShift }"
>
<div v-if="hour.content">
{{ hour.content }}
</div>
</th>
</tr>
</thead>
@ -348,8 +360,8 @@ function tableElementsFromStretches(
timezone: string,
) {
type Col = { minutes?: number };
type DayHead = { span: number, content?: string }
type HourHead = { span: number, content?: string }
type DayHead = { span: number, isBreak: 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 RoleCell = { span: number, slots: Set<ClientScheduleShiftSlot>, title: string };
const columnGroups: { className?: string, cols: Col[] }[] = [];
@ -364,11 +376,11 @@ function tableElementsFromStretches(
function startColumnGroup(className?: string) {
columnGroups.push({ className, cols: []})
}
function startDay(content?: string) {
dayHeaders.push({ span: 0, content })
function startDay(isBreak: boolean, content?: string) {
dayHeaders.push({ span: 0, isBreak, content })
}
function startHour(content?: string) {
hourHeaders.push({ span: 0, content })
function startHour(isBreak: boolean, content?: string, isDayShift = false) {
hourHeaders.push({ span: 0, isBreak, isDayShift, content })
}
function startLocation(id: number, slots = new Set<ClientScheduleEventSlot>()) {
const rows = locationRows.get(id)!;
@ -409,8 +421,8 @@ function tableElementsFromStretches(
if (first) {
first = false;
startColumnGroup();
startDay(startDate.toFormat("yyyy-LL-dd"));
startHour(startDate.toFormat("HH:mm"));
startDay(false, startDate.toFormat("yyyy-LL-dd"));
startHour(false, startDate.toFormat("HH:mm"));
for(const location of locations.values()) {
startLocation(location.id);
}
@ -423,8 +435,8 @@ function tableElementsFromStretches(
const lastDayHeader = dayHeaders[dayHeaders.length - 1]
const sameDay = dayName === lastDayHeader.content && lastDayHeader.span;
if (!sameDay)
startDay();
startHour("break");
startDay(true);
startHour(true, "break");
for(const location of locations.values()) {
startLocation(location.id);
}
@ -435,8 +447,8 @@ function tableElementsFromStretches(
startColumnGroup();
if (!sameDay)
startDay(dayName);
startHour(startDate.toFormat("HH:mm"));
startDay(false, dayName);
startHour(false, startDate.toFormat("HH:mm"));
for(const location of locations.values()) {
startLocation(location.id);
}
@ -469,16 +481,20 @@ function tableElementsFromStretches(
pushColumn(durationMs / oneMinMs);
const endDate = DateTime.fromMillis(end, { zone: timezone, locale: accountStore.activeLocale });
if (end === endDate.startOf("day").toMillis()) {
const isDayShift = end === endDate.startOf("day").toMillis();
if (isDayShift) {
startDay(
false,
DateTime.fromMillis(cutSpan.end.ts, { zone: timezone, locale: accountStore.activeLocale })
.toFormat("yyyy-LL-dd")
);
}
if (end === endDate.startOf("hour").toMillis()) {
startHour(
false,
DateTime.fromMillis(cutSpan.end.ts, { zone: timezone, locale: accountStore.activeLocale })
.toFormat("HH:mm")
.toFormat("HH:mm"),
isDayShift,
);
}
}
@ -594,10 +610,33 @@ const roleRows = computed(() => elements.value.roleRows);
border-bottom: 1px solid var(--foreground);
}
.break {
colgroup.break {
background-color: color-mix(in oklab, var(--background), rgb(50, 50, 255) 60%);
}
tr.hours>th:is(.break, :first-child) + th div {
visibility: hidden;
}
tr.hours>th:first-child {
z-index: 1;
}
tr.hours>th + th:not(.break) {
overflow: visible;
padding-top: 0;
vertical-align: top;
}
tr.hours>th + th:not(.break) div {
font-variant-numeric: tabular-nums;
padding-top: 0.2rem;
background-color: Canvas;
translate: calc(-0.5 * var(--cell-size)) 0;
}
tr.hours>th + th.dayShift div {
padding-top: 0;
margin-top: 0.2rem;
}
.event, .shift {
background-color: color-mix(in oklab, var(--background), rgb(255, 125, 50) 60%);
}