Files
siftlode/frontend/src/components/ui/pageHeading.ts
T
peter eddeca82d3 feat(design): the page band (B4) — one h1 per page, section headings, skip to content, filters fold on a short window (E28 S3d4)
- PageShell names the page with a visually hidden h1; a view with its own title renders it as
  PageHeading and the hidden one steps aside (contract: no hand <h1> inside the shell).
- Section captions are SectionLabel headings (h2, h3 in a dialog), ui/form Section included.
- "Skip to content" is the first Tab stop and focuses the scroller's <main>.
- Below 600px of height the band's filter row folds into "Filters · n" (Feed, Plex, server log),
  the same row shown in place.
- The band holds controls only: Downloads and Notifications lose their title cards, the Config and
  channel-discovery intros scroll with the content, the Stats tabs and the audit pager join the band,
  and the server log's toolbar sticks with the fade under it.
2026-09-26 00:39:01 +02:00

16 lines
851 B
TypeScript

import { createContext, useContext, useLayoutEffect } from "react";
// B4 / UX-15: every page has exactly one `h1`. The shell renders the page's name as a visually hidden
// one; a view that shows its OWN title (a channel, a Plex show, a playlist) renders that as the page's
// `h1` through `PageHeading`, which says so here, and the shell drops its hidden one while it is
// mounted. The same shape as ./stickyTop: the element announces itself, no page opts out by hand.
const PageHeadingContext = createContext<(() => () => void) | null>(null);
export const PageHeadingProvider = PageHeadingContext.Provider;
/** Called by `PageHeading`: while mounted, the shell's hidden page name steps aside. */
export function useOwnPageHeading(): void {
const register = useContext(PageHeadingContext);
useLayoutEffect(() => register?.(), [register]);
}