feat: contextmenu deel 1

This commit is contained in:
kodi
2026-03-14 09:22:24 +01:00
parent 3987de27e0
commit 0615324607
5 changed files with 114 additions and 4 deletions
Binary file not shown.
@@ -274,7 +274,10 @@ class UiSmokeGoldenTest(unittest.TestCase):
self.assertIn("function mediaIconSvg(type)", app_js)
self.assertIn('const iconType = iconTypeForEntry(entry);', app_js)
self.assertIn('function createMediaSlot(entry)', app_js)
self.assertNotIn("select-marker", app_js)
self.assertIn('function createSelectionSlot(pane, entry, index)', app_js)
self.assertIn('entry-select-slot', app_js)
self.assertIn('entry-select-toggle', app_js)
self.assertIn('toggleSelectionAtIndex(pane, selectedEntryFromItem(entry), index);', app_js)
self.assertIn('function openSearch()', app_js)
self.assertIn('async function submitSearch()', app_js)
self.assertIn('async function openInfo()', app_js)
+44 -3
View File
@@ -1237,6 +1237,45 @@ function createMediaSlot(entry) {
return slot;
}
function createSelectionSlot(pane, entry, index) {
const slot = document.createElement("span");
slot.className = "entry-select-slot";
if (entry.isParent) {
const placeholder = document.createElement("span");
placeholder.className = "entry-select-toggle is-disabled";
placeholder.setAttribute("aria-hidden", "true");
const indicator = document.createElement("span");
indicator.className = "entry-select-indicator";
placeholder.append(indicator);
slot.append(placeholder);
return slot;
}
const button = document.createElement("button");
button.type = "button";
button.className = "entry-select-toggle";
const selected = selectedPaths(pane).includes(entry.path);
if (selected) {
button.classList.add("is-selected");
}
button.setAttribute("aria-label", `${selected ? "Deselect" : "Select"} ${entry.name}`);
button.setAttribute("aria-pressed", selected ? "true" : "false");
const indicator = document.createElement("span");
indicator.className = "entry-select-indicator";
button.append(indicator);
button.onclick = (event) => {
event.preventDefault();
event.stopPropagation();
setActivePane(pane);
paneState(pane).currentRowIndex = index;
toggleSelectionAtIndex(pane, selectedEntryFromItem(entry), index);
renderPaneItems(pane);
};
slot.append(button);
return slot;
}
async function loadSettings() {
const data = await apiRequest("GET", "/api/settings");
settingsState.showThumbnails = !!data.show_thumbnails;
@@ -1546,7 +1585,7 @@ function formatFileSize(bytes) {
return `${(bytes / (1024 ** 4)).toFixed(1)} TB`;
}
function createBrowseItem(pane, entry, kind) {
function createBrowseItem(pane, entry, kind, index) {
const li = document.createElement("li");
li.className = "selectable";
li.dataset.path = entry.path;
@@ -1567,6 +1606,7 @@ function createBrowseItem(pane, entry, kind) {
const name = document.createElement("span");
name.className = `entry-name ${kind === "directory" ? "entry-dir" : "entry-file"}`;
name.append(createSelectionSlot(pane, { ...entry, kind }, index));
name.append(createMediaSlot({ ...entry, kind }));
if (kind === "directory") {
@@ -1680,6 +1720,7 @@ function renderPaneItems(pane) {
};
const upNameCell = document.createElement("span");
upNameCell.className = "entry-name entry-dir";
upNameCell.append(createSelectionSlot(pane, { ...entry, isParent: true }, index));
upNameCell.append(createMediaSlot({ name: "..", path: entry.path, kind: "directory" }));
const upName = document.createElement("button");
upName.type = "button";
@@ -1705,7 +1746,7 @@ function renderPaneItems(pane) {
return;
}
const row = createBrowseItem(pane, entry, entry.kind);
const row = createBrowseItem(pane, entry, entry.kind, index);
row.dataset.rowIndex = String(index);
if (index === model.currentRowIndex) {
row.classList.add("is-current-row");
@@ -1724,7 +1765,7 @@ function renderPaneItems(pane) {
navigateTo(pane, entry.path);
};
}
const fileName = row.querySelector(".entry-file span");
const fileName = row.querySelector(".entry-file .entry-label");
if (fileName) {
fileName.onclick = (ev) => {
ev.stopPropagation();
+66
View File
@@ -346,6 +346,72 @@ button:disabled {
min-width: 0;
}
.entry-select-slot {
width: 18px;
min-width: 18px;
height: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.entry-select-toggle {
width: 18px;
min-width: 18px;
height: 18px;
padding: 0;
border: none;
border-radius: 999px;
background: transparent;
display: inline-flex;
align-items: center;
justify-content: center;
box-shadow: none;
}
.entry-select-toggle:hover {
background: transparent;
border-color: transparent;
box-shadow: none;
}
.entry-select-toggle.is-disabled {
pointer-events: none;
}
.entry-select-indicator {
width: 16px;
height: 16px;
border-radius: 999px;
border: 1.5px solid color-mix(in srgb, var(--color-text-muted) 80%, transparent);
opacity: 0;
transition: opacity 100ms ease, border-color 100ms ease, background 100ms ease;
position: relative;
}
.list li:hover .entry-select-indicator,
.entry-select-toggle:focus-visible .entry-select-indicator,
.entry-select-toggle.is-selected .entry-select-indicator {
opacity: 1;
}
.entry-select-toggle.is-selected .entry-select-indicator {
border-color: var(--color-accent);
background: var(--color-accent);
}
.entry-select-toggle.is-selected .entry-select-indicator::after {
content: "✓";
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
line-height: 1;
color: var(--color-surface);
}
.entry-media-slot {
width: 28px;
min-width: 28px;