From ffca6175c0ad281d42f3f3dbedc2f72b00811024 Mon Sep 17 00:00:00 2001 From: aleidk Date: Wed, 26 Feb 2025 04:16:11 -0300 Subject: [PATCH] feat: add basic htmx example --- Cargo.lock | 32 +++++++++++++++++++++ Cargo.toml | 1 + frontend/templates/base.html | 3 +- frontend/templates/index.html | 52 ++++++++++++++++++++--------------- src/main.rs | 2 ++ src/router.rs | 15 ++++++++-- 6 files changed, 80 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4bdeaa6..35989ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,6 +117,23 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-htmx" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16a4be621f96b959fc829e4cbf02fd79ffb8427525002af31a9e2979599fbb7" +dependencies = [ + "axum-core", + "futures", + "futures-core", + "http", + "pin-project-lite", + "serde", + "serde_json", + "tokio", + "tower", +] + [[package]] name = "axum-macros" version = "0.5.0" @@ -250,6 +267,7 @@ name = "compendium" version = "0.1.0" dependencies = [ "axum", + "axum-htmx", "axum-sqlx-tx", "chrono", "minijinja", @@ -481,6 +499,20 @@ dependencies = [ "libc", ] +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.31" diff --git a/Cargo.toml b/Cargo.toml index 6565179..3867079 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] axum = { version = "0.8.1", features = ["macros"] } +axum-htmx = { version = "0.7.0", features = ["auto-vary", "serde", "guards"] } axum-sqlx-tx = "0.10.0" chrono = { version = "0.4.39", features = ["serde"] } minijinja = { version = "2.7.0", features = ["loader"] } diff --git a/frontend/templates/base.html b/frontend/templates/base.html index 108110e..d5b63a4 100644 --- a/frontend/templates/base.html +++ b/frontend/templates/base.html @@ -1,10 +1,11 @@ + - + {% block title %}Axum web service!{% endblock %} diff --git a/frontend/templates/index.html b/frontend/templates/index.html index 824925a..c7591f0 100644 --- a/frontend/templates/index.html +++ b/frontend/templates/index.html @@ -1,26 +1,34 @@ {% extends "base.html" %} {% block content %} - - - - - - - - - - - - {% for row in rows %} - - - - - - - - {% endfor %} - -
DatabaseVersionDatabase NameCurrent UserCurrent Timestamp
{{ row.database }}{{ row.version }}{{ row.current_database }}{{ row.current_user }}{{ row.current_timestamp }}
+ +
+ +
+ + + {% block htmx %} + + + + + + + + + + + + {% for row in rows %} + + + + + + + + {% endfor %} + +
DatabaseVersionDatabase NameCurrent UserCurrent Timestamp
{{ row.database }}{{ row.version }}{{ row.current_database }}{{ row.current_user }}{{ row.current_timestamp }}
+ {% endblock htmx %} {% endblock content %} diff --git a/src/main.rs b/src/main.rs index 80c905b..824067f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![allow(unused)] #![allow(dead_code)] +use axum_htmx::AutoVaryLayer; use compendium::{router, AppState, Error, Link, Result, Tx}; use minijinja::{Environment, Value}; use sqlx::postgres::PgPoolOptions; @@ -78,6 +79,7 @@ async fn main() -> Result<()> { let app = router::new() .layer(TraceLayer::new_for_http().on_request(())) .layer(tx_layer) + .layer(AutoVaryLayer) .with_state(AppState::new(tmpl_env, tx_state)); // Add hot reload only on dev mode diff --git a/src/router.rs b/src/router.rs index 02fb279..9fd870f 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,4 +1,5 @@ use axum::{extract::State, response::Html, routing::get, Router}; +use axum_htmx::HxRequest; use chrono::Utc; use minijinja::context; use serde::Serialize; @@ -22,7 +23,11 @@ struct ExampleRow { pub current_timestamp: chrono::DateTime, } -async fn handler_home(State(state): State, mut tx: Tx) -> ResultTemplate { +async fn handler_home( + State(state): State, + HxRequest(hx_request): HxRequest, + mut tx: Tx, +) -> ResultTemplate { let template = state.tmpl_env.get_template("index.html")?; let rows = sqlx::query_as::<_, ExampleRow>("select 'Postgres' as database, setting as version, current_database(), current_user, current_timestamp from pg_settings where name = 'server_version'") @@ -31,7 +36,13 @@ async fn handler_home(State(state): State, mut tx: Tx) -> ResultTempla println!("{:?}", rows); - let content = template.render(context!(rows => rows))?; + let content = if hx_request { + template + .eval_to_state(context!(rows => rows))? + .render_block("htmx")? + } else { + template.render(context!(rows => rows))? + }; Ok(Html(content)) }