Add Zen Mode toggle

Implement Zen Mode that hides all UI except Matrix background and MusicPlayer, toggleable via Z key. Adds useZenMode hook, integrates into Index to render/hide UI accordingly, and enables Escape to exit.

X-Lovable-Edit-ID: edt-718e1520-c8f0-4fbc-b60d-412ed28dddb1
This commit is contained in:
gpt-engineer-app[bot]
2026-01-06 09:31:21 +00:00
2 changed files with 73 additions and 5 deletions
+33
View File
@@ -0,0 +1,33 @@
import { useState, useEffect, useCallback } from 'react';
export const useZenMode = () => {
const [isZenMode, setIsZenMode] = useState(false);
const toggleZenMode = useCallback(() => {
setIsZenMode(prev => !prev);
}, []);
const exitZenMode = useCallback(() => {
setIsZenMode(false);
}, []);
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
// Toggle with 'Z' key (not in input fields)
if (e.key.toLowerCase() === 'z' &&
!['INPUT', 'TEXTAREA'].includes((e.target as HTMLElement).tagName) &&
!e.ctrlKey && !e.metaKey && !e.altKey) {
toggleZenMode();
}
// Exit with Escape
if (e.key === 'Escape' && isZenMode) {
exitZenMode();
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [isZenMode, toggleZenMode, exitZenMode]);
return { isZenMode, toggleZenMode, exitZenMode };
};
+40 -5
View File
@@ -8,8 +8,10 @@ import { VERIFIED_KEY, BYPASS_KEY } from '@/components/HumanVerification';
import { useSettings } from '@/contexts/SettingsContext';
import { useAchievements } from '@/contexts/AchievementsContext';
import { useKonamiCode } from '@/hooks/useKonamiCode';
import { useZenMode } from '@/hooks/useZenMode';
import { toast } from '@/hooks/use-toast';
import { AudioBlockedOverlay } from '@/components/AudioBlockedOverlay';
import { motion, AnimatePresence } from 'framer-motion';
// Lazy load conditionally rendered components to reduce initial bundle
const HumanVerification = lazy(() => import('@/components/HumanVerification'));
@@ -47,6 +49,7 @@ const Index = () => {
} = useSettings();
const { unlockAchievement } = useAchievements();
const { activated: konamiActivated, reset: resetKonami } = useKonamiCode();
const { isZenMode, toggleZenMode } = useZenMode();
const location = useLocation();
// Hide mini music player when on the full music page (to avoid UI duplication)
@@ -153,15 +156,47 @@ const Index = () => {
{/* Moving scanline - only visible when CRT is enabled */}
<div className="moving-scanline" />
{/* Zen Mode indicator */}
<AnimatePresence>
{isZenMode && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 20 }}
transition={{ duration: 0.3 }}
className="fixed bottom-4 left-1/2 -translate-x-1/2 z-50 bg-background/80 border border-primary/50 px-4 py-2 rounded-lg backdrop-blur-sm"
>
<p className="text-primary text-sm font-minecraft">
ZEN MODE Press <kbd className="bg-primary/20 px-1.5 py-0.5 rounded mx-1">Z</kbd> or <kbd className="bg-primary/20 px-1.5 py-0.5 rounded mx-1">ESC</kbd> to exit
</p>
</motion.div>
)}
</AnimatePresence>
{!isLoading && (
<Suspense fallback={null}>
<CryptoConsentModal isOpen={showConsentModal} onClose={handleConsentClose} />
<SettingsPanel onToggleTheme={toggleTheme} isRedTheme={isRedTheme} />
<TerminalCommand />
<div className="relative z-10 flex flex-col items-center min-h-screen pb-16">
<MainLayout />
</div>
{/* Hide UI elements in Zen Mode */}
<AnimatePresence>
{!isZenMode && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.3 }}
>
<SettingsPanel onToggleTheme={toggleTheme} isRedTheme={isRedTheme} />
<TerminalCommand />
<div className="relative z-10 flex flex-col items-center min-h-screen pb-16">
<MainLayout />
</div>
</motion.div>
)}
</AnimatePresence>
{/* Music player stays visible in Zen Mode */}
{showMiniPlayer && <MusicPlayer />}
</Suspense>
)}