soma-ui 0.1.1

A Leptos 0.8 component library: 160+ accessible UI components, blocks, charts, and a ChartDB-style schema diagram — with a prebuilt stylesheet.
Documentation
use crate::components::data_display::card::{Card, CardContent};
use crate::icons::{icondata, Icon};
use leptos::prelude::*;

#[derive(Clone, Copy, PartialEq, Eq)]
pub enum StatTrend {
    Up,
    Down,
    Neutral,
}

#[component]
pub fn Stat(
    #[prop(into)] label: String,
    #[prop(into)] value: String,
    #[prop(default = None)] delta: Option<String>,
    #[prop(default = None)] trend: Option<StatTrend>,
    #[prop(optional)] icon: Option<icondata::Icon>,
    #[prop(default = String::new())] class: String,
) -> impl IntoView {
    let delta_view = delta.map(|d| {
        let (trend_class, prefix) = match trend {
            Some(StatTrend::Up) => (
                "bg-green-500/10 text-green-600 dark:text-green-400",
                "\u{2191} ",
            ),
            Some(StatTrend::Down) => ("bg-red-500/10 text-red-600 dark:text-red-400", "\u{2193} "),
            _ => ("bg-muted text-muted-foreground", ""),
        };
        let text = format!("{}{}", prefix, d);
        let chip_class = format!(
            "inline-flex items-center gap-1 text-xs font-medium mt-2 px-2 py-0.5 rounded-full {}",
            trend_class
        );
        view! { <span class=chip_class>{text}</span> }
    });

    let icon_view = icon.map(|ic| {
        view! {
            <div class="p-2 bg-accent rounded-md">
                <Icon icon=Signal::derive(move || ic) attr:class="w-5 h-5 text-muted-foreground" />
            </div>
        }
    });

    view! {
        <Card class=class>
            <CardContent>
                <div class="flex items-start justify-between">
                    <div>
                        <p class="text-sm text-muted-foreground">{label}</p>
                        <p class="font-heading text-3xl font-bold text-foreground mt-1">{value}</p>
                        {delta_view}
                    </div>
                    {icon_view}
                </div>
            </CardContent>
        </Card>
    }
}