add tag display to sidebar
This commit is contained in:
parent
f5d6c9c05b
commit
a2debf5b2c
3 changed files with 46 additions and 3 deletions
31
src/main.rs
31
src/main.rs
|
@ -14,6 +14,7 @@ use percent_encoding::{percent_decode_str, utf8_percent_encode};
|
||||||
use pulldown_cmark::{html, Event, Options, Parser, Tag};
|
use pulldown_cmark::{html, Event, Options, Parser, Tag};
|
||||||
use regex::{Captures, Regex};
|
use regex::{Captures, Regex};
|
||||||
use slug::slugify;
|
use slug::slugify;
|
||||||
|
use std::cmp::Reverse;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
@ -44,6 +45,7 @@ struct MutableState {
|
||||||
struct GardenCache {
|
struct GardenCache {
|
||||||
pages: HashMap<String, ParsedPage>,
|
pages: HashMap<String, ParsedPage>,
|
||||||
files: Vec<PathBuf>,
|
files: Vec<PathBuf>,
|
||||||
|
tags: HashMap<String, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GardenCache {
|
impl Default for GardenCache {
|
||||||
|
@ -51,6 +53,7 @@ impl Default for GardenCache {
|
||||||
GardenCache {
|
GardenCache {
|
||||||
pages: HashMap::new(),
|
pages: HashMap::new(),
|
||||||
files: vec![],
|
files: vec![],
|
||||||
|
tags: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,6 +300,12 @@ async fn render(
|
||||||
data.title.as_ref().unwrap_or(&"Digital Garden".to_string()),
|
data.title.as_ref().unwrap_or(&"Digital Garden".to_string()),
|
||||||
);
|
);
|
||||||
context.insert("files", &cache.files);
|
context.insert("files", &cache.files);
|
||||||
|
|
||||||
|
let mut tags: Vec<(&String, &u32)> = cache.tags.iter().collect();
|
||||||
|
tags.sort_by_key(|(t, _)| *t);
|
||||||
|
tags.sort_by_key(|(_, n)| Reverse(*n));
|
||||||
|
context.insert("tags", &tags);
|
||||||
|
|
||||||
context.insert(
|
context.insert(
|
||||||
"recently_changed",
|
"recently_changed",
|
||||||
&recently_changed
|
&recently_changed
|
||||||
|
@ -387,6 +396,7 @@ fn update_garden<P: AsRef<Path>>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut pages = current.pages;
|
let mut pages = current.pages;
|
||||||
|
let mut tags = current.tags;
|
||||||
|
|
||||||
let markdown_paths = files
|
let markdown_paths = files
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -428,9 +438,13 @@ fn update_garden<P: AsRef<Path>>(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
result.tags.into_iter().for_each(|tag| {
|
||||||
|
*tags.entry(tag).or_insert(0) += 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = GardenCache { pages, files };
|
let result = GardenCache { pages, files, tags };
|
||||||
trace!("{:#?}", result);
|
trace!("{:#?}", result);
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
@ -439,6 +453,7 @@ struct ParseResult {
|
||||||
html: String,
|
html: String,
|
||||||
title: Option<String>,
|
title: Option<String>,
|
||||||
links: Vec<String>,
|
links: Vec<String>,
|
||||||
|
tags: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_garden<S: AsRef<str>>(text: S) -> anyhow::Result<ParseResult> {
|
fn parse_garden<S: AsRef<str>>(text: S) -> anyhow::Result<ParseResult> {
|
||||||
|
@ -448,10 +463,19 @@ fn parse_garden<S: AsRef<str>>(text: S) -> anyhow::Result<ParseResult> {
|
||||||
let mut last_nontext_event: Option<Event> = None;
|
let mut last_nontext_event: Option<Event> = None;
|
||||||
|
|
||||||
let mut links: Vec<String> = vec![];
|
let mut links: Vec<String> = vec![];
|
||||||
|
let mut tags: Vec<String> = vec![];
|
||||||
|
|
||||||
let parser = Parser::new_ext(text.as_ref(), Options::all()).map(|event| {
|
let parser = Parser::new_ext(text.as_ref(), Options::all()).map(|event| {
|
||||||
if let Event::Start(Tag::Link(_, str, _)) = &event {
|
if let Event::Start(Tag::Link(_, dest, _)) = &event {
|
||||||
links.push(str.to_string());
|
links.push(dest.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(Event::Start(Tag::Link(_, dest, _))) = &last_nontext_event {
|
||||||
|
if let Event::Text(str) = &event {
|
||||||
|
if str.starts_with("#") {
|
||||||
|
tags.push(dest.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(Event::Start(Tag::Heading(hl))) = last_nontext_event {
|
if let Some(Event::Start(Tag::Heading(hl))) = last_nontext_event {
|
||||||
|
@ -476,6 +500,7 @@ fn parse_garden<S: AsRef<str>>(text: S) -> anyhow::Result<ParseResult> {
|
||||||
html,
|
html,
|
||||||
title: top_heading_text,
|
title: top_heading_text,
|
||||||
links,
|
links,
|
||||||
|
tags,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,10 @@ nav .graph-view {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tag .count {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
padding: 1em 0;
|
padding: 1em 0;
|
||||||
color: gray;
|
color: gray;
|
||||||
|
|
|
@ -73,6 +73,20 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
{% if tags %}
|
||||||
|
<section>
|
||||||
|
<h2>Tags</h2>
|
||||||
|
<ul>
|
||||||
|
{% for tag_cnt in tags %}
|
||||||
|
<li class="tag">
|
||||||
|
<a href="/{{tag_cnt.0}}">
|
||||||
|
<span class="label">#{{tag_cnt.0}}</span> <span class="count">({{tag_cnt.1}})</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
<section class="graph-view">
|
<section class="graph-view">
|
||||||
<a href="/!graph">Graph view (beta)</a>
|
<a href="/!graph">Graph view (beta)</a>
|
||||||
</section>
|
</section>
|
||||||
|
|
Loading…
Reference in a new issue