11import { StrictMode , useState , useCallback , useEffect } from 'react'
22import { createRoot } from 'react-dom/client'
3- import { Theme , Flex , Text , Box , Heading } from '@radix-ui/themes'
3+ import { Theme , Flex , Text , Heading , IconButton } from '@radix-ui/themes'
4+ import { SunIcon , MoonIcon , DesktopIcon } from '@radix-ui/react-icons'
45import '@radix-ui/themes/styles.css'
56import { useChatroom } from './hooks/useChatroom.js'
67import { useEntityTypes } from './hooks/useEntityTypes.js'
8+ import {
9+ DarkModeProvider ,
10+ useDarkModeContext ,
11+ type ThemePreference ,
12+ } from './hooks/useDarkMode.js'
713import { RoomsSidebar } from './components/RoomsSidebar.js'
814import { ChatArea } from './components/ChatArea.js'
915import { MembersSidebar } from './components/MembersSidebar.js'
1016import './main.css'
1117
18+ function themeButtonIcon ( preference : ThemePreference ) {
19+ if ( preference === `light` ) return < SunIcon />
20+ if ( preference === `dark` ) return < MoonIcon />
21+ return < DesktopIcon />
22+ }
23+
24+ function themeButtonAriaLabel ( preference : ThemePreference ) : string {
25+ if ( preference === `light` ) return `Switch to dark mode`
26+ if ( preference === `dark` ) return `Switch to system theme`
27+ return `Switch to light mode`
28+ }
29+
1230interface Room {
1331 id : string
1432 name : string
@@ -21,6 +39,35 @@ function getRoomFromHash(): string | null {
2139 return hash || null
2240}
2341
42+ function ThemeToggle ( ) {
43+ const { preference, cyclePreference } = useDarkModeContext ( )
44+ return (
45+ < IconButton
46+ variant = "ghost"
47+ size = "2"
48+ color = "gray"
49+ onClick = { cyclePreference }
50+ aria-label = { themeButtonAriaLabel ( preference ) }
51+ >
52+ { themeButtonIcon ( preference ) }
53+ </ IconButton >
54+ )
55+ }
56+
57+ function ThemedApp ( ) {
58+ const { darkMode } = useDarkModeContext ( )
59+ return (
60+ < Theme
61+ accentColor = "indigo"
62+ grayColor = "mauve"
63+ radius = "medium"
64+ appearance = { darkMode ? `dark` : `light` }
65+ >
66+ < App />
67+ </ Theme >
68+ )
69+ }
70+
2471function App ( ) {
2572 const [ config , setConfig ] = useState < { agentsUrl : string } | null > ( null )
2673 const [ rooms , setRooms ] = useState < Room [ ] > ( [ ] )
@@ -137,7 +184,13 @@ function App() {
137184 creating = { creating }
138185 />
139186 < Flex direction = "column" flexGrow = "1" style = { { minWidth : 0 } } >
140- < Box px = "3" py = "3" className = "chat-header" >
187+ < Flex
188+ px = "3"
189+ py = "3"
190+ align = "center"
191+ justify = "between"
192+ className = "chat-header"
193+ >
141194 { activeRoom ? (
142195 < Heading size = "3" >
143196 < Text color = "gray" > # </ Text >
@@ -148,7 +201,8 @@ function App() {
148201 Chat
149202 </ Heading >
150203 ) }
151- </ Box >
204+ < ThemeToggle />
205+ </ Flex >
152206 < Flex flexGrow = "1" style = { { minHeight : 0 } } >
153207 < ChatArea
154208 messagesCollection = { messagesCollection }
@@ -173,8 +227,8 @@ function App() {
173227
174228createRoot ( document . getElementById ( `root` ) ! ) . render (
175229 < StrictMode >
176- < Theme accentColor = "indigo" grayColor = "mauve" radius = "medium" >
177- < App />
178- </ Theme >
230+ < DarkModeProvider >
231+ < ThemedApp />
232+ </ DarkModeProvider >
179233 </ StrictMode >
180234)
0 commit comments