10 KiB
Site Module
The Site module provides a structured way to define website configurations, navigation menus, pages, and sections using HeroScript. It's designed to work with static site generators like Docusaurus.
Purpose
The Site module allows you to:
- Define website structure and configuration in a declarative way using HeroScript
- Organize pages into sections/categories
- Configure navigation menus and footers
- Manage page metadata (title, description, slug, etc.)
- Support multiple content collections
- Define build and publish destinations
Quick Start
#!/usr/bin/env -S v -n -w -gc none -cg -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.develop.gittools
import incubaid.herolib.web.site
import incubaid.herolib.core.playcmds
// Clone or use existing repository with HeroScript files
mysitepath := gittools.path(
git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/ebooks/tech'
git_pull: true
)!
// Process all HeroScript files in the path
playcmds.run(heroscript_path: mysitepath.path)!
// Access the configured site
mut mysite := site.get(name: 'my_docs')!
// Print available pages
for page_id, page in mysite.pages {
console.print_item('Page: ${page_id} - "${page.title}"')
}
println('Site has ${mysite.pages.len} pages')
API Reference
Site Factory
Factory functions to create and retrieve site instances:
// Create a new site
mut mysite := site.new(name: 'my_docs')!
// Get existing site
mut mysite := site.get(name: 'my_docs')!
// Check if site exists
if site.exists(name: 'my_docs') {
println('Site exists')
}
// Get all site names
site_names := site.list() // Returns []string
// Get default site (creates if needed)
mut default := site.default()!
Site Object Structure
pub struct Site {
pub mut:
pages map[string]Page // key: "collection:page_name"
nav NavConfig // Navigation sidebar
siteconfig SiteConfig // Full configuration
}
Accessing Pages
// Access all pages
pages := mysite.pages // map[string]Page
// Get specific page
page := mysite.pages['docs:introduction']
// Page structure
pub struct Page {
pub mut:
id string // "collection:page_name"
title string // Display title
description string // SEO metadata
draft bool // Hidden if true
hide_title bool // Don't show title in rendering
src string // Source reference
}
Navigation Structure
// Access sidebar navigation
sidebar := mysite.nav.my_sidebar // []NavItem
// NavItem is a sum type (can be one of three types):
pub type NavItem = NavDoc | NavCat | NavLink
// Navigation items:
pub struct NavDoc {
pub:
id string // page id
label string // display name
}
pub struct NavCat {
pub mut:
label string
collapsible bool
collapsed bool
items []NavItem // nested NavDoc/NavCat/NavLink
}
pub struct NavLink {
pub:
label string
href string
description string
}
// Example: iterate navigation
for item in mysite.nav.my_sidebar {
match item {
NavDoc {
println('Page: ${item.label} (${item.id})')
}
NavCat {
println('Category: ${item.label} (${item.items.len} items)')
}
NavLink {
println('Link: ${item.label} -> ${item.href}')
}
}
}
Site Configuration
pub struct SiteConfig {
pub mut:
// Core
name string
title string
description string
tagline string
favicon string
image string
copyright string
// URLs (Docusaurus)
url string // Full site URL
base_url string // Base path (e.g., "/" or "/docs/")
url_home string // Home page path
// SEO Metadata
meta_title string // SEO title override
meta_image string // OG image override
// Publishing
build_dest []BuildDest // Production destinations
build_dest_dev []BuildDest // Development destinations
// Navigation & Footer
footer Footer
menu Menu
announcement AnnouncementBar
// Imports
imports []ImportItem
}
pub struct BuildDest {
pub mut:
path string
ssh_name string
}
Core Concepts
Site
A website configuration that contains pages, navigation structure, and metadata.
Page
A single page with:
- ID:
collection:page_nameformat - Title: Display name (optional - extracted from markdown if not provided)
- Description: SEO metadata
- Draft: Hidden from navigation if true
Category (Section)
Groups related pages together in the navigation sidebar. Automatically collapsed/expandable.
Collection
A logical group of pages. Pages reuse the collection once specified.
!!site.page src: "tech:intro" # Specifies collection "tech"
!!site.page src: "benefits" # Reuses collection "tech"
!!site.page src: "components" # Still uses collection "tech"
!!site.page src: "api:reference" # Switches to collection "api"
!!site.page src: "endpoints" # Uses collection "api"
HeroScript Syntax
Basic Configuration
!!site.config
name: "my_site"
title: "My Documentation Site"
description: "Comprehensive documentation"
tagline: "Your awesome documentation"
favicon: "img/favicon.png"
image: "img/site-image.png"
copyright: "© 2024 My Organization"
url: "https://docs.example.com"
base_url: "/"
Navigation Menu
!!site.navbar
title: "My Site"
logo_alt: "Site Logo"
logo_src: "img/logo.svg"
logo_src_dark: "img/logo-dark.svg"
!!site.navbar_item
label: "Documentation"
to: "docs/intro"
position: "left"
!!site.navbar_item
label: "GitHub"
href: "https://github.com/myorg/myrepo"
position: "right"
Footer Configuration
!!site.footer
style: "dark"
!!site.footer_item
title: "Docs"
label: "Introduction"
to: "intro"
!!site.footer_item
title: "Docs"
label: "Getting Started"
href: "https://docs.example.com/getting-started"
!!site.footer_item
title: "Community"
label: "Discord"
href: "https://discord.gg/example"
Page Organization
Example 1: Simple Pages Without Categories
When you don't need categories, pages are added sequentially. The collection only needs to be specified once, then it's reused for subsequent pages.
!!site.announcement
content: "🎉 Version 2.0 is now available!"
background_color: "#20232a"
text_color: "#fff"
is_closeable: true
Key Points:
- First page specifies collection as
tech:introduction(collection:page_name format) - Subsequent pages only need the page name (e.g.,
vision) - thetechcollection is reused - If
titleis not specified, it will be extracted from the markdown file itself - Pages are ordered by their appearance in the HeroScript file
slugcan be used to customize the URL path (e.g.,"/"for homepage)
Example 2: Pages with Categories
Categories (sections) help organize pages into logical groups with their own navigation structure.
!!site.page_category
name: "first_principle_thinking"
label: "First Principle Thinking"
!!site.page src: "first_principle_thinking:hardware_badly_used"
description: "Hardware is not used properly, why it is important to understand hardware"
!!site.page src: "internet_risk"
description: "Internet risk, how to mitigate it, and why it is important"
!!site.page src: "onion_analogy"
description: "Compare onion with a computer, layers of abstraction"
Key Points:
Category Parameters:
name- Category identifier (required)label- Display label (auto-generated from name if omitted)position- Sort order (auto-incremented if omitted)
7. Content Imports
!!site.import
url: "https://github.com/example/external-docs"
dest: "external"
replace: "PROJECT_NAME:My Project,VERSION:1.0.0"
visible: true
Publish Destinations
!!site.publish
path: "/var/www/html/docs"
ssh_name: "production_server"
!!site.publish_dev
path: "/tmp/docs-preview"
Factory Methods
Create or Get a Site
import incubaid.herolib.web.site
// Create a new site
mut mysite := site.new(name: 'my_docs')!
// Get an existing site
mut mysite := site.get(name: 'my_docs')!
// Get default site
mut mysite := site.default()!
// Check if site exists
if site.exists(name: 'my_docs') {
println('Site exists')
}
// List all sites
sites := site.list()
println(sites)
Using with PlayBook
import incubaid.herolib.core.playbook
import incubaid.herolib.web.site
// Create playbook from path
mut plbook := playbook.new(path: '/path/to/heroscripts')!
// Process site configuration
site.play(mut plbook)!
// Access the configured site
mut mysite := site.get(name: 'my_site')!
Data Structures
Site
pub struct Site {
pub mut:
pages []Page
sections []Section
siteconfig SiteConfig
}
Page
File Organization
Recommended Ebook Structure
The modern ebook structure uses .hero files for configuration and .heroscript files for page definitions:
my_ebook/
├── scan.hero # !!atlas.scan - collection scanning
├── config.hero # !!site.config - site configuration
├── menus.hero # !!site.navbar and !!site.footer
├── include.hero # !!docusaurus.define and !!atlas.export
├── 1_intro.heroscript # Page definitions (categories + pages)
├── 2_concepts.heroscript # More page definitions
└── 3_advanced.heroscript # Additional pages
File Types
.herofiles: Configuration files processed in any order.heroscriptfiles: Page definition files processed alphabetically
Use numeric prefixes on .heroscript files to control page/category ordering in the sidebar.
Example scan.hero
!!atlas.scan path:"../../collections/my_collection"
Example include.hero
// Include shared configuration (optional)
!!play.include path:'../../heroscriptall' replace:'SITENAME:my_ebook'
// Or define directly
!!docusaurus.define name:'my_ebook'
!!atlas.export include:true
Running an Ebook
# Development server
hero docs -d -p /path/to/my_ebook
# Build for production
hero docs -p /path/to/my_ebook