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.
125 lines
4.0 KiB
Rust
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()))
|
|
}
|