ui/components/
stats_card.rs1use gpui::{AnyElement, FontWeight};
2
3use crate::prelude::*;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum StatsTrend {
12 Up,
13 Down,
14}
15
16#[derive(IntoElement, RegisterComponent)]
19pub struct StatsCard {
20 label: SharedString,
21 value: SharedString,
22 trend: Option<(StatsTrend, SharedString)>,
23}
24
25impl StatsCard {
26 pub fn new(label: impl Into<SharedString>, value: impl Into<SharedString>) -> Self {
27 Self {
28 label: label.into(),
29 value: value.into(),
30 trend: None,
31 }
32 }
33
34 pub fn trend(mut self, trend: StatsTrend, delta: impl Into<SharedString>) -> Self {
35 self.trend = Some((trend, delta.into()));
36 self
37 }
38}
39
40impl RenderOnce for StatsCard {
41 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
42 Card::new().child(
43 v_flex()
44 .gap_2()
45 .child(
46 Label::new(self.label)
47 .size(LabelSize::Small)
48 .color(Color::Muted),
49 )
50 .child(
51 h_flex()
52 .items_end()
53 .justify_between()
54 .child(
55 div()
56 .text_size(rems(1.75))
57 .font_weight(FontWeight::BOLD)
58 .text_color(semantic::text(cx))
59 .child(self.value),
60 )
61 .when_some(self.trend, |this, (trend, delta)| {
62 let (icon, color) = match trend {
63 StatsTrend::Up => (IconName::ArrowUp, palette::success(600)),
64 StatsTrend::Down => (IconName::ArrowDown, palette::danger(600)),
65 };
66 this.child(
67 h_flex()
68 .gap_1()
69 .items_center()
70 .child(
71 Icon::new(icon)
72 .size(IconSize::XSmall)
73 .color(Color::Custom(color)),
74 )
75 .child(
76 Label::new(delta)
77 .size(LabelSize::Small)
78 .color(Color::Custom(color)),
79 ),
80 )
81 }),
82 ),
83 )
84 }
85}
86
87impl Component for StatsCard {
88 fn scope() -> ComponentScope {
89 ComponentScope::DataDisplay
90 }
91
92 fn description() -> Option<&'static str> {
93 Some("A metric tile built on `Card`, with a large number, label, and optional trend.")
94 }
95
96 fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
97 Some(
98 h_flex()
99 .gap_4()
100 .child(StatsCard::new("Total Subscribers", "71,897"))
101 .child(StatsCard::new("Avg. Open Rate", "58.16%").trend(StatsTrend::Up, "4.05%"))
102 .child(StatsCard::new("Avg. Click Rate", "24.57%").trend(StatsTrend::Down, "1.39%"))
103 .into_any_element(),
104 )
105 }
106}