From afabdce17cc5f3a5e85b37809c134f37f4204e1b Mon Sep 17 00:00:00 2001 From: Ponte Date: Thu, 5 Mar 2026 19:36:03 +0100 Subject: [PATCH] UI V3: add top navigation, sidebar layout, and dedicated loans/stats views --- app.js | 116 ++++++++++++++++++++++++++++++++++++++++++++++------- index.html | 86 +++++++++++++++++++++++++++------------ styles.css | 108 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 268 insertions(+), 42 deletions(-) diff --git a/app.js b/app.js index c4a683e..d38f4ab 100644 --- a/app.js +++ b/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 = '

Ajoute une section pour commencer.

'; diff --git a/index.html b/index.html index fd23571..af67074 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,18 @@ - +
+
+

Collection Manager

+

Collection Jeux Video

+
+ +
-
+
+ + +
diff --git a/styles.css b/styles.css index 61001e8..217969a 100644 --- a/styles.css +++ b/styles.css @@ -27,6 +27,49 @@ body { min-height: 100vh; } +.topbar { + position: sticky; + top: 0; + z-index: 60; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 0.8rem; + padding: 0.7rem 1rem; + border-bottom: 1px solid var(--border); + background: rgba(248, 250, 253, 0.92); + backdrop-filter: blur(8px); +} + +.topbar-brand h1 { + margin: 0.1rem 0 0; + font-size: clamp(1.05rem, 1.8vw, 1.35rem); +} + +.topbar-nav { + display: flex; + flex-wrap: wrap; + gap: 0.45rem; +} + +.topnav-btn { + background: #dde7f3; + color: #1f324a; + border: 1px solid #cfd9e7; + border-radius: 10px; + padding: 0.48rem 0.72rem; + font-family: inherit; + font-weight: 600; + cursor: pointer; +} + +.topnav-btn.active { + background: #0f6ab8; + color: #ffffff; + border-color: #0f6ab8; +} + .tools-toggle-btn { position: fixed; top: 1rem; @@ -161,12 +204,36 @@ body { } .app-shell { - width: min(1100px, 94vw); - margin: 2rem auto; + width: min(1320px, 95vw); + margin: 1rem auto 2rem; display: grid; gap: 1rem; } +.v3-layout { + grid-template-columns: minmax(260px, 320px) minmax(0, 1fr); + align-items: start; +} + +.v3-main { + display: grid; + gap: 1rem; +} + +.v3-sidebar { + position: sticky; + top: 5rem; +} + +.sidebar-block + .sidebar-block { + margin-top: 0.9rem; +} + +.sidebar-title { + margin: 0 0 0.7rem; + font-size: 1rem; +} + .hero, .panel { background: var(--surface); @@ -206,6 +273,12 @@ h1 { color: var(--muted); } +.stats-grid { + display: grid; + gap: 0.75rem; + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + .panel { padding: 1rem; } @@ -819,7 +892,7 @@ body.ui-v2 .game-actions { body.ui-v2 .hero { position: sticky; - top: 4.2rem; + top: 5.3rem; z-index: 15; } @@ -861,6 +934,22 @@ body.ui-v2 .hero { } @media (max-width: 900px) { + .topbar { + padding: 0.6rem 0.7rem; + } + + .v3-layout { + grid-template-columns: 1fr; + } + + .v3-sidebar { + position: static; + } + + .stats-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .v2-toolbar { grid-template-columns: repeat(2, minmax(0, 1fr)); } @@ -881,6 +970,19 @@ body.ui-v2 .hero { } @media (max-width: 640px) { + .topbar-nav { + width: 100%; + } + + .topnav-btn { + flex: 1 1 calc(50% - 0.3rem); + text-align: center; + } + + .stats-grid { + grid-template-columns: 1fr; + } + .grid-form, .game-form { grid-template-columns: 1fr;