Дезайн ыыыы
This commit is contained in:
parent
403d7086d4
commit
e7c02c7feb
174 changed files with 15802 additions and 9725 deletions
79
frontend/js/dnd.js
Normal file
79
frontend/js/dnd.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// Native HTML5 drag & drop, standing in for egui's dnd_drag_source /
|
||||
// dnd_drop_zone. Payload shape mirrors the old Rust `DragPayload` enum:
|
||||
// { source: 'local', path, name }
|
||||
// { source: 'remote', path, name, connectionId }
|
||||
const MIME = "application/x-wherry-payload";
|
||||
|
||||
// "Spring-loaded folder" hover delay: you can't click a folder open while
|
||||
// your mouse is busy carrying a payload, so a drag has to linger this long
|
||||
// over a folder row (or another pane) before it auto-opens -- mirrors
|
||||
// Finder/Explorer's spring-loaded folders.
|
||||
export const HOVER_OPEN_DELAY = 900;
|
||||
|
||||
export function makeDraggable(el, entry, payload) {
|
||||
if (entry.name === "..") return; // parent row is never a drag source
|
||||
el.draggable = true;
|
||||
el.addEventListener("dragstart", (e) => {
|
||||
e.dataTransfer.effectAllowed = "move";
|
||||
e.dataTransfer.setData(MIME, JSON.stringify(payload));
|
||||
requestAnimationFrame(() => el.classList.add("dragging"));
|
||||
});
|
||||
el.addEventListener("dragend", () => el.classList.remove("dragging"));
|
||||
}
|
||||
|
||||
/** opts.onHoverHold, if given, fires once after HOVER_OPEN_DELAY of
|
||||
* uninterrupted dragover -- used to spring a folder row open without
|
||||
* ending the drag. */
|
||||
export function makeDropTarget(el, { onDrop, onHoverChange, onHoverHold } = {}) {
|
||||
let holdTimer = null;
|
||||
const clearHold = () => {
|
||||
clearTimeout(holdTimer);
|
||||
holdTimer = null;
|
||||
};
|
||||
|
||||
el.addEventListener("dragover", (e) => {
|
||||
if (!e.dataTransfer.types.includes(MIME)) return;
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = "move";
|
||||
onHoverChange?.(true);
|
||||
if (onHoverHold && !holdTimer) {
|
||||
holdTimer = setTimeout(() => {
|
||||
holdTimer = null;
|
||||
onHoverHold();
|
||||
}, HOVER_OPEN_DELAY);
|
||||
}
|
||||
});
|
||||
el.addEventListener("dragleave", (e) => {
|
||||
if (el.contains(e.relatedTarget)) return; // moved onto a child, not actually left
|
||||
onHoverChange?.(false);
|
||||
clearHold();
|
||||
});
|
||||
el.addEventListener("drop", (e) => {
|
||||
if (!e.dataTransfer.types.includes(MIME)) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation(); // don't let the pane-level drop zone also fire for this same drop
|
||||
onHoverChange?.(false);
|
||||
clearHold();
|
||||
const raw = e.dataTransfer.getData(MIME);
|
||||
if (!raw) return;
|
||||
try {
|
||||
onDrop(JSON.parse(raw));
|
||||
} catch {
|
||||
/* malformed payload, ignore */
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ── Tab-bar → pane drag tracking ────────────────────────────────────────
|
||||
// dataTransfer.getData() only returns data on dragstart/drop, not dragover
|
||||
// (a browser security restriction) -- so paneLayout.js can't read which tab
|
||||
// is mid-drag from the dragover event itself. Track it here instead; tabs.js
|
||||
// sets it on dragstart/dragend. `undefined` means no tab drag is in flight
|
||||
// (kept distinct from `null`, which is the Local tab's real id).
|
||||
let draggedTabId;
|
||||
export function setDraggedTabId(id) {
|
||||
draggedTabId = id;
|
||||
}
|
||||
export function getDraggedTabId() {
|
||||
return draggedTabId;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue