diff --git a/examples/web/doctree/doctree_meta.vsh b/examples/web/doctree/doctree_meta.vsh new file mode 100755 index 00000000..7af5ab1a --- /dev/null +++ b/examples/web/doctree/doctree_meta.vsh @@ -0,0 +1,208 @@ +#!/usr/bin/env -S v -n -w -cg -gc none -cc tcc -d use_openssl -enable-globals run + +import incubaid.herolib.web.doctree.meta + +import incubaid.herolib.core.playbook +import incubaid.herolib.ui.console + +// Comprehensive HeroScript for testing multi-level navigation depths +const test_heroscript_nav_depth = ' +!!site.config + name: "nav_depth_test" + title: "Navigation Depth Test Site" + description: "Testing multi-level nested navigation" + tagline: "Deep navigation structures" + +!!site.navbar + title: "Nav Depth Test" + +!!site.navbar_item + label: "Home" + to: "/" + position: "left" + +// ============================================================ +// LEVEL 1: Simple top-level category +// ============================================================ +!!site.page_category + path: "Why" + collapsible: true + collapsed: false + +//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" + +!!site.page src: "benefits" + label: "Key Benefits" + title: "Key Benefits" + description: "Main benefits overview" + +// ============================================================ +// LEVEL 1: Simple top-level category +// ============================================================ +!!site.page_category + path: "Tutorials" + collapsible: true + collapsed: false + +!!site.page src: "getting_started" + label: "Getting Started" + title: "Getting Started" + description: "Basic tutorial to get started" + +!!site.page src: "first_steps" + label: "First Steps" + title: "First Steps" + description: "Your first steps with the platform" + +// ============================================================ +// LEVEL 3: Three-level nested category (Tutorials > Operations > Urgent) +// ============================================================ +!!site.page_category + path: "Tutorials/Operations/Urgent" + collapsible: true + collapsed: false + +!!site.page src: "emergency_restart" + label: "Emergency Restart" + title: "Emergency Restart" + description: "How to emergency restart the system" + +!!site.page src: "critical_fixes" + label: "Critical Fixes" + title: "Critical Fixes" + description: "Apply critical fixes immediately" + +!!site.page src: "incident_response" + label: "Incident Response" + title: "Incident Response" + description: "Handle incidents in real-time" + +// ============================================================ +// LEVEL 2: Two-level nested category (Tutorials > Operations) +// ============================================================ +!!site.page_category + path: "Tutorials/Operations" + collapsible: true + collapsed: false + +!!site.page src: "daily_checks" + label: "Daily Checks" + title: "Daily Checks" + description: "Daily maintenance checklist" + +!!site.page src: "monitoring" + label: "Monitoring" + title: "Monitoring" + description: "System monitoring procedures" + +!!site.page src: "backups" + label: "Backups" + title: "Backups" + description: "Backup and restore procedures" + +// ============================================================ +// LEVEL 1: One-to-two level (Tutorials) +// ============================================================ +// Note: This creates a sibling at the Tutorials level (not nested deeper) +!!site.page src: "advanced_concepts" + label: "Advanced Concepts" + title: "Advanced Concepts" + description: "Deep dive into advanced concepts" + +!!site.page src: "troubleshooting" + label: "Troubleshooting" + title: "Troubleshooting" + description: "Troubleshooting guide" + +// ============================================================ +// LEVEL 2: Two-level nested category (Why > FAQ) +// ============================================================ +!!site.page_category + path: "Why/FAQ" + collapsible: true + collapsed: false + +!!site.page src: "general" + label: "General Questions" + title: "General Questions" + description: "Frequently asked questions" + +!!site.page src: "pricing_questions" + label: "Pricing" + title: "Pricing Questions" + description: "Questions about pricing" + +!!site.page src: "technical_faq" + label: "Technical FAQ" + title: "Technical FAQ" + description: "Technical frequently asked questions" + +!!site.page src: "support_faq" + label: "Support" + title: "Support FAQ" + description: "Support-related FAQ" + +// ============================================================ +// 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: "query_optimization" + label: "Query Optimization" + title: "Query Optimization" + description: "Optimize your database queries" + +!!site.page src: "indexing_strategy" + label: "Indexing Strategy" + title: "Indexing Strategy" + description: "Effective indexing strategies" + +!!site.page_category + path: "Tutorials/Operations/Database" + collapsible: true + collapsed: false + +!!site.page src: "configuration" + label: "Configuration" + title: "Database Configuration" + description: "Configure your database" + +!!site.page src: "replication" + label: "Replication" + title: "Database Replication" + description: "Set up database replication" + +' + +fn check(s2 meta.Site) { + + // assert s == s2 +} + + +// ======================================================== +// SETUP: Create and process playbook +// ======================================================== +console.print_item('Creating playbook from HeroScript') +mut plbook := playbook.new(text: test_heroscript_nav_depth)! +console.print_green('✓ Playbook created') +console.lf() + +console.print_item('Processing site configuration') +meta.play(mut plbook)! +console.print_green('✓ Site processed') +console.lf() + +console.print_item('Retrieving configured site') +mut nav_site := meta.get(name: 'nav_depth_test')! +console.print_green('✓ Site retrieved') +console.lf() + +// check(nav_site) diff --git a/lib/web/doctree/meta/factory.v b/lib/web/doctree/meta/factory.v index 1a207517..93ff0684 100644 --- a/lib/web/doctree/meta/factory.v +++ b/lib/web/doctree/meta/factory.v @@ -25,6 +25,7 @@ pub fn new(args FactoryArgs) !&Site { config: SiteConfig{ name: name } + root_category: Category{} } sites_global[name] = &site return get(name: name)! diff --git a/lib/web/doctree/meta/model_category.v b/lib/web/doctree/meta/model_category.v index 4b7ed2b2..d1254bc1 100644 --- a/lib/web/doctree/meta/model_category.v +++ b/lib/web/doctree/meta/model_category.v @@ -1,8 +1,111 @@ module meta +@[heap] struct Category { pub mut: path string // e.g. Operations/Daily (means 2 levels deep, first level is Operations) collapsible bool = true collapsed bool + items []CategoryItem } + +//return the label of the category (last part of the path) +pub fn (mut c Category) label() !string { + if c.path.count('/') == 0 { + return c.path + } + return c.path.all_after_last('/') +} + +type CategoryItem = Page | Link | Category + + + +pub fn (mut self Category) up(path string) !&Category { + // Split the requested path into parts + path_parts := path.split('/') + + // Start at current category + mut current := &self + + // Navigate through each part of the path + for part in path_parts { + // Skip empty parts (from leading/trailing slashes) + if part.len == 0 { + continue + } + + // Check if this part already exists in current category's items + mut found := false + for item in current.items { + match item { + &Category { + item_label := item.label()! + if item_label == part { + current = item + found = true + break + } + } + else {} + } + } + + // If not found, create a new category and add it + if !found { + mut new_category := Category{ + path: part + collapsible: true + collapsed: true + items: []CategoryItem{} + } + current.items << new_category + current = &new_category + } + } + + return current +} + + +fn (mut self Category) page_get(src string)! &Page { + for item in self.items { + match item { + Page { + if item.src == src { + return it + } + } + else {} + } + } + return error('Page with src="${src}" not found in site.') +} + +fn (mut self Category) link_get(href string)! &Link { + for item in self.items { + match item { + Link { + if item.href == href { + return it + } + } + else {} + } + } + return error('Link with href="${href}" not found in site.') +} + +fn (mut self Category) category_get(path string)! &Category { + for item in self.items { + match item { + Category { + if item.path == path { + return it + } + } + else {} + } + } + return error('Category with path="${path}" not found in site.') +} \ No newline at end of file diff --git a/lib/web/doctree/meta/model_category_str.v b/lib/web/doctree/meta/model_category_str.v new file mode 100644 index 00000000..123165de --- /dev/null +++ b/lib/web/doctree/meta/model_category_str.v @@ -0,0 +1,76 @@ +module meta + +pub fn (mut self Category) str() string { + mut result := []string{} + + if self.items.len == 0 { + return 'Sidebar is empty\n' + } + + result << '📑 SIDEBAR STRUCTURE' + result << '━'.repeat(60) + + for i, item in self.items { + is_last := i == self.items.len - 1 + prefix := if is_last { '└── ' } else { '├── ' } + + match item { + NavDoc { + result << '${prefix}📄 ${item.label}' + result << ' └─ path: ${item.path}' + } + NavCat { + // Category header + collapse_icon := if item.collapsed { '▶ ' } else { '▼ ' } + result << '${prefix}${collapse_icon}📁 ${item.label}' + + // Category metadata + if !item.collapsed { + result << ' ├─ collapsible: ${item.collapsible}' + result << ' └─ items: ${item.items.len}' + + // Sub-items + for j, sub_item in item.items { + is_last_sub := j == item.items.len - 1 + sub_prefix := if is_last_sub { ' └── ' } else { ' ├── ' } + + match sub_item { + NavDoc { + result << '${sub_prefix}📄 ${sub_item.label} [${sub_item.src_path}]' + } + NavCat { + // Nested categories + sub_collapse_icon := if sub_item.collapsed { '▶ ' } else { '▼ ' } + result << '${sub_prefix}${sub_collapse_icon}📁 ${sub_item.label}' + } + NavLink { + result << '${sub_prefix}🔗 ${sub_item.label}' + if sub_item.description.len > 0 { + result << ' └─ ${sub_item.description}' + } + } + } + } + } + } + NavLink { + result << '${prefix}🔗 ${item.label}' + result << ' └─ href: ${item.href}' + if item.description.len > 0 { + result << ' └─ desc: ${item.description}' + } + } + } + + // Add spacing between root items + if i < self.items.len - 1 { + result << '' + } + } + + result << '━'.repeat(60) + result << '📊 SUMMARY' + result << ' Total items: ${self.items.len}' + + return result.join('\n') + '\n' +} diff --git a/lib/web/doctree/meta/model_page.v b/lib/web/doctree/meta/model_page.v index 3fff9249..8569e786 100644 --- a/lib/web/doctree/meta/model_page.v +++ b/lib/web/doctree/meta/model_page.v @@ -11,4 +11,5 @@ pub mut: hide_title bool // Should the title be hidden on the page? hide bool // Should the page be hidden from navigation? category_id int // Optional category ID this page belongs to, if 0 it means its at root level + nav_path string // navigation path e.g. "Operations/Daily" } diff --git a/lib/web/doctree/meta/model_sidebar.v b/lib/web/doctree/meta/model_sidebar.v deleted file mode 100644 index ee67ba0d..00000000 --- a/lib/web/doctree/meta/model_sidebar.v +++ /dev/null @@ -1,34 +0,0 @@ -module meta - -// ============================================================================ -// Sidebar Navigation Models (Domain Types) -// is the result of walking through the pages, links and categories to build the sidebar structure -// ============================================================================ - -pub struct SideBar { -pub mut: - my_sidebar []NavItem -} - -pub type NavItem = NavDoc | NavCat | NavLink - -pub struct NavDoc { -pub: - path string // path is $collection/$name without .md, this is a subdir of the doctree export dir - label string -} - -pub struct NavCat { -pub mut: - label string - collapsible bool = true - collapsed bool - items []NavItem -} - -pub struct NavLink { -pub: - label string - href string - description string -} diff --git a/lib/web/doctree/meta/model_site.v b/lib/web/doctree/meta/model_site.v index 590c1125..45055d60 100644 --- a/lib/web/doctree/meta/model_site.v +++ b/lib/web/doctree/meta/model_site.v @@ -5,316 +5,28 @@ pub struct Site { pub mut: doctree_path string // path to the export of the doctree site config SiteConfig // Full site configuration - pages []Page - links []Link - categories []Category + root // The root category containing all top-level items announcements []Announcement // there can be more than 1 announcement imports []ImportItem build_dest []BuildDest // Production build destinations (from !!site.build_dest) build_dest_dev []BuildDest // Development build destinations (from !!site.build_dest_dev) } -pub fn (mut s Site) sidebar() SideBar { - mut result := SideBar{ - my_sidebar: []NavItem{} - } - // If no pages, return empty sidebar - if s.pages.len == 0 { - return result - } - - // Build a map of category_id -> pages for efficient lookup - mut category_pages := map[int][]Page{} - 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() { - category_pages[category_id].sort(a.src < b.src) - } - - // Sort uncategorized pages - uncategorized_pages.sort(a.src < b.src) - - // ============================================================ - // 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 first - // Collect all paths first, then sort by depth (shallow first) - mut all_paths := []string{} - for i, category in s.categories { - path_parts := if category.path.contains('/') { - category.path.split('/') - } else { - [category.path] - } - - mut current_path := '' - for part_idx, part in path_parts { - if current_path.len > 0 { - current_path += '/' - } - current_path += part - - // Add this path if not already added - if current_path !in category_tree { - all_paths << current_path - } - } - } - - // 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 // 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] - for page in category_pages[category_id] { - if !page.hide { - // 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 } - } - leaf_cat.items << nav_doc - } - } - } else { - eprintln(' ERROR: Category path "${full_path}" not in category_tree!') - } - } - - // ============================================================ - // PASS 4: Add root-level categories to sidebar - // ============================================================ - // Find all root-level categories (those without '/') and add them once - mut added_roots := map[string]bool{} - - for i, category in s.categories { - // Only process top-level categories - if !category.path.contains('/') && category.path.len > 0 { - root_path := category.path - // Only add each root once - if root_path !in added_roots { - if root_path in category_tree { - result.my_sidebar << category_tree[root_path] - added_roots[root_path] = true - } - } - } - } - - // ============================================================ - // PASS 5: Add uncategorized pages at root level - // ============================================================ - for page in uncategorized_pages { - if !page.hide { - // Convert page src format "collection:name" to path "collection/name" - path := page.src.replace(':', '/') - - nav_doc := NavDoc{ - path: path - label: if page.label.len > 0 { page.label } else { page.title } - } - result.my_sidebar << nav_doc - } - } - - // ============================================================ - // PASS 6: Add standalone links (if needed) - // ============================================================ - for link in s.links { - nav_link := NavLink{ - label: link.label - href: link.href - description: link.description - } - result.my_sidebar << nav_link - } - - return result +pub fn (mut self Site) page_get(src string)! &Page { + return self.root.page_get(src)! +} + +pub fn (mut self Site) link_get(href string)! &Link { + return self.root.link_get(href)! } -pub fn (mut s Site) sidebar_str() string { - mut result := []string{} - mut sidebar := s.sidebar() - - if sidebar.my_sidebar.len == 0 { - return 'Sidebar is empty\n' - } - - result << '📑 SIDEBAR STRUCTURE' - result << '━'.repeat(60) - - for i, item in sidebar.my_sidebar { - is_last := i == sidebar.my_sidebar.len - 1 - prefix := if is_last { '└── ' } else { '├── ' } - - match item { - NavDoc { - result << '${prefix}📄 ${item.label}' - result << ' └─ path: ${item.path}' - } - NavCat { - // Category header - collapse_icon := if item.collapsed { '▶ ' } else { '▼ ' } - result << '${prefix}${collapse_icon}📁 ${item.label}' - - // Category metadata - if !item.collapsed { - result << ' ├─ collapsible: ${item.collapsible}' - result << ' └─ items: ${item.items.len}' - - // Sub-items - for j, sub_item in item.items { - is_last_sub := j == item.items.len - 1 - sub_prefix := if is_last_sub { ' └── ' } else { ' ├── ' } - - match sub_item { - NavDoc { - result << '${sub_prefix}📄 ${sub_item.label} [${sub_item.path}]' - } - NavCat { - // Nested categories - sub_collapse_icon := if sub_item.collapsed { '▶ ' } else { '▼ ' } - result << '${sub_prefix}${sub_collapse_icon}📁 ${sub_item.label}' - } - NavLink { - result << '${sub_prefix}🔗 ${sub_item.label}' - if sub_item.description.len > 0 { - result << ' └─ ${sub_item.description}' - } - } - } - } - } - } - NavLink { - result << '${prefix}🔗 ${item.label}' - result << ' └─ href: ${item.href}' - if item.description.len > 0 { - result << ' └─ desc: ${item.description}' - } - } - } - - // Add spacing between root items - if i < sidebar.my_sidebar.len - 1 { - result << '' - } - } - - result << '━'.repeat(60) - result << '📊 SUMMARY' - result << ' Total items: ${sidebar.my_sidebar.len}' - result << ' Pages: ${s.pages.len}' - result << ' Categories: ${s.categories.len}' - result << ' Links: ${s.links.len}' - - return result.join('\n') + '\n' +pub fn (mut self Site) category_get(path string)! &Category { + return self.root.category_get(path)! } + +//sidebar returns the root category for building the sidebar navigation +pub fn (mut self Site) sidebar()! &Category { + return self.root +} + diff --git a/lib/web/doctree/meta/play_pages_categories.v b/lib/web/doctree/meta/play_pages_categories.v index 14dfde51..fab0737d 100644 --- a/lib/web/doctree/meta/play_pages_categories.v +++ b/lib/web/doctree/meta/play_pages_categories.v @@ -9,7 +9,8 @@ import incubaid.herolib.ui.console // ============================================================ fn play_pages(mut plbook PlayBook, mut website Site) ! { mut collection_current := '' - mut category_current := 0 + + mut category_current := &website.root_category // start at root category, this is basically the navigation tree root // ============================================================ // PASS 1: Process all page and category actions @@ -26,16 +27,18 @@ fn play_pages(mut plbook PlayBook, mut website Site) ! { mut p := action.params // label is empty when not specified (we support label & path for flexibility) + mut category_path := p.get_default('path', '')! + category_current = category_current.up(category_path)! + category_current.collapsible = p.get_default_true('collapsible') + category_current.collapsed = p.get_default_true('collapsed') - mut category := Category{ - path: p.get_default('path', p.get_default('label', '')!)! - collapsible: p.get_default_true('collapsible') - collapsed: p.get_default_true('collapsed') - } - website.categories << category - category_current = website.categories.len - 1 - console.print_item('Created page category: "${category.path}" ') + console.print_item('Created page category: "${category_current.path}" ') action.done = true + println(category_current) + + website.categories << category_current + + $dbg(); continue } @@ -76,6 +79,8 @@ fn play_pages(mut plbook PlayBook, mut website Site) ! { page_title := p.get_default('title', '')! // is title shown on the page, if not from the page content, if empty then will be brought in from the content page_description := p.get_default('description', '')! + + // Create page mut page := Page{ src: '${page_collection}:${page_name}' diff --git a/lib/web/doctree/meta/readme.md b/lib/web/doctree/meta/readme.md index 37deca73..9818228d 100644 --- a/lib/web/doctree/meta/readme.md +++ b/lib/web/doctree/meta/readme.md @@ -127,7 +127,7 @@ pub mut: } // Generate sidebar navigation -sidebar := mysite.sidebar() // Returns SideBar +sidebar := mysite.sidebar()! // Returns SideBar // Sidebar structure pub struct SideBar { @@ -159,7 +159,7 @@ pub: } // Example: iterate navigation -sidebar := mysite.sidebar() +sidebar := mysite.sidebar()! for item in sidebar.my_sidebar { match item { NavDoc { diff --git a/lib/web/doctree/meta/site_nav_test.v b/lib/web/doctree/meta2/site_nav_test.v similarity index 99% rename from lib/web/doctree/meta/site_nav_test.v rename to lib/web/doctree/meta2/site_nav_test.v index 26ec4c4b..c087e8a0 100644 --- a/lib/web/doctree/meta/site_nav_test.v +++ b/lib/web/doctree/meta2/site_nav_test.v @@ -560,7 +560,7 @@ pub fn test_navigation_depth() ! { // ======================================================== console.print_header('TEST 3: Navigation Structure Analysis') - mut sidebar := nav_site.sidebar() + mut sidebar := nav_site.sidebar()! console.print_item('Sidebar root items: ${sidebar.my_sidebar.len}') console.lf() diff --git a/lib/web/doctree/meta/siteplay_test.v b/lib/web/doctree/meta2/siteplay_test.v similarity index 99% rename from lib/web/doctree/meta/siteplay_test.v rename to lib/web/doctree/meta2/siteplay_test.v index 3d173816..ad076a83 100644 --- a/lib/web/doctree/meta/siteplay_test.v +++ b/lib/web/doctree/meta2/siteplay_test.v @@ -403,7 +403,7 @@ fn test_site2() ! { // ======================================================== console.print_header('Validating Navigation Structure (Sidebar)') - mut sidebar := test_site.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' diff --git a/lib/web/docusaurus/dsite.v b/lib/web/docusaurus/dsite.v index deda3043..1d061847 100644 --- a/lib/web/docusaurus/dsite.v +++ b/lib/web/docusaurus/dsite.v @@ -1,7 +1,7 @@ module docusaurus import incubaid.herolib.core.pathlib -import incubaid.herolib.web.site +import incubaid.herolib.web.doctree.meta import incubaid.herolib.osal.core as osal import incubaid.herolib.ui.console @@ -15,7 +15,7 @@ pub mut: path_build pathlib.Path errors []SiteError config Configuration - website site.Site + website meta.Site generated bool } @@ -50,7 +50,7 @@ pub fn (mut s DocSite) build_publish() ! { ' retry: 0 )! - for item in s.website.siteconfig.build_dest { + for item in s.build_dest { if item.path.trim_space().trim('/ ') == '' { $if debug { print_backtrace() diff --git a/lib/web/docusaurus/dsite_configuration.v b/lib/web/docusaurus/dsite_configuration.v index 9bb8cdaa..d58134c3 100644 --- a/lib/web/docusaurus/dsite_configuration.v +++ b/lib/web/docusaurus/dsite_configuration.v @@ -1,6 +1,6 @@ module docusaurus -import incubaid.herolib.web.site +import incubaid.herolib.web.doctree.meta // IS THE ONE AS USED BY DOCUSAURUS @@ -87,9 +87,9 @@ pub mut: } // This function is a pure transformer: site.SiteConfig -> docusaurus.Configuration -fn new_configuration(mysite site.Site) !Configuration { +fn new_configuration(mysite meta.Site) !Configuration { // Transform site.SiteConfig to docusaurus.Configuration - mut site_cfg := mysite.siteconfig + mut site_cfg := mysite.config mut nav_items := []NavbarItem{} for item in site_cfg.menu.items { nav_items << NavbarItem{ diff --git a/lib/web/docusaurus/dsite_to_sidebar_json.v b/lib/web/docusaurus/dsite_to_sidebar_json.v index 69deebeb..564e0de4 100644 --- a/lib/web/docusaurus/dsite_to_sidebar_json.v +++ b/lib/web/docusaurus/dsite_to_sidebar_json.v @@ -1,7 +1,16 @@ module doc -import incubaid.herolib.web.site -//this is the logic to create docusaurus sidebar.json from site.NavItems +import incubaid.herolib.web.doctree.meta as site +import json + +// this is the logic to create docusaurus sidebar.json from site.NavItems + +struct Sidebar { +pub mut: + items []NavItem +} + +type NavItem = NavDoc | NavCat | NavLink struct SidebarItem { typ string @[json: 'type'] @@ -14,11 +23,32 @@ struct SidebarItem { items []SidebarItem @[omitempty] } +pub struct NavDoc { +pub mut: + id string + label string +} + +pub struct NavCat { +pub mut: + label string + collapsible bool = true + collapsed bool + items []NavItem +} + +pub struct NavLink { +pub mut: + label string + href string + description string +} + // ============================================================================ // JSON Serialization // ============================================================================ -pub fn sidebar_to_json(sb site.SideBar) !string { +pub fn sidebar_to_json(sb site.SideBar) !string { items := sb.my_sidebar.map(to_sidebar_item(it)) return json.encode_pretty(items) } @@ -57,4 +87,3 @@ fn from_category(cat site.NavCat) SidebarItem { items: cat.items.map(to_sidebar_item(it)) } } -