Right-click context menus on file panels
Native menus (electrobun ContextMenu) on rows and empty panel space. Rows: Open (dirs navigate; local files open with the default app via Utils.openPath), Edit, Copy to Other Panel, Rename, Permissions, Copy Path (works for remote paths too), Reveal in Finder (local, Utils.showItemInFolder), Move to Trash (local, Utils.moveToTrash — tooltip notes Finder Restore doesn't apply) and Delete. Empty space / '..': New Folder, New File, Refresh, Reveal in Finder. Right-click parks the cursor on the row (keeping the selection when clicking inside it). Local shell actions run bun-side directly; everything else routes through the existing menuAction channel back to the stored click target. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import { ContextMenu, Utils, type ApplicationMenuItemConfig } from "electrobun/bun";
|
||||
|
||||
export interface RowMenuContext {
|
||||
path: string;
|
||||
name: string;
|
||||
type: "file" | "dir" | "symlink";
|
||||
isLocal: boolean;
|
||||
hasEntry: boolean; // false = right-click on empty panel space
|
||||
}
|
||||
|
||||
/**
|
||||
* Native right-click menus for the file panels. Local-only items run directly
|
||||
* here via Utils (reveal, open with default app, copy path); everything else
|
||||
* forwards to the webview through the menuAction channel — the UI kept its own
|
||||
* context (which panel/row was clicked) when it requested the menu.
|
||||
*/
|
||||
export class PanelContextMenu {
|
||||
private context: RowMenuContext | null = null;
|
||||
/** Forwards actions the UI must handle (ctx-open, ctx-delete, ...). */
|
||||
onAction: (action: string) => void = () => {};
|
||||
|
||||
constructor() {
|
||||
ContextMenu.on("context-menu-clicked", (event) => {
|
||||
const action = (event as { data?: { action?: string } }).data?.action;
|
||||
const ctx = this.context;
|
||||
if (!action || !ctx) return;
|
||||
switch (action) {
|
||||
case "ctx-reveal":
|
||||
Utils.showItemInFolder(ctx.path);
|
||||
break;
|
||||
case "ctx-open-default":
|
||||
Utils.openPath(ctx.path);
|
||||
break;
|
||||
case "ctx-copy-path":
|
||||
Utils.clipboardWriteText(ctx.path);
|
||||
break;
|
||||
default:
|
||||
if (action.startsWith("ctx-")) this.onAction(action);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
show(context: RowMenuContext): void {
|
||||
this.context = context;
|
||||
ContextMenu.showContextMenu(this.build(context));
|
||||
}
|
||||
|
||||
private build(ctx: RowMenuContext): ApplicationMenuItemConfig[] {
|
||||
const items: ApplicationMenuItemConfig[] = [];
|
||||
|
||||
if (!ctx.hasEntry || ctx.name === "..") {
|
||||
// empty space (or the parent row): folder-level actions
|
||||
items.push({ label: "New Folder", action: "ctx-new-folder" });
|
||||
items.push({ label: "New File", action: "ctx-new-file" });
|
||||
items.push({ type: "separator" });
|
||||
items.push({ label: "Refresh", action: "ctx-refresh" });
|
||||
if (ctx.isLocal) {
|
||||
items.push({ type: "separator" });
|
||||
items.push({ label: "Reveal in Finder", action: "ctx-reveal" });
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
if (ctx.type === "dir") {
|
||||
items.push({ label: "Open", action: "ctx-open" });
|
||||
} else {
|
||||
if (ctx.isLocal) {
|
||||
items.push({ label: "Open", action: "ctx-open-default", tooltip: "Open with the default application" });
|
||||
}
|
||||
items.push({ label: "Edit", action: "ctx-edit", accelerator: "e" });
|
||||
}
|
||||
items.push({ label: "Copy to Other Panel", action: "ctx-copy" });
|
||||
items.push({ label: "Rename", action: "ctx-rename" });
|
||||
items.push({ label: "Permissions", action: "ctx-chmod" });
|
||||
items.push({ type: "separator" });
|
||||
items.push({ label: "Copy Path", action: "ctx-copy-path" });
|
||||
if (ctx.isLocal) {
|
||||
items.push({ label: "Reveal in Finder", action: "ctx-reveal" });
|
||||
}
|
||||
items.push({ type: "separator" });
|
||||
if (ctx.isLocal) {
|
||||
items.push({
|
||||
label: "Move to Trash",
|
||||
action: "ctx-trash",
|
||||
tooltip: "Finder's Restore is not available for items trashed from here",
|
||||
});
|
||||
}
|
||||
items.push({ label: "Delete", action: "ctx-delete" });
|
||||
return items;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user