facepile.rs

  1use crate::{prelude::*, Avatar};
  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)]
 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 description() -> impl Into<Option<&'static str>> {
 65        "A facepile is a collection of faces stacked horizontally–\
 66        always with the leftmost face on top and descending in z-index.\
 67        \n\nFacepiles are used to display a group of people or things,\
 68        such as a list of participants in a collaboration session."
 69    }
 70    fn examples(_window: &mut Window, _: &mut App) -> Vec<ComponentExampleGroup<Self>> {
 71        let few_faces: [&'static str; 3] = [
 72            "https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
 73            "https://avatars.githubusercontent.com/u/67129314?s=60&v=4",
 74            "https://avatars.githubusercontent.com/u/482957?s=60&v=4",
 75        ];
 76
 77        let many_faces: [&'static str; 6] = [
 78            "https://avatars.githubusercontent.com/u/326587?s=60&v=4",
 79            "https://avatars.githubusercontent.com/u/2280405?s=60&v=4",
 80            "https://avatars.githubusercontent.com/u/1789?s=60&v=4",
 81            "https://avatars.githubusercontent.com/u/67129314?s=60&v=4",
 82            "https://avatars.githubusercontent.com/u/482957?s=60&v=4",
 83            "https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
 84        ];
 85
 86        vec![example_group_with_title(
 87            "Examples",
 88            vec![
 89                single_example(
 90                    "Few Faces",
 91                    Facepile::new(
 92                        few_faces
 93                            .iter()
 94                            .map(|&url| Avatar::new(url).into_any_element())
 95                            .collect(),
 96                    ),
 97                ),
 98                single_example(
 99                    "Many Faces",
100                    Facepile::new(
101                        many_faces
102                            .iter()
103                            .map(|&url| Avatar::new(url).into_any_element())
104                            .collect(),
105                    ),
106                ),
107                single_example(
108                    "Custom Size",
109                    Facepile::new(
110                        few_faces
111                            .iter()
112                            .map(|&url| Avatar::new(url).size(px(24.)).into_any_element())
113                            .collect(),
114                    ),
115                ),
116            ],
117        )]
118    }
119}