Add delete confirmation modal with preview

This commit is contained in:
2026-02-04 15:27:12 +01:00
parent 534fc41d33
commit f58ef641b4
3 changed files with 71 additions and 7 deletions

View File

@@ -98,6 +98,8 @@ const translations = {
"modal.editTitle": "Edit game", "modal.editTitle": "Edit game",
"modal.addTitle": "Suggest a game", "modal.addTitle": "Suggest a game",
"modal.confirmDeleteTitle": "Are you sure?",
"modal.confirmDelete": "Confirm delete",
"modal.save": "Save changes", "modal.save": "Save changes",
"modal.cancel": "Cancel", "modal.cancel": "Cancel",
"modal.close": "Close", "modal.close": "Close",
@@ -203,6 +205,8 @@ const translations = {
"modal.editTitle": "Spiel bearbeiten", "modal.editTitle": "Spiel bearbeiten",
"modal.addTitle": "Spiel vorschlagen", "modal.addTitle": "Spiel vorschlagen",
"modal.confirmDeleteTitle": "Bist du sicher?",
"modal.confirmDelete": "Löschen bestätigen",
"modal.save": "Änderungen speichern", "modal.save": "Änderungen speichern",
"modal.cancel": "Abbrechen", "modal.cancel": "Abbrechen",
"modal.close": "Schließen", "modal.close": "Schließen",

View File

@@ -353,13 +353,7 @@ export function buildCard(
if (allowDelete) { if (allowDelete) {
const del = card.querySelector("[data-delete]"); const del = card.querySelector("[data-delete]");
del.addEventListener("click", async () => { del.addEventListener("click", async () => {
try { openDeleteConfirmModal(s);
await api.deleteSuggestion(s.id);
toast(t("toast.suggestionDeleted"));
await window.loadSuggestData();
} catch (err) {
toast(err.message, true);
}
}); });
} }
return card; return card;
@@ -596,6 +590,64 @@ function formatMyVote(score) {
return `${score} ${scoreToEmoji(score)}`; return `${score} ${scoreToEmoji(score)}`;
} }
function openDeleteConfirmModal(s) {
const overlay = document.createElement("div");
overlay.className = "edit-modal";
const panel = document.createElement("div");
panel.className = "edit-panel";
panel.innerHTML = `
<div class="edit-header">
<h3>${t("modal.confirmDeleteTitle")}</h3>
<button class="lightbox-close" aria-label="${t("modal.close")}">x</button>
</div>
<div class="edit-body delete-body"></div>
`;
const preview = buildCard(
{ ...s, id: s.id }, // shallow copy to avoid mutations
{ showAuthor: true, allowDelete: false, allowEdit: false },
);
preview.classList.add("preview-card");
const actions = document.createElement("div");
actions.className = "stack horizontal";
const confirmBtn = document.createElement("button");
confirmBtn.className = "danger";
confirmBtn.textContent = t("modal.confirmDelete");
const cancelBtn = document.createElement("button");
cancelBtn.type = "button";
cancelBtn.className = "ghost";
cancelBtn.textContent = t("modal.cancel");
actions.append(confirmBtn, cancelBtn);
const body = panel.querySelector(".delete-body");
body?.append(preview, actions);
const close = () => overlay.remove();
overlay.addEventListener("click", (e) => {
if (
e.target.classList.contains("edit-modal") ||
e.target.classList.contains("lightbox-close")
)
close();
});
cancelBtn.addEventListener("click", close);
confirmBtn.addEventListener("click", async () => {
try {
await api.deleteSuggestion(s.id);
toast(t("toast.suggestionDeleted"));
close();
await window.loadSuggestData();
} catch (err) {
toast(err.message, true);
}
});
overlay.appendChild(panel);
document.body.appendChild(overlay);
}
function isValidImageUrl(url) { function isValidImageUrl(url) {
if (!url) return true; if (!url) return true;
try { try {

View File

@@ -610,6 +610,14 @@ input[type="range"].full-slider::-moz-range-track {
overflow: auto; overflow: auto;
max-height: 70vh; max-height: 70vh;
} }
.edit-modal .delete-body {
display: flex;
flex-direction: column;
gap: 12px;
}
.preview-card {
pointer-events: none;
}
.panel-header { .panel-header {
display: flex; display: flex;