Use styled modal dialogs for confirmations
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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 = `
|
||||
<div class="auth-card confirm-card fade-in" role="dialog" aria-modal="true" aria-labelledby="confirm-title">
|
||||
<div class="auth-card__icon confirm-card__icon confirm-card__icon--danger">
|
||||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M12 9v4"/>
|
||||
<path d="M12 17h.01"/>
|
||||
<path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
<h2 id="confirm-title" class="auth-card__title">${title}</h2>
|
||||
<p class="auth-card__desc">${message}</p>
|
||||
<div class="confirm-card__actions">
|
||||
<button type="button" class="btn btn--ghost" data-action="cancel">${cancelText}</button>
|
||||
<button type="button" class="btn ${confirmClass}" data-action="confirm">${confirmText}</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user