Krolyxon
Tag v0.3.0

ferreniumsrchandlersmod.rs

97 lines · 3.1 KB · Rust

1//! Request handlers. Each page is an askama template that embeds a [`Layout`].
2
3pub mod archive;
4pub mod blame;
5pub mod blob;
6pub mod commit;
7pub mod error;
8pub mod feed;
9pub mod find;
10pub mod index;
11pub mod log;
12pub mod raw;
13pub mod refs;
14pub mod repo;
15pub mod summary;
16pub mod tree;
17
18use std::sync::Arc;
19
20use askama::Template;
21use axum::http::StatusCode;
22use axum::response::{Html, IntoResponse, Response};
23
24use crate::config::Config;
25use crate::server::assets;
26use crate::state::AppState;
27
28/// Data shared by every page: site chrome, asset URLs and customization.
29pub struct Layout {
30 /// `server.base_path`, always ending in `/`.
31 pub base: String,
32 /// `{base}-/static/{hash}/`
33 pub static_base: String,
34 pub site_title: String,
35 /// Full `<title>` text.
36 pub page_title: String,
37 /// Server default theme: `auto`, `dark` or `light`.
38 pub theme: &'static str,
39 /// Versioned URL of `/-/site.css`, when there is anything in it.
40 pub site_css: Option<String>,
41 pub header: Option<Arc<str>>,
42 pub footer: Option<Arc<str>>,
43 /// Favicon URL and media type: `site.favicon` or the built-in icon.
44 pub favicon: (String, &'static str),
45 /// Versioned URL of `site.logo`.
46 pub logo: Option<String>,
47 pub version: &'static str,
48 /// Atom feed advertised in `<head>`.
49 pub feed: Option<String>,
50}
51
52impl Layout {
53 /// `title` is the page-specific part; the site title is appended.
54 pub fn new(state: &AppState, config: &Config, title: Option<&str>) -> Self {
55 let base = config.server.base_path.clone();
56 let site_title = config.site.title.clone();
57 let static_base = format!("{base}-/static/{}/", state.assets.hash());
58 Layout {
59 favicon: match &config.custom.favicon {
60 Some(icon) => (
61 format!("{base}-/favicon?v={}", icon.version),
62 icon.content_type,
63 ),
64 None => (format!("{static_base}icons/favicon.svg"), "image/svg+xml"),
65 },
66 logo: config
67 .custom
68 .logo
69 .as_ref()
70 .map(|logo| format!("{base}-/logo?v={}", logo.version)),
71 static_base,
72 site_css: assets::site_css_version(config).map(|v| format!("{base}-/site.css?v={v}")),
73 page_title: match title {
74 Some(t) => format!("{t} · {site_title}"),
75 None => site_title.clone(),
76 },
77 site_title,
78 base,
79 theme: config.ui.theme.as_str(),
80 header: config.custom.header.clone(),
81 footer: config.custom.footer.clone(),
82 version: env!("CARGO_PKG_VERSION"),
83 feed: None,
84 }
85 }
86}
87
88/// Render a template into an HTML response with the given status.
89pub fn render(status: StatusCode, page: &impl Template) -> Response {
90 match page.render() {
91 Ok(html) => (status, Html(html)).into_response(),
92 Err(e) => {
93 tracing::error!("template error: {e}");
94 (StatusCode::INTERNAL_SERVER_ERROR, "internal error\n").into_response()
95 }
96 }
97}