Merge pull request 'Make the library page header (title + search bar) fully sticky' (#14) from feature/library-sticky-header into master
This commit is contained in:
commit
3ba0de341e
7 changed files with 86 additions and 3 deletions
|
|
@ -367,6 +367,8 @@ Then put it behind your existing reverse proxy like everything else
|
|||
- [x] Library/artist grid tiles shrink fluidly on a narrow phone instead
|
||||
of a fixed 160px floor collapsing to one column per row — see
|
||||
docs/architecture.md
|
||||
- [x] Library page title now stays pinned alongside the search bar while
|
||||
scrolling, instead of just the search bar — see docs/architecture.md
|
||||
- [ ] Try a full party end-to-end with two real accounts (still the main gap)
|
||||
- [ ] Try casting to a real Chromecast (only the SDK's own bootstrap is
|
||||
confirmed here — no real device/session)
|
||||
|
|
|
|||
|
|
@ -79,7 +79,8 @@
|
|||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 3;
|
||||
padding: 14px 16px;
|
||||
height: var(--mobile-topbar-h);
|
||||
padding: 0 16px;
|
||||
background: var(--bg-header);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
--accent: #52b54b; /* Emby's theme-primary-color (hsl(116, 41.7%, 50.2%)) */
|
||||
--accent-bright: #6ccf65; /* Emby's --theme-accent-text-color-darkbg */
|
||||
--danger: #ff6b6b;
|
||||
--mobile-topbar-h: 49px; /* shell/Shell.css's .mobileTopBar - a fixed height so any other sticky element (e.g. views/library's .libraryHeader) can stack directly below it instead of guessing its rendered height */
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
|
|
|||
24
client/src/views/library/Library.css
Normal file
24
client/src/views/library/Library.css
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
/* ---- Library page header (title + search bar) - see Library.ts/html. ----
|
||||
Wraps .pageHeader and tiles.css's .searchBar (already sticky on its own)
|
||||
in one sticky block so the title stays put too, instead of scrolling
|
||||
away while the search bar stays behind - reported directly. Needs its
|
||||
own opaque background since .pageHeader's <h1> has none - without it,
|
||||
grid tiles scrolling underneath would show through the title text once
|
||||
stuck. */
|
||||
.libraryHeader {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 2;
|
||||
background: var(--bg);
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
/* Below 720px, shell/Shell.css's own sticky .mobileTopBar already occupies
|
||||
top:0 - stacking this header at top:0 too would have both fighting over
|
||||
the same spot, with this one (later in paint order) covering the app's
|
||||
brand bar. Stick it right below instead. */
|
||||
@media (max-width: 720px) {
|
||||
.libraryHeader {
|
||||
top: var(--mobile-topbar-h);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
<div class="libraryHeader">
|
||||
<div class="pageHeader"><h1></h1></div>
|
||||
<input id="searchInput" class="searchBar" type="search" placeholder="Rechercher dans cette bibliothèque..." />
|
||||
</div>
|
||||
<p class="hint searchEmpty hide">Aucun résultat.</p>
|
||||
<div id="grid" class="grid"><p class="hint"><span class="spinner"></span>Chargement...</p></div>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import './Library.css';
|
||||
import html from './Library.html';
|
||||
import { getArtists, getLibraries, getLibraryItems } from '../../api/embyApi';
|
||||
import { createParty } from '../../api/party';
|
||||
|
|
|
|||
|
|
@ -3911,6 +3911,58 @@ from 320 to 393px now gets 2 columns (previously 1), 430px gets 3, and
|
|||
768/1200px match what the old fixed `160px` floor already gave -
|
||||
confirmed empirically, not assumed from the formula alone.
|
||||
|
||||
## The library header wasn't fully sticky: the title still scrolled away
|
||||
|
||||
"A sticky search bar" (above) only ever made the `<input>` itself
|
||||
sticky - asked for directly again, this time to also keep the page
|
||||
title (`.pageHeader`'s `<h1>`) pinned alongside it on `views/library`,
|
||||
so both stay visible together while a long grid scrolls underneath
|
||||
instead of just the search box.
|
||||
|
||||
New `.libraryHeader` wrapper (`views/library/Library.css` - the one
|
||||
view of this shape that had no dedicated stylesheet yet, everything
|
||||
borrowed from `tiles.css`/`base.css`) around the existing `.pageHeader`
|
||||
+ `.searchBar` pair, `position: sticky; top: 0` on the wrapper itself
|
||||
with its own opaque `var(--bg)` background - the `<h1>` has none of its
|
||||
own, so without this, tiles scrolling underneath would show through the
|
||||
title text once stuck. `.searchBar` keeps its own pre-existing
|
||||
`position: sticky; top: 0` from `tiles.css` unchanged (still needed as-is
|
||||
on `views/artist`/`views/album`, which don't get this wrapper); nested
|
||||
inside an already-stuck ancestor that isn't itself scrolling, it's
|
||||
inert rather than conflicting.
|
||||
|
||||
Scoped to `views/library` only, not `tiles.css`'s shared `.pageHeader` -
|
||||
`views/home` uses that same class for a plain, non-sticky title, and
|
||||
`views/artist`/`views/album` have since moved to their own hero headers
|
||||
(see "Music UI rework" above), not `.pageHeader` at all.
|
||||
|
||||
One real collision worth catching: below 720px, `shell/Shell.css`'s own
|
||||
`.mobileTopBar` is *also* `position: sticky; top: 0` (the app's brand
|
||||
bar, sitting above `.mainContent` as a sibling, not an ancestor) - the
|
||||
pre-existing sticky `.searchBar` already raced it for the same spot,
|
||||
just narrowly enough (one slim input) not to get reported. Stacking a
|
||||
whole title+search block at `top: 0` too would have properly covered
|
||||
it, later in paint order. `.mobileTopBar` got an explicit
|
||||
`height: var(--mobile-topbar-h)` (new `base.css` token, `49px` -
|
||||
replacing its previous padding-derived auto height with a fixed one
|
||||
anything else can reliably stack against), and `.libraryHeader` sticks
|
||||
to `top: var(--mobile-topbar-h)` instead of `0` under that same 720px
|
||||
breakpoint - directly below the brand bar instead of underneath it.
|
||||
|
||||
Verified: full `typecheck`/`build` (client only). No Emby session is
|
||||
needed to see either state, so checked directly: real compiled
|
||||
`app.css` loaded (same-origin, from the running dev server) into two
|
||||
`<iframe>`s - 1000px and 375px wide, each its own independent viewport
|
||||
for the 720px media query, the same workaround this sandbox's own
|
||||
broken `resize_window` emulation has needed all session - reproducing
|
||||
`Shell.html`'s `.mobileTopBar`/`.mainContent` plus `Library.html`'s new
|
||||
markup and a couple dozen dummy tiles, then scrolled deep into the grid
|
||||
in both and read `getBoundingClientRect()` back: on the 1000px frame
|
||||
the title and search bar both stayed at the viewport top, tiles
|
||||
scrolling underneath, opaque background confirmed; on the 375px frame
|
||||
`.libraryHeader`'s top edge landed exactly at `.mobileTopBar`'s bottom
|
||||
edge (49px) with zero overlap, both bars' text still visible together.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- Playback always goes through `hls.js` against whatever Emby's
|
||||
|
|
|
|||
Loading…
Reference in a new issue