From 7c0322605499f71494fd9f5f8b347970a5f974fa Mon Sep 17 00:00:00 2001 From: despiegk Date: Fri, 28 Nov 2025 09:37:21 +0100 Subject: [PATCH] ... --- examples/web/site/USAGE.md | 201 ++++++++ examples/web/site/basic.heroscript | 53 +++ examples/web/site/multi_section.heroscript | 155 +++++++ examples/web/site/process_site.vsh | 116 +++++ lib/web/site/play_pages.v | 62 ++- lib/web/site/readme.md | 508 ++++++++++----------- 6 files changed, 835 insertions(+), 260 deletions(-) create mode 100644 examples/web/site/USAGE.md create mode 100644 examples/web/site/basic.heroscript create mode 100644 examples/web/site/multi_section.heroscript create mode 100644 examples/web/site/process_site.vsh diff --git a/examples/web/site/USAGE.md b/examples/web/site/USAGE.md new file mode 100644 index 00000000..21378db4 --- /dev/null +++ b/examples/web/site/USAGE.md @@ -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). \ No newline at end of file diff --git a/examples/web/site/basic.heroscript b/examples/web/site/basic.heroscript new file mode 100644 index 00000000..836e8eed --- /dev/null +++ b/examples/web/site/basic.heroscript @@ -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" diff --git a/examples/web/site/multi_section.heroscript b/examples/web/site/multi_section.heroscript new file mode 100644 index 00000000..7cdda621 --- /dev/null +++ b/examples/web/site/multi_section.heroscript @@ -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" diff --git a/examples/web/site/process_site.vsh b/examples/web/site/process_site.vsh new file mode 100644 index 00000000..f4d1c854 --- /dev/null +++ b/examples/web/site/process_site.vsh @@ -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()) diff --git a/lib/web/site/play_pages.v b/lib/web/site/play_pages.v index ca504e3e..c50b799c 100644 --- a/lib/web/site/play_pages.v +++ b/lib/web/site/play_pages.v @@ -34,10 +34,10 @@ fn play_pages(mut plbook PlayBook, mut website Site) ! { 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) - 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)! // Auto-increment position if using default @@ -46,14 +46,15 @@ fn play_pages(mut plbook PlayBook, mut website Site) ! { } // Create and store category info - categories[category_name] = CategoryInfo{ - name: category_name + categories[category_name_fixed] = CategoryInfo{ + name: category_name_fixed label: label position: position 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 continue } @@ -131,12 +132,63 @@ fn play_pages(mut plbook PlayBook, mut website Site) ! { mut cat_info := categories[category_current] cat_info.nav_items << nav_doc categories[category_current] = cat_info + console.print_debug('Added page "${page_id}" to category "${category_current}"') } } else { root_nav_items << nav_doc + console.print_debug('Added root page "${page_id}"') } action.done = true 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 +} diff --git a/lib/web/site/readme.md b/lib/web/site/readme.md index 4f055790..eda5ed03 100644 --- a/lib/web/site/readme.md +++ b/lib/web/site/readme.md @@ -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. -## 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 +### 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 #!/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.core.playcmds +import incubaid.herolib.ui.console -// 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 HeroScript file +mut plbook := playbook.new(path: './site_config.heroscript')! -// Process all HeroScript files in the path -playcmds.run(heroscript_path: mysitepath.path)! +// Execute site configuration +site.play(mut plbook)! -// Get the configured site -mut mysite := site.get(name: 'tfgrid_tech')! -println(mysite) +// Access the configured site +mut mysite := site.get(name: 'my_docs')! + +// 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 -### Basic Configuration +### 1. Site Configuration (Required) ```heroscript !!site.config @@ -51,20 +91,49 @@ println(mysite) copyright: "© 2024 My Organization" url: "https://docs.example.com" 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 !!site.navbar - title: "My Site" + title: "My Documentation" logo_alt: "Site Logo" logo_src: "img/logo.svg" logo_src_dark: "img/logo-dark.svg" !!site.navbar_item label: "Documentation" - to: "docs/intro" + to: "intro" + position: "left" + +!!site.navbar_item + label: "API Reference" + to: "docs/api" position: "left" !!site.navbar_item @@ -73,7 +142,13 @@ println(mysite) 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 !!site.footer @@ -87,311 +162,234 @@ println(mysite) !!site.footer_item title: "Docs" label: "Getting Started" - href: "https://docs.example.com/getting-started" + to: "getting-started" !!site.footer_item title: "Community" label: "Discord" href: "https://discord.gg/example" + +!!site.footer_item + title: "Legal" + label: "Privacy" + href: "https://example.com/privacy" ``` -## 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. +### 5. Announcement Bar (Optional) ```heroscript -!!site.page src: "mycelium_tech:introduction" - description: "Introduction to ThreeFold Technology" - slug: "/" - -!!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" +!!site.announcement + id: "new-release" + content: "🎉 Version 2.0 is now available!" + background_color: "#20232a" + text_color: "#fff" + is_closeable: true ``` -**Key Points:** +### 6. Pages and Categories -- 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) +#### Simple: Pages Without Categories -### 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 !!site.page_category - name: "first_principle_thinking" - label: "First Principle Thinking" + name: "basics" + label: "Getting Started" -!!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: "guides:introduction" + title: "Introduction" + description: "Learn the basics" -!!site.page src: "internet_risk" - description: "Internet risk, how to mitigate it, and why it is important" +!!site.page src: "installation" + title: "Installation" -!!site.page src: "onion_analogy" - description: "Compare onion with a computer, layers of abstraction" -``` +!!site.page src: "configuration" + 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 - name: "components" - label: "System Components" - position: 100 + name: "advanced" + label: "Advanced Topics" -!!site.page src: "mycelium_tech:mycelium" - title: "Mycelium Network" - description: "Peer-to-peer overlay network" - slug: "mycelium-network" - position: 1 - draft: false - hide_title: false +!!site.page src: "advanced:performance" + title: "Performance Tuning" -!!site.page src: "fungistor" - title: "Fungistor Storage" - description: "Distributed storage system" - position: 2 +!!site.page src: "scaling" + title: "Scaling Guide" ``` -**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) -- `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 +### 7. Content Imports ```heroscript !!site.import url: "https://github.com/example/external-docs" + path: "/local/path/to/repo" dest: "external" replace: "PROJECT_NAME:My Project,VERSION:1.0.0" visible: true ``` -## Publish Destinations +### 8. Publishing Destinations ```heroscript !!site.publish path: "/var/www/html/docs" - ssh_name: "production_server" + ssh_name: "production" !!site.publish_dev 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 - - 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 +### Pattern 1: Multi-Section Technical Documentation -### Error Handling - -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 +```heroscript !!site.config - name: "my_docs" - title: "My Documentation" + name: "tech_docs" + title: "Technical Documentation" -# 2. Set up navigation -!!site.navbar title: "MyDocs" +!!site.page_category + name: "getting_started" + label: "Getting Started" -# 3. Define pages with reusable collection -!!site.page_category name: "intro" +!!site.page src: "docs:intro" + title: "Introduction" -!!site.page src: "guides:introduction" - title: "Getting Started" - -!!site.page src: "setup" # Reuses "guides" collection +!!site.page src: "installation" title: "Installation" -!!site.page src: "tutorial" # Still uses "guides" - title: "Tutorial" +!!site.page_category + name: "concepts" + label: "Core Concepts" -# 4. Change collection when needed -!!site.page src: "api:reference" - title: "API Reference" +!!site.page src: "concepts:architecture" + title: "Architecture" -!!site.page src: "endpoints" # Now uses "api" collection - title: "Endpoints" +!!site.page src: "components" + 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 -import incubaid.herolib.web.site +!!site.page src: "articles:first_post" + title: "Welcome to Our Blog" -// Create a new site -mut mysite := site.new(name: 'my_docs')! +!!site.page src: "second_post" + title: "Understanding the Basics" -// 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) +!!site.page src: "third_post" + title: "Advanced Techniques" ``` -### Using with PlayBook +### Pattern 3: Project with External Imports -```v -import incubaid.herolib.core.playbook -import incubaid.herolib.web.site +```heroscript +!!site.config + name: "project_docs" + title: "Project Documentation" -// Create playbook from path -mut plbook := playbook.new(path: '/path/to/heroscripts')! +!!site.import + url: "https://github.com/org/shared-docs" + dest: "shared" + visible: true -// Process site configuration -site.play(mut plbook)! +!!site.page_category + name: "product" + label: "Product Guide" -// Access the configured site -mut mysite := site.get(name: 'my_site')! +!!site.page src: "docs:overview" + 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 -pub struct Site { -pub mut: - pages []Page - sections []Section - siteconfig SiteConfig -} +Organize HeroScript files with numeric prefixes to control execution order: + +``` +docs/ +├── 0_config.heroscript +│ └── !!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 -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 -} -``` +Files are processed in alphabetical order. Numeric prefixes ensure: +- Site config runs first +- Navigation menu configures before pages +- Pages build the final structure +- Publishing configured last -### Section +--- -```v -pub struct Section { -pub mut: - name string // Internal identifier - position int // Sort order - path string // URL path - label string // Display name -} -``` +## Processing Order -## Best Practices +The Site module processes HeroScript in this strict order: -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 +1. Site Configuration +2. Metadata Overrides +3. Imports +4. Navigation +5. Footer +6. Announcement +7. Publishing +8. Pages & Categories -## Complete Example - -See `examples/web/site/site_example.vsh` for a complete working example. - -For a real-world example, check: +Each stage depends on previous stages completing successfully.