Wherry/frontend/js/components/localPane.js
2026-07-11 00:01:26 +03:00

140 lines
5.1 KiB
JavaScript

import { state, notify, activeTab } from "../store.js";
import { t } from "../i18n.js";
import { iconMarkup } from "../icons.js";
import { formatSize } from "../format.js";
import { renderFileTable } from "./fileTable.js";
import { renderBreadcrumbs } from "./breadcrumbs.js";
import { makeDropTarget } from "../dnd.js";
import { showContextMenu } from "./contextMenu.js";
import { openRename, openDelete } from "./opDialogs.js";
import {
navigateLocal,
openLocalEntry,
addBookmark,
handleDropOnLocal,
queueUpload,
queueUploadMany,
} from "../fsActions.js";
export function renderLocalPane(container) {
container.innerHTML = `
<div class="path-bar">
<span class="path-bar-label">${t("panels.localLabel")}</span>
<div class="breadcrumbs" data-role="breadcrumbs"></div>
</div>
<div data-role="table" class="file-table-wrap"></div>
<div class="pane-footer">
<span data-role="count" class="text-dim" style="font-size:11px"></span>
<span data-role="size" class="text-hint" style="font-size:11px"></span>
<div class="pane-footer-right">
<button type="button" class="btn icon-btn btn-ghost" data-action="bookmark" title="${t("panels.bookmarkThisFolder")}">${iconMarkup("star", 13)}</button>
</div>
</div>
`;
container.querySelector('[data-action="bookmark"]').addEventListener("click", () => {
const path = state.local.path;
const name = path.split("/").filter(Boolean).pop() ?? "Bookmark";
addBookmark(name, path);
});
makeDropTarget(container, {
onDrop: (payload) => handleDropOnLocal(payload, state.local.path),
onHoverChange: (hover) => container.classList.toggle("drag-over", hover),
});
updateLocalPane(container);
}
export function updateLocalPane(container) {
renderBreadcrumbs(container.querySelector('[data-role="breadcrumbs"]'), state.local.path || "/", navigateLocal);
const tab = activeTab();
const connected = tab?.status === "connected";
renderFileTable(container.querySelector('[data-role="table"]'), {
entries: state.local.entries,
selected: state.local.selected,
anchor: state.local.selectAnchor,
sort: state.local.sort,
onSort: (next) => {
state.local.sort = next;
notify();
},
onSelect: (names, anchor) => {
state.local.selected = names;
state.local.selectAnchor = anchor;
state.activePane = "local";
notify();
},
onOpen: (name) => openLocalEntry(name),
onHoverOpen: (entry) => openLocalEntry(entry.name),
dragPayload: (entry) => {
if (entry.name === "..") return null;
const group =
state.local.selected.includes(entry.name) && state.local.selected.length > 1
? state.local.entries.filter((e) => state.local.selected.includes(e.name))
: [entry];
return {
source: "local",
items: group.map((e) => ({ path: e.path, name: e.name, kind: e.kind })),
};
},
onDropOnEntry: (entry, payload) => handleDropOnLocal(payload, entry.path),
contextMenuItems: (entry, selectedEntries) => {
if (selectedEntries.length > 1) {
const files = selectedEntries.filter((e) => e.kind === "file");
return [
{
label: t("common.delete") + ` (${selectedEntries.length})`,
icon: "trash",
danger: true,
onClick: () => openDeleteLocal(selectedEntries),
},
...(files.length > 0 && connected
? [
"sep",
{
label: t("panels.uploadToServer") + ` (${files.length})`,
icon: "upload",
onClick: () => queueUploadMany(tab, files),
},
]
: []),
];
}
return [
{ label: t("common.open"), icon: "folder", onClick: () => openLocalEntry(entry.name) },
{ label: t("common.rename"), icon: "pen", onClick: () => openRenameLocal(entry) },
{ label: t("common.delete"), icon: "trash", danger: true, onClick: () => openDeleteLocal([entry]) },
"sep",
...(entry.kind === "dir"
? [{ label: t("panels.addToBookmarks"), icon: "star", onClick: () => addBookmark(entry.name, entry.path) }]
: []),
{ label: t("common.copyPath"), icon: "copy", onClick: () => copyPath(entry.path) },
...(entry.kind === "file" && connected
? ["sep", { label: t("panels.uploadToServer"), icon: "upload", onClick: () => queueUpload(tab, entry) }]
: []),
];
},
});
const count = state.local.entries.filter((e) => e.name !== "..").length;
const totalSize = state.local.entries.reduce((sum, e) => sum + (e.size ?? 0), 0);
container.querySelector('[data-role="count"]').textContent = t("panels.countItems", { n: count });
container.querySelector('[data-role="size"]').textContent = totalSize > 0 ? `(${formatSize(totalSize)})` : "";
}
function openRenameLocal(entry) {
state.opTarget = "local";
openRename(entry.name);
}
function openDeleteLocal(entries) {
state.opTarget = "local";
openDelete(entries.map((e) => e.name));
}
function copyPath(path) {
navigator.clipboard?.writeText(path);
state.statusMessage = t("panels.pathCopied");
notify();
}