From 5140b87cb02df5f52719223832e2593a5e071aa9 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:07:56 +0330 Subject: [PATCH] Import source: src/components/GenreExplorer/GenreExplorer Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- .../GenreExplorer/GenreExplorer.jsx | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 src/components/GenreExplorer/GenreExplorer.jsx diff --git a/src/components/GenreExplorer/GenreExplorer.jsx b/src/components/GenreExplorer/GenreExplorer.jsx new file mode 100644 index 0000000..7d3bf23 --- /dev/null +++ b/src/components/GenreExplorer/GenreExplorer.jsx @@ -0,0 +1,129 @@ +import { useRef } from 'react' +import { Canvas, useFrame } from '@react-three/fiber' +import { motion, useMotionValue, useSpring, useTransform } from 'framer-motion' + +const genres = [ + { name: 'Ambient', count: '12.4K', icon: '◉' }, + { name: 'Electronic', count: '48.2K', icon: '◈' }, + { name: 'Cinematic', count: '9.1K', icon: '◎' }, + { name: 'Dark Wave', count: '7.8K', icon: '◆' }, + { name: 'Synthwave', count: '31.5K', icon: '◇' }, + { name: 'Lo-Fi', count: '22.9K', icon: '○' }, + { name: 'Jazz Fusion', count: '5.3K', icon: '◐' }, + { name: 'Neo-Soul', count: '18.7K', icon: '◑' }, +] + +function RotatingRing() { + const ref = useRef() + useFrame(({ clock }) => { + ref.current.rotation.x = clock.getElapsedTime() * 0.12 + ref.current.rotation.y = clock.getElapsedTime() * 0.18 + }) + return ( + + + + + + + + + + + + + + + + + + + ) +} + +function GenreCard({ genre, index }) { + const x = useMotionValue(0) + const y = useMotionValue(0) + const rotateX = useSpring(useTransform(y, [-0.5, 0.5], [10, -10]), { stiffness: 250, damping: 25 }) + const rotateY = useSpring(useTransform(x, [-0.5, 0.5], [-10, 10]), { stiffness: 250, damping: 25 }) + const cardRef = useRef() + + const handleMouseMove = (e) => { + const rect = cardRef.current.getBoundingClientRect() + x.set((e.clientX - rect.left) / rect.width - 0.5) + y.set((e.clientY - rect.top) / rect.height - 0.5) + } + + return ( + { x.set(0); y.set(0) }} + style={{ rotateX, rotateY, transformStyle: 'preserve-3d', perspective: 600 }} + initial={{ opacity: 0, y: 30 }} + whileInView={{ opacity: 1, y: 0 }} + viewport={{ once: true }} + transition={{ duration: 0.5, delay: index * 0.07 }} + whileHover={{ scale: 1.05, y: -4 }} + className="relative cursor-pointer group rounded-2xl p-5 flex flex-col justify-between" + style={{ background: '#101010', border: '1px solid #1e1e1e', height: '130px' }} + > +
+ +
+ {genre.icon} + {genre.count} +
+ +
+

{genre.name}

+

tracks

+
+ + ) +} + +export default function GenreExplorer() { + return ( +
+
+
+
+ + {/* Left: 3D orbit animation */} +
+ + + + + + +
+ + {/* Right: genre cards */} +
+ +

Browse

+

+ Explore by Genre +

+
+ +
+ {genres.map((genre, i) => ( + + ))} +
+
+
+
+
+ ) +}