Initial commit: 风影 OA 全栈源码(API/Web/Flutter/IM)
含 Phase 1.1 IM seq 排序、断线重连、多端已读同步与微信式语音转文字 UI。 排除 node_modules、构建产物、安装包与 .env 密钥。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export default function AmbientBackground() {
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
let frame = 0;
|
||||
let width = (canvas.width = window.innerWidth);
|
||||
let height = (canvas.height = window.innerHeight);
|
||||
const onResize = () => {
|
||||
width = canvas.width = window.innerWidth;
|
||||
height = canvas.height = window.innerHeight;
|
||||
};
|
||||
window.addEventListener('resize', onResize);
|
||||
|
||||
const particles = Array.from({ length: 32 }, () => ({
|
||||
x: Math.random() * width,
|
||||
y: Math.random() * height,
|
||||
size: Math.random() * 3 + 1.2,
|
||||
speedY: -(Math.random() * 0.4 + 0.15),
|
||||
speedX: (Math.random() - 0.5) * 0.2,
|
||||
opacity: Math.random() * 0.5 + 0.2,
|
||||
pulse: Math.random() * Math.PI,
|
||||
pulseSpeed: Math.random() * 0.03 + 0.01,
|
||||
}));
|
||||
|
||||
const render = () => {
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
for (const p of particles) {
|
||||
p.y += p.speedY;
|
||||
p.x += p.speedX;
|
||||
p.pulse += p.pulseSpeed;
|
||||
if (p.y < -10) {
|
||||
p.y = height + 10;
|
||||
p.x = Math.random() * width;
|
||||
}
|
||||
if (p.x < -10) p.x = width + 10;
|
||||
if (p.x > width + 10) p.x = -10;
|
||||
const a = p.opacity * (0.7 + 0.3 * Math.sin(p.pulse));
|
||||
ctx.beginPath();
|
||||
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
|
||||
ctx.fillStyle = `rgba(107, 56, 212, ${a * 0.45})`;
|
||||
ctx.fill();
|
||||
}
|
||||
frame = requestAnimationFrame(render);
|
||||
};
|
||||
render();
|
||||
return () => {
|
||||
window.removeEventListener('resize', onResize);
|
||||
cancelAnimationFrame(frame);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="yzl-ambient" aria-hidden>
|
||||
<div className="yzl-orb yzl-orb-a" />
|
||||
<div className="yzl-orb yzl-orb-b" />
|
||||
<div className="yzl-orb yzl-orb-c" />
|
||||
<canvas ref={canvasRef} className="yzl-particles" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user