/* global React */
const { useState, useEffect, useRef } = React;
/* ============ Icons ============ */
const Icon = ({ name, size = 20, stroke = 1.6 }) => {
const paths = {
arrow: ,
arrowUp: ,
check: ,
plus: <>>,
star: ,
shield: ,
bolt: ,
cloud: ,
server: <>>,
lock: <>>,
chart: <>>,
layers: <>>,
settings: <>>,
cube: <>>,
code: <>>,
grid: <>>,
factory: <>>,
shop: <>>,
health: <>>,
truck: <>>,
bank: <>>,
book: <>>,
home: <>>,
cart: <>>,
phone: ,
mail: <>>,
pin: <>>,
linkedin: <>>,
twitter: ,
whatsapp: ,
sparkle: <>>,
target: <>>,
rocket: ,
refresh: <>>,
clock: <>>,
users: <>>,
x: <>>,
};
return (
);
};
/* ============ Reveal Observer ============ */
function useReveal() {
useEffect(() => {
const els = document.querySelectorAll(".reveal, .reveal-stagger");
els.forEach(el => el.classList.add("is-pending"));
const io = new IntersectionObserver((entries) => {
entries.forEach((e) => {
if (e.isIntersecting) {
e.target.classList.add("in");
io.unobserve(e.target);
}
});
}, { threshold: 0.05, rootMargin: "0px 0px -3% 0px" });
els.forEach(el => io.observe(el));
// Safety net for initial viewport: mark anything visible now
requestAnimationFrame(() => {
els.forEach(el => {
const r = el.getBoundingClientRect();
if (r.top < window.innerHeight * 0.95 && r.bottom > 0) {
el.classList.add("in");
}
});
});
return () => io.disconnect();
}, []);
}
/* ============ Counter ============ */
function Counter({ to, suffix = "", duration = 1800 }) {
const ref = useRef(null);
const [val, setVal] = useState(0);
const started = useRef(false);
useEffect(() => {
const io = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && !started.current) {
started.current = true;
const start = performance.now();
const tick = (now) => {
const t = Math.min(1, (now - start) / duration);
const eased = 1 - Math.pow(1 - t, 3);
setVal(Math.round(to * eased));
if (t < 1) requestAnimationFrame(tick);
};
requestAnimationFrame(tick);
}
}, { threshold: 0.5 });
if (ref.current) io.observe(ref.current);
return () => io.disconnect();
}, [to, duration]);
return {val}{suffix};
}
window.Icon = Icon;
window.useReveal = useReveal;
window.Counter = Counter;