UI: move backup and migration actions into a sidebar tools menu
This commit is contained in:
@@ -144,6 +144,7 @@ git pull
|
|||||||
- GET `/api/backup/export`
|
- GET `/api/backup/export`
|
||||||
- POST `/api/backup/restore` (modes `merge` ou `replace`)
|
- POST `/api/backup/restore` (modes `merge` ou `replace`)
|
||||||
- snapshot auto en base avant restore `replace` (`backup_snapshots`)
|
- snapshot auto en base avant restore `replace` (`backup_snapshots`)
|
||||||
|
- actions accessibles dans le panneau lateral `Outils`
|
||||||
|
|
||||||
## Licence
|
## Licence
|
||||||
|
|
||||||
|
|||||||
30
app.js
30
app.js
@@ -32,6 +32,9 @@ const brandTabs = document.getElementById("brandTabs");
|
|||||||
const consoleTabs = document.getElementById("consoleTabs");
|
const consoleTabs = document.getElementById("consoleTabs");
|
||||||
const gameSectionTitle = document.getElementById("gameSectionTitle");
|
const gameSectionTitle = document.getElementById("gameSectionTitle");
|
||||||
const dataModeInfo = document.getElementById("dataModeInfo");
|
const dataModeInfo = document.getElementById("dataModeInfo");
|
||||||
|
const toolsDrawer = document.getElementById("toolsDrawer");
|
||||||
|
const toolsToggleBtn = document.getElementById("toolsToggleBtn");
|
||||||
|
const toolsCloseBtn = document.getElementById("toolsCloseBtn");
|
||||||
const migrateBtn = document.getElementById("migrateBtn");
|
const migrateBtn = document.getElementById("migrateBtn");
|
||||||
const backupControls = document.getElementById("backupControls");
|
const backupControls = document.getElementById("backupControls");
|
||||||
const backupBtn = document.getElementById("backupBtn");
|
const backupBtn = document.getElementById("backupBtn");
|
||||||
@@ -43,6 +46,33 @@ const gameCardTemplate = document.getElementById("gameCardTemplate");
|
|||||||
let editingGameId = null;
|
let editingGameId = null;
|
||||||
let pendingRestoreMode = "merge";
|
let pendingRestoreMode = "merge";
|
||||||
|
|
||||||
|
toolsToggleBtn.addEventListener("click", () => {
|
||||||
|
toolsDrawer.classList.toggle("open");
|
||||||
|
});
|
||||||
|
|
||||||
|
toolsCloseBtn.addEventListener("click", () => {
|
||||||
|
toolsDrawer.classList.remove("open");
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("click", (event) => {
|
||||||
|
if (!(event.target instanceof Element)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!toolsDrawer.classList.contains("open")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (toolsDrawer.contains(event.target) || toolsToggleBtn.contains(event.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toolsDrawer.classList.remove("open");
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("keydown", (event) => {
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
toolsDrawer.classList.remove("open");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
platformForm.addEventListener("submit", async (event) => {
|
platformForm.addEventListener("submit", async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
|||||||
27
index.html
27
index.html
@@ -13,6 +13,24 @@
|
|||||||
<link rel="stylesheet" href="styles.css" />
|
<link rel="stylesheet" href="styles.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<button id="toolsToggleBtn" type="button" class="tools-toggle-btn">Outils</button>
|
||||||
|
<aside id="toolsDrawer" class="tools-drawer" aria-label="Menu outils">
|
||||||
|
<div class="tools-header">
|
||||||
|
<h2>Outils</h2>
|
||||||
|
<button id="toolsCloseBtn" type="button" class="btn-secondary tools-close-btn">Fermer</button>
|
||||||
|
</div>
|
||||||
|
<p class="tools-subtitle">Sauvegarde, restauration et migration.</p>
|
||||||
|
<button id="migrateBtn" type="button" class="btn-secondary hidden">
|
||||||
|
Migrer localStorage vers DB
|
||||||
|
</button>
|
||||||
|
<div id="backupControls" class="backup-controls hidden">
|
||||||
|
<button id="backupBtn" type="button" class="btn-secondary">Sauvegarder JSON</button>
|
||||||
|
<button id="restoreMergeBtn" type="button" class="btn-secondary">Restaurer (fusion)</button>
|
||||||
|
<button id="restoreReplaceBtn" type="button" class="btn-secondary">Restaurer (remplacement)</button>
|
||||||
|
<input id="restoreFileInput" type="file" accept="application/json" class="hidden" />
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
|
||||||
<main class="app-shell">
|
<main class="app-shell">
|
||||||
<header class="hero">
|
<header class="hero">
|
||||||
<div>
|
<div>
|
||||||
@@ -50,15 +68,6 @@
|
|||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2 id="gameSectionTitle">Jeux</h2>
|
<h2 id="gameSectionTitle">Jeux</h2>
|
||||||
<p id="dataModeInfo" class="data-mode"></p>
|
<p id="dataModeInfo" class="data-mode"></p>
|
||||||
<button id="migrateBtn" type="button" class="btn-secondary hidden">
|
|
||||||
Migrer localStorage vers DB
|
|
||||||
</button>
|
|
||||||
<div id="backupControls" class="backup-controls hidden">
|
|
||||||
<button id="backupBtn" type="button" class="btn-secondary">Sauvegarder JSON</button>
|
|
||||||
<button id="restoreMergeBtn" type="button" class="btn-secondary">Restaurer (fusion)</button>
|
|
||||||
<button id="restoreReplaceBtn" type="button" class="btn-secondary">Restaurer (remplacement)</button>
|
|
||||||
<input id="restoreFileInput" type="file" accept="application/json" class="hidden" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form id="gameForm" class="grid-form game-form">
|
<form id="gameForm" class="grid-form game-form">
|
||||||
|
|||||||
62
styles.css
62
styles.css
@@ -24,6 +24,57 @@ body {
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tools-toggle-btn {
|
||||||
|
position: fixed;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
z-index: 30;
|
||||||
|
background: var(--accent-2);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-drawer {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: min(360px, 92vw);
|
||||||
|
height: 100vh;
|
||||||
|
background: #f9fbff;
|
||||||
|
border-left: 1px solid var(--border);
|
||||||
|
box-shadow: -8px 0 24px rgba(17, 36, 57, 0.14);
|
||||||
|
padding: 1rem;
|
||||||
|
transform: translateX(102%);
|
||||||
|
transition: transform 180ms ease;
|
||||||
|
z-index: 40;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-drawer.open {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-header h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-close-btn {
|
||||||
|
padding: 0.45rem 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools-subtitle {
|
||||||
|
margin: 0.6rem 0 0.9rem;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
.app-shell {
|
.app-shell {
|
||||||
width: min(1100px, 94vw);
|
width: min(1100px, 94vw);
|
||||||
margin: 2rem auto;
|
margin: 2rem auto;
|
||||||
@@ -81,13 +132,12 @@ h1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#migrateBtn {
|
#migrateBtn {
|
||||||
width: fit-content;
|
width: 100%;
|
||||||
margin-bottom: 0.9rem;
|
margin-bottom: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.backup-controls {
|
.backup-controls {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
margin-bottom: 0.9rem;
|
margin-bottom: 0.9rem;
|
||||||
}
|
}
|
||||||
@@ -256,6 +306,12 @@ button {
|
|||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tools-toggle-btn {
|
||||||
|
top: auto;
|
||||||
|
bottom: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.game-card {
|
.game-card {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
Reference in New Issue
Block a user