use maud::{html, Markup};
use crate::primitives::card;
#[derive(Clone, Debug, Default)]
pub struct Props {
pub title: Option<String>,
pub subtitle: Option<String>,
pub cards: Vec<StatCard>,
pub chart: Option<Markup>,
pub activity: Option<Vec<ActivityItem>>,
}
#[derive(Clone, Debug)]
pub struct StatCard {
pub label: String,
pub value: String,
pub delta: Option<Delta>,
pub hint: Option<String>,
}
#[derive(Clone, Debug)]
pub struct Delta {
pub value: String,
pub positive: bool,
}
#[derive(Clone, Debug)]
pub struct ActivityItem {
pub actor: String,
pub action: String,
pub timestamp: String,
pub avatar_initials: String,
}
pub fn render(props: Props) -> Markup {
html! {
section class="mui-block mui-block--stats" {
@if props.title.is_some() || props.subtitle.is_some() {
header class="mui-block--stats__header" {
@if let Some(title) = &props.title {
h2 class="mui-block--stats__title" { (title) }
}
@if let Some(subtitle) = &props.subtitle {
p class="mui-block--stats__subtitle" { (subtitle) }
}
}
}
div class="mui-block--stats__grid" {
@for c in &props.cards {
(card::render(card::Props {
children: html! {
div class="mui-block--stats__card" {
p class="mui-block--stats__label" { (c.label) }
p class="mui-block--stats__value" { (c.value) }
@if c.delta.is_some() || c.hint.is_some() {
p class="mui-block--stats__delta-row" {
@if let Some(d) = &c.delta {
span class=(if d.positive {
"mui-block--stats__delta mui-block--stats__delta--up"
} else {
"mui-block--stats__delta mui-block--stats__delta--down"
}) { (d.value) }
}
@if let Some(hint) = &c.hint {
span class="mui-block--stats__hint" { (hint) }
}
}
}
}
},
..Default::default()
}))
}
}
@if let Some(chart) = &props.chart {
div class="mui-block--stats__chart" {
(card::render(card::Props {
children: html! { (chart) },
..Default::default()
}))
}
}
@if let Some(items) = &props.activity {
div class="mui-block--stats__activity" {
(card::render(card::Props {
title: Some("Recent activity".into()),
children: html! {
ul class="mui-block--stats__activity-list" {
@for item in items {
li class="mui-block--stats__activity-item" {
span class="mui-block--stats__activity-avatar" aria-hidden="true" {
(item.avatar_initials)
}
span class="mui-block--stats__activity-text" {
span class="mui-block--stats__activity-actor" { (item.actor) }
" " (item.action)
}
span class="mui-block--stats__activity-time" { (item.timestamp) }
}
}
}
},
..Default::default()
}))
}
}
}
}
}
pub fn preview() -> Markup {
render(Props {
title: Some("Overview".into()),
subtitle: Some("Last 30 days compared to the previous period.".into()),
cards: vec![
StatCard {
label: "MRR".into(),
value: "$42,310".into(),
delta: Some(Delta {
value: "+12.4%".into(),
positive: true,
}),
hint: Some("vs last month".into()),
},
StatCard {
label: "New customers".into(),
value: "284".into(),
delta: Some(Delta {
value: "+8.1%".into(),
positive: true,
}),
hint: Some("vs last month".into()),
},
StatCard {
label: "Active sessions".into(),
value: "1,429".into(),
delta: Some(Delta {
value: "-3.2%".into(),
positive: false,
}),
hint: Some("vs last month".into()),
},
StatCard {
label: "Churn".into(),
value: "2.1%".into(),
delta: Some(Delta {
value: "-0.4%".into(),
positive: true,
}),
hint: Some("lower is better".into()),
},
],
chart: None,
activity: Some(vec![
ActivityItem {
actor: "Sofia Davis".into(),
action: "upgraded to the Pro plan".into(),
timestamp: "2 min ago".into(),
avatar_initials: "SD".into(),
},
ActivityItem {
actor: "Mateo Ortega".into(),
action: "invited 3 teammates".into(),
timestamp: "14 min ago".into(),
avatar_initials: "MO".into(),
},
ActivityItem {
actor: "Jin-Ho Lee".into(),
action: "published a new workflow".into(),
timestamp: "37 min ago".into(),
avatar_initials: "JL".into(),
},
ActivityItem {
actor: "Amira Khan".into(),
action: "exported the Q1 revenue report".into(),
timestamp: "1 hour ago".into(),
avatar_initials: "AK".into(),
},
]),
})
}