liora_components/
empty.rs1use gpui::{AnyElement, App, IntoElement, RenderOnce, SharedString, Window, div, prelude::*, px};
2use liora_core::Config;
3use liora_icons::Icon;
4use liora_icons_lucide::IconName;
5
6pub struct Empty {
7 image: Option<AnyElement>,
8 description: SharedString,
9 extra: Option<Box<dyn Fn(&mut Window, &mut App) -> AnyElement + 'static>>,
10}
11
12impl Empty {
13 pub fn new() -> Self {
14 Self {
15 image: None,
16 description: "暂无数据".into(),
17 extra: None,
18 }
19 }
20
21 pub fn image(mut self, image: impl IntoElement) -> Self {
22 self.image = Some(image.into_any_element());
23 self
24 }
25
26 pub fn description(mut self, d: impl Into<SharedString>) -> Self {
27 self.description = d.into();
28 self
29 }
30
31 pub fn extra<F>(mut self, f: F) -> Self
32 where
33 F: Fn(&mut Window, &mut App) -> AnyElement + 'static,
34 {
35 self.extra = Some(Box::new(f));
36 self
37 }
38}
39
40impl RenderOnce for Empty {
41 fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
42 let theme = cx.global::<Config>().theme.clone();
43
44 div()
45 .flex()
46 .flex_col()
47 .items_center()
48 .justify_center()
49 .w_full()
50 .p_10()
51 .gap_4()
52 .child(
53 div()
54 .flex()
55 .items_center()
56 .justify_center()
57 .w(px(160.0))
58 .h(px(160.0))
59 .child(match self.image {
60 Some(img) => img,
61 None => Icon::new(IconName::PackageOpen)
62 .size(px(100.0))
63 .color(theme.neutral.text_3)
64 .into_any_element(),
65 }),
66 )
67 .child(
68 div()
69 .text_sm()
70 .text_color(theme.neutral.text_3)
71 .child(self.description),
72 )
73 .when_some(self.extra, |s, extra| {
74 s.child(div().mt_2().child((extra)(window, cx)))
75 })
76 }
77}
78
79impl IntoElement for Empty {
80 type Element = gpui::Component<Self>;
81 fn into_element(self) -> Self::Element {
82 gpui::Component::new(self)
83 }
84}