import React, { useState, useRef, useEffect } from 'react';
export default function FidgetToy() {
const [sliderValue, setSliderValue] = useState(0);
const [isDragging, setIsDragging] = useState(false);
const [selectedEmotion, setSelectedEmotion] = useState(0);
const sliderRef = useRef(null);
const emotions = [
{ name: 'SERENITY', color: '#7FDBCA' },
{ name: 'RAGE', color: '#FF6B6B' },
{ name: 'JOY', color: '#FFD93D' },
{ name: 'SADNESS', color: '#6C9BCF' },
{ name: 'FEAR', color: '#B39DDB' },
{ name: 'DISGUST', color: '#98D8A0' },
{ name: 'LOVE', color: '#FFB3BA' },
{ name: 'ENVY', color: '#90EE90' },
];
const numBars = 20;
const updateSliderFromPosition = (clientY) => {
if (!sliderRef.current) return;
const rect = sliderRef.current.getBoundingClientRect();
const y = clientY - rect.top;
const percentage = Math.max(0, Math.min(100, ((rect.height - y) / rect.height) * 100));
setSliderValue(percentage);
};
const handleStart = (clientY) => {
setIsDragging(true);
updateSliderFromPosition(clientY);
};
const handleMove = (clientY) => {
if (!isDragging) return;
updateSliderFromPosition(clientY);
};
const handleEnd = () => {
setIsDragging(false);
};
const handleReset = () => {
setSliderValue(0);
};
const handleTouchStart = (e) => {
const touch = e.touches[0];
handleStart(touch.clientY);
};
const handleTouchMove = (e) => {
const touch = e.touches[0];
handleMove(touch.clientY);
};
const handleMouseDown = (e) => {
handleStart(e.clientY);
};
useEffect(() => {
const handleGlobalMouseMove = (e) => handleMove(e.clientY);
const handleGlobalMouseUp = () => handleEnd();
if (isDragging) {
window.addEventListener('mousemove', handleGlobalMouseMove);
window.addEventListener('mouseup', handleGlobalMouseUp);
}
return () => {
window.removeEventListener('mousemove', handleGlobalMouseMove);
window.removeEventListener('mouseup', handleGlobalMouseUp);
};
}, [isDragging]);
const filledBars = Math.floor((sliderValue / 100) * numBars);
return (
<div
className="relative w-full h-screen overflow-hidden flex flex-col items-center justify-center select-none"
style={{
backgroundColor: '#1a1a1a'
}}
>
{/* Scrollable emotions */}
<div className="absolute top-16 left-0 right-0 overflow-x-auto overflow-y-hidden px-8"
style={{
scrollbarWidth: 'none',
msOverflowStyle: 'none',
WebkitOverflowScrolling: 'touch'
}}
>
<style jsx>{`
div::-webkit-scrollbar {
display: none;
}
`}</style>
<div className="flex gap-8 pb-4">
{emotions.map((emotion, i) => (
<button
key={i}
onClick={() => setSelectedEmotion(i)}
className="flex-shrink-0 text-2xl font-light tracking-widest transition-all"
style={{
color: selectedEmotion === i ? emotion.color : 'rgba(255, 255, 255, 0.3)',
textShadow: selectedEmotion === i ? `0 0 20px ${emotion.color}` : 'none',
cursor: 'pointer'
}}
>
{emotion.name}
</button>
))}
</div>
</div>
{/* Dot indicators */}
<div className="absolute top-36 flex gap-2">
{emotions.map((_, i) => (
<div
key={i}
className="w-1.5 h-1.5 rounded-full transition-all"
style={{
backgroundColor: selectedEmotion === i ? emotions[selectedEmotion].color : 'rgba(255, 255, 255, 0.2)'
}}
/>
))}
</div>
{/* Slider container */}
<div
ref={sliderRef}
className="relative cursor-pointer"
style={{
height: '50%',
width: '200px',
marginTop: '40px'
}}
onMouseDown={handleMouseDown}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleEnd}
>
{/* Horizontal bars */}
<div className="absolute inset-0 flex flex-col-reverse justify-start gap-1">
{[...Array(numBars)].map((_, i) => (
<div
key={i}
className="w-full relative"
style={{
height: `${100 / numBars}%`,
}}
>
{/* Background bar */}
<div
className="absolute inset-0"
style={{
backgroundColor: 'rgba(255, 255, 255, 0.05)',
borderRadius: '2px',
}}
/>
{/* Filled bar */}
<div
className="absolute inset-0"
style={{
backgroundColor: i < filledBars ? emotions[selectedEmotion].color : 'transparent',
borderRadius: '2px',
transition: 'background-color 0.2s ease',
boxShadow: i < filledBars ? `0 0 10px ${emotions[selectedEmotion].color}40` : 'none',
}}
/>
</div>
))}
</div>
{/* Finger indicator line */}
{isDragging && (
<div
className="absolute left-0 right-0 pointer-events-none"
style={{
bottom: `${sliderValue}%`,
height: '2px',
backgroundColor: 'rgba(255, 255, 255, 0.6)',
boxShadow: '0 0 10px rgba(255, 255, 255, 0.4)',
}}
/>
)}
</div>
{/* Reset button */}
<button
onClick={handleReset}
className="absolute bottom-24 px-8 py-3 text-sm font-light tracking-widest transition-all"
style={{
fontFamily: 'Georgia, serif',
color: 'rgba(255, 255, 255, 0.6)',
border: '1px solid rgba(255, 255, 255, 0.2)',
borderRadius: '25px',
backgroundColor: 'rgba(255, 255, 255, 0.05)',
cursor: 'pointer'
}}
onMouseEnter={(e) => {
e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.1)';
e.currentTarget.style.color = 'rgba(255, 255, 255, 0.9)';
}}
onMouseLeave={(e) => {
e.currentTarget.style.backgroundColor = 'rgba(255, 255, 255, 0.05)';
e.currentTarget.style.color = 'rgba(255, 255, 255, 0.6)';
}}
>
RESET
</button>
{/* Hint text */}
<div className="absolute bottom-8 left-0 right-0 text-center">
<p
className="text-gray-500 text-sm font-light tracking-wide"
style={{ fontFamily: 'Georgia, serif' }}
>
tap emotion · drag upward to fill
</p>
</div>
</div>
);
}