/* embeddedTR — inline icon set (stroke, currentColor) + small helpers */ const { useState, useEffect, useRef } = React; const Ic = ({ d, size = 22, sw = 1.6, fill = "none", children, ...p }) => ( {d ? : children} ); const Icons = { share: (p) => , article: (p) => , qa: (p) => , learn: (p) => , chip: (p) => , star: (p) => , fork: (p) => , arrow: (p) => , arrowUp: (p) => , check: (p) => , search: (p) => , menu: (p) => , close: (p) => , sun: (p) => , moon: (p) => , terminal:(p) => , github: (p) => , youtube: (p) => , play: (p) => , bolt: (p) => , book: (p) => , users: (p) => , }; /* reveal on scroll — scroll/rect based (robust even when IntersectionObserver doesn't fire in hidden/preview iframes) */ function useReveal() { const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; const nodes = el.classList.contains("reveal") ? [el] : Array.from(el.querySelectorAll(".reveal")); const check = () => { const vh = window.innerHeight || 800; let pending = false; nodes.forEach((n) => { if (n.classList.contains("in")) return; const r = n.getBoundingClientRect(); if (r.top < vh * 0.94 && r.bottom > 0) n.classList.add("in"); else pending = true; }); if (!pending) { window.removeEventListener("scroll", check); window.removeEventListener("resize", check); } }; check(); const t1 = setTimeout(check, 200); const t2 = setTimeout(check, 700); window.addEventListener("scroll", check, { passive: true }); window.addEventListener("resize", check); return () => { window.removeEventListener("scroll", check); window.removeEventListener("resize", check); clearTimeout(t1); clearTimeout(t2); }; }, []); return ref; } /* count-up number — scroll/rect triggered with setTimeout safety */ function Counter({ to, suffix = "", dur = 1400 }) { const [n, setN] = useState(0); const ref = useRef(null); useEffect(() => { const el = ref.current; if (!el) return; let raf, safety, started = false; const run = () => { if (started) return; started = true; window.removeEventListener("scroll", check); const t0 = performance.now(); const tick = (t) => { const p = Math.min(1, (t - t0) / dur); const e = 1 - Math.pow(1 - p, 3); setN(Math.round(to * e)); if (p < 1) raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); safety = setTimeout(() => setN(to), dur + 150); // guarantee final value }; const check = () => { const vh = window.innerHeight || 800; const r = el.getBoundingClientRect(); if (r.top < vh * 0.9 && r.bottom > 0) run(); }; check(); const t1 = setTimeout(check, 300); window.addEventListener("scroll", check, { passive: true }); return () => { window.removeEventListener("scroll", check); cancelAnimationFrame(raf); clearTimeout(safety); clearTimeout(t1); }; }, [to]); return {n.toLocaleString("tr-TR")}{suffix}; } /* animated oscilloscope trace — sine (default) or square ("blink") */ function Waveform({ h = 70, color, shape = "sine" }) { const ref = useRef(null); useEffect(() => { const path = ref.current; if (!path) return; let raf, ph = 0, reduce = matchMedia("(prefers-reduced-motion: reduce)").matches; const W = 300; const mod2 = (v) => ((Math.floor(v) % 2) + 2) % 2; const draw = () => { let d = ""; if (shape === "square") { const period = 58, top = 7, bot = h - 7; let prev = null; for (let x = 0; x <= W; x += 1) { const y = mod2(x / period + ph) === 0 ? top : bot; if (prev === null) { d = "M" + x + " " + y; } else if (y !== prev) { d += " L" + x + " " + prev + " L" + x + " " + y; } else { d += " L" + x + " " + y; } prev = y; } ph += 0.018; } else { for (let x = 0; x <= W; x += 4) { const y = h / 2 + Math.sin(x / 18 + ph) * (h / 2 - 6) * Math.sin(x / 120 + ph / 3); d += (x === 0 ? "M" : "L") + x + " " + y.toFixed(1) + " "; } ph += 0.06; } path.setAttribute("d", d); if (!reduce) raf = requestAnimationFrame(draw); }; draw(); return () => cancelAnimationFrame(raf); }, [shape, h]); return ( ); } /* ---- Brand mark: vector circuit-tree badge (replaces the raster logo) ---- */ function BrandMark({ size = 40, className = "" }) { const id = React.useMemo(() => "bm" + Math.random().toString(36).slice(2, 7), []); return ( {/* badge */} {/* circuit traces */} {/* base pad */} {/* nodes */} ); } /* full lockup: mark + wordmark + online dot */ function BrandLockup({ size = 38, withDot = true }) { return ( embeddedTR {withDot && } ); } Object.assign(window, { Icons, useReveal, Counter, Waveform, BrandMark, BrandLockup });