use std::collections::HashMap; use std::sync::OnceLock; use dioxus::prelude::*; use super::button::{ErrorButton, SuccessButton, WarningButton}; use crate::infrastructure::services::random_svg_generators::{ generate_random_svg_avatar, AvatarConfig, AvatarFeeling, }; include!(concat!(env!("OUT_DIR"), "/style_tokens.rs")); use style::{COLOR_CRITICAL_100, COLOR_SUCCESS_100, COLOR_WARNING_100}; turf::style_sheet!("src/ui/components/modal.scss"); #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub enum Severity { Ok, Warning, Critical, } fn avatar_configs() -> &'static HashMap> { static HASHMAP: OnceLock> = OnceLock::new(); HASHMAP.get_or_init(|| { let mut configs = HashMap::new(); configs.insert( Severity::Critical, AvatarConfig::new(AvatarFeeling::Alerting, COLOR_CRITICAL_100), ); configs.insert( Severity::Warning, AvatarConfig::new(AvatarFeeling::Warning, COLOR_WARNING_100), ); configs.insert( Severity::Ok, AvatarConfig::new(AvatarFeeling::Ok, COLOR_SUCCESS_100), ); configs }) } #[derive(Clone, PartialEq, Props)] pub struct ModalProps { pub severity: Severity, #[props(optional)] pub title: Option, pub children: Element, #[props(optional)] pub on_confirm: Option>, } #[component] pub fn Modal(props: ModalProps) -> Element { let avatar_config = avatar_configs().get(&props.severity); let random_figure_future = use_resource(move || async move { generate_random_svg_avatar(avatar_config).await }); let icon = (*random_figure_future.read_unchecked()) .as_ref() .map(|svg| { rsx! { div { class: ClassName::MODAL_CONTENT_ICON_PLACEHOLDER, dangerous_inner_html: svg.as_str(), } } }); let button_class = match &props.severity { Severity::Ok => SuccessButton, Severity::Warning => WarningButton, Severity::Critical => ErrorButton, }; let _ = icon.as_ref().ok_or(VNode::empty()); rsx! { style { {STYLE_SHEET} } div { class: ClassName::MODAL, div { class: ClassName::MODAL_CONTENT, div { class: ClassName::MODAL_CONTENT_ICON, {icon} } div { class: ClassName::MODAL_CONTENT_TITLE, {props.title} } div { class: ClassName::MODAL_CONTENT_MSG, {props.children} } div { class: ClassName::MODAL_CONTENT_BUTTONS, button_class { onclick: move |evt| { if let Some(cb) = &props.on_confirm { cb.call(evt); } } } } } } } }