Modernize file context menu

This commit is contained in:
Mikei386
2026-07-14 18:35:51 +02:00
parent 19a869d55a
commit af9e7703ea
5 changed files with 78 additions and 27 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
set -eu set -eu
PLUGIN="u-navigator" PLUGIN="u-navigator"
VERSION="2026.07.14.r015" VERSION="2026.07.14.r016"
PKG_DIR="packages" PKG_DIR="packages"
WORK_DIR=".plugin-build" WORK_DIR=".plugin-build"
PKG_NAME="${PLUGIN}-${VERSION}.tgz" PKG_NAME="${PLUGIN}-${VERSION}.tgz"
Binary file not shown.
+28 -14
View File
@@ -51,7 +51,10 @@ const uiIcons = {
chevronDown: '<path d="m6 9 6 6 6-6"></path>', chevronDown: '<path d="m6 9 6 6 6-6"></path>',
chevronRight: '<path d="m9 18 6-6-6-6"></path>', chevronRight: '<path d="m9 18 6-6-6-6"></path>',
close: '<path d="M18 6 6 18"></path><path d="m6 6 12 12"></path>', close: '<path d="M18 6 6 18"></path><path d="m6 6 12 12"></path>',
copy: '<rect x="9" y="9" width="11" height="11" rx="2"></rect><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"></path>',
delete: '<path d="M4 7h16"></path><path d="M10 11v6"></path><path d="M14 11v6"></path><path d="M6 7l1 14h10l1-14"></path><path d="M9 7V4h6v3"></path>', delete: '<path d="M4 7h16"></path><path d="M10 11v6"></path><path d="M14 11v6"></path><path d="M6 7l1 14h10l1-14"></path><path d="M9 7V4h6v3"></path>',
download: '<path d="M12 3v12"></path><path d="m7 10 5 5 5-5"></path><path d="M5 21h14"></path>',
edit: '<path d="M12 20h9"></path><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L8 18l-4 1 1-4Z"></path>',
enter: '<path d="M7 8 3 12l4 4"></path><path d="M3 12h12a4 4 0 0 0 4-4V5"></path>', enter: '<path d="M7 8 3 12l4 4"></path><path d="M3 12h12a4 4 0 0 0 4-4V5"></path>',
file: '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"></path><path d="M14 2v6h6"></path>', file: '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"></path><path d="M14 2v6h6"></path>',
folder: '<path d="M3 7a2 2 0 0 1 2-2h5l2 2h7a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"></path>', folder: '<path d="M3 7a2 2 0 0 1 2-2h5l2 2h7a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"></path>',
@@ -59,9 +62,13 @@ const uiIcons = {
grid: '<rect x="4" y="4" width="6" height="6" rx="1"></rect><rect x="14" y="4" width="6" height="6" rx="1"></rect><rect x="4" y="14" width="6" height="6" rx="1"></rect><rect x="14" y="14" width="6" height="6" rx="1"></rect>', grid: '<rect x="4" y="4" width="6" height="6" rx="1"></rect><rect x="14" y="4" width="6" height="6" rx="1"></rect><rect x="4" y="14" width="6" height="6" rx="1"></rect><rect x="14" y="14" width="6" height="6" rx="1"></rect>',
list: '<path d="M9 6h11"></path><path d="M9 12h11"></path><path d="M9 18h11"></path><path d="M4 6h.01"></path><path d="M4 12h.01"></path><path d="M4 18h.01"></path>', list: '<path d="M9 6h11"></path><path d="M9 12h11"></path><path d="M9 18h11"></path><path d="M4 6h.01"></path><path d="M4 12h.01"></path><path d="M4 18h.01"></path>',
link: '<path d="M10 13a5 5 0 0 0 7.5.5l2-2a5 5 0 0 0-7-7l-1.1 1.1"></path><path d="M14 11a5 5 0 0 0-7.5-.5l-2 2a5 5 0 0 0 7 7l1.1-1.1"></path>', link: '<path d="M10 13a5 5 0 0 0 7.5.5l2-2a5 5 0 0 0-7-7l-1.1 1.1"></path><path d="M14 11a5 5 0 0 0-7.5-.5l-2 2a5 5 0 0 0 7 7l1.1-1.1"></path>',
info: '<circle cx="12" cy="12" r="9"></circle><path d="M12 11v5"></path><path d="M12 8h.01"></path>',
maximize: '<rect x="5" y="5" width="14" height="14" rx="2"></rect>', maximize: '<rect x="5" y="5" width="14" height="14" rx="2"></rect>',
minimize: '<path d="M8 4h12v12"></path><path d="M4 8h12v12H4Z"></path>', minimize: '<path d="M8 4h12v12"></path><path d="M4 8h12v12H4Z"></path>',
move: '<path d="M5 12h14"></path><path d="m14 7 5 5-5 5"></path><path d="M5 7v10"></path>',
preview: '<path d="M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6S2 12 2 12Z"></path><circle cx="12" cy="12" r="2.5"></circle>',
refresh: '<path d="M20 6v5h-5"></path><path d="M4 18v-5h5"></path><path d="M19 11a7 7 0 0 0-12-4.9L4 9"></path><path d="M5 13a7 7 0 0 0 12 4.9l3-2.9"></path>', refresh: '<path d="M20 6v5h-5"></path><path d="M4 18v-5h5"></path><path d="M19 11a7 7 0 0 0-12-4.9L4 9"></path><path d="M5 13a7 7 0 0 0 12 4.9l3-2.9"></path>',
shield: '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10Z"></path><path d="m9 12 2 2 4-4"></path>',
tree: '<path d="M4 5h6"></path><path d="M4 12h10"></path><path d="M4 19h14"></path><path d="M4 5v14"></path><circle cx="4" cy="5" r="1.5"></circle><circle cx="4" cy="12" r="1.5"></circle><circle cx="4" cy="19" r="1.5"></circle>', tree: '<path d="M4 5h6"></path><path d="M4 12h10"></path><path d="M4 19h14"></path><path d="M4 5v14"></path><circle cx="4" cy="5" r="1.5"></circle><circle cx="4" cy="12" r="1.5"></circle><circle cx="4" cy="19" r="1.5"></circle>',
upload: '<path d="M12 16V5"></path><path d="m8 9 4-4 4 4"></path><path d="M5 16v3h14v-3"></path>' upload: '<path d="M12 16V5"></path><path d="m8 9 4-4 4 4"></path><path d="M5 16v3h14v-3"></path>'
}; };
@@ -1995,33 +2002,40 @@ function renderContextMenu() {
if (entry) { if (entry) {
if (entry.type === 'directory') { if (entry.type === 'directory') {
actions.push(['Öffnen', () => loadExplorer(win, entry.path)]); actions.push({ label: 'Öffnen', icon: 'folder', action: () => loadExplorer(win, entry.path) });
} else if (isPreviewable(entry)) { } else if (isPreviewable(entry)) {
actions.push(['Vorschau', () => openPreview(entry, win.id)]); actions.push({ label: 'Vorschau', icon: 'preview', action: () => openPreview(entry, win.id) });
} }
actions.push(['Eigenschaften', () => showPropertiesForEntry(win, entry)]); actions.push({ label: 'Eigenschaften', icon: 'info', action: () => showPropertiesForEntry(win, entry) });
actions.push(['Herunterladen', () => downloadEntries(win, entry)]); actions.push({ label: 'Herunterladen', icon: 'download', action: () => downloadEntries(win, entry) });
if (!isReadOnly()) { if (!isReadOnly()) {
actions.push(['Umbenennen', () => renameEntry(win, entry)]); actions.push({ label: 'Umbenennen', icon: 'edit', separator: true, action: () => renameEntry(win, entry) });
actions.push(['Berechtigungen...', () => openPermissionsDialog(win, entry)]); actions.push({ label: 'Berechtigungen…', icon: 'shield', action: () => openPermissionsDialog(win, entry) });
actions.push(['Kopieren nach...', () => promptTransfer(win, entry, 'copy')]); actions.push({ label: 'Kopieren nach…', icon: 'copy', action: () => promptTransfer(win, entry, 'copy') });
actions.push(['Verschieben nach...', () => promptTransfer(win, entry, 'move')]); actions.push({ label: 'Verschieben nach…', icon: 'move', action: () => promptTransfer(win, entry, 'move') });
actions.push(['Löschen', () => deleteEntries(win, entry)]); actions.push({ label: 'Löschen', icon: 'delete', danger: true, separator: true, action: () => deleteEntries(win, entry) });
} }
} else { } else {
actions.push(['Aktuellen Ordner herunterladen', () => downloadEntries(win, null)]); actions.push({ label: 'Aktuellen Ordner herunterladen', icon: 'download', action: () => downloadEntries(win, null) });
actions.push(['Neu laden', () => loadExplorer(win, win.data.path)]); actions.push({ label: 'Neu laden', icon: 'refresh', action: () => loadExplorer(win, win.data.path) });
} }
for (const [label, action] of actions) { for (const item of actions) {
if (item.separator) {
const separator = document.createElement('div');
separator.className = 'context-separator';
separator.setAttribute('role', 'separator');
menu.appendChild(separator);
}
const button = document.createElement('button'); const button = document.createElement('button');
button.type = 'button'; button.type = 'button';
button.textContent = label; button.className = `context-action ${item.danger ? 'danger' : ''}`;
button.innerHTML = `<span class="context-icon">${iconSvg(item.icon)}</span><span>${escapeHtml(item.label)}</span>`;
button.addEventListener('click', async () => { button.addEventListener('click', async () => {
state.contextMenu = null; state.contextMenu = null;
render(); render();
try { try {
await action(); await item.action();
} catch (error) { } catch (error) {
showError(error); showError(error);
} }
+47 -10
View File
@@ -792,25 +792,62 @@
.u-nav .context-menu { .u-nav .context-menu {
background: var(--surface); background: var(--surface);
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: 8px; border-radius: 10px;
box-shadow: var(--shadow); box-shadow: var(--shadow);
display: grid; display: grid;
min-width: 170px; min-width: 205px;
padding: 5px; padding: 4px;
position: absolute; position: absolute;
z-index: 100000; z-index: 100000;
} }
.u-nav .context-menu button { .u-nav .context-menu .context-action {
border-color: transparent; align-items: center;
justify-content: flex-start; background: transparent;
text-align: left; border: 0;
border-radius: 7px;
box-shadow: none;
display: grid;
font: 500 12px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
gap: 7px;
grid-template-columns: 18px minmax(0, 1fr);
justify-content: stretch !important;
letter-spacing: normal !important;
margin: 0 !important;
min-height: 30px;
padding: 0 8px !important;
text-align: left !important;
text-transform: none !important;
white-space: nowrap;
width: 100%; width: 100%;
} }
.u-nav .context-menu button:hover { .u-nav .context-menu .context-action:hover,
background: var(--surface-2); .u-nav .context-menu .context-action:focus-visible {
border-color: var(--line); background: var(--accent-soft);
color: var(--accent);
}
.u-nav .context-menu .context-action.danger {
color: #c4382d;
}
.u-nav .context-icon {
align-items: center;
display: inline-flex;
justify-content: center;
}
.u-nav .context-icon .unav-icon {
height: 15px;
stroke-width: 1.9;
width: 15px;
}
.u-nav .context-separator {
border-top: 1px solid var(--line);
height: 1px;
margin: 4px 5px;
} }
.u-nav .modal-overlay { .u-nav .modal-overlay {
+2 -2
View File
@@ -1,7 +1,7 @@
<!DOCTYPE PLUGIN [ <!DOCTYPE PLUGIN [
<!ENTITY name "u-navigator"> <!ENTITY name "u-navigator">
<!ENTITY author "Michael Roll"> <!ENTITY author "Michael Roll">
<!ENTITY version "2026.07.14.r015"> <!ENTITY version "2026.07.14.r016">
<!ENTITY package "&name;-&version;.tgz"> <!ENTITY package "&name;-&version;.tgz">
<!ENTITY pluginURL "https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg"> <!ENTITY pluginURL "https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg">
<!ENTITY support "https://git.casaderoll.de/michael/Unraid-Navigator"> <!ENTITY support "https://git.casaderoll.de/michael/Unraid-Navigator">
@@ -24,7 +24,7 @@
<FILE Name="/boot/config/plugins/&name;/&package;"> <FILE Name="/boot/config/plugins/&name;/&package;">
<URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL> <URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL>
<MD5>e7bd64a4dda7a5915d9ef73657dec517</MD5> <MD5>8c943cbf6a929bfb8e3249c901fb3869</MD5>
</FILE> </FILE>
<FILE Run="/bin/bash"> <FILE Run="/bin/bash">