// ===== Shared parts for Peeka v2 ===== const { useState, useEffect, useRef, useMemo } = React; const rupiah = (n) => "Rp " + n.toLocaleString("id-ID"); const toPascal = (s) => s .split("-") .map((w) => w[0].toUpperCase() + w.slice(1)) .join(""); const Icon = ({ name, className = "", size = 20, strokeWidth = 2 }) => { const ref = useRef(null); useEffect(() => { if (ref.current && window.lucide) { ref.current.innerHTML = ""; const svg = window.lucide.createElement( window.lucide[toPascal(name)] || window.lucide.Circle, ); svg.setAttribute("width", size); svg.setAttribute("height", size); svg.setAttribute("stroke-width", strokeWidth); svg.setAttribute("class", className); ref.current.appendChild(svg); } }, [name, className, size, strokeWidth]); return ; }; // ===== Fireflies ===== const Fireflies = ({ count = 14 }) => { const flies = useMemo( () => Array.from({ length: count }, () => ({ top: Math.random() * 90 + 2, left: Math.random() * 95 + 2, delay: Math.random() * 3, driftDelay: Math.random() * 9, scale: 0.5 + Math.random() * 1.2, })), [count], ); return (
); }; // ===== Reveal on scroll ===== const useReveal = () => { useEffect(() => { const els = document.querySelectorAll(".reveal"); const io = new IntersectionObserver( (entries) => { entries.forEach((e) => { if (e.isIntersecting) e.target.classList.add("in"); }); }, { threshold: 0.12 }, ); els.forEach((el) => io.observe(el)); return () => io.disconnect(); }, []); }; // ===== Logo ===== const Logo = ({ light = false }) => (