calathea/src/template/view.rs

97 lines
2.4 KiB
Rust

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<dyn Template>),
}
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<String> {
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<String> {
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<String> {
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<String> {
let view = self.view.render(tera)?;
self.wrap(tera, view)
}
fn render_ctx(&self, tera: &tera::Tera, ctx: &tera::Context) -> tera::Result<String> {
let view = self.view.render_ctx(tera, ctx)?;
self.wrap(tera, view)
}
}