+ {/* At 150 % the browser rounds the sticky header a device pixel below
+ the pane's edge, and a sliver of the week scrolled under it showed. */}
+
{weekSegments.map(({ week, segments, rowCount, dayEventRows, dayTasks, contentRows }) => {
- const overflowing = capRows && contentRows > rowCapacity;
- // Rows drawn per day; the last one is taken by the "N more" link.
- const rowLimit = overflowing ? rowCapacity - 1 : Infinity;
- const hiddenPerDay = overflowing
- ? week.map((_, dayIndex) => {
- const hiddenEvents = segments.filter((segment) =>
- segment.row >= rowLimit
- && dayIndex >= segment.startIndex
- && dayIndex < segment.startIndex + segment.span,
- ).length;
- const hiddenTasks = dayTasks[dayIndex].filter((_, taskIndex) => dayEventRows[dayIndex] + taskIndex >= rowLimit).length;
- return hiddenEvents + hiddenTasks;
- })
- : null;
+ // A fixed-height week: each day shows what fits and "+n more" (pim-6).
+ const fit = capRows ? fitMonthWeek(segments, dayEventRows, dayTasks.map((list) => list.length), rowCapacity, moreInHeader) : null;
+ const hiddenPerDay = fit?.hidden ?? null;
// Rows that grow with their content make room for the new event's preview.
const previewRows = !capRows && pendingPreview && week.some((day) => checkIsSameDay(pendingPreview.start, day)) ? 1 : 0;
return (
@@ -577,7 +638,8 @@ export function CalendarMonthView({
dayIndex={dayIndex}
week={week}
segments={segments}
- rowLimit={rowLimit}
+ rowLimit={fit ? fit.limits[dayIndex] : Infinity}
+ isShown={fit?.isShown}
rowCount={rowCount}
dayEventRows={dayEventRows}
dayTasks={dayTasks}
@@ -603,6 +665,7 @@ export function CalendarMonthView({
onSelectTask={onSelectTask}
onShowMore={() => (onOpenDay ?? onSelectDate)(week[dayIndex])}
moreLabel={t("events.more", { count: hiddenPerDay?.[dayIndex] ?? 0 })}
+ moreInHeader={moreInHeader}
paint={paint}
/>
)}
@@ -630,14 +693,17 @@ type WeekSegment = ReturnType[number];
* across the following ones.
*/
function MonthCellEntries({
- dayIndex, week, segments, rowLimit, rowCount, dayEventRows, dayTasks, hidden, overlayTop, rowHeight, chipHeight,
+ dayIndex, week, segments, rowLimit, isShown, rowCount, dayEventRows, dayTasks, hidden, overlayTop, rowHeight, chipHeight,
isMobile, calendarMap, pendingPreview, lastRow, selectedEventId, currentUserEmails, canEditEvent, inView, timedStyle,
- onSelectEvent, onHoverEvent, onHoverLeave, onContextMenuEvent, onReplyEvent, onToggleTaskComplete, onSelectTask, onShowMore, moreLabel, paint,
+ onSelectEvent, onHoverEvent, onHoverLeave, onContextMenuEvent, onReplyEvent, onToggleTaskComplete, onSelectTask, onShowMore, moreLabel, moreInHeader = false, paint,
}: {
dayIndex: number;
week: Date[];
segments: WeekSegment[];
+ /** This day's first row without an entry: its "N more" row when some are hidden. */
rowLimit: number;
+ /** Whether a fixed-height week has room for an event on all its days. */
+ isShown?: (segment: WeekSegment) => boolean;
rowCount: number;
dayEventRows: number[];
dayTasks: CalendarTask[][];
@@ -665,6 +731,8 @@ function MonthCellEntries({
onSelectTask?: (task: CalendarTask) => void;
onShowMore: () => void;
moreLabel: string;
+ /** The link goes beside the date ("+2"), named in full. */
+ moreInHeader?: boolean;
paint: (color: string) => string;
}) {
const day = week[dayIndex];
@@ -683,7 +751,7 @@ function MonthCellEntries({
onDoubleClick: (e: React.MouseEvent) => e.stopPropagation(),
onContextMenu: (e: React.MouseEvent) => e.stopPropagation(),
};
- const daySegments = segments.filter((segment) => segment.startIndex === dayIndex && segment.row < rowLimit);
+ const daySegments = segments.filter((segment) => segment.startIndex === dayIndex && (isShown ? isShown(segment) : segment.row < rowLimit));
const tasks = dayTasks[dayIndex].filter((_, taskIndex) => dayEventRows[dayIndex] + taskIndex < rowLimit);
const preview = pendingPreview && isSameDay(pendingPreview.start, day) ? pendingPreview : null;
@@ -739,7 +807,22 @@ function MonthCellEntries({
);
})}
- {hidden > 0 && (
+ {hidden > 0 && moreInHeader && (
+
+
+
+ )}
+ {hidden > 0 && !moreInHeader && (