add empty state
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
use gpui::prelude::FluentBuilder as _;
|
||||
use gpui::{
|
||||
App, IntoElement, ParentElement as _, RenderOnce, SharedString, StyleRefinement, Styled as _,
|
||||
Window, div, relative,
|
||||
};
|
||||
use gpui_native_icons::{IconRole, icon};
|
||||
use gpui_native_theme::{ActiveTheme as _, Size};
|
||||
|
||||
use crate::common::{StyledExt, v_flex};
|
||||
|
||||
/// The centered "nothing here yet" panel for lists, tables, and searches.
|
||||
#[derive(IntoElement)]
|
||||
pub struct EmptyState {
|
||||
icon: Option<IconRole>,
|
||||
headline: SharedString,
|
||||
hint: Option<SharedString>,
|
||||
action: Option<gpui::AnyElement>,
|
||||
style: StyleRefinement,
|
||||
}
|
||||
|
||||
impl EmptyState {
|
||||
/// Creates an empty state whose headline is the primary statement.
|
||||
pub fn new<L>(headline: L) -> Self
|
||||
where
|
||||
L: Into<SharedString>,
|
||||
{
|
||||
Self {
|
||||
icon: None,
|
||||
headline: headline.into(),
|
||||
hint: None,
|
||||
action: None,
|
||||
style: StyleRefinement::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a large muted icon above the headline.
|
||||
pub fn icon(mut self, role: IconRole) -> Self {
|
||||
self.icon = Some(role);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a secondary line under the headline.
|
||||
pub fn hint<L>(mut self, hint: L) -> Self
|
||||
where
|
||||
L: Into<SharedString>,
|
||||
{
|
||||
self.hint = Some(hint.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets an action element — usually a button — under the hint.
|
||||
pub fn action<E>(mut self, action: E) -> Self
|
||||
where
|
||||
E: IntoElement,
|
||||
{
|
||||
self.action = Some(action.into_any_element());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl gpui::Styled for EmptyState {
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
&mut self.style
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for EmptyState {
|
||||
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let theme = cx.theme();
|
||||
let metrics = theme.sizes.resolve(Size::Medium);
|
||||
let muted_foreground = theme.colors.muted_foreground;
|
||||
let foreground = theme.colors.foreground;
|
||||
let illustration = metrics.icon_size * 2.0;
|
||||
|
||||
v_flex()
|
||||
.w_full()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.text_center()
|
||||
.p_4()
|
||||
.when_some(self.icon, |state, role| {
|
||||
state.child(
|
||||
div()
|
||||
.mb_2()
|
||||
.child(icon(role).size(illustration).color(muted_foreground)),
|
||||
)
|
||||
})
|
||||
.child(
|
||||
div()
|
||||
.text_size(metrics.text_size)
|
||||
.font_weight(gpui::FontWeight::MEDIUM)
|
||||
.text_color(foreground)
|
||||
.line_height(relative(1.3))
|
||||
.child(self.headline),
|
||||
)
|
||||
.when_some(self.hint, |state, hint| {
|
||||
state.child(
|
||||
div()
|
||||
.text_size(metrics.caption_size)
|
||||
.text_color(muted_foreground)
|
||||
.child(hint),
|
||||
)
|
||||
})
|
||||
.when_some(self.action, |state, action| {
|
||||
state.child(div().mt_3().child(action))
|
||||
})
|
||||
.refine_style(&self.style)
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,9 @@ pub mod input;
|
||||
#[cfg(feature = "dialog")]
|
||||
pub mod dialog;
|
||||
|
||||
#[cfg(feature = "empty_state")]
|
||||
pub mod empty_state;
|
||||
|
||||
#[cfg(feature = "menu")]
|
||||
pub mod menu;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user