зеркало из
https://github.com/kodackx/disinformation-quest.git
synced 2025-10-29 04:44:15 +02:00
Revise network animation
Updated the network animation to enhance its elegance and visual appeal. [skip gpt_engineer]
Этот коммит содержится в:
родитель
232ec7e58e
Коммит
23e32c1e18
@ -1,90 +1,112 @@
|
|||||||
import React from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
interface Node {
|
interface Node {
|
||||||
id: number;
|
id: number;
|
||||||
baseX: number;
|
x: number;
|
||||||
baseY: number;
|
y: number;
|
||||||
|
size: number;
|
||||||
|
delay: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NetworkAnimation = ({ className = '' }: { className?: string }) => {
|
export const NetworkAnimation = ({ className = '' }: { className?: string }) => {
|
||||||
const nodes: Node[] = Array.from({ length: 6 }, (_, i) => {
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const row = Math.floor(i / 2);
|
|
||||||
const col = i % 2;
|
// Generate nodes with different sizes and positions
|
||||||
return {
|
const nodes: Node[] = Array.from({ length: 12 }, (_, i) => ({
|
||||||
id: i,
|
id: i,
|
||||||
baseX: 30 + col * 40,
|
x: 20 + Math.random() * 60, // Random position between 20-80%
|
||||||
baseY: 25 + row * 25,
|
y: 20 + Math.random() * 60,
|
||||||
};
|
size: 2 + Math.random() * 2, // Random size between 2-4
|
||||||
});
|
delay: i * 0.1 // Staggered animation delay
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Create pairs of nodes for connections
|
||||||
|
const connections = nodes.flatMap((node, i) =>
|
||||||
|
nodes.slice(i + 1).map(otherNode => ({
|
||||||
|
id: `${node.id}-${otherNode.id}`,
|
||||||
|
from: node,
|
||||||
|
to: otherNode,
|
||||||
|
opacity: Math.random() * 0.3 + 0.1 // Random opacity between 0.1-0.4
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative w-full h-40 overflow-hidden bg-black/20 rounded-lg ${className}`}>
|
<div
|
||||||
<svg className="absolute inset-0 w-full h-full pointer-events-none">
|
ref={containerRef}
|
||||||
{nodes.map((node1) =>
|
className={`relative w-full h-40 overflow-hidden bg-black/20 rounded-lg ${className}`}
|
||||||
nodes
|
>
|
||||||
.filter((node2) => node2.id !== node1.id)
|
<svg className="absolute inset-0 w-full h-full">
|
||||||
.map((node2) => (
|
{/* Render connections between nodes */}
|
||||||
<motion.line
|
{connections.map(({ id, from, to, opacity }) => (
|
||||||
key={`${node1.id}-${node2.id}`}
|
<motion.line
|
||||||
x1={`${node1.baseX}%`}
|
key={id}
|
||||||
y1={`${node1.baseY}%`}
|
x1={`${from.x}%`}
|
||||||
x2={`${node2.baseX}%`}
|
y1={`${from.y}%`}
|
||||||
y2={`${node2.baseY}%`}
|
x2={`${to.x}%`}
|
||||||
stroke="rgba(255, 215, 0, 0.15)"
|
y2={`${to.y}%`}
|
||||||
strokeWidth="1"
|
stroke="rgba(255, 215, 0, 0.2)"
|
||||||
initial={{ opacity: 0 }}
|
strokeWidth="0.5"
|
||||||
animate={{
|
initial={{ opacity: 0, pathLength: 0 }}
|
||||||
opacity: [0, 0.5, 0],
|
animate={{
|
||||||
x1: [`${node1.baseX}%`, `${node1.baseX + (Math.random() > 0.5 ? 10 : -10)}%`],
|
opacity: [0, opacity, opacity/2],
|
||||||
y1: [`${node1.baseY}%`, `${node1.baseY + (Math.random() > 0.5 ? 10 : -10)}%`],
|
pathLength: [0, 1, 1]
|
||||||
x2: [`${node2.baseX}%`, `${node2.baseX + (Math.random() > 0.5 ? 10 : -10)}%`],
|
}}
|
||||||
y2: [`${node2.baseY}%`, `${node2.baseY + (Math.random() > 0.5 ? 10 : -10)}%`],
|
transition={{
|
||||||
}}
|
duration: 3,
|
||||||
transition={{
|
repeat: Infinity,
|
||||||
duration: 4,
|
repeatType: "reverse",
|
||||||
repeat: Infinity,
|
ease: "easeInOut",
|
||||||
repeatType: "mirror",
|
delay: from.delay
|
||||||
ease: "easeInOut"
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
))}
|
||||||
))
|
|
||||||
)}
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
|
{/* Render nodes */}
|
||||||
{nodes.map((node) => (
|
{nodes.map((node) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={node.id}
|
key={node.id}
|
||||||
className="absolute w-3 h-3"
|
className="absolute"
|
||||||
style={{
|
style={{
|
||||||
left: '-6px',
|
left: `${node.x}%`,
|
||||||
top: '-6px',
|
top: `${node.y}%`,
|
||||||
|
width: `${node.size}px`,
|
||||||
|
height: `${node.size}px`,
|
||||||
}}
|
}}
|
||||||
|
initial={{ scale: 0, opacity: 0 }}
|
||||||
animate={{
|
animate={{
|
||||||
|
scale: [0, 1, 1.2, 1],
|
||||||
|
opacity: [0, 1, 0.8, 1],
|
||||||
x: [
|
x: [
|
||||||
`${node.baseX}%`,
|
-10,
|
||||||
`${node.baseX + (Math.random() > 0.5 ? 10 : -10)}%`,
|
10,
|
||||||
`${node.baseX}%`,
|
-5,
|
||||||
|
5,
|
||||||
|
0
|
||||||
],
|
],
|
||||||
y: [
|
y: [
|
||||||
`${node.baseY}%`,
|
-5,
|
||||||
`${node.baseY + (Math.random() > 0.5 ? 10 : -10)}%`,
|
5,
|
||||||
`${node.baseY}%`,
|
-10,
|
||||||
],
|
10,
|
||||||
|
0
|
||||||
|
]
|
||||||
}}
|
}}
|
||||||
transition={{
|
transition={{
|
||||||
duration: 6,
|
duration: 8,
|
||||||
repeat: Infinity,
|
repeat: Infinity,
|
||||||
repeatType: "reverse",
|
repeatType: "reverse",
|
||||||
ease: "easeInOut",
|
ease: "easeInOut",
|
||||||
delay: node.id * 0.2,
|
delay: node.delay,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{/* Core node */}
|
||||||
<motion.div
|
<motion.div
|
||||||
className="absolute w-full h-full rounded-full bg-yellow-500"
|
className="absolute w-full h-full rounded-full bg-yellow-500"
|
||||||
animate={{
|
animate={{
|
||||||
scale: [1, 1.2, 1],
|
scale: [1, 1.2, 1],
|
||||||
opacity: [0.7, 1, 0.7],
|
opacity: [0.8, 1, 0.8],
|
||||||
}}
|
}}
|
||||||
transition={{
|
transition={{
|
||||||
duration: 2,
|
duration: 2,
|
||||||
@ -93,6 +115,7 @@ export const NetworkAnimation = ({ className = '' }: { className?: string }) =>
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Outer glow */}
|
||||||
<motion.div
|
<motion.div
|
||||||
className="absolute w-full h-full rounded-full bg-yellow-500/30"
|
className="absolute w-full h-full rounded-full bg-yellow-500/30"
|
||||||
animate={{
|
animate={{
|
||||||
@ -103,9 +126,29 @@ export const NetworkAnimation = ({ className = '' }: { className?: string }) =>
|
|||||||
duration: 3,
|
duration: 3,
|
||||||
repeat: Infinity,
|
repeat: Infinity,
|
||||||
ease: "easeInOut",
|
ease: "easeInOut",
|
||||||
delay: node.id * 0.1,
|
delay: node.delay * 0.5,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Particle effects */}
|
||||||
|
{Array.from({ length: 3 }).map((_, i) => (
|
||||||
|
<motion.div
|
||||||
|
key={i}
|
||||||
|
className="absolute w-1 h-1 rounded-full bg-yellow-500/20"
|
||||||
|
animate={{
|
||||||
|
x: [0, (i - 1) * 10],
|
||||||
|
y: [0, (i - 1) * 10],
|
||||||
|
scale: [0, 1, 0],
|
||||||
|
opacity: [0, 0.5, 0],
|
||||||
|
}}
|
||||||
|
transition={{
|
||||||
|
duration: 2,
|
||||||
|
repeat: Infinity,
|
||||||
|
delay: i * 0.3 + node.delay,
|
||||||
|
ease: "easeOut",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Загрузка…
x
Ссылка в новой задаче
Block a user