rustyle_css/components/
badge.rs

1//! Badge component styles
2//!
3//! Provides type-safe badge styling with variants and sizes.
4
5use super::{ComponentStyle, Size, Variant};
6use crate::css::{Color, Radius, Spacing};
7use crate::tokens::{BorderTokens, ColorTokens, SpacingTokens};
8
9/// Badge style configuration
10#[derive(Clone, Debug)]
11pub struct BadgeStyle {
12    pub variant: Variant,
13    pub size: Size,
14    pub tokens: Option<BadgeTokens>,
15}
16
17/// Badge design tokens
18#[derive(Clone, Debug)]
19pub struct BadgeTokens {
20    pub colors: ColorTokens,
21    pub spacing: SpacingTokens,
22    pub borders: BorderTokens,
23}
24
25impl BadgeStyle {
26    /// Create a new badge style
27    pub fn new(variant: Variant, size: Size) -> Self {
28        Self {
29            variant,
30            size,
31            tokens: None,
32        }
33    }
34
35    /// Set custom tokens
36    pub fn tokens(mut self, tokens: BadgeTokens) -> Self {
37        self.tokens = Some(tokens);
38        self
39    }
40
41    fn background_color(&self) -> Color {
42        let default_colors = ColorTokens::default();
43        let colors = self
44            .tokens
45            .as_ref()
46            .map(|t| &t.colors)
47            .unwrap_or(&default_colors);
48
49        match &self.variant {
50            Variant::Primary => colors.primary.c100.clone(),
51            Variant::Secondary => colors.secondary.c100.clone(),
52            Variant::Success => colors.semantic.success.clone(),
53            Variant::Error => colors.semantic.error.clone(),
54            Variant::Warning => colors.semantic.warning.clone(),
55            Variant::Info => colors.semantic.info.clone(),
56        }
57    }
58
59    fn text_color(&self) -> Color {
60        let default_colors = ColorTokens::default();
61        let colors = self
62            .tokens
63            .as_ref()
64            .map(|t| &t.colors)
65            .unwrap_or(&default_colors);
66
67        match &self.variant {
68            Variant::Primary => colors.primary.c700.clone(),
69            Variant::Secondary => colors.secondary.c700.clone(),
70            Variant::Success | Variant::Error | Variant::Warning | Variant::Info => {
71                colors.text.inverse.clone()
72            }
73        }
74    }
75
76    fn padding(&self) -> Spacing {
77        let default_spacing = SpacingTokens::default();
78        let spacing = self
79            .tokens
80            .as_ref()
81            .map(|t| &t.spacing)
82            .unwrap_or(&default_spacing);
83
84        match &self.size {
85            Size::Small => Spacing::vh(spacing.xs.clone(), spacing.sm.clone()),
86            Size::Medium => Spacing::vh(spacing.sm.clone(), spacing.md.clone()),
87            Size::Large => Spacing::vh(spacing.md.clone(), spacing.lg.clone()),
88            Size::ExtraLarge => Spacing::vh(spacing.lg.clone(), spacing.xl.clone()),
89        }
90    }
91
92    fn border_radius(&self) -> Radius {
93        let default_borders = BorderTokens::default();
94        let borders = self
95            .tokens
96            .as_ref()
97            .map(|t| &t.borders)
98            .unwrap_or(&default_borders);
99
100        match &self.size {
101            Size::Small => Radius::all(borders.radius.sm.clone()),
102            Size::Medium => Radius::all(borders.radius.base.clone()),
103            Size::Large => Radius::all(borders.radius.lg.clone()),
104            Size::ExtraLarge => Radius::all(borders.radius.xl.clone()),
105        }
106    }
107}
108
109impl ComponentStyle for BadgeStyle {
110    fn to_css(&self) -> String {
111        let mut css = String::new();
112
113        css.push_str(&format!(
114            "background-color: {}; ",
115            self.background_color().to_css()
116        ));
117        css.push_str(&format!("color: {}; ", self.text_color().to_css()));
118        css.push_str(&format!("padding: {}; ", self.padding().to_css()));
119        css.push_str(&format!(
120            "border-radius: {}; ",
121            self.border_radius().to_css()
122        ));
123        css.push_str("display: inline-flex; ");
124        css.push_str("align-items: center; ");
125        css.push_str("justify-content: center; ");
126        css.push_str("font-weight: 500; ");
127        css.push_str("font-size: 0.875rem; ");
128        css.push_str("line-height: 1; ");
129        css.push_str("white-space: nowrap; ");
130
131        css
132    }
133
134    fn class_name(&self) -> &str {
135        "rustyle-badge"
136    }
137}
138
139impl Default for BadgeStyle {
140    fn default() -> Self {
141        Self::new(Variant::Primary, Size::Medium)
142    }
143}