diff --git a/Cargo.lock b/Cargo.lock index a72ba92..999539e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,61 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "askama" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" -dependencies = [ - "askama_derive", - "askama_escape", - "humansize", - "num-traits", - "percent-encoding", -] - -[[package]] -name = "askama_axum" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41603f7cdbf5ac4af60760f17253eb6adf6ec5b6f14a7ed830cf687d375f163" -dependencies = [ - "askama", - "axum-core", - "http", -] - -[[package]] -name = "askama_derive" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" -dependencies = [ - "askama_parser", - "basic-toml", - "mime", - "mime_guess", - "proc-macro2", - "quote", - "serde", - "syn", -] - -[[package]] -name = "askama_escape" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" - -[[package]] -name = "askama_parser" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" -dependencies = [ - "nom", -] - [[package]] name = "async-trait" version = "0.1.83" @@ -83,12 +28,6 @@ dependencies = [ "syn", ] -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - [[package]] name = "axum" version = "0.7.7" @@ -165,15 +104,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "basic-toml" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" -dependencies = [ - "serde", -] - [[package]] name = "bincode" version = "1.3.3" @@ -199,13 +129,11 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" name = "blog" version = "0.1.0" dependencies = [ - "askama", - "askama_axum", "axum", "http-body-util", "include_dir", + "maud", "pulldown-cmark", - "serde", "syntect", "tokio", "tower", @@ -378,15 +306,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humansize" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" -dependencies = [ - "libm", -] - [[package]] name = "hyper" version = "1.4.1" @@ -463,12 +382,6 @@ version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -488,32 +401,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] -name = "memchr" -version = "2.7.4" +name = "maud" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "df518b75016b4289cdddffa1b01f2122f4a49802c93191f3133f6dc2472ebcaa" +dependencies = [ + "axum-core", + "http", + "itoa", + "maud_macros", +] [[package]] -name = "mime" -version = "0.3.17" +name = "maud_macros" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "fa453238ec218da0af6b11fc5978d3b5c3a45ed97b722391a2a11f3306274e18" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "mime_guess" -version = "2.0.5" +name = "memchr" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] -name = "minimal-lexical" -version = "0.2.1" +name = "mime" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" @@ -536,31 +457,12 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - [[package]] name = "object" version = "0.36.4" @@ -650,6 +552,29 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.86" diff --git a/Cargo.toml b/Cargo.toml index 0c4f074..e222689 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,11 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] -askama = "0.12" -askama_axum = "0.4" axum = "0.7" include_dir = "0.7" -serde = { version = "1.0.210", features = ["derive"] } +maud = { version = "0.26", features = ["axum"] } tokio = { version = "1.40", features = ["macros", "rt-multi-thread", "signal"] } [build-dependencies] diff --git a/README.md b/README.md index 9b66cf6..8fbed1c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This is the source code of my personal website at [khuedoan.com](https://khuedoa - [Rust](https://www.rust-lang.org) - [Axum](https://github.com/tokio-rs/axum) -- [Askama](https://github.com/djc/askama) +- [Maud](https://maud.lambda.xyz) - [Pico CSS](https://picocss.com) - [HTMX](https://htmx.org) diff --git a/content/posts/why-i-rewrote-my-blog-in-rust-twice.md b/content/posts/why-i-rewrote-my-blog-in-rust-twice.md index fdcd048..e67c579 100644 --- a/content/posts/why-i-rewrote-my-blog-in-rust-twice.md +++ b/content/posts/why-i-rewrote-my-blog-in-rust-twice.md @@ -7,7 +7,7 @@ My blog has gone through four major versions: 2. Hugo static site with the PaperMod theme, also on GitHub Pages. 3. NextJS with Tailwind CSS, which never published. 4. First Rust rewrite with Axum, Leptos, Tailwind CSS, on Kubernetes. -5. Second Rust rewrite with Axum, Askama, Pico CSS, HTMX, on Kubernetes. +5. Second Rust rewrite with Axum, Maud, Pico CSS, HTMX, on Kubernetes. ## The stepping stone diff --git a/src/about.rs b/src/about.rs index 56c2502..f189d81 100644 --- a/src/about.rs +++ b/src/about.rs @@ -1,10 +1,34 @@ -use askama_axum::Template; -use axum::response::{IntoResponse, Response}; +use crate::page::base; +use maud::{html, Markup}; -#[derive(Template)] -#[template(path = "about.html")] -pub struct AboutTemplate {} - -pub async fn page() -> Response { - AboutTemplate {}.into_response() +pub async fn view() -> Markup { + base( + "About", + html! { + p { + "Hey there, I'm Khue! I'm a Site Reliability Engineer. I have a wide + range of interests in technology that I love to explore and tinker + with." + } + p { + "When I was in high school, my dad gave me his old laptop and showed me + Linux. I was instantly hooked and spent countless hours customizing it + to my liking, fixing many issues, trying different distros, building my + own themes, and building Linux From Scratch. Those experiences were + super fun and ended up paving the way for my career." + } + p { + "Aside from work, I enjoy staying active through calisthenics and + swimming. I'm also an avid gamer and enjoy playing a variety of games + such as Overwatch, Elden Ring and Hades. I play all my games on Linux, + thanks to Wine and Proton." + } + p { + "If you're interested in checking out some of the projects I've been + working on, be sure to take a look " + a target="_blank" href="https://github.com/khuedoan" { "here" } + ". Who knows, you might find something that scratches your itch!" + } + }, + ) } diff --git a/src/contact.rs b/src/contact.rs index 2f809ca..625c256 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -1,10 +1,22 @@ -use askama_axum::Template; -use axum::response::{IntoResponse, Response}; +use crate::page::base; +use maud::{html, Markup}; -#[derive(Template)] -#[template(path = "contact.html")] -pub struct ContactTemplate {} - -pub async fn page() -> Response { - ContactTemplate {}.into_response() +pub async fn view() -> Markup { + base( + "Contact", + html! { + p { "You can reach me via one of the following links:" } + ul { + li { a target="_blank" href="mailto:mail@khuedoan.com" { "Email" } } + li { a target="_blank" href="https://github.com/khuedoan" { "GitHub" } } + li { a target="_blank" href="https://linkedin.com/in/khuedoan" { "LinkedIn" } } + li { a target="_blank" href="https://twitter.com/KhueDoanID" { "Twitter" } } + } + p { + "If you need to send sensitive information, you can encrypt the message + using my" + } + a target="_blank" href="/gpg" { "GPG public key" } + }, + ) } diff --git a/src/index.rs b/src/index.rs index fc3e07a..e420653 100644 --- a/src/index.rs +++ b/src/index.rs @@ -1,14 +1,36 @@ -use crate::posts::{list_posts, PostMetadata}; -use askama_axum::Template; +use crate::page::base; +use crate::posts::list_posts; +use maud::{html, Markup}; -#[derive(Template)] -#[template(path = "index.html")] -pub struct IndexTemplate { - posts: Vec, -} +pub async fn view() -> Markup { + let posts = list_posts(); -pub async fn page() -> IndexTemplate { - IndexTemplate { - posts: list_posts(), - } + base( + "Hi there, I’m Khue šŸ‘‹", + html! { + p { + "Welcome to my website, where I write about Linux, DevOps, homelab, workflow optimization, and more!" + } + table { + thead { + tr { + th scope="col" { "Title" } + th scope="col" { "Date" } + } + } + @for post in posts { + tr { + th scope="row" { + a href=(format!("/posts/{}", post.id)) class="contrast" { + (post.title) + } + } + th scope="row" { + (post.date) + } + } + } + } + }, + ) } diff --git a/src/main.rs b/src/main.rs index 3a80cc3..ca9a228 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use tokio::signal; mod about; mod contact; mod index; +mod page; mod posts; mod public; @@ -23,10 +24,10 @@ async fn main() { fn app() -> Router { Router::new() - .route("/", get(index::page)) - .route("/posts/:id", get(posts::page)) - .route("/about", get(about::page)) - .route("/contact", get(contact::page)) + .route("/", get(index::view)) + .route("/posts/:id", get(posts::view)) + .route("/about", get(about::view)) + .route("/contact", get(contact::view)) .route("/*path", get(public::file)) } diff --git a/src/page.rs b/src/page.rs new file mode 100644 index 0000000..4ae790f --- /dev/null +++ b/src/page.rs @@ -0,0 +1,34 @@ +use maud::{html, Markup, DOCTYPE}; + +fn header(title: &str) -> Markup { + html! { + (DOCTYPE) + meta charset="utf-8"; + meta name="viewport" content="width=device-width, initial-scale=1"; + meta name="color-scheme" content="light dark"; + link rel="stylesheet" href="/pico.min.css"; + script src="/htmx.min.js" {} + title { (title) } + } +} + +pub fn base(title: &str, body: Markup) -> Markup { + html! { + (header(title)) + header class="container" { + nav { + ul { + li { strong { a href="/" { "Khue Doan" } } } + } + ul { + li { a href="/contact" { "Contact" } } + li { a href="/about" { "About" } } + } + } + } + main class="container" { + h1 { (title) } + (body) + } + } +} diff --git a/src/posts.rs b/src/posts.rs index 658dd65..8660798 100644 --- a/src/posts.rs +++ b/src/posts.rs @@ -1,14 +1,14 @@ -use askama_axum::Template; +use crate::page::base; use axum::{ extract::Path, http::StatusCode, response::{IntoResponse, Response}, }; -use serde::Deserialize; +use maud::PreEscaped; include!(concat!(env!("OUT_DIR"), "/posts_data.rs")); -#[derive(Debug, Deserialize)] +#[derive(Debug)] pub struct PostMetadata { pub id: String, pub title: String, @@ -46,16 +46,9 @@ pub fn get_post(path: String) -> Option<(PostMetadata, String)> { .next() } -#[derive(Template)] -#[template(path = "posts/page.html")] -pub struct PostPageTemplate { - metadata: PostMetadata, - content: String, -} - -pub async fn page(Path(id): Path) -> Response { +pub async fn view(Path(id): Path) -> Response { match get_post(id) { - Some((metadata, content)) => PostPageTemplate { metadata, content }.into_response(), + Some((metadata, content)) => base(&metadata.title, PreEscaped(content)).into_response(), None => (StatusCode::NOT_FOUND).into_response(), } } @@ -67,8 +60,8 @@ mod tests { use http_body_util::BodyExt; #[tokio::test] - async fn rendered_page() { - let response = page(Path("convert-from-init-vim-to-init-lua".to_string())).await; + async fn rendered_content() { + let response = view(Path("convert-from-init-vim-to-init-lua".to_string())).await; assert_eq!(response.status(), StatusCode::OK); let body = String::from_utf8( diff --git a/templates/about.html b/templates/about.html deleted file mode 100644 index ed184ed..0000000 --- a/templates/about.html +++ /dev/null @@ -1,30 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Khue Doan{% endblock title %} - -{% block main %} -

About

-

- Hey there, I'm Khue! I'm a Site Reliability Engineer. I have a wide - range of interests in technology that I love to explore and tinker - with. -

-

- When I was in high school, my dad gave me his old laptop and showed me - Linux. I was instantly hooked and spent countless hours customizing it - to my liking, fixing many issues, trying different distros, building my - own themes, and building Linux From Scratch. Those experiences were - super fun and ended up paving the way for my career. -

-

- Aside from work, I enjoy staying active through calisthenics and - swimming. I'm also an avid gamer and enjoy playing a variety of games - such as Overwatch, Elden Ring and Hades. I play all my games on Linux, - thanks to Wine and Proton. -

-

- If you're interested in checking out some of the projects I've been - working on, be sure to take a look here. - Who knows, you might find something that scratches your itch! -

-{% endblock main %} diff --git a/templates/base.html b/templates/base.html deleted file mode 100644 index 94bf18c..0000000 --- a/templates/base.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - {% block title %} - {% endblock title %} - - {% block head %} - {% endblock head %} - - -
- -
-
- {% block main %} - {% endblock main %} -
- - diff --git a/templates/contact.html b/templates/contact.html deleted file mode 100644 index ca355ca..0000000 --- a/templates/contact.html +++ /dev/null @@ -1,18 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Khue Doan{% endblock title %} - -{% block main %} -

Contact

-

You can reach me via one of the following links:

- -

- If you need to send sensitive information, you can encrypt the message - using my GPG public key. -

-{% endblock main %} diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index 14c7aea..0000000 --- a/templates/index.html +++ /dev/null @@ -1,32 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Khue Doan{% endblock title %} - -{% block main %} -

Hi there, I’m Khue šŸ‘‹

-

- Welcome to my website, where I write about Linux, DevOps, homelab, workflow optimization, and more! -

- - - - - - - - - {% for post in posts %} - - - - - {% endfor %} - -
TitleDate
- - {{ post.title }} - - - {{ post.date }} -
-{% endblock main %} diff --git a/templates/posts/page.html b/templates/posts/page.html deleted file mode 100644 index c433c8a..0000000 --- a/templates/posts/page.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "base.html" %} - -{% block title %}{{ metadata.title }}{% endblock title %} - -{% block main %} -

{{ metadata.title }}

- {{ content|safe }} -{% endblock main %}