From 46d7cf66b8d0855ea399ec80c918006933a9d51c Mon Sep 17 00:00:00 2001 From: NeilClack Date: Fri, 11 Sep 2026 18:24:54 -0500 Subject: [PATCH] Render overnight blocks across midnight in the day view --- src/lib/components/schedule/BlockModal.svelte | 15 +++- .../schedule/BlockModal.svelte.spec.ts | 6 ++ .../components/schedule/DaySchedule.svelte | 69 +++++++++++++------ 3 files changed, 66 insertions(+), 24 deletions(-) diff --git a/src/lib/components/schedule/BlockModal.svelte b/src/lib/components/schedule/BlockModal.svelte index 352aece..1743433 100644 --- a/src/lib/components/schedule/BlockModal.svelte +++ b/src/lib/components/schedule/BlockModal.svelte @@ -2,7 +2,13 @@ import { enhance } from '$app/forms'; import type { SubmitFunction } from '@sveltejs/kit'; import ProclamationBrowser from './ProclamationBrowser.svelte'; - import { MINUTE_STEP, formatTime, validateBlock, type BlockSibling } from '$lib/schedule-utils'; + import { + MINUTE_STEP, + formatTime, + isOvernight, + validateBlock, + type BlockSibling + } from '$lib/schedule-utils'; type BrowserCategory = { id: number; name: string }; type BrowserGroup = { id: number; name: string }; @@ -77,6 +83,9 @@ const startMinutes = $derived((Number(startHour) * 60 + Number(startMinute)) | 0); const endMinutes = $derived((Number(endHour) * 60 + Number(endMinute)) | 0); + const overnight = $derived( + startMinutes !== endMinutes && isOvernight({ startMinutes, endMinutes }) + ); const siblings = $derived(existingBlocks.filter((block) => block.id !== blockId)); @@ -276,7 +285,9 @@ >

Review

- {formatTime(startMinutes)} – {formatTime(endMinutes)} + {formatTime(startMinutes)} – {formatTime(endMinutes)}{overnight + ? ' (next day)' + : ''}

{#if selectedTitles.length === 0}

diff --git a/src/lib/components/schedule/BlockModal.svelte.spec.ts b/src/lib/components/schedule/BlockModal.svelte.spec.ts index 507d062..b9f66cb 100644 --- a/src/lib/components/schedule/BlockModal.svelte.spec.ts +++ b/src/lib/components/schedule/BlockModal.svelte.spec.ts @@ -74,6 +74,12 @@ describe('BlockModal', () => { await expect.element(page.getByText('Peace')).toBeInTheDocument(); }); + it('marks an overnight block in the review', async () => { + mount({ initialStartMinutes: 21 * 60, initialEndMinutes: 9 * 60 }); + + await expect.element(page.getByText('9:00 PM – 9:00 AM (next day)')).toBeInTheDocument(); + }); + it('rejects an overlapping time range with the specific error', async () => { mount({ existingBlocks: [{ id: 'b1', startMinutes: 6 * 60, endMinutes: 8 * 60 }], diff --git a/src/lib/components/schedule/DaySchedule.svelte b/src/lib/components/schedule/DaySchedule.svelte index c9dc434..1d1b080 100644 --- a/src/lib/components/schedule/DaySchedule.svelte +++ b/src/lib/components/schedule/DaySchedule.svelte @@ -1,5 +1,12 @@

@@ -113,27 +132,33 @@ >
{/if} - {#each blocks as block (block.id)} - {@const top = (block.startMinutes / MINUTES_PER_DAY) * 100} - {@const height = ((block.endMinutes - block.startMinutes) / MINUTES_PER_DAY) * 100} - + {#each blockViews as view (view.block.id)} + {#each view.segments as segment, segmentIndex (`${view.block.id}-${segmentIndex}`)} + + {/each} {/each} {#if blocks.length === 0}