use chrono::TimeDelta; use maud::{Markup, PreEscaped, html}; use page::{ RenderContext, servable::{Page, PageMetadata, PageTemplate}, }; use crate::components::{ fa::FAIcon, md::{Markdown, meta_from_markdown}, misc::FarLink, }; mod handouts; mod index; mod notfound; pub use handouts::handouts; pub use index::index; pub use notfound::notfound; pub fn links() -> Page { /* Dead links: https://www.commitstrip.com/en/ http://www.3dprintmath.com/ */ page_from_markdown( include_str!("links.md"), Some("/assets/img/icon.png".to_owned()), ) } pub fn betalupi() -> Page { page_from_markdown( include_str!("betalupi.md"), Some("/assets/img/icon.png".to_owned()), ) } pub fn htwah_typesetting() -> Page { page_from_markdown( include_str!("htwah-typesetting.md"), Some("/assets/img/icon.png".to_owned()), ) } // // MARK: md // fn page_from_markdown(md: impl Into, default_image: Option) -> Page { let md: String = md.into(); let md = Markdown::parse(&md); let mut meta = meta_from_markdown(&md) .unwrap_or(Some(PageMetadata { title: "Invalid frontmatter!".into(), ..Default::default() })) .unwrap_or_default(); if meta.image.is_none() { meta.image = default_image } let html = PreEscaped(md.render()); MAIN_TEMPLATE .derive(meta, move |_page, ctx| { let html = html.clone(); Box::pin(async move { html! { div class="wrapper" style="margin-top:3ex;" { @if let Some(backlinks) = backlinks(ctx) { (backlinks) } (html) (footer()) } } }) }) .html_ttl(Some(TimeDelta::days(1))) .immutable(true) } // // MARK: components // const MAIN_TEMPLATE: PageTemplate = PageTemplate { // Order matters, base htmx goes first scripts_linked: &["/assets/htmx.js", "/assets/htmx-json.js"], // TODO: use htmx for this scripts_inline: &[" window.onload = function() { var imgs = document.querySelectorAll('.img-placeholder'); imgs.forEach(img => { img.style.border = 'none'; img.style.filter = 'blur(10px)'; img.style.transition = 'filter 0.3s'; var lg = new Image(); lg.src = img.dataset.large; lg.onload = function () { img.src = img.dataset.large; img.style.filter = 'blur(0px)'; }; }) } "], styles_inline: &[], styles_linked: &["/assets/css/main.css"], extra_meta: &[( "viewport", "width=device-width,initial-scale=1,user-scalable=no", )], ..PageTemplate::const_default() }; pub fn backlinks(ctx: &RenderContext) -> Option { let mut backlinks = vec![("/", "home")]; let mut segments = ctx.route.split("/").skip(1).collect::>(); let last = segments.pop(); let mut end = 0; for s in segments { end += s.len(); backlinks.push((&ctx.route[0..=end], s)); end += 1; // trailing slash } last.map(|last| { html! { div { @for (url, text) in backlinks { a href=(url) style="padding-left:5pt;padding-right:5pt;" { (text) } "/" } span style="color:var(--metaColor);padding-left:5pt;padding-right:5pt;" { (last) } } } }) } pub fn footer() -> Markup { html!( footer style="margin-top:10rem;" { hr class = "footline"; div class = "footContainer" { p { "This site was built by hand with " (FarLink("https://rust-lang.org", "Rust")) ", " (FarLink("https://maud.lambda.xyz", "Maud")) ", and " (FarLink("https://docs.rs/axum/latest/axum", "Axum")) ". " ( FarLink( "https://git.betalupi.com/Mark/webpage", html!( (FAIcon::Git) "Source here!" ) ) ) } } } ) }