/* global React, window */
// Eyad Academy — shared atoms: icons, mascot, reveal, counter
const { useEffect, useRef, useState } = React;
// ============================================================
// Icon set — hand-tuned to match brand. Uses currentColor.
// ============================================================
function Icon({ name, size = 22 }) {
const s = { width: size, height: size, display: "inline-block", verticalAlign: "middle" };
const stroke = { fill: "none", stroke: "currentColor", strokeWidth: 1.8, strokeLinecap: "round", strokeLinejoin: "round" };
switch (name) {
case "menu":
return ();
case "arrow":
return ();
case "play":
return ();
case "spark":
return ();
case "compass":
return ();
case "shield":
return ();
case "trophy":
return ();
case "book":
return ();
case "clock":
return ();
case "users":
return ();
case "star":
return ();
case "check":
return ();
case "close":
return ();
case "chevron":
return ();
case "quote":
return ();
case "quran":
return ();
case "arabic":
return ();
case "math":
return ();
case "science":
return ();
case "lightning":
return ();
case "twitter":
return ();
case "insta":
return ();
case "youtube":
return ();
case "tiktok":
return ();
default: return null;
}
}
// ============================================================
// Mascot — 4 styles, swap via Tweaks
// ============================================================
function Mascot({ style = "real", className = "", size }) {
const sty = size ? { width: size, height: size } : {};
if (style === "real") {
return (
);
}
if (style === "geometric") {
return (
);
}
if (style === "lineart") {
return (
);
}
// "sunny" — soft sun
return (
);
}
// ============================================================
// Reveal — fade-up on scroll
// ============================================================
function Reveal({ children, delay = 0, as = "div", ...rest }) {
const ref = useRef(null);
const [shown, setShown] = useState(false);
useEffect(() => {
const el = ref.current; if (!el) return;
const io = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) { setTimeout(() => setShown(true), delay); io.disconnect(); }
});
}, { threshold: 0.12, rootMargin: "0px 0px -40px 0px" });
io.observe(el);
return () => io.disconnect();
}, [delay]);
const Tag = as;
return (
{children}
);
}
// ============================================================
// Animated counter — counts up when in view
// ============================================================
function Counter({ value, decimal = false, suffix = "" }) {
const ref = useRef(null);
const [n, setN] = useState(0);
useEffect(() => {
const el = ref.current; if (!el) return;
let started = false;
const io = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && !started) {
started = true;
const start = performance.now();
const dur = 1600;
const tick = (t) => {
const p = Math.min(1, (t - start) / dur);
const eased = 1 - Math.pow(1 - p, 3);
setN(value * eased);
if (p < 1) requestAnimationFrame(tick);
};
requestAnimationFrame(tick);
}
}, { threshold: 0.3 });
io.observe(el);
return () => io.disconnect();
}, [value]);
const display = decimal
? n.toFixed(1)
: Math.round(n).toLocaleString("ar-EG");
return {display}{suffix};
}
// ============================================================
// Floating decorative shapes for backgrounds
// ============================================================
function FloatingDeco({ variant = "hero" }) {
if (variant === "hero") {
return (
);
}
if (variant === "subtle") {
return (
);
}
return null;
}
function Sparkles({ count = 6 }) {
const pts = useRef(
Array.from({ length: count }).map(() => ({
top: 5 + Math.random() * 85,
left: 5 + Math.random() * 90,
d: Math.random() * 4,
s: 0.6 + Math.random() * 0.8,
}))
).current;
return pts.map((p, i) => (
));
}
Object.assign(window, { Icon, Mascot, Reveal, Counter, FloatingDeco, Sparkles });
// ============================================================
// I18N + THEME CONTEXT
// ============================================================
const EyadCtx = React.createContext({
lang: "ar", theme: "light", t: {},
setLang: () => {}, setTheme: () => {},
});
function EyadProvider({ children }) {
const [lang, setLangState] = useState(() => {
try { return localStorage.getItem("eyad-lang") || "ar"; } catch { return "ar"; }
});
const [theme, setThemeState] = useState(() => {
try { return localStorage.getItem("eyad-theme") || "light"; } catch { return "light"; }
});
useEffect(() => {
document.documentElement.setAttribute("lang", window.I18N[lang].htmlLang);
document.documentElement.setAttribute("dir", window.I18N[lang].dir);
try { localStorage.setItem("eyad-lang", lang); } catch {}
}, [lang]);
useEffect(() => {
document.documentElement.setAttribute("data-theme", theme);
try { localStorage.setItem("eyad-theme", theme); } catch {}
}, [theme]);
const setLang = (l) => setLangState(l);
const setTheme = (th) => setThemeState(th);
const t = window.I18N[lang];
return (
{children}
);
}
function useEyad() { return React.useContext(EyadCtx); }
function useT() { return React.useContext(EyadCtx).t; }
Object.assign(window, { EyadCtx, EyadProvider, useEyad, useT });