Compare commits

...

2 Commits

Author SHA1 Message Date
Patrick Cleavelin ac7ce64408 add syntax highlighting
ci/woodpecker/push/woodpecker Pipeline failed Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
2024-10-25 13:23:15 -05:00
Patrick Cleavelin d496efe835 support videos
ci/woodpecker/tag/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline failed Details
2024-10-02 20:07:41 -05:00
3 changed files with 553 additions and 17 deletions

311
Cargo.lock generated
View File

@ -17,6 +17,15 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
[[package]]
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
@ -32,6 +41,16 @@ dependencies = [
"libc",
]
[[package]]
name = "ansi-to-html"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d73c455ae09fa2223a75114789f30ad605e9e297f79537953523366c05995f5f"
dependencies = [
"regex",
"thiserror",
]
[[package]]
name = "anstream"
version = "0.6.15"
@ -168,15 +187,39 @@ dependencies = [
"windows-targets",
]
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "blog-thing"
version = "0.1.0"
dependencies = [
"ansi-to-html",
"axum",
"chrono",
"clap",
"markdown",
"syntect",
"tokio",
"two-face",
]
[[package]]
@ -272,6 +315,40 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crc32fast"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
dependencies = [
"cfg-if",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "flate2"
version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0"
dependencies = [
"crc32fast",
"miniz_oxide",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -326,6 +403,12 @@ version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
[[package]]
name = "heck"
version = "0.5.0"
@ -442,6 +525,16 @@ dependencies = [
"cc",
]
[[package]]
name = "indexmap"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
@ -469,6 +562,12 @@ version = "0.2.159"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "log"
version = "0.4.22"
@ -523,6 +622,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.19"
@ -550,6 +655,28 @@ dependencies = [
"portable-atomic",
]
[[package]]
name = "onig"
version = "6.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f"
dependencies = [
"bitflags",
"libc",
"once_cell",
"onig_sys",
]
[[package]]
name = "onig_sys"
version = "69.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7"
dependencies = [
"cc",
"pkg-config",
]
[[package]]
name = "percent-encoding"
version = "2.3.1"
@ -568,12 +695,37 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "plist"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
dependencies = [
"base64",
"indexmap",
"quick-xml",
"serde",
"time",
]
[[package]]
name = "portable-atomic"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "proc-macro2"
version = "1.0.86"
@ -583,6 +735,15 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-xml"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
version = "1.0.37"
@ -592,6 +753,35 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@ -610,6 +800,15 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "serde"
version = "1.0.210"
@ -715,6 +914,79 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
[[package]]
name = "syntect"
version = "5.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1"
dependencies = [
"bincode",
"bitflags",
"flate2",
"fnv",
"once_cell",
"onig",
"plist",
"regex-syntax",
"serde",
"serde_derive",
"serde_json",
"thiserror",
"walkdir",
"yaml-rust",
]
[[package]]
name = "thiserror"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "time"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "time-macros"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
dependencies = [
"num-conv",
"time-core",
]
[[package]]
name = "tokio"
version = "1.40.0"
@ -789,6 +1061,17 @@ dependencies = [
"once_cell",
]
[[package]]
name = "two-face"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ccd4843ea031c609fe9c16cae00e9657bad8a9f735a3cc2e420955d802b4268"
dependencies = [
"once_cell",
"serde",
"syntect",
]
[[package]]
name = "unicode-id"
version = "0.3.5"
@ -807,6 +1090,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@ -868,6 +1161,15 @@ version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]]
name = "windows-core"
version = "0.52.0"
@ -949,3 +1251,12 @@ name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

View File

@ -4,8 +4,11 @@ version = "0.1.0"
edition = "2021"
[dependencies]
ansi-to-html = "0.2.1"
axum = "0.7.7"
chrono = "0.4.38"
clap = { version = "4.5.18", features = ["derive", "env"] }
markdown = "1.0.0-alpha.21"
syntect = "5.2.0"
tokio = { version = "1.40.0", features = [ "rt-multi-thread" ] }
two-face = "0.4.0"

View File

@ -5,14 +5,24 @@ use axum::{
routing::get,
Router,
};
use std::{collections::HashMap, path::PathBuf, sync::Arc};
use clap::Parser;
use markdown::ParseOptions;
use std::{collections::HashMap, path::PathBuf, sync::Arc};
use syntect::{
highlighting::{Theme, ThemeSet},
html::highlighted_html_for_string,
parsing::{SyntaxSet, SyntaxSetBuilder},
};
use two_face::theme::EmbeddedLazyThemeSet;
#[derive(Debug)]
// #[derive(Debug)]
struct BlogState {
templates: HashMap<String, Cached<Template>>,
posts: HashMap<String, Cached<Post>>,
ps: SyntaxSet,
ts: EmbeddedLazyThemeSet,
config: Config,
}
type AppState = State<Arc<BlogState>>;
@ -77,25 +87,198 @@ struct Post {
embed_template_name: Option<String>,
}
trait ToHtml {
fn is_directive(&self) -> bool;
fn to_html(&self, ps: &SyntaxSet, theme: &Theme) -> String;
fn template(&self) -> Option<String>;
}
impl ToHtml for markdown::mdast::Node {
fn to_html(&self, ps: &SyntaxSet, theme: &Theme) -> String {
let mut s = String::new();
if self.is_directive() {
return s;
}
match self {
markdown::mdast::Node::Root(root) => {
for child in &root.children {
s += &child.to_html(ps, theme);
}
}
markdown::mdast::Node::Blockquote(block_quote) => {
s += "<blockquote>";
for child in &block_quote.children {
s += &child.to_html(ps, theme);
}
s += "</blockquote>";
}
markdown::mdast::Node::FootnoteDefinition(_) => {}
markdown::mdast::Node::MdxJsxFlowElement(_) => {}
markdown::mdast::Node::List(list) => {
s += "<ul>";
for child in &list.children {
s += &child.to_html(ps, theme);
}
s += "</ul>";
}
markdown::mdast::Node::MdxjsEsm(_) => {}
markdown::mdast::Node::Toml(_) => {}
markdown::mdast::Node::Yaml(_) => {}
markdown::mdast::Node::Break(_) => {}
markdown::mdast::Node::InlineCode(inline_code) => {
s += &format!(
"<code>{}</code>",
&ansi_to_html::convert(&inline_code.value).unwrap()
);
}
markdown::mdast::Node::InlineMath(_) => {}
markdown::mdast::Node::Delete(_) => {}
markdown::mdast::Node::Emphasis(emphasis) => {
s += "<em>";
for child in &emphasis.children {
s += &child.to_html(ps, theme);
}
s += "</em>";
}
markdown::mdast::Node::MdxTextExpression(_) => {}
markdown::mdast::Node::FootnoteReference(_) => {}
markdown::mdast::Node::Html(_) => {}
markdown::mdast::Node::Image(image) => {
if image.url.ends_with(".mp4") {
s += &format!("<video controls src={}>", image.url);
} else {
s += &format!("<img src={}>", image.url);
}
}
markdown::mdast::Node::ImageReference(_) => {}
markdown::mdast::Node::MdxJsxTextElement(_) => {}
markdown::mdast::Node::Link(link) => {
s += &format!("<a href={}>", link.url);
for child in &link.children {
s += &child.to_html(ps, theme);
}
s += "</a>";
}
markdown::mdast::Node::LinkReference(_) => {}
markdown::mdast::Node::Strong(strong) => {
s += "<b>";
for child in &strong.children {
s += &child.to_html(ps, theme);
}
s += "</b>";
}
markdown::mdast::Node::Text(text) => s += &ansi_to_html::convert(&text.value).unwrap(),
markdown::mdast::Node::Code(code) => {
if let Some(syntax) = code
.lang
.as_ref()
.and_then(|lang| ps.find_syntax_by_extension(&lang))
{
println!("{:?}", code.lang);
let escaped = highlighted_html_for_string(&code.value, &ps, syntax, theme)
.expect("generate html");
s += &escaped;
} else {
s += "<pre><code>";
s += &ansi_to_html::convert(&code.value).unwrap();
s += "</code></pre>";
}
}
markdown::mdast::Node::Math(_) => {}
markdown::mdast::Node::MdxFlowExpression(_) => {}
markdown::mdast::Node::Heading(heading) => {
s += &format!("<h{}>", heading.depth);
for child in &heading.children {
s += &child.to_html(ps, theme);
}
s += &format!("</h{}>", heading.depth);
}
markdown::mdast::Node::Table(_) => {}
markdown::mdast::Node::ThematicBreak(_) => {
s += "<hr>";
}
markdown::mdast::Node::TableRow(_) => {}
markdown::mdast::Node::TableCell(_) => {}
markdown::mdast::Node::ListItem(item) => {
s += "<li>";
for child in &item.children {
s += &child.to_html(ps, theme);
}
s += "</li>";
}
markdown::mdast::Node::Definition(_) => {}
markdown::mdast::Node::Paragraph(paragraph) => {
s += "<p>";
for child in &paragraph.children {
s += &child.to_html(ps, theme);
}
s += "</p>";
}
}
s
}
fn is_directive(&self) -> bool {
self.children()
.and_then(|children| children.first())
.map(|first| match first {
markdown::mdast::Node::Text(text) => {
if text.value.starts_with("%{") && text.value.ends_with("}") {
text.value.chars().filter(|x| *x == '}').count() == 1
} else {
false
}
}
_ => false,
})
.is_some_and(|x| x)
}
fn template(&self) -> Option<String> {
self.children()
.and_then(|children| children.first())
.and_then(|first| match first {
markdown::mdast::Node::Paragraph(_) => first.template(),
markdown::mdast::Node::Text(text) => {
if text.value.starts_with("%{") {
text.value[2..].split('}').next().map(String::from)
} else {
None
}
}
_ => None,
})
}
}
impl Post {
fn to_html(&self, templates: &HashMap<String, Cached<Template>>) -> String {
fn to_html(
&self,
templates: &HashMap<String, Cached<Template>>,
ps: &SyntaxSet,
ts: &Theme,
) -> String {
let mut s = String::with_capacity(self.content.len());
if let Some(template) = self
.embed_template_name
.as_ref()
.and_then(|name| templates.get(name))
{
let ast = markdown::to_mdast(&self.content, &ParseOptions::default()).unwrap();
let template_name = ast.template();
if let Some(template) = template_name.and_then(|name| templates.get(&name)) {
if template.data.index > 0 {
s += &template.data.content[0..template.data.index];
}
s += &markdown::to_html(&self.content);
s += &ast.to_html(ps, ts);
if template.data.index > 0 {
s += &template.data.content[template.data.index + 3..]
}
} else {
s += &markdown::to_html(&self.content);
s += &ast.to_html(ps, ts);
}
s
@ -105,7 +288,8 @@ impl Post {
impl From<String> for Post {
fn from(value: String) -> Self {
let template_name = if value.starts_with("%{") {
value[2..].split('}').next().map(Into::into)
// value[2..].split('}').next().map(Into::into)
None
} else {
None
};
@ -132,13 +316,25 @@ struct Config {
#[tokio::main]
async fn main() {
let config = Config::parse();
let mut builder = two_face::syntax::extra_newlines().into_builder();
builder
.add_from_folder(format!("{}/syntaxes", &config.blog_dir), true)
.expect("load syntaxes");
let ps = builder.build();
let mut blog_state = BlogState {
templates: HashMap::new(),
posts: HashMap::new(),
ps,
ts: two_face::theme::extra(),
config,
};
for dir in std::fs::read_dir(&blog_state.config.blog_dir).unwrap().flatten() {
for dir in std::fs::read_dir(&blog_state.config.blog_dir)
.unwrap()
.flatten()
{
if dir.file_type().unwrap().is_file() {
let file_name = dir.file_name().into_string().unwrap();
let Some((file_name, extension)) = file_name.split_once('.') else {
@ -169,7 +365,9 @@ async fn main() {
.route("/:post", get(blog_post))
.route("/images/:image", get(image))
.with_state(Arc::new(blog_state));
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port)).await.unwrap();
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port))
.await
.unwrap();
axum::serve(listener, app).await.unwrap();
}
@ -177,7 +375,15 @@ async fn main() {
async fn home_page(State(state): AppState) -> Result<Html<String>, Html<String>> {
match state.posts.get("home") {
Some(post) => match post.data() {
Ok(content) => Ok(Html(content.to_html(&state.templates))),
Ok(content) => Ok(Html(
content.to_html(
&state.templates,
&state.ps,
state
.ts
.get(two_face::theme::EmbeddedThemeName::GruvboxDark),
),
)),
Err(e) => Err(Html(e.to_string())),
},
None => Err(Html("<h1>404 - Not Found</h1>".to_string())),
@ -190,7 +396,15 @@ async fn blog_post(
) -> Result<Html<String>, Html<String>> {
match state.posts.get(&post) {
Some(post) => match post.data() {
Ok(content) => Ok(Html(content.to_html(&state.templates))),
Ok(content) => Ok(Html(
content.to_html(
&state.templates,
&state.ps,
state
.ts
.get(two_face::theme::EmbeddedThemeName::GruvboxDark),
),
)),
Err(e) => Err(Html(e.to_string())),
},
None => Err(not_found_page(state)),
@ -199,7 +413,7 @@ async fn blog_post(
async fn image(State(state): AppState, Path(image_path): Path<String>) -> impl IntoResponse {
match std::fs::read(format!("{}/images/{image_path}", state.config.blog_dir)) {
Ok(contents) => Ok(([(header::CONTENT_TYPE, "image/png")], contents)),
Ok(contents) => Ok(([(header::CONTENT_TYPE, "image/png;video/mp4")], contents)),
Err(e) => {
eprintln!("{e:#?}");
Err(StatusCode::NOT_FOUND)
@ -210,7 +424,15 @@ async fn image(State(state): AppState, Path(image_path): Path<String>) -> impl I
fn not_found_page(state: Arc<BlogState>) -> Html<String> {
match state.posts.get("404") {
Some(post) => match post.data() {
Ok(content) => Html(content.to_html(&state.templates)),
Ok(content) => Html(
content.to_html(
&state.templates,
&state.ps,
state
.ts
.get(two_face::theme::EmbeddedThemeName::GruvboxDark),
),
),
Err(e) => Html(e.to_string()),
},
None => Html("<h1>404 - Not Found</h1>".to_string()),