Documentation
¶
Overview ¶
Package render owns the html/template loading and rendering pipeline. S02 ships the helper set that the rest of the project will rely on (safeHTML, relativeTime, pluralize, pathJoin, octicon, csrfToken). S25 will broaden this with the markdown pipeline.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type OcticonResolver ¶
OcticonResolver returns the inline SVG markup for a named octicon. The implementation is provided by the caller; for S02 we ship a tiny built-in set; later sprints can plug in the full Primer octicon catalog.
func BuiltinOcticons ¶
func BuiltinOcticons() OcticonResolver
BuiltinOcticons returns a tiny starter set of octicons. S02 ships only what the chrome needs (mark-github, three-bars, sun, moon, alert). The full Primer catalog is several hundred icons; we vendor on demand rather than bloating the binary.
type Renderer ¶
type Renderer struct {
// contains filtered or unexported fields
}
Renderer holds parsed templates indexed by page name.
func New ¶
New parses every page template under tmplFS.
Naming contract — read this before adding files to internal/web/templates/:
- **Pages** are .html files whose basename does NOT begin with an underscore. A page at `repo/tree.html` is registered under the lookup name `repo/tree`. Render that name from a handler.
- **Partials** are .html files whose basename begins with an underscore (`_layout.html`, `profile/_tabs.html`). Partials are parsed into *every* page so the `{{ define "name" }}` blocks they declare are resolvable from any page template.
Both pages and partials are picked up recursively. Earlier versions of this loader walked only the root for partials, which caused a page that referenced a subdir partial (`profile/_tabs.html`'s `{{ define "tabs" }}`) to render blank — html/template silently ignored the missing-template ref at exec time. We now also validate that every `{{ template "name" }}` action in every parsed page resolves; an undefined ref fails loud at startup with the offending page + the missing name.
func (*Renderer) HTTPError ¶
HTTPError writes an error page with the appropriate status code. If the named error template doesn't exist a plain-text fallback is written.
func (*Renderer) Render ¶
Render writes the named page to w using data as the template root context.
Prefer RenderPage when a *http.Request is in scope — it auto-injects the viewer (current logged-in user) into map data so partials like _nav.html can branch on .Viewer without every handler remembering to thread it.
When w is an http.ResponseWriter, Render sets Content-Type to `text/html; charset=utf-8` *before* the first body byte. This is load-bearing: a handler that calls WriteHeader(non-200) without pre-setting Content-Type otherwise produces a 4xx/5xx response with no Content-Type, which the browser renders as raw text. Setting it here makes that class of bug structurally impossible.
func (*Renderer) RenderPage ¶
RenderPage is the request-aware Render: when data is a map[string]any, it injects "Viewer" (from middleware.CurrentUserFromContext) and "CSRFToken" (the per-request token) if the caller hasn't set them. The nav partial's sign-out form uses the token, so every layout-rendered page needs it. Typed-struct callers must include those fields themselves — we don't reflect-mutate to avoid surprising aliasing.