component: Add component and component_preview crates to power UI components (#24456)

This PR formalizes design components with the Component and
ComponentPreview traits.

You can open the preview UI with `workspace: open component preview`.

Component previews no longer need to return `Self` allowing for more
complex previews, and previews of components like `ui::Tooltip` that
supplement other components rather than are rendered by default.

`cargo-machete` incorrectly identifies `linkme` as an unused dep on
crates that have components deriving `IntoComponent`, so you may need to
add this to that crate's `Cargo.toml`:

```toml
# cargo-machete doesn't understand that linkme is used in the component macro
[package.metadata.cargo-machete]
ignored = ["linkme"]
```

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
This commit is contained in:
Nate Butler 2025-02-09 13:25:03 -05:00 committed by GitHub
parent 56cfc60875
commit 8f1ff189cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 1582 additions and 976 deletions

View file

@ -34,6 +34,7 @@ call.workspace = true
client.workspace = true
clock.workspace = true
collections.workspace = true
component.workspace = true
db.workspace = true
derive_more.workspace = true
fs.workspace = true

View file

@ -27,7 +27,6 @@ pub fn init(cx: &mut App) {
enum ThemePreviewPage {
Overview,
Typography,
Components,
}
impl ThemePreviewPage {
@ -35,7 +34,6 @@ impl ThemePreviewPage {
match self {
Self::Overview => "Overview",
Self::Typography => "Typography",
Self::Components => "Components",
}
}
}
@ -64,9 +62,6 @@ impl ThemePreview {
ThemePreviewPage::Typography => {
self.render_typography_page(window, cx).into_any_element()
}
ThemePreviewPage::Components => {
self.render_components_page(window, cx).into_any_element()
}
}
}
}
@ -392,28 +387,6 @@ impl ThemePreview {
)
}
fn render_components_page(&self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let layer = ElevationIndex::Surface;
v_flex()
.id("theme-preview-components")
.overflow_scroll()
.size_full()
.gap_2()
.child(Button::render_component_previews(window, cx))
.child(Checkbox::render_component_previews(window, cx))
.child(CheckboxWithLabel::render_component_previews(window, cx))
.child(ContentGroup::render_component_previews(window, cx))
.child(DecoratedIcon::render_component_previews(window, cx))
.child(Facepile::render_component_previews(window, cx))
.child(Icon::render_component_previews(window, cx))
.child(IconDecoration::render_component_previews(window, cx))
.child(KeybindingHint::render_component_previews(window, cx))
.child(Indicator::render_component_previews(window, cx))
.child(Switch::render_component_previews(window, cx))
.child(Table::render_component_previews(window, cx))
}
fn render_page_nav(&self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
h_flex()
.id("theme-preview-nav")

View file

@ -148,6 +148,7 @@ actions!(
Open,
OpenFiles,
OpenInTerminal,
OpenComponentPreview,
ReloadActiveItem,
SaveAs,
SaveWithoutFormat,
@ -378,6 +379,7 @@ fn prompt_and_open_paths(app_state: Arc<AppState>, options: PathPromptOptions, c
pub fn init(app_state: Arc<AppState>, cx: &mut App) {
init_settings(cx);
component::init();
theme_preview::init(cx);
cx.on_action(Workspace::close_global);