11import React , { useContext , useEffect , useState } from 'react' ;
2+ import { motion , useMotionValue , useSpring } from 'framer-motion' ;
23import { DndContext } from '../../context/DndContext' ;
34import DndNavbar from './DndNavbar' ;
45import DndFooter from './DndFooter' ;
56import dndWallpapers from '../../utils/dndWallpapers' ;
67import { parseWallpaperName } from '../../utils/dndUtils' ;
78import '../../styles/dnd-refactor.css' ;
9+ import { GameController } from '@phosphor-icons/react' ;
810
911const DustMotes = ( ) => (
1012 < div className = "fixed inset-0 pointer-events-none z-10 overflow-hidden" >
@@ -46,6 +48,95 @@ const FloatingRunes = () => {
4648 ) ;
4749} ;
4850
51+ const FireParticles = ( ) => {
52+ const colors = [
53+ 'radial-gradient(circle, #ff4500 0%, #ff8c00 70%, transparent 100%)' , // Red-Orange
54+ 'radial-gradient(circle, #ff8c00 0%, #ffd700 70%, transparent 100%)' , // Orange-Gold
55+ 'radial-gradient(circle, #ff0000 0%, #ff4500 70%, transparent 100%)' , // Pure Red
56+ ] ;
57+
58+ return (
59+ < div className = "fixed inset-0 pointer-events-none z-10 overflow-hidden" >
60+ { [ ...Array ( 50 ) ] . map ( ( _ , i ) => {
61+ const size = 3 + Math . random ( ) * 8 ;
62+ return (
63+ < div
64+ key = { i }
65+ className = "dnd-fire-particle"
66+ style = { {
67+ left : `${ Math . random ( ) * 100 } %` ,
68+ width : `${ size } px` ,
69+ height : `${ size } px` ,
70+ background : colors [ Math . floor ( Math . random ( ) * colors . length ) ] ,
71+ animationDuration : `${ 5 + Math . random ( ) * 10 } s` ,
72+ animationDelay : `${ - Math . random ( ) * 15 } s` ,
73+ boxShadow : `0 0 ${ size * 2 } px #ff4500` ,
74+ } }
75+ />
76+ ) ;
77+ } ) }
78+ </ div >
79+ ) ;
80+ } ;
81+ const Torchlight = ( ) => {
82+ const mouseX = useMotionValue ( 0 ) ;
83+ const mouseY = useMotionValue ( 0 ) ;
84+
85+ const springX = useSpring ( mouseX , { damping : 50 , stiffness : 200 } ) ;
86+ const springY = useSpring ( mouseY , { damping : 50 , stiffness : 200 } ) ;
87+
88+ useEffect ( ( ) => {
89+ const handleMouseMove = ( e ) => {
90+ mouseX . set ( e . clientX ) ;
91+ mouseY . set ( e . clientY ) ;
92+ } ;
93+ window . addEventListener ( 'mousemove' , handleMouseMove ) ;
94+ return ( ) => window . removeEventListener ( 'mousemove' , handleMouseMove ) ;
95+ } , [ mouseX , mouseY ] ) ;
96+
97+ return (
98+ < motion . div
99+ className = "fixed inset-0 pointer-events-none z-[100] hidden md:block"
100+ style = { {
101+ background : `radial-gradient(circle 400px at ${ springX } px ${ springY } px, rgba(255, 180, 50, 0.08), transparent 80%)` ,
102+ } }
103+ />
104+ ) ;
105+ } ;
106+
107+ const DiceRoller = ( ) => {
108+ const [ roll , setRoll ] = useState ( null ) ;
109+ const [ isRolling , setIsRolling ] = useState ( false ) ;
110+
111+ const rollDice = ( ) => {
112+ setIsRolling ( true ) ;
113+ setTimeout ( ( ) => {
114+ setRoll ( Math . floor ( Math . random ( ) * 20 ) + 1 ) ;
115+ setIsRolling ( false ) ;
116+ } , 600 ) ;
117+ } ;
118+
119+ return (
120+ < div className = "fixed bottom-8 right-8 z-[110] flex flex-col items-center gap-4" >
121+ { roll !== null && (
122+ < motion . div
123+ initial = { { opacity : 0 , scale : 0.5 , y : 20 } }
124+ animate = { { opacity : 1 , scale : 1 , y : 0 } }
125+ className = "bg-dnd-crimson border-2 border-dnd-gold text-white px-4 py-2 rounded-sm font-mono text-xs shadow-2xl"
126+ >
127+ { roll === 20 ? 'CRITICAL SUCCESS!' : roll === 1 ? 'CRITICAL FAILURE...' : `YOU ROLLED: ${ roll } ` }
128+ </ motion . div >
129+ ) }
130+ < button
131+ onClick = { rollDice }
132+ className = { `p-4 bg-dnd-crimson border-2 border-dnd-gold rounded-full text-dnd-gold shadow-2xl transition-all hover:scale-110 active:scale-95 ${ isRolling ? 'dnd-dice-action' : '' } ` }
133+ >
134+ < GameController size = { 32 } weight = "fill" />
135+ </ button >
136+ </ div >
137+ ) ;
138+ } ;
139+
49140const DndLayout = ( { children } ) => {
50141 const { setBgImageName } = useContext ( DndContext ) ;
51142 const [ bgImage , setBgImage ] = useState ( '' ) ;
@@ -58,6 +149,9 @@ const DndLayout = ({ children }) => {
58149
59150 return (
60151 < div className = "dnd-theme-root min-h-screen flex flex-col relative overflow-x-hidden" >
152+ < Torchlight />
153+ < DiceRoller />
154+ < FireParticles />
61155 < DustMotes />
62156 < FloatingRunes />
63157 { /* Immersive Background */ }
@@ -87,4 +181,4 @@ const DndLayout = ({ children }) => {
87181 ) ;
88182} ;
89183
90- export default DndLayout ;
184+ export default DndLayout ;
0 commit comments