
This PR adds the `ui::Table` component. It has a rather simple API, but cells can contain either strings or elements, allowing for some complex uses. Example usage: ```rust Table::new(vec!["Product", "Price", "Stock"]) .width(px(600.)) .striped() .row(vec!["Laptop", "$999", "In Stock"]) .row(vec!["Phone", "$599", "Low Stock"]) .row(vec!["Tablet", "$399", "Out of Stock"]) ``` For more complex use cases, the table supports mixed content: ```rust Table::new(vec!["Status", "Name", "Priority", "Deadline", "Action"]) .width(px(840.)) .row(vec![ element_cell(Indicator::dot().color(Color::Success).into_any_element()), string_cell("Project A"), string_cell("High"), string_cell("2023-12-31"), element_cell(Button::new("view_a", "View").style(ButtonStyle::Filled).full_width().into_any_element()), ]) // ... more rows ``` Preview:  This component is pretty basic, improvements are welcome! Release Notes: - N/A
119 lines
3.9 KiB
Rust
119 lines
3.9 KiB
Rust
use crate::{prelude::*, Avatar};
|
||
use gpui::{AnyElement, StyleRefinement};
|
||
use smallvec::SmallVec;
|
||
|
||
/// A facepile is a collection of faces stacked horizontally–
|
||
/// always with the leftmost face on top and descending in z-index
|
||
///
|
||
/// Facepiles are used to display a group of people or things,
|
||
/// such as a list of participants in a collaboration session.
|
||
#[derive(IntoElement)]
|
||
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, _cx: &mut WindowContext) -> 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)),
|
||
)
|
||
}
|
||
}
|
||
|
||
impl ComponentPreview for Facepile {
|
||
fn description() -> impl Into<Option<&'static str>> {
|
||
"A facepile is a collection of faces stacked horizontally–\
|
||
always with the leftmost face on top and descending in z-index.\
|
||
\n\nFacepiles are used to display a group of people or things,\
|
||
such as a list of participants in a collaboration session."
|
||
}
|
||
fn examples() -> Vec<ComponentExampleGroup<Self>> {
|
||
let few_faces: [&'static str; 3] = [
|
||
"https://avatars.githubusercontent.com/u/1714999?s=60&v=4",
|
||
"https://avatars.githubusercontent.com/u/67129314?s=60&v=4",
|
||
"https://avatars.githubusercontent.com/u/482957?s=60&v=4",
|
||
];
|
||
|
||
let many_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",
|
||
];
|
||
|
||
vec![example_group_with_title(
|
||
"Examples",
|
||
vec![
|
||
single_example(
|
||
"Few Faces",
|
||
Facepile::new(
|
||
few_faces
|
||
.iter()
|
||
.map(|&url| Avatar::new(url).into_any_element())
|
||
.collect(),
|
||
),
|
||
),
|
||
single_example(
|
||
"Many Faces",
|
||
Facepile::new(
|
||
many_faces
|
||
.iter()
|
||
.map(|&url| Avatar::new(url).into_any_element())
|
||
.collect(),
|
||
),
|
||
),
|
||
single_example(
|
||
"Custom Size",
|
||
Facepile::new(
|
||
few_faces
|
||
.iter()
|
||
.map(|&url| Avatar::new(url).size(px(24.)).into_any_element())
|
||
.collect(),
|
||
),
|
||
),
|
||
],
|
||
)]
|
||
}
|
||
}
|