Compare commits
No commits in common. "d466f531ebe117c3a83410f9ff74fc4865b036fc" and "f86165ab944b49c66c94032c5c6c175ba678407e" have entirely different histories.
d466f531eb
...
f86165ab94
9 changed files with 25 additions and 96 deletions
|
@ -1,5 +0,0 @@
|
||||||
{
|
|
||||||
"useTabs": true,
|
|
||||||
"tabWidth": 4,
|
|
||||||
"printWidth": 140
|
|
||||||
}
|
|
|
@ -1,9 +1,7 @@
|
||||||
use std::{collections::HashMap, time::Duration};
|
use std::time::Duration;
|
||||||
|
|
||||||
use chrono::{DateTime, TimeZone};
|
use chrono::{DateTime, TimeZone};
|
||||||
|
|
||||||
use crate::post::PostMetadata;
|
|
||||||
|
|
||||||
pub fn date<T: TimeZone>(date: &DateTime<T>) -> Result<String, askama::Error> {
|
pub fn date<T: TimeZone>(date: &DateTime<T>) -> Result<String, askama::Error> {
|
||||||
Ok(date.to_rfc3339_opts(chrono::SecondsFormat::Secs, true))
|
Ok(date.to_rfc3339_opts(chrono::SecondsFormat::Secs, true))
|
||||||
}
|
}
|
||||||
|
@ -11,24 +9,3 @@ pub fn date<T: TimeZone>(date: &DateTime<T>) -> Result<String, askama::Error> {
|
||||||
pub fn duration(duration: &&Duration) -> Result<String, askama::Error> {
|
pub fn duration(duration: &&Duration) -> Result<String, askama::Error> {
|
||||||
Ok(format!("{:?}", duration))
|
Ok(format!("{:?}", duration))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_tags(posts: &Vec<PostMetadata>) -> Result<Vec<(String, u64)>, askama::Error> {
|
|
||||||
let mut tags = HashMap::new();
|
|
||||||
|
|
||||||
for post in posts {
|
|
||||||
for tag in &post.tags {
|
|
||||||
if let Some((existing_tag, count)) = tags.remove_entry(tag) {
|
|
||||||
tags.insert(existing_tag, count + 1);
|
|
||||||
} else {
|
|
||||||
tags.insert(tag.clone(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tags: Vec<(String, u64)> = tags.into_iter().collect();
|
|
||||||
|
|
||||||
tags.sort_unstable_by_key(|(v, _)| v.clone());
|
|
||||||
tags.sort_by_key(|(_, v)| -(*v as i64));
|
|
||||||
|
|
||||||
Ok(tags)
|
|
||||||
}
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilte
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::error::{AppResult, PostError};
|
use crate::error::{AppResult, PostError};
|
||||||
use crate::post::cache::{Cache, CACHE_VERSION};
|
|
||||||
use crate::post::{PostManager, PostMetadata, RenderStats};
|
use crate::post::{PostManager, PostMetadata, RenderStats};
|
||||||
|
|
||||||
type ArcState = Arc<AppState>;
|
type ArcState = Arc<AppState>;
|
||||||
|
@ -180,13 +179,8 @@ async fn main() -> eyre::Result<()> {
|
||||||
.context("failed to read cache file")?;
|
.context("failed to read cache file")?;
|
||||||
buf
|
buf
|
||||||
};
|
};
|
||||||
let mut cache: Cache =
|
let cache =
|
||||||
bitcode::deserialize(serialized.as_slice()).context("failed to parse cache")?;
|
bitcode::deserialize(serialized.as_slice()).context("failed to parse cache")?;
|
||||||
if cache.version() < CACHE_VERSION {
|
|
||||||
warn!("cache version changed, clearing cache");
|
|
||||||
cache = Cache::default();
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok::<PostManager, color_eyre::Report>(PostManager::new_with_cache(
|
Ok::<PostManager, color_eyre::Report>(PostManager::new_with_cache(
|
||||||
config.dirs.posts.clone(),
|
config.dirs.posts.clone(),
|
||||||
config.render.clone(),
|
config.render.clone(),
|
||||||
|
|
|
@ -7,9 +7,6 @@ use tracing::{debug, instrument};
|
||||||
use crate::config::RenderConfig;
|
use crate::config::RenderConfig;
|
||||||
use crate::post::PostMetadata;
|
use crate::post::PostMetadata;
|
||||||
|
|
||||||
/// do not persist cache if this version number changed
|
|
||||||
pub const CACHE_VERSION: u16 = 1;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct CacheValue {
|
pub struct CacheValue {
|
||||||
pub metadata: PostMetadata,
|
pub metadata: PostMetadata,
|
||||||
|
@ -18,14 +15,8 @@ pub struct CacheValue {
|
||||||
config_hash: u64,
|
config_hash: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Default, Clone)]
|
||||||
pub struct Cache(HashMap<String, CacheValue>, u16);
|
pub struct Cache(HashMap<String, CacheValue>);
|
||||||
|
|
||||||
impl Default for Cache {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self(Default::default(), CACHE_VERSION)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cache {
|
impl Cache {
|
||||||
pub async fn lookup(
|
pub async fn lookup(
|
||||||
|
@ -126,9 +117,4 @@ impl Cache {
|
||||||
let new_size = self.0.len();
|
let new_size = self.0.len();
|
||||||
debug!("removed {i} entries ({old_size} -> {new_size} entries)");
|
debug!("removed {i} entries ({old_size} -> {new_size} entries)");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn version(&self) -> u16 {
|
|
||||||
self.1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
pub mod cache;
|
mod cache;
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
|
||||||
use std::io;
|
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};
|
||||||
|
@ -28,7 +27,7 @@ struct FrontMatter {
|
||||||
pub created_at: Option<DateTime<Utc>>,
|
pub created_at: Option<DateTime<Utc>>,
|
||||||
pub modified_at: Option<DateTime<Utc>>,
|
pub modified_at: Option<DateTime<Utc>>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub tags: BTreeSet<String>,
|
pub tags: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FrontMatter {
|
impl FrontMatter {
|
||||||
|
@ -46,7 +45,7 @@ impl FrontMatter {
|
||||||
icon: self.icon,
|
icon: self.icon,
|
||||||
created_at: self.created_at.or_else(|| created.map(|t| t.into())),
|
created_at: self.created_at.or_else(|| created.map(|t| t.into())),
|
||||||
modified_at: self.modified_at.or_else(|| modified.map(|t| t.into())),
|
modified_at: self.modified_at.or_else(|| modified.map(|t| t.into())),
|
||||||
tags: self.tags.into_iter().collect(),
|
tags: self.tags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,8 @@
|
||||||
:root,
|
:root,
|
||||||
code {
|
code {
|
||||||
/* please have one at least one good monospace font */
|
/* please have one at least one good monospace font */
|
||||||
font-family: "Hack", "Hack Nerd Font", "JetBrains Mono", "JetBrainsMono Nerd Font", "Ubuntu Mono", monospace, sans-serif;
|
font-family: "Hack", "Hack Nerd Font", "JetBrains Mono",
|
||||||
|
"JetBrainsMono Nerd Font", "Ubuntu Mono", monospace, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
@ -80,10 +81,6 @@ footer {
|
||||||
opacity: 0.65;
|
opacity: 0.65;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.post {
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* BEGIN cool effect everyone liked */
|
/* BEGIN cool effect everyone liked */
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
{%- import "macros.askama" as macros -%}
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
@ -18,23 +17,20 @@
|
||||||
<!-- prettier-ignore -->
|
<!-- prettier-ignore -->
|
||||||
<div>
|
<div>
|
||||||
{% for post in posts %}
|
{% for post in posts %}
|
||||||
<div class="post">
|
<p>
|
||||||
<a href="/posts/{{ post.name }}"><b>{{ post.title }}</b></a>
|
<a href="/posts/{{ post.name }}"><b>{{ post.title }}</b></a>
|
||||||
<span class="post-author">- by {{ post.author }}</span>
|
<span class="post-author">- by {{ post.author }}</span>
|
||||||
<br />
|
<br />
|
||||||
{{ post.description }}<br />
|
{{ post.description }}<br />
|
||||||
{% call macros::table(post) %}
|
{% match post.created_at %} {% when Some(created_at) %}
|
||||||
</div>
|
written: {{ created_at|date }}<br />
|
||||||
|
{% when None %} {% endmatch %}
|
||||||
|
{% match post.modified_at %} {% when Some(modified_at) %}
|
||||||
|
last modified: {{ modified_at|date }}
|
||||||
|
{% when None %} {% endmatch %}
|
||||||
|
</p>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% let tags = posts|collect_tags %}<!-- prettier-br -->
|
|
||||||
{% if !tags.is_empty() %}
|
|
||||||
<h2>tags</h2>
|
|
||||||
{% endif %}<!-- prettier-br -->
|
|
||||||
{% for tag in tags %}
|
|
||||||
<a href="/?tag={{ tag.0 }}" title="view all posts with this tag">{{ tag.0 }}</a>
|
|
||||||
<span class="post-author">- {{ tag.1 }} post{% if tag.1 != 1 %}s{%endif %}</span><br />
|
|
||||||
{% endfor %}
|
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
{% macro table(post) %}
|
|
||||||
{% match post.created_at %}
|
|
||||||
{% when Some(created_at) %}
|
|
||||||
written: {{ created_at|date }}<br />
|
|
||||||
{% when None %}
|
|
||||||
{% endmatch %}
|
|
||||||
{% match post.modified_at %}
|
|
||||||
{% when Some(modified_at) %}
|
|
||||||
last modified: {{ modified_at|date }}<br />
|
|
||||||
{% when None %}
|
|
||||||
{% endmatch %}
|
|
||||||
|
|
||||||
{% if !post.tags.is_empty() %}
|
|
||||||
tags:
|
|
||||||
{% for tag in post.tags %}
|
|
||||||
<a href="/?tag={{ tag }}" title="view all posts with this tag">{{ tag }}</a>
|
|
||||||
{% endfor %}<br />
|
|
||||||
{% endif %}
|
|
||||||
{% endmacro %}
|
|
|
@ -1,4 +1,3 @@
|
||||||
{%- import "macros.askama" as macros -%}
|
|
||||||
<h1 class="post-title">
|
<h1 class="post-title">
|
||||||
{{ meta.title }}
|
{{ meta.title }}
|
||||||
<span class="post-author">- by {{ meta.author }}</span>
|
<span class="post-author">- by {{ meta.author }}</span>
|
||||||
|
@ -7,7 +6,12 @@
|
||||||
<p>
|
<p>
|
||||||
<!-- prettier-ignore -->
|
<!-- prettier-ignore -->
|
||||||
<div>
|
<div>
|
||||||
{% call macros::table(meta) %}
|
{% match meta.created_at %} {% when Some(created_at) %}
|
||||||
|
written: {{ created_at|date }}<br />
|
||||||
|
{% when None %} {% endmatch %}
|
||||||
|
{% match meta.modified_at %} {% when Some(modified_at) %}
|
||||||
|
last modified: {{ modified_at|date }}
|
||||||
|
{% when None %} {% endmatch %}
|
||||||
</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>
|
||||||
|
|
Loading…
Reference in a new issue