Docs shell
The Gx docs shell: header, sidebar, table of contents, pagination, splash, 404 and search dialog.
<shell.Header site={shell.Config{
Title: "Deedbox docs",
Version: "v0.1.0",
Links: []shell.Link{{Label: "GitHub", Href: gx.URL("https://example.com/gx")}},
EditBase: "https://example.com/edit/main/content/docs/",
}} />Installation
Run the command in the app module.
gx add docs-shellThe command writes these files.
| File | Path in the app |
|---|---|
Header.fixtures.go |
ui/docs-shell/Header.fixtures.go |
Header.gx |
ui/docs-shell/Header.gx |
NotFound.fixtures.go |
ui/docs-shell/NotFound.fixtures.go |
NotFound.gx |
ui/docs-shell/NotFound.gx |
PageMeta.fixtures.go |
ui/docs-shell/PageMeta.fixtures.go |
PageMeta.gx |
ui/docs-shell/PageMeta.gx |
Pagination.fixtures.go |
ui/docs-shell/Pagination.fixtures.go |
Pagination.gx |
ui/docs-shell/Pagination.gx |
SearchDialog.fixtures.go |
ui/docs-shell/SearchDialog.fixtures.go |
SearchDialog.gx |
ui/docs-shell/SearchDialog.gx |
Shell.fixtures.go |
ui/docs-shell/Shell.fixtures.go |
Shell.gx |
ui/docs-shell/Shell.gx |
Sidebar.fixtures.go |
ui/docs-shell/Sidebar.fixtures.go |
Sidebar.gx |
ui/docs-shell/Sidebar.gx |
SidebarGroup.fixtures.go |
ui/docs-shell/SidebarGroup.fixtures.go |
SidebarGroup.gx |
ui/docs-shell/SidebarGroup.gx |
SidebarItem.fixtures.go |
ui/docs-shell/SidebarItem.fixtures.go |
SidebarItem.gx |
ui/docs-shell/SidebarItem.gx |
Splash.fixtures.go |
ui/docs-shell/Splash.fixtures.go |
Splash.gx |
ui/docs-shell/Splash.gx |
ThemeSelect.fixtures.go |
ui/docs-shell/ThemeSelect.fixtures.go |
ThemeSelect.gx |
ui/docs-shell/ThemeSelect.gx |
Toc.fixtures.go |
ui/docs-shell/Toc.fixtures.go |
Toc.gx |
ui/docs-shell/Toc.gx |
fixtures.go |
ui/docs-shell/fixtures.go |
helpers.go |
ui/docs-shell/helpers.go |
nav.go |
ui/docs-shell/nav.go |
Copy each file to its path in the app. Change each import of a registry package to the path of that package in the app.
package shell
import "github.com/alternayte/gx"
var HeaderFixtures = gx.Fixtures[HeaderProps]{
"Default": {Site: fixtureSite},
}package shell
props {
// Site is the site-wide data: the title, the version and the header links.
Site Config
}
<header class="gx-header sticky top-0 z-40 border-b border-border bg-background/95 backdrop-blur">
<div class="mx-auto flex max-w-7xl items-center gap-4 px-4 py-3">
<button type="button" class="gx-menu-button rounded-md border border-border px-2 py-1 text-sm lg:hidden" data-gx-menu aria-expanded="false" aria-controls="gx-sidebar">Menu</button>
<a class="gx-site-title font-semibold" href={gx.URL("/")}>{p.Site.Title}</a>
if p.Site.Version != "" {
<span class="gx-version rounded-full border border-border px-2 py-0.5 text-xs text-muted-foreground" data-gx-version>{p.Site.Version}</span>
}
<div class="ml-auto flex items-center gap-3 text-sm">
<button type="button" class="gx-search-button rounded-md border border-border px-2 py-1 text-muted-foreground" data-gx-search-open aria-haspopup="dialog">Search <kbd class="ml-1 text-xs">Ctrl K</kbd></button>
for _, l := range p.Site.Links {
<a class="gx-header-link" href={l.Href}>{l.Label}</a>
}
<ThemeSelect />
</div>
</div>
</header>package shell
import "github.com/alternayte/gx"
var NotFoundFixtures = gx.Fixtures[NotFoundProps]{
"Default": {},
}package shell
props {
// Title is the heading of the page.
Title string = "Page not found"
// Message is the text below the title.
Message string = "The page does not exist. Check the address or return to the start."
// Home is the target of the Go home link.
Home string = "/"
}
<div class="gx-not-found mx-auto my-16 max-w-lg text-center">
<p class="text-5xl font-bold">404</p>
<h1 class="mt-4 text-2xl font-semibold">{p.Title}</h1>
<p class="mt-2 text-muted-foreground">{p.Message}</p>
<a class="mt-6 inline-flex items-center rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground" href={gx.URL(p.Home)}>Go home</a>
</div>package shell
import "github.com/alternayte/gx"
var PageMetaFixtures = gx.Fixtures[PageMetaProps]{
"Default": {Site: fixtureSite, Page: fixturePage},
"Plain": {Site: Config{Title: "Site"}, Page: Page{Title: "Page", Path: "/page/"}},
}package shell
props {
// Site is the site-wide data. Its EditBase builds the edit link; empty hides the link.
Site Config
// Page is the data of the current page: its path and its last-updated text.
Page Page
}
<div class="gx-page-meta mt-8 flex flex-wrap gap-4 text-sm text-muted-foreground">
if p.Site.EditURL(p.Page) != "" {
<a class="gx-edit-link" href={gx.URL(p.Site.EditURL(p.Page))}>Edit this page</a>
}
if p.Page.Updated != "" {
<span class="gx-updated" data-gx-updated>Last updated {p.Page.Updated}</span>
}
</div>package shell
import "github.com/alternayte/gx"
var PaginationFixtures = gx.Fixtures[PaginationProps]{
"Both": {Prev: &NavItem{Label: "Start", Href: gx.URL("/start/")}, Next: fixtureNext},
"Next": {Next: fixtureNext},
"Empty": {},
}package shell
props {
// Prev is the previous sidebar item. Nil omits the link.
Prev *NavItem
// Next is the next sidebar item. Nil omits the link.
Next *NavItem
}
if p.Prev != nil || p.Next != nil {
<nav class="gx-pagination mt-10 flex justify-between gap-4 border-t border-border pt-4 text-sm" aria-label="Pages">
if p.Prev != nil {
<a class="gx-pagination-prev" href={p.Prev.Href} rel="prev">Previous: {p.Prev.Label}</a>
} else {
<span></span>
}
if p.Next != nil {
<a class="gx-pagination-next" href={p.Next.Href} rel="next">Next: {p.Next.Label}</a>
}
</nav>
}package shell
import "github.com/alternayte/gx"
var SearchDialogFixtures = gx.Fixtures[SearchDialogProps]{
"Default": {},
}package shell
<dialog id="gx-search" class="gx-search-dialog w-full max-w-lg rounded-lg border border-border bg-background p-0 text-foreground" data-gx-search data-gx-search-src="/pagefind/pagefind.js" aria-label="Search">
<form method="get" action="/search" class="flex items-center gap-2 p-3" data-gx-search-form>
<input type="search" name="q" class="gx-search-input w-full rounded-md border border-border bg-transparent px-3 py-2 text-sm" placeholder="Search the docs" data-gx-search-input autocomplete="off" />
<button type="submit" class="rounded-md bg-primary px-3 py-2 text-sm text-primary-foreground">Search</button>
<button type="button" class="gx-search-close rounded-md border border-border px-3 py-2 text-sm" data-gx-search-close aria-label="Close">Close</button>
</form>
<div class="gx-search-results max-h-80 overflow-y-auto px-3 pb-3 text-sm" data-gx-search-results></div>
</dialog>package shell
import "github.com/alternayte/gx"
var ShellFixtures = gx.Fixtures[ShellProps]{
"Default": {Site: fixtureSite, Nav: fixtureNav, Page: fixturePage, Children: gx.Text("Body.")},
}package shell
props {
// Site is the site-wide data: the title, the version and the header links.
Site Config
// Nav is the sidebar model: the groups and their items.
Nav Nav
// Page is the data of the current page: its path, its headings and its previous and next
// items.
Page Page
// Children is the content of the page.
Children gx.Node
}
<gx.Head bodyClass="bg-background text-foreground antialiased" />
<a class="gx-skip-link sr-only focus:not-sr-only focus:absolute focus:left-2 focus:top-2 focus:z-50 focus:rounded-md focus:bg-primary focus:px-3 focus:py-2 focus:text-primary-foreground" href="#gx-main">Skip to content</a>
<div class="gx-shell min-h-screen">
<Header site={p.Site} />
<div class="mx-auto flex max-w-7xl gap-8 px-4">
<Sidebar nav={p.Nav} path={p.Page.Path} />
<main id="gx-main" class="min-w-0 flex-1 py-8">
<article class="gx-content" data-pagefind-body>{p.Children}</article>
<Pagination prev={p.Page.Prev} next={p.Page.Next} />
<PageMeta site={p.Site} page={p.Page} />
</main>
<Toc headings={p.Page.ShownTOC()} />
</div>
</div>
<SearchDialog />package shell
import "github.com/alternayte/gx"
var SidebarFixtures = gx.Fixtures[SidebarProps]{
"Default": {Nav: fixtureNav, Path: "/guides/routing/pages/"},
}package shell
props {
// Nav is the sidebar model: the groups and their items.
Nav Nav
// Path is the site path of the current page.
// A nested item that holds the page starts open.
Path string
}
<aside id="gx-sidebar" class="gx-sidebar w-64 shrink-0 border-r border-border" data-gx-sidebar>
<nav aria-label="Docs" class="sticky top-16 max-h-[calc(100vh-4rem)] overflow-y-auto py-6 pr-4">
for _, g := range p.Nav.Groups {
<SidebarGroup group={g} path={p.Path} />
}
</nav>
</aside>package shell
import "github.com/alternayte/gx"
var SidebarGroupFixtures = gx.Fixtures[SidebarGroupProps]{
"Default": {Group: fixtureStart, Path: "/start/"},
"Nested": {Group: fixtureGuides, Path: "/guides/routing/pages/"},
}package shell
props {
// Group is the sidebar section: its label, its badge and its items.
// A group with Collapsed starts closed.
Group NavGroup
// Path is the site path of the current page.
// A nested item that holds the page starts open.
Path string
}
<details class="gx-nav-group mb-4" open={!p.Group.Collapsed}>
<summary class="gx-nav-group-label flex cursor-pointer items-center gap-2 py-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
{p.Group.Label}
if p.Group.Badge != "" {
<span class="gx-nav-badge rounded-full border border-border px-1.5 text-[10px]">{p.Group.Badge}</span>
}
</summary>
<ul class="mt-1 list-none space-y-0.5 p-0">
for _, it := range p.Group.Items {
<SidebarItem item={it} path={p.Path} />
}
</ul>
</details>package shell
import "github.com/alternayte/gx"
var SidebarItemFixtures = gx.Fixtures[SidebarItemProps]{
"Link": {Item: NavItem{Label: "Routing", Href: gx.URL("/guides/routing/")}, Path: "/guides/routing/"},
"Nested": {Item: fixtureRouting, Path: "/guides/routing/pages/"},
}package shell
props {
// Item is the sidebar link. An item with nested items shows as a collapsible list.
Item NavItem
// Path is the site path of the current page.
// A nested item that holds the page starts open.
Path string
}
<li class="gx-nav-item">
if len(p.Item.Items) > 0 {
<details class="gx-nav-sub" open={ActiveItem(p.Path, p.Item)}>
<summary class="gx-nav-sub-label cursor-pointer py-1 text-sm text-muted-foreground">
{p.Item.Label}
if p.Item.Badge != "" {
<span class="gx-nav-badge ml-1 rounded-full border border-border px-1.5 text-[10px]">{p.Item.Badge}</span>
}
</summary>
<ul class="mt-1 list-none space-y-0.5 border-l border-border p-0 pl-3">
for _, child := range p.Item.Items {
<SidebarItem item={child} path={p.Path} />
}
</ul>
</details>
} else {
<a class="gx-nav-link block py-1 text-sm text-muted-foreground hover:text-foreground [&[aria-current=page]]:font-medium [&[aria-current=page]]:text-foreground" href={p.Item.Href} active="page">
{p.Item.Label}
if p.Item.Badge != "" {
<span class="gx-nav-badge ml-1 rounded-full border border-border px-1.5 text-[10px]">{p.Item.Badge}</span>
}
</a>
}
</li>package shell
import "github.com/alternayte/gx"
var SplashFixtures = gx.Fixtures[SplashProps]{
"Default": {Title: "Deedbox", Tagline: "Event sourcing in .NET.", Actions: gx.Text("Docs")},
"Plain": {Title: "Deedbox"},
}package shell
props {
// Title is the heading of the splash.
Title string
// Tagline is the text below the title. Empty omits it.
Tagline string = ""
// Actions is the row of links or buttons below the tagline. Nil omits it.
Actions gx.Node = nil
// Children is the content below the actions. Nil omits it.
Children gx.Node = nil
}
<header class="gx-splash my-12 text-center">
<h1 class="m-0 text-5xl font-bold tracking-tight">{p.Title}</h1>
if p.Tagline != "" {
<p class="mx-auto mt-4 max-w-2xl text-lg text-muted-foreground">{p.Tagline}</p>
}
if p.Actions != nil {
<div class="mt-6 flex flex-wrap items-center justify-center gap-3">{p.Actions}</div>
}
if p.Children != nil {
<div class="gx-splash-body mt-10">{p.Children}</div>
}
</header>package shell
import "github.com/alternayte/gx"
var ThemeSelectFixtures = gx.Fixtures[ThemeSelectProps]{
"Default": {},
}package shell
<div class="gx-theme inline-flex gap-1 rounded-md border border-border p-0.5" role="group" aria-label="Theme">
<button type="button" class="gx-theme-button rounded px-2 py-0.5 text-xs" data-gx-theme="light" aria-pressed="false">Light</button>
<button type="button" class="gx-theme-button rounded px-2 py-0.5 text-xs" data-gx-theme="dark" aria-pressed="false">Dark</button>
<button type="button" class="gx-theme-button rounded px-2 py-0.5 text-xs" data-gx-theme="auto" aria-pressed="false">Auto</button>
</div>package shell
import "github.com/alternayte/gx"
var TocFixtures = gx.Fixtures[TocProps]{
"Default": {Headings: fixtureHeadings},
}package shell
props {
// Headings holds the entries of the table of contents. Empty renders nothing.
Headings []Heading
}
if len(p.Headings) > 0 {
<nav class="gx-toc hidden w-56 shrink-0 xl:block" data-gx-toc aria-label="On this page">
<div class="sticky top-16 max-h-[calc(100vh-4rem)] overflow-y-auto py-8 text-sm">
<p class="mb-2 font-medium">On this page</p>
<ul class="list-none space-y-1 border-l border-border p-0">
for _, h := range p.Headings {
<li class="gx-toc-item" data-level={h.Level}>
<a class="gx-toc-link block pl-3 text-muted-foreground hover:text-foreground [&[aria-current=location]]:text-foreground [&[data-level='3']]:pl-6" href={gx.URL("#" + h.ID)} data-gx-toc-target={h.ID} data-level={h.Level}>{h.Text}</a>
</li>
}
</ul>
</div>
</nav>
}package shell
import "github.com/alternayte/gx"
// fixtureRouting is the nested item of the shell fixtures.
var fixtureRouting = NavItem{Label: "Routing", Href: gx.URL("/guides/routing/"), Items: []NavItem{
{Label: "Pages", Href: gx.URL("/guides/routing/pages/")},
}}
// fixtureStart and fixtureGuides are the open groups of the shell fixtures.
var fixtureStart = NavGroup{Label: "Start", Items: []NavItem{
{Label: "Introduction", Href: gx.URL("/start/"), Badge: "New"},
}}
var fixtureGuides = NavGroup{Label: "Guides", Badge: "12", Items: []NavItem{fixtureRouting}}
// fixtureNav is the sidebar model of the shell fixtures (REQ-CNT-06).
var fixtureNav = Nav{Groups: []NavGroup{
fixtureStart,
fixtureGuides,
{Label: "Errors", Collapsed: true, Items: []NavItem{
{Label: "GX1000", Href: gx.URL("/errors/GX1000/")},
}},
}}
// fixtureSite is the site config of the shell fixtures.
var fixtureSite = Config{
Title: "Deedbox docs",
Version: "v0.1.0",
Links: []Link{{Label: "GitHub", Href: gx.URL("https://example.com/gx")}},
EditBase: "https://example.com/edit/main/content/docs/",
}
// fixtureNext is the next page of the shell fixtures.
var fixtureNext = &NavItem{Label: "Routing", Href: gx.URL("/guides/routing/")}
// fixtureHeadings are the headings of the shell fixtures. Each one is in
// the default depth of the table of contents.
var fixtureHeadings = []Heading{
{Level: 2, Text: "Install", ID: "install"},
{Level: 3, Text: "First page", ID: "first-page"},
}
// fixturePage is the page data of the shell fixtures.
var fixturePage = Page{
Title: "Introduction",
Path: "/start/",
Section: "Start",
Updated: "Oct 2, 2026",
Prev: nil,
Next: fixtureNext,
TOC: fixtureHeadings,
}package shell
import "strings"
// Active reports whether href is the current page or a parent of it
// (REQ-CNT-06). The sidebar marks active items on the server.
func Active(path string, href string) bool {
if href == "" || path == "" {
return false
}
if path == href {
return true
}
return len(path) > len(href) && path[:len(href)] == href && path[len(href)-1] == '/'
}
// ActiveItem reports whether any descendant of item is active.
func ActiveItem(path string, item NavItem) bool {
if Active(path, string(item.Href)) {
return true
}
for _, child := range item.Items {
if ActiveItem(path, child) {
return true
}
}
return false
}
// HasTOC reports whether the page has headings to show.
func (p Page) HasTOC() bool {
for _, h := range p.TOC {
if h.Text != "" {
return true
}
}
return false
}
// TocDepth returns the heading depth limit of the page.
func (p Page) TocDepth() int {
if p.Depth <= 0 {
return 3
}
return p.Depth
}
// ShownTOC returns the headings the table of contents shows.
func (p Page) ShownTOC() []Heading {
depth := p.TocDepth()
var out []Heading
for _, h := range p.TOC {
if h.Level >= 2 && h.Level <= depth && h.Text != "" {
out = append(out, h)
}
}
return out
}
// EditURL returns the edit-page link of the page (REQ-CNT-06). The page
// path maps to its Markdown file: "/start/" to "start.md".
func (c Config) EditURL(p Page) string {
if c.EditBase == "" || p.Path == "" {
return ""
}
base := c.EditBase
if base[len(base)-1] != '/' {
base += "/"
}
path := strings.TrimPrefix(p.Path, "/")
path = strings.TrimSuffix(path, "/")
if path == "" {
path = "index"
}
return base + path + ".md"
}// Package shell is the docs-shell registry block (REQ-CNT-06): a layout
// with a header, a sidebar, a table of contents, pagination and a 404, plus
// the client behaviours they need.
package shell
import "github.com/alternayte/gx"
// Nav is the sidebar model (REQ-CNT-06).
type Nav struct {
Groups []NavGroup
}
// NavGroup is one sidebar section. A group with Collapsed starts closed.
type NavGroup struct {
Label string
Badge string
Collapsed bool
Items []NavItem
}
// NavItem is one sidebar link. Items nest under a parent item.
type NavItem struct {
Label string
Href gx.URL
Badge string
Items []NavItem
}
// Link is one header link: a social link or a plain link.
type Link struct {
Label string
Href gx.URL
}
// Config is the site-wide shell data (REQ-CNT-06).
type Config struct {
Title string
Version string
Links []Link
// EditBase is the repository edit URL up to the file path, for example
// https://github.com/acme/site/edit/main/content/docs/. Empty hides
// the edit link.
EditBase string
}
// Page is the shell data of one page (REQ-CNT-06).
type Page struct {
Title string
// Path is the site path of the page, for example /start/.
Path string
// Section is the sidebar group label of the page.
Section string
// Updated is the last-updated text. Empty hides it.
Updated string
// Prev and Next are the previous and next sidebar items.
Prev *NavItem
Next *NavItem
// TOC holds the page headings, in document order.
TOC []Heading
// Depth limits the table of contents to headings at or below this
// level. Zero means 3.
Depth int
}
// Heading is one table-of-contents entry (REQ-CNT-06).
type Heading struct {
Level int
Text string
ID string
}The theme must define these tokens: --background, --foreground, --primary, --primary-foreground, --muted, --muted-foreground, --accent, --border.
Usage
The Gx docs shell: header, sidebar, table of contents, pagination, splash,
404 and the search dialog. It pairs with the docs kit.
var Site = shell.Config{Title: "Deedbox", Version: "v1.0.0", EditBase: "https://github.com/acme/site/edit/main/content/docs/"}
func View(e gx.Entry[DocMeta]) gx.Node {
return shell.Shell(shell.ShellProps{Site: Site, Nav: Nav(), Page: PageFor(e), Children: DocsBody(e)})
}Set [site] url in gx.toml so the export writes canonical links,
sitemap.xml and robots.txt.
Examples
Header: Default
<shell.Header site={shell.Config{
Title: "Deedbox docs",
Version: "v0.1.0",
Links: []shell.Link{{Label: "GitHub", Href: gx.URL("https://example.com/gx")}},
EditBase: "https://example.com/edit/main/content/docs/",
}} />NotFound: Default
<shell.NotFound />PageMeta: Default
<shell.PageMeta site={shell.Config{
Title: "Deedbox docs",
Version: "v0.1.0",
Links: []shell.Link{{Label: "GitHub", Href: gx.URL("https://example.com/gx")}},
EditBase: "https://example.com/edit/main/content/docs/",
}} page={shell.Page{
Title: "Introduction",
Path: "/start/",
Section: "Start",
Updated: "Oct 2, 2026",
Prev: nil,
Next: &shell.NavItem{Label: "Routing", Href: gx.URL("/guides/routing/")},
TOC: []shell.Heading{
{Level: 2, Text: "Install", ID: "install"},
{Level: 3, Text: "First page", ID: "first-page"},
},
}} />PageMeta: Plain
<shell.PageMeta site={shell.Config{Title: "Site"}} page={shell.Page{Title: "Page", Path: "/page/"}} />Pagination: Both
<shell.Pagination prev={&shell.NavItem{Label: "Start", Href: gx.URL("/start/")}} next={&shell.NavItem{Label: "Routing", Href: gx.URL("/guides/routing/")}} />Pagination: Next
<shell.Pagination next={&shell.NavItem{Label: "Routing", Href: gx.URL("/guides/routing/")}} prev={(*shell.NavItem)(nil)} />Pagination: Empty
<shell.Pagination prev={(*shell.NavItem)(nil)} next={(*shell.NavItem)(nil)} />SearchDialog: Default
<shell.SearchDialog />Shell: Default
<shell.Shell site={shell.Config{
Title: "Deedbox docs",
Version: "v0.1.0",
Links: []shell.Link{{Label: "GitHub", Href: gx.URL("https://example.com/gx")}},
EditBase: "https://example.com/edit/main/content/docs/",
}} nav={shell.Nav{Groups: []shell.NavGroup{
shell.NavGroup{Label: "Start", Items: []shell.NavItem{
{Label: "Introduction", Href: gx.URL("/start/"), Badge: "New"},
}},
shell.NavGroup{Label: "Guides", Badge: "12", Items: []shell.NavItem{shell.NavItem{Label: "Routing", Href: gx.URL("/guides/routing/"), Items: []shell.NavItem{
{Label: "Pages", Href: gx.URL("/guides/routing/pages/")},
}}}},
{Label: "Errors", Collapsed: true, Items: []shell.NavItem{
{Label: "GX1000", Href: gx.URL("/errors/GX1000/")},
}},
}}} page={shell.Page{
Title: "Introduction",
Path: "/start/",
Section: "Start",
Updated: "Oct 2, 2026",
Prev: nil,
Next: &shell.NavItem{Label: "Routing", Href: gx.URL("/guides/routing/")},
TOC: []shell.Heading{
{Level: 2, Text: "Install", ID: "install"},
{Level: 3, Text: "First page", ID: "first-page"},
},
}}>
Body.
</shell.Shell>Sidebar: Default
<shell.Sidebar nav={shell.Nav{Groups: []shell.NavGroup{
shell.NavGroup{Label: "Start", Items: []shell.NavItem{
{Label: "Introduction", Href: gx.URL("/start/"), Badge: "New"},
}},
shell.NavGroup{Label: "Guides", Badge: "12", Items: []shell.NavItem{shell.NavItem{Label: "Routing", Href: gx.URL("/guides/routing/"), Items: []shell.NavItem{
{Label: "Pages", Href: gx.URL("/guides/routing/pages/")},
}}}},
{Label: "Errors", Collapsed: true, Items: []shell.NavItem{
{Label: "GX1000", Href: gx.URL("/errors/GX1000/")},
}},
}}} path="/guides/routing/pages/" />SidebarGroup: Default
<shell.SidebarGroup group={shell.NavGroup{Label: "Start", Items: []shell.NavItem{
{Label: "Introduction", Href: gx.URL("/start/"), Badge: "New"},
}}} path="/start/" />SidebarGroup: Nested
<shell.SidebarGroup group={shell.NavGroup{Label: "Guides", Badge: "12", Items: []shell.NavItem{shell.NavItem{Label: "Routing", Href: gx.URL("/guides/routing/"), Items: []shell.NavItem{
{Label: "Pages", Href: gx.URL("/guides/routing/pages/")},
}}}}} path="/guides/routing/pages/" />SidebarItem: Link
<shell.SidebarItem item={shell.NavItem{Label: "Routing", Href: gx.URL("/guides/routing/")}} path="/guides/routing/" />SidebarItem: Nested
<shell.SidebarItem item={shell.NavItem{Label: "Routing", Href: gx.URL("/guides/routing/"), Items: []shell.NavItem{
{Label: "Pages", Href: gx.URL("/guides/routing/pages/")},
}}} path="/guides/routing/pages/" />Splash: Default
<shell.Splash title="Deedbox" tagline="Event sourcing in .NET."><:actions>Docs</:actions></shell.Splash>Splash: Plain
<shell.Splash title="Deedbox" />ThemeSelect: Default
<shell.ThemeSelect />Toc: Default
<shell.Toc headings={[]shell.Heading{
{Level: 2, Text: "Install", ID: "install"},
{Level: 3, Text: "First page", ID: "first-page"},
}} />API reference
A tag sets a prop by its name with a lower-case first letter: Class is class.
shell.Header
| Prop | Type | Default | Description |
|---|---|---|---|
Site |
Config |
Required | Site is the site-wide data: the title, the version and the header links. |
shell.NotFound
| Prop | Type | Default | Description |
|---|---|---|---|
Title |
string |
"Page not found" |
Title is the heading of the page. |
Message |
string |
"The page does not exist. Check the address or return to the start." |
Message is the text below the title. |
Home |
string |
"/" |
Home is the target of the Go home link. |
shell.PageMeta
| Prop | Type | Default | Description |
|---|---|---|---|
Site |
Config |
Required | Site is the site-wide data. Its EditBase builds the edit link; empty hides the link. |
Page |
Page |
Required | Page is the data of the current page: its path and its last-updated text. |
shell.Pagination
| Prop | Type | Default | Description |
|---|---|---|---|
Prev |
*NavItem |
Required | Prev is the previous sidebar item. Nil omits the link. |
Next |
*NavItem |
Required | Next is the next sidebar item. Nil omits the link. |
shell.SearchDialog
The component has no props.
shell.Shell
| Prop | Type | Default | Description |
|---|---|---|---|
Site |
Config |
Required | Site is the site-wide data: the title, the version and the header links. |
Nav |
Nav |
Required | Nav is the sidebar model: the groups and their items. |
Page |
Page |
Required | Page is the data of the current page: its path, its headings and its previous and next items. |
Children |
gx.Node |
Required | Children is the content of the page. |
shell.Sidebar
| Prop | Type | Default | Description |
|---|---|---|---|
Nav |
Nav |
Required | Nav is the sidebar model: the groups and their items. |
Path |
string |
Required | Path is the site path of the current page. A nested item that holds the page starts open. |
shell.SidebarGroup
| Prop | Type | Default | Description |
|---|---|---|---|
Group |
NavGroup |
Required | Group is the sidebar section: its label, its badge and its items. A group with Collapsed starts closed. |
Path |
string |
Required | Path is the site path of the current page. A nested item that holds the page starts open. |
shell.SidebarItem
| Prop | Type | Default | Description |
|---|---|---|---|
Item |
NavItem |
Required | Item is the sidebar link. An item with nested items shows as a collapsible list. |
Path |
string |
Required | Path is the site path of the current page. A nested item that holds the page starts open. |
shell.Splash
| Prop | Type | Default | Description |
|---|---|---|---|
Title |
string |
Required | Title is the heading of the splash. |
Tagline |
string |
"" |
Tagline is the text below the title. Empty omits it. |
Actions |
gx.Node |
nil |
Actions is the row of links or buttons below the tagline. Nil omits it. |
Children |
gx.Node |
nil |
Children is the content below the actions. Nil omits it. |
shell.ThemeSelect
The component has no props.
shell.Toc
| Prop | Type | Default | Description |
|---|---|---|---|
Headings |
[]Heading |
Required | Headings holds the entries of the table of contents. Empty renders nothing. |
Do and do not
Do
- Sort the sidebar with explicit
ordervalues on the pages that need it. - Keep the page
Pathwith a trailing slash.
Don't
- Do not render
Shellwithout aPage; the table of contents and the navigation need the path. - Do not put a
Tocoutside the shell.
Keyboard
| Key | Action |
|---|---|
| Enter, Space | Opens the search dialog or the mobile menu. |
| Ctrl/Cmd K | Opens the search dialog. |
| Escape | Closes the search dialog. |
| Tab | Moves through the header, the sidebar and the table of contents. |