From b1695912099e3c3fdcbc6df07402dd74a12af6ce Mon Sep 17 00:00:00 2001 From: Kristian Wind Date: Tue, 18 Aug 2026 09:04:30 +0200 Subject: [PATCH] feat(upcoming): a week at a time, so a drag can cross a month boundary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A month grid is anchored to a month, so the two days on either side of its edge sit in different grids — and you cannot page mid-drag, because a drag in flight swallows the click that would page. A week that straddles the 31st and the 1st has both days in the same row. The same component as the month, with `span="week"`, rather than a second one: the part that is easy to get almost right is the same in both. A drop target has to decide from `dataTransfer.types` alone whether it accepts, and two copies of that are two places to be almost right. Seven cells instead of forty-two, so the height a month spends on six rows goes into one and the cells hold a real list rather than a hint. On a phone the row stacks and each day carries its own weekday name, because a column of bare numbers is not a week. `calendar` still means the month in localStorage. It is the value already stored for everybody who chose it, and renaming it would silently reset them. Co-Authored-By: Claude Opus 5 --- web/src/lib/components/CalendarView.svelte | 236 ++++++++++++++++++--- web/src/lib/stores.svelte.js | 60 +++++- web/src/routes/upcoming/+page.svelte | 29 ++- 3 files changed, 277 insertions(+), 48 deletions(-) diff --git a/web/src/lib/components/CalendarView.svelte b/web/src/lib/components/CalendarView.svelte index 4cac559..a377b6a 100644 --- a/web/src/lib/components/CalendarView.svelte +++ b/web/src/lib/components/CalendarView.svelte @@ -1,10 +1,15 @@ -
+
- -

{monthName}

- - + +

+ {heading} + {#if weekNumber}uge {weekNumber}{/if} +

+ +
@@ -128,7 +218,8 @@
{#each grid as date (date.toISOString())} {@const tasks = tasksOn(date)} - {@const outside = date.getMonth() !== cursor.getMonth()} + + {@const outside = span !== 'week' && date.getMonth() !== cursor.getMonth()}
(over = null)} ondrop={(e) => onDrop(e, date)} > + + {#if span === 'week'} + {WEEKDAYS[(date.getDay() + 6) % 7]} + {/if} {date.getDate()} - {#each tasks.slice(0, 3) as task (task.id)} + {#each tasks.slice(0, chipLimit) as task (task.id)}