WIP: ToC implementation #69
4 changed files with 30 additions and 47 deletions
|
@ -21,7 +21,7 @@ pub struct FileMetadataBlog {
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
pub publish: Option<bool>,
|
pub publish: Option<bool>,
|
||||||
pub tags: Option<Vec<Tag>>,
|
pub tags: Option<Vec<Tag>>,
|
||||||
pub toc: Option<String>,
|
pub toc: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A tag, related to post blog
|
/// A tag, related to post blog
|
||||||
|
@ -119,6 +119,7 @@ impl Metadata {
|
||||||
pub struct File {
|
pub struct File {
|
||||||
pub metadata: Metadata,
|
pub metadata: Metadata,
|
||||||
pub content: String,
|
pub content: String,
|
||||||
|
pub toc_data: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options used for parser and compiler MD --> HTML
|
/// Options used for parser and compiler MD --> HTML
|
||||||
|
@ -314,6 +315,8 @@ pub fn read_md(
|
||||||
html_content = custom_img_size(&html_content);
|
html_content = custom_img_size(&html_content);
|
||||||
(html_content, mail_obfsucated) = mail_obfuscation(&html_content);
|
(html_content, mail_obfsucated) = mail_obfuscation(&html_content);
|
||||||
|
|
||||||
|
let toc = toc_to_html(&generate_toc(root));
|
||||||
|
|
||||||
let mut final_metadata = Metadata {
|
let mut final_metadata = Metadata {
|
||||||
info: metadata,
|
info: metadata,
|
||||||
mermaid: check_mermaid(root, mermaid_name),
|
mermaid: check_mermaid(root, mermaid_name),
|
||||||
|
@ -326,6 +329,7 @@ pub fn read_md(
|
||||||
File {
|
File {
|
||||||
metadata: final_metadata,
|
metadata: final_metadata,
|
||||||
content: html_content,
|
content: html_content,
|
||||||
|
toc_data: toc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,15 +344,10 @@ pub fn get_metadata<'a>(root: &'a AstNode<'a>, mtype: &TypeFileMetadata) -> File
|
||||||
.find_map(|node| match &node.data.borrow().value {
|
.find_map(|node| match &node.data.borrow().value {
|
||||||
// Extract metadata from frontmatter
|
// Extract metadata from frontmatter
|
||||||
NodeValue::FrontMatter(text) => Some(match mtype {
|
NodeValue::FrontMatter(text) => Some(match mtype {
|
||||||
TypeFileMetadata::Blog => {
|
TypeFileMetadata::Blog => FileMetadata {
|
||||||
let mut metadata: FileMetadataBlog = deserialize_metadata(text);
|
blog: Some(deserialize_metadata(text)),
|
||||||
metadata.toc = toc_to_html(&generate_toc(root));
|
|
||||||
|
|
||||||
FileMetadata {
|
|
||||||
blog: Some(metadata),
|
|
||||||
..FileMetadata::default()
|
..FileMetadata::default()
|
||||||
}
|
},
|
||||||
}
|
|
||||||
TypeFileMetadata::Contact => {
|
TypeFileMetadata::Contact => {
|
||||||
let mut metadata: FileMetadataContact = deserialize_metadata(text);
|
let mut metadata: FileMetadataContact = deserialize_metadata(text);
|
||||||
|
|
||||||
|
@ -575,9 +574,9 @@ fn generate_toc<'a>(root: &'a AstNode<'a>) -> Vec<TOCEntry> {
|
||||||
toc
|
toc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toc_to_html(toc: &[TOCEntry]) -> Option<String> {
|
fn toc_to_html(toc: &[TOCEntry]) -> String {
|
||||||
if toc.is_empty() {
|
if toc.is_empty() {
|
||||||
return None;
|
return String::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut html = Vec::with_capacity(20 + 20 * toc.len());
|
let mut html = Vec::with_capacity(20 + 20 * toc.len());
|
||||||
|
@ -597,5 +596,5 @@ fn toc_to_html(toc: &[TOCEntry]) -> Option<String> {
|
||||||
|
|
||||||
html.extend_from_slice(b"</ul>");
|
html.extend_from_slice(b"</ul>");
|
||||||
|
|
||||||
Some(String::from_utf8(html).unwrap())
|
String::from_utf8(html).unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,5 +81,6 @@ fn read_pdf(data: Vec<u8>) -> File {
|
||||||
style="width: 100%; height: 79vh";
|
style="width: 100%; height: 79vh";
|
||||||
>"#
|
>"#
|
||||||
),
|
),
|
||||||
|
toc_data: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,7 +186,6 @@ fn get_posts(location: &str) -> Vec<Post> {
|
||||||
struct BlogPostTemplate {
|
struct BlogPostTemplate {
|
||||||
navbar: NavBar,
|
navbar: NavBar,
|
||||||
post: Option<File>,
|
post: Option<File>,
|
||||||
toc: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/blog/p/{id}")]
|
#[get("/blog/p/{id}")]
|
||||||
|
@ -199,7 +198,7 @@ pub async fn page(path: web::Path<(String,)>, config: web::Data<Config>) -> impl
|
||||||
|
|
||||||
fn build_post(file: &str, config: Config) -> String {
|
fn build_post(file: &str, config: Config) -> String {
|
||||||
let mut post = None;
|
let mut post = None;
|
||||||
let (infos, toc) = get_post(
|
let infos = get_post(
|
||||||
&mut post,
|
&mut post,
|
||||||
file,
|
file,
|
||||||
&config.fc.name.unwrap_or_default(),
|
&config.fc.name.unwrap_or_default(),
|
||||||
|
@ -214,18 +213,12 @@ fn build_post(file: &str, config: Config) -> String {
|
||||||
..NavBar::default()
|
..NavBar::default()
|
||||||
},
|
},
|
||||||
post,
|
post,
|
||||||
toc,
|
|
||||||
},
|
},
|
||||||
infos,
|
infos,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_post(
|
fn get_post(post: &mut Option<File>, filename: &str, name: &str, data_dir: &str) -> InfosPage {
|
||||||
post: &mut Option<File>,
|
|
||||||
filename: &str,
|
|
||||||
name: &str,
|
|
||||||
data_dir: &str,
|
|
||||||
) -> (InfosPage, String) {
|
|
||||||
let blog_dir = format!("{data_dir}/{BLOG_DIR}/{POST_DIR}");
|
let blog_dir = format!("{data_dir}/{BLOG_DIR}/{POST_DIR}");
|
||||||
let ext = ".md";
|
let ext = ".md";
|
||||||
|
|
||||||
|
@ -234,13 +227,8 @@ fn get_post(
|
||||||
&TypeFileMetadata::Blog,
|
&TypeFileMetadata::Blog,
|
||||||
);
|
);
|
||||||
|
|
||||||
let default = (
|
let default = (filename, &format!("Blog d'{name}"), Vec::new());
|
||||||
filename,
|
let (title, desc, tags) = match post {
|
||||||
&format!("Blog d'{name}"),
|
|
||||||
Vec::new(),
|
|
||||||
String::new(),
|
|
||||||
);
|
|
||||||
let (title, desc, tags, toc) = match post {
|
|
||||||
Some(data) => (
|
Some(data) => (
|
||||||
match &data.metadata.info.blog.as_ref().unwrap().title {
|
match &data.metadata.info.blog.as_ref().unwrap().title {
|
||||||
Some(text) => text,
|
Some(text) => text,
|
||||||
|
@ -254,15 +242,10 @@ fn get_post(
|
||||||
Some(tags) => tags.clone(),
|
Some(tags) => tags.clone(),
|
||||||
None => default.2,
|
None => default.2,
|
||||||
},
|
},
|
||||||
match &data.metadata.info.blog.as_ref().unwrap().toc {
|
|
||||||
Some(toc) => toc.into(),
|
|
||||||
_ => default.3,
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
None => default,
|
None => default,
|
||||||
};
|
};
|
||||||
|
|
||||||
(
|
|
||||||
InfosPage {
|
InfosPage {
|
||||||
title: Some(format!("Post: {title}")),
|
title: Some(format!("Post: {title}")),
|
||||||
desc: Some(desc.clone()),
|
desc: Some(desc.clone()),
|
||||||
|
@ -272,9 +255,7 @@ fn get_post(
|
||||||
.chain(tags.iter().map(|t| t.name.as_str()))
|
.chain(tags.iter().map(|t| t.name.as_str()))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)),
|
)),
|
||||||
},
|
}
|
||||||
toc,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[routes]
|
#[routes]
|
||||||
|
|
|
@ -28,7 +28,9 @@
|
||||||
<main>
|
<main>
|
||||||
{{^post}}
|
{{^post}}
|
||||||
<p>This post doesn't exist... sorry</p>
|
<p>This post doesn't exist... sorry</p>
|
||||||
{{/post}} {{#post}} {{&toc}}
|
{{/post}} {{#post}} {{#metadata}} {{#info}} {{#blog}} {{#toc}}
|
||||||
|
<aside>{{&toc_data}}</aside>
|
||||||
|
{{/toc}} {{/blog}} {{/info}} {{/metadata}}
|
||||||
<article>{{&content}}</article>
|
<article>{{&content}}</article>
|
||||||
{{/post}}
|
{{/post}}
|
||||||
</main>
|
</main>
|
||||||
|
|
Loading…
Reference in a new issue