Improve layout of contact panel rows

Max Brunsfeld and Nathan Sobo created

Co-authored-by: Nathan Sobo <nathan@zed.dev>

Change summary

assets/themes/cave-dark.json                | 19 ++++++++++++++-----
assets/themes/cave-light.json               | 19 ++++++++++++++-----
assets/themes/dark.json                     | 19 ++++++++++++++-----
assets/themes/light.json                    | 19 ++++++++++++++-----
assets/themes/solarized-dark.json           | 19 ++++++++++++++-----
assets/themes/solarized-light.json          | 19 ++++++++++++++-----
assets/themes/sulphurpool-dark.json         | 19 ++++++++++++++-----
assets/themes/sulphurpool-light.json        | 19 ++++++++++++++-----
crates/contacts_panel/src/contacts_panel.rs | 19 +++++++++++++++----
crates/theme/src/theme.rs                   |  2 ++
styles/src/styleTree/contactsPanel.ts       | 14 ++++++++------
11 files changed, 137 insertions(+), 50 deletions(-)

Detailed changes

assets/themes/cave-dark.json 🔗

@@ -1240,6 +1240,7 @@
         "top": 4
       }
     },
+    "user_query_editor_height": 32,
     "add_contact_button": {
       "margin": {
         "left": 6
@@ -1248,7 +1249,20 @@
       "button_width": 8,
       "icon_width": 8
     },
+    "row": {
+      "padding": {
+        "left": 8
+      }
+    },
     "row_height": 28,
+    "header": {
+      "family": "Zed Mono",
+      "color": "#8b8792",
+      "size": 14,
+      "margin": {
+        "top": 8
+      }
+    },
     "tree_branch_color": "#655f6d",
     "tree_branch_width": 1,
     "contact_avatar": {
@@ -1280,11 +1294,6 @@
       "button_width": 16,
       "corner_radius": 8
     },
-    "header": {
-      "family": "Zed Mono",
-      "color": "#8b8792",
-      "size": 14
-    },
     "project": {
       "guest_avatar_spacing": 4,
       "height": 24,

assets/themes/cave-light.json 🔗

@@ -1240,6 +1240,7 @@
         "top": 4
       }
     },
+    "user_query_editor_height": 32,
     "add_contact_button": {
       "margin": {
         "left": 6
@@ -1248,7 +1249,20 @@
       "button_width": 8,
       "icon_width": 8
     },
+    "row": {
+      "padding": {
+        "left": 8
+      }
+    },
     "row_height": 28,
+    "header": {
+      "family": "Zed Mono",
+      "color": "#585260",
+      "size": 14,
+      "margin": {
+        "top": 8
+      }
+    },
     "tree_branch_color": "#7e7887",
     "tree_branch_width": 1,
     "contact_avatar": {
@@ -1280,11 +1294,6 @@
       "button_width": 16,
       "corner_radius": 8
     },
-    "header": {
-      "family": "Zed Mono",
-      "color": "#585260",
-      "size": 14
-    },
     "project": {
       "guest_avatar_spacing": 4,
       "height": 24,

assets/themes/dark.json 🔗

@@ -1240,6 +1240,7 @@
         "top": 4
       }
     },
+    "user_query_editor_height": 32,
     "add_contact_button": {
       "margin": {
         "left": 6
@@ -1248,7 +1249,20 @@
       "button_width": 8,
       "icon_width": 8
     },
+    "row": {
+      "padding": {
+        "left": 8
+      }
+    },
     "row_height": 28,
+    "header": {
+      "family": "Zed Mono",
+      "color": "#9c9c9c",
+      "size": 14,
+      "margin": {
+        "top": 8
+      }
+    },
     "tree_branch_color": "#404040",
     "tree_branch_width": 1,
     "contact_avatar": {
@@ -1280,11 +1294,6 @@
       "button_width": 16,
       "corner_radius": 8
     },
-    "header": {
-      "family": "Zed Mono",
-      "color": "#9c9c9c",
-      "size": 14
-    },
     "project": {
       "guest_avatar_spacing": 4,
       "height": 24,

assets/themes/light.json 🔗

@@ -1240,6 +1240,7 @@
         "top": 4
       }
     },
+    "user_query_editor_height": 32,
     "add_contact_button": {
       "margin": {
         "left": 6
@@ -1248,7 +1249,20 @@
       "button_width": 8,
       "icon_width": 8
     },
+    "row": {
+      "padding": {
+        "left": 8
+      }
+    },
     "row_height": 28,
+    "header": {
+      "family": "Zed Mono",
+      "color": "#474747",
+      "size": 14,
+      "margin": {
+        "top": 8
+      }
+    },
     "tree_branch_color": "#e3e3e3",
     "tree_branch_width": 1,
     "contact_avatar": {
@@ -1280,11 +1294,6 @@
       "button_width": 16,
       "corner_radius": 8
     },
-    "header": {
-      "family": "Zed Mono",
-      "color": "#474747",
-      "size": 14
-    },
     "project": {
       "guest_avatar_spacing": 4,
       "height": 24,

assets/themes/solarized-dark.json 🔗

@@ -1240,6 +1240,7 @@
         "top": 4
       }
     },
+    "user_query_editor_height": 32,
     "add_contact_button": {
       "margin": {
         "left": 6
@@ -1248,7 +1249,20 @@
       "button_width": 8,
       "icon_width": 8
     },
+    "row": {
+      "padding": {
+        "left": 8
+      }
+    },
     "row_height": 28,
+    "header": {
+      "family": "Zed Mono",
+      "color": "#93a1a1",
+      "size": 14,
+      "margin": {
+        "top": 8
+      }
+    },
     "tree_branch_color": "#657b83",
     "tree_branch_width": 1,
     "contact_avatar": {
@@ -1280,11 +1294,6 @@
       "button_width": 16,
       "corner_radius": 8
     },
-    "header": {
-      "family": "Zed Mono",
-      "color": "#93a1a1",
-      "size": 14
-    },
     "project": {
       "guest_avatar_spacing": 4,
       "height": 24,

assets/themes/solarized-light.json 🔗

@@ -1240,6 +1240,7 @@
         "top": 4
       }
     },
+    "user_query_editor_height": 32,
     "add_contact_button": {
       "margin": {
         "left": 6
@@ -1248,7 +1249,20 @@
       "button_width": 8,
       "icon_width": 8
     },
+    "row": {
+      "padding": {
+        "left": 8
+      }
+    },
     "row_height": 28,
+    "header": {
+      "family": "Zed Mono",
+      "color": "#586e75",
+      "size": 14,
+      "margin": {
+        "top": 8
+      }
+    },
     "tree_branch_color": "#839496",
     "tree_branch_width": 1,
     "contact_avatar": {
@@ -1280,11 +1294,6 @@
       "button_width": 16,
       "corner_radius": 8
     },
-    "header": {
-      "family": "Zed Mono",
-      "color": "#586e75",
-      "size": 14
-    },
     "project": {
       "guest_avatar_spacing": 4,
       "height": 24,

assets/themes/sulphurpool-dark.json 🔗

@@ -1240,6 +1240,7 @@
         "top": 4
       }
     },
+    "user_query_editor_height": 32,
     "add_contact_button": {
       "margin": {
         "left": 6
@@ -1248,7 +1249,20 @@
       "button_width": 8,
       "icon_width": 8
     },
+    "row": {
+      "padding": {
+        "left": 8
+      }
+    },
     "row_height": 28,
+    "header": {
+      "family": "Zed Mono",
+      "color": "#979db4",
+      "size": 14,
+      "margin": {
+        "top": 8
+      }
+    },
     "tree_branch_color": "#6b7394",
     "tree_branch_width": 1,
     "contact_avatar": {
@@ -1280,11 +1294,6 @@
       "button_width": 16,
       "corner_radius": 8
     },
-    "header": {
-      "family": "Zed Mono",
-      "color": "#979db4",
-      "size": 14
-    },
     "project": {
       "guest_avatar_spacing": 4,
       "height": 24,

assets/themes/sulphurpool-light.json 🔗

@@ -1240,6 +1240,7 @@
         "top": 4
       }
     },
+    "user_query_editor_height": 32,
     "add_contact_button": {
       "margin": {
         "left": 6
@@ -1248,7 +1249,20 @@
       "button_width": 8,
       "icon_width": 8
     },
+    "row": {
+      "padding": {
+        "left": 8
+      }
+    },
     "row_height": 28,
+    "header": {
+      "family": "Zed Mono",
+      "color": "#5e6687",
+      "size": 14,
+      "margin": {
+        "top": 8
+      }
+    },
     "tree_branch_color": "#898ea4",
     "tree_branch_width": 1,
     "contact_avatar": {
@@ -1280,11 +1294,6 @@
       "button_width": 16,
       "corner_radius": 8
     },
-    "header": {
-      "family": "Zed Mono",
-      "color": "#5e6687",
-      "size": 14
-    },
     "project": {
       "guest_avatar_spacing": 4,
       "height": 24,

crates/contacts_panel/src/contacts_panel.rs 🔗

@@ -90,11 +90,12 @@ impl ContactsPanel {
                         ContactEntry::Header(text) => {
                             Label::new(text.to_string(), theme.header.text.clone())
                                 .contained()
-                                .with_style(theme.header.container)
                                 .aligned()
                                 .left()
                                 .constrained()
                                 .with_height(theme.row_height)
+                                .contained()
+                                .with_style(theme.header.container)
                                 .boxed()
                         }
                         ContactEntry::IncomingRequest(user) => {
@@ -302,6 +303,8 @@ impl ContactsPanel {
                             .boxed()
                     }),
             )
+            .contained()
+            .with_style(theme.row.clone())
             .boxed()
     }
 
@@ -380,7 +383,11 @@ impl ContactsPanel {
             .boxed(),
         ]);
 
-        row.constrained().with_height(theme.row_height).boxed()
+        row.constrained()
+            .with_height(theme.row_height)
+            .contained()
+            .with_style(theme.row.clone())
+            .boxed()
     }
 
     fn render_outgoing_contact_request(
@@ -434,7 +441,11 @@ impl ContactsPanel {
             .boxed(),
         );
 
-        row.constrained().with_height(theme.row_height).boxed()
+        row.constrained()
+            .with_height(theme.row_height)
+            .contained()
+            .with_style(theme.row)
+            .boxed()
     }
 
     fn update_entries(&mut self, cx: &mut ViewContext<Self>) {
@@ -643,7 +654,7 @@ impl View for ContactsPanel {
                             .boxed(),
                         )
                         .constrained()
-                        .with_height(32.)
+                        .with_height(theme.user_query_editor_height)
                         .boxed(),
                 )
                 .with_child(List::new(self.list_state.clone()).flex(1., false).boxed())

crates/theme/src/theme.rs 🔗

@@ -237,7 +237,9 @@ pub struct ContactsPanel {
     pub container: ContainerStyle,
     pub header: ContainedText,
     pub user_query_editor: FieldEditor,
+    pub user_query_editor_height: f32,
     pub add_contact_button: IconButton,
+    pub row: ContainerStyle,
     pub row_height: f32,
     pub contact_avatar: ImageStyle,
     pub contact_username: ContainedText,

styles/src/styleTree/contactsPanel.ts 🔗

@@ -55,13 +55,21 @@ export default function contactsPanel(theme: Theme) {
         top: 4,
       },
     },
+    userQueryEditorHeight: 32,
     addContactButton: {
       margin: { left: 6 },
       color: iconColor(theme, "primary"),
       buttonWidth: 8,
       iconWidth: 8,
     },
+    row: {
+      padding: { left: 8 },
+    },
     rowHeight: 28,
+    header: {
+      ...text(theme, "mono", "secondary", { size: "sm" }),
+      margin: { top: 8 },
+    },
     treeBranchColor: borderColor(theme, "muted"),
     treeBranchWidth: 1,
     contactAvatar: {
@@ -85,12 +93,6 @@ export default function contactsPanel(theme: Theme) {
       background: backgroundColor(theme, 100),
       color: iconColor(theme, "muted"),
     },
-    header: {
-      ...text(theme, "mono", "secondary", { size: "sm" }),
-      // padding: {
-      //   left: 8,
-      // }
-    },
     project,
     sharedProject,
     hoveredSharedProject: {