shcool / static /js /main.js
CORVO-AI's picture
Upload 111 files
b7f55e1 verified
Raw
History Blame Contribute Delete
7.92 kB
/* ── School System β€” GSAP Animations & UI Logic ── */
// Wait for GSAP CDN to be ready
document.addEventListener('DOMContentLoaded', () => {
/* ── Register GSAP Plugins ── */
if (window.gsap) {
gsap.registerPlugin(ScrollTrigger);
initAnimations();
}
initSidebar();
initAlerts();
initSearch();
initTooltips();
});
/* ══════════════════════════════════════
GSAP ANIMATIONS
══════════════════════════════════════ */
function initAnimations() {
/* Page entrance β€” topbar */
gsap.from('.topbar', {
y: -64, opacity: 0, duration: .5,
ease: 'power3.out'
});
/* Sidebar nav items stagger */
gsap.from('.nav-item', {
x: -24, opacity: 0, duration: .4,
stagger: .04, ease: 'power2.out', delay: .15
});
/* Page header */
gsap.from('.page-header', {
y: 20, opacity: 0, duration: .5,
ease: 'power3.out', delay: .2
});
/* Stat cards stagger */
gsap.from('.stat-card', {
y: 32, opacity: 0, duration: .5,
stagger: .08, ease: 'power3.out', delay: .3,
clearProps: 'all'
});
/* Animate stat values counting up */
document.querySelectorAll('.stat-value[data-count]').forEach(el => {
const target = parseInt(el.dataset.count, 10);
gsap.from({ val: 0 }, {
val: target, duration: 1.2, delay: .5,
ease: 'power2.out',
onUpdate: function () {
el.textContent = Math.round(this.targets()[0].val).toLocaleString();
}
});
});
/* Cards scroll reveal */
gsap.utils.toArray('.card').forEach((card, i) => {
gsap.from(card, {
scrollTrigger: {
trigger: card,
start: 'top 88%',
toggleActions: 'play none none none'
},
y: 28, opacity: 0, duration: .5,
delay: i * .04,
ease: 'power3.out',
clearProps: 'all'
});
});
/* Table rows stagger on scroll */
gsap.utils.toArray('tbody tr').forEach((row, i) => {
gsap.from(row, {
scrollTrigger: {
trigger: row,
start: 'top 92%',
toggleActions: 'play none none none'
},
x: -16, opacity: 0, duration: .35,
delay: i * .03,
ease: 'power2.out',
clearProps: 'all'
});
});
/* Buttons hover micro-animation */
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener('mouseenter', () => {
gsap.to(btn, { scale: 1.03, duration: .15, ease: 'power1.out' });
});
btn.addEventListener('mouseleave', () => {
gsap.to(btn, { scale: 1, duration: .15, ease: 'power1.out' });
});
});
/* Progress bars animate in */
document.querySelectorAll('.progress-bar').forEach(bar => {
const width = bar.style.width || bar.dataset.width || '0%';
bar.style.width = '0%';
gsap.to(bar, {
scrollTrigger: { trigger: bar, start: 'top 90%' },
width: width, duration: .9, ease: 'power3.out', delay: .1
});
});
/* Notice cards */
gsap.utils.toArray('.notice-card').forEach((card, i) => {
gsap.from(card, {
scrollTrigger: { trigger: card, start: 'top 90%' },
y: 20, opacity: 0, duration: .4,
delay: i * .06, ease: 'power2.out', clearProps: 'all'
});
});
/* Login card */
const loginCard = document.querySelector('.login-card');
if (loginCard) {
gsap.from(loginCard, {
y: 40, opacity: 0, scale: .96,
duration: .6, ease: 'power3.out'
});
gsap.from('.login-card .form-group', {
y: 16, opacity: 0, duration: .4,
stagger: .08, delay: .3, ease: 'power2.out'
});
}
/* Dashboard welcome banner */
const banner = document.querySelector('.dashboard-banner');
if (banner) {
gsap.from(banner, {
y: -20, opacity: 0, duration: .6, ease: 'power3.out', delay: .1
});
gsap.from(banner.querySelectorAll('h1, p, .btn'), {
y: 16, opacity: 0, stagger: .1, duration: .5, delay: .3, ease: 'power2.out'
});
}
}
/* ══════════════════════════════════════
SIDEBAR TOGGLE (mobile)
══════════════════════════════════════ */
function initSidebar() {
const toggle = document.getElementById('sidebar-toggle');
const sidebar = document.querySelector('.sidebar');
const overlay = document.getElementById('sidebar-overlay');
if (!toggle || !sidebar) return;
toggle.addEventListener('click', () => {
const isOpen = sidebar.classList.toggle('open');
if (overlay) overlay.classList.toggle('active', isOpen);
if (window.gsap) {
gsap.from(sidebar, { x: -260, duration: .3, ease: 'power3.out' });
}
});
if (overlay) {
overlay.addEventListener('click', () => {
sidebar.classList.remove('open');
overlay.classList.remove('active');
});
}
}
/* ══════════════════════════════════════
AUTO-DISMISS ALERTS
══════════════════════════════════════ */
function initAlerts() {
document.querySelectorAll('.alert').forEach(alert => {
const close = alert.querySelector('.alert-close');
if (close) {
close.addEventListener('click', () => dismissAlert(alert));
}
setTimeout(() => dismissAlert(alert), 5000);
});
}
function dismissAlert(alert) {
if (!alert.parentNode) return;
if (window.gsap) {
gsap.to(alert, {
opacity: 0, y: -8, height: 0, marginBottom: 0,
padding: 0, duration: .3, ease: 'power2.in',
onComplete: () => alert.remove()
});
} else {
alert.remove();
}
}
/* ══════════════════════════════════════
LIVE SEARCH FILTER (client-side)
══════════════════════════════════════ */
function initSearch() {
const searchInput = document.getElementById('table-search');
if (!searchInput) return;
searchInput.addEventListener('input', () => {
const q = searchInput.value.toLowerCase();
document.querySelectorAll('tbody tr').forEach(row => {
const text = row.textContent.toLowerCase();
row.style.display = text.includes(q) ? '' : 'none';
});
});
}
/* ══════════════════════════════════════
SIMPLE TOOLTIPS
══════════════════════════════════════ */
function initTooltips() {
document.querySelectorAll('[data-tooltip]').forEach(el => {
el.addEventListener('mouseenter', e => {
const tip = document.createElement('div');
tip.className = 'gsap-tooltip';
tip.textContent = el.dataset.tooltip;
tip.style.cssText = `
position:fixed;background:#0f172a;color:#fff;font-size:12px;
padding:5px 10px;border-radius:6px;pointer-events:none;z-index:9999;
white-space:nowrap;box-shadow:0 4px 12px rgba(0,0,0,.2);
`;
document.body.appendChild(tip);
const rect = el.getBoundingClientRect();
tip.style.left = rect.left + rect.width / 2 - tip.offsetWidth / 2 + 'px';
tip.style.top = rect.top - tip.offsetHeight - 8 + 'px';
if (window.gsap) gsap.from(tip, { opacity: 0, y: 4, duration: .15 });
el._tooltip = tip;
});
el.addEventListener('mouseleave', () => {
if (el._tooltip) { el._tooltip.remove(); el._tooltip = null; }
});
});
}