This commit is contained in:
2025-12-02 05:41:57 +01:00
parent da2429104a
commit 4096b52244
2 changed files with 388 additions and 41 deletions

View File

@@ -29,18 +29,26 @@ pub fn (mut s Site) sidebar() SideBar {
mut uncategorized_pages := []Page{}
// Group pages by category
eprintln('DEBUG: Grouping ${s.pages.len} pages into categories')
for page in s.pages {
if page.category_id == 0 {
// Page at root level (no category)
uncategorized_pages << page
eprintln(' Page "${page.src}": UNCATEGORIZED')
} else {
// Page belongs to a category
if page.category_id !in category_pages {
category_pages[page.category_id] = []Page{}
}
category_pages[page.category_id] << page
if page.category_id < s.categories.len {
eprintln(' Page "${page.src}": category_id=${page.category_id} -> "${s.categories[page.category_id].path}"')
} else {
eprintln(' Page "${page.src}": category_id=${page.category_id} -> INVALID INDEX!')
}
}
}
eprintln('DEBUG: Grouped into ${category_pages.len} categories + ${uncategorized_pages.len} uncategorized')
// Sort pages within each category by their order in the pages array
for category_id in category_pages.keys() {
@@ -54,62 +62,111 @@ pub fn (mut s Site) sidebar() SideBar {
// Build nested category structure from path
// ============================================================
mut category_tree := map[string]&NavCat{}
mut parent_map := map[string]string{} // Map of path -> parent_path
// PASS 1: Create all category nodes (even empty intermediate ones)
// PASS 1: Create ALL category nodes first
// Collect all paths first, then sort by depth (shallow first)
mut all_paths := []string{}
for i, category in s.categories {
category_id := i + 1 // categories are 1-indexed
// Split path into parts (e.g., "Getting Started/Advanced/Deep" -> ["Getting Started", "Advanced", "Deep"])
path_parts := if category.path.contains('/') {
category.path.split('/')
} else {
[category.path]
}
// Create all nodes in the path hierarchy
mut current_path := ''
for part_idx, part in path_parts {
if current_path.len > 0 {
current_path += '/'
}
current_path += part
// Check if this node already exists
// Add this path if not already added
if current_path !in category_tree {
// Create new category node
mut new_cat := &NavCat{
label: part
collapsible: category.collapsible
collapsed: category.collapsed
items: []NavItem{}
}
category_tree[current_path] = new_cat
// If this is not the root of the path, add it to its parent
if part_idx > 0 {
parent_path := path_parts[0..part_idx].join('/')
if parent_path in category_tree {
mut parent_cat := category_tree[parent_path]
parent_cat.items << new_cat
}
}
all_paths << current_path
}
}
}
// PASS 2: Add pages to their designated categories
// Sort paths by depth (number of '/') so we create parents before children
all_paths.sort(a.count('/') < b.count('/'))
// Now create all nodes in order of depth
for path in all_paths {
if path !in category_tree {
path_parts := path.split('/')
part := path_parts[path_parts.len - 1]
// Find the category with this path to get collapsible/collapsed settings
mut collapsible := true
mut collapsed := false
for category in s.categories {
if category.path == path {
collapsible = category.collapsible
collapsed = category.collapsed
break
}
}
// Create new category node
mut new_cat := &NavCat{
label: part
collapsible: collapsible
collapsed: collapsed
items: []NavItem{}
}
category_tree[path] = new_cat
// Record parent for later linking
if path.contains('/') {
last_slash := path.last_index('/') or { 0 }
parent_path := path[0..last_slash]
parent_map[path] = parent_path
}
}
}
// PASS 2: Link all parent-child relationships
// Process these in order of depth to ensure parents are linked first
mut sorted_paths := parent_map.keys()
sorted_paths.sort(a.count('/') < b.count('/'))
for path in sorted_paths {
parent_path := parent_map[path]
if parent_path in category_tree && path in category_tree {
mut parent_cat := category_tree[parent_path]
child_cat := category_tree[path]
// Only add if not already added
mut already_added := false
for item in parent_cat.items {
if item is NavCat && item.label == child_cat.label {
already_added = true
break
}
}
if !already_added {
parent_cat.items << child_cat
}
}
}
// PASS 3: Add pages to their designated categories
eprintln('DEBUG PASS 3: Adding pages to categories')
for i, category in s.categories {
category_id := i + 1 // categories are 1-indexed
category_id := i // categories are 0-indexed in the page assignment
// Skip if no pages in this category
if category_id !in category_pages {
eprintln(' Category ${category_id} ("${category.path}"): no pages')
continue
}
// Build the full path for this category
full_path := category.path
eprintln(' Category ${category_id} ("${full_path}"): ${category_pages[category_id].len} pages')
// Add pages to this category
if full_path in category_tree {
mut leaf_cat := category_tree[full_path]
@@ -118,6 +175,8 @@ pub fn (mut s Site) sidebar() SideBar {
// Convert page src format "collection:name" to path "collection/name"
path := page.src.replace(':', '/')
eprintln(' Adding page: ${page.src} -> ${path}')
nav_doc := NavDoc{
path: path
label: if page.label.len > 0 { page.label } else { page.title }
@@ -125,13 +184,15 @@ pub fn (mut s Site) sidebar() SideBar {
leaf_cat.items << nav_doc
}
}
} else {
eprintln(' ERROR: Category path "${full_path}" not in category_tree!')
}
}
// ============================================================
// PASS 3: Add root-level categories to sidebar
// PASS 4: Add root-level categories to sidebar
// ============================================================
// Find all root-level categories (those without '/')
// Find all root-level categories (those without '/') and add them once
mut added_roots := map[string]bool{}
for i, category in s.categories {
@@ -149,7 +210,7 @@ pub fn (mut s Site) sidebar() SideBar {
}
// ============================================================
// PASS 4: Add uncategorized pages at root level
// PASS 5: Add uncategorized pages at root level
// ============================================================
for page in uncategorized_pages {
if !page.hide {
@@ -165,7 +226,7 @@ pub fn (mut s Site) sidebar() SideBar {
}
// ============================================================
// PASS 5: Add standalone links (if needed)
// PASS 6: Add standalone links (if needed)
// ============================================================
for link in s.links {
nav_link := NavLink{

View File

@@ -27,7 +27,8 @@ const test_heroscript_nav_depth = '
collapsible: true
collapsed: false
!!site.page src: "why:intro"
//COLLECTION WILL BE REPEATED, HAS NO INFLUENCE ON NAVIGATION LEVELS
!!site.page src: "mycollection:intro"
label: "Why Choose Us"
title: "Why Choose Us"
description: "Reasons to use this platform"
@@ -38,14 +39,14 @@ const test_heroscript_nav_depth = '
description: "Main benefits overview"
// ============================================================
// LEVEL 2: Two-level nested category
// LEVEL 1: Simple top-level category
// ============================================================
!!site.page_category
path: "Tutorials"
collapsible: true
collapsed: false
!!site.page src: "tutorials:getting_started"
!!site.page src: "getting_started"
label: "Getting Started"
title: "Getting Started"
description: "Basic tutorial to get started"
@@ -63,7 +64,7 @@ const test_heroscript_nav_depth = '
collapsible: true
collapsed: false
!!site.page src: "operations:emergency_restart"
!!site.page src: "emergency_restart"
label: "Emergency Restart"
title: "Emergency Restart"
description: "How to emergency restart the system"
@@ -79,14 +80,14 @@ const test_heroscript_nav_depth = '
description: "Handle incidents in real-time"
// ============================================================
// LEVEL 2.5: Two-level nested category (Tutorials > Operations)
// LEVEL 2: Two-level nested category (Tutorials > Operations)
// ============================================================
!!site.page_category
path: "Tutorials/Operations"
collapsible: true
collapsed: false
!!site.page src: "ops:daily_checks"
!!site.page src: "daily_checks"
label: "Daily Checks"
title: "Daily Checks"
description: "Daily maintenance checklist"
@@ -102,7 +103,7 @@ const test_heroscript_nav_depth = '
description: "Backup and restore procedures"
// ============================================================
// LEVEL 1.5: One-to-two level (Tutorials)
// LEVEL 1: One-to-two level (Tutorials)
// ============================================================
// Note: This creates a sibling at the Tutorials level (not nested deeper)
!!site.page src: "advanced_concepts"
@@ -123,7 +124,7 @@ const test_heroscript_nav_depth = '
collapsible: true
collapsed: false
!!site.page src: "faq:general"
!!site.page src: "general"
label: "General Questions"
title: "General Questions"
description: "Frequently asked questions"
@@ -144,14 +145,14 @@ const test_heroscript_nav_depth = '
description: "Support-related FAQ"
// ============================================================
// LEVEL 3+: Even deeper nesting for comprehensive testing
// LEVEL 4: Four-level nested category (Tutorials > Operations > Database > Optimization)
// ============================================================
!!site.page_category
path: "Tutorials/Operations/Database/Optimization"
collapsible: true
collapsed: false
!!site.page src: "database:query_optimization"
!!site.page src: "query_optimization"
label: "Query Optimization"
title: "Query Optimization"
description: "Optimize your database queries"
@@ -166,7 +167,7 @@ const test_heroscript_nav_depth = '
collapsible: true
collapsed: false
!!site.page src: "db:configuration"
!!site.page src: "configuration"
label: "Configuration"
title: "Database Configuration"
description: "Configure your database"
@@ -178,6 +179,289 @@ const test_heroscript_nav_depth = '
'
fn check(s2 Site) {
mut s := Site{
doctree_path: ''
config: SiteConfig{
name: 'nav_depth_test'
title: 'Navigation Depth Test Site'
description: 'Testing multi-level nested navigation'
tagline: 'Deep navigation structures'
favicon: 'img/favicon.png'
image: 'img/tf_graph.png'
copyright: '© 2025 Example Organization'
footer: Footer{
style: 'dark'
links: []
}
menu: Menu{
title: 'Nav Depth Test'
items: [
MenuItem{
href: ''
to: '/'
label: 'Home'
position: 'left'
},
]
logo_alt: ''
logo_src: ''
logo_src_dark: ''
}
url: ''
base_url: '/'
url_home: ''
meta_title: ''
meta_image: ''
}
pages: [
Page{
src: 'mycollection:intro'
label: 'Why Choose Us'
title: 'Why Choose Us'
description: 'Reasons to use this platform'
draft: false
hide_title: false
hide: false
category_id: 0
},
Page{
src: 'mycollection:benefits'
label: 'Key Benefits'
title: 'Key Benefits'
description: 'Main benefits overview'
draft: false
hide_title: false
hide: false
category_id: 0
},
Page{
src: 'mycollection:getting_started'
label: 'Getting Started'
title: 'Getting Started'
description: 'Basic tutorial to get started'
draft: false
hide_title: false
hide: false
category_id: 1
},
Page{
src: 'mycollection:first_steps'
label: 'First Steps'
title: 'First Steps'
description: 'Your first steps with the platform'
draft: false
hide_title: false
hide: false
category_id: 1
},
Page{
src: 'mycollection:emergency_restart'
label: 'Emergency Restart'
title: 'Emergency Restart'
description: 'How to emergency restart the system'
draft: false
hide_title: false
hide: false
category_id: 2
},
Page{
src: 'mycollection:critical_fixes'
label: 'Critical Fixes'
title: 'Critical Fixes'
description: 'Apply critical fixes immediately'
draft: false
hide_title: false
hide: false
category_id: 2
},
Page{
src: 'mycollection:incident_response'
label: 'Incident Response'
title: 'Incident Response'
description: 'Handle incidents in real-time'
draft: false
hide_title: false
hide: false
category_id: 2
},
Page{
src: 'mycollection:daily_checks'
label: 'Daily Checks'
title: 'Daily Checks'
description: 'Daily maintenance checklist'
draft: false
hide_title: false
hide: false
category_id: 3
},
Page{
src: 'mycollection:monitoring'
label: 'Monitoring'
title: 'Monitoring'
description: 'System monitoring procedures'
draft: false
hide_title: false
hide: false
category_id: 3
},
Page{
src: 'mycollection:backups'
label: 'Backups'
title: 'Backups'
description: 'Backup and restore procedures'
draft: false
hide_title: false
hide: false
category_id: 3
},
Page{
src: 'mycollection:advanced_concepts'
label: 'Advanced Concepts'
title: 'Advanced Concepts'
description: 'Deep dive into advanced concepts'
draft: false
hide_title: false
hide: false
category_id: 3
},
Page{
src: 'mycollection:troubleshooting'
label: 'Troubleshooting'
title: 'Troubleshooting'
description: 'Troubleshooting guide'
draft: false
hide_title: false
hide: false
category_id: 3
},
Page{
src: 'mycollection:general'
label: 'General Questions'
title: 'General Questions'
description: 'Frequently asked questions'
draft: false
hide_title: false
hide: false
category_id: 4
},
Page{
src: 'mycollection:pricing_questions'
label: 'Pricing'
title: 'Pricing Questions'
description: 'Questions about pricing'
draft: false
hide_title: false
hide: false
category_id: 4
},
Page{
src: 'mycollection:technical_faq'
label: 'Technical FAQ'
title: 'Technical FAQ'
description: 'Technical frequently asked questions'
draft: false
hide_title: false
hide: false
category_id: 4
},
Page{
src: 'mycollection:support_faq'
label: 'Support'
title: 'Support FAQ'
description: 'Support-related FAQ'
draft: false
hide_title: false
hide: false
category_id: 4
},
Page{
src: 'mycollection:query_optimization'
label: 'Query Optimization'
title: 'Query Optimization'
description: 'Optimize your database queries'
draft: false
hide_title: false
hide: false
category_id: 5
},
Page{
src: 'mycollection:indexing_strategy'
label: 'Indexing Strategy'
title: 'Indexing Strategy'
description: 'Effective indexing strategies'
draft: false
hide_title: false
hide: false
category_id: 5
},
Page{
src: 'mycollection:configuration'
label: 'Configuration'
title: 'Database Configuration'
description: 'Configure your database'
draft: false
hide_title: false
hide: false
category_id: 6
},
Page{
src: 'mycollection:replication'
label: 'Replication'
title: 'Database Replication'
description: 'Set up database replication'
draft: false
hide_title: false
hide: false
category_id: 6
},
]
links: []
categories: [
Category{
path: 'Why'
collapsible: true
collapsed: false
},
Category{
path: 'Tutorials'
collapsible: true
collapsed: false
},
Category{
path: 'Tutorials/Operations/Urgent'
collapsible: true
collapsed: false
},
Category{
path: 'Tutorials/Operations'
collapsible: true
collapsed: false
},
Category{
path: 'Why/FAQ'
collapsible: true
collapsed: false
},
Category{
path: 'Tutorials/Operations/Database/Optimization'
collapsible: true
collapsed: false
},
Category{
path: 'Tutorials/Operations/Database'
collapsible: true
collapsed: false
},
]
announcements: []
imports: []
build_dest: []
build_dest_dev: []
}
assert s == s2
}
pub fn test_navigation_depth() ! {
console.print_header('🧭 Navigation Depth Multi-Level Test')
console.lf()
@@ -200,6 +484,8 @@ pub fn test_navigation_depth() ! {
console.print_green(' Site retrieved')
console.lf()
check(nav_site)
// ========================================================
// TEST 1: Validate Categories Structure
// ========================================================