diff --git a/assets/themes/cave-dark.json b/assets/themes/cave-dark.json index f0cb374632..fb5b6314b1 100644 --- a/assets/themes/cave-dark.json +++ b/assets/themes/cave-dark.json @@ -161,54 +161,10 @@ }, "cursor": "Arrow" }, - "left_sidebar": { - "width": 30, - "background": "#26232a", - "border": { - "color": "#19171c", - "width": 1, - "right": true - }, - "item": { - "height": 32, - "icon_color": "#8b8792", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#efecf4", - "icon_size": 18 - }, - "resize_handle": { - "background": "#19171c", - "padding": { - "left": 1 - } - } - }, - "right_sidebar": { - "width": 30, - "background": "#26232a", - "border": { - "color": "#19171c", - "width": 1, - "left": true - }, - "item": { - "height": 32, - "icon_color": "#8b8792", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#efecf4", - "icon_size": 18 - }, - "resize_handle": { - "background": "#19171c", - "padding": { - "left": 1 - } + "sidebar_resize_handle": { + "background": "#19171c", + "padding": { + "left": 1 } }, "pane_divider": { @@ -252,6 +208,21 @@ "family": "Zed Sans", "color": "#8b8792", "size": 14 + }, + "sidebar_item": { + "height": 32, + "icon_color": "#8b8792", + "icon_size": 18 + }, + "sidebar_item_hover": { + "height": 32, + "icon_color": "#8b8792", + "icon_size": 18 + }, + "sidebar_item_active": { + "height": 32, + "icon_color": "#efecf4", + "icon_size": 18 } }, "titlebar": { diff --git a/assets/themes/cave-light.json b/assets/themes/cave-light.json index aa062d4786..3242164847 100644 --- a/assets/themes/cave-light.json +++ b/assets/themes/cave-light.json @@ -161,54 +161,10 @@ }, "cursor": "Arrow" }, - "left_sidebar": { - "width": 30, - "background": "#e2dfe7", - "border": { - "color": "#efecf4", - "width": 1, - "right": true - }, - "item": { - "height": 32, - "icon_color": "#585260", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#19171c", - "icon_size": 18 - }, - "resize_handle": { - "background": "#efecf4", - "padding": { - "left": 1 - } - } - }, - "right_sidebar": { - "width": 30, - "background": "#e2dfe7", - "border": { - "color": "#efecf4", - "width": 1, - "left": true - }, - "item": { - "height": 32, - "icon_color": "#585260", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#19171c", - "icon_size": 18 - }, - "resize_handle": { - "background": "#efecf4", - "padding": { - "left": 1 - } + "sidebar_resize_handle": { + "background": "#efecf4", + "padding": { + "left": 1 } }, "pane_divider": { @@ -252,6 +208,21 @@ "family": "Zed Sans", "color": "#585260", "size": 14 + }, + "sidebar_item": { + "height": 32, + "icon_color": "#585260", + "icon_size": 18 + }, + "sidebar_item_hover": { + "height": 32, + "icon_color": "#585260", + "icon_size": 18 + }, + "sidebar_item_active": { + "height": 32, + "icon_color": "#19171c", + "icon_size": 18 } }, "titlebar": { diff --git a/assets/themes/dark.json b/assets/themes/dark.json index 2a371680f5..49f78bee1b 100644 --- a/assets/themes/dark.json +++ b/assets/themes/dark.json @@ -161,54 +161,10 @@ }, "cursor": "Arrow" }, - "left_sidebar": { - "width": 30, - "background": "#1c1c1c", - "border": { - "color": "#070707", - "width": 1, - "right": true - }, - "item": { - "height": 32, - "icon_color": "#9c9c9c", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#ffffff", - "icon_size": 18 - }, - "resize_handle": { - "background": "#070707", - "padding": { - "left": 1 - } - } - }, - "right_sidebar": { - "width": 30, - "background": "#1c1c1c", - "border": { - "color": "#070707", - "width": 1, - "left": true - }, - "item": { - "height": 32, - "icon_color": "#9c9c9c", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#ffffff", - "icon_size": 18 - }, - "resize_handle": { - "background": "#070707", - "padding": { - "left": 1 - } + "sidebar_resize_handle": { + "background": "#070707", + "padding": { + "left": 1 } }, "pane_divider": { @@ -252,6 +208,21 @@ "family": "Zed Sans", "color": "#808080", "size": 14 + }, + "sidebar_item": { + "height": 32, + "icon_color": "#9c9c9c", + "icon_size": 18 + }, + "sidebar_item_hover": { + "height": 32, + "icon_color": "#9c9c9c", + "icon_size": 18 + }, + "sidebar_item_active": { + "height": 32, + "icon_color": "#ffffff", + "icon_size": 18 } }, "titlebar": { diff --git a/assets/themes/light.json b/assets/themes/light.json index 8d56526e20..88fe8f5a91 100644 --- a/assets/themes/light.json +++ b/assets/themes/light.json @@ -161,54 +161,10 @@ }, "cursor": "Arrow" }, - "left_sidebar": { - "width": 30, - "background": "#f8f8f8", - "border": { - "color": "#d5d5d5", - "width": 1, - "right": true - }, - "item": { - "height": 32, - "icon_color": "#717171", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#000000", - "icon_size": 18 - }, - "resize_handle": { - "background": "#d5d5d5", - "padding": { - "left": 1 - } - } - }, - "right_sidebar": { - "width": 30, - "background": "#f8f8f8", - "border": { - "color": "#d5d5d5", - "width": 1, - "left": true - }, - "item": { - "height": 32, - "icon_color": "#717171", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#000000", - "icon_size": 18 - }, - "resize_handle": { - "background": "#d5d5d5", - "padding": { - "left": 1 - } + "sidebar_resize_handle": { + "background": "#d5d5d5", + "padding": { + "left": 1 } }, "pane_divider": { @@ -252,6 +208,21 @@ "family": "Zed Sans", "color": "#636363", "size": 14 + }, + "sidebar_item": { + "height": 32, + "icon_color": "#717171", + "icon_size": 18 + }, + "sidebar_item_hover": { + "height": 32, + "icon_color": "#717171", + "icon_size": 18 + }, + "sidebar_item_active": { + "height": 32, + "icon_color": "#000000", + "icon_size": 18 } }, "titlebar": { diff --git a/assets/themes/solarized-dark.json b/assets/themes/solarized-dark.json index bd73ab934e..7d53cce491 100644 --- a/assets/themes/solarized-dark.json +++ b/assets/themes/solarized-dark.json @@ -161,54 +161,10 @@ }, "cursor": "Arrow" }, - "left_sidebar": { - "width": 30, - "background": "#073642", - "border": { - "color": "#002b36", - "width": 1, - "right": true - }, - "item": { - "height": 32, - "icon_color": "#93a1a1", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#fdf6e3", - "icon_size": 18 - }, - "resize_handle": { - "background": "#002b36", - "padding": { - "left": 1 - } - } - }, - "right_sidebar": { - "width": 30, - "background": "#073642", - "border": { - "color": "#002b36", - "width": 1, - "left": true - }, - "item": { - "height": 32, - "icon_color": "#93a1a1", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#fdf6e3", - "icon_size": 18 - }, - "resize_handle": { - "background": "#002b36", - "padding": { - "left": 1 - } + "sidebar_resize_handle": { + "background": "#002b36", + "padding": { + "left": 1 } }, "pane_divider": { @@ -252,6 +208,21 @@ "family": "Zed Sans", "color": "#93a1a1", "size": 14 + }, + "sidebar_item": { + "height": 32, + "icon_color": "#93a1a1", + "icon_size": 18 + }, + "sidebar_item_hover": { + "height": 32, + "icon_color": "#93a1a1", + "icon_size": 18 + }, + "sidebar_item_active": { + "height": 32, + "icon_color": "#fdf6e3", + "icon_size": 18 } }, "titlebar": { diff --git a/assets/themes/solarized-light.json b/assets/themes/solarized-light.json index 35de751a2b..167bf305cb 100644 --- a/assets/themes/solarized-light.json +++ b/assets/themes/solarized-light.json @@ -161,54 +161,10 @@ }, "cursor": "Arrow" }, - "left_sidebar": { - "width": 30, - "background": "#eee8d5", - "border": { - "color": "#fdf6e3", - "width": 1, - "right": true - }, - "item": { - "height": 32, - "icon_color": "#586e75", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#002b36", - "icon_size": 18 - }, - "resize_handle": { - "background": "#fdf6e3", - "padding": { - "left": 1 - } - } - }, - "right_sidebar": { - "width": 30, - "background": "#eee8d5", - "border": { - "color": "#fdf6e3", - "width": 1, - "left": true - }, - "item": { - "height": 32, - "icon_color": "#586e75", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#002b36", - "icon_size": 18 - }, - "resize_handle": { - "background": "#fdf6e3", - "padding": { - "left": 1 - } + "sidebar_resize_handle": { + "background": "#fdf6e3", + "padding": { + "left": 1 } }, "pane_divider": { @@ -252,6 +208,21 @@ "family": "Zed Sans", "color": "#586e75", "size": 14 + }, + "sidebar_item": { + "height": 32, + "icon_color": "#586e75", + "icon_size": 18 + }, + "sidebar_item_hover": { + "height": 32, + "icon_color": "#586e75", + "icon_size": 18 + }, + "sidebar_item_active": { + "height": 32, + "icon_color": "#002b36", + "icon_size": 18 } }, "titlebar": { diff --git a/assets/themes/sulphurpool-dark.json b/assets/themes/sulphurpool-dark.json index 20123449bb..db76b4502a 100644 --- a/assets/themes/sulphurpool-dark.json +++ b/assets/themes/sulphurpool-dark.json @@ -161,54 +161,10 @@ }, "cursor": "Arrow" }, - "left_sidebar": { - "width": 30, - "background": "#293256", - "border": { - "color": "#202746", - "width": 1, - "right": true - }, - "item": { - "height": 32, - "icon_color": "#979db4", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#f5f7ff", - "icon_size": 18 - }, - "resize_handle": { - "background": "#202746", - "padding": { - "left": 1 - } - } - }, - "right_sidebar": { - "width": 30, - "background": "#293256", - "border": { - "color": "#202746", - "width": 1, - "left": true - }, - "item": { - "height": 32, - "icon_color": "#979db4", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#f5f7ff", - "icon_size": 18 - }, - "resize_handle": { - "background": "#202746", - "padding": { - "left": 1 - } + "sidebar_resize_handle": { + "background": "#202746", + "padding": { + "left": 1 } }, "pane_divider": { @@ -252,6 +208,21 @@ "family": "Zed Sans", "color": "#979db4", "size": 14 + }, + "sidebar_item": { + "height": 32, + "icon_color": "#979db4", + "icon_size": 18 + }, + "sidebar_item_hover": { + "height": 32, + "icon_color": "#979db4", + "icon_size": 18 + }, + "sidebar_item_active": { + "height": 32, + "icon_color": "#f5f7ff", + "icon_size": 18 } }, "titlebar": { diff --git a/assets/themes/sulphurpool-light.json b/assets/themes/sulphurpool-light.json index 9bebd82036..9957f42a6b 100644 --- a/assets/themes/sulphurpool-light.json +++ b/assets/themes/sulphurpool-light.json @@ -161,54 +161,10 @@ }, "cursor": "Arrow" }, - "left_sidebar": { - "width": 30, - "background": "#dfe2f1", - "border": { - "color": "#f5f7ff", - "width": 1, - "right": true - }, - "item": { - "height": 32, - "icon_color": "#5e6687", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#202746", - "icon_size": 18 - }, - "resize_handle": { - "background": "#f5f7ff", - "padding": { - "left": 1 - } - } - }, - "right_sidebar": { - "width": 30, - "background": "#dfe2f1", - "border": { - "color": "#f5f7ff", - "width": 1, - "left": true - }, - "item": { - "height": 32, - "icon_color": "#5e6687", - "icon_size": 18 - }, - "active_item": { - "height": 32, - "icon_color": "#202746", - "icon_size": 18 - }, - "resize_handle": { - "background": "#f5f7ff", - "padding": { - "left": 1 - } + "sidebar_resize_handle": { + "background": "#f5f7ff", + "padding": { + "left": 1 } }, "pane_divider": { @@ -252,6 +208,21 @@ "family": "Zed Sans", "color": "#5e6687", "size": 14 + }, + "sidebar_item": { + "height": 32, + "icon_color": "#5e6687", + "icon_size": 18 + }, + "sidebar_item_hover": { + "height": 32, + "icon_color": "#5e6687", + "icon_size": 18 + }, + "sidebar_item_active": { + "height": 32, + "icon_color": "#202746", + "icon_size": 18 } }, "titlebar": { diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index b4533298ac..e8bf1a1553 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -38,8 +38,7 @@ pub struct Workspace { pub pane_divider: Border, pub leader_border_opacity: f32, pub leader_border_width: f32, - pub left_sidebar: Sidebar, - pub right_sidebar: Sidebar, + pub sidebar_resize_handle: ContainerStyle, pub status_bar: StatusBar, pub toolbar: Toolbar, pub disconnected_overlay: ContainedText, @@ -139,16 +138,13 @@ pub struct FindEditor { #[derive(Deserialize, Default)] pub struct Sidebar { - #[serde(flatten)] - pub container: ContainerStyle, - pub width: f32, - pub item: SidebarItem, - pub active_item: SidebarItem, pub resize_handle: ContainerStyle, } -#[derive(Deserialize, Default)] +#[derive(Clone, Copy, Deserialize, Default)] pub struct SidebarItem { + #[serde(flatten)] + pub container: ContainerStyle, pub icon_color: Color, pub icon_size: f32, pub height: f32, @@ -165,6 +161,9 @@ pub struct StatusBar { pub lsp_message: TextStyle, pub auto_update_progress_message: TextStyle, pub auto_update_done_message: TextStyle, + pub sidebar_item: SidebarItem, + pub sidebar_item_active: SidebarItem, + pub sidebar_item_hover: SidebarItem, } #[derive(Deserialize, Default)] diff --git a/crates/workspace/src/sidebar.rs b/crates/workspace/src/sidebar.rs index 46ec3089e7..58d4bc6afc 100644 --- a/crates/workspace/src/sidebar.rs +++ b/crates/workspace/src/sidebar.rs @@ -1,9 +1,14 @@ -use super::Workspace; -use gpui::{elements::*, impl_actions, platform::CursorStyle, AnyViewHandle, RenderContext}; +use gpui::{ + elements::*, impl_actions, platform::CursorStyle, AnyViewHandle, Entity, RenderContext, View, + ViewContext, ViewHandle, +}; use serde::Deserialize; +use settings::Settings; use std::{cell::RefCell, rc::Rc}; use theme::Theme; +use crate::StatusItemView; + pub struct Sidebar { side: Side, items: Vec, @@ -12,31 +17,36 @@ pub struct Sidebar { custom_width: Rc>, } -#[derive(Clone, Copy, Deserialize)] +#[derive(Clone, Copy, Debug, Deserialize)] pub enum Side { Left, Right, } +#[derive(Clone)] struct Item { icon_path: &'static str, view: AnyViewHandle, } -#[derive(Clone, Deserialize)] -pub struct ToggleSidebarItem(pub SidebarItemId); +pub struct SidebarButtons { + sidebar: ViewHandle, +} -#[derive(Clone, Deserialize)] -pub struct ToggleSidebarItemFocus(pub SidebarItemId); - -impl_actions!(workspace, [ToggleSidebarItem, ToggleSidebarItemFocus]); - -#[derive(Clone, Deserialize)] -pub struct SidebarItemId { +#[derive(Clone, Debug, Deserialize)] +pub struct ToggleSidebarItem { pub side: Side, pub item_index: usize, } +#[derive(Clone, Debug, Deserialize)] +pub struct ToggleSidebarItemFocus { + pub side: Side, + pub item_index: usize, +} + +impl_actions!(workspace, [ToggleSidebarItem, ToggleSidebarItemFocus]); + impl Sidebar { pub fn new(side: Side) -> Self { Self { @@ -48,20 +58,28 @@ impl Sidebar { } } - pub fn add_item(&mut self, icon_path: &'static str, view: AnyViewHandle) { + pub fn add_item( + &mut self, + icon_path: &'static str, + view: AnyViewHandle, + cx: &mut ViewContext, + ) { self.items.push(Item { icon_path, view }); + cx.notify() } - pub fn activate_item(&mut self, item_ix: usize) { + pub fn activate_item(&mut self, item_ix: usize, cx: &mut ViewContext) { self.active_item_ix = Some(item_ix); + cx.notify(); } - pub fn toggle_item(&mut self, item_ix: usize) { + pub fn toggle_item(&mut self, item_ix: usize, cx: &mut ViewContext) { if self.active_item_ix == Some(item_ix) { self.active_item_ix = None; } else { self.active_item_ix = Some(item_ix); } + cx.notify(); } pub fn active_item(&self) -> Option<&AnyViewHandle> { @@ -70,101 +88,14 @@ impl Sidebar { .map(|item| &item.view) } - fn theme<'a>(&self, theme: &'a Theme) -> &'a theme::Sidebar { - match self.side { - Side::Left => &theme.workspace.left_sidebar, - Side::Right => &theme.workspace.right_sidebar, - } - } - - pub fn render(&self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { - let side = self.side; - let theme = self.theme(theme); - - ConstrainedBox::new( - Container::new( - Flex::column() - .with_children(self.items.iter().enumerate().map(|(item_index, item)| { - let theme = if Some(item_index) == self.active_item_ix { - &theme.active_item - } else { - &theme.item - }; - enum SidebarButton {} - MouseEventHandler::new::(item.view.id(), cx, |_, _| { - ConstrainedBox::new( - Align::new( - ConstrainedBox::new( - Svg::new(item.icon_path) - .with_color(theme.icon_color) - .boxed(), - ) - .with_height(theme.icon_size) - .boxed(), - ) - .boxed(), - ) - .with_height(theme.height) - .boxed() - }) - .with_cursor_style(CursorStyle::PointingHand) - .on_mouse_down(move |cx| { - cx.dispatch_action(ToggleSidebarItem(SidebarItemId { - side, - item_index, - })) - }) - .boxed() - })) - .boxed(), - ) - .with_style(theme.container) - .boxed(), - ) - .with_width(theme.width) - .boxed() - } - - pub fn render_active_item( - &self, - theme: &Theme, - cx: &mut RenderContext, - ) -> Option { - if let Some(active_item) = self.active_item() { - let mut container = Flex::row(); - if matches!(self.side, Side::Right) { - container.add_child(self.render_resize_handle(theme, cx)); - } - - container.add_child( - Hook::new( - ConstrainedBox::new(ChildView::new(active_item).boxed()) - .with_max_width(*self.custom_width.borrow()) - .boxed(), - ) - .on_after_layout({ - let actual_width = self.actual_width.clone(); - move |size, _| *actual_width.borrow_mut() = size.x() - }) - .flex(1., false) - .boxed(), - ); - if matches!(self.side, Side::Left) { - container.add_child(self.render_resize_handle(theme, cx)); - } - Some(container.boxed()) - } else { - None - } - } - - fn render_resize_handle(&self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { + fn render_resize_handle(&self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { let actual_width = self.actual_width.clone(); let custom_width = self.custom_width.clone(); let side = self.side; MouseEventHandler::new::(side as usize, cx, |_, _| { - Container::new(Empty::new().boxed()) - .with_style(self.theme(theme).resize_handle) + Empty::new() + .contained() + .with_style(theme.workspace.sidebar_resize_handle) .boxed() }) .with_padding(Padding { @@ -185,3 +116,109 @@ impl Sidebar { .boxed() } } + +impl Entity for Sidebar { + type Event = (); +} + +impl View for Sidebar { + fn ui_name() -> &'static str { + "Sidebar" + } + + fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + let theme = cx.global::().theme.clone(); + if let Some(active_item) = self.active_item() { + let mut container = Flex::row(); + if matches!(self.side, Side::Right) { + container.add_child(self.render_resize_handle(&theme, cx)); + } + + container.add_child( + Hook::new( + ChildView::new(active_item) + .constrained() + .with_max_width(*self.custom_width.borrow()) + .boxed(), + ) + .on_after_layout({ + let actual_width = self.actual_width.clone(); + move |size, _| *actual_width.borrow_mut() = size.x() + }) + .flex(1., false) + .boxed(), + ); + if matches!(self.side, Side::Left) { + container.add_child(self.render_resize_handle(&theme, cx)); + } + container.boxed() + } else { + Empty::new().boxed() + } + } +} + +impl SidebarButtons { + pub fn new(sidebar: ViewHandle, cx: &mut ViewContext) -> Self { + cx.observe(&sidebar, |_, _, cx| cx.notify()).detach(); + Self { sidebar } + } +} + +impl Entity for SidebarButtons { + type Event = (); +} + +impl View for SidebarButtons { + fn ui_name() -> &'static str { + "SidebarToggleButton" + } + + fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + let theme = &cx.global::().theme.workspace.status_bar; + let style = theme.sidebar_item; + let hover_style = theme.sidebar_item_hover; + let active_style = theme.sidebar_item_active; + let sidebar = self.sidebar.read(cx); + let active_ix = sidebar.active_item_ix; + let side = sidebar.side; + let items = sidebar.items.clone(); + Flex::row() + .with_children(items.iter().enumerate().map(|(ix, item)| { + MouseEventHandler::new::(ix, cx, move |state, _| { + let style = if Some(ix) == active_ix { + active_style + } else if state.hovered { + hover_style + } else { + style + }; + Svg::new(item.icon_path) + .with_color(style.icon_color) + .constrained() + .with_height(style.icon_size) + .contained() + .with_style(style.container) + .boxed() + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(move |cx| { + cx.dispatch_action(ToggleSidebarItem { + side, + item_index: ix, + }) + }) + .boxed() + })) + .boxed() + } +} + +impl StatusItemView for SidebarButtons { + fn set_active_pane_item( + &mut self, + _: Option<&dyn crate::ItemHandle>, + _: &mut ViewContext, + ) { + } +} diff --git a/crates/workspace/src/status_bar.rs b/crates/workspace/src/status_bar.rs index c9a2c819e2..f84940e8fb 100644 --- a/crates/workspace/src/status_bar.rs +++ b/crates/workspace/src/status_bar.rs @@ -1,9 +1,9 @@ use crate::{ItemHandle, Pane}; -use settings::Settings; use gpui::{ elements::*, AnyViewHandle, ElementBox, Entity, MutableAppContext, RenderContext, Subscription, View, ViewContext, ViewHandle, }; +use settings::Settings; pub trait StatusItemView: View { fn set_active_pane_item( @@ -48,7 +48,7 @@ impl View for StatusBar { .with_margin_right(theme.item_spacing) .boxed() })) - .with_children(self.right_items.iter().map(|i| { + .with_children(self.right_items.iter().rev().map(|i| { ChildView::new(i.as_ref()) .aligned() .contained() diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 88007081e1..4e7f64201b 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -31,7 +31,7 @@ pub use pane_group::*; use postage::prelude::Stream; use project::{fs, Fs, Project, ProjectEntryId, ProjectPath, Worktree}; use settings::Settings; -use sidebar::{Side, Sidebar, SidebarItemId, ToggleSidebarItem, ToggleSidebarItemFocus}; +use sidebar::{Side, Sidebar, SidebarButtons, ToggleSidebarItem, ToggleSidebarItemFocus}; use status_bar::StatusBar; pub use status_bar::StatusItemView; use std::{ @@ -678,8 +678,8 @@ pub struct Workspace { themes: Arc, modal: Option, center: PaneGroup, - left_sidebar: Sidebar, - right_sidebar: Sidebar, + left_sidebar: ViewHandle, + right_sidebar: ViewHandle, panes: Vec>, active_pane: ViewHandle, status_bar: ViewHandle, @@ -751,7 +751,6 @@ impl Workspace { cx.focus(&pane); cx.emit(Event::PaneAdded(pane.clone())); - let status_bar = cx.add_view(|cx| StatusBar::new(&pane, cx)); let mut current_user = params.user_store.read(cx).watch_current_user().clone(); let mut connection_status = params.client.status().clone(); let _observe_current_user = cx.spawn_weak(|this, mut cx| async move { @@ -773,6 +772,18 @@ impl Workspace { cx.emit_global(WorkspaceCreated(weak_self.clone())); + let left_sidebar = cx.add_view(|_| Sidebar::new(Side::Left)); + let right_sidebar = cx.add_view(|_| Sidebar::new(Side::Right)); + let left_sidebar_buttons = cx.add_view(|cx| SidebarButtons::new(left_sidebar.clone(), cx)); + let right_sidebar_buttons = + cx.add_view(|cx| SidebarButtons::new(right_sidebar.clone(), cx)); + let status_bar = cx.add_view(|cx| { + let mut status_bar = StatusBar::new(&pane.clone(), cx); + status_bar.add_left_item(left_sidebar_buttons, cx); + status_bar.add_right_item(right_sidebar_buttons, cx); + status_bar + }); + let mut this = Workspace { modal: None, weak_self, @@ -785,8 +796,8 @@ impl Workspace { user_store: params.user_store.clone(), fs: params.fs.clone(), themes: params.themes.clone(), - left_sidebar: Sidebar::new(Side::Left), - right_sidebar: Sidebar::new(Side::Right), + left_sidebar, + right_sidebar, project: params.project.clone(), leader_state: Default::default(), follower_states_by_leader: Default::default(), @@ -801,12 +812,12 @@ impl Workspace { self.weak_self.clone() } - pub fn left_sidebar_mut(&mut self) -> &mut Sidebar { - &mut self.left_sidebar + pub fn left_sidebar(&self) -> &ViewHandle { + &self.left_sidebar } - pub fn right_sidebar_mut(&mut self) -> &mut Sidebar { - &mut self.right_sidebar + pub fn right_sidebar(&self) -> &ViewHandle { + &self.right_sidebar } pub fn status_bar(&self) -> &ViewHandle { @@ -1028,12 +1039,15 @@ impl Workspace { } pub fn toggle_sidebar_item(&mut self, action: &ToggleSidebarItem, cx: &mut ViewContext) { - let sidebar = match action.0.side { + let sidebar = match action.side { Side::Left => &mut self.left_sidebar, Side::Right => &mut self.right_sidebar, }; - sidebar.toggle_item(action.0.item_index); - if let Some(active_item) = sidebar.active_item() { + let active_item = sidebar.update(cx, |sidebar, cx| { + sidebar.toggle_item(action.item_index, cx); + sidebar.active_item().cloned() + }); + if let Some(active_item) = active_item { cx.focus(active_item); } else { cx.focus_self(); @@ -1046,12 +1060,15 @@ impl Workspace { action: &ToggleSidebarItemFocus, cx: &mut ViewContext, ) { - let sidebar = match action.0.side { + let sidebar = match action.side { Side::Left => &mut self.left_sidebar, Side::Right => &mut self.right_sidebar, }; - sidebar.activate_item(action.0.item_index); - if let Some(active_item) = sidebar.active_item() { + let active_item = sidebar.update(cx, |sidebar, cx| { + sidebar.toggle_item(action.item_index, cx); + sidebar.active_item().cloned() + }); + if let Some(active_item) = active_item { if active_item.is_focused(cx) { cx.focus_self(); } else { @@ -1610,7 +1627,7 @@ impl Workspace { .boxed(), ) .constrained() - .with_width(theme.workspace.right_sidebar.width) + .with_width(theme.workspace.titlebar.avatar_width) .contained() .with_margin_left(2.) .boxed(); @@ -1656,7 +1673,7 @@ impl Workspace { .with_width(24.) .aligned() .constrained() - .with_width(theme.workspace.right_sidebar.width) + .with_width(24.) .aligned() .boxed() }) @@ -1983,37 +2000,39 @@ impl View for Workspace { .with_child( Stack::new() .with_child({ - let mut content = Flex::row(); - content.add_child(self.left_sidebar.render(&theme, cx)); - if let Some(element) = - self.left_sidebar.render_active_item(&theme, cx) - { - content - .add_child(FlexItem::new(element).flex(0.8, false).boxed()); - } - content.add_child( - Flex::column() - .with_child( - FlexItem::new(self.center.render( - &theme, - &self.follower_states_by_leader, - self.project.read(cx).collaborators(), - )) - .flex(1., true) - .boxed(), - ) - .with_child(ChildView::new(&self.status_bar).boxed()) + Flex::row() + .with_children( + if self.left_sidebar.read(cx).active_item().is_some() { + Some( + ChildView::new(&self.left_sidebar) + .flex(0.8, false) + .boxed(), + ) + } else { + None + }, + ) + .with_child( + FlexItem::new(self.center.render( + &theme, + &self.follower_states_by_leader, + self.project.read(cx).collaborators(), + )) .flex(1., true) .boxed(), - ); - if let Some(element) = - self.right_sidebar.render_active_item(&theme, cx) - { - content - .add_child(FlexItem::new(element).flex(0.8, false).boxed()); - } - content.add_child(self.right_sidebar.render(&theme, cx)); - content.boxed() + ) + .with_children( + if self.right_sidebar.read(cx).active_item().is_some() { + Some( + ChildView::new(&self.right_sidebar) + .flex(0.8, false) + .boxed(), + ) + } else { + None + }, + ) + .boxed() }) .with_children(self.modal.as_ref().map(|m| { ChildView::new(m) @@ -2026,6 +2045,7 @@ impl View for Workspace { .flex(1.0, true) .boxed(), ) + .with_child(ChildView::new(&self.status_bar).boxed()) .contained() .with_background_color(theme.workspace.background) .boxed(), @@ -2202,10 +2222,10 @@ pub fn open_paths( let mut workspace = (app_state.build_workspace)(project, &app_state, cx); if contains_directory { workspace.toggle_sidebar_item( - &ToggleSidebarItem(SidebarItemId { + &ToggleSidebarItem { side: Side::Left, item_index: 0, - }), + }, cx, ); } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 71ce6f065a..b4ff271f15 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -6,7 +6,6 @@ pub mod test; use anyhow::{anyhow, Context, Result}; use breadcrumbs::Breadcrumbs; -use chat_panel::ChatPanel; pub use client; pub use contacts_panel; use contacts_panel::ContactsPanel; @@ -147,7 +146,7 @@ pub fn build_workspace( user_store: app_state.user_store.clone(), channel_list: app_state.channel_list.clone(), }; - let mut workspace = Workspace::new(&workspace_params, cx); + let workspace = Workspace::new(&workspace_params, cx); let project = workspace.project().clone(); let theme_names = app_state.themes.list().collect(); @@ -171,22 +170,15 @@ pub fn build_workspace( })); }); - workspace.left_sidebar_mut().add_item( - "icons/folder-tree-16.svg", - ProjectPanel::new(project, cx).into(), - ); - workspace.right_sidebar_mut().add_item( - "icons/user-16.svg", - cx.add_view(|cx| ContactsPanel::new(app_state.clone(), cx)) - .into(), - ); - workspace.right_sidebar_mut().add_item( - "icons/comment-16.svg", - cx.add_view(|cx| { - ChatPanel::new(app_state.client.clone(), app_state.channel_list.clone(), cx) - }) - .into(), - ); + let project_panel = ProjectPanel::new(project, cx); + let contact_panel = cx.add_view(|cx| ContactsPanel::new(app_state.clone(), cx)); + + workspace.left_sidebar().update(cx, |sidebar, cx| { + sidebar.add_item("icons/folder-tree-16.svg", project_panel.into(), cx) + }); + workspace.right_sidebar().update(cx, |sidebar, cx| { + sidebar.add_item("icons/user-16.svg", contact_panel.into(), cx) + }); let diagnostic_message = cx.add_view(|_| editor::items::DiagnosticMessage::new()); let diagnostic_summary = @@ -200,8 +192,8 @@ pub fn build_workspace( status_bar.add_left_item(diagnostic_summary, cx); status_bar.add_left_item(diagnostic_message, cx); status_bar.add_left_item(lsp_status, cx); - status_bar.add_right_item(auto_update, cx); status_bar.add_right_item(cursor_position, cx); + status_bar.add_right_item(auto_update, cx); }); workspace @@ -362,7 +354,7 @@ mod tests { let workspace_1 = cx.root_view::(cx.window_ids()[0]).unwrap(); workspace_1.update(cx, |workspace, cx| { assert_eq!(workspace.worktrees(cx).count(), 2); - assert!(workspace.left_sidebar_mut().active_item().is_some()); + assert!(workspace.left_sidebar().read(cx).active_item().is_some()); assert!(workspace.active_pane().is_focused(cx)); }); diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index 609639c467..a960f9508d 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -52,22 +52,6 @@ export default function workspace(theme: Theme) { iconColor: iconColor(theme, "secondary"), iconSize: 18, }; - const sidebar = { - width: 30, - background: backgroundColor(theme, 300), - border: border(theme, "primary", { right: true }), - item: sidebarItem, - activeItem: { - ...sidebarItem, - iconColor: iconColor(theme, "active"), - }, - resizeHandle: { - background: border(theme, "primary").color, - padding: { - left: 1, - }, - }, - }; const shareIcon = { margin: { top: 3, bottom: 2 }, cornerRadius: 6, @@ -86,19 +70,17 @@ export default function workspace(theme: Theme) { }, cursor: "Arrow" }, - leftSidebar: { - ...sidebar, - border: border(theme, "primary", { right: true }), - }, - rightSidebar: { - ...sidebar, - border: border(theme, "primary", { left: true }), + sidebarResizeHandle: { + background: border(theme, "primary").color, + padding: { + left: 1, + }, }, paneDivider: { color: border(theme, "secondary").color, width: 1, }, - status_bar: { + statusBar: { height: 24, itemSpacing: 8, padding: { @@ -111,6 +93,16 @@ export default function workspace(theme: Theme) { lspMessage: text(theme, "sans", "muted"), autoUpdateProgressMessage: text(theme, "sans", "muted"), autoUpdateDoneMessage: text(theme, "sans", "muted"), + sidebarItem: { + ...sidebarItem + }, + sidebarItemHover: { + ...sidebarItem + }, + sidebarItemActive: { + ...sidebarItem, + iconColor: iconColor(theme, "active"), + }, }, titlebar: { avatarWidth: 18,