feat(web): distill shell rail
This commit is contained in:
@@ -22,6 +22,12 @@ const ICON_PATHS = {
|
||||
"M11.2 2.4a1.5 1.5 0 0 1 2.1 0l.3.3a1.5 1.5 0 0 1 0 2.1L5.9 12.5l-3.2.8.8-3.2z",
|
||||
"M10.1 3.5l2.4 2.4",
|
||||
],
|
||||
cog: [
|
||||
"M8 5.2a2.8 2.8 0 1 0 0 5.6 2.8 2.8 0 0 0 0-5.6Z",
|
||||
"M8 1.6v1.3M8 13.1v1.3M14.4 8h-1.3M2.9 8H1.6M12.5 3.5l-.9.9M4.4 11.6l-.9.9M12.5 12.5l-.9-.9M4.4 4.4l-.9-.9",
|
||||
"M10.8 3.1l.7 1.7 1.7.7-1.7.7-.7 1.7-.7-1.7-1.7-.7 1.7-.7z",
|
||||
],
|
||||
warning: ["M8 1.8l6.2 11H1.8z", "M8 5.3v3.4M8 11.2h.01"],
|
||||
} as const;
|
||||
|
||||
/** Stroke glyph on the shared 16-grid; the control's aria-label carries the meaning. */
|
||||
|
||||
+6
-16
@@ -325,7 +325,7 @@ function main() {
|
||||
library.open();
|
||||
await movieDetail.open(
|
||||
route.movieId,
|
||||
must<HTMLElement>("#nav-library"),
|
||||
must<HTMLElement>("#wordmark"),
|
||||
must<HTMLElement>("#library"),
|
||||
{
|
||||
kind: "library",
|
||||
@@ -350,7 +350,7 @@ function main() {
|
||||
library.open();
|
||||
await seriesDetail.open(
|
||||
route.seriesId,
|
||||
must<HTMLElement>("#nav-library"),
|
||||
must<HTMLElement>("#wordmark"),
|
||||
must<HTMLElement>("#library"),
|
||||
{
|
||||
kind: "library",
|
||||
@@ -396,7 +396,7 @@ function main() {
|
||||
library.open();
|
||||
await seriesDetail.open(
|
||||
seriesId,
|
||||
must<HTMLElement>("#nav-library"),
|
||||
must<HTMLElement>("#wordmark"),
|
||||
must<HTMLElement>("#library"),
|
||||
{ kind: "library" },
|
||||
);
|
||||
@@ -407,7 +407,7 @@ function main() {
|
||||
sub,
|
||||
seriesId,
|
||||
target,
|
||||
origin: must<HTMLElement>("#nav-library"),
|
||||
origin: must<HTMLElement>("#wordmark"),
|
||||
returnTo: must<HTMLElement>("#series"),
|
||||
parentRoute: { kind: "series", seriesId },
|
||||
});
|
||||
@@ -2532,7 +2532,6 @@ function libraryMain(
|
||||
): LibraryView {
|
||||
const view = must<HTMLElement>("#library");
|
||||
const deck = must<HTMLElement>("#deck");
|
||||
const nav = must<HTMLButtonElement>("#nav-library");
|
||||
const summary = must<HTMLElement>("#library-summary");
|
||||
const toggle = must<HTMLButtonElement>("#library-toggle");
|
||||
const status = must<HTMLElement>("#library-status");
|
||||
@@ -2677,25 +2676,14 @@ function libraryMain(
|
||||
}
|
||||
deck.hidden = true;
|
||||
view.hidden = false;
|
||||
nav.setAttribute("aria-pressed", "true");
|
||||
void load();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
view.hidden = true;
|
||||
nav.setAttribute("aria-pressed", "false");
|
||||
sequence += 1;
|
||||
}
|
||||
|
||||
// §9.7: the library is the homepage — the bottom layer. There is nothing
|
||||
// beneath it, so the nav control never toggles off and Esc has no handler.
|
||||
nav.addEventListener("click", () => {
|
||||
if (view.hidden) {
|
||||
navigate({ kind: "library" });
|
||||
open();
|
||||
}
|
||||
});
|
||||
|
||||
toggle.addEventListener("click", () => {
|
||||
showAll = !showAll;
|
||||
render();
|
||||
@@ -4128,6 +4116,7 @@ function queuesMain(movieDetail: MovieView, views: HideableView[], goHome: () =>
|
||||
const view = must<HTMLElement>("#queues");
|
||||
const deck = must<HTMLElement>("#deck");
|
||||
const nav = must<HTMLButtonElement>("#nav-queues");
|
||||
nav.prepend(icon("warning"));
|
||||
const badge = must<HTMLElement>("#queues-count");
|
||||
const summary = must<HTMLElement>("#queues-summary");
|
||||
const status = must<HTMLElement>("#queues-status");
|
||||
@@ -4167,6 +4156,7 @@ function queuesMain(movieDetail: MovieView, views: HideableView[], goHome: () =>
|
||||
}
|
||||
|
||||
function paintBadge(total: number) {
|
||||
nav.hidden = total === 0;
|
||||
badge.hidden = total === 0;
|
||||
badge.textContent = total === 0 ? "" : String(total);
|
||||
}
|
||||
|
||||
@@ -206,6 +206,7 @@ export function settingsMain(views: { hide: () => void }[], goHome: () => void):
|
||||
const view = must<HTMLElement>("#settings");
|
||||
const deck = must<HTMLElement>("#deck");
|
||||
const nav = must<HTMLButtonElement>("#nav-settings");
|
||||
nav.append(icon("cog"));
|
||||
const summary = must<HTMLElement>("#settings-summary");
|
||||
const status = must<HTMLElement>("#settings-status");
|
||||
const rootsSection = must<HTMLElement>("#group-roots");
|
||||
|
||||
+14
-14
@@ -142,6 +142,7 @@ body {
|
||||
|
||||
/* contents share the deck's column; the panel itself stays full-bleed */
|
||||
.rail-inner {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-6);
|
||||
@@ -178,8 +179,6 @@ body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
/* the verdict line used to absorb the slack; without it the readout
|
||||
needs to claim the right edge itself */
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@@ -529,9 +528,11 @@ body {
|
||||
/* ---- unified search (§9.2) ------------------------------------------- */
|
||||
|
||||
.rail-search {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
width: min(30rem, calc(100% - 20rem));
|
||||
max-width: 30rem;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -1337,10 +1338,6 @@ body {
|
||||
|
||||
/* ---- library view (§4.2) ---------------------------------------------- */
|
||||
|
||||
.rail-nav {
|
||||
flex: none;
|
||||
}
|
||||
|
||||
/* the library's master line: total readout left, the one §4.2 toggle right */
|
||||
.library-bar {
|
||||
margin: 0 0 var(--space-6);
|
||||
@@ -1639,6 +1636,10 @@ body {
|
||||
color: var(--signal-warn);
|
||||
}
|
||||
|
||||
.rail #nav-queues[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.queue-note {
|
||||
margin: var(--space-2) var(--space-1) 0;
|
||||
font-size: var(--text-xs);
|
||||
@@ -1901,6 +1902,7 @@ body {
|
||||
|
||||
@media (max-width: 46rem) {
|
||||
.rail-inner {
|
||||
position: static;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--space-3) var(--space-4);
|
||||
}
|
||||
@@ -1919,15 +1921,13 @@ body {
|
||||
}
|
||||
|
||||
.rail-search {
|
||||
position: relative;
|
||||
left: auto;
|
||||
width: auto;
|
||||
order: 4;
|
||||
flex-basis: 100%;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
/* deterministic first row: identity, views, then meta pushed right —
|
||||
never re-wrapped by content or scrollbar changes */
|
||||
.rail-nav {
|
||||
order: 2;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.rail-meta {
|
||||
|
||||
Reference in New Issue
Block a user