UI V3: add top navigation, sidebar layout, and dedicated loans/stats views
This commit is contained in:
116
app.js
116
app.js
@@ -60,6 +60,15 @@ const googleBackupBtn = document.getElementById("googleBackupBtn");
|
||||
const googleRestoreBtn = document.getElementById("googleRestoreBtn");
|
||||
const quickSearchInput = document.getElementById("quickSearchInput");
|
||||
const quickSearchResults = document.getElementById("quickSearchResults");
|
||||
const topNavButtons = document.querySelectorAll(".topnav-btn[data-view]");
|
||||
const gamesPanel = document.getElementById("gamesPanel");
|
||||
const statsView = document.getElementById("statsView");
|
||||
const scannerZone = document.getElementById("scannerZone");
|
||||
const searchZone = document.getElementById("searchZone");
|
||||
const statsTotalGames = document.getElementById("statsTotalGames");
|
||||
const statsTotalValue = document.getElementById("statsTotalValue");
|
||||
const statsLoanedGames = document.getElementById("statsLoanedGames");
|
||||
const statsConsoleCount = document.getElementById("statsConsoleCount");
|
||||
const loanedFilterBtn = document.getElementById("loanedFilterBtn");
|
||||
const bulkActionsBar = document.getElementById("bulkActionsBar");
|
||||
const bulkSelectPage = document.getElementById("bulkSelectPage");
|
||||
@@ -105,6 +114,7 @@ let selectedGameIds = new Set();
|
||||
let currentPage = 1;
|
||||
let currentPageGameIds = [];
|
||||
let currentTotalPages = 1;
|
||||
let currentView = "catalogue";
|
||||
// V2 is now the default UI. Use ?ui=v1 to force legacy mode if needed.
|
||||
const uiParam = new URLSearchParams(window.location.search).get("ui");
|
||||
const uiV2Enabled = uiParam !== "v1";
|
||||
@@ -232,12 +242,19 @@ quickSearchInput.addEventListener("input", (event) => {
|
||||
});
|
||||
|
||||
loanedFilterBtn.addEventListener("click", () => {
|
||||
showLoanedOnly = !showLoanedOnly;
|
||||
resetPaging();
|
||||
selectedGameIds.clear();
|
||||
renderGames();
|
||||
setCurrentView(currentView === "loans" ? "catalogue" : "loans");
|
||||
});
|
||||
|
||||
for (const navButton of topNavButtons) {
|
||||
navButton.addEventListener("click", () => {
|
||||
const view = navButton.dataset.view;
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
setCurrentView(view);
|
||||
});
|
||||
}
|
||||
|
||||
if (bulkSelectPage) {
|
||||
bulkSelectPage.addEventListener("change", (event) => {
|
||||
const checked = Boolean(event.target.checked);
|
||||
@@ -885,6 +902,7 @@ restoreFileInput.addEventListener("change", async (event) => {
|
||||
|
||||
function render() {
|
||||
renderV2Chrome();
|
||||
renderViewChrome();
|
||||
renderDataMode();
|
||||
renderGoogleStatus();
|
||||
renderBrandTabs();
|
||||
@@ -895,6 +913,59 @@ function render() {
|
||||
renderCollectionStats();
|
||||
}
|
||||
|
||||
function setCurrentView(view) {
|
||||
const allowed = new Set(["catalogue", "loans", "stats"]);
|
||||
if (!allowed.has(view)) {
|
||||
return;
|
||||
}
|
||||
currentView = view;
|
||||
showLoanedOnly = view === "loans";
|
||||
resetPaging();
|
||||
selectedGameIds.clear();
|
||||
render();
|
||||
}
|
||||
|
||||
function renderViewChrome() {
|
||||
const isStats = currentView === "stats";
|
||||
const isLoans = currentView === "loans";
|
||||
|
||||
for (const navButton of topNavButtons) {
|
||||
navButton.classList.toggle("active", navButton.dataset.view === currentView);
|
||||
}
|
||||
|
||||
if (gamesPanel) {
|
||||
gamesPanel.classList.toggle("hidden", isStats);
|
||||
}
|
||||
if (statsView) {
|
||||
statsView.classList.toggle("hidden", !isStats);
|
||||
}
|
||||
if (gameForm) {
|
||||
gameForm.classList.toggle("hidden", isLoans || isStats || v2FormCollapsed);
|
||||
}
|
||||
if (scannerZone) {
|
||||
scannerZone.classList.toggle("hidden", isLoans || isStats);
|
||||
}
|
||||
if (searchZone) {
|
||||
searchZone.classList.toggle("hidden", isStats);
|
||||
}
|
||||
if (bulkActionsBar) {
|
||||
bulkActionsBar.classList.toggle("hidden", isStats);
|
||||
}
|
||||
if (paginationBar) {
|
||||
paginationBar.classList.toggle("hidden", isStats);
|
||||
}
|
||||
if (v2ToggleFormBtn) {
|
||||
v2ToggleFormBtn.classList.toggle("hidden", isLoans || isStats);
|
||||
}
|
||||
if (v2QuickBackupBtn) {
|
||||
v2QuickBackupBtn.classList.toggle("hidden", isStats);
|
||||
}
|
||||
if (loanedFilterBtn) {
|
||||
loanedFilterBtn.textContent = isLoans ? "Retour catalogue" : "Aller a la vue prets";
|
||||
loanedFilterBtn.classList.toggle("hidden", isStats);
|
||||
}
|
||||
}
|
||||
|
||||
function renderDataMode() {
|
||||
if (!dataModeInfo) {
|
||||
return;
|
||||
@@ -1040,9 +1111,24 @@ function renderCollectionStats() {
|
||||
const value = typeof game.value === "number" ? game.value : Number(game.value);
|
||||
return Number.isFinite(value) ? sum + value : sum;
|
||||
}, 0);
|
||||
const loanedCount = allGames.filter((game) => normalizeText(game.loanedTo)).length;
|
||||
const activeConsoles = Object.values(state.gamesByConsole).filter((games) => Array.isArray(games) && games.length > 0)
|
||||
.length;
|
||||
|
||||
totalGamesCount.textContent = String(totalCount);
|
||||
totalGamesValue.textContent = `${totalValue.toFixed(2)} EUR`;
|
||||
if (statsTotalGames) {
|
||||
statsTotalGames.textContent = String(totalCount);
|
||||
}
|
||||
if (statsTotalValue) {
|
||||
statsTotalValue.textContent = `${totalValue.toFixed(2)} EUR`;
|
||||
}
|
||||
if (statsLoanedGames) {
|
||||
statsLoanedGames.textContent = String(loanedCount);
|
||||
}
|
||||
if (statsConsoleCount) {
|
||||
statsConsoleCount.textContent = String(activeConsoles);
|
||||
}
|
||||
}
|
||||
|
||||
function showToast(message, type = "info", timeoutMs = 2600) {
|
||||
@@ -1211,10 +1297,12 @@ function updateBulkAndPaginationUi(pageGames, totalFilteredCount) {
|
||||
nextPageBtn.disabled = currentPage >= currentTotalPages;
|
||||
}
|
||||
if (paginationBar) {
|
||||
paginationBar.classList.toggle("hidden", totalFilteredCount <= pageSizeForViewport());
|
||||
const shouldHidePagination = currentView === "stats" || totalFilteredCount <= pageSizeForViewport();
|
||||
paginationBar.classList.toggle("hidden", shouldHidePagination);
|
||||
}
|
||||
if (bulkActionsBar) {
|
||||
bulkActionsBar.classList.toggle("hidden", totalFilteredCount === 0);
|
||||
const shouldHideBulk = currentView === "stats" || totalFilteredCount === 0;
|
||||
bulkActionsBar.classList.toggle("hidden", shouldHideBulk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1412,15 +1500,15 @@ async function performBulkAction(action) {
|
||||
function renderGames() {
|
||||
const selectedConsole = state.selectedConsole;
|
||||
const inV2 = uiV2Enabled;
|
||||
gameSectionTitle.textContent = inV2
|
||||
? "Catalogue jeux"
|
||||
: showLoanedOnly
|
||||
? "Jeux pretes - Toutes consoles"
|
||||
: selectedConsole
|
||||
? `Jeux - ${selectedConsole}`
|
||||
: "Jeux";
|
||||
gameSectionTitle.textContent =
|
||||
currentView === "loans"
|
||||
? "Jeux pretes"
|
||||
: inV2
|
||||
? "Catalogue jeux"
|
||||
: selectedConsole
|
||||
? `Jeux - ${selectedConsole}`
|
||||
: "Jeux";
|
||||
gamesList.innerHTML = "";
|
||||
loanedFilterBtn.textContent = showLoanedOnly ? "Voir tous les jeux" : "Voir jeux pretes";
|
||||
|
||||
if (!inV2 && !showLoanedOnly && !selectedConsole) {
|
||||
gamesList.innerHTML = '<p class="empty">Ajoute une section pour commencer.</p>';
|
||||
|
||||
Reference in New Issue
Block a user