use axum::response::IntoResponse; use maud::{html, Markup, DOCTYPE}; use crate::db::product::{Product, ProductMarker}; use crate::error::AppError; pub async fn home() -> Result { Ok(html!((page("Home".to_string(), Markup::default())))) } fn page(page_title: String, content: Markup) -> Markup { html!( (head(page_title)) body class="bg-[#eae3d2] text-[#333] dark:bg-[#333] dark:text-[#eae3d2] font-mono text-base" { (header()) (navbar()) (content) } ) } fn header() -> Markup { html!( header { h1 class="underline decoration-[#601B69] dark:decoration-[#e1b1e7] text-center tracking-widest font-serif p-3 text-xl" {"Vithuran Vishnuthas"} } ) } fn navbar() -> Markup { html!({ navbar class="p-3 text-sm flex flex-row flex-wrap content-center justify-around decoration-[#eae3d2] tracking-wide" { a class="hover:underline" href="/" { "Home" } a class="hover:underline" href="/stories" { "Stories" } a class="hover:underline" href="/" { "Tools" } a class="hover:underline" href="/" { "Games" } } }) } fn cards( products: Vec>, category: String, ) -> Markup { html!( div class="m-12" { h1 class="p-6 font-serif text-xl tracking-wider underline decoration-[#601B69] dark:decoration-[#E1B1E7]" { (category) } div class="grid grid-cols-2 gap-8" { @for product in products { (card(product)) } } } ) } fn card(specific_product: SpecificProduct) -> Markup { html!( div class="p-9 shadow" { h2 class="text-[#601B69] dark:text-[#E1B1E7]" { (specific_product.product.name) } div { (specific_product.product.description) } div { (specific_product.specific.product_specific_card_content()) } div class="flex flex-row space-x-5 mt-9 text-xs" { span {"Update: " (specific_product.product.updatedate)} span {"Upload: " (specific_product.product.uploaddate)} } } ) } fn head(page_title: String) -> Markup { html! { head { (DOCTYPE) meta charset="utf-8"; link rel="stylesheet" type="text/css" href="/static/styles.css"; title { (page_title) } } } } pub async fn build_page( ) -> Result { Ok(html!( (page(T::page_title(), cards(T::products(), T::page_title()))) )) } pub trait PageBuilder { fn page_title() -> String; fn products() -> Vec> where Self: Sized + ProductMarker; fn product_specific_card_content(&self) -> Markup; } // TODO: Remove after first implementation #[derive(Hash, PartialEq, Eq)] pub struct DummyProduct { dummy: String, } impl PageBuilder for DummyProduct { fn page_title() -> String { "Dummy Products".to_string() } fn products() -> Vec> where Self: Sized, { let product1 = Product { id: 0, name: "Willensfreiheit in Ketten".to_string(), description: "Nach der Flucht seines Bruders, verzweifelt Fahim an der Existenz der Willensfreiheit." .to_string(), uploaddate: 1, updatedate: 1, }; let product2 = Product { id: 1, name: "Aufbruch und Abbruch".to_string(), description: "Ein frischer Absolvent muss sich vor der ersten Quest nur noch bei der Gilde für Heilkünstler anmelden.".to_string(), uploaddate: 1, updatedate: 1, }; let product3 = Product { id: 2, name: "Mit gutem Gewissen".to_string(), description: "Ein frischer Absolvent muss sich vor der ersten Quest nur noch bei der Gilde für Heilkünstler anmelden.".to_string(), uploaddate: 1, updatedate: 1, }; let test1 = DummyProduct { dummy: "/".to_string(), }; let test2 = DummyProduct { dummy: "/".to_string(), }; let test3 = DummyProduct { dummy: "/".to_string(), }; let specific1 = SpecificProduct { product: product1, specific: test1, }; let specific2 = SpecificProduct { product: product2, specific: test2, }; let specific3 = SpecificProduct { product: product3, specific: test3, }; vec![specific1, specific2, specific3] } fn product_specific_card_content(&self) -> Markup { html!( a class="mt-9 text-[#601B69] dark:text-[#E1B1E7]" href=(self.dummy) { "Link" } ) } } impl ProductMarker for DummyProduct {} // TODO: Refactoring pub struct SpecificProduct { product: Product, specific: T, }