Move library browsing to main grid

This commit is contained in:
Dymas
2026-09-15 15:37:43 +02:00
parent a2b26f6680
commit 9f39478018
7 changed files with 158 additions and 45 deletions
+49 -25
View File
@@ -1,17 +1,18 @@
const state = {
titles: [],
activeId: "",
query: ""
query: "",
view: "collection"
};
const els = {
libraryBadge: document.querySelector("#libraryBadge"),
libraryPath: document.querySelector("#libraryPath"),
backBtn: document.querySelector("#backBtn"),
rescanBtn: document.querySelector("#rescanBtn"),
searchInput: document.querySelector("#searchInput"),
titleList: document.querySelector("#titleList"),
details: document.querySelector("#details"),
titleButtonTemplate: document.querySelector("#titleButtonTemplate")
titleCardTemplate: document.querySelector("#titleCardTemplate")
};
function bytes(value) {
@@ -40,9 +41,9 @@ async function loadLibrary() {
state.titles = data.titles;
els.libraryPath.textContent = data.libraryDir;
els.libraryBadge.textContent = `${state.titles.length} title${state.titles.length === 1 ? "" : "s"}`;
if (!state.activeId && state.titles.length) state.activeId = state.titles[0].id;
if (!state.titles.some((title) => title.id === state.activeId)) {
state.activeId = state.titles[0]?.id || "";
state.activeId = "";
state.view = "collection";
}
render();
}
@@ -61,28 +62,18 @@ function filteredTitles() {
}
function render() {
renderTitleList();
renderDetails();
}
function renderTitleList() {
els.titleList.innerHTML = "";
for (const title of filteredTitles()) {
const node = els.titleButtonTemplate.content.firstElementChild.cloneNode(true);
node.classList.toggle("is-active", title.id === state.activeId);
node.querySelector(".title-button__name").textContent = title.title;
node.querySelector(".title-button__meta").textContent = `${title.count} file${title.count === 1 ? "" : "s"} · ${bytes(title.size)}`;
node.addEventListener("click", () => {
state.activeId = title.id;
render();
});
els.titleList.append(node);
const activeTitle = state.titles.find((item) => item.id === state.activeId);
els.backBtn.classList.toggle("hidden", state.view !== "details");
if (state.view === "details" && activeTitle) {
renderDetails(activeTitle);
return;
}
renderCollection();
}
function renderDetails() {
const title = state.titles.find((item) => item.id === state.activeId);
if (!title) {
function renderCollection() {
const titles = filteredTitles();
if (!titles.length) {
els.details.innerHTML = `
<div class="empty">
<h2>No titles found</h2>
@@ -92,6 +83,33 @@ function renderDetails() {
return;
}
els.details.innerHTML = `
<div class="collection-grid" id="collectionGrid"></div>
`;
const grid = document.querySelector("#collectionGrid");
for (const title of titles) {
const node = els.titleCardTemplate.content.firstElementChild.cloneNode(true);
node.querySelector(".title-card__name").textContent = title.title;
node.querySelector(".title-card__meta").textContent = `${title.count} file${title.count === 1 ? "" : "s"} · ${bytes(title.size)}`;
node.querySelector(".title-card__fallback").textContent = initials(title.title);
const poster = node.querySelector(".title-card__poster");
const image = node.querySelector("img");
if (title.thumbnail) {
poster.classList.add("has-image");
image.src = title.thumbnail;
image.alt = "";
}
node.addEventListener("click", () => {
state.activeId = title.id;
state.view = "details";
render();
});
grid.append(node);
}
}
function renderDetails(title) {
els.details.innerHTML = `
<div class="hero">
<div class="poster">${title.thumbnail ? `<img src="${escapeAttr(title.thumbnail)}" alt="">` : `<span>${initials(title.title)}</span>`}</div>
@@ -192,7 +210,13 @@ function escapeAttr(value) {
els.searchInput.addEventListener("input", (event) => {
state.query = event.target.value;
renderTitleList();
state.view = "collection";
render();
});
els.backBtn.addEventListener("click", () => {
state.view = "collection";
render();
});
els.rescanBtn.addEventListener("click", async () => {