Refactor, create service-assets

This commit is contained in:
2026-03-23 09:46:37 -07:00
parent 368034a177
commit 67e63019c5
61 changed files with 482 additions and 785 deletions

View File

@@ -9,6 +9,7 @@ workspace = true
[dependencies]
libservice = { workspace = true }
service-assets = { workspace = true }
md-footnote = { workspace = true }
@@ -18,7 +19,6 @@ axum = { workspace = true }
tracing = { workspace = true }
maud = { workspace = true }
emojis = { workspace = true }
strum = { workspace = true }
chrono = { workspace = true }
parking_lot = { workspace = true }
lazy_static = { workspace = true }
@@ -28,3 +28,4 @@ reqwest = { workspace = true }
tokio = { workspace = true }
tower-http = { workspace = true }
servable = { workspace = true }
mime = { workspace = true }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

View File

@@ -0,0 +1,145 @@
ul {
list-style: none;
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
li {
margin-bottom: 0.25rem;
}
li p {
margin-bottom: 0.2rem;
}
/* Bonus space after last li */
//li:last-child {
// margin-bottom: 3rem;
//}
ul li::marker {
content: "> ";
color: var(--metaColor);
}
ul li:hover::marker {
content: ">> ";
font-weight: 1000;
color: var(--linkColor);
transition: 100ms;
}
.titleList li {
margin-bottom: .75rem;
}
blockquote {
border-left: .5rem solid var(--metaColor);
margin: 1rem;
padding: 0 0 0 1rem
}
textarea {
border: 2px dotted;
outline: 0;
resize: none;
overflow: auto;
background-color: var(--bgColor)
}
pre .wrap {
overflow: hidden;
overflow-wrap: break-word;
word-break: break-all;
white-space: pre-wrap;
}
pre :not(.wrap) {
padding: 1rem;
font-style: monospace;
white-space: pre;
overflow: scroll;
display: block;
border: solid .2rem transparent;
transition: 150ms;
counter-reset: line;
}
pre:hover {
border: solid .2rem var(--lightBgColor);
}
pre span:first-of-type:before {
border-top: 1px dashed var(--lightBgColor);
}
pre span:before {
counter-increment: line;
content: counter(line, decimal-leading-zero);
display: inline-block;
border-right: 1px solid var(--lightBgColor);
border-bottom: 1px dashed var(--lightBgColor);
padding: 0 .5em;
margin-right: .5em;
color: #888
}
p code,
li code,
div code {
padding: .2rem .4rem .2rem .4rem;
font-size: 85%;
border-radius: .3rem;
color: var(--codeFgColor);
background-color: var(--codeBgColor);
}
pre code {
padding: 0;
border-radius: 0;
color: inherit;
background-color: inherit;
}
table {
table-layout: fixed;
width: 100%;
border-collapse: collapse;
border: none;
margin-left: auto;
margin-right: auto;
margin-bottom: 1rem;
line-height: 1.1
}
thead th:first-child {
width: 20%
}
td,
th {
text-align: left
}
th {
font-weight: 400
}
td,
th {
padding: .5rem;
border: dashed .1rem var(--metaColor)
}
.metaData,
hr,
textarea {
color: var(--metaColor)
}

View File

@@ -0,0 +1,32 @@
img {
max-width: 90%;
height: auto;
margin: .2rem;
padding: .2rem;
border-radius: 15px;
border: solid .2rem transparent;
transition: 150ms;
image-rendering: pixelated;
}
img:hover {
border: solid .2rem var(--metaColor);
transform: scale(1.02);
}
.icons {
width: 2.0rem;
height: 2.0rem;
aspect-ratio: 1/1;
display: inline-block;
vertical-align: middle;
color: var(--fgColor);
fill: var(--fgColor);
background-color: transparent;
}
.icons__background:hover {
background-color: transparent;
color: var(--metaColor);
}

View File

@@ -0,0 +1,119 @@
@import "text";
@import "blocks";
@import "images";
@import "special";
:root {
// Misc colors
--bgColor: #121212;
--lightBgColor: #3a3f46;
--fgColor: #ebebeb;
--metaColor: #6199bb;
--lightMetaColor: #638c86;
--linkColor: #e4dab3;
--codeBgColor: #292929;
--codeFgColor: var(--fgColor);
// Main colors
--grey: #696969;
// Accent colors, used only manally
--green: #a2c579;
--magenta: #ad79c5;
--orange: #e86a33;
--yellow: #e8bc00;
--pink: #fa9f83;
}
::selection,
::-moz-selection {
color: var(--bgColor);
background: var(--metaColor);
}
html {
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-size: 62.5%;
scrollbar-color: var(--metaColor) var(--bgColor);
scrollbar-width: auto;
background: var(--bgColor);
}
body {
font-family: "Fira";
font-size: 1.6rem;
line-height: 1.35;
max-width: 64rem;
margin: auto;
overflow-wrap: break-word;
background: var(--bgColor);
color: var(--fgColor);
}
div.wrapper {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-between;
}
hr.footline {
border: 1pt solid;
}
hr {
border: 1pt dashed;
width: 100%;
}
iframe {
max-width: 90%;
}
.footContainer {
padding-top: 0;
padding-bottom: 1em;
padding-left: 1em;
padding-right: 1em;
}
@media (max-width: 650px) {
.wrapper {
margin: 1rem;
}
}
// Loading spinner (three dots)
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 8px 0;
}
@keyframes dot-bounce {
0%, 80%, 100% { opacity: 0.2; transform: scale(0.8); }
40% { opacity: 1; transform: scale(1); }
}
.search-meta {
font-size: 1.2rem;
color: var(--grey);
margin: 0 0 1.5em 0;
text-align: left;
}
#search-results {
margin-top: 0;
}
#search-results ul {
margin-top: 1.5em;
}

View File

@@ -0,0 +1,88 @@
.handout-li-links {
color: var(--grey);
}
.handout-li-links a {
@extend a;
text-decoration: underline;
text-underline-offset: 1.5pt;
padding-left: 1ex;
padding-right: 1ex;
}
// Only do hover magic on mouse devices
@media(hover: hover) and (pointer: fine) {
.handout-ul li:hover {
margin-left: 1ex;
transition: 50ms;
}
.handout-ul li {
transition: 50ms;
transition-delay: 50ms;
}
.handout-ul li:hover .handout-li-links {
display: inline-block;
opacity: 1;
transition: 100ms;
}
.handout-ul li .handout-li-links {
transition-delay: 50ms;
transition: 100ms;
opacity: 0;
display: none;
}
}
// Email obfuscation
// Works with "{{ email_*() }}" shortcodes.
.eobf {
@extend a;
}
.eobf:hover {
@extend a, :hover;
}
// Change icon on hover
.eobf #eobf-kb,
.eobf:hover #eobf-en {
display: none;
}
.eobf #eobf-en,
.eobf:hover #eobf-kb {
display: inline;
}
// Hover text
.eobf:hover span:before {
unicode-bidi: bidi-override;
direction: ltr;
content: attr(data-h);
}
// Text for email_beta
.eobf-beta span:before {
content: "mo" attr(data-a) "teb" "\0040" attr(data-b) "m";
unicode-bidi: bidi-override;
direction: rtl;
}
// Text for email_goog
.eobf-goog span:before {
content: "mo" attr(data-a) "mg" "\0040" attr(data-b) "p." attr(data-c) "m";
unicode-bidi: bidi-override;
direction: rtl;
}
// Text for email_this
.eobf-this span:before {
content: attr(data-a);
}

View File

@@ -0,0 +1,87 @@
h1 {
font-size: 3.5rem;
margin-top: 1ex;
margin-bottom: 1ex;
}
h2 {
font-size: 2.5rem;
margin-top: 1ex;
margin-bottom: 0.5ex;
}
h3 {
font-size: 2rem;
}
h3::before {
color: var(--lightMetaColor);
content: '## '
}
h1::before,
h2::before,
h4::before,
h5::before,
h6::before {
color: var(--metaColor);
content: '# '
}
a {
text-decoration: none;
border-radius: .3rem;
padding: 0 .2ex 0 .2ex;
color: var(--linkColor);
transition: 150ms;
}
a:hover {
background-color: var(--linkColor);
color: var(--bgColor);
transition: 150ms;
}
footer {
font-size: 1.4rem;
clear: both;
opacity: 0.5;
}
footer {
text-align: left
}
.footnote-item p {
display: inline;
padding: 0 0 0 1rem;
}
hr.footnotes-sep {
margin: 5rem 0 0 0;
}
.footnote-ref > a {
padding: 0 2pt 0.8rem 2pt !important;
}
a.footnote-backref, .footnote-ref > a
{
color: var(--metaColor);
padding: 0 2pt 0 2pt;
}
a.footnote-backref:hover,
.footnote-ref > a:hover
{
color: var(--bgColor);
background-color: var(--metaColor);
}
.footContainer {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}

View File

@@ -1,57 +0,0 @@
use maud::{Markup, Render, html};
use strum::{Display, EnumString};
#[derive(Debug, Clone, Copy, EnumString, Display)]
#[strum(serialize_all = "snake_case")]
pub enum FAIcon {
Github,
Git,
Python,
Rust,
Discord,
Instagram,
Link,
Envelope,
At,
Key,
SStar,
RStar,
Leaf,
Lock,
Fire,
Pen,
Pencil,
}
impl Render for FAIcon {
fn render(&self) -> Markup {
let classes = match self {
Self::Github => "fa-brands fa-github",
Self::Git => "fa-brands fa-git-alt",
Self::Python => "fa-brands fa-python",
Self::Rust => "fa-brands fa-rust",
Self::Discord => "fa-brands fa-discord",
Self::Instagram => "fa-brands fa-instagram",
Self::Link => "fa-solid fa-link",
Self::Envelope => "fa-solid fa-envelope",
Self::At => "fa-solid fa-at",
Self::Key => "fa-solid fa-key",
Self::SStar => "fa-solid fa-star",
Self::RStar => "fa-regular fa-star",
Self::Leaf => "fa-regular fa-leaf",
Self::Lock => "fa-solid fa-lock",
Self::Fire => "fa-solid fa-fire",
Self::Pen => "fa-solid fa-pen-nib",
Self::Pencil => "fa-solid fa-pencil",
};
html!(
i
class=(classes)
style="margin-right:5pt" // TODO: configure, color
{}
)
}
}

View File

@@ -1,10 +1,8 @@
use std::str::FromStr;
use markdown_it::parser::inline::{InlineRule, InlineState};
use markdown_it::{Node, NodeValue, Renderer};
use maud::Render;
use crate::components::fa::FAIcon;
use service_assets::components::fa::FAIcon;
use std::str::FromStr;
#[derive(Debug)]
pub struct InlineEmote(String);

View File

@@ -1,17 +0,0 @@
use maud::{Markup, Render, html};
/// Shorthand for an `<a>` link that opens a new tab
/// Values are (url, text)
pub struct FarLink<'a, T: Render>(pub &'a str, pub T);
impl<T: Render> Render for FarLink<'_, T> {
fn render(&self) -> Markup {
html!(
a
target="_blank"
rel="noopener noreferrer"
href=(self.0)
{ (self.1) }
)
}
}

View File

@@ -1,4 +1,2 @@
pub mod fa;
pub mod mangle;
pub mod md;
pub mod misc;

View File

@@ -31,4 +31,4 @@ A snippet of the [_Endless Sky_][es] map is below.
<br/>
<img class="img-placeholder" src="/assets/img/betalupi.png?t=maxdim(50,50)" data-large="/assets/img/betalupi.png" style="width:100%;height=10rem;"></img>
<img class="img-placeholder" src="/static/img/betalupi.png?t=maxdim(50,50)" data-large="/static/img/betalupi.png" style="width:100%;height=10rem;"></img>

View File

@@ -9,15 +9,16 @@ use maud::{Markup, PreEscaped, html};
use parking_lot::Mutex;
use serde::Deserialize;
use servable::{DeviceType, HtmlPage, RenderContext};
use service_assets::{
assets::{CSS_FIRA, CSS_FONTAWESOME, IMG_ICON},
components::misc::FarLink,
};
use tracing::{debug, warn};
use crate::{
components::{
md::{Markdown, meta_from_markdown},
misc::FarLink,
},
components::md::{Markdown, meta_from_markdown},
pages::{LAZY_IMAGE_JS, backlinks, footer},
routes::{IMG_ICON, MAIN_CSS},
routes::MAIN_CSS,
};
#[derive(Debug, Deserialize)]
@@ -189,13 +190,15 @@ pub static HANDOUTS: LazyLock<HtmlPage> = LazyLock::new(|| {
let mut meta = meta_from_markdown(&md).unwrap().unwrap();
if meta.image.is_none() {
meta.image = Some(IMG_ICON.route().into());
meta.image = Some(IMG_ICON.route_at("/assets"));
}
let html = PreEscaped(md.render());
HtmlPage::default()
.with_style_linked(MAIN_CSS.route())
.with_style_linked(CSS_FIRA.route_at("/assets"))
.with_style_linked(CSS_FONTAWESOME.route_at("/assets"))
.with_script_inline(LAZY_IMAGE_JS)
.with_meta(meta)
.with_render(move |page, ctx| {

View File

@@ -1,27 +1,31 @@
use maud::{Markup, html};
use servable::{HtmlPage, PageMetadata, RenderContext};
use service_assets::{
assets::{CSS_FIRA, CSS_FONTAWESOME, IMG_ICON},
components::{fa::FAIcon, misc::FarLink},
};
use std::{pin::Pin, sync::LazyLock};
use crate::{
components::{
fa::FAIcon,
mangle::{MangledBetaEmail, MangledGoogleEmail},
md::Markdown,
misc::FarLink,
},
pages::{LAZY_IMAGE_JS, footer},
routes::{IMG_ICON, MAIN_CSS},
routes::{IMG_COVER_SMALL, MAIN_CSS},
};
pub static INDEX: LazyLock<HtmlPage> = LazyLock::new(|| {
HtmlPage::default()
.with_style_linked(MAIN_CSS.route())
.with_style_linked(CSS_FIRA.route_at("/assets"))
.with_style_linked(CSS_FONTAWESOME.route_at("/assets"))
.with_script_inline(LAZY_IMAGE_JS)
.with_meta(PageMetadata {
title: "Betalupi: About".into(),
author: Some("Mark".into()),
description: None,
image: Some(IMG_ICON.route().into()),
image: Some(IMG_ICON.route_at("/assets")),
})
.with_render(render)
});
@@ -38,8 +42,8 @@ fn render<'a>(
img
class="img-placeholder"
src="/assets/img/cover-small.jpg?t=maxdim(20,20)"
data-large="/assets/img/cover-small.jpg"
src=(format!("{}?t=maxdim(20,20)", IMG_COVER_SMALL.route()))
data-large=(IMG_COVER_SMALL.route())
style="image-rendering:pixelated;float:left;margin:10px;display:block;width:25%;"
{}

View File

@@ -2,15 +2,15 @@ use chrono::TimeDelta;
use maud::{Markup, PreEscaped, html};
use reqwest::StatusCode;
use servable::{HtmlPage, PageMetadata, RenderContext};
use service_assets::{
assets::{CSS_FIRA, CSS_FONTAWESOME, IMG_ICON},
components::{fa::FAIcon, misc::FarLink},
};
use std::sync::LazyLock;
use crate::{
components::{
fa::FAIcon,
md::{Markdown, meta_from_markdown},
misc::FarLink,
},
routes::{IMG_ICON, MAIN_CSS},
components::md::{Markdown, meta_from_markdown},
routes::MAIN_CSS,
};
mod handouts;
@@ -43,6 +43,8 @@ fn page_from_markdown(md: impl Into<String>, default_image: Option<String>) -> H
HtmlPage::default()
.with_script_inline(LAZY_IMAGE_JS)
.with_style_linked(MAIN_CSS.route())
.with_style_linked(CSS_FIRA.route_at("/assets"))
.with_style_linked(CSS_FONTAWESOME.route_at("/assets"))
.with_meta(meta)
.with_render(move |_page, ctx| {
let html = html.clone();
@@ -162,7 +164,7 @@ pub fn footer() -> Markup {
// MARK: pages
//
pub const LINKS: LazyLock<HtmlPage> = LazyLock::new(|| {
pub static LINKS: LazyLock<HtmlPage> = LazyLock::new(|| {
/*
Dead links:
@@ -170,28 +172,33 @@ pub const LINKS: LazyLock<HtmlPage> = LazyLock::new(|| {
http://www.3dprintmath.com/
*/
page_from_markdown(include_str!("links.md"), Some(IMG_ICON.route().into()))
page_from_markdown(include_str!("links.md"), Some(IMG_ICON.route_at("/assets")))
});
pub const BETALUPI: LazyLock<HtmlPage> = LazyLock::new(|| {
page_from_markdown(include_str!("betalupi.md"), Some(IMG_ICON.route().into()))
pub static BETALUPI: LazyLock<HtmlPage> = LazyLock::new(|| {
page_from_markdown(
include_str!("betalupi.md"),
Some(IMG_ICON.route_at("/assets")),
)
});
pub const HTWAH_TYPESETTING: LazyLock<HtmlPage> = LazyLock::new(|| {
pub static HTWAH_TYPESETTING: LazyLock<HtmlPage> = LazyLock::new(|| {
page_from_markdown(
include_str!("htwah-typesetting.md"),
Some(IMG_ICON.route().into()),
Some(IMG_ICON.route_at("/assets")),
)
});
pub static NOT_FOUND: LazyLock<HtmlPage> = LazyLock::new(|| {
HtmlPage::default()
.with_style_linked(MAIN_CSS.route())
.with_style_linked(CSS_FIRA.route_at("/assets"))
.with_style_linked(CSS_FONTAWESOME.route_at("/assets"))
.with_meta(PageMetadata {
title: "Page not found".into(),
author: None,
description: None,
image: Some(IMG_ICON.route().into()),
image: Some(IMG_ICON.route_at("/assets")),
})
.with_render(
move |_page, _ctx| {

View File

@@ -1,7 +1,5 @@
use axum::Router;
use servable::{
CACHE_BUST_STR, Redirect, ServableRouter, ServableWithRoute, StaticAsset, mime::MimeType,
};
use servable::{CACHE_BUST_STR, Redirect, ServableRouter, ServableWithRoute, StaticAsset};
use tower_http::compression::{CompressionLayer, DefaultPredicate};
use crate::pages;
@@ -17,163 +15,29 @@ pub(super) fn router() -> Router<()> {
build_server().into_router().layer(compression)
}
pub static HTMX: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/htmx-2.0.8.js".into(),
servable::HTMX_2_0_8.with_ttl(None),
);
pub static HTMX_JSON: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/htmx-json-1.19.12.js".into(),
servable::EXT_JSON_1_19_12,
);
pub static MAIN_CSS: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| format!("/assets/{}/css/main.css", *CACHE_BUST_STR),
|| format!("/static/{}/css/main.css", *CACHE_BUST_STR),
StaticAsset {
bytes: grass::include!("css/main.scss").as_bytes(),
mime: MimeType::Css,
bytes: grass::include!("crates/service/service-webpage/css/main.scss").as_bytes(),
mime: mime::TEXT_CSS,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static IMG_COVER_SMALL: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/img/cover-small.jpg".into(),
|| "/static/img/cover-small.jpg".into(),
StaticAsset {
bytes: include_bytes!("../../assets/images/cover-small.jpg"),
mime: MimeType::Jpg,
mime: mime::IMAGE_JPEG,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static IMG_BETALUPI: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/img/betalupi.png".into(),
|| "/static/img/betalupi.png".into(),
StaticAsset {
bytes: include_bytes!("../../assets/images/betalupi-map.png"),
mime: MimeType::Png,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static IMG_ICON: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/img/icon.png".into(),
StaticAsset {
bytes: include_bytes!("../../assets/images/icon.png"),
mime: MimeType::Png,
ttl: StaticAsset::DEFAULT_TTL,
},
);
//
// MARK: fonts
//
pub static FONT_FIRACODE_BOLD: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/FiraCode-Bold.woff2".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fira/FiraCode-Bold.woff2"),
mime: MimeType::Woff2,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FIRACODE_LIGHT: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/FiraCode-Light.woff2".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fira/FiraCode-Light.woff2"),
mime: MimeType::Woff2,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FIRACODE_MEDIUM: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/FiraCode-Medium.woff2".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fira/FiraCode-Medium.woff2"),
mime: MimeType::Woff2,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FIRACODE_REGULAR: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/FiraCode-Regular.woff2".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fira/FiraCode-Regular.woff2"),
mime: MimeType::Woff2,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FIRACODE_SEMIBOLD: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/FiraCode-SemiBold.woff2".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fira/FiraCode-SemiBold.woff2"),
mime: MimeType::Woff2,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FIRACODE_VF: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/FiraCode-VF.woff2".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fira/FiraCode-VF.woff2"),
mime: MimeType::Woff2,
ttl: StaticAsset::DEFAULT_TTL,
},
);
//
// MARK: icons
//
pub static FONT_FA_BRANDS_WOFF2: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/fa/fa-brands-400.woff2".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fa/fa-brands-400.woff2"),
mime: MimeType::Woff2,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FA_REGULAR_WOFF2: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/fa/fa-regular-400.woff2".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fa/fa-regular-400.woff2"),
mime: MimeType::Woff2,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FA_SOLID_WOFF2: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/fa/fa-solid-900.woff2".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fa/fa-solid-900.woff2"),
mime: MimeType::Woff2,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FA_BRANDS_TTF: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/fa/fa-brands-400.ttf".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fa/fa-brands-400.ttf"),
mime: MimeType::Ttf,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FA_REGULAR_TTF: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/fa/fa-regular-400.ttf".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fa/fa-regular-400.ttf"),
mime: MimeType::Ttf,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static FONT_FA_SOLID_TTF: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/fonts/fa/fa-solid-900.ttf".into(),
StaticAsset {
bytes: include_bytes!("../../assets/fonts/fa/fa-solid-900.ttf"),
mime: MimeType::Ttf,
mime: mime::IMAGE_PNG,
ttl: StaticAsset::DEFAULT_TTL,
},
);
@@ -182,55 +46,55 @@ pub static FONT_FA_SOLID_TTF: ServableWithRoute<StaticAsset> = ServableWithRoute
// MARK: htwah
//
pub static HTWAH_DEFINITIONS: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/htwah/definitions.pdf".into(),
|| "/static/htwah/definitions.pdf".into(),
StaticAsset {
bytes: include_bytes!("../../assets/htwah/definitions.pdf"),
mime: MimeType::Pdf,
mime: mime::APPLICATION_PDF,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static HTWAH_NUMBERING: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/htwah/numbering.pdf".into(),
|| "/static/htwah/numbering.pdf".into(),
StaticAsset {
bytes: include_bytes!("../../assets/htwah/numbering.pdf"),
mime: MimeType::Pdf,
mime: mime::APPLICATION_PDF,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static HTWAH_SOLS_A: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/htwah/sols-a.pdf".into(),
|| "/static/htwah/sols-a.pdf".into(),
StaticAsset {
bytes: include_bytes!("../../assets/htwah/sols-a.pdf"),
mime: MimeType::Pdf,
mime: mime::APPLICATION_PDF,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static HTWAH_SOLS_B: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/htwah/sols-b.pdf".into(),
|| "/static/htwah/sols-b.pdf".into(),
StaticAsset {
bytes: include_bytes!("../../assets/htwah/sols-b.pdf"),
mime: MimeType::Pdf,
mime: mime::APPLICATION_PDF,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static HTWAH_SPACING_A: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/htwah/spacing-a.pdf".into(),
|| "/static/htwah/spacing-a.pdf".into(),
StaticAsset {
bytes: include_bytes!("../../assets/htwah/spacing-a.pdf"),
mime: MimeType::Pdf,
mime: mime::APPLICATION_PDF,
ttl: StaticAsset::DEFAULT_TTL,
},
);
pub static HTWAH_SPACING_B: ServableWithRoute<StaticAsset> = ServableWithRoute::new(
|| "/assets/htwah/spacing-b.pdf".into(),
|| "/static/htwah/spacing-b.pdf".into(),
StaticAsset {
bytes: include_bytes!("../../assets/htwah/spacing-b.pdf"),
mime: MimeType::Pdf,
mime: mime::APPLICATION_PDF,
ttl: StaticAsset::DEFAULT_TTL,
},
);
@@ -239,39 +103,18 @@ fn build_server() -> ServableRouter {
ServableRouter::new()
.with_404(&pages::NOT_FOUND)
.add_page("/", &pages::INDEX)
.add_page("/links", pages::LINKS)
.add_page("/whats-a-betalupi", pages::BETALUPI)
.add_page("/links", &pages::LINKS)
.add_page("/whats-a-betalupi", &pages::BETALUPI)
.add_page("/handouts", &pages::HANDOUTS)
.add_page("/htwah", {
#[expect(clippy::unwrap_used)]
Redirect::new("/handouts").unwrap()
})
.add_page("/htwah/typesetting", pages::HTWAH_TYPESETTING)
.add_page_with_route(&HTMX)
.add_page_with_route(&HTMX_JSON)
.add_page("/htwah/typesetting", &pages::HTWAH_TYPESETTING)
//
.add_page_with_route(&MAIN_CSS)
.add_page_with_route(&IMG_COVER_SMALL)
.add_page_with_route(&IMG_BETALUPI)
.add_page_with_route(&IMG_ICON)
//
// MARK: fonts
//
.add_page_with_route(&FONT_FIRACODE_BOLD)
.add_page_with_route(&FONT_FIRACODE_LIGHT)
.add_page_with_route(&FONT_FIRACODE_MEDIUM)
.add_page_with_route(&FONT_FIRACODE_REGULAR)
.add_page_with_route(&FONT_FIRACODE_SEMIBOLD)
.add_page_with_route(&FONT_FIRACODE_VF)
//
// MARK: icons
//
.add_page_with_route(&FONT_FA_BRANDS_WOFF2)
.add_page_with_route(&FONT_FA_REGULAR_WOFF2)
.add_page_with_route(&FONT_FA_SOLID_WOFF2)
.add_page_with_route(&FONT_FA_BRANDS_TTF)
.add_page_with_route(&FONT_FA_REGULAR_TTF)
.add_page_with_route(&FONT_FA_SOLID_TTF)
//
// MARK: htwah
//
@@ -284,6 +127,7 @@ fn build_server() -> ServableRouter {
}
#[test]
#[expect(clippy::unwrap_used)]
fn server_builds_without_panic() {
tokio::runtime::Builder::new_current_thread()
.enable_all()