LordOdin721's picture
This project delivers a production‑ready online learning admin platform with a premium 3D graduation‑cap brand system, dark/light theming, and fully responsive UX, backed by a hosted REST API wired to a MySQL database (host: sql207.infinityfree.com, user: if0_40314195, password: QClTpJOogkd, database: if0_40314195_learning_platform) for real‑time reads/writes across users, courses, enrollments, assignments, submissions, certificates, payments, and analytics; the dashboard surfaces KPIs (users, courses, enrollments, revenue), popularity and revenue trends, while management views provide search, sort, pagination, status/date filters, safe CRUD with confirmation modals, mobile‑first tables, non‑overlapping hamburger navigation, and a reliable SQL query tool with result export; accessibility is enforced via high‑contrast tokens, keyboard focus, ARIA labels, and overlay fixes (no persistent blur), performance is optimized with lazy loading and minified assets, and deployment ships with schema.sql, optional seed data, health checks, structured logging, and CORS, ensuring a polished, secure, and demo‑ready experience end to end.
fee3420 verified
document.addEventListener('DOMContentLoaded', () => {
// Check for saved theme preference
const savedTheme = localStorage.getItem('theme') || 'dark';
if (savedTheme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
// Initialize tooltips
const initTooltips = () => {
const tooltipElements = document.querySelectorAll('[data-tooltip]');
tooltipElements.forEach(el => {
const tooltipId = 'tooltip-' + Math.random().toString(36).substr(2, 9);
const tooltipText = el.getAttribute('data-tooltip');
el.setAttribute('aria-describedby', tooltipId);
const tooltip = document.createElement('div');
tooltip.id = tooltipId;
tooltip.className = 'absolute z-10 invisible inline-block px-3 py-2 text-sm font-medium text-white bg-gray-900 rounded-lg shadow-sm tooltip dark:bg-gray-700';
tooltip.innerHTML = tooltipText;
document.body.appendChild(tooltip);
const popperInstance = Popper.createPopper(el, tooltip, {
placement: 'top',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
],
});
const showEvents = ['mouseenter', 'focus'];
const hideEvents = ['mouseleave', 'blur'];
showEvents.forEach(event => {
el.addEventListener(event, () => {
tooltip.setAttribute('data-show', '');
popperInstance.update();
});
});
hideEvents.forEach(event => {
el.addEventListener(event, () => {
tooltip.removeAttribute('data-show');
});
});
});
};
// Check if Popper is loaded before initializing tooltips
const checkPopper = setInterval(() => {
if (typeof Popper !== 'undefined') {
clearInterval(checkPopper);
initTooltips();
}
}, 100);
// Add animations to dashboard cards
const dashboardCards = document.querySelectorAll('.bg-white, .dark\\:bg-gray-800');
dashboardCards.forEach((card, index) => {
card.style.animationDelay = `${index * 0.1}s`;
card.classList.add('slide-up');
});
});