feat(dashboard): replace emojis with Font Awesome, add theme support, and styled dialogs
This commit implements three major improvements to the dashboard system: 1. **Font Awesome Icons for Tabs** - Replace emoji tab icons (📊, 🌍, 🎒) with Font Awesome classes - Update defaultLayout.js with fa-solid icon classes - Add automatic migration for existing saved dashboards with emoji icons - Implement migrateEmojiIcons() to convert old emoji icons on load - Update fallback icons throughout the system 2. **Custom Theme Support for Dashboard** - Replace all --SmartTheme* variables with --rpg-* variables - Ensure custom themes (sci-fi, fantasy, cyberpunk) apply to dashboard - Update CSS for tabs, buttons, dropdowns, modals, and widget cards - Dashboard now respects extension themes instead of main SillyTavern theme 3. **Styled Confirmation Dialogs** - Create confirmDialog.js with showConfirmDialog() and showAlertDialog() - Support three variants: danger (red), warning (yellow), info (blue) - Add keyboard navigation (Enter/Escape) and accessibility features - Replace all native confirm() and alert() calls with styled dialogs - Add confirmation dialog modal to dashboardTemplate.html Files Modified: - src/systems/dashboard/confirmDialog.js (NEW) - src/systems/dashboard/dashboardManager.js - src/systems/dashboard/defaultLayout.js - src/systems/dashboard/tabManager.js - src/systems/dashboard/dashboardIntegration.js - src/systems/dashboard/editModeManager.js - src/systems/dashboard/widgets/inventoryWidget.js - src/systems/dashboard/dashboardTemplate.html - style.css
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Confirmation Dialog System
|
||||
*
|
||||
* Provides styled confirmation and alert dialogs to replace native browser popups.
|
||||
* Supports three variants: danger (red), warning (yellow), and info (blue).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Show a confirmation dialog
|
||||
* @param {Object} options - Dialog options
|
||||
* @param {string} options.title - Dialog title
|
||||
* @param {string} options.message - Dialog message
|
||||
* @param {string} [options.variant='danger'] - Dialog variant: 'danger', 'warning', or 'info'
|
||||
* @param {string} [options.confirmText='Confirm'] - Confirm button text
|
||||
* @param {string} [options.cancelText='Cancel'] - Cancel button text
|
||||
* @param {Function} [options.onConfirm] - Callback when confirmed
|
||||
* @param {Function} [options.onCancel] - Callback when cancelled
|
||||
* @returns {Promise<boolean>} Resolves to true if confirmed, false if cancelled
|
||||
*/
|
||||
export function showConfirmDialog(options) {
|
||||
return new Promise((resolve) => {
|
||||
const {
|
||||
title = 'Confirm Action',
|
||||
message = 'Are you sure?',
|
||||
variant = 'danger',
|
||||
confirmText = 'Confirm',
|
||||
cancelText = 'Cancel',
|
||||
onConfirm = null,
|
||||
onCancel = null
|
||||
} = options;
|
||||
|
||||
// Get modal elements
|
||||
const modal = document.getElementById('rpg-confirm-dialog');
|
||||
const modalContent = modal.querySelector('.rpg-confirm-content');
|
||||
const icon = document.getElementById('rpg-confirm-icon');
|
||||
const titleEl = document.getElementById('rpg-confirm-title');
|
||||
const messageEl = document.getElementById('rpg-confirm-message');
|
||||
const confirmBtn = document.getElementById('rpg-confirm-confirm');
|
||||
const cancelBtn = document.getElementById('rpg-confirm-cancel');
|
||||
const closeBtn = modal.querySelector('.rpg-confirm-close');
|
||||
|
||||
if (!modal) {
|
||||
console.error('[ConfirmDialog] Modal not found');
|
||||
return resolve(false);
|
||||
}
|
||||
|
||||
// Set icon based on variant
|
||||
const iconMap = {
|
||||
danger: 'fa-solid fa-triangle-exclamation',
|
||||
warning: 'fa-solid fa-circle-exclamation',
|
||||
info: 'fa-solid fa-circle-info'
|
||||
};
|
||||
icon.className = `rpg-confirm-icon ${iconMap[variant] || iconMap.danger}`;
|
||||
|
||||
// Set variant class on modal content
|
||||
modalContent.className = `rpg-modal-content rpg-confirm-content rpg-confirm-${variant}`;
|
||||
|
||||
// Set content
|
||||
titleEl.textContent = title;
|
||||
messageEl.textContent = message;
|
||||
confirmBtn.textContent = confirmText;
|
||||
cancelBtn.textContent = cancelText;
|
||||
|
||||
// Show modal
|
||||
modal.style.display = 'flex';
|
||||
|
||||
// Handle confirm
|
||||
const handleConfirm = () => {
|
||||
modal.style.display = 'none';
|
||||
cleanup();
|
||||
if (onConfirm) onConfirm();
|
||||
resolve(true);
|
||||
};
|
||||
|
||||
// Handle cancel
|
||||
const handleCancel = () => {
|
||||
modal.style.display = 'none';
|
||||
cleanup();
|
||||
if (onCancel) onCancel();
|
||||
resolve(false);
|
||||
};
|
||||
|
||||
// Handle keyboard
|
||||
const handleKeyDown = (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
handleCancel();
|
||||
} else if (e.key === 'Enter') {
|
||||
handleConfirm();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle backdrop click
|
||||
const handleBackdropClick = (e) => {
|
||||
if (e.target === modal) {
|
||||
handleCancel();
|
||||
}
|
||||
};
|
||||
|
||||
// Clean up event listeners
|
||||
const cleanup = () => {
|
||||
confirmBtn.removeEventListener('click', handleConfirm);
|
||||
cancelBtn.removeEventListener('click', handleCancel);
|
||||
closeBtn.removeEventListener('click', handleCancel);
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
modal.removeEventListener('click', handleBackdropClick);
|
||||
};
|
||||
|
||||
// Attach event listeners
|
||||
confirmBtn.addEventListener('click', handleConfirm);
|
||||
cancelBtn.addEventListener('click', handleCancel);
|
||||
closeBtn.addEventListener('click', handleCancel);
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
modal.addEventListener('click', handleBackdropClick);
|
||||
|
||||
// Focus confirm button
|
||||
setTimeout(() => confirmBtn.focus(), 100);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an alert dialog (info only, single OK button)
|
||||
* @param {Object} options - Dialog options
|
||||
* @param {string} options.title - Dialog title
|
||||
* @param {string} options.message - Dialog message
|
||||
* @param {string} [options.variant='info'] - Dialog variant: 'danger', 'warning', or 'info'
|
||||
* @param {string} [options.okText='OK'] - OK button text
|
||||
* @param {Function} [options.onOk] - Callback when OK clicked
|
||||
* @returns {Promise<void>} Resolves when OK clicked
|
||||
*/
|
||||
export function showAlertDialog(options) {
|
||||
return new Promise((resolve) => {
|
||||
const {
|
||||
title = 'Alert',
|
||||
message = '',
|
||||
variant = 'info',
|
||||
okText = 'OK',
|
||||
onOk = null
|
||||
} = options;
|
||||
|
||||
// Get modal elements
|
||||
const modal = document.getElementById('rpg-confirm-dialog');
|
||||
const modalContent = modal.querySelector('.rpg-confirm-content');
|
||||
const icon = document.getElementById('rpg-confirm-icon');
|
||||
const titleEl = document.getElementById('rpg-confirm-title');
|
||||
const messageEl = document.getElementById('rpg-confirm-message');
|
||||
const confirmBtn = document.getElementById('rpg-confirm-confirm');
|
||||
const cancelBtn = document.getElementById('rpg-confirm-cancel');
|
||||
const closeBtn = modal.querySelector('.rpg-confirm-close');
|
||||
|
||||
if (!modal) {
|
||||
console.error('[ConfirmDialog] Modal not found');
|
||||
return resolve();
|
||||
}
|
||||
|
||||
// Set icon based on variant
|
||||
const iconMap = {
|
||||
danger: 'fa-solid fa-triangle-exclamation',
|
||||
warning: 'fa-solid fa-circle-exclamation',
|
||||
info: 'fa-solid fa-circle-info'
|
||||
};
|
||||
icon.className = `rpg-confirm-icon ${iconMap[variant] || iconMap.info}`;
|
||||
|
||||
// Set variant class on modal content
|
||||
modalContent.className = `rpg-modal-content rpg-confirm-content rpg-confirm-${variant}`;
|
||||
|
||||
// Set content
|
||||
titleEl.textContent = title;
|
||||
messageEl.textContent = message;
|
||||
confirmBtn.textContent = okText;
|
||||
|
||||
// Hide cancel button for alerts
|
||||
cancelBtn.style.display = 'none';
|
||||
|
||||
// Show modal
|
||||
modal.style.display = 'flex';
|
||||
|
||||
// Handle OK
|
||||
const handleOk = () => {
|
||||
modal.style.display = 'none';
|
||||
cancelBtn.style.display = ''; // Restore for future confirms
|
||||
cleanup();
|
||||
if (onOk) onOk();
|
||||
resolve();
|
||||
};
|
||||
|
||||
// Handle keyboard
|
||||
const handleKeyDown = (e) => {
|
||||
if (e.key === 'Escape' || e.key === 'Enter') {
|
||||
handleOk();
|
||||
}
|
||||
};
|
||||
|
||||
// Handle backdrop click
|
||||
const handleBackdropClick = (e) => {
|
||||
if (e.target === modal) {
|
||||
handleOk();
|
||||
}
|
||||
};
|
||||
|
||||
// Clean up event listeners
|
||||
const cleanup = () => {
|
||||
confirmBtn.removeEventListener('click', handleOk);
|
||||
closeBtn.removeEventListener('click', handleOk);
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
modal.removeEventListener('click', handleBackdropClick);
|
||||
};
|
||||
|
||||
// Attach event listeners
|
||||
confirmBtn.addEventListener('click', handleOk);
|
||||
closeBtn.addEventListener('click', handleOk);
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
modal.addEventListener('click', handleBackdropClick);
|
||||
|
||||
// Focus OK button
|
||||
setTimeout(() => confirmBtn.focus(), 100);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user