Use styled modal dialogs for confirmations
This commit is contained in:
@@ -489,9 +489,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: rgba(0, 0, 0, 0.72);
|
background: color-mix(in srgb, var(--bg-void) 44%, transparent);
|
||||||
backdrop-filter: blur(6px);
|
backdrop-filter: blur(2px);
|
||||||
-webkit-backdrop-filter: blur(6px);
|
-webkit-backdrop-filter: blur(2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-card {
|
.auth-card {
|
||||||
@@ -559,6 +559,27 @@
|
|||||||
margin: 0;
|
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 ─────────────────────────────────────────────────────── */
|
/* ── Quick shortcuts ─────────────────────────────────────────────────────── */
|
||||||
|
|
||||||
.shortcuts-container {
|
.shortcuts-container {
|
||||||
|
|||||||
@@ -27,6 +27,64 @@ export function toast(message, type = 'info') {
|
|||||||
}, 3000);
|
}, 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 ──────────────────────────────────────────────────────
|
// ── Token auth modal ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
function showTokenModal(onSuccess) {
|
function showTokenModal(onSuccess) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import { state } from './state.js';
|
import { state } from './state.js';
|
||||||
import { api } from './api.js';
|
import { api } from './api.js';
|
||||||
import { toast } from './app.js';
|
import { confirmDialog, toast } from './app.js';
|
||||||
|
|
||||||
// ── SVG icon helpers ──────────────────────────────────────────────────────
|
// ── SVG icon helpers ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -137,7 +137,14 @@ function renderPendingCard(item, index) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
deleteBtn.addEventListener('click', async () => {
|
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;
|
deleteBtn.disabled = true;
|
||||||
try {
|
try {
|
||||||
await api.deleteInstruction(item.id);
|
await api.deleteInstruction(item.id);
|
||||||
@@ -215,7 +222,14 @@ export function initInstructions() {
|
|||||||
|
|
||||||
// Clear history button
|
// Clear history button
|
||||||
clearHistoryBtn.addEventListener('click', async () => {
|
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;
|
clearHistoryBtn.disabled = true;
|
||||||
try {
|
try {
|
||||||
const res = await api.clearConsumed();
|
const res = await api.clearConsumed();
|
||||||
|
|||||||
Reference in New Issue
Block a user