Files
GoMFT/components/shared/toast/toast_js.templ
T
StarFleetCPTN 16e7b7e6e5 refactor: Improve toast notification rendering and event handling
- Refactored the ShowToastJS function to create toast elements using DOM methods for better safety and maintainability.
- Changed the event listener for the 'showToast' event from document.body to document for improved event handling.
- Ensured that the message content is set using textContent to prevent potential XSS vulnerabilities.
2025-04-07 11:21:11 -07:00

93 lines
3.5 KiB
Templ

package toast
templ ShowToastJS() {
<script>
// Notification system
function showToast(message, type) {
const toastContainer = document.getElementById('toast-container');
if (!toastContainer) {
console.error("Toast container not found!");
return;
}
// Create toast element
const toast = document.createElement('div');
toast.id = 'toast-' + type + '-' + Date.now();
toast.className = 'flex items-center w-full max-w-xs p-4 mb-4 rounded-lg shadow text-gray-500 bg-white dark:text-gray-400 dark:bg-gray-800 transform translate-y-16 opacity-0 transition-all duration-300 ease-out';
toast.role = 'alert';
// Set toast content based on type
let iconClass, bgColorClass, textColorClass;
if (type === 'success') {
iconClass = 'text-green-500 bg-green-100 dark:bg-green-800 dark:text-green-200';
bgColorClass = 'text-green-500 dark:text-green-200';
textColorClass = 'text-green-500 dark:text-green-200';
} else if (type === 'error') {
iconClass = 'text-red-500 bg-red-100 dark:bg-red-800 dark:text-red-200';
bgColorClass = 'text-red-500 dark:text-red-200';
textColorClass = 'text-red-500 dark:text-red-200';
} else { // Default to info
iconClass = 'text-blue-500 bg-blue-100 dark:bg-blue-800 dark:text-blue-200';
bgColorClass = 'text-blue-500 dark:text-blue-200';
textColorClass = 'text-blue-500 dark:text-blue-200';
}
// Create icon div
const iconDiv = document.createElement('div');
iconDiv.className = `inline-flex items-center justify-center flex-shrink-0 w-8 h-8 rounded-lg ${iconClass}`;
iconDiv.innerHTML = type === 'success'
? '<i class="fas fa-check"></i>'
: type === 'error'
? '<i class="fas fa-exclamation-circle"></i>'
: '<i class="fas fa-info-circle"></i>';
// Create message div and set text content safely
const messageDiv = document.createElement('div');
messageDiv.className = 'ml-3 text-sm font-normal';
messageDiv.textContent = message; // Use textContent for safety
// Create close button
const closeButton = document.createElement('button'); // Keep this declaration
closeButton.type = 'button';
closeButton.className = 'ml-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex h-8 w-8 dark:text-gray-500 dark:hover:text-white dark:bg-gray-800 dark:hover:bg-gray-700';
closeButton.setAttribute('data-dismiss-target', `#${toast.id}`);
closeButton.setAttribute('aria-label', 'Close');
closeButton.innerHTML = `
<span class="sr-only">Close</span>
<i class="fas fa-times"></i>
`;
// Append elements to the toast
toast.appendChild(iconDiv);
toast.appendChild(messageDiv);
toast.appendChild(closeButton);
// Add toast to container
toastContainer.appendChild(toast);
// Trigger animation after a small delay
setTimeout(() => {
toast.classList.remove('translate-y-16', 'opacity-0');
toast.classList.add('translate-y-0', 'opacity-100');
}, 10);
// Add event listener to the close button we created earlier
closeButton.addEventListener('click', function() { // Use the existing closeButton variable
// Animate out before removing
toast.classList.add('opacity-0', 'translate-y-4');
setTimeout(() => {
toast.remove();
}, 300);
});
// Auto-remove toast after 5 seconds
setTimeout(() => {
toast.classList.add('opacity-0', 'translate-y-4');
setTimeout(() => {
toast.remove();
}, 300);
}, 5000);
}
</script>
}