@@ -13,7 +13,7 @@ import { ThemeModeProvider, useThemeMode } from '../hooks/useThemeMode';
1313import indexCss from '../index.css?raw' ;
1414import { StyleProvider , createCache } from '@ant-design/cssinjs' ;
1515import { QueryClient , QueryClientProvider } from '@tanstack/react-query' ;
16- import { useUpdateEffect } from 'ahooks' ;
16+ import { useSessionStorageState , useUpdateEffect } from 'ahooks' ;
1717import { App , AppProps , theme , Typography } from 'antd' ;
1818import { BAIConfigProvider } from 'backend.ai-ui' ;
1919import dayjs from 'dayjs' ;
@@ -47,17 +47,20 @@ import weekday from 'dayjs/plugin/weekday';
4747import i18n from 'i18next' ;
4848import Backend from 'i18next-http-backend' ;
4949import { createStore , Provider as JotaiProvider } from 'jotai' ;
50+ import _ from 'lodash' ;
5051import { GlobeIcon } from 'lucide-react' ;
5152import React , {
5253 Suspense ,
5354 useEffect ,
55+ useEffectEvent ,
5456 useLayoutEffect ,
5557 useMemo ,
5658 useState ,
5759} from 'react' ;
5860import { useTranslation , initReactI18next } from 'react-i18next' ;
5961import { RelayEnvironmentProvider } from 'react-relay/hooks' ;
6062import { BrowserRouter , useLocation , useNavigate } from 'react-router-dom' ;
63+ import { useBAISettingUserState } from 'src/hooks/useBAISetting' ;
6164import { QueryParamProvider } from 'use-query-params' ;
6265import { ReactRouter6Adapter } from 'use-query-params/adapters/react-router-6' ;
6366
@@ -205,7 +208,34 @@ const DefaultProvidersForWebComponent: React.FC<DefaultProvidersProps> = ({
205208} ) => {
206209 const cache = useMemo ( ( ) => createCache ( ) , [ ] ) ;
207210 const [ lang ] = useCurrentLanguage ( ) ;
211+
212+ const [ userCustomThemeConfig ] = useBAISettingUserState ( 'custom_theme_config' ) ;
213+ const [ isThemePreviewMode ] = useSessionStorageState ( 'isThemePreviewMode' , {
214+ defaultValue : false ,
215+ } ) ;
208216 const themeConfig = useCustomThemeConfig ( ) ;
217+ const defaultThemeConfig =
218+ isThemePreviewMode && ! _ . isEmpty ( userCustomThemeConfig )
219+ ? userCustomThemeConfig
220+ : themeConfig ;
221+
222+ const reloadPreviewWindow = useEffectEvent ( ( ) => {
223+ if ( ! isThemePreviewMode ) return ;
224+
225+ const handleLocalStorageChange = ( e : StorageEvent ) => {
226+ if ( e . key === 'backendaiwebui.settings.user.custom_theme_config' ) {
227+ window . location . reload ( ) ;
228+ }
229+ } ;
230+ window . addEventListener ( 'storage' , handleLocalStorageChange ) ;
231+ return ( ) =>
232+ window . removeEventListener ( 'storage' , handleLocalStorageChange ) ;
233+ } ) ;
234+
235+ useEffect ( ( ) => {
236+ reloadPreviewWindow ( ) ;
237+ } , [ ] ) ;
238+
209239 const { isDarkMode } = useThemeMode ( ) ;
210240
211241 const componentValues = useMemo ( ( ) => {
@@ -249,8 +279,8 @@ const DefaultProvidersForWebComponent: React.FC<DefaultProvidersProps> = ({
249279 } }
250280 theme = { {
251281 ...( isDarkMode
252- ? { ...themeConfig ?. dark }
253- : { ...themeConfig ?. light } ) ,
282+ ? { ...defaultThemeConfig ?. dark }
283+ : { ...defaultThemeConfig ?. light } ) ,
254284 algorithm : isDarkMode
255285 ? theme . darkAlgorithm
256286 : theme . defaultAlgorithm ,
@@ -325,9 +355,35 @@ export const DefaultProvidersForReactRoot: React.FC<
325355 Partial < DefaultProvidersProps >
326356> = ( { children } ) => {
327357 const [ lang ] = useCurrentLanguage ( ) ;
328- const themeConfig = useCustomThemeConfig ( ) ;
329358 const { isDarkMode } = useThemeMode ( ) ;
330359
360+ const [ userCustomThemeConfig ] = useBAISettingUserState ( 'custom_theme_config' ) ;
361+ const [ isThemePreviewMode ] = useSessionStorageState ( 'isThemePreviewMode' , {
362+ defaultValue : false ,
363+ } ) ;
364+ const themeConfig = useCustomThemeConfig ( ) ;
365+ const defaultThemeConfig =
366+ isThemePreviewMode && ! _ . isEmpty ( userCustomThemeConfig )
367+ ? userCustomThemeConfig
368+ : themeConfig ;
369+
370+ const reloadPreviewWindow = useEffectEvent ( ( ) => {
371+ if ( ! isThemePreviewMode ) return ;
372+
373+ const handleLocalStorageChange = ( e : StorageEvent ) => {
374+ if ( e . key === 'backendaiwebui.settings.user.custom_theme_config' ) {
375+ window . location . reload ( ) ;
376+ }
377+ } ;
378+ window . addEventListener ( 'storage' , handleLocalStorageChange ) ;
379+ return ( ) =>
380+ window . removeEventListener ( 'storage' , handleLocalStorageChange ) ;
381+ } ) ;
382+
383+ useEffect ( ( ) => {
384+ reloadPreviewWindow ( ) ;
385+ } , [ ] ) ;
386+
331387 return (
332388 < >
333389 < style > { indexCss } </ style >
@@ -341,8 +397,8 @@ export const DefaultProvidersForReactRoot: React.FC<
341397 }
342398 theme = { {
343399 ...( isDarkMode
344- ? { ...themeConfig ?. dark }
345- : { ...themeConfig ?. light } ) ,
400+ ? { ...defaultThemeConfig ?. dark }
401+ : { ...defaultThemeConfig ?. light } ) ,
346402 algorithm : isDarkMode
347403 ? theme . darkAlgorithm
348404 : theme . defaultAlgorithm ,
0 commit comments