use axum::http::{HeaderMap, HeaderValue}; use tera::Context; use super::Template; const HX_REQUEST_HEADER: &str = "HX-Request"; const HX_HISTORY_RESTORE_HEADER: &str = "HX-History-Restore-Request"; pub enum View { Plant, Images, Index, Login, Other(Box), } impl View { pub fn other(tmpl: impl Template + 'static) -> Self { View::Other(Box::new(tmpl)) } 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::Index => "views/index.html", View::Images => "views/images.html", View::Login => "views/login.html", View::Other(tmpl) => tmpl.template(), } } fn render(&self, tera: &tera::Tera) -> tera::Result { match self { View::Other(tmpl) => tmpl.render(tera), _ => tera.render(self.template(), &Context::new()), } } fn render_ctx(&self, tera: &tera::Tera, ctx: &tera::Context) -> tera::Result { match self { View::Other(tmpl) => tmpl.render_ctx(tera, ctx), _ => tera.render(self.template(), ctx), } } } pub struct ViewWrapper { view: View, include_base: bool, } impl ViewWrapper { fn wrap(&self, tera: &tera::Tera, view: String) -> tera::Result { if self.include_base { let mut ctx = tera::Context::new(); ctx.insert("view", &view); tera.render("base.html", &ctx) } else { Ok(view) } } } impl Template for ViewWrapper { fn template(&self) -> &'static str { self.view.template() } fn render(&self, tera: &tera::Tera) -> tera::Result { let view = self.view.render(tera)?; self.wrap(tera, view) } fn render_ctx(&self, tera: &tera::Tera, ctx: &tera::Context) -> tera::Result { let view = self.view.render_ctx(tera, ctx)?; self.wrap(tera, view) } }