htmx_components/server/
alert.rs

1use rscx::{component, html, props};
2
3pub enum AlertKind {
4    Error,
5    Info,
6    Success,
7    Warning,
8}
9
10#[props]
11pub struct AlertProps {
12    #[builder(default=AlertKind::Error)]
13    kind: AlertKind,
14
15    #[builder(setter(into))]
16    title: String,
17
18    #[builder(setter(into), default)]
19    class: String,
20
21    #[builder(default)]
22    children: String,
23}
24
25#[component]
26pub fn Alert(props: AlertProps) -> String {
27    let (bg_color, title_color, description_color) = match props.kind {
28        AlertKind::Error => ("bg-red-50", "text-red-800", "text-red-700"),
29        AlertKind::Info => ("bg-blue-50", "text-blue-800", "text-blue-700"),
30        AlertKind::Warning => ("bg-yellow-50", "text-yellow-800", "text-yellow-700"),
31        AlertKind::Success => ("bg-green-50", "text-green-800", "text-green-700"),
32    };
33
34    html! {
35        <div class=format!("rounded-md {} p-4 {}", bg_color, props.class).trim()>
36            <div class="flex">
37                <div class="flex-shrink-0">
38                    <AlertIcon kind=props.kind />
39                </div>
40                <div class="ml-3">
41                    <h3 class=format!("text-sm font-medium {}", title_color)>{props.title}</h3>
42                    {if !props.children.is_empty() {
43                        html! {
44                            <div class=format!("mt-2 text-sm {}", description_color)>{props.children}</div>
45                        }
46                    } else {
47                        html! {
48                            <></>
49                        }
50                    }}
51                </div>
52            </div>
53        </div>
54    }
55}
56
57#[component]
58fn AlertIcon(kind: AlertKind) -> String {
59    match kind {
60        AlertKind::Error => html! {
61            <svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
62                <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
63            </svg>
64        },
65        AlertKind::Info => html! {
66            <svg class="h-5 w-5 text-blue-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
67                <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z" clip-rule="evenodd" />
68            </svg>
69        },
70        AlertKind::Success => html! {
71            <svg class="h-5 w-5 text-green-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
72                <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z" clip-rule="evenodd" />
73            </svg>
74        },
75        AlertKind::Warning => html! {
76            <svg class="h-5 w-5 text-yellow-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
77                <path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z" clip-rule="evenodd" />
78            </svg>
79        },
80    }
81}