Files
Ely-GPUI-Components/src/lists/grouped.rs
T

86 lines
2.6 KiB
Rust

use gpui::{
AnyElement, App, Div, ElementId, FontWeight, InteractiveElement, IntoElement, ParentElement,
RenderOnce, ScrollHandle, SharedString, StatefulInteractiveElement, StyleRefinement, Styled,
Window, div,
};
use crate::{
layout::StickyHeader,
theme::{ActiveTheme, TextSize},
};
/// Rows under group headers; each header pins to the top while its group scrolls past. Give it a height.
#[derive(IntoElement)]
pub struct GroupedList {
id: ElementId,
base: Div,
groups: Vec<(SharedString, Vec<AnyElement>)>,
}
impl GroupedList {
pub fn new(id: impl Into<ElementId>) -> Self {
Self {
id: id.into(),
base: div(),
groups: Vec::new(),
}
}
pub fn group(
mut self,
title: impl Into<SharedString>,
rows: impl IntoIterator<Item = impl IntoElement>,
) -> Self {
let rows = rows
.into_iter()
.map(IntoElement::into_any_element)
.collect();
self.groups.push((title.into(), rows));
self
}
}
impl Styled for GroupedList {
fn style(&mut self) -> &mut StyleRefinement {
self.base.style()
}
}
impl RenderOnce for GroupedList {
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
let handle = window
.use_keyed_state((self.id.clone(), "scroll"), cx, |_, _| ScrollHandle::new())
.read(cx)
.clone();
let id = self.id.clone();
self.base
.id(self.id)
.overflow_y_scroll()
.track_scroll(&handle)
.children(
self.groups
.into_iter()
.enumerate()
.map(|(ix, (title, rows))| {
StickyHeader::new(
(id.clone(), format!("group-{ix}")),
&handle,
move |_, cx| {
let theme = cx.theme();
div()
.px_3()
.pt_3()
.pb_1()
.text_size(theme.text_size(TextSize::Xs))
.font_weight(FontWeight::SEMIBOLD)
.text_color(theme.colors.fg_muted)
.child(title.clone())
.into_any_element()
},
)
.children(rows)
}),
)
}
}