From e19d32150d43970bed59bb1f3b44f848004f8ab1 Mon Sep 17 00:00:00 2001 From: Dan <39170265+chillenberger@users.noreply.github.com> Date: Mon, 8 Jan 2024 14:45:12 -0700 Subject: [PATCH 1/5] fix links for docs headers --- pgml-dashboard/src/templates/docs.rs | 6 +- pgml-dashboard/src/utils/markdown.rs | 110 +++++++++++++++++---------- 2 files changed, 75 insertions(+), 41 deletions(-) diff --git a/pgml-dashboard/src/templates/docs.rs b/pgml-dashboard/src/templates/docs.rs index ad18d2215..e3e56424d 100644 --- a/pgml-dashboard/src/templates/docs.rs +++ b/pgml-dashboard/src/templates/docs.rs @@ -1,5 +1,6 @@ use sailfish::TemplateOnce; use serde::{Deserialize, Serialize}; +use convert_case; use crate::utils::markdown::SearchResult; @@ -27,7 +28,10 @@ impl TocLink { /// * `title` - The title of the link. /// pub fn new(title: &str, counter: usize) -> TocLink { - let id = format!("header-{}", counter); + + let conv = convert_case::Converter::new().to_case(convert_case::Case::Kebab); + let id = conv.convert(title.to_string()); + let id = format!("{}{}", id, if counter > 0 { format!("-{counter}")} else {String::new()}); TocLink { title: title.to_string(), diff --git a/pgml-dashboard/src/utils/markdown.rs b/pgml-dashboard/src/utils/markdown.rs index fb0557aa2..19d197130 100644 --- a/pgml-dashboard/src/utils/markdown.rs +++ b/pgml-dashboard/src/utils/markdown.rs @@ -22,18 +22,20 @@ use tantivy::query::{QueryParser, RegexQuery}; use tantivy::schema::*; use tantivy::tokenizer::{LowerCaser, NgramTokenizer, TextAnalyzer}; use tantivy::{Index, IndexReader, SnippetGenerator}; -use url::Url; +use convert_case; + +use std::sync::Mutex; use std::fmt; pub struct MarkdownHeadings { - counter: Arc, + header_map: Arc>>, } impl Default for MarkdownHeadings { fn default() -> Self { Self { - counter: Arc::new(AtomicUsize::new(0)), + header_map: Arc::new(Mutex::new(HashMap::new())) } } } @@ -46,9 +48,17 @@ impl MarkdownHeadings { impl HeadingAdapter for MarkdownHeadings { fn enter(&self, meta: &HeadingMeta) -> String { - // let id = meta.content.to_case(convert_case::Case::Kebab); - let id = self.counter.fetch_add(1, Ordering::SeqCst); - let id = format!("header-{}", id); + let conv = convert_case::Converter::new().to_case(convert_case::Case::Kebab); + let id = conv.convert(meta.content.to_string()); + + let index = match self.header_map.lock().unwrap().get(&id) { + Some(value) => value + 1, + _ => 0 + }; + + let id = TocLink::new(&id, index).id; + + self.header_map.lock().unwrap().insert(id.clone(), index); match meta.level { 1 => format!(r#"

"#), @@ -335,37 +345,38 @@ where Ok(()) } -pub fn nest_relative_links(node: &mut markdown::mdast::Node, path: &PathBuf) { - let _ = iter_mut_all(node, &mut |node| { - if let markdown::mdast::Node::Link(ref mut link) = node { - match Url::parse(&link.url) { - Ok(url) => { - if !url.has_host() { - let mut url_path = url.path().to_string(); - let url_path_path = Path::new(&url_path); - match url_path_path.extension() { - Some(ext) => { - if ext.to_str() == Some(".md") { - let base = url_path_path.with_extension(""); - url_path = base.into_os_string().into_string().unwrap(); - } - } - _ => { - warn!("not markdown path: {:?}", path) - } - } - link.url = path.join(url_path).into_os_string().into_string().unwrap(); - } - } - Err(e) => { - warn!("could not parse url in markdown: {}", e) - } - } - } - - Ok(()) - }); -} +// pub fn nest_relative_links(node: &mut markdown::mdast::Node, path: &PathBuf) { +// let _ = iter_mut_all(node, &mut |node| { +// println!("link node: {:?}", node); +// if let markdown::mdast::Node::Link(ref mut link) = node { +// match Url::parse(&link.url) { +// Ok(url) => { +// if !url.has_host() { +// let mut url_path = url.path().to_string(); +// let url_path_path = Path::new(&url_path); +// match url_path_path.extension() { +// Some(ext) => { +// if ext.to_str() == Some(".md") { +// let base = url_path_path.with_extension(""); +// url_path = base.into_os_string().into_string().unwrap(); +// } +// } +// _ => { +// warn!("not markdown path: {:?}", path) +// } +// } +// link.url = path.join(url_path).into_os_string().into_string().unwrap(); +// } +// } +// Err(e) => { +// warn!("could not parse url in markdown: {}", e) +// } +// } +// } + +// Ok(()) +// }); +// } /// Get the title of the article. /// @@ -462,11 +473,10 @@ pub fn wrap_tables<'a>(root: &'a AstNode<'a>, arena: &'a Arena>) -> /// pub fn get_toc<'a>(root: &'a AstNode<'a>) -> anyhow::Result> { let mut links = Vec::new(); - let mut header_counter = 0; + let mut header_count: HashMap = HashMap::new(); iter_nodes(root, &mut |node| { if let NodeValue::Heading(header) = &node.data.borrow().value { - header_counter += 1; if header.level != 1 { let sibling = match node.first_child() { Some(child) => child, @@ -476,7 +486,14 @@ pub fn get_toc<'a>(root: &'a AstNode<'a>) -> anyhow::Result> { } }; if let NodeValue::Text(text) = &sibling.data.borrow().value { - links.push(TocLink::new(text, header_counter - 1).level(header.level)); + let index = match header_count.get(text) { + Some(index) => index + 1, + _ => 0 + }; + + header_count.insert(text.clone(), index); + + links.push(TocLink::new(text, index).level(header.level)); return Ok(false); } } @@ -760,11 +777,24 @@ pub fn mkdocs<'a>(root: &'a AstNode<'a>, arena: &'a Arena>) -> anyho let path = Path::new(link.url.as_str()); if path.is_relative() { + let fragment = match link.url.find("#") { + Some(index) => link.url[index..link.url.len()].to_string(), + _ => "".to_string() + }; + + for _ in 0..fragment.len() { + link.url.pop(); + } + if link.url.ends_with(".md") { for _ in 0..".md".len() { link.url.pop(); } } + + for c in fragment.chars() { + link.url.push(c) + } } Ok(true) From 3d1fd7ec6935a517dfbc4db7ef2c14824b632e4e Mon Sep 17 00:00:00 2001 From: Dan <39170265+chillenberger@users.noreply.github.com> Date: Mon, 8 Jan 2024 17:48:44 -0700 Subject: [PATCH 2/5] prevent css collision, change url on header or toc click --- pgml-dashboard/src/templates/docs.rs | 49 +++++++++++-- pgml-dashboard/src/utils/markdown.rs | 68 ++++++------------- .../static/css/scss/pages/_docs.scss | 6 ++ pgml-dashboard/static/js/docs-toc.js | 22 +++++- pgml-dashboard/templates/components/toc.html | 2 +- pgml-dashboard/templates/layout/nav/toc.html | 2 +- 6 files changed, 94 insertions(+), 55 deletions(-) diff --git a/pgml-dashboard/src/templates/docs.rs b/pgml-dashboard/src/templates/docs.rs index e3e56424d..9ff68abfd 100644 --- a/pgml-dashboard/src/templates/docs.rs +++ b/pgml-dashboard/src/templates/docs.rs @@ -1,6 +1,9 @@ use sailfish::TemplateOnce; use serde::{Deserialize, Serialize}; use convert_case; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; +use lazy_static::lazy_static; use crate::utils::markdown::SearchResult; @@ -12,6 +15,26 @@ pub struct Search { pub results: Vec, } +lazy_static! { + static ref CMS_IDENTIFIER: CmsIdentifier = CmsIdentifier::new(); +} + +// Prevent css collisions in cms header ids. +pub struct CmsIdentifier { + pub id: String +} + +impl CmsIdentifier { + pub fn new() -> CmsIdentifier { + let mut s = DefaultHasher::new(); + "cms header".hash(&mut s); + + CmsIdentifier { + id: s.finish().to_string() + } + } +} + /// Table of contents link. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct TocLink { @@ -26,12 +49,14 @@ impl TocLink { /// # Arguments /// /// * `title` - The title of the link. - /// - pub fn new(title: &str, counter: usize) -> TocLink { - + /// * `counter` - The number of times that header is in the document + /// + pub fn new(title: &str, counter: usize) -> TocLink { let conv = convert_case::Converter::new().to_case(convert_case::Case::Kebab); let id = conv.convert(title.to_string()); - let id = format!("{}{}", id, if counter > 0 { format!("-{counter}")} else {String::new()}); + + // gitbook style id's + let id = format!("{}{}-{}", id, if counter > 0 { format!("-{counter}")} else {String::new()}, CMS_IDENTIFIER.id); TocLink { title: title.to_string(), @@ -47,6 +72,22 @@ impl TocLink { self.level = level; self } + + /// Converts gitbook link fragment to toc header + pub fn from_fragment(link: String) -> TocLink { + match link.is_empty() { + true => TocLink { + title: String::new(), + id: String::new(), + level: 0, + }, + _ => TocLink { + title: link.clone(), + id: format!("#{}-{}", link.clone(), CMS_IDENTIFIER.id), + level: 0 + } + } + } } /// Table of contents template. diff --git a/pgml-dashboard/src/utils/markdown.rs b/pgml-dashboard/src/utils/markdown.rs index 19d197130..4cc8f4a15 100644 --- a/pgml-dashboard/src/utils/markdown.rs +++ b/pgml-dashboard/src/utils/markdown.rs @@ -46,6 +46,10 @@ impl MarkdownHeadings { } } +/// Sets the document headers +/// +/// uses toclink to ensure header id matches what the TOC expects +/// impl HeadingAdapter for MarkdownHeadings { fn enter(&self, meta: &HeadingMeta) -> String { let conv = convert_case::Converter::new().to_case(convert_case::Case::Kebab); @@ -61,24 +65,24 @@ impl HeadingAdapter for MarkdownHeadings { self.header_map.lock().unwrap().insert(id.clone(), index); match meta.level { - 1 => format!(r#"

"#), - 2 => format!(r#"

"#), - 3 => format!(r#"

"#), - 4 => format!(r#"

"#), - 5 => format!(r#"

"#), - 6 => format!(r#"
"#), + 1 => format!(r##"

"##), + 2 => format!(r##"

"##), + 3 => format!(r##"

"##), + 4 => format!(r##"

"##), + 5 => format!(r##"
"##), + 6 => format!(r##"
"##), _ => unreachable!(), } } fn exit(&self, meta: &HeadingMeta) -> String { match meta.level { - 1 => r#"
"#, - 2 => r#"
"#, - 3 => r#"

"#, - 4 => r#"

"#, - 5 => r#"

"#, - 6 => r#"

"#, + 1 => r#"

"#, + 2 => r#""#, + 3 => r#""#, + 4 => r#""#, + 5 => r#""#, + 6 => r#""#, _ => unreachable!(), } .into() @@ -345,39 +349,6 @@ where Ok(()) } -// pub fn nest_relative_links(node: &mut markdown::mdast::Node, path: &PathBuf) { -// let _ = iter_mut_all(node, &mut |node| { -// println!("link node: {:?}", node); -// if let markdown::mdast::Node::Link(ref mut link) = node { -// match Url::parse(&link.url) { -// Ok(url) => { -// if !url.has_host() { -// let mut url_path = url.path().to_string(); -// let url_path_path = Path::new(&url_path); -// match url_path_path.extension() { -// Some(ext) => { -// if ext.to_str() == Some(".md") { -// let base = url_path_path.with_extension(""); -// url_path = base.into_os_string().into_string().unwrap(); -// } -// } -// _ => { -// warn!("not markdown path: {:?}", path) -// } -// } -// link.url = path.join(url_path).into_os_string().into_string().unwrap(); -// } -// } -// Err(e) => { -// warn!("could not parse url in markdown: {}", e) -// } -// } -// } - -// Ok(()) -// }); -// } - /// Get the title of the article. /// /// # Arguments @@ -778,11 +749,11 @@ pub fn mkdocs<'a>(root: &'a AstNode<'a>, arena: &'a Arena>) -> anyho if path.is_relative() { let fragment = match link.url.find("#") { - Some(index) => link.url[index..link.url.len()].to_string(), + Some(index) => link.url[index + 1..link.url.len()].to_string(), _ => "".to_string() }; - for _ in 0..fragment.len() { + for _ in 0..fragment.len() + 1 { link.url.pop(); } @@ -792,7 +763,8 @@ pub fn mkdocs<'a>(root: &'a AstNode<'a>, arena: &'a Arena>) -> anyho } } - for c in fragment.chars() { + let header_id = TocLink::from_fragment(fragment).id; + for c in header_id.chars() { link.url.push(c) } } diff --git a/pgml-dashboard/static/css/scss/pages/_docs.scss b/pgml-dashboard/static/css/scss/pages/_docs.scss index 4fca4c7ae..6390c8bb4 100644 --- a/pgml-dashboard/static/css/scss/pages/_docs.scss +++ b/pgml-dashboard/static/css/scss/pages/_docs.scss @@ -206,5 +206,11 @@ display: contents !important; } } + + h1, h2, h3, h4, h5, h6 { + a { + color: inherit !important; + } + } } diff --git a/pgml-dashboard/static/js/docs-toc.js b/pgml-dashboard/static/js/docs-toc.js index 25d83c382..c6df7d63f 100644 --- a/pgml-dashboard/static/js/docs-toc.js +++ b/pgml-dashboard/static/js/docs-toc.js @@ -7,7 +7,13 @@ export default class extends Controller { this.scrollSpyAppend(); } - scrollSpyAppend() { + scrollSpyAppend(e) { + // intercept click event callback so we can set the url + if( e && e.type == "click") { + console.log("append click") + this.clicked(e) + } + const spy = new bootstrap.ScrollSpy(document.body, { target: '#toc-nav', smoothScroll: true, @@ -15,4 +21,18 @@ export default class extends Controller { threshold: [1], }) } + + clicked(e) { + + console.log("clicked clicked") + let href = e.target.attributes.href.nodeValue; + if (href) { + if (href.startsWith("#")) { + let hash = href.slice(1); + if (window.location.hash != hash) { + window.location.hash = hash + } + } + } + } } diff --git a/pgml-dashboard/templates/components/toc.html b/pgml-dashboard/templates/components/toc.html index 88dbb9d89..968824f0e 100644 --- a/pgml-dashboard/templates/components/toc.html +++ b/pgml-dashboard/templates/components/toc.html @@ -9,7 +9,7 @@
Table of Contents
<% for link in links.iter() { %> diff --git a/pgml-dashboard/templates/layout/nav/toc.html b/pgml-dashboard/templates/layout/nav/toc.html index 65d7ebe0c..08feae8ea 100644 --- a/pgml-dashboard/templates/layout/nav/toc.html +++ b/pgml-dashboard/templates/layout/nav/toc.html @@ -10,7 +10,7 @@
Table of Contents
<% for link in toc_links.iter() { %> From 0e6adb22d99c519afb52c508849697fcfea4705d Mon Sep 17 00:00:00 2001 From: Dan <39170265+chillenberger@users.noreply.github.com> Date: Tue, 9 Jan 2024 10:19:22 -0700 Subject: [PATCH 3/5] clean up scrollspy, remove dead code --- pgml-dashboard/src/templates/docs.rs | 7 ------- pgml-dashboard/static/js/docs-toc.js | 10 +--------- pgml-dashboard/templates/components/toc.html | 18 ------------------ pgml-dashboard/templates/layout/nav/toc.html | 2 +- 4 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 pgml-dashboard/templates/components/toc.html diff --git a/pgml-dashboard/src/templates/docs.rs b/pgml-dashboard/src/templates/docs.rs index 9ff68abfd..75a39e611 100644 --- a/pgml-dashboard/src/templates/docs.rs +++ b/pgml-dashboard/src/templates/docs.rs @@ -89,10 +89,3 @@ impl TocLink { } } } - -/// Table of contents template. -#[derive(TemplateOnce)] -#[template(path = "components/toc.html")] -pub struct Toc { - pub links: Vec, -} diff --git a/pgml-dashboard/static/js/docs-toc.js b/pgml-dashboard/static/js/docs-toc.js index c6df7d63f..3d0ee90b3 100644 --- a/pgml-dashboard/static/js/docs-toc.js +++ b/pgml-dashboard/static/js/docs-toc.js @@ -8,12 +8,6 @@ export default class extends Controller { } scrollSpyAppend(e) { - // intercept click event callback so we can set the url - if( e && e.type == "click") { - console.log("append click") - this.clicked(e) - } - const spy = new bootstrap.ScrollSpy(document.body, { target: '#toc-nav', smoothScroll: true, @@ -22,9 +16,7 @@ export default class extends Controller { }) } - clicked(e) { - - console.log("clicked clicked") + setUrlFragment(e) { let href = e.target.attributes.href.nodeValue; if (href) { if (href.startsWith("#")) { diff --git a/pgml-dashboard/templates/components/toc.html b/pgml-dashboard/templates/components/toc.html deleted file mode 100644 index 968824f0e..000000000 --- a/pgml-dashboard/templates/components/toc.html +++ /dev/null @@ -1,18 +0,0 @@ - -<% if !links.is_empty() { %> -
Table of Contents
- - -
- <% for link in links.iter() { %> - - <% } %> -
-<% } %> diff --git a/pgml-dashboard/templates/layout/nav/toc.html b/pgml-dashboard/templates/layout/nav/toc.html index 08feae8ea..6c851deee 100644 --- a/pgml-dashboard/templates/layout/nav/toc.html +++ b/pgml-dashboard/templates/layout/nav/toc.html @@ -10,7 +10,7 @@
Table of Contents
<% for link in toc_links.iter() { %> From bfdcce2094263ae1c931d2e6573a917b218074f7 Mon Sep 17 00:00:00 2001 From: Dan <39170265+chillenberger@users.noreply.github.com> Date: Tue, 9 Jan 2024 10:44:11 -0700 Subject: [PATCH 4/5] fmt, fix cms tests --- pgml-dashboard/src/api/cms.rs | 4 ++-- pgml-dashboard/src/templates/docs.rs | 35 +++++++++++++++++----------- pgml-dashboard/src/utils/markdown.rs | 19 +++++++-------- pgml-dashboard/static/js/docs-toc.js | 2 +- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/pgml-dashboard/src/api/cms.rs b/pgml-dashboard/src/api/cms.rs index 756b6514f..f40d4204f 100644 --- a/pgml-dashboard/src/api/cms.rs +++ b/pgml-dashboard/src/api/cms.rs @@ -557,7 +557,7 @@ This is the end of the markdown #[sqlx::test] async fn render_blogs_test() { let client = Client::tracked(rocket().await).await.unwrap(); - let blog: Collection = Collection::new("Blog", true); + let blog: Collection = Collection::new("Blog", true, HashMap::new()); for path in blog.index { let req = client.get(path.clone().href); @@ -579,7 +579,7 @@ This is the end of the markdown #[sqlx::test] async fn render_guides_test() { let client = Client::tracked(rocket().await).await.unwrap(); - let docs: Collection = Collection::new("Docs", true); + let docs: Collection = Collection::new("Docs", true, HashMap::new()); for path in docs.index { let req = client.get(path.clone().href); diff --git a/pgml-dashboard/src/templates/docs.rs b/pgml-dashboard/src/templates/docs.rs index 75a39e611..8c735c237 100644 --- a/pgml-dashboard/src/templates/docs.rs +++ b/pgml-dashboard/src/templates/docs.rs @@ -1,9 +1,9 @@ +use convert_case; +use lazy_static::lazy_static; use sailfish::TemplateOnce; use serde::{Deserialize, Serialize}; -use convert_case; use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; -use lazy_static::lazy_static; use crate::utils::markdown::SearchResult; @@ -19,9 +19,9 @@ lazy_static! { static ref CMS_IDENTIFIER: CmsIdentifier = CmsIdentifier::new(); } -// Prevent css collisions in cms header ids. +// Prevent css collisions in cms header ids. pub struct CmsIdentifier { - pub id: String + pub id: String, } impl CmsIdentifier { @@ -30,7 +30,7 @@ impl CmsIdentifier { "cms header".hash(&mut s); CmsIdentifier { - id: s.finish().to_string() + id: s.finish().to_string(), } } } @@ -50,13 +50,22 @@ impl TocLink { /// /// * `title` - The title of the link. /// * `counter` - The number of times that header is in the document - /// - pub fn new(title: &str, counter: usize) -> TocLink { + /// + pub fn new(title: &str, counter: usize) -> TocLink { let conv = convert_case::Converter::new().to_case(convert_case::Case::Kebab); let id = conv.convert(title.to_string()); // gitbook style id's - let id = format!("{}{}-{}", id, if counter > 0 { format!("-{counter}")} else {String::new()}, CMS_IDENTIFIER.id); + let id = format!( + "{}{}-{}", + id, + if counter > 0 { + format!("-{counter}") + } else { + String::new() + }, + CMS_IDENTIFIER.id + ); TocLink { title: title.to_string(), @@ -77,15 +86,15 @@ impl TocLink { pub fn from_fragment(link: String) -> TocLink { match link.is_empty() { true => TocLink { - title: String::new(), + title: String::new(), id: String::new(), level: 0, }, _ => TocLink { - title: link.clone(), - id: format!("#{}-{}", link.clone(), CMS_IDENTIFIER.id), - level: 0 - } + title: link.clone(), + id: format!("#{}-{}", link.clone(), CMS_IDENTIFIER.id), + level: 0, + }, } } } diff --git a/pgml-dashboard/src/utils/markdown.rs b/pgml-dashboard/src/utils/markdown.rs index 9b9f67c20..31f0ef824 100644 --- a/pgml-dashboard/src/utils/markdown.rs +++ b/pgml-dashboard/src/utils/markdown.rs @@ -3,10 +3,7 @@ use crate::{templates::docs::TocLink, utils::config}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::path::{Path, PathBuf}; -use std::sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, -}; +use std::sync::Arc; use anyhow::Result; use comrak::{ @@ -15,6 +12,7 @@ use comrak::{ nodes::{Ast, AstNode, NodeValue}, parse_document, Arena, ComrakExtensionOptions, ComrakOptions, ComrakRenderOptions, }; +use convert_case; use itertools::Itertools; use regex::Regex; use tantivy::collector::TopDocs; @@ -22,7 +20,6 @@ use tantivy::query::{QueryParser, RegexQuery}; use tantivy::schema::*; use tantivy::tokenizer::{LowerCaser, NgramTokenizer, TextAnalyzer}; use tantivy::{Index, IndexReader, SnippetGenerator}; -use convert_case; use std::sync::Mutex; @@ -35,7 +32,7 @@ pub struct MarkdownHeadings { impl Default for MarkdownHeadings { fn default() -> Self { Self { - header_map: Arc::new(Mutex::new(HashMap::new())) + header_map: Arc::new(Mutex::new(HashMap::new())), } } } @@ -47,9 +44,9 @@ impl MarkdownHeadings { } /// Sets the document headers -/// +/// /// uses toclink to ensure header id matches what the TOC expects -/// +/// impl HeadingAdapter for MarkdownHeadings { fn enter(&self, meta: &HeadingMeta) -> String { let conv = convert_case::Converter::new().to_case(convert_case::Case::Kebab); @@ -57,7 +54,7 @@ impl HeadingAdapter for MarkdownHeadings { let index = match self.header_map.lock().unwrap().get(&id) { Some(value) => value + 1, - _ => 0 + _ => 0, }; let id = TocLink::new(&id, index).id; @@ -459,7 +456,7 @@ pub fn get_toc<'a>(root: &'a AstNode<'a>) -> anyhow::Result> { if let NodeValue::Text(text) = &sibling.data.borrow().value { let index = match header_count.get(text) { Some(index) => index + 1, - _ => 0 + _ => 0, }; header_count.insert(text.clone(), index); @@ -743,7 +740,7 @@ pub fn mkdocs<'a>(root: &'a AstNode<'a>, arena: &'a Arena>) -> anyho if path.is_relative() { let fragment = match link.url.find("#") { Some(index) => link.url[index + 1..link.url.len()].to_string(), - _ => "".to_string() + _ => "".to_string(), }; for _ in 0..fragment.len() + 1 { diff --git a/pgml-dashboard/static/js/docs-toc.js b/pgml-dashboard/static/js/docs-toc.js index 3d0ee90b3..496278ae4 100644 --- a/pgml-dashboard/static/js/docs-toc.js +++ b/pgml-dashboard/static/js/docs-toc.js @@ -7,7 +7,7 @@ export default class extends Controller { this.scrollSpyAppend(); } - scrollSpyAppend(e) { + scrollSpyAppend() { const spy = new bootstrap.ScrollSpy(document.body, { target: '#toc-nav', smoothScroll: true, From 032397c1c92a8376f7c752c578f42f2df9f3fd5e Mon Sep 17 00:00:00 2001 From: Dan <39170265+chillenberger@users.noreply.github.com> Date: Tue, 9 Jan 2024 11:15:47 -0700 Subject: [PATCH 5/5] add indicator headings are clickable --- pgml-dashboard/src/utils/markdown.rs | 3 +-- pgml-dashboard/static/css/scss/pages/_docs.scss | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/pgml-dashboard/src/utils/markdown.rs b/pgml-dashboard/src/utils/markdown.rs index 31f0ef824..949bf7b17 100644 --- a/pgml-dashboard/src/utils/markdown.rs +++ b/pgml-dashboard/src/utils/markdown.rs @@ -56,11 +56,10 @@ impl HeadingAdapter for MarkdownHeadings { Some(value) => value + 1, _ => 0, }; + self.header_map.lock().unwrap().insert(id.clone(), index); let id = TocLink::new(&id, index).id; - self.header_map.lock().unwrap().insert(id.clone(), index); - match meta.level { 1 => format!(r##"

"##), 2 => format!(r##"

"##), diff --git a/pgml-dashboard/static/css/scss/pages/_docs.scss b/pgml-dashboard/static/css/scss/pages/_docs.scss index 6390c8bb4..e7890ada0 100644 --- a/pgml-dashboard/static/css/scss/pages/_docs.scss +++ b/pgml-dashboard/static/css/scss/pages/_docs.scss @@ -208,6 +208,16 @@ } h1, h2, h3, h4, h5, h6 { + scroll-margin-top: 108px; + + &:hover { + &:after { + content: '#'; + margin-left: 0.2em; + position: absolute; + } + } + a { color: inherit !important; }