mirror of
https://github.com/myronblair/tomsjavajive-app
synced 2026-06-30 17:50:56 -05:00
v1.0.0 - Initial backup
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* Tom's Java Jive - Admin JavaScript
|
||||
*/
|
||||
|
||||
// Sidebar Toggle
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const sidebarToggle = document.getElementById('sidebarToggle');
|
||||
const sidebar = document.querySelector('.admin-sidebar');
|
||||
|
||||
if (sidebarToggle && sidebar) {
|
||||
sidebarToggle.addEventListener('click', function() {
|
||||
sidebar.classList.toggle('open');
|
||||
});
|
||||
|
||||
// Close sidebar when clicking outside on mobile
|
||||
document.addEventListener('click', function(e) {
|
||||
if (window.innerWidth <= 1024) {
|
||||
if (!sidebar.contains(e.target) && !sidebarToggle.contains(e.target)) {
|
||||
sidebar.classList.remove('open');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Confirm dialogs
|
||||
document.querySelectorAll('[data-confirm]').forEach(el => {
|
||||
el.addEventListener('click', function(e) {
|
||||
if (!confirm(this.dataset.confirm)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Auto-hide alerts
|
||||
document.querySelectorAll('.alert').forEach(alert => {
|
||||
setTimeout(() => {
|
||||
alert.style.opacity = '0';
|
||||
alert.style.transform = 'translateY(-10px)';
|
||||
setTimeout(() => alert.remove(), 300);
|
||||
}, 5000);
|
||||
});
|
||||
});
|
||||
|
||||
// Toast notifications
|
||||
const AdminToast = {
|
||||
container: null,
|
||||
|
||||
init() {
|
||||
if (!this.container) {
|
||||
this.container = document.createElement('div');
|
||||
this.container.style.cssText = 'position:fixed;bottom:20px;right:20px;z-index:1000;display:flex;flex-direction:column;gap:8px;';
|
||||
document.body.appendChild(this.container);
|
||||
}
|
||||
},
|
||||
|
||||
show(message, type = 'success', duration = 3000) {
|
||||
this.init();
|
||||
|
||||
const colors = {
|
||||
success: '#10B981',
|
||||
error: '#EF4444',
|
||||
warning: '#F59E0B',
|
||||
info: '#3B82F6'
|
||||
};
|
||||
|
||||
const toast = document.createElement('div');
|
||||
toast.style.cssText = `
|
||||
background: white;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 15px rgba(0,0,0,0.1);
|
||||
border-left: 4px solid ${colors[type] || colors.info};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
animation: slideIn 0.3s ease;
|
||||
`;
|
||||
toast.innerHTML = `
|
||||
<i class="fas fa-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-circle' : 'info-circle'}" style="color:${colors[type]}"></i>
|
||||
<span>${message}</span>
|
||||
`;
|
||||
|
||||
this.container.appendChild(toast);
|
||||
|
||||
setTimeout(() => {
|
||||
toast.style.animation = 'slideIn 0.3s ease reverse';
|
||||
setTimeout(() => toast.remove(), 300);
|
||||
}, duration);
|
||||
},
|
||||
|
||||
success(msg) { this.show(msg, 'success'); },
|
||||
error(msg) { this.show(msg, 'error'); },
|
||||
warning(msg) { this.show(msg, 'warning'); },
|
||||
info(msg) { this.show(msg, 'info'); }
|
||||
};
|
||||
|
||||
// API helper
|
||||
async function adminFetch(url, options = {}) {
|
||||
const defaults = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
};
|
||||
|
||||
const response = await fetch(url, { ...defaults, ...options });
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || 'Request failed');
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Loading state
|
||||
function setLoading(button, isLoading) {
|
||||
if (isLoading) {
|
||||
button.dataset.originalHtml = button.innerHTML;
|
||||
button.innerHTML = '<span class="loading"></span> Loading...';
|
||||
button.disabled = true;
|
||||
} else {
|
||||
button.innerHTML = button.dataset.originalHtml || button.innerHTML;
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Format currency
|
||||
function formatCurrency(amount) {
|
||||
return '$' + parseFloat(amount).toFixed(2);
|
||||
}
|
||||
|
||||
// Format date
|
||||
function formatDate(dateString) {
|
||||
return new Date(dateString).toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric'
|
||||
});
|
||||
}
|
||||
|
||||
// Debounce
|
||||
function debounce(func, wait) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func.apply(this, args), wait);
|
||||
};
|
||||
}
|
||||
|
||||
// Modal
|
||||
const Modal = {
|
||||
open(modalId) {
|
||||
const modal = document.getElementById(modalId);
|
||||
if (modal) {
|
||||
modal.classList.add('active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
},
|
||||
|
||||
close(modalId) {
|
||||
const modal = document.getElementById(modalId);
|
||||
if (modal) {
|
||||
modal.classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Close modals on overlay click
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('modal-overlay')) {
|
||||
e.target.classList.remove('active');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
});
|
||||
|
||||
// Image preview
|
||||
function previewImage(input, previewId) {
|
||||
const preview = document.getElementById(previewId);
|
||||
if (!preview) return;
|
||||
|
||||
if (input.files && input.files[0]) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
preview.src = e.target.result;
|
||||
preview.style.display = 'block';
|
||||
};
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add slideIn animation
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
@keyframes slideIn {
|
||||
from { transform: translateX(100%); opacity: 0; }
|
||||
to { transform: translateX(0); opacity: 1; }
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
Reference in New Issue
Block a user