feat: getting the hang of htmx
This commit is contained in:
parent
f96bf4d193
commit
4c84c944d4
12 changed files with 153 additions and 46 deletions
|
|
@ -1,23 +1,41 @@
|
|||
mod plants;
|
||||
|
||||
use axum::{
|
||||
extract::State,
|
||||
http::{header::VARY, HeaderMap, HeaderValue},
|
||||
response::Html,
|
||||
routing::{get, post},
|
||||
Form, Router,
|
||||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use tera::Context;
|
||||
use tower_http::set_header::SetResponseHeaderLayer;
|
||||
|
||||
use crate::db;
|
||||
|
||||
const HX_REQUEST_HEADER: &str = "HX-Request";
|
||||
|
||||
pub fn is_htmx_req(headers: &HeaderMap) -> bool {
|
||||
headers.get(HX_REQUEST_HEADER).is_some()
|
||||
}
|
||||
|
||||
pub fn app(ctx: crate::Context) -> axum::Router {
|
||||
let mut router = Router::new()
|
||||
.route("/", get(get_index))
|
||||
.route("/plants", post(post_plants));
|
||||
.with_state(ctx.clone())
|
||||
.nest("/plants", plants::app(ctx.clone()));
|
||||
|
||||
for (name, content) in crate::STATIC_FILES {
|
||||
router = router.route(&format!("/static/{}", name), get(content))
|
||||
}
|
||||
|
||||
router.with_state(ctx)
|
||||
// Routes return either partial or full pages depending on whether the request is done using
|
||||
// HTMX or just as a plain HTTP request. Adding the Vary header ensures caches don't mix
|
||||
// partial and full responses.
|
||||
// https://htmx.org/docs/#caching
|
||||
router.layer(SetResponseHeaderLayer::appending(
|
||||
VARY,
|
||||
HeaderValue::from_static(HX_REQUEST_HEADER),
|
||||
))
|
||||
}
|
||||
|
||||
async fn get_index(State(ctx): State<crate::Context>) -> Html<String> {
|
||||
|
|
@ -30,17 +48,3 @@ async fn get_index(State(ctx): State<crate::Context>) -> Html<String> {
|
|||
context.insert("plants", &plants);
|
||||
Html(ctx.tera.render("index.html", &context).unwrap())
|
||||
}
|
||||
|
||||
async fn post_plants(
|
||||
State(ctx): State<crate::Context>,
|
||||
Form(plant): Form<db::NewPlant>,
|
||||
) -> Html<String> {
|
||||
let plant = tokio::task::spawn_blocking(move || db::insert_plant(&ctx.pool, &plant))
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let mut context = Context::new();
|
||||
context.insert("plant", &plant);
|
||||
Html(ctx.tera.render("plant_li.html", &context).unwrap())
|
||||
}
|
||||
|
|
|
|||
55
src/server/plants.rs
Normal file
55
src/server/plants.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
use axum::{
|
||||
extract::{Path, State},
|
||||
http::HeaderMap,
|
||||
response::Html,
|
||||
routing::{get, post},
|
||||
Form, Router,
|
||||
};
|
||||
use tera::Context;
|
||||
|
||||
use crate::db;
|
||||
|
||||
use super::is_htmx_req;
|
||||
|
||||
pub fn app(ctx: crate::Context) -> axum::Router {
|
||||
Router::new()
|
||||
.route("/:id", get(get_plant_page))
|
||||
.route("/", post(post_plant))
|
||||
.with_state(ctx)
|
||||
}
|
||||
|
||||
async fn get_plant_page(
|
||||
State(ctx): State<crate::Context>,
|
||||
headers: HeaderMap,
|
||||
Path(plant_id): Path<u32>,
|
||||
) -> Html<String> {
|
||||
let plant = tokio::task::spawn_blocking(move || db::get_plant(&ctx.pool, plant_id))
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let mut context = Context::new();
|
||||
context.insert("plant", &plant);
|
||||
|
||||
let tmpl = if is_htmx_req(&headers) {
|
||||
"partials/plant_info.html"
|
||||
} else {
|
||||
"plant_page.html"
|
||||
};
|
||||
|
||||
Html(ctx.tera.render(tmpl, &context).unwrap())
|
||||
}
|
||||
|
||||
async fn post_plant(
|
||||
State(ctx): State<crate::Context>,
|
||||
Form(plant): Form<db::NewPlant>,
|
||||
) -> Html<String> {
|
||||
let plant = tokio::task::spawn_blocking(move || db::insert_plant(&ctx.pool, &plant))
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
let mut context = Context::new();
|
||||
context.insert("plant", &plant);
|
||||
Html(ctx.tera.render("partials/plant_li.html", &context).unwrap())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue