feat: delete button for all boards + custom confirm dialog

- Show × delete button for all boards (not just userCreated)
- Custom confirm dialog "Wirklich löschen?" replaces browser confirm()
- HIDDEN_BOARDS: deleted DEFAULTS boards persist via kanban_hidden in localStorage
- loadHidden() called before loadState() so hidden boards are excluded on load

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Robin Choice
2026-05-20 16:46:54 +02:00
parent 02cd75a8bb
commit 59b1f000b9

View File

@@ -376,6 +376,10 @@ body { background:var(--bg); color:var(--text); font-family:-apple-system,BlinkM
.promote-ok { flex:1; padding:7px; background:var(--accent); color:#fff; border:none; border-radius:5px; font-size:12px; font-weight:700; cursor:pointer; }
.promote-ok:hover { opacity:.85; }
.promote-cancel { padding:7px 12px; background:var(--surface2); border:1px solid var(--border2); color:var(--text-muted); border-radius:5px; font-size:12px; cursor:pointer; }
.confirm-box { background:var(--surface); border:1px solid var(--border2); border-radius:10px; padding:20px; width:260px; box-shadow:0 8px 32px rgba(0,0,0,.5); }
.confirm-msg { font-size:13px; color:var(--text); margin-bottom:14px; }
.confirm-ok { flex:1; padding:7px; background:var(--red); color:#fff; border:none; border-radius:5px; font-size:12px; font-weight:700; cursor:pointer; }
.confirm-ok:hover { opacity:.85; }
</style>
</head>
<body>
@@ -514,6 +518,16 @@ body { background:var(--bg); color:var(--text); font-family:-apple-system,BlinkM
</div>
</div>
<div id="confirm-overlay" style="display:none" class="promote-overlay" onclick="if(event.target===this)closeConfirm()">
<div class="confirm-box">
<div class="confirm-msg" id="confirm-msg"></div>
<div class="promote-btns">
<button class="confirm-ok" id="confirm-ok">Löschen</button>
<button class="promote-cancel" onclick="closeConfirm()">Abbrechen</button>
</div>
</div>
</div>
<script>
// ── BOARD DATA ────────────────────────────────────────────────────────────
const TODAY = new Date('2026-05-19');
@@ -934,6 +948,9 @@ function getBoardsForGroup(g) {
// ── STATE (localStorage) ──────────────────────────────────────────────────
let BOARDS = {};
let HIDDEN_BOARDS = new Set();
function loadHidden() { try { HIDDEN_BOARDS = new Set(JSON.parse(localStorage.getItem('kanban_hidden') || '[]')); } catch {} }
function saveHidden() { localStorage.setItem('kanban_hidden', JSON.stringify([...HIDDEN_BOARDS])); }
function deepClone(o) { return JSON.parse(JSON.stringify(o)); }
@@ -956,6 +973,7 @@ function migrateCols(board) {
function loadState() {
BOARDS = deepClone(DEFAULTS);
HIDDEN_BOARDS.forEach(id => { delete BOARDS[id]; });
Object.keys(BOARDS).forEach(id => {
const m = BOARD_META[id] || {group:'Privat', color:'#7c6af7', ring:'?'};
BOARDS[id].group = m.group;
@@ -1069,28 +1087,31 @@ function saveBoardSetting(key, el, min, max) {
if (curView === 'analytics') renderAnalytics(curId);
}
function showConfirm(msg, onOk) {
document.getElementById('confirm-msg').textContent = msg;
document.getElementById('confirm-ok').onclick = () => { closeConfirm(); onOk(); };
document.getElementById('confirm-overlay').style.display = 'flex';
}
function closeConfirm() { document.getElementById('confirm-overlay').style.display = 'none'; }
function resetCurrentBoard() {
const b = BOARDS[curId];
if (b.userCreated) {
if (!confirm(`"${b.name}" löschen?`)) return;
deleteBoard(curId);
return;
}
if (!confirm(`"${b.name}" auf Standardzustand zurücksetzen?`)) return;
BOARDS[curId].cols = deepClone(DEFAULTS[curId].cols);
saveState();
show(curId);
renderSidebar();
if (b.userCreated) { deleteBoard(curId); return; }
showConfirm(`"${b.name}" auf Standardzustand zurücksetzen?`, () => {
BOARDS[curId].cols = deepClone(DEFAULTS[curId].cols);
saveState(); show(curId); renderSidebar();
});
}
function deleteBoard(id, e) {
if (e) e.stopPropagation();
if (!confirm(`"${BOARDS[id].name}" löschen?`)) return;
delete BOARDS[id];
saveState();
const firstId = Object.keys(BOARDS)[0];
show(firstId);
renderSidebar();
showConfirm(`"${BOARDS[id]?.name}" wirklich löschen?`, () => {
if (!BOARDS[id].userCreated) { HIDDEN_BOARDS.add(id); saveHidden(); }
delete BOARDS[id];
saveState();
const firstId = Object.keys(BOARDS)[0];
show(firstId); renderSidebar();
});
}
function addCard(boardId, colId, text) {
@@ -2157,8 +2178,7 @@ function renderSidebar() {
const rem = remaining(b);
const blk = hasBlocker(b);
const badgeCls = blk ? ' blk' : colCount(b,'wip') > 0 ? ' wip' : '';
const del = b.userCreated
? `<span class="nav-del" onclick="deleteBoard('${id}',event)">×</span>` : '';
const del = `<span class="nav-del" onclick="deleteBoard('${id}',event)">×</span>`;
const ring = b.ring || '?';
const ringCls = ring === '?' ? 'r-q' : 'r-' + ring;
const ringLbl = RING_LABELS[ring] || '?';
@@ -2376,7 +2396,7 @@ function renderIdeas() {
// ── EXPORT / IMPORT ──────────────────────────────────────────────────────────
function exportState() {
const keys = ['kanban_v2','kanban_groups','kanban_board_order','kanban_ideas','kanban_ideas_seeded','kanban_cards_seeded'];
const keys = ['kanban_v2','kanban_groups','kanban_board_order','kanban_ideas','kanban_ideas_seeded','kanban_hidden'];
const snap = {};
keys.forEach(k => { const v = localStorage.getItem(k); if (v !== null) snap[k] = v; });
const blob = new Blob([JSON.stringify(snap, null, 2)], {type:'application/json'});
@@ -2407,6 +2427,7 @@ if (window.location.protocol === 'file:') {
}
loadGroups();
loadBoardOrder();
loadHidden();
loadState();
renderSidebar();
loadIdeas();