Dialogs scroll inside themselves on a phone: nothing squeezed, clear of the status bar, buttons pinned
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
a446a03b7d
commit
a229f2b597
@@ -348,6 +348,17 @@ and a regression of Escape everywhere, terminals, Files, sensors, alerts and dee
|
||||
and menu: widget picker, machine menu, rule editor, Power, New stack, and that Escape on
|
||||
"Delete the rule?" deletes nothing.
|
||||
|
||||
10. ✅ **Phone: the bottom of the New container dialog could not be reached** (Mitchell, from
|
||||
his iPhone). A dialog is a column whose parts were allowed to shrink, so instead of the
|
||||
dialog scrolling, the one part with its own scrollbar — the compose preview — was
|
||||
squeezed to 22 px and everything "fitted". And `92vh` on iOS is taller than the screen
|
||||
with the address bar gone, so the top sat under the clock. Parts now keep their height
|
||||
and the dialog scrolls inside itself; it is never taller than the space between the
|
||||
status bar and the home indicator (safe-area insets, no `vh`); Create / Cancel — and
|
||||
any error — stay pinned at the bottom while the form scrolls. Applies to every dialog;
|
||||
measured at 390×844, 375×667 and sideways, and the picker, rule editor, token and Power
|
||||
dialogs rechecked.
|
||||
|
||||
## Checked and fine
|
||||
|
||||
All 13 pages × four machines × both sizes: no page errors, failed requests, sideways
|
||||
|
||||
@@ -93,11 +93,13 @@ export default function StackNew({ mode, onClose, onCreated }: { mode: 'stack' |
|
||||
<textarea className="mono" rows={2} value={env} onChange={(e) => setEnv(e.target.value)} placeholder={'SECRET=…'} spellCheck={false} />
|
||||
</label>
|
||||
</>}
|
||||
{err && <div className="error" style={{ whiteSpace: 'pre-wrap' }}>{err}</div>}
|
||||
<div className="svc-actions">
|
||||
<Btn className="btn on" disabled={!okName || (how === 'form' && !form.image.trim())} onClick={create(true)}>Create and deploy</Btn>
|
||||
<Btn className="btn" disabled={!okName || (how === 'form' && !form.image.trim())} onClick={create(false)}>Create only</Btn>
|
||||
<span className="spacer" /><button className="btn" onClick={close}>Cancel</button>
|
||||
<div className="modal-foot">
|
||||
{err && <div className="error" style={{ whiteSpace: 'pre-wrap' }}>{err}</div>}
|
||||
<div className="svc-actions">
|
||||
<Btn className="btn on" disabled={!okName || (how === 'form' && !form.image.trim())} onClick={create(true)}>Create and deploy</Btn>
|
||||
<Btn className="btn" disabled={!okName || (how === 'form' && !form.image.trim())} onClick={create(false)}>Create only</Btn>
|
||||
<span className="spacer" /><button className="btn" onClick={close}>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</>}
|
||||
{err && !homes && <div className="error">{err}</div>}
|
||||
|
||||
+14
-5
@@ -205,8 +205,17 @@ button { font: inherit; color: inherit; background: none; border: 0; cursor: poi
|
||||
|
||||
/* power + modal */
|
||||
.power { font-size: 15px; } .power.attn { color: var(--s2); }
|
||||
.modal-back { position: fixed; inset: 0; z-index: 50; background: rgba(0,0,0,.6); display: flex; align-items: center; justify-content: center; padding: 16px; }
|
||||
.modal { width: min(420px, 100%); background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
|
||||
/* The backdrop keeps clear of the phone's status bar and home indicator; a dialog is never taller
|
||||
than what is left, and scrolls inside itself. Its parts keep their height: in a column that
|
||||
may shrink, anything with its own scrollbar (a preview, a list) is squeezed to a sliver
|
||||
instead, and the dialog never scrolls at all. */
|
||||
.modal-back { position: fixed; inset: 0; z-index: 50; background: rgba(0,0,0,.6); display: flex; align-items: center; justify-content: center; padding: max(16px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(16px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left)); }
|
||||
.modal { --modal-bg: var(--bg2); width: min(420px, 100%); max-height: 100%; overflow-y: auto; overscroll-behavior: contain; background: var(--modal-bg); border: 1px solid var(--border); border-radius: 10px; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
|
||||
.modal > * { flex-shrink: 0; }
|
||||
/* a long dialog's buttons (and what went wrong) stay in reach while the rest scrolls */
|
||||
.modal:has(> .modal-foot) { padding-bottom: 0; }
|
||||
.modal-foot { position: sticky; bottom: 0; z-index: 1; margin: 0 -16px; padding: 12px 16px 16px; background: var(--modal-bg); border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 10px; }
|
||||
.modal-foot .error { max-height: 30vh; overflow-y: auto; }
|
||||
.modal h3 { margin: 0; font-size: 15px; }
|
||||
.modal label { display: flex; flex-direction: column; gap: 6px; font-size: 12px; }
|
||||
.modal input { padding: 9px 10px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--fg); font-size: 16px; }
|
||||
@@ -405,7 +414,7 @@ h2.section { margin: 0; font-size: 13px; font-weight: 600; color: var(--muted);
|
||||
.w-row { display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; font-size: 13px; align-items: baseline; }
|
||||
.w-row .k { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .w-row .meter { grid-column: 1 / 3; margin-top: 0; }
|
||||
.tile.add-widget { border-style: dashed; color: var(--accent2); min-height: 72px; display: flex; align-items: center; justify-content: center; cursor: pointer; }
|
||||
.modal.picker { width: min(520px, 100%); max-height: 90vh; }
|
||||
.modal.picker { width: min(520px, 100%); }
|
||||
.picker-list { overflow-y: auto; max-height: 34vh; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); }
|
||||
.picker-row { display: flex; justify-content: space-between; gap: 10px; width: 100%; padding: 7px 10px; text-align: left; font-size: 12px; border-bottom: 1px solid var(--border); }
|
||||
.picker-row:hover, .picker-row.active { background: var(--bg3); } .picker-row.active { box-shadow: inset 3px 0 0 var(--accent); }
|
||||
@@ -452,7 +461,7 @@ a.btn { text-decoration: none; display: inline-flex; align-items: center; }
|
||||
/* HUD: light drawn on glass — hairlines, no fills, thin type */
|
||||
[data-theme="hud"] .tile, [data-theme="hud"] .card, [data-theme="hud"] .box { background: rgba(53, 214, 255, .03); border-color: rgba(53, 214, 255, .28); border-radius: 2px; box-shadow: 0 0 0 1px rgba(53, 214, 255, .05), inset 0 0 24px rgba(53, 214, 255, .04); }
|
||||
/* anything that floats over the page is solid: glass on glass is two layers of text */
|
||||
[data-theme="hud"] .modal { background: #061019; border-color: rgba(53, 214, 255, .45); border-radius: 2px; box-shadow: 0 0 0 1px rgba(53, 214, 255, .08), 0 0 40px rgba(53, 214, 255, .12), inset 0 0 24px rgba(53, 214, 255, .04); }
|
||||
[data-theme="hud"] .modal { --modal-bg: #061019; border-color: rgba(53, 214, 255, .45); border-radius: 2px; box-shadow: 0 0 0 1px rgba(53, 214, 255, .08), 0 0 40px rgba(53, 214, 255, .12), inset 0 0 24px rgba(53, 214, 255, .04); }
|
||||
[data-theme="hud"] .modal-back { background: rgba(0, 3, 6, .82); }
|
||||
[data-theme="hud"] .tile::before, [data-theme="hud"] .card::before { content: ''; position: absolute; top: -1px; left: -1px; width: 12px; height: 12px; border-top: 2px solid var(--accent); border-left: 2px solid var(--accent); }
|
||||
[data-theme="hud"] .tile, [data-theme="hud"] .card { position: relative; }
|
||||
@@ -503,7 +512,7 @@ pre.diff .add { color: var(--ok); background: color-mix(in srgb, var(--ok) 12%,
|
||||
.env-masked { position: relative; display: flex; flex-direction: column; flex: 1; } .env-masked pre { margin: 0; min-height: 30vh; opacity: .8; } .env-masked .btn { position: absolute; top: 10px; right: 10px; }
|
||||
|
||||
/* new stack / new container */
|
||||
.modal.stack-new { width: min(680px, 100%); max-height: 92vh; overflow-y: auto; }
|
||||
.modal.stack-new { width: min(680px, 100%); }
|
||||
.stack-new textarea, .stack-new select, .stack-new input:not([type=checkbox]) { padding: 8px 10px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--fg); font-size: 14px; width: 100%; box-sizing: border-box; }
|
||||
.stack-new textarea.mono, .stack-new input.mono { font-family: var(--mono); font-size: 13px; } .stack-new textarea { resize: vertical; }
|
||||
.stack-new .two { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } .stack-new .stack-editor { min-height: 32vh; }
|
||||
|
||||
Reference in New Issue
Block a user