gitea
This commit is contained in:
120
frontend/components/landing/MagneticElements.tsx
Normal file
120
frontend/components/landing/MagneticElements.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
'use client'
|
||||
|
||||
import { motion, useMotionValue, useSpring, useTransform } from 'framer-motion'
|
||||
import { useRef, ReactNode } from 'react'
|
||||
|
||||
interface MagneticButtonProps {
|
||||
children: ReactNode
|
||||
className?: string
|
||||
onClick?: () => void
|
||||
strength?: number
|
||||
}
|
||||
|
||||
export function MagneticButton({
|
||||
children,
|
||||
className = '',
|
||||
onClick,
|
||||
strength = 0.3
|
||||
}: MagneticButtonProps) {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
|
||||
const x = useMotionValue(0)
|
||||
const y = useMotionValue(0)
|
||||
|
||||
const springConfig = { stiffness: 300, damping: 20 }
|
||||
const springX = useSpring(x, springConfig)
|
||||
const springY = useSpring(y, springConfig)
|
||||
|
||||
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (!ref.current) return
|
||||
|
||||
const rect = ref.current.getBoundingClientRect()
|
||||
const centerX = rect.left + rect.width / 2
|
||||
const centerY = rect.top + rect.height / 2
|
||||
|
||||
const deltaX = (e.clientX - centerX) * strength
|
||||
const deltaY = (e.clientY - centerY) * strength
|
||||
|
||||
x.set(deltaX)
|
||||
y.set(deltaY)
|
||||
}
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
x.set(0)
|
||||
y.set(0)
|
||||
}
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
ref={ref}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
onClick={onClick}
|
||||
style={{ x: springX, y: springY }}
|
||||
className={`inline-block ${className}`}
|
||||
>
|
||||
{children}
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
||||
interface SectionDividerProps {
|
||||
variant?: 'wave' | 'diagonal' | 'curve'
|
||||
fromColor?: string
|
||||
toColor?: string
|
||||
flip?: boolean
|
||||
}
|
||||
|
||||
export function SectionDivider({
|
||||
variant = 'wave',
|
||||
fromColor = 'section-bg-3',
|
||||
toColor = 'section-bg-4',
|
||||
flip = false
|
||||
}: SectionDividerProps) {
|
||||
if (variant === 'wave') {
|
||||
return (
|
||||
<div className={`w-full h-20 -mt-1 overflow-hidden ${flip ? 'rotate-180' : ''}`}>
|
||||
<svg
|
||||
viewBox="0 0 1200 120"
|
||||
preserveAspectRatio="none"
|
||||
className="w-full h-full"
|
||||
>
|
||||
<path
|
||||
d="M0,0 Q300,80 600,40 T1200,0 L1200,120 L0,120 Z"
|
||||
fill={`hsl(var(--${toColor}))`}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (variant === 'diagonal') {
|
||||
return (
|
||||
<div
|
||||
className={`w-full h-16 ${flip ? '-skew-y-2' : 'skew-y-2'}`}
|
||||
style={{
|
||||
background: `linear-gradient(to bottom right, hsl(var(--${fromColor})), hsl(var(--${toColor})))`
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (variant === 'curve') {
|
||||
return (
|
||||
<div className={`w-full h-24 -mt-1 overflow-hidden ${flip ? 'rotate-180' : ''}`}>
|
||||
<svg
|
||||
viewBox="0 0 1200 120"
|
||||
preserveAspectRatio="none"
|
||||
className="w-full h-full"
|
||||
>
|
||||
<path
|
||||
d="M0,60 Q300,120 600,60 T1200,60 L1200,120 L0,120 Z"
|
||||
fill={`hsl(var(--${toColor}))`}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user