// ui.jsx — shared atoms + Header + Footer (function () { const { useState, useEffect, useRef } = React; const Icon = window.Icon; const D = window.DATA; /* ---------- Logo ---------- */ function Logo({ light, size = 40, onClick }) { const logoUrl = (window.INFOTECH && window.INFOTECH.logo) || ""; const mark = logoUrl ? ( INFOTECH logo ) : ( ); return ( {mark} INFOTECH Institute of Computer Education ); } /* ---------- Placeholder image ---------- */ function Placeholder({ label, icon = "image", style, className, ratio }) { const r = ratio ? { aspectRatio: ratio } : null; return (
{label && {label}}
); } /* ---------- Stars ---------- */ function Stars({ n = 5, size = 16 }) { return ( {[1, 2, 3, 4, 5].map((i) => ( ))} ); } /* ---------- Scroll reveal ---------- */ function useReveal() { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver((entries) => { entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add("in-view"); io.unobserve(e.target); } }); }, { threshold: 0.12 }); io.observe(el); return () => io.disconnect(); }, []); return ref; } /* ---------- Count-up ---------- */ function CountUp({ value }) { const ref = useRef(null); const [shown, setShown] = useState(false); useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver((e) => { if (e[0].isIntersecting) { setShown(true); io.disconnect(); } }, { threshold: .4 }); io.observe(el); return () => io.disconnect(); }, []); const m = String(value).match(/^([\d,]+)(.*)$/); const [disp, setDisp] = useState(m ? "0" + (m[2] || "") : value); useEffect(() => { if (!shown || !m) { if (!m) setDisp(value); return; } const target = parseInt(m[1].replace(/,/g, ""), 10); const suffix = m[2] || ""; let raf; const start = performance.now(); const dur = 1300; const tick = (now) => { const p = Math.min(1, (now - start) / dur); const e = 1 - Math.pow(1 - p, 3); const cur = Math.round(target * e); setDisp(cur.toLocaleString() + suffix); if (p < 1) raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [shown]); return {disp}; } /* ---------- Header ---------- */ function Header({ route, navigate }) { const [scrolled, setScrolled] = useState(false); const [open, setOpen] = useState(false); useEffect(() => { const onScroll = () => setScrolled(window.scrollY > 12); onScroll(); window.addEventListener("scroll", onScroll, { passive: true }); return () => window.removeEventListener("scroll", onScroll); }, []); useEffect(() => { setOpen(false); }, [route]); useEffect(() => { document.body.style.overflow = open ? "hidden" : ""; }, [open]); const go = (e, key) => { e.preventDefault(); navigate(key); }; const active = (k) => route === k || (k === "courses" && route === "course"); return (
go(e, "home")} />
go(e, "login")} className="btn btn-outline btn-sm"> Login go(e, "verify")} className="btn btn-accent btn-sm"> Verify
{/* mobile drawer */}
{D.NAV.map((n) => ( go(e, n.key)} style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "16px 18px", borderRadius: 16, fontWeight: 700, fontSize: "1.05rem", background: active(n.key) ? "var(--surface)" : "transparent", color: active(n.key) ? "var(--brand)" : "var(--ink)", boxShadow: active(n.key) ? "var(--sh-sm)" : "none" }}> {n.label} ))}
go(e, "login")} className="btn btn-outline" style={{ flex: 1 }}> Student Login
{D.INSTITUTE.phone}
); } /* ---------- Footer ---------- */ function Footer({ navigate }) { const I = D.INSTITUTE; const go = (e, k) => { e.preventDefault(); navigate(k); }; const socials = [["facebook", I.facebook || "#"], ["instagram", I.instagram || "#"], ["linkedin", I.linkedin || "#"], ["youtube", I.youtube || "#"]]; const quick = [["about", "About Us"], ["courses", "Courses"], ["gallery", "Gallery"], ["testimonials", "Testimonials"], ["verify", "Verify Certificate"], ["contact", "Contact"]]; const topCourses = D.COURSES.filter(c => c.featured).concat(D.COURSES.filter(c => !c.featured)).slice(0, 6); return ( ); } /* ---------- WhatsApp float ---------- */ function FloatActions() { return ( ); } Object.assign(window, { Logo, Placeholder, Stars, useReveal, CountUp, Header, Footer, FloatActions }); })();