FileExplorer shows the folder at the end of a path three ways: the directory listing, a grid of tiles, or a column per folder along the path with the next folder lit. Its name, its count and a switch of views sit above one path bar that climbs. A folder opens in place; a file goes to the host, which lists each folder it goes to. A pick in an earlier column closes the columns past it, and a new deepest column scrolls into view. The directory listing takes its pick from its owner and reports it, so the pick carries across views; its path bar and its first order are shared. The gallery walks a small file system and shows the tree, the context menu, renaming in place and a drop zone in use.
121 lines
4.1 KiB
Rust
121 lines
4.1 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::{change, keep, section},
|
|
};
|
|
|
|
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,
|
|
)
|
|
.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),
|
|
))
|
|
}
|