// The types in this file are the theme contract in Go: what a template receives, nothing about how it is // produced. Split from render.go when that file crossed the size warning — the seam was already here, since // docs/theme-contract.md describes exactly this and nothing else. package render import ( "html/template" "time" "khosra/internal/content" ) // head is what every kind of page shares: the document shell the base template needs. Absence is the // zero value — a template reads what exists and never fails on a missing field (invariant 1). type head struct { // Title may be empty for a bundle; a listing always has one. Title string // Lang is the locale being served. Lang string // Canonical is the permalink of what was actually served, which differs from the URL requested when // the fallback chain supplied another language (ADR-0009). Canonical string // Alternates lists every language this key exists in, for hreflang. Alternates []Alternate // Style is the reference theme's stylesheet, inlined so a bare site root needs no asset route. Style template.CSS // Site is what the site declared about itself in site.yaml (ADR-0039). Zero when it declared nothing. Site content.Settings // Sections are the site's sections, for navigation: only .Title and .URL are set. Empty until the engine is // told where to find them, which cmd does at wiring time (ADR-0049). Sections []Item } // Page is one bundle rendered. type Page struct { head // Key is the bundle's identity, useful for building links. Key string // HTML is the rendered body. HTML template.HTML // Extra carries every frontmatter key the parser does not name (ADR-0002). Extra map[string]any // Sequence is the series this page sits in, nil when it sits in none. Sequence *Sequence // Tags are this bundle's own terms, each with the URL of its listing. Empty when it carries none. Tags []Item // ExtrasURL links this bundle's supporting files, empty when it has none — so a theme can offer them // without guessing whether they exist (ADR-0047). ExtrasURL string } // Sequence is a series as a page sees it: its members in reading order, and where this page is in them // (ADR-0033). type Sequence struct { // Title is the series' title, empty when the landing page omits one; URL is its permalink. Title, URL string // Members are every entry in reading order — ascending, unlike a dated listing. Members []Item // Index is this page's 1-based position, zero when this page is the series landing itself. Count is // how many members there are. Index, Count int // Prev and Next are the neighbours in reading order, nil at the ends and on the landing page. Prev is // the *earlier* entry, the opposite sense of a listing's PrevURL. Prev, Next *Item // First and Last are the ends of the series, set whenever it has members. First, Last *Item } // Extras is a bundle's supporting files, browsable (ADR-0047). type Extras struct { head // Bundle is the page these files belong to, so a theme has its title and a way back. Bundle Item // Entries is the whole tree, sorted by path. Entries []content.Entry // Selected is the entry the URL named, nil on the bare listing. Selected *Selected } // Selected is the entry a request picked out of the tree. type Selected struct { content.Entry // HTML is the rendered file for a markdown or text entry, empty for anything else. HTML template.HTML // RawURL always works: it is how a theme embeds an image, links a PDF, or offers a download. RawURL string } // List is a collection page: the result of a Query, one page of it. type List struct { head // Items are the entries on this page, in the Query's order. Items []Item // Page is 1-based; Pages is the total, at least 1 even when empty. Page, Pages int // PrevURL and NextURL are empty at the ends. Newer is "prev" because the order is newest first. PrevURL, NextURL string // Groups is the same entries partitioned by section, set alongside Items for a tag listing. Both shapes // are offered because which one to show is the theme's decision, not the engine's (ADR-0046). Groups []Group } // Group is a named run of entries within a listing. type Group struct { Name string Items []Item } // Item is one entry in a listing. type Item struct { Title string Key string URL string Date time.Time // Section is the entry's top-level section, so a flat listing can label where an entry came from without // the engine deciding that it must be grouped (ADR-0046). Section string } // Alternate is one language a bundle exists in. type Alternate struct { Lang string // URL is absolute when the site declares a base, because hreflang is read by machines that resolve nothing // against the page. URL string // Path is the same address, root-relative — what a *visible* language link wants. Found by looking at a // rendered page: using URL sent a reader from a local server to the canonical host (ADR-0049). Path string }