mirror of
https://github.com/JorySeverijnse/ui-fixer-supreme.git
synced 2026-01-29 23:38:36 +00:00
149 lines
6.1 KiB
TypeScript
149 lines
6.1 KiB
TypeScript
import { useState } from 'react';
|
|
import { motion, AnimatePresence } from 'framer-motion';
|
|
import { Settings, Monitor, Volume2, Cpu, X, Contrast } from 'lucide-react';
|
|
import { useSettings } from '@/contexts/SettingsContext';
|
|
import { useAchievements } from '@/contexts/AchievementsContext';
|
|
import CryptoConsentModal from './CryptoConsentModal';
|
|
|
|
interface SettingsPanelProps {
|
|
onToggleTheme: () => void;
|
|
isRedTheme: boolean;
|
|
}
|
|
|
|
const SettingsPanel = ({ onToggleTheme, isRedTheme }: SettingsPanelProps) => {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [showCryptoModal, setShowCryptoModal] = useState(false);
|
|
const { crtEnabled, setCrtEnabled, soundEnabled, setSoundEnabled, cryptoConsent, playSound } = useSettings();
|
|
const { unlockAchievement } = useAchievements();
|
|
|
|
const handleToggle = (setter: (value: boolean) => void, currentValue: boolean, achievementId?: string) => {
|
|
playSound('click');
|
|
setter(!currentValue);
|
|
if (achievementId) unlockAchievement(achievementId);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<button
|
|
onClick={() => {
|
|
playSound('click');
|
|
setIsOpen(!isOpen);
|
|
}}
|
|
aria-label="Open settings"
|
|
className="fixed top-4 right-4 z-[150] p-2 border border-primary text-primary bg-background/80 transition-all duration-300 hover:bg-primary hover:text-background box-glow"
|
|
>
|
|
<Settings size={20} className={isOpen ? 'animate-spin' : ''} />
|
|
</button>
|
|
|
|
<AnimatePresence>
|
|
{isOpen && (
|
|
<motion.div
|
|
initial={{ opacity: 0, x: 100 }}
|
|
animate={{ opacity: 1, x: 0 }}
|
|
exit={{ opacity: 0, x: 100 }}
|
|
className="fixed top-16 right-4 z-[150] w-72 border-2 border-primary bg-background p-4 box-glow"
|
|
>
|
|
<div className="flex items-center justify-between mb-4">
|
|
<h2 className="font-minecraft text-lg text-primary text-glow">Settings</h2>
|
|
<button
|
|
onClick={() => setIsOpen(false)}
|
|
aria-label="Close settings"
|
|
className="text-primary hover:text-primary/80"
|
|
>
|
|
<X size={16} />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
{/* Theme Toggle */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<Contrast size={16} className="text-primary" />
|
|
<span className="font-pixel text-sm text-foreground/90">Color Theme</span>
|
|
</div>
|
|
<button
|
|
onClick={onToggleTheme}
|
|
className="px-3 py-1 text-xs font-pixel border border-primary transition-all duration-300 bg-transparent text-primary hover:bg-primary hover:text-background"
|
|
>
|
|
{isRedTheme ? 'RED' : 'GREEN'}
|
|
</button>
|
|
</div>
|
|
|
|
{/* CRT Toggle */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<Monitor size={16} className="text-primary" />
|
|
<span className="font-pixel text-sm text-foreground/90">CRT Effects</span>
|
|
</div>
|
|
<button
|
|
onClick={() => handleToggle(setCrtEnabled, crtEnabled, 'crt_toggler')}
|
|
className={`w-12 h-6 rounded-full border border-primary transition-all duration-300 ${
|
|
crtEnabled ? 'bg-primary' : 'bg-transparent'
|
|
}`}
|
|
>
|
|
<div
|
|
className={`w-4 h-4 rounded-full bg-background border border-primary transition-transform duration-300 ${
|
|
crtEnabled ? 'translate-x-6' : 'translate-x-1'
|
|
}`}
|
|
/>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Sound Toggle */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<Volume2 size={16} className="text-primary" />
|
|
<span className="font-pixel text-sm text-foreground/90">Sound Effects</span>
|
|
</div>
|
|
<button
|
|
onClick={() => handleToggle(setSoundEnabled, soundEnabled, 'sound_toggler')}
|
|
className={`w-12 h-6 rounded-full border border-primary transition-all duration-300 ${
|
|
soundEnabled ? 'bg-primary' : 'bg-transparent'
|
|
}`}
|
|
>
|
|
<div
|
|
className={`w-4 h-4 rounded-full bg-background border border-primary transition-transform duration-300 ${
|
|
soundEnabled ? 'translate-x-6' : 'translate-x-1'
|
|
}`}
|
|
/>
|
|
</button>
|
|
</div>
|
|
|
|
{/* Crypto Consent */}
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center gap-2">
|
|
<Cpu size={16} className="text-primary" />
|
|
<span className="font-pixel text-sm text-foreground/90">CPU Mining</span>
|
|
</div>
|
|
<button
|
|
onClick={() => {
|
|
playSound('click');
|
|
setShowCryptoModal(true);
|
|
}}
|
|
className={`px-3 py-1 text-xs font-pixel border border-primary transition-all duration-300 ${
|
|
cryptoConsent
|
|
? 'bg-primary text-background'
|
|
: 'bg-transparent text-primary hover:bg-primary hover:text-background'
|
|
}`}
|
|
>
|
|
{cryptoConsent ? 'ON' : 'OFF'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-4 pt-4 border-t border-primary/30">
|
|
<p className="font-pixel text-xs text-muted-foreground">
|
|
Settings are saved locally
|
|
</p>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
|
|
<CryptoConsentModal isOpen={showCryptoModal} onClose={() => setShowCryptoModal(false)} />
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default SettingsPanel;
|