...
This commit is contained in:
11
lib/web/doctree/meta/model_announcement.v
Normal file
11
lib/web/doctree/meta/model_announcement.v
Normal file
@@ -0,0 +1,11 @@
|
||||
module meta
|
||||
|
||||
// Announcement bar config structure
|
||||
pub struct Announcement {
|
||||
pub mut:
|
||||
// id string @[json: 'id']
|
||||
content string @[json: 'content']
|
||||
background_color string @[json: 'backgroundColor']
|
||||
text_color string @[json: 'textColor']
|
||||
is_closeable bool @[json: 'isCloseable']
|
||||
}
|
||||
7
lib/web/doctree/meta/model_builddest.v
Normal file
7
lib/web/doctree/meta/model_builddest.v
Normal file
@@ -0,0 +1,7 @@
|
||||
module meta
|
||||
|
||||
pub struct BuildDest {
|
||||
pub mut:
|
||||
path string
|
||||
ssh_name string
|
||||
}
|
||||
8
lib/web/doctree/meta/model_category.v
Normal file
8
lib/web/doctree/meta/model_category.v
Normal file
@@ -0,0 +1,8 @@
|
||||
module meta
|
||||
|
||||
struct Category {
|
||||
pub mut:
|
||||
path string // e.g. Operations/Daily (means 2 levels deep, first level is Operations)
|
||||
collapsible bool = true
|
||||
collapsed bool
|
||||
}
|
||||
11
lib/web/doctree/meta/model_import.v
Normal file
11
lib/web/doctree/meta/model_import.v
Normal file
@@ -0,0 +1,11 @@
|
||||
module meta
|
||||
|
||||
// is to import one site into another, can be used to e.g. import static parts from one location into the build one we are building
|
||||
pub struct ImportItem {
|
||||
pub mut:
|
||||
url string // http git url can be to specific path
|
||||
path string
|
||||
dest string // location in the docs folder of the place where we will build the documentation site e.g. docusaurus
|
||||
replace map[string]string // will replace ${NAME} in the imported content
|
||||
visible bool = true
|
||||
}
|
||||
8
lib/web/doctree/meta/model_link.v
Normal file
8
lib/web/doctree/meta/model_link.v
Normal file
@@ -0,0 +1,8 @@
|
||||
module meta
|
||||
|
||||
struct Link {
|
||||
pub mut:
|
||||
label string
|
||||
href string
|
||||
description string
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
module meta
|
||||
|
||||
import incubaid.herolib.web.doctree.client as doctree_client
|
||||
|
||||
|
||||
// Page represents a single documentation page
|
||||
pub struct Page {
|
||||
pub mut:
|
||||
id string // Unique identifier: "collection:page_name"
|
||||
src string // Unique identifier: "collection:page_name" marks where the page is from. (is also name_fix'ed)
|
||||
label string // Display label in navigation e.g. "Getting Started"
|
||||
title string // Display title (optional, extracted from markdown if empty)
|
||||
description string // Brief description for metadata
|
||||
draft bool // Is this page a draft? Means only show in development mode
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
module meta
|
||||
|
||||
import json
|
||||
|
||||
// ============================================================================
|
||||
// Sidebar Navigation Models (Domain Types)
|
||||
// is the result of walking through the pages, links and categories to build the sidebar structure
|
||||
// ============================================================================
|
||||
|
||||
pub struct SideBar {
|
||||
@@ -15,9 +14,8 @@ pub type NavItem = NavDoc | NavCat | NavLink
|
||||
|
||||
pub struct NavDoc {
|
||||
pub:
|
||||
id string
|
||||
path string // path is $collection/$name without .md, this is a subdir of the doctree export dir
|
||||
label string
|
||||
hide_title bool
|
||||
}
|
||||
|
||||
pub struct NavCat {
|
||||
|
||||
@@ -3,7 +3,18 @@ module meta
|
||||
@[heap]
|
||||
pub struct Site {
|
||||
pub mut:
|
||||
pages map[string]Page // key: "collection:page_name"
|
||||
nav SideBar // Navigation sidebar configuration
|
||||
siteconfig SiteConfig // Full site configuration
|
||||
doctree_path string // path to the export of the doctree site
|
||||
config SiteConfig // Full site configuration
|
||||
pages []Page
|
||||
links []Link
|
||||
categories []Category
|
||||
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 {
|
||||
// TODO: implement, use all info abouve []page, []categories, []links to build the sidebar
|
||||
return SideBar{}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ pub mut:
|
||||
copyright string = 'someone'
|
||||
footer Footer
|
||||
menu Menu
|
||||
imports []ImportItem
|
||||
|
||||
// New fields for Docusaurus compatibility
|
||||
url string // The main URL of the site (from !!site.config url:)
|
||||
@@ -24,21 +23,6 @@ pub mut:
|
||||
|
||||
meta_title string // Specific title for SEO metadata (from !!site.config_meta title:)
|
||||
meta_image string // Specific image for SEO metadata (og:image) (from !!site.config_meta image:)
|
||||
|
||||
build_dest []BuildDest // Production build destinations (from !!site.build_dest)
|
||||
build_dest_dev []BuildDest // Development build destinations (from !!site.build_dest_dev)
|
||||
|
||||
announcement AnnouncementBar // Announcement bar configuration (from !!site.announcement)
|
||||
}
|
||||
|
||||
// Announcement bar config structure
|
||||
pub struct AnnouncementBar {
|
||||
pub mut:
|
||||
// id string @[json: 'id']
|
||||
content string @[json: 'content']
|
||||
background_color string @[json: 'backgroundColor']
|
||||
text_color string @[json: 'textColor']
|
||||
is_closeable bool @[json: 'isCloseable']
|
||||
}
|
||||
|
||||
// Footer config structures
|
||||
@@ -78,20 +62,3 @@ pub mut:
|
||||
logo_src string @[json: 'logoSrc']
|
||||
logo_src_dark string @[json: 'logoSrcDark']
|
||||
}
|
||||
|
||||
pub struct BuildDest {
|
||||
pub mut:
|
||||
path string
|
||||
ssh_name string
|
||||
}
|
||||
|
||||
// is to import one docusaurus site into another, can be used to e.g. import static parts from one location into the build one we are building
|
||||
pub struct ImportItem {
|
||||
pub mut:
|
||||
name string // will normally be empty
|
||||
url string // http git url can be to specific path
|
||||
path string
|
||||
dest string // location in the docs folder of the place where we will build the documentation site e.g. docusaurus
|
||||
replace map[string]string // will replace ${NAME} in the imported content
|
||||
visible bool = true
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
module meta
|
||||
|
||||
import os
|
||||
import incubaid.herolib.core.playbook { PlayBook }
|
||||
import incubaid.herolib.core.texttools
|
||||
import time
|
||||
import incubaid.herolib.ui.console
|
||||
|
||||
// ============================================================
|
||||
// ANNOUNCEMENT: Process announcement bar (optional)
|
||||
// ============================================================
|
||||
fn play_announcement(mut plbook PlayBook, mut config SiteConfig) ! {
|
||||
fn play_announcement(mut plbook PlayBook, mut site Site) ! {
|
||||
mut announcement_actions := plbook.find(filter: 'site.announcement')!
|
||||
|
||||
if announcement_actions.len > 0 {
|
||||
@@ -21,7 +17,7 @@ fn play_announcement(mut plbook PlayBook, mut config SiteConfig) ! {
|
||||
return error('!!site.announcement: must specify "content"')
|
||||
}
|
||||
|
||||
config.announcement = AnnouncementBar{
|
||||
site.announcements << Announcement{
|
||||
// id: p.get('id')!
|
||||
content: content
|
||||
background_color: p.get_default('background_color', '#20232a')!
|
||||
|
||||
@@ -9,7 +9,7 @@ import incubaid.herolib.ui.console
|
||||
// ============================================================
|
||||
// IMPORTS: Process content imports
|
||||
// ============================================================
|
||||
fn play_imports(mut plbook PlayBook, mut config SiteConfig) ! {
|
||||
fn play_imports(mut plbook PlayBook, mut site Site) ! {
|
||||
mut import_actions := plbook.find(filter: 'site.import')!
|
||||
|
||||
for mut action in import_actions {
|
||||
@@ -37,7 +37,6 @@ fn play_imports(mut plbook PlayBook, mut config SiteConfig) ! {
|
||||
|
||||
// Create import item
|
||||
mut import_item := ImportItem{
|
||||
name: p.get_default('name', '')!
|
||||
url: p.get_default('url', '')!
|
||||
path: import_path
|
||||
dest: p.get_default('dest', '')!
|
||||
@@ -45,7 +44,7 @@ fn play_imports(mut plbook PlayBook, mut config SiteConfig) ! {
|
||||
visible: p.get_default_false('visible')
|
||||
}
|
||||
|
||||
config.imports << import_item
|
||||
site.imports << import_item
|
||||
action.done = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,193 +0,0 @@
|
||||
module meta
|
||||
|
||||
import os
|
||||
import incubaid.herolib.core.playbook { PlayBook }
|
||||
import incubaid.herolib.core.texttools
|
||||
import time
|
||||
import incubaid.herolib.ui.console
|
||||
|
||||
|
||||
// ============================================================
|
||||
// Internal structure for tracking category information
|
||||
// ============================================================
|
||||
struct CategoryInfo {
|
||||
pub mut:
|
||||
name string
|
||||
label string
|
||||
position int
|
||||
nav_items []NavItem
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PAGES: Process pages and build navigation structure
|
||||
// ============================================================
|
||||
fn play_pages(mut plbook PlayBook, mut website Site) ! {
|
||||
mut collection_current := '' // Track current collection for reuse
|
||||
mut categories := map[string]CategoryInfo{} // Map of category name -> info
|
||||
mut category_current := '' // Track current active category
|
||||
mut root_nav_items := []NavItem{} // Root-level items (pages without category)
|
||||
mut next_category_position := 100 // Auto-increment position for categories
|
||||
|
||||
// ============================================================
|
||||
// PASS 1: Process all page and category actions
|
||||
// ============================================================
|
||||
mut all_actions := plbook.find(filter: 'site.')!
|
||||
|
||||
for mut action in all_actions {
|
||||
if action.done {
|
||||
continue
|
||||
}
|
||||
|
||||
// ========== PAGE CATEGORY ==========
|
||||
if action.name == 'page_category' {
|
||||
mut p := action.params
|
||||
|
||||
category_name := p.get('name') or {
|
||||
return error('!!site.page_category: must specify "name"')
|
||||
}
|
||||
|
||||
category_name_fixed := texttools.name_fix(category_name)
|
||||
|
||||
// label is empty when not specified
|
||||
mut label := p.get_default('label', "")!
|
||||
mut position := p.get_int_default('position', next_category_position)!
|
||||
|
||||
// Auto-increment position if using default
|
||||
if position == next_category_position {
|
||||
next_category_position += 100
|
||||
}
|
||||
|
||||
// Create and store category info
|
||||
categories[category_name_fixed] = CategoryInfo{
|
||||
name: category_name_fixed
|
||||
label: label
|
||||
position: position
|
||||
nav_items: []NavItem{}
|
||||
}
|
||||
|
||||
category_current = category_name_fixed
|
||||
console.print_item('Created page category: "${label}" (${category_name_fixed})')
|
||||
action.done = true
|
||||
continue
|
||||
}
|
||||
|
||||
// ========== PAGE ==========
|
||||
if action.name == 'page' {
|
||||
mut p := action.params
|
||||
|
||||
mut page_src := p.get_default('src', '')!
|
||||
mut page_collection := ''
|
||||
mut page_name := ''
|
||||
|
||||
// Parse collection:page format from src
|
||||
if page_src.contains(':') {
|
||||
parts := page_src.split(':')
|
||||
page_collection = texttools.name_fix(parts[0])
|
||||
page_name = normalize_page_name(parts[1])
|
||||
} else {
|
||||
// Use previously specified collection if available
|
||||
if collection_current.len > 0 {
|
||||
page_collection = collection_current
|
||||
page_name = normalize_page_name(page_src)
|
||||
} else {
|
||||
return error('!!site.page: must specify source as "collection:page_name" in "src".\nGot src="${page_src}" with no collection previously set.\nEither specify "collection:page_name" or define a collection first.')
|
||||
}
|
||||
}
|
||||
|
||||
// Validation
|
||||
if page_name.len == 0 {
|
||||
return error('!!site.page: could not extract valid page name from src="${page_src}"')
|
||||
}
|
||||
if page_collection.len == 0 {
|
||||
return error('!!site.page: could not determine collection')
|
||||
}
|
||||
|
||||
// Store collection for subsequent pages
|
||||
collection_current = page_collection
|
||||
|
||||
// Build page ID
|
||||
page_id := '${page_collection}:${page_name}'
|
||||
|
||||
// Get optional page metadata
|
||||
page_title := p.get_default('title', '')!
|
||||
page_description := p.get_default('description', '')!
|
||||
page_draft := p.get_default_false('draft')
|
||||
page_hide_title := p.get_default_false('hide_title')
|
||||
|
||||
// Create page
|
||||
mut page := Page{
|
||||
id: page_id
|
||||
title: page_title
|
||||
description: page_description
|
||||
draft: page_draft
|
||||
hide_title: page_hide_title
|
||||
src: page_id
|
||||
}
|
||||
|
||||
website.pages[page_id] = page
|
||||
|
||||
// Create navigation item with human-readable label
|
||||
// nav_label := page_title.len
|
||||
nav_doc := NavDoc{
|
||||
id: page.id
|
||||
label: page.title
|
||||
hide_title: page.hide_title
|
||||
}
|
||||
|
||||
// Add to appropriate category or root
|
||||
if category_current.len > 0 {
|
||||
if category_current in categories {
|
||||
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')
|
||||
}
|
||||
97
lib/web/doctree/meta/play_pages_categories.v
Normal file
97
lib/web/doctree/meta/play_pages_categories.v
Normal file
@@ -0,0 +1,97 @@
|
||||
module meta
|
||||
|
||||
import incubaid.herolib.core.playbook { PlayBook }
|
||||
import incubaid.herolib.web.doctree as doctreetools
|
||||
import incubaid.herolib.ui.console
|
||||
|
||||
//=========================================================
|
||||
// PAGES: Process pages and build navigation structure
|
||||
// ============================================================
|
||||
fn play_pages(mut plbook PlayBook, mut website Site) ! {
|
||||
mut collection_current := ''
|
||||
mut category_current := 0
|
||||
|
||||
// ============================================================
|
||||
// PASS 1: Process all page and category actions
|
||||
// ============================================================
|
||||
mut all_actions := plbook.find(filter: 'site.')!
|
||||
|
||||
for mut action in all_actions {
|
||||
if action.done {
|
||||
continue
|
||||
}
|
||||
|
||||
// ========== PAGE CATEGORY ==========
|
||||
if action.name == 'page_category' {
|
||||
mut p := action.params
|
||||
|
||||
// label is empty when not specified (we support label & path for flexibility)
|
||||
|
||||
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}" ')
|
||||
action.done = true
|
||||
continue
|
||||
}
|
||||
|
||||
// ========== PAGE ==========
|
||||
if action.name == 'page' {
|
||||
mut p := action.params
|
||||
|
||||
mut page_src := p.get_default('src', '')!
|
||||
mut page_collection := ''
|
||||
mut page_name := ''
|
||||
|
||||
// Parse collection:page format from src
|
||||
if page_src.contains(':') {
|
||||
page_collection, page_name = doctreetools.key_parse(page_src)!
|
||||
} else {
|
||||
// Use previously specified collection if available
|
||||
if collection_current.len > 0 {
|
||||
page_collection = collection_current
|
||||
page_name = doctreetools.name_fix(page_src)
|
||||
} else {
|
||||
return error('!!site.page: must specify source as "collection:page_name" in "src".\nGot src="${page_src}" with no collection previously set.\nEither specify "collection:page_name" or define a collection first.')
|
||||
}
|
||||
}
|
||||
|
||||
// Validation
|
||||
if page_name.len == 0 {
|
||||
return error('!!site.page: could not extract valid page name from src="${page_src}"')
|
||||
}
|
||||
if page_collection.len == 0 {
|
||||
return error('!!site.page: could not determine collection')
|
||||
}
|
||||
|
||||
// Store collection for subsequent pages
|
||||
collection_current = page_collection
|
||||
|
||||
// Get optional page metadata
|
||||
page_label := p.get_default('label', p.get_default('title', '')!)! // is what is shown in the sidebar
|
||||
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}'
|
||||
label: page_label
|
||||
title: page_title
|
||||
description: page_description
|
||||
draft: p.get_default_false('draft')
|
||||
hide_title: p.get_default_false('hide_title')
|
||||
category_id: category_current
|
||||
hide: p.get_default_false('hide')
|
||||
}
|
||||
|
||||
website.pages << page
|
||||
|
||||
action.done = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ pub fn key_parse(key string) !(string, string) {
|
||||
pub fn name_fix(name string) string {
|
||||
mut result := name
|
||||
// Remove .md extension if present for processing
|
||||
result = result.replace('/', '_')
|
||||
if result.ends_with('.md') {
|
||||
result = result[0..result.len - 3]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user