feat: Add announcement bar configuration
- Add AnnouncementBar struct and field to Configuration - Add announcement.json file generation - Implement play_announcement function for importing announcement config - Improve fix_links to calculate relative paths dynamically - Escape single quotes in YAML frontmatter fields
This commit is contained in:
@@ -6,9 +6,10 @@ import incubaid.herolib.web.site
|
||||
|
||||
pub struct Configuration {
|
||||
pub mut:
|
||||
main Main
|
||||
navbar Navbar
|
||||
footer Footer
|
||||
main Main
|
||||
navbar Navbar
|
||||
footer Footer
|
||||
announcement AnnouncementBar
|
||||
}
|
||||
|
||||
pub struct Main {
|
||||
@@ -75,6 +76,15 @@ pub mut:
|
||||
to string @[omitempty]
|
||||
}
|
||||
|
||||
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']
|
||||
}
|
||||
|
||||
// ... (struct definitions remain the same) ...
|
||||
|
||||
// This function is now a pure transformer: site.SiteConfig -> docusaurus.Configuration
|
||||
@@ -107,7 +117,7 @@ fn new_configuration(site_cfg site.SiteConfig) !Configuration {
|
||||
}
|
||||
|
||||
cfg := Configuration{
|
||||
main: Main{
|
||||
main: Main{
|
||||
title: site_cfg.title
|
||||
tagline: site_cfg.tagline
|
||||
favicon: site_cfg.favicon
|
||||
@@ -137,7 +147,7 @@ fn new_configuration(site_cfg site.SiteConfig) !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
|
||||
@@ -146,10 +156,17 @@ fn new_configuration(site_cfg site.SiteConfig) !Configuration {
|
||||
}
|
||||
items: nav_items
|
||||
}
|
||||
footer: Footer{
|
||||
footer: Footer{
|
||||
style: site_cfg.footer.style
|
||||
links: footer_links
|
||||
}
|
||||
announcement: AnnouncementBar{
|
||||
id: site_cfg.announcement.id
|
||||
content: site_cfg.announcement.content
|
||||
background_color: site_cfg.announcement.background_color
|
||||
text_color: site_cfg.announcement.text_color
|
||||
is_closeable: site_cfg.announcement.is_closeable
|
||||
}
|
||||
}
|
||||
return config_fix(cfg)!
|
||||
}
|
||||
|
||||
@@ -31,6 +31,9 @@ pub fn (mut docsite DocSite) generate() ! {
|
||||
mut footer_file := pathlib.get_file(path: '${cfg_path}/footer.json', create: true)!
|
||||
footer_file.write(json.encode_pretty(docsite.config.footer))!
|
||||
|
||||
mut announcement_file := pathlib.get_file(path: '${cfg_path}/announcement.json', create: true)!
|
||||
announcement_file.write(json.encode_pretty(docsite.config.announcement))!
|
||||
|
||||
docsite.generate_docs()!
|
||||
|
||||
docsite.import()!
|
||||
|
||||
@@ -86,14 +86,18 @@ fn (mut generator SiteGenerator) page_generate(args_ Page) ! {
|
||||
args.title = page_name
|
||||
}
|
||||
}
|
||||
content << "title: '${args.title}'"
|
||||
// Escape single quotes in YAML by doubling them
|
||||
escaped_title := args.title.replace("'", "''")
|
||||
content << "title: '${escaped_title}'"
|
||||
|
||||
if args.description.len > 0 {
|
||||
content << "description: '${args.description}'"
|
||||
escaped_description := args.description.replace("'", "''")
|
||||
content << "description: '${escaped_description}'"
|
||||
}
|
||||
|
||||
if args.slug.len > 0 {
|
||||
content << "slug: '${args.slug}'"
|
||||
escaped_slug := args.slug.replace("'", "''")
|
||||
content << "slug: '${escaped_slug}'"
|
||||
}
|
||||
|
||||
if args.hide_title {
|
||||
@@ -118,7 +122,7 @@ fn (mut generator SiteGenerator) page_generate(args_ Page) ! {
|
||||
}
|
||||
|
||||
// Fix links to account for nested categories
|
||||
page_content = generator.fix_links(page_content)
|
||||
page_content = generator.fix_links(page_content, args.path)
|
||||
|
||||
c += '\n${page_content}\n'
|
||||
|
||||
@@ -190,10 +194,81 @@ fn strip_numeric_prefix(name string) string {
|
||||
return name
|
||||
}
|
||||
|
||||
// Calculate relative path from current directory to target directory
|
||||
// current_dir: directory of the current page (e.g., '' for root, 'tokens' for tokens/, 'farming/advanced' for nested)
|
||||
// target_dir: directory of the target page
|
||||
// page_name: name of the target page
|
||||
// Returns: relative path (e.g., './page', '../dir/page', '../../page')
|
||||
fn calculate_relative_path(current_dir string, target_dir string, page_name string) string {
|
||||
// Both at root level
|
||||
if current_dir == '' && target_dir == '' {
|
||||
return './${page_name}'
|
||||
}
|
||||
|
||||
// Current at root, target in subdirectory
|
||||
if current_dir == '' && target_dir != '' {
|
||||
return './${target_dir}/${page_name}'
|
||||
}
|
||||
|
||||
// Current in subdirectory, target at root
|
||||
if current_dir != '' && target_dir == '' {
|
||||
// Count directory levels to go up
|
||||
levels := current_dir.split('/').len
|
||||
up := '../'.repeat(levels)
|
||||
return '${up}${page_name}'
|
||||
}
|
||||
|
||||
// Both in subdirectories
|
||||
current_parts := current_dir.split('/')
|
||||
target_parts := target_dir.split('/')
|
||||
|
||||
// Find common prefix
|
||||
mut common_len := 0
|
||||
for i := 0; i < current_parts.len && i < target_parts.len; i++ {
|
||||
if current_parts[i] == target_parts[i] {
|
||||
common_len++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate how many levels to go up
|
||||
up_levels := current_parts.len - common_len
|
||||
mut path_parts := []string{}
|
||||
|
||||
// Add ../ for each level up
|
||||
for _ in 0 .. up_levels {
|
||||
path_parts << '..'
|
||||
}
|
||||
|
||||
// Add remaining target path parts
|
||||
for i in common_len .. target_parts.len {
|
||||
path_parts << target_parts[i]
|
||||
}
|
||||
|
||||
// Add page name
|
||||
path_parts << page_name
|
||||
|
||||
return path_parts.join('/')
|
||||
}
|
||||
|
||||
// Fix links to account for nested categories and Docusaurus URL conventions
|
||||
fn (generator SiteGenerator) fix_links(content string) string {
|
||||
fn (generator SiteGenerator) fix_links(content string, current_page_path string) string {
|
||||
mut result := content
|
||||
|
||||
// Extract current page's directory path
|
||||
mut current_dir := current_page_path.trim('/')
|
||||
if current_dir.contains('/') && !current_dir.ends_with('/') {
|
||||
last_part := current_dir.all_after_last('/')
|
||||
if last_part.contains('.') {
|
||||
current_dir = current_dir.all_before_last('/')
|
||||
}
|
||||
}
|
||||
// If path is just a filename or empty, current_dir should be empty (root level)
|
||||
if !current_dir.contains('/') && current_dir.contains('.') {
|
||||
current_dir = ''
|
||||
}
|
||||
|
||||
// Build maps for link fixing
|
||||
mut collection_paths := map[string]string{} // collection -> directory path (for nested collections)
|
||||
mut page_to_path := map[string]string{} // page_name -> full directory path in Docusaurus
|
||||
@@ -275,25 +350,20 @@ fn (generator SiteGenerator) fix_links(content string) string {
|
||||
// STEP 3: Fix same-collection links: ./page -> correct path based on Docusaurus structure
|
||||
for page_name, target_dir in page_to_path {
|
||||
old_link := './${page_name}'
|
||||
if result.contains(old_link) && target_dir != '' {
|
||||
new_link := '../${target_dir}/${page_name}'
|
||||
if result.contains(old_link) {
|
||||
new_link := calculate_relative_path(current_dir, target_dir, page_name)
|
||||
result = result.replace(old_link, new_link)
|
||||
}
|
||||
}
|
||||
|
||||
// STEP 4: Convert collection:page format to proper relative paths
|
||||
// Pattern: collection:page_name -> ../dir/page_name
|
||||
// Calculate relative path from current page to target page
|
||||
for collection_page, target_dir in collection_page_map {
|
||||
old_pattern := collection_page
|
||||
if result.contains(old_pattern) {
|
||||
// Extract just the page name from "collection:page"
|
||||
page_name := collection_page.all_after(':')
|
||||
mut new_link := ''
|
||||
if target_dir != '' {
|
||||
new_link = '../${target_dir}/${page_name}'
|
||||
} else {
|
||||
new_link = './${page_name}'
|
||||
}
|
||||
new_link := calculate_relative_path(current_dir, target_dir, page_name)
|
||||
result = result.replace(old_pattern, new_link)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,18 @@ pub mut:
|
||||
|
||||
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
|
||||
@@ -73,7 +85,7 @@ pub mut:
|
||||
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
|
||||
// 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
|
||||
|
||||
@@ -50,6 +50,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
play_import(mut plbook, mut config)!
|
||||
play_menu(mut plbook, mut config)!
|
||||
play_footer(mut plbook, mut config)!
|
||||
play_announcement(mut plbook, mut config)!
|
||||
play_publish(mut plbook, mut config)!
|
||||
play_publish_dev(mut plbook, mut config)!
|
||||
play_pages(mut plbook, mut website)!
|
||||
@@ -178,6 +179,25 @@ fn play_footer(mut plbook PlayBook, mut config SiteConfig) ! {
|
||||
}
|
||||
}
|
||||
|
||||
fn play_announcement(mut plbook PlayBook, mut config SiteConfig) ! {
|
||||
mut announcement_actions := plbook.find(filter: 'site.announcement')!
|
||||
if announcement_actions.len > 0 {
|
||||
// Only process the first announcement action
|
||||
mut action := announcement_actions[0]
|
||||
mut p := action.params
|
||||
|
||||
config.announcement = AnnouncementBar{
|
||||
id: p.get_default('id', 'announcement')!
|
||||
content: p.get_default('content', '')!
|
||||
background_color: p.get_default('background_color', '#20232a')!
|
||||
text_color: p.get_default('text_color', '#fff')!
|
||||
is_closeable: p.get_default_true('is_closeable')
|
||||
}
|
||||
|
||||
action.done = true // Mark the action as done
|
||||
}
|
||||
}
|
||||
|
||||
fn play_publish(mut plbook PlayBook, mut config SiteConfig) ! {
|
||||
mut build_dest_actions := plbook.find(filter: 'site.publish')!
|
||||
for mut action in build_dest_actions {
|
||||
|
||||
Reference in New Issue
Block a user