From a64cc4af5cf045103e0f9014b133024b209fc4e3 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Tue, 3 Nov 2026 09:12:28 +0100 Subject: [PATCH] fix: grow month view event rows with the text size so titles are not cut off --- .../calendar-month-view-text-scale.test.ts | 25 ++++++++++++++++++ components/calendar/calendar-month-view.tsx | 26 ++++++++++++++----- 2 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 components/calendar/__tests__/calendar-month-view-text-scale.test.ts diff --git a/components/calendar/__tests__/calendar-month-view-text-scale.test.ts b/components/calendar/__tests__/calendar-month-view-text-scale.test.ts new file mode 100644 index 000000000..3337b4f7e --- /dev/null +++ b/components/calendar/__tests__/calendar-month-view-text-scale.test.ts @@ -0,0 +1,25 @@ +import { describe, expect, it, vi } from 'vitest'; + +vi.mock('next-intl', () => ({ useTranslations: () => (k: string) => k, useFormatter: () => ({}) })); + +const { monthGridMetrics } = await import('../calendar-month-view'); + +describe('monthGridMetrics', () => { + it('keeps the 24px chip with a mouse at normal text size', () => { + const m = monthGridMetrics(false, 1); + expect(m.chipHeight).toBe(24); + expect(m.overlayTop).toBe(30); + expect(m.baseRowMinHeight).toBe(30 + 4 + 8 + 4 * 26); + }); + + it('grows the rows and the day number strip with larger text', () => { + const m = monthGridMetrics(false, 2); + expect(m.chipHeight).toBe(50); + expect(m.overlayTop).toBe(60); + expect(m.baseRowMinHeight).toBe(60 + 4 + 8 + 4 * 52); + }); + + it('does not shrink chips below the target size for smaller text', () => { + expect(monthGridMetrics(false, 0.875).chipHeight).toBe(24); + }); +}); diff --git a/components/calendar/calendar-month-view.tsx b/components/calendar/calendar-month-view.tsx index e40694a19..8233a4932 100644 --- a/components/calendar/calendar-month-view.tsx +++ b/components/calendar/calendar-month-view.tsx @@ -14,6 +14,7 @@ import { useAuthStore } from "@/stores/auth-store"; import { useCalendarStore } from "@/stores/calendar-store"; import { movedEventUpdates } from "@/lib/calendar-participants"; import { useSettingsStore, type MonthTimedEventStyle } from "@/stores/settings-store"; +import { FONT_SIZE_SCALE } from "@/lib/accessibility-settings"; import type { PendingEventPreview } from "./event-modal"; import { toast } from "@/stores/toast-store"; import { useCalendarLocale } from "@/hooks/use-calendar-locale"; @@ -61,6 +62,22 @@ interface CalendarMonthViewProps extends ScrollWindowViewProps { onMoveEvent?: MoveEventHandler; } +/** + * The month grid's rows are positioned in pixels, so they follow the text size + * by hand: at a fixed height large text was cut off and ran into the day number. + */ +export function monthGridMetrics(isMobile: boolean, textScale: number) { + const scale = Math.max(1, textScale); + const overlayTop = Math.round((isMobile ? 34 : 30) * scale); + // 24px chips with a mouse (WCAG 2.5.8); touch screens show dots. + const rowHeight = Math.round((isMobile ? 18 : 26) * scale); + const chipHeight = rowHeight - 2; + // A wide-screen week row fits at least three entries and the "N more" + // link, so a short window (1280x720) does not cut every day to one. + const baseRowMinHeight = isMobile ? 52 : overlayTop + 4 + 8 + 4 * rowHeight; + return { overlayTop, rowHeight, chipHeight, baseRowMinHeight }; +} + export function CalendarMonthView({ selectedDate, focus, @@ -99,13 +116,8 @@ export function CalendarMonthView({ // On mobile the month view collapses events to dots unless the user opted // into full entries via "Show time in month view" (#666). const showChips = !isMobile || showTimeInMonthView; - const overlayTop = isMobile ? 34 : 30; - // 24px chips with a mouse (WCAG 2.5.8); touch screens show dots. - const rowHeight = isMobile ? 18 : 26; - const chipHeight = rowHeight - 2; - // A wide-screen week row fits at least three entries and the "N more" - // link, so a short window (1280x720) does not cut every day to one. - const baseRowMinHeight = isMobile ? 52 : overlayTop + 4 + 8 + 4 * rowHeight; + const textScale = FONT_SIZE_SCALE[useSettingsStore((state) => state.fontSize)] ?? 1; + const { overlayTop, rowHeight, chipHeight, baseRowMinHeight } = monthGridMetrics(isMobile, textScale); const { dayHeaderKeys, getMonthGridDays,