feat: Implement initial cinematic portfolio UI with animated components and page structure.
This commit is contained in:
1 parent
9d779390e5
commit
2ede7e98f9
18 files changed
+2107
-147
No files matched your search
@@ -0,0 +1,112 @@
|
||||
"use client";
|
||||
|
||||
import { useRef, useEffect } from "react";
|
||||
|
||||
interface SectionDividerProps {
|
||||
variant?: "gradient" | "pulse" | "waveform";
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export default function SectionDivider({
|
||||
variant = "gradient",
|
||||
className = "",
|
||||
}: SectionDividerProps) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (variant !== "waveform") return;
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
let animId: number;
|
||||
|
||||
const resize = () => {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = 60;
|
||||
};
|
||||
resize();
|
||||
window.addEventListener("resize", resize);
|
||||
|
||||
const render = () => {
|
||||
animId = requestAnimationFrame(render);
|
||||
const { width, height } = canvas;
|
||||
const t = performance.now() * 0.001;
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
// Draw multiple waveforms
|
||||
for (let wave = 0; wave < 3; wave++) {
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = `rgba(204, 255, 0, ${0.1 - wave * 0.03})`;
|
||||
ctx.lineWidth = 1;
|
||||
|
||||
for (let x = 0; x < width; x++) {
|
||||
const frequency = 0.005 + wave * 0.002;
|
||||
const amplitude = 8 + wave * 4;
|
||||
const speed = t * (0.5 + wave * 0.2);
|
||||
const y =
|
||||
height / 2 +
|
||||
Math.sin(x * frequency + speed) * amplitude +
|
||||
Math.sin(x * frequency * 2.3 + speed * 1.5) * (amplitude * 0.4);
|
||||
|
||||
if (x === 0) ctx.moveTo(x, y);
|
||||
else ctx.lineTo(x, y);
|
||||
}
|
||||
|
||||
ctx.stroke();
|
||||
}
|
||||
};
|
||||
|
||||
animId = requestAnimationFrame(render);
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(animId);
|
||||
window.removeEventListener("resize", resize);
|
||||
};
|
||||
}, [variant]);
|
||||
|
||||
if (variant === "gradient") {
|
||||
return (
|
||||
<div className={`relative h-px w-full overflow-hidden ${className}`}>
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-[var(--slash)] to-transparent opacity-30" />
|
||||
<div
|
||||
className="absolute inset-0 bg-gradient-to-r from-transparent via-[var(--slash)] to-transparent opacity-60"
|
||||
style={{
|
||||
animation: "shimmerDivider 3s ease-in-out infinite",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (variant === "pulse") {
|
||||
return (
|
||||
<div className={`flex items-center justify-center gap-2 py-8 ${className}`}>
|
||||
{[...Array(5)].map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="h-1 w-1 rounded-full bg-[var(--slash)]"
|
||||
style={{
|
||||
animation: `pulseDot 2s ease-in-out ${i * 0.15}s infinite`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// waveform
|
||||
return (
|
||||
<div className={`relative ${className}`}>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
className="w-full opacity-60"
|
||||
style={{ height: 60 }}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user