feat: fix portrait mode design in pwa

Task #44 completed by ClaudeQueue

ClaudeQueue
This commit is contained in:
Claude Worker
2026-06-30 15:36:12 +00:00
parent 136e21f1fa
commit fc61defba5
7 changed files with 1336 additions and 40 deletions

View File

@@ -2005,13 +2005,13 @@ function applyPortraitPwaClass() {
}
}
// Scroll the player pane to the top of the scrollable .body so it's visible.
// Only fires when in portrait-standalone mode where .body is the scroll root.
// Scroll the list-pane to the top so the player content is at the start of the
// list area. In portrait mode, .list-pane is the scroll container (not .body).
function scrollPlayerIntoViewPortrait() {
if (!isPortraitPWA()) return;
const body = document.querySelector('.body');
if (body) {
body.scrollTo({ top: 0, behavior: 'smooth' });
const listPane = document.querySelector('.list-pane');
if (listPane) {
listPane.scrollTo({ top: 0, behavior: 'smooth' });
}
}

View File

@@ -1650,10 +1650,11 @@ input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.25); }
/* --- Body: vertical stack (player above list) -------------------------- */
.body {
flex-direction: column;
overflow-y: auto;
overflow-x: hidden;
/* Let the body scroll instead of individual panes */
height: 100%;
overflow: hidden;
/* Body itself does NOT scroll — player-pane is fixed height,
list-pane takes remaining space and scrolls independently.
This keeps the player always visible and gives the list/settings
the full remaining viewport to scroll in. */
}
/* --- Player pane: full width, compact vertical padding ----------------- */
@@ -1662,7 +1663,7 @@ input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.25); }
width: 100%;
padding: 14px calc(14px + env(safe-area-inset-right)) 14px
calc(14px + env(safe-area-inset-left));
overflow-y: visible; /* scroll is on .body */
overflow-y: visible;
}
/* Player stage: keep 16:9 aspect ratio, fill viewport width */
@@ -1689,24 +1690,31 @@ input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.25); }
gap: 6px;
}
/* --- List pane: full width below player, no side border ---------------- */
/* --- List pane: full width below player, fills remaining height, scrolls independently --- */
.list-pane {
flex: none;
flex: 1;
min-height: 0; /* required for flex children to shrink below content size */
width: 100%;
border-left: none;
border-top: 1px solid var(--line-soft);
/* Give it enough room; body scrolls */
min-height: 40vh;
overflow-y: visible;
overflow-y: auto;
overflow-x: hidden;
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
/* Pad bottom to clear the fixed mini-bar (~52px) plus safe area */
padding-bottom: calc(60px + env(safe-area-inset-bottom));
}
/* Cards list: scroll within list-pane in portrait */
/* Cards list: unconstrained height — list-pane is now the scroll container */
.cards {
max-height: 50vh;
overflow-y: auto;
padding-bottom: calc(28px + env(safe-area-inset-bottom));
max-height: none;
overflow-y: visible;
padding-bottom: 0;
}
/* Settings panel: ensure full accessibility with bottom clearance for mini-bar */
.settings {
padding-bottom: calc(20px + env(safe-area-inset-bottom));
}
/* --- Mini now-playing bar: respect home indicator ---------------------- */
@@ -1769,10 +1777,9 @@ input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.25); }
* that can't be expressed purely with CSS media queries).
* ========================================================================== */
.portrait-pwa .body {
/* Reinforce scroll snapping so the player stays at the viewport top after
JS scrolls to it; helps on iOS Safari where scroll restoration can fight. */
scroll-snap-type: y proximity;
/* Body does not scroll in portrait — list-pane handles scrolling.
Scroll-snap is intentionally omitted since there is no scroll root here. */
}
.portrait-pwa .player-pane {
scroll-snap-align: start;
/* Player pane is always visible at top; no snap needed. */
}