Hold every calendar cell to the same size

A calendar whose boxes resize is not a calendar. Each week row is its own
grid, and a bare 1fr track takes its minimum from its content, so the one
week containing "Alla helgons dag" had its seven cells squeezed while
every other week's stayed wide. The tracks are now minmax(0, 1fr) and the
cell, the day and the holiday name each refuse to contribute an intrinsic
width; the name clips to an ellipsis and keeps its full text in the title.

Row height follows the same rule: the band lanes are reserved from the
month's tallest week rather than each row's own, so a week with no leave
in it stands as tall as the week beside it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ei7gCZzdd751uZtPzb1Pep
This commit is contained in:
2026-09-19 14:08:04 +02:00
parent 224fe7ae3e
commit f0f537c95f
6 changed files with 281 additions and 6 deletions
+12 -1
View File
@@ -24,7 +24,7 @@ import type {
} from '@/types'
import { Layout } from '@/components/layout/Layout'
import { LoadingSpinner } from '@/components/common/LoadingSpinner'
import { CalendarWeek, type BandClickInfo } from '@/components/common/CalendarWeek'
import { CalendarWeek, computeWeekLaneCount, type BandClickInfo } from '@/components/common/CalendarWeek'
import { PlannedDayModal } from '@/components/modals/PlannedDayModal'
import { PeriodPopover, type PeriodPopoverSavePayload } from '@/components/calendar/PeriodPopover'
import { PresetRail, type SeasonPreset } from '@/components/calendar/PresetRail'
@@ -432,6 +432,16 @@ export function Calendar(): ReactNode {
weeks.push(currentWeek)
}
// Every week row must be the same height regardless of how many bands
// overlap in it — see `CalendarWeek`'s `monthMaxLaneCount` doc comment.
// Computed once here (the month's tallest week) and passed down
// uniformly to every `CalendarWeek` below, instead of each week reserving
// only its own bottom padding.
const monthMaxLaneCount = weeks.reduce(
(max, week) => Math.max(max, computeWeekLaneCount(week, plannedDaysHook.data ?? [], calendarDaysByDate)),
0,
)
// These four all derive the *other* axis (year when the month changes, and
// vice versa) from live state rather than the `year`/`month` consts closed
// over by this render. Two selects changed in quick succession (as
@@ -894,6 +904,7 @@ export function Calendar(): ReactNode {
calendarDaysByDate={calendarDaysByDate}
onBandClick={handleBandClick}
flashWishId={flashWishId}
monthMaxLaneCount={monthMaxLaneCount}
/>
))}
</div>