mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 22:06:38 +08:00
63cd906cfc
- Merge all files inside openflare-server to the repository root directory. - Relocate agent, relay, and flared subprojects from internal/ to internal/apps/. - Combine docker-compose files and update build context paths to root. - Update GitHub workflows and Dockerfiles to refer to new directories and package names. - Rewrite Go package imports across all files. - Resolve database renew test race condition and clean up docs.
97 lines
2.2 KiB
TypeScript
97 lines
2.2 KiB
TypeScript
"use client"
|
|
|
|
import {useEffect, useRef} from "react"
|
|
|
|
interface Snowflake {
|
|
x: number
|
|
y: number
|
|
radius: number
|
|
speed: number
|
|
opacity: number
|
|
drift: number
|
|
}
|
|
|
|
export function SnowEffect() {
|
|
const canvasRef = useRef<HTMLCanvasElement>(null)
|
|
|
|
useEffect(() => {
|
|
const canvas = canvasRef.current
|
|
if (!canvas) return
|
|
|
|
const ctx = canvas.getContext("2d")
|
|
if (!ctx) return
|
|
|
|
let animationFrameId: number
|
|
let snowflakes: Snowflake[] = []
|
|
|
|
const resizeCanvas = () => {
|
|
canvas.width = window.innerWidth
|
|
canvas.height = window.innerHeight
|
|
}
|
|
|
|
const createSnowflakes = () => {
|
|
const count = Math.floor(window.innerWidth / 4)
|
|
snowflakes = []
|
|
for (let i = 0; i < count; i++) {
|
|
snowflakes.push({
|
|
x: Math.random() * canvas.width,
|
|
y: Math.random() * canvas.height,
|
|
radius: Math.random() * 3 + 1,
|
|
speed: Math.random() * 2 + 0.5,
|
|
opacity: Math.random() * 0.5 + 0.3,
|
|
drift: Math.random() * 1 - 0.5
|
|
})
|
|
}
|
|
}
|
|
|
|
const drawSnowflakes = () => {
|
|
if (!ctx || !canvas) return
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height)
|
|
|
|
snowflakes.forEach((flake) => {
|
|
ctx.beginPath()
|
|
ctx.arc(flake.x, flake.y, flake.radius, 0, Math.PI * 2)
|
|
ctx.fillStyle = `rgba(255, 255, 255, ${ flake.opacity })`
|
|
ctx.fill()
|
|
|
|
flake.y += flake.speed
|
|
flake.x += flake.drift
|
|
|
|
if (flake.y > canvas.height) {
|
|
flake.y = -flake.radius
|
|
flake.x = Math.random() * canvas.width
|
|
}
|
|
if (flake.x > canvas.width) {
|
|
flake.x = 0
|
|
} else if (flake.x < 0) {
|
|
flake.x = canvas.width
|
|
}
|
|
})
|
|
|
|
animationFrameId = requestAnimationFrame(drawSnowflakes)
|
|
}
|
|
|
|
resizeCanvas()
|
|
createSnowflakes()
|
|
drawSnowflakes()
|
|
|
|
window.addEventListener("resize", () => {
|
|
resizeCanvas()
|
|
createSnowflakes()
|
|
})
|
|
|
|
return () => {
|
|
cancelAnimationFrame(animationFrameId)
|
|
window.removeEventListener("resize", resizeCanvas)
|
|
}
|
|
}, [])
|
|
|
|
return (
|
|
<canvas
|
|
ref={canvasRef}
|
|
className="fixed inset-0 pointer-events-none z-50"
|
|
style={{ background: "transparent" }}
|
|
/>
|
|
)
|
|
}
|