Files
siftlode/frontend/src/components/ui/Headings.tsx
T
peter ec22eefd31 fix(ui): E31 S2 — the tab names the object, the channel header wraps, the player fits a short window
- 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).
2026-10-01 21:17:20 +02:00

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>
);
}