use crate::{ routes::ui::account::{ admin::rocket_uri_macro_r_account_admin_dashboard, rocket_uri_macro_r_account_login, rocket_uri_macro_r_account_logout, rocket_uri_macro_r_account_register, session::Session, }, uri, CONF, }; use async_std::task::block_on; use markup::Render; use rocket::{ http::ContentType, response::{self, Responder}, Request, Response, }; use std::io::Cursor; markup::define! { Layout(title: String, main: Main, session: Option) { @markup::doctype() html { head { title { @title " - " @CONF.brand } link[rel="stylesheet", href="/assets/style.css"]; script[src="/assets/bundle.js"] {} } body { nav { h1 { a[href="/"] { @CONF.brand } } @if let Some(_) = session { a[href="/library"] { "My Library" } } div.account { @if let Some(session) = session { span { "Logged in as " @session.user.display_name } @if session.user.admin { a[href=uri!(r_account_admin_dashboard())] { "Administration" } } a[href=uri!(r_account_logout())] { "Log out" } } else { a[href=uri!(r_account_register())] { "Register" } a[href=uri!(r_account_login())] { "Log in" } } } } #main { @main } } } } } pub type DynLayoutPage<'a> = LayoutPage>; pub struct LayoutPage { pub title: String, pub content: T, } impl<'r, Main: Render> Responder<'r, 'static> for LayoutPage
{ fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> { // TODO blocking the event loop here. it seems like there is no other way to // TODO offload this, since the guard references `req` which has a lifetime. // TODO therefore we just block. that is fine since the database is somewhat fast. let session = block_on(req.guard::>()).unwrap(); let mut out = String::new(); Layout { main: self.content, title: self.title, session, } .render(&mut out) .unwrap(); Response::build() .header(ContentType::HTML) .streamed_body(Cursor::new(out)) .ok() } }