diff --git a/src/assets.rs b/src/assets.rs index 16cd83b..360e7c1 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -67,6 +67,10 @@ pub static STORE: LazyLock = LazyLock::new(|| { "password-toggle.js" => "../static/password-toggle.js", "htmx.min.js" => "../static/htmx.min.js", "htmx-ws.min.js" => "../static/htmx-ws.min.js", + "favicon.ico" => "../static/favicon.ico", + "favicon-32x32.png" => "../static/favicon-32x32.png", + "apple-touch-icon.png" => "../static/apple-touch-icon.png", + "logo.svg" => "../static/logo.svg", } }); diff --git a/src/http.rs b/src/http.rs index 5173a20..35e20a8 100644 --- a/src/http.rs +++ b/src/http.rs @@ -342,8 +342,11 @@ async fn static_asset(Path(path): Path) -> Response { let Some(asset) = assets::STORE.get(&path) else { return StatusCode::NOT_FOUND.into_response(); }; - let mime = match path.as_str() { - "style.css" => "text/css", + let mime = match path.rsplit('.').next() { + Some("css") => "text/css", + Some("ico") => "image/x-icon", + Some("png") => "image/png", + Some("svg") => "image/svg+xml", _ => "application/javascript", }; let mut response = ([(header::CONTENT_TYPE, mime)], asset.data).into_response(); diff --git a/src/views.rs b/src/views.rs index a504f49..24c0256 100644 --- a/src/views.rs +++ b/src/views.rs @@ -1308,13 +1308,16 @@ fn page(title: &str, user: Option<&User>, content: Markup) -> Markup { meta charset="utf-8"; meta name="viewport" content="width=device-width, initial-scale=1"; title { (title) " ยท Sustenance" } + link rel="icon" href=(crate::assets::url("favicon.ico")) sizes="any"; + link rel="icon" type="image/png" href=(crate::assets::url("favicon-32x32.png")) sizes="32x32"; + link rel="apple-touch-icon" href=(crate::assets::url("apple-touch-icon.png")); link rel="stylesheet" href=(crate::assets::url("style.css")); script src=(crate::assets::url("htmx.min.js")) {} script src=(crate::assets::url("htmx-ws.min.js")) {} } body hx-boost="true" { header class="site-header" { - a class="brand" href="/lists" { span class="brand-mark" { "S" } "Sustenance" } + a class="brand" href="/lists" { img class="brand-mark" src=(crate::assets::url("logo.svg")) alt="Sustenance logo"; "Sustenance" } @if let Some(user) = user { nav class="site-nav" { a href="/lists" { "Lists" } diff --git a/static/apple-touch-icon.png b/static/apple-touch-icon.png new file mode 100644 index 0000000..c5e0c76 Binary files /dev/null and b/static/apple-touch-icon.png differ diff --git a/static/favicon-32x32.png b/static/favicon-32x32.png new file mode 100644 index 0000000..750fb27 Binary files /dev/null and b/static/favicon-32x32.png differ diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..c11a75e Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/logo.svg b/static/logo.svg new file mode 100644 index 0000000..6dfc4d3 --- /dev/null +++ b/static/logo.svg @@ -0,0 +1,143 @@ + + Sustenance grocery bag with produce + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/style.css b/static/style.css index 04aa1ef..bf68d6c 100644 --- a/static/style.css +++ b/static/style.css @@ -38,7 +38,7 @@ a { color: inherit; } } .brand { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; font-weight: 800; letter-spacing: -.03em; } -.brand-mark { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 11px 11px 11px 3px; background: var(--deep-sage); color: white; transform: rotate(-6deg); } +.brand-mark { display: block; width: 34px; height: 34px; border-radius: 9px; object-fit: cover; } .site-nav { display: flex; align-items: center; gap: 6px; } .site-nav a { padding: 8px 14px;