"use client"; import { useMemo, useRef, type ReactNode } from "react"; import { cn } from "@/lib/utils"; import { usePixelHeat } from "@/components/use-pixel-heat"; /** * Hero'daki dot-matrix dilini (TurkeyPixelMap) bölüm ayraçlarına ve * dekorlara taşıyan piksel süsleri. Rastgelelik yerine deterministik * hash kullanılır ki sunucu ve istemci aynı deseni üretsin. * * Hepsi hero'daki imleç ısı fırçasına katılır (usePixelHeat): imleç * yaklaşınca pikseller turuncuya ısınır, uzaklaşınca yavaşça soğur. * Turuncu vurgu (accent) pikselleri hero'daki şehirler gibi fırçaya * katılmaz. */ // Hero ile aynı ızgara ölçüleri const CELL = 10; const DOT = 7.4; const INSET = (CELL - DOT) / 2; // Hero ile aynı doku paleti const OPACITIES = [0.3, 0.16, 0.24, 0.12, 0.27, 0.19]; const opacityFor = (x: number, y: number) => OPACITIES[(x * 7 + y * 11) % OPACITIES.length]; // Deterministik sözde-rastgele: aynı girdi her ortamda aynı deseni verir const hash = (x: number, y: number, seed: number) => { const n = Math.sin(x * 127.1 + y * 311.7 + seed * 74.7) * 43758.5453; return n - Math.floor(n); }; function pixelRect( x: number, y: number, extra: { key: string; accent?: boolean; accentDelay?: number }, ) { const shared = { x: x * CELL + INSET, y: y * CELL + INSET, width: DOT, height: DOT, rx: 2, }; if (extra.accent) { return ( ); } const op = opacityFor(x, y); return ( ); } /** * Geniş alanlar için seyrek piksel zemini (ör. koyu CTA bandı). * İçeriğin oturduğu orta bölge tamamen boş bırakılır; pikseller * kenarlara doğru yoğunlaşır. */ export function PixelField({ seed = 7, className, }: { seed?: number; className?: string; }) { const svgRef = useRef(null); usePixelHeat(svgRef); const COLS = 42; const ROWS = 12; // Çıktı seed'e göre deterministik; 504 iterasyon + ~150 element üretimini // her render'da (ör. çekmece reorder'ında) tekrarlama (rendering-hoist-jsx) const pixels = useMemo(() => { const cx = (COLS - 1) / 2; const cy = (ROWS - 1) / 2; const maxD = Math.sqrt(cx * cx + cy * cy); const sonuc: ReactNode[] = []; let accentIdx = 0; // Hero serpintisiyle aynı kural: içeriğin oturduğu orta kolon // (genişliğin %22–78 bandı) tüm yükseklik boyunca tamamen boş kalır const BAND_MIN = COLS * 0.22; const BAND_MAX = COLS * 0.78; for (let y = 0; y < ROWS; y++) { for (let x = 0; x < COLS; x++) { if (x > BAND_MIN && x < BAND_MAX) continue; // Kenarlara doğru artan doluluk const d = Math.sqrt((x - cx) ** 2 + (y - cy) ** 2) / maxD; const density = 0.1 + 0.42 * d * d; if (hash(x, y, seed) > density) continue; const accent = hash(x, y, seed + 99) > 0.96; sonuc.push( pixelRect(x, y, { key: `${x}-${y}`, accent, accentDelay: accent ? (accentIdx++ % 8) * 0.45 : 0, }), ); } } return sonuc; }, [seed]); return ( ); } /** * Bölümler arasında sert border çizgileri yerine kullanılan, ortada * yoğunlaşıp kenarlara doğru dağılan piksel ayraç. Hero'nun dot-matrix * dilini bölüm geçişlerine taşır. */ export function PixelDivider({ seed = 5, className, }: { seed?: number; className?: string; }) { const svgRef = useRef(null); usePixelHeat(svgRef); const COLS = 12; const ROWS = 2; // Deterministik çıktı — render başına yeniden üretme (PixelField ile aynı) const pixels = useMemo(() => { const cx = (COLS - 1) / 2; const sonuc: ReactNode[] = []; let accentPlaced = false; for (let y = 0; y < ROWS; y++) { for (let x = 0; x < COLS; x++) { // Az sayıda, iri piksel: ortada yoğun, kenara doğru seyrelen küçük küme const dx = Math.abs(x - cx) / cx; const rowFalloff = y === 0 ? 0.9 : 0.35; const density = (1 - dx) ** 1.1 * rowFalloff; if (hash(x, y, seed) > density) continue; const accent = !accentPlaced && hash(x, y, seed + 99) > 0.8; if (accent) accentPlaced = true; sonuc.push( pixelRect(x, y, { key: `${x}-${y}`, accent, }), ); } } return sonuc; }, [seed]); return ( ); } /** Alt sayfa başlıklarını içerikten ayıran kompakt piksel imzası. */ export function PagePixelDivider({ seed = 5, className, }: { seed?: number; className?: string; }) { return ( ); } /** Küçük sabit süslerde (mark/korner) data-px öznitelikli rect. */ function fixedPixel(x: number, y: number, opacity: number) { return ( ); } /** Eyebrow rozetlerinde kullanılan 2×2'lik minik piksel imzası. */ export function PixelMark({ className }: { className?: string }) { const svgRef = useRef(null); usePixelHeat(svgRef, { radius: 24 }); return ( ); } /** Kart köşelerine iliştirilen sessiz piksel kümesi. */ export function PixelCorner({ className }: { className?: string }) { const svgRef = useRef(null); usePixelHeat(svgRef, { radius: 28 }); return ( ); } /** Bölüm başlıklarının üstünde duran piksel imzalı eyebrow rozeti. */ export function SectionEyebrow({ children, className, }: { children: ReactNode; className?: string; }) { return ( {children} ); }