Files
Ely-GPUI-Components/examples/gallery/pages/lists/long.rs
T
ZacharyZhang-NY 4c3ed1bbb9 Port · Build: Zed's gpui at 1a28cff
gpui and gpui_platform now come from Zed's repo by git at 1a28cff,
the code gpui-pre 0.3.7 republishes, so the gallery can later build
for the browser. gpui takes stacker, as 0.2.2 always did, and
gpui_platform takes font-kit, without which macOS draws no text;
runtime_shaders moves to gpui_platform.

The API moved: focus, blur and Tab steps take cx, Corner is Anchor,
shaped lines paint with an alignment, defer_draw takes a content
mask, the inspector registers a factory, async updates return their
value, and wrapped lines are shared, not cloned. Updates through a
window context go through the window, so a closed window still ends
them as it did.

Where the new gpui behaves differently, Ely keeps its old intent.
Holds and reveals under a resting pointer survive typing through
gpui's input-modality-independent hover; previews the keyboard also
moves keep the default, and the calendar's leave ignores a key press.
Enter reaches a button inside the code editor, since gpui now arms a
key click on the press. The event logger skips a lone modifier. A
video and an image grid keep their shape in a flex column under
taffy 0.13, as a picture does.

AGENTS.md records the new stack and the rules this port changes; the
rest of the old gpui and taffy rules are re-tested in T44c.
2026-09-28 20:30:17 -04:00

125 lines
4.0 KiB
Rust

use std::time::Duration;
use ely_gpui_component::{
data_display::Avatar,
lists::{GroupedList, InfiniteList, ListItem, VirtualList},
theme::{ActiveTheme, AvatarSize, Radius},
};
use gpui::{
App, InteractiveElement, IntoElement, ParentElement, SharedString, StatefulInteractiveElement,
Styled, Window, div, px,
};
use crate::ui::{keep, section, set};
fn framed(cx: &App) -> gpui::Div {
let theme = cx.theme();
div()
.w(px(420.))
.h(px(280.))
.rounded(theme.radius(Radius::Md))
.border_1()
.border_color(theme.colors.border)
}
pub fn virtual_list(cx: &mut App) -> impl IntoElement + use<> {
section(
"VirtualList",
"Ten thousand rows, each as tall as it needs; only those near the view are built.",
cx,
)
.child(
framed(cx).child(
VirtualList::new("long", 10_000, |ix, _, _| {
let row = ListItem::new(("long-row", ix), format!("Row {}", ix + 1));
let row = if ix % 7 == 0 {
row.description("Every seventh row carries a second line, so heights differ.")
} else {
row
};
div().px_1().child(row).into_any_element()
})
.size_full(),
),
)
}
/// Pages of twelve, five pages in all.
const PAGE: usize = 12;
pub fn infinite(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let state = keep("infinite", || (PAGE, false), window, cx);
let ((rows, loading), more) = (*state.read(cx), state.clone());
section(
"InfiniteList",
"Scroll to the end and the next page comes, a spinner holding its place while it loads. After five pages, the list ends quietly.",
cx,
)
.child(
framed(cx).child(
div().id("infinite-scroll").size_full().overflow_y_scroll().child(
InfiniteList::new("infinite")
.children((0..rows).map(|ix| ListItem::new(("infinite-row", ix), format!("Message {}", ix + 1))))
.loading(loading)
.done(rows >= PAGE * 5)
.on_more(move |_, cx| {
set(&more, (rows, true), cx);
let more = more.clone();
cx.spawn(async move |cx| {
cx.background_executor().timer(Duration::from_millis(700)).await;
cx.update(|cx| set(&more, (rows + PAGE, false), cx));
})
.detach();
}),
),
),
)
}
const PEOPLE: [&str; 14] = [
"Ada Lovelace",
"Alan Kay",
"Alan Turing",
"Barbara Liskov",
"Brian Kernighan",
"Claude Shannon",
"Dennis Ritchie",
"Donald Knuth",
"Edsger Dijkstra",
"Frances Allen",
"Grace Hopper",
"Katherine Johnson",
"Ken Thompson",
"Margaret Hamilton",
];
pub fn grouped(cx: &mut App) -> impl IntoElement + use<> {
let mut letters: Vec<char> = PEOPLE
.iter()
.filter_map(|name| name.chars().next())
.collect();
letters.dedup();
let list = letters
.into_iter()
.fold(GroupedList::new("people"), |list, letter| {
let rows = PEOPLE
.iter()
.filter(move |name| name.starts_with(letter))
.map(|name| {
div().px_1().child(
ListItem::new(SharedString::from(format!("person-{name}")), *name).leading(
Avatar::new(SharedString::from(format!("face-{name}")), *name)
.size(AvatarSize::Sm),
),
)
});
list.group(letter.to_string(), rows)
});
section(
"GroupedList / SectionList",
"Rows under their letter; each letter pins to the top while its group scrolls past.",
cx,
)
.child(framed(cx).child(list.size_full()))
}