fix(dashboard): remove right-edge dead space on landscape-tablet task pop-ups

The `.floating-window__body` resize-handle clearance gutter (FN-8015) was
carved out only for 769-1024px, so landscape iPads (1180-1366 CSS px) fell
through to the desktop contract and kept it — content stopped ~17px short of
the right edge while the left edge stayed flush.

Gate the carve-out on the input device instead of viewport width: the gutter
only protects resize hot zones a pointer can actually grab. `(pointer: coarse)`
is primary-input only, so a touchscreen laptop on a trackpad still reports
`fine` and keeps desktop clearance.

Measured at 1180px: header inset went from 1px/17px to 1px/1px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-07-26 00:00:19 -07:00
parent 106c61e6ee
commit 8b9cf3d4e8
3 changed files with 56 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Remove the dead space on the right edge of the task pop-up on landscape tablets.
category: fix
dev: The `.floating-window__body` resize-handle clearance gutter was width-gated to 769-1024px; a new `@media (pointer: coarse)` block zeroes it (and hides the resize handles) for `.floating-window--task-detail` at any width, covering iPad Air/Pro landscape at 1180-1366 CSS px.

View File

@@ -120,6 +120,22 @@ Tablet task-detail popups prioritize symmetric content insets over desktop resiz
}
}
/*
FNXC:FloatingWindow 2026-07-25-00:00:
The tablet carve-out above is width-gated at 1024px, so a landscape tablet (iPad Air/Pro report 1180-1366 CSS px) fell back to the desktop contract and kept FN-8015's `margin-inline-end: var(--space-lg)` body gutter — content stopped ~17px short of the right edge while the left edge stayed flush, reading as unexplained dead space on the right of the task pop-up.
Width cannot answer this: the gutter exists to keep a hosted scrollbar out of the east/north-east/south-east resize hot zones, which only matters when a pointer can actually grab them. Gate the carve-out on the input device instead, so every touch-primary tablet gets symmetric insets at any width. `(pointer: coarse)` is primary-input only, so a touchscreen laptop driven by a trackpad still reports `fine` and keeps desktop resize clearance.
Kept as a separate block rather than folded into the width query so the existing 769-1024px contract stays independently addressable.
*/
@media (pointer: coarse) {
.floating-window--task-detail .floating-window__body {
margin-inline-end: 0;
}
.floating-window--task-detail .floating-window__resize-handle {
display: none;
}
}
/*
FNXC:ChatModal 2026-06-22-14:49:
On mobile/narrow app viewports, opening Quick Chat should present the full Chat modal as a full-screen sheet instead of a small draggable desktop window. Scope this to the chat FloatingWindow and override the inline desktop geometry only at the mobile breakpoint; desktop pop-out behavior remains movable/resizable.

View File

@@ -198,6 +198,39 @@ describe("FloatingWindow", () => {
expect(cssRuleFor(floatingWindowCss, ".floating-window--chat.floating-window--headerless .floating-window__body")).toContain("overflow: hidden;");
});
/*
FNXC:FloatingWindow 2026-07-25-00:00:
Regression guard for the landscape-tablet right-inset gap: the width-gated
769-1024px carve-out let iPad Air/Pro landscape (1180-1366 CSS px) fall back to
the desktop contract and keep FN-8015's body gutter, so the task pop-up's
content stopped short of the right edge while the left edge stayed flush.
Assert the input-device-gated block covers the same two declarations at ANY
width, and that it stays scoped to task-detail so other floating-window callers
(whose right resize handles remain live) keep their scrollbar clearance.
*/
it("removes task-detail resize clearance on touch-primary pointers at any width", () => {
const coarseBlock = mediaBlockFor(floatingWindowCss, "(pointer: coarse)");
expect(coarseBlock).not.toBe("");
expect(cssRuleFor(coarseBlock, ".floating-window--task-detail .floating-window__body")).toContain("margin-inline-end: 0;");
expect(cssRuleFor(coarseBlock, ".floating-window--task-detail .floating-window__resize-handle")).toContain("display: none;");
// The carve-out is task-detail only: every other shared caller keeps the gutter.
for (const callerClass of [
"floating-window--automation",
"floating-window--mission-interview",
"floating-window--pr-create",
"floating-window--file-browser",
"floating-window--workflow-editor",
"artifacts-gallery-window",
]) {
expect(cssRulesForClass(coarseBlock, callerClass), callerClass).toHaveLength(0);
}
// No width bound may creep back into the coarse-pointer query.
expect(floatingWindowCss).toContain("@media (pointer: coarse) {");
});
it("removes only tablet task-detail resize clearance and handles for empty and populated popups", () => {
const tabletBlock = mediaBlockFor(floatingWindowCss, "(min-width: 769px) and (max-width: 1024px)");
const mobileBlock = mediaBlockFor(floatingWindowCss, "(max-width: 768px)");