forked from emre/www_projectmycelium_com
- Integrated next-themes for dark mode theming with default dark theme - Added new UI components (GridBlink, Spotlight) and enhanced world map with cyan glow effects - Updated homepage messaging to emphasize Mycelium as a living network with new audience imagery
65 lines
1.6 KiB
TypeScript
65 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useRef } from "react";
|
|
|
|
export function GridBlink() {
|
|
const svgRef = useRef<SVGSVGElement>(null);
|
|
const maxActive = 3; // ✅ limit active squares
|
|
|
|
useEffect(() => {
|
|
const svg = svgRef.current;
|
|
if (!svg) return;
|
|
|
|
const squares = Array.from(svg.querySelectorAll<SVGRectElement>(".blink-square"));
|
|
|
|
function scheduleBlink() {
|
|
// ✅ only blink if we have too few active
|
|
const currentlyActive = squares.filter(sq => sq.classList.contains("active"));
|
|
if (currentlyActive.length < maxActive) {
|
|
const sq = squares[Math.floor(Math.random() * squares.length)];
|
|
sq.classList.add("active");
|
|
|
|
const duration = 800 + Math.random() * 1000; // ✅ slower fade-out
|
|
setTimeout(() => {
|
|
sq.classList.remove("active");
|
|
}, duration);
|
|
}
|
|
|
|
// ✅ slower scheduling
|
|
setTimeout(scheduleBlink, 300 + Math.random() * 600);
|
|
}
|
|
|
|
scheduleBlink();
|
|
}, []);
|
|
|
|
const rows = 20;
|
|
const cols = 32;
|
|
const size = 40;
|
|
|
|
return (
|
|
<svg
|
|
ref={svgRef}
|
|
className="pointer-events-none absolute inset-0 z-0"
|
|
style={{ width: "100%", height: "100%" }}
|
|
>
|
|
{Array.from({ length: rows * cols }).map((_, i) => {
|
|
const x = (i % cols) * size;
|
|
const y = Math.floor(i / cols) * size;
|
|
return (
|
|
<rect
|
|
key={i}
|
|
className="blink-square"
|
|
x={x}
|
|
y={y}
|
|
width={size}
|
|
height={size}
|
|
fill="transparent"
|
|
stroke="#efefef"
|
|
strokeWidth="1"
|
|
/>
|
|
);
|
|
})}
|
|
</svg>
|
|
);
|
|
}
|