...
This commit is contained in:
201
examples/web/site/USAGE.md
Normal file
201
examples/web/site/USAGE.md
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
# Site Module Usage Guide
|
||||||
|
|
||||||
|
## Quick Examples
|
||||||
|
|
||||||
|
### 1. Run Basic Example
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd examples/web/site
|
||||||
|
vrun process_site.vsh ./
|
||||||
|
```
|
||||||
|
|
||||||
|
With output:
|
||||||
|
```
|
||||||
|
=== Site Configuration Processor ===
|
||||||
|
Processing HeroScript files from: ./
|
||||||
|
Found 1 HeroScript file(s):
|
||||||
|
- basic.heroscript
|
||||||
|
|
||||||
|
Processing: basic.heroscript
|
||||||
|
|
||||||
|
=== Configuration Complete ===
|
||||||
|
Site: simple_docs
|
||||||
|
Title: Simple Documentation
|
||||||
|
Pages: 4
|
||||||
|
Description: A basic documentation site
|
||||||
|
Navigation structure:
|
||||||
|
- [Page] Getting Started
|
||||||
|
- [Page] Installation
|
||||||
|
- [Page] Usage Guide
|
||||||
|
- [Page] FAQ
|
||||||
|
|
||||||
|
✓ Site configuration ready for deployment
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Run Multi-Section Example
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vrun process_site.vsh ./
|
||||||
|
# Edit process_site.vsh to use multi_section.heroscript instead
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Process Custom Directory
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vrun process_site.vsh /path/to/your/site/config
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/
|
||||||
|
├── 0_config.heroscript # Basic config
|
||||||
|
├── 1_menu.heroscript # Navigation
|
||||||
|
├── 2_pages.heroscript # Pages and categories
|
||||||
|
└── process.vsh # Your processing script
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating Your Own Site
|
||||||
|
|
||||||
|
1. **Create a config directory:**
|
||||||
|
```bash
|
||||||
|
mkdir my_site
|
||||||
|
cd my_site
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create config file (0_config.heroscript):**
|
||||||
|
```heroscript
|
||||||
|
!!site.config
|
||||||
|
name: "my_site"
|
||||||
|
title: "My Site"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Create pages file (1_pages.heroscript):**
|
||||||
|
```heroscript
|
||||||
|
!!site.page src: "docs:intro"
|
||||||
|
title: "Getting Started"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Process with script:**
|
||||||
|
```bash
|
||||||
|
vrun ../process_site.vsh ./
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Workflows
|
||||||
|
|
||||||
|
### Workflow 1: Documentation Site
|
||||||
|
|
||||||
|
```
|
||||||
|
docs/
|
||||||
|
├── 0_config.heroscript
|
||||||
|
│ └── Basic config + metadata
|
||||||
|
├── 1_menu.heroscript
|
||||||
|
│ └── Navbar + footer
|
||||||
|
├── 2_getting_started.heroscript
|
||||||
|
│ └── Getting started pages
|
||||||
|
├── 3_api.heroscript
|
||||||
|
│ └── API reference pages
|
||||||
|
└── 4_advanced.heroscript
|
||||||
|
└── Advanced topic pages
|
||||||
|
```
|
||||||
|
|
||||||
|
### Workflow 2: Internal Knowledge Base
|
||||||
|
|
||||||
|
```
|
||||||
|
kb/
|
||||||
|
├── 0_config.heroscript
|
||||||
|
├── 1_navigation.heroscript
|
||||||
|
└── 2_articles.heroscript
|
||||||
|
```
|
||||||
|
|
||||||
|
### Workflow 3: Product Documentation with Imports
|
||||||
|
|
||||||
|
```
|
||||||
|
product_docs/
|
||||||
|
├── 0_config.heroscript
|
||||||
|
├── 1_imports.heroscript
|
||||||
|
│ └── Import shared templates
|
||||||
|
├── 2_menu.heroscript
|
||||||
|
└── 3_pages.heroscript
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tips & Tricks
|
||||||
|
|
||||||
|
### Tip 1: Reuse Collections
|
||||||
|
|
||||||
|
```heroscript
|
||||||
|
# Specify once, reuse multiple times
|
||||||
|
!!site.page src: "guides:intro"
|
||||||
|
!!site.page src: "setup" # Reuses "guides"
|
||||||
|
!!site.page src: "deployment" # Still "guides"
|
||||||
|
|
||||||
|
# Switch to new collection
|
||||||
|
!!site.page src: "api:reference"
|
||||||
|
!!site.page src: "examples" # Now "api"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tip 2: Auto-Increment Categories
|
||||||
|
|
||||||
|
```heroscript
|
||||||
|
# Automatically positioned at 100, 200, 300...
|
||||||
|
!!site.page_category name: "basics"
|
||||||
|
!!site.page_category name: "advanced"
|
||||||
|
!!site.page_category name: "expert"
|
||||||
|
|
||||||
|
# Or specify explicit positions
|
||||||
|
!!site.page_category name: "basics" position: 10
|
||||||
|
!!site.page_category name: "advanced" position: 20
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tip 3: Title Extraction
|
||||||
|
|
||||||
|
Let titles come from markdown files:
|
||||||
|
|
||||||
|
```heroscript
|
||||||
|
# Don't specify title
|
||||||
|
!!site.page src: "docs:introduction"
|
||||||
|
# Title will be extracted from # Heading in introduction.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tip 4: Draft Pages
|
||||||
|
|
||||||
|
Hide pages while working on them:
|
||||||
|
|
||||||
|
```heroscript
|
||||||
|
!!site.page src: "docs:work_in_progress"
|
||||||
|
draft: true
|
||||||
|
title: "Work in Progress"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
### Debug: Check What Got Configured
|
||||||
|
|
||||||
|
```v
|
||||||
|
mut s := site.get(name: 'my_site')!
|
||||||
|
println(s.pages) // All pages
|
||||||
|
println(s.nav) // Navigation structure
|
||||||
|
println(s.siteconfig) // Configuration
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug: List All Sites
|
||||||
|
|
||||||
|
```v
|
||||||
|
sites := site.list()
|
||||||
|
for site_name in sites {
|
||||||
|
println('Site: ${site_name}')
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug: Enable Verbose Output
|
||||||
|
|
||||||
|
Add `console.print_debug()` calls in your HeroScript processing.
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- Customize `process_site.vsh` for your needs
|
||||||
|
- Add your existing pages (in markdown)
|
||||||
|
- Export to Docusaurus
|
||||||
|
- Deploy to production
|
||||||
|
|
||||||
|
For more info, see the main [Site Module README](./readme.md).
|
||||||
53
examples/web/site/basic.heroscript
Normal file
53
examples/web/site/basic.heroscript
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env hero
|
||||||
|
# Basic single-section documentation site
|
||||||
|
|
||||||
|
!!site.config
|
||||||
|
name: "simple_docs"
|
||||||
|
title: "Simple Documentation"
|
||||||
|
description: "A basic documentation site"
|
||||||
|
copyright: "© 2024 Example"
|
||||||
|
url: "https://docs.example.com"
|
||||||
|
base_url: "/"
|
||||||
|
|
||||||
|
!!site.navbar
|
||||||
|
title: "Simple Docs"
|
||||||
|
logo_src: "img/logo.png"
|
||||||
|
|
||||||
|
!!site.navbar_item
|
||||||
|
label: "Docs"
|
||||||
|
to: "/"
|
||||||
|
position: "left"
|
||||||
|
|
||||||
|
!!site.navbar_item
|
||||||
|
label: "GitHub"
|
||||||
|
href: "https://github.com/example/repo"
|
||||||
|
position: "right"
|
||||||
|
|
||||||
|
!!site.footer
|
||||||
|
style: "dark"
|
||||||
|
|
||||||
|
!!site.footer_item
|
||||||
|
title: "Documentation"
|
||||||
|
label: "Getting Started"
|
||||||
|
to: "getting-started"
|
||||||
|
|
||||||
|
!!site.footer_item
|
||||||
|
title: "Community"
|
||||||
|
label: "Discord"
|
||||||
|
href: "https://discord.gg/example"
|
||||||
|
|
||||||
|
!!site.page src: "docs:introduction"
|
||||||
|
title: "Getting Started"
|
||||||
|
description: "Learn the basics"
|
||||||
|
|
||||||
|
!!site.page src: "installation"
|
||||||
|
title: "Installation"
|
||||||
|
description: "How to install"
|
||||||
|
|
||||||
|
!!site.page src: "usage"
|
||||||
|
title: "Usage Guide"
|
||||||
|
description: "How to use the system"
|
||||||
|
|
||||||
|
!!site.page src: "faq"
|
||||||
|
title: "FAQ"
|
||||||
|
description: "Frequently asked questions"
|
||||||
155
examples/web/site/multi_section.heroscript
Normal file
155
examples/web/site/multi_section.heroscript
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
#!/usr/bin/env hero
|
||||||
|
# Multi-section documentation with categories
|
||||||
|
|
||||||
|
!!site.config
|
||||||
|
name: "multi_docs"
|
||||||
|
title: "Complete Documentation"
|
||||||
|
description: "Comprehensive documentation with multiple sections"
|
||||||
|
tagline: "Everything you need to know"
|
||||||
|
copyright: "© 2024 Tech Company"
|
||||||
|
url: "https://docs.techcompany.com"
|
||||||
|
base_url: "/docs"
|
||||||
|
|
||||||
|
!!site.navbar
|
||||||
|
title: "Tech Documentation"
|
||||||
|
logo_src: "img/logo.svg"
|
||||||
|
|
||||||
|
!!site.navbar_item
|
||||||
|
label: "Documentation"
|
||||||
|
to: "/"
|
||||||
|
position: "left"
|
||||||
|
|
||||||
|
!!site.navbar_item
|
||||||
|
label: "API"
|
||||||
|
to: "api"
|
||||||
|
position: "left"
|
||||||
|
|
||||||
|
!!site.navbar_item
|
||||||
|
label: "GitHub"
|
||||||
|
href: "https://github.com/techcompany"
|
||||||
|
position: "right"
|
||||||
|
|
||||||
|
!!site.footer
|
||||||
|
style: "dark"
|
||||||
|
|
||||||
|
!!site.footer_item
|
||||||
|
title: "Guides"
|
||||||
|
label: "Getting Started"
|
||||||
|
to: "getting-started"
|
||||||
|
|
||||||
|
!!site.footer_item
|
||||||
|
title: "Guides"
|
||||||
|
label: "Installation"
|
||||||
|
to: "installation"
|
||||||
|
|
||||||
|
!!site.footer_item
|
||||||
|
title: "Company"
|
||||||
|
label: "Website"
|
||||||
|
href: "https://techcompany.com"
|
||||||
|
|
||||||
|
!!site.footer_item
|
||||||
|
title: "Legal"
|
||||||
|
label: "Privacy"
|
||||||
|
href: "https://techcompany.com/privacy"
|
||||||
|
|
||||||
|
# ==================================================
|
||||||
|
# Getting Started Section
|
||||||
|
# ==================================================
|
||||||
|
|
||||||
|
!!site.page_category
|
||||||
|
name: "getting_started"
|
||||||
|
label: "Getting Started"
|
||||||
|
position: 100
|
||||||
|
|
||||||
|
!!site.page src: "docs:introduction"
|
||||||
|
title: "Introduction"
|
||||||
|
description: "What is this project?"
|
||||||
|
|
||||||
|
!!site.page src: "installation"
|
||||||
|
title: "Installation"
|
||||||
|
description: "Get up and running"
|
||||||
|
|
||||||
|
!!site.page src: "quickstart"
|
||||||
|
title: "Quick Start"
|
||||||
|
description: "Your first steps"
|
||||||
|
|
||||||
|
# ==================================================
|
||||||
|
# Core Concepts Section
|
||||||
|
# ==================================================
|
||||||
|
|
||||||
|
!!site.page_category
|
||||||
|
name: "concepts"
|
||||||
|
label: "Core Concepts"
|
||||||
|
position: 200
|
||||||
|
|
||||||
|
!!site.page src: "concepts:architecture"
|
||||||
|
title: "Architecture"
|
||||||
|
description: "System design and architecture"
|
||||||
|
|
||||||
|
!!site.page src: "components"
|
||||||
|
title: "Components"
|
||||||
|
description: "Main system components"
|
||||||
|
|
||||||
|
!!site.page src: "data_flow"
|
||||||
|
title: "Data Flow"
|
||||||
|
description: "How data flows through the system"
|
||||||
|
|
||||||
|
!!site.page src: "security"
|
||||||
|
title: "Security"
|
||||||
|
description: "Security considerations"
|
||||||
|
|
||||||
|
# ==================================================
|
||||||
|
# Advanced Topics Section
|
||||||
|
# ==================================================
|
||||||
|
|
||||||
|
!!site.page_category
|
||||||
|
name: "advanced"
|
||||||
|
label: "Advanced Topics"
|
||||||
|
position: 300
|
||||||
|
|
||||||
|
!!site.page src: "advanced:performance"
|
||||||
|
title: "Performance Tuning"
|
||||||
|
description: "Optimize your system"
|
||||||
|
|
||||||
|
!!site.page src: "scaling"
|
||||||
|
title: "Scaling"
|
||||||
|
description: "Scale to millions of users"
|
||||||
|
|
||||||
|
!!site.page src: "deployment"
|
||||||
|
title: "Deployment"
|
||||||
|
description: "Deploy to production"
|
||||||
|
|
||||||
|
# ==================================================
|
||||||
|
# API Reference Section
|
||||||
|
# ==================================================
|
||||||
|
|
||||||
|
!!site.page_category
|
||||||
|
name: "api"
|
||||||
|
label: "API Reference"
|
||||||
|
position: 400
|
||||||
|
|
||||||
|
!!site.page src: "api:overview"
|
||||||
|
title: "API Overview"
|
||||||
|
description: "API capabilities and base URLs"
|
||||||
|
|
||||||
|
!!site.page src: "rest_api"
|
||||||
|
title: "REST API"
|
||||||
|
description: "Complete REST API documentation"
|
||||||
|
|
||||||
|
!!site.page src: "graphql_api"
|
||||||
|
title: "GraphQL"
|
||||||
|
description: "GraphQL API documentation"
|
||||||
|
|
||||||
|
!!site.page src: "webhooks"
|
||||||
|
title: "Webhooks"
|
||||||
|
description: "Implement webhooks in your app"
|
||||||
|
|
||||||
|
# ==================================================
|
||||||
|
# Publishing
|
||||||
|
# ==================================================
|
||||||
|
|
||||||
|
!!site.publish
|
||||||
|
path: "/var/www/html/docs"
|
||||||
|
|
||||||
|
!!site.publish_dev
|
||||||
|
path: "/tmp/docs-preview"
|
||||||
116
examples/web/site/process_site.vsh
Normal file
116
examples/web/site/process_site.vsh
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env -S v -n -w -gc none -cg -cc tcc -d use_openssl -enable-globals run
|
||||||
|
|
||||||
|
import incubaid.herolib.core.playbook
|
||||||
|
import incubaid.herolib.web.site
|
||||||
|
import incubaid.herolib.ui.console
|
||||||
|
import os
|
||||||
|
|
||||||
|
// Process a site configuration from HeroScript files
|
||||||
|
|
||||||
|
println(console.color_fg(.green) + '=== Site Configuration Processor ===' + console.reset())
|
||||||
|
|
||||||
|
// Get directory from command line or use default
|
||||||
|
mut config_dir := './docs'
|
||||||
|
if os.args.len > 1 {
|
||||||
|
config_dir = os.args[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if !os.exists(config_dir) {
|
||||||
|
console.print_stderr('Error: Directory not found: ${config_dir}')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.print_item('Processing HeroScript files from: ${config_dir}')
|
||||||
|
|
||||||
|
// Find all heroscript files
|
||||||
|
mut heroscript_files := []string{}
|
||||||
|
entries := os.ls(config_dir) or {
|
||||||
|
console.print_stderr('Error reading directory: ${err}')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for entry in entries {
|
||||||
|
if entry.ends_with('.heroscript') {
|
||||||
|
heroscript_files << entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort files (to ensure numeric prefix order)
|
||||||
|
heroscript_files.sort()
|
||||||
|
|
||||||
|
if heroscript_files.len == 0 {
|
||||||
|
console.print_stderr('No .heroscript files found in ${config_dir}')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.print_item('Found ${heroscript_files.len} HeroScript file(s):')
|
||||||
|
for file in heroscript_files {
|
||||||
|
console.print_item(' - ${file}')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process each file
|
||||||
|
mut site_names := []string{}
|
||||||
|
for file in heroscript_files {
|
||||||
|
full_path := os.join_path(config_dir, file)
|
||||||
|
console.print_lf(1)
|
||||||
|
console.print_header('Processing: ${file}')
|
||||||
|
|
||||||
|
mut plbook := playbook.new(path: full_path) or {
|
||||||
|
console.print_stderr('Error loading ${file}: ${err}')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
site.play(mut plbook) or {
|
||||||
|
console.print_stderr('Error processing ${file}: ${err}')
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all configured sites
|
||||||
|
site_names = site.list()
|
||||||
|
|
||||||
|
if site_names.len == 0 {
|
||||||
|
console.print_stderr('No sites were configured')
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.print_lf(2)
|
||||||
|
console.print_green('=== Configuration Complete ===')
|
||||||
|
|
||||||
|
// Display configured sites
|
||||||
|
for site_name in site_names {
|
||||||
|
mut configured_site := site.get(name: site_name) or { continue }
|
||||||
|
|
||||||
|
console.print_header('Site: ${site_name}')
|
||||||
|
console.print_item('Title: ${configured_site.siteconfig.title}')
|
||||||
|
console.print_item('Pages: ${configured_site.pages.len}')
|
||||||
|
console.print_item('Description: ${configured_site.siteconfig.description}')
|
||||||
|
|
||||||
|
// Show pages organized by category
|
||||||
|
if configured_site.nav.my_sidebar.len > 0 {
|
||||||
|
console.print_item('Navigation structure:')
|
||||||
|
for nav_item in configured_site.nav.my_sidebar {
|
||||||
|
match nav_item {
|
||||||
|
site.NavDoc {
|
||||||
|
console.print_item(' - [Page] ${nav_item.label}')
|
||||||
|
}
|
||||||
|
site.NavCat {
|
||||||
|
console.print_item(' - [Category] ${nav_item.label}')
|
||||||
|
for sub_item in nav_item.items {
|
||||||
|
match sub_item {
|
||||||
|
site.NavDoc {
|
||||||
|
console.print_item(' - ${sub_item.label}')
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.print_lf(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
println(console.color_fg(.green) + '✓ Site configuration ready for deployment' + console.reset())
|
||||||
@@ -34,10 +34,10 @@ fn play_pages(mut plbook PlayBook, mut website Site) ! {
|
|||||||
return error('!!site.page_category: must specify "name"')
|
return error('!!site.page_category: must specify "name"')
|
||||||
}
|
}
|
||||||
|
|
||||||
category_name = texttools.name_fix(category_name)
|
category_name_fixed := texttools.name_fix(category_name)
|
||||||
|
|
||||||
// Get label (derive from name if not specified)
|
// Get label (derive from name if not specified)
|
||||||
mut label := p.get_default('label', texttools.name_fix_snake_to_pascal(category_name))!
|
mut label := p.get_default('label', texttools.name_fix_snake_to_pascal(category_name_fixed))!
|
||||||
mut position := p.get_int_default('position', next_category_position)!
|
mut position := p.get_int_default('position', next_category_position)!
|
||||||
|
|
||||||
// Auto-increment position if using default
|
// Auto-increment position if using default
|
||||||
@@ -46,14 +46,15 @@ fn play_pages(mut plbook PlayBook, mut website Site) ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create and store category info
|
// Create and store category info
|
||||||
categories[category_name] = CategoryInfo{
|
categories[category_name_fixed] = CategoryInfo{
|
||||||
name: category_name
|
name: category_name_fixed
|
||||||
label: label
|
label: label
|
||||||
position: position
|
position: position
|
||||||
nav_items: []NavItem{}
|
nav_items: []NavItem{}
|
||||||
}
|
}
|
||||||
|
|
||||||
category_current = category_name
|
category_current = category_name_fixed
|
||||||
|
console.print_item('Created page category: "${label}" (${category_name_fixed})')
|
||||||
action.done = true
|
action.done = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -131,12 +132,63 @@ fn play_pages(mut plbook PlayBook, mut website Site) ! {
|
|||||||
mut cat_info := categories[category_current]
|
mut cat_info := categories[category_current]
|
||||||
cat_info.nav_items << nav_doc
|
cat_info.nav_items << nav_doc
|
||||||
categories[category_current] = cat_info
|
categories[category_current] = cat_info
|
||||||
|
console.print_debug('Added page "${page_id}" to category "${category_current}"')
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
root_nav_items << nav_doc
|
root_nav_items << nav_doc
|
||||||
|
console.print_debug('Added root page "${page_id}"')
|
||||||
}
|
}
|
||||||
|
|
||||||
action.done = true
|
action.done = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// PASS 2: Build final navigation structure from categories
|
||||||
|
// ============================================================
|
||||||
|
console.print_item('Building navigation structure...')
|
||||||
|
|
||||||
|
mut final_nav_items := []NavItem{}
|
||||||
|
|
||||||
|
// Add root items first
|
||||||
|
for item in root_nav_items {
|
||||||
|
final_nav_items << item
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort categories by position and add them
|
||||||
|
mut sorted_categories := []CategoryInfo{}
|
||||||
|
for _, cat_info in categories {
|
||||||
|
sorted_categories << cat_info
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by position
|
||||||
|
sorted_categories.sort(a.position < b.position)
|
||||||
|
|
||||||
|
// Convert categories to NavCat items and add to navigation
|
||||||
|
for cat_info in sorted_categories {
|
||||||
|
// Unwrap NavDoc items from cat_info.nav_items (they're already NavItem)
|
||||||
|
nav_cat := NavCat{
|
||||||
|
label: cat_info.label
|
||||||
|
collapsible: true
|
||||||
|
collapsed: false
|
||||||
|
items: cat_info.nav_items
|
||||||
|
}
|
||||||
|
final_nav_items << nav_cat
|
||||||
|
console.print_debug('Added category to nav: "${cat_info.label}" with ${cat_info.nav_items.len} items')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update website navigation
|
||||||
|
website.nav.my_sidebar = final_nav_items
|
||||||
|
|
||||||
|
console.print_green('Navigation structure built with ${website.pages.len} pages in ${categories.len} categories')
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------- Internal Type for Tracking --------
|
||||||
|
struct CategoryInfo {
|
||||||
|
pub mut:
|
||||||
|
name string
|
||||||
|
label string
|
||||||
|
position int
|
||||||
|
nav_items []NavItem
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,43 +2,83 @@
|
|||||||
|
|
||||||
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.
|
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
|
## Quick Start
|
||||||
|
|
||||||
|
### Minimal HeroScript Example
|
||||||
|
|
||||||
|
```heroscript
|
||||||
|
!!site.config
|
||||||
|
name: "my_docs"
|
||||||
|
title: "My Documentation"
|
||||||
|
|
||||||
|
!!site.page src: "docs:introduction"
|
||||||
|
title: "Getting Started"
|
||||||
|
|
||||||
|
!!site.page src: "setup"
|
||||||
|
title: "Installation"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Processing with V Code
|
||||||
|
|
||||||
```v
|
```v
|
||||||
#!/usr/bin/env -S v -n -w -gc none -cg -cc tcc -d use_openssl -enable-globals run
|
#!/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.core.playbook
|
||||||
import incubaid.herolib.web.site
|
import incubaid.herolib.web.site
|
||||||
import incubaid.herolib.core.playcmds
|
import incubaid.herolib.ui.console
|
||||||
|
|
||||||
// Clone or use existing repository with HeroScript files
|
// Process HeroScript file
|
||||||
mysitepath := gittools.path(
|
mut plbook := playbook.new(path: './site_config.heroscript')!
|
||||||
git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/ebooks/tech'
|
|
||||||
git_pull: true
|
|
||||||
)!
|
|
||||||
|
|
||||||
// Process all HeroScript files in the path
|
// Execute site configuration
|
||||||
playcmds.run(heroscript_path: mysitepath.path)!
|
site.play(mut plbook)!
|
||||||
|
|
||||||
// Get the configured site
|
// Access the configured site
|
||||||
mut mysite := site.get(name: 'tfgrid_tech')!
|
mut mysite := site.get(name: 'my_docs')!
|
||||||
println(mysite)
|
|
||||||
|
// Print available pages
|
||||||
|
pages_map := mysite.list_pages()
|
||||||
|
for page_id, _ in pages_map {
|
||||||
|
console.print_item('Page: ${page_id}')
|
||||||
|
}
|
||||||
|
|
||||||
|
println('Site has ${mysite.pages.len} pages')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Core Concepts
|
||||||
|
|
||||||
|
### Site
|
||||||
|
A website configuration that contains pages, navigation structure, and metadata.
|
||||||
|
|
||||||
|
### Page
|
||||||
|
A single page with:
|
||||||
|
- **ID**: `collection:page_name` format
|
||||||
|
- **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.
|
||||||
|
|
||||||
|
```heroscript
|
||||||
|
!!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
|
## HeroScript Syntax
|
||||||
|
|
||||||
### Basic Configuration
|
### 1. Site Configuration (Required)
|
||||||
|
|
||||||
```heroscript
|
```heroscript
|
||||||
!!site.config
|
!!site.config
|
||||||
@@ -51,20 +91,49 @@ println(mysite)
|
|||||||
copyright: "© 2024 My Organization"
|
copyright: "© 2024 My Organization"
|
||||||
url: "https://docs.example.com"
|
url: "https://docs.example.com"
|
||||||
base_url: "/"
|
base_url: "/"
|
||||||
|
url_home: "/docs"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Navigation Menu
|
**Parameters:**
|
||||||
|
- `name` - Internal site identifier (default: 'default')
|
||||||
|
- `title` - Main site title (shown in browser tab)
|
||||||
|
- `description` - Site description for SEO
|
||||||
|
- `tagline` - Short tagline/subtitle
|
||||||
|
- `favicon` - Path to favicon image
|
||||||
|
- `image` - Default OG image for social sharing
|
||||||
|
- `copyright` - Copyright notice
|
||||||
|
- `url` - Full site URL for Docusaurus
|
||||||
|
- `base_url` - Base URL path (e.g., "/" or "/docs/")
|
||||||
|
- `url_home` - Home page path
|
||||||
|
|
||||||
|
### 2. Metadata Overrides (Optional)
|
||||||
|
|
||||||
|
```heroscript
|
||||||
|
!!site.config_meta
|
||||||
|
title: "My Docs - Technical Reference"
|
||||||
|
image: "img/tech-og.png"
|
||||||
|
description: "Technical documentation and API reference"
|
||||||
|
```
|
||||||
|
|
||||||
|
Overrides specific metadata for SEO without changing core config.
|
||||||
|
|
||||||
|
### 3. Navigation Bar
|
||||||
|
|
||||||
```heroscript
|
```heroscript
|
||||||
!!site.navbar
|
!!site.navbar
|
||||||
title: "My Site"
|
title: "My Documentation"
|
||||||
logo_alt: "Site Logo"
|
logo_alt: "Site Logo"
|
||||||
logo_src: "img/logo.svg"
|
logo_src: "img/logo.svg"
|
||||||
logo_src_dark: "img/logo-dark.svg"
|
logo_src_dark: "img/logo-dark.svg"
|
||||||
|
|
||||||
!!site.navbar_item
|
!!site.navbar_item
|
||||||
label: "Documentation"
|
label: "Documentation"
|
||||||
to: "docs/intro"
|
to: "intro"
|
||||||
|
position: "left"
|
||||||
|
|
||||||
|
!!site.navbar_item
|
||||||
|
label: "API Reference"
|
||||||
|
to: "docs/api"
|
||||||
position: "left"
|
position: "left"
|
||||||
|
|
||||||
!!site.navbar_item
|
!!site.navbar_item
|
||||||
@@ -73,7 +142,13 @@ println(mysite)
|
|||||||
position: "right"
|
position: "right"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Footer Configuration
|
**Parameters:**
|
||||||
|
- `label` - Display text (required)
|
||||||
|
- `to` - Internal link
|
||||||
|
- `href` - External URL
|
||||||
|
- `position` - "left" or "right" in navbar
|
||||||
|
|
||||||
|
### 4. Footer Configuration
|
||||||
|
|
||||||
```heroscript
|
```heroscript
|
||||||
!!site.footer
|
!!site.footer
|
||||||
@@ -87,311 +162,234 @@ println(mysite)
|
|||||||
!!site.footer_item
|
!!site.footer_item
|
||||||
title: "Docs"
|
title: "Docs"
|
||||||
label: "Getting Started"
|
label: "Getting Started"
|
||||||
href: "https://docs.example.com/getting-started"
|
to: "getting-started"
|
||||||
|
|
||||||
!!site.footer_item
|
!!site.footer_item
|
||||||
title: "Community"
|
title: "Community"
|
||||||
label: "Discord"
|
label: "Discord"
|
||||||
href: "https://discord.gg/example"
|
href: "https://discord.gg/example"
|
||||||
|
|
||||||
|
!!site.footer_item
|
||||||
|
title: "Legal"
|
||||||
|
label: "Privacy"
|
||||||
|
href: "https://example.com/privacy"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Page Organization
|
### 5. Announcement Bar (Optional)
|
||||||
|
|
||||||
### 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.
|
|
||||||
|
|
||||||
```heroscript
|
```heroscript
|
||||||
!!site.page src: "mycelium_tech:introduction"
|
!!site.announcement
|
||||||
description: "Introduction to ThreeFold Technology"
|
id: "new-release"
|
||||||
slug: "/"
|
content: "🎉 Version 2.0 is now available!"
|
||||||
|
background_color: "#20232a"
|
||||||
!!site.page src: "vision"
|
text_color: "#fff"
|
||||||
description: "Our Vision for the Future Internet"
|
is_closeable: true
|
||||||
|
|
||||||
!!site.page src: "what"
|
|
||||||
description: "What ThreeFold is Building"
|
|
||||||
|
|
||||||
!!site.page src: "presentation"
|
|
||||||
description: "ThreeFold Technology Presentation"
|
|
||||||
|
|
||||||
!!site.page src: "status"
|
|
||||||
description: "Current Development Status"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Key Points:**
|
### 6. Pages and Categories
|
||||||
|
|
||||||
- First page specifies collection as `tech:introduction` (collection:page_name format)
|
#### Simple: Pages Without Categories
|
||||||
- Subsequent pages only need the page name (e.g., `vision`) - the `tech` collection is reused
|
|
||||||
- If `title` is not specified, it will be extracted from the markdown file itself
|
|
||||||
- Pages are ordered by their appearance in the HeroScript file
|
|
||||||
- `slug` can be used to customize the URL path (e.g., `"/"` for homepage)
|
|
||||||
|
|
||||||
### Example 2: Pages with Categories
|
```heroscript
|
||||||
|
!!site.page src: "guides:introduction"
|
||||||
|
title: "Getting Started"
|
||||||
|
description: "Introduction to the platform"
|
||||||
|
|
||||||
Categories (sections) help organize pages into logical groups with their own navigation structure.
|
!!site.page src: "installation"
|
||||||
|
title: "Installation"
|
||||||
|
|
||||||
|
!!site.page src: "configuration"
|
||||||
|
title: "Configuration"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Advanced: Pages With Categories
|
||||||
|
|
||||||
```heroscript
|
```heroscript
|
||||||
!!site.page_category
|
!!site.page_category
|
||||||
name: "first_principle_thinking"
|
name: "basics"
|
||||||
label: "First Principle Thinking"
|
label: "Getting Started"
|
||||||
|
|
||||||
!!site.page src: "first_principle_thinking:hardware_badly_used"
|
!!site.page src: "guides:introduction"
|
||||||
description: "Hardware is not used properly, why it is important to understand hardware"
|
title: "Introduction"
|
||||||
|
description: "Learn the basics"
|
||||||
|
|
||||||
!!site.page src: "internet_risk"
|
!!site.page src: "installation"
|
||||||
description: "Internet risk, how to mitigate it, and why it is important"
|
title: "Installation"
|
||||||
|
|
||||||
!!site.page src: "onion_analogy"
|
!!site.page src: "configuration"
|
||||||
description: "Compare onion with a computer, layers of abstraction"
|
title: "Configuration"
|
||||||
```
|
|
||||||
|
|
||||||
**Key Points:**
|
|
||||||
|
|
||||||
- `!!site.page_category` creates a new section/category
|
|
||||||
- `name` is the internal identifier (snake_case)
|
|
||||||
- `label` is the display name (automatically derived from `name` if not specified)
|
|
||||||
- Category name is converted to title case: `first_principle_thinking` → "First Principle Thinking"
|
|
||||||
- Once a category is defined, all subsequent pages belong to it until a new category is declared
|
|
||||||
- Collection persistence works the same: specify once (e.g., `first_principle_thinking:hardware_badly_used`), then reuse
|
|
||||||
|
|
||||||
### Example 3: Advanced Page Configuration
|
|
||||||
|
|
||||||
```heroscript
|
|
||||||
!!site.page_category
|
!!site.page_category
|
||||||
name: "components"
|
name: "advanced"
|
||||||
label: "System Components"
|
label: "Advanced Topics"
|
||||||
position: 100
|
|
||||||
|
|
||||||
!!site.page src: "mycelium_tech:mycelium"
|
!!site.page src: "advanced:performance"
|
||||||
title: "Mycelium Network"
|
title: "Performance Tuning"
|
||||||
description: "Peer-to-peer overlay network"
|
|
||||||
slug: "mycelium-network"
|
|
||||||
position: 1
|
|
||||||
draft: false
|
|
||||||
hide_title: false
|
|
||||||
|
|
||||||
!!site.page src: "fungistor"
|
!!site.page src: "scaling"
|
||||||
title: "Fungistor Storage"
|
title: "Scaling Guide"
|
||||||
description: "Distributed storage system"
|
|
||||||
position: 2
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Available Page Parameters:**
|
**Page Parameters:**
|
||||||
|
- `src` - Source as `collection:page` (first page) or just `page_name` (reuse collection)
|
||||||
|
- `title` - Page title (optional, extracted from markdown if not provided)
|
||||||
|
- `description` - Page description
|
||||||
|
- `draft` - Hide from navigation (default: false)
|
||||||
|
- `hide_title` - Don't show title in page (default: false)
|
||||||
|
|
||||||
- `src`: Source reference as `collection:page_name` (required for first page in collection)
|
### 7. Content Imports
|
||||||
- `title`: Page title (optional, extracted from markdown if not provided)
|
|
||||||
- `description`: Page description for metadata
|
|
||||||
- `slug`: Custom URL slug
|
|
||||||
- `position`: Manual ordering (auto-incremented if not specified)
|
|
||||||
- `draft`: Mark page as draft (default: false)
|
|
||||||
- `hide_title`: Hide the page title in rendering (default: false)
|
|
||||||
- `path`: Custom path for the page (defaults to category name)
|
|
||||||
- `category`: Override the current category for this page
|
|
||||||
|
|
||||||
## File Organization
|
|
||||||
|
|
||||||
HeroScript files should be organized with numeric prefixes to control execution order:
|
|
||||||
|
|
||||||
```
|
|
||||||
docs/
|
|
||||||
├── 0_config.heroscript # Site configuration
|
|
||||||
├── 1_menu.heroscript # Navigation and footer
|
|
||||||
├── 2_intro_pages.heroscript # Introduction pages
|
|
||||||
├── 3_tech_pages.heroscript # Technical documentation
|
|
||||||
└── 4_api_pages.heroscript # API reference
|
|
||||||
```
|
|
||||||
|
|
||||||
**Important:** Files are processed in alphabetical order, so use numeric prefixes (0_, 1_, 2_, etc.) to ensure correct execution sequence.
|
|
||||||
|
|
||||||
## Import External Content
|
|
||||||
|
|
||||||
```heroscript
|
```heroscript
|
||||||
!!site.import
|
!!site.import
|
||||||
url: "https://github.com/example/external-docs"
|
url: "https://github.com/example/external-docs"
|
||||||
|
path: "/local/path/to/repo"
|
||||||
dest: "external"
|
dest: "external"
|
||||||
replace: "PROJECT_NAME:My Project,VERSION:1.0.0"
|
replace: "PROJECT_NAME:My Project,VERSION:1.0.0"
|
||||||
visible: true
|
visible: true
|
||||||
```
|
```
|
||||||
|
|
||||||
## Publish Destinations
|
### 8. Publishing Destinations
|
||||||
|
|
||||||
```heroscript
|
```heroscript
|
||||||
!!site.publish
|
!!site.publish
|
||||||
path: "/var/www/html/docs"
|
path: "/var/www/html/docs"
|
||||||
ssh_name: "production_server"
|
ssh_name: "production"
|
||||||
|
|
||||||
!!site.publish_dev
|
!!site.publish_dev
|
||||||
path: "/tmp/docs-preview"
|
path: "/tmp/docs-preview"
|
||||||
```
|
```
|
||||||
|
|
||||||
## HeroScript Processing Order
|
---
|
||||||
|
|
||||||
Atlas processes HeroScript actions in a fixed order. Each step depends on previous steps:
|
## Common Patterns
|
||||||
|
|
||||||
1. **Site Configuration** (`!!site.config`) - Required
|
### Pattern 1: Multi-Section Technical Documentation
|
||||||
- Sets basic site metadata and URLs
|
|
||||||
|
|
||||||
2. **Metadata Overrides** (`!!site.config_meta`) - Optional
|
|
||||||
- Overrides specific SEO metadata
|
|
||||||
|
|
||||||
3. **Content Imports** (`!!site.import`) - Optional
|
|
||||||
- Defines external content imports
|
|
||||||
|
|
||||||
4. **Navigation Menu** (`!!site.navbar` + `!!site.navbar_item`) - Recommended
|
|
||||||
- Configures top navigation bar
|
|
||||||
|
|
||||||
5. **Footer** (`!!site.footer` + `!!site.footer_item`) - Recommended
|
|
||||||
- Configures footer links
|
|
||||||
|
|
||||||
6. **Announcement Bar** (`!!site.announcement`) - Optional
|
|
||||||
- Configures optional announcement banner
|
|
||||||
|
|
||||||
7. **Publishing** (`!!site.publish` + `!!site.publish_dev`) - Optional
|
|
||||||
- Defines deployment destinations
|
|
||||||
|
|
||||||
8. **Pages** (`!!site.page_category` + `!!site.page`) - Recommended
|
|
||||||
- Defines content pages and navigation structure
|
|
||||||
|
|
||||||
### Error Handling
|
```heroscript
|
||||||
|
|
||||||
The play function validates parameters and provides helpful error messages:
|
|
||||||
|
|
||||||
```/dev/null/error_example.txt#L1-4
|
|
||||||
!!site.page: must specify source as "collection:page_name" in "src"
|
|
||||||
Got src="invalid_page" with no collection previously set
|
|
||||||
Either specify "collection:page_name" or define a collection first
|
|
||||||
```
|
|
||||||
|
|
||||||
### Best Practices for HeroScript
|
|
||||||
|
|
||||||
```heroscript/example.heroscript#L1-20
|
|
||||||
# 1. Always start with config
|
|
||||||
!!site.config
|
!!site.config
|
||||||
name: "my_docs"
|
name: "tech_docs"
|
||||||
title: "My Documentation"
|
title: "Technical Documentation"
|
||||||
|
|
||||||
# 2. Set up navigation
|
!!site.page_category
|
||||||
!!site.navbar title: "MyDocs"
|
name: "getting_started"
|
||||||
|
label: "Getting Started"
|
||||||
|
|
||||||
# 3. Define pages with reusable collection
|
!!site.page src: "docs:intro"
|
||||||
!!site.page_category name: "intro"
|
title: "Introduction"
|
||||||
|
|
||||||
!!site.page src: "guides:introduction"
|
!!site.page src: "installation"
|
||||||
title: "Getting Started"
|
|
||||||
|
|
||||||
!!site.page src: "setup" # Reuses "guides" collection
|
|
||||||
title: "Installation"
|
title: "Installation"
|
||||||
|
|
||||||
!!site.page src: "tutorial" # Still uses "guides"
|
!!site.page_category
|
||||||
title: "Tutorial"
|
name: "concepts"
|
||||||
|
label: "Core Concepts"
|
||||||
|
|
||||||
# 4. Change collection when needed
|
!!site.page src: "concepts:architecture"
|
||||||
!!site.page src: "api:reference"
|
title: "Architecture"
|
||||||
title: "API Reference"
|
|
||||||
|
|
||||||
!!site.page src: "endpoints" # Now uses "api" collection
|
!!site.page src: "components"
|
||||||
title: "Endpoints"
|
title: "Components"
|
||||||
|
|
||||||
|
!!site.page_category
|
||||||
|
name: "api"
|
||||||
|
label: "API Reference"
|
||||||
|
|
||||||
|
!!site.page src: "api:rest"
|
||||||
|
title: "REST API"
|
||||||
|
|
||||||
|
!!site.page src: "graphql"
|
||||||
|
title: "GraphQL"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Factory Methods
|
### Pattern 2: Simple Blog/Knowledge Base
|
||||||
|
|
||||||
### Create or Get a Site
|
```heroscript
|
||||||
|
!!site.config
|
||||||
|
name: "blog"
|
||||||
|
title: "Knowledge Base"
|
||||||
|
|
||||||
```v
|
!!site.page src: "articles:first_post"
|
||||||
import incubaid.herolib.web.site
|
title: "Welcome to Our Blog"
|
||||||
|
|
||||||
// Create a new site
|
!!site.page src: "second_post"
|
||||||
mut mysite := site.new(name: 'my_docs')!
|
title: "Understanding the Basics"
|
||||||
|
|
||||||
// Get an existing site
|
!!site.page src: "third_post"
|
||||||
mut mysite := site.get(name: 'my_docs')!
|
title: "Advanced Techniques"
|
||||||
|
|
||||||
// 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
|
### Pattern 3: Project with External Imports
|
||||||
|
|
||||||
```v
|
```heroscript
|
||||||
import incubaid.herolib.core.playbook
|
!!site.config
|
||||||
import incubaid.herolib.web.site
|
name: "project_docs"
|
||||||
|
title: "Project Documentation"
|
||||||
|
|
||||||
// Create playbook from path
|
!!site.import
|
||||||
mut plbook := playbook.new(path: '/path/to/heroscripts')!
|
url: "https://github.com/org/shared-docs"
|
||||||
|
dest: "shared"
|
||||||
|
visible: true
|
||||||
|
|
||||||
// Process site configuration
|
!!site.page_category
|
||||||
site.play(mut plbook)!
|
name: "product"
|
||||||
|
label: "Product Guide"
|
||||||
|
|
||||||
// Access the configured site
|
!!site.page src: "docs:overview"
|
||||||
mut mysite := site.get(name: 'my_site')!
|
title: "Overview"
|
||||||
|
|
||||||
|
!!site.page src: "features"
|
||||||
|
title: "Features"
|
||||||
|
|
||||||
|
!!site.page_category
|
||||||
|
name: "resources"
|
||||||
|
label: "Shared Resources"
|
||||||
|
|
||||||
|
!!site.page src: "shared:common"
|
||||||
|
title: "Common Patterns"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Data Structures
|
---
|
||||||
|
|
||||||
### Site
|
## File Organization
|
||||||
|
|
||||||
```v
|
Organize HeroScript files with numeric prefixes to control execution order:
|
||||||
pub struct Site {
|
|
||||||
pub mut:
|
```
|
||||||
pages []Page
|
docs/
|
||||||
sections []Section
|
├── 0_config.heroscript
|
||||||
siteconfig SiteConfig
|
│ └── !!site.config and !!site.config_meta
|
||||||
}
|
│
|
||||||
|
├── 1_menu.heroscript
|
||||||
|
│ └── !!site.navbar and !!site.footer
|
||||||
|
│
|
||||||
|
├── 2_pages.heroscript
|
||||||
|
│ └── !!site.page_category and !!site.page actions
|
||||||
|
│
|
||||||
|
└── 3_publish.heroscript
|
||||||
|
└── !!site.publish destinations
|
||||||
```
|
```
|
||||||
|
|
||||||
### Page
|
**Why numeric prefixes?**
|
||||||
|
|
||||||
```v
|
Files are processed in alphabetical order. Numeric prefixes ensure:
|
||||||
pub struct Page {
|
- Site config runs first
|
||||||
pub mut:
|
- Navigation menu configures before pages
|
||||||
name string // Page identifier
|
- Pages build the final structure
|
||||||
title string // Display title
|
- Publishing configured last
|
||||||
description string // Page description
|
|
||||||
draft bool // Draft status
|
|
||||||
position int // Sort order
|
|
||||||
hide_title bool // Hide title in rendering
|
|
||||||
src string // Source as collection:page_name
|
|
||||||
path string // URL path (without page name)
|
|
||||||
section_name string // Category/section name
|
|
||||||
title_nr int // Title numbering level
|
|
||||||
slug string // Custom URL slug
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Section
|
---
|
||||||
|
|
||||||
```v
|
## Processing Order
|
||||||
pub struct Section {
|
|
||||||
pub mut:
|
|
||||||
name string // Internal identifier
|
|
||||||
position int // Sort order
|
|
||||||
path string // URL path
|
|
||||||
label string // Display name
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Best Practices
|
The Site module processes HeroScript in this strict order:
|
||||||
|
|
||||||
1. **File Naming**: Use numeric prefixes (0_, 1_, 2_) to control execution order
|
1. Site Configuration
|
||||||
2. **Collection Reuse**: Specify collection once, then reuse for subsequent pages
|
2. Metadata Overrides
|
||||||
3. **Category Organization**: Group related pages under categories for better navigation
|
3. Imports
|
||||||
4. **Title Extraction**: Let titles be extracted from markdown files when possible
|
4. Navigation
|
||||||
5. **Position Management**: Use automatic positioning unless you need specific ordering
|
5. Footer
|
||||||
6. **Description**: Always provide descriptions for better SEO and navigation
|
6. Announcement
|
||||||
7. **Draft Status**: Use `draft: true` for work-in-progress pages
|
7. Publishing
|
||||||
|
8. Pages & Categories
|
||||||
|
|
||||||
## Complete Example
|
Each stage depends on previous stages completing successfully.
|
||||||
|
|
||||||
See `examples/web/site/site_example.vsh` for a complete working example.
|
|
||||||
|
|
||||||
For a real-world example, check: <https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/ebooks/tech>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user