facepile.rs

  1use crate::{Avatar, prelude::*};
  2use gpui::{AnyElement, StyleRefinement};
  3use smallvec::SmallVec;
  4
  5/// A facepile is a collection of faces stacked horizontally–
  6/// always with the leftmost face on top and descending in z-index
  7///
  8/// Facepiles are used to display a group of people or things,
  9/// such as a list of participants in a collaboration session.
 10#[derive(IntoElement, IntoComponent)]
 11pub struct Facepile {
 12    base: Div,
 13    faces: SmallVec<[AnyElement; 2]>,
 14}
 15
 16impl Facepile {
 17    /// Creates a new empty facepile.
 18    pub fn empty() -> Self {
 19        Self::new(SmallVec::new())
 20    }
 21
 22    /// Creates a new facepile with the given faces.
 23    pub fn new(faces: SmallVec<[AnyElement; 2]>) -> Self {
 24        Self { base: div(), faces }
 25    }
 26}
 27
 28impl ParentElement for Facepile {
 29    fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
 30        self.faces.extend(elements);
 31    }
 32}
 33
 34// Style methods.
 35impl Facepile {
 36    fn style(&mut self) -> &mut StyleRefinement {
 37        self.base.style()
 38    }
 39
 40    gpui::padding_style_methods!({
 41        visibility: pub
 42    });
 43}
 44
 45impl RenderOnce for Facepile {
 46    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
 47        // Lay the faces out in reverse so they overlap in the desired order (left to right, front to back)
 48        self.base
 49            .flex()
 50            .flex_row_reverse()
 51            .items_center()
 52            .justify_start()
 53            .children(
 54                self.faces
 55                    .into_iter()
 56                    .enumerate()
 57                    .rev()
 58                    .map(|(ix, player)| div().when(ix > 0, |div| div.ml_neg_1()).child(player)),
 59            )
 60    }
 61}
 62
 63impl ComponentPreview for Facepile {
 64    fn preview(_window: &mut Window, _cx: &mut App) -> AnyElement {
 65        let faces: [&'static str; 6] = [
 66            "https://avatars.githubusercontent.com/u/326587?s=60&v=4",
 67            "https://avatars.githubusercontent.com/u/2280405?s=60&v=4",
 68            "https://avatars.githubusercontent.com/u/1789?s=60&v=4",
 69            "https://avatars.githubusercontent.com/u/67129314?s=60&v=4",
 70            "https://avatars.githubusercontent.com/u/482957?s=60&v=4",
 71            "https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
 72        ];
 73
 74        v_flex()
 75            .gap_6()
 76            .children(vec![
 77                example_group_with_title(
 78                    "Facepile Examples",
 79                    vec![
 80                        single_example(
 81                            "Default",
 82                            Facepile::new(
 83                                faces
 84                                    .iter()
 85                                    .map(|&url| Avatar::new(url).into_any_element())
 86                                    .collect(),
 87                            )
 88                            .into_any_element(),
 89                        ),
 90                        single_example(
 91                            "Custom Size",
 92                            Facepile::new(
 93                                faces
 94                                    .iter()
 95                                    .map(|&url| Avatar::new(url).size(px(24.)).into_any_element())
 96                                    .collect(),
 97                            )
 98                            .into_any_element(),
 99                        ),
100                    ],
101                ),
102                example_group_with_title(
103                    "Special Cases",
104                    vec![
105                        single_example("Empty Facepile", Facepile::empty().into_any_element()),
106                        single_example(
107                            "Single Face",
108                            Facepile::new(vec![Avatar::new(faces[0]).into_any_element()].into())
109                                .into_any_element(),
110                        ),
111                    ],
112                ),
113            ])
114            .into_any_element()
115    }
116}