From f2e125995b7343de7b55b10a2b290125d0aa74ee Mon Sep 17 00:00:00 2001
From: Stephen D <webmaster@scd31.com>
Date: Mon, 3 Mar 2025 18:47:19 -0500
Subject: [PATCH] web badge support

---
 Cargo.lock           | 36 +++++++++++++++++++++++++++---------
 src/assets/style.css | 13 +++++++++++++
 src/blog.rs          | 22 ++++++++++++++++++++--
 src/config.rs        |  9 +++++++++
 src/misc.rs          |  3 +++
 5 files changed, 72 insertions(+), 11 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index 715f457..819899f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "addr2line"
@@ -241,9 +241,12 @@ dependencies = [
 
 [[package]]
 name = "deranged"
-version = "0.3.8"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
+dependencies = [
+ "powerfmt",
+]
 
 [[package]]
 name = "digest"
@@ -877,6 +880,12 @@ dependencies = [
  "minimal-lexical",
 ]
 
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
 [[package]]
 name = "num-integer"
 version = "0.1.45"
@@ -1085,6 +1094,12 @@ dependencies = [
  "miniz_oxide",
 ]
 
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
 [[package]]
 name = "ppv-lite86"
 version = "0.2.17"
@@ -1509,12 +1524,14 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.28"
+version = "0.3.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48"
+checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
 dependencies = [
  "deranged",
  "itoa",
+ "num-conv",
+ "powerfmt",
  "serde",
  "time-core",
  "time-macros",
@@ -1522,16 +1539,17 @@ dependencies = [
 
 [[package]]
 name = "time-core"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
 [[package]]
 name = "time-macros"
-version = "0.2.14"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572"
+checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
 dependencies = [
+ "num-conv",
  "time-core",
 ]
 
diff --git a/src/assets/style.css b/src/assets/style.css
index 35ccd05..470fec5 100644
--- a/src/assets/style.css
+++ b/src/assets/style.css
@@ -60,3 +60,16 @@ code {
   color: #e83e8c;
   word-break: break-word;
 }
+
+.badge {
+    image-rendering: auto;
+    image-rendering: crisp-edges;
+    image-rendering: pixelated;
+    image-rendering: -webkit-optimize-contrast;
+    margin: 2px;
+}
+
+.badges {
+    width: 550px;
+    margin: 3em auto;
+}
diff --git a/src/blog.rs b/src/blog.rs
index a937856..205182c 100644
--- a/src/blog.rs
+++ b/src/blog.rs
@@ -46,8 +46,26 @@ impl Blog {
         let name = &self.config.name;
         let description = &self.config.description;
 
-        let mut content = format!(
-            r#"<div class="centered"><h1>{name}</h1>{description}</div><h2>Recent Posts <a href="/posts.rss"><img src="/rss.svg" width="16em" /></a></h2><table>"#
+        let mut content =
+            format!(r#"<div class="centered"><h1>{name}</h1>{description}<div class="badges">"#);
+
+        for b in &self.config.badge {
+            if let Some(href) = &b.href {
+                content.push_str(&format!(r#"<a href="{}">"#, href));
+            }
+
+            content.push_str(&format!(
+                r#"<img class="badge" src="/img/badges/{}" alt="{}" />"#,
+                b.name, b.alt
+            ));
+
+            if b.href.is_some() {
+                content.push_str("</a>")
+            }
+        }
+
+        content.push_str(
+            r#"</div></div><h2>Recent Posts <a href="/posts.rss"><img src="/rss.svg" width="16em" /></a></h2><table>"#
         );
 
         for post in &self.posts {
diff --git a/src/config.rs b/src/config.rs
index afa0b5c..e4965c1 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -16,6 +16,13 @@ pub struct Logo {
     pub alt: String,
 }
 
+#[derive(Deserialize, Clone)]
+pub struct Badge {
+    pub name: String,
+    pub href: Option<String>,
+    pub alt: String,
+}
+
 #[derive(Deserialize, Clone)]
 pub struct Config {
     pub name: String,
@@ -23,6 +30,8 @@ pub struct Config {
     pub path: String,
     pub root: String,
     pub logo: Option<Logo>,
+    #[serde(default)]
+    pub badge: Vec<Badge>,
     pub metrics: Metrics,
 }
 
diff --git a/src/misc.rs b/src/misc.rs
index fa80bdb..1b2271e 100644
--- a/src/misc.rs
+++ b/src/misc.rs
@@ -59,6 +59,9 @@ fn content_type(ext: &str) -> anyhow::Result<&'static str> {
         "mp4" => "video/mp4",
         "ico" => "image/x-icon",
         "svg" => "image/svg+xml",
+        "png" => "image/png",
+        "gif" => "image/gif",
+        "webp" => "image/webp",
         _ => bail!("Unsure how to handle extension {ext}"),
     };
 
-- 
GitLab