Compare commits

..

No commits in common. "86787584405c99411eed7314ea6f304118de9df5" and "457692f766c47a367e8b2ba7cc41dbb17257b35f" have entirely different histories.

5 changed files with 93 additions and 62 deletions

View file

@ -59,8 +59,8 @@ struct IndexTemplate {
} }
#[derive(Template)] #[derive(Template)]
#[template(path = "post.html")] #[template(path = "view_post.html")]
struct PostTemplate { struct ViewPostTemplate {
meta: PostMetadata, meta: PostMetadata,
rendered: String, rendered: String,
rendered_in: RenderStats, rendered_in: RenderStats,
@ -112,12 +112,7 @@ async fn rss(
let posts = state let posts = state
.posts .posts
.get_all_posts_filtered(|metadata, _| { .get_max_n_posts_with_optional_tag_sorted(query.num_posts, query.tag.as_ref())
!query
.tag
.as_ref()
.is_some_and(|tag| !metadata.tags.contains(tag))
})
.await?; .await?;
let mut channel = ChannelBuilder::default(); let mut channel = ChannelBuilder::default();
@ -176,7 +171,7 @@ async fn post(State(state): State<ArcState>, Path(name): Path<String>) -> AppRes
Ok(([("content-type", "text/plain")], buf).into_response()) Ok(([("content-type", "text/plain")], buf).into_response())
} else { } else {
let post = state.posts.get_post(&name).await?; let post = state.posts.get_post(&name).await?;
let page = PostTemplate { let page = ViewPostTemplate {
meta: post.0, meta: post.0,
rendered: post.1, rendered: post.1,
rendered_in: post.2, rendered_in: post.2,

View file

@ -8,7 +8,7 @@ use crate::config::RenderConfig;
use crate::post::PostMetadata; use crate::post::PostMetadata;
/// do not persist cache if this version number changed /// do not persist cache if this version number changed
pub const CACHE_VERSION: u16 = 2; pub const CACHE_VERSION: u16 = 1;
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct CacheValue { pub struct CacheValue {

View file

@ -5,6 +5,7 @@ use std::io;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::time::{Duration, Instant, SystemTime}; use std::time::{Duration, Instant, SystemTime};
use askama::Template;
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use fronma::parser::{parse, ParsedData}; use fronma::parser::{parse, ParsedData};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -62,6 +63,14 @@ pub struct PostMetadata {
pub tags: Vec<String>, pub tags: Vec<String>,
} }
use crate::filters;
#[derive(Template)]
#[template(path = "post.html")]
struct Post<'a> {
pub meta: &'a PostMetadata,
pub rendered_markdown: String,
}
#[allow(unused)] #[allow(unused)]
pub enum RenderStats { pub enum RenderStats {
Cached(Duration), Cached(Duration),
@ -118,7 +127,12 @@ impl PostManager {
let parsing = parsing_start.elapsed(); let parsing = parsing_start.elapsed();
let before_render = Instant::now(); let before_render = Instant::now();
let post = render(body, &self.config); let rendered_markdown = render(body, &self.config);
let post = Post {
meta: &metadata,
rendered_markdown,
}
.render()?;
let rendering = before_render.elapsed(); let rendering = before_render.elapsed();
if let Some(cache) = self.cache.as_ref() { if let Some(cache) = self.cache.as_ref() {
@ -236,6 +250,26 @@ impl PostManager {
Ok(posts) Ok(posts)
} }
pub async fn get_max_n_posts_with_optional_tag_sorted(
&self,
n: Option<usize>,
tag: Option<&String>,
) -> Result<Vec<(PostMetadata, String, RenderStats)>, PostError> {
let mut posts = self
.get_all_posts_filtered(|metadata, _| {
!tag.is_some_and(|tag| !metadata.tags.contains(tag))
})
.await?;
posts.sort_unstable_by_key(|(metadata, ..)| metadata.modified_at.unwrap_or_default());
posts.sort_by_key(|(metadata, ..)| metadata.created_at.unwrap_or_default());
posts.reverse();
if let Some(n) = n {
posts.truncate(n);
}
Ok(posts)
}
pub async fn get_post( pub async fn get_post(
&self, &self,
name: &str, name: &str,

View file

@ -1,52 +1,16 @@
{%- import "macros.askama" as macros -%} {%- import "macros.askama" as macros -%}
<!DOCTYPE html> <h1 class="post-title">
<html lang="en">
<head>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="{{ meta.title }}" />
<meta property="og:title" content="{{ meta.title }}" />
<meta property="og:description" content="{{ meta.description }}" />
{% match meta.icon %} {% when Some with (url) %}
<meta property="og:image" content="{{ url }}" />
<link rel="shortcut icon" href="{{ url }}" />
{% when None %} {% endmatch %}
<title>{{ meta.title }}</title>
<link rel="stylesheet" href="/static/style.css" />
<link rel="stylesheet" href="/static/post.css" />
</head>
</head>
<body>
<main>
<h1 class="post-title">
{{ meta.title }} {{ meta.title }}
<span class="post-author">- by {{ meta.author }}</span> <span class="post-author">- by {{ meta.author }}</span>
</h1> </h1>
<p class="post-desc">{{ meta.description }}</p> <p class="post-desc">{{ meta.description }}</p>
<div class="" post> <p>
<!-- prettier-ignore --> <!-- prettier-ignore -->
<div> <div>
{% call macros::table(meta) %} {% call macros::table(meta) %}
</div> </div>
<a href="/posts/{{ meta.name }}">link</a><br /> <a href="/posts/{{ meta.name }}">link</a><br />
<a href="/">back to home</a> <a href="/">back to home</a>
</div> </p>
<hr /> <hr />
{{ rendered|escape("none") }} {{ rendered_markdown|escape("none") }}
</main>
<!-- prettier-ignore -->
<footer>
{% match rendered_in %}
{% when RenderStats::ParsedAndRendered(total, parsing, rendering) %}
<span class="tooltipped" title="parsing took {{ parsing|duration }}">parsed</span> and
<span class="tooltipped" title="rendering took {{ rendering|duration }}">rendered</span> in {{ total|duration }}
{% when RenderStats::Cached(total) %}
retrieved from cache in {{ total|duration }}
{% endmatch %}
{% if markdown_access %}
- <a href="/posts/{{ meta.name }}.md">view raw</a>
{% endif %}
</footer>
</body>
</html>

38
templates/view_post.html Normal file
View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<meta name="description" content="{{ meta.title }}" />
<meta property="og:title" content="{{ meta.title }}" />
<meta property="og:description" content="{{ meta.description }}" />
{% match meta.icon %} {% when Some with (url) %}
<meta property="og:image" content="{{ url }}" />
<link rel="shortcut icon" href="{{ url }}" />
{% when None %} {% endmatch %}
<title>{{ meta.title }}</title>
<link rel="stylesheet" href="/static/style.css" />
<link rel="stylesheet" href="/static/post.css" />
</head>
</head>
<body>
<main>{{ rendered|escape("none") }}</main>
<!-- prettier-ignore -->
<footer>
{% match rendered_in %}
{% when RenderStats::ParsedAndRendered(total, parsing, rendering) %}
<span class="tooltipped" title="parsing took {{ parsing|duration }}">parsed</span> and
<span class="tooltipped" title="rendering took {{ rendering|duration }}">rendered</span> in {{ total|duration }}
{% when RenderStats::Cached(total) %}
retrieved from cache in {{ total|duration }}
{% endmatch %}
{% if markdown_access %}
- <a href="/posts/{{ meta.name }}.md">view raw</a>
{% endif %}
</footer>
</body>
</html>