11import * as React from 'react' ;
2- import { App as AntdApp , ConfigProvider , Spin } from 'antd' ;
2+ import { App as AntdApp , ConfigProvider , Spin , theme } from 'antd' ;
33import { Router , Switch , Route } from 'react-router-dom' ;
44
55import { getApplicationConfig } from './actions/ConfigActions' ;
@@ -15,6 +15,7 @@ import SavedQueries from './components/saved_queries/SavedQueries';
1515import SavedQueryBar from './components/saved_queries/SavedQueryBar' ;
1616import usePromiseResult from './hooks/usePromiseResult' ;
1717import useApplicationConfigStore from './stores/ApplicationConfigStore' ;
18+ import useThemeStore from './stores/ThemeStore' ;
1819import { history } from './stores/QueryStore' ;
1920import { renderFromPromiseResult } from './utils/PromiseResultUtils' ;
2021
@@ -26,71 +27,97 @@ import { BulkActionPage } from './components/bulk_actions/BulkActionPage';
2627
2728const AppRouter : React . FC = ( ) => {
2829 const updateApplicationConfig = useApplicationConfigStore ( ( state ) => state . updateApplicationConfig ) ;
30+ const themeMode = useThemeStore ( ( state ) => {
31+ return state . mode ;
32+ } ) ;
2933
3034 const applicationConfigResult = usePromiseResult ( async ( ) => {
3135 const appConfig = await getApplicationConfig ( ) ;
3236 updateApplicationConfig ( appConfig ) ;
3337 } ) ;
3438
35- const theme = React . useMemo ( ( ) => {
39+ const isDark = themeMode === 'dark' ;
40+ // Mirror of CSS tokens in Colors.module.css. Antd's algorithm needs concrete
41+ // color strings at render time to compute its derivatives, so we can't pass
42+ // var(--*) directly. Keep these literals in sync with their tokens:
43+ // colorPrimary ↔ --brand-primary
44+ // Menu.itemSelectedColor ↔ --text-dark-primary
45+ const themeConfig = React . useMemo ( ( ) => {
3646 return {
37- token : {
38- colorPrimary :
39- getComputedStyle ( document . documentElement ) . getPropertyValue ( '--brand-primary' ) . trim ( ) || '#1227ce' ,
47+ token : { colorPrimary : isDark ? '#4858e0' : '#1227ce' } ,
48+ algorithm : isDark ? theme . darkAlgorithm : theme . defaultAlgorithm ,
49+ components : {
50+ Menu : {
51+ collapsedWidth : 56 ,
52+ ...( isDark ? { itemSelectedColor : '#ebebeb' } : { } ) ,
53+ } ,
4054 } ,
41- components : { Menu : { collapsedWidth : 56 } } ,
4255 } ;
43- } , [ ] ) ;
56+ } , [ isDark ] ) ;
4457
45- return renderFromPromiseResult ( applicationConfigResult , ( ) => (
46- < ConfigProvider theme = { theme } >
47- < AntdApp >
48- < Router history = { history } >
49- < Switch >
50- < Route path = "/events/:eventId" >
51- < EventPage />
52- </ Route >
53- < Route >
54- < NavBar >
55- < Route exact path = { [ Routes . SAVED_QUERY , Routes . SAVED_QUERY_LATEST ] } >
56- < SavedQueryBar />
57- </ Route >
58- < Route exact path = { Routes . ENTITY } >
59- < EntityViewBar />
60- </ Route >
61- < Switch >
62- < Route path = { Routes . QUERY_HISTORY } >
63- < QueryHistory />
64- </ Route >
65- < Route path = { Routes . SAVED_QUERIES } >
66- < SavedQueries />
67- </ Route >
68- < Route path = { Routes . DOCS_UDFS } >
69- < UdfDocsView />
70- </ Route >
71- < Route path = { Routes . BULK_JOB_HISTORY } >
72- < BulkJobHistoryView />
73- </ Route >
74- < Route path = { Routes . RULES_VISUALIZER } >
75- < RulesVisualizerView />
76- </ Route >
77- < Route exact path = { [ Routes . ENTITY , Routes . HOME , Routes . SAVED_QUERY ] } >
78- < QueryView />
58+ React . useLayoutEffect ( ( ) => {
59+ // Cold-start theme is set by the inline script in public/index.html so the
60+ // first paint matches the stored preference. This effect keeps the class in
61+ // sync when the user toggles themes.
62+ const root = document . documentElement ;
63+ if ( isDark ) {
64+ root . classList . add ( 'dark-theme' ) ;
65+ } else {
66+ root . classList . remove ( 'dark-theme' ) ;
67+ }
68+ } , [ isDark ] ) ;
69+
70+ return (
71+ < ConfigProvider theme = { themeConfig } >
72+ { renderFromPromiseResult ( applicationConfigResult , ( ) => (
73+ < AntdApp >
74+ < Router history = { history } >
75+ < Switch >
76+ < Route path = "/events/:eventId" >
77+ < EventPage />
78+ </ Route >
79+ < Route >
80+ < NavBar >
81+ < Route exact path = { [ Routes . SAVED_QUERY , Routes . SAVED_QUERY_LATEST ] } >
82+ < SavedQueryBar />
7983 </ Route >
80- < Route exact path = { Routes . SAVED_QUERY_LATEST } >
81- < div className = { styles . spinner } >
82- < Spin size = "large" />
83- </ div >
84+ < Route exact path = { Routes . ENTITY } >
85+ < EntityViewBar />
8486 </ Route >
85- < Route exact path = { Routes . BULK_ACTION } component = { BulkActionPage } />
86- </ Switch >
87- </ NavBar >
88- </ Route >
89- </ Switch >
90- </ Router >
91- </ AntdApp >
87+ < Switch >
88+ < Route path = { Routes . QUERY_HISTORY } >
89+ < QueryHistory />
90+ </ Route >
91+ < Route path = { Routes . SAVED_QUERIES } >
92+ < SavedQueries />
93+ </ Route >
94+ < Route path = { Routes . DOCS_UDFS } >
95+ < UdfDocsView />
96+ </ Route >
97+ < Route path = { Routes . BULK_JOB_HISTORY } >
98+ < BulkJobHistoryView />
99+ </ Route >
100+ < Route path = { Routes . RULES_VISUALIZER } >
101+ < RulesVisualizerView />
102+ </ Route >
103+ < Route exact path = { [ Routes . ENTITY , Routes . HOME , Routes . SAVED_QUERY ] } >
104+ < QueryView />
105+ </ Route >
106+ < Route exact path = { Routes . SAVED_QUERY_LATEST } >
107+ < div className = { styles . spinner } >
108+ < Spin size = "large" />
109+ </ div >
110+ </ Route >
111+ < Route exact path = { Routes . BULK_ACTION } component = { BulkActionPage } />
112+ </ Switch >
113+ </ NavBar >
114+ </ Route >
115+ </ Switch >
116+ </ Router >
117+ </ AntdApp >
118+ ) ) }
92119 </ ConfigProvider >
93- ) ) ;
120+ ) ;
94121} ;
95122
96123export default AppRouter ;
0 commit comments