use maud::{Markup, html}; use maudit::{ content::MarkdownHeading, route::{PageContext, RouteExt}, }; use crate::{ content::{DocsContent, DocsSection}, routes::{DocsPage, DocsPageParams}, }; pub fn left_sidebar(ctx: &mut PageContext) -> Markup { let content = ctx.content.get_source::("docs"); let mut sections = std::collections::HashMap::new(); for entry in content.entries.iter() { if let Some(section) = &entry.data(ctx).section { sections.entry(section).or_insert_with(Vec::new).push(entry); } } let mut sections: Vec<_> = sections.into_iter().collect(); // TODO: Implement sorting on the enum ord itself? sections.sort_by_key(|(section, _)| { // Define sort order match section { DocsSection::GettingStarted => 0, DocsSection::CoreConcepts => 1, DocsSection::Guide => 2, DocsSection::Advanced => 3, } }); let static_links: Vec<(&str, &str)> = vec![ ("Reference", "https://docs.rs/maudit"), ( "Examples", "https://github.com/bruits/maudit/tree/main/examples", ), ]; let entries = sections.iter().map(|(section, entries)| { html! { li.mb-6.sm:mb-4 { h2.text-xl.sm:text-lg.font-bold { (section) } ul { @for entry in entries { @let url = DocsPage.url(DocsPageParams { slug: entry.id.clone() }); @let is_current_page = url == *ctx.current_path; li { @let base_classes = "block py-2 sm:py-1 px-4 sm:px-3 text-lg sm:text-base font-medium sm:font-normal transition-colors border-b border-borders sm:border-0"; @let conditional_classes = if is_current_page { "text-brand-red sm:border-l-2 sm:border-l-brand-red" } else { "text-our-black hover:text-brand-red sm:border-l-2 sm:border-l-borders sm:hover:border-l-brand-red" }; a class=(format!("{} {}", base_classes, conditional_classes)) href=(url) { (entry.data(ctx).title) } } } } } } }); html! { ul.mb-6.sm:mb-4.space-y-0.sm:space-y-1 { @for (name, link) in static_links { li { a.block.py-2.sm:py-0.px-4.sm:px-0.text-xl.sm:text-lg.font-medium.text-our-black.border-b.border-borders.sm:border-0.transition-colors."hover:text-brand-red".sm:bg-transparent.sm:hover:bg-transparent href=(link) { (name) } } } } ul.space-y-1 { @for entry in entries { (entry) } } } } pub fn right_sidebar(headings: &[MarkdownHeading]) -> Markup { let mut html_headings: Vec> = Vec::new(); let mut i = 0; let mut seen_h2 = false; while i < headings.len() { let heading = &headings[i]; let (pad, border) = match heading.level { 2 => ("pl-0", ""), // h2 3 => ("pl-4", "sm:border-l-2 sm:border-borders"), // h3 4 => ("pl-8", "sm:border-l-2 sm:border-borders"), // h4 5 => ("pl-12", "sm:border-l-2 sm:border-borders"), // h5 6 => ("pl-16", "sm:border-l-2 sm:border-borders"), // h6 _ => ("pl-0", ""), // fallback }; let next_level = if i + 1 < headings.len() { headings[i + 1].level } else { 0 }; let margin_top = if heading.level == 2 && next_level > 2 && seen_h2 { "mt-4" } else { "" }; if heading.level == 2 { seen_h2 = true; } html_headings.push(html! { li.(border).(margin_top) { a class=(format!("block py-1 px-3 sm:py-0 text-lg sm:text-base transition-colors hover:bg-gray-50 sm:hover:bg-transparent hover:text-brand-red border-b border-borders sm:border-b-0 {}", pad)) href=(format!("#{}", heading.id)) { (heading.title) } } }); i += 1; } html!( h2.text-xl.sm:text-lg.font-bold.mb-4.sm:mb-0 { "On This Page" } nav.sticky.top-8 { ul { @for heading in html_headings { (heading) } } } ) }