use maud::{html, Markup};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Variant {
Info,
Success,
Warning,
Danger,
}
impl Variant {
fn class(&self) -> &'static str {
match self {
Self::Info => "mui-toast--info",
Self::Success => "mui-toast--success",
Self::Warning => "mui-toast--warning",
Self::Danger => "mui-toast--danger",
}
}
fn role(&self) -> &'static str {
match self {
Self::Danger => "alert",
_ => "status",
}
}
fn aria_live(&self) -> &'static str {
match self {
Self::Danger => "assertive",
_ => "polite",
}
}
}
#[derive(Debug, Clone)]
pub struct Props {
pub title: String,
pub description: Option<String>,
pub variant: Variant,
pub duration_ms: u32,
pub id: String,
}
impl Default for Props {
fn default() -> Self {
Self {
title: String::new(),
description: None,
variant: Variant::Info,
duration_ms: 5000,
id: String::new(),
}
}
}
pub fn render(props: Props) -> Markup {
let role = props.variant.role();
let aria_live = props.variant.aria_live();
html! {
div class={"mui-toast " (props.variant.class())}
id=(props.id)
role=(role)
aria-live=(aria_live)
data-mui="toast"
data-duration=(props.duration_ms.to_string())
{
div.mui-toast__title {
(props.title)
}
@if let Some(desc) = props.description {
div.mui-toast__description {
(desc)
}
}
button type="button" class="mui-toast__close" aria-label="Dismiss" {
"×"
}
}
}
}
pub fn viewport() -> Markup {
html! {
div id="mui-toast-viewport" class="mui-toast-viewport" aria-live="polite" {}
}
}
pub fn showcase() -> Markup {
html! {
(viewport())
div.mui-showcase__grid {
div {
p.mui-showcase__caption { "Static toasts (inline)" }
div style="position: static;" {
(render(Props {
title: "Profile updated".into(),
description: Some("Your display name and avatar have been saved.".into()),
variant: Variant::Info,
duration_ms: 5000,
id: "toast-info-static".into(),
}))
(render(Props {
title: "Invoice sent".into(),
description: Some("Invoice #1042 has been emailed to the client.".into()),
variant: Variant::Success,
duration_ms: 5000,
id: "toast-success-static".into(),
}))
(render(Props {
title: "Session expiring in 5 minutes".into(),
description: Some("Save your work now to avoid losing unsaved changes.".into()),
variant: Variant::Warning,
duration_ms: 5000,
id: "toast-warning-static".into(),
}))
(render(Props {
title: "Payment failed".into(),
description: Some("Please check your card details and try again.".into()),
variant: Variant::Danger,
duration_ms: 5000,
id: "toast-danger-static".into(),
}))
}
}
div {
p.mui-showcase__caption { "Imperative (click to dispatch)" }
p.mui-showcase__caption { "Title only" }
div.mui-showcase__row {
button type="button"
class="mui-btn mui-btn--default mui-btn--md"
onclick="MaudUI.toast({variant:'info', title:'Profile updated', duration_ms:5000})"
{
"Show info toast"
}
button type="button"
class="mui-btn mui-btn--default mui-btn--md"
onclick="MaudUI.toast({variant:'success', title:'Changes saved', duration_ms:5000})"
{
"Show success toast"
}
button type="button"
class="mui-btn mui-btn--default mui-btn--md"
onclick="MaudUI.toast({variant:'warning', title:'Session expiring soon', duration_ms:5000})"
{
"Show warning toast"
}
button type="button"
class="mui-btn mui-btn--default mui-btn--md"
onclick="MaudUI.toast({variant:'danger', title:'Upload failed', duration_ms:5000})"
{
"Show error toast"
}
}
p.mui-showcase__caption { "With description" }
div.mui-showcase__row {
button type="button"
class="mui-btn mui-btn--default mui-btn--md"
onclick="MaudUI.toast({variant:'info', title:'New comment', description:'Alex replied to your thread in #design.', duration_ms:5000})"
{
"Info with description"
}
button type="button"
class="mui-btn mui-btn--default mui-btn--md"
onclick="MaudUI.toast({variant:'success', title:'Deployment complete', description:'v2.4.1 is now live in production.', duration_ms:5000})"
{
"Success with description"
}
button type="button"
class="mui-btn mui-btn--default mui-btn--md"
onclick="MaudUI.toast({variant:'warning', title:'API rate limit', description:'You have 12 requests remaining this minute.', duration_ms:5000})"
{
"Warning with description"
}
button type="button"
class="mui-btn mui-btn--default mui-btn--md"
onclick="MaudUI.toast({variant:'danger', title:'Payment failed', description:'Please check your card details and try again.', duration_ms:5000})"
{
"Error with description"
}
}
}
}
}
}