UNPKG

@jager-ai/holy-editor

Version:

Rich text editor with Bible verse slash commands and PWA keyboard tracking, extracted from Holy Habit project

275 lines β€’ 8.02 kB
"use strict"; /** * Toast Manager * * Toast notification system for user feedback * Extracted from Holy Habit holy-editor-pro.js */ Object.defineProperty(exports, "__esModule", { value: true }); exports.ToastManager = void 0; class ToastManager { constructor() { this.toastContainer = null; this.createToastContainer(); } /** * Get singleton instance */ static getInstance() { if (!ToastManager.instance) { ToastManager.instance = new ToastManager(); } return ToastManager.instance; } /** * Show toast message */ show(message, duration = 3000, type = 'info') { // Remove existing toast const existingToast = document.querySelector('.holy-toast'); if (existingToast) { existingToast.remove(); } // Create new toast const toast = document.createElement('div'); toast.className = `holy-toast holy-toast-${type}`; toast.textContent = message; // Apply styles this.applyToastStyles(toast, type); // Add to document document.body.appendChild(toast); // Fade in animation requestAnimationFrame(() => { toast.style.opacity = '1'; }); // Auto remove setTimeout(() => { this.removeToast(toast); }, duration); console.log(`πŸ“’ Toast (${type}):`, message); } /** * Show success toast */ success(message, duration) { this.show(message, duration, 'success'); } /** * Show error toast */ error(message, duration) { this.show(message, duration || 4000, 'error'); } /** * Show warning toast */ warning(message, duration) { this.show(message, duration, 'warning'); } /** * Show info toast */ info(message, duration) { this.show(message, duration, 'info'); } /** * Remove all toasts */ clear() { const toasts = document.querySelectorAll('.holy-toast'); toasts.forEach(toast => toast.remove()); } /** * Create toast container if needed */ createToastContainer() { if (!this.toastContainer) { this.toastContainer = document.createElement('div'); this.toastContainer.className = 'holy-toast-container'; this.toastContainer.style.cssText = ` position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 9999; `; document.body.appendChild(this.toastContainer); } } /** * Apply styles to toast element */ applyToastStyles(toast, type) { const baseStyles = ` position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); padding: 12px 24px; border-radius: 4px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 10000; opacity: 0; transition: opacity 0.3s ease; font-size: 14px; white-space: nowrap; max-width: 90%; overflow: hidden; text-overflow: ellipsis; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; font-weight: 500; pointer-events: auto; `; const typeStyles = this.getTypeStyles(type); toast.style.cssText = baseStyles + typeStyles; } /** * Get type-specific styles */ getTypeStyles(type) { const styles = { info: ` background-color: #333; color: white; border-left: 4px solid #2196F3; `, success: ` background-color: #4CAF50; color: white; border-left: 4px solid #388E3C; `, warning: ` background-color: #FF9800; color: white; border-left: 4px solid #F57C00; `, error: ` background-color: #F44336; color: white; border-left: 4px solid #D32F2F; ` }; return styles[type] || styles.info; } /** * Remove toast with animation */ removeToast(toast) { toast.style.opacity = '0'; setTimeout(() => { if (toast.parentNode) { toast.parentNode.removeChild(toast); } }, 300); } /** * Handle API error and show appropriate toast */ handleApiError(error, ref) { console.error('API Error:', error); let message = ''; if (error.message.includes('404')) { message = ref ? `"${ref}" κ΅¬μ ˆμ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€. 책이름:μž₯:절 ν˜•μ‹μ„ ν™•μΈν•΄μ£Όμ„Έμš”.` : 'μš”μ²­ν•œ λ‚΄μš©μ„ 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.'; } else if (error.message.includes('λ„€νŠΈμ›Œν¬') || error.message.includes('Network')) { message = 'λ„€νŠΈμ›Œν¬ 연결을 ν™•μΈν•΄μ£Όμ„Έμš”.'; } else if (error.message.includes('500')) { message = 'μ„œλ²„ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. μž μ‹œ ν›„ λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”.'; } else { message = 'μš”μ²­ 처리 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.'; } this.error(message, 4000); } /** * Show loading toast (returns cleanup function) */ showLoading(message = '처리 쀑...') { const toast = document.createElement('div'); toast.className = 'holy-toast holy-toast-loading'; toast.innerHTML = ` <div class="loading-spinner"></div> <span>${message}</span> `; // Apply loading styles toast.style.cssText = ` position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: #333; color: white; padding: 12px 24px; border-radius: 4px; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 10000; font-size: 14px; display: flex; align-items: center; gap: 8px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; `; // Add spinner styles const spinner = toast.querySelector('.loading-spinner'); if (spinner) { spinner.style.cssText = ` width: 16px; height: 16px; border: 2px solid rgba(255,255,255,0.3); border-top: 2px solid white; border-radius: 50%; animation: spin 1s linear infinite; `; } // Add spinner animation CSS if not exists this.addSpinnerStyles(); document.body.appendChild(toast); // Return cleanup function return () => { if (toast.parentNode) { toast.parentNode.removeChild(toast); } }; } /** * Add spinner animation CSS */ addSpinnerStyles() { if (!document.querySelector('#holy-toast-spinner-styles')) { const style = document.createElement('style'); style.id = 'holy-toast-spinner-styles'; style.textContent = ` @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } `; document.head.appendChild(style); } } /** * Show toast with custom HTML content */ showCustom(htmlContent, duration = 3000, className = '') { const existingToast = document.querySelector('.holy-toast'); if (existingToast) { existingToast.remove(); } const toast = document.createElement('div'); toast.className = `holy-toast ${className}`; toast.innerHTML = htmlContent; this.applyToastStyles(toast, 'info'); document.body.appendChild(toast); requestAnimationFrame(() => { toast.style.opacity = '1'; }); setTimeout(() => { this.removeToast(toast); }, duration); } } exports.ToastManager = ToastManager; //# sourceMappingURL=ToastManager.js.map