diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/collect_files.rs | 30 | ||||
| -rw-r--r-- | src/generate_html.rs | 26 |
2 files changed, 40 insertions, 16 deletions
diff --git a/src/collect_files.rs b/src/collect_files.rs index cb785fc..30dcb98 100644 --- a/src/collect_files.rs +++ b/src/collect_files.rs @@ -33,6 +33,7 @@ pub struct Heading { pub name: String, pub url: String, pub level: Level, + pub block_id: usize, } pub struct StaticItem { @@ -199,23 +200,44 @@ impl Website { "md" => { let markdown = std::fs::read_to_string(&source_path).unwrap(); let document = MarkdownDocument::from_str(&markdown); + // Collect headings, check for duplicates. let mut heading_set = HashSet::new(); let mut duplicates = HashSet::new(); - let headings = document.blocks.iter() - .filter_map(|block| if let Block::Heading { line, level } = block { + let mut headings: Vec<_> = document.blocks.iter().enumerate() + .filter_map(|(block_id, block)| if let Block::Heading { line, level } = block { let name = line.to_string(); let url = make_url_safe(strip_appendix(&name)); let level = level.to_owned(); if !heading_set.insert(url.clone()) { duplicates.insert(url.clone()); } - Some(Heading { name, url, level }) + Some(Heading { name, url, level, block_id }) } else { None }).collect(); + + // Namespace any duplicate headings to the parent h1 heading. + let mut parent_url = String::new(); + for heading in &mut headings { + if let Level::Heading1 = heading.level { + parent_url = heading.url.clone(); + } + if duplicates.contains(&heading.url) { + heading.url = format!("{parent_url}-{}", heading.url); + } + } + // Check for duplicates again, and warn if any. + heading_set.clear(); + duplicates.clear(); + for heading in &headings { + if !heading_set.insert(heading.url.clone()) { + duplicates.insert(heading.url.clone()); + } + } for url in duplicates { warn!("Page {full_name:?} contains multiple headings with ID \"#{url}\""); } + if name_url == "+index" { if parents.is_empty() { // This is the index file for the whole site. @@ -351,7 +373,7 @@ impl Website { if !path.starts_with('/') { path = format!("{}{path}", from.parent_url()); } - let path = make_url_safe(&collapse_path(&path)); + path = make_url_safe(&collapse_path(&path)); // Find page with this path in website. for page in &self.pages { diff --git a/src/generate_html.rs b/src/generate_html.rs index 33158a5..306892b 100644 --- a/src/generate_html.rs +++ b/src/generate_html.rs @@ -28,12 +28,10 @@ pub fn generate_html(page: &Page, website: &Website) -> String { None => String::new(), }; let toc = get_table_of_contents(page); - let toc_main = if page.headings.len() > 3 { + let toc_main = if page.headings.len() >= 3 { format!("<details><summary></summary>\n{toc}</details>\n") } else { String::new() }; - let toc_side = if page.headings.len() > 3 { - format!("<div>{toc}</div>\n") - } else { String::new() }; + let toc_side = format!("<div>{toc}</div>\n"); let main = document_to_html(page, website); let main = main.trim(); format!("\ @@ -45,7 +43,8 @@ pub fn generate_html(page: &Page, website: &Website) -> String { {head} </head> <body> -<nav id='toc-side'> +<nav id='outline' class='hidden'> +<h1></h1> {toc_side} </nav> <div id='page'> @@ -107,9 +106,6 @@ pub fn get_html_head(page: &Page, website: &Website) -> String { pub fn get_table_of_contents(page: &Page) -> String { - if page.headings.len() < 3 { - return String::new(); - } let mut toc = String::from("<ul>\n"); let site_name = sanitize_text(&page.name, true); toc.push_str(&format!("<li class='l1'><a href='#title'>{site_name}</a></li>\n")); @@ -146,21 +142,27 @@ pub fn document_to_html(page: &Page, website: &Website) -> String { ($t:expr,$f:expr) => {{ html!("<{}>", $t); $f; html!("</{}>", $t); }}; } wrap!("article", - for block in &page.document.blocks { + for (i, block) in page.document.blocks.iter().enumerate() { match block { Block::Heading { level, line } => { if let Level::Heading1 = level { html!("</article>"); html!("<article>"); + // html!("<nav class='return'><a href='#'></a></nav>"); + }; + // Find namespaced heading ID from headings list. + let url = match page.headings.iter().find(|h| h.block_id == i) { + Some(heading) => heading.url.clone(), + None => unreachable!("Couldn't find heading in headings list"), }; - let id = make_url_safe(strip_appendix(&line.to_string())); + // let url = make_url_safe(strip_appendix(&line.to_string())); let heading_tag = match level { Level::Heading1 => "h1", Level::Heading2 => "h2", Level::Heading3 => "h3", }; - wrap!(heading_tag, format!("id='{id}'"), { - tag!("a", line, format!("href='#{id}'")); + wrap!(heading_tag, format!("id='{url}'"), { + tag!("a", line, format!("href='#{url}'")); }); } Block::Paragraph(line) => tag!("p", line), |
