Skip to main content

photon_ui/theme/
color.rs

1//! Raw RGB color definitions for the Beam Design Language palette.
2
3/// An RGB color with 8-bit channels.
4#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
5pub struct Color(pub u8, pub u8, pub u8);
6
7impl Color {
8    /// Beam gold — `#ffe295`.
9    pub const BEAM_GOLD: Self = Self(0xff, 0xe2, 0x95);
10    /// Beam orange — `#ff8105`.
11    pub const BEAM_ORANGE: Self = Self(0xff, 0x81, 0x05);
12    /// Pure black — `#000000`.
13    pub const BLACK: Self = Self(0x00, 0x00, 0x00);
14    /// Bright yellow — `#ffd900`.
15    pub const BRIGHT_YELLOW: Self = Self(0xff, 0xd9, 0x00);
16    /// Dark card surface — `#2a2a2a`.
17    pub const CARD_DARK: Self = Self(0x2a, 0x2a, 0x2a);
18    /// Warm cream — `#fff0c2`.
19    pub const CREAM: Self = Self(0xff, 0xf0, 0xc2);
20    /// Sunbeam black — `#1f1f1f`.
21    pub const SUNBEAM_BLACK: Self = Self(0x1f, 0x1f, 0x1f);
22    /// Sunbeam flame — `#fb6424`.
23    pub const SUNBEAM_FLAME: Self = Self(0xfb, 0x64, 0x24);
24    // ── Primary colors ──────────────────────────────────────────────
25    /// Sunbeam orange — `#fa520f`.
26    pub const SUNBEAM_ORANGE: Self = Self(0xfa, 0x52, 0x0f);
27    /// Sunshine 300 — `#ffd06a`.
28    pub const SUNSHINE_300: Self = Self(0xff, 0xd0, 0x6a);
29    /// Sunshine 500 — `#ffb83e`.
30    pub const SUNSHINE_500: Self = Self(0xff, 0xb8, 0x3e);
31    /// Sunshine 700 — `#ffa110`.
32    pub const SUNSHINE_700: Self = Self(0xff, 0xa1, 0x10);
33    // ── Sunshine scale ──────────────────────────────────────────────
34    /// Sunshine 900 — `#ff8a00`.
35    pub const SUNSHINE_900: Self = Self(0xff, 0x8a, 0x00);
36    // ── Surfaces ────────────────────────────────────────────────────
37    /// Warm ivory — `#fffaed`.
38    pub const WARM_IVORY: Self = Self(0xff, 0xfa, 0xed);
39    // ── Neutrals ────────────────────────────────────────────────────
40    /// Pure white — `#ffffff`.
41    pub const WHITE: Self = Self(0xff, 0xff, 0xff);
42
43    /// Parse a hex color string (e.g. `"#fa520f"` or `"fa520f"`).
44    pub fn from_hex(hex: &str) -> Option<Self> {
45        let s = hex.strip_prefix('#').unwrap_or(hex);
46        if s.len() != 6 {
47            return None;
48        }
49        let r = match u8::from_str_radix(&s[0..2], 0x10) {
50            | Ok(v) => v,
51            | Err(_) => return None,
52        };
53        let g = match u8::from_str_radix(&s[2..4], 0x10) {
54            | Ok(v) => v,
55            | Err(_) => return None,
56        };
57        let b = match u8::from_str_radix(&s[4..6], 0x10) {
58            | Ok(v) => v,
59            | Err(_) => return None,
60        };
61        Some(Self(r, g, b))
62    }
63
64    /// Return the color as a 6-digit hex string.
65    pub fn to_hex(&self) -> String {
66        format!("#{:02x}{:02x}{:02x}", self.0, self.1, self.2)
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn color_from_hex() {
76        assert_eq!(Color::from_hex("#fa520f"), Some(Color::SUNBEAM_ORANGE));
77        assert_eq!(Color::from_hex("fa520f"), Some(Color::SUNBEAM_ORANGE));
78        assert_eq!(Color::from_hex("fff"), None);
79        assert_eq!(Color::from_hex("#gg0000"), None);
80        assert_eq!(Color::from_hex("#00zz00"), None);
81        assert_eq!(Color::from_hex("#0000aa1"), None);
82        assert_eq!(Color::from_hex("#0000zz"), None);
83    }
84
85    #[test]
86    fn color_to_hex() {
87        assert_eq!(Color::SUNBEAM_ORANGE.to_hex(), "#fa520f");
88        assert_eq!(Color::WHITE.to_hex(), "#ffffff");
89        assert_eq!(Color::BLACK.to_hex(), "#000000");
90    }
91}