diff --git a/css/style.css b/css/style.css index cb24455..12926cc 100644 --- a/css/style.css +++ b/css/style.css @@ -215,7 +215,7 @@ input:focus, select:focus { border-color:var(--accent); } /* Trash */ .trash-badge { background:var(--danger); color:#fff; padding:0.15rem 0.5rem; border-radius:1rem; font-size:0.65rem; margin-left:0.3rem; } .trash-info { font-size:0.7rem; color:var(--text2); margin-top:0.2rem; } -.restore-btn { background:var(--success); color:#fff; border:none; padding:0.2rem 0.6rem; border-radius:1.5rem; cursor:pointer; font-size:0.7rem; } +.restore-btn { background:none; color:#fff; border:none; padding:0.2rem 0.6rem; border-radius:1.5rem; cursor:pointer; font-size:0.7rem; } .restore-btn:hover { filter:brightness(1.2); } .empty-trash-btn { background:var(--danger); color:#fff; border:none; padding:0.3rem 0.8rem; border-radius:1.5rem; cursor:pointer; font-size:0.75rem; } .empty-trash-btn:hover { filter:brightness(1.2); } @@ -331,4 +331,6 @@ input:focus, select:focus { border-color:var(--accent); } border-color:var(--danger)!important; box-shadow:0 0 15px rgba(239,68,68,0.4); background:rgba(239,68,68,0.15); -} \ No newline at end of file +} +/* Batch confirm modal backdrop */ +.batch-confirm-overlay { background:rgba(0,0,0,0.3); } \ No newline at end of file diff --git a/js/app.js b/js/app.js index 5d2b37c..e240198 100644 --- a/js/app.js +++ b/js/app.js @@ -305,10 +305,13 @@ async function permanentDelete(id, silent) { try { const r = await fetch(API + '/entries/' + id + '?permanent=1', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } }); if (r.ok) { order = order.filter(x => x != id); localStorage.setItem('entryOrder', JSON.stringify(order)); if (!silent) { toast('🗑️ Permanently deleted'); await loadEntries(); playSound('error'); } } } catch (e) { if (!silent) toast('⚠️ Error', 'error'); } }; if (silent) { await doDelete(); return; } - showCenterConfirm('Permanently delete?', doDelete); + const btn = document.querySelector('.delete-btn[data-id="' + id + '"]'); + if (btn) showBatchConfirm(btn, 'Permanently delete?', doDelete); + else showBatchConfirm(document.body, 'Permanently delete?', doDelete); } async function emptyTrash() { - showCenterConfirm('Delete ALL trashed entries?', async () => { + const btn = document.querySelector('.empty-trash-btn'); + showBatchConfirm(btn || document.body, 'Delete ALL trashed entries?', async () => { try { const r = await fetch(API + '/entries/trash/empty', { method: 'DELETE', headers: { 'Authorization': 'Bearer ' + token, 'X-CSRF-Token': csrfToken } }); if (r.ok) { toast('🗑️ Trash emptied'); await loadEntries(); playSound('error'); } } catch (e) { toast('⚠️ Error', 'error'); } }); } @@ -941,35 +944,40 @@ function showConfirm(btn, message, callback) { }, 10); } function entryPw(id) { const e = entries.find(x => x.id == id); return e ? e.password : ''; } -function showCenterConfirm(message, callback) { - const existing = document.querySelector('.custom-confirm'); +function showBatchConfirm(btn, message, callback) { + const existing = document.querySelector('.batch-confirm-overlay'); if (existing) existing.remove(); + const overlay = document.createElement('div'); + overlay.className = 'batch-confirm-overlay'; + overlay.style.cssText = 'position:fixed;top:0;left:0;right:0;bottom:0;z-index:9999;background:transparent;'; const confirm = document.createElement('div'); confirm.className = 'custom-confirm show'; - confirm.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:10000;'; + confirm.style.cssText = 'position:fixed;background:var(--bg2);border:1px solid var(--accent);border-radius:0.8rem;padding:0.7rem 1rem;z-index:10000;box-shadow:0 10px 30px rgba(0,0,0,0.5);font-size:0.8rem;color:var(--text);white-space:nowrap;'; confirm.innerHTML = '