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 (
{HEADER_NAV.map((item) => (
{item.label}
))}
);
}
// 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). */}
);
}