Improved save and load system, added description and sort options

This commit is contained in:
2026-03-30 19:22:14 +02:00
parent bc377b6e33
commit b90d6d0f03
12 changed files with 378 additions and 46 deletions
+150 -15
View File
@@ -15,6 +15,8 @@ const btnQueens = document.getElementById("btnQueens");
const btnRooks = document.getElementById("btnRooks");
const settingsSidebar = document.getElementById("settingsSidebar");
const sidebarBackdrop = document.getElementById("sidebarBackdrop");
const saveSidebar = document.getElementById("saveSidebar");
const saveBackdrop = document.getElementById("saveBackdrop");
const savePointsSidebar = document.getElementById("savePointsSidebar");
const savePointsBackdrop = document.getElementById("savePointsBackdrop");
const boardSizeInput = document.getElementById("boardSizeInput");
@@ -23,6 +25,13 @@ const boardSizeValueMirror = document.getElementById("boardSizeValueMirror");
const sidebarBoardSizeValue = document.getElementById("sidebarBoardSizeValue");
const sidebarBoardSizeValueMirror = document.getElementById("sidebarBoardSizeValueMirror");
const savePointsList = document.getElementById("savePointsList");
const saveNameInput = document.getElementById("saveNameInput");
const saveNoteInput = document.getElementById("saveNoteInput");
const saveFavoriteInput = document.getElementById("saveFavoriteInput");
const savePointModeFilter = document.getElementById("savePointModeFilter");
const savePointSizeFilter = document.getElementById("savePointSizeFilter");
const savePointSortFilter = document.getElementById("savePointSortFilter");
const savePointFavoritesOnly = document.getElementById("savePointFavoritesOnly");
function createEmptyBoard(size) {
return Array(size).fill(EMPTY_CELL);
@@ -67,6 +76,12 @@ function setMode(newMode) {
updateModeButtons();
}
function closeAllPanels() {
toggleSidebar(false);
toggleSavePanel(false);
toggleSavePointsPanel(false);
}
function getConflicts() {
const conflicts = [];
@@ -178,6 +193,7 @@ function toggleSidebar(forceOpen) {
const shouldOpen = typeof forceOpen === "boolean" ? forceOpen : !settingsSidebar.classList.contains("open");
if (shouldOpen) {
toggleSavePanel(false);
toggleSavePointsPanel(false);
}
@@ -186,9 +202,27 @@ function toggleSidebar(forceOpen) {
settingsSidebar.setAttribute("aria-hidden", String(!shouldOpen));
}
function toggleSavePanel(forceOpen) {
const shouldOpen = typeof forceOpen === "boolean" ? forceOpen : !saveSidebar.classList.contains("open");
if (shouldOpen) {
toggleSidebar(false);
toggleSavePointsPanel(false);
}
saveSidebar.classList.toggle("open", shouldOpen);
saveBackdrop.classList.toggle("visible", shouldOpen);
saveSidebar.setAttribute("aria-hidden", String(!shouldOpen));
}
function toggleSavePointsPanel(forceOpen) {
const shouldOpen = typeof forceOpen === "boolean" ? forceOpen : !savePointsSidebar.classList.contains("open");
if (shouldOpen) {
toggleSidebar(false);
toggleSavePanel(false);
}
savePointsSidebar.classList.toggle("open", shouldOpen);
savePointsBackdrop.classList.toggle("visible", shouldOpen);
savePointsSidebar.setAttribute("aria-hidden", String(!shouldOpen));
@@ -198,6 +232,21 @@ function getPieceLabel(selectedMode) {
return selectedMode === "queens" ? "Dame" : "Turm";
}
function getPlacedPieceCount() {
return board.filter((col) => col !== EMPTY_CELL).length;
}
function resetSaveForm() {
saveNameInput.value = `${getPieceLabel(mode)} ${boardSize}x${boardSize} - ${getPlacedPieceCount()} gesetzt`;
saveNoteInput.value = "";
saveFavoriteInput.checked = false;
}
function openSavePanel() {
resetSaveForm();
toggleSavePanel(true);
}
function getBoardPreview(savedBoard, limit = 4) {
const preview = [];
@@ -216,11 +265,40 @@ function getBoardPreview(savedBoard, limit = 4) {
return preview.length > 0 ? preview.join(", ") : "Noch keine Figuren gesetzt";
}
function getSavePointFilters() {
const params = new URLSearchParams();
if (savePointModeFilter.value !== "all") {
params.set("mode", savePointModeFilter.value);
}
if (savePointSizeFilter.value !== "all") {
params.set("board_size", savePointSizeFilter.value);
}
params.set("sort", savePointSortFilter.value);
if (savePointFavoritesOnly.checked) {
params.set("favorites_only", "true");
}
return params.toString();
}
function createSavePointActionButton(label, className, onClick) {
const button = document.createElement("button");
button.className = className;
button.type = "button";
button.textContent = label;
button.onclick = onClick;
return button;
}
function renderSavePoints(savePoints) {
savePointsList.innerHTML = "";
if (savePoints.length === 0) {
savePointsList.innerHTML = '<p class="sidebar-hint">Noch keine Speicherstaende gefunden.</p>';
savePointsList.innerHTML = '<p class="sidebar-hint">Keine Speicherstaende fuer diese Filter gefunden.</p>';
return;
}
@@ -228,42 +306,54 @@ function renderSavePoints(savePoints) {
const item = document.createElement("article");
const title = document.createElement("h4");
const createdAt = document.createElement("p");
const updatedAt = document.createElement("p");
const boardMeta = document.createElement("p");
const preview = document.createElement("p");
const loadButton = document.createElement("button");
const note = document.createElement("p");
const actions = document.createElement("div");
item.className = "save-point-card";
title.textContent = `Save Point #${savePoint.id}`;
title.textContent = `${savePoint.is_favorite ? "★ " : ""}${savePoint.save_name}`;
createdAt.className = "save-point-meta";
createdAt.textContent = `Gespeichert: ${savePoint.created_at}`;
createdAt.textContent = `Erstellt: ${savePoint.created_at}`;
updatedAt.className = "save-point-meta";
updatedAt.textContent = `Aktualisiert: ${savePoint.updated_at}`;
boardMeta.className = "save-point-meta";
boardMeta.textContent = `${getPieceLabel(savePoint.mode)} | ${savePoint.board_size} x ${savePoint.board_size} | ${savePoint.pieces_placed}/${savePoint.board_size} gesetzt`;
preview.className = "save-point-preview";
preview.textContent = `Vorschau: ${getBoardPreview(savePoint.board)}`;
note.className = "save-point-note";
note.textContent = savePoint.save_note ? `Notiz: ${savePoint.save_note}` : "Notiz: Keine Notiz";
actions.className = "save-point-actions";
loadButton.className = "btn";
loadButton.type = "button";
loadButton.textContent = "Diesen laden";
loadButton.onclick = () => loadSavePoint(savePoint.id);
actions.appendChild(createSavePointActionButton("Laden", "btn", () => loadSavePoint(savePoint.id)));
actions.appendChild(createSavePointActionButton(
savePoint.is_favorite ? "Favorit entfernen" : "Als Favorit",
"btn secondary",
() => toggleSavePointFavorite(savePoint.id)
));
actions.appendChild(createSavePointActionButton("Loeschen", "btn ghost", () => deleteSavePoint(savePoint.id)));
item.appendChild(title);
item.appendChild(createdAt);
item.appendChild(updatedAt);
item.appendChild(boardMeta);
item.appendChild(preview);
item.appendChild(loadButton);
item.appendChild(note);
item.appendChild(actions);
savePointsList.appendChild(item);
}
}
async function refreshSavePoints() {
const response = await fetch("/save_points");
const queryString = getSavePointFilters();
const response = await fetch(`/save_points${queryString ? `?${queryString}` : ""}`);
const savePoints = await response.json();
renderSavePoints(savePoints);
}
async function openSavePointsPanel() {
await refreshSavePoints();
toggleSidebar(false);
toggleSavePointsPanel(true);
}
@@ -316,7 +406,7 @@ function updateQueenList() {
}
async function saveGame() {
await fetch("/save", {
const response = await fetch("/save", {
method: "POST",
headers: {
"Content-Type": "application/json"
@@ -324,12 +414,23 @@ async function saveGame() {
body: JSON.stringify({
board,
mode,
boardSize
boardSize,
saveName: saveNameInput.value,
saveNote: saveNoteInput.value,
isFavorite: saveFavoriteInput.checked
})
});
if (!response.ok) {
setStatus("❌ Der Speicherstand konnte nicht gespeichert werden.", "red");
return;
}
const data = await response.json();
toggleSavePanel(false);
await refreshSavePoints();
alert("💾 Spiel gespeichert!");
setStatus(`Speicherpunkt "${data.save_point.save_name}" gespeichert.`, "green");
}
async function loadGame() {
@@ -349,10 +450,44 @@ async function loadSavePoint(savePointId) {
const data = await response.json();
applyLoadedGame(data);
setStatus(`Speicherstand #${savePointId} geladen.`, "green");
setStatus(`Speicherpunkt "${data.save_name}" geladen.`, "green");
toggleSavePointsPanel(false);
}
async function toggleSavePointFavorite(savePointId) {
const response = await fetch(`/save_points/${savePointId}/favorite`, {
method: "POST"
});
if (!response.ok) {
setStatus("❌ Favorit konnte nicht aktualisiert werden.", "red");
return;
}
await refreshSavePoints();
setStatus("Favoritenstatus aktualisiert.", "#2563eb");
}
async function deleteSavePoint(savePointId) {
const confirmed = window.confirm("Diesen Speicherpunkt wirklich loeschen?");
if (!confirmed) {
return;
}
const response = await fetch(`/save_points/${savePointId}`, {
method: "DELETE"
});
if (!response.ok) {
setStatus("❌ Speicherpunkt konnte nicht geloescht werden.", "red");
return;
}
await refreshSavePoints();
setStatus("Speicherpunkt geloescht.", "#2563eb");
}
pendingBoardSize = boardSize;
updateModeButtons();
updateBoardSizeDisplays(boardSize);