diff --git a/CHANGELOG.md b/CHANGELOG.md index b882a6df..ea49704a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Added + +- Rosé Pine theme, selectable with `WASTEBIN_THEME=rosepine`. + ### Changed - Top-align Markdown-rendered table cells. diff --git a/README.md b/README.md index dd0911cd..fd443fcf 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ to released versions here: * compresses pastes using [zstd](https://github.com/facebook/zstd) * syntax highlighting for > 170 languages with [syntect](https://github.com/trishume/syntect) * renders Markdown pastes to HTML, including GitHub-flavored tables, task lists and admonitions -* comes with [eight color themes](https://matze.github.io/wastebin/) in light and dark mode +* comes with [nine color themes](https://matze.github.io/wastebin/) in light and dark mode * encrypts entries using ChaCha20Poly1305 and argon2 hashed passwords * allows deletion after expiration, after reading or by anonymous owners * shows QR code to browse a paste's URL on mobile devices @@ -197,7 +197,7 @@ run-time behavior: | `WASTEBIN_PASSWORD_SALT` | Salt used to hash user passwords used for encrypting pastes. | `somesalt` | | `WASTEBIN_PASTE_EXPIRATIONS` | Possible paste expirations as a comma-separated list of seconds or values with duration magnitudes (`s`, `m`, `h`, `d`, `M`, `y` for seconds, minutes, hours, days, months and years respectively). Appending `=d` to one of the value makes it the default selection. | see [here](https://github.com/matze/wastebin/blob/eb61c78506a165605f145e8374ed64822405eda0/crates/wastebin_server/src/env.rs#L166) | | `WASTEBIN_SIGNING_KEY` | Key to sign cookies. Must be at least 64 bytes long. | Random key generated at startup, i.e. cookies will become invalid after restarts and paste creators will not be able to delete their pastes. | -| `WASTEBIN_THEME` | Theme colors, one of `ayu`, `base16ocean`, `catppuccin`, `coldark`, `gruvbox`, `monokai`, `onehalf`, `solarized`. See [this page](https://matze.github.io/wastebin/) for a preview. | `ayu` | +| `WASTEBIN_THEME` | Theme colors, one of `ayu`, `base16ocean`, `catppuccin`, `coldark`, `gruvbox`, `monokai`, `onehalf`, `rosepine`, `solarized`. See [this page](https://matze.github.io/wastebin/) for a preview. | `ayu` | | `WASTEBIN_TITLE` | HTML page title. | `wastebin` | | `WASTEBIN_UNIX_SOCKET_PATH` | Path to a Unix socket to accept connections from. | | | `RUST_LOG` | Log level. Besides the typical `trace`, `debug`, `info` etc. keys, you can also set the `tower_http` key to a log level to get additional request and response logs. | | diff --git a/crates/wastebin_highlight/src/theme.rs b/crates/wastebin_highlight/src/theme.rs index 59360b2b..884b42c1 100644 --- a/crates/wastebin_highlight/src/theme.rs +++ b/crates/wastebin_highlight/src/theme.rs @@ -15,6 +15,7 @@ pub enum Theme { Gruvbox, Monokai, Onehalf, + RosePine, Solarized, } @@ -35,6 +36,7 @@ impl FromStr for Theme { "gruvbox" => Ok(Theme::Gruvbox), "monokai" => Ok(Theme::Monokai), "onehalf" => Ok(Theme::Onehalf), + "rosepine" => Ok(Theme::RosePine), "solarized" => Ok(Theme::Solarized), _ => Err(ParseThemeNameError), } @@ -64,6 +66,10 @@ impl Theme { .get(EmbeddedThemeName::MonokaiExtendedLight) .clone(), Theme::Onehalf => theme_set.get(EmbeddedThemeName::OneHalfLight).clone(), + Theme::RosePine => { + let theme = include_str!("../themes/rose-pine-dawn.tmTheme"); + ThemeSet::load_from_reader(&mut Cursor::new(theme)).expect("loading theme") + } Theme::Solarized => theme_set.get(EmbeddedThemeName::SolarizedLight).clone(), } } @@ -88,6 +94,10 @@ impl Theme { Theme::Gruvbox => theme_set.get(EmbeddedThemeName::GruvboxDark).clone(), Theme::Monokai => theme_set.get(EmbeddedThemeName::MonokaiExtended).clone(), Theme::Onehalf => theme_set.get(EmbeddedThemeName::OneHalfDark).clone(), + Theme::RosePine => { + let theme = include_str!("../themes/rose-pine.tmTheme"); + ThemeSet::load_from_reader(&mut Cursor::new(theme)).expect("loading theme") + } Theme::Solarized => theme_set.get(EmbeddedThemeName::SolarizedDark).clone(), } } @@ -103,6 +113,7 @@ impl Theme { Theme::Gruvbox => "gruvbox", Theme::Monokai => "monokai", Theme::Onehalf => "onehalf", + Theme::RosePine => "rosepine", Theme::Solarized => "solarized", } } @@ -128,3 +139,30 @@ fn combined_css(color_scheme: &str, theme: &highlighting::Theme) -> Vec { ) .into_bytes() } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn rose_pine_round_trips() -> Result<(), Box> { + let theme: Theme = "rosepine".parse()?; + assert_eq!(theme.name(), "rosepine"); + Ok(()) + } + + #[test] + fn rose_pine_bundled_files_load() -> Result<(), Box> { + let theme: Theme = "rosepine".parse()?; + + // The bundled Dawn and main variants carry these background colors, so seeing them in the + // generated CSS proves the right file ended up on each side. + let light = String::from_utf8(theme.light_css())?; + assert!(light.contains("rgb(250, 244, 237")); + + let dark = String::from_utf8(theme.dark_css())?; + assert!(dark.contains("rgb(25, 23, 36")); + + Ok(()) + } +} diff --git a/crates/wastebin_highlight/themes/rose-pine-dawn.tmTheme b/crates/wastebin_highlight/themes/rose-pine-dawn.tmTheme new file mode 100644 index 00000000..bf3f90e9 --- /dev/null +++ b/crates/wastebin_highlight/themes/rose-pine-dawn.tmTheme @@ -0,0 +1,329 @@ + + + + + name + Rosé Pine Dawn + settings + + + settings + + background + #faf4ed + caret + #cecacd + foreground + #575279 + invisibles + #fffaf3 + lineHighlight + #f4ede8 + selection + #dfdad9 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #797593 + + + + name + String + scope + string, punctuation.definition.string + settings + + foreground + #ea9d34 + + + + name + Number + scope + constant.numeric + settings + + foreground + #ea9d34 + + + + name + Built-in constant + scope + constant.language + settings + + fontStyle + bold + foreground + #ea9d34 + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #ea9d34 + + + + name + Variable + scope + variable + settings + + fontStyle + italic + foreground + #575279 + + + + name + Keyword + scope + keyword + settings + + foreground + #286983 + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #56949f + + + + name + Storage type + scope + storage.type + settings + + fontStyle + + foreground + #56949f + + + + name + Class name + scope + entity.name.class, entity.name + settings + + fontStyle + bold + foreground + #286983 + + + + name + Headings + scope + markup.heading + settings + + fontStyle + bold + foreground + #d7827e + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #286983 + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + italic + foreground + #d7827e + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + + foreground + #907aa9 + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + bold + foreground + #286983 + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #907aa9 + + + + name + Library function + scope + support.function + settings + + fontStyle + bold + foreground + #d7827e + + + + name + Library constant + scope + support.constant + settings + + fontStyle + bold + foreground + #ea9d34 + + + + name + Library class/type + scope + support.type, support.class + settings + + fontStyle + bold + foreground + #56949f + + + + name + Library variable + scope + support.other.variable + settings + + fontStyle + bold + foreground + #b4637a + + + + name + Invalid + scope + invalid + settings + + background + #b4637a + fontStyle + + foreground + #575279 + + + + name + Invalid deprecated + scope + invalid.deprecated + settings + + background + #907aa9 + foreground + #575279 + + + + name + Punctuation, Operators + scope + punctuation, keyword.operator + settings + + foreground + #797593 + + + + colorSpaceName + sRGB + semanticClass + theme.light.rose-pine-dawn + author + arrrgi + comment + All natural pine, faux fur and a bit of soho vibes for the classy minimalist + uuid + BB4B4616-E742-41D5-BB5B-63D45FA614F + + diff --git a/crates/wastebin_highlight/themes/rose-pine.tmTheme b/crates/wastebin_highlight/themes/rose-pine.tmTheme new file mode 100644 index 00000000..3be026c8 --- /dev/null +++ b/crates/wastebin_highlight/themes/rose-pine.tmTheme @@ -0,0 +1,329 @@ + + + + + name + Rosé Pine + settings + + + settings + + background + #191724 + caret + #524f67 + foreground + #e0def4 + invisibles + #1f1d2e + lineHighlight + #21202e + selection + #403d52 + + + + name + Comment + scope + comment + settings + + fontStyle + italic + foreground + #908caa + + + + name + String + scope + string, punctuation.definition.string + settings + + foreground + #f6c177 + + + + name + Number + scope + constant.numeric + settings + + foreground + #f6c177 + + + + name + Built-in constant + scope + constant.language + settings + + fontStyle + bold + foreground + #f6c177 + + + + name + User-defined constant + scope + constant.character, constant.other + settings + + foreground + #f6c177 + + + + name + Variable + scope + variable + settings + + fontStyle + italic + foreground + #e0def4 + + + + name + Keyword + scope + keyword + settings + + foreground + #31748f + + + + name + Storage + scope + storage + settings + + fontStyle + + foreground + #9ccfd8 + + + + name + Storage type + scope + storage.type + settings + + fontStyle + + foreground + #9ccfd8 + + + + name + Class name + scope + entity.name.class, entity.name + settings + + fontStyle + bold + foreground + #31748f + + + + name + Headings + scope + markup.heading + settings + + fontStyle + bold + foreground + #ebbcba + + + + name + Inherited class + scope + entity.other.inherited-class + settings + + fontStyle + italic + foreground + #31748f + + + + name + Function name + scope + entity.name.function + settings + + fontStyle + italic + foreground + #ebbcba + + + + name + Function argument + scope + variable.parameter + settings + + fontStyle + + foreground + #c4a7e7 + + + + name + Tag name + scope + entity.name.tag + settings + + fontStyle + bold + foreground + #31748f + + + + name + Tag attribute + scope + entity.other.attribute-name + settings + + fontStyle + + foreground + #c4a7e7 + + + + name + Library function + scope + support.function + settings + + fontStyle + bold + foreground + #ebbcba + + + + name + Library constant + scope + support.constant + settings + + fontStyle + bold + foreground + #f6c177 + + + + name + Library class/type + scope + support.type, support.class + settings + + fontStyle + bold + foreground + #9ccfd8 + + + + name + Library variable + scope + support.other.variable + settings + + fontStyle + bold + foreground + #eb6f92 + + + + name + Invalid + scope + invalid + settings + + background + #eb6f92 + fontStyle + + foreground + #e0def4 + + + + name + Invalid deprecated + scope + invalid.deprecated + settings + + background + #c4a7e7 + foreground + #e0def4 + + + + name + Punctuation, Operators + scope + punctuation, keyword.operator + settings + + foreground + #908caa + + + + colorSpaceName + sRGB + semanticClass + theme.dark.rose-pine + author + arrrgi + comment + All natural pine, faux fur and a bit of soho vibes for the classy minimalist + uuid + 14991673-80EB-41A2-BEFF-03216A233730 + + diff --git a/crates/wastebin_theme_showcase/src/main.rs b/crates/wastebin_theme_showcase/src/main.rs index b465c1bd..bf489157 100644 --- a/crates/wastebin_theme_showcase/src/main.rs +++ b/crates/wastebin_theme_showcase/src/main.rs @@ -37,6 +37,7 @@ fn main() { Theme::Gruvbox, Theme::Monokai, Theme::Onehalf, + Theme::RosePine, Theme::Solarized, ] .into_iter()