This commit is contained in:
2025-12-01 16:45:47 +01:00
parent 5f9a95f2ca
commit 55966be158
72 changed files with 710 additions and 1233 deletions

View File

@@ -25,10 +25,10 @@ The recommended structure for an ebook follows this pattern:
```
my_ebook/
├── scan.hero # Atlas collection scanning
├── scan.hero # DocTree collection scanning
├── config.hero # Site configuration
├── menus.hero # Navbar and footer configuration
├── include.hero # Docusaurus define and atlas export
├── include.hero # Docusaurus define and doctree export
├── 1_intro.heroscript # Page definitions (numbered for ordering)
├── 2_concepts.heroscript # More page definitions
└── 3_advanced.heroscript # Additional pages
@@ -42,10 +42,10 @@ Defines which collections to scan for content:
```heroscript
// Scan local collections
!!atlas.scan path:"../../collections/my_collection"
!!doctree.scan path:"../../collections/my_collection"
// Scan remote collections from git
!!atlas.scan git_url:"https://git.example.com/org/repo/src/branch/main/collections/docs"
!!doctree.scan git_url:"https://git.example.com/org/repo/src/branch/main/collections/docs"
```
#### `config.hero` - Site Configuration
@@ -113,7 +113,7 @@ Links to shared configuration or defines docusaurus directly:
// Option 2: Define directly
!!docusaurus.define name:'my_ebook'
!!atlas.export include:true
!!doctree.export include:true
```
#### Page Definition Files (`*.heroscript`)
@@ -145,7 +145,7 @@ Define pages and categories:
## Collections
Collections are directories containing markdown files. They're scanned by Atlas and referenced in page definitions.
Collections are directories containing markdown files. They're scanned by DocTree and referenced in page definitions.
```
collections/
@@ -189,16 +189,16 @@ The older approach using `!!docusaurus.add` is still supported but not recommend
## HeroScript Actions Reference
### `!!atlas.scan`
### `!!doctree.scan`
Scans a directory for markdown collections:
- `path` (string): Local path to scan
- `git_url` (string): Git URL to clone and scan
- `name` (string): Atlas instance name (default: `main`)
- `name` (string): DocTree instance name (default: `main`)
- `ignore` (list): Directory names to skip
### `!!atlas.export`
### `!!doctree.export`
Exports scanned collections:
@@ -215,7 +215,7 @@ Configures the Docusaurus build environment:
- `reset` (bool): Clean build directory before starting
- `template_update` (bool): Update Docusaurus template
- `install` (bool): Run `bun install`
- `atlas_dir` (string): Atlas export directory
- `doctree_dir` (string): DocTree export directory
### `!!site.config`
@@ -254,4 +254,4 @@ Defines a sidebar category:
## See Also
- `lib/web/site` - Generic site configuration module
- `lib/data/atlas` - Atlas collection management
- `lib/data/doctree` - DocTree collection management

View File

@@ -17,7 +17,7 @@ pub mut:
reset bool
template_update bool
coderoot string
atlas_dir string
doctree_dir string
}
@[params]
@@ -29,7 +29,7 @@ pub mut:
reset bool
template_update bool
coderoot string
atlas_dir string
doctree_dir string
}
// return the last know config
@@ -38,8 +38,8 @@ pub fn config() !DocusaurusConfig {
docusaurus_config << DocusaurusConfigParams{}
}
mut args := docusaurus_config[0] or { panic('bug in docusaurus config') }
if args.atlas_dir == '' {
return error('atlas_dir is not set')
if args.doctree_dir == '' {
return error('doctree_dir is not set')
}
if args.path_build == '' {
args.path_build = '${os.home_dir()}/hero/var/docusaurus/build'
@@ -58,7 +58,7 @@ pub fn config() !DocusaurusConfig {
install: args.install
reset: args.reset
template_update: args.template_update
atlas_dir: args.atlas_dir
doctree_dir: args.doctree_dir
}
if c.install {
install(c)!

View File

@@ -73,7 +73,7 @@ pub mut:
port int = 3000
open bool = true // whether to open the browser automatically
watch_changes bool // whether to watch for changes in docs and rebuild automatically
skip_generate bool // whether to skip generation (useful when docs are pre-generated, e.g., from atlas)
skip_generate bool // whether to skip generation (useful when docs are pre-generated, e.g., from doctree)
}
pub fn (mut s DocSite) open(args DevArgs) ! {

View File

@@ -37,7 +37,7 @@ pub fn (mut docsite DocSite) generate() ! {
mut sidebar_file := pathlib.get_file(path: '${cfg_path}/sidebar.json', create: true)!
sidebar_file.write(docsite.config.sidebar_json_txt)!
docsite.link_docs()!
docsite.generate_docs()!
docsite.import()!
}

View File

@@ -1,14 +1,14 @@
module docusaurus
import incubaid.herolib.core.pathlib
import incubaid.herolib.data.atlas.client as atlas_client
import incubaid.herolib.data.doctree.client as doctree_client
import incubaid.herolib.data.markdown.tools as markdowntools
import incubaid.herolib.ui.console
import incubaid.herolib.web.site
import os
// ============================================================================
// Doc Linking - Generate Docusaurus docs from Atlas collections
// Doc Linking - Generate Docusaurus docs from DocTree collections
// ============================================================================
// get_first_doc_from_sidebar recursively finds the first doc ID in the sidebar.
@@ -35,16 +35,16 @@ fn get_first_doc_from_sidebar(items []site.NavItem) string {
return ''
}
// link_docs generates markdown files from site page definitions.
// Pages are fetched from Atlas collections and written with frontmatter.
pub fn (mut docsite DocSite) link_docs() ! {
// generate_docs generates markdown files from site page definitions.
// Pages are fetched from DocTree collections and written with frontmatter.
pub fn (mut docsite DocSite) generate_docs() ! {
c := config()!
docs_path := '${c.path_build.path}/docs'
reset_docs_dir(docs_path)!
console.print_header('Linking docs to ${docs_path}')
console.print_header('Write doc: ${docs_path}')
mut client := atlas_client.new(export_dir: c.atlas_dir)!
mut client := doctree_client.new(export_dir: c.doctree_dir)!
mut errors := []string{}
// Determine if we need to set a docs landing page (when url_home ends with "/")
@@ -72,7 +72,7 @@ fn reset_docs_dir(docs_path string) ! {
os.mkdir_all(docs_path)!
}
fn report_errors(mut client atlas_client.AtlasClient, errors []string) ! {
fn report_errors(mut client doctree_client.AtlasClient, errors []string) ! {
available := client.list_markdown() or { 'Could not list available pages' }
console.print_stderr('Available pages:\n${available}')
return error('Errors during doc generation:\n${errors.join('\n\n')}')
@@ -82,7 +82,7 @@ fn report_errors(mut client atlas_client.AtlasClient, errors []string) ! {
// Page Processing
// ============================================================================
fn process_page(mut client atlas_client.AtlasClient, docs_path string, page site.Page, first_doc_page string, mut errors []string) {
fn process_page(mut client doctree_client.AtlasClient, docs_path string, page site.Page, first_doc_page string, mut errors []string) {
collection, page_name := parse_page_src(page.src) or {
errors << err.msg()
return
@@ -122,7 +122,7 @@ fn write_page(docs_path string, page_name string, page site.Page, content string
file.write(final_content)!
}
fn copy_page_assets(mut client atlas_client.AtlasClient, docs_path string, collection string, page_name string) {
fn copy_page_assets(mut client doctree_client.AtlasClient, docs_path string, collection string, page_name string) {
client.copy_images(collection, page_name, docs_path) or {}
client.copy_files(collection, page_name, docs_path) or {}
}
@@ -132,12 +132,21 @@ fn copy_page_assets(mut client atlas_client.AtlasClient, docs_path string, colle
// ============================================================================
fn build_frontmatter(page site.Page, content string, is_landing_page bool) string {
title := get_title(page, content)
description := get_description(page, title)
mut lines := ['---']
lines << "title: '${escape_yaml(title)}'"
lines << "description: '${escape_yaml(description)}'"
lines << "title: '${title}'"
lines << "description: '${description}'"
// if page.id.contains('tfhowto_tools'){
// println('extracted title: ${title}')
// println('page.src: ${lines}')
// $dbg;
// }
// Add slug: / for the docs landing page so /docs/ works directly
if is_landing_page {
@@ -154,25 +163,3 @@ fn build_frontmatter(page site.Page, content string, is_landing_page bool) strin
lines << '---'
return lines.join('\n')
}
fn get_title(page site.Page, content string) string {
if page.title.len > 0 {
return page.title
}
extracted := markdowntools.extract_title(content)
if extracted.len > 0 {
return extracted
}
return page.src.split(':').last()
}
fn get_description(page site.Page, title string) string {
if page.description.len > 0 {
return page.description
}
return title
}
fn escape_yaml(s string) string {
return s.replace("'", "''")
}

View File

@@ -1,7 +1,7 @@
module docusaurus
import incubaid.herolib.core.pathlib
// import incubaid.herolib.data.atlas.client as atlas_client
// import incubaid.herolib.data.doctree.client as doctree_client
// import incubaid.herolib.web.site { Page, Section, Site }
// import incubaid.herolib.data.markdown.tools as markdowntools
// import incubaid.herolib.ui.console
@@ -24,7 +24,7 @@ import incubaid.herolib.core.pathlib
// docs_path := '${c.path_build.path}/docs'
// // Create the appropriate client based on configuration
// mut client_instance := atlas_client.new(export_dir: c.atlas_dir)!
// mut client_instance := doctree_client.new(export_dir: c.doctree_dir)!
// mut client := IDocClient(client_instance)
// mut gen := SiteGenerator{
@@ -378,8 +378,8 @@ import incubaid.herolib.core.pathlib
// }
// }
// // STEP 5: Fix bare page references (from atlas self-contained exports)
// // Atlas exports convert cross-collection links to simple relative links like "token_system2.md"
// // STEP 5: Fix bare page references (from doctree self-contained exports)
// // DocTree exports convert cross-collection links to simple relative links like "token_system2.md"
// // We need to transform these to proper relative paths based on Docusaurus structure
// for page_name, target_dir in page_to_path {
// // Match links in the format ](page_name) or ](page_name.md)

View File

@@ -0,0 +1,60 @@
module doc
import incubaid.herolib.web.site
//this is the logic to create docusaurus sidebar.json from site.NavItems
struct SidebarItem {
typ string @[json: 'type']
id string @[omitempty]
label string
href string @[omitempty]
description string @[omitempty]
collapsible bool @[json: 'collapsible'; omitempty]
collapsed bool @[json: 'collapsed'; omitempty]
items []SidebarItem @[omitempty]
}
// ============================================================================
// JSON Serialization
// ============================================================================
pub fn sidebar_to_json(sb site.SideBar) !string {
items := sb.my_sidebar.map(to_sidebar_item(it))
return json.encode_pretty(items)
}
fn to_sidebar_item(item site.NavItem) SidebarItem {
return match item {
NavDoc { from_doc(item) }
NavLink { from_link(item) }
NavCat { from_category(item) }
}
}
fn from_doc(doc site.NavDoc) SidebarItem {
return SidebarItem{
typ: 'doc'
id: doc.id
label: doc.label
}
}
fn from_link(link site.NavLink) SidebarItem {
return SidebarItem{
typ: 'link'
label: link.label
href: link.href
description: link.description
}
}
fn from_category(cat site.NavCat) SidebarItem {
return SidebarItem{
typ: 'category'
label: cat.label
collapsible: cat.collapsible
collapsed: cat.collapsed
items: cat.items.map(to_sidebar_item(it))
}
}

View File

@@ -75,7 +75,7 @@ After running the test:
If links don't resolve:
1. Check that the collection is registered in the atlas
1. Check that the collection is registered in the doctree
2. Verify page names match (no typos)
3. Run with debug flag (`-d`) to see detailed output
4. Check `~/hero/var/docusaurus/build/docs/` for generated files

View File

@@ -10,7 +10,7 @@ If links appear broken, check:
1. The collection name is correct
2. The page name matches the markdown filename (without `.md`)
3. The collection is properly registered in the atlas
3. The collection is properly registered in the doctree
### Page Not Found
@@ -29,11 +29,11 @@ Ensure the page is defined in your heroscript:
## Error Messages
| Error | Solution |
|-------|----------|
| "Page not found" | Check page name spelling |
| "Collection not found" | Verify atlas configuration |
| "Link resolution failed" | Check link syntax |
| Error | Solution |
| ------------------------ | ---------------------------- |
| "Page not found" | Check page name spelling |
| "Collection not found" | Verify doctree configuration |
| "Link resolution failed" | Check link syntax |
## Navigation

View File

@@ -1,4 +1,4 @@
!!docusaurus.define name:'test_site'
!!atlas.export include:true
!!doctree.export include:true

View File

@@ -1,2 +1,2 @@
!!atlas.scan path:"../../collections/test_collection"
!!doctree.scan path:"../../collections/test_collection"

View File

@@ -1,7 +1,7 @@
module docusaurus
import incubaid.herolib.core.playbook { PlayBook }
import incubaid.herolib.data.atlas
import incubaid.herolib.data.doctree
import incubaid.herolib.ui.console
import os
@@ -24,7 +24,7 @@ fn process_define(mut plbook PlayBook) !&DocSite {
mut action := plbook.ensure_once(filter: 'docusaurus.define')!
p := action.params
atlas_dir := p.get_default('atlas_dir', '${os.home_dir()}/hero/var/atlas_export')!
doctree_dir := p.get_default('doctree_dir', '${os.home_dir()}/hero/var/doctree_export')!
config_set(
path_build: p.get_default('path_build', '')!
@@ -32,13 +32,13 @@ fn process_define(mut plbook PlayBook) !&DocSite {
reset: p.get_default_false('reset')
template_update: p.get_default_false('template_update')
install: p.get_default_false('install')
atlas_dir: atlas_dir
doctree_dir: doctree_dir
)!
site_name := p.get('name') or { return error('docusaurus.define: "name" is required') }
atlas_name := p.get_default('atlas', 'main')!
doctree_name := p.get_default('doctree', 'main')!
export_atlas(atlas_name, atlas_dir)!
export_doctree(doctree_name, doctree_dir)!
dsite_define(site_name)!
action.done = true
@@ -77,11 +77,11 @@ fn process_dev(mut plbook PlayBook, mut dsite DocSite) ! {
action.done = true
}
fn export_atlas(name string, dir string) ! {
if !atlas.exists(name) {
fn export_doctree(name string, dir string) ! {
if !doctree.exists(name) {
return
}
console.print_debug('Auto-exporting Atlas "${name}" to ${dir}')
mut a := atlas.get(name)!
console.print_debug('Auto-exporting DocTree "${name}" to ${dir}')
mut a := doctree.get(name)!
a.export(destination: dir, reset: true, include: true, redis: false)!
}