Skip to content

Commit 45d0bd7

Browse files
authored
Merge pull request #49 from wlee261/feat/light-and-dark-theme-setup
feat: theme setup
2 parents 5f904a3 + e4e6c3d commit 45d0bd7

File tree

6 files changed

+171
-11
lines changed

6 files changed

+171
-11
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { useAppTheme } from "../../context/AppThemeContext";
2+
3+
const AppThemeToggle = () => {
4+
// context for handling app theme
5+
const { appTheme, toggleAppTheme } = useAppTheme()
6+
7+
const handleClick = () => {
8+
toggleAppTheme()
9+
}
10+
11+
console.log(appTheme)
12+
13+
return <div>
14+
<button onClick={handleClick}>{appTheme}</button>
15+
</div>
16+
}
17+
18+
export default AppThemeToggle;

src/components/NavigationBar/NavigationBar.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { handleLogin } from '../../services/authService';
55
import { useAuth } from '../../context/AuthContext';
66
import { SiteConfig } from '../../constants/SiteConfig';
77
import logo from '../../assets/images/logo.png';
8+
import AppThemeToggle from './AppThemeToggle';
89

910
/**
1011
* Navigation bar for users to navigate between pages.
@@ -217,6 +218,7 @@ const NavigationBar = () => {
217218
setUserData(null)
218219
navigate('/')
219220
}}
221+
className="mr-8"
220222
>
221223
Logout
222224
</button>
@@ -227,12 +229,15 @@ const NavigationBar = () => {
227229
<button
228230
type="button"
229231
onClick={() => handleLogin()}
230-
className="hover:text-blue-500"
232+
className="hover:text-blue-500 mr-8"
231233
>
232234
Login
233235
</button>
234236
</li>
235237
)}
238+
<li>
239+
<AppThemeToggle />
240+
</li>
236241
</ul>
237242
</nav>
238243
)

src/context/AppThemeContext.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React, {
2+
createContext,
3+
useContext,
4+
useState,
5+
ReactNode,
6+
useEffect
7+
} from 'react'
8+
9+
type AppThemeType = 'light' | 'dark'
10+
11+
type AppThemeContextType = {
12+
appTheme: 'light' | 'dark'
13+
toggleAppTheme: () => void
14+
}
15+
16+
const AppThemeContext = createContext<AppThemeContextType>({
17+
appTheme: 'dark',
18+
// eslint-disable-next-line @typescript-eslint/no-empty-function
19+
toggleAppTheme: () => {}
20+
})
21+
22+
type AppThemeProviderProps = {
23+
children: ReactNode
24+
}
25+
26+
const AppThemeProvider: React.FC<AppThemeProviderProps> = ({ children }) => {
27+
const [appTheme, setAppTheme] = useState<AppThemeType>(
28+
() => window.matchMedia("(prefers-color-theme: dark)").matches ? 'dark' : 'light'
29+
)
30+
31+
useEffect(() => {
32+
document.documentElement.setAttribute('app-theme', appTheme)
33+
},[])
34+
35+
const toggleAppTheme = () => {
36+
setAppTheme((prevAppTheme) => {
37+
const isDarkTheme = prevAppTheme === 'dark'
38+
document.documentElement.setAttribute('app-theme', isDarkTheme ? 'light' : 'dark')
39+
return isDarkTheme ? 'light' : 'dark'
40+
})
41+
}
42+
43+
return (
44+
<AppThemeContext.Provider
45+
value={{ appTheme, toggleAppTheme }}
46+
>
47+
{children}
48+
</AppThemeContext.Provider>
49+
)
50+
}
51+
52+
const useAppTheme = (): AppThemeContextType => {
53+
const context = useContext(AppThemeContext)
54+
if (!context) {
55+
throw new Error('useTheme must be used within an AppThemeProvider')
56+
}
57+
return context
58+
}
59+
60+
export {
61+
AppThemeProvider,
62+
useAppTheme
63+
}

src/index.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import ThemeBuilderPage from './pages/ThemeBuilder';
1111
import UserProfilePage from './pages/UserProfile'
1212
import NavigationBar from './components/NavigationBar/NavigationBar'
1313
import { AuthProvider } from './context/AuthContext'
14+
import { AppThemeProvider } from './context/AppThemeContext';
1415
import ProtectedRoute from './routes/ProtectedRoute'
1516
import LoginProcessPage from './pages/LoginProcess'
1617

@@ -67,7 +68,9 @@ const router = createBrowserRouter(routes)
6768
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
6869
<React.StrictMode>
6970
<AuthProvider>
70-
<RouterProvider router={router} />
71+
<AppThemeProvider>
72+
<RouterProvider router={router} />
73+
</AppThemeProvider>
7174
</AuthProvider>
7275
</React.StrictMode>
7376
)

src/styles/index.css

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,50 @@
22
@tailwind components;
33
@tailwind utilities;
44

5+
56
:root {
6-
--main-color: #201E50;
7-
--smooth-shadow:
8-
0px 1.1px 2.2px rgba(0, 0, 0, 0.02),
9-
0px 2.5px 5.3px rgba(0, 0, 0, 0.028),
10-
0px 4.8px 10px rgba(0, 0, 0, 0.035),
11-
0px 8.5px 17.9px rgba(0, 0, 0, 0.042),
12-
0px 15.9px 33.4px rgba(0, 0, 0, 0.05),
13-
0px 38px 80px rgba(0, 0, 0, 0.07);
7+
--main-color: #201E50;
8+
--smooth-shadow:
9+
0px 1.1px 2.2px rgba(0, 0, 0, 0.02),
10+
0px 2.5px 5.3px rgba(0, 0, 0, 0.028),
11+
0px 4.8px 10px rgba(0, 0, 0, 0.035),
12+
0px 8.5px 17.9px rgba(0, 0, 0, 0.042),
13+
0px 15.9px 33.4px rgba(0, 0, 0, 0.05),
14+
0px 38px 80px rgba(0, 0, 0, 0.07);
15+
}
16+
17+
:root[app-theme="light"] {
18+
/* Light Theme Accent Palette */
19+
--accent-50: #020617;
20+
--accent-100: #0F172A;
21+
--accent-200: #1E293B;
22+
--accent-300: #334155;
23+
--accent-400: #475569;
24+
--accent-500: #64748B;
25+
--accent-600: #94A3B8;
26+
--accent-700: #CBD5E1;
27+
--accent-800: #E2E8F0;
28+
--accent-900: #F1F5F9;
29+
--accent-950: #F8FAFC;
1430
}
1531

32+
:root[app-theme="dark"] {
33+
/* Dark Theme Accent Palette */
34+
--accent-50: #F8FAFC;
35+
--accent-100: #F1F5F9;
36+
--accent-200: #E2E8F0;
37+
--accent-300: #C8D5E1;
38+
--accent-400: #94A3B8;
39+
--accent-500: #64748B;
40+
--accent-600: #475569;
41+
--accent-700: #334155;
42+
--accent-800: #1E293B;
43+
--accent-900: #0F172A;
44+
--accent-950: #020617;
45+
}
46+
47+
48+
1649
body {
1750
margin: 0;
1851
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',

tailwind.config.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,45 @@ export default {
77
center: true,
88
},
99
extend: {
10+
colors: {
11+
primary: {
12+
50: '#E6F8FA',
13+
100: '#C2EDF2',
14+
200: '#9CE1EA',
15+
300: '#75D5E1',
16+
400: '#58C9D8',
17+
500: '#42B0C5',
18+
600: '#3593A1',
19+
700: '#29757C',
20+
800: '#1E5757',
21+
900: '#143838',
22+
},
23+
secondary: {
24+
50: '#F5F3FF',
25+
100: '#EDE9FE',
26+
200: '#DDD6FE',
27+
300: '#C4B5FD',
28+
400: '#A78BFA',
29+
500: '#8B5CF6',
30+
600: '#7C3AED',
31+
700: '#6D28D9',
32+
800: '#5B21B6',
33+
900: '#4C1D95',
34+
950: '#2E1065',
35+
},
36+
accent: {
37+
50: 'var(--accent-50)',
38+
100: 'var(--accent-100)',
39+
200: 'var(--accent-200)',
40+
300: 'var(--accent-300)',
41+
400: 'var(--accent-400)',
42+
500: 'var(--accent-500)',
43+
600: 'var(--accent-600)',
44+
700: 'var(--accent-700)',
45+
800: 'var(--accent-800)',
46+
900: 'var(--accent-900)',
47+
},
48+
},
1049
keyframes: {
1150
wiggle: {
1251
'0%, 100%': { transform: 'rotate(-3deg)' },
@@ -22,7 +61,6 @@ export default {
2261
wiggle: 'wiggle 1s ease-in-out infinite',
2362
pulse: 'pulse 5s cubic-bezier(0.4, 0, 0.6, 1) infinite',
2463
}
25-
// colors: {},
2664
},
2765
},
2866
plugins: [],

0 commit comments

Comments
 (0)