import { useState, useEffect } from 'react'; import './App.css'; import { THEMES } from './themes'; import { CatEasterEgg } from './components/CatEasterEgg'; import { FooterSection } from './components/FooterSection'; import { EducationSection } from './components/EducationSection'; import { HeroSection } from './components/HeroSection'; import { LabNotesSection } from './components/LabNotesSection'; import { NavigationBar } from './components/NavigationBar'; import { ProjectsSection } from './components/ProjectsSection'; import { ResumeSection } from './components/ResumeSection'; import { SystemOverviewSection } from './components/SystemOverviewSection'; import { deterministicIpValue } from './utils'; import { ThemeMapperModal } from './components/ThemeMapperModal'; export default function App() { const [activeTheme, setActiveTheme] = useState(() => THEMES[0]); const [viewerIp, setViewerIp] = useState(null); const [deterministicIndex, setDeterministicIndex] = useState(null); const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); const [hasClickedThemePill, setHasClickedThemePill] = useState(false); const [showThemePillTooltip, setShowThemePillTooltip] = useState(false); const [cpuModeEnabled, setCpuModeEnabled] = useState(false); const [showThemeModal, setShowThemeModal] = useState(false); useEffect(() => { const shouldRandomize = import.meta.env.DEV && import.meta.env.VITE_RANDOMIZE_THEME === 'true'; if (shouldRandomize) { const idx = Math.floor(Math.random() * THEMES.length); setActiveTheme(THEMES[idx]); return; } const setDeterministicTheme = async () => { try { const response = await fetch('https://api.ipify.org?format=json'); if (!response.ok) { throw new Error('Failed to fetch IP address'); } const data = await response.json(); const ip = typeof data.ip === 'string' ? data.ip : ''; const nextDeterministicIndex = deterministicIpValue(ip, THEMES.length); console.log('[theme] viewer ip', ip, 'deterministic index', nextDeterministicIndex); setViewerIp(ip); setDeterministicIndex(nextDeterministicIndex); const themeIndex = nextDeterministicIndex - 1; setActiveTheme(THEMES[Math.max(0, Math.min(themeIndex, THEMES.length - 1))]); } catch { const fallbackIndex = Math.floor(Math.random() * THEMES.length); setViewerIp(null); setDeterministicIndex(null); setActiveTheme(THEMES[fallbackIndex]); } }; void setDeterministicTheme(); }, []); // Update CSS variables for dynamic theming useEffect(() => { const root = document.documentElement; // Central palette root.style.setProperty('--color-accent', activeTheme.colors.accent); root.style.setProperty('--color-accent-muted', `${activeTheme.colors.accent}33`); root.style.setProperty('--bg-base', activeTheme.colors.bgBase); root.style.setProperty('--bg-surface', activeTheme.colors.bgSurface); root.style.setProperty('--bg-panel', activeTheme.colors.bgPanel); root.style.setProperty('--text-main', activeTheme.colors.textMain); root.style.setProperty('--text-muted', activeTheme.colors.textMuted); root.style.setProperty('--text-dim', activeTheme.colors.textDim); root.style.setProperty('--border-main', activeTheme.colors.borderMain); root.style.setProperty('--grid-pattern', activeTheme.colors.gridPattern); root.style.setProperty('--status-success', activeTheme.colors.statusSuccess); // Cat root.style.setProperty('--cat-body', activeTheme.colors.bgBase); root.style.setProperty('--cat-stroke', activeTheme.colors.catStroke); root.style.setProperty('--cat-nose', activeTheme.colors.catNose); root.style.setProperty('--cat-eyes', activeTheme.colors.catEyes); root.style.setProperty('--heart-color', activeTheme.colors.heartColor); }, [activeTheme]); // Subtle interactive background effect useEffect(() => { const handleMouseMove = (e: MouseEvent) => { setMousePos({ x: e.clientX, y: e.clientY }); }; window.addEventListener('mousemove', handleMouseMove); return () => window.removeEventListener('mousemove', handleMouseMove); }, []); useEffect(() => { if (!showThemePillTooltip) return; const t = window.setTimeout(() => setShowThemePillTooltip(false), 1400); return () => window.clearTimeout(t); }, [showThemePillTooltip]); return (
{/* */}
{/* Blueprint Dot Grid Background */}
{/* Subtle mouse glow */}
setCpuModeEnabled(prev => !prev)} /> { setHasClickedThemePill(true); setShowThemePillTooltip(true); setShowThemeModal(true); }} cpuModeEnabled={cpuModeEnabled} />
setShowThemeModal(false)} />
); }