From d7226089476e72e4329f29d3bbe3cb1243dcc19b Mon Sep 17 00:00:00 2001 From: boojack Date: Thu, 6 Aug 2026 22:59:21 +0800 Subject: [PATCH] fix(sidebar): stop the month calendar growing with the rail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calendar cells were `aspect-square w-full`, so cell height was a pure function of rail width. Dragging the rail from 224px to its 400px max took the calendar block from 231px to 382px — a 65% jump that pushed Views and Tags out of view, left a 12px numeral floating in a 50px box, and turned the selected day into a 50x50 slab against a rail whose every other row is 30px. Split the cell in two: the button spans its whole column and takes the pointer, while a chip inside it carries the fill, the ring and the today dot, and stops growing at `maxSize`. A chip is therefore `min(column, 30px)` — narrow rails are untouched (224px still yields 25px cells, 170px of grid) and wider ones spend the surplus on hit area instead of height, holding the grid at 200px from 258px up. The today dot stops detaching as a side effect: it is positioned against a chip that no longer grows, rather than against a cell floor that drifted 19px below the numeral at full width. --- .../ActivityCalendar/CalendarCell.tsx | 52 ++++++++++-------- .../components/ActivityCalendar/constants.ts | 12 ++++- web/src/components/AppSidebar/SidebarRow.tsx | 29 +++++++--- web/src/components/AppSidebar/TagsSection.tsx | 45 +++++++--------- web/src/components/TagTree.tsx | 36 ++++++++----- .../calendar-cell-empty-clickable.test.tsx | 19 +++++-- web/tests/sidebar-row-grammar.test.tsx | 53 +++++++++++++++++++ 7 files changed, 172 insertions(+), 74 deletions(-) create mode 100644 web/tests/sidebar-row-grammar.test.tsx diff --git a/web/src/components/ActivityCalendar/CalendarCell.tsx b/web/src/components/ActivityCalendar/CalendarCell.tsx index 33549d94..0b2f1de4 100644 --- a/web/src/components/ActivityCalendar/CalendarCell.tsx +++ b/web/src/components/ActivityCalendar/CalendarCell.tsx @@ -24,31 +24,47 @@ export const CalendarCell = memo((props: CalendarCellProps) => { }; const sizeConfig = size === "small" ? SMALL_CELL_SIZE : DEFAULT_CELL_SIZE; - const smallExtraClasses = size === "small" ? `${SMALL_CELL_SIZE.dimensions} min-h-0` : ""; - const baseClasses = cn( - "relative aspect-square w-full flex items-center justify-center text-center transition-[background-color,color,filter,box-shadow] duration-150 ease-out select-none", + // Two elements with two jobs: the cell spans its whole column and takes the pointer, the + // chip inside it is the square that carries the fill and sets the row's height. + const cellClasses = "group/day flex w-full items-center justify-center select-none"; + const chipClasses = cn( + "relative flex aspect-square w-full items-center justify-center text-center transition-[background-color,color,filter,box-shadow] duration-150 ease-out", sizeConfig.font, sizeConfig.borderRadius, - smallExtraClasses, + sizeConfig.maxSize, ); const isInteractive = Boolean(onClick); const ariaLabel = day.isSelected ? `${tooltipText} (selected)` : tooltipText; if (!day.isCurrentMonth) { - return
{day.label}
; + return ( +
+ {day.label} +
+ ); } const intensityClass = getCellIntensityClass(day, maxCount); - const buttonClasses = cn( - "h-auto p-0", - baseClasses, - intensityClass, - getCalendarCellStateClass(day), - isInteractive - ? "cursor-pointer hover:brightness-[0.97] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-inset" - : "cursor-default", + const chip = ( + + {day.label} + {day.isToday && ( + ); const button = ( @@ -59,15 +75,9 @@ export const CalendarCell = memo((props: CalendarCellProps) => { aria-label={ariaLabel} aria-current={day.isToday ? "date" : undefined} aria-disabled={!isInteractive} - className={buttonClasses} + className={cn(cellClasses, "p-0 focus-visible:outline-none", isInteractive ? "cursor-pointer" : "cursor-default")} > - {day.label} - {day.isToday && ( -