fix: show toasts beside the calendar's event and task panels instead of over their title and Save

This commit is contained in:
Linus Rath
2026-11-04 13:54:22 +01:00
parent cf844ff4d7
commit b269d2f2ed
3 changed files with 52 additions and 2 deletions
+8
View File
@@ -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;
@@ -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}<TaskModal/);
});
});
+2 -2
View File
@@ -2412,7 +2412,7 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps =
on small screens, so the week keeps its width (pim-25). Above
the views' sticky headers (z-50) inside this isolated row. */}
{!isMobile && showEventModal && (
<div data-testid="event-panel" className="absolute inset-y-0 end-0 z-[55] w-[400px] max-w-full border-s border-border bg-background shadow-xl overflow-hidden">
<div data-testid="event-panel" data-end-sheet="" className="absolute inset-y-0 end-0 z-[55] w-[400px] max-w-full border-s border-border bg-background shadow-xl overflow-hidden">
<EventModal
key={`${editEvent?.id ?? (copySource ? `copy:${copySource.id}` : 'new')}${modalStartsInEdit ? ':edit' : ''}`}
event={editEvent}
@@ -2442,7 +2442,7 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps =
{/* Desktop task panel */}
{!isMobile && showTaskModal && (
<div className="w-[400px] border-s border-border flex-shrink-0 overflow-hidden">
<div data-end-sheet="" className="w-[400px] border-s border-border flex-shrink-0 overflow-hidden">
<TaskModal
key={editTask?.id ?? 'new-task'}
task={editTask}