android: the phone turned sideways — the player beside itself, the chrome cut down

The phone UI was drawn portrait-first and had never been looked at in
landscape. The player sheet was the casualty: its cover is a square sized by
width, so at 915×411 it came out 879px tall and the title, the scrubber, the
transport and the face buttons all sat below the bottom of a sheet that does
not scroll — a corner of the artwork and no way to pause. Sideways the sheet
is two columns now, the cover sized by height beside the controls, with a
lyrics or queue face taking the cover's column; the nav and the mini bar come
down to 48 and 60dp, the artist hero becomes the banner the desktop's hero has
always been rather than 300px of a 411px screen, the record head puts the
cover beside the title, and the shell reads the side insets the cutout and the
gesture pill take when the phone is on its side. The walk turns the phone over
and back on its own: `{ view: [w, h] }` is a step kind now, and the steps
assert what used to be off the screen.
This commit is contained in:
KeelrLeek committed 2026-09-14 00:14:23 -05:00
1 parent aff29aba5c
commit 9df162360e
5 files changed
+228 -3

No files matched your search

+1 -1
View File
@@ -141,7 +141,7 @@
<div class="amb-tint"></div>
<div class="grain"></div>
</div>
<div class="np">
<div class="np" class:small>
<div class="np-head">
<button class="iconbtn" onclick={closeSheet} aria-label="Close"><Icon name="chevron-down" size={24} /></button>
<button class="np-ctx" onclick={goAlbum} aria-label="Go to the record">
+4
View File
@@ -57,6 +57,10 @@
/* Android's own insets: the status bar above, the gesture handle below. */
--inset-top: env(safe-area-inset-top, 0px);
--inset-bottom: env(safe-area-inset-bottom, 0px);
/* landscape moves the cutout and the gesture pill to the SIDES, and
viewport-fit=cover puts our content under both */
--inset-left: env(safe-area-inset-left, 0px);
--inset-right: env(safe-area-inset-right, 0px);
--top-h: calc(var(--bar-h) + var(--inset-top));
/* ── motion: real springs, sampled ────────────────────────────────────
+92
View File
@@ -1415,3 +1415,95 @@ html[data-motion="off"] *, html[data-motion="off"] *::before, html[data-motion="
.sy-foot .iconbtn { width: auto; min-width: var(--tap); padding: 0 12px; border-radius: var(--r-pill); font-size: 13px; font-weight: 750; }
.sy-foot .iconbtn:disabled { opacity: 0.4; }
.sy-save { flex: 1; }
/* ── the phone turned sideways ────────────────────────────────────────────
The activity declares no screenOrientation and handles orientation and
screenSize itself, so a rotation is a RESIZE: no state is lost and the
layout is the only thing that has to answer. Two queries do it. The player
sheet is the surface whose portrait shape cannot survive a wide viewport —
its artwork is a square sized by WIDTH, so at 915x411 the cover came out
879px tall and the title, the lane, the transport and the face buttons all
sat below the bottom of a sheet that does not scroll. That is aspect, not
height, so its rule keys off orientation alone and a tablet gets it too;
everything under it is a phone-sized query.
These rules are appended, and the order is load-bearing: the side-inset
longhands below have to come after .gbar's padding shorthand, .mini's
left/right and .toast's left/right to win at equal specificity. */
/* the side insets: the cutout and the gesture pill, from the edges */
.gbar { padding-left: calc(6px + var(--inset-left)); padding-right: calc(8px + var(--inset-right)); }
.nav { padding-left: var(--inset-left); padding-right: var(--inset-right); }
.mini { left: calc(8px + var(--inset-left)); right: calc(8px + var(--inset-right)); }
.screen { padding-left: var(--inset-left); padding-right: var(--inset-right); }
.np { padding-left: var(--inset-left); padding-right: var(--inset-right); }
.halfsheet { padding-left: var(--inset-left); padding-right: var(--inset-right); }
.syncroom { padding-left: var(--inset-left); padding-right: var(--inset-right); }
.toast { left: calc(12px + var(--inset-left)); right: calc(12px + var(--inset-right)); }
/* ── the player sheet, beside itself ─────────────────────────────────── */
@media (orientation: landscape) {
.np {
display: grid;
grid-template-columns: minmax(0, 46%) minmax(0, 1fr);
grid-template-rows: auto minmax(0, 1fr) auto auto auto auto;
grid-template-areas:
"head head"
"left slack"
"left meta"
"left scrub"
"left trans"
"left foot";
column-gap: 6px;
/* insurance for a viewport shorter than the controls themselves —
the keyboard up on a small phone — where the sheet would clip */
overflow-y: auto;
overscroll-behavior: contain;
}
.np-head { grid-area: head; }
.np-art { grid-area: left; padding: 10px 4px 10px var(--pad); }
/* the square is sized by whichever is smaller, the column or the height */
.np-frame { width: min(100%, calc(100vh - var(--inset-top) - var(--inset-bottom) - 92px)); }
.np-spacer { grid-area: slack; padding: 10px var(--pad) 0; justify-content: center; }
.np-face { grid-area: left; }
.np-meta { grid-area: meta; padding-top: 2px; }
.np-scrub { grid-area: scrub; padding-top: 8px; }
.np-transport { grid-area: trans; padding-top: 10px; justify-self: center; width: min(100%, 430px); }
.np-foot { grid-area: foot; padding-top: 8px; }
/* a face is up: it takes the artwork's column and the thumbnail goes —
the record is already the ground behind the whole sheet */
.np.small { grid-template-columns: minmax(0, 1fr) minmax(0, 430px); }
.np.small .np-art { display: none; }
}
/* ── a phone turned sideways: 411 pixels of height to spend ───────────── */
@media (orientation: landscape) and (max-height: 560px) {
/* the nav comes down to Android's own 48dp minimum and the mini bar to a
60dp row over the same lane strip: 22 pixels back, 46% of the height as
chrome down to 40% */
:root { --nav-h: 48px; --mini-h: 60px; }
.nav button .gl { height: 22px; }
.nav button .lb { font-size: 9.5px; }
.nav button .pill { top: 3px; height: 24px; }
.mini { padding-bottom: 24px; }
.mini .art { width: 34px; height: 34px; }
.mini .mini-lane { bottom: 5px; }
/* the hero stops being a portrait and becomes the banner the desktop's
hero has always been */
.hero { height: 190px; }
.hero-name { font-size: 27px; }
.hero-logo { max-height: 64px; }
/* the record head puts the cover beside the title, again the desktop's
own shape; .pl needs naming because its own rule is more specific */
.rec-head { flex-direction: row; align-items: center; gap: 22px; padding: calc(var(--bar-h) + 12px) var(--pad) 4px; }
.rec-head .rec-cover, .rec-head.pl .rec-cover { width: 34%; max-width: 240px; }
.rec-meta { text-align: left; }
.rec-title { margin-top: 0; }
.rec-chips { justify-content: flex-start; }
.rec-acts { justify-content: flex-start; padding: 14px 0 4px; }
/* 76% of 411 is 312; a half sheet may take all but a strip */
.halfsheet { max-height: calc(100% - 36px); }
}