page rewrite
Some checks failed
CI / Check typos (push) Successful in 1m3s
CI / Check links (push) Failing after 1m14s
CI / Clippy (push) Successful in 1m43s
CI / Build and test (push) Successful in 1m31s
CI / Build container (push) Successful in 1m45s
CI / Deploy on waypoint (push) Failing after 1m23s
Some checks failed
CI / Check typos (push) Successful in 1m3s
CI / Check links (push) Failing after 1m14s
CI / Clippy (push) Successful in 1m43s
CI / Build and test (push) Successful in 1m31s
CI / Build container (push) Successful in 1m45s
CI / Deploy on waypoint (push) Failing after 1m23s
This commit is contained in:
@@ -28,3 +28,4 @@ toml = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tower-http = { workspace = true }
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use lazy_static::lazy_static;
|
||||
use markdown_it::generics::inline::full_link;
|
||||
use markdown_it::{MarkdownIt, Node};
|
||||
use maud::{Markup, PreEscaped, Render, html};
|
||||
use page::RequestContext;
|
||||
use page::page::{Page, PageMetadata};
|
||||
use maud::{Markup, PreEscaped, Render};
|
||||
use page::servable::PageMetadata;
|
||||
|
||||
use crate::components::md::emote::InlineEmote;
|
||||
use crate::components::md::frontmatter::{TomlFrontMatter, YamlFrontMatter};
|
||||
@@ -86,10 +85,6 @@ impl Markdown<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// MARK: helpers
|
||||
//
|
||||
|
||||
/// Try to read page metadata from a markdown file's frontmatter.
|
||||
/// - returns `none` if there is no frontmatter
|
||||
/// - returns an error if we fail to parse frontmatter
|
||||
@@ -101,33 +96,3 @@ pub fn meta_from_markdown(root_node: &Node) -> Result<Option<PageMetadata>, toml
|
||||
.map(|x| toml::from_str::<PageMetadata>(&x.content))
|
||||
.map_or(Ok(None), |v| v.map(Some))
|
||||
}
|
||||
|
||||
pub fn backlinks(page: &Page, ctx: &RequestContext) -> Option<Markup> {
|
||||
let mut last = None;
|
||||
let mut backlinks = vec![("/", "home")];
|
||||
|
||||
if page.meta.backlinks.unwrap_or(false) {
|
||||
let mut segments = ctx.route.split("/").skip(1).collect::<Vec<_>>();
|
||||
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) }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,18 +6,17 @@ use std::{
|
||||
|
||||
use chrono::{DateTime, TimeDelta, Utc};
|
||||
use maud::{Markup, PreEscaped, html};
|
||||
use page::{DeviceType, RequestContext, page::Page};
|
||||
use page::{DeviceType, RenderContext, servable::Page};
|
||||
use parking_lot::Mutex;
|
||||
use reqwest::StatusCode;
|
||||
use serde::Deserialize;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use crate::{
|
||||
components::{
|
||||
md::{Markdown, backlinks, meta_from_markdown},
|
||||
md::{Markdown, meta_from_markdown},
|
||||
misc::FarLink,
|
||||
},
|
||||
pages::page_wrapper,
|
||||
pages::{MAIN_TEMPLATE, backlinks, footer},
|
||||
};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -114,11 +113,7 @@ async fn get_index() -> Result<Vec<HandoutEntry>, reqwest::Error> {
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
fn build_list_for_group(
|
||||
handouts: &[HandoutEntry],
|
||||
group: &str,
|
||||
req_ctx: &RequestContext,
|
||||
) -> Markup {
|
||||
fn build_list_for_group(handouts: &[HandoutEntry], group: &str, req_ctx: &RenderContext) -> Markup {
|
||||
let mobile = req_ctx.client_info.device_type == DeviceType::Mobile;
|
||||
|
||||
if mobile {
|
||||
@@ -198,74 +193,79 @@ pub fn handouts() -> Page {
|
||||
|
||||
let html = PreEscaped(md.render());
|
||||
|
||||
Page {
|
||||
meta,
|
||||
html_ttl: Some(TimeDelta::seconds(300)),
|
||||
immutable: false,
|
||||
response_code: StatusCode::OK,
|
||||
|
||||
generate_html: Box::new(move |page, ctx| {
|
||||
let html = html.clone(); // TODO: find a way to not clone here
|
||||
MAIN_TEMPLATE
|
||||
.derive(meta, move |page, ctx| {
|
||||
let html = html.clone();
|
||||
let index = index.clone();
|
||||
Box::pin(async move {
|
||||
let handouts = index.get().await;
|
||||
|
||||
let fallback = html! {
|
||||
span style="color:var(--yellow)" {
|
||||
"Could not load handouts, something broke."
|
||||
}
|
||||
" "
|
||||
(
|
||||
FarLink(
|
||||
"https://git.betalupi.com/Mark/-/packages/generic/ormc-handouts/latest",
|
||||
"Try this direct link."
|
||||
)
|
||||
)
|
||||
};
|
||||
|
||||
let warmups = match &*handouts {
|
||||
Ok(handouts) => build_list_for_group(handouts, "Warm-Ups", ctx),
|
||||
Err(error) => {
|
||||
warn!("Could not load handout index: {error:?}");
|
||||
fallback.clone()
|
||||
}
|
||||
};
|
||||
|
||||
let advanced = match &*handouts {
|
||||
Ok(handouts) => build_list_for_group(handouts, "Advanced", ctx),
|
||||
Err(_) => fallback,
|
||||
};
|
||||
|
||||
let inner = html! {
|
||||
@if let Some(backlinks) = backlinks(page, ctx) {
|
||||
(backlinks)
|
||||
}
|
||||
|
||||
(html)
|
||||
|
||||
(Markdown(concat!(
|
||||
"## Warm-Ups",
|
||||
"\n\n",
|
||||
"Students never show up on time. Some come early, some come late. Warm-ups ",
|
||||
"are my solution to this problem: we hand these out as students walk in, ",
|
||||
"giving them something to do until we can start the lesson.",
|
||||
)))
|
||||
(warmups)
|
||||
br {}
|
||||
|
||||
(Markdown(concat!(
|
||||
"## Advanced",
|
||||
"\n\n",
|
||||
"The highest level of the ORMC, and the group I spend most of my time with. ",
|
||||
"Students in ORMC Advanced are in high school, which means ",
|
||||
"they're ~14-18 years old.",
|
||||
)))
|
||||
(advanced)
|
||||
br {}
|
||||
};
|
||||
|
||||
page_wrapper(&page.meta, inner, true).await
|
||||
})
|
||||
}),
|
||||
}
|
||||
render(html, index, page, ctx)
|
||||
})
|
||||
.html_ttl(Some(TimeDelta::seconds(300)))
|
||||
}
|
||||
|
||||
fn render<'a>(
|
||||
html: Markup,
|
||||
index: Arc<CachedRequest<Result<Vec<HandoutEntry>, reqwest::Error>>>,
|
||||
_page: &'a Page,
|
||||
ctx: &'a RenderContext,
|
||||
) -> Pin<Box<dyn Future<Output = Markup> + Send + Sync + 'a>> {
|
||||
Box::pin(async move {
|
||||
let handouts = index.get().await;
|
||||
|
||||
let fallback = html! {
|
||||
span style="color:var(--yellow)" {
|
||||
"Could not load handouts, something broke."
|
||||
}
|
||||
" "
|
||||
(
|
||||
FarLink(
|
||||
"https://git.betalupi.com/Mark/-/packages/generic/ormc-handouts/latest",
|
||||
"Try this direct link."
|
||||
)
|
||||
)
|
||||
};
|
||||
|
||||
let warmups = match &*handouts {
|
||||
Ok(handouts) => build_list_for_group(handouts, "Warm-Ups", ctx),
|
||||
Err(error) => {
|
||||
warn!("Could not load handout index: {error:?}");
|
||||
fallback.clone()
|
||||
}
|
||||
};
|
||||
|
||||
let advanced = match &*handouts {
|
||||
Ok(handouts) => build_list_for_group(handouts, "Advanced", ctx),
|
||||
Err(_) => fallback,
|
||||
};
|
||||
|
||||
html! {
|
||||
div class="wrapper" style="margin-top:3ex;" {
|
||||
@if let Some(backlinks) = backlinks(ctx) {
|
||||
(backlinks)
|
||||
}
|
||||
|
||||
(html)
|
||||
|
||||
(Markdown(concat!(
|
||||
"## Warm-Ups",
|
||||
"\n\n",
|
||||
"Students never show up on time. Some come early, some come late. Warm-ups ",
|
||||
"are my solution to this problem: we hand these out as students walk in, ",
|
||||
"giving them something to do until we can start the lesson.",
|
||||
)))
|
||||
(warmups)
|
||||
br {}
|
||||
|
||||
(Markdown(concat!(
|
||||
"## Advanced",
|
||||
"\n\n",
|
||||
"The highest level of the ORMC, and the group I spend most of my time with. ",
|
||||
"Students in ORMC Advanced are in high school, which means ",
|
||||
"they're ~14-18 years old.",
|
||||
)))
|
||||
(advanced)
|
||||
br {}
|
||||
(footer())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use maud::html;
|
||||
use page::page::{Page, PageMetadata};
|
||||
use maud::{Markup, html};
|
||||
use page::{
|
||||
RenderContext,
|
||||
servable::{Page, PageMetadata},
|
||||
};
|
||||
use std::pin::Pin;
|
||||
|
||||
use crate::{
|
||||
components::{
|
||||
@@ -8,76 +12,78 @@ use crate::{
|
||||
md::Markdown,
|
||||
misc::FarLink,
|
||||
},
|
||||
pages::page_wrapper,
|
||||
pages::{MAIN_TEMPLATE, footer},
|
||||
};
|
||||
|
||||
pub fn index() -> Page {
|
||||
Page {
|
||||
meta: PageMetadata {
|
||||
MAIN_TEMPLATE.derive(
|
||||
PageMetadata {
|
||||
title: "Betalupi: About".into(),
|
||||
author: Some("Mark".into()),
|
||||
description: None,
|
||||
image: Some("/assets/img/icon.png".to_owned()),
|
||||
backlinks: Some(false),
|
||||
},
|
||||
render,
|
||||
)
|
||||
}
|
||||
|
||||
generate_html: Box::new(move |page, _ctx| {
|
||||
Box::pin(async {
|
||||
let inner = html! {
|
||||
h2 id="about" { "About" }
|
||||
fn render<'a>(
|
||||
_page: &'a Page,
|
||||
_ctx: &'a RenderContext,
|
||||
) -> Pin<Box<dyn Future<Output = Markup> + Send + Sync + 'a>> {
|
||||
Box::pin(async {
|
||||
html! {
|
||||
div class="wrapper" style="margin-top:3ex;" {
|
||||
h2 id="about" { "About" }
|
||||
div {
|
||||
|
||||
div {
|
||||
img
|
||||
class="img-placeholder"
|
||||
src="/assets/img/cover-small.jpg?t=maxdim(20,20)"
|
||||
data-large="/assets/img/cover-small.jpg"
|
||||
style="image-rendering:pixelated;float:left;margin:10px;display:block;width:25%;"
|
||||
{}
|
||||
|
||||
img
|
||||
class="img-placeholder"
|
||||
src="/assets/img/cover-small.jpg?t=maxdim(20,20)"
|
||||
data-large="/assets/img/cover-small.jpg"
|
||||
style="image-rendering:pixelated;float:left;margin:10px;display:block;width:25%;"
|
||||
{}
|
||||
div style="margin:2ex 1ex 2ex 1ex;display:inline-block;overflow:hidden;width:60%;" {
|
||||
"Welcome, you've reached Mark's main page. Here you'll find"
|
||||
" links to various projects I've worked on."
|
||||
|
||||
div style="margin:2ex 1ex 2ex 1ex;display:inline-block;overflow:hidden;width:60%;" {
|
||||
"Welcome, you've reached Mark's main page. Here you'll find"
|
||||
" links to various projects I've worked on."
|
||||
ul {
|
||||
li { (MangledBetaEmail {}) }
|
||||
li { (MangledGoogleEmail {}) }
|
||||
|
||||
ul {
|
||||
li { (MangledBetaEmail {}) }
|
||||
li { (MangledGoogleEmail {}) }
|
||||
|
||||
li {
|
||||
(
|
||||
FarLink(
|
||||
"https://github.com/rm-dr",
|
||||
html!(
|
||||
(FAIcon::Github)
|
||||
"rm-dr"
|
||||
)
|
||||
li {
|
||||
(
|
||||
FarLink(
|
||||
"https://github.com/rm-dr",
|
||||
html!(
|
||||
(FAIcon::Github)
|
||||
"rm-dr"
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
li {
|
||||
(
|
||||
FarLink(
|
||||
"https://git.betalupi.com",
|
||||
html!(
|
||||
(FAIcon::Git)
|
||||
"git.betalupi.com"
|
||||
)
|
||||
li {
|
||||
(
|
||||
FarLink(
|
||||
"https://git.betalupi.com",
|
||||
html!(
|
||||
(FAIcon::Git)
|
||||
"git.betalupi.com"
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
br style="clear:both;" {}
|
||||
}
|
||||
br style="clear:both;" {}
|
||||
}
|
||||
|
||||
(Markdown(include_str!("index.md")))
|
||||
};
|
||||
(Markdown(include_str!("index.md")))
|
||||
|
||||
page_wrapper(&page.meta, inner, true).await
|
||||
})
|
||||
}),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
(footer())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use chrono::TimeDelta;
|
||||
use maud::{DOCTYPE, Markup, PreEscaped, html};
|
||||
use page::page::{Page, PageMetadata};
|
||||
use reqwest::StatusCode;
|
||||
use std::pin::Pin;
|
||||
use maud::{Markup, PreEscaped, html};
|
||||
use page::{
|
||||
RenderContext,
|
||||
servable::{Page, PageMetadata, PageTemplate},
|
||||
};
|
||||
|
||||
use crate::components::{
|
||||
fa::FAIcon,
|
||||
md::{Markdown, backlinks, meta_from_markdown},
|
||||
md::{Markdown, meta_from_markdown},
|
||||
misc::FarLink,
|
||||
};
|
||||
|
||||
@@ -67,120 +68,119 @@ fn page_from_markdown(md: impl Into<String>, default_image: Option<String>) -> P
|
||||
|
||||
let html = PreEscaped(md.render());
|
||||
|
||||
Page {
|
||||
meta,
|
||||
immutable: true,
|
||||
response_code: StatusCode::OK,
|
||||
|
||||
html_ttl: Some(TimeDelta::days(1)),
|
||||
generate_html: Box::new(move |page, ctx| {
|
||||
MAIN_TEMPLATE
|
||||
.derive(meta, move |_page, ctx| {
|
||||
let html = html.clone();
|
||||
|
||||
Box::pin(async move {
|
||||
let inner = html! {
|
||||
@if let Some(backlinks) = backlinks(page, ctx) {
|
||||
(backlinks)
|
||||
html! {
|
||||
div class="wrapper" style="margin-top:3ex;" {
|
||||
@if let Some(backlinks) = backlinks(ctx) {
|
||||
(backlinks)
|
||||
}
|
||||
|
||||
(html)
|
||||
|
||||
(footer())
|
||||
}
|
||||
|
||||
(html)
|
||||
};
|
||||
|
||||
page_wrapper(&page.meta, inner, true).await
|
||||
}
|
||||
})
|
||||
}),
|
||||
}
|
||||
})
|
||||
.html_ttl(Some(TimeDelta::days(1)))
|
||||
.immutable(true)
|
||||
}
|
||||
|
||||
//
|
||||
// MARK: wrapper
|
||||
// MARK: components
|
||||
//
|
||||
|
||||
pub fn page_wrapper<'a>(
|
||||
meta: &'a PageMetadata,
|
||||
inner: Markup,
|
||||
footer: bool,
|
||||
) -> Pin<Box<dyn Future<Output = Markup> + 'a + Send + Sync>> {
|
||||
Box::pin(async move {
|
||||
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<Markup> {
|
||||
let mut backlinks = vec![("/", "home")];
|
||||
|
||||
let mut segments = ctx.route.split("/").skip(1).collect::<Vec<_>>();
|
||||
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! {
|
||||
(DOCTYPE)
|
||||
html {
|
||||
head {
|
||||
meta charset="UTF8" {}
|
||||
meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" {}
|
||||
meta content="text/html; charset=UTF-8" http-equiv="content-type" {}
|
||||
meta property="og:type" content="website" {}
|
||||
|
||||
link rel="stylesheet" href=("/assets/css/main.css") {}
|
||||
|
||||
(&meta)
|
||||
title { (PreEscaped(meta.title.clone())) }
|
||||
|
||||
|
||||
// Use a small blurred placeholder while full-size images load.
|
||||
// Requires no other special scripts or css, just add some tags
|
||||
// to your <img>!
|
||||
script {
|
||||
(PreEscaped("
|
||||
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)';
|
||||
};
|
||||
})
|
||||
}
|
||||
"))
|
||||
}
|
||||
div {
|
||||
@for (url, text) in backlinks {
|
||||
a href=(url) style="padding-left:5pt;padding-right:5pt;" { (text) }
|
||||
"/"
|
||||
}
|
||||
|
||||
body {
|
||||
main{
|
||||
div class="wrapper" style=(
|
||||
// for 404 page. Margin makes it scroll.
|
||||
match footer {
|
||||
true => "margin-top:3ex;",
|
||||
false =>""
|
||||
}
|
||||
) {
|
||||
(inner)
|
||||
|
||||
@if footer {
|
||||
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!"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
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!"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,34 +1,29 @@
|
||||
use maud::html;
|
||||
use page::page::{Page, PageMetadata};
|
||||
use page::servable::{Page, PageMetadata};
|
||||
use reqwest::StatusCode;
|
||||
|
||||
use crate::pages::page_wrapper;
|
||||
use crate::pages::MAIN_TEMPLATE;
|
||||
|
||||
pub fn notfound() -> Page {
|
||||
Page {
|
||||
meta: PageMetadata {
|
||||
title: "Betalupi: About".into(),
|
||||
author: None,
|
||||
MAIN_TEMPLATE.derive(
|
||||
PageMetadata {
|
||||
title: "Page not found".into(),
|
||||
author:None,
|
||||
description: None,
|
||||
image: Some("/assets/img/icon.png".to_owned()),
|
||||
backlinks: Some(false),
|
||||
},
|
||||
|
||||
response_code: StatusCode::NOT_FOUND,
|
||||
generate_html: Box::new(move |page, _ctx| {
|
||||
move |_page, _ctx| {
|
||||
Box::pin(async {
|
||||
let inner = html! {
|
||||
div style="display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh" {
|
||||
p style="font-weight:bold;font-size:50pt;margin:0;" { "404" }
|
||||
p style="font-size:13pt;margin:0;color:var(--grey);" { "(page not found)" }
|
||||
a style="font-size:12pt;margin:10pt;padding:5px;" href="/" {"<- Back to site"}
|
||||
html! {
|
||||
div class="wrapper" {
|
||||
div style="display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:100vh" {
|
||||
p style="font-weight:bold;font-size:50pt;margin:0;" { "404" }
|
||||
p style="font-size:13pt;margin:0;color:var(--grey);" { "(page not found)" }
|
||||
a style="font-size:12pt;margin:10pt;padding:5px;" href="/" {"<- Back to site"}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
page_wrapper(&page.meta, inner, false).await
|
||||
}
|
||||
})
|
||||
}),
|
||||
|
||||
..Default::default()
|
||||
}
|
||||
},
|
||||
).response_code(StatusCode::NOT_FOUND)
|
||||
}
|
||||
|
||||
@@ -1,27 +1,39 @@
|
||||
use axum::Router;
|
||||
use macro_sass::sass;
|
||||
use page::{PageServer, asset::StaticAsset, redirect::Redirect};
|
||||
use std::sync::Arc;
|
||||
use page::{
|
||||
ServableRoute,
|
||||
servable::{Redirect, StaticAsset},
|
||||
};
|
||||
use toolbox::mime::MimeType;
|
||||
use tower_http::compression::{CompressionLayer, DefaultPredicate};
|
||||
|
||||
use crate::pages;
|
||||
|
||||
pub(super) fn router() -> Router<()> {
|
||||
build_server().into_router()
|
||||
let compression: CompressionLayer = CompressionLayer::new()
|
||||
.br(true)
|
||||
.deflate(true)
|
||||
.gzip(true)
|
||||
.zstd(true)
|
||||
.compress_when(DefaultPredicate::new());
|
||||
|
||||
build_server().into_router().layer(compression)
|
||||
}
|
||||
|
||||
fn build_server() -> Arc<PageServer> {
|
||||
let server = PageServer::new();
|
||||
|
||||
#[expect(clippy::unwrap_used)]
|
||||
server
|
||||
fn build_server() -> ServableRoute {
|
||||
ServableRoute::new()
|
||||
.with_404(pages::notfound())
|
||||
.add_page("/", pages::index())
|
||||
.add_page("/links", pages::links())
|
||||
.add_page("/whats-a-betalupi", pages::betalupi())
|
||||
.add_page("/handouts", pages::handouts())
|
||||
.add_page("/htwah", Redirect::new("/handouts").unwrap())
|
||||
.add_page("/htwah", {
|
||||
#[expect(clippy::unwrap_used)]
|
||||
Redirect::new("/handouts").unwrap()
|
||||
})
|
||||
.add_page("/htwah/typesetting", pages::htwah_typesetting())
|
||||
.add_page("/assets/htmx.js", page::HTMX_2_0_8)
|
||||
.add_page("/assets/htmx-json.js", page::EXT_JSON_1_19_12)
|
||||
//
|
||||
.add_page(
|
||||
"/assets/css/main.css",
|
||||
@@ -185,9 +197,7 @@ fn build_server() -> Arc<PageServer> {
|
||||
bytes: include_bytes!("../../assets/htwah/spacing-b.pdf"),
|
||||
mime: MimeType::Pdf,
|
||||
},
|
||||
);
|
||||
|
||||
server
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -197,7 +207,6 @@ fn server_builds_without_panic() {
|
||||
.build()
|
||||
.unwrap()
|
||||
.block_on(async {
|
||||
// Needs tokio context
|
||||
let _server = build_server().into_router();
|
||||
let _server = build_server();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user