diff --git a/src/main.rs b/src/main.rs index 83627d3..5536a58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ mod cli; mod db; mod server; -mod template; use std::{ fs, diff --git a/src/server/events.rs b/src/server/events.rs index d23d539..ba34300 100644 --- a/src/server/events.rs +++ b/src/server/events.rs @@ -1,10 +1,7 @@ use axum::{extract::State, response::Html, routing::post, Form, Router}; use tera::Context; -use crate::{ - db, - template::{Template, Update}, -}; +use crate::db; pub fn app() -> axum::Router { Router::new().route("/", post(post_event)) @@ -20,5 +17,5 @@ async fn post_event( let mut context = Context::new(); context.insert("event", &event); - Ok(Html(Update::EventLi.render(&ctx.tera, &context)?)) + Ok(Html(ctx.tera.render("updates/event_li.html", &context)?)) } diff --git a/src/server/images.rs b/src/server/images.rs index bd9203b..0ea87f1 100644 --- a/src/server/images.rs +++ b/src/server/images.rs @@ -20,7 +20,6 @@ use std::{io::BufWriter, path::PathBuf}; use super::error::AppError; use crate::{ db::{self, Image, NewImage, Pagination}, - template::{Template, View}, IMG_DIR, }; @@ -78,9 +77,12 @@ async fn get_images( let is_final_page = images.len() < page.per_page.try_into().unwrap(); context.insert("is_final_page", &is_final_page); - Ok(Html( - View::Images.headers(&headers).render(&ctx.tera, &context)?, - )) + Ok(Html(super::render_view( + &ctx.tera, + "views/images.html", + &context, + &headers, + )?)) } async fn get_image_original( diff --git a/src/server/mod.rs b/src/server/mod.rs index bb99d8e..1af8eed 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -18,14 +18,40 @@ use axum::{ use tera::Context; use tower_http::{services::ServeDir, set_header::SetResponseHeaderLayer}; -use crate::{ - db::Plant, - template::{Template, View}, -}; +use crate::db::Plant; pub type Result = std::result::Result; const HX_REQUEST_HEADER: &str = "HX-Request"; +const HX_HISTORY_RESTORE_HEADER: &str = "HX-History-Restore-Request"; + +pub fn should_render_full(headers: &HeaderMap) -> bool { + let is_htmx_req = headers.get(HX_REQUEST_HEADER).is_some(); + let is_hist_restore_req = headers + .get(HX_HISTORY_RESTORE_HEADER) + .map(|val| val == HeaderValue::from_static("true")) + .unwrap_or(false); + + !is_htmx_req || is_hist_restore_req +} + +pub fn render_view( + tera: &tera::Tera, + view: &str, + ctx: &tera::Context, + headers: &HeaderMap, +) -> tera::Result { + let view = tera.render(view, ctx)?; + + if should_render_full(headers) { + let mut ctx = tera::Context::new(); + ctx.insert("view", &view); + + tera.render("base.html", &ctx) + } else { + Ok(view) + } +} pub fn app(ctx: crate::Context, static_dir: impl AsRef) -> axum::Router { let router = Router::new() @@ -58,18 +84,23 @@ pub async fn render_home(ctx: crate::Context, headers: &HeaderMap) -> Result Result> { let context = Context::new(); - Ok(Html( - View::Login.headers(headers).render(&ctx.tera, &context)?, - )) + Ok(Html(render_view( + &ctx.tera, + "views/login.html", + &context, + &headers, + )?)) } async fn get_index(State(ctx): State, headers: HeaderMap) -> Result> { diff --git a/src/server/plants.rs b/src/server/plants.rs index 7fbcabc..2bf5c0e 100644 --- a/src/server/plants.rs +++ b/src/server/plants.rs @@ -7,10 +7,7 @@ use axum::{ }; use tera::Context; -use crate::{ - db::{self, DbError, Event, Pagination, Plant}, - template::{Template, Update, View}, -}; +use crate::db::{self, DbError, Event, Pagination, Plant}; use super::{error::AppError, query::ToQuery}; @@ -46,9 +43,12 @@ async fn get_plant_page( context.insert("events", &events); context.insert("event_types", &db::EVENT_TYPES); - Ok(Html( - View::Plant.headers(&headers).render(&ctx.tera, &context)?, - )) + Ok(Html(super::render_view( + &ctx.tera, + "views/plant.html", + &context, + &headers, + )?)) } None => Err(AppError::NotFound), } @@ -75,9 +75,12 @@ async fn get_plants( context.insert("query", &page.to_query().encode()); } - Ok(Html( - View::Plants.headers(&headers).render(&ctx.tera, &context)?, - )) + Ok(Html(super::render_view( + &ctx.tera, + "views/plants.html", + &context, + &headers, + )?)) } async fn post_plant( @@ -90,5 +93,5 @@ async fn post_plant( let mut context = Context::new(); context.insert("plant", &plant); - Ok(Html(Update::PlantLi.render(&ctx.tera, &context)?)) + Ok(Html(ctx.tera.render("updates/plant_li.html", &context)?)) } diff --git a/src/template/mod.rs b/src/template/mod.rs deleted file mode 100644 index 757dbcc..0000000 --- a/src/template/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -mod update; -mod view; - -pub use update::Update; -pub use view::View; - -pub trait Template { - /// Returns the name or path used to identify the template in the Tera struct - fn template(&self) -> &'static str; - - /// Render the template with the given context - fn render(&self, tera: &tera::Tera, ctx: &tera::Context) -> tera::Result { - tera.render(self.template(), ctx) - } -} diff --git a/src/template/update.rs b/src/template/update.rs deleted file mode 100644 index 14039f8..0000000 --- a/src/template/update.rs +++ /dev/null @@ -1,15 +0,0 @@ -use super::Template; - -pub enum Update { - EventLi, - PlantLi, -} - -impl Template for Update { - fn template(&self) -> &'static str { - match self { - Update::EventLi => "updates/event_li.html", - Update::PlantLi => "updates/plant_li.html", - } - } -} diff --git a/src/template/view.rs b/src/template/view.rs deleted file mode 100644 index 6d06da2..0000000 --- a/src/template/view.rs +++ /dev/null @@ -1,68 +0,0 @@ -use axum::http::{HeaderMap, HeaderValue}; - -use super::Template; - -const HX_REQUEST_HEADER: &str = "HX-Request"; -const HX_HISTORY_RESTORE_HEADER: &str = "HX-History-Restore-Request"; - -#[derive(Clone, Copy)] -pub enum View { - Plant, - Plants, - Images, - Index, - Login, -} - -impl View { - pub fn headers(self, headers: &HeaderMap) -> ViewWrapper { - let is_htmx_req = headers.get(HX_REQUEST_HEADER).is_some(); - let is_hist_restore_req = headers - .get(HX_HISTORY_RESTORE_HEADER) - .map(|val| val == HeaderValue::from_static("true")) - .unwrap_or(false); - - let include_base = !is_htmx_req || is_hist_restore_req; - - ViewWrapper { - view: self, - include_base, - } - } -} - -impl Template for View { - fn template(&self) -> &'static str { - match self { - View::Plant => "views/plant.html", - View::Plants => "views/plants.html", - View::Index => "views/index.html", - View::Images => "views/images.html", - View::Login => "views/login.html", - } - } -} - -pub struct ViewWrapper { - view: View, - include_base: bool, -} - -impl Template for ViewWrapper { - fn template(&self) -> &'static str { - self.view.template() - } - - fn render(&self, tera: &tera::Tera, ctx: &tera::Context) -> tera::Result { - let view = self.view.render(tera, ctx)?; - - if self.include_base { - let mut ctx = tera::Context::new(); - ctx.insert("view", &view); - - tera.render("base.html", &ctx) - } else { - Ok(view) - } - } -}