diff --git a/lib/web/doctree/meta/factory.v b/lib/web/doctree/meta/factory.v index a5eb3f73..1a207517 100644 --- a/lib/web/doctree/meta/factory.v +++ b/lib/web/doctree/meta/factory.v @@ -22,8 +22,7 @@ pub fn new(args FactoryArgs) !&Site { } mut site := Site{ - nav: SideBar{} - siteconfig: SiteConfig{ + config: SiteConfig{ name: name } } @@ -45,6 +44,10 @@ pub fn exists(args FactoryArgs) bool { return name in sites_global } +pub fn reset() { + sites_global.clear() +} + pub fn default() !&Site { if sites_global.len == 0 { return new(name: 'default')! diff --git a/lib/web/doctree/meta/play.v b/lib/web/doctree/meta/play.v index 089ded68..c7633f90 100644 --- a/lib/web/doctree/meta/play.v +++ b/lib/web/doctree/meta/play.v @@ -23,7 +23,7 @@ pub fn play(mut plbook PlayBook) ! { name := p.get_default('name', 'default')! mut website := new(name: name)! - mut config := &website.siteconfig + mut config := &website.config // Load core configuration config.name = texttools.name_fix(name) @@ -60,7 +60,7 @@ pub fn play(mut plbook PlayBook) ! { // STEP 3: Configure content imports // ============================================================ console.print_item('Step 3: Configuring content imports') - play_imports(mut plbook, mut config)! + play_imports(mut plbook, mut website)! // ============================================================ // STEP 4: Configure navigation menu @@ -78,13 +78,13 @@ pub fn play(mut plbook PlayBook) ! { // STEP 6: Configure announcement bar (optional) // ============================================================ console.print_item('Step 6: Configuring announcement bar (if present)') - play_announcement(mut plbook, mut config)! + play_announcement(mut plbook, mut website)! // ============================================================ // STEP 7: Configure publish destinations // ============================================================ console.print_item('Step 7: Configuring publish destinations') - play_publishing(mut plbook, mut config)! + play_publishing(mut plbook, mut website)! // ============================================================ // STEP 8: Build pages and navigation structure diff --git a/lib/web/doctree/meta/play_publish.v b/lib/web/doctree/meta/play_publish.v index b07f25f0..8b4a5d5e 100644 --- a/lib/web/doctree/meta/play_publish.v +++ b/lib/web/doctree/meta/play_publish.v @@ -9,7 +9,7 @@ import incubaid.herolib.ui.console // ============================================================ // PUBLISHING: Configure build and publish destinations // ============================================================ -fn play_publishing(mut plbook PlayBook, mut config SiteConfig) ! { +fn play_publishing(mut plbook PlayBook, mut website Site) ! { // Production publish destinations mut build_dest_actions := plbook.find(filter: 'site.publish')! for mut action in build_dest_actions { @@ -23,7 +23,7 @@ fn play_publishing(mut plbook PlayBook, mut config SiteConfig) ! { path: path ssh_name: p.get_default('ssh_name', '')! } - config.build_dest << dest + website.build_dest << dest action.done = true } @@ -40,7 +40,7 @@ fn play_publishing(mut plbook PlayBook, mut config SiteConfig) ! { path: path ssh_name: p.get_default('ssh_name', '')! } - config.build_dest_dev << dest + website.build_dest_dev << dest action.done = true } } diff --git a/lib/web/doctree/meta/readme.md b/lib/web/doctree/meta/readme.md index b04c7e28..d4c8f6ba 100644 --- a/lib/web/doctree/meta/readme.md +++ b/lib/web/doctree/meta/readme.md @@ -2,7 +2,6 @@ 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. - ## Quick Start ### Minimal HeroScript Example @@ -13,33 +12,33 @@ The Site module provides a structured way to define website configurations, navi title: "My Documentation" !!site.page src: "docs:introduction" + label: "Getting Started" title: "Getting Started" !!site.page src: "setup" + label: "Installation" 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.core.playbook -import incubaid.herolib.web.site +import incubaid.herolib.web.doctree.meta as site_module import incubaid.herolib.ui.console // Process HeroScript file mut plbook := playbook.new(path: './site_config.heroscript')! // Execute site configuration -site.play(mut plbook)! +site_module.play(mut plbook)! // Access the configured site -mut mysite := site.get(name: 'my_docs')! +mut mysite := site_module.get(name: 'my_docs')! // Print available pages -for page_id, page in mysite.pages { - console.print_item('Page: ${page_id} - "${page.title}"') +for page in mysite.pages { + console.print_item('Page: "${page.src}" - "${page.title}"') } println('Site has ${mysite.pages.len} pages') @@ -55,31 +54,38 @@ Factory functions to create and retrieve site instances: ```v // Create a new site -mut mysite := site.new(name: 'my_docs')! +mut mysite := site_module.new(name: 'my_docs')! // Get existing site -mut mysite := site.get(name: 'my_docs')! +mut mysite := site_module.get(name: 'my_docs')! // Check if site exists -if site.exists(name: 'my_docs') { +if site_module.exists(name: 'my_docs') { println('Site exists') } // Get all site names -site_names := site.list() // Returns []string +site_names := site_module.list() // Returns []string // Get default site (creates if needed) -mut default := site.default()! +mut default := site_module.default()! ``` ### Site Object Structure ```v +@[heap] pub struct Site { pub mut: - pages map[string]Page // key: "collection:page_name" - nav NavConfig // Navigation sidebar - siteconfig SiteConfig // Full configuration + doctree_path string // path to the export of the doctree site + config SiteConfig // Full site configuration + pages []Page // Array of pages + links []Link // Array of links + categories []Category // Array of categories + announcements []Announcement // Array of announcements (can be multiple) + imports []ImportItem // Array of imports + build_dest []BuildDest // Production build destinations + build_dest_dev []BuildDest // Development build destinations } ``` @@ -87,44 +93,60 @@ pub mut: ```v // Access all pages -pages := mysite.pages // map[string]Page +pages := mysite.pages // []Page -// Get specific page -page := mysite.pages['docs:introduction'] +// Access specific page by index +page := mysite.pages[0] // Page structure pub struct Page { pub mut: - id string // "collection:page_name" - title string // Display title + src string // "collection:page_name" format (unique identifier) + label string // Display label in navigation + title string // Display title on page (extracted from markdown if empty) description string // SEO metadata - draft bool // Hidden if true - hide_title bool // Don't show title in rendering - src string // Source reference + draft bool // Hide from navigation if true + hide_title bool // Don't show title on page + hide bool // Hide page completely + category_id int // Optional category ID (0 = root level) } ``` -### Navigation Structure +### Categories and Navigation ```v -// Access sidebar navigation -sidebar := mysite.nav.my_sidebar // []NavItem +// Access all categories +categories := mysite.categories // []Category + +// Category structure +pub struct Category { +pub mut: + path string // e.g., "Getting Started" or "Operations/Daily" + collapsible bool = true + collapsed bool +} + +// Generate sidebar navigation +sidebar := mysite.sidebar() // Returns SideBar + +// Sidebar structure +pub struct SideBar { +pub mut: + my_sidebar []NavItem +} -// NavItem is a sum type (can be one of three types): pub type NavItem = NavDoc | NavCat | NavLink -// Navigation items: - pub struct NavDoc { pub: - id string // page id - label string // display name + path string // path is $collection/$name without .md + label string } pub struct NavCat { pub mut: label string - collapsible bool + collapsible bool = true collapsed bool items []NavItem // nested NavDoc/NavCat/NavLink } @@ -137,10 +159,11 @@ pub: } // Example: iterate navigation -for item in mysite.nav.my_sidebar { +sidebar := mysite.sidebar() +for item in sidebar.my_sidebar { match item { NavDoc { - println('Page: ${item.label} (${item.id})') + println('Page: ${item.label} (${item.path})') } NavCat { println('Category: ${item.label} (${item.items.len} items)') @@ -150,11 +173,15 @@ for item in mysite.nav.my_sidebar { } } } + +// Print formatted sidebar +println(mysite.sidebar_str()) ``` ### Site Configuration ```v +@[heap] pub struct SiteConfig { pub mut: // Core @@ -175,15 +202,14 @@ pub mut: meta_title string // SEO title override meta_image string // OG image override + // Navigation & Footer + footer Footer + menu Menu + // Publishing build_dest []BuildDest // Production destinations build_dest_dev []BuildDest // Development destinations - // Navigation & Footer - footer Footer - menu Menu - announcement AnnouncementBar - // Imports imports []ImportItem } @@ -193,6 +219,59 @@ pub mut: path string ssh_name string } + +pub struct Menu { +pub mut: + title string + items []MenuItem + logo_alt string + logo_src string + logo_src_dark string +} + +pub struct MenuItem { +pub mut: + href string + to string + label string + position string // "left" or "right" +} + +pub struct Footer { +pub mut: + style string // e.g., "dark" or "light" + links []FooterLink +} + +pub struct FooterLink { +pub mut: + title string + items []FooterItem +} + +pub struct FooterItem { +pub mut: + label string + to string + href string +} + +pub struct Announcement { +pub mut: + content string + background_color string + text_color string + is_closeable bool +} + +pub struct ImportItem { +pub mut: + url string // http or git url + path string + dest string // location in docs folder + replace map[string]string + visible bool = true +} ``` --- @@ -200,20 +279,32 @@ pub mut: ## Core Concepts ### Site -A website configuration that contains pages, navigation structure, and metadata. +A website configuration that contains pages, navigation structure, and metadata. Each site is registered globally and can be retrieved by name. ### 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 +A single documentation page with: +- **src**: `collection:page_name` format (unique identifier) +- **label**: Display name in sidebar +- **title**: Display name on page (extracted from markdown if empty) +- **description**: SEO metadata +- **draft**: Hidden from navigation if true +- **category_id**: Links page to a category (0 = root level) ### Category (Section) -Groups related pages together in the navigation sidebar. Automatically collapsed/expandable. +Groups related pages together in the navigation sidebar. Categories can be nested and are automatically collapsed/expandable. + +```heroscript +!!site.page_category + path: "Getting Started" + collapsible: true + collapsed: false + +!!site.page src: "tech:intro" + category_id: 1 // Links to the category above +``` ### Collection -A logical group of pages. Pages reuse the collection once specified. +A logical group of pages. Pages reuse the collection once specified: ```heroscript !!site.page src: "tech:intro" # Specifies collection "tech" @@ -326,6 +417,8 @@ Overrides specific metadata for SEO without changing core config. ### 5. Announcement Bar (Optional) +Multiple announcements are supported and stored in an array: + ```heroscript !!site.announcement content: "🎉 Version 2.0 is now available!" @@ -334,61 +427,71 @@ Overrides specific metadata for SEO without changing core config. is_closeable: true ``` +**Note:** Each `!!site.announcement` block adds to the `announcements[]` array. Only the first is typically displayed, but all are stored. + ### 6. Pages and Categories #### Simple: Pages Without Categories ```heroscript !!site.page src: "guides:introduction" + label: "Getting Started" title: "Getting Started" description: "Introduction to the platform" !!site.page src: "installation" + label: "Installation" title: "Installation" - -!!site.page src: "configuration" - title: "Configuration" ``` #### Advanced: Pages With Categories ```heroscript !!site.page_category - name: "basics" - label: "Getting Started" + path: "Getting Started" + collapsible: true + collapsed: false !!site.page src: "guides:introduction" + label: "Introduction" title: "Introduction" description: "Learn the basics" !!site.page src: "installation" + label: "Installation" title: "Installation" !!site.page src: "configuration" + label: "Configuration" title: "Configuration" !!site.page_category - name: "advanced" - label: "Advanced Topics" + path: "Advanced Topics" + collapsible: true + collapsed: false !!site.page src: "advanced:performance" + label: "Performance Tuning" title: "Performance Tuning" !!site.page src: "scaling" + label: "Scaling Guide" title: "Scaling Guide" ``` **Page Parameters:** -- `src` - Source as `collection:page` (first page) or just `page_name` (reuse collection) +- `src` - Source as `collection:page_name` (first page) or just `page_name` (reuse collection) +- `label` - Display label in sidebar (required) - `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) +- `hide` - Hide page completely (default: false) **Category Parameters:** -- `name` - Category identifier (required) -- `label` - Display label (auto-generated from name if omitted) -- `position` - Sort order (auto-incremented if omitted) +- `path` - Category path/label (required) +- `collapsible` - Allow collapsing (default: true) +- `collapsed` - Initially collapsed (default: false) ### 7. Content Imports @@ -424,33 +527,42 @@ Overrides specific metadata for SEO without changing core config. title: "Technical Documentation" !!site.page_category - name: "getting_started" - label: "Getting Started" + path: "Getting Started" + collapsible: true + collapsed: false !!site.page src: "docs:intro" + label: "Introduction" title: "Introduction" !!site.page src: "installation" + label: "Installation" title: "Installation" !!site.page_category - name: "concepts" - label: "Core Concepts" + path: "Core Concepts" + collapsible: true + collapsed: false !!site.page src: "concepts:architecture" + label: "Architecture" title: "Architecture" !!site.page src: "components" + label: "Components" title: "Components" !!site.page_category - name: "api" - label: "API Reference" + path: "API Reference" + collapsible: true + collapsed: false !!site.page src: "api:rest" + label: "REST API" title: "REST API" !!site.page src: "graphql" + label: "GraphQL" title: "GraphQL" ``` @@ -462,12 +574,15 @@ Overrides specific metadata for SEO without changing core config. title: "Knowledge Base" !!site.page src: "articles:first_post" + label: "Welcome to Our Blog" title: "Welcome to Our Blog" !!site.page src: "second_post" + label: "Understanding the Basics" title: "Understanding the Basics" !!site.page src: "third_post" + label: "Advanced Techniques" title: "Advanced Techniques" ``` @@ -484,20 +599,25 @@ Overrides specific metadata for SEO without changing core config. visible: true !!site.page_category - name: "product" - label: "Product Guide" + path: "Product Guide" + collapsible: true + collapsed: false !!site.page src: "docs:overview" + label: "Overview" title: "Overview" !!site.page src: "features" + label: "Features" title: "Features" !!site.page_category - name: "resources" - label: "Shared Resources" + path: "Shared Resources" + collapsible: true + collapsed: false !!site.page src: "shared:common" + label: "Common Patterns" title: "Common Patterns" ``` @@ -554,4 +674,3 @@ hero docs -d -p /path/to/my_ebook # Build for production hero docs -p /path/to/my_ebook ``` - diff --git a/lib/web/doctree/meta/siteplay_test.v b/lib/web/doctree/meta/siteplay_test.v index 70c904aa..1a2e8210 100644 --- a/lib/web/doctree/meta/siteplay_test.v +++ b/lib/web/doctree/meta/siteplay_test.v @@ -2,7 +2,6 @@ module meta import incubaid.herolib.core.playbook import incubaid.herolib.ui.console -import os // Big comprehensive HeroScript for testing const test_heroscript = ' @@ -94,74 +93,86 @@ const test_heroscript = ' is_closeable: true !!site.page_category - name: "getting_started" - label: "Getting Started" - position: 10 + path: "Getting Started" + collapsible: true + collapsed: false !!site.page src: "guides:introduction" + label: "Introduction to Test Docs" title: "Introduction to Test Docs" description: "Learn what this project is about" !!site.page src: "installation" + label: "Installation Guide" title: "Installation Guide" description: "How to install and setup" !!site.page src: "quick_start" + label: "Quick Start" title: "Quick Start" description: "5 minute quick start guide" !!site.page_category - name: "concepts" - label: "Core Concepts" - position: 20 + path: "Core Concepts" + collapsible: true + collapsed: false !!site.page src: "concepts:architecture" + label: "Architecture Overview" title: "Architecture Overview" description: "Understanding the system architecture" !!site.page src: "components" + label: "Key Components" title: "Key Components" description: "Learn about the main components" !!site.page src: "workflow" + label: "Typical Workflow" title: "Typical Workflow" description: "How to use the system" !!site.page_category - name: "api" - label: "API Reference" - position: 30 + path: "API Reference" + collapsible: true + collapsed: false !!site.page src: "api:rest" + label: "REST API" title: "REST API" description: "Complete REST API reference" !!site.page src: "graphql" + label: "GraphQL API" title: "GraphQL API" description: "GraphQL API documentation" !!site.page src: "webhooks" + label: "Webhooks" title: "Webhooks" description: "Webhook configuration and examples" !!site.page_category - name: "advanced" - label: "Advanced Topics" - position: 40 + path: "Advanced Topics" + collapsible: true + collapsed: false !!site.page src: "advanced:performance" + label: "Performance Optimization" title: "Performance Optimization" description: "Tips for optimal performance" !!site.page src: "scaling" + label: "Scaling Guide" title: "Scaling Guide" - description: "How to scale the system" !!site.page src: "security" + label: "Security Best Practices" title: "Security Best Practices" description: "Security considerations and best practices" !!site.page src: "troubleshooting" + label: "Troubleshooting" title: "Troubleshooting" description: "Common issues and solutions" draft: false @@ -174,10 +185,8 @@ const test_heroscript = ' path: "/tmp/docs-dev" ' - - fn test_site1() ! { - console.print_header('Site Module Comprehensive Test') + console.print_header('Site Module Comprehensive Test - Part 1') console.lf() // ======================================================== @@ -200,7 +209,7 @@ fn test_site1() ! { // TEST 3: Retrieve site and validate // ======================================================== console.print_item('TEST 3: Retrieving configured site') - mut test_site := site.get(name: 'test_docs')! + mut test_site := get(name: 'test_docs')! console.print_green('✓ Site retrieved successfully') console.lf() @@ -208,7 +217,7 @@ fn test_site1() ! { // TEST 4: Validate SiteConfig // ======================================================== console.print_header('Validating SiteConfig') - mut config := &test_site.siteconfig + mut config := &test_site.config help_test_string('Site Name', config.name, 'test_docs') help_test_string('Site Title', config.title, 'Test Documentation Site') @@ -221,15 +230,14 @@ fn test_site1() ! { help_test_string('Meta Title', config.meta_title, 'Test Docs - Advanced') help_test_string('Meta Image', config.meta_image, 'img/test-og-alternative.png') - assert config.build_dest.len == 1, 'Should have 1 production build destination' - console.print_green('✓ Production build dest: ${config.build_dest[0].path}') + assert test_site.build_dest.len == 1, 'Should have 1 production build destination' + console.print_green('✓ Production build dest: ${test_site.build_dest[0].path}') - assert config.build_dest_dev.len == 1, 'Should have 1 dev build destination' - console.print_green('✓ Dev build dest: ${config.build_dest_dev[0].path}') + assert test_site.build_dest_dev.len == 1, 'Should have 1 dev build destination' + console.print_green('✓ Dev build dest: ${test_site.build_dest_dev[0].path}') console.lf() - // ======================================================== // TEST 5: Validate Menu Configuration // ======================================================== @@ -253,7 +261,6 @@ fn test_site1() ! { console.lf() - // ======================================================== // TEST 6: Validate Footer Configuration // ======================================================== @@ -291,7 +298,10 @@ fn test_site1() ! { // TEST 7: Validate Announcement Bar // ======================================================== console.print_header('Validating Announcement Bar') - mut announcement := config.announcement + assert test_site.announcements.len == 1, 'Should have 1 announcement, got ${test_site.announcements.len}' + console.print_green('✓ Announcement bar present') + + mut announcement := test_site.announcements[0] help_test_string('Announcement Content', announcement.content, '🎉 Version 2.0 is now available! Check out the new features.') help_test_string('Announcement BG Color', announcement.background_color, '#1a472a') @@ -300,109 +310,150 @@ fn test_site1() ! { console.print_green('✓ Announcement bar configured correctly') console.lf() - - } - - fn test_site2() ! { - console.print_header('Site Module Comprehensive Test') + console.print_header('Site Module Comprehensive Test - Part 2') console.lf() + reset() + mut plbook := playbook.new(text: test_heroscript)! - mut test_site := site.get(name: 'test_docs')! + play(mut plbook)! + mut test_site := get(name: 'test_docs')! // ======================================================== // TEST 8: Validate Pages // ======================================================== console.print_header('Validating Pages') - mut pages := test_site.pages.clone() - assert pages.len == 13, 'Should have 13 pages, got ${pages.len}' - console.print_green('✓ Total pages: ${pages.len}') + println(test_site) + + assert test_site.pages.len == 13, 'Should have 13 pages, got ${test_site.pages.len}' + console.print_green('✓ Total pages: ${test_site.pages.len}') // List and validate pages - mut page_ids := pages.keys() - page_ids.sort() - - for page_id in page_ids { - mut page := pages[page_id] - console.print_debug(' Page: ${page_id} - "${page.title}"') + for i, page in test_site.pages { + console.print_debug(' Page ${i}: "${page.src}" - "${page.label}"') } - // Validate specific pages - assert 'guides:introduction' in pages, 'guides:introduction page not found' + // Validate specific pages exist by src + mut src_exists := false + for page in test_site.pages { + if page.src == 'guides:introduction' { + src_exists = true + break + } + } + assert src_exists, 'guides:introduction page not found' console.print_green('✓ Found guides:introduction') - assert 'concepts:architecture' in pages, 'concepts:architecture page not found' + src_exists = false + for page in test_site.pages { + if page.src == 'concepts:architecture' { + src_exists = true + break + } + } + assert src_exists, 'concepts:architecture page not found' console.print_green('✓ Found concepts:architecture') - assert 'api:rest' in pages, 'api:rest page not found' + src_exists = false + for page in test_site.pages { + if page.src == 'api:rest' { + src_exists = true + break + } + } + assert src_exists, 'api:rest page not found' console.print_green('✓ Found api:rest') console.lf() // ======================================================== - // TEST 9: Validate Navigation Structure + // TEST 9: Validate Categories // ======================================================== - console.print_header('Validating Navigation Structure') - mut sidebar := unsafe { test_site.nav.my_sidebar.clone() } + console.print_header('Validating Categories') - console.print_item('Navigation sidebar has ${sidebar.len} items') + assert test_site.categories.len == 4, 'Should have 4 categories, got ${test_site.categories.len}' + console.print_green('✓ Total categories: ${test_site.categories.len}') - // Count categories - mut category_count := 0 - mut doc_count := 0 + for i, category in test_site.categories { + console.print_debug(' Category ${i}: "${category.path}" (collapsible: ${category.collapsible}, collapsed: ${category.collapsed})') + } - for item in sidebar { + // Validate category paths + mut category_paths := test_site.categories.map(it.path) + assert category_paths.contains('Getting Started'), 'Missing "Getting Started" category' + console.print_green('✓ Found "Getting Started" category') + + assert category_paths.contains('Core Concepts'), 'Missing "Core Concepts" category' + console.print_green('✓ Found "Core Concepts" category') + + assert category_paths.contains('API Reference'), 'Missing "API Reference" category' + console.print_green('✓ Found "API Reference" category') + + assert category_paths.contains('Advanced Topics'), 'Missing "Advanced Topics" category' + console.print_green('✓ Found "Advanced Topics" category') + + console.lf() + + // ======================================================== + // TEST 10: Validate Navigation Structure (Sidebar) + // ======================================================== + console.print_header('Validating Navigation Structure (Sidebar)') + + mut sidebar := test_site.sidebar() + + console.print_item('Sidebar has ${sidebar.my_sidebar.len} root items') + assert sidebar.my_sidebar.len > 0, 'Sidebar should not be empty' + console.print_green('✓ Sidebar generated successfully') + + // Count categories in sidebar + mut sidebar_category_count := 0 + mut sidebar_doc_count := 0 + + for item in sidebar.my_sidebar { match item { NavCat { - category_count++ - console.print_debug(' Category: "${item.label}" with ${item.items.len} sub-items') + sidebar_category_count++ } NavDoc { - doc_count++ - console.print_debug(' Doc: "${item.label}" (${item.id})') + sidebar_doc_count++ } - NavLink { - console.print_debug(' Link: "${item.label}" -> ${item.href}') + else { + // Other types } } } - assert category_count == 4, 'Should have 4 categories, got ${category_count}' - console.print_green('✓ Navigation has 4 categories') + console.print_item('Sidebar contains: ${sidebar_category_count} categories, ${sidebar_doc_count} docs') - // Validate category structure - for item in sidebar { + // Detailed sidebar validation + for i, item in sidebar.my_sidebar { match item { NavCat { - console.print_item('Category: "${item.label}"') - println(' Collapsible: ${item.collapsible}, Collapsed: ${item.collapsed}') - println(' Items: ${item.items.len}') - - // Validate sub-items + console.print_debug(' Category ${i}: "${item.label}" (${item.items.len} items)') for sub_item in item.items { match sub_item { NavDoc { - println(' - ${sub_item.label} (${sub_item.id})') - } - else { - println(' - Unexpected item type') + console.print_debug(' └─ Doc: "${sub_item.label}" (${sub_item.path})') } + else {} } } } + NavDoc { + console.print_debug(' Doc ${i}: "${item.label}" (${item.path})') + } else {} } } console.lf() - // ======================================================== - // TEST 10: Validate Site Factory + // TEST 11: Validate Site Factory // ======================================================== console.print_header('Validating Site Factory') @@ -420,11 +471,16 @@ fn test_site2() ! { console.lf() - // println(test_site) - // if true{panic("ss33")} + // ======================================================== + // TEST 12: Validate Print Output + // ======================================================== + console.print_header('Site Sidebar String Output') + println(test_site.sidebar_str()) + if true { + panic('End of tests reached - panic to stop further execution') + } } - // ============================================================ // Helper Functions for Testing // ============================================================