import Link from "next/link"; import { PROJECT_NAME, PROJECT_WORDMARK_LEAD, } from "yt-dlp-transcript-common/lib/project"; import { ICON_PALETTES } from "yt-dlp-transcript-common/lib/brand"; import { BrandMark } from "yt-dlp-transcript-common/components/BrandMark"; import { Wordmark } from "yt-dlp-transcript-common/components/Wordmark"; import { ThemeToggle } from "yt-dlp-transcript-common/components/ThemeToggle"; import { SocialLinks } from "yt-dlp-transcript-common/components/SocialLinks"; import { SocialScroll } from "yt-dlp-transcript-common/components/SocialScroll"; import { getSettings } from "yt-dlp-transcript-common/lib/settings"; import { resolveHomepageSocialLinks } from "yt-dlp-transcript-common/lib/homepage"; import { headerSocialLinks } from "yt-dlp-transcript-common/lib/socialLinks"; import { currentHomepage } from "../lib/homepage"; import { HEADER_NAV } from "../lib/nav"; function NavList({ className }: { className?: string }) { return ( ); } // The project site's header: a hairline bar with the wordmark and the four // destinations (Changelog is in the footer only; lib/nav.ts). It carried NO // links at all before this — the page it sat above was the whole site. // // The wordmark is PRODUCT identity (common/lib/project.ts), not the operator's // editable homepage config: this bar says what the software is called, and that // is the same string on every install. The operator's own naming still governs // /stats/ and the social links, which this bar carries as well as the footer. // // THE SOCIAL ROW AND THE THEME TOGGLE ARE ONE GROUP, in the bar at every width: // the operator's links (common/components/SocialLinks.tsx) and then the toggle // that cycles the base (common/components/ThemeToggle.tsx, `variant="bare"`), // dressed alike, their 36 px boxes touching, so every glyph is 16 px from the // next. There is no accent control: the homepage wears its own (layout.tsx). // THE HEADER KEEPS THE NAME ON A NARROW SCREEN (the ruling of 2026-09-28): below // the switch the row holds only the links marked `featured` (none marked → // none; the footer shows them all); from it the row holds every link, up to // four, the marked ones kept first (headerSocialLinks, "narrow" and "wide"). // Both rows are rendered and CSS shows one; the other is display:none, so // exactly one is focusable and in the accessibility tree. The switch is // 32.5rem, the export's (520 px at the default text size, where every link, // the toggle and the longest real site title fit the export's bar, menu button // included; this bar is shorter), in rem so it moves with the reader's text // size as the keys and the wordmark do. With the wordmark // link at 148–152 px, the nav at 276 px and a key 36 px (44 px under a coarse // pointer): // ≥ md (768) wordmark · nav · group, the nav 32 px from the group's first // box (40 px from its first glyph). // < md wordmark · group, and the nav alone on the rule below. // THE LAST RESORTS, now rare: when the bar — a size container, `@container/bar` // — is still narrower than the full wordmark, a 12 px gap and the group the // bar shows, the wordmark's TEXT is hidden and the mark stays (the link keeps // its name, "Archilyzer home"); the class is chosen by the row's count from // WORDMARK_FITS — below the switch the narrow row's, from it the wide row's — // (the bar's content width in px at the default text size, 152 + 12 + (n + 1) // keys; the classes say it in rem): // links mouse (36 px keys) touch (44 px keys) viewport // 0 < 200 < 208 < 240 / < 248 // 1 < 236 < 252 < 276 / < 292 // 2 < 272 < 296 < 312 / < 336 // 3 < 308 < 340 < 348 / < 380 // 4 < 344 < 384 < 384 / < 424 // And after that the row scrolls sideways inside the bar (SocialScroll), its // END shown first, the toggle outside it, the header never wider than the // screen; a link that takes focus is scrolled into view with its ring. // // The mark is the family's Found-line mark in its parent colours — bone on // slate, no accent: the project spends no colour on its own chrome. The // wordmark splits on the subject ("Archi" + "lyzer"); the link keeps its // explicit name, "Archilyzer home". // The wordmark text's hiding classes, by how many links the header shows: // complete literal classes, one set per count (see the table above), in rem so // they scale with the reader's text size as the wordmark and the keys do. The // NARROW set applies below the switch and is keyed by the narrow row's count; // the WIDE set from the switch, keyed by the wide row's. const WORDMARK_FITS_NARROW: Record = { 0: "max-[32.5rem]:@max-[12.5rem]/bar:hidden pointer-coarse:max-[32.5rem]:@max-[13rem]/bar:hidden", 1: "max-[32.5rem]:@max-[14.75rem]/bar:hidden pointer-coarse:max-[32.5rem]:@max-[15.75rem]/bar:hidden", 2: "max-[32.5rem]:@max-[17rem]/bar:hidden pointer-coarse:max-[32.5rem]:@max-[18.5rem]/bar:hidden", 3: "max-[32.5rem]:@max-[19.25rem]/bar:hidden pointer-coarse:max-[32.5rem]:@max-[21.25rem]/bar:hidden", 4: "max-[32.5rem]:@max-[21.5rem]/bar:hidden pointer-coarse:max-[32.5rem]:@max-[24rem]/bar:hidden", }; const WORDMARK_FITS_WIDE: Record = { 0: "min-[32.5rem]:@max-[12.5rem]/bar:hidden pointer-coarse:min-[32.5rem]:@max-[13rem]/bar:hidden", 1: "min-[32.5rem]:@max-[14.75rem]/bar:hidden pointer-coarse:min-[32.5rem]:@max-[15.75rem]/bar:hidden", 2: "min-[32.5rem]:@max-[17rem]/bar:hidden pointer-coarse:min-[32.5rem]:@max-[18.5rem]/bar:hidden", 3: "min-[32.5rem]:@max-[19.25rem]/bar:hidden pointer-coarse:min-[32.5rem]:@max-[21.25rem]/bar:hidden", 4: "min-[32.5rem]:@max-[21.5rem]/bar:hidden pointer-coarse:min-[32.5rem]:@max-[24rem]/bar:hidden", }; export default function Header() { const socialLinks = resolveHomepageSocialLinks(currentHomepage(), getSettings()); const narrow = headerSocialLinks(socialLinks, "narrow").length; const wide = headerSocialLinks(socialLinks, "wide").length; return (
{narrow > 0 && ( )} {wide > 0 && ( )}
{/* Below `md` the nav drops to its own rule rather than collapsing behind a menu button — four links do not earn a disclosure widget, and they fit a 320 px rule. Only one of the two navs is ever in the accessibility tree (the other is display:none), but they carry distinct labels so a test or a screen reader can never conflate them. `overflow-x-auto` only guards a larger text setting or a screen under 320 px; nothing scrolls at the default size from 320 px. `tabIndex={-1}`: Firefox makes a scroll container that overflows a tab stop of its own; the links are the stops (as SocialScroll). */}
); }