Make `FacePile` a component again (#4143)

Marshall Bowers created

This PR turns `FacePile` back into a component.

Our usage of it seemed a little weird, with us calling `render`
manually.

We're now implementing `Styled` on `FacePile` through its inner `Div` so
that we can apply the `p_1` at the call site.

Release Notes:

- N/A

Change summary

crates/collab_ui/src/collab_panel.rs         | 10 +++---
crates/collab_ui/src/collab_titlebar_item.rs |  5 +--
crates/collab_ui/src/face_pile.rs            | 32 +++++++++++++++++----
3 files changed, 33 insertions(+), 14 deletions(-)

Detailed changes

crates/collab_ui/src/collab_panel.rs 🔗

@@ -2214,15 +2214,15 @@ impl CollabPanel {
 
         let face_pile = if !participants.is_empty() {
             let extra_count = participants.len().saturating_sub(FACEPILE_LIMIT);
-            let result = FacePile {
-                faces: participants
+            let result = FacePile::new(
+                participants
                     .iter()
                     .map(|user| Avatar::new(user.avatar_uri.clone()).into_any_element())
                     .take(FACEPILE_LIMIT)
                     .chain(if extra_count > 0 {
                         Some(
                             div()
-                                .ml_1()
+                                .ml_2()
                                 .child(Label::new(format!("+{extra_count}")))
                                 .into_any_element(),
                         )
@@ -2230,7 +2230,7 @@ impl CollabPanel {
                         None
                     })
                     .collect::<SmallVec<_>>(),
-            };
+            );
 
             Some(result)
         } else {
@@ -2295,7 +2295,7 @@ impl CollabPanel {
                         h_flex()
                             .id(channel_id as usize)
                             .child(Label::new(channel.name.clone()))
-                            .children(face_pile.map(|face_pile| face_pile.render().p_1())),
+                            .children(face_pile.map(|face_pile| face_pile.p_1())),
                     ),
             )
             .child(

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -495,7 +495,7 @@ impl CollabTitlebarItem {
                     div.rounded_md().bg(color)
                 })
                 .child(
-                    FacePile::default()
+                    FacePile::empty()
                         .child(
                             Avatar::new(user.avatar_uri.clone())
                                 .grayscale(!is_present)
@@ -547,8 +547,7 @@ impl CollabTitlebarItem {
                             )
                         } else {
                             None
-                        })
-                        .render(),
+                        }),
                 ),
         )
     }

crates/collab_ui/src/face_pile.rs 🔗

@@ -1,14 +1,28 @@
-use gpui::{div, AnyElement, Div, ParentElement, Styled};
+use gpui::AnyElement;
 use smallvec::SmallVec;
-use ui::FluentBuilder;
+use ui::prelude::*;
 
-#[derive(Default)]
+#[derive(IntoElement)]
 pub struct FacePile {
-    pub faces: SmallVec<[AnyElement; 2]>,
+    base: Div,
+    faces: SmallVec<[AnyElement; 2]>,
 }
 
 impl FacePile {
-    pub fn render(self) -> Div {
+    pub fn empty() -> Self {
+        Self::new(SmallVec::new())
+    }
+
+    pub fn new(faces: SmallVec<[AnyElement; 2]>) -> Self {
+        Self {
+            base: h_flex(),
+            faces,
+        }
+    }
+}
+
+impl RenderOnce for FacePile {
+    fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
         let player_count = self.faces.len();
         let player_list = self.faces.into_iter().enumerate().map(|(ix, player)| {
             let isnt_last = ix < player_count - 1;
@@ -18,7 +32,7 @@ impl FacePile {
                 .when(isnt_last, |div| div.neg_mr_1())
                 .child(player)
         });
-        div().flex().items_center().children(player_list)
+        self.base.children(player_list)
     }
 }
 
@@ -27,3 +41,9 @@ impl ParentElement for FacePile {
         &mut self.faces
     }
 }
+
+impl Styled for FacePile {
+    fn style(&mut self) -> &mut gpui::StyleRefinement {
+        self.base.style()
+    }
+}