From 8fc560ae78a57a2ed4f03d181133fb7e0c6113ce Mon Sep 17 00:00:00 2001 From: Mahmoud-Emad Date: Mon, 1 Dec 2025 11:54:02 +0200 Subject: [PATCH] feat: add docs landing page slug handling - Add function to find first doc in sidebar - Pass found doc ID to process_page - Set slug: / for landing page in frontmatter --- lib/web/docusaurus/dsite_configuration.v | 22 +++-- lib/web/docusaurus/dsite_link_docs.v | 51 ++++++++++-- lib/web/docusaurus/for_testing/README.md | 82 +++++++++++++++++++ .../collections/test_collection/.collection | 3 + .../collections/test_collection/page1.md | 21 +++++ .../collections/test_collection/page2.md | 30 +++++++ .../collections/test_collection/page3.md | 39 +++++++++ .../collections/test_collection/page4.md | 37 +++++++++ .../collections/test_collection/page5.md | 43 ++++++++++ .../collections/test_collection/page6.md | 44 ++++++++++ .../collections/test_collection/page7.md | 37 +++++++++ .../for_testing/ebooks/test_site/config.hero | 16 ++++ .../for_testing/ebooks/test_site/include.hero | 4 + .../for_testing/ebooks/test_site/menus.hero | 33 ++++++++ .../ebooks/test_site/pages.heroscript | 34 ++++++++ .../for_testing/ebooks/test_site/scan.hero | 2 + lib/web/site/model_sidebar.v | 4 +- 17 files changed, 483 insertions(+), 19 deletions(-) create mode 100644 lib/web/docusaurus/for_testing/README.md create mode 100644 lib/web/docusaurus/for_testing/collections/test_collection/.collection create mode 100644 lib/web/docusaurus/for_testing/collections/test_collection/page1.md create mode 100644 lib/web/docusaurus/for_testing/collections/test_collection/page2.md create mode 100644 lib/web/docusaurus/for_testing/collections/test_collection/page3.md create mode 100644 lib/web/docusaurus/for_testing/collections/test_collection/page4.md create mode 100644 lib/web/docusaurus/for_testing/collections/test_collection/page5.md create mode 100644 lib/web/docusaurus/for_testing/collections/test_collection/page6.md create mode 100644 lib/web/docusaurus/for_testing/collections/test_collection/page7.md create mode 100644 lib/web/docusaurus/for_testing/ebooks/test_site/config.hero create mode 100644 lib/web/docusaurus/for_testing/ebooks/test_site/include.hero create mode 100644 lib/web/docusaurus/for_testing/ebooks/test_site/menus.hero create mode 100644 lib/web/docusaurus/for_testing/ebooks/test_site/pages.heroscript create mode 100644 lib/web/docusaurus/for_testing/ebooks/test_site/scan.hero diff --git a/lib/web/docusaurus/dsite_configuration.v b/lib/web/docusaurus/dsite_configuration.v index 356cff78..9bb8cdaa 100644 --- a/lib/web/docusaurus/dsite_configuration.v +++ b/lib/web/docusaurus/dsite_configuration.v @@ -6,11 +6,11 @@ import incubaid.herolib.web.site pub struct Configuration { pub mut: - main Main - navbar Navbar - footer Footer - sidebar_json_txt string //will hold the sidebar.json content - announcement AnnouncementBar + main Main + navbar Navbar + footer Footer + sidebar_json_txt string // will hold the sidebar.json content + announcement AnnouncementBar } pub struct Main { @@ -86,9 +86,7 @@ pub mut: is_closeable bool @[json: 'isCloseable'] } -// ... (struct definitions remain the same) ... - -// This function is now a pure transformer: site.SiteConfig -> docusaurus.Configuration +// This function is a pure transformer: site.SiteConfig -> docusaurus.Configuration fn new_configuration(mysite site.Site) !Configuration { // Transform site.SiteConfig to docusaurus.Configuration mut site_cfg := mysite.siteconfig @@ -121,7 +119,7 @@ fn new_configuration(mysite site.Site) !Configuration { sidebar_json_txt := mysite.nav.sidebar_to_json()! cfg := Configuration{ - main: Main{ + main: Main{ title: site_cfg.title tagline: site_cfg.tagline favicon: site_cfg.favicon @@ -151,7 +149,7 @@ fn new_configuration(mysite site.Site) !Configuration { copyright: site_cfg.copyright name: site_cfg.name } - navbar: Navbar{ + navbar: Navbar{ title: site_cfg.menu.title logo: Logo{ alt: site_cfg.menu.logo_alt @@ -160,11 +158,11 @@ fn new_configuration(mysite site.Site) !Configuration { } items: nav_items } - footer: Footer{ + footer: Footer{ style: site_cfg.footer.style links: footer_links } - announcement: AnnouncementBar{ + announcement: AnnouncementBar{ // id: site_cfg.announcement.id content: site_cfg.announcement.content background_color: site_cfg.announcement.background_color diff --git a/lib/web/docusaurus/dsite_link_docs.v b/lib/web/docusaurus/dsite_link_docs.v index e0eb8c3f..04576c5a 100644 --- a/lib/web/docusaurus/dsite_link_docs.v +++ b/lib/web/docusaurus/dsite_link_docs.v @@ -11,6 +11,30 @@ import os // Doc Linking - Generate Docusaurus docs from Atlas collections // ============================================================================ +// get_first_doc_from_sidebar recursively finds the first doc ID in the sidebar. +// Used to determine which page should get slug: / in frontmatter when url_home ends with "/". +fn get_first_doc_from_sidebar(items []site.NavItem) string { + for item in items { + match item { + site.NavDoc { + return site.extract_page_id(item.id) + } + site.NavCat { + // Recursively search in category items + doc := get_first_doc_from_sidebar(item.items) + if doc.len > 0 { + return doc + } + } + site.NavLink { + // Skip links, we want docs + continue + } + } + } + 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() ! { @@ -23,8 +47,15 @@ pub fn (mut docsite DocSite) link_docs() ! { mut client := atlas_client.new(export_dir: c.atlas_dir)! mut errors := []string{} + // Determine if we need to set a docs landing page (when url_home ends with "/") + first_doc_page := if docsite.website.siteconfig.url_home.ends_with('/') { + get_first_doc_from_sidebar(docsite.website.nav.my_sidebar) + } else { + '' + } + for _, page in docsite.website.pages { - process_page(mut client, docs_path, page, mut errors) + process_page(mut client, docs_path, page, first_doc_page, mut errors) } if errors.len > 0 { @@ -51,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, mut errors []string) { +fn process_page(mut client atlas_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 @@ -62,7 +93,10 @@ fn process_page(mut client atlas_client.AtlasClient, docs_path string, page site return } - write_page(docs_path, page_name, page, content) or { + // Check if this page is the docs landing page + is_landing_page := first_doc_page.len > 0 && page_name == first_doc_page + + write_page(docs_path, page_name, page, content, is_landing_page) or { errors << "Failed to write page '${page_name}': ${err.msg()}" return } @@ -79,8 +113,8 @@ fn parse_page_src(src string) !(string, string) { return parts[0], parts[1] } -fn write_page(docs_path string, page_name string, page site.Page, content string) ! { - frontmatter := build_frontmatter(page, content) +fn write_page(docs_path string, page_name string, page site.Page, content string, is_landing_page bool) ! { + frontmatter := build_frontmatter(page, content, is_landing_page) final_content := frontmatter + '\n\n' + content output_path := '${docs_path}/${page_name}.md' @@ -97,7 +131,7 @@ fn copy_page_assets(mut client atlas_client.AtlasClient, docs_path string, colle // Frontmatter Generation // ============================================================================ -fn build_frontmatter(page site.Page, content string) string { +fn build_frontmatter(page site.Page, content string, is_landing_page bool) string { title := get_title(page, content) description := get_description(page, title) @@ -105,6 +139,11 @@ fn build_frontmatter(page site.Page, content string) string { lines << "title: '${escape_yaml(title)}'" lines << "description: '${escape_yaml(description)}'" + // Add slug: / for the docs landing page so /docs/ works directly + if is_landing_page { + lines << 'slug: /' + } + if page.draft { lines << 'draft: true' } diff --git a/lib/web/docusaurus/for_testing/README.md b/lib/web/docusaurus/for_testing/README.md new file mode 100644 index 00000000..4a9c99dc --- /dev/null +++ b/lib/web/docusaurus/for_testing/README.md @@ -0,0 +1,82 @@ +# Docusaurus Link Resolution Test + +This directory contains a comprehensive test for the herolib documentation linking mechanism. + +## Structure + +``` +for_testing/ +├── README.md # This file +├── collections/ +│ └── test_collection/ # Markdown source files +│ ├── .collection # Collection metadata +│ ├── page1.md # Introduction +│ ├── page2.md # Basic Concepts +│ ├── page3.md # Configuration +│ ├── page4.md # Advanced Features +│ ├── page5.md # Troubleshooting +│ ├── page6.md # Best Practices +│ └── page7.md # Conclusion +└── ebooks/ + └── test_site/ # Heroscript configuration + ├── heroscriptall # Master configuration (entry point) + ├── config.heroscript # Site configuration + ├── pages.heroscript # Page definitions + └── docusaurus.heroscript # Docusaurus settings +``` + +## What This Tests + +1. **Link Resolution** - Each page contains links using the `[text](collection:page)` format +2. **Navigation Chain** - Pages link sequentially: 1 → 2 → 3 → 4 → 5 → 6 → 7 +3. **Sidebar Generation** - All 7 pages should appear in the sidebar +4. **Category Support** - Pages are organized into categories (root, basics, advanced, reference) + +## Running the Test + +From the herolib root directory: + +```bash +# Build herolib first +./cli/compile.vsh + +# Run the test site +/Users/mahmoud/hero/bin/hero docs -d -p lib/web/docusaurus/for_testing/ebooks/test_site +``` + +## Expected Results + +When the test runs successfully: + +1. ✅ All 7 pages are generated in `~/hero/var/docusaurus/build/docs/` +2. ✅ Sidebar shows all pages organized by category +3. ✅ Clicking navigation links works (page1 → page2 → ... → page7) +4. ✅ No broken links or 404 errors +5. ✅ Back-links also work (e.g., page7 → page1) + +## Link Syntax Being Tested + +```markdown +[Next Page](test_collection:page2) +``` + +This should resolve to a proper Docusaurus link when the site is built. + +## Verification + +After running the test: + +1. Open http://localhost:3000/test/ in your browser +2. Click through all navigation links from Page 1 to Page 7 +3. Verify the back-link on Page 7 returns to Page 1 +4. Check the sidebar displays all pages correctly + +## Troubleshooting + +If links don't resolve: + +1. Check that the collection is registered in the atlas +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 + diff --git a/lib/web/docusaurus/for_testing/collections/test_collection/.collection b/lib/web/docusaurus/for_testing/collections/test_collection/.collection new file mode 100644 index 00000000..92322691 --- /dev/null +++ b/lib/web/docusaurus/for_testing/collections/test_collection/.collection @@ -0,0 +1,3 @@ +name: test_collection +description: Test collection for link resolution testing + diff --git a/lib/web/docusaurus/for_testing/collections/test_collection/page1.md b/lib/web/docusaurus/for_testing/collections/test_collection/page1.md new file mode 100644 index 00000000..b16b09d6 --- /dev/null +++ b/lib/web/docusaurus/for_testing/collections/test_collection/page1.md @@ -0,0 +1,21 @@ +# Page 1: Introduction + +Welcome to the documentation linking test. This page serves as the entry point for testing herolib's link resolution mechanism. + +## Overview + +This test suite consists of 7 interconnected pages that form a chain. Each page links to the next, demonstrating that the `collection:page_name` link syntax works correctly across multiple layers. + +## What We're Testing + +- Link resolution using `collection:page_name` format +- Proper generation of Docusaurus-compatible links +- Navigation chain integrity from page 1 through page 7 +- Sidebar generation with all pages + +## Navigation + +Continue to the next section to learn about the basic concepts. + +**Next:** [Page 2: Basic Concepts](test_collection:page2) + diff --git a/lib/web/docusaurus/for_testing/collections/test_collection/page2.md b/lib/web/docusaurus/for_testing/collections/test_collection/page2.md new file mode 100644 index 00000000..dcd8bc07 --- /dev/null +++ b/lib/web/docusaurus/for_testing/collections/test_collection/page2.md @@ -0,0 +1,30 @@ +# Page 2: Basic Concepts + +This page covers the basic concepts of the documentation system. + +## Link Syntax + +In herolib, links between pages use the format: + +``` +[Link Text](collection_name:page_name) +``` + +For example, to link to `page3` in `test_collection`: + +```markdown +[Go to Page 3](test_collection:page3) +``` + +## How It Works + +1. The parser identifies links with the `collection:page` format +2. During site generation, these are resolved to actual file paths +3. Docusaurus receives properly formatted relative links + +## Navigation + +**Previous:** [Page 1: Introduction](test_collection:page1) + +**Next:** [Page 3: Configuration](test_collection:page3) + diff --git a/lib/web/docusaurus/for_testing/collections/test_collection/page3.md b/lib/web/docusaurus/for_testing/collections/test_collection/page3.md new file mode 100644 index 00000000..8c3144a6 --- /dev/null +++ b/lib/web/docusaurus/for_testing/collections/test_collection/page3.md @@ -0,0 +1,39 @@ +# Page 3: Configuration + +This page explains configuration options for the documentation system. + +## Site Configuration + +The site is configured using heroscript files: + +```heroscript +!!site.config + name:"test_site" + title:"Test Documentation" + base_url:"/test/" + url_home:"docs/page1" +``` + +## Page Definitions + +Each page is defined using the `!!site.page` action: + +```heroscript +!!site.page src:"test_collection:page1" + title:"Introduction" +``` + +## Important Settings + +| Setting | Description | +|---------|-------------| +| `name` | Unique page identifier | +| `collection` | Source collection name | +| `title` | Display title in sidebar | + +## Navigation + +**Previous:** [Page 2: Basic Concepts](test_collection:page2) + +**Next:** [Page 4: Advanced Features](test_collection:page4) + diff --git a/lib/web/docusaurus/for_testing/collections/test_collection/page4.md b/lib/web/docusaurus/for_testing/collections/test_collection/page4.md new file mode 100644 index 00000000..556c1ef2 --- /dev/null +++ b/lib/web/docusaurus/for_testing/collections/test_collection/page4.md @@ -0,0 +1,37 @@ +# Page 4: Advanced Features + +This page covers advanced features of the linking mechanism. + +## Cross-Collection Links + +You can link to pages in different collections: + +```markdown +[Link to other collection](other_collection:some_page) +``` + +## Categories + +Pages can be organized into categories: + +```heroscript +!!site.page_category name:'advanced' label:"Advanced Topics" + +!!site.page name:'page4' collection:'test_collection' + title:"Advanced Features" +``` + +## Multiple Link Formats + +The system supports various link formats: + +1. **Collection links:** `[text](collection:page)` +2. **Relative links:** `[text](./other_page.md)` +3. **External links:** `[text](https://example.com)` + +## Navigation + +**Previous:** [Page 3: Configuration](test_collection:page3) + +**Next:** [Page 5: Troubleshooting](test_collection:page5) + diff --git a/lib/web/docusaurus/for_testing/collections/test_collection/page5.md b/lib/web/docusaurus/for_testing/collections/test_collection/page5.md new file mode 100644 index 00000000..6f19053c --- /dev/null +++ b/lib/web/docusaurus/for_testing/collections/test_collection/page5.md @@ -0,0 +1,43 @@ +# Page 5: Troubleshooting + +This page helps you troubleshoot common issues. + +## Common Issues + +### Broken Links + +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 + +### Page Not Found + +Ensure the page is defined in your heroscript: + +```heroscript +!!site.page name:'page5' collection:'test_collection' + title:"Troubleshooting" +``` + +## Debugging Tips + +- Run with debug flag: `hero docs -d -p .` +- Check the generated `sidebar.json` +- Verify the docs output in `~/hero/var/docusaurus/build/docs/` + +## Error Messages + +| Error | Solution | +|-------|----------| +| "Page not found" | Check page name spelling | +| "Collection not found" | Verify atlas configuration | +| "Link resolution failed" | Check link syntax | + +## Navigation + +**Previous:** [Page 4: Advanced Features](test_collection:page4) + +**Next:** [Page 6: Best Practices](test_collection:page6) + diff --git a/lib/web/docusaurus/for_testing/collections/test_collection/page6.md b/lib/web/docusaurus/for_testing/collections/test_collection/page6.md new file mode 100644 index 00000000..d38fff10 --- /dev/null +++ b/lib/web/docusaurus/for_testing/collections/test_collection/page6.md @@ -0,0 +1,44 @@ +# Page 6: Best Practices + +This page outlines best practices for documentation. + +## Naming Conventions + +- Use lowercase for page names: `page_name.md` +- Use underscores for multi-word names: `my_long_page_name.md` +- Keep names short but descriptive + +## Link Organization + +### Do This ✓ + +```markdown +See the [configuration guide](test_collection:page3) for details. +``` + +### Avoid This ✗ + +```markdown +Click [here](test_collection:page3) for more. +``` + +## Documentation Structure + +A well-organized documentation site should: + +1. **Start with an introduction** - Explain what the documentation covers +2. **Progress logically** - Each page builds on the previous +3. **End with reference material** - API docs, troubleshooting, etc. + +## Content Guidelines + +- Keep paragraphs short +- Use code blocks for examples +- Include navigation links at the bottom of each page + +## Navigation + +**Previous:** [Page 5: Troubleshooting](test_collection:page5) + +**Next:** [Page 7: Conclusion](test_collection:page7) + diff --git a/lib/web/docusaurus/for_testing/collections/test_collection/page7.md b/lib/web/docusaurus/for_testing/collections/test_collection/page7.md new file mode 100644 index 00000000..3b8af335 --- /dev/null +++ b/lib/web/docusaurus/for_testing/collections/test_collection/page7.md @@ -0,0 +1,37 @@ +# Page 7: Conclusion + +Congratulations! You've reached the final page of the documentation linking test. + +## Summary + +This test suite demonstrated: + +- ✅ Link resolution using `collection:page_name` format +- ✅ Navigation chain across 7 pages +- ✅ Proper sidebar generation +- ✅ Docusaurus-compatible output + +## Test Verification + +If you've reached this page by clicking through all the navigation links, the linking mechanism is working correctly! + +### Link Chain Verified + +1. [Page 1: Introduction](test_collection:page1) → Entry point +2. [Page 2: Basic Concepts](test_collection:page2) → Link syntax +3. [Page 3: Configuration](test_collection:page3) → Site setup +4. [Page 4: Advanced Features](test_collection:page4) → Cross-collection links +5. [Page 5: Troubleshooting](test_collection:page5) → Common issues +6. [Page 6: Best Practices](test_collection:page6) → Guidelines +7. **Page 7: Conclusion** → You are here! + +## What's Next + +You can now use the herolib documentation system with confidence that links will resolve correctly across your entire documentation site. + +## Navigation + +**Previous:** [Page 6: Best Practices](test_collection:page6) + +**Back to Start:** [Page 1: Introduction](test_collection:page1) + diff --git a/lib/web/docusaurus/for_testing/ebooks/test_site/config.hero b/lib/web/docusaurus/for_testing/ebooks/test_site/config.hero new file mode 100644 index 00000000..24cd6adf --- /dev/null +++ b/lib/web/docusaurus/for_testing/ebooks/test_site/config.hero @@ -0,0 +1,16 @@ +!!site.config + name:"test_site" + title:"Link Resolution Test" + tagline:"Testing herolib documentation linking mechanism" + url:"http://localhost:3000" + url_home:"docs/" + base_url:"/test/" + favicon:"img/favicon.png" + copyright:"© 2024 Herolib Test" + default_collection:"test_collection" + +!!site.config_meta + description:"Test suite for verifying herolib documentation link resolution across multiple pages" + title:"Link Resolution Test - Herolib" + keywords:"herolib, docusaurus, testing, links, documentation" + diff --git a/lib/web/docusaurus/for_testing/ebooks/test_site/include.hero b/lib/web/docusaurus/for_testing/ebooks/test_site/include.hero new file mode 100644 index 00000000..ab430d31 --- /dev/null +++ b/lib/web/docusaurus/for_testing/ebooks/test_site/include.hero @@ -0,0 +1,4 @@ +!!docusaurus.define name:'test_site' + +!!atlas.export include:true + diff --git a/lib/web/docusaurus/for_testing/ebooks/test_site/menus.hero b/lib/web/docusaurus/for_testing/ebooks/test_site/menus.hero new file mode 100644 index 00000000..0c4c601a --- /dev/null +++ b/lib/web/docusaurus/for_testing/ebooks/test_site/menus.hero @@ -0,0 +1,33 @@ +// Navbar configuration +!!site.navbar + title:"Link Test" + +!!site.navbar_item + label:"Documentation" + to:"docs/" + position:"left" + +!!site.navbar_item + label:"GitHub" + href:"https://github.com/incubaid/herolib" + position:"right" + +// Footer configuration +!!site.footer + style:"dark" + +!!site.footer_item + title:"Docs" + label:"Introduction" + to:"docs/" + +!!site.footer_item + title:"Docs" + label:"Configuration" + to:"docs/page3" + +!!site.footer_item + title:"Community" + label:"GitHub" + href:"https://github.com/incubaid/herolib" + diff --git a/lib/web/docusaurus/for_testing/ebooks/test_site/pages.heroscript b/lib/web/docusaurus/for_testing/ebooks/test_site/pages.heroscript new file mode 100644 index 00000000..8711c9c5 --- /dev/null +++ b/lib/web/docusaurus/for_testing/ebooks/test_site/pages.heroscript @@ -0,0 +1,34 @@ +// Page Definitions for Link Resolution Test +// Each page maps to a markdown file in the test_collection + +// Root pages (no category) +!!site.page src:"test_collection:page1" + title:"Introduction" + +!!site.page src:"page2" + title:"Basic Concepts" + +// Basics category +!!site.page_category name:'basics' label:"Getting Started" + +!!site.page src:"page3" + title:"Configuration" + +!!site.page src:"page4" + title:"Advanced Features" + +// Advanced category +!!site.page_category name:'advanced' label:"Advanced Topics" + +!!site.page src:"page5" + title:"Troubleshooting" + +!!site.page src:"page6" + title:"Best Practices" + +// Reference category +!!site.page_category name:'reference' label:"Reference" + +!!site.page src:"page7" + title:"Conclusion" + diff --git a/lib/web/docusaurus/for_testing/ebooks/test_site/scan.hero b/lib/web/docusaurus/for_testing/ebooks/test_site/scan.hero new file mode 100644 index 00000000..8bb6e71c --- /dev/null +++ b/lib/web/docusaurus/for_testing/ebooks/test_site/scan.hero @@ -0,0 +1,2 @@ +!!atlas.scan path:"../../collections/test_collection" + diff --git a/lib/web/site/model_sidebar.v b/lib/web/site/model_sidebar.v index ba75ec1f..4868dddc 100644 --- a/lib/web/site/model_sidebar.v +++ b/lib/web/site/model_sidebar.v @@ -93,7 +93,9 @@ fn from_category(cat NavCat) SidebarItem { } } -fn extract_page_id(id string) string { +// extract_page_id extracts the page name from a "collection:page_name" format. +// If the id doesn't contain a colon, returns the id as-is. +pub fn extract_page_id(id string) string { parts := id.split(':') if parts.len == 2 { return parts[1]