feat: Implement IP to color scheme mapping
closes #2 - updated page title - attatched modal to "YOU GET" pill
This commit is contained in:
53
src/App.tsx
53
src/App.tsx
@@ -10,16 +10,52 @@ 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] = useState(() => {
|
||||
const idx = Math.floor(Math.random() * THEMES.length);
|
||||
return THEMES[idx];
|
||||
});
|
||||
const [activeTheme, setActiveTheme] = useState(() => THEMES[0]);
|
||||
const [viewerIp, setViewerIp] = useState<string | null>(null);
|
||||
const [deterministicIndex, setDeterministicIndex] = useState<number | null>(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(() => {
|
||||
@@ -58,7 +94,6 @@ export default function App() {
|
||||
return () => window.removeEventListener('mousemove', handleMouseMove);
|
||||
}, []);
|
||||
|
||||
// Auto-hide the "HAHA Made you click" tooltip
|
||||
useEffect(() => {
|
||||
if (!showThemePillTooltip) return;
|
||||
const t = window.setTimeout(() => setShowThemePillTooltip(false), 1400);
|
||||
@@ -99,6 +134,7 @@ export default function App() {
|
||||
onThemePillClick={() => {
|
||||
setHasClickedThemePill(true);
|
||||
setShowThemePillTooltip(true);
|
||||
setShowThemeModal(true);
|
||||
}}
|
||||
cpuModeEnabled={cpuModeEnabled}
|
||||
/>
|
||||
@@ -117,6 +153,13 @@ export default function App() {
|
||||
</div>
|
||||
<FooterSection />
|
||||
</div>
|
||||
<ThemeMapperModal
|
||||
isOpen={showThemeModal}
|
||||
viewerIp={viewerIp}
|
||||
deterministicIndex={deterministicIndex}
|
||||
themeName={activeTheme.name}
|
||||
onClose={() => setShowThemeModal(false)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user