diff --git a/src/main.rs b/src/main.rs index e228dcd..fe034af 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ use client::{canonical_path, proxy}; use log::info; use once_cell::sync::Lazy; use server::RequestExt; -use utils::{error, redirect, ThemeAssets}; +use utils::{error, redirect, ThemeAssets, MascotAssets}; use crate::client::OAUTH_CLIENT; @@ -111,6 +111,20 @@ async fn style() -> Result, String> { ) } +/// Serve mascot +async fn mascot_image(req: Request) -> Result, String> { + let res = MascotAssets::get(&req.param("name").unwrap()) + .unwrap_or(MascotAssets::get("redsunlib.png").unwrap()); + Ok( + Response::builder() + .status(200) + .header("content-type", "image/png") + .header("Cache-Control", "public, max-age=1209600, s-maxage=86400") + .body(res.data.into()) + .unwrap_or_default(), + ) +} + #[tokio::main] async fn main() { // Load environment variables @@ -265,6 +279,9 @@ async fn main() { app.at("/settings/restore").get(|r| settings::restore(r).boxed()); app.at("/settings/update").get(|r| settings::update(r).boxed()); + // Mascots + app.at("/mascot/:name").get(|r| mascot_image(r).boxed()); + // Subreddit services app .at("/r/:sub") diff --git a/src/settings.rs b/src/settings.rs index 6964675..8c51a41 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -19,8 +19,9 @@ struct SettingsTemplate { // CONSTANTS -const PREFS: [&str; 16] = [ +const PREFS: [&str; 17] = [ "theme", + "mascot", "front_page", "layout", "wide", diff --git a/src/utils.rs b/src/utils.rs index dbaf1de..62f8f45 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -570,7 +570,9 @@ pub struct Params { #[derive(Default)] pub struct Preferences { pub available_themes: Vec, + pub available_mascots: Vec, pub theme: String, + pub mascot: String, pub front_page: String, pub layout: String, pub wide: String, @@ -595,6 +597,11 @@ pub struct Preferences { #[include = "*.css"] pub struct ThemeAssets; +#[derive(RustEmbed)] +#[folder = "static/mascots/"] +#[include = "*.png"] +pub struct MascotAssets; + impl Preferences { // Build preferences from cookies pub fn new(req: &Request) -> Self { @@ -605,9 +612,18 @@ impl Preferences { let chunks: Vec<&str> = file.as_ref().split(".css").collect(); themes.push(chunks[0].to_owned()); } + // Read available mascot names from embedded png files. + // Always make default "none" option available. + let mut mascots = vec!["none".to_string()]; + for file in MascotAssets::iter() { + let chunks: Vec<&str> = file.as_ref().split(".png").collect(); + mascots.push(chunks[0].to_owned()); + } Self { available_themes: themes, + available_mascots: mascots, theme: setting(req, "theme"), + mascot: setting(req, "mascot"), front_page: setting(req, "front_page"), layout: setting(req, "layout"), wide: setting(req, "wide"), diff --git a/static/mascots/BoymoderBlahaj.png b/static/mascots/BoymoderBlahaj.png new file mode 100644 index 0000000..1fca469 Binary files /dev/null and b/static/mascots/BoymoderBlahaj.png differ diff --git a/static/mascots/redsunlib.png b/static/mascots/redsunlib.png new file mode 100644 index 0000000..e3bf580 Binary files /dev/null and b/static/mascots/redsunlib.png differ diff --git a/static/style.css b/static/style.css index fdfc832..4f99e34 100644 --- a/static/style.css +++ b/static/style.css @@ -1774,3 +1774,16 @@ td, th { background-color: var(--accent); color: var(--text); } + +.mascot { + position: fixed; + right: 1em; + bottom: 1em; + pointer-events: none; + opacity: 0.5; + z-index: 1; +} + +.mascot > img { + max-width: 20em; +} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 84dc9c8..b2b2945 100644 --- a/templates/base.html +++ b/templates/base.html @@ -59,6 +59,13 @@ + + {% if prefs.mascot != "none" && prefs.mascot != "" %} + +
+ +
+ {% endif %} {% block body %} diff --git a/templates/settings.html b/templates/settings.html index 496b9b1..aaf8152 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -19,6 +19,12 @@ {% call utils::options(prefs.theme, prefs.available_themes, "system") %} +
+ + +
Interface