- The browser tab names the place and the object: PageHeading reports the view's own title (lib/documentTitle), so a channel, playlist or any Plex view reads "<object> · <module> · Siftlode" however it was opened; the Feed is named too; a season adds its show (tabTitle). - The channel page's tab + action row wraps and lets the tag lane fold into "+N": at 1024 it ran past the edge and the page scrolled sideways. - The YouTube player card's width is capped from the window height less the chrome measured under the video: at 133% zoom (685px) it cut its channel row. - Plex certificate words (Not Rated, Approved, Passed) are named through the vocabulary on the info badge, show page, collection, filter and chips. - DESIGN.md: the zoom target is 125% and 133%, not 200% (decision log).
38 lines
1.4 KiB
TypeScript
38 lines
1.4 KiB
TypeScript
import { type ComponentPropsWithoutRef, type ReactNode, useRef } from "react";
|
|
import { useNameTabAfter } from "../../lib/documentTitle";
|
|
import { useOwnPageHeading } from "./pageHeading";
|
|
|
|
// The page's heading outline (B4, UX-15): one `h1` per page, then a heading per section. A screen
|
|
// reader user moves by headings, so a section caption drawn as a styled `div` hides the page's
|
|
// structure from exactly the people who navigate by it.
|
|
|
|
/** A view's own visible title (a channel, a Plex show, a playlist): the page's `h1`, in place of the
|
|
* shell's hidden page name, and the object the browser tab names (`lib/documentTitle`). `tabTitle`
|
|
* only when the heading alone does not say what it is (a season: "Season 1" → "Voyager · Season 1"). */
|
|
export function PageHeading({
|
|
tabTitle,
|
|
...props
|
|
}: ComponentPropsWithoutRef<"h1"> & { tabTitle?: string }) {
|
|
useOwnPageHeading();
|
|
const ref = useRef<HTMLHeadingElement>(null);
|
|
useNameTabAfter(ref, tabTitle);
|
|
return <h1 ref={ref} {...props} />;
|
|
}
|
|
|
|
/** A section's caption: the small uppercase muted label, as a heading. `level` 3 inside a dialog or
|
|
* a panel whose own title is the `h2`. */
|
|
export function SectionLabel({
|
|
level = 2,
|
|
className = "",
|
|
children,
|
|
}: {
|
|
level?: 2 | 3;
|
|
className?: string;
|
|
children: ReactNode;
|
|
}) {
|
|
const Tag = level === 2 ? "h2" : "h3";
|
|
return (
|
|
<Tag className={`text-xs uppercase tracking-wide text-muted ${className}`}>{children}</Tag>
|
|
);
|
|
}
|