Preview: add UI V2 mode with grid, filters, sort, and toasts
This commit is contained in:
249
app.js
249
app.js
@@ -61,6 +61,16 @@ const googleRestoreBtn = document.getElementById("googleRestoreBtn");
|
||||
const quickSearchInput = document.getElementById("quickSearchInput");
|
||||
const quickSearchResults = document.getElementById("quickSearchResults");
|
||||
const loanedFilterBtn = document.getElementById("loanedFilterBtn");
|
||||
const v2Toolbar = document.getElementById("v2Toolbar");
|
||||
const v2SearchInput = document.getElementById("v2SearchInput");
|
||||
const v2ConsoleFilter = document.getElementById("v2ConsoleFilter");
|
||||
const v2GenreFilter = document.getElementById("v2GenreFilter");
|
||||
const v2SortSelect = document.getElementById("v2SortSelect");
|
||||
const v2StickyBar = document.getElementById("v2StickyBar");
|
||||
const v2StickyCount = document.getElementById("v2StickyCount");
|
||||
const v2ToggleFormBtn = document.getElementById("v2ToggleFormBtn");
|
||||
const v2QuickBackupBtn = document.getElementById("v2QuickBackupBtn");
|
||||
const toastContainer = document.getElementById("toastContainer");
|
||||
const scannerStatus = document.getElementById("scannerStatus");
|
||||
const scannerStartBtn = document.getElementById("scannerStartBtn");
|
||||
const scannerStopBtn = document.getElementById("scannerStopBtn");
|
||||
@@ -80,6 +90,12 @@ let scannerRunning = false;
|
||||
let scannerLoopId = null;
|
||||
let scannerLastCodeValue = "";
|
||||
let scannerLastCodeAt = 0;
|
||||
const uiV2Enabled = new URLSearchParams(window.location.search).get("ui") === "v2";
|
||||
let v2SearchTerm = "";
|
||||
let v2ConsoleValue = "";
|
||||
let v2GenreValue = "";
|
||||
let v2SortValue = "title_asc";
|
||||
let v2FormCollapsed = false;
|
||||
|
||||
coverFileInput.addEventListener("change", async (event) => {
|
||||
const input = event.target;
|
||||
@@ -203,6 +219,48 @@ loanedFilterBtn.addEventListener("click", () => {
|
||||
renderGames();
|
||||
});
|
||||
|
||||
if (v2SearchInput) {
|
||||
v2SearchInput.addEventListener("input", (event) => {
|
||||
v2SearchTerm = event.target.value.trim();
|
||||
renderGames();
|
||||
});
|
||||
}
|
||||
|
||||
if (v2ConsoleFilter) {
|
||||
v2ConsoleFilter.addEventListener("change", (event) => {
|
||||
v2ConsoleValue = event.target.value;
|
||||
renderGames();
|
||||
});
|
||||
}
|
||||
|
||||
if (v2GenreFilter) {
|
||||
v2GenreFilter.addEventListener("change", (event) => {
|
||||
v2GenreValue = event.target.value;
|
||||
renderGames();
|
||||
});
|
||||
}
|
||||
|
||||
if (v2SortSelect) {
|
||||
v2SortSelect.addEventListener("change", (event) => {
|
||||
v2SortValue = event.target.value || "title_asc";
|
||||
renderGames();
|
||||
});
|
||||
}
|
||||
|
||||
if (v2ToggleFormBtn) {
|
||||
v2ToggleFormBtn.addEventListener("click", () => {
|
||||
v2FormCollapsed = !v2FormCollapsed;
|
||||
gameForm.classList.toggle("hidden", v2FormCollapsed);
|
||||
v2ToggleFormBtn.textContent = v2FormCollapsed ? "Afficher formulaire" : "Ajouter";
|
||||
});
|
||||
}
|
||||
|
||||
if (v2QuickBackupBtn) {
|
||||
v2QuickBackupBtn.addEventListener("click", () => {
|
||||
backupBtn.click();
|
||||
});
|
||||
}
|
||||
|
||||
if (scannerStartBtn) {
|
||||
scannerStartBtn.addEventListener("click", async () => {
|
||||
await startScanner();
|
||||
@@ -258,6 +316,7 @@ platformForm.addEventListener("submit", async (event) => {
|
||||
|
||||
gameForm.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
const wasEditing = Boolean(editingGameId);
|
||||
|
||||
const title = titleInput.value.trim();
|
||||
if (!title || !state.selectedConsole) {
|
||||
@@ -297,6 +356,7 @@ gameForm.addEventListener("submit", async (event) => {
|
||||
|
||||
resetEditMode();
|
||||
await refreshFromApi(state.selectedBrand, state.selectedConsole);
|
||||
showToast(wasEditing ? "Jeu mis a jour." : "Jeu ajoute.", "success");
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@@ -350,6 +410,7 @@ gameForm.addEventListener("submit", async (event) => {
|
||||
persist();
|
||||
markLocalDataForImport();
|
||||
render();
|
||||
showToast(wasEditing ? "Jeu mis a jour." : "Jeu ajoute.", "success");
|
||||
});
|
||||
|
||||
brandTabs.addEventListener("click", (event) => {
|
||||
@@ -496,6 +557,7 @@ gamesList.addEventListener("click", async (event) => {
|
||||
persist();
|
||||
markLocalDataForImport();
|
||||
render();
|
||||
showToast("Jeu mis a jour.", "success");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -530,6 +592,7 @@ gamesList.addEventListener("click", async (event) => {
|
||||
}
|
||||
|
||||
await refreshFromApi(state.selectedBrand, state.selectedConsole);
|
||||
showToast("Action enregistree.", "success");
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
@@ -564,6 +627,7 @@ gamesList.addEventListener("click", async (event) => {
|
||||
persist();
|
||||
markLocalDataForImport();
|
||||
render();
|
||||
showToast("Action enregistree.", "success");
|
||||
});
|
||||
|
||||
cancelEditBtn.addEventListener("click", () => {
|
||||
@@ -678,10 +742,12 @@ restoreFileInput.addEventListener("change", async (event) => {
|
||||
});
|
||||
|
||||
function render() {
|
||||
renderV2Chrome();
|
||||
renderDataMode();
|
||||
renderGoogleStatus();
|
||||
renderBrandTabs();
|
||||
renderConsoleTabs();
|
||||
updateV2FilterOptions();
|
||||
renderGames();
|
||||
renderSearchResults();
|
||||
renderCollectionStats();
|
||||
@@ -837,6 +903,78 @@ function renderCollectionStats() {
|
||||
totalGamesValue.textContent = `${totalValue.toFixed(2)} EUR`;
|
||||
}
|
||||
|
||||
function showToast(message, type = "info", timeoutMs = 2600) {
|
||||
if (!toastContainer || !message) {
|
||||
return;
|
||||
}
|
||||
const toast = document.createElement("div");
|
||||
toast.className = `toast ${type}`.trim();
|
||||
toast.textContent = message;
|
||||
toastContainer.append(toast);
|
||||
window.setTimeout(() => {
|
||||
toast.remove();
|
||||
}, timeoutMs);
|
||||
}
|
||||
|
||||
function renderV2Chrome() {
|
||||
if (!uiV2Enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.body.classList.add("ui-v2");
|
||||
if (v2Toolbar) {
|
||||
v2Toolbar.classList.remove("hidden");
|
||||
}
|
||||
if (v2StickyBar) {
|
||||
v2StickyBar.classList.remove("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function updateV2FilterOptions() {
|
||||
if (!uiV2Enabled || !v2ConsoleFilter || !v2GenreFilter) {
|
||||
return;
|
||||
}
|
||||
|
||||
const allGames = collectAllGames();
|
||||
const consoles = Array.from(new Set(allGames.map((game) => normalizeText(game.consoleName)).filter(Boolean))).sort();
|
||||
const genres = Array.from(new Set(allGames.flatMap((game) => splitGenres(game.genre)))).sort();
|
||||
|
||||
v2ConsoleFilter.innerHTML = `<option value="">Toutes</option>${consoles
|
||||
.map((consoleName) => `<option value="${escapeHtml(consoleName)}">${escapeHtml(consoleName)}</option>`)
|
||||
.join("")}`;
|
||||
v2GenreFilter.innerHTML = `<option value="">Tous</option>${genres
|
||||
.map((genre) => `<option value="${escapeHtml(genre)}">${escapeHtml(genre)}</option>`)
|
||||
.join("")}`;
|
||||
|
||||
v2ConsoleFilter.value = v2ConsoleValue;
|
||||
v2GenreFilter.value = v2GenreValue;
|
||||
v2SortSelect.value = v2SortValue;
|
||||
}
|
||||
|
||||
function splitGenres(genreRaw) {
|
||||
return normalizeText(genreRaw)
|
||||
.split(/[\/,|]/)
|
||||
.map((item) => normalizeText(item))
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function badgeClassForGenre(genreValue) {
|
||||
const normalized = normalizeText(genreValue).toLowerCase();
|
||||
if (normalized.includes("rpg")) {
|
||||
return "rpg";
|
||||
}
|
||||
if (normalized.includes("action") || normalized.includes("aventure") || normalized.includes("adventure")) {
|
||||
return "action";
|
||||
}
|
||||
if (normalized.includes("sport") || normalized.includes("football") || normalized.includes("course")) {
|
||||
return "sport";
|
||||
}
|
||||
if (normalized.includes("racing") || normalized.includes("kart")) {
|
||||
return "racing";
|
||||
}
|
||||
return "default";
|
||||
}
|
||||
|
||||
function renderSearchResults() {
|
||||
if (!quickSearchResults) {
|
||||
return;
|
||||
@@ -941,27 +1079,76 @@ function renderConsoleTabs() {
|
||||
|
||||
function renderGames() {
|
||||
const selectedConsole = state.selectedConsole;
|
||||
gameSectionTitle.textContent = showLoanedOnly
|
||||
? "Jeux pretes - Toutes consoles"
|
||||
: selectedConsole
|
||||
? `Jeux - ${selectedConsole}`
|
||||
: "Jeux";
|
||||
const inV2 = uiV2Enabled;
|
||||
gameSectionTitle.textContent = inV2
|
||||
? "Catalogue jeux"
|
||||
: showLoanedOnly
|
||||
? "Jeux pretes - Toutes consoles"
|
||||
: selectedConsole
|
||||
? `Jeux - ${selectedConsole}`
|
||||
: "Jeux";
|
||||
gamesList.innerHTML = "";
|
||||
loanedFilterBtn.textContent = showLoanedOnly ? "Voir tous les jeux" : "Voir jeux pretes";
|
||||
|
||||
if (!showLoanedOnly && !selectedConsole) {
|
||||
if (!inV2 && !showLoanedOnly && !selectedConsole) {
|
||||
gamesList.innerHTML = '<p class="empty">Ajoute une section pour commencer.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const games = showLoanedOnly
|
||||
? collectAllGames().filter((game) => normalizeText(game.loanedTo))
|
||||
: state.gamesByConsole[selectedConsole] || [];
|
||||
let games = inV2
|
||||
? collectAllGames()
|
||||
: showLoanedOnly
|
||||
? collectAllGames().filter((game) => normalizeText(game.loanedTo))
|
||||
: state.gamesByConsole[selectedConsole] || [];
|
||||
|
||||
if (showLoanedOnly) {
|
||||
games = games.filter((game) => normalizeText(game.loanedTo));
|
||||
}
|
||||
|
||||
if (inV2) {
|
||||
const searchTerm = v2SearchTerm.toLowerCase();
|
||||
if (searchTerm) {
|
||||
games = games.filter((game) => {
|
||||
const fields = [
|
||||
game.title,
|
||||
game.publisher,
|
||||
game.barcode,
|
||||
game.consoleName,
|
||||
game.genre,
|
||||
]
|
||||
.map((value) => normalizeText(value).toLowerCase())
|
||||
.join(" ");
|
||||
return fields.includes(searchTerm);
|
||||
});
|
||||
}
|
||||
if (v2ConsoleValue) {
|
||||
games = games.filter((game) => normalizeText(game.consoleName) === v2ConsoleValue);
|
||||
}
|
||||
if (v2GenreValue) {
|
||||
games = games.filter((game) =>
|
||||
splitGenres(game.genre).some((genre) => genre.toLowerCase() === v2GenreValue.toLowerCase()),
|
||||
);
|
||||
}
|
||||
|
||||
games.sort((a, b) => {
|
||||
if (v2SortValue === "year_desc") {
|
||||
return Number(b.year || 0) - Number(a.year || 0);
|
||||
}
|
||||
if (v2SortValue === "value_desc") {
|
||||
return Number(b.value || 0) - Number(a.value || 0);
|
||||
}
|
||||
return normalizeText(a.title).localeCompare(normalizeText(b.title), "fr", { sensitivity: "base" });
|
||||
});
|
||||
|
||||
if (v2StickyCount) {
|
||||
v2StickyCount.textContent = `${games.length} jeu${games.length > 1 ? "x" : ""}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (!games.length) {
|
||||
gamesList.innerHTML = showLoanedOnly
|
||||
? '<p class="empty">Aucun jeu prete actuellement.</p>'
|
||||
: '<p class="empty">Aucun jeu sur cette console pour le moment.</p>';
|
||||
: '<p class="empty">Aucun jeu pour ces filtres.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -974,20 +1161,38 @@ function renderGames() {
|
||||
|
||||
card.querySelector(".game-title").textContent = game.title;
|
||||
|
||||
const metaParts = [
|
||||
showLoanedOnly ? `${game.brand} / ${game.consoleName}` : null,
|
||||
game.barcode ? `Code: ${game.barcode}` : null,
|
||||
game.version ? `Version: ${game.version}` : null,
|
||||
game.genre ? `Genre: ${game.genre}` : null,
|
||||
game.publisher ? `Editeur: ${game.publisher}` : null,
|
||||
game.isDuplicate ? "Double: OUI" : null,
|
||||
game.year ? `Annee: ${game.year}` : null,
|
||||
game.purchasePrice != null ? `Prix achat: ${game.purchasePrice.toFixed(2)} EUR` : null,
|
||||
game.value != null ? `Cote: ${game.value.toFixed(2)} EUR` : null,
|
||||
game.condition != null ? `Etat: ${game.condition}` : null,
|
||||
].filter(Boolean);
|
||||
const metaParts = inV2
|
||||
? [
|
||||
game.publisher ? `Editeur: ${game.publisher}` : null,
|
||||
game.year ? `Annee: ${game.year}` : null,
|
||||
game.version ? `Version: ${game.version}` : null,
|
||||
game.value != null ? `Cote: ${Number(game.value).toFixed(2)} EUR` : null,
|
||||
game.consoleName ? `Console: ${game.consoleName}` : null,
|
||||
].filter(Boolean)
|
||||
: [
|
||||
showLoanedOnly ? `${game.brand} / ${game.consoleName}` : null,
|
||||
game.barcode ? `Code: ${game.barcode}` : null,
|
||||
game.version ? `Version: ${game.version}` : null,
|
||||
game.genre ? `Genre: ${game.genre}` : null,
|
||||
game.publisher ? `Editeur: ${game.publisher}` : null,
|
||||
game.isDuplicate ? "Double: OUI" : null,
|
||||
game.year ? `Annee: ${game.year}` : null,
|
||||
game.purchasePrice != null ? `Prix achat: ${game.purchasePrice.toFixed(2)} EUR` : null,
|
||||
game.value != null ? `Cote: ${game.value.toFixed(2)} EUR` : null,
|
||||
game.condition != null ? `Etat: ${game.condition}` : null,
|
||||
].filter(Boolean);
|
||||
|
||||
card.querySelector(".game-meta").textContent = metaParts.join(" | ") || "Aucune information complementaire";
|
||||
const badgesContainer = card.querySelector(".game-badges");
|
||||
const genres = splitGenres(game.genre);
|
||||
if (genres.length) {
|
||||
badgesContainer.innerHTML = genres
|
||||
.slice(0, 4)
|
||||
.map((genre) => `<span class="genre-badge ${badgeClassForGenre(genre)}">${escapeHtml(genre)}</span>`)
|
||||
.join("");
|
||||
} else {
|
||||
badgesContainer.innerHTML = "";
|
||||
}
|
||||
const coverEl = card.querySelector(".game-cover");
|
||||
const coverUrl = normalizeText(game.coverUrl);
|
||||
if (coverUrl) {
|
||||
|
||||
37
index.html
37
index.html
@@ -61,6 +61,15 @@
|
||||
</aside>
|
||||
|
||||
<main class="app-shell">
|
||||
<div id="v2StickyBar" class="v2-sticky hidden">
|
||||
<div class="v2-sticky-title">UI V2 Preview</div>
|
||||
<div id="v2StickyCount" class="v2-sticky-count">0 jeu</div>
|
||||
<div class="v2-sticky-actions">
|
||||
<button id="v2ToggleFormBtn" type="button" class="btn-secondary">Ajouter</button>
|
||||
<button id="v2QuickBackupBtn" type="button" class="btn-secondary">Sauvegarder</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<header class="hero">
|
||||
<div class="hero-copy">
|
||||
<p class="eyebrow">Catalogue perso</p>
|
||||
@@ -94,6 +103,32 @@
|
||||
<h2 id="gameSectionTitle">Jeux</h2>
|
||||
<p id="dataModeInfo" class="data-mode"></p>
|
||||
</div>
|
||||
<div id="v2Toolbar" class="v2-toolbar hidden">
|
||||
<label>
|
||||
Recherche
|
||||
<input id="v2SearchInput" placeholder="Titre, editeur, code-barres..." />
|
||||
</label>
|
||||
<label>
|
||||
Console
|
||||
<select id="v2ConsoleFilter">
|
||||
<option value="">Toutes</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Genre
|
||||
<select id="v2GenreFilter">
|
||||
<option value="">Tous</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
Tri
|
||||
<select id="v2SortSelect">
|
||||
<option value="title_asc">Titre (A-Z)</option>
|
||||
<option value="year_desc">Annee (recent d'abord)</option>
|
||||
<option value="value_desc">Cote (elevee d'abord)</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="games-actions-bar">
|
||||
<button id="loanedFilterBtn" type="button" class="btn-secondary">Voir jeux pretes</button>
|
||||
</div>
|
||||
@@ -177,12 +212,14 @@
|
||||
<div id="gamesList" class="games-list"></div>
|
||||
</section>
|
||||
</main>
|
||||
<div id="toastContainer" class="toast-container" aria-live="polite" aria-atomic="true"></div>
|
||||
|
||||
<template id="gameCardTemplate">
|
||||
<article class="game-card">
|
||||
<img class="game-cover hidden" alt="Pochette du jeu" loading="lazy" />
|
||||
<div class="game-main">
|
||||
<h3 class="game-title"></h3>
|
||||
<div class="game-badges"></div>
|
||||
<p class="game-meta"></p>
|
||||
<p class="game-loan"></p>
|
||||
</div>
|
||||
|
||||
201
styles.css
201
styles.css
@@ -8,6 +8,9 @@
|
||||
--danger: #bf2f47;
|
||||
--border: #d6dde6;
|
||||
--shadow: 0 10px 24px rgba(17, 36, 57, 0.08);
|
||||
--v2-primary: #6c5ce7;
|
||||
--v2-success: #00b894;
|
||||
--v2-bg: #f8f9fa;
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -519,7 +522,201 @@ button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.v2-sticky {
|
||||
position: sticky;
|
||||
top: 0.55rem;
|
||||
z-index: 20;
|
||||
background: linear-gradient(130deg, #f2eeff, #edf7f4);
|
||||
border: 1px solid #d8d8ea;
|
||||
border-radius: 14px;
|
||||
padding: 0.55rem 0.7rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.7rem;
|
||||
}
|
||||
|
||||
.v2-sticky-title {
|
||||
font-weight: 700;
|
||||
color: #2f2a66;
|
||||
}
|
||||
|
||||
.v2-sticky-count {
|
||||
font-size: 0.88rem;
|
||||
color: #3c4e61;
|
||||
}
|
||||
|
||||
.v2-sticky-actions {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.v2-toolbar {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
background: #f8fbff;
|
||||
padding: 0.7rem;
|
||||
margin-bottom: 0.8rem;
|
||||
display: grid;
|
||||
gap: 0.55rem;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.v2-toolbar select {
|
||||
width: 100%;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 10px;
|
||||
padding: 0.62rem 0.65rem;
|
||||
font-family: inherit;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.game-badges {
|
||||
margin: 0.4rem 0 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.33rem;
|
||||
}
|
||||
|
||||
.genre-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.2rem 0.5rem;
|
||||
border-radius: 999px;
|
||||
font-size: 0.73rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.01em;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.genre-badge.default {
|
||||
background: #e8eef8;
|
||||
color: #234361;
|
||||
border-color: #d4dfed;
|
||||
}
|
||||
|
||||
.genre-badge.rpg {
|
||||
background: #efe7ff;
|
||||
color: #4f2f9a;
|
||||
border-color: #ddccff;
|
||||
}
|
||||
|
||||
.genre-badge.action {
|
||||
background: #ffe9ec;
|
||||
color: #a23649;
|
||||
border-color: #ffd2d9;
|
||||
}
|
||||
|
||||
.genre-badge.sport {
|
||||
background: #e6fbf4;
|
||||
color: #146c57;
|
||||
border-color: #c7f2e4;
|
||||
}
|
||||
|
||||
.genre-badge.racing {
|
||||
background: #fff4df;
|
||||
color: #9c6515;
|
||||
border-color: #ffe6b9;
|
||||
}
|
||||
|
||||
.toast-container {
|
||||
position: fixed;
|
||||
right: 1rem;
|
||||
bottom: 1rem;
|
||||
z-index: 80;
|
||||
display: grid;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.toast {
|
||||
min-width: 220px;
|
||||
max-width: 360px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #d7e0ec;
|
||||
background: #ffffff;
|
||||
color: #1d2f44;
|
||||
padding: 0.58rem 0.7rem;
|
||||
box-shadow: var(--shadow);
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
|
||||
.toast.success {
|
||||
border-color: #bdecd8;
|
||||
background: #eefbf5;
|
||||
}
|
||||
|
||||
.toast.error {
|
||||
border-color: #ffd1da;
|
||||
background: #fff1f4;
|
||||
}
|
||||
|
||||
body.ui-v2 {
|
||||
background: radial-gradient(circle at top right, #efeaff 0, transparent 34%), var(--v2-bg);
|
||||
}
|
||||
|
||||
body.ui-v2 .games-list {
|
||||
grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
|
||||
}
|
||||
|
||||
body.ui-v2 .game-card {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.55rem;
|
||||
transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
|
||||
}
|
||||
|
||||
body.ui-v2 .game-card:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: #d3cef9;
|
||||
box-shadow: 0 12px 24px rgba(50, 50, 93, 0.14);
|
||||
}
|
||||
|
||||
body.ui-v2 .game-cover {
|
||||
width: 72px;
|
||||
height: 98px;
|
||||
}
|
||||
|
||||
body.ui-v2 .game-actions {
|
||||
width: 100%;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body.ui-v2 {
|
||||
background: #10141a;
|
||||
color: #e8edf6;
|
||||
}
|
||||
|
||||
body.ui-v2 .panel,
|
||||
body.ui-v2 .hero,
|
||||
body.ui-v2 .v2-toolbar,
|
||||
body.ui-v2 .v2-sticky,
|
||||
body.ui-v2 .game-card,
|
||||
body.ui-v2 .search-zone,
|
||||
body.ui-v2 .scanner-zone {
|
||||
background: #161d26;
|
||||
border-color: #2b3747;
|
||||
}
|
||||
|
||||
body.ui-v2 .btn-secondary,
|
||||
body.ui-v2 .btn-inline {
|
||||
background: #2a3647;
|
||||
color: #dbe5f2;
|
||||
}
|
||||
|
||||
body.ui-v2 input,
|
||||
body.ui-v2 select {
|
||||
background: #10161f;
|
||||
border-color: #314157;
|
||||
color: #e7eef8;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.v2-toolbar {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.grid-form,
|
||||
.game-form {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
@@ -532,6 +729,10 @@ button {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.v2-toolbar {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.tools-toggle-btn {
|
||||
top: auto;
|
||||
bottom: 1rem;
|
||||
|
||||
Reference in New Issue
Block a user