From e25e5df79737f0359ac1ed4dbdc573fdbabc117c Mon Sep 17 00:00:00 2001 From: Thomas Decaux Date: Mon, 7 Nov 2022 19:21:58 +0100 Subject: [PATCH] feat(ui): Add theme switcher #5 --- front/src/components/LayoutHeader.tsx | 68 +++++++++++- front/src/index.tsx | 137 ++++++++++++------------ front/src/providers/SiteMetaContext.tsx | 30 +++++- front/src/themes/Dark.tsx | 7 ++ front/src/themes/Light.tsx | 7 ++ 5 files changed, 177 insertions(+), 72 deletions(-) create mode 100644 front/src/themes/Dark.tsx create mode 100644 front/src/themes/Light.tsx diff --git a/front/src/components/LayoutHeader.tsx b/front/src/components/LayoutHeader.tsx index efe94bc..4afdf9f 100644 --- a/front/src/components/LayoutHeader.tsx +++ b/front/src/components/LayoutHeader.tsx @@ -1,4 +1,4 @@ -import { EuiAvatar, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiHeader, EuiHeaderLogo, EuiHeaderSection, EuiHeaderSectionItem, EuiHeaderSectionItemButton, EuiLink, EuiPopover, EuiSpacer, EuiText, useGeneratedHtmlId } from '@elastic/eui' +import { EuiAvatar, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiHeader, EuiHeaderLogo, EuiHeaderSection, EuiHeaderSectionItem, EuiHeaderSectionItemButton, EuiLink, EuiPopover, EuiSpacer, EuiSwitch, EuiSwitchEvent, EuiText, useGeneratedHtmlId } from '@elastic/eui' import { useNavigate } from 'react-router-dom' import { useSiteMetaContext } from 'providers/SiteMetaContext' import { useAuthContext } from 'providers/AuthContext' @@ -97,8 +97,7 @@ const HeaderAboutMenu: FC = () => { aria-label="Account menu" onClick={onMenuButtonClick} iconType='help' - > - + >About ) return ( @@ -133,6 +132,63 @@ const HeaderAboutMenu: FC = () => { ) } +interface SMProps { + theme: string + setTheme: (theme: string) => void +} + +interface SwitchEvent extends EuiSwitchEvent { + checked: boolean +} + +const HeaderSettingsMenu: FC = ({ theme, setTheme }) => { + const headerUserPopoverId = useGeneratedHtmlId({ + prefix: 'headerSettingsPopover' + }) + const [isOpen, setIsOpen] = useState(false) + + const onMenuButtonClick = (): void => { + setIsOpen(!isOpen) + } + + const closeMenu = (): void => { + setIsOpen(false) + } + + const button = ( + + Settings + + ) + + return ( + +
+ { setTheme(theme === 'dark' ? 'light' : 'dark') }} + checked={theme === 'dark'} + /> +
+
+ ) +} + const LayoutHeader: FC = () => { /** * Hooks @@ -162,6 +218,11 @@ const LayoutHeader: FC = () => { , []) + const settingsMenu = + return ( { + {settingsMenu} {aboutMenu} {userMenu} diff --git a/front/src/index.tsx b/front/src/index.tsx index 95078d4..8df8880 100644 --- a/front/src/index.tsx +++ b/front/src/index.tsx @@ -15,15 +15,12 @@ import { EuiPageTemplate, EuiProvider } from '@elastic/eui' -// import '@elastic/eui/dist/eui_theme_light.css'; -import '@elastic/eui/dist/eui_theme_dark.css' - import AnonymousLoginPage from 'views/Auth/AnonymousPage' import ProtectedRoute from 'components/ProtectedRoute' import BucketContextProvider from 'providers/BucketContext' import HomePage from 'views/Bucket/HomePage/HomePage' import DetailsPage from 'views/Bucket/DetailsPage/DetailsPage' -import { SiteMetaContextProvider } from 'providers/SiteMetaContext' +import { SiteContext, SiteMetaContextProvider } from 'providers/SiteMetaContext' import { AuthContext, AuthContextProvider } from 'providers/AuthContext' import BrowserPage from 'views/Bucket/BrowserPage/BrowserPage' import UploadPage from 'views/Bucket/UploadPage/UploadPage' @@ -34,88 +31,92 @@ import { NotificationToasts } from 'components/NotificationToasts' ReactDOM.render( - - - - - - - - - - - {({ apiAccessToken }) => ( - apiAccessToken !== '' - ? - : - )} - - )} - /> + + + {({ theme }) => ( + + + - - - - - - )} - > - } /> - } /> - - + - - - - - - )} - > + + + {({ apiAccessToken }) => ( + apiAccessToken !== '' + ? + : + )} + + )} + /> + + - - + + + )} + > + } /> + } /> + + - + + + + + )} - /> + > - }> } + element={( + + + + + + + + + )} /> - } /> - } /> - } /> - } /> + + }> + } + /> + } /> + } /> + } /> + } /> + - - } /> - + } /> + - - - - - + + + + + )} + + , document.getElementById('root') diff --git a/front/src/providers/SiteMetaContext.tsx b/front/src/providers/SiteMetaContext.tsx index 575807a..e46f5e5 100644 --- a/front/src/providers/SiteMetaContext.tsx +++ b/front/src/providers/SiteMetaContext.tsx @@ -1,4 +1,12 @@ import React, { FC } from 'react' +import store from 'store' + +const LightTheme = React.lazy(async () => await import('../themes/Light')) +const DarkTheme = React.lazy(async () => await import('../themes/Dark')) +const themes = ['light', 'dark'] + +const themeFromStore = store.get('theme') +const themeDefault = themes.includes(themeFromStore) ? themeFromStore : themes[0] interface BreadcrumbItem { text: string @@ -8,10 +16,12 @@ interface BreadcrumbItem { interface ISiteMetaState { title: string breadcrumbs: BreadcrumbItem[] + theme: string } interface ISiteMetaContext extends ISiteMetaState { setTitle: (title: string) => void + setTheme: (theme: string) => void setBreadcrumbs: (breadcrumbs: BreadcrumbItem[]) => void } @@ -21,7 +31,9 @@ interface ISiteMetaContext extends ISiteMetaState { export const SiteContext = React.createContext({ title: '', breadcrumbs: [], + theme: themeDefault, setTitle: (title: string) => {}, + setTheme: (theme: string) => {}, setBreadcrumbs: (breadcrumbs: BreadcrumbItem[]) => {} }) @@ -54,7 +66,8 @@ export const useSetSiteMetaTitle = (): (title: string) => void => { export const SiteMetaContextProvider: FC = ({ children }) => { const [state, setState] = React.useState({ title: 'GUI', - breadcrumbs: [] + breadcrumbs: [], + theme: themeDefault }) const actions = { @@ -73,11 +86,26 @@ export const SiteMetaContextProvider: FC = ({ children }) => { title }) } + }, + + setTheme: (theme: string) => { + if (theme !== state.theme) { + store.set('theme', theme) + + setState({ + ...state, + theme + }) + } } } return ( + }> + {(state.theme === 'light') && } + {(state.theme === 'dark') && } + {children} ) diff --git a/front/src/themes/Dark.tsx b/front/src/themes/Dark.tsx new file mode 100644 index 0000000..a032b95 --- /dev/null +++ b/front/src/themes/Dark.tsx @@ -0,0 +1,7 @@ +import React, { FC } from 'react' + +import '@elastic/eui/dist/eui_theme_dark.css' + +const Theme: FC = () => () + +export default Theme diff --git a/front/src/themes/Light.tsx b/front/src/themes/Light.tsx new file mode 100644 index 0000000..dd602d6 --- /dev/null +++ b/front/src/themes/Light.tsx @@ -0,0 +1,7 @@ +import React, { FC } from 'react' + +import '@elastic/eui/dist/eui_theme_light.css' + +const Theme: FC = () => () + +export default Theme