fix(dashboard): mobile rendering for resizable modals

The Settings, Workflow Steps, Automations (and friends) modals all carried
desktop `min-width: 480-520px` constraints from the resize work. On phones
that pushed them off-screen, and the overlay's 10vh top padding plus a
fractional `height: 80vh` left awkward gaps top and bottom.

Apply the same `@media (max-width: 768px)` full-screen-sheet treatment
that File Browser already had to every resize-aware modal: drop the
overlay padding, set width/height to `100vw`/`100dvh`, zero out the
min-* / max-* constraints, and disable `resize` (touchscreens can't grab
the corner grip anyway).

Also tightened the existing File Browser and GitHub Import overrides to
match (`min-width: 0`, `min-height: 0`, `resize: none`).

For TaskDetailModal the mobile rules go inside the existing first
`@media (max-width: 768px)` block to keep the FN-1331 detail-body
padding regression test happy (it captures from the first 768px media
query greedily).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-04-27 18:10:24 -07:00
parent 1fe59be960
commit 3b3d456ca8
8 changed files with 147 additions and 24 deletions

View File

@@ -894,12 +894,15 @@
.modal.file-browser-modal {
width: 100vw;
min-width: 0;
height: 100dvh;
min-height: 0;
max-width: 100vw;
max-height: 100dvh;
margin: 0;
border: none;
border-radius: 0;
resize: none;
}
.file-browser-body {

View File

@@ -740,12 +740,15 @@
.modal.github-import-modal {
width: 100vw;
min-width: 0;
max-width: 100vw;
height: 100dvh;
min-height: 0;
max-height: 100dvh;
margin: 0;
border: none;
border-radius: 0;
resize: none;
}
.github-import-modal__body {

View File

@@ -265,6 +265,26 @@
/* Mobile: stack — only one pane visible at a time */
@media (max-width: 720px) {
/* Full-screen sheet — drop overlay padding so the modal fills the
viewport instead of being pushed below it, and disable resize since
touchscreen users can't drag the corner grip anyway. */
.modal-overlay:has(.planning-modal) {
padding-top: 0;
align-items: stretch;
justify-content: stretch;
}
.modal.planning-modal {
width: 100vw;
min-width: 0;
max-width: 100vw;
height: 100dvh;
min-height: 0;
max-height: 100dvh;
margin: 0;
border: none;
border-radius: 0;
resize: none;
}
.planning-modal-body--split {
flex-direction: column;
}

View File

@@ -70,70 +70,71 @@
transition: background var(--transition-fast);
}
/* Edge handles */
/* Edge handles — inset matches corner handle size so they don't overlap. */
.quick-chat-resize-handle[data-resize-direction="n"] {
cursor: n-resize;
top: 0;
left: 10px;
right: 10px;
left: 16px;
right: 16px;
height: 6px;
}
.quick-chat-resize-handle[data-resize-direction="s"] {
cursor: s-resize;
bottom: 0;
left: 10px;
right: 10px;
left: 16px;
right: 16px;
height: 6px;
}
.quick-chat-resize-handle[data-resize-direction="e"] {
cursor: e-resize;
top: 10px;
top: 16px;
right: 0;
bottom: 10px;
bottom: 16px;
width: 6px;
}
.quick-chat-resize-handle[data-resize-direction="w"] {
cursor: w-resize;
top: 10px;
top: 16px;
left: 0;
bottom: 10px;
bottom: 16px;
width: 6px;
}
/* Corner handles */
/* Corner handles — sized to clear the panel's 12px border-radius so the
diagonal hit target reaches outside the curve. */
.quick-chat-resize-handle[data-resize-direction="nw"] {
cursor: nw-resize;
top: 0;
left: 0;
width: 10px;
height: 10px;
width: 16px;
height: 16px;
}
.quick-chat-resize-handle[data-resize-direction="ne"] {
cursor: ne-resize;
top: 0;
right: 0;
width: 10px;
height: 10px;
width: 16px;
height: 16px;
}
.quick-chat-resize-handle[data-resize-direction="sw"] {
cursor: sw-resize;
bottom: 0;
left: 0;
width: 10px;
height: 10px;
width: 16px;
height: 16px;
}
.quick-chat-resize-handle[data-resize-direction="se"] {
cursor: se-resize;
bottom: 0;
right: 0;
width: 10px;
height: 10px;
width: 16px;
height: 16px;
}
/* Subtle hover accent on edge handles */
@@ -157,6 +158,20 @@
);
}
/* Subtle hover accent on corner handles — small radial dot that hints at
the diagonal grip without competing with the panel's rounded border. */
.quick-chat-resize-handle[data-resize-direction="nw"]:hover,
.quick-chat-resize-handle[data-resize-direction="ne"]:hover,
.quick-chat-resize-handle[data-resize-direction="sw"]:hover,
.quick-chat-resize-handle[data-resize-direction="se"]:hover {
background: radial-gradient(
circle at center,
color-mix(in srgb, var(--border) 70%, transparent) 0%,
color-mix(in srgb, var(--border) 30%, transparent) 50%,
transparent 75%
);
}
.quick-chat-panel-header {
display: flex;
align-items: center;

View File

@@ -3213,12 +3213,36 @@
.modal.gm-modal {
width: 100vw;
min-width: 0;
max-width: 100vw;
height: 100dvh;
min-height: 0;
max-height: 100dvh;
margin: 0;
border: none;
border-radius: 0;
resize: none;
}
/* Same treatment for the Automations modal — same min-width: 480px would
otherwise force it wider than narrow viewports. */
.modal-overlay:has(.automation-modal) {
padding-top: 0;
align-items: stretch;
justify-content: stretch;
}
.modal.automation-modal {
width: 100vw;
min-width: 0;
max-width: 100vw;
height: 100dvh;
min-height: 0;
max-height: 100dvh;
margin: 0;
border: none;
border-radius: 0;
resize: none;
}
.gm-layout {

View File

@@ -68,6 +68,32 @@
resize: both;
}
/* Mobile: full-screen sheet. The desktop `min-width: 520px` was forcing the
modal wider than narrow viewports, pushing it off-screen; the desktop
`height: 80vh` left awkward strips of overlay above and below. Drop the
overlay's default top padding so the modal actually fills the viewport,
and disable resize (touchscreen users can't drag the grip anyway). */
@media (max-width: 768px) {
.modal-overlay:has(.settings-modal) {
padding-top: 0;
align-items: stretch;
justify-content: stretch;
}
.modal.settings-modal {
width: 100vw;
min-width: 0;
max-width: 100vw;
height: 100dvh;
min-height: 0;
max-height: 100dvh;
margin: 0;
border: none;
border-radius: 0;
resize: none;
}
}
/* === Settings Layout === */
.settings-modal-heading {
display: flex;

View File

@@ -742,6 +742,28 @@
.detail-move-split-btn__chevron {
min-width: calc(var(--space-md) + var(--space-sm));
}
/* Full-screen sheet on mobile. Desktop `min-width: 480px` would otherwise
push the modal off narrow viewports; overlay padding-top leaves awkward
gaps. Resize is disabled (touchscreens can't drag the grip). */
.modal-overlay:has(.task-detail-modal) {
padding-top: 0;
align-items: stretch;
justify-content: stretch;
}
.modal.task-detail-modal {
width: 100vw;
min-width: 0;
max-width: 100vw;
height: 100dvh;
min-height: 0;
max-height: 100dvh;
margin: 0;
border: none;
border-radius: 0;
resize: none;
}
}
.detail-actions-menu-item-danger {

View File

@@ -408,15 +408,25 @@
}
@media (max-width: 768px) {
.workflow-step-manager-modal {
width: 100%;
max-width: 100%;
height: 100vh;
/* Full-screen sheet on mobile — drop the overlay's top padding so the
modal fills the viewport instead of being pushed below it. */
.modal-overlay:has(.workflow-step-manager-modal) {
padding-top: 0;
align-items: stretch;
justify-content: stretch;
}
.modal.workflow-step-manager-modal {
width: 100vw;
min-width: 0;
max-width: 100vw;
height: 100dvh;
max-height: 100vh;
min-height: 0;
max-height: 100dvh;
border-radius: 0;
margin: 0;
border: none;
border-radius: 0;
resize: none;
}
.wfm-body {