From 975214e4fd6d8f79941c5806ebc5707026e9c48f Mon Sep 17 00:00:00 2001 From: Yannick Khalfouni Date: Fri, 20 Mar 2026 15:25:55 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20feat(style):=20setup=20MUI=20the?= =?UTF-8?q?me?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/app/index.html | 4 +-- web/app/src/App.tsx | 23 +++----------- .../{app.tsx => AppLayout/component.tsx} | 8 +++-- web/app/src/layouts/AppLayout/styles.tsx | 14 +++++++++ .../{base.tsx => BaseLayout/component.tsx} | 6 ++-- web/app/src/layouts/BaseLayout/styles.tsx | 8 +++++ web/app/src/router/index.tsx | 6 ++-- web/app/src/theme/ThemeRegistry.tsx | 29 +++++++++++++++++ web/app/src/theme/emotionCache.ts | 5 +++ web/app/src/theme/globalStyles.ts | 26 ++++++++++++++++ web/app/src/theme/index.ts | 3 ++ web/app/src/theme/theme.ts | 31 +++++++++++++++++++ web/app/src/theme/tokens/breakpoints.ts | 19 ++++++++++++ web/app/src/theme/tokens/colors.ts | 11 +++++++ web/app/src/theme/tokens/index.ts | 15 +++++++++ 15 files changed, 180 insertions(+), 28 deletions(-) rename web/app/src/layouts/{app.tsx => AppLayout/component.tsx} (87%) create mode 100644 web/app/src/layouts/AppLayout/styles.tsx rename web/app/src/layouts/{base.tsx => BaseLayout/component.tsx} (87%) create mode 100644 web/app/src/layouts/BaseLayout/styles.tsx create mode 100644 web/app/src/theme/ThemeRegistry.tsx create mode 100644 web/app/src/theme/emotionCache.ts create mode 100644 web/app/src/theme/globalStyles.ts create mode 100644 web/app/src/theme/index.ts create mode 100644 web/app/src/theme/theme.ts create mode 100644 web/app/src/theme/tokens/breakpoints.ts create mode 100644 web/app/src/theme/tokens/colors.ts create mode 100644 web/app/src/theme/tokens/index.ts diff --git a/web/app/index.html b/web/app/index.html index 78d7e8c6a..4bf664009 100644 --- a/web/app/index.html +++ b/web/app/index.html @@ -15,7 +15,7 @@ - -
+ +
diff --git a/web/app/src/App.tsx b/web/app/src/App.tsx index f2c174524..c8be15530 100644 --- a/web/app/src/App.tsx +++ b/web/app/src/App.tsx @@ -1,28 +1,13 @@ -import { RouterProvider } from 'react-router' +import { ThemeRegistry } from '@/theme' -import * as colors from '@mui/material/colors' -import { ThemeProvider, createTheme } from '@mui/material/styles' +import { RouterProvider } from 'react-router' import router from '@/router' -const theme = createTheme({ - shape: { - borderRadius: 0, - }, - palette: { - primary: { - main: colors.blue[800], - }, - secondary: { - main: colors.teal[400], - }, - }, -}) - const App = () => ( - + - + ) export default App diff --git a/web/app/src/layouts/app.tsx b/web/app/src/layouts/AppLayout/component.tsx similarity index 87% rename from web/app/src/layouts/app.tsx rename to web/app/src/layouts/AppLayout/component.tsx index 680d3ccdb..721252d1d 100644 --- a/web/app/src/layouts/app.tsx +++ b/web/app/src/layouts/AppLayout/component.tsx @@ -10,6 +10,8 @@ import NavBar from '@/components/NavBar' import PageFooter from '@/components/PageFooter' import ProfileProvider from '@/components/ProfileProvider' +import { StyledAppLayout } from './styles' + export const loader = async () => { return await loginRequired(authApi.whoami)() } @@ -20,15 +22,15 @@ const AppLayout = () => { return ( -
+ -
+
-
+
) } diff --git a/web/app/src/layouts/AppLayout/styles.tsx b/web/app/src/layouts/AppLayout/styles.tsx new file mode 100644 index 000000000..9e52a6a88 --- /dev/null +++ b/web/app/src/layouts/AppLayout/styles.tsx @@ -0,0 +1,14 @@ +import { styled } from '@mui/material' + +export const StyledAppLayout = styled('div')` + height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; + + > main { + flex-grow: 1; + flex-shrink: 1; + height: 0px; + } +` diff --git a/web/app/src/layouts/base.tsx b/web/app/src/layouts/BaseLayout/component.tsx similarity index 87% rename from web/app/src/layouts/base.tsx rename to web/app/src/layouts/BaseLayout/component.tsx index df9ba19b1..7b218dac1 100644 --- a/web/app/src/layouts/base.tsx +++ b/web/app/src/layouts/BaseLayout/component.tsx @@ -6,9 +6,11 @@ import { Outlet } from 'react-router' import { DialogsProvider } from '@toolpad/core/useDialogs' import { NotificationsProvider } from '@toolpad/core/useNotifications' +import { StyledBaseLayout } from './styles' + const BaseLayout = () => { return ( -
+ @@ -16,7 +18,7 @@ const BaseLayout = () => { -
+ ) } diff --git a/web/app/src/layouts/BaseLayout/styles.tsx b/web/app/src/layouts/BaseLayout/styles.tsx new file mode 100644 index 000000000..cffceb730 --- /dev/null +++ b/web/app/src/layouts/BaseLayout/styles.tsx @@ -0,0 +1,8 @@ +import { styled } from '@mui/material' + +export const StyledBaseLayout = styled('div')` + height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; +` diff --git a/web/app/src/router/index.tsx b/web/app/src/router/index.tsx index 217a213fc..6e17933c4 100644 --- a/web/app/src/router/index.tsx +++ b/web/app/src/router/index.tsx @@ -8,7 +8,8 @@ export default createBrowserRouter([ { path: '/web/', lazy: async () => { - const { default: Component } = await import('@/layouts/base') + const { default: Component } = + await import('@/layouts/BaseLayout/component') return { Component, HydrateFallback: () => , @@ -34,7 +35,8 @@ export default createBrowserRouter([ { path: '', lazy: async () => { - const { default: Component, loader } = await import('@/layouts/app') + const { default: Component, loader } = + await import('@/layouts/AppLayout/component') return { Component, loader } }, children: [ diff --git a/web/app/src/theme/ThemeRegistry.tsx b/web/app/src/theme/ThemeRegistry.tsx new file mode 100644 index 000000000..71d7c35b5 --- /dev/null +++ b/web/app/src/theme/ThemeRegistry.tsx @@ -0,0 +1,29 @@ +import { CacheProvider } from '@emotion/react' + +import { type ReactNode, useMemo } from 'react' + +import CssBaseline from '@mui/material/CssBaseline' +import GlobalStyles from '@mui/material/GlobalStyles' +import { ThemeProvider } from '@mui/material/styles' + +import { createEmotionCache } from './emotionCache' +import globalStyles from './globalStyles' +import theme from './theme' + +interface ThemeRegistryProps { + children: ReactNode +} + +export default function ThemeRegistry({ children }: ThemeRegistryProps) { + const cache = useMemo(() => createEmotionCache(), []) + + return ( + + + + + {children} + + + ) +} diff --git a/web/app/src/theme/emotionCache.ts b/web/app/src/theme/emotionCache.ts new file mode 100644 index 000000000..4c8648c01 --- /dev/null +++ b/web/app/src/theme/emotionCache.ts @@ -0,0 +1,5 @@ +import createCache from '@emotion/cache' + +export function createEmotionCache() { + return createCache({ key: 'css', prepend: true }) +} diff --git a/web/app/src/theme/globalStyles.ts b/web/app/src/theme/globalStyles.ts new file mode 100644 index 000000000..f7ee3bd00 --- /dev/null +++ b/web/app/src/theme/globalStyles.ts @@ -0,0 +1,26 @@ +import type { GlobalStylesProps } from '@mui/material/GlobalStyles' + +import { colors } from './tokens' + +const globalStyles: GlobalStylesProps['styles'] = { + 'html, body': { + margin: 0, + padding: 0, + width: '100vw', + height: '100vh', + backgroundColor: colors.backgroundBody, + overflow: 'hidden', + }, + '#root': { + width: '100vw', + height: '100vh', + display: 'flex', + flexDirection: 'column', + }, + a: { + textDecoration: 'none', + color: 'inherit', + }, +} + +export default globalStyles diff --git a/web/app/src/theme/index.ts b/web/app/src/theme/index.ts new file mode 100644 index 000000000..3a97f83d5 --- /dev/null +++ b/web/app/src/theme/index.ts @@ -0,0 +1,3 @@ +export { default as ThemeRegistry } from './ThemeRegistry' +export { default as theme } from './theme' +export { createEmotionCache } from './emotionCache' diff --git a/web/app/src/theme/theme.ts b/web/app/src/theme/theme.ts new file mode 100644 index 000000000..c68a5c38d --- /dev/null +++ b/web/app/src/theme/theme.ts @@ -0,0 +1,31 @@ +import { colors } from '@mui/material' + +import { createTheme } from '@mui/material/styles' + +import { type TokensType, tokens } from './tokens' + +declare module '@mui/material/styles' { + interface Theme { + tokens: TokensType + } + interface ThemeOptions { + tokens?: TokensType + } +} + +const theme = createTheme({ + tokens, + shape: { + borderRadius: 0, + }, + palette: { + primary: { + main: colors.blue[800], + }, + secondary: { + main: colors.teal[400], + }, + }, +}) + +export default theme diff --git a/web/app/src/theme/tokens/breakpoints.ts b/web/app/src/theme/tokens/breakpoints.ts new file mode 100644 index 000000000..38c0c7ec4 --- /dev/null +++ b/web/app/src/theme/tokens/breakpoints.ts @@ -0,0 +1,19 @@ +export type BreakpointsType = { + xs: string + sm: string + md: string + lg: string + xl: string + xxl: string +} + +export const breakpoints: BreakpointsType = { + xs: '320px', + sm: '480px', + md: '768px', + lg: '1024px', + xl: '1280px', + xxl: '1536px', +} + +export default breakpoints diff --git a/web/app/src/theme/tokens/colors.ts b/web/app/src/theme/tokens/colors.ts new file mode 100644 index 000000000..499d811bd --- /dev/null +++ b/web/app/src/theme/tokens/colors.ts @@ -0,0 +1,11 @@ +export type ColorsType = { + white: string + backgroundBody: string +} + +export const colors: ColorsType = { + white: '#ffffff', + backgroundBody: '#e2e8f0', +} + +export default colors diff --git a/web/app/src/theme/tokens/index.ts b/web/app/src/theme/tokens/index.ts new file mode 100644 index 000000000..0f3a6395b --- /dev/null +++ b/web/app/src/theme/tokens/index.ts @@ -0,0 +1,15 @@ +import breakpoints, { BreakpointsType } from './breakpoints' +import colors, { ColorsType } from './colors' + +export const tokens = { + breakpoints, + colors, +} + +export type TokensType = { + breakpoints: BreakpointsType + colors: ColorsType +} + +export { breakpoints, colors } +export type { BreakpointsType, ColorsType }