336 lines
15 KiB
TypeScript
336 lines
15 KiB
TypeScript
'use client';
|
||
|
||
import { useState, useRef, useEffect } from 'react';
|
||
import styles from './SocialConnect.module.css';
|
||
|
||
const socialPlatforms = [
|
||
{ name: 'Bluesky', icon: '🦋', color: '#0085ff', delay: 0, symbol: 'B' },
|
||
{ name: 'Facebook', icon: 'f', color: '#1877f2', delay: 0.1, symbol: 'F' },
|
||
{ name: 'Google', icon: 'G', color: '#4285f4', delay: 0.2, symbol: 'G' },
|
||
{ name: 'Instagram', icon: '📷', color: '#e4405f', delay: 0.3, symbol: 'I' },
|
||
{ name: 'LinkedIn', icon: 'in', color: '#0a66c2', delay: 0.4, symbol: 'L' },
|
||
{ name: 'Mastodon', icon: '🐘', color: '#6364ff', delay: 0.5, symbol: 'M' },
|
||
{ name: 'Pinterest', icon: 'P', color: '#e60023', delay: 0.6, symbol: 'P' },
|
||
{ name: 'Threads', icon: '@', color: '#000000', delay: 0.7, symbol: 'T' },
|
||
{ name: 'TikTok', icon: '♪', color: '#000000', delay: 0.8, symbol: 'TT' },
|
||
{ name: 'X', icon: '𝕏', color: '#000000', delay: 0.9, symbol: 'X' },
|
||
{ name: 'YouTube', icon: '▶', color: '#ff0000', delay: 1.0, symbol: 'Y' },
|
||
];
|
||
|
||
interface Particle {
|
||
x: number;
|
||
y: number;
|
||
vx: number;
|
||
vy: number;
|
||
life: number;
|
||
color: string;
|
||
}
|
||
|
||
export default function SocialConnect() {
|
||
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
||
const [selectedPlatforms, setSelectedPlatforms] = useState<number[]>([]);
|
||
const [particles, setParticles] = useState<Particle[]>([]);
|
||
const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
|
||
const containerRef = useRef<HTMLDivElement>(null);
|
||
const cardRefs = useRef<(HTMLDivElement | null)[]>([]);
|
||
|
||
// 3D Tilt Effect on Mouse Move
|
||
const handleMouseMove = (e: React.MouseEvent, index: number) => {
|
||
const card = cardRefs.current[index];
|
||
if (!card) return;
|
||
|
||
const rect = card.getBoundingClientRect();
|
||
const x = e.clientX - rect.left;
|
||
const y = e.clientY - rect.top;
|
||
|
||
const centerX = rect.width / 2;
|
||
const centerY = rect.height / 2;
|
||
|
||
const rotateX = ((y - centerY) / centerY) * -15;
|
||
const rotateY = ((x - centerX) / centerX) * 15;
|
||
|
||
card.style.transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) translateY(-10px) scale(1.05)`;
|
||
};
|
||
|
||
const handleMouseLeave = (index: number) => {
|
||
const card = cardRefs.current[index];
|
||
if (card) {
|
||
card.style.transform = '';
|
||
}
|
||
setHoveredIndex(null);
|
||
};
|
||
|
||
// Particle Explosion on Click
|
||
const createParticles = (e: React.MouseEvent, color: string) => {
|
||
const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
|
||
const x = e.clientX - rect.left;
|
||
const y = e.clientY - rect.top;
|
||
|
||
const newParticles: Particle[] = [];
|
||
for (let i = 0; i < 12; i++) {
|
||
const angle = (Math.PI * 2 * i) / 12;
|
||
newParticles.push({
|
||
x,
|
||
y,
|
||
vx: Math.cos(angle) * (2 + Math.random() * 3),
|
||
vy: Math.sin(angle) * (2 + Math.random() * 3),
|
||
life: 1,
|
||
color,
|
||
});
|
||
}
|
||
setParticles(prev => [...prev, ...newParticles]);
|
||
};
|
||
|
||
const handlePlatformClick = (index: number, e: React.MouseEvent) => {
|
||
const isSelected = selectedPlatforms.includes(index);
|
||
|
||
setSelectedPlatforms(prev =>
|
||
prev.includes(index)
|
||
? prev.filter(i => i !== index)
|
||
: [...prev, index]
|
||
);
|
||
|
||
// Create particle explosion
|
||
createParticles(e, socialPlatforms[index].color);
|
||
};
|
||
|
||
// Animate particles
|
||
useEffect(() => {
|
||
if (particles.length === 0) return;
|
||
|
||
const interval = setInterval(() => {
|
||
setParticles(prev =>
|
||
prev
|
||
.map(p => ({
|
||
...p,
|
||
x: p.x + p.vx,
|
||
y: p.y + p.vy,
|
||
vy: p.vy + 0.2, // gravity
|
||
life: p.life - 0.02,
|
||
}))
|
||
.filter(p => p.life > 0)
|
||
);
|
||
}, 16);
|
||
|
||
return () => clearInterval(interval);
|
||
}, [particles]);
|
||
|
||
// Magnetic cursor effect
|
||
const handleContainerMouseMove = (e: React.MouseEvent) => {
|
||
setMousePos({ x: e.clientX, y: e.clientY });
|
||
};
|
||
|
||
return (
|
||
<section className={styles.connectSection} onMouseMove={handleContainerMouseMove}>
|
||
<div className="container">
|
||
{/* Animated Background Elements */}
|
||
<div className={styles.backgroundAnimation}>
|
||
<div className={styles.floatingOrb1}></div>
|
||
<div className={styles.floatingOrb2}></div>
|
||
<div className={styles.floatingOrb3}></div>
|
||
<div className={styles.gridPattern}></div>
|
||
</div>
|
||
|
||
{/* Header */}
|
||
<div className={styles.header}>
|
||
<span className={styles.badge}>
|
||
<span className={styles.badgeIcon}>🔗</span>
|
||
<span>One Platform, All Networks</span>
|
||
<span className={styles.badgePulse}></span>
|
||
</span>
|
||
<h2 className={styles.title}>
|
||
Connect Your <span className={styles.highlight}>Favorite Accounts</span>
|
||
</h2>
|
||
<p className={styles.subtitle}>
|
||
Seamlessly integrate all your social media platforms in one place.
|
||
Manage, schedule, and analyze everything from a single dashboard.
|
||
</p>
|
||
</div>
|
||
|
||
{/* Interactive Platform Grid */}
|
||
<div className={styles.platformsContainer} ref={containerRef}>
|
||
<div className={styles.connectText}>
|
||
<div className={styles.connectIconWrapper}>
|
||
<div className={styles.connectIcon}>🌐</div>
|
||
<div className={styles.iconRings}>
|
||
<div className={styles.ring}></div>
|
||
<div className={styles.ring}></div>
|
||
<div className={styles.ring}></div>
|
||
</div>
|
||
</div>
|
||
<h3>Connect your<br /><span className={styles.gradientText}>favorite accounts</span></h3>
|
||
<p className={styles.connectSubtext}>Click to select platforms</p>
|
||
</div>
|
||
|
||
<div className={styles.platformsGrid}>
|
||
{socialPlatforms.map((platform, index) => (
|
||
<div
|
||
key={platform.name}
|
||
ref={el => { cardRefs.current[index] = el; }}
|
||
className={`${styles.platformCard} ${selectedPlatforms.includes(index) ? styles.selected : ''
|
||
} ${hoveredIndex === index ? styles.hovered : ''}`}
|
||
style={{
|
||
animationDelay: `${platform.delay}s`,
|
||
'--platform-color': platform.color
|
||
} as React.CSSProperties}
|
||
onMouseEnter={() => setHoveredIndex(index)}
|
||
onMouseMove={(e) => handleMouseMove(e, index)}
|
||
onMouseLeave={() => handleMouseLeave(index)}
|
||
onClick={(e) => handlePlatformClick(index, e)}
|
||
>
|
||
{/* 3D Card Inner */}
|
||
<div className={styles.cardInner}>
|
||
<div className={styles.cardFront}>
|
||
<div className={styles.platformIcon}>
|
||
<span className={styles.iconEmoji} style={{ color: platform.color }}>
|
||
{platform.icon}
|
||
</span>
|
||
<div className={styles.platformName}>{platform.name}</div>
|
||
{selectedPlatforms.includes(index) && (
|
||
<div className={styles.checkmark}>
|
||
<span>✓</span>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Animated border */}
|
||
<div className={styles.animatedBorder}></div>
|
||
|
||
{/* Shine effect */}
|
||
<div className={styles.shineEffect}></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div className={styles.platformRipple}></div>
|
||
<div className={styles.platformGlow}></div>
|
||
|
||
{/* Connection dots */}
|
||
{selectedPlatforms.includes(index) && (
|
||
<div className={styles.connectionDots}>
|
||
<span></span>
|
||
<span></span>
|
||
<span></span>
|
||
</div>
|
||
)}
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
{/* Particle System */}
|
||
<div className={styles.particleContainer}>
|
||
{particles.map((particle, i) => (
|
||
<div
|
||
key={i}
|
||
className={styles.particle}
|
||
style={{
|
||
left: `${particle.x}px`,
|
||
top: `${particle.y}px`,
|
||
backgroundColor: particle.color,
|
||
opacity: particle.life,
|
||
transform: `scale(${particle.life})`,
|
||
}}
|
||
/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Enhanced Stats Bar */}
|
||
<div className={styles.statsBar}>
|
||
<div className={styles.statItem}>
|
||
<div className={styles.statIconWrapper}>
|
||
<div className={styles.statIcon}>🎯</div>
|
||
<div className={styles.statIconGlow}></div>
|
||
</div>
|
||
<div className={styles.statContent}>
|
||
<div className={styles.statNumber}>11+</div>
|
||
<div className={styles.statLabel}>Platforms Supported</div>
|
||
</div>
|
||
</div>
|
||
<div className={styles.statDivider}></div>
|
||
<div className={styles.statItem}>
|
||
<div className={styles.statIconWrapper}>
|
||
<div className={styles.statIcon}>⚡</div>
|
||
<div className={styles.statIconGlow}></div>
|
||
</div>
|
||
<div className={styles.statContent}>
|
||
<div className={`${styles.statNumber} ${styles.animated}`}>
|
||
{selectedPlatforms.length > 0 ? selectedPlatforms.length : '0'}
|
||
</div>
|
||
<div className={styles.statLabel}>Selected Networks</div>
|
||
</div>
|
||
</div>
|
||
<div className={styles.statDivider}></div>
|
||
<div className={styles.statItem}>
|
||
<div className={styles.statIconWrapper}>
|
||
<div className={styles.statIcon}>🚀</div>
|
||
<div className={styles.statIconGlow}></div>
|
||
</div>
|
||
<div className={styles.statContent}>
|
||
<div className={styles.statNumber}>1-Click</div>
|
||
<div className={styles.statLabel}>Easy Integration</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Enhanced CTA Section */}
|
||
<div className={styles.ctaSection}>
|
||
<div className={styles.ctaBackground}>
|
||
<div className={styles.ctaOrb1}></div>
|
||
<div className={styles.ctaOrb2}></div>
|
||
</div>
|
||
<div className={styles.ctaContent}>
|
||
<h3 className={styles.ctaTitle}>Ready to streamline your social media?</h3>
|
||
<p className={styles.ctaText}>
|
||
Connect all your accounts now and start managing them from one powerful dashboard.
|
||
</p>
|
||
</div>
|
||
<div className={styles.ctaButtons}>
|
||
<button className="btn btn-primary btn-large">
|
||
Get Started Free
|
||
<span className={styles.arrow}>→</span>
|
||
</button>
|
||
<button className="btn btn-secondary btn-large">
|
||
View All Features
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Floating Connection Lines Animation */}
|
||
<svg className={styles.connectionLines} viewBox="0 0 1200 400" preserveAspectRatio="none">
|
||
<defs>
|
||
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||
<stop offset="0%" stopColor="#ec4899" stopOpacity="0.6" />
|
||
<stop offset="50%" stopColor="#a855f7" stopOpacity="0.6" />
|
||
<stop offset="100%" stopColor="#3b82f6" stopOpacity="0.6" />
|
||
</linearGradient>
|
||
<filter id="glow">
|
||
<feGaussianBlur stdDeviation="3" result="coloredBlur" />
|
||
<feMerge>
|
||
<feMergeNode in="coloredBlur" />
|
||
<feMergeNode in="SourceGraphic" />
|
||
</feMerge>
|
||
</filter>
|
||
</defs>
|
||
<path
|
||
className={styles.animatedPath}
|
||
d="M 0 200 Q 300 100 600 200 T 1200 200"
|
||
stroke="url(#lineGradient)"
|
||
strokeWidth="3"
|
||
fill="none"
|
||
filter="url(#glow)"
|
||
/>
|
||
<path
|
||
className={styles.animatedPath}
|
||
d="M 0 250 Q 300 350 600 250 T 1200 250"
|
||
stroke="url(#lineGradient)"
|
||
strokeWidth="3"
|
||
fill="none"
|
||
filter="url(#glow)"
|
||
style={{ animationDelay: '1s' }}
|
||
/>
|
||
</svg>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|