infinite-agents-public/src_enhanced/ui_enhanced_5.html

1019 lines
38 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modal Enhanced</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-color: #5b69ff;
--secondary-color: #ff6b6b;
--success-color: #51cf66;
--warning-color: #ffd93d;
--bg-color: #f8f9fa;
--text-color: #2c3e50;
--border-color: #e1e8ed;
--shadow-sm: 0 2px 4px rgba(0, 0, 0, 0.04);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
--shadow-lg: 0 12px 28px rgba(0, 0, 0, 0.12);
--shadow-xl: 0 20px 48px rgba(0, 0, 0, 0.16);
--modal-max-width: 600px;
--modal-animation-duration: 0.3s;
--modal-animation-easing: cubic-bezier(0.34, 1.56, 0.64, 1);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background-color: var(--bg-color);
color: var(--text-color);
line-height: 1.6;
min-height: 100vh;
padding: 40px 20px;
}
main {
max-width: 1200px;
margin: 0 auto;
}
h1 {
font-size: 2.5rem;
font-weight: 700;
background: linear-gradient(135deg, var(--primary-color), #7c3aed);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-align: center;
margin-bottom: 50px;
}
.component-showcase {
background: white;
border-radius: 20px;
padding: 40px;
box-shadow: var(--shadow-md);
}
.demo-controls {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.btn {
padding: 12px 24px;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
position: relative;
overflow: hidden;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.btn::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.btn:active::before {
width: 300px;
height: 300px;
}
.btn-primary {
background: linear-gradient(135deg, var(--primary-color), #7c3aed);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(91, 105, 255, 0.3);
}
.btn-secondary {
background: #e3e8ef;
color: var(--text-color);
}
.btn-secondary:hover {
background: #d4dae5;
transform: translateY(-1px);
}
.btn-danger {
background: linear-gradient(135deg, var(--secondary-color), #ff5252);
color: white;
}
.btn-danger:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(255, 107, 107, 0.3);
}
.btn-success {
background: linear-gradient(135deg, var(--success-color), #42c767);
color: white;
}
.btn-loading {
color: transparent;
pointer-events: none;
}
.btn-loading::after {
content: '';
position: absolute;
width: 20px;
height: 20px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-top-color: white;
border-radius: 50%;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: translate(-50%, -50%) rotate(360deg); }
}
/* Modal Styles */
.modal-backdrop {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
z-index: 1000;
opacity: 0;
transition: opacity var(--modal-animation-duration) ease;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.modal-backdrop.active {
opacity: 1;
}
.modal {
background: white;
border-radius: 20px;
max-width: var(--modal-max-width);
width: 100%;
max-height: 90vh;
display: flex;
flex-direction: column;
box-shadow: var(--shadow-xl);
transform: translateY(20px) scale(0.95);
opacity: 0;
transition: all var(--modal-animation-duration) var(--modal-animation-easing);
position: relative;
}
.modal-backdrop.active .modal {
transform: translateY(0) scale(1);
opacity: 1;
}
.modal-header {
padding: 24px 32px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
position: sticky;
top: 0;
background: white;
border-radius: 20px 20px 0 0;
z-index: 10;
}
.modal-title {
font-size: 1.5rem;
font-weight: 700;
color: var(--text-color);
margin: 0;
}
.modal-close {
width: 36px;
height: 36px;
border: none;
background: #f3f4f6;
border-radius: 10px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
color: #6b7280;
}
.modal-close:hover {
background: #e5e7eb;
transform: rotate(90deg);
}
.modal-close:focus {
outline: 2px solid var(--primary-color);
outline-offset: 2px;
}
.modal-body {
padding: 32px;
overflow-y: auto;
flex: 1;
position: relative;
}
.modal-body::-webkit-scrollbar {
width: 8px;
}
.modal-body::-webkit-scrollbar-track {
background: #f3f4f6;
border-radius: 4px;
}
.modal-body::-webkit-scrollbar-thumb {
background: #d1d5db;
border-radius: 4px;
}
.modal-body::-webkit-scrollbar-thumb:hover {
background: #9ca3af;
}
.modal-footer {
padding: 24px 32px;
border-top: 1px solid var(--border-color);
display: flex;
gap: 12px;
justify-content: flex-end;
flex-shrink: 0;
position: sticky;
bottom: 0;
background: white;
border-radius: 0 0 20px 20px;
}
/* Modal Sizes */
.modal.modal-sm {
--modal-max-width: 400px;
}
.modal.modal-lg {
--modal-max-width: 800px;
}
.modal.modal-xl {
--modal-max-width: 1200px;
}
.modal.modal-fullscreen {
--modal-max-width: 100%;
max-height: 100%;
height: 100%;
border-radius: 0;
}
.modal.modal-fullscreen .modal-header,
.modal.modal-fullscreen .modal-footer {
border-radius: 0;
}
/* Stacked Modals */
.modal-backdrop[data-level="2"] {
z-index: 1010;
}
.modal-backdrop[data-level="3"] {
z-index: 1020;
}
.modal-backdrop[data-level="2"] .modal {
transform: translateY(40px) scale(0.9);
}
.modal-backdrop[data-level="3"] .modal {
transform: translateY(60px) scale(0.85);
}
/* Loading State */
.modal-loading {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255, 255, 255, 0.9);
display: flex;
align-items: center;
justify-content: center;
border-radius: 20px;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
z-index: 20;
}
.modal-loading.active {
opacity: 1;
pointer-events: all;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid #f3f4f6;
border-top-color: var(--primary-color);
border-radius: 50%;
animation: spin 1s linear infinite;
}
/* Confirmation Dialog */
.confirmation-icon {
width: 80px;
height: 80px;
margin: 0 auto 24px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
font-size: 36px;
}
.confirmation-icon.warning {
background: #fef3c7;
color: #f59e0b;
}
.confirmation-icon.danger {
background: #fee2e2;
color: #ef4444;
}
.confirmation-icon.success {
background: #d1fae5;
color: #10b981;
}
/* Demo Content */
.demo-form {
display: flex;
flex-direction: column;
gap: 24px;
}
.form-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.form-group label {
font-weight: 600;
color: var(--text-color);
}
.form-control {
padding: 12px 16px;
border: 2px solid var(--border-color);
border-radius: 10px;
font-size: 16px;
transition: all 0.2s ease;
}
.form-control:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(91, 105, 255, 0.1);
}
/* Accessibility */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
/* Reduced Motion */
@media (prefers-reduced-motion: reduce) {
.modal-backdrop,
.modal,
.btn,
.modal-close {
transition-duration: 0.01ms !important;
}
.btn-loading::after,
.spinner {
animation-duration: 0.01ms !important;
}
}
/* Mobile Styles */
@media (max-width: 640px) {
.modal {
margin: 10px;
}
.modal-header,
.modal-body,
.modal-footer {
padding: 20px;
}
.modal.modal-fullscreen {
margin: 0;
}
}
/* Demo Description */
.demo-description {
margin-bottom: 30px;
padding: 20px;
background: #f8f9fb;
border-radius: 12px;
border-left: 4px solid var(--primary-color);
}
.demo-description h2 {
font-size: 1.2rem;
margin-bottom: 10px;
color: var(--primary-color);
}
.demo-description ul {
list-style: none;
padding-left: 0;
}
.demo-description li {
padding-left: 24px;
position: relative;
margin-bottom: 8px;
}
.demo-description li::before {
content: '✨';
position: absolute;
left: 0;
}
</style>
</head>
<body>
<main>
<h1>Modal - Enhanced</h1>
<div class="component-showcase">
<div class="demo-description">
<h2>Enhanced Modal Features</h2>
<ul>
<li>Smooth slide + fade entrance animations</li>
<li>Beautiful backdrop blur with fallback</li>
<li>Complete focus trap with tab cycling</li>
<li>Escape key and backdrop click to close</li>
<li>Support for stacked modals</li>
<li>Responsive sizing with mobile full-screen</li>
<li>Sticky header/footer for long content</li>
<li>Loading states within modals</li>
<li>Confirmation dialogs with proper focus</li>
<li>Smooth scrolling with custom scrollbar</li>
<li>Full keyboard navigation</li>
<li>ARIA attributes for accessibility</li>
</ul>
</div>
<div class="demo-controls">
<button class="btn btn-primary" onclick="openModal('basic')">
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"></path>
</svg>
Basic Modal
</button>
<button class="btn btn-primary" onclick="openModal('form')">
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
Form Modal
</button>
<button class="btn btn-primary" onclick="openModal('long')">
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
Long Content
</button>
<button class="btn btn-danger" onclick="openModal('confirm')">
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
</svg>
Confirmation Dialog
</button>
<button class="btn btn-secondary" onclick="openModal('sizes')">
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"></path>
</svg>
Modal Sizes
</button>
<button class="btn btn-secondary" onclick="openModal('loading')">
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
</svg>
Loading State
</button>
</div>
</div>
</main>
<script>
// Modal Manager
class ModalManager {
constructor() {
this.activeModals = [];
this.focusableElements = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';
this.lastFocusedElement = null;
this.init();
}
init() {
document.addEventListener('keydown', this.handleKeydown.bind(this));
}
createModal(options = {}) {
const {
title = 'Modal Title',
content = '',
size = 'default',
showFooter = true,
buttons = [
{ text: 'Cancel', type: 'secondary', action: 'close' },
{ text: 'Save', type: 'primary', action: 'save' }
],
onClose = null,
onSave = null
} = options;
const level = this.activeModals.length + 1;
const modalId = `modal-${Date.now()}`;
// Create backdrop
const backdrop = document.createElement('div');
backdrop.className = 'modal-backdrop';
backdrop.setAttribute('data-level', level);
backdrop.setAttribute('role', 'dialog');
backdrop.setAttribute('aria-modal', 'true');
backdrop.setAttribute('aria-labelledby', `${modalId}-title`);
// Create modal
const modal = document.createElement('div');
modal.className = `modal ${size !== 'default' ? `modal-${size}` : ''}`;
modal.id = modalId;
// Header
const header = document.createElement('div');
header.className = 'modal-header';
const titleEl = document.createElement('h2');
titleEl.className = 'modal-title';
titleEl.id = `${modalId}-title`;
titleEl.textContent = title;
const closeBtn = document.createElement('button');
closeBtn.className = 'modal-close';
closeBtn.setAttribute('aria-label', 'Close modal');
closeBtn.innerHTML = `
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
`;
header.appendChild(titleEl);
header.appendChild(closeBtn);
// Body
const body = document.createElement('div');
body.className = 'modal-body';
body.innerHTML = content;
// Footer
const footer = document.createElement('div');
footer.className = 'modal-footer';
if (showFooter) {
buttons.forEach((button, index) => {
const btn = document.createElement('button');
btn.className = `btn btn-${button.type}`;
btn.textContent = button.text;
if (button.action === 'close') {
btn.onclick = () => this.closeModal(backdrop);
} else if (button.action === 'save' && onSave) {
btn.onclick = () => {
onSave();
this.closeModal(backdrop);
};
} else if (button.onClick) {
btn.onclick = button.onClick;
}
// Focus primary button by default
if (button.type === 'primary' && index === buttons.length - 1) {
btn.setAttribute('data-initial-focus', 'true');
}
footer.appendChild(btn);
});
}
// Loading overlay
const loadingOverlay = document.createElement('div');
loadingOverlay.className = 'modal-loading';
loadingOverlay.innerHTML = '<div class="spinner"></div>';
// Assemble modal
modal.appendChild(header);
modal.appendChild(body);
if (showFooter) {
modal.appendChild(footer);
}
modal.appendChild(loadingOverlay);
backdrop.appendChild(modal);
// Event listeners
closeBtn.onclick = () => this.closeModal(backdrop);
backdrop.onclick = (e) => {
if (e.target === backdrop) {
this.closeModal(backdrop);
}
};
// Store modal info
this.activeModals.push({
backdrop,
modal,
onClose,
level
});
return { backdrop, modal, loadingOverlay };
}
openModal(options) {
// Store last focused element
this.lastFocusedElement = document.activeElement;
const { backdrop, modal } = this.createModal(options);
// Add to DOM
document.body.appendChild(backdrop);
// Force reflow
backdrop.offsetHeight;
// Trigger animation
requestAnimationFrame(() => {
backdrop.classList.add('active');
// Set initial focus
setTimeout(() => {
const initialFocus = modal.querySelector('[data-initial-focus]') ||
modal.querySelector(this.focusableElements);
if (initialFocus) {
initialFocus.focus();
}
}, 300);
});
return { backdrop, modal };
}
closeModal(backdrop) {
const modalIndex = this.activeModals.findIndex(m => m.backdrop === backdrop);
if (modalIndex === -1) return;
const modalInfo = this.activeModals[modalIndex];
// Remove active class
backdrop.classList.remove('active');
// Wait for animation
setTimeout(() => {
backdrop.remove();
this.activeModals.splice(modalIndex, 1);
// Restore focus
if (this.activeModals.length === 0 && this.lastFocusedElement) {
this.lastFocusedElement.focus();
this.lastFocusedElement = null;
} else if (this.activeModals.length > 0) {
// Focus previous modal
const prevModal = this.activeModals[this.activeModals.length - 1];
const focusEl = prevModal.modal.querySelector(this.focusableElements);
if (focusEl) focusEl.focus();
}
// Call onClose callback
if (modalInfo.onClose) {
modalInfo.onClose();
}
}, 300);
}
handleKeydown(e) {
if (this.activeModals.length === 0) return;
const currentModal = this.activeModals[this.activeModals.length - 1];
// Escape key
if (e.key === 'Escape') {
e.preventDefault();
this.closeModal(currentModal.backdrop);
return;
}
// Tab key - focus trap
if (e.key === 'Tab') {
const focusableElements = currentModal.modal.querySelectorAll(this.focusableElements);
const focusableArray = Array.from(focusableElements);
if (focusableArray.length === 0) return;
const currentIndex = focusableArray.indexOf(document.activeElement);
if (e.shiftKey) {
// Backward tab
e.preventDefault();
const prevIndex = currentIndex <= 0 ? focusableArray.length - 1 : currentIndex - 1;
focusableArray[prevIndex].focus();
} else {
// Forward tab
if (currentIndex === focusableArray.length - 1) {
e.preventDefault();
focusableArray[0].focus();
}
}
}
}
showLoading(modal) {
const loadingOverlay = modal.querySelector('.modal-loading');
if (loadingOverlay) {
loadingOverlay.classList.add('active');
}
}
hideLoading(modal) {
const loadingOverlay = modal.querySelector('.modal-loading');
if (loadingOverlay) {
loadingOverlay.classList.remove('active');
}
}
}
// Initialize modal manager
const modalManager = new ModalManager();
// Demo modal functions
function openModal(type) {
switch(type) {
case 'basic':
modalManager.openModal({
title: 'Welcome to Enhanced Modals',
content: `
<p>This modal demonstrates all the enhanced features:</p>
<ul style="padding-left: 20px; margin-top: 16px;">
<li>Smooth entrance and exit animations</li>
<li>Backdrop blur effect</li>
<li>Focus trap with tab cycling</li>
<li>Keyboard navigation (try Tab and Escape)</li>
<li>Click outside to close</li>
</ul>
<p style="margin-top: 20px;">Try opening multiple modals to see stacking in action!</p>
`
});
break;
case 'form':
modalManager.openModal({
title: 'User Information',
content: `
<form class="demo-form" onsubmit="handleFormSubmit(event)">
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" class="form-control" placeholder="Enter your name" required>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" class="form-control" placeholder="Enter your email" required>
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea id="message" class="form-control" rows="4" placeholder="Enter your message"></textarea>
</div>
</form>
`,
buttons: [
{ text: 'Cancel', type: 'secondary', action: 'close' },
{ text: 'Submit', type: 'primary', onClick: () => handleFormSubmit() }
]
});
break;
case 'long':
modalManager.openModal({
title: 'Terms of Service',
size: 'lg',
content: `
<h3>1. Introduction</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<h3>2. User Agreement</h3>
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
<h3>3. Privacy Policy</h3>
<p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium.</p>
<h3>4. Data Collection</h3>
<p>Totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit.</p>
<h3>5. User Rights</h3>
<p>Sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit.</p>
<h3>6. Limitations</h3>
<p>Sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam.</p>
<h3>7. Modifications</h3>
<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident.</p>
<h3>8. Contact Information</h3>
<p>Similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.</p>
`,
buttons: [
{ text: 'Decline', type: 'secondary', action: 'close' },
{ text: 'Accept', type: 'success', action: 'close' }
]
});
break;
case 'confirm':
modalManager.openModal({
title: 'Delete Confirmation',
size: 'sm',
content: `
<div style="text-align: center;">
<div class="confirmation-icon danger">
<svg width="40" height="40" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
</svg>
</div>
<h3 style="margin-bottom: 12px;">Are you sure?</h3>
<p style="color: #6b7280;">This action cannot be undone. This will permanently delete your account and remove your data from our servers.</p>
</div>
`,
buttons: [
{ text: 'Cancel', type: 'secondary', action: 'close' },
{ text: 'Delete', type: 'danger', action: 'close' }
]
});
break;
case 'sizes':
const { backdrop, modal } = modalManager.openModal({
title: 'Modal Sizes Demo',
content: `
<p>Choose a modal size to see it in action:</p>
<div style="display: flex; flex-wrap: wrap; gap: 12px; margin-top: 20px;">
<button class="btn btn-secondary" onclick="openSizeDemo('sm')">Small Modal</button>
<button class="btn btn-secondary" onclick="openSizeDemo('default')">Default Modal</button>
<button class="btn btn-secondary" onclick="openSizeDemo('lg')">Large Modal</button>
<button class="btn btn-secondary" onclick="openSizeDemo('xl')">Extra Large Modal</button>
<button class="btn btn-secondary" onclick="openSizeDemo('fullscreen')">Fullscreen Modal</button>
</div>
`,
showFooter: false
});
break;
case 'loading':
const { backdrop: loadingBackdrop, modal: loadingModal } = modalManager.openModal({
title: 'Loading Demo',
content: `
<p>Click the button below to see the loading state:</p>
<div style="text-align: center; margin-top: 24px;">
<button class="btn btn-primary" onclick="simulateLoading(this)">
Simulate Loading
</button>
</div>
`
});
window.currentLoadingModal = loadingModal;
break;
}
}
function openSizeDemo(size) {
modalManager.openModal({
title: `${size.charAt(0).toUpperCase() + size.slice(1)} Modal`,
size: size,
content: `
<p>This is a ${size} sized modal. Notice how it adapts to different content needs:</p>
<ul style="padding-left: 20px; margin-top: 16px;">
<li>Small: Perfect for confirmations and simple forms</li>
<li>Default: Standard size for most content</li>
<li>Large: Great for detailed forms or content</li>
<li>Extra Large: Ideal for tables or complex layouts</li>
<li>Fullscreen: Maximum space for immersive experiences</li>
</ul>
`,
showFooter: true
});
}
function handleFormSubmit(event) {
if (event) event.preventDefault();
// Get the current modal
const currentModal = modalManager.activeModals[modalManager.activeModals.length - 1];
// Show loading
modalManager.showLoading(currentModal.modal);
// Simulate API call
setTimeout(() => {
modalManager.hideLoading(currentModal.modal);
modalManager.closeModal(currentModal.backdrop);
// Show success modal
modalManager.openModal({
title: 'Success!',
size: 'sm',
content: `
<div style="text-align: center;">
<div class="confirmation-icon success">
<svg width="40" height="40" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
</div>
<p>Your form has been submitted successfully!</p>
</div>
`,
buttons: [
{ text: 'OK', type: 'primary', action: 'close' }
]
});
}, 2000);
}
function simulateLoading(button) {
button.classList.add('btn-loading');
modalManager.showLoading(window.currentLoadingModal);
setTimeout(() => {
button.classList.remove('btn-loading');
modalManager.hideLoading(window.currentLoadingModal);
}, 3000);
}
</script>
</body>
</html>