shadow-design 0.1.0

Modular, high-performance UI component library for Dioxus 0.7 applications
Documentation
use dioxus::prelude::*;

#[derive(Clone, Copy, PartialEq, Debug, Default)]
pub enum CardShadow {
    None,
    Sm,
    #[default]
    Md,
    Lg,
    Xl,
}

impl CardShadow {
    pub fn scss_class(&self) -> &'static str {
        match self {
            CardShadow::None => "sd-card--shadow-none",
            CardShadow::Sm => "sd-card--shadow-sm",
            CardShadow::Md => "sd-card--shadow-md",
            CardShadow::Lg => "sd-card--shadow-lg",
            CardShadow::Xl => "sd-card--shadow-xl",
        }
    }
}

#[derive(Clone, Copy, PartialEq, Debug, Default)]
pub enum CardVariant {
    #[default]
    Default,
    Elevated,
    Interactive,
    Metric,
}

impl CardVariant {
    pub fn scss_class(&self) -> &'static str {
        match self {
            CardVariant::Default => "",
            CardVariant::Elevated => "sd-card--elevated",
            CardVariant::Interactive => "sd-card--interactive",
            CardVariant::Metric => "sd-card--metric",
        }
    }
}

#[component]
pub fn Card(
    #[props(default)] title: Option<String>,
    #[props(default)] subtitle: Option<String>,
    #[props(default)] variant: CardVariant,
    #[props(default)] shadow: CardShadow,
    #[props(default)] hover_glow: bool,
    #[props(default)] glow: Option<bool>,
    #[props(default = false)] overflow_hidden: bool,
    #[props(default)] class: String,
    #[props(default)] footer: Option<Element>,
    children: Element,
) -> Element {
    let variant_class = variant.scss_class();
    let shadow_class = shadow.scss_class();
    let overflow_class = if overflow_hidden {
        "sd-card--overflow-hidden"
    } else {
        ""
    };

    #[cfg(feature = "theme")]
    let theme = crate::theme::use_theme();
    #[cfg(feature = "theme")]
    let radius_class = theme().radius_scale.md();
    #[cfg(feature = "theme")]
    let glow_class = match glow {
        Some(true) => match theme().primary_color {
            crate::theme::PrimaryColor::Violet => "sd-card--glow-violet",
            crate::theme::PrimaryColor::Obsidian => "sd-card--glow-obsidian",
            crate::theme::PrimaryColor::Crimson => "sd-card--glow-crimson",
            crate::theme::PrimaryColor::Cyan => "sd-card--glow-cyan",
            crate::theme::PrimaryColor::Emerald => "sd-card--glow-emerald",
        },
        Some(false) => "",
        None => {
            if hover_glow
                || (theme().glow_mode != crate::theme::GlowMode::Off
                    && variant == CardVariant::Interactive)
            {
                "sd-card--hover-glow"
            } else {
                ""
            }
        }
    };

    #[cfg(not(feature = "theme"))]
    let radius_class = "";
    #[cfg(not(feature = "theme"))]
    let glow_class = if hover_glow || glow == Some(true) {
        "sd-card--hover-glow"
    } else {
        ""
    };

    rsx! {
        div {
            class: "sd-card {variant_class} {shadow_class} {radius_class} {glow_class} {overflow_class} {class}",
            if title.is_some() || subtitle.is_some() {
                div { class: "sd-card__header",
                    if let Some(t) = title {
                        h3 { class: "sd-card__title", "{t}" }
                    }
                    if let Some(s) = subtitle {
                        p { class: "sd-card__subtitle", "{s}" }
                    }
                }
            }
            div { class: "sd-card__body",
                {children}
            }
            if let Some(f) = footer {
                div { class: "sd-card__footer",
                    {f}
                }
            }
        }
    }
}