Components Reference
A lookup table for the whole component tree. TVfolio has 33 sections outside the dev catalog, 40 UI primitives, and one icon component.
The layering is: pages compose sections; sections build on primitives and native elements; primitives are token-only and know nothing about the site. UI Components explains when to reach for which.
Global sections
The 21 sections in Sections/Global/, used by two or more pages — or, in the case of the television, by all of them.
The television
| Section | Draws |
|---|---|
TvSet |
the whole set: room, table, cabinet, tube, and the two chrome slots. Every page renders inside it |
TvControlPanel |
the bottom strip — speaker grille, brand badge, VOL knob, LIGHT/DARK switch, four social caps, power LED. A sub-part of TvSet |
TvScreenBar |
the channel bar: channel number, page name, signal strength, clock. Goes in slot="screen-top" |
FastextBar |
the six coloured keys. Goes in slot="screen-bottom" |
PagesDropup |
the channel index the F6 key opens. Rendered by FastextBar, because a <summary> must be its <details>’s first child |
Structure and headings
| Section | Draws |
|---|---|
SectionHead |
the two-part heading every block shares — a tracked title left, a dimmer routing hint right |
TitleBlock |
a page’s opening: region head, the name in lights, the standfirst. Animates on load, not scroll |
PageIntro |
a detail page’s opening: the return-to-index row over its rule, then title and standfirst |
SpecStrip |
a rule over a row of key/value specs. Drawn three times across About and Project |
StatsStrip |
three bordered stat cells, each counting up when it scrolls into view |
CurrentlyBlock |
the availability panel — where, when, which timezone |
ContactRow |
the sign-off: a live mailto plus the fastext routing hint to the next page |
Content blocks
| Section | Draws |
|---|---|
TubeStill |
the framed, scroll-scaling capture. Use this for any image inside the tube |
TubeFigure |
a full-width TubeStill plus its FIG caption row |
CamTag |
the stamped-on camera identifier in a still’s corner |
TestCard |
the EBU 75% colour-bar test card, framed and captioned |
PullQuote |
the ruled-off pull quote — hairlines on both sides, unlike every other block |
TransmissionList |
a numbered list of transmissions; also the 404’s channel lineup |
CareerList |
the career log, one numbered posting per row |
TubeSlab |
one slab from the action row — a tracked label over a sub-line |
LinkButtons |
a row of TubeSlabs, side-by-side above the cabinet split |
_fastext.ts sits alongside them: not a section, but the shared module holding the F-number opacity, because two components draw a key and the contrast check imports the value rather than guessing it.
Page sections
| Folder | Section | Draws |
|---|---|---|
Home/ |
Hero |
the home hero, in the CRT idiom |
About/ |
ProfileBlock |
the portrait beside the long-form briefing |
Work/ |
TransmissionGrid |
the six project cards CH 02 tunes to |
ProjectBriefing |
the long-form column beside the highlights list | |
ProjectGallery |
the STILLS block, two-up on desktop | |
ProjectActions |
LAUNCH DEMO and VIEW SOURCE — each renders only if its URL exists | |
Blog/ |
BulletinIndex |
the log index: featured bulletin then the numbered archive |
BulletinArticle |
the two-column post — prose left, aside blocks right | |
PostNav |
the sign-off row: the older bulletin, and this one’s position | |
SubscribeRow |
the feed’s printed address as a live link | |
Contact/ |
ContactForm |
the only block on the set that takes input |
Legal/ |
LegalArticle |
the shared renderer for Terms and Privacy |
UiCatalog/ holds nine more sections for the dev-only /examples/ui route. Delete the folder before launch.
UI primitives
All 40, in src/components/ui/<name>/. Each exports its component, a <Name>Variants object and a default.
Tier 1 — button · input · label · textarea · badge · card (Image, Header, Title, Description, Action, Content, Footer) · alert · separator · skeleton · avatar
Tier 2 — accordion (<details>) · tabs · tooltip (CSS-only) · breadcrumb · pagination · progress · spinner
Tier 3 — dialog (native <dialog>) · sheet (a Dialog pinned to an edge) · dropdown (Popover API) · select (native) · checkbox · radio · switch · table
Advanced form controls — slider (native range) · input-number · toggle-count · password (PasswordInput + PasswordStrength) · combobox · advanced-select · searchbox (⌘K palette)
Navigation & content — nav (Nav, NavItem, NavLink) · mega-menu · list
Content & motion — split-text · count-up · marquee · reveal
Theme — theme-toggle
The three the design uses
reveal, split-text and count-up. Plus two modules: _client.ts’s onReady, and theme-toggle/theme.ts, which the cabinet’s LIGHT/DARK switch imports without using the component.
The other thirty-seven exist so /examples/ui can render them. That is a decision, and UI Components explains the rule it gives you.
Shared internals
Not primitives — modules, prefixed accordingly:
| Module | Job |
|---|---|
_client.ts |
onReady — the load + astro:after-swap re-init contract every scripted primitive shares |
_dialog.ts |
the delegated Dialog/Sheet controller; binds once, survives view transitions |
_popover.ts |
placement for Dropdown and MegaMenu, plus arrow-key roving |
_field.ts |
the shared field look — size and validation state |
_listbox.ts |
filterByText / nextIndex / createActiveDescendant for the filterable trio |
_overlay.css |
Dialog and Sheet transitions, the backdrop scrim, the modal scroll-lock |
_Chevron.astro |
the one disclosure/select chevron glyph |
password/strength.ts |
the rule-based scorePassword |
Icons
<Icon /> from @components/svg/icons — 572 icons, name typed as IconName, size in four steps, title for an accessible name. See Icons.
Layouts
| File | Job |
|---|---|
BaseLayout.astro |
<html> + <head> + a chrome-free <body> with one slot |
BaseHead.astro |
every meta, OG, Twitter and JSON-LD tag; the pre-paint theme script; <ClientRouter /> |
BaseLayout is deliberately chrome-free — no nav, no footer. Those are composed per page, which for this theme means composed inside TvSet.
Utilities
| Module | Exports |
|---|---|
@js/blog |
getBulletins() |
@js/work |
getWork() |
@js/schema |
six JSON-LD builders, organizationId, serializeJsonLd, the SeoProps type |
@js/cv |
cvRecord, renderCvText, renderCvPdf, toWinAnsi, pdfEscape |
@js/rss |
buildRss |
@js/contact |
parseContact, rateLimited, contactEmail, statusUrl, the limits and constants |
@js/textUtils |
slugify, isoDate, pad2, readingTime, readableUrl, formatDate |
@config/navData |
channelFor, fkeyFor, fkeyLabelFor, assertChannelLabels, channels, the keys |
@config/siteData |
the site record plus availabilityLabels |