allowthem_server/
branding.rs1use allowthem_core::AllowThem;
2use allowthem_core::applications::BrandingConfig;
3use allowthem_core::types::ClientId;
4
5pub fn compute_accent_variants(hex: &str) -> (String, String, String) {
10 match parse_hex(hex) {
11 Some((r, g, b)) => {
12 let accent = format!("#{:02x}{:02x}{:02x}", r, g, b);
13 let hover = darken(r, g, b, 0.15);
14 let ring = lighten(r, g, b, 0.25);
15 (accent, hover, ring)
16 }
17 None => default_accents(),
18 }
19}
20
21pub fn default_accents() -> (String, String, String) {
22 ("#2563eb".into(), "#1d4ed8".into(), "#3b82f6".into())
23}
24
25pub async fn lookup_branding(
30 ath: &AllowThem,
31 client_id: Option<&ClientId>,
32) -> Option<BrandingConfig> {
33 let cid = client_id?;
34 match ath.db().get_branding_by_client_id(cid).await {
35 Ok(branding) => branding,
36 Err(e) => {
37 tracing::warn!(client_id = %cid, error = %e, "branding lookup failed");
38 None
39 }
40 }
41}
42
43fn parse_hex(hex: &str) -> Option<(u8, u8, u8)> {
44 let bytes = hex.as_bytes();
45 if bytes.len() != 7 || bytes[0] != b'#' {
46 return None;
47 }
48 let r = u8::from_str_radix(&hex[1..3], 16).ok()?;
49 let g = u8::from_str_radix(&hex[3..5], 16).ok()?;
50 let b = u8::from_str_radix(&hex[5..7], 16).ok()?;
51 Some((r, g, b))
52}
53
54fn darken(r: u8, g: u8, b: u8, factor: f32) -> String {
55 let scale = 1.0 - factor;
56 format!(
57 "#{:02x}{:02x}{:02x}",
58 (r as f32 * scale) as u8,
59 (g as f32 * scale) as u8,
60 (b as f32 * scale) as u8,
61 )
62}
63
64fn lighten(r: u8, g: u8, b: u8, factor: f32) -> String {
65 format!(
66 "#{:02x}{:02x}{:02x}",
67 (r as f32 + (255.0 - r as f32) * factor) as u8,
68 (g as f32 + (255.0 - g as f32) * factor) as u8,
69 (b as f32 + (255.0 - b as f32) * factor) as u8,
70 )
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn parse_hex_valid() {
79 assert_eq!(compute_accent_variants("#2563eb").0, "#2563eb");
80 }
81
82 #[test]
83 fn default_accents_are_blue() {
84 let (accent, _, _) = default_accents();
85 assert_eq!(accent, "#2563eb");
86 }
87
88 #[test]
89 fn compute_variants_invalid_falls_back() {
90 assert_eq!(compute_accent_variants("invalid"), default_accents());
91 }
92}