annotate hg-web/src/components/theme.tsx @ 212:84826b3c655b

[MrJuneJune] Forgot to add assets.
author MrJuneJune <me@mrjunejune.com>
date Sun, 15 Feb 2026 21:38:36 -0800
parents 9f4429c49733
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
193
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
1 import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode } from 'react';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3 interface ThemeContextType {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
4 isDark: boolean;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
5 toggleTheme: () => void;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
6 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
7
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
8 const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
9
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
10 // Apply theme class to document root
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
11 function applyTheme(isDark: boolean) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
12 const root = document.documentElement;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
13 if (isDark) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
14 root.classList.add('dark');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
15 root.classList.remove('light');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
16 } else {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
17 root.classList.add('light');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
18 root.classList.remove('dark');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
19 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
20 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
21
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
22 interface ThemeProviderProps {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
23 children: ReactNode;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
24 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
25
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
26 function ThemeProvider({ children }: ThemeProviderProps) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
27 const [isDark, setIsDark] = useState(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
28 const saved = localStorage.getItem('theme');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
29 if (saved) return saved === 'dark';
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
30 return window.matchMedia('(prefers-color-scheme: dark)').matches;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
31 });
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
32
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
33 // Apply theme on mount and change
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
34 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
35 applyTheme(isDark);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
36 localStorage.setItem('theme', isDark ? 'dark' : 'light');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
37 }, [isDark]);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
38
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
39 // Listen for system theme changes
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
40 useEffect(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
41 const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
42 const handleChange = (e: MediaQueryListEvent) => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
43 // Only apply if no explicit preference is saved
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
44 if (!localStorage.getItem('theme')) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
45 setIsDark(e.matches);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
46 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
47 };
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
48
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
49 mediaQuery.addEventListener('change', handleChange);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
50 return () => mediaQuery.removeEventListener('change', handleChange);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
51 }, []);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
52
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
53 const toggleTheme = useCallback(() => {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
54 setIsDark(prev => !prev);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
55 }, []);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
56
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
57 return (
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
58 <ThemeContext.Provider value={{ isDark, toggleTheme }}>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
59 {children}
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
60 </ThemeContext.Provider>
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
61 );
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
62 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
63
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
64 function useTheme(): ThemeContextType {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
65 const context = useContext(ThemeContext);
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
66 if (context === undefined) {
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
67 throw new Error('useTheme must be used within a ThemeProvider');
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
68 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
69 return context;
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
70 }
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
71
9f4429c49733 [HgWeb] Making progress....
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
72 export { ThemeProvider, useTheme };