implement blog tag filtering
This commit is contained in:
parent
139c26158b
commit
a135acf943
46
src/main.rs
46
src/main.rs
|
@ -5,6 +5,7 @@ mod scrobbles;
|
||||||
mod skweets;
|
mod skweets;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use rocket::fs::{relative, FileServer};
|
use rocket::fs::{relative, FileServer};
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
|
@ -47,24 +48,6 @@ async fn home(clients: &State<Clients>) -> Template {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/blog")]
|
|
||||||
async fn blog() -> Template {
|
|
||||||
let mut blogposts = posts::get_blogposts().await.unwrap_or_default();
|
|
||||||
let tags = posts::get_tags(&blogposts);
|
|
||||||
for blogpost in &mut blogposts {
|
|
||||||
blogpost.render().await;
|
|
||||||
}
|
|
||||||
let reverse = "reverse".to_owned();
|
|
||||||
Template::render(
|
|
||||||
"blog",
|
|
||||||
context! {
|
|
||||||
reverse,
|
|
||||||
blogposts,
|
|
||||||
tags,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[get("/blog/<blogpost>")]
|
#[get("/blog/<blogpost>")]
|
||||||
async fn blogpost(blogpost: &str) -> Result<Template> {
|
async fn blogpost(blogpost: &str) -> Result<Template> {
|
||||||
let mut blogpost = posts::get_blogpost(blogpost).await?;
|
let mut blogpost = posts::get_blogpost(blogpost).await?;
|
||||||
|
@ -77,6 +60,33 @@ async fn blogpost(blogpost: &str) -> Result<Template> {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/blog?<filter>")]
|
||||||
|
async fn blog(filter: Vec<String>) -> Result<Template> {
|
||||||
|
let mut blogposts = posts::get_blogposts().await?;
|
||||||
|
let tags: Vec<String> = posts::get_tags(&blogposts)
|
||||||
|
.into_iter()
|
||||||
|
.map(|tag| tag.to_owned())
|
||||||
|
.collect();
|
||||||
|
let mut filter_hashset: HashSet<String> = HashSet::new();
|
||||||
|
if !filter.is_empty() {
|
||||||
|
filter_hashset.extend(filter.into_iter());
|
||||||
|
blogposts = posts::filter_by_tags(blogposts, &filter_hashset);
|
||||||
|
}
|
||||||
|
for blogpost in &mut blogposts {
|
||||||
|
blogpost.render().await?;
|
||||||
|
}
|
||||||
|
let reverse = true;
|
||||||
|
Ok(Template::render(
|
||||||
|
"blog",
|
||||||
|
context! {
|
||||||
|
reverse,
|
||||||
|
tags,
|
||||||
|
filter_hashset,
|
||||||
|
blogposts,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/contact")]
|
#[get("/contact")]
|
||||||
async fn contact() -> Template {
|
async fn contact() -> Template {
|
||||||
Template::render("contact", context! {})
|
Template::render("contact", context! {})
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
mod article;
|
||||||
|
mod note;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
@ -16,12 +19,6 @@ enum PostType {
|
||||||
Note,
|
Note,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TextFormat {
|
|
||||||
Markdown,
|
|
||||||
Plaintext,
|
|
||||||
Html,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Post<D: Content> {
|
pub struct Post<D: Content> {
|
||||||
// id: i64,
|
// id: i64,
|
||||||
|
@ -34,7 +31,7 @@ pub struct Post<D: Content> {
|
||||||
data: D,
|
data: D,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D: Content + Serialize> Post<D> {
|
impl<D: Content> Post<D> {
|
||||||
pub async fn render(&mut self) -> Result<()> {
|
pub async fn render(&mut self) -> Result<()> {
|
||||||
self.render = Some(self.data.render().await?);
|
self.render = Some(self.data.render().await?);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -74,6 +71,8 @@ pub async fn get_blogposts() -> Result<Vec<Post<Article>>> {
|
||||||
let blogpost = Post::try_from(blogpost).await.unwrap();
|
let blogpost = Post::try_from(blogpost).await.unwrap();
|
||||||
blogposts.push(blogpost);
|
blogposts.push(blogpost);
|
||||||
}
|
}
|
||||||
|
blogposts.sort_by_key(|post| post.created_at);
|
||||||
|
blogposts.reverse();
|
||||||
Ok(blogposts)
|
Ok(blogposts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,21 +86,45 @@ pub async fn get_blogpost(post_name: &str) -> Result<Post<Article>> {
|
||||||
path: file.path().to_str().unwrap_or_default().to_owned(),
|
path: file.path().to_str().unwrap_or_default().to_owned(),
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
};
|
};
|
||||||
let blogpost = Post::try_from(blogpost).await.unwrap();
|
let blogpost = Post::try_from(blogpost).await?;
|
||||||
return Ok(blogpost);
|
return Ok(blogpost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(BlossomError::NotFound(Status::new(404)))
|
Err(BlossomError::NotFound(Status::new(404)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tags<D: Content>(posts: &Vec<Post<D>>) -> HashSet<String> {
|
pub fn get_tags<D: Content>(posts: &Vec<Post<D>>) -> Vec<&String> {
|
||||||
posts.into_iter().fold(HashSet::new(), |mut acc, post| {
|
let mut tags = posts
|
||||||
let tags = &post.tags;
|
.into_iter()
|
||||||
for tag in tags {
|
.fold(HashSet::new(), |mut acc, post| {
|
||||||
acc.insert(tag.to_owned());
|
let tags = &post.tags;
|
||||||
}
|
for tag in tags {
|
||||||
acc
|
acc.insert(tag);
|
||||||
})
|
}
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
tags.sort();
|
||||||
|
tags
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filter_by_tags<'p, D: Content>(
|
||||||
|
posts: Vec<Post<D>>,
|
||||||
|
filter_tags: &HashSet<String>,
|
||||||
|
) -> Vec<Post<D>> {
|
||||||
|
posts
|
||||||
|
.into_iter()
|
||||||
|
.filter(|post| {
|
||||||
|
for tag in &post.tags {
|
||||||
|
match filter_tags.contains(tag) {
|
||||||
|
true => return true,
|
||||||
|
false => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
|
|
@ -1 +1,7 @@
|
||||||
struct note
|
enum TextFormat {
|
||||||
|
Markdown,
|
||||||
|
Plaintext,
|
||||||
|
Html,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Note {}
|
||||||
|
|
|
@ -329,9 +329,9 @@ iframe {
|
||||||
}
|
}
|
||||||
|
|
||||||
.tags {
|
.tags {
|
||||||
display: flexbox;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: 0.5em;
|
gap: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tags a {
|
.tags a {
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main class="{% if reverse %}{{ reverse }}{% endif %}">
|
<main class="{% if reverse %}reverse{% endif %}">
|
||||||
<div class="main-content">
|
<div class="main-content">
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="panel content blogpost">
|
<div class="panel content blogpost">
|
||||||
<h1 class="title">{{ blogpost.subject }}</h1>
|
<h1 class="title">{{ blogpost.subject }}</h1>
|
||||||
<h2 class="created-at">{{ blogpost.created_at }} <a href="/blog/{{ blogpost.data.name }}">permalink</a></h2>
|
<h2 class="created-at">{{ blogpost.created_at }} <a href="/blog/{{ blogpost.data.name }}">permalink</a></h2>
|
||||||
<div class="tags">{% for tag in blogpost.tags %}<a class="tag" href="/tag/{{ tag }}">{{ tag }}</a>{% endfor %}</div>
|
<div class="tags">{% for tag in blogpost.tags %}<a class="tag {% if filter_hashset %}{% if tag in filter_hashset %}active{% endif %}{% endif %}" href="/blog?filter={{ tag }}">{{ tag }}</a>{% endfor %}</div>
|
||||||
<div class="blogpost-content">
|
<div class="blogpost-content">
|
||||||
{{ blogpost.render }}
|
{{ blogpost.render }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="panel" id="filter-tags">
|
<div class="panel" id="filter-tags">
|
||||||
<h2>filter tag</h2>
|
<h2>filter by tags</h2>
|
||||||
<div class="tags">
|
<div class="tags">
|
||||||
{% for tag in tags %}<a href="/blog/tag/{{ tag }}">{{ tag }}</a>{% endfor %}
|
{% for tag in tags %}<a class="{% if tag in filter_hashset %}active{% endif %}" href="{% if tag in filter_hashset %}/blog{% else %}/blog?filter={{ tag }}{% endif %}">{{ tag }}</a>{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in New Issue