fix: keep the tour card off its target on phones narrower than the card

This commit is contained in:
Linus Rath
2026-11-03 05:32:33 +01:00
parent 1069c9fac0
commit 1616f9c9d7
2 changed files with 22 additions and 2 deletions
+18
View File
@@ -157,6 +157,24 @@ describe('tour targets', () => {
}
});
it('keeps the card off the target on a phone narrower than the card', () => {
const w = window.innerWidth;
const hgt = window.innerHeight;
Object.defineProperty(window, 'innerWidth', { configurable: true, value: 320 });
Object.defineProperty(window, 'innerHeight', { configurable: true, value: 568 });
try {
const fab = { top: 440, left: 247, width: 56, height: 56 };
// Measured off screen the card is at its full 360 px.
const pos = computeTooltipPosition(fab, 'right', { width: 360, height: 196 });
expect(pos.actualPlacement).toBe('top');
expect(pos.top + 196).toBeLessThanOrEqual(fab.top);
expect(pos.left).toBe(8);
} finally {
Object.defineProperty(window, 'innerWidth', { configurable: true, value: w });
Object.defineProperty(window, 'innerHeight', { configurable: true, value: hgt });
}
});
it('leaves out on a phone the steps that point into the rail or the folder drawer', () => {
const ids = (phone: boolean) =>
getTourSteps({ isDemoMode: true, supportsCalendar: true, supportsWebDAV: true, touch: phone, phone }).map((s) => s.id);
+4 -2
View File
@@ -48,7 +48,8 @@ export function computeTooltipPosition(
): { top: number; left: number; actualPlacement: string } {
const vw = window.innerWidth;
const vh = window.innerHeight;
const tw = Math.max(tooltipSize.width, 200); // minimum fallback width
// minimum fallback width; never wider than the screen, measured off screen it can be
const tw = Math.min(Math.max(tooltipSize.width, 200), vw - 16);
const th = Math.max(tooltipSize.height, 100); // minimum fallback height
// Along the side it sits on, the card slides to stay on screen: above a
@@ -384,7 +385,8 @@ export function TourOverlay() {
style={{
top: tooltipPos?.top ?? -9999,
left: tooltipPos?.left ?? -9999,
maxWidth: TOOLTIP_MAX_W,
// A margin of 8 on both sides, like the placement keeps.
maxWidth: `min(${TOOLTIP_MAX_W}px, calc(100vw - 16px))`,
transition: reducedMotion ? "none" : "opacity 200ms ease, transform 200ms ease, top 300ms ease, left 300ms ease",
pointerEvents: visible ? "auto" : "none",
}}