tablo_ui/components/composites/
empty_state.rs1use topcoat::{
2 Result,
3 icon::icon,
4 view::{Attributes, Child, StaticClass, View, class, component, view},
5};
6
7const EMPTY_STATE: StaticClass = class!("flex flex-col items-center gap-2 px-6 py-12 text-center");
8const EMPTY_STATE_ICON: StaticClass = class!(
9 "mb-1 flex size-10 items-center justify-center rounded-full bg-muted \
10 text-muted-foreground [&>svg]:size-5"
11);
12const EMPTY_STATE_TITLE: StaticClass = class!("text-sm font-medium text-foreground");
13const EMPTY_STATE_DETAIL: StaticClass = class!("text-sm text-muted-foreground");
14const EMPTY_STATE_ACTION: StaticClass =
15 class!("mt-2 flex flex-wrap items-center justify-center gap-2");
16
17#[component]
28pub async fn empty_state(
29 #[into]
31 title: String,
32 #[into]
34 #[default]
35 detail: String,
36 #[default]
38 action: Option<Child<'_>>,
39 #[default]
41 mut attrs: Attributes,
42) -> Result<impl View> {
43 Ok(view! {
44 <div class=(class!(EMPTY_STATE, attrs.remove("class"))) (attrs)>
45 <div class=(EMPTY_STATE_ICON) aria-hidden="true">
46 icon(data: crate::icons::INBOX)
47 </div>
48 <p class=(EMPTY_STATE_TITLE)>(title)</p>
49 if !detail.is_empty() {
50 <p class=(EMPTY_STATE_DETAIL)>(detail)</p>
51 }
52 if let Some(action) = action {
53 <div class=(EMPTY_STATE_ACTION)>(action)</div>
54 }
55 </div>
56 })
57}