Add disclosure arrows to the project panel

Max Brunsfeld and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

zed/assets/icons/disclosure-closed.svg |  3 ++
zed/assets/icons/disclosure-open.svg   |  3 ++
zed/assets/themes/_base.toml           |  5 ++
zed/src/project_panel.rs               | 38 ++++++++++++++++++++++++++-
zed/src/theme.rs                       | 16 +++++++++--
5 files changed, 59 insertions(+), 6 deletions(-)

Detailed changes

zed/assets/icons/disclosure-closed.svg 🔗

@@ -0,0 +1,3 @@
+<svg width="4" height="8" viewBox="0 0 4 8" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M0.923915 0.64914L3.7699 3.67213C3.85691 3.76411 3.9004 3.88214 3.9004 4.00028C3.9004 4.11835 3.85689 4.23635 3.7699 4.32843L0.923915 7.35142C0.742536 7.54234 0.440436 7.5503 0.249113 7.36932C0.0564376 7.18784 0.0496359 6.88444 0.230468 6.69431L2.7841 3.99948L0.230468 1.30465C0.0496359 1.11452 0.0563979 0.813217 0.249113 0.630446C0.440436 0.449663 0.742536 0.457618 0.923915 0.64914Z" fill="#66686A"/>
+</svg>

zed/assets/icons/disclosure-open.svg 🔗

@@ -0,0 +1,3 @@
+<svg width="8" height="4" viewBox="0 0 8 4" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.35131 0.916948L4.32837 3.76288C4.23689 3.8663 4.11756 3.91005 4.00022 3.91005C3.88289 3.91005 3.76396 3.86654 3.67208 3.77955L0.649138 0.916948C0.457619 0.733981 0.449664 0.431687 0.630444 0.240765C0.812019 0.0478537 1.11531 0.0418875 1.30543 0.222866L4.00022 2.77446L6.69501 0.220877C6.88518 0.0400179 7.18723 0.0468593 7.37 0.239522C7.55019 0.431687 7.54223 0.733981 7.35131 0.916948Z" fill="#66686A"/>
+</svg>

zed/assets/themes/_base.toml 🔗

@@ -165,8 +165,11 @@ padding = 0
 entry_base_padding = "$panel.padding"
 
 [project_panel.entry]
-extends = "$text.0"
+text = "$text.1"
 padding = { top = 3, bottom = 3 }
+icon_color = "$text.3.color"
+icon_size = 8
+icon_spacing = 8
 
 [project_panel.hovered_entry]
 extends = "$project_panel.entry"

zed/src/project_panel.rs 🔗

@@ -7,7 +7,10 @@ use crate::{
 };
 use gpui::{
     action,
-    elements::{Label, MouseEventHandler, UniformList, UniformListState},
+    elements::{
+        Align, ConstrainedBox, Empty, Flex, Label, MouseEventHandler, ParentElement, Svg,
+        UniformList, UniformListState,
+    },
     keymap::{
         self,
         menu::{SelectNext, SelectPrev},
@@ -474,7 +477,38 @@ impl ProjectPanel {
                 } else {
                     &theme.entry
                 };
-                Label::new(details.filename, style.text.clone())
+                Flex::row()
+                    .with_child(
+                        ConstrainedBox::new(
+                            Align::new(
+                                ConstrainedBox::new(if is_dir {
+                                    if details.is_expanded {
+                                        Svg::new("icons/disclosure-open.svg")
+                                            .with_color(style.icon_color)
+                                            .boxed()
+                                    } else {
+                                        Svg::new("icons/disclosure-closed.svg")
+                                            .with_color(style.icon_color)
+                                            .boxed()
+                                    }
+                                } else {
+                                    Empty::new().boxed()
+                                })
+                                .with_max_width(style.icon_size)
+                                .with_max_height(style.icon_size)
+                                .boxed(),
+                            )
+                            .boxed(),
+                        )
+                        .with_width(style.icon_size)
+                        .boxed(),
+                    )
+                    .with_child(
+                        Label::new(details.filename, style.text.clone())
+                            .contained()
+                            .with_margin_left(style.icon_spacing)
+                            .boxed(),
+                    )
                     .contained()
                     .with_style(style.container)
                     .with_padding_left(theme.entry_base_padding + details.depth as f32 * 20.)

zed/src/theme.rs 🔗

@@ -112,9 +112,19 @@ pub struct ProjectPanel {
     #[serde(flatten)]
     pub container: ContainerStyle,
     pub entry_base_padding: f32,
-    pub entry: ContainedText,
-    pub hovered_entry: ContainedText,
-    pub selected_entry: ContainedText,
+    pub entry: ProjectPanelEntry,
+    pub hovered_entry: ProjectPanelEntry,
+    pub selected_entry: ProjectPanelEntry,
+}
+
+#[derive(Deserialize)]
+pub struct ProjectPanelEntry {
+    #[serde(flatten)]
+    pub container: ContainerStyle,
+    pub text: TextStyle,
+    pub icon_color: Color,
+    pub icon_size: f32,
+    pub icon_spacing: f32,
 }
 
 #[derive(Deserialize)]