From 9e2932fbc3e591b9cfb31e4d8dd9d74e285c74bb Mon Sep 17 00:00:00 2001 From: Brandon Zhang Date: Fri, 27 Mar 2026 18:51:34 +0800 Subject: [PATCH] Use styled modal dialogs for confirmations --- static/css/components.css | 27 ++++++++++++++++-- static/js/app.js | 58 +++++++++++++++++++++++++++++++++++++++ static/js/instructions.js | 20 ++++++++++++-- 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/static/css/components.css b/static/css/components.css index 497fe5e..0cf40a3 100644 --- a/static/css/components.css +++ b/static/css/components.css @@ -489,9 +489,9 @@ display: flex; align-items: center; justify-content: center; - background: rgba(0, 0, 0, 0.72); - backdrop-filter: blur(6px); - -webkit-backdrop-filter: blur(6px); + background: color-mix(in srgb, var(--bg-void) 44%, transparent); + backdrop-filter: blur(2px); + -webkit-backdrop-filter: blur(2px); } .auth-card { @@ -559,6 +559,27 @@ margin: 0; } +.confirm-card { + max-width: 420px; +} + +.confirm-card__icon--danger { + color: var(--red); + background: color-mix(in srgb, var(--red) 12%, transparent); + border-color: color-mix(in srgb, var(--red) 30%, transparent); +} + +.confirm-card__actions { + width: 100%; + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-3); +} + +.confirm-card__actions .btn { + width: 100%; +} + /* ── Quick shortcuts ─────────────────────────────────────────────────────── */ .shortcuts-container { diff --git a/static/js/app.js b/static/js/app.js index 210b9b2..8ceb7eb 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -27,6 +27,64 @@ export function toast(message, type = 'info') { }, 3000); } +export function confirmDialog({ + title, + message, + confirmText = 'Confirm', + cancelText = 'Cancel', + confirmClass = 'btn--danger', +}) { + document.getElementById('confirm-modal')?.remove(); + + return new Promise((resolve) => { + const overlay = document.createElement('div'); + overlay.id = 'confirm-modal'; + overlay.className = 'auth-overlay'; + overlay.tabIndex = -1; + overlay.innerHTML = ` + + `; + + document.body.appendChild(overlay); + + const cancelBtn = overlay.querySelector('[data-action="cancel"]'); + const confirmBtn = overlay.querySelector('[data-action="confirm"]'); + + const close = (result) => { + overlay.remove(); + resolve(result); + }; + + overlay.addEventListener('click', (e) => { + if (e.target === overlay) close(false); + }); + + cancelBtn.addEventListener('click', () => close(false)); + confirmBtn.addEventListener('click', () => close(true)); + + overlay.addEventListener('keydown', (e) => { + if (e.key === 'Escape') close(false); + }); + + overlay.focus(); + confirmBtn.focus(); + }); +} + // ── Token auth modal ────────────────────────────────────────────────────── function showTokenModal(onSuccess) { diff --git a/static/js/instructions.js b/static/js/instructions.js index 5ffcfe7..a0dffa1 100644 --- a/static/js/instructions.js +++ b/static/js/instructions.js @@ -6,7 +6,7 @@ import { state } from './state.js'; import { api } from './api.js'; -import { toast } from './app.js'; +import { confirmDialog, toast } from './app.js'; // ── SVG icon helpers ────────────────────────────────────────────────────── @@ -137,7 +137,14 @@ function renderPendingCard(item, index) { }); deleteBtn.addEventListener('click', async () => { - if (!confirm('Delete this instruction?')) return; + const confirmed = await confirmDialog({ + title: 'Delete instruction?', + message: 'This removes the pending instruction from the queue before any agent can consume it.', + confirmText: 'Delete Instruction', + cancelText: 'Keep Instruction', + }); + if (!confirmed) return; + deleteBtn.disabled = true; try { await api.deleteInstruction(item.id); @@ -215,7 +222,14 @@ export function initInstructions() { // Clear history button clearHistoryBtn.addEventListener('click', async () => { - if (!confirm('Clear all consumed instruction history? This cannot be undone.')) return; + const confirmed = await confirmDialog({ + title: 'Clear consumed history?', + message: 'This removes all consumed instructions from the history panel. This action cannot be undone.', + confirmText: 'Clear History', + cancelText: 'Keep History', + }); + if (!confirmed) return; + clearHistoryBtn.disabled = true; try { const res = await api.clearConsumed();