Files
Ely-GPUI-Components/examples/gallery/pages/files/actions.rs
T
ZacharyZhang-NY 95db323797 T44d Web · What a browser cannot do says why; fonts resolve; the bundle builds
Demos that open a second window, take files, move the window, read the
clipboard or set native menus show a note on the web in the blocked style.
IBM Plex Sans Regular joins the assets, unmodified, where gpui's svg
renderer loads it: gpui_web answers .SystemUIFont with it. The gallery's
web entry registers a Hebrew cut of Noto Sans Hebrew. scripts/web.sh builds
the bundle with wasm-bindgen and wasm-opt -Oz, 20.0 MB, and fails past 25 MiB.
2026-09-29 19:16:41 -04:00

122 lines
4.2 KiB
Rust

use ely_gpui_component::{
files::{FileGrid, FileIcon, FileItem},
forms::{DropZone, InlineEdit},
lists::{DirEntry, SelectableList},
menus::{ContextMenu, Menu, MenuItem},
primitives::IconName,
};
use gpui::{App, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
use jiff::Timestamp;
use crate::{
probe::probe,
ui::{NO_FILES, change, keep, section, web_note},
};
pub fn context_menu(cx: &mut App) -> impl IntoElement + use<> {
let item = |label: &'static str, icon: IconName| {
MenuItem::new(label)
.icon(icon)
.on_click(move |_, _| log::info!("gallery: {label}"))
};
let menu = Menu::new()
.item(item("Open", IconName::FolderOpen))
.item(item("Rename", IconName::PenLine))
.item(item("Duplicate", IconName::Copy))
.separator()
.item(item("Move to Trash", IconName::Trash2));
section(
"FileContextMenu",
"What a right press on files offers, as menus::ContextMenu draws it: open, rename, duplicate, and the trash apart.",
cx,
)
.child(probe(
"files-context",
div().w(px(640.)).child(
ContextMenu::new("files-context", menu)
.child(FileGrid::new("files-context-grid", super::entries().into_iter().take(6))),
),
))
}
pub fn rename(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let name = keep(
"files-rename",
|| SharedString::from("Brief.md"),
window,
cx,
);
let now = name.read(cx).clone();
section(
"RenameInline",
"A name edited in place, as forms::InlineEdit does it: a press or Enter edits, Enter keeps and Escape drops; the icon follows the new name.",
cx,
)
.child(probe(
"files-rename",
div()
.w(px(320.))
.flex()
.items_center()
.gap_2()
.child(FileIcon::file(&now))
.child(div().flex_1().min_w_0().child(
InlineEdit::new("files-rename", now).on_commit(move |text, _, cx| {
change(&name, cx, |name| *name = text.clone())
}),
)),
))
}
pub fn drop_files(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let dropped = keep("files-dropped", Vec::<DirEntry>::new, window, cx);
let now = dropped.read(cx).clone();
let take = dropped.clone();
let list = now
.iter()
.fold(SelectableList::new("files-dropped"), |list, entry| {
let key = entry.name().clone();
let id = SharedString::from(format!("files-dropped-{key}"));
list.row(key, FileItem::new(id, entry.clone()).into())
});
section(
"DragDropFiles",
"Files dropped in, as forms::DropZone takes them; each lands in the list below.",
cx,
)
.children(web_note(NO_FILES, cx))
.child(probe(
"files-drop",
div()
.w(px(420.))
.flex()
.flex_col()
.gap_3()
.child(
DropZone::new("files-drop")
.multiple()
.hint("Any kind of file")
.on_drop(move |paths, _, cx| {
let entries = paths.iter().map(|path| {
let bytes = path.metadata().expect("a dropped file reads").len();
let name = path.file_name().expect("a file name");
DirEntry::file(
name.to_string_lossy().to_string(),
bytes,
Timestamp::now(),
)
});
let entries: Vec<DirEntry> = entries.collect();
change(&take, cx, |dropped| {
for entry in entries {
if !dropped.iter().any(|kept| kept.name() == entry.name()) {
dropped.push(entry);
}
}
})
}),
)
.child(list),
))
}