docs

package module
v0.0.0-...-25877fb Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2026 License: MIT Imports: 44 Imported by: 0

README

fastr-docs

Reusable, white-label documentation sites built on GoFastr.

The central API is docs.Router. It owns the route tree, explicit sibling order, navigation metadata, local-search records, Markdown pages, typed GoFastr screens, and plugins such as OpenAPI. GoFastr remains responsible for screen rendering, DI, policies, lifecycle, and the PWA/offline shell. The default layout includes router-derived navigation, a sticky Markdown table of contents with scrollspy, and a local search index. Static builds can run Pagefind as a first-class export backend while JSON remains the zero-dependency development fallback.

Create a site

From this repository while developing the package:

go run ./cmd/fastr-docs init my-docs --name "Acme Docs" --module example.com/acme-docs
cd my-docs
fastr-docs check .
fastr-docs dev .
# run once without the watcher
go run .
# or export a static PWA with chunked Pagefind search
fastr-docs export . --out dist --pagefind

After publishing the module, the CLI is intended to be installed with:

go install github.com/DonaldMurillo/fastr-docs/cmd/fastr-docs@latest

The generated project exposes the same workflow through the CLI:

fastr-docs check .
fastr-docs build .
fastr-docs dev .
fastr-docs upgrade .
fastr-docs export . --out dist
fastr-docs sync-skills .

Generated projects carry a set of agent skills, authored under .agents/skills/ and mirrored to .claude/skills/ where Claude Code loads them. fastr-docs check fails when the two copies disagree, naming each file that is stale, missing, or orphaned, so an edit cannot land in one and leave the other agent following older rules. fastr-docs sync-skills copies the authored version across; add --prune to also delete files that exist only under .claude/skills.

fastr-docs dev delegates to GoFastr's development loop. It watches Go, Markdown, HTML, CSS, JavaScript, and JSON/YAML spec files, rebuilds the server, and refreshes open browser tabs after a successful rebuild. Use go run . when you want a single process without file watching.

fastr-docs build delegates to GoFastr's build gates and compiler. Use fastr-docs upgrade . --apply to apply GoFastr framework migrations through the same project wrapper.

Generated sites are installable PWAs through GoFastr's WithPWA host option. Deploy the static export when the installed app must include every document offline:

fastr-docs export . --out dist --pagefind

GoFastr fingerprints the exported worker cache and updates it on the next visit after a redeploy. Existing tabs finish on their current version; new tabs use the updated docs. Use fastr-docs upgrade . to review and apply GoFastr framework and CLI migrations when updating a generated project.

The generated project includes two top-level pages, a nested getting-started page, the in-project OpenAPI plugin, agents/claude.md, and skills covering authoring, blogging, theming, OpenAPI, and publishing. It also emits an installable PWA/static export with the OpenAPI and docs runtimes plus the router search index precached. The live host publishes GoFastr's agent-ready /llms.txt, agent card, and /mcp discovery surfaces alongside the page-level Markdown references. Static exports retain the documentation surfaces; /mcp is a live server endpoint.

Registering content

router := docs.NewRouter(docs.WithSiteName("Acme Docs"))
router.MustPage("/", docs.PageConfig{
    Title: "Acme Docs",
    Source: "# Welcome\n\nYour documentation starts here.",
    Order: 1,
    Offline: true,
})
router.MustScreen("/playground", docs.ScreenConfig{
    Title: "Playground",
    Component: &PlaygroundScreen{},
    Order: 2,
})

Use router.Mount(site, layout) to register the tree into a GoFastr core-ui/app.App. Plugins implement Name and Apply, so extensions stay in the same navigation and search model instead of creating a parallel system.

When serving through a GoFastr HTTP host, mount the framework-owned mobile navigation drawer and native command palette once after creating the host:

router.MountNavigation(server.Router())
router.MountCommandPalette(server.Router())

The layout uses GoFastr SiteHeader, Sidebar, DocLayout, AnchoredRail, CommandPalette, and ShortcutHint components. The primary header follows top-level route groups, while Meta/Control + K opens the native command palette for route navigation. Their drawer behavior, active route state, and scrollspy should be extended through GoFastr components rather than replaced with page-specific JavaScript.

The first-party OpenAPI plugin accepts JSON or YAML, reads the spec's servers URL, and exposes an optional request console. Set ServerURL to override it per deployment; the generated starter maps that override to API_SERVER_URL.

router.Use(openapi.Plugin{
    SpecPath:  "openapi.json",
    ServerURL: os.Getenv("API_SERVER_URL"),
})

Generated hosts also enable GoFastr's read-only MCP introspection surface: framework.WithMCP() mounts /mcp, and framework.WithMCPIntrospection() exposes tools that describe the running app. The generated agent card advertises the same endpoint. Remove both options and AgentCard.MCPEndpoint together when a deployment must not expose an MCP endpoint.

Content components and plugins

Every Router registers a shortcode vocabulary by default, so Markdown authors get components without writing Go:

{{< warning title="Important" >}}
This body is still Markdown and can contain links and emphasis.
{{< /warning >}}

note, info, tip, success, warning, caution, and danger are admonitions; callout takes the tone as a prop. cards lays out card children, tabs holds tab children, and hero holds action children. steps, filetree, details, badge, tag, banner, icon, and diff round it out.

Shortcodes come in three shapes. MarkdownComponent receives its body as rendered Markdown. MarkdownContainer receives its nested shortcodes as separate children, which is what tabs and card grids need. MarkdownRawComponent receives the body unrendered, for content that is data rather than prose: diff and filetree both read line structure that Markdown rendering would destroy.

Registering a name replaces whatever held it:

router.Use(docs.MarkdownComponentsPlugin{Components: map[string]docs.MarkdownComponent{
    "note": func(props map[string]string, body render.HTML) render.HTML {
        return ui.Callout(ui.CalloutConfig{Title: props["title"], Variant: ui.StatusNeutral}, body)
    },
}})

docs.WithoutDefaultComponents() starts from an empty vocabulary, where any unregistered shortcode fails the build instead of rendering.

MarkdownCollectionPlugin packages filesystem content discovery for projects that want a plugin-owned collection. Use MarkdownCollectionFS for embed.FS or another virtual filesystem, and MarkdownCollection for disk-backed development content. Other extensions implement Plugin, and may additionally implement ValidatingPlugin or AssetPlugin; route content, search metadata, origins, validation, and assets should remain attached to the same Router.

When a project contains localized or versioned route siblings, the header emits route-aware Language and Version selectors that preserve the current page family.

Diagrams

plugin/mermaid renders Mermaid diagrams from Markdown:

router.Use(mermaid.Plugin{})
{{< mermaid title="How a page renders" >}}

graph LR MD[Markdown] --> R[docs.Router] --> PAGE[Page]

{{< /mermaid >}}

Mermaid renders by injecting a <style> element and emitting SVG with inline styles, both of which default-src 'self' blocks. Rather than relaxing the policy for every page, the diagram renders inside a same-origin frame document loaded in <iframe sandbox="allow-scripts"> with no allow-same-origin. Only that document carries style-src 'unsafe-inline'; the pages stay strict.

The frame has an opaque origin, so it cannot reach the host's DOM, cookies, or storage, and connect-src 'none' keeps it off the network. postMessage carries two things: the diagram source in, the rendered height back. Without JavaScript the page shows the diagram source as preformatted text.

It is a separate package, so Mermaid's bundle is only linked into projects that import it.

Plugin assets

The docs runtime, the search index, the export manifest, and every plugin's browser assets are collected by one call, for serving and for export:

router.MountRuntimeAssets(server.Router(), router.AssetPrefix(), exportBase)
router.WriteRuntimeAssets(dist, router.AssetPrefix(), exportBase)

RuntimeAssetNames returns the same list, so the PWA precache list and the host's script tags are derived rather than repeated by hand.

A plugin joins in by implementing RuntimeAssetPlugin:

func (Plugin) RuntimeAssets() (map[string][]byte, error) {
    body, err := fs.ReadFile(runtimeFS, "openapi.js")
    return map[string][]byte{"openapi.js": body}, err
}

Names are validated: a plugin cannot overwrite docs.js or escape the asset directory. AssetPrefix follows WithSearchIndexPath, so the prefix and the index URL cannot disagree.

Translating the chrome

WithUIStrings translates every framework-owned label. The struct is grouped, and empty fields keep their English defaults, so a project can translate one label at a time:

router := docs.NewRouter(docs.WithUIStrings(docs.UIStrings{
    Search:     "Rechercher",
    DateFormat: "02/01/2006",
    Blog: docs.BlogStrings{
        Archive:    "Archives",
        ResultsFor: "Résultats pour « %s »",
    },
    NotFound: docs.NotFoundStrings{Heading: "Page introuvable"},
}))

Labels containing %s or %d are format strings; a translation may reorder the surrounding words. Dropping the placeholder is tolerated rather than producing Go's %!(EXTRA ...) in the middle of a page.

Dates use DateFormat, a Go layout, with Months and ShortMonths naming the months for a layout that spells them out. The standard library ships no CLDR data, so the layout is the project's choice rather than something inferred from the locale.

Fallback for untranslated pages

By default a page tagged locale: en is absent from a build for another locale, which leaves a partially translated site with missing pages. WithLocaleFallback serves the default-locale page instead:

router := docs.NewRouter(
    docs.WithLocale(os.Getenv("DOCS_CONTENT_LOCALE")),
    docs.WithLocaleFallback("en"),
)

A fallback never shadows a real translation: if the family has a page in the build locale, that one wins and the default-locale variant stays hidden.

Router.LocaleCoverage() reports which families are missing a translation, and fastr-docs check logs those gaps. They are advisory. A partially translated site is a normal state, not a broken build.

Landing pages

A page can opt into the splash shell from front matter, so a landing page needs no Go:

---
template: splash
hero:
  eyebrow: Documentation built on GoFastr
  title: Acme Docs
  tagline: One explicit route tree drives everything.
  actions:
    - text: Get started
      link: /docs/getting-started
      variant: primary
    - text: Browse the docs
      link: /docs
      variant: secondary
---

{{< cards >}}
{{< card title="Concepts" href="/docs/concepts/router" >}}{{< /card >}}
{{< /cards >}}

Splash pages drop the table of contents and breadcrumbs, and reclaim the column the layout reserves for a table of contents, so the landing page is wider than a reference page. The body below the hero is ordinary Markdown, so the whole shortcode vocabulary composes into it.

For a landing page that outgrows front matter, PageConfig.Body still takes a typed GoFastr component. Both generated projects ship one of each: the home page is a splash page and /examples/typed-landing is the Go equivalent.

edit_url and last_updated can both be derived from history instead of being typed into every page and left to rot:

router := docs.NewRouter(docs.WithGitMetadata(docs.GitMetadataConfig{
    RepoURL: "https://github.com/acme/docs",
    Branch:  "main",
}))

Front matter always wins, so a page that declares either keeps what it declared. One git log covers the whole repository rather than one process per page. Pages served from an embed.FS have no file on disk and are skipped.

It degrades silently by design: no git binary, no repository, or a shallow clone leaves every page exactly as authored, because a documentation build must not require version-control history to be present. EditURLFor replaces the built-in GitHub-style link for hosts that shape edit URLs differently.

Use WithPagefindPath when the generated search bundle is served from a custom asset prefix, such as a reverse-proxy mount:

router := docs.NewRouter(docs.WithPagefind(), docs.WithPagefindPath("/assets/pagefind/"))

WithSearchIndexPath does the same for the JSON search index. The default, /__fastr-docs/search.json, matches the prefix the generated starter mounts. A host that serves the docs assets somewhere else must set it, or the command palette falls back to an unfiltered route list:

router := docs.NewRouter(docs.WithSearchIndexPath("/assets/search.json"))

End-to-end tests

The Playwright suite generates a fresh starter project for every run and covers desktop/mobile navigation, search, theme persistence, sticky TOC, OpenAPI server requests, static export, and PWA assets:

cd e2e
npm install
npx playwright install chromium
npm test

Documentation

Overview

Package docs is the route and content layer for reusable documentation sites. It deliberately keeps navigation, search metadata, and page registration in one Router so an extension contributes to the same tree as ordinary documentation pages.

Index

Constants

View Source
const DefaultAssetPrefix = "/__fastr-docs"

DefaultAssetPrefix is where a generated project serves the docs runtime, search index, and plugin assets.

View Source
const PageTemplateSplash = "splash"

PageTemplateSplash renders a landing page: a hero from front matter, no table of contents, no breadcrumbs, and a wider content column.

Variables

This section is empty.

Functions

func ContentSecurityPolicy

func ContentSecurityPolicy(connectOrigins ...string) string

ContentSecurityPolicy returns the strict default GoFastr policy with only the explicitly declared browser connect origins added to connect-src.

func DefaultIconPNG

func DefaultIconPNG() []byte

DefaultIconPNG provides one source image for GoFastr's derived PWA icons. Projects can replace it with their own image or use BrandConfig for the browser-facing logo.

func DefaultMarkdownComponents

func DefaultMarkdownComponents() map[string]MarkdownComponent

DefaultMarkdownComponents is the shortcode vocabulary every Router registers unless WithoutDefaultComponents is passed. A project overrides any of these by registering the same name, which replaces rather than conflicts.

func DefaultMarkdownContainers

func DefaultMarkdownContainers() map[string]MarkdownContainer

DefaultMarkdownContainers is the shortcode vocabulary that needs to see its children individually.

func DefaultMarkdownRawComponents

func DefaultMarkdownRawComponents() map[string]MarkdownRawComponent

DefaultMarkdownRawComponents is the shortcode vocabulary whose bodies are data rather than prose, so they must not be rendered as Markdown first.

func DefaultTheme

func DefaultTheme() style.Theme

DefaultTheme is kept as a convenient compatibility entry point for projects that do not need template selection. It is the same Editorial theme used by a new Router.

func IsValidLocale

func IsValidLocale(locale string) bool

effectiveLocale is the locale a route counts as for pairing purposes.

A page declares its locale in front matter, but a site rarely marks its original pages: writing `locale: en` on thirty English files to get a language selector is busywork, and forgetting it fails silently, because a route in no locale pairs with nothing. So when the project has named a default locale, an unmarked route is treated as being in it.

This is deliberately only about pairing. Which routes publish is decided by localeAllows, and that is left alone: a route with no declared locale is still served in every locale build. IsValidLocale reports whether a locale tag is BCP 47 shaped: a two or three letter primary subtag, optionally extended. Plugins and projects use it to refuse a locale that would fork the language pairing silently.

func RewriteStaticCSP

func RewriteStaticCSP(dir, policy string) error

RewriteStaticCSP replaces the generated Content-Security-Policy metadata and any hosting-header policy in an exported site. It matches the element by its semantic http-equiv attribute, so changes to attribute order or unrelated GoFastr metadata do not silently leave the default policy behind.

func RuntimeJS

func RuntimeJS() string

RuntimeJS is the small docs-owned browser layer. GoFastr still owns its core runtime; this file only wires docs-specific controls such as the responsive in-page selector, publication search, and active anchor state.

func TemplateDescription

func TemplateDescription(template Template) string

TemplateDescription gives configuration UIs and generated docs a concise explanation of each visual starting point.

func WriteAgentAssets

func WriteAgentAssets(dir, basePath string, handler http.Handler) error

WriteAgentAssets materializes GoFastr's opt-in agent discovery responses in a static export. GoFastr serves these responses dynamically, while its static builder intentionally writes declared page and asset routes. The helper keeps generated and hand-authored docs projects from losing /llms.txt and the agent card when they switch to offline hosting.

A 404 is ignored so callers can use this with hosts that do not enable the agent-ready option. Root-relative Markdown links are prefixed with basePath because the response is being moved below the export mount point.

func WriteStaticNotFound

func WriteStaticNotFound(dir, basePath string, screen NotFoundScreen, css string) error

WriteStaticNotFound writes the branded fallback page used by static deployments. A project's public/404.html can replace this file later in the export pipeline when it needs a fully custom fallback.

func WriteStaticRSS

func WriteStaticRSS(dir, basePath, feedPath string, body []byte) error

WriteStaticRSS writes a feed to the same base-path layout used by static route exports. Call RSSXML first so the feed is generated from the Router.

func WriteStaticRedirect

func WriteStaticRedirect(dir, basePath, from, to string) error

WriteStaticRedirect materializes one declared redirect as a tiny meta-refresh page, so a static host with no redirect configuration still honors the redirects a page declares in front matter. The manifest lists them for real hosting adapters; this is the floor everyone else gets.

Types

type AssetConfig

type AssetConfig struct {
	// FS serves the public assets; a project points it at its own
	// embedded or on-disk tree.
	FS fs.FS
	// Prefix is the URL path the assets answer under.
	Prefix string
	// MaxAge sets the assets' cache duration; zero uses the built-in
	// default.
	MaxAge time.Duration
}

AssetConfig mounts a project's public fs.FS through GoFastr's hardened static handler. It works with embed.FS, os.DirFS, or any other fs.FS.

type AssetPlugin

type AssetPlugin interface {
	Plugin
	MountAssets(*Router, *gofastrRouter.Router) error
}

AssetPlugin lets an extension mount its own browser assets through the project's GoFastr HTTP router. This is optional; ordinary route plugins need only implement Plugin.

type BlogConfig

type BlogConfig struct {
	// Title names the collection in navigation and feeds.
	Title string
	// Description is the collection's meta description.
	Description string
	// Order positions the collection among the site sections.
	Order int
	// PostOrderStart is the Order given to the first post, so posts sort
	// after the collection's own views; zero uses Order + 1.
	PostOrderStart int
	// Offline marks every generated view precacheable by the service
	// worker.
	Offline bool
	// IncludeDrafts publishes posts whose front matter marks them as
	// drafts.
	IncludeDrafts bool
	// DefaultLocale is the language the collection's views and unmarked
	// posts count as, so a Spanish collection reads the Spanish labels.
	DefaultLocale string
	// DefaultVersion is the version the collection serves when a post
	// declares none.
	DefaultVersion string
	// LocalePrefix pairs the collection's generated views with their
	// translations by path shape, the way /es/blog pairs with /blog.
	LocalePrefix bool
	// VersionPrefix pairs the collection's views with their versioned
	// variants by path shape.
	VersionPrefix bool
	// PostsPerPage controls archive pagination. Zero uses the built-in
	// default of 10.
	PostsPerPage int
	// The aggregate views are enabled by default. Disable* is explicit so a
	// zero-value BlogConfig still produces a complete publishing surface.
	DisableSearch  bool
	DisableTags    bool
	DisableAuthors bool
	DisableArchive bool
	// RelatedPosts controls the number of related links on a post. Zero uses
	// the built-in default of 3.
	RelatedPosts int
}

BlogConfig configures a Router-backed Markdown blog. The directory's index.md becomes the archive route at prefix. Every other Markdown file becomes a post route under that prefix.

type BlogStrings

type BlogStrings struct {
	// Title names the collection in its sidebar rail. One word; the English
	// default is "Blog".
	Title string
	// Navigation is the aria-label of the collection sidebar. Not rendered
	// visually.
	Navigation string
	// Breadcrumb is the root crumb of the collection trail. One word.
	Breadcrumb string
	// AllPosts labels the link to the collection root.
	AllPosts string
	// LatestPosts heads the collection root when it lists the newest posts.
	LatestPosts string
	// RecentPosts titles the sidebar group of recent posts.
	RecentPosts string
	// KeepReading is the continue-reading link after a truncated post.
	// Imperative.
	KeepReading string
	// NoPostsYet is the line an empty collection renders. Full sentence.
	NoPostsYet string
	// NothingClassified is the line a tag or author page renders when it
	// has no posts. Full sentence.
	NothingClassified string
	// CollectionDescription is the meta description of generated views.
	// Format string taking the collection title as %s.
	CollectionDescription string
	// Search titles the collection search view. One word.
	Search string
	// SearchDescription is the meta description of the search view.
	// Format string taking the collection title as %s.
	SearchDescription string
	// SearchPosts is the visible heading over search results.
	SearchPosts string
	// SearchThePublication is the search input placeholder. Ellipsis is
	// conventional.
	SearchThePublication string
	// ResultsFor heads results with the query. Format string taking the query
	// as %s.
	ResultsFor string
	// NoPostsMatched is the empty-results line. Full sentence; the English
	// default names no query.
	NoPostsMatched string
	// MatchesSummary counts results for screen readers and the live filter.
	// Format string taking the count as %d; it also rides a data attribute
	// the client-side filter re-renders, so the %d must survive.
	MatchesSummary string
	// Archive titles the archive view. One word.
	Archive string
	// ArchiveDescription is the meta description of the archive view.
	// Format string taking the collection title as %s.
	ArchiveDescription string
	// ArchiveYear heads one year in the archive. Format string taking the
	// year as %s.
	ArchiveYear string
	// ArchiveYearDescription is the meta description of one year. Format
	// string taking the year as %d.
	ArchiveYearDescription string
	// Tag heads one tag page. One word.
	Tag string
	// Tags titles the tag index. One word.
	Tags string
	// TagsDescription is the meta description of the tag index. Format
	// string taking the collection title as %s.
	TagsDescription string
	// ExploreTerms is the lede of the tag index. Format string taking a
	// summary of the terms as %s.
	ExploreTerms string
	// PostCount counts a term's or author's posts. Format string taking the
	// count as %d.
	PostCount string
	// Publication names the publication in generated copy where "blog"
	// reads wrong for the project.
	Publication string
	// ReadingTime estimates a post's length. Format string taking the minute
	// count as %s.
	ReadingTime string
	// Featured labels the featured posts group. One word.
	Featured string
	// Latest labels the newest-posts group. One word.
	Latest string
	// Feed labels the link to the collection's RSS feed. One word.
	Feed string
	// TopicsPrefix introduces a post's topics for screen readers. Not
	// rendered visually; sentence fragment.
	TopicsPrefix string
	// Lede is the intro line of the collection's post list.
	Lede string
	// TagDescription is the meta description of one tag page. Format string
	// taking the term as %s.
	TagDescription string
	// Authors titles the author index. One word.
	Authors string
	// AuthorsDescription is the meta description of the author index.
	// Format string taking the collection title as %s.
	AuthorsDescription string
	// Author heads one author page. One word.
	Author string
	// AuthorDescription is the meta description of one author page. Format
	// string taking the name as %s.
	AuthorDescription string
	// Page is the word "Page" in a numbered page title. One word.
	Page string
	// PagedTitle titles a numbered page of the collection. Format string
	// taking the page number as %d.
	PagedTitle string
	// PageDescription is the meta description of a numbered page. Format
	// string taking the collection title as %s.
	PageDescription string
	// OlderPosts labels the link to older pages of the feed. Comparative.
	OlderPosts string
	// NewerPosts labels the link to newer pages of the feed. Comparative.
	NewerPosts string
	// Pagination is the aria-label of the pager between pages. Not
	// rendered visually.
	Pagination string
	// PostActions heads the share actions under a post.
	PostActions string
	// Share is the short share heading. One word.
	Share string
	// ShareThisPost is the full share heading. Imperative.
	ShareThisPost string
	// CopyLink is the copy-link button. Imperative.
	CopyLink string
	// LinkCopied is the transient confirmation after copying; announced to
	// screen readers. Past participle.
	LinkCopied string
}

BlogStrings are the labels for the publication surface: route titles for the generated views, and the chrome around posts.

type BrandConfig

type BrandConfig struct {
	// Name is the site name in the header, footer, and PWA.
	Name string
	// LogoURL is the header logo image; empty falls back to the text
	// mark.
	LogoURL string
	// LogoAlt is the logo's alt text.
	LogoAlt string
	// FaviconURL is the bookmark and tab icon.
	FaviconURL string
	// ThemeColor tints the browser and OS chrome around the page.
	ThemeColor string
	// AccentColor overrides the theme's accent for brand-specific
	// highlights.
	AccentColor string
}

BrandConfig describes the small set of identity hooks a white-label site needs. Empty fields intentionally fall back to the framework-neutral mark and the Router's site name.

type CollectionConfig

type CollectionConfig struct {
	// OrderStart is the Order given to the first page in the
	// collection; zero derives one.
	OrderStart int
	// Offline marks the collection's pages precacheable.
	Offline bool
	// IncludeDrafts publishes pages whose front matter marks them as
	// drafts.
	IncludeDrafts bool
	// DefaultLocale is the language unmarked pages in the collection
	// count as.
	DefaultLocale string
	// DefaultVersion is the version pages serve when they declare
	// none.
	DefaultVersion string
	// LocalePrefix and VersionPrefix make non-default slices addressable at
	// /<prefix>/<locale>/... and /<prefix>/<version>/..., allowing several
	// localized/versioned documents to coexist in one Router.
	LocalePrefix bool
	// VersionPrefix pairs the collection's pages with their versioned
	// variants by path shape.
	VersionPrefix bool
}

CollectionConfig configures MarkdownCollection and MarkdownCollectionFS. Files are discovered in lexical path order, while each document can override its order in front matter. Drafts remain registered for validation and preview, but IncludeDrafts or WithIncludeDrafts makes them publishable.

type ContentIssue

type ContentIssue struct {
	// RoutePath is the page the issue belongs to; SourcePath names the
	// file when the issue came from content.
	RoutePath  string
	SourcePath string
	// Link is the offending anchor, for issues found by link checking.
	Link string
	// Line and Column locate the issue inside the source file; zero
	// when unknown.
	Line   int
	Column int
	// Message describes the issue in one line.
	Message string
}

ContentIssue is a source-level problem found in a Markdown page. The Router reports these during strict validation so a broken link can be fixed in the file that authored it instead of being discovered after deployment.

func (ContentIssue) Error

func (i ContentIssue) Error() string

Error renders the issue with its location, for Validate's aggregated error.

type ContentMetadata

type ContentMetadata struct {
	// Title overrides the page heading and nav label. Front matter wins
	// over the file name, which is the fallback.
	Title string `json:"title,omitempty" yaml:"title,omitempty"`
	// Slug overrides the last segment of the route path. The page pairs
	// with its original through TranslationOf, because the paths no longer
	// mirror each other.
	Slug string `json:"slug,omitempty" yaml:"slug,omitempty"`
	// Description fills the meta description and the search entry.
	Description string `json:"description,omitempty" yaml:"description,omitempty"`
	// Excerpt is the summary shown in cards and the blog feed.
	Excerpt string `json:"excerpt,omitempty" yaml:"excerpt,omitempty"`
	// Draft withholds the page from every build unless drafts are
	// explicitly included.
	Draft bool `json:"draft,omitempty" yaml:"draft,omitempty"`
	// NoIndex asks search engines not to index the page.
	NoIndex bool `json:"noIndex,omitempty" yaml:"noindex,omitempty"`
	// EditURL is the "Edit this page" link target.
	EditURL string `json:"editUrl,omitempty" yaml:"edit_url,omitempty"`
	// CanonicalURL overrides the canonical link, for pages mirrored
	// from another address.
	CanonicalURL string `json:"canonicalUrl,omitempty" yaml:"canonical,omitempty"`
	// Image is the social preview image.
	Image string `json:"image,omitempty" yaml:"image,omitempty"`
	// Authors names the byline of a post.
	Authors []string `json:"authors,omitempty" yaml:"authors,omitempty"`
	// DatePublished sets the publish date shown and fed to RSS.
	DatePublished string `json:"datePublished,omitempty" yaml:"date,omitempty"`
	// DateModified sets the "Updated" date.
	DateModified string `json:"dateModified,omitempty" yaml:"last_updated,omitempty"`
	// Locale declares the page language as a BCP 47 tag. It pairs the page
	// with its translations, feeds the language selector, and decides which
	// language search indexes it under; publication itself is governed by the
	// build locale filter, and an unmarked page still serves in every build.
	Locale string `json:"locale,omitempty" yaml:"locale,omitempty"`
	// Version marks the page as one variant of a versioned family, so
	// v1 and v2 of the same guide coexist and the version selector can
	// aim at both.
	Version string `json:"version,omitempty" yaml:"version,omitempty"`
	// TranslationOf names the route this page translates, so the two pair as
	// variants of one family whatever their paths are. Without it a
	// translation pairs by path shape alone: /es/docs/guide is the Spanish
	// /docs/guide because stripping the locale segment leaves the same path.
	// A translated slug such as /es/docs/guia breaks that, and this is how it
	// says which page it is.
	TranslationOf string `json:"translationOf,omitempty" yaml:"translation_of,omitempty"`
	// Alternates names the canonical hreflang targets by hand, for a
	// family whose pairing cannot be derived from paths. Keys are language
	// tags, values are route paths.
	Alternates map[string]string `json:"alternates,omitempty" yaml:"alternates,omitempty"`
	// Tags are free-form labels used by blog tag views.
	Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
	// Redirects lists old paths that should 301 to this page.
	Redirects []string `json:"redirects,omitempty" yaml:"redirects,omitempty"`
	// Order sorts the page among its siblings; lower comes first.
	Order int `json:"order,omitempty" yaml:"order,omitempty"`
	// PageTemplate selects the page shell. Empty is the standard
	// documentation page; PageTemplateSplash is the landing-page shell.
	PageTemplate string `json:"template,omitempty" yaml:"template,omitempty"`
	// Hero is the front-matter hero of a splash page.
	Hero *PageHero `json:"hero,omitempty" yaml:"hero,omitempty"`
}

ContentMetadata is the portable metadata schema shared by Markdown, typed screens, search, SEO, drafts, versions, and localized content. Markdown pages can provide the same fields in a YAML front matter block.

type ExportManifest

type ExportManifest struct {
	// Schema is the manifest schema version, for consumers that
	// check it before reading.
	Schema string `json:"schema"`
	// SiteName is the site the manifest describes.
	SiteName string `json:"siteName"`
	// BasePath is the prefix the export serves under, empty at the
	// root of a domain.
	BasePath string `json:"basePath,omitempty"`
	// SearchIndex is the URL of the search index the runtime fetches.
	SearchIndex string `json:"searchIndex"`
	// SearchBackend names the backend answering searches, json or
	// pagefind.
	SearchBackend SearchBackend `json:"searchBackend"`
	// SearchPath is the URL of the Pagefind bundle when that is the
	// backend.
	SearchPath string `json:"searchPath,omitempty"`
	// AssetsPrefix is where the runtime assets are served from.
	AssetsPrefix string `json:"assetsPrefix"`
	// Locales lists the languages the build serves.
	Locales []string `json:"locales,omitempty"`
	// Versions lists the route versions present in the tree.
	Versions []string `json:"versions,omitempty"`
	// Routes lists every published route with its language, version,
	// and fetch metadata.
	Routes []ManifestRoute `json:"routes"`
	// Redirects lists the source-to-target pairs the export writes.
	Redirects []ManifestRedirect `json:"redirects,omitempty"`
	// Drawers names the mounted navigation drawer widgets, one per
	// language plus one per blog collection, so an offline host can
	// precache exactly the chrome that exists.
	Drawers []string `json:"drawers,omitempty"`
}

ExportManifest is the deployment-neutral route manifest emitted alongside static runtime assets. Hosting adapters can use it to build redirects, preloads, or edge metadata without parsing rendered HTML.

type GitMetadataConfig

type GitMetadataConfig struct {
	// Dir is where git runs. Empty uses the working directory.
	Dir string
	// RepoURL is the repository's web URL, such as
	// https://github.com/acme/docs. Empty leaves edit links alone.
	RepoURL string
	// Branch is the branch edit links point at. Empty uses "main".
	Branch string
	// EditURLFor replaces the built-in GitHub-style link for hosts that shape
	// their edit URLs differently. It receives the file's repository-relative,
	// slash-separated path.
	EditURLFor func(path string) string
	// Timeout caps the single git invocation. Empty uses 10 seconds.
	Timeout time.Duration
}

GitMetadataConfig fills in edit links and last-updated dates from the repository, so neither has to be typed into every page's front matter and then left to rot.

Front matter always wins. A page that sets edit_url or last_updated keeps what it declared.

type Group

type Group struct {
	// contains filtered or unexported fields
}

Group scopes page and screen registration beneath a group path.

func (*Group) MustPage

func (g *Group) MustPage(path string, cfg PageConfig)

MustPage adds a page beneath the group and panics on invalid config.

func (*Group) MustPageFile

func (g *Group) MustPageFile(path string, cfg PageConfig)

MustPageFile adds a Markdown file beneath the group and panics on error.

func (*Group) MustScreen

func (g *Group) MustScreen(path string, cfg ScreenConfig)

MustScreen adds a typed screen beneath the group and panics on invalid config.

func (*Group) Page

func (g *Group) Page(path string, cfg PageConfig) error

Page adds a page beneath the group.

func (*Group) PageFile

func (g *Group) PageFile(path string, cfg PageConfig) error

PageFile adds a Markdown file beneath the group.

func (*Group) Route

func (g *Group) Route() *Route

Route returns the group node.

func (*Group) Screen

func (g *Group) Screen(path string, cfg ScreenConfig) error

Screen adds a typed screen beneath the group.

type GroupConfig

type GroupConfig struct {
	// Title is the group's label in navigation and search.
	Title string
	// Description is the group's meta description.
	Description string
	// Order sorts the group among its siblings; lower comes first.
	Order int
	// Hidden keeps the group out of navigation without unregistering its
	// pages.
	Hidden bool
	// Badge pins a small badge beside the group in sidebars and drawers.
	Badge NavBadge
	// Locale and Version place the group in a translated or versioned slice of
	// the site.
	//
	// A page takes these from its front matter, but a group is pure Go and has
	// no front matter to read, so without them a translated section could never
	// be paired with its original: variantFamily had no locale segment to
	// strip, and the language selector and header nav both went looking for a
	// counterpart that did not exist.
	Locale  string
	Version string
	// TranslationOf names the group this one translates, for a translated
	// section whose path does not mirror the original's. See
	// ContentMetadata.TranslationOf.
	TranslationOf string
}

GroupConfig describes a navigation group. Groups are metadata-only routes; their children are mounted as the actual GoFastr screens.

type Heading

type Heading struct {
	// ID is the anchor fragment the heading renders with.
	ID string
	// Title is the heading text.
	Title string
	// Level is 1 to 6; the rail and select carry the 2s and 3s.
	Level int
}

Heading is a Markdown heading exposed to a page table of contents.

type JSONSearchProvider

type JSONSearchProvider struct{}

JSONSearchProvider is the default portable search provider.

func (JSONSearchProvider) Build

func (JSONSearchProvider) Build(r *Router) ([]byte, error)

type LayoutConfig

type LayoutConfig struct {
	// Global builds the outermost layout wrapped around every
	// section; nil uses the built-in docs shell.
	Global func(*Router) *uiapp.Layout
	// Section builds the layout wrapping one top-level section;
	// nil keeps the built-in section shell with its sidebar.
	Section func(*Router, *Route) *uiapp.Layout
}

LayoutConfig lets a project replace the generated global or section shell while keeping route registration, navigation, and search in Router. A section factory receives the top-level route that owns the active layout. Returning nil uses the built-in shell for that level.

type LocaleNotFound

type LocaleNotFound struct {
	// Prefix is the language's path prefix, such as "/es". The longest
	// matching prefix wins.
	Prefix string
	// HomeHref is that language's home, so the recovery link does not drop the
	// reader into another language.
	HomeHref string
	// Strings holds the 404 labels for one language; a screen serving
	// several languages carries one per locale.
	Strings NotFoundStrings
}

LocaleNotFound is the 404 for URLs beneath one language's path prefix.

type ManifestRedirect

type ManifestRedirect struct {
	// From is the requested path; To is where it lands.
	From string `json:"from"`
	To   string `json:"to"`
}

ManifestRedirect is one source-to-target pair of the export's redirects.

type ManifestRoute

type ManifestRoute struct {
	// ID is the stable route identifier.
	ID string `json:"id"`
	// Path is the route path relative to the deployment base.
	Path string `json:"path"`
	// Title is the route heading and nav label.
	Title string `json:"title"`
	// Description is the route's meta description.
	Description string `json:"description,omitempty"`
	// Kind says whether the route is a page, screen, or group.
	Kind RouteKind `json:"kind"`
	// Locale is the language the route serves, empty for unmarked
	// routes.
	Locale string `json:"locale,omitempty"`
	// Version is the route's version variant, empty when the site
	// is not versioned.
	Version string `json:"version,omitempty"`
	// Tags label the route for tag views.
	Tags []string `json:"tags,omitempty"`
	// Offline says the service worker precaches the route.
	Offline bool `json:"offline,omitempty"`
	// NoIndex asks search engines to skip the route.
	NoIndex bool `json:"noIndex,omitempty"`
	// Blog says the route belongs to a publication collection.
	Blog bool `json:"blog,omitempty"`
	// BlogIndex marks a collection's generated landing view.
	BlogIndex bool `json:"blogIndex,omitempty"`
	// DatePublished is the page's publish date as declared, for consumers
	// that sort or display recency.
	DatePublished string `json:"datePublished,omitempty"`
	// Alternates maps language tags to the route's translations, the
	// hreflang pairs derived from the route tree.
	Alternates map[string]string `json:"alternates,omitempty"`
}

ManifestRoute is one published route in the export manifest, carrying the fields a static host or AI consumer needs: where it is, what it is called, which language and version it serves, and how it may be fetched.

type MarkdownChild

type MarkdownChild struct {
	// Name is the nested shortcode as written.
	Name string
	// Props are the nested shortcode's attributes.
	Props map[string]string
	// Body is the nested shortcode's inner text.
	Body render.HTML
}

MarkdownChild is one shortcode nested directly inside a container. Body is that child's own rendered output, so a child may itself be a component or another container.

type MarkdownCollectionPlugin

type MarkdownCollectionPlugin struct {
	// Path is the route prefix the collection mounts under.
	Path string
	// Dir is the disk directory of the collection; FS replaces it.
	Dir string
	// FS serves the collection from an embedded filesystem instead
	// of disk.
	FS fs.FS
	// Root is the subdirectory of FS the collection lives in.
	Root string
	// Config carries the collection's ordering, locale, and view
	// settings.
	Config CollectionConfig
}

MarkdownCollectionPlugin turns a directory of Markdown files into Router routes. It is the reusable content plugin behind generated projects and is intentionally independent of the CLI.

func (MarkdownCollectionPlugin) Apply

Apply mounts the collection's Markdown tree onto the Router, from disk or from the embedded FS.

func (MarkdownCollectionPlugin) Name

Name identifies the plugin in diagnostics.

type MarkdownComponent

type MarkdownComponent func(props map[string]string, body render.HTML) render.HTML

MarkdownComponent renders a typed component embedded in Markdown. Props are parsed from the shortcode's key/value attributes and body is already rendered Markdown, so a component can wrap headings, links, and prose with GoFastr UI primitives.

Example:

{{< callout variant="warning" >}}
Keep the route order explicit.
{{< /callout >}}

type MarkdownComponentsPlugin

type MarkdownComponentsPlugin struct {
	// Components maps each shortcode name to its implementation;
	// applying the plugin retires any earlier meaning the names had.
	Components map[string]MarkdownComponent
}

MarkdownComponentsPlugin registers a shared component vocabulary for Markdown shortcodes. It lets a plugin own both its component implementation and the authoring interface without requiring pages to repeat a map.

func (MarkdownComponentsPlugin) Apply

Apply registers every shortcode component in the map under its own name, retiring any earlier meaning the name had.

func (MarkdownComponentsPlugin) Name

Name identifies the plugin in diagnostics.

type MarkdownContainer

type MarkdownContainer func(props map[string]string, children []MarkdownChild, body render.HTML) render.HTML

MarkdownContainer renders a shortcode that needs its nested shortcodes as separate items rather than as one merged blob. Tabs, card grids, steps, and file trees all have to know where one child ends and the next begins, which a MarkdownComponent cannot see.

Children are the shortcodes nested directly inside it. Body is whatever Markdown sat between them, so a container can support both shapes.

Example:

{{< tabs >}}
{{< tab label="Go" >}}...{{< /tab >}}
{{< tab label="Shell" >}}...{{< /tab >}}
{{< /tabs >}}

type MarkdownDocument

type MarkdownDocument struct {
	// Metadata is the parsed front matter.
	Metadata ContentMetadata
	// Body is the Markdown with the front matter removed.
	Body string
}

MarkdownDocument is a parsed Markdown file with its front matter removed from Body. Keeping the two values together prevents search, TOC, and render paths from disagreeing about what the reader actually sees.

func LoadMarkdownFile

func LoadMarkdownFile(path string) (MarkdownDocument, error)

LoadMarkdownFile reads and parses a Markdown document from disk.

func ParseMarkdown

func ParseMarkdown(source string) (MarkdownDocument, error)

ParseMarkdown parses an optional YAML front matter block. A document without front matter remains valid Markdown and returns zero metadata.

type MarkdownRawComponent

type MarkdownRawComponent func(props map[string]string, raw string) render.HTML

MarkdownRawComponent renders a shortcode from its unrendered body. Use it when the content is data rather than prose: a diff patch, a file tree, a table. Rendering the body as Markdown first turns line structure into markup and there is no reliable way to get it back.

type MarkdownSourceTransform

type MarkdownSourceTransform func(source string, place func(render.HTML) string) string

MarkdownSourceTransform rewrites Markdown source before the parser runs.

A shortcode can only claim text a writer wrapped in {{< >}}. Some syntax is ambient instead: math delimited by $ appears mid-sentence, and rewriting it after parsing would mean pattern-matching rendered HTML, which cannot tell a dollar sign in prose from one in a code span.

place takes rendered HTML and returns an opaque marker to splice into the source in its stead. The Markdown parser only ever sees the marker, so the fragment survives untouched and nothing inside it is parsed as Markdown. This is the same mechanism option-carrying code fences already use.

type NavBadge struct {
	// Label is the badge text; it also titles the badge for
	// hover discovery.
	Label string
	// Tone selects the badge color.
	Tone NavBadgeTone
}

NavBadge adds concise, optional metadata to a route in the sidebar. Badges are presentation metadata only: they do not affect URLs, search, ordering, active state, or route visibility.

type NavBadgeTone string

NavBadgeTone controls the visual emphasis of a route badge. The label is project-owned, so a badge can say "New", "Popular", "Hot", "Beta", or any other short piece of navigation metadata without coupling the Router to a particular product vocabulary.

const (
	NavBadgeToneNeutral NavBadgeTone = "neutral"
	NavBadgeToneAccent  NavBadgeTone = "accent"
	NavBadgeToneInfo    NavBadgeTone = "info"
	NavBadgeToneSuccess NavBadgeTone = "success"
	NavBadgeToneWarning NavBadgeTone = "warning"
)
type NavItem struct {
	// ID mirrors Route.ID for the flattened view.
	ID string
	// Path is the route path, root-relative.
	Path string
	// Title is the nav label.
	Title string
	// Kind separates pages, screens, and groups.
	Kind RouteKind
	// Depth is the nesting level, zero at the top.
	Depth int
	// Active says this item is the current page.
	Active bool
	// Children are the nested items.
	Children int
	// Badge pins a small badge beside the item.
	Badge NavBadge
}

NavItem is a flattened, render-agnostic navigation item. Consumers can use it to render a sidebar, breadcrumbs, mobile navigation, or an API index.

type NotFoundScreen

type NotFoundScreen struct {
	// SiteName is drawn on the branded 404.
	SiteName string
	// HomeHref is the way back into the site.
	HomeHref string
	// Strings translates the page. Empty fields keep the English defaults, so
	// a host that does not localize passes nothing.
	Strings NotFoundStrings
	// Locales translates the page per language, matched against the URL that
	// was not found.
	//
	// The 404 is built once for the whole site, so unlike every other surface
	// it has no route to read a language from. The requested path is all there
	// is, and it is enough: a miss under /es is a Spanish reader who mistyped a
	// Spanish URL, and answering in English strands them.
	Locales []LocaleNotFound
}

NotFoundScreen is a small, framework-neutral 404 component for generated docs hosts. Mount it with uihost.WithNotFoundScreen so missing URLs keep the site's header, theme, and recovery link instead of falling back to a bare server response.

func (NotFoundScreen) Render

func (s NotFoundScreen) Render() render.HTML

Render draws the 404 without a request path; the host uses it when no path-specific variant is available.

func (NotFoundScreen) RenderNotFound

func (s NotFoundScreen) RenderNotFound(path string) render.HTML

RenderNotFound adds the unmatched path as escaped diagnostic text. The host passes the path per request, so the component remains safe to share between concurrent requests.

type NotFoundStrings

type NotFoundStrings struct {
	// Heading is the 404 page title. Short and capitalized.
	Heading string
	// Message is the static body line of the 404. Full sentence.
	Message string
	// MessageForURL is the body line naming the missed address. Format
	// string taking the requested path as %s.
	MessageForURL string
	// BackTo labels the way back into the site. Format string taking the
	// site name as %s.
	BackTo string
	// SiteFallback is the link text of the fallback to the site root.
	SiteFallback string
	// Search labels the way back into search from a dead end. One word.
	Search string
}

NotFoundStrings are the labels on the branded 404 page.

type OpenAPIPlugin

type OpenAPIPlugin struct {
	// SpecPath reads the OpenAPI document from a file; Spec wins when
	// both are set.
	SpecPath string
	// Spec is the OpenAPI document as bytes, for embedded specs.
	Spec []byte
	// Path mounts the reference; defaults to /api-reference.
	Path string
	// Title overrides the document's info.title in navigation.
	Title string
	// Description overrides the document's info.description.
	Description string
	// Order positions the reference among the site sections.
	Order int
}

OpenAPIPlugin adds a readable API reference page to the same Router as the rest of the site. It intentionally starts from the portable OpenAPI JSON spec; a richer renderer can later replace the generated Markdown while keeping this registration surface stable.

func (OpenAPIPlugin) Apply

func (p OpenAPIPlugin) Apply(r *Router) error

Apply validates the OpenAPI document, creates a generated reference page, and registers it as a plugin route. Spec is preferred in tests or embedded builds; SpecPath is resolved from the process working directory.

func (OpenAPIPlugin) Name

func (p OpenAPIPlugin) Name() string

Name identifies the plugin in diagnostics.

type Option

type Option func(*Router)

Option configures a Router.

func WithBrand

func WithBrand(config BrandConfig) Option

WithBrand applies white-label identity without coupling the docs package to a particular product or logo asset.

func WithContentSecurityPolicy

func WithContentSecurityPolicy(policy string) Option

WithContentSecurityPolicy replaces the default policy wholesale, for hosts that must match an organization-wide header. The framework's strict default is a good starting point: copy it before loosening.

func WithGitMetadata

func WithGitMetadata(config GitMetadataConfig) Option

WithGitMetadata derives last-updated dates, and optionally edit links, from git history.

It reads one `git log` for the whole repository rather than one per page, and it degrades silently: no git binary, no repository, or a shallow clone leaves every page exactly as authored. A documentation build must not depend on version-control history being present.

func WithIncludeDrafts

func WithIncludeDrafts(enabled bool) Option

WithIncludeDrafts makes draft routes available to navigation, search, and mounting. It is intended for local preview and content review; production projects should leave the default (false) in place.

func WithLanguage

func WithLanguage(language string) Option

WithLanguage sets the document language used by host adapters. It does not filter routes, which makes it safe for sites with runtime locale selectors.

func WithLayouts

func WithLayouts(config LayoutConfig) Option

WithLayouts installs optional layout factories. This is the extension point for a footer, custom section chrome, or a product-specific nested layout; callers do not need to fork Mount or duplicate route traversal.

func WithLocale

func WithLocale(locale string) Option

WithLocale limits published content to the requested content locale. Routes without a locale remain shared across every locale. Use WithLanguage when the goal is only to set the document language while keeping runtime locale variants mounted.

func WithLocaleFallback

func WithLocaleFallback(defaultLocale string) Option

WithLocaleFallback keeps a partially translated site usable. Without it, a page tagged `locale: en` simply disappears from a build for another locale, so the French site is missing pages rather than showing English ones.

With it, a route family that has no variant in the build locale falls back to the variant in defaultLocale. A family that does have a translation is unaffected, so a fallback never shadows real translated content. An empty defaultLocale falls back to routes that carry no locale at all.

func WithLocaleNames

func WithLocaleNames(names map[string]string) Option

WithLocaleNames gives locales the names a reader should see in the language selector. Without it the selector shows raw codes, and "es" is a worse label than "Español" for exactly the person who needs it.

Go's standard library carries no locale display names, so a project supplies them rather than the framework pretending to know.

func WithLocaleUIStrings

func WithLocaleUIStrings(locale string, strings UIStrings) Option

WithLocaleUIStrings translates the chrome for one locale.

WithUIStrings sets labels for the whole Router, which is all a site needs when one build serves one language. A site that serves several locales from a single build needs a set per locale, or its Spanish pages come wrapped in English furniture: "Contents", "On this page", "Search".

Fields left empty fall back to WithUIStrings, and then to the English defaults, so a locale can be translated a label at a time.

func WithPageScript

func WithPageScript(name, js string) Option

WithPageScript contributes a project script to the runtime asset set: it is served beside docs.js and listed by RuntimeScriptNames, so analytics or product glue ships without editing the generated host.

func WithPagefind

func WithPagefind() Option

WithPagefind is the explicit form of WithSearchBackend for projects that want Pagefind in static exports and the native command palette.

func WithPagefindPath

func WithPagefindPath(path string) Option

WithPagefindPath changes the URL prefix used to load the generated Pagefind runtime. The default is /pagefind/; custom prefixes are useful when an export is mounted below a reverse-proxy asset path.

func WithSearchBackend

func WithSearchBackend(backend string) Option

WithSearchBackend selects the browser search integration. Invalid values fall back to JSON so a typo cannot make a development server unusable.

func WithSearchIndexPath

func WithSearchIndexPath(path string) Option

WithSearchIndexPath changes the URL the browser runtime fetches for the JSON search index. The default is /__fastr-docs/search.json, which matches the asset prefix the generated starter mounts. Hosts that serve the docs assets from another prefix must set this, or the command palette silently falls back to an unfiltered route list.

func WithSearchProvider

func WithSearchProvider(provider SearchProvider) Option

WithSearchProvider replaces the default local JSON search artifact.

func WithSearchWeights

func WithSearchWeights(weights map[string]int) Option

WithSearchWeights tunes the built-in ranker. The map names a field (title, headings, description, tags, body) and the weight a term match there adds; fields left out keep their defaults, and unknown names are ignored.

func WithSiteName

func WithSiteName(name string) Option

WithSiteName sets the generated site name used by adapters and templates.

func WithStrictValidation

func WithStrictValidation(enabled bool) Option

WithStrictValidation keeps the default safety checks enabled or explicitly disables them for an advanced project. The CLI never disables strict mode unless the project opts out in code.

func WithTemplate

func WithTemplate(template Template) Option

WithTemplate selects one of the built-in visual templates. It preserves any token overrides supplied by an earlier WithTheme option, which makes option order safe for composition.

func WithTheme

func WithTheme(config ThemeConfig) Option

WithTheme selects a template and/or applies semantic token overrides. A zero Template keeps the current template, allowing callers to write only the custom values they need:

docs.WithTheme(docs.ThemeConfig{
	Template: docs.TemplateBlueprint,
	Overrides: docs.ThemeOverrides{Primary: "#155E9A"},
})

func WithUIStrings

func WithUIStrings(strings UIStrings) Option

WithUIStrings overrides the framework-owned labels. Empty fields retain the English defaults, so a project can translate one label at a time.

func WithVersion

func WithVersion(version string) Option

WithVersion limits published content to the requested documentation version. Routes without a version remain shared across every version.

func WithoutDefaultComponents

func WithoutDefaultComponents() Option

WithoutDefaultComponents drops the built-in shortcode vocabulary. Use it when a project wants Markdown to fail on any shortcode it did not register itself.

type PageConfig

type PageConfig struct {
	// Title is the page heading and nav label.
	Title string
	// Description is the page's meta description and search entry.
	Description string
	// Source is the Markdown body as a string, for pages authored in Go.
	Source string
	// SourcePath reads the Markdown body from a file; relative to the
	// project, resolved by the caller.
	SourcePath string
	// Body supplies the rendered HTML directly, bypassing Markdown
	// entirely.
	Body func() render.HTML
	// ContextBody is the request-aware form of Body. It is useful for
	// server-rendered aggregate views such as a blog search page. During
	// static export it receives a background context and should render the
	// canonical, query-free view.
	ContextBody func(context.Context) render.HTML
	// SearchText overrides the text fed to the search index; empty uses
	// the rendered content.
	SearchText string
	// Preload asks GoFastr to prefetch this route on hover, visibility, or
	// idle. Leave empty to keep the route opt-in and never prefetched.
	Preload string
	// DisableTOC drops the heading rail and its mobile select.
	DisableTOC bool
	// Order sorts the page among its siblings; lower comes first.
	Order int
	// Offline marks the page precacheable by the service worker.
	Offline bool
	// Hidden keeps the page out of navigation while it still serves.
	Hidden bool
	// Tags label the page for blog tag views.
	Tags []string
	// Metadata is the page's front-matter equivalent: locale, version,
	// translation pairing, redirects, and the rest.
	Metadata ContentMetadata
	// Badge pins a small badge beside the page in sidebars and drawers.
	Badge NavBadge
	// Components exposes typed GoFastr renderers to Markdown through the
	// {{< name key="value" >}} shortcode syntax. Components are rendered
	// server-side and may contain nested Markdown content.
	Components map[string]MarkdownComponent
	// Containers are shortcodes that receive their nested shortcodes as
	// separate children rather than one merged body, which is what tabs,
	// card grids, and steps need.
	Containers map[string]MarkdownContainer
}

PageConfig describes a Markdown or server-rendered documentation page. Source is Markdown when Body is nil. Body is useful when a page needs a custom GoFastr component-like render function but is still a docs page.

type PageHero

type PageHero struct {
	// Eyebrow is the small line above the hero title.
	Eyebrow string `json:"eyebrow,omitempty" yaml:"eyebrow,omitempty"`
	// Title is the hero heading.
	Title string `json:"title,omitempty" yaml:"title,omitempty"`
	// Tagline is the supporting line under the title.
	Tagline string `json:"tagline,omitempty" yaml:"tagline,omitempty"`
	// Actions are the call-to-action buttons, in order.
	Actions []PageHeroAction `json:"actions,omitempty" yaml:"actions,omitempty"`
}

PageHero is the front-matter-driven hero of a splash page, so a landing page does not require writing a typed screen.

type PageHeroAction

type PageHeroAction struct {
	// Text is the button label.
	Text string `json:"text,omitempty" yaml:"text,omitempty"`
	// Link is the button target.
	Link string `json:"link,omitempty" yaml:"link,omitempty"`
	// Variant selects the button style.
	Variant string `json:"variant,omitempty" yaml:"variant,omitempty"`
}

PageHeroAction is one call-to-action button in a hero.

type PageScript

type PageScript struct {
	Name string
	JS   string
}

PageScript is one host-mountable browser script contributed by the project alongside the framework runtime.

type PageScriptPlugin

type PageScriptPlugin interface {
	RuntimeAssetPlugin
	// PageScripts returns the subset of RuntimeAssets names to load on every
	// page. An empty slice means the plugin has no page script at all.
	PageScripts() []string
}

PageScriptPlugin narrows which of a plugin's runtime assets belong in a <script> tag on every page.

Without this, a project picks page scripts by file extension, and any .js a plugin contributes is loaded on every page. That is wrong for a plugin whose bundle is meant for somewhere else: the Mermaid frame bundle is several megabytes and is loaded by the frame document, never by the page.

type Plugin

type Plugin interface {
	Name() string
	Apply(*Router) error
}

Plugin contributes routes or metadata to a Router.

type RSSConfig

type RSSConfig struct {
	// Prefix names the collection whose published posts feed this
	// channel.
	Prefix string
	// Title is the channel title; empty uses the collection's.
	Title string
	// Description is the channel description; empty uses the
	// collection's.
	Description string
	// SiteURL is the absolute origin of the site, needed for valid
	// RSS link elements on a static export.
	SiteURL string
	// FeedPath is the URL the feed itself is served at, used for the
	// channel's atom:link rel="self". Empty derives prefix + "/feed.xml".
	FeedPath string
	// Limit caps the item count; zero includes every published post.
	Limit int
}

RSSConfig controls the RSS projection of a blog route collection.

type Route

type Route struct {
	// ID is the stable identifier derived from the path.
	ID string
	// Path is the route path, root-relative.
	Path string
	// Title is the nav label and page heading.
	Title string
	// Description is the meta description.
	Description string
	// Kind separates pages, screens, and metadata-only groups.
	Kind RouteKind
	// Order sorts the route among its siblings.
	Order int
	// Hidden keeps the route out of navigation while it still serves.
	Hidden bool
	// Offline marks the route precacheable by the service worker.
	Offline bool
	// Tags label the route for tag views.
	Tags []string
	// Plugin names the plugin that contributed the route, empty for
	// project-owned routes.
	Plugin string
	// SearchText is what the search index stores; empty derives it
	// from the rendered content.
	SearchText string
	// Preload asks GoFastr to prefetch the route on hover or idle.
	Preload string
	// Metadata carries locale, version, pairing, and redirects.
	Metadata ContentMetadata
	// Badge pins a small badge beside the route in sidebars and
	// drawers.
	Badge NavBadge
	// Blog marks a route as a post or archive entry created by MarkdownBlog.
	// BlogIndex distinguishes the archive route from individual posts.
	Blog bool
	// BlogIndex marks a publication collection's generated landing.
	BlogIndex bool
	// Parent links up the tree; nil at the root.
	Parent *Route
	// Children are the nested routes, in explicit order with
	// registration order as tie-breaker.
	Children []*Route
	// contains filtered or unexported fields
}

Route is a node in the docs route tree. Children are always returned in explicit order, with registration order as the stable tie-breaker.

func (*Route) HeroActions

func (route *Route) HeroActions() []PageHeroAction

HeroActions returns the splash hero's actions, empty when there is no hero, so validation can range without a nil guard.

type RouteKind

type RouteKind string

RouteKind identifies how a route is rendered.

const (
	KindGroup  RouteKind = "group"
	KindPage   RouteKind = "page"
	KindScreen RouteKind = "screen"
	KindPlugin RouteKind = "plugin"
)

type Router

type Router struct {
	// contains filtered or unexported fields
}

Router is the central object for a documentation site. Register pages, screens, groups, and plugins here; adapters and generators derive their navigation and search surfaces from the same object.

func NewRouter

func NewRouter(options ...Option) *Router

NewRouter creates a strict Router. Strict validation is intentionally the default so broken links, missing titles, duplicate order, and unusable content fail during startup or build instead of shipping silently.

func (*Router) AllowConnectOrigin

func (r *Router) AllowConnectOrigin(raw string)

AllowConnectOrigin records an origin that a browser-side extension is expected to contact. The generated GoFastr host can use ConnectOrigins to extend its strict CSP without allowing arbitrary network destinations.

func (*Router) AssetPrefix

func (r *Router) AssetPrefix() string

AssetPrefix returns the prefix the runtime assets are served from, matching the configured search index path so the two cannot disagree.

func (*Router) BlogPosts

func (r *Router) BlogPosts(prefix string) []*Route

BlogPosts returns visible blog posts beneath prefix, newest first. The archive route itself is excluded. No-index posts remain available here so a project can choose whether an internal archive should link to them; RSSXML excludes them from the public feed.

func (*Router) Brand

func (r *Router) Brand() BrandConfig

Brand returns a copy of the configured white-label identity.

func (*Router) BrandCSS

func (r *Router) BrandCSS() string

BrandCSS emits the optional token overrides for a host stylesheet.

func (*Router) CSS

func (r *Router) CSS() string

CSS returns the white-label visual layer around GoFastr's UI components. The framework still owns structure and interaction; these rules own the fastr-docs editorial identity, responsive placement, and semantic tokens.

func (*Router) ConnectOrigins

func (r *Router) ConnectOrigins() []string

ConnectOrigins returns the normalized external origins declared by extensions on this router.

func (*Router) ContentIssues

func (r *Router) ContentIssues() []ContentIssue

ContentIssues checks internal Markdown links and heading fragments without making network requests. External HTTP links are intentionally left to a deployment-time checker because a documentation build must remain deterministic and usable offline.

func (*Router) ContentSecurityPolicy

func (r *Router) ContentSecurityPolicy() string

ContentSecurityPolicy returns the effective policy for this Router: the project's override when set, otherwise the strict default with the declared connect origins.

func (*Router) DirectionFor

func (r *Router) DirectionFor(path string) string

DirectionFor returns "rtl" or "ltr" for the document served at path, resolved the way LanguageFor resolves the language: the route's effective locale, or the deepest route above an unmatched path.

func (*Router) ExportManifestJSON

func (r *Router) ExportManifestJSON(basePath string) ([]byte, error)

ExportManifestJSON builds a deterministic manifest for the current public route slice and deployment base path.

func (*Router) Group

func (r *Router) Group(path string, cfg GroupConfig) (*Group, error)

Group adds a metadata group and returns a scoped registrar for its children.

func (*Router) Language

func (r *Router) Language() string

Language returns the document language for the host shell. It is separate from Locale, which is an optional build-time content filter.

func (*Router) LanguageFor

func (r *Router) LanguageFor(path string) string

func (*Router) Layout

func (r *Router) Layout() *uiapp.Layout

Layout returns the global white-label shell derived from this Router. Top-level route sections are nested inside this shell by Mount, allowing each section to own its own layout and navigation without duplicating the global header, search, theme, or PWA chrome.

func (*Router) Locale

func (r *Router) Locale() string

Locale returns the active content locale filter, if one was configured.

func (*Router) LocaleCoverage

func (r *Router) LocaleCoverage() map[string][]string

LocaleCoverage reports, for every locale present in the route tree, which families are missing a translation.

func (*Router) LocaleName

func (r *Router) LocaleName(locale string) string

LocaleName returns the display name for a locale, falling back to the code itself so a selector is never empty.

func (*Router) Locales

func (r *Router) Locales() []string

Locales returns the sorted locale values present in published route variants. It describes the whole registered site, not only the active WithLocale filter, so headers, export tools, and external adapters can build their own selectors without walking Route nodes.

func (*Router) Markdown

func (r *Router) Markdown(path string, title string, source string) error

Markdown is a named convenience for Page when the source is Markdown.

func (*Router) MarkdownBlog

func (r *Router) MarkdownBlog(prefix, dir string, cfg BlogConfig) error

MarkdownBlog registers an archive and all Markdown posts found beneath dir. Disk-backed posts retain SourcePath, so the normal development reload loop can reread changed content without introducing a second content system.

func (*Router) MarkdownBlogFS

func (r *Router) MarkdownBlogFS(prefix string, content fs.FS, root string, cfg BlogConfig) error

MarkdownBlogFS is the embedded or virtual-filesystem form of MarkdownBlog. It captures document bodies at registration, matching MarkdownCollectionFS.

func (*Router) MarkdownCollection

func (r *Router) MarkdownCollection(prefix, dir string, cfg CollectionConfig) error

MarkdownCollection registers every Markdown file beneath dir. `index.md` maps to the collection prefix; nested files map to their relative path. This is the reusable content-collection primitive behind generated sites.

func (*Router) MarkdownCollectionFS

func (r *Router) MarkdownCollectionFS(prefix string, content fs.FS, root string, cfg CollectionConfig) error

MarkdownCollectionFS registers Markdown content from any fs.FS, including embed.FS, fstest.MapFS, and application-provided virtual filesystems. `root` is an fs.ValidPath relative to content; use "." for the filesystem root. Unlike MarkdownCollection, the document body is captured at registration so a virtual filesystem does not need to masquerade as an OS path.

func (*Router) MarkdownComponents

func (r *Router) MarkdownComponents() map[string]MarkdownComponent

MarkdownComponents returns a copy of the registered Markdown components by name, so callers can inspect or compose them without being able to mutate the Router's registry.

func (*Router) MarkdownContainers

func (r *Router) MarkdownContainers() map[string]MarkdownContainer

MarkdownContainers returns the registered container vocabulary.

func (*Router) MarkdownRawComponents

func (r *Router) MarkdownRawComponents() map[string]MarkdownRawComponent

MarkdownRawComponents returns the registered raw vocabulary.

func (*Router) MarkdownSourceTransformNames

func (r *Router) MarkdownSourceTransformNames() []string

MarkdownSourceTransformNames lists the registered transforms in the order they run.

func (*Router) MarkdownVersionedCollection

func (r *Router) MarkdownVersionedCollection(prefix, dir string, cfg VersionedCollectionConfig) error

MarkdownVersionedCollection registers disk-backed Markdown snapshots from one directory per version. It preserves the ordinary MarkdownCollection behavior for front matter, locale prefixes, drafts, search, and validation.

func (*Router) MarkdownVersionedCollectionFS

func (r *Router) MarkdownVersionedCollectionFS(prefix string, content fs.FS, root string, cfg VersionedCollectionConfig) error

MarkdownVersionedCollectionFS registers versioned Markdown snapshots from an fs.FS, including embed.FS. The root has the same child-directory layout as MarkdownVersionedCollection.

func (*Router) Mount

func (r *Router) Mount(site *uiapp.App, layout *uiapp.Layout) error

Mount registers every navigable route with a GoFastr UI app. The route metadata remains owned by docs.Router; GoFastr owns rendering, DI, policies, and lifecycle after registration.

func (*Router) MountAssets

func (r *Router) MountAssets(httpRouter *router.Router, cfg AssetConfig) error

MountAssets serves public assets from the same host as the docs app. The framework static handler supplies MIME types, ETags, cache headers, and traversal/dotfile protection.

func (*Router) MountCommandPalette

func (r *Router) MountCommandPalette(httpRouter *gofastrRouter.Router) error

MountCommandPalette mounts GoFastr's native command/search surface. The visible trigger is rendered by Layout; the widget itself must be mounted on the host router once, just like any other GoFastr widget.

func (*Router) MountNavigation

func (r *Router) MountNavigation(httpRouter *gofastrRouter.Router) error

MountNavigation mounts the framework-owned mobile docs Sidebar drawers. Call it on the GoFastr HTTP router after creating the UI host and before starting or exporting the application. The route tree remains owned by this Router; GoFastr owns drawer focus, escape handling, backdrop, and scroll locking.

One drawer is mounted per language, because a widget's body is fixed at mount time and a single drawer would serve every page the default locale's tree. Each drawer also carries a section select above the tree: below md the header tabs are hidden and the drawer is the only navigation left.

func (*Router) MountPluginAssets

func (r *Router) MountPluginAssets(httpRouter *gofastrRouter.Router) error

MountPluginAssets invokes optional asset hooks after the host HTTP router exists. It is safe to call more than once for idempotent plugins, but a project should normally call it once during host setup.

func (*Router) MountRSS

func (r *Router) MountRSS(httpRouter *gofastrRouter.Router, path string, cfg RSSConfig) error

MountRSS mounts a live RSS endpoint on the GoFastr HTTP router. The feed is rendered per request so a development server sees metadata changes without duplicating route registration or content loading.

func (*Router) MountRuntimeAssets

func (r *Router) MountRuntimeAssets(httpRouter *gofastrRouter.Router, prefix, exportBase string) error

MountRuntimeAssets serves the collected assets under prefix. An empty prefix uses DefaultAssetPrefix.

func (*Router) MustGroup

func (r *Router) MustGroup(path string, cfg GroupConfig) *Group

MustGroup is the concise form for declarative app setup. It panics during startup when the route tree is malformed, which is preferable to a server running with an incomplete navigation tree.

func (*Router) MustPage

func (r *Router) MustPage(path string, cfg PageConfig)

MustPage registers a page and panics on invalid configuration.

func (*Router) MustPageFile

func (r *Router) MustPageFile(path string, cfg PageConfig)

MustPageFile is the panic-on-error form of PageFile.

func (*Router) MustScreen

func (r *Router) MustScreen(path string, cfg ScreenConfig)

MustScreen registers a typed screen and panics on invalid configuration.

func (*Router) Navigation

func (r *Router) Navigation() []NavItem

Navigation returns a flattened navigation model, including groups, in the same order the site should render them.

func (*Router) NavigationAt

func (r *Router) NavigationAt(currentPath string) []NavItem

NavigationAt returns the flattened navigation model with active state derived from currentPath. Prefix matching keeps a parent page/group active while a nested route is open; the root route only matches exactly.

func (*Router) NavigationDrawerNames

func (r *Router) NavigationDrawerNames() []string

NavigationDrawerNames lists every navigation drawer this Router mounts: the default drawer, one per additional locale, and one per blog collection. The export manifest publishes them so an offline host can precache exactly the chrome that exists.

func (*Router) NotFoundScreen

func (r *Router) NotFoundScreen() NotFoundScreen

NotFoundScreen builds the 404 for this Router, already translated.

A project can construct NotFoundScreen itself, but it would have to restate what the Router already knows: which languages exist, where each one's home is, and what its labels are. Getting any of those wrong is invisible until someone mistypes a URL.

func (*Router) Page

func (r *Router) Page(path string, cfg PageConfig) error

Page registers a page at path.

func (*Router) PageFile

func (r *Router) PageFile(path string, cfg PageConfig) error

PageFile registers a Markdown page whose source is loaded and validated from SourcePath during registration. Keeping the path in the route config means a generated project does not need boilerplate file-reading helpers.

func (*Router) PageScripts

func (r *Router) PageScripts() []PageScript

PageScripts lists the project-contributed scripts in registration order.

func (*Router) PagefindPath

func (r *Router) PagefindPath() string

PagefindPath returns the static Pagefind bundle directory used by the browser runtime.

func (*Router) PublishedRoutes

func (r *Router) PublishedRoutes() []*Route

PublishedRoutes returns routes safe for a public build. Drafts, hidden routes, and routes outside the active locale/version are excluded.

func (*Router) RSSXML

func (r *Router) RSSXML(cfg RSSConfig) ([]byte, error)

RSSXML returns a valid RSS 2.0 document for the published posts beneath cfg.Prefix. Links are absolute when SiteURL is configured and otherwise remain route-relative, which keeps local development deterministic.

func (*Router) RegisterMarkdownComponent

func (r *Router) RegisterMarkdownComponent(name string, component MarkdownComponent) error

RegisterMarkdownComponent adds a reusable typed component to every Markdown page. PageConfig.Components remains available for page-local registrations; global components are useful for a project's shared callouts, tabs, code samples, or custom content blocks.

func (*Router) RegisterMarkdownContainer

func (r *Router) RegisterMarkdownContainer(name string, container MarkdownContainer) error

MarkdownComponents returns a copy of the globally registered Markdown component registry for adapters, tooling, and plugin validation. RegisterMarkdownContainer registers a shortcode that receives its nested shortcodes as separate children. A name may resolve to a component or a container, so registering one clears the other.

func (*Router) RegisterMarkdownRawComponent

func (r *Router) RegisterMarkdownRawComponent(name string, raw MarkdownRawComponent) error

RegisterMarkdownRawComponent registers a shortcode that receives its body unrendered. A name resolves to one kind, so registering one retires the rest.

func (*Router) RegisterMarkdownSourceTransform

func (r *Router) RegisterMarkdownSourceTransform(name string, transform MarkdownSourceTransform) error

RegisterMarkdownSourceTransform adds a source rewriter, which runs on every Markdown page before shortcodes expand. Registering the same name twice replaces the earlier transform rather than running both.

Transforms run in registration order. Keep one narrow: a transform that claims text another one wanted makes the two order-dependent.

func (*Router) Routes

func (r *Router) Routes() []*Route

Routes returns all navigable (non-group) routes in stable tree order.

func (*Router) RuntimeAssetNames

func (r *Router) RuntimeAssetNames(exportBase string) ([]string, error)

RuntimeAssetNames lists the collected asset names, sorted. Useful for precache lists and for asserting an export is complete.

func (*Router) RuntimeAssets

func (r *Router) RuntimeAssets(exportBase string) (map[string][]byte, error)

RuntimeAssets collects every file that belongs under the docs asset prefix: the browser runtime, the search index, the export manifest, and whatever each registered plugin contributes.

Before this existed, each of those was written out by hand in the generated main.go, once for serving and again for export, so adding any asset-bearing plugin meant editing every project that wanted it.

func (*Router) RuntimeScriptNames

func (r *Router) RuntimeScriptNames(exportBase string) ([]string, error)

RuntimeScriptNames lists the assets that belong in a page <script> tag, sorted, relative to the asset prefix.

A plugin that does not implement PageScriptPlugin contributes every .js file it owns, which is what a single-file browser runtime wants.

func (*Router) Screen

func (r *Router) Screen(path string, cfg ScreenConfig) error

Screen registers a typed GoFastr component in the same route tree.

func (*Router) Search

func (r *Router) Search(query string) []SearchResult

Search ranks published content using title, description, tags, headings, and body text. Exact title matches receive the strongest weight; ties are stable in intentional route order.

func (*Router) SearchBackend

func (r *Router) SearchBackend() SearchBackend

SearchBackend returns the configured browser search backend.

func (*Router) SearchIndex

func (r *Router) SearchIndex() []SearchEntry

SearchIndex returns records for visible navigable routes. Markdown source is preserved as text so a local indexer can tokenize it later.

func (*Router) SearchIndexCacheControl

func (r *Router) SearchIndexCacheControl() string

SearchIndexCacheControl returns the Cache-Control header a host should serve the JSON search index with. The index is content-addressed per build, so it is immutable and safe to cache hard.

func (*Router) SearchIndexJSON

func (r *Router) SearchIndexJSON() ([]byte, error)

SearchIndexJSON serializes the portable search records for a local static indexer such as Pagefind or a small client-side search worker.

func (*Router) SearchIndexPath

func (r *Router) SearchIndexPath() string

SearchIndexPath returns the URL the browser runtime fetches for the JSON search index.

func (*Router) SearchLimited

func (r *Router) SearchLimited(query string, limit int) []SearchResult

SearchLimited bounds the result count, so a caller showing three hints under a search box does not rank the whole index and truncate by hand.

func (*Router) SiteName

func (r *Router) SiteName() string

SiteName returns the configured site name.

func (*Router) Sitemap

func (r *Router) Sitemap() []byte

Sitemap builds a sitemap.xml URL set from the published routes: every servable path that search engines may index, with the locale alternates each page pairs with. NoIndex pages are left out.

func (*Router) SitemapExcludePaths

func (r *Router) SitemapExcludePaths() []string

SitemapExcludePaths returns route prefixes that must not be emitted in a sitemap: hidden, draft, locale/version-inactive, and explicit noindex content. Hosts can pass the result directly to uihost.SitemapConfig.

func (*Router) Template

func (r *Router) Template() Template

Template returns the active visual template.

func (*Router) Theme

func (r *Router) Theme() style.Theme

Theme returns the complete adaptive GoFastr theme for the active template. Hosts should pass this directly to uiapp.NewApp(...).WithTheme(...).

func (*Router) ThemeCSS

func (r *Router) ThemeCSS() string

ThemeCSS returns the template-specific structural layer. GoFastr emits the semantic color, typography, radius, and dark-mode variables from Router.Theme; this layer applies those variables to the documentation shell and adds the small visual signature that distinguishes each template.

func (*Router) ThemeColor

func (r *Router) ThemeColor() string

ThemeColor returns the browser chrome color for the active theme. A brand override wins; otherwise the light background token is used as the stable metadata value for both color schemes.

func (*Router) ThemeConfig

func (r *Router) ThemeConfig() ThemeConfig

ThemeConfig returns a copy of the active theme configuration.

func (*Router) Tree

func (r *Router) Tree() []*Route

Tree returns a copy of the root slice. Route nodes are immutable after registration by convention; callers should not mutate them.

func (*Router) UIStrings

func (r *Router) UIStrings() UIStrings

UIStrings returns the effective labels used by this Router.

func (*Router) UIStringsForLocale

func (r *Router) UIStringsForLocale(locale string) UIStrings

UIStringsForLocale returns the labels for one locale, merged over the Router-wide strings and the English defaults.

func (*Router) UntranslatedFamilies

func (r *Router) UntranslatedFamilies(locale string) []string

func (*Router) Use

func (r *Router) Use(plugin Plugin) error

Use applies a plugin to this Router. A plugin is not a separate app: its routes become ordinary children of the same route tree.

func (*Router) Validate

func (r *Router) Validate() error

Validate checks the full route tree and returns all problems together.

func (*Router) ValidateContent

func (r *Router) ValidateContent() error

ValidateContent returns all Markdown link and anchor problems as one error. Callers that need structured diagnostics should use ContentIssues directly.

func (*Router) Version

func (r *Router) Version() string

Version returns the active documentation version filter, if one was configured.

func (*Router) Versions

func (r *Router) Versions() []string

Versions returns the sorted documentation version values present in published route variants. Version lifecycle tools can use this inventory to show or validate available versions while Router remains the source of truth for the actual pages.

func (*Router) Warnings

func (r *Router) Warnings() []string

Warnings reports advisory findings that never fail Validate: draft pages counting down to publication, and locale label sets that are only partly translated. A build stays usable while incomplete; these are the notes that say what is still rough.

func (*Router) WriteExportManifest

func (r *Router) WriteExportManifest(w io.Writer, basePath string) error

WriteExportManifest writes ExportManifestJSON to a deployment artifact.

func (*Router) WriteRuntimeAssets

func (r *Router) WriteRuntimeAssets(dir, prefix, exportBase string) error

WriteRuntimeAssets writes the collected assets into a static export.

func (*Router) WriteSearchIndex

func (r *Router) WriteSearchIndex(w io.Writer) error

WriteSearchIndex writes SearchIndexJSON to an output stream.

type RuntimeAssetPlugin

type RuntimeAssetPlugin interface {
	Plugin
	// RuntimeAssets returns file names relative to the asset prefix.
	RuntimeAssets() (map[string][]byte, error)
}

RuntimeAssetPlugin contributes files to the docs asset prefix. Implement it so a project never has to hand-wire a plugin's browser runtime into its own main.go, for both serving and static export.

type ScreenConfig

type ScreenConfig struct {
	// Title is the screen heading and nav label.
	Title string
	// Description is the screen's meta description.
	Description string
	// Component renders the screen's body; it owns everything inside the
	// content column.
	Component component.Component
	// SearchText is what the search index stores for the screen; screens
	// have no Markdown to derive it from.
	SearchText string
	// Preload asks GoFastr to prefetch this route on hover, visibility, or
	// idle. Leave empty to keep the route opt-in and never prefetched.
	Preload string
	// Plugin names the plugin that contributed the screen, surfaced for
	// provenance.
	Plugin string
	// Order sorts the screen among its siblings; lower comes first.
	Order int
	// Offline marks the screen precacheable by the service worker.
	Offline bool
	// Hidden keeps the screen out of navigation while it still serves.
	Hidden bool
	// Tags label the screen for blog tag views.
	Tags []string
	// Metadata carries locale and version for the screen, the same fields
	// front matter would give a page; a translated plugin mount sets it so its
	// section pairs with the original.
	Metadata ContentMetadata
	// Badge pins a small badge beside the screen in sidebars and drawers.
	Badge NavBadge
}

ScreenConfig registers an arbitrary typed GoFastr component in the same documentation tree as Markdown pages.

type SearchBackend

type SearchBackend string

SearchBackend selects how the command palette answers on this site: the JSON index the Router builds, or a Pagefind index built over the export. WithSearchBackend sets it.

const (
	SearchBackendJSON     SearchBackend = "json"
	SearchBackendPagefind SearchBackend = "pagefind"
)

type SearchEntry

type SearchEntry struct {
	// ID is the stable record identifier.
	ID string `json:"id"`
	// Path is the page the entry points at.
	Path string `json:"path"`
	// Title heads the result.
	Title string `json:"title"`
	// Description is the result's summary line.
	Description string `json:"description"`
	// Text is the searchable body the index matches against.
	Text string `json:"text"`
	// Tags join the searchable text.
	Tags []string `json:"tags,omitempty"`
	// Locale is the page's language; the JSON backend filters
	// results to the reader's language with it.
	Locale string `json:"locale,omitempty"`
	// Version is the page's version variant.
	Version string `json:"version,omitempty"`
	// EditURL links the result to its source.
	EditURL string `json:"editUrl,omitempty"`
	// Canonical is the page's canonical URL.
	Canonical string `json:"canonical,omitempty"`
	// NoIndex says the page asked search engines to skip it.
	NoIndex bool `json:"noIndex,omitempty"`
	// Kind separates pages, screens, and groups.
	Kind RouteKind `json:"kind,omitempty"`
	// Order breaks score ties the way the tree does.
	Order int `json:"order,omitempty"`
	// Headings carry the page's table of contents into the entry.
	Headings []string `json:"headings,omitempty"`
	// Alternates maps language tags to the entry's translations, the
	// hreflang pairs derived from the route tree.
	Alternates map[string]string `json:"alternates,omitempty"`
}

SearchEntry is the portable local-search record produced by the Router. A static indexer such as Pagefind can consume these records without knowing anything about GoFastr.

type SearchProvider

type SearchProvider interface {
	Build(*Router) ([]byte, error)
}

SearchProvider lets a project replace the JSON artifact with a richer index such as Pagefind while keeping route registration in the central Router.

type SearchResult

type SearchResult struct {
	// Entry is the matched record.
	Entry SearchEntry
	// Score ranks the result; higher wins.
	Score int
	// Matches are the terms that hit, for highlighting.
	Matches []string
}

SearchResult is a ranked local-search result. The Router's built-in search is deliberately small and dependency-free, while SearchIndexJSON remains a portable hand-off point for Pagefind or another static indexer.

type Template

type Template string

Template selects the visual starting point for a documentation site. Templates are build-time choices: they change the visual system while the Router, route tree, content, search, PWA, and plugin behavior stay the same.

const (
	// TemplateEditorial is the default warm, compact documentation theme.
	TemplateEditorial Template = "editorial"
	// TemplateTerminal is a monospace, high-contrast command-line theme.
	TemplateTerminal Template = "terminal"
	// TemplateBlueprint is a cool, technical theme with grid details.
	TemplateBlueprint Template = "blueprint"
	// TemplateStudio is a softer, expressive product-studio theme.
	TemplateStudio Template = "studio"
	// TemplateNotebook is a reading-first paper and serif theme.
	TemplateNotebook Template = "notebook"
)

func ParseTemplate

func ParseTemplate(value string) Template

ParseTemplate normalizes a template name from configuration or an environment variable. Unknown or empty values intentionally fall back to the safe editorial default. ParseTemplate folds case and whitespace; an unknown name still resolves to the editorial default, and Warnings says so.

func ThemeTemplates

func ThemeTemplates() []Template

ThemeTemplates returns the five supported starting points in gallery order.

type ThemeConfig

type ThemeConfig struct {
	// Template is the starting point; one of ThemeTemplates.
	Template Template
	// Overrides replace individual theme variables.
	Overrides ThemeOverrides
	// CustomCSS is appended after the theme, for brand rules.
	CustomCSS string
}

func (ThemeConfig) Variables

func (c ThemeConfig) Variables() map[string]string

ThemeConfig selects a template and optionally overrides its semantic tokens. CustomCSS is appended after the fastr-docs visual layer, so it is suitable for project-specific components and small layout adjustments. Keep it in source control and treat it as trusted CSS. Variables returns the theme's CSS custom properties as data: the template's baseline with this config's overrides applied. Tooling can diff or preview a theme without parsing CSS.

type ThemeOverrides

type ThemeOverrides = uitheme.Overrides

ThemeOverrides is the GoFastr semantic token set exposed through the fastr-docs wrapper. It includes light and dark color tokens, font families, and the three shared radii. Empty fields retain the selected template value.

type UIStrings

type UIStrings struct {
	// Contents titles the sidebar rail above the route tree. One word;
	// the English default is "Contents".
	Contents string
	// Home labels the sidebar link to the site root, rendered in the
	// language of the page being read. One word.
	Home string
	// SkipToContent labels the skip link that jumps the keyboard past the
	// navigation chrome. GoFastr renders the element with English text; the
	// runtime rewrites it from this label per page language.
	SkipToContent string
	// SectionHelp is the helper line under the drawer's section select,
	// wired as the select's accessible description.
	SectionHelp string
	// AnchorLabel names the copy-anchor button beside each heading, so a
	// screen reader announces an action rather than a glyph.
	AnchorLabel string
	// Sections labels the section select at the top of the mobile drawer,
	// where the whole site's navigation lives because the header tabs are
	// hidden below md.
	Sections string
	// OnThisPage heads the in-page heading rail on wide viewports and the
	// section select that replaces it below md.
	OnThisPage string
	// Search is the visible label of the header search trigger. One word.
	Search string
	// SearchPlaceholder is the command palette input placeholder. An
	// ellipsis is conventional; keep it if your language does.
	SearchPlaceholder string
	// OpenSearch is the aria-label of the search trigger. Imperative, not
	// rendered visually.
	OpenSearch string
	// CloseSearch is the aria-label of the palette close button.
	// Imperative, not rendered visually.
	CloseSearch string
	// OpenNavigation is the aria-label of the mobile navigation trigger,
	// the hamburger in the phone header. Imperative, not rendered visually.
	OpenNavigation string
	// EditPage is the text of the edit link under a document. Imperative;
	EditPage string
	// LastUpdated prefixes the modified date under a document. One word
	// or short phrase, capitalized as your language prefixes metadata.
	LastUpdated string
	// Published prefixes the date on a blog post. One word.
	Published string
	// By joins a post and its authors in the byline. Lowercase in English
	// ("By ..."); follow your language byline convention.
	By string
	// Language is the aria-label of the language selector. Not rendered
	// visually.
	Language string
	// Version is the aria-label of the version selector. Not rendered
	// visually.
	Version string
	// Previous and Next label the pager under a document. They carry their own
	// arrows because a translation may want them on the other side of the word.
	Previous string
	Next     string

	// DateFormat is a Go time layout used for published and updated dates.
	// The standard library has no CLDR data, so the layout is the project's
	// choice rather than something derived from the locale.
	DateFormat string
	// Months and ShortMonths name the months in the language, January first,
	// for a DateFormat that spells them out. Go prints month names in English
	// only, so "2 January 2006" gave "30 August 2026" on a Spanish page; with
	// twelve names here the same layout prints "30 agosto 2026". A numeric
	// layout needs neither. Twelve entries, or none.
	Months      []string
	ShortMonths []string
	// VersionDescription describes a generated version route. Takes the
	// version name.
	VersionDescription string

	// Blog nests the publication labels, resolved per collection through the
	// collection's own locale.
	Blog BlogStrings
	// NotFound nests the branded 404 labels.
	NotFound NotFoundStrings
}

UIStrings contains the framework-owned labels rendered around a document. Content remains project-owned, but every piece of surrounding chrome must be translatable for sites that publish more than one language.

Fields holding a %s or %d are format strings. Translations may reorder the surrounding words but must keep the same verbs.

func (UIStrings) Keys

func (UIStrings) Keys() []string

Keys lists the label field names a translation can set, so tooling can diff a locale against the inventory without importing the struct layout.

type ValidatingPlugin

type ValidatingPlugin interface {
	Plugin
	Validate(*Router) error
}

ValidatingPlugin adds plugin-specific checks to the Router's strict build validation without forcing every plugin to own a second validation pass.

type VersionedCollectionConfig

type VersionedCollectionConfig struct {
	// Current names the version the unversioned paths serve.
	Current string
	// Versions lists the snapshots to mount, oldest first.
	Versions []string
	// Collection configures every snapshot's pages.
	Collection CollectionConfig
}

VersionedCollectionConfig describes a content directory with one child directory per documentation version. The current version is mounted at the collection prefix; older versions receive a /<version>/ path segment.

For example, a collection rooted at content/versions with Current "v2" mounts content/versions/v2/guide.md at /docs/guide and content/versions/v1/guide.md at /docs/v1/guide. Versions may be supplied to make the source layout explicit. When omitted, immediate child directories are discovered in sorted order.

Directories

Path Synopsis
cmd
fastr-docs command
internal
cli
plugin
katex
Package katex renders TeX math in documentation pages.
Package katex renders TeX math in documentation pages.
mermaid
Package mermaid renders Mermaid diagrams in documentation pages.
Package mermaid renders Mermaid diagrams in documentation pages.
openapi
Package openapi is the first-party OpenAPI route plugin.
Package openapi is the first-party OpenAPI route plugin.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL