diff --git a/crates/terminal_view2/src/terminal_view.rs b/crates/terminal_view2/src/terminal_view.rs index 3cbea11072..330e289aa8 100644 --- a/crates/terminal_view2/src/terminal_view.rs +++ b/crates/terminal_view2/src/terminal_view.rs @@ -300,11 +300,14 @@ impl TerminalView { cx: &mut ViewContext, ) { self.context_menu = Some(ContextMenu::build(cx, |menu, _| { - menu.action(ListEntry::new(Label::new("Clear")), Box::new(Clear)) - .action( - ListEntry::new(Label::new("Close")), - Box::new(CloseActiveItem { save_intent: None }), - ) + menu.action( + ListEntry::new("clear", Label::new("Clear")), + Box::new(Clear), + ) + .action( + ListEntry::new("close", Label::new("Close")), + Box::new(CloseActiveItem { save_intent: None }), + ) })); dbg!(&position); // todo!() diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 3814dca471..eb9daf3cda 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use std::rc::Rc; -use crate::{prelude::*, v_stack, List, ListItem}; +use crate::{prelude::*, v_stack, List}; use crate::{ListEntry, ListSeparator, ListSubHeader}; use gpui::{ overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, DispatchPhase, Div, @@ -9,7 +9,7 @@ use gpui::{ MouseDownEvent, Pixels, Point, Render, RenderOnce, View, VisualContext, WeakView, }; -pub enum ContextMenuItem { +pub enum ContextMenuItem { Separator(ListSeparator), Header(ListSubHeader), Entry( @@ -18,7 +18,7 @@ pub enum ContextMenuItem { ), } -pub struct ContextMenu { +pub struct ContextMenu { items: Vec>, focus_handle: FocusHandle, handle: WeakView, @@ -105,25 +105,25 @@ impl Render for ContextMenu { // .bg(cx.theme().colors().elevated_surface_background) // .border() // .border_color(cx.theme().colors().border) - .child(List::new( - self.items - .iter() - .map(|item| match item { - ContextMenuItem::Separator(separator) => { - ListItem::Separator(separator.clone()) - } - ContextMenuItem::Header(header) => ListItem::Header(header.clone()), - ContextMenuItem::Entry(entry, callback) => { - let callback = callback.clone(); - let handle = self.handle.clone(); - ListItem::Entry(entry.clone().on_click(move |this, cx| { + .child( + List::new().children(self.items.iter().map(|item| match item { + ContextMenuItem::Separator(separator) => { + separator.clone().render_into_any() + } + ContextMenuItem::Header(header) => header.clone().render_into_any(), + ContextMenuItem::Entry(entry, callback) => { + let callback = callback.clone(); + let handle = self.handle.clone(); + entry + .clone() + .on_click(move |this, cx| { handle.update(cx, |view, cx| callback(view, cx)).ok(); cx.emit(Manager::Dismiss); - })) - } - }) - .collect(), - )), + }) + .render_into_any() + } + })), + ), ) } } @@ -322,13 +322,17 @@ mod stories { ContextMenu::build(cx, |menu, _| { menu.header(header) .separator() - .entry(ListEntry::new(Label::new("Print current time")), |v, cx| { - println!("dispatching PrintCurrentTime action"); - cx.dispatch_action(PrintCurrentDate.boxed_clone()) - }) - .entry(ListEntry::new(Label::new("Print best food")), |v, cx| { - cx.dispatch_action(PrintBestFood.boxed_clone()) - }) + .entry( + ListEntry::new("Print current time", Label::new("Print current time")), + |v, cx| { + println!("dispatching PrintCurrentTime action"); + cx.dispatch_action(PrintCurrentDate.boxed_clone()) + }, + ) + .entry( + ListEntry::new("Print best food", Label::new("Print best food")), + |v, cx| cx.dispatch_action(PrintBestFood.boxed_clone()), + ) }) } diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index 485253d4df..59a97e0c5d 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -1,4 +1,5 @@ -use gpui::{div, Div, RenderOnce, Stateful, StatefulInteractiveElement}; +use gpui::{div, AnyElement, Div, RenderOnce, Stateful, StatefulInteractiveElement}; +use smallvec::SmallVec; use std::rc::Rc; use crate::settings::user_settings; @@ -177,7 +178,7 @@ impl ListHeader { // } } -#[derive(Clone)] +#[derive(RenderOnce, Clone)] pub struct ListSubHeader { label: SharedString, left_icon: Option, @@ -197,8 +198,12 @@ impl ListSubHeader { self.left_icon = left_icon; self } +} - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Element { +impl Component for ListSubHeader { + type Rendered = Div; + + fn render(self, view: &mut V, cx: &mut ViewContext) -> Self::Rendered { h_stack().flex_1().w_full().relative().py_1().child( div() .h_6() @@ -232,55 +237,9 @@ pub enum ListEntrySize { Medium, } -#[derive(Clone)] -pub enum ListItem { - Entry(ListEntry), - Separator(ListSeparator), - Header(ListSubHeader), -} - -impl From> for ListItem { - fn from(entry: ListEntry) -> Self { - Self::Entry(entry) - } -} - -impl From for ListItem { - fn from(entry: ListSeparator) -> Self { - Self::Separator(entry) - } -} - -impl From for ListItem { - fn from(entry: ListSubHeader) -> Self { - Self::Header(entry) - } -} - -impl ListItem { - pub fn new(label: Label) -> Self { - Self::Entry(ListEntry::new(label)) - } - - pub fn as_entry(&mut self) -> Option<&mut ListEntry> { - if let Self::Entry(entry) = self { - Some(entry) - } else { - None - } - } - - fn render(self, view: &mut V, ix: usize, cx: &mut ViewContext) -> Div { - match self { - ListItem::Entry(entry) => div().child(entry.render(ix, cx)), - ListItem::Separator(separator) => div().child(separator.render(view, cx)), - ListItem::Header(header) => div().child(header.render(view, cx)), - } - } -} - -// #[derive(RenderOnce)] -pub struct ListEntry { +#[derive(RenderOnce)] +pub struct ListEntry { + id: ElementId, disabled: bool, // TODO: Reintroduce this // disclosure_control_style: DisclosureControlVisibility, @@ -297,6 +256,7 @@ pub struct ListEntry { impl Clone for ListEntry { fn clone(&self) -> Self { Self { + id: self.id.clone(), disabled: self.disabled, indent_level: self.indent_level, label: self.label.clone(), @@ -311,8 +271,9 @@ impl Clone for ListEntry { } impl ListEntry { - pub fn new(label: Label) -> Self { + pub fn new(id: impl Into, label: Label) -> Self { Self { + id: id.into(), disabled: false, indent_level: 0, label, @@ -364,8 +325,12 @@ impl ListEntry { self.size = size; self } +} - fn render(self, ix: usize, cx: &mut ViewContext) -> Stateful> { +impl Component for ListEntry { + type Rendered = Stateful>; + + fn render(self, view: &mut V, cx: &mut ViewContext) -> Self::Rendered { let settings = user_settings(cx); let left_content = match self.left_slot.clone() { @@ -386,7 +351,7 @@ impl ListEntry { ListEntrySize::Medium => div().h_7(), }; div() - .id(ix) + .id(self.id) .relative() .hover(|mut style| { style.background = Some(cx.theme().colors().editor_background.into()); @@ -454,25 +419,20 @@ impl Component for ListSeparator { #[derive(RenderOnce)] pub struct List { - items: Vec>, /// Message to display when the list is empty /// Defaults to "No items" empty_message: SharedString, header: Option, toggle: Toggle, + children: SmallVec<[AnyElement; 2]>, } impl Component for List { type Rendered = Div; fn render(self, view: &mut V, cx: &mut ViewContext) -> Self::Rendered { - let list_content = match (self.items.is_empty(), self.toggle) { - (false, _) => div().children( - self.items - .into_iter() - .enumerate() - .map(|(ix, item)| item.render(view, ix, cx)), - ), + let list_content = match (self.children.is_empty(), self.toggle) { + (false, _) => div().children(self.children), (true, Toggle::Toggled(false)) => div(), (true, _) => { div().child(Label::new(self.empty_message.clone()).color(TextColor::Muted)) @@ -488,12 +448,12 @@ impl Component for List { } impl List { - pub fn new(items: Vec>) -> Self { + pub fn new() -> Self { Self { - items, empty_message: "No items".into(), header: None, toggle: Toggle::NotToggleable, + children: SmallVec::new(), } } @@ -511,25 +471,10 @@ impl List { self.toggle = toggle; self } +} - fn render(self, view: &mut V, cx: &mut ViewContext) -> impl Element { - let list_content = match (self.items.is_empty(), self.toggle) { - (false, _) => div().children( - self.items - .into_iter() - .enumerate() - .map(|(ix, item)| item.render(view, ix, cx)), - ), - (true, Toggle::Toggled(false)) => div(), - (true, _) => { - div().child(Label::new(self.empty_message.clone()).color(TextColor::Muted)) - } - }; - - v_stack() - .w_full() - .py_1() - .children(self.header.map(|header| header)) - .child(list_content) +impl ParentElement for List { + fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> { + &mut self.children } } diff --git a/crates/ui2/src/static_data.rs b/crates/ui2/src/static_data.rs index 673766c411..84d89eb092 100644 --- a/crates/ui2/src/static_data.rs +++ b/crates/ui2/src/static_data.rs @@ -7,14 +7,13 @@ use gpui::{AppContext, ViewContext}; use rand::Rng; use theme2::ActiveTheme; -use crate::{binding, HighlightedText}; use crate::{ - Buffer, BufferRow, BufferRows, Button, EditorPane, FileSystemStatus, GitStatus, - HighlightedLine, Icon, KeyBinding, Label, ListEntry, ListEntrySize, Livestream, MicStatus, - Notification, PaletteItem, Player, PlayerCallStatus, PlayerWithCallStatus, PublicPlayer, - ScreenShareStatus, Symbol, Tab, TextColor, Toggle, VideoStatus, + binding, Buffer, BufferRow, BufferRows, Button, EditorPane, FileSystemStatus, GitStatus, + HighlightedLine, HighlightedText, Icon, KeyBinding, Label, ListEntry, ListEntrySize, + Livestream, MicStatus, Notification, NotificationAction, PaletteItem, Player, PlayerCallStatus, + PlayerWithCallStatus, PublicPlayer, ScreenShareStatus, Symbol, Tab, TextColor, Toggle, + VideoStatus, }; -use crate::{ListItem, NotificationAction}; pub fn static_tabs_example() -> Vec { vec![ @@ -478,225 +477,238 @@ pub fn static_new_notification_items_2() -> Vec> { ] } -pub fn static_project_panel_project_items() -> Vec> { +pub fn static_project_panel_project_items() -> Vec> { vec![ - ListEntry::new(Label::new("zed")) + ListEntry::new("zed", Label::new("zed")) .left_icon(Icon::FolderOpen.into()) .indent_level(0) .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new(".cargo")) + ListEntry::new(".cargo", Label::new(".cargo")) .left_icon(Icon::Folder.into()) .indent_level(1), - ListEntry::new(Label::new(".config")) + ListEntry::new(".config", Label::new(".config")) .left_icon(Icon::Folder.into()) .indent_level(1), - ListEntry::new(Label::new(".git").color(TextColor::Hidden)) + ListEntry::new(".git", Label::new(".git").color(TextColor::Hidden)) .left_icon(Icon::Folder.into()) .indent_level(1), - ListEntry::new(Label::new(".cargo")) + ListEntry::new(".cargo", Label::new(".cargo")) .left_icon(Icon::Folder.into()) .indent_level(1), - ListEntry::new(Label::new(".idea").color(TextColor::Hidden)) + ListEntry::new(".idea", Label::new(".idea").color(TextColor::Hidden)) .left_icon(Icon::Folder.into()) .indent_level(1), - ListEntry::new(Label::new("assets")) + ListEntry::new("assets", Label::new("assets")) .left_icon(Icon::Folder.into()) .indent_level(1) .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new("cargo-target").color(TextColor::Hidden)) - .left_icon(Icon::Folder.into()) - .indent_level(1), - ListEntry::new(Label::new("crates")) + ListEntry::new( + "cargo-target", + Label::new("cargo-target").color(TextColor::Hidden), + ) + .left_icon(Icon::Folder.into()) + .indent_level(1), + ListEntry::new("crates", Label::new("crates")) .left_icon(Icon::FolderOpen.into()) .indent_level(1) .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new("activity_indicator")) + ListEntry::new("activity_indicator", Label::new("activity_indicator")) .left_icon(Icon::Folder.into()) .indent_level(2), - ListEntry::new(Label::new("ai")) + ListEntry::new("ai", Label::new("ai")) .left_icon(Icon::Folder.into()) .indent_level(2), - ListEntry::new(Label::new("audio")) + ListEntry::new("audio", Label::new("audio")) .left_icon(Icon::Folder.into()) .indent_level(2), - ListEntry::new(Label::new("auto_update")) + ListEntry::new("auto_update", Label::new("auto_update")) .left_icon(Icon::Folder.into()) .indent_level(2), - ListEntry::new(Label::new("breadcrumbs")) + ListEntry::new("breadcrumbs", Label::new("breadcrumbs")) .left_icon(Icon::Folder.into()) .indent_level(2), - ListEntry::new(Label::new("call")) + ListEntry::new("call", Label::new("call")) .left_icon(Icon::Folder.into()) .indent_level(2), - ListEntry::new(Label::new("sqlez").color(TextColor::Modified)) + ListEntry::new("sqlez", Label::new("sqlez").color(TextColor::Modified)) .left_icon(Icon::Folder.into()) .indent_level(2) .toggle(Toggle::Toggled(false)), - ListEntry::new(Label::new("gpui2")) + ListEntry::new("gpui2", Label::new("gpui2")) .left_icon(Icon::FolderOpen.into()) .indent_level(2) .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new("src")) + ListEntry::new("src", Label::new("src")) .left_icon(Icon::FolderOpen.into()) .indent_level(3) .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new("derive_element.rs")) + ListEntry::new("derive_element.rs", Label::new("derive_element.rs")) .left_icon(Icon::FileRust.into()) .indent_level(4), - ListEntry::new(Label::new("storybook").color(TextColor::Modified)) - .left_icon(Icon::FolderOpen.into()) - .indent_level(1) - .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new("docs").color(TextColor::Default)) + ListEntry::new( + "storybook", + Label::new("storybook").color(TextColor::Modified), + ) + .left_icon(Icon::FolderOpen.into()) + .indent_level(1) + .toggle(Toggle::Toggled(true)), + ListEntry::new("docs", Label::new("docs").color(TextColor::Default)) .left_icon(Icon::Folder.into()) .indent_level(2) .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new("src").color(TextColor::Modified)) + ListEntry::new("src", Label::new("src").color(TextColor::Modified)) .left_icon(Icon::FolderOpen.into()) .indent_level(3) .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new("ui").color(TextColor::Modified)) + ListEntry::new("ui", Label::new("ui").color(TextColor::Modified)) .left_icon(Icon::FolderOpen.into()) .indent_level(4) .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new("component").color(TextColor::Created)) - .left_icon(Icon::FolderOpen.into()) - .indent_level(5) - .toggle(Toggle::Toggled(true)), - ListEntry::new(Label::new("facepile.rs").color(TextColor::Default)) + ListEntry::new( + "component", + Label::new("component").color(TextColor::Created), + ) + .left_icon(Icon::FolderOpen.into()) + .indent_level(5) + .toggle(Toggle::Toggled(true)), + ListEntry::new( + "facepile.rs", + Label::new("facepile.rs").color(TextColor::Default), + ) + .left_icon(Icon::FileRust.into()) + .indent_level(6), + ListEntry::new( + "follow_group.rs", + Label::new("follow_group.rs").color(TextColor::Default), + ) + .left_icon(Icon::FileRust.into()) + .indent_level(6), + ListEntry::new( + "list_item.rs", + Label::new("list_item.rs").color(TextColor::Created), + ) + .left_icon(Icon::FileRust.into()) + .indent_level(6), + ListEntry::new("tab.rs", Label::new("tab.rs").color(TextColor::Default)) .left_icon(Icon::FileRust.into()) .indent_level(6), - ListEntry::new(Label::new("follow_group.rs").color(TextColor::Default)) - .left_icon(Icon::FileRust.into()) - .indent_level(6), - ListEntry::new(Label::new("list_item.rs").color(TextColor::Created)) - .left_icon(Icon::FileRust.into()) - .indent_level(6), - ListEntry::new(Label::new("tab.rs").color(TextColor::Default)) - .left_icon(Icon::FileRust.into()) - .indent_level(6), - ListEntry::new(Label::new("target").color(TextColor::Hidden)) + ListEntry::new("target", Label::new("target").color(TextColor::Hidden)) .left_icon(Icon::Folder.into()) .indent_level(1), - ListEntry::new(Label::new(".dockerignore")) + ListEntry::new(".dockerignore", Label::new(".dockerignore")) .left_icon(Icon::FileGeneric.into()) .indent_level(1), - ListEntry::new(Label::new(".DS_Store").color(TextColor::Hidden)) - .left_icon(Icon::FileGeneric.into()) - .indent_level(1), - ListEntry::new(Label::new("Cargo.lock")) + ListEntry::new( + ".DS_Store", + Label::new(".DS_Store").color(TextColor::Hidden), + ) + .left_icon(Icon::FileGeneric.into()) + .indent_level(1), + ListEntry::new("Cargo.lock", Label::new("Cargo.lock")) .left_icon(Icon::FileLock.into()) .indent_level(1), - ListEntry::new(Label::new("Cargo.toml")) + ListEntry::new("Cargo.toml", Label::new("Cargo.toml")) .left_icon(Icon::FileToml.into()) .indent_level(1), - ListEntry::new(Label::new("Dockerfile")) + ListEntry::new("Dockerfile", Label::new("Dockerfile")) .left_icon(Icon::FileGeneric.into()) .indent_level(1), - ListEntry::new(Label::new("Procfile")) + ListEntry::new("Procfile", Label::new("Procfile")) .left_icon(Icon::FileGeneric.into()) .indent_level(1), - ListEntry::new(Label::new("README.md")) + ListEntry::new("README.md", Label::new("README.md")) .left_icon(Icon::FileDoc.into()) .indent_level(1), ] - .into_iter() - .map(From::from) - .collect() } -pub fn static_project_panel_single_items() -> Vec> { +pub fn static_project_panel_single_items() -> Vec> { vec![ - ListEntry::new(Label::new("todo.md")) + ListEntry::new("todo.md", Label::new("todo.md")) .left_icon(Icon::FileDoc.into()) .indent_level(0), - ListEntry::new(Label::new("README.md")) + ListEntry::new("README.md", Label::new("README.md")) .left_icon(Icon::FileDoc.into()) .indent_level(0), - ListEntry::new(Label::new("config.json")) + ListEntry::new("config.json", Label::new("config.json")) .left_icon(Icon::FileGeneric.into()) .indent_level(0), ] - .into_iter() - .map(From::from) - .collect() } -pub fn static_collab_panel_current_call() -> Vec> { +pub fn static_collab_panel_current_call() -> Vec> { vec![ - ListEntry::new(Label::new("as-cii")).left_avatar("http://github.com/as-cii.png?s=50"), - ListEntry::new(Label::new("nathansobo")) + ListEntry::new("as-cii", Label::new("as-cii")) + .left_avatar("http://github.com/as-cii.png?s=50"), + ListEntry::new("nathansobo", Label::new("nathansobo")) .left_avatar("http://github.com/nathansobo.png?s=50"), - ListEntry::new(Label::new("maxbrunsfeld")) + ListEntry::new("maxbrunsfeld", Label::new("maxbrunsfeld")) .left_avatar("http://github.com/maxbrunsfeld.png?s=50"), ] - .into_iter() - .map(From::from) - .collect() } -pub fn static_collab_panel_channels() -> Vec> { +pub fn static_collab_panel_channels() -> Vec> { vec![ - ListEntry::new(Label::new("zed")) + ListEntry::new("zed", Label::new("zed")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(0), - ListEntry::new(Label::new("community")) + ListEntry::new("community", Label::new("community")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(1), - ListEntry::new(Label::new("dashboards")) + ListEntry::new("dashboards", Label::new("dashboards")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), - ListEntry::new(Label::new("feedback")) + ListEntry::new("feedback", Label::new("feedback")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), - ListEntry::new(Label::new("teams-in-channels-alpha")) - .left_icon(Icon::Hash.into()) - .size(ListEntrySize::Medium) - .indent_level(2), - ListEntry::new(Label::new("current-projects")) + ListEntry::new( + "teams-in-channels-alpha", + Label::new("teams-in-channels-alpha"), + ) + .left_icon(Icon::Hash.into()) + .size(ListEntrySize::Medium) + .indent_level(2), + ListEntry::new("current-projects", Label::new("current-projects")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(1), - ListEntry::new(Label::new("codegen")) + ListEntry::new("codegen", Label::new("codegen")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), - ListEntry::new(Label::new("gpui2")) + ListEntry::new("gpui2", Label::new("gpui2")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), - ListEntry::new(Label::new("livestreaming")) + ListEntry::new("livestreaming", Label::new("livestreaming")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), - ListEntry::new(Label::new("open-source")) + ListEntry::new("open-source", Label::new("open-source")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), - ListEntry::new(Label::new("replace")) + ListEntry::new("replace", Label::new("replace")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), - ListEntry::new(Label::new("semantic-index")) + ListEntry::new("semantic-index", Label::new("semantic-index")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), - ListEntry::new(Label::new("vim")) + ListEntry::new("vim", Label::new("vim")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), - ListEntry::new(Label::new("web-tech")) + ListEntry::new("web-tech", Label::new("web-tech")) .left_icon(Icon::Hash.into()) .size(ListEntrySize::Medium) .indent_level(2), ] - .into_iter() - .map(From::from) - .collect() } pub fn example_editor_actions() -> Vec { diff --git a/crates/ui2/src/to_extract/collab_panel.rs b/crates/ui2/src/to_extract/collab_panel.rs index e5fafa62f1..aa12e354bc 100644 --- a/crates/ui2/src/to_extract/collab_panel.rs +++ b/crates/ui2/src/to_extract/collab_panel.rs @@ -28,41 +28,45 @@ impl Component for CollabPanel { .border_color(cx.theme().colors().border) .border_b() .child( - List::new(static_collab_panel_current_call()) + List::new() .header( ListHeader::new("CRDB") .left_icon(Icon::Hash.into()) .toggle(Toggle::Toggled(true)), ) - .toggle(Toggle::Toggled(true)), + .toggle(Toggle::Toggled(true)) + .children(static_collab_panel_current_call()), ), ) .child( v_stack().id("channels").py_1().child( - List::new(static_collab_panel_channels()) + List::new() .header(ListHeader::new("CHANNELS").toggle(Toggle::Toggled(true))) .empty_message("No channels yet. Add a channel to get started.") - .toggle(Toggle::Toggled(true)), + .toggle(Toggle::Toggled(true)) + .children(static_collab_panel_channels()), ), ) .child( v_stack().id("contacts-online").py_1().child( - List::new(static_collab_panel_current_call()) + List::new() .header( ListHeader::new("CONTACTS – ONLINE") .toggle(Toggle::Toggled(true)), ) - .toggle(Toggle::Toggled(true)), + .toggle(Toggle::Toggled(true)) + .children(static_collab_panel_current_call()), ), ) .child( v_stack().id("contacts-offline").py_1().child( - List::new(static_collab_panel_current_call()) + List::new() .header( ListHeader::new("CONTACTS – OFFLINE") .toggle(Toggle::Toggled(false)), ) - .toggle(Toggle::Toggled(false)), + .toggle(Toggle::Toggled(false)) + .children(static_collab_panel_current_call()), ), ), ) diff --git a/crates/ui2/src/to_extract/project_panel.rs b/crates/ui2/src/to_extract/project_panel.rs index 06735356c7..cd19c6a8a8 100644 --- a/crates/ui2/src/to_extract/project_panel.rs +++ b/crates/ui2/src/to_extract/project_panel.rs @@ -29,14 +29,16 @@ impl Component for ProjectPanel { .flex_col() .overflow_y_scroll() .child( - List::new(static_project_panel_single_items()) + List::new() .header(ListHeader::new("FILES")) - .empty_message("No files in directory"), + .empty_message("No files in directory") + .children(static_project_panel_single_items()), ) .child( - List::new(static_project_panel_project_items()) + List::new() .header(ListHeader::new("PROJECT")) - .empty_message("No folders in directory"), + .empty_message("No folders in directory") + .children(static_project_panel_project_items()), ), ) .child( @@ -67,14 +69,16 @@ impl ProjectPanel { .flex_col() .overflow_y_scroll() .child( - List::new(static_project_panel_single_items()) + List::new() .header(ListHeader::new("FILES")) - .empty_message("No files in directory"), + .empty_message("No files in directory") + .children(static_project_panel_single_items()), ) .child( - List::new(static_project_panel_project_items()) + List::new() .header(ListHeader::new("PROJECT")) - .empty_message("No folders in directory"), + .empty_message("No folders in directory") + .children(static_project_panel_project_items()), ), ) .child( diff --git a/crates/workspace2/src/dock.rs b/crates/workspace2/src/dock.rs index 9d81267603..d41f2b0078 100644 --- a/crates/workspace2/src/dock.rs +++ b/crates/workspace2/src/dock.rs @@ -719,10 +719,10 @@ impl Render for PanelButtons { { let panel = panel.clone(); menu = menu.entry( - ListEntry::new(Label::new(format!( - "Dock {}", - position.to_label() - ))), + ListEntry::new( + SharedString::from(format!("dock-{position:?}")), + Label::new(format!("Dock {}", position.to_label())), + ), move |_, cx| { panel.set_position(position, cx); },