feat: add activity feed and background effects
- Implemented ActivityFeed component to display real-time user activity including coding, music, and chat interactions. - Added GooFilter and BackgroundBlobs components for enhanced visual effects. - Updated layout to include new components and ensure proper stacking context. - Enhanced Tailwind CSS configuration with new color and font settings. - Created API route to mock activity data from n8n. - Refactored main page structure to streamline component rendering.
This commit is contained in:
77
components/BackgroundBlobs.tsx
Normal file
77
components/BackgroundBlobs.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
'use client';
|
||||
|
||||
import { motion, useMotionValue, useTransform, useSpring } from 'framer-motion';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
export const BackgroundBlobs = () => {
|
||||
const mouseX = useMotionValue(0);
|
||||
const mouseY = useMotionValue(0);
|
||||
|
||||
const springConfig = { damping: 50, stiffness: 200 };
|
||||
const springX = useSpring(mouseX, springConfig);
|
||||
const springY = useSpring(mouseY, springConfig);
|
||||
|
||||
// Parallax offsets
|
||||
const x1 = useTransform(springX, (value) => value / 20);
|
||||
const y1 = useTransform(springY, (value) => value / 20);
|
||||
|
||||
const x2 = useTransform(springX, (value) => value / -15);
|
||||
const y2 = useTransform(springY, (value) => value / -15);
|
||||
|
||||
const x3 = useTransform(springX, (value) => value / 10);
|
||||
const y3 = useTransform(springY, (value) => value / 10);
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseMove = (e: MouseEvent) => {
|
||||
// Center the coordinate system
|
||||
const { innerWidth, innerHeight } = window;
|
||||
const x = e.clientX - innerWidth / 2;
|
||||
const y = e.clientY - innerHeight / 2;
|
||||
mouseX.set(x);
|
||||
mouseY.set(y);
|
||||
};
|
||||
|
||||
window.addEventListener('mousemove', handleMouseMove);
|
||||
return () => window.removeEventListener('mousemove', handleMouseMove);
|
||||
}, [mouseX, mouseY]);
|
||||
|
||||
// Prevent hydration mismatch
|
||||
const [mounted, setMounted] = useState(false);
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
if (!mounted) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 overflow-hidden pointer-events-none z-0 liquid-container">
|
||||
<motion.div
|
||||
className="absolute top-[-10%] left-[-10%] w-[40vw] h-[40vw] bg-liquid-mint/40 rounded-full blur-[80px] mix-blend-multiply opacity-70"
|
||||
style={{ x: x1, y: y1 }}
|
||||
animate={{
|
||||
scale: [1, 1.2, 1],
|
||||
rotate: [0, 90, 0],
|
||||
}}
|
||||
transition={{ duration: 25, repeat: Infinity, ease: "linear" }}
|
||||
/>
|
||||
<motion.div
|
||||
className="absolute top-[20%] right-[-10%] w-[35vw] h-[35vw] bg-liquid-lavender/40 rounded-full blur-[80px] mix-blend-multiply opacity-70"
|
||||
style={{ x: x2, y: y2 }}
|
||||
animate={{
|
||||
scale: [1, 1.1, 1],
|
||||
rotate: [0, -60, 0],
|
||||
}}
|
||||
transition={{ duration: 30, repeat: Infinity, ease: "linear" }}
|
||||
/>
|
||||
<motion.div
|
||||
className="absolute bottom-[-10%] left-[20%] w-[45vw] h-[45vw] bg-liquid-rose/30 rounded-full blur-[80px] mix-blend-multiply opacity-70"
|
||||
style={{ x: x3, y: y3 }}
|
||||
animate={{
|
||||
scale: [1, 1.3, 1],
|
||||
rotate: [0, 45, 0]
|
||||
}}
|
||||
transition={{ duration: 35, repeat: Infinity, ease: "linear" }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user