Skip to content

Commit 3e5ef4c

Browse files
committed
feat: add dark mode with Win98 aesthetic
1 parent ff4bcc8 commit 3e5ef4c

3 files changed

Lines changed: 105 additions & 0 deletions

File tree

src/context/ThemeContext.jsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { createContext, useState, useEffect } from 'react';
2+
3+
export const ThemeContext = createContext();
4+
5+
export const ThemeProvider = ({ children }) => {
6+
const [isDark, setIsDark] = useState(() => {
7+
const saved = localStorage.getItem('theme');
8+
return saved === 'dark';
9+
});
10+
11+
useEffect(() => {
12+
localStorage.setItem('theme', isDark ? 'dark' : 'light');
13+
14+
if (isDark) {
15+
document.documentElement.classList.add('dark');
16+
document.body.classList.add('dark');
17+
} else {
18+
document.documentElement.classList.remove('dark');
19+
document.body.classList.remove('dark');
20+
}
21+
}, [isDark]);
22+
23+
const toggleTheme = () => setIsDark(prev => !prev);
24+
25+
return (
26+
<ThemeContext.Provider value={{ isDark, toggleTheme }}>
27+
{children}
28+
</ThemeContext.Provider>
29+
);
30+
};

src/hooks/useTheme.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { useContext } from 'react';
2+
import { ThemeContext } from '../context/ThemeContext';
3+
4+
export const useTheme = () => {
5+
const context = useContext(ThemeContext);
6+
if (!context) {
7+
throw new Error('useTheme must be used within a ThemeProvider');
8+
}
9+
return context;
10+
};

src/index.css

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,3 +608,68 @@ input:focus-visible {
608608
.skip-link:focus {
609609
top: 0;
610610
}
611+
612+
/* ================================================== */
613+
/* DARK MODE - WIN95 AESTHETIC */
614+
/* ================================================== */
615+
616+
.dark {
617+
/* Dark Win95 Flat Color Palette */
618+
--win95-white: #1a1a1a;
619+
--win95-light-gray: #2d2d2d;
620+
--win95-medium-gray: #3d3d3d;
621+
--win95-dark-gray: #a0a0a0;
622+
--win95-black: #e0e0e0;
623+
624+
/* Accent Colors - Adjusted for dark mode contrast */
625+
--win95-blue: #4040c0;
626+
--win95-green: #00cc00;
627+
--win95-red: #ff4444;
628+
--win95-yellow: #ffdd00;
629+
630+
/* Legacy XP/Win98 variables - dark mode */
631+
--xp-window-bg: #2d2d2d;
632+
--xp-text-black: #e0e0e0;
633+
--xp-text-white: #1a1a1a;
634+
--win98-gray-light: #2d2d2d;
635+
--win98-gray-medium: #505050;
636+
--win98-gray-dark: #a0a0a0;
637+
--win98-blue-dark: #4040c0;
638+
--win98-black: #e0e0e0;
639+
--win98-white: #1a1a1a;
640+
}
641+
642+
/* Dark mode body background */
643+
.dark body,
644+
body.dark {
645+
background-color: #1a1a1a;
646+
}
647+
648+
/* Dark mode scrollbar */
649+
.dark ::-webkit-scrollbar-track {
650+
background-color: #2d2d2d;
651+
border-color: #505050;
652+
}
653+
654+
.dark ::-webkit-scrollbar-thumb {
655+
background-color: #505050;
656+
border-color: #606060;
657+
}
658+
659+
.dark ::-webkit-scrollbar-thumb:hover {
660+
background-color: #606060;
661+
}
662+
663+
.dark ::-webkit-scrollbar-button {
664+
background-color: #3d3d3d;
665+
border-color: #505050;
666+
}
667+
668+
/* Dark mode scrollbar arrows */
669+
.dark ::-webkit-scrollbar-button:vertical:decrement {
670+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath d='M4 2L1 6h6z' fill='%23e0e0e0'/%3E%3C/svg%3E");
671+
}
672+
673+
.dark ::-webkit-scrollbar-button:vertical:increment {
674+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath d='M4 6L1 2h6z' fill='%23e0e0e0'/%3E%3C/svg%3E");
675+
}

0 commit comments

Comments
 (0)