Use SVG icons for UI buttons

This commit is contained in:
Mikei386
2026-07-04 10:24:43 +02:00
parent 4e05ef3a8b
commit 4843f7412e
6 changed files with 50 additions and 19 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
set -eu
PLUGIN="u-navigator"
VERSION="2026.07.04.r003"
VERSION="2026.07.04.r004"
PKG_DIR="packages"
WORK_DIR=".plugin-build"
PKG_NAME="${PLUGIN}-${VERSION}.tgz"
Binary file not shown.
Binary file not shown.
+35 -16
View File
@@ -44,6 +44,20 @@ const icons = {
symlink: 'Link',
other: 'Item'
};
const uiIcons = {
arrowLeft: '<path d="M19 12H5"></path><path d="m12 19-7-7 7-7"></path>',
arrowRight: '<path d="M5 12h14"></path><path d="m12 5 7 7-7 7"></path>',
close: '<path d="M18 6 6 18"></path><path d="m6 6 12 12"></path>',
delete: '<path d="M3 6h18"></path><path d="M8 6V4h8v2"></path><path d="M19 6l-1 14H6L5 6"></path><path d="M10 11v5"></path><path d="M14 11v5"></path>',
enter: '<path d="M9 18 3 12l6-6"></path><path d="M3 12h13a4 4 0 0 0 4-4V5"></path>',
folderUpload: '<path d="M3 7h7l2 2h9v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"></path><path d="M12 17V11"></path><path d="m9 14 3-3 3 3"></path>',
grid: '<rect x="4" y="4" width="6" height="6"></rect><rect x="14" y="4" width="6" height="6"></rect><rect x="4" y="14" width="6" height="6"></rect><rect x="14" y="14" width="6" height="6"></rect>',
list: '<path d="M8 6h13"></path><path d="M8 12h13"></path><path d="M8 18h13"></path><path d="M3 6h.01"></path><path d="M3 12h.01"></path><path d="M3 18h.01"></path>',
maximize: '<path d="M8 3H3v5"></path><path d="M16 3h5v5"></path><path d="M21 16v5h-5"></path><path d="M3 16v5h5"></path>',
minimize: '<path d="M8 3v5H3"></path><path d="M16 3v5h5"></path><path d="M21 16h-5v5"></path><path d="M3 16h5v5"></path>',
refresh: '<path d="M21 12a9 9 0 0 1-15 6.7"></path><path d="M3 12a9 9 0 0 1 15-6.7"></path><path d="M18 3v5h-5"></path><path d="M6 21v-5h5"></path>',
upload: '<path d="M12 15V3"></path><path d="m7 8 5-5 5 5"></path><path d="M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"></path>'
};
const previewExtensions = new Set(['txt', 'log', 'md', 'rd', 'rst', 'yaml', 'yml', 'json', 'xml', 'csv', 'tsv', 'ini', 'cfg', 'conf', 'env', 'toml', 'sql', 'nfo', 'srt', 'sub', 'vtt', 'm3u', 'm3u8', 'pls', 'sh', 'bash', 'zsh', 'php', 'js', 'ts', 'tsx', 'jsx', 'css', 'html', 'py', 'go', 'rs', 'java', 'c', 'cpp', 'h', 'hpp', 'bat', 'ps1', 'properties', 'service', 'timer', 'mount', 'rules', 'cron', 'plg', 'page', 'jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'pdf', 'mp3', 'flac', 'm4a', 'ogg', 'wav', 'mp4', 'mkv', 'webm', 'mov']);
const previewFilenames = new Set(['dockerfile', 'makefile']);
@@ -221,8 +235,8 @@ function renderWindow(win) {
titlebar.innerHTML = `
<strong>${escapeHtml(windowTitle(win))}</strong>
<div class="window-actions">
<button class="icon" data-action="maximize" title="Maximieren">${win.maximized ? '' : '□'}</button>
<button class="icon" data-action="close" title="Schließen">×</button>
<button class="icon" data-action="maximize" title="Maximieren">${iconSvg(win.maximized ? 'minimize' : 'maximize')}</button>
<button class="icon" data-action="close" title="Schließen">${iconSvg('close')}</button>
</div>
`;
titlebar.addEventListener('pointerdown', (event) => startDragWindow(event, win));
@@ -272,18 +286,18 @@ function renderExplorer(body, win) {
const data = win.data;
body.innerHTML = `
<div class="pathbar">
<button class="icon up-button" data-action="up" title="Eine Ebene zurueck" aria-label="Eine Ebene zurueck"></button>
<button class="icon up-button" data-action="up" title="Eine Ebene zurueck" aria-label="Eine Ebene zurueck">${iconSvg('arrowLeft')}</button>
<input value="${escapeAttr(data.path || '')}" aria-label="Pfad">
<button class="icon" data-action="go" title="Öffnen" aria-label="Öffnen"></button>
<button class="icon" data-action="refresh" title="Neu laden" aria-label="Neu laden"></button>
<button class="icon" data-action="upload-files" title="Dateien hochladen" aria-label="Dateien hochladen" ${isReadOnly() ? 'disabled' : ''}></button>
<button class="icon" data-action="upload-folder" title="Ordner hochladen" aria-label="Ordner hochladen" ${isReadOnly() ? 'disabled' : ''}></button>
<button class="icon danger" data-action="delete-selected" title="Auswahl löschen" aria-label="Auswahl löschen" ${isReadOnly() ? 'disabled' : ''}>×</button>
<button class="icon" data-action="go" title="Öffnen" aria-label="Öffnen">${iconSvg('enter')}</button>
<button class="icon" data-action="refresh" title="Neu laden" aria-label="Neu laden">${iconSvg('refresh')}</button>
<button class="icon" data-action="upload-files" title="Dateien hochladen" aria-label="Dateien hochladen" ${isReadOnly() ? 'disabled' : ''}>${iconSvg('upload')}</button>
<button class="icon" data-action="upload-folder" title="Ordner hochladen" aria-label="Ordner hochladen" ${isReadOnly() ? 'disabled' : ''}>${iconSvg('folderUpload')}</button>
<button class="icon danger" data-action="delete-selected" title="Auswahl löschen" aria-label="Auswahl löschen" ${isReadOnly() ? 'disabled' : ''}>${iconSvg('delete')}</button>
<input class="upload-input" data-upload="files" type="file" multiple>
<input class="upload-input" data-upload="folder" type="file" multiple webkitdirectory directory>
<div class="view-toggle" aria-label="Ansicht">
<button class="icon ${data.view !== 'icons' ? 'active' : ''}" data-action="view-list" title="Listenansicht" aria-label="Listenansicht"></button>
<button class="icon ${data.view === 'icons' ? 'active' : ''}" data-action="view-icons" title="Symbolansicht" aria-label="Symbolansicht"></button>
<button class="icon ${data.view !== 'icons' ? 'active' : ''}" data-action="view-list" title="Listenansicht" aria-label="Listenansicht">${iconSvg('list')}</button>
<button class="icon ${data.view === 'icons' ? 'active' : ''}" data-action="view-icons" title="Symbolansicht" aria-label="Symbolansicht">${iconSvg('grid')}</button>
</div>
</div>
<div class="drop-zone ${data.dragOver ? 'drag-over' : ''}">
@@ -468,8 +482,8 @@ function renderPreview(body, win) {
body.innerHTML = `
<div class="preview-meta">
<div class="preview-nav">
<button class="icon" data-action="preview-prev" title="Vorherige Datei" aria-label="Vorherige Datei" ${navigation.previous ? '' : 'disabled'}></button>
<button class="icon" data-action="preview-next" title="Nächste Datei" aria-label="Nächste Datei" ${navigation.next ? '' : 'disabled'}></button>
<button class="icon" data-action="preview-prev" title="Vorherige Datei" aria-label="Vorherige Datei" ${navigation.previous ? '' : 'disabled'}>${iconSvg('arrowLeft')}</button>
<button class="icon" data-action="preview-next" title="Nächste Datei" aria-label="Nächste Datei" ${navigation.next ? '' : 'disabled'}>${iconSvg('arrowRight')}</button>
</div>
<strong>${escapeHtml(entry?.name || data.name || 'Vorschau')}</strong>
<span>${escapeHtml(formatBytes(data.size || entry?.size || 0))}</span>
@@ -773,7 +787,7 @@ function renderTransferPanel() {
panel.innerHTML = `
<header class="transfer-panel-header">
<strong>Transfers</strong>
<button type="button" class="icon" data-action="close-transfers" title="Schließen">×</button>
<button type="button" class="icon" data-action="close-transfers" title="Schließen">${iconSvg('close')}</button>
</header>
<div class="transfer-panel-body">${queueMarkup()}</div>
`;
@@ -815,7 +829,7 @@ function renderSettingsPanel() {
panel.innerHTML = `
<header class="settings-panel-header">
<strong>Einstellungen</strong>
<button type="button" class="icon" data-action="close-settings" title="Schließen">×</button>
<button type="button" class="icon" data-action="close-settings" title="Schließen">${iconSvg('close')}</button>
</header>
<div class="settings-panel-body">
<label class="setting-row">
@@ -1403,7 +1417,7 @@ function renderPermissionsDialog() {
<form class="permissions-modal" aria-label="Berechtigungen ändern">
<header>
<strong>Berechtigungen ändern</strong>
<button type="button" class="icon" data-action="cancel" title="Schließen" aria-label="Schließen">×</button>
<button type="button" class="icon" data-action="cancel" title="Schließen" aria-label="Schließen">${iconSvg('close')}</button>
</header>
<div class="modal-body">
<p class="muted">${dialog.entries.length === 1 ? escapeHtml(dialog.entries[0].name) : `${dialog.entries.length} Objekte ausgewählt`}</p>
@@ -1476,7 +1490,7 @@ function renderUploadConflictDialog() {
<form class="permissions-modal conflict-modal" aria-label="Datei existiert bereits">
<header>
<strong>Datei existiert bereits</strong>
<button type="button" class="icon" data-action="skip" title="Überspringen" aria-label="Überspringen">×</button>
<button type="button" class="icon" data-action="skip" title="Überspringen" aria-label="Überspringen">${iconSvg('close')}</button>
</header>
<div class="modal-body">
<p>Im Zielordner existiert bereits eine Datei mit diesem Namen.</p>
@@ -2368,6 +2382,11 @@ function formatPrincipal(name, id) {
return `${name} (${id})`;
}
function iconSvg(name) {
const paths = uiIcons[name] || uiIcons.close;
return `<svg class="ui-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">${paths}</svg>`;
}
function escapeHtml(value) {
return String(value ?? '').replace(/[&<>"']/g, (char) => ({
'&': '&amp;',
+12
View File
@@ -75,6 +75,18 @@
width: 22px;
}
.u-nav .ui-icon {
display: block;
fill: none;
height: 15px;
pointer-events: none;
stroke: currentColor;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 2;
width: 15px;
}
.u-nav .topbar {
align-items: center;
background: var(--surface);
+2 -2
View File
@@ -1,7 +1,7 @@
<!DOCTYPE PLUGIN [
<!ENTITY name "u-navigator">
<!ENTITY author "Michael Roll">
<!ENTITY version "2026.07.04.r003">
<!ENTITY version "2026.07.04.r004">
<!ENTITY package "&name;-&version;.tgz">
<!ENTITY pluginURL "https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg">
<!ENTITY support "https://git.casaderoll.de/michael/Unraid-Navigator">
@@ -24,7 +24,7 @@
<FILE Name="/boot/config/plugins/&name;/&package;">
<URL>https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package;</URL>
<MD5>ee518cf2d919b9f7abfdf363109e3bff</MD5>
<MD5>aa0e96d68378a77f2a6d08b6cd41bf74</MD5>
</FILE>
<FILE Run="/bin/bash">