@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
JavaScript
;
/**
* 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