tablo_ui/components/composites/
error_state.rs1use topcoat::{
2 Result,
3 icon::{icon, iconify::iconify_icon},
4 view::{Attributes, Child, StaticClass, View, class, component, view},
5};
6
7const ERROR_STATE: StaticClass = class!(
8 "flex flex-col items-center gap-2 rounded-xl border border-destructive/30 \
9 bg-card px-6 py-12 text-center text-card-foreground \
10 [&>svg]:mb-1 [&>svg]:size-6 [&>svg]:text-destructive"
11);
12const ERROR_STATE_TITLE: StaticClass = class!("text-sm font-medium text-destructive");
13const ERROR_STATE_DETAIL: StaticClass = class!("text-sm text-muted-foreground");
14const ERROR_STATE_ACTION: StaticClass = class!("text-sm font-medium text-primary hover:underline");
15
16#[component]
32pub async fn error_state(
33 #[into]
35 title: String,
36 #[into]
38 #[default]
39 detail: String,
40 #[default]
44 action: Option<Child<'_>>,
45 #[default]
48 mut attrs: Attributes,
49) -> Result<impl View> {
50 Ok(view! {
51 <div class=(class!(ERROR_STATE, attrs.remove("class"))) (attrs)>
52 icon(data: iconify_icon!("lucide:circle-alert"))
53 <p class=(class!(ERROR_STATE_TITLE))>(title)</p>
54 if !detail.is_empty() {
55 <p class=(class!(ERROR_STATE_DETAIL))>(detail)</p>
56 }
57 if let Some(action) = action {
58 <div class=(class!(ERROR_STATE_ACTION))>(action)</div>
59 }
60 </div>
61 })
62}
63
64#[cfg(test)]
65mod tests;