Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb987f83

Browse files
Dan doc link fix (#1281)
1 parentd9333f2 commitb987f83

File tree

7 files changed

+140
-85
lines changed

7 files changed

+140
-85
lines changed

‎pgml-dashboard/src/api/cms.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ This is the end of the markdown
557557
#[sqlx::test]
558558
asyncfnrender_blogs_test(){
559559
let client =Client::tracked(rocket().await).await.unwrap();
560-
let blog:Collection =Collection::new("Blog",true);
560+
let blog:Collection =Collection::new("Blog",true,HashMap::new());
561561

562562
for pathin blog.index{
563563
let req = client.get(path.clone().href);
@@ -579,7 +579,7 @@ This is the end of the markdown
579579
#[sqlx::test]
580580
asyncfnrender_guides_test(){
581581
let client =Client::tracked(rocket().await).await.unwrap();
582-
let docs:Collection =Collection::new("Docs",true);
582+
let docs:Collection =Collection::new("Docs",true,HashMap::new());
583583

584584
for pathin docs.index{
585585
let req = client.get(path.clone().href);

‎pgml-dashboard/src/templates/docs.rs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
use convert_case;
2+
use lazy_static::lazy_static;
13
use sailfish::TemplateOnce;
24
use serde::{Deserialize,Serialize};
5+
use std::collections::hash_map::DefaultHasher;
6+
use std::hash::{Hash,Hasher};
37

48
usecrate::utils::markdown::SearchResult;
59

@@ -11,6 +15,26 @@ pub struct Search {
1115
pubresults:Vec<SearchResult>,
1216
}
1317

18+
lazy_static!{
19+
static refCMS_IDENTIFIER:CmsIdentifier =CmsIdentifier::new();
20+
}
21+
22+
// Prevent css collisions in cms header ids.
23+
pubstructCmsIdentifier{
24+
pubid:String,
25+
}
26+
27+
implCmsIdentifier{
28+
pubfnnew() ->CmsIdentifier{
29+
letmut s =DefaultHasher::new();
30+
"cms header".hash(&mut s);
31+
32+
CmsIdentifier{
33+
id: s.finish().to_string(),
34+
}
35+
}
36+
}
37+
1438
/// Table of contents link.
1539
#[derive(Clone,Debug,Serialize,Deserialize)]
1640
pubstructTocLink{
@@ -25,9 +49,23 @@ impl TocLink {
2549
/// # Arguments
2650
///
2751
/// * `title` - The title of the link.
52+
/// * `counter` - The number of times that header is in the document
2853
///
2954
pubfnnew(title:&str,counter:usize) ->TocLink{
30-
let id =format!("header-{}", counter);
55+
let conv = convert_case::Converter::new().to_case(convert_case::Case::Kebab);
56+
let id = conv.convert(title.to_string());
57+
58+
// gitbook style id's
59+
let id =format!(
60+
"{}{}-{}",
61+
id,
62+
if counter >0{
63+
format!("-{counter}")
64+
} else{
65+
String::new()
66+
},
67+
CMS_IDENTIFIER.id
68+
);
3169

3270
TocLink{
3371
title: title.to_string(),
@@ -43,11 +81,20 @@ impl TocLink {
4381
self.level = level;
4482
self
4583
}
46-
}
4784

48-
/// Table of contents template.
49-
#[derive(TemplateOnce)]
50-
#[template(path ="components/toc.html")]
51-
pubstructToc{
52-
publinks:Vec<TocLink>,
85+
/// Converts gitbook link fragment to toc header
86+
pubfnfrom_fragment(link:String) ->TocLink{
87+
match link.is_empty(){
88+
true =>TocLink{
89+
title:String::new(),
90+
id:String::new(),
91+
level:0,
92+
},
93+
_ =>TocLink{
94+
title: link.clone(),
95+
id:format!("#{}-{}", link.clone(),CMS_IDENTIFIER.id),
96+
level:0,
97+
},
98+
}
99+
}
53100
}

‎pgml-dashboard/src/utils/markdown.rs

Lines changed: 55 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ use crate::{templates::docs::TocLink, utils::config};
33
use std::cell::RefCell;
44
use std::collections::{HashMap,HashSet};
55
use std::path::{Path,PathBuf};
6-
use std::sync::{
7-
atomic::{AtomicUsize,Ordering},
8-
Arc,
9-
};
6+
use std::sync::Arc;
107

118
use anyhow::Result;
129
use comrak::{
@@ -15,25 +12,27 @@ use comrak::{
1512
nodes::{Ast,AstNode,NodeValue},
1613
parse_document,Arena,ComrakExtensionOptions,ComrakOptions,ComrakRenderOptions,
1714
};
15+
use convert_case;
1816
use itertools::Itertools;
1917
use regex::Regex;
2018
use tantivy::collector::TopDocs;
2119
use tantivy::query::{QueryParser,RegexQuery};
2220
use tantivy::schema::*;
2321
use tantivy::tokenizer::{LowerCaser,NgramTokenizer,TextAnalyzer};
2422
use tantivy::{Index,IndexReader,SnippetGenerator};
25-
use url::Url;
23+
24+
use std::sync::Mutex;
2625

2726
use std::fmt;
2827

2928
pubstructMarkdownHeadings{
30-
counter:Arc<AtomicUsize>,
29+
header_map:Arc<Mutex<HashMap<String,usize>>>,
3130
}
3231

3332
implDefaultforMarkdownHeadings{
3433
fndefault() ->Self{
3534
Self{
36-
counter:Arc::new(AtomicUsize::new(0)),
35+
header_map:Arc::new(Mutex::new(HashMap::new())),
3736
}
3837
}
3938
}
@@ -44,31 +43,42 @@ impl MarkdownHeadings {
4443
}
4544
}
4645

46+
/// Sets the document headers
47+
///
48+
/// uses toclink to ensure header id matches what the TOC expects
49+
///
4750
implHeadingAdapterforMarkdownHeadings{
4851
fnenter(&self,meta:&HeadingMeta) ->String{
49-
// let id = meta.content.to_case(convert_case::Case::Kebab);
50-
let id =self.counter.fetch_add(1,Ordering::SeqCst);
51-
let id =format!("header-{}", id);
52+
let conv = convert_case::Converter::new().to_case(convert_case::Case::Kebab);
53+
let id = conv.convert(meta.content.to_string());
54+
55+
let index =matchself.header_map.lock().unwrap().get(&id){
56+
Some(value) => value +1,
57+
_ =>0,
58+
};
59+
self.header_map.lock().unwrap().insert(id.clone(), index);
60+
61+
let id =TocLink::new(&id, index).id;
5262

5363
match meta.level{
54-
1 =>format!(r#"<h1>"#),
55-
2 =>format!(r#"<h2>"#),
56-
3 =>format!(r#"<h3>"#),
57-
4 =>format!(r#"<h4>"#),
58-
5 =>format!(r#"<h5>"#),
59-
6 =>format!(r#"<h6>"#),
64+
1 =>format!(r##"<h1><a href="#{id}">"##),
65+
2 =>format!(r##"<h2><a href="#{id}">"##),
66+
3 =>format!(r##"<h3><a href="#{id}">"##),
67+
4 =>format!(r##"<h4><a href="#{id}">"##),
68+
5 =>format!(r##"<h5><a href="#{id}">"##),
69+
6 =>format!(r##"<h6><a href="#{id}">"##),
6070
_ =>unreachable!(),
6171
}
6272
}
6373

6474
fnexit(&self,meta:&HeadingMeta) ->String{
6575
match meta.level{
66-
1 =>r#"</h1>"#,
67-
2 =>r#"</h2>"#,
68-
3 =>r#"</h3>"#,
69-
4 =>r#"</h4>"#,
70-
5 =>r#"</h5>"#,
71-
6 =>r#"</h6>"#,
76+
1 =>r#"</a></h1>"#,
77+
2 =>r#"</a></h2>"#,
78+
3 =>r#"</a></h3>"#,
79+
4 =>r#"</a></h4>"#,
80+
5 =>r#"</a></h5>"#,
81+
6 =>r#"</a></h6>"#,
7282
_ =>unreachable!(),
7383
}
7484
.into()
@@ -335,38 +345,6 @@ where
335345
Ok(())
336346
}
337347

338-
pubfnnest_relative_links(node:&mut markdown::mdast::Node,path:&PathBuf){
339-
let _ =iter_mut_all(node,&mut |node|{
340-
iflet markdown::mdast::Node::Link(refmut link) = node{
341-
matchUrl::parse(&link.url){
342-
Ok(url) =>{
343-
if !url.has_host(){
344-
letmut url_path = url.path().to_string();
345-
let url_path_path =Path::new(&url_path);
346-
match url_path_path.extension(){
347-
Some(ext) =>{
348-
if ext.to_str() ==Some(".md"){
349-
let base = url_path_path.with_extension("");
350-
url_path = base.into_os_string().into_string().unwrap();
351-
}
352-
}
353-
_ =>{
354-
warn!("not markdown path: {:?}", path)
355-
}
356-
}
357-
link.url = path.join(url_path).into_os_string().into_string().unwrap();
358-
}
359-
}
360-
Err(e) =>{
361-
warn!("could not parse url in markdown: {}", e)
362-
}
363-
}
364-
}
365-
366-
Ok(())
367-
});
368-
}
369-
370348
/// Get the title of the article.
371349
///
372350
/// # Arguments
@@ -462,11 +440,10 @@ pub fn wrap_tables<'a>(root: &'a AstNode<'a>, arena: &'a Arena<AstNode<'a>>) ->
462440
///
463441
pubfnget_toc<'a>(root:&'aAstNode<'a>) -> anyhow::Result<Vec<TocLink>>{
464442
letmut links =Vec::new();
465-
letmutheader_counter =0;
443+
letmutheader_count:HashMap<String,usize> =HashMap::new();
466444

467445
iter_nodes(root,&mut |node|{
468446
ifletNodeValue::Heading(header) =&node.data.borrow().value{
469-
header_counter +=1;
470447
if header.level !=1{
471448
let sibling =match node.first_child(){
472449
Some(child) => child,
@@ -476,7 +453,14 @@ pub fn get_toc<'a>(root: &'a AstNode<'a>) -> anyhow::Result<Vec<TocLink>> {
476453
}
477454
};
478455
ifletNodeValue::Text(text) =&sibling.data.borrow().value{
479-
links.push(TocLink::new(text, header_counter -1).level(header.level));
456+
let index =match header_count.get(text){
457+
Some(index) => index +1,
458+
_ =>0,
459+
};
460+
461+
header_count.insert(text.clone(), index);
462+
463+
links.push(TocLink::new(text, index).level(header.level));
480464
returnOk(false);
481465
}
482466
}
@@ -753,11 +737,25 @@ pub fn mkdocs<'a>(root: &'a AstNode<'a>, arena: &'a Arena<AstNode<'a>>) -> anyho
753737
let path =Path::new(link.url.as_str());
754738

755739
if path.is_relative(){
740+
let fragment =match link.url.find("#"){
741+
Some(index) => link.url[index +1..link.url.len()].to_string(),
742+
_ =>"".to_string(),
743+
};
744+
745+
for _in0..fragment.len() +1{
746+
link.url.pop();
747+
}
748+
756749
if link.url.ends_with(".md"){
757750
for _in0..".md".len(){
758751
link.url.pop();
759752
}
760753
}
754+
755+
let header_id =TocLink::from_fragment(fragment).id;
756+
for cin header_id.chars(){
757+
link.url.push(c)
758+
}
761759
}
762760

763761
Ok(true)

‎pgml-dashboard/static/css/scss/pages/_docs.scss

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,5 +206,21 @@
206206
display:contents!important;
207207
}
208208
}
209+
210+
h1,h2,h3,h4,h5,h6 {
211+
scroll-margin-top:108px;
212+
213+
&:hover {
214+
&:after {
215+
content:'#';
216+
margin-left:0.2em;
217+
position:absolute;
218+
}
219+
}
220+
221+
a {
222+
color:inherit!important;
223+
}
224+
}
209225
}
210226

‎pgml-dashboard/static/js/docs-toc.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,16 @@ export default class extends Controller {
1515
threshold:[1],
1616
})
1717
}
18+
19+
setUrlFragment(e){
20+
lethref=e.target.attributes.href.nodeValue;
21+
if(href){
22+
if(href.startsWith("#")){
23+
lethash=href.slice(1);
24+
if(window.location.hash!=hash){
25+
window.location.hash=hash
26+
}
27+
}
28+
}
29+
}
1830
}

‎pgml-dashboard/templates/components/toc.html

Lines changed: 0 additions & 18 deletions
This file was deleted.

‎pgml-dashboard/templates/layout/nav/toc.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h6 class="mb-2 pb-2 d-none d-xxl-block">Table of Contents</h6>
1010
<divid="toc-nav"class="d-xxl-flex pt-2 flex-column collapse border-top"aria-orientation="vertical"data-controller="docs-toc">
1111
<% for link in toc_links.iter() { %>
1212
<divstyle="padding-left: <%= link.level as f32 * 0.7 - 1.4 %>rem;">
13-
<aclass="nav-link px-0 text-break"href="#<%= link.id %>"role="button"data-action="docs-toc#scrollSpyAppend">
13+
<aclass="nav-link px-0 text-break"href="#<%= link.id %>"role="button"data-action="click->docs-toc#setUrlFragment">
1414
<%= link.title %>
1515
</a>
1616
</div>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp