Add explorer icon view
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
PLUGIN="u-navigator"
|
PLUGIN="u-navigator"
|
||||||
VERSION="2026.06.23.r009"
|
VERSION="2026.06.23.r010"
|
||||||
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.
Binary file not shown.
+29
-2
@@ -73,6 +73,7 @@ function openExplorer(initialPath = state.config?.roots?.[0]?.path) {
|
|||||||
path: initialPath,
|
path: initialPath,
|
||||||
entries: [],
|
entries: [],
|
||||||
selectedPath: null,
|
selectedPath: null,
|
||||||
|
view: 'list',
|
||||||
loading: false,
|
loading: false,
|
||||||
error: null
|
error: null
|
||||||
}
|
}
|
||||||
@@ -202,10 +203,14 @@ function renderExplorer(body, win) {
|
|||||||
<input value="${escapeAttr(data.path || '')}" aria-label="Pfad">
|
<input value="${escapeAttr(data.path || '')}" aria-label="Pfad">
|
||||||
<button data-action="go">Öffnen</button>
|
<button data-action="go">Öffnen</button>
|
||||||
<button data-action="refresh">Neu laden</button>
|
<button data-action="refresh">Neu laden</button>
|
||||||
|
<div class="view-toggle" aria-label="Ansicht">
|
||||||
|
<button class="${data.view !== 'icons' ? 'active' : ''}" data-action="view-list" title="Listenansicht">Liste</button>
|
||||||
|
<button class="${data.view === 'icons' ? 'active' : ''}" data-action="view-icons" title="Symbolansicht">Symbole</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="drop-zone ${data.dragOver ? 'drag-over' : ''}">
|
<div class="drop-zone ${data.dragOver ? 'drag-over' : ''}">
|
||||||
${data.error ? `<p class="muted">${escapeHtml(data.error)}</p>` : ''}
|
${data.error ? `<p class="muted">${escapeHtml(data.error)}</p>` : ''}
|
||||||
${data.loading ? '<p class="muted">Lade...</p>' : renderFileTable(data.entries || [])}
|
${data.loading ? '<p class="muted">Lade...</p>' : renderFileEntries(data.entries || [], data.view || 'list')}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -213,6 +218,8 @@ function renderExplorer(body, win) {
|
|||||||
body.querySelector('[data-action="go"]').addEventListener('click', () => loadExplorer(win, input.value));
|
body.querySelector('[data-action="go"]').addEventListener('click', () => loadExplorer(win, input.value));
|
||||||
body.querySelector('[data-action="refresh"]').addEventListener('click', () => loadExplorer(win, data.path));
|
body.querySelector('[data-action="refresh"]').addEventListener('click', () => loadExplorer(win, data.path));
|
||||||
body.querySelector('[data-action="up"]').addEventListener('click', () => loadExplorer(win, parentPath(data.path)));
|
body.querySelector('[data-action="up"]').addEventListener('click', () => loadExplorer(win, parentPath(data.path)));
|
||||||
|
body.querySelector('[data-action="view-list"]').addEventListener('click', () => setExplorerView(win, 'list'));
|
||||||
|
body.querySelector('[data-action="view-icons"]').addEventListener('click', () => setExplorerView(win, 'icons'));
|
||||||
|
|
||||||
const dropZone = body.querySelector('.drop-zone');
|
const dropZone = body.querySelector('.drop-zone');
|
||||||
dropZone.addEventListener('dragenter', (event) => {
|
dropZone.addEventListener('dragenter', (event) => {
|
||||||
@@ -273,11 +280,14 @@ function renderExplorer(body, win) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFileTable(entries) {
|
function renderFileEntries(entries, view) {
|
||||||
if (!entries.length) {
|
if (!entries.length) {
|
||||||
return '<p class="muted">Dieser Ordner ist leer. Dateien können hier abgelegt werden.</p>';
|
return '<p class="muted">Dieser Ordner ist leer. Dateien können hier abgelegt werden.</p>';
|
||||||
}
|
}
|
||||||
|
return view === 'icons' ? renderFileIcons(entries) : renderFileTable(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFileTable(entries) {
|
||||||
const rows = entries.map((entry) => `
|
const rows = entries.map((entry) => `
|
||||||
<tr class="file-row ${entry.path === state.selectedEntry?.path ? 'selected' : ''}" data-path="${escapeAttr(entry.path)}" data-type="${escapeAttr(entry.type)}">
|
<tr class="file-row ${entry.path === state.selectedEntry?.path ? 'selected' : ''}" data-path="${escapeAttr(entry.path)}" data-type="${escapeAttr(entry.type)}">
|
||||||
<td><span class="name-cell"><span class="badge">${icons[entry.type] || 'Item'}</span>${escapeHtml(entry.name)}</span></td>
|
<td><span class="name-cell"><span class="badge">${icons[entry.type] || 'Item'}</span>${escapeHtml(entry.name)}</span></td>
|
||||||
@@ -295,6 +305,23 @@ function renderFileTable(entries) {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderFileIcons(entries) {
|
||||||
|
const items = entries.map((entry) => `
|
||||||
|
<button type="button" class="file-row icon-item ${entry.path === state.selectedEntry?.path ? 'selected' : ''}" data-path="${escapeAttr(entry.path)}" data-type="${escapeAttr(entry.type)}">
|
||||||
|
<span class="file-icon ${escapeAttr(entry.type)}">${icons[entry.type] || 'Item'}</span>
|
||||||
|
<span class="icon-name">${escapeHtml(entry.name)}</span>
|
||||||
|
<span class="icon-meta">${entry.type === 'file' ? formatBytes(entry.size) : entry.type}</span>
|
||||||
|
</button>
|
||||||
|
`).join('');
|
||||||
|
|
||||||
|
return `<div class="icon-grid">${items}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setExplorerView(win, view) {
|
||||||
|
win.data.view = view;
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
function renderProperties(body) {
|
function renderProperties(body) {
|
||||||
const entry = state.selectedEntry;
|
const entry = state.selectedEntry;
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
|
|||||||
@@ -169,7 +169,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
grid-template-columns: auto 1fr auto auto;
|
grid-template-columns: auto 1fr auto auto auto;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,6 +197,30 @@
|
|||||||
box-shadow: inset 0 0 0 2px var(--accent);
|
box-shadow: inset 0 0 0 2px var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.u-nav .view-toggle {
|
||||||
|
display: inline-flex;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .view-toggle button {
|
||||||
|
border-radius: 0;
|
||||||
|
min-width: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .view-toggle button:first-child {
|
||||||
|
border-radius: 6px 0 0 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .view-toggle button:last-child {
|
||||||
|
border-left: 0;
|
||||||
|
border-radius: 0 6px 6px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .view-toggle button.active {
|
||||||
|
background: var(--surface-2);
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
.u-nav .file-table {
|
.u-nav .file-table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
@@ -277,6 +301,80 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.u-nav .icon-grid {
|
||||||
|
display: grid;
|
||||||
|
gap: 10px;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .icon-item {
|
||||||
|
align-items: center;
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--text);
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
grid-template-rows: auto minmax(32px, auto) auto;
|
||||||
|
justify-items: center;
|
||||||
|
min-height: 126px;
|
||||||
|
padding: 10px 8px;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .icon-item:hover,
|
||||||
|
.u-nav .icon-item.selected,
|
||||||
|
.u-nav .icon-item.dragging,
|
||||||
|
.u-nav .icon-item.drop-target {
|
||||||
|
background: var(--surface-2);
|
||||||
|
border-color: var(--line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .icon-item.selected,
|
||||||
|
.u-nav .icon-item.drop-target {
|
||||||
|
border-color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .file-icon {
|
||||||
|
align-items: center;
|
||||||
|
background: var(--surface-2);
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: var(--muted);
|
||||||
|
display: inline-flex;
|
||||||
|
font-size: 12px;
|
||||||
|
height: 48px;
|
||||||
|
justify-content: center;
|
||||||
|
width: 58px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .file-icon.directory {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .file-icon.file {
|
||||||
|
color: var(--accent-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .icon-name {
|
||||||
|
color: var(--text);
|
||||||
|
display: -webkit-box;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.25;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-nav .icon-meta {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
.u-nav .context-menu {
|
.u-nav .context-menu {
|
||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE PLUGIN [
|
<!DOCTYPE PLUGIN [
|
||||||
<!ENTITY name "u-navigator">
|
<!ENTITY name "u-navigator">
|
||||||
<!ENTITY author "michael">
|
<!ENTITY author "michael">
|
||||||
<!ENTITY version "2026.06.23.r009">
|
<!ENTITY version "2026.06.23.r010">
|
||||||
<!ENTITY package "&name;-&version;.tgz">
|
<!ENTITY package "&name;-&version;.tgz">
|
||||||
]>
|
]>
|
||||||
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg">
|
<PLUGIN name="&name;" author="&author;" version="&version;" pluginURL="https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/u-navigator.plg">
|
||||||
@@ -14,7 +14,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>1388b0f68a4cc0ddfaacc4e6f2402ea7</MD5>
|
<MD5>0189ab9d23d2027dfc4c8dc6ebb2ee68</MD5>
|
||||||
</FILE>
|
</FILE>
|
||||||
|
|
||||||
<FILE Run="/bin/bash">
|
<FILE Run="/bin/bash">
|
||||||
|
|||||||
Reference in New Issue
Block a user