From 9b43f16d806d54fcfdbdb9b3988a4b0c5c0a5cb1 Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Sat, 13 Mar 2021 09:03:19 -0500 Subject: [PATCH] css/gruvbox-dark: enable light mode if the os tells me to (#342) * css/gruvbox-dark: enable light mode if the os tells me to Signed-off-by: Christine Dodrill * handlers: add Last-Modified support Signed-off-by: Christine Dodrill --- css/gruvbox-dark.css | 239 +++++++++++++++++++++++++++++++++++++++- src/handlers/blog.rs | 18 ++- src/handlers/feeds.rs | 6 +- src/handlers/gallery.rs | 16 ++- src/handlers/mod.rs | 42 +++++-- src/handlers/talks.rs | 16 ++- 6 files changed, 311 insertions(+), 26 deletions(-) diff --git a/css/gruvbox-dark.css b/css/gruvbox-dark.css index a947d9d..f3478df 100644 --- a/css/gruvbox-dark.css +++ b/css/gruvbox-dark.css @@ -1 +1,238 @@ -.gruvbox-dark{background-color:#282828;color:#ebdbb2}.gruvbox-dark h1,.gruvbox-dark h2,.gruvbox-dark h3,.gruvbox-dark h4,.gruvbox-dark h5,.gruvbox-dark h6{color:#98971a}.gruvbox-dark h1 a,.gruvbox-dark h2 a,.gruvbox-dark h3 a,.gruvbox-dark h4 a,.gruvbox-dark h5 a,.gruvbox-dark h6 a{color:#d79921;border-bottom-color:#d79921}.gruvbox-dark h1 a:hover,.gruvbox-dark h2 a:hover,.gruvbox-dark h3 a:hover,.gruvbox-dark h4 a:hover,.gruvbox-dark h5 a:hover,.gruvbox-dark h6 a:hover{background-color:#d79921;color:#fbf1c7}.gruvbox-dark pre{background-color:#1d2021;padding:0;border:none}.gruvbox-dark pre code{color:#689d6a}.gruvbox-dark .progress-bar-filled:after,.gruvbox-dark .progress-bar-filled:before,.gruvbox-dark code,.gruvbox-dark strong{color:#98971a}.gruvbox-dark code{font-weight:100}.gruvbox-dark .progress-bar-filled{background-color:#98971a}.gruvbox-dark table{color:#fdf4c1}.gruvbox-dark table td,.gruvbox-dark table th{border-color:#b0bec5}.gruvbox-dark table tbody td:first-child{color:#b0bec5}.gruvbox-dark .form-control,.gruvbox-dark .form-group label{color:#fdf4c1;border-color:#98971a}.gruvbox-dark .form-group.form-textarea label:after{background-color:#282828}.gruvbox-dark .form-control:focus{border-color:#bdae93;color:#bdae93}.gruvbox-dark textarea.form-control{color:#fdf4c1}.gruvbox-dark .card{border-color:#98971a}.gruvbox-dark .card .card-header{background-color:transparent;color:#fdf4c1;border-bottom:1px solid #98971a}.gruvbox-dark .btn.btn-ghost.btn-default{border-color:#607d8b;color:#607d8b}.gruvbox-dark .btn.btn-ghost.btn-default:focus,.gruvbox-dark .btn.btn-ghost.btn-default:hover{z-index:1;border-color:#ebdbb2;color:#ebdbb2}.gruvbox-dark .btn.btn-ghost.btn-primary:focus,.gruvbox-dark .btn.btn-ghost.btn-primary:hover{border-color:#689d6a;color:#689d6a}.gruvbox-dark .btn.btn-ghost.btn-success:focus,.gruvbox-dark .btn.btn-ghost.btn-success:hover{border-color:#98971a;color:#98971a}.gruvbox-dark .btn.btn-ghost.btn-info:focus,.gruvbox-dark .btn.btn-ghost.btn-info:hover{border-color:#458588;color:#458588}.gruvbox-dark .btn.btn-ghost.btn-error:focus,.gruvbox-dark .btn.btn-ghost.btn-error:hover{border-color:#cc241d;color:#cc241d}.gruvbox-dark .btn.btn-ghost.btn-warning:focus,.gruvbox-dark .btn.btn-ghost.btn-warning:hover{border-color:#d79931;color:#d79931}.gruvbox-dark .avatarholder,.gruvbox-dark .placeholder{background-color:transparent;border-color:#3c3836}.gruvbox-dark .menu .menu-item{color:#fdf4c1;border-color:#98971a}.gruvbox-dark .menu .menu-item.active,.gruvbox-dark .menu .menu-item:hover{color:#fdf4c1;border-color:#fdf4c1}.gruvbox-dark a:visited{color:#a89984;border-color:#a89984}.gruvbox-dark a:visited:hover{color:#fdf4c1;background-color:#a89984} \ No newline at end of file + + +.gruvbox-dark { + background-color: #282828; + color: #ebdbb2 +} + +.gruvbox-dark h1, +.gruvbox-dark h2, +.gruvbox-dark h3, +.gruvbox-dark h4, +.gruvbox-dark h5, +.gruvbox-dark h6 { + color: #98971a +} + +.gruvbox-dark h1 a, +.gruvbox-dark h2 a, +.gruvbox-dark h3 a, +.gruvbox-dark h4 a, +.gruvbox-dark h5 a, +.gruvbox-dark h6 a { + color: #d79921; + border-bottom-color: #d79921 +} + +.gruvbox-dark h1 a:hover, +.gruvbox-dark h2 a:hover, +.gruvbox-dark h3 a:hover, +.gruvbox-dark h4 a:hover, +.gruvbox-dark h5 a:hover, +.gruvbox-dark h6 a:hover { + background-color: #d79921; + color: #fbf1c7 +} + +.gruvbox-dark pre { + background-color: #1d2021; + padding: 0; + border: none +} + +.gruvbox-dark pre code { + color: #689d6a +} + +.gruvbox-dark .progress-bar-filled:after, +.gruvbox-dark .progress-bar-filled:before, +.gruvbox-dark code, +.gruvbox-dark strong { + color: #98971a +} + +.gruvbox-dark code { + font-weight: 100 +} + +.gruvbox-dark .progress-bar-filled { + background-color: #98971a +} + +.gruvbox-dark table { + color: #fdf4c1 +} + +.gruvbox-dark table td, +.gruvbox-dark table th { + border-color: #b0bec5 +} + +.gruvbox-dark table tbody td:first-child { + color: #b0bec5 +} + +.gruvbox-dark .form-control, +.gruvbox-dark .form-group label { + color: #fdf4c1; + border-color: #98971a +} + +.gruvbox-dark .form-group.form-textarea label:after { + background-color: #282828 +} + +.gruvbox-dark .form-control:focus { + border-color: #bdae93; + color: #bdae93 +} + +.gruvbox-dark textarea.form-control { + color: #fdf4c1 +} + +.gruvbox-dark .card { + border-color: #98971a +} + +.gruvbox-dark .card .card-header { + background-color: transparent; + color: #fdf4c1; + border-bottom: 1px solid #98971a +} + +.gruvbox-dark .btn.btn-ghost.btn-default { + border-color: #607d8b; + color: #607d8b +} + +.gruvbox-dark .btn.btn-ghost.btn-default:focus, +.gruvbox-dark .btn.btn-ghost.btn-default:hover { + z-index: 1; + border-color: #ebdbb2; + color: #ebdbb2 +} + +.gruvbox-dark .btn.btn-ghost.btn-primary:focus, +.gruvbox-dark .btn.btn-ghost.btn-primary:hover { + border-color: #689d6a; + color: #689d6a +} + +.gruvbox-dark .btn.btn-ghost.btn-success:focus, +.gruvbox-dark .btn.btn-ghost.btn-success:hover { + border-color: #98971a; + color: #98971a +} + +.gruvbox-dark .btn.btn-ghost.btn-info:focus, +.gruvbox-dark .btn.btn-ghost.btn-info:hover { + border-color: #458588; + color: #458588 +} + +.gruvbox-dark .btn.btn-ghost.btn-error:focus, +.gruvbox-dark .btn.btn-ghost.btn-error:hover { + border-color: #cc241d; + color: #cc241d +} + +.gruvbox-dark .btn.btn-ghost.btn-warning:focus, +.gruvbox-dark .btn.btn-ghost.btn-warning:hover { + border-color: #d79931; + color: #d79931 +} + +.gruvbox-dark .avatarholder, +.gruvbox-dark .placeholder { + background-color: transparent; + border-color: #3c3836 +} + +.gruvbox-dark .menu .menu-item { + color: #fdf4c1; + border-color: #98971a +} + +.gruvbox-dark .menu .menu-item.active, +.gruvbox-dark .menu .menu-item:hover { + color: #fdf4c1; + border-color: #fdf4c1 +} + +.gruvbox-dark a:visited { + color: #a89984; + border-color: #a89984 +} + +.gruvbox-dark a:visited:hover { + color: #fdf4c1; + background-color: #a89984 +} + +@media (prefers-color-scheme: light) { + .gruvbox-dark { + background-color: #fbf1c7; + color: #282828; + } + .gruvbox-dark h1 a:hover, + .gruvbox-dark h2 a:hover, + .gruvbox-dark h3 a:hover, + .gruvbox-dark h4 a:hover, + .gruvbox-dark h5 a:hover, + .gruvbox-dark h6 a:hover { + background-color: #d79921; + color: #282828; + } + .gruvbox-dark pre { + background-color: #f9f5d7; + padding: 0; + border: none; + } + .gruvbox-dark table { + color: #1d2021; + } + .gruvbox-dark .form-control, + .gruvbox-dark .form-group label { + color: #1d2021; + border-color: #98971a + } + .gruvbox-dark .form-group.form-textarea label:after { + background-color: #3c3836; + } + .gruvbox-dark .form-control:focus { + border-color: #665c54; + color: #665c54; + } + .gruvbox-dark textarea.form-control { + color: #282828; + } + .gruvbox-dark .card .card-header { + background-color: transparent; + color: #282828; + border-bottom: 1px solid #98971a + } + .gruvbox-dark .btn.btn-ghost.btn-default:focus, + .gruvbox-dark .btn.btn-ghost.btn-default:hover { + z-index: 1; + border-color: #3c3836; + color: #3c3836; + } + .gruvbox-dark .menu .menu-item { + color: #282828; + border-color: #98971a + } + .gruvbox-dark .menu .menu-item.active, + .gruvbox-dark .menu .menu-item:hover { + color: #282828; + border-color: #282828; + } + .gruvbox-dark a:visited { + color: #7c6f64; + border-color: #7c6f64; + } + .gruvbox-dark a:visited:hover { + color: #3c3836; + background-color: #bdae93; + } +} \ No newline at end of file diff --git a/src/handlers/blog.rs b/src/handlers/blog.rs index fbc0c24..007b8e0 100644 --- a/src/handlers/blog.rs +++ b/src/handlers/blog.rs @@ -1,4 +1,4 @@ -use super::{PostNotFound, SeriesNotFound}; +use super::{PostNotFound, SeriesNotFound, LAST_MODIFIED}; use crate::{ app::State, post::Post, @@ -21,7 +21,9 @@ lazy_static! { #[instrument(skip(state))] pub async fn index(state: Arc) -> Result { let state = state.clone(); - Response::builder().html(|o| templates::blogindex_html(o, state.blog.clone())) + Response::builder() + .header("Last-Modified", &*LAST_MODIFIED) + .html(|o| templates::blogindex_html(o, state.blog.clone())) } #[instrument(skip(state))] @@ -38,7 +40,9 @@ pub async fn series(state: Arc) -> Result { series.sort(); series.dedup(); - Response::builder().html(|o| templates::series_html(o, series)) + Response::builder() + .header("Last-Modified", &*LAST_MODIFIED) + .html(|o| templates::series_html(o, series)) } #[instrument(skip(state))] @@ -60,7 +64,9 @@ pub async fn series_view(series: String, state: Arc) -> Result) -> Result, since: Option) -> Result, since: Option) -> Result) -> Result { Response::builder() .status(200) .header("Content-Type", "application/xml") + .header("Last-Modified", &*LAST_MODIFIED) .body(state.sitemap.clone()) .map_err(RenderError::Build) .map_err(warp::reject::custom) diff --git a/src/handlers/gallery.rs b/src/handlers/gallery.rs index ba3cba2..02bc01b 100644 --- a/src/handlers/gallery.rs +++ b/src/handlers/gallery.rs @@ -5,15 +5,17 @@ use crate::{ templates::{self, Html, RenderRucte}, }; use lazy_static::lazy_static; -use prometheus::{IntCounterVec, register_int_counter_vec, opts}; +use prometheus::{opts, register_int_counter_vec, IntCounterVec}; use std::sync::Arc; -use warp::{http::Response, Rejection, Reply}; use tracing::instrument; +use warp::{http::Response, Rejection, Reply}; lazy_static! { - static ref HIT_COUNTER: IntCounterVec = - register_int_counter_vec!(opts!("gallery_hits", "Number of hits to gallery images"), &["name"]) - .unwrap(); + static ref HIT_COUNTER: IntCounterVec = register_int_counter_vec!( + opts!("gallery_hits", "Number of hits to gallery images"), + &["name"] + ) + .unwrap(); } #[instrument(skip(state))] @@ -35,7 +37,9 @@ pub async fn post_view(name: String, state: Arc) -> Result Err(PostNotFound("gallery".into(), name).into()), Some(post) => { - HIT_COUNTER.with_label_values(&[name.clone().as_str()]).inc(); + HIT_COUNTER + .with_label_values(&[name.clone().as_str()]) + .inc(); let body = Html(post.body_html.clone()); Response::builder().html(|o| templates::gallerypost_html(o, post, body)) } diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index c6dbd65..798a911 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -2,6 +2,7 @@ use crate::{ app::State, templates::{self, Html, RenderRucte}, }; +use chrono::{Datelike, Timelike, Utc}; use lazy_static::lazy_static; use prometheus::{opts, register_int_counter_vec, IntCounterVec}; use std::{convert::Infallible, fmt, sync::Arc}; @@ -15,31 +16,52 @@ lazy_static! { static ref HIT_COUNTER: IntCounterVec = register_int_counter_vec!(opts!("hits", "Number of hits to various pages"), &["page"]) .unwrap(); + pub static ref LAST_MODIFIED: String = { + let now = Utc::now(); + format!( + "{dayname}, {day} {month} {year} {hour}:{minute}:{second} GMT", + dayname = now.weekday(), + day = now.day(), + month = now.month(), + year = now.year(), + hour = now.hour(), + minute = now.minute(), + second = now.second() + ) + }; } #[instrument] pub async fn index() -> Result { HIT_COUNTER.with_label_values(&["index"]).inc(); - Response::builder().html(|o| templates::index_html(o)) + Response::builder() + .header("Last-Modified", &*LAST_MODIFIED) + .html(|o| templates::index_html(o)) } #[instrument] pub async fn contact() -> Result { HIT_COUNTER.with_label_values(&["contact"]).inc(); - Response::builder().html(|o| templates::contact_html(o)) + Response::builder() + .header("Last-Modified", &*LAST_MODIFIED) + .html(|o| templates::contact_html(o)) } #[instrument] pub async fn feeds() -> Result { HIT_COUNTER.with_label_values(&["feeds"]).inc(); - Response::builder().html(|o| templates::feeds_html(o)) + Response::builder() + .header("Last-Modified", &*LAST_MODIFIED) + .html(|o| templates::feeds_html(o)) } #[instrument(skip(state))] pub async fn resume(state: Arc) -> Result { HIT_COUNTER.with_label_values(&["resume"]).inc(); let state = state.clone(); - Response::builder().html(|o| templates::resume_html(o, Html(state.resume.clone()))) + Response::builder() + .header("Last-Modified", &*LAST_MODIFIED) + .html(|o| templates::resume_html(o, Html(state.resume.clone()))) } #[instrument(skip(state))] @@ -53,7 +75,9 @@ pub async fn patrons(state: Arc) -> Result { "Could not load patrons, let me know the API token expired again".to_string(), ) }), - Some(patrons) => Response::builder().html(|o| templates::patrons_html(o, patrons.clone())), + Some(patrons) => Response::builder() + .header("Last-Modified", &*LAST_MODIFIED) + .html(|o| templates::patrons_html(o, patrons.clone())), } } @@ -61,13 +85,17 @@ pub async fn patrons(state: Arc) -> Result { pub async fn signalboost(state: Arc) -> Result { HIT_COUNTER.with_label_values(&["signalboost"]).inc(); let state = state.clone(); - Response::builder().html(|o| templates::signalboost_html(o, state.signalboost.clone())) + Response::builder() + .header("Last-Modified", &*LAST_MODIFIED) + .html(|o| templates::signalboost_html(o, state.signalboost.clone())) } #[instrument] pub async fn not_found() -> Result { HIT_COUNTER.with_label_values(&["not_found"]).inc(); - Response::builder().html(|o| templates::notfound_html(o, "some path".into())) + Response::builder() + .header("Last-Modified", &*LAST_MODIFIED) + .html(|o| templates::notfound_html(o, "some path".into())) } pub mod blog; diff --git a/src/handlers/talks.rs b/src/handlers/talks.rs index b64575c..8db5c9e 100644 --- a/src/handlers/talks.rs +++ b/src/handlers/talks.rs @@ -5,15 +5,17 @@ use crate::{ templates::{self, Html, RenderRucte}, }; use lazy_static::lazy_static; -use prometheus::{IntCounterVec, register_int_counter_vec, opts}; +use prometheus::{opts, register_int_counter_vec, IntCounterVec}; use std::sync::Arc; -use warp::{http::Response, Rejection, Reply}; use tracing::instrument; +use warp::{http::Response, Rejection, Reply}; lazy_static! { - static ref HIT_COUNTER: IntCounterVec = - register_int_counter_vec!(opts!("talks_hits", "Number of hits to talks images"), &["name"]) - .unwrap(); + static ref HIT_COUNTER: IntCounterVec = register_int_counter_vec!( + opts!("talks_hits", "Number of hits to talks images"), + &["name"] + ) + .unwrap(); } #[instrument(skip(state))] @@ -35,7 +37,9 @@ pub async fn post_view(name: String, state: Arc) -> Result Err(PostNotFound("talks".into(), name).into()), Some(post) => { - HIT_COUNTER.with_label_values(&[name.clone().as_str()]).inc(); + HIT_COUNTER + .with_label_values(&[name.clone().as_str()]) + .inc(); let body = Html(post.body_html.clone()); Response::builder().html(|o| templates::talkpost_html(o, post, body)) }