
- Merge `Component` and `ComponentPreview` trait - Adds a number of component previews - Removes a number of stories Release Notes: - N/A
133 lines
4 KiB
Rust
133 lines
4 KiB
Rust
use crate::component_prelude::*;
|
|
use crate::prelude::*;
|
|
use gpui::{AnyElement, StyleRefinement};
|
|
use smallvec::SmallVec;
|
|
|
|
use super::Avatar;
|
|
|
|
/// An element that displays a collection of (usually) faces stacked
|
|
/// horizontally, with the left-most face on top, visually descending
|
|
/// from left to right.
|
|
///
|
|
/// Facepiles are used to display a group of people or things,
|
|
/// such as a list of participants in a collaboration session.
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ## Default
|
|
///
|
|
/// A default, horizontal facepile.
|
|
///
|
|
/// ```
|
|
/// use ui::{Avatar, Facepile, EXAMPLE_FACES};
|
|
///
|
|
/// Facepile::new(
|
|
/// EXAMPLE_FACES.iter().take(3).iter().map(|&url|
|
|
/// Avatar::new(url).into_any_element()).collect())
|
|
/// ```
|
|
#[derive(IntoElement, Documented, RegisterComponent)]
|
|
pub struct Facepile {
|
|
base: Div,
|
|
faces: SmallVec<[AnyElement; 2]>,
|
|
}
|
|
|
|
impl Facepile {
|
|
/// Creates a new empty facepile.
|
|
pub fn empty() -> Self {
|
|
Self::new(SmallVec::new())
|
|
}
|
|
|
|
/// Creates a new facepile with the given faces.
|
|
pub fn new(faces: SmallVec<[AnyElement; 2]>) -> Self {
|
|
Self { base: div(), faces }
|
|
}
|
|
}
|
|
|
|
impl ParentElement for Facepile {
|
|
fn extend(&mut self, elements: impl IntoIterator<Item = AnyElement>) {
|
|
self.faces.extend(elements);
|
|
}
|
|
}
|
|
|
|
// Style methods.
|
|
impl Facepile {
|
|
fn style(&mut self) -> &mut StyleRefinement {
|
|
self.base.style()
|
|
}
|
|
|
|
gpui::padding_style_methods!({
|
|
visibility: pub
|
|
});
|
|
}
|
|
|
|
impl RenderOnce for Facepile {
|
|
fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
|
|
// Lay the faces out in reverse so they overlap in the desired order (left to right, front to back)
|
|
self.base
|
|
.flex()
|
|
.flex_row_reverse()
|
|
.items_center()
|
|
.justify_start()
|
|
.children(
|
|
self.faces
|
|
.into_iter()
|
|
.enumerate()
|
|
.rev()
|
|
.map(|(ix, player)| div().when(ix > 0, |div| div.ml_neg_1()).child(player)),
|
|
)
|
|
}
|
|
}
|
|
|
|
pub const EXAMPLE_FACES: [&'static str; 6] = [
|
|
"https://avatars.githubusercontent.com/u/326587?s=60&v=4",
|
|
"https://avatars.githubusercontent.com/u/2280405?s=60&v=4",
|
|
"https://avatars.githubusercontent.com/u/1789?s=60&v=4",
|
|
"https://avatars.githubusercontent.com/u/67129314?s=60&v=4",
|
|
"https://avatars.githubusercontent.com/u/482957?s=60&v=4",
|
|
"https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
|
|
];
|
|
|
|
impl Component for Facepile {
|
|
fn scope() -> ComponentScope {
|
|
ComponentScope::Collaboration
|
|
}
|
|
|
|
fn description() -> Option<&'static str> {
|
|
Some(
|
|
"Displays a collection of avatars or initials in a compact format. Often used to represent active collaborators or a subset of contributors.",
|
|
)
|
|
}
|
|
|
|
fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
|
|
Some(
|
|
v_flex()
|
|
.gap_6()
|
|
.children(vec![example_group_with_title(
|
|
"Facepile Examples",
|
|
vec![
|
|
single_example(
|
|
"Default",
|
|
Facepile::new(
|
|
EXAMPLE_FACES
|
|
.iter()
|
|
.map(|&url| Avatar::new(url).into_any_element())
|
|
.collect(),
|
|
)
|
|
.into_any_element(),
|
|
),
|
|
single_example(
|
|
"Custom Size",
|
|
Facepile::new(
|
|
EXAMPLE_FACES
|
|
.iter()
|
|
.map(|&url| Avatar::new(url).size(px(24.)).into_any_element())
|
|
.collect(),
|
|
)
|
|
.into_any_element(),
|
|
),
|
|
],
|
|
)])
|
|
.into_any_element(),
|
|
)
|
|
}
|
|
}
|