|
| 1 | +import React, {useState} from 'react'; |
| 2 | +import {useNavigate} from 'react-router-dom'; |
| 3 | +import {motion} from 'framer-motion'; |
| 4 | +import { |
| 5 | + Monitor, |
| 6 | + CaretRight, |
| 7 | + Palette, |
| 8 | + GameController, |
| 9 | + Eyeglasses, |
| 10 | +} from '@phosphor-icons/react'; |
| 11 | +import {useVisualSettings} from '../context/VisualSettingsContext'; |
| 12 | +import {useAchievements} from '../context/AchievementContext'; |
| 13 | +import CustomToggle from '../components/CustomToggle'; |
| 14 | +import CustomDropdown from '../components/CustomDropdown'; |
| 15 | +import useSeo from '../hooks/useSeo'; |
| 16 | + |
| 17 | +const OptionCard = ({title, icon: Icon, children, colorClass, delay}) => ( |
| 18 | + <motion.div |
| 19 | + initial={{opacity: 0, y: 20}} |
| 20 | + animate={{opacity: 1, y: 0}} |
| 21 | + transition={{duration: 0.5, delay}} |
| 22 | + className="bg-gray-800/40 backdrop-blur-md border border-white/5 rounded-2xl p-6 hover:bg-gray-800/60 hover:border-white/10 transition-all duration-300 group flex flex-col justify-between" |
| 23 | + > |
| 24 | + <div className="flex items-start justify-between mb-4"> |
| 25 | + <div className={`p-3 rounded-xl ${colorClass} bg-opacity-20 text-white`}> |
| 26 | + <Icon size={28} weight="duotone"/> |
| 27 | + </div> |
| 28 | + <div className="text-right"> |
| 29 | + <h3 className="font-arvo text-lg text-white font-medium">{title}</h3> |
| 30 | + </div> |
| 31 | + </div> |
| 32 | + <div className="relative z-10">{children}</div> |
| 33 | + </motion.div> |
| 34 | +); |
| 35 | + |
| 36 | +const WelcomePage = () => { |
| 37 | + useSeo({ |
| 38 | + title: 'Initialize | Fezcodex', |
| 39 | + description: 'Setup your Fezcodex experience.', |
| 40 | + }); |
| 41 | + |
| 42 | + const navigate = useNavigate(); |
| 43 | + const [isLaunching, setIsLaunching] = useState(false); |
| 44 | + |
| 45 | + const { |
| 46 | + blogPostViewMode, |
| 47 | + setBlogPostViewMode, |
| 48 | + sidebarColor, |
| 49 | + setSidebarColor, |
| 50 | + isRetro, |
| 51 | + toggleRetro, |
| 52 | + } = useVisualSettings(); |
| 53 | + |
| 54 | + const {showAchievementToast, toggleAchievementToast} = useAchievements(); |
| 55 | + |
| 56 | + const handleFinish = () => { |
| 57 | + setIsLaunching(true); |
| 58 | + setTimeout(() => { |
| 59 | + navigate('/'); |
| 60 | + }, 800); |
| 61 | + }; |
| 62 | + |
| 63 | + return ( |
| 64 | + <div |
| 65 | + className="min-h-screen flex flex-col items-center justify-center p-4 sm:p-8 bg-[#0a0a0c] text-gray-100 relative overflow-hidden"> |
| 66 | + {/* Dynamic Background */} |
| 67 | + <div className="absolute inset-0 overflow-hidden pointer-events-none"> |
| 68 | + <div |
| 69 | + className="absolute top-[-20%] left-[-10%] w-[60%] h-[60%] bg-primary-900/10 rounded-full blur-[120px] animate-pulse"/> |
| 70 | + <div |
| 71 | + className="absolute bottom-[-20%] right-[-10%] w-[60%] h-[60%] bg-blue-900/10 rounded-full blur-[120px] animate-pulse" |
| 72 | + style={{animationDelay: '2s'}}/> |
| 73 | + <div |
| 74 | + className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-20 brightness-100 contrast-150 mix-blend-overlay"></div> |
| 75 | + </div> |
| 76 | + |
| 77 | + <div className="max-w-5xl w-full relative z-10"> |
| 78 | + {/* Header Section */} |
| 79 | + <motion.div |
| 80 | + initial={{opacity: 0, y: -20}} |
| 81 | + animate={{opacity: 1, y: 0}} |
| 82 | + className="text-center mb-16" |
| 83 | + > |
| 84 | + <motion.div |
| 85 | + className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/5 border border-white/10 text-xs font-mono text-gray-400 mb-6" |
| 86 | + > |
| 87 | + <span className="w-2 h-2 rounded-full bg-green-500 animate-pulse"/> |
| 88 | + SYSTEM INITIALIZATION |
| 89 | + </motion.div> |
| 90 | + |
| 91 | + <h1 |
| 92 | + className="text-5xl md:text-7xl font-bold bg-clip-text text-transparent bg-gradient-to-b from-white via-white to-gray-500 font-arvo mb-4 tracking-tight"> |
| 93 | + Hello, Traveler. |
| 94 | + </h1> |
| 95 | + <p className="text-xl text-gray-400 max-w-xl mx-auto"> |
| 96 | + Configure your terminal environment before accessing the mainframe. |
| 97 | + </p> |
| 98 | + </motion.div> |
| 99 | + |
| 100 | + {/* Cards Grid */} |
| 101 | + <div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-16"> |
| 102 | + |
| 103 | + {/* 1. Reading Experience */} |
| 104 | + <OptionCard |
| 105 | + title="Reading Mode" |
| 106 | + icon={Eyeglasses} |
| 107 | + colorClass="bg-blue-500" |
| 108 | + delay={0.1} |
| 109 | + > |
| 110 | + <p className="text-sm text-gray-400 mb-4 h-10"> |
| 111 | + Select how data logs and articles should be rendered on your display. |
| 112 | + </p> |
| 113 | + <CustomDropdown |
| 114 | + label="Select View" |
| 115 | + options={[ |
| 116 | + {label: 'Standard (Clean)', value: 'standard'}, |
| 117 | + {label: 'Dossier (Files)', value: 'dossier'}, |
| 118 | + {label: 'Terminal (Retro)', value: 'terminal'}, |
| 119 | + ]} |
| 120 | + value={blogPostViewMode} |
| 121 | + onChange={setBlogPostViewMode} |
| 122 | + className="w-full" |
| 123 | + /> |
| 124 | + </OptionCard> |
| 125 | + |
| 126 | + {/* 2. Gamification */} |
| 127 | + <OptionCard |
| 128 | + title="Gamification" |
| 129 | + icon={GameController} |
| 130 | + colorClass="bg-rose-500" |
| 131 | + delay={0.2} |
| 132 | + > |
| 133 | + <p className="text-sm text-gray-400 mb-4 h-10"> |
| 134 | + Enable achievement tracking and popup notifications during exploration. |
| 135 | + </p> |
| 136 | + <CustomToggle |
| 137 | + id="gamification-toggle" |
| 138 | + label={showAchievementToast ? "Achievements Active" : "Achievements Muted"} |
| 139 | + checked={showAchievementToast} |
| 140 | + onChange={toggleAchievementToast} |
| 141 | + colorTheme="rose" |
| 142 | + /> |
| 143 | + </OptionCard> |
| 144 | + |
| 145 | + {/* 3. Interface Color */} |
| 146 | + <OptionCard |
| 147 | + title="Sidebar Tint" |
| 148 | + icon={Palette} |
| 149 | + colorClass="bg-purple-500" |
| 150 | + delay={0.3} |
| 151 | + > |
| 152 | + <p className="text-sm text-gray-400 mb-4 h-10"> |
| 153 | + Customize the accent color of your primary navigation panel. |
| 154 | + </p> |
| 155 | + <CustomDropdown |
| 156 | + label="Select Color" |
| 157 | + options={[ |
| 158 | + {label: 'Default (Dark)', value: 'default'}, |
| 159 | + {label: 'Salmon', value: 'salmon-medium'}, |
| 160 | + {label: 'Cyber Blue', value: 'blue-transparent'}, |
| 161 | + {label: 'Matrix Green', value: 'green-transparent'}, |
| 162 | + {label: 'Neon Purple', value: 'purple-transparent'}, |
| 163 | + ]} |
| 164 | + value={sidebarColor} |
| 165 | + onChange={setSidebarColor} |
| 166 | + className="w-full" |
| 167 | + /> |
| 168 | + </OptionCard> |
| 169 | + |
| 170 | + {/* 4. Visual Processing */} |
| 171 | + <OptionCard |
| 172 | + title="Retro FX" |
| 173 | + icon={Monitor} |
| 174 | + colorClass="bg-emerald-500" |
| 175 | + delay={0.4} |
| 176 | + > |
| 177 | + <p className="text-sm text-gray-400 mb-4 h-10"> |
| 178 | + Engage cathode-ray tube emulation for maximum nostalgia. |
| 179 | + </p> |
| 180 | + <CustomToggle |
| 181 | + id="retro-toggle" |
| 182 | + label={isRetro ? "CRT Effects Online" : "CRT Effects Offline"} |
| 183 | + checked={isRetro} |
| 184 | + onChange={toggleRetro} |
| 185 | + colorTheme="green" |
| 186 | + /> |
| 187 | + </OptionCard> |
| 188 | + </div> |
| 189 | + |
| 190 | + {/* Action Area */} |
| 191 | + <motion.div |
| 192 | + initial={{opacity: 0, y: 20}} |
| 193 | + animate={{opacity: 1, y: 0}} |
| 194 | + transition={{delay: 0.5}} |
| 195 | + className="flex flex-col items-center" |
| 196 | + > |
| 197 | + <button |
| 198 | + onClick={handleFinish} |
| 199 | + className={` |
| 200 | + group relative flex items-center gap-3 px-8 py-4 |
| 201 | + bg-white text-black border-2 border-white |
| 202 | + font-mono font-bold text-sm tracking-widest uppercase |
| 203 | + transition-all duration-300 |
| 204 | + hover:bg-emerald-500 hover:border-emerald-500 hover:text-black |
| 205 | + hover:shadow-[0_0_20px_rgba(16,185,129,0.4)] |
| 206 | + ${isLaunching ? 'scale-95 opacity-80' : ''} |
| 207 | + `} |
| 208 | + > |
| 209 | + <span className="relative z-10">Launch Fezcodex</span> |
| 210 | + <CaretRight weight="bold" size={20} |
| 211 | + className="relative z-10 group-hover:translate-x-1 transition-transform"/> |
| 212 | + </button> |
| 213 | + |
| 214 | + <p className="text-xs text-gray-500 mt-6 font-mono"> |
| 215 | + * Additional configurations available in Settings |
| 216 | + </p> |
| 217 | + |
| 218 | + <button |
| 219 | + onClick={handleFinish} |
| 220 | + className="mt-4 text-xs text-gray-600 hover:text-gray-400 transition-colors font-mono uppercase tracking-wider" |
| 221 | + > |
| 222 | + Skip Configuration |
| 223 | + </button> |
| 224 | + </motion.div> |
| 225 | + </div> |
| 226 | + </div> |
| 227 | + ); |
| 228 | +}; |
| 229 | + |
| 230 | +export default WelcomePage; |
0 commit comments