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; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy