Compare commits
No commits in common. "86787584405c99411eed7314ea6f304118de9df5" and "457692f766c47a367e8b2ba7cc41dbb17257b35f" have entirely different histories.
8678758440
...
457692f766
5 changed files with 93 additions and 62 deletions
13
src/main.rs
13
src/main.rs
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
38
templates/view_post.html
Normal 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>
|
Loading…
Reference in a new issue