/** * Simple Modal Component for Hugo * Provides modal functionality similar to React patterns */ class Modal { constructor(modalId, options = {}) { this.modalId = modalId; this.options = { closeOnOverlayClick: true, closeOnEscape: true, ...options }; this.modal = null; this.isOpen = false; this.init(); } init() { // Create modal if it doesn't exist if (!document.getElementById(this.modalId)) { this.createModal(); } this.modal = document.getElementById(this.modalId); this.bindEvents(); } createModal() { const modalHTML = `
`; document.body.insertAdjacentHTML('beforeend', modalHTML); this.loadReactComponent(); } bindEvents() { if (!this.modal) return; // Close button const closeBtn = this.modal.querySelector('.modal-close'); if (closeBtn) { closeBtn.addEventListener('click', () => this.close()); } // Overlay click if (this.options.closeOnOverlayClick) { this.modal.addEventListener('click', (e) => { if (e.target === this.modal) { this.close(); } }); } // Escape key if (this.options.closeOnEscape) { document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && this.isOpen) { this.close(); } }); } } open() { if (!this.modal) return; this.modal.classList.add('active'); this.isOpen = true; document.body.style.overflow = 'hidden'; // Prevent background scrolling // Focus management for accessibility const firstFocusable = this.modal.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'); if (firstFocusable) { firstFocusable.focus(); } } close() { if (!this.modal) return; this.modal.classList.remove('active'); this.isOpen = false; document.body.style.overflow = ''; // Restore scrolling } loadReactComponent() { // Load React and ReactDOM from CDN if not already loaded if (typeof React === 'undefined' || typeof ReactDOM === 'undefined') { this.loadReactLibraries().then(() => { this.loadModalReactBundle(); }); } else { this.loadModalReactBundle(); } } loadReactLibraries() { return new Promise((resolve) => { const reactScript = document.createElement('script'); reactScript.src = 'https://unpkg.com/react@18/umd/react.production.min.js'; reactScript.onload = () => { const reactDOMScript = document.createElement('script'); reactDOMScript.src = 'https://unpkg.com/react-dom@18/umd/react-dom.production.min.js'; reactDOMScript.onload = resolve; document.head.appendChild(reactDOMScript); }; document.head.appendChild(reactScript); }); } loadModalReactBundle() { const script = document.createElement('script'); script.src = '/js/modal-react.js'; script.onload = () => { if (typeof window.renderModalReact === 'function') { window.renderModalReact('modal-react-root'); } }; script.onerror = () => { document.getElementById('modal-react-root').innerHTML = 'React component failed to load, but the modal works!