Nova versao codex Parecer, atualizacao completa
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useId,
|
||||
useRef,
|
||||
useState,
|
||||
type ComponentPropsWithoutRef,
|
||||
} from "react"
|
||||
import { motion } from "motion/react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
export interface AnimatedGridPatternProps extends ComponentPropsWithoutRef<"svg"> {
|
||||
width?: number
|
||||
height?: number
|
||||
x?: number
|
||||
y?: number
|
||||
strokeDasharray?: number
|
||||
numSquares?: number
|
||||
maxOpacity?: number
|
||||
duration?: number
|
||||
repeatDelay?: number
|
||||
}
|
||||
|
||||
type Square = {
|
||||
id: number
|
||||
pos: [number, number]
|
||||
iteration: number
|
||||
}
|
||||
|
||||
export function AnimatedGridPattern({
|
||||
width = 40,
|
||||
height = 40,
|
||||
x = -1,
|
||||
y = -1,
|
||||
strokeDasharray = 0,
|
||||
numSquares = 50,
|
||||
className,
|
||||
maxOpacity = 0.5,
|
||||
duration = 4,
|
||||
repeatDelay = 0.5,
|
||||
...props
|
||||
}: AnimatedGridPatternProps) {
|
||||
const id = useId()
|
||||
const containerRef = useRef<SVGSVGElement | null>(null)
|
||||
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
|
||||
const [squares, setSquares] = useState<Array<Square>>([])
|
||||
|
||||
const getPos = useCallback((): [number, number] => {
|
||||
return [
|
||||
Math.floor((Math.random() * dimensions.width) / width),
|
||||
Math.floor((Math.random() * dimensions.height) / height),
|
||||
]
|
||||
}, [dimensions.height, dimensions.width, height, width])
|
||||
|
||||
const generateSquares = useCallback(
|
||||
(count: number) => {
|
||||
return Array.from({ length: count }, (_, i) => ({
|
||||
id: i,
|
||||
pos: getPos(),
|
||||
iteration: 0,
|
||||
}))
|
||||
},
|
||||
[getPos]
|
||||
)
|
||||
|
||||
const updateSquarePosition = useCallback(
|
||||
(squareId: number) => {
|
||||
setSquares((currentSquares) => {
|
||||
const current = currentSquares[squareId]
|
||||
if (!current || current.id !== squareId) return currentSquares
|
||||
|
||||
const nextSquares = currentSquares.slice()
|
||||
nextSquares[squareId] = {
|
||||
...current,
|
||||
pos: getPos(),
|
||||
iteration: current.iteration + 1,
|
||||
}
|
||||
|
||||
return nextSquares
|
||||
})
|
||||
},
|
||||
[getPos]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (dimensions.width && dimensions.height) {
|
||||
setSquares(generateSquares(numSquares))
|
||||
}
|
||||
}, [dimensions.width, dimensions.height, generateSquares, numSquares])
|
||||
|
||||
useEffect(() => {
|
||||
const element = containerRef.current
|
||||
let resizeObserver: ResizeObserver | null = null
|
||||
|
||||
if (element) {
|
||||
resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
setDimensions((currentDimensions) => {
|
||||
const nextWidth = entry.contentRect.width
|
||||
const nextHeight = entry.contentRect.height
|
||||
if (
|
||||
currentDimensions.width === nextWidth &&
|
||||
currentDimensions.height === nextHeight
|
||||
) {
|
||||
return currentDimensions
|
||||
}
|
||||
return { width: nextWidth, height: nextHeight }
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
resizeObserver.observe(element)
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (resizeObserver) {
|
||||
resizeObserver.disconnect()
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<svg
|
||||
ref={containerRef}
|
||||
aria-hidden="true"
|
||||
className={cn(
|
||||
"pointer-events-none absolute inset-0 h-full w-full fill-gray-400/30 stroke-gray-400/30",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<defs>
|
||||
<pattern
|
||||
id={id}
|
||||
width={width}
|
||||
height={height}
|
||||
patternUnits="userSpaceOnUse"
|
||||
x={x}
|
||||
y={y}
|
||||
>
|
||||
<path
|
||||
d={`M.5 ${height}V.5H${width}`}
|
||||
fill="none"
|
||||
strokeDasharray={strokeDasharray}
|
||||
/>
|
||||
</pattern>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill={`url(#${id})`} />
|
||||
<svg x={x} y={y} className="overflow-visible">
|
||||
{squares.map(({ pos: [squareX, squareY], id, iteration }, index) => (
|
||||
<motion.rect
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: maxOpacity }}
|
||||
transition={{
|
||||
duration,
|
||||
repeat: 1,
|
||||
delay: index * 0.1,
|
||||
repeatType: "reverse",
|
||||
repeatDelay,
|
||||
}}
|
||||
onAnimationComplete={() => updateSquarePosition(id)}
|
||||
key={`${id}-${iteration}`}
|
||||
width={width - 1}
|
||||
height={height - 1}
|
||||
x={squareX * width + 1}
|
||||
y={squareY * height + 1}
|
||||
fill="currentColor"
|
||||
strokeWidth="0"
|
||||
/>
|
||||
))}
|
||||
</svg>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user