From b269d2f2ed5c2184f29064238e999e208ee3f003 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Wed, 4 Nov 2026 13:54:22 +0100 Subject: [PATCH] fix: show toasts beside the calendar's event and task panels instead of over their title and Save --- app/globals.css | 8 ++++ .../toast-beside-sheet-ux-p2-pim.test.tsx | 42 +++++++++++++++++++ components/calendar/calendar-app.tsx | 4 +- 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 components/calendar/__tests__/toast-beside-sheet-ux-p2-pim.test.tsx diff --git a/app/globals.css b/app/globals.css index 6ecc0f095..b99ba0f7e 100644 --- a/app/globals.css +++ b/app/globals.css @@ -638,6 +638,14 @@ html[data-window-controls] [data-own-window-close] { display: none; } +/* + * A sheet docked at the window's end (the calendar's event and task panels) has its title + * and close at the top and Save at the foot: toasts stand beside it, not on it (pim-p2-19). + */ +body:has([data-end-sheet]) [data-toast-container] { + inset-inline-end: calc(var(--end-sheet-width, 400px) + 1.25rem); +} + /* Toasts that step out of the focus's way go to the top end corner: below the controls there. */ html[data-window-controls] [data-toast-container][data-dodging] { top: calc(var(--titlebar-row-height) + 0.75rem) !important; diff --git a/components/calendar/__tests__/toast-beside-sheet-ux-p2-pim.test.tsx b/components/calendar/__tests__/toast-beside-sheet-ux-p2-pim.test.tsx new file mode 100644 index 000000000..148a6a4e5 --- /dev/null +++ b/components/calendar/__tests__/toast-beside-sheet-ux-p2-pim.test.tsx @@ -0,0 +1,42 @@ +import { readFileSync } from 'fs'; +import path from 'path'; +import { describe, expect, it } from 'vitest'; + +// pim-p2-19: toasts at the top right covered the event sheet's title and +// close button; at the bottom right they covered its Save. They stand beside +// a sheet docked at the window's end now. jsdom has no layout, so the rule is +// checked through the cascade: the stylesheet's own rule, applied in jsdom. + +const css = readFileSync(path.join(process.cwd(), 'app', 'globals.css'), 'utf8'); + +function endSheetRule(): string { + const match = /body:has\(\[data-end-sheet\]\) \[data-toast-container\] \{[^}]*\}/.exec(css); + expect(match, 'no end-sheet rule for toasts in globals.css').not.toBeNull(); + return match![0]; +} + +describe('toasts beside an end sheet', () => { + it('move the stack past the sheet while one is open', () => { + const style = document.createElement('style'); + style.textContent = endSheetRule(); + document.head.appendChild(style); + const container = document.createElement('div'); + container.setAttribute('data-toast-container', ''); + document.body.appendChild(container); + expect(getComputedStyle(container).getPropertyValue('inset-inline-end')).not.toContain('400px'); + + const sheet = document.createElement('div'); + sheet.setAttribute('data-end-sheet', ''); + document.body.appendChild(sheet); + expect(getComputedStyle(container).getPropertyValue('inset-inline-end')).toBe('calc(var(--end-sheet-width, 400px) + 1.25rem)'); + style.remove(); + container.remove(); + sheet.remove(); + }); + + it('marks the calendar event and task panels as end sheets', () => { + const app = readFileSync(path.join(process.cwd(), 'components', 'calendar', 'calendar-app.tsx'), 'utf8'); + expect(app).toMatch(/data-testid="event-panel" data-end-sheet=""/); + expect(app).toMatch(/data-end-sheet="" className="w-\[400px\][^"]*"[\s\S]{0,40} +
+