...
This commit is contained in:
@@ -1,20 +1,99 @@
|
||||
#!/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 os
|
||||
import incubaid.herolib.develop.gittools
|
||||
import incubaid.herolib.web.site
|
||||
import incubaid.herolib.core.playcmds
|
||||
|
||||
// Example 1: Load site configuration from a Git repository
|
||||
println('=== Example 1: Loading from Git Repository ===')
|
||||
url := 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/ebooks/tech'
|
||||
|
||||
mysitepath := gittools.path(
|
||||
// git_pull: true
|
||||
// git_reset: true
|
||||
git_url: url
|
||||
// git_root: '/tmp/code'
|
||||
git_pull: true
|
||||
// git_reset: true // Uncomment to reset to latest
|
||||
)!
|
||||
|
||||
// Process all HeroScript files in the repository
|
||||
playcmds.run(heroscript_path: mysitepath.path)!
|
||||
|
||||
// Get the configured site
|
||||
mut mysite := site.get(name: 'tfgrid_tech')!
|
||||
println(mysite)
|
||||
println('Site loaded: ${mysite.siteconfig.name}')
|
||||
println('Title: ${mysite.siteconfig.title}')
|
||||
println('Pages: ${mysite.pages.len}')
|
||||
println('Sections: ${mysite.sections.len}')
|
||||
println('')
|
||||
|
||||
// Example 2: Inspect site structure
|
||||
println('=== Example 2: Site Structure ===')
|
||||
println('Sections:')
|
||||
for section in mysite.sections {
|
||||
println(' - ${section.label} (${section.name})')
|
||||
}
|
||||
println('')
|
||||
|
||||
println('Pages (first 5):')
|
||||
for i, page in mysite.pages {
|
||||
if i >= 5 {
|
||||
break
|
||||
}
|
||||
println(' - ${page.name}: ${page.description}')
|
||||
println(' Section: ${page.section_name}, Position: ${page.position}')
|
||||
}
|
||||
println('')
|
||||
|
||||
// Example 3: Access menu configuration
|
||||
println('=== Example 3: Navigation Menu ===')
|
||||
println('Menu Title: ${mysite.siteconfig.menu.title}')
|
||||
println('Menu Items:')
|
||||
for item in mysite.siteconfig.menu.items {
|
||||
if item.href != '' {
|
||||
println(' - ${item.label} -> ${item.href} (external)')
|
||||
} else {
|
||||
println(' - ${item.label} -> ${item.to} (internal)')
|
||||
}
|
||||
}
|
||||
println('')
|
||||
|
||||
// Example 4: Access footer configuration
|
||||
println('=== Example 4: Footer Configuration ===')
|
||||
println('Footer Style: ${mysite.siteconfig.footer.style}')
|
||||
println('Footer Links:')
|
||||
for link in mysite.siteconfig.footer.links {
|
||||
println(' ${link.title}:')
|
||||
for item in link.items {
|
||||
if item.href != '' {
|
||||
println(' - ${item.label} -> ${item.href}')
|
||||
} else {
|
||||
println(' - ${item.label} -> ${item.to}')
|
||||
}
|
||||
}
|
||||
}
|
||||
println('')
|
||||
|
||||
// Example 5: List all configured sites
|
||||
println('=== Example 5: All Configured Sites ===')
|
||||
all_sites := site.list()
|
||||
println('Total sites: ${all_sites.len}')
|
||||
for site_name in all_sites {
|
||||
println(' - ${site_name}')
|
||||
}
|
||||
println('')
|
||||
|
||||
// Example 6: Check if a site exists
|
||||
println('=== Example 6: Site Existence Check ===')
|
||||
if site.exists(name: 'tfgrid_tech') {
|
||||
println('Site "tfgrid_tech" exists')
|
||||
} else {
|
||||
println('Site "tfgrid_tech" does not exist')
|
||||
}
|
||||
|
||||
if site.exists(name: 'nonexistent_site') {
|
||||
println('Site "nonexistent_site" exists')
|
||||
} else {
|
||||
println('Site "nonexistent_site" does not exist')
|
||||
}
|
||||
println('')
|
||||
|
||||
println('=== Example Complete ===')
|
||||
536
lib/web/site/ai_instructions.md
Normal file
536
lib/web/site/ai_instructions.md
Normal file
@@ -0,0 +1,536 @@
|
||||
# AI Instructions for Site Module HeroScript
|
||||
|
||||
This document provides comprehensive instructions for AI agents working with the Site module's HeroScript format.
|
||||
|
||||
## HeroScript Format Overview
|
||||
|
||||
HeroScript is a declarative configuration language with the following characteristics:
|
||||
|
||||
### Basic Syntax
|
||||
|
||||
```heroscript
|
||||
!!actor.action
|
||||
param1: "value1"
|
||||
param2: "value2"
|
||||
multiline_param: "
|
||||
This is a multiline value.
|
||||
It can span multiple lines.
|
||||
"
|
||||
arg1 arg2 // Arguments without keys
|
||||
```
|
||||
|
||||
**Key Rules:**
|
||||
1. Actions start with `!!` followed by `actor.action` format
|
||||
2. Parameters are indented and use `key: "value"` or `key: value` format
|
||||
3. Values with spaces must be quoted
|
||||
4. Multiline values are supported with quotes
|
||||
5. Arguments without keys are space-separated
|
||||
6. Comments start with `//`
|
||||
|
||||
## Site Module Actions
|
||||
|
||||
### 1. Site Configuration (`!!site.config`)
|
||||
|
||||
**Purpose:** Define the main site configuration including title, description, and metadata.
|
||||
|
||||
**Required Parameters:**
|
||||
- `name`: Site identifier (will be normalized to snake_case)
|
||||
|
||||
**Optional Parameters:**
|
||||
- `title`: Site title (default: "Documentation Site")
|
||||
- `description`: Site description
|
||||
- `tagline`: Site tagline
|
||||
- `favicon`: Path to favicon (default: "img/favicon.png")
|
||||
- `image`: Default site image (default: "img/tf_graph.png")
|
||||
- `copyright`: Copyright text
|
||||
- `url`: Main site URL
|
||||
- `base_url`: Base URL path (default: "/")
|
||||
- `url_home`: Home page path
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.config
|
||||
name: "my_documentation"
|
||||
title: "My Documentation Site"
|
||||
description: "Comprehensive technical documentation"
|
||||
tagline: "Learn everything you need"
|
||||
url: "https://docs.example.com"
|
||||
base_url: "/"
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- Always include `name` parameter
|
||||
- Use descriptive titles and descriptions
|
||||
- Ensure URLs are properly formatted with protocol
|
||||
|
||||
### 2. Metadata Configuration (`!!site.config_meta`)
|
||||
|
||||
**Purpose:** Override specific metadata for SEO purposes.
|
||||
|
||||
**Optional Parameters:**
|
||||
- `title`: SEO-specific title (overrides site.config title for meta tags)
|
||||
- `image`: SEO-specific image (overrides site.config image for og:image)
|
||||
- `description`: SEO-specific description
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.config_meta
|
||||
title: "My Docs - Complete Guide"
|
||||
image: "img/social-preview.png"
|
||||
description: "The ultimate guide to using our platform"
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- Use only when SEO metadata needs to differ from main config
|
||||
- Keep titles concise for social media sharing
|
||||
- Use high-quality images for social previews
|
||||
|
||||
### 3. Navigation Bar (`!!site.navbar` or `!!site.menu`)
|
||||
|
||||
**Purpose:** Configure the main navigation bar.
|
||||
|
||||
**Optional Parameters:**
|
||||
- `title`: Navigation title (defaults to site.config title)
|
||||
- `logo_alt`: Logo alt text
|
||||
- `logo_src`: Logo image path
|
||||
- `logo_src_dark`: Dark mode logo path
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.navbar
|
||||
title: "My Site"
|
||||
logo_alt: "My Site Logo"
|
||||
logo_src: "img/logo.svg"
|
||||
logo_src_dark: "img/logo-dark.svg"
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- Use `!!site.navbar` for modern syntax (preferred)
|
||||
- `!!site.menu` is supported for backward compatibility
|
||||
- Provide both light and dark logos when possible
|
||||
|
||||
### 4. Navigation Items (`!!site.navbar_item` or `!!site.menu_item`)
|
||||
|
||||
**Purpose:** Add items to the navigation bar.
|
||||
|
||||
**Required Parameters (one of):**
|
||||
- `to`: Internal link path
|
||||
- `href`: External URL
|
||||
|
||||
**Optional Parameters:**
|
||||
- `label`: Display text (required in practice)
|
||||
- `position`: "left" or "right" (default: "right")
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.navbar_item
|
||||
label: "Documentation"
|
||||
to: "docs/intro"
|
||||
position: "left"
|
||||
|
||||
!!site.navbar_item
|
||||
label: "GitHub"
|
||||
href: "https://github.com/myorg/repo"
|
||||
position: "right"
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- Use `to` for internal navigation
|
||||
- Use `href` for external links
|
||||
- Position important items on the left, secondary items on the right
|
||||
|
||||
### 5. Footer Configuration (`!!site.footer`)
|
||||
|
||||
**Purpose:** Configure footer styling.
|
||||
|
||||
**Optional Parameters:**
|
||||
- `style`: "dark" or "light" (default: "dark")
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.footer
|
||||
style: "dark"
|
||||
```
|
||||
|
||||
### 6. Footer Items (`!!site.footer_item`)
|
||||
|
||||
**Purpose:** Add links to the footer, grouped by title.
|
||||
|
||||
**Required Parameters:**
|
||||
- `title`: Group title (items with same title are grouped together)
|
||||
- `label`: Link text
|
||||
|
||||
**Required Parameters (one of):**
|
||||
- `to`: Internal link path
|
||||
- `href`: External URL
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.footer_item
|
||||
title: "Docs"
|
||||
label: "Introduction"
|
||||
to: "intro"
|
||||
|
||||
!!site.footer_item
|
||||
title: "Docs"
|
||||
label: "API Reference"
|
||||
to: "api"
|
||||
|
||||
!!site.footer_item
|
||||
title: "Community"
|
||||
label: "Discord"
|
||||
href: "https://discord.gg/example"
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- Group related links under the same title
|
||||
- Use consistent title names across related items
|
||||
- Provide both internal and external links as appropriate
|
||||
|
||||
### 7. Page Categories (`!!site.page_category`)
|
||||
|
||||
**Purpose:** Create a section/category to organize pages.
|
||||
|
||||
**Required Parameters:**
|
||||
- `name`: Category identifier (snake_case)
|
||||
|
||||
**Optional Parameters:**
|
||||
- `label`: Display name (auto-generated from name if not provided)
|
||||
- `position`: Manual sort order (auto-incremented if not specified)
|
||||
- `path`: URL path segment (defaults to normalized label)
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.page_category
|
||||
name: "getting_started"
|
||||
label: "Getting Started"
|
||||
position: 100
|
||||
|
||||
!!site.page_category
|
||||
name: "advanced_topics"
|
||||
label: "Advanced Topics"
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- Use descriptive snake_case names
|
||||
- Let label be auto-generated when possible (name_fix converts to Title Case)
|
||||
- Categories persist for all subsequent pages until a new category is declared
|
||||
- Position values should leave gaps (100, 200, 300) for future insertions
|
||||
|
||||
### 8. Pages (`!!site.page`)
|
||||
|
||||
**Purpose:** Define individual pages in the site.
|
||||
|
||||
**Required Parameters:**
|
||||
- `src`: Source reference as `collection:page_name` (required for first page in a collection)
|
||||
|
||||
**Optional Parameters:**
|
||||
- `name`: Page identifier (extracted from src if not provided)
|
||||
- `title`: Page title (extracted from markdown if not provided)
|
||||
- `description`: Page description for metadata
|
||||
- `slug`: Custom URL slug
|
||||
- `position`: Manual sort order (auto-incremented if not specified)
|
||||
- `draft`: Mark as draft (default: false)
|
||||
- `hide_title`: Hide title in rendering (default: false)
|
||||
- `path`: Custom path (defaults to current category name)
|
||||
- `category`: Override current category
|
||||
- `title_nr`: Title numbering level
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.page src: "docs:introduction"
|
||||
description: "Introduction to the platform"
|
||||
slug: "/"
|
||||
|
||||
!!site.page src: "quickstart"
|
||||
description: "Get started in 5 minutes"
|
||||
|
||||
!!site.page src: "installation"
|
||||
title: "Installation Guide"
|
||||
description: "How to install and configure"
|
||||
position: 10
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- **Collection Persistence:** Specify collection once (e.g., `docs:introduction`), then subsequent pages only need page name (e.g., `quickstart`)
|
||||
- **Category Persistence:** Pages belong to the most recently declared category
|
||||
- **Title Extraction:** Prefer extracting titles from markdown files
|
||||
- **Position Management:** Use automatic positioning unless specific order is required
|
||||
- **Description Required:** Always provide descriptions for SEO
|
||||
- **Slug Usage:** Use slug for special pages like homepage (`slug: "/"`)
|
||||
|
||||
### 9. Import External Content (`!!site.import`)
|
||||
|
||||
**Purpose:** Import content from external sources.
|
||||
|
||||
**Optional Parameters:**
|
||||
- `name`: Import identifier
|
||||
- `url`: Git URL or HTTP URL
|
||||
- `path`: Local file system path
|
||||
- `dest`: Destination path in site
|
||||
- `replace`: Comma-separated key:value pairs for variable replacement
|
||||
- `visible`: Whether imported content is visible (default: true)
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.import
|
||||
url: "https://github.com/example/docs"
|
||||
dest: "external"
|
||||
replace: "VERSION:1.0.0,PROJECT:MyProject"
|
||||
visible: true
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- Use for shared documentation across multiple sites
|
||||
- Replace variables using `${VARIABLE}` syntax in source content
|
||||
- Set `visible: false` for imported templates or partials
|
||||
|
||||
### 10. Publish Destinations (`!!site.publish` and `!!site.publish_dev`)
|
||||
|
||||
**Purpose:** Define where to publish the built site.
|
||||
|
||||
**Optional Parameters:**
|
||||
- `path`: File system path or URL
|
||||
- `ssh_name`: SSH connection name for remote deployment
|
||||
|
||||
**Example:**
|
||||
```heroscript
|
||||
!!site.publish
|
||||
path: "/var/www/html/docs"
|
||||
ssh_name: "production_server"
|
||||
|
||||
!!site.publish_dev
|
||||
path: "/tmp/docs-preview"
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- Use `!!site.publish` for production deployments
|
||||
- Use `!!site.publish_dev` for development/preview deployments
|
||||
- Can specify multiple destinations
|
||||
|
||||
## File Organization Best Practices
|
||||
|
||||
### Naming Convention
|
||||
|
||||
Use numeric prefixes to control execution order:
|
||||
|
||||
```
|
||||
0_config.heroscript # Site configuration
|
||||
1_navigation.heroscript # Menu and footer
|
||||
2_intro.heroscript # Introduction pages
|
||||
3_guides.heroscript # User guides
|
||||
4_reference.heroscript # API reference
|
||||
```
|
||||
|
||||
**AI Guidelines:**
|
||||
- Always use numeric prefixes (0_, 1_, 2_, etc.)
|
||||
- Leave gaps in numbering (0, 10, 20) for future insertions
|
||||
- Group related configurations in the same file
|
||||
- Process order matters: config → navigation → pages
|
||||
|
||||
### Execution Order Rules
|
||||
|
||||
1. **Configuration First:** `!!site.config` must be processed before other actions
|
||||
2. **Categories Before Pages:** Declare `!!site.page_category` before pages in that category
|
||||
3. **Collection Persistence:** First page in a collection must specify `collection:page_name`
|
||||
4. **Category Persistence:** Pages inherit the most recent category declaration
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern 1: Simple Documentation Site
|
||||
|
||||
```heroscript
|
||||
!!site.config
|
||||
name: "simple_docs"
|
||||
title: "Simple Documentation"
|
||||
|
||||
!!site.navbar
|
||||
title: "Simple Docs"
|
||||
|
||||
!!site.page src: "docs:index"
|
||||
description: "Welcome page"
|
||||
slug: "/"
|
||||
|
||||
!!site.page src: "getting-started"
|
||||
description: "Getting started guide"
|
||||
|
||||
!!site.page src: "api"
|
||||
description: "API reference"
|
||||
```
|
||||
|
||||
### Pattern 2: Multi-Section Documentation
|
||||
|
||||
```heroscript
|
||||
!!site.config
|
||||
name: "multi_section_docs"
|
||||
title: "Complete Documentation"
|
||||
|
||||
!!site.page_category
|
||||
name: "introduction"
|
||||
label: "Introduction"
|
||||
|
||||
!!site.page src: "docs:welcome"
|
||||
description: "Welcome to our documentation"
|
||||
|
||||
!!site.page src: "overview"
|
||||
description: "Platform overview"
|
||||
|
||||
!!site.page_category
|
||||
name: "tutorials"
|
||||
label: "Tutorials"
|
||||
|
||||
!!site.page src: "tutorial_basics"
|
||||
description: "Basic tutorial"
|
||||
|
||||
!!site.page src: "tutorial_advanced"
|
||||
description: "Advanced tutorial"
|
||||
```
|
||||
|
||||
### Pattern 3: Complex Site with External Links
|
||||
|
||||
```heroscript
|
||||
!!site.config
|
||||
name: "complex_site"
|
||||
title: "Complex Documentation Site"
|
||||
url: "https://docs.example.com"
|
||||
|
||||
!!site.navbar
|
||||
title: "My Platform"
|
||||
logo_src: "img/logo.svg"
|
||||
|
||||
!!site.navbar_item
|
||||
label: "Docs"
|
||||
to: "docs/intro"
|
||||
position: "left"
|
||||
|
||||
!!site.navbar_item
|
||||
label: "API"
|
||||
to: "api"
|
||||
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: "docs/intro"
|
||||
|
||||
!!site.footer_item
|
||||
title: "Community"
|
||||
label: "Discord"
|
||||
href: "https://discord.gg/example"
|
||||
|
||||
!!site.page_category
|
||||
name: "getting_started"
|
||||
|
||||
!!site.page src: "docs:introduction"
|
||||
description: "Introduction to the platform"
|
||||
slug: "/"
|
||||
|
||||
!!site.page src: "installation"
|
||||
description: "Installation guide"
|
||||
```
|
||||
|
||||
## Error Prevention
|
||||
|
||||
### Common Mistakes to Avoid
|
||||
|
||||
1. **Missing Collection on First Page:**
|
||||
```heroscript
|
||||
# WRONG - no collection specified
|
||||
!!site.page src: "introduction"
|
||||
|
||||
# CORRECT
|
||||
!!site.page src: "docs:introduction"
|
||||
```
|
||||
|
||||
2. **Category Without Name:**
|
||||
```heroscript
|
||||
# WRONG - missing name
|
||||
!!site.page_category
|
||||
label: "Getting Started"
|
||||
|
||||
# CORRECT
|
||||
!!site.page_category
|
||||
name: "getting_started"
|
||||
label: "Getting Started"
|
||||
```
|
||||
|
||||
3. **Missing Description:**
|
||||
```heroscript
|
||||
# WRONG - no description
|
||||
!!site.page src: "docs:intro"
|
||||
|
||||
# CORRECT
|
||||
!!site.page src: "docs:intro"
|
||||
description: "Introduction to the platform"
|
||||
```
|
||||
|
||||
4. **Incorrect File Ordering:**
|
||||
```
|
||||
# WRONG - pages before config
|
||||
pages.heroscript
|
||||
config.heroscript
|
||||
|
||||
# CORRECT - config first
|
||||
0_config.heroscript
|
||||
1_pages.heroscript
|
||||
```
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
When generating HeroScript for the Site module, verify:
|
||||
|
||||
- [ ] `!!site.config` includes `name` parameter
|
||||
- [ ] All pages have `description` parameter
|
||||
- [ ] First page in each collection specifies `collection:page_name`
|
||||
- [ ] Categories are declared before their pages
|
||||
- [ ] Files use numeric prefixes for ordering
|
||||
- [ ] Navigation items have either `to` or `href`
|
||||
- [ ] Footer items are grouped by `title`
|
||||
- [ ] External URLs include protocol (https://)
|
||||
- [ ] Paths don't have trailing slashes unless intentional
|
||||
- [ ] Draft pages are marked with `draft: true`
|
||||
|
||||
## Integration with V Code
|
||||
|
||||
When working with the Site module in V code:
|
||||
|
||||
```v
|
||||
import incubaid.herolib.web.site
|
||||
import incubaid.herolib.core.playbook
|
||||
|
||||
// Process HeroScript files
|
||||
mut plbook := playbook.new(path: '/path/to/heroscripts')!
|
||||
site.play(mut plbook)!
|
||||
|
||||
// Access configured site
|
||||
mut mysite := site.get(name: 'my_site')!
|
||||
|
||||
// Iterate through pages
|
||||
for page in mysite.pages {
|
||||
println('Page: ${page.name} - ${page.description}')
|
||||
}
|
||||
|
||||
// Iterate through sections
|
||||
for section in mysite.sections {
|
||||
println('Section: ${section.label}')
|
||||
}
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
The Site module's HeroScript format provides a declarative way to configure websites with:
|
||||
- Clear separation of concerns (config, navigation, content)
|
||||
- Automatic ordering and organization
|
||||
- Collection and category persistence for reduced repetition
|
||||
- Flexible metadata and SEO configuration
|
||||
- Support for both internal and external content
|
||||
|
||||
Always follow the execution order rules, use numeric file prefixes, and provide complete metadata for best results.
|
||||
@@ -1,329 +1,324 @@
|
||||
# Site Module
|
||||
|
||||
This module has the structure of a website, which menus to use, which pages, etc.
|
||||
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.
|
||||
|
||||
example see https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/ebooks/tech
|
||||
## Purpose
|
||||
|
||||
## example how to get started
|
||||
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
|
||||
|
||||
```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 os
|
||||
import incubaid.herolib.develop.gittools
|
||||
import incubaid.herolib.web.site
|
||||
import incubaid.herolib.core.playcmds
|
||||
|
||||
url := "https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/ebooks/tech"
|
||||
|
||||
// Clone or use existing repository with HeroScript files
|
||||
mysitepath := gittools.path(
|
||||
// git_pull: true
|
||||
// git_reset: true
|
||||
git_url: url
|
||||
git_root: '/tmp/code'
|
||||
git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/ebooks/tech'
|
||||
git_pull: true
|
||||
)!
|
||||
|
||||
playcmds.run(heroscript_path:mysitepath.path)!
|
||||
// Process all HeroScript files in the path
|
||||
playcmds.run(heroscript_path: mysitepath.path)!
|
||||
|
||||
mut mysite:=site.get(name:"tfgrid_tech")!
|
||||
// Get the configured site
|
||||
mut mysite := site.get(name: 'tfgrid_tech')!
|
||||
println(mysite)
|
||||
|
||||
|
||||
```
|
||||
|
||||
## config heroscript
|
||||
## HeroScript Syntax
|
||||
|
||||
```yaml
|
||||
### Basic Configuration
|
||||
|
||||
```heroscript
|
||||
!!site.config
|
||||
name:"ThreeFold DePIN Tech"
|
||||
description:"ThreeFold is laying the foundation for a geo aware Web 4, the next generation of the Internet."
|
||||
tagline:"Geo Aware Internet Platform"
|
||||
favicon:"img/favicon.png"
|
||||
image:"img/tf_graph.png"
|
||||
copyright:"ThreeFold"
|
||||
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: "/"
|
||||
```
|
||||
|
||||
!!site.menu
|
||||
title:"ThreeFold DePIN Tech"
|
||||
logo_alt:"ThreeFold Logo"
|
||||
logo_src:"img/logo.svg"
|
||||
logo_src_dark:"img/new_logo_tft.png"
|
||||
### Navigation Menu
|
||||
|
||||
!!site.menu_item
|
||||
label:"ThreeFold.io"
|
||||
href:"https://threefold.io"
|
||||
position:"right"
|
||||
```heroscript
|
||||
!!site.navbar
|
||||
title: "My Site"
|
||||
logo_alt: "Site Logo"
|
||||
logo_src: "img/logo.svg"
|
||||
logo_src_dark: "img/logo-dark.svg"
|
||||
|
||||
!!site.menu_item
|
||||
label:"Mycelium Network"
|
||||
href:"https://mycelium.threefold.io/"
|
||||
position:"right"
|
||||
!!site.navbar_item
|
||||
label: "Documentation"
|
||||
to: "docs/intro"
|
||||
position: "left"
|
||||
|
||||
!!site.menu_item
|
||||
label:"AI Box"
|
||||
href:"https://aibox.threefold.io/"
|
||||
position:"right"
|
||||
!!site.navbar_item
|
||||
label: "GitHub"
|
||||
href: "https://github.com/myorg/myrepo"
|
||||
position: "right"
|
||||
```
|
||||
|
||||
### Footer Configuration
|
||||
|
||||
```heroscript
|
||||
!!site.footer
|
||||
style:"dark"
|
||||
style: "dark"
|
||||
|
||||
!!site.footer_item
|
||||
title:"Docs"
|
||||
label:"Introduction"
|
||||
href:"https://docs.threefold.io/docs/introduction"
|
||||
title: "Docs"
|
||||
label: "Introduction"
|
||||
to: "intro"
|
||||
|
||||
!!site.footer_item
|
||||
title:"Docs"
|
||||
label:"Litepaper"
|
||||
href:"https://docs.threefold.io/docs/litepaper/"
|
||||
title: "Docs"
|
||||
label: "Getting Started"
|
||||
href: "https://docs.example.com/getting-started"
|
||||
|
||||
!!site.footer_item
|
||||
title:"Features"
|
||||
label:"Become a Farmer"
|
||||
href:"https://docs.threefold.io/docs/category/become-a-farmer"
|
||||
|
||||
!!site.footer_item
|
||||
title:"Features"
|
||||
label:"Components"
|
||||
href:"https://docs.threefold.io/docs/category/components"
|
||||
|
||||
|
||||
!!site.footer_item
|
||||
title:"Web"
|
||||
label:"ThreeFold.io"
|
||||
href:"https://threefold.io"
|
||||
|
||||
!!site.footer_item
|
||||
title:"Web"
|
||||
label:"Dashboard"
|
||||
href:"https://dashboard.grid.tf"
|
||||
|
||||
!!site.collections
|
||||
url:"https://github.com/example/external-docs"
|
||||
replace:"PROJECT_NAME:My Project, VERSION:1.0.0"
|
||||
title: "Community"
|
||||
label: "Discord"
|
||||
href: "https://discord.gg/example"
|
||||
```
|
||||
|
||||
## site structure
|
||||
## Page Organization
|
||||
|
||||
```yaml
|
||||
!!site.page name:intro
|
||||
description:"ThreeFold is laying the foundation for a geo aware Web 4, the next generation of the Internet."
|
||||
### Example 1: Simple Pages Without Categories
|
||||
|
||||
#next is example where we use all properties, folder is where the page is located, prio is the order of the page, if not used the filled in from order in which we parse this config file
|
||||
!!site.page name:mycelium draft:true folder:"/specs/components" prio:4
|
||||
content:"the page content itself, only for small pages"
|
||||
title:"Mycelium as Title"
|
||||
description:"..."
|
||||
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.page name:fungistor folder:"/specs/components" prio:1
|
||||
src:"mycollection:mycelium.md"
|
||||
title:"fungistor as Title"
|
||||
description:"...."
|
||||
```heroscript
|
||||
!!site.page src: "tech:introduction"
|
||||
description: "Introduction to ThreeFold Technology"
|
||||
slug: "/"
|
||||
|
||||
!!site.page name:fungistor folder:"/specs/components" prio:1
|
||||
src:"mycollection:mycelium" //can be without .md
|
||||
title:"fungistor as Title"
|
||||
description:"..."
|
||||
!!site.page src: "vision"
|
||||
description: "Our Vision for the Future Internet"
|
||||
|
||||
!!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"
|
||||
```
|
||||
|
||||
## factory
|
||||
**Key Points:**
|
||||
- First page specifies collection as `tech:introduction` (collection:page_name format)
|
||||
- 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
|
||||
|
||||
Categories (sections) help organize pages into logical groups with their own navigation structure.
|
||||
|
||||
```heroscript
|
||||
!!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:**
|
||||
- `!!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
|
||||
name: "components"
|
||||
label: "System Components"
|
||||
position: 100
|
||||
|
||||
!!site.page src: "tech:mycelium"
|
||||
title: "Mycelium Network"
|
||||
description: "Peer-to-peer overlay network"
|
||||
slug: "mycelium-network"
|
||||
position: 1
|
||||
draft: false
|
||||
hide_title: false
|
||||
|
||||
!!site.page src: "fungistor"
|
||||
title: "Fungistor Storage"
|
||||
description: "Distributed storage system"
|
||||
position: 2
|
||||
```
|
||||
|
||||
**Available Page Parameters:**
|
||||
- `src`: Source reference as `collection:page_name` (required for first page in collection)
|
||||
- `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
|
||||
!!site.import
|
||||
url: "https://github.com/example/external-docs"
|
||||
dest: "external"
|
||||
replace: "PROJECT_NAME:My Project,VERSION:1.0.0"
|
||||
visible: true
|
||||
```
|
||||
|
||||
## Publish Destinations
|
||||
|
||||
```heroscript
|
||||
!!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
|
||||
|
||||
```v
|
||||
import incubaid.herolib.web.site
|
||||
mut mysite := site.new()!
|
||||
|
||||
// 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)
|
||||
```
|
||||
|
||||
## how to use with plbook
|
||||
### Using with PlayBook
|
||||
|
||||
```v
|
||||
import incubaid.herolib.core.playbook
|
||||
import incubaid.herolib.web.site
|
||||
// path string
|
||||
// text string
|
||||
// git_url string
|
||||
// git_pull bool
|
||||
// git_branch string
|
||||
// git_reset bool
|
||||
// session ?&base.Session is optional
|
||||
mut plbook := playbook.new( "....")!
|
||||
|
||||
// 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')!
|
||||
```
|
||||
|
||||
## example json
|
||||
## Data Structures
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "depin",
|
||||
"title": "Documentation Site",
|
||||
"description": "ThreeFold is laying the foundation for a geo aware Web 4, the next generation of the Internet.",
|
||||
"tagline": "Geo Aware Internet Platform",
|
||||
"favicon": "img/favicon.png",
|
||||
"image": "img/tf_graph.png",
|
||||
"copyright": "ThreeFold",
|
||||
"footer": {
|
||||
"style": "dark",
|
||||
"links": [
|
||||
{
|
||||
"title": "Docs",
|
||||
"items": [
|
||||
{
|
||||
"label": "Introduction",
|
||||
"to": "intro",
|
||||
"href": ""
|
||||
},
|
||||
{
|
||||
"label": "Litepaper",
|
||||
"to": "",
|
||||
"href": "https://docs.threefold.io/docs/litepaper/"
|
||||
},
|
||||
{
|
||||
"label": "Roadmap",
|
||||
"to": "",
|
||||
"href": "https://docs.threefold.io/docs/roadmap"
|
||||
},
|
||||
{
|
||||
"label": "Manual",
|
||||
"to": "",
|
||||
"href": "https://manual.grid.tf/"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Features",
|
||||
"items": [
|
||||
{
|
||||
"label": "Become a Farmer",
|
||||
"to": "",
|
||||
"href": "https://docs.threefold.io/docs/category/become-a-farmer"
|
||||
},
|
||||
{
|
||||
"label": "Components",
|
||||
"to": "",
|
||||
"href": "https://docs.threefold.io/docs/category/components"
|
||||
},
|
||||
{
|
||||
"label": "Technology",
|
||||
"to": "",
|
||||
"href": "https://threefold.info/tech/"
|
||||
},
|
||||
{
|
||||
"label": "Tokenomics",
|
||||
"to": "",
|
||||
"href": "https://docs.threefold.io/docs/tokens/tokenomics"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Web",
|
||||
"items": [
|
||||
{
|
||||
"label": "ThreeFold.io",
|
||||
"to": "",
|
||||
"href": "https://threefold.io"
|
||||
},
|
||||
{
|
||||
"label": "Dashboard",
|
||||
"to": "",
|
||||
"href": "https://dashboard.grid.tf"
|
||||
},
|
||||
{
|
||||
"label": "GitHub",
|
||||
"to": "",
|
||||
"href": "https://github.com/threefoldtech/home"
|
||||
},
|
||||
{
|
||||
"label": "Mycelium Network",
|
||||
"to": "",
|
||||
"href": "https://mycelium.threefold.io/"
|
||||
},
|
||||
{
|
||||
"label": "AI Box",
|
||||
"to": "",
|
||||
"href": "https://www2.aibox.threefold.io/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"menu": {
|
||||
"title": "ThreeFold DePIN Tech",
|
||||
"items": [
|
||||
{
|
||||
"href": "https://threefold.io",
|
||||
"to": "",
|
||||
"label": "ThreeFold.io",
|
||||
"position": "right"
|
||||
},
|
||||
{
|
||||
"href": "https://mycelium.threefold.io/",
|
||||
"to": "",
|
||||
"label": "Mycelium Network",
|
||||
"position": "right"
|
||||
},
|
||||
{
|
||||
"href": "https://aibox.threefold.io/",
|
||||
"to": "",
|
||||
"label": "AI Box",
|
||||
"position": "right"
|
||||
}
|
||||
]
|
||||
},
|
||||
"import_collections": [
|
||||
{
|
||||
"url": "https://github.com/example/external-docs",
|
||||
"path": "",
|
||||
"dest": "",
|
||||
"replace": {
|
||||
"PROJECT_NAME": "My Project",
|
||||
"VERSION": "1.0.0"
|
||||
},
|
||||
"visible": false
|
||||
}
|
||||
],
|
||||
"pages": [
|
||||
{
|
||||
"name": "intro",
|
||||
"content": "",
|
||||
"title": "",
|
||||
"description": "ThreeFold is laying the foundation for a geo aware Web 4, the next generation of the Internet.",
|
||||
"draft": false,
|
||||
"folder": "",
|
||||
"prio": 0,
|
||||
"src": ""
|
||||
},
|
||||
{
|
||||
"name": "mycelium",
|
||||
"content": "the page content itself, only for small pages",
|
||||
"title": "Mycelium as Title",
|
||||
"description": "...",
|
||||
"draft": true,
|
||||
"folder": "/specs/components",
|
||||
"prio": 4,
|
||||
"src": ""
|
||||
},
|
||||
{
|
||||
"name": "fungistor",
|
||||
"content": "",
|
||||
"title": "fungistor as Title",
|
||||
"description": "....",
|
||||
"draft": false,
|
||||
"folder": "/specs/components",
|
||||
"prio": 1,
|
||||
"src": "mycollection:mycelium.md"
|
||||
},
|
||||
{
|
||||
"name": "fungistor",
|
||||
"content": "",
|
||||
"title": "fungistor as Title",
|
||||
"description": "...",
|
||||
"draft": false,
|
||||
"folder": "/specs/components",
|
||||
"prio": 1,
|
||||
"src": "mycollection:mycelium"
|
||||
}
|
||||
]
|
||||
### Site
|
||||
|
||||
```v
|
||||
pub struct Site {
|
||||
pub mut:
|
||||
pages []Page
|
||||
sections []Section
|
||||
siteconfig SiteConfig
|
||||
}
|
||||
```
|
||||
|
||||
### Page
|
||||
|
||||
```v
|
||||
pub struct Page {
|
||||
pub mut:
|
||||
name string // Page identifier
|
||||
title string // Display title
|
||||
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
|
||||
pub struct Section {
|
||||
pub mut:
|
||||
name string // Internal identifier
|
||||
position int // Sort order
|
||||
path string // URL path
|
||||
label string // Display name
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **File Naming**: Use numeric prefixes (0_, 1_, 2_) to control execution order
|
||||
2. **Collection Reuse**: Specify collection once, then reuse for subsequent pages
|
||||
3. **Category Organization**: Group related pages under categories for better navigation
|
||||
4. **Title Extraction**: Let titles be extracted from markdown files when possible
|
||||
5. **Position Management**: Use automatic positioning unless you need specific ordering
|
||||
6. **Description**: Always provide descriptions for better SEO and navigation
|
||||
7. **Draft Status**: Use `draft: true` for work-in-progress pages
|
||||
|
||||
## Complete Example
|
||||
|
||||
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