feat: Implement IP to color scheme mapping

closes #2
- updated page title
- attatched modal to "YOU GET" pill
This commit is contained in:
2026-02-23 13:23:59 +05:30
parent 804fde0051
commit cfee953dee
8 changed files with 272 additions and 49 deletions

View File

@@ -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>
);
}