
This PR further organizes and documents the component crate. It: - Simplifies the component registry - Gives access to `ComponentMetadata` sooner - Enables lookup by id in preview extension implementations (`ComponentId` -> `ComponentMetadata`) - Should slightly improve the performance of ComponentPreview It also brings component statuses to the Component trait:    Release Notes: - N/A
205 lines
6.1 KiB
Rust
205 lines
6.1 KiB
Rust
use gpui::{
|
|
AnyElement, App, IntoElement, Pixels, RenderOnce, SharedString, Window, div, pattern_slash,
|
|
prelude::*, px, rems,
|
|
};
|
|
use theme::ActiveTheme;
|
|
|
|
/// A single example of a component.
|
|
#[derive(IntoElement)]
|
|
pub struct ComponentExample {
|
|
pub variant_name: SharedString,
|
|
pub description: Option<SharedString>,
|
|
pub element: AnyElement,
|
|
pub width: Option<Pixels>,
|
|
}
|
|
|
|
impl RenderOnce for ComponentExample {
|
|
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
|
div()
|
|
.pt_2()
|
|
.map(|this| {
|
|
if let Some(width) = self.width {
|
|
this.w(width)
|
|
} else {
|
|
this.w_full()
|
|
}
|
|
})
|
|
.flex()
|
|
.flex_col()
|
|
.gap_3()
|
|
.child(
|
|
div()
|
|
.flex()
|
|
.flex_col()
|
|
.child(
|
|
div()
|
|
.child(self.variant_name.clone())
|
|
.text_size(rems(1.0))
|
|
.text_color(cx.theme().colors().text),
|
|
)
|
|
.when_some(self.description, |this, description| {
|
|
this.child(
|
|
div()
|
|
.text_size(rems(0.875))
|
|
.text_color(cx.theme().colors().text_muted)
|
|
.child(description.clone()),
|
|
)
|
|
}),
|
|
)
|
|
.child(
|
|
div()
|
|
.flex()
|
|
.w_full()
|
|
.rounded_xl()
|
|
.min_h(px(100.))
|
|
.justify_center()
|
|
.p_8()
|
|
.border_1()
|
|
.border_color(cx.theme().colors().border.opacity(0.5))
|
|
.bg(pattern_slash(
|
|
cx.theme().colors().surface_background.opacity(0.5),
|
|
12.0,
|
|
12.0,
|
|
))
|
|
.shadow_sm()
|
|
.child(self.element),
|
|
)
|
|
.into_any_element()
|
|
}
|
|
}
|
|
|
|
impl ComponentExample {
|
|
pub fn new(variant_name: impl Into<SharedString>, element: AnyElement) -> Self {
|
|
Self {
|
|
variant_name: variant_name.into(),
|
|
element,
|
|
description: None,
|
|
width: None,
|
|
}
|
|
}
|
|
|
|
pub fn description(mut self, description: impl Into<SharedString>) -> Self {
|
|
self.description = Some(description.into());
|
|
self
|
|
}
|
|
|
|
pub fn width(mut self, width: Pixels) -> Self {
|
|
self.width = Some(width);
|
|
self
|
|
}
|
|
}
|
|
|
|
/// A group of component examples.
|
|
#[derive(IntoElement)]
|
|
pub struct ComponentExampleGroup {
|
|
pub title: Option<SharedString>,
|
|
pub examples: Vec<ComponentExample>,
|
|
pub width: Option<Pixels>,
|
|
pub grow: bool,
|
|
pub vertical: bool,
|
|
}
|
|
|
|
impl RenderOnce for ComponentExampleGroup {
|
|
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
|
|
div()
|
|
.flex_col()
|
|
.text_sm()
|
|
.text_color(cx.theme().colors().text_muted)
|
|
.map(|this| {
|
|
if let Some(width) = self.width {
|
|
this.w(width)
|
|
} else {
|
|
this.w_full()
|
|
}
|
|
})
|
|
.when_some(self.title, |this, title| {
|
|
this.gap_4().child(
|
|
div()
|
|
.flex()
|
|
.items_center()
|
|
.gap_3()
|
|
.pb_1()
|
|
.child(div().h_px().w_4().bg(cx.theme().colors().border))
|
|
.child(
|
|
div()
|
|
.flex_none()
|
|
.text_size(px(10.))
|
|
.child(title.to_uppercase()),
|
|
)
|
|
.child(
|
|
div()
|
|
.h_px()
|
|
.w_full()
|
|
.flex_1()
|
|
.bg(cx.theme().colors().border),
|
|
),
|
|
)
|
|
})
|
|
.child(
|
|
div()
|
|
.flex()
|
|
.flex_col()
|
|
.items_start()
|
|
.w_full()
|
|
.gap_6()
|
|
.children(self.examples)
|
|
.into_any_element(),
|
|
)
|
|
.into_any_element()
|
|
}
|
|
}
|
|
|
|
impl ComponentExampleGroup {
|
|
pub fn new(examples: Vec<ComponentExample>) -> Self {
|
|
Self {
|
|
title: None,
|
|
examples,
|
|
width: None,
|
|
grow: false,
|
|
vertical: false,
|
|
}
|
|
}
|
|
pub fn with_title(title: impl Into<SharedString>, examples: Vec<ComponentExample>) -> Self {
|
|
Self {
|
|
title: Some(title.into()),
|
|
examples,
|
|
width: None,
|
|
grow: false,
|
|
vertical: false,
|
|
}
|
|
}
|
|
pub fn width(mut self, width: Pixels) -> Self {
|
|
self.width = Some(width);
|
|
self
|
|
}
|
|
pub fn grow(mut self) -> Self {
|
|
self.grow = true;
|
|
self
|
|
}
|
|
pub fn vertical(mut self) -> Self {
|
|
self.vertical = true;
|
|
self
|
|
}
|
|
}
|
|
|
|
pub fn single_example(
|
|
variant_name: impl Into<SharedString>,
|
|
example: AnyElement,
|
|
) -> ComponentExample {
|
|
ComponentExample::new(variant_name, example)
|
|
}
|
|
|
|
pub fn empty_example(variant_name: impl Into<SharedString>) -> ComponentExample {
|
|
ComponentExample::new(variant_name, div().w_full().text_center().items_center().text_xs().opacity(0.4).child("This space is intentionally left blank. It indicates a case that should render nothing.").into_any_element())
|
|
}
|
|
|
|
pub fn example_group(examples: Vec<ComponentExample>) -> ComponentExampleGroup {
|
|
ComponentExampleGroup::new(examples)
|
|
}
|
|
|
|
pub fn example_group_with_title(
|
|
title: impl Into<SharedString>,
|
|
examples: Vec<ComponentExample>,
|
|
) -> ComponentExampleGroup {
|
|
ComponentExampleGroup::with_title(title, examples)
|
|
}
|