Skip to main content

max / audiofiles

theme: consume the shared intent layer (theme-common 0.6.0) theme.rs parses + resolves via theme_common::resolve and reads each egui field from the intent tokens (rgb()); the local color math (BT.601 contrast, sRGB lerp) is gone — contrast_color/lerp_color now wrap theme_common's OKLab blend and WCAG contrast, so the derivation choices stay here but the math is shared. Accent fields read the categorical ramp (all six stay distinct). The 28 bundled themes are migrated to the intent schema; [spacing] and classification_color stay app-local. Tests updated for the intent schema + perceptual math. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-06-13 01:37 UTC
Commit: abbaa6684d5cba5584689c5002d921bb4221f162
Parent: a620402
30 files changed, +845 insertions, -555 deletions
M Cargo.lock +1 -1
@@ -5045,7 +5045,7 @@ dependencies = [
5045 5045
5046 5046 [[package]]
5047 5047 name = "theme-common"
5048 - version = "0.4.0"
5048 + version = "0.6.0"
5049 5049 dependencies = [
5050 5050 "serde",
5051 5051 "toml",
@@ -159,22 +159,28 @@ pub use theme_common::ThemeMeta;
159 159 static THEME: LazyLock<RwLock<ThemeColors>> = LazyLock::new(|| RwLock::new(ThemeColors::default()));
160 160
161 161 // --- Derived color helpers ---
162 + //
163 + // The color math lives once in `theme_common` (OKLab blends + WCAG contrast),
164 + // shared with GoingsOn / Balanced Breakfast / MNW. These thin wrappers adapt
165 + // egui's `Color32` to that shared implementation; the derivation *choices*
166 + // (which colors, what ratio) stay here as audiofiles' egui styling.
167 +
168 + fn to_rgb(c: Color32) -> theme_common::Rgb {
169 + theme_common::Rgb { r: c.r(), g: c.g(), b: c.b() }
170 + }
171 + fn from_rgb(c: theme_common::Rgb) -> Color32 {
172 + Color32::from_rgb(c.r, c.g, c.b)
173 + }
162 174
163 - /// Pick white or black text depending on which contrasts better against `bg`.
164 - /// Uses the ITU-R BT.601 luminance formula.
175 + /// Pick white or black text for legibility on `bg`, by WCAG contrast ratio.
165 176 fn contrast_color(bg: Color32) -> Color32 {
166 - let luminance = (0.299 * bg.r() as f32 + 0.587 * bg.g() as f32 + 0.114 * bg.b() as f32) / 255.0;
167 - if luminance > 0.5 { Color32::BLACK } else { Color32::WHITE }
177 + from_rgb(theme_common::readable_on(to_rgb(bg)))
168 178 }
169 179
170 - /// Linearly interpolate between two colors channel-by-channel.
171 - /// `t=0.0` returns `a`, `t=1.0` returns `b`. Used to derive row stripes,
172 - /// selection highlights, and hover states from the base palette.
180 + /// Perceptual (OKLab) blend from `a` to `b` by `t` in [0,1]. Used to derive row
181 + /// stripes, selection highlights, and hover states from the base palette.
173 182 fn lerp_color(a: Color32, b: Color32, t: f32) -> Color32 {
174 - let mix = |a: u8, b: u8| -> u8 {
175 - (a as f32 + (b as f32 - a as f32) * t).round() as u8
176 - };
177 - Color32::from_rgb(mix(a.r(), b.r()), mix(a.g(), b.g()), mix(a.b(), b.b()))
183 + from_rgb(theme_common::mix(to_rgb(a), to_rgb(b), t))
178 184 }
179 185
180 186 // --- Public accessors ---
@@ -395,19 +401,30 @@ fn parse_hex(s: &str) -> Option<Color32> {
395 401 Some(Color32::from_rgb(r, g, b))
396 402 }
397 403
398 - /// Look up a dot-notation key (e.g., `"accent.blue"`) in the parsed TOML color map
399 - /// and convert it to `Color32`. Returns `None` if the key is missing or unparseable.
404 + /// Look up a dot-notation key (e.g., `"action.primary"`) in a raw color map and
405 + /// convert it to `Color32`. Returns `None` if missing or unparseable.
400 406 fn get_color(colors: &HashMap<String, String>, key: &str) -> Option<Color32> {
401 407 colors.get(key).and_then(|v| parse_hex(v))
402 408 }
403 409
404 410 /// Parse TOML content string into `ThemeColors`.
411 + ///
412 + /// Colors come from the shared resolver: the theme is parsed and resolved into
413 + /// its intent tokens (`theme_common::resolve`), then each egui field reads the
414 + /// matching intent via `rgb()`. The accent fields use the categorical ramp so
415 + /// all six remain distinct (category three == the action/primary color).
405 416 fn parse_theme(content: &str) -> Result<ThemeColors, toml::de::Error> {
406 417 let table: toml::Table = content.parse()?;
418 + let theme = theme_common::ThemeColors {
419 + meta: theme_common::parse_meta("theme", &table, false),
420 + colors: theme_common::extract_colors(&table),
421 + };
422 + let t = theme_common::resolve(&theme);
423 + let c = |key: &str, default: Color32| {
424 + t.rgb(key).map(|(r, g, b)| Color32::from_rgb(r, g, b)).unwrap_or(default)
425 + };
407 426
408 - let colors = theme_common::extract_colors(&table);
409 -
410 - // Parse optional [spacing] section
427 + // Parse optional [spacing] section (audiofiles-specific, not a theme intent).
411 428 let spacing = table.get("spacing").and_then(|s| s.as_table());
412 429 let get_f32 = |key: &str, default: f32| -> f32 {
413 430 spacing
@@ -417,20 +434,20 @@ fn parse_theme(content: &str) -> Result<ThemeColors, toml::de::Error> {
417 434 };
418 435
419 436 Ok(ThemeColors {
420 - bg_primary: get_color(&colors, "background.primary").unwrap_or(Color32::BLACK),
421 - bg_secondary: get_color(&colors, "background.secondary").unwrap_or(Color32::BLACK),
422 - bg_tertiary: get_color(&colors, "background.tertiary").unwrap_or(Color32::BLACK),
423 - bg_surface: get_color(&colors, "background.surface").unwrap_or(Color32::BLACK),
424 - fg_primary: get_color(&colors, "foreground.primary").unwrap_or(Color32::WHITE),
425 - fg_secondary: get_color(&colors, "foreground.secondary").unwrap_or(Color32::WHITE),
426 - fg_muted: get_color(&colors, "foreground.muted").unwrap_or(Color32::GRAY),
427 - accent_red: get_color(&colors, "accent.red").unwrap_or(Color32::RED),
428 - accent_green: get_color(&colors, "accent.green").unwrap_or(Color32::GREEN),
429 - accent_blue: get_color(&colors, "accent.blue").unwrap_or(Color32::BLUE),
430 - accent_yellow: get_color(&colors, "accent.yellow").unwrap_or(Color32::YELLOW),
431 - accent_purple: get_color(&colors, "accent.purple").unwrap_or(Color32::from_rgb(0xBD, 0x93, 0xF9)),
432 - accent_cyan: get_color(&colors, "accent.cyan").unwrap_or(Color32::from_rgb(0x88, 0xC0, 0xD0)),
433 - border_default: get_color(&colors, "border.default").unwrap_or(Color32::DARK_GRAY),
437 + bg_primary: c("surface-page", Color32::BLACK),
438 + bg_secondary: c("surface-overlay", Color32::BLACK),
439 + bg_tertiary: c("surface-sunken", Color32::BLACK),
440 + bg_surface: c("surface-raised", Color32::BLACK),
441 + fg_primary: c("content", Color32::WHITE),
442 + fg_secondary: c("content-secondary", Color32::WHITE),
443 + fg_muted: c("content-muted", Color32::GRAY),
444 + accent_red: c("category-one", Color32::RED),
445 + accent_green: c("category-two", Color32::GREEN),
446 + accent_blue: c("category-three", Color32::BLUE),
447 + accent_yellow: c("category-four", Color32::YELLOW),
448 + accent_purple: c("category-five", Color32::from_rgb(0xBD, 0x93, 0xF9)),
449 + accent_cyan: c("category-six", Color32::from_rgb(0x88, 0xC0, 0xD0)),
450 + border_default: c("border", Color32::DARK_GRAY),
434 451 rounding: get_f32("rounding", 4.0),
435 452 item_spacing_x: get_f32("item_spacing_x", 8.0),
436 453 item_spacing_y: get_f32("item_spacing_y", 5.0),
@@ -521,9 +538,9 @@ pub fn theme_preview_colors(id: &str) -> Option<(Color32, Color32, Color32)> {
521 538
522 539 let table: toml::Table = content.parse().ok()?;
523 540 let colors = theme_common::extract_colors(&table);
524 - let bg = get_color(&colors, "background.primary").unwrap_or(Color32::from_rgb(30, 30, 30));
525 - let accent = get_color(&colors, "accent.blue").unwrap_or(Color32::from_rgb(100, 100, 255));
526 - let fg = get_color(&colors, "foreground.primary").unwrap_or(Color32::from_rgb(220, 220, 220));
541 + let bg = get_color(&colors, "surface.page").unwrap_or(Color32::from_rgb(30, 30, 30));
542 + let accent = get_color(&colors, "action.primary").unwrap_or(Color32::from_rgb(100, 100, 255));
543 + let fg = get_color(&colors, "content.primary").unwrap_or(Color32::from_rgb(220, 220, 220));
527 544 Some((bg, accent, fg))
528 545 }
529 546
@@ -677,10 +694,10 @@ mod tests {
677 694 }
678 695
679 696 #[test]
680 - fn contrast_color_dark_blue_returns_white() {
681 - // Dark blue (accent_blue from tokyonight: #7aa2f7 → luminance ~0.62)
682 - // Actually 0x0a84ff is the default accent_blue (very dark blue)
683 - assert_eq!(contrast_color(Color32::from_rgb(0x0a, 0x84, 0xff)), Color32::WHITE);
697 + fn contrast_color_medium_blue_returns_black() {
698 + // #0a84ff is a medium blue; by WCAG contrast ratio black reads better
699 + // than white on it (~5.8:1 vs ~3.6:1), so readable_on picks black.
700 + assert_eq!(contrast_color(Color32::from_rgb(0x0a, 0x84, 0xff)), Color32::BLACK);
684 701 }
685 702
686 703 #[test]
@@ -707,19 +724,25 @@ mod tests {
707 724 }
708 725
709 726 #[test]
710 - fn lerp_color_midpoint() {
727 + fn lerp_color_midpoint_is_between() {
728 + // OKLab blend: not the sRGB arithmetic mean, but each channel lies
729 + // between the endpoints.
711 730 let a = Color32::from_rgb(0, 0, 0);
712 731 let b = Color32::from_rgb(100, 200, 50);
713 732 let mid = lerp_color(a, b, 0.5);
714 - assert_eq!(mid, Color32::from_rgb(50, 100, 25));
733 + assert!(mid.r() > 0 && mid.r() < 100);
734 + assert!(mid.g() > 0 && mid.g() < 200);
735 + assert!(mid.b() > 0 && mid.b() < 50);
715 736 }
716 737
717 738 #[test]
718 - fn lerp_color_quarter() {
739 + fn lerp_color_quarter_is_closer_to_a() {
719 740 let a = Color32::from_rgb(0, 0, 0);
720 741 let b = Color32::from_rgb(100, 200, 40);
721 - let result = lerp_color(a, b, 0.25);
722 - assert_eq!(result, Color32::from_rgb(25, 50, 10));
742 + let quarter = lerp_color(a, b, 0.25);
743 + let half = lerp_color(a, b, 0.5);
744 + // 0.25 sits between a and the midpoint along lightness.
745 + assert!(quarter.g() > 0 && quarter.g() < half.g());
723 746 }
724 747
725 748 #[test]
@@ -733,7 +756,10 @@ mod tests {
733 756 let black = Color32::from_rgb(0, 0, 0);
734 757 let white = Color32::from_rgb(255, 255, 255);
735 758 let mid = lerp_color(black, white, 0.5);
736 - assert_eq!(mid, Color32::from_rgb(128, 128, 128));
759 + // Perceptual mid-gray (r==g==b, strictly between the endpoints).
760 + assert_eq!(mid.r(), mid.g());
761 + assert_eq!(mid.g(), mid.b());
762 + assert!(mid.r() > 0 && mid.r() < 255);
737 763 }
738 764
739 765 #[test]
@@ -741,7 +767,9 @@ mod tests {
741 767 let black = Color32::from_rgb(0, 0, 0);
742 768 let white = Color32::from_rgb(255, 255, 255);
743 769 let mid = lerp_color(white, black, 0.5);
744 - assert_eq!(mid, Color32::from_rgb(128, 128, 128));
770 + assert_eq!(mid.r(), mid.g());
771 + assert_eq!(mid.g(), mid.b());
772 + assert!(mid.r() > 0 && mid.r() < 255);
745 773 }
746 774
747 775 // ---------------------------------------------------------------
@@ -851,27 +879,36 @@ mod tests {
851 879 name = "Test Theme"
852 880 variant = "dark"
853 881
854 - [background]
855 - primary = "#1a1b26"
856 - secondary = "#16161e"
857 - tertiary = "#283457"
858 - surface = "#1a1b26"
882 + [surface]
883 + page = "#1a1b26"
884 + raised = "#1a1b26"
885 + sunken = "#283457"
886 + overlay = "#16161e"
859 887
860 - [foreground]
888 + [content]
861 889 primary = "#c0caf5"
862 890 secondary = "#a9b1d6"
863 891 muted = "#565f89"
864 892
865 - [accent]
866 - red = "#f7768e"
867 - green = "#9ece6a"
868 - blue = "#7aa2f7"
869 - yellow = "#e0af68"
870 - purple = "#9d7cd8"
871 - cyan = "#7dcfff"
872 -
873 - [border]
874 - default = "#3b4261"
893 + [action]
894 + primary = "#7aa2f7"
895 +
896 + [status]
897 + danger = "#f7768e"
898 + success = "#9ece6a"
899 + warning = "#e0af68"
900 + info = "#7dcfff"
901 +
902 + [line]
903 + border = "#3b4261"
904 +
905 + [category]
906 + one = "#f7768e"
907 + two = "#9ece6a"
908 + three = "#7aa2f7"
909 + four = "#e0af68"
910 + five = "#9d7cd8"
911 + six = "#7dcfff"
875 912 "##
876 913 }
877 914
@@ -896,10 +933,10 @@ default = "#3b4261"
896 933
897 934 #[test]
898 935 fn parse_theme_missing_sections_uses_defaults() {
899 - // Only background section; other sections should get fallback colors
936 + // Only surface.page; other roles should get fallback colors
900 937 let toml = r##"
901 - [background]
902 - primary = "#112233"
938 + [surface]
939 + page = "#112233"
903 940 "##;
904 941 let theme = parse_theme(toml).unwrap();
905 942 assert_eq!(theme.bg_primary, Color32::from_rgb(0x11, 0x22, 0x33));
@@ -935,14 +972,14 @@ primary = "#112233"
935 972 #[test]
936 973 fn parse_theme_partial_accent() {
937 974 let toml = r##"
938 - [accent]
939 - red = "#ff0000"
940 - blue = "#0000ff"
975 + [category]
976 + one = "#ff0000"
977 + three = "#0000ff"
941 978 "##;
942 979 let theme = parse_theme(toml).unwrap();
943 980 assert_eq!(theme.accent_red, Color32::from_rgb(255, 0, 0));
944 981 assert_eq!(theme.accent_blue, Color32::from_rgb(0, 0, 255));
945 - // green missing, falls back
982 + // green (category.two) missing, falls back
946 983 assert_eq!(theme.accent_green, Color32::GREEN);
947 984 }
948 985
@@ -953,8 +990,8 @@ blue = "#0000ff"
953 990 name = "Extra"
954 991 variant = "dark"
955 992
956 - [background]
957 - primary = "#aabbcc"
993 + [surface]
994 + page = "#aabbcc"
958 995
959 996 [custom_section]
960 997 foo = "bar"
@@ -966,14 +1003,14 @@ foo = "bar"
966 1003 #[test]
967 1004 fn parse_theme_invalid_hex_in_field_uses_fallback() {
968 1005 let toml = r##"
969 - [background]
970 - primary = "not-a-color"
971 - secondary = "#16161e"
1006 + [surface]
1007 + page = "not-a-color"
1008 + overlay = "#16161e"
972 1009 "##;
973 1010 let theme = parse_theme(toml).unwrap();
974 1011 // Invalid hex falls back to BLACK for bg
975 1012 assert_eq!(theme.bg_primary, Color32::BLACK);
976 - // Valid hex parses correctly
1013 + // Valid hex parses correctly (surface.overlay -> bg_secondary)
977 1014 assert_eq!(theme.bg_secondary, Color32::from_rgb(0x16, 0x16, 0x1e));
978 1015 }
979 1016
@@ -1024,10 +1061,11 @@ secondary = "#16161e"
1024 1061 #[test]
1025 1062 fn theme_colors_default_is_audiofiles() {
1026 1063 let d = ThemeColors::default();
1027 - assert_eq!(d.bg_primary, Color32::from_rgb(0x00, 0x00, 0x00));
1028 - assert_eq!(d.fg_primary, Color32::from_rgb(0xff, 0xff, 0xff));
1029 - assert_eq!(d.accent_blue, Color32::from_rgb(0x0a, 0x84, 0xff));
1030 - assert_eq!(d.border_default, Color32::from_rgb(0x33, 0x33, 0x33));
1064 + // The muted sage-and-mocha default skin.
1065 + assert_eq!(d.bg_primary, Color32::from_rgb(0xCC, 0xDA, 0xD1));
1066 + assert_eq!(d.fg_primary, Color32::from_rgb(0x38, 0x30, 0x2E));
1067 + assert_eq!(d.accent_blue, Color32::from_rgb(0x5E, 0x7C, 0x8E));
1068 + assert_eq!(d.border_default, Color32::from_rgb(0x9C, 0xAE, 0xA9));
1031 1069 }
1032 1070
1033 1071 // ---------------------------------------------------------------
@@ -7,24 +7,33 @@
7 7 name = "audiofiles"
8 8 variant = "light"
9 9
10 - [background]
11 - primary = "#CCDAD1" # Ash Grey — main canvas
12 - secondary = "#B4C5BB" # mid sage — headers / secondary panels
13 - tertiary = "#9CAEA9" # Ash Grey deep — selected / inset
14 - surface = "#DAE3DC" # lighter sage — raised cards/rows
10 + [surface]
11 + page = "#CCDAD1"
12 + raised = "#DAE3DC"
13 + sunken = "#9CAEA9"
14 + overlay = "#B4C5BB"
15 15
16 - [foreground]
17 - primary = "#38302E" # Deep Mocha — body text
18 - secondary = "#6F6866" # Dim Grey
19 - muted = "#788585" # Grey Olive — hints / disabled
16 + [content]
17 + primary = "#38302E"
18 + secondary = "#6F6866"
19 + muted = "#788585"
20 20
21 - [accent]
22 - red = "#B05F4E" # muted terracotta
23 - green = "#6F8A5C" # muted olive
24 - blue = "#5E7C8E" # muted slate
25 - yellow = "#C19A53" # muted ochre
26 - purple = "#836A80" # muted mauve
27 - cyan = "#5F8C82" # muted teal
21 + [action]
22 + primary = "#5E7C8E"
28 23
29 - [border]
30 - default = "#9CAEA9"
24 + [status]
25 + danger = "#B05F4E"
26 + success = "#6F8A5C"
27 + warning = "#C19A53"
28 + info = "#5F8C82"
29 +
30 + [line]
31 + border = "#9CAEA9"
32 +
33 + [category]
34 + one = "#B05F4E"
35 + two = "#6F8A5C"
36 + three = "#5E7C8E"
37 + four = "#C19A53"
38 + five = "#836A80"
39 + six = "#5F8C82"
@@ -5,24 +5,33 @@
5 5 name = "Ayu Light"
6 6 variant = "light"
7 7
8 - [background]
9 - primary = "#e7eaed"
10 - secondary = "#dde1e5"
11 - tertiary = "#d0d4d8"
12 - surface = "#f2f4f6"
8 + [surface]
9 + page = "#e7eaed"
10 + raised = "#f2f4f6"
11 + sunken = "#d0d4d8"
12 + overlay = "#dde1e5"
13 13
14 - [foreground]
15 - primary = "#5c6166"
14 + [content]
15 + primary = "#5c6166"
16 16 secondary = "#6b7580"
17 - muted = "#8b9199"
17 + muted = "#8b9199"
18 18
19 - [accent]
20 - red = "#f07171"
21 - green = "#86b300"
22 - blue = "#399ee6"
23 - yellow = "#ffaa33"
24 - purple = "#a37acc"
25 - cyan = "#55b4d4"
19 + [action]
20 + primary = "#399ee6"
26 21
27 - [border]
28 - default = "#828c9a"
22 + [status]
23 + danger = "#f07171"
24 + success = "#86b300"
25 + warning = "#ffaa33"
26 + info = "#55b4d4"
27 +
28 + [line]
29 + border = "#828c9a"
30 +
31 + [category]
32 + one = "#f07171"
33 + two = "#86b300"
34 + three = "#399ee6"
35 + four = "#ffaa33"
36 + five = "#a37acc"
37 + six = "#55b4d4"
@@ -5,24 +5,33 @@
5 5 name = "Ayu Mirage"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#1f2430"
10 - secondary = "#191e29"
11 - tertiary = "#272d38"
12 - surface = "#242936"
8 + [surface]
9 + page = "#1f2430"
10 + raised = "#242936"
11 + sunken = "#272d38"
12 + overlay = "#191e29"
13 13
14 - [foreground]
15 - primary = "#cccac2"
14 + [content]
15 + primary = "#cccac2"
16 16 secondary = "#b8b4aa"
17 - muted = "#707a8c"
17 + muted = "#707a8c"
18 18
19 - [accent]
20 - red = "#f28779"
21 - green = "#bae67e"
22 - blue = "#5ccfe6"
23 - yellow = "#ffd580"
24 - purple = "#d4bfff"
25 - cyan = "#95e6cb"
19 + [action]
20 + primary = "#5ccfe6"
26 21
27 - [border]
28 - default = "#33415e"
22 + [status]
23 + danger = "#f28779"
24 + success = "#bae67e"
25 + warning = "#ffd580"
26 + info = "#95e6cb"
27 +
28 + [line]
29 + border = "#33415e"
30 +
31 + [category]
32 + one = "#f28779"
33 + two = "#bae67e"
34 + three = "#5ccfe6"
35 + four = "#ffd580"
36 + five = "#d4bfff"
37 + six = "#95e6cb"
@@ -5,24 +5,33 @@
5 5 name = "Carbonfox"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#161616"
10 - secondary = "#101010"
11 - tertiary = "#1e1e1e"
12 - surface = "#252525"
8 + [surface]
9 + page = "#161616"
10 + raised = "#252525"
11 + sunken = "#1e1e1e"
12 + overlay = "#101010"
13 13
14 - [foreground]
15 - primary = "#f2f4f8"
14 + [content]
15 + primary = "#f2f4f8"
16 16 secondary = "#dde1e6"
17 - muted = "#878d96"
17 + muted = "#878d96"
18 18
19 - [accent]
20 - red = "#ee5396"
21 - green = "#25be6a"
22 - blue = "#78a9ff"
23 - yellow = "#08bdba"
24 - purple = "#be95ff"
25 - cyan = "#33b1ff"
19 + [action]
20 + primary = "#78a9ff"
26 21
27 - [border]
28 - default = "#393939"
22 + [status]
23 + danger = "#ee5396"
24 + success = "#25be6a"
25 + warning = "#08bdba"
26 + info = "#33b1ff"
27 +
28 + [line]
29 + border = "#393939"
30 +
31 + [category]
32 + one = "#ee5396"
33 + two = "#25be6a"
34 + three = "#78a9ff"
35 + four = "#08bdba"
36 + five = "#be95ff"
37 + six = "#33b1ff"
@@ -5,24 +5,33 @@
5 5 name = "Catppuccin Frappé"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#303446"
10 - secondary = "#292c3c"
11 - tertiary = "#414559"
12 - surface = "#232634"
8 + [surface]
9 + page = "#303446"
10 + raised = "#232634"
11 + sunken = "#414559"
12 + overlay = "#292c3c"
13 13
14 - [foreground]
15 - primary = "#c6d0f5"
14 + [content]
15 + primary = "#c6d0f5"
16 16 secondary = "#b5bfe2"
17 - muted = "#a5adce"
17 + muted = "#a5adce"
18 18
19 - [accent]
20 - red = "#e78284"
21 - green = "#a6d189"
22 - blue = "#8caaee"
23 - yellow = "#e5c890"
24 - purple = "#ca9ee6"
25 - cyan = "#81c8be"
19 + [action]
20 + primary = "#8caaee"
26 21
27 - [border]
28 - default = "#626880"
22 + [status]
23 + danger = "#e78284"
24 + success = "#a6d189"
25 + warning = "#e5c890"
26 + info = "#81c8be"
27 +
28 + [line]
29 + border = "#626880"
30 +
31 + [category]
32 + one = "#e78284"
33 + two = "#a6d189"
34 + three = "#8caaee"
35 + four = "#e5c890"
36 + five = "#ca9ee6"
37 + six = "#81c8be"
@@ -5,24 +5,33 @@
5 5 name = "Catppuccin Latte"
6 6 variant = "light"
7 7
8 - [background]
9 - primary = "#e6e9ef"
10 - secondary = "#dce0e8"
11 - tertiary = "#ccd0da"
12 - surface = "#eff1f5"
8 + [surface]
9 + page = "#e6e9ef"
10 + raised = "#eff1f5"
11 + sunken = "#ccd0da"
12 + overlay = "#dce0e8"
13 13
14 - [foreground]
15 - primary = "#4c4f69"
14 + [content]
15 + primary = "#4c4f69"
16 16 secondary = "#5c5f77"
17 - muted = "#6c6f82"
17 + muted = "#6c6f82"
18 18
19 - [accent]
20 - red = "#d20f39"
21 - green = "#40a02b"
22 - blue = "#1e66f5"
23 - yellow = "#df8e1d"
24 - purple = "#8839ef"
25 - cyan = "#04a5e5"
19 + [action]
20 + primary = "#1e66f5"
26 21
27 - [border]
28 - default = "#bcc0cc"
22 + [status]
23 + danger = "#d20f39"
24 + success = "#40a02b"
25 + warning = "#df8e1d"
26 + info = "#04a5e5"
27 +
28 + [line]
29 + border = "#bcc0cc"
30 +
31 + [category]
32 + one = "#d20f39"
33 + two = "#40a02b"
34 + three = "#1e66f5"
35 + four = "#df8e1d"
36 + five = "#8839ef"
37 + six = "#04a5e5"
@@ -5,24 +5,33 @@
5 5 name = "Catppuccin Macchiato"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#24273a"
10 - secondary = "#1e2030"
11 - tertiary = "#363a4f"
12 - surface = "#181926"
8 + [surface]
9 + page = "#24273a"
10 + raised = "#181926"
11 + sunken = "#363a4f"
12 + overlay = "#1e2030"
13 13
14 - [foreground]
15 - primary = "#cad3f5"
14 + [content]
15 + primary = "#cad3f5"
16 16 secondary = "#b8c0e0"
17 - muted = "#a5adcb"
17 + muted = "#a5adcb"
18 18
19 - [accent]
20 - red = "#ed8796"
21 - green = "#a6da95"
22 - blue = "#8aadf4"
23 - yellow = "#eed49f"
24 - purple = "#c6a0f6"
25 - cyan = "#8bd5ca"
19 + [action]
20 + primary = "#8aadf4"
26 21
27 - [border]
28 - default = "#5b6078"
22 + [status]
23 + danger = "#ed8796"
24 + success = "#a6da95"
25 + warning = "#eed49f"
26 + info = "#8bd5ca"
27 +
28 + [line]
29 + border = "#5b6078"
30 +
31 + [category]
32 + one = "#ed8796"
33 + two = "#a6da95"
34 + three = "#8aadf4"
35 + four = "#eed49f"
36 + five = "#c6a0f6"
37 + six = "#8bd5ca"
@@ -5,24 +5,33 @@
5 5 name = "Catppuccin Mocha"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#181825"
10 - secondary = "#11111b"
11 - tertiary = "#313244"
12 - surface = "#1e1e2e"
8 + [surface]
9 + page = "#181825"
10 + raised = "#1e1e2e"
11 + sunken = "#313244"
12 + overlay = "#11111b"
13 13
14 - [foreground]
15 - primary = "#cdd6f4"
14 + [content]
15 + primary = "#cdd6f4"
16 16 secondary = "#bac2de"
17 - muted = "#9399b2"
17 + muted = "#9399b2"
18 18
19 - [accent]
20 - red = "#f38ba8"
21 - green = "#a6e3a1"
22 - blue = "#89b4fa"
23 - yellow = "#f9e2af"
24 - purple = "#cba6f7"
25 - cyan = "#89dceb"
19 + [action]
20 + primary = "#89b4fa"
26 21
27 - [border]
28 - default = "#45475a"
22 + [status]
23 + danger = "#f38ba8"
24 + success = "#a6e3a1"
25 + warning = "#f9e2af"
26 + info = "#89dceb"
27 +
28 + [line]
29 + border = "#45475a"
30 +
31 + [category]
32 + one = "#f38ba8"
33 + two = "#a6e3a1"
34 + three = "#89b4fa"
35 + four = "#f9e2af"
36 + five = "#cba6f7"
37 + six = "#89dceb"
@@ -5,24 +5,33 @@
5 5 name = "Dawnfox"
6 6 variant = "light"
7 7
8 - [background]
9 - primary = "#faf4ed"
10 - secondary = "#ebe5df"
11 - tertiary = "#ebe0df"
12 - surface = "#f5efe8"
8 + [surface]
9 + page = "#faf4ed"
10 + raised = "#f5efe8"
11 + sunken = "#ebe0df"
12 + overlay = "#ebe5df"
13 13
14 - [foreground]
15 - primary = "#575279"
14 + [content]
15 + primary = "#575279"
16 16 secondary = "#625c87"
17 - muted = "#a8a3b3"
17 + muted = "#a8a3b3"
18 18
19 - [accent]
20 - red = "#b4637a"
21 - green = "#618774"
22 - blue = "#286983"
23 - yellow = "#ea9d34"
24 - purple = "#907aa9"
25 - cyan = "#56949f"
19 + [action]
20 + primary = "#286983"
26 21
27 - [border]
28 - default = "#bdbfc9"
22 + [status]
23 + danger = "#b4637a"
24 + success = "#618774"
25 + warning = "#ea9d34"
26 + info = "#56949f"
27 +
28 + [line]
29 + border = "#bdbfc9"
30 +
31 + [category]
32 + one = "#b4637a"
33 + two = "#618774"
34 + three = "#286983"
35 + four = "#ea9d34"
36 + five = "#907aa9"
37 + six = "#56949f"
@@ -5,24 +5,33 @@
5 5 name = "Dracula"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#222430"
10 - secondary = "#191A21"
11 - tertiary = "#44475a"
12 - surface = "#282A36"
8 + [surface]
9 + page = "#222430"
10 + raised = "#282A36"
11 + sunken = "#44475a"
12 + overlay = "#191A21"
13 13
14 - [foreground]
15 - primary = "#f8f8f2"
14 + [content]
15 + primary = "#f8f8f2"
16 16 secondary = "#f8f8f2"
17 - muted = "#6272A4"
17 + muted = "#6272A4"
18 18
19 - [accent]
20 - red = "#ff5555"
21 - green = "#50fa7b"
22 - blue = "#8be9fd"
23 - yellow = "#f1fa8c"
24 - purple = "#BD93F9"
25 - cyan = "#8be9fd"
19 + [action]
20 + primary = "#8be9fd"
26 21
27 - [border]
28 - default = "#44475a"
22 + [status]
23 + danger = "#ff5555"
24 + success = "#50fa7b"
25 + warning = "#f1fa8c"
26 + info = "#8be9fd"
27 +
28 + [line]
29 + border = "#44475a"
30 +
31 + [category]
32 + one = "#ff5555"
33 + two = "#50fa7b"
34 + three = "#8be9fd"
35 + four = "#f1fa8c"
36 + five = "#BD93F9"
37 + six = "#8be9fd"
@@ -5,24 +5,33 @@
5 5 name = "Everforest"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#2d353b"
10 - secondary = "#272e33"
11 - tertiary = "#3d484d"
12 - surface = "#343f44"
8 + [surface]
9 + page = "#2d353b"
10 + raised = "#343f44"
11 + sunken = "#3d484d"
12 + overlay = "#272e33"
13 13
14 - [foreground]
15 - primary = "#d3c6aa"
14 + [content]
15 + primary = "#d3c6aa"
16 16 secondary = "#9da9a0"
17 - muted = "#7a8478"
17 + muted = "#7a8478"
18 18
19 - [accent]
20 - red = "#e67e80"
21 - green = "#a7c080"
22 - blue = "#7fbbb3"
23 - yellow = "#dbbc7f"
24 - purple = "#d699b6"
25 - cyan = "#83c092"
19 + [action]
20 + primary = "#7fbbb3"
26 21
27 - [border]
28 - default = "#3d484d"
22 + [status]
23 + danger = "#e67e80"
24 + success = "#a7c080"
25 + warning = "#dbbc7f"
26 + info = "#83c092"
27 +
28 + [line]
29 + border = "#3d484d"
30 +
31 + [category]
32 + one = "#e67e80"
33 + two = "#a7c080"
34 + three = "#7fbbb3"
35 + four = "#dbbc7f"
36 + five = "#d699b6"
37 + six = "#83c092"
@@ -5,24 +5,33 @@
5 5 name = "Flatwhite"
6 6 variant = "light"
7 7
8 - [background]
9 - primary = "#f1ece4"
10 - secondary = "#e4ddd2"
11 - tertiary = "#dcd3c6"
12 - surface = "#f7f3ee"
8 + [surface]
9 + page = "#f1ece4"
10 + raised = "#f7f3ee"
11 + sunken = "#dcd3c6"
12 + overlay = "#e4ddd2"
13 13
14 - [foreground]
15 - primary = "#605a52"
14 + [content]
15 + primary = "#605a52"
16 16 secondary = "#786d5e"
17 - muted = "#9a8b78"
17 + muted = "#9a8b78"
18 18
19 - [accent]
20 - red = "#ff1414"
21 - green = "#2db448"
22 - blue = "#4c5361"
23 - yellow = "#f2a60d"
24 - purple = "#614c61"
25 - cyan = "#465953"
19 + [action]
20 + primary = "#4c5361"
26 21
27 - [border]
28 - default = "#93836c"
22 + [status]
23 + danger = "#ff1414"
24 + success = "#2db448"
25 + warning = "#f2a60d"
26 + info = "#465953"
27 +
28 + [line]
29 + border = "#93836c"
30 +
31 + [category]
32 + one = "#ff1414"
33 + two = "#2db448"
34 + three = "#4c5361"
35 + four = "#f2a60d"
36 + five = "#614c61"
37 + six = "#465953"
@@ -5,24 +5,33 @@
5 5 name = "Gruvbox Dark"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#282828"
10 - secondary = "#1d2021"
11 - tertiary = "#504945"
12 - surface = "#3c3836"
8 + [surface]
9 + page = "#282828"
10 + raised = "#3c3836"
11 + sunken = "#504945"
12 + overlay = "#1d2021"
13 13
14 - [foreground]
15 - primary = "#ebdbb2"
14 + [content]
15 + primary = "#ebdbb2"
16 16 secondary = "#d5c4a1"
17 - muted = "#a89984"
17 + muted = "#a89984"
18 18
19 - [accent]
20 - red = "#fb4934"
21 - green = "#b8bb26"
22 - blue = "#83a598"
23 - yellow = "#fabd2f"
24 - purple = "#d3869b"
25 - cyan = "#8ec07c"
19 + [action]
20 + primary = "#83a598"
26 21
27 - [border]
28 - default = "#504945"
22 + [status]
23 + danger = "#fb4934"
24 + success = "#b8bb26"
25 + warning = "#fabd2f"
26 + info = "#8ec07c"
27 +
28 + [line]
29 + border = "#504945"
30 +
31 + [category]
32 + one = "#fb4934"
33 + two = "#b8bb26"
34 + three = "#83a598"
35 + four = "#fabd2f"
36 + five = "#d3869b"
37 + six = "#8ec07c"
@@ -5,24 +5,33 @@
5 5 name = "Gruvbox Light"
6 6 variant = "light"
7 7
8 - [background]
9 - primary = "#fbf1c7"
10 - secondary = "#f2e5bc"
11 - tertiary = "#d5c4a1"
12 - surface = "#f9f5d7"
8 + [surface]
9 + page = "#fbf1c7"
10 + raised = "#f9f5d7"
11 + sunken = "#d5c4a1"
12 + overlay = "#f2e5bc"
13 13
14 - [foreground]
15 - primary = "#3c3836"
14 + [content]
15 + primary = "#3c3836"
16 16 secondary = "#504945"
17 - muted = "#7c6f64"
17 + muted = "#7c6f64"
18 18
19 - [accent]
20 - red = "#9d0006"
21 - green = "#79740e"
22 - blue = "#076678"
23 - yellow = "#b57614"
24 - purple = "#8f3f71"
25 - cyan = "#427b58"
19 + [action]
20 + primary = "#076678"
26 21
27 - [border]
28 - default = "#d5c4a1"
22 + [status]
23 + danger = "#9d0006"
24 + success = "#79740e"
25 + warning = "#b57614"
26 + info = "#427b58"
27 +
28 + [line]
29 + border = "#d5c4a1"
30 +
31 + [category]
32 + one = "#9d0006"
33 + two = "#79740e"
34 + three = "#076678"
35 + four = "#b57614"
36 + five = "#8f3f71"
37 + six = "#427b58"
@@ -4,24 +4,33 @@
4 4 name = "High Contrast"
5 5 variant = "high-contrast"
6 6
7 - [background]
8 - primary = "#000000"
9 - secondary = "#141414"
10 - tertiary = "#262626"
11 - surface = "#0a0a0a"
7 + [surface]
8 + page = "#000000"
9 + raised = "#0a0a0a"
10 + sunken = "#262626"
11 + overlay = "#141414"
12 12
13 - [foreground]
14 - primary = "#ffffff"
13 + [content]
14 + primary = "#ffffff"
15 15 secondary = "#f0f0f0"
16 - muted = "#b0b0b0"
16 + muted = "#b0b0b0"
17 17
18 - [accent]
19 - red = "#ff6b6b"
20 - green = "#51cf66"
21 - blue = "#74c0fc"
22 - yellow = "#ffd43b"
23 - purple = "#da77f2"
24 - cyan = "#66d9e8"
18 + [action]
19 + primary = "#74c0fc"
25 20
26 - [border]
27 - default = "#666666"
21 + [status]
22 + danger = "#ff6b6b"
23 + success = "#51cf66"
24 + warning = "#ffd43b"
25 + info = "#66d9e8"
26 +
27 + [line]
28 + border = "#666666"
29 +
30 + [category]
31 + one = "#ff6b6b"
32 + two = "#51cf66"
33 + three = "#74c0fc"
34 + four = "#ffd43b"
35 + five = "#da77f2"
36 + six = "#66d9e8"
@@ -5,24 +5,33 @@
5 5 name = "Kanagawa"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#1F1F28"
10 - secondary = "#16161D"
11 - tertiary = "#2A2A37"
12 - surface = "#363646"
8 + [surface]
9 + page = "#1F1F28"
10 + raised = "#363646"
11 + sunken = "#2A2A37"
12 + overlay = "#16161D"
13 13
14 - [foreground]
15 - primary = "#DCD7BA"
14 + [content]
15 + primary = "#DCD7BA"
16 16 secondary = "#C8C093"
17 - muted = "#727169"
17 + muted = "#727169"
18 18
19 - [accent]
20 - red = "#E46876"
21 - green = "#98BB6C"
22 - blue = "#7E9CD8"
23 - yellow = "#E6C384"
24 - purple = "#957FB8"
25 - cyan = "#7FB4CA"
19 + [action]
20 + primary = "#7E9CD8"
26 21
27 - [border]
28 - default = "#54546D"
22 + [status]
23 + danger = "#E46876"
24 + success = "#98BB6C"
25 + warning = "#E6C384"
26 + info = "#7FB4CA"
27 +
28 + [line]
29 + border = "#54546D"
30 +
31 + [category]
32 + one = "#E46876"
33 + two = "#98BB6C"
34 + three = "#7E9CD8"
35 + four = "#E6C384"
36 + five = "#957FB8"
37 + six = "#7FB4CA"
@@ -4,24 +4,33 @@
4 4 name = "Neobrute"
5 5 variant = "light"
6 6
7 - [background]
8 - primary = "#E8F4F8"
9 - secondary = "#D4EBF2"
10 - tertiary = "#C0E2EC"
11 - surface = "#FFFFFF"
7 + [surface]
8 + page = "#E8F4F8"
9 + raised = "#FFFFFF"
10 + sunken = "#C0E2EC"
11 + overlay = "#D4EBF2"
12 12
13 - [foreground]
14 - primary = "#1B365D"
13 + [content]
14 + primary = "#1B365D"
15 15 secondary = "#3D5A80"
16 - muted = "#4d6b82"
16 + muted = "#4d6b82"
17 17
18 - [accent]
19 - red = "#DC3545"
20 - green = "#5CB85C"
21 - blue = "#1B365D"
22 - yellow = "#F7D154"
23 - purple = "#7B68EE"
24 - cyan = "#17A2B8"
18 + [action]
19 + primary = "#1B365D"
25 20
26 - [border]
27 - default = "#1B365D"
21 + [status]
22 + danger = "#DC3545"
23 + success = "#5CB85C"
24 + warning = "#F7D154"
25 + info = "#17A2B8"
26 +
27 + [line]
28 + border = "#1B365D"
29 +
30 + [category]
31 + one = "#DC3545"
32 + two = "#5CB85C"
33 + three = "#1B365D"
34 + four = "#F7D154"
35 + five = "#7B68EE"
36 + six = "#17A2B8"
@@ -5,24 +5,33 @@
5 5 name = "Nightfox"
6 6 variant = "dark"
7 7
8 - [background]
9 - primary = "#192330"
10 - secondary = "#131a24"
11 - tertiary = "#212e3f"
12 - surface = "#29394f"
8 + [surface]
9 + page = "#192330"
10 + raised = "#29394f"
11 + sunken = "#212e3f"
12 + overlay = "#131a24"
13 13
14 - [foreground]
15 - primary = "#cdcecf"
14 + [content]
15 + primary = "#cdcecf"
16 16 secondary = "#aeafb0"
17 - muted = "#71839b"
17 + muted = "#71839b"
18 18
19 - [accent]
20 - red = "#c94f6d"
21 - green = "#81b29a"
22 - blue = "#719cd6"
23 - yellow = "#dbc074"
24 - purple = "#9d79d6"
25 - cyan = "#63cdcf"
19 + [action]
20 + primary = "#719cd6"
26 21
27 - [border]
28 - default = "#39506d"
22 + [status]
23 + danger = "#c94f6d"
24 + success = "#81b29a"
25 + warning = "#dbc074"
26 + info = "#63cdcf"
27 +
28 + [line]
29 + border = "#39506d"
30 +
31 + [category]
32 + one = "#c94f6d"
33 + two = "#81b29a"
34 + three = "#719cd6"
35 + four = "#dbc074"
36 + five = "#9d79d6"
37 + six = "#63cdcf"