//! # Rust Letter Backend //! //! `rust_letter_be` handles the backend execution using Rocket. #[macro_use] extern crate rocket; /// A module that handles the backend for the site. pub mod web_app_backend { use once_cell::sync::OnceCell; use rocket::fs::FileServer; use rocket::http::{Cookie, CookieJar}; use rocket::response::Redirect; use rocket::{Build, Rocket}; use rocket_dyn_templates::{context, Template}; use void_fe::utils::prop_structs::{PoemDatabase, VoidProps, ContentProps}; use void_fe::utils::user_prefs::*; use void_fe::void_app::{self, VirtualDom}; pub use void_fe::components::void_content::RenderContent; use void_fe::utils::helpers::get_homepage_paragraph; static POEM_DATABASE: OnceCell = OnceCell::new(); async fn get_user_prefs(cookies: &CookieJar<'_>) -> UserPrefs { let user_theme = match cookies.get("theme") { Some(c) => match c.value() { "auto" => ThemePref::Auto, "light" => ThemePref::Light, "dark" => ThemePref::Dark, _ => { cookies.remove("theme"); cookies.add(Cookie::new("theme", "auto")); ThemePref::Auto } }, None => { cookies.add(Cookie::new("theme", "auto")); ThemePref::Auto } }; let user_font = match cookies.get("font") { Some(c) => match c.value() { "nerd" => FontPref::NerdFont, "open" => FontPref::OpenDyslexic, _ => { cookies.remove("font"); cookies.add(Cookie::new("font", "open")); FontPref::OpenDyslexic } }, None => { cookies.add(Cookie::new("font", "open")); FontPref::OpenDyslexic } }; UserPrefs::new(user_theme, user_font) } async fn set_user_theme(cookies: &CookieJar<'_>, theme: &str) { if theme == "light" || theme == "dark" || theme == "auto" { cookies.remove("theme"); cookies.add(Cookie::new("theme", format!("{theme}"))); } else { return; } } async fn set_user_font(cookies: &CookieJar<'_>, font: &str) { if font == "nerd" || font == "open" { cookies.remove("font"); cookies.add(Cookie::new("font", format!("{font}"))); } else { return; } } #[get("/")] async fn index(cookies: &CookieJar<'_>) -> Template { let user_prefs = get_user_prefs(cookies).await; let void_props = VoidProps { slug: None, poem_database: POEM_DATABASE .get() .expect("Poem database is not initialized") .clone(), user_prefs: user_prefs, }; // let content_props = ContentProps { // content: get_homepage_paragraph(), // user_prefs: user_prefs // }; // let mut vdom = VirtualDom::new_with_props(void_app::HomePage, void_props); let mut vdom = VirtualDom::new_with_props(void_app::HomePage, void_fe::void_app::HomePageProps { props: void_props }); let _ = vdom.rebuild_in_place(); let output = dioxus_ssr::render(&vdom); Template::render( "index", context! { app_title: "A Letter to the Void", style_include: "", test: &output, dark_mode: "", }, ) } #[get("/", rank = 3)] async fn settings(cookies: &CookieJar<'_>) -> Template { let user_prefs = get_user_prefs(cookies).await; let mut vdom = VirtualDom::new_with_props(void_app::SettingsPage, user_prefs); let _ = vdom.rebuild_in_place(); let output = dioxus_ssr::render(&vdom); Template::render( "index", context! { app_title: "Settings", style_include: "", test: &output, dark_mode: "" }, ) } #[get("/?", rank = 2)] async fn theme(cookies: &CookieJar<'_>, theme: &str) -> Redirect { set_user_theme(cookies, theme).await; Redirect::to("/settings") } #[get("/?")] async fn font(cookies: &CookieJar<'_>, font: &str) -> Redirect { set_user_font(cookies, font).await; Redirect::to("/settings") } #[get("/")] async fn poem_list(cookies: &CookieJar<'_>) -> Template { let user_prefs = get_user_prefs(cookies).await; let void_props = VoidProps { slug: None, poem_database: POEM_DATABASE .get() .expect("Poem database is not initialized") .clone(), user_prefs: user_prefs, }; let mut vdom = VirtualDom::new_with_props(void_app::PoemListPage, void_props); let _ = vdom.rebuild_in_place(); let output = dioxus_ssr::render(&vdom); Template::render( "index", context! { app_title: "A Letter to the Void", style_include: "", test: &output, dark_mode: "", }, ) } #[get("/")] async fn poem(cookies: &CookieJar<'_>, entry: &str) -> Template { let user_prefs = get_user_prefs(cookies).await; let void_props = VoidProps { slug: Some(entry.to_string()), poem_database: POEM_DATABASE .get() .expect("Poem database is not initialized") .clone(), user_prefs: user_prefs, }; let mut vdom = VirtualDom::new_with_props(void_app::PoemPage, void_props); let _ = vdom.rebuild_in_place(); let output = dioxus_ssr::render(&vdom); Template::render( "index", context! { app_title: "A Letter to the Void", style_include: "", test: &output, dark_mode: "", }, ) } /// This runs `rocket::build()` with the needed mounts and routes. pub async fn build_rocket() -> Rocket { let mut poem_database = PoemDatabase::new(); poem_database.build_poem_database().await; POEM_DATABASE.set(poem_database).expect("Could not initialize poem database."); rocket::build() .mount("/images", FileServer::from("public/images")) .mount("/styles", FileServer::from("public/styles")) .mount("/fonts", FileServer::from("public/fonts")) .mount("/poems", routes![poem_list, poem]) .mount("/settings", routes![settings, theme, font]) .mount("/", routes![index]) .attach(Template::fairing()) } }