diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index de7628453..13cdf0b55 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -9,6 +9,7 @@ import useAuth from 'src/hooks/useAuth'; import { Alert, CssBaseline } from '@mui/material'; import ThemeProvider from './theme/ThemeProvider'; import AppInit from './components/AppInit'; +import ThemeSettings from './components/ThemeSettings'; import { CustomSnackBarProvider } from './contexts/CustomSnackBarContext'; import ReactGA from 'react-ga4'; import { @@ -201,6 +202,7 @@ function App() { open={shouldShowPrompt} onClose={dismissPrompt} /> + diff --git a/frontend/src/components/ThemeSettings/index.tsx b/frontend/src/components/ThemeSettings/index.tsx index 39cd5eb44..e46327998 100644 --- a/frontend/src/components/ThemeSettings/index.tsx +++ b/frontend/src/components/ThemeSettings/index.tsx @@ -1,10 +1,8 @@ -import { FC, useContext, useRef, useState, MouseEvent } from 'react'; +import { FC, useContext, useRef, useState } from 'react'; import { Popover, styled, Button, - MenuItem, - Menu, Typography, Stack, Divider, @@ -16,8 +14,6 @@ import CheckTwoToneIcon from '@mui/icons-material/CheckTwoTone'; import SettingsTwoToneIcon from '@mui/icons-material/SettingsTwoTone'; import Fab from '@mui/material/Fab'; import { useTranslation } from 'react-i18next'; -import UnfoldMoreTwoToneIcon from '@mui/icons-material/UnfoldMoreTwoTone'; -import { NavLink } from 'react-router-dom'; const ThemeSettingsButton = styled(Box)( ({ theme }) => ` @@ -25,7 +21,7 @@ const ThemeSettingsButton = styled(Box)( z-index: 9999; right: ${theme.spacing(4)}; bottom: ${theme.spacing(4)}; - + &::before { width: 30px; height: 30px; @@ -86,7 +82,7 @@ const ColorSchemeWrapper = styled(Box)( border-radius: ${theme.general.borderRadiusXl}; height: 28px; - + &.colorSchemeWrapper { display: flex; align-items: stretch; @@ -113,7 +109,7 @@ const ColorSchemeWrapper = styled(Box)( .primary { background: #5569ff; } - + .secondary { background: #f2f5f9; } @@ -123,21 +119,51 @@ const ColorSchemeWrapper = styled(Box)( .primary { background: #2442AF; } - + .secondary { background: #F8F8F8; } } - + &.purpleFlow { .primary { background: #9b52e1; } - + .secondary { background: #00b795; } } + + &.theme1 { + .primary { + background: #0EA5E9; + } + + .secondary { + background: #06B6D4; + } + } + + &.theme2 { + .primary { + background: #EC4899; + } + + .secondary { + background: #8B5CF6; + } + } + + &.theme3 { + .primary { + background: #06B6D4; + } + + .secondary { + background: #6366F1; + } + } ` ); @@ -189,15 +215,6 @@ const ThemeSettings: FC = () => { setThemeName(theme); }; - const [anchorEl, setAnchorEl] = useState(null); - const open = Boolean(anchorEl); - const openMenu = (event: MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const closeMenu = () => { - setAnchorEl(null); - }; - return ( <> @@ -220,110 +237,6 @@ const ThemeSettings: FC = () => { horizontal: 'right' }} > - - - Layout Blueprints - - - - - Extended Sidebar - - - Accent Header - - - Accent Sidebar - - - Boxed Sidebar - - - Collapsed Sidebar - - - Bottom Navigation - - - Top Navigation - - - - { + + { + changeTheme('SkyView'); + }} + > + {theme === 'SkyView' && ( + + + + )} + + + + + + + + + + Dark color schemes + + + + { + changeTheme('PureDarkTheme'); + }} + > + {theme === 'PureDarkTheme' && ( + + + + )} + + + + + + + + { + changeTheme('ElegantNightTheme'); + }} + > + {theme === 'ElegantNightTheme' && ( + + + + )} + + + + + + diff --git a/frontend/src/content/own/Settings/Features/index.tsx b/frontend/src/content/own/Settings/Features/index.tsx index bac88c80c..714fcb3af 100644 --- a/frontend/src/content/own/Settings/Features/index.tsx +++ b/frontend/src/content/own/Settings/Features/index.tsx @@ -181,7 +181,7 @@ function FeaturesSettings() { diff --git a/frontend/src/content/own/Settings/Integrations/ApiKeysPage.tsx b/frontend/src/content/own/Settings/Integrations/ApiKeysPage.tsx index ff21054f9..94332b244 100644 --- a/frontend/src/content/own/Settings/Integrations/ApiKeysPage.tsx +++ b/frontend/src/content/own/Settings/Integrations/ApiKeysPage.tsx @@ -281,10 +281,10 @@ function ApiKeys() { justifyContent="space-between" p={2} sx={{ - backgroundColor: 'grey.100', + backgroundColor: 'action.hover', borderRadius: 1, border: '1px solid', - borderColor: 'grey.300' + borderColor: 'divider' }} > ( ({ theme, highlighted }) => ` padding: ${theme.spacing(2)}; border-radius: ${theme.general.borderRadius}; - background: ${theme.colors.alpha.white[100]}; + background: ${theme.palette.background.paper}; border: ${ highlighted ? `2px solid ${theme.palette.primary.main}` - : `1px solid ${theme.colors.alpha.black[10]}` + : `1px solid ${theme.palette.divider}` }; transition: all 0.2s ease-in-out; ${highlighted ? `box-shadow: 0 0 8px ${theme.palette.primary.main}40;` : ''} diff --git a/frontend/src/content/own/components/CustomDatagrid2/index.tsx b/frontend/src/content/own/components/CustomDatagrid2/index.tsx index 64d1a39d0..4af70225f 100644 --- a/frontend/src/content/own/components/CustomDatagrid2/index.tsx +++ b/frontend/src/content/own/components/CustomDatagrid2/index.tsx @@ -119,8 +119,6 @@ interface CustomDatagrid2Props { getRowId?: (row: TData) => string; } -const PINNED_BG = '#F2F5F9'; - function CustomDatagrid2({ columns, data, @@ -523,7 +521,7 @@ function CustomDatagrid2({ fontWeight: 'bold', textTransform: 'uppercase', borderBottom: `1px solid ${theme.palette.divider}`, - backgroundColor: '#E8EAEE', + backgroundColor: theme.palette.background.paper, position: 'sticky', top: 0, zIndex: 3 @@ -558,12 +556,12 @@ function CustomDatagrid2({ whiteSpace: 'nowrap', position: isPinned ? 'sticky' : 'relative', left: isPinned ? stickyLeft : undefined, - backgroundColor: PINNED_BG, + backgroundColor: isPinned ? alpha(theme.palette.primary.main, 0.06) : theme.palette.background.paper, userSelect: isResizing ? 'none' : 'auto', cursor: canDrag ? 'pointer' : 'default', borderRight: isPinned ? `2px solid ${theme.palette.divider}` - : `1px solid #F2F5F9`, + : `1px solid ${theme.palette.divider}`, boxShadow: isPinned ? `2px 0 4px ${alpha( theme.palette.common.black, @@ -762,7 +760,7 @@ function CustomDatagrid2({ textOverflow: 'ellipsis', position: isPinned ? 'sticky' : undefined, left: isPinned ? stickyLeft : undefined, - backgroundColor: isPinned ? PINNED_BG : undefined, + backgroundColor: isPinned ? alpha(theme.palette.primary.main, 0.06) : undefined, borderRight: isPinned ? `2px solid ${theme.palette.divider}` : undefined, diff --git a/frontend/src/content/own/components/form/SelectTasks/SingleTask.tsx b/frontend/src/content/own/components/form/SelectTasks/SingleTask.tsx index ac9efa943..ffed774e0 100644 --- a/frontend/src/content/own/components/form/SelectTasks/SingleTask.tsx +++ b/frontend/src/content/own/components/form/SelectTasks/SingleTask.tsx @@ -127,7 +127,7 @@ export default function SingleTask({ onChange={(event) => !preview && handleChange(event.target.value, task.id) } - sx={{ backgroundColor: 'white' }} + sx={{ backgroundColor: theme.palette.background.paper }} disabled={ (task.taskBase.user && task.taskBase.user.id !== user.id) || disabled @@ -142,7 +142,7 @@ export default function SingleTask({ )} ) : ( - + )} - + diff --git a/frontend/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx b/frontend/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx index b5b03e30a..4ced50cf6 100644 --- a/frontend/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx +++ b/frontend/src/layouts/ExtendedSidebarLayout/Sidebar/index.tsx @@ -53,7 +53,7 @@ function Sidebar() { top: 0, background: theme.palette.mode === 'dark' - ? alpha(lighten(theme.header.background, 0.1), 0.5) + ? '#0F0F0F' : darken(theme.colors.alpha.black[100], 0.5), boxShadow: theme.palette.mode === 'dark' ? theme.sidebar.boxShadow : 'none' @@ -114,7 +114,7 @@ function Sidebar() { sx={{ background: theme.palette.mode === 'dark' - ? theme.colors.alpha.white[100] + ? '#0F0F0F' : darken(theme.colors.alpha.black[100], 0.5) }} > diff --git a/frontend/src/theme/ThemeProvider.tsx b/frontend/src/theme/ThemeProvider.tsx index a38779197..a77b4fe51 100644 --- a/frontend/src/theme/ThemeProvider.tsx +++ b/frontend/src/theme/ThemeProvider.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { ThemeProvider } from '@mui/material'; +import { ThemeProvider } from '@mui/material/styles'; import { themeCreator } from './base'; import { StylesProvider } from '@mui/styles'; import { CacheProvider } from '@emotion/react'; diff --git a/frontend/src/theme/base.ts b/frontend/src/theme/base.ts index 9e82347c4..b3485df1a 100644 --- a/frontend/src/theme/base.ts +++ b/frontend/src/theme/base.ts @@ -4,9 +4,12 @@ import { Theme } from '@mui/material'; import { PureLightTheme } from './schemes/PureLightTheme'; import { GreyGooseTheme } from './schemes/GreyGooseTheme'; import { PurpleFlowTheme } from './schemes/PurpleFlowTheme'; +import { SkyView } from './schemes/SkyView'; +import { PureDarkTheme } from './schemes/PureDarkTheme'; +import { ElegantNightTheme } from './schemes/ElegantNightTheme'; export function themeCreator(theme: string): Theme { - return themeMap[theme]; + return themeMap[theme] || PureLightTheme; } declare module '@mui/material/styles' { @@ -253,5 +256,8 @@ declare module '@mui/material/styles' { const themeMap: { [key: string]: Theme } = { PureLightTheme, GreyGooseTheme, - PurpleFlowTheme + PurpleFlowTheme, + SkyView, + PureDarkTheme, + ElegantNightTheme }; diff --git a/frontend/src/theme/schemes/ElegantNightTheme.ts b/frontend/src/theme/schemes/ElegantNightTheme.ts new file mode 100644 index 000000000..fd12dc0de --- /dev/null +++ b/frontend/src/theme/schemes/ElegantNightTheme.ts @@ -0,0 +1,1452 @@ +import { alpha, createTheme, lighten, darken } from '@mui/material'; +import '@mui/lab/themeAugmentation'; +import { customColors } from '../../config'; + +const themeColors = { + primary: '#06B6D4', + secondary: '#6366F1', + success: '#10B981', + warning: '#F59E0B', + error: '#EF4444', + info: '#3B82F6', + black: '#0A0E27', + white: '#ffffff', + primaryAlt: '#0891B2', + ...customColors +}; + +const colors = { + gradients: { + blue1: 'linear-gradient(135deg, #667EEA 0%, #764BA2 100%)', + blue2: 'linear-gradient(135deg, #00D4FF 0%, #0099FF 100%)', + blue3: 'linear-gradient(127.55deg, #1A2847 3.73%, #2D3F5C 92.26%)', + blue4: 'linear-gradient(-20deg, #2d4a6e 0%, #3d3a5c 100%)', + blue5: 'linear-gradient(135deg, #7DD3FC 10%, #1E40AF 100%)', + orange1: 'linear-gradient(135deg, #FBBF24 0%, #F87171 100%)', + orange2: 'linear-gradient(135deg, #FCD34D 0%, #FB7185 100%)', + orange3: 'linear-gradient(120deg, #FDE047 0%, #FB923C 100%)', + purple1: 'linear-gradient(135deg, #67E8F9 0%, #A78BFA 100%)', + purple3: 'linear-gradient(135deg, #818CF8 0%, #A855F7 100%)', + pink1: 'linear-gradient(135deg, #F5D0FE 0%, #D946EF 100%)', + pink2: 'linear-gradient(135deg, #FCA5A5 0%, #EC4899 100%)', + green1: 'linear-gradient(135deg, #BBF7D0 0%, #059669 100%)', + green2: 'linear-gradient(to bottom, #14B8A6, #6EE7B7)', + black1: 'linear-gradient(100.66deg, #2D3E5F 6.56%, #0A0E27 93.57%)', + black2: 'linear-gradient(60deg, #111629 0%, #1A2239 100%)' + }, + shadows: { + success: + '0px 1px 4px rgba(16, 185, 129, 0.25), 0px 3px 12px 2px rgba(16, 185, 129, 0.35)', + error: + '0px 1px 4px rgba(239, 68, 68, 0.25), 0px 3px 12px 2px rgba(239, 68, 68, 0.35)', + info: '0px 1px 4px rgba(59, 130, 246, 0.25), 0px 3px 12px 2px rgba(59, 130, 246, 0.35)', + primary: + '0px 1px 4px rgba(6, 182, 212, 0.25), 0px 3px 12px 2px rgba(6, 182, 212, 0.35)', + warning: + '0px 1px 4px rgba(245, 158, 11, 0.25), 0px 3px 12px 2px rgba(245, 158, 11, 0.35)', + card: '0px 9px 16px rgba(0, 0, 0, 0.6), 0px 2px 2px rgba(0, 0, 0, 0.7)', + cardSm: + '0px 2px 3px rgba(0, 0, 0, 0.5), 0px 1px 1px rgba(0, 0, 0, 0.6)', + cardLg: + '0 5rem 14rem 0 rgb(0 0 0 / 70%), 0 0.8rem 2.3rem rgb(0 0 0 / 85%), 0 0.2rem 0.3rem rgb(0 0 0 / 80%)' + }, + layout: { + general: { + bodyBg: '#0A0E27' + }, + sidebar: { + background: '#0A0E27', + textColor: '#CBD5E1', + dividerBg: '#1E293B', + menuItemColor: '#E2E8F0', + menuItemColorActive: themeColors.primary, + menuItemBg: '#0A0E27', + menuItemBgActive: '#0F3947', + menuItemIconColor: '#94A3B8', + menuItemIconColorActive: themeColors.primary, + menuItemHeadingColor: '#F1F5F9' + } + }, + alpha: { + white: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + trueWhite: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + black: { + 5: alpha(themeColors.black, 0.02), + 10: alpha(themeColors.black, 0.1), + 30: alpha(themeColors.black, 0.3), + 50: alpha(themeColors.black, 0.5), + 70: alpha(themeColors.black, 0.7), + 100: themeColors.black + } + }, + secondary: { + lighter: lighten(themeColors.secondary, 0.85), + light: lighten(themeColors.secondary, 0.25), + main: themeColors.secondary, + dark: darken(themeColors.secondary, 0.2) + }, + primary: { + lighter: lighten(themeColors.primary, 0.85), + light: lighten(themeColors.primary, 0.3), + main: themeColors.primary, + dark: darken(themeColors.primary, 0.2) + }, + success: { + lighter: lighten(themeColors.success, 0.85), + light: lighten(themeColors.success, 0.3), + main: themeColors.success, + dark: darken(themeColors.success, 0.2) + }, + warning: { + lighter: lighten(themeColors.warning, 0.85), + light: lighten(themeColors.warning, 0.3), + main: themeColors.warning, + dark: darken(themeColors.warning, 0.2) + }, + error: { + lighter: lighten(themeColors.error, 0.85), + light: lighten(themeColors.error, 0.3), + main: themeColors.error, + dark: darken(themeColors.error, 0.2) + }, + info: { + lighter: lighten(themeColors.info, 0.85), + light: lighten(themeColors.info, 0.3), + main: themeColors.info, + dark: darken(themeColors.info, 0.2) + } +}; + +export const ElegantNightTheme = createTheme({ + direction: 'ltr', + colors: { + gradients: { + blue1: colors.gradients.blue1, + blue2: colors.gradients.blue2, + blue3: colors.gradients.blue3, + blue4: colors.gradients.blue4, + blue5: colors.gradients.blue5, + orange1: colors.gradients.orange1, + orange2: colors.gradients.orange2, + orange3: colors.gradients.orange3, + purple1: colors.gradients.purple1, + purple3: colors.gradients.purple3, + pink1: colors.gradients.pink1, + pink2: colors.gradients.pink2, + green1: colors.gradients.green1, + green2: colors.gradients.green2, + black1: colors.gradients.black1, + black2: colors.gradients.black2 + }, + shadows: { + success: colors.shadows.success, + error: colors.shadows.error, + primary: colors.shadows.primary, + info: colors.shadows.info, + warning: colors.shadows.warning + }, + alpha: { + white: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + trueWhite: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + black: { + 5: alpha(themeColors.black, 0.02), + 10: alpha(themeColors.black, 0.1), + 30: alpha(themeColors.black, 0.3), + 50: alpha(themeColors.black, 0.5), + 70: alpha(themeColors.black, 0.7), + 100: themeColors.black + } + }, + secondary: { + lighter: alpha(themeColors.secondary, 0.1), + light: lighten(themeColors.secondary, 0.3), + main: themeColors.secondary, + dark: darken(themeColors.secondary, 0.2) + }, + primary: { + lighter: alpha(themeColors.primary, 0.1), + light: lighten(themeColors.primary, 0.3), + main: themeColors.primary, + dark: darken(themeColors.primary, 0.2) + }, + success: { + lighter: alpha(themeColors.success, 0.1), + light: lighten(themeColors.success, 0.3), + main: themeColors.success, + dark: darken(themeColors.success, 0.2) + }, + warning: { + lighter: alpha(themeColors.warning, 0.1), + light: lighten(themeColors.warning, 0.3), + main: themeColors.warning, + dark: darken(themeColors.warning, 0.2) + }, + error: { + lighter: alpha(themeColors.error, 0.1), + light: lighten(themeColors.error, 0.3), + main: themeColors.error, + dark: darken(themeColors.error, 0.2) + }, + info: { + lighter: alpha(themeColors.info, 0.1), + light: lighten(themeColors.info, 0.3), + main: themeColors.info, + dark: darken(themeColors.info, 0.2) + } + }, + general: { + reactFrameworkColor: '#00D8FF', + borderRadiusSm: '6px', + borderRadius: '10px', + borderRadiusLg: '12px', + borderRadiusXl: '16px' + }, + sidebar: { + background: colors.layout.sidebar.background, + textColor: colors.layout.sidebar.textColor, + dividerBg: colors.layout.sidebar.dividerBg, + menuItemColor: colors.layout.sidebar.menuItemColor, + menuItemColorActive: colors.layout.sidebar.menuItemColorActive, + menuItemBg: colors.layout.sidebar.menuItemBg, + menuItemBgActive: colors.layout.sidebar.menuItemBgActive, + menuItemIconColor: colors.layout.sidebar.menuItemIconColor, + menuItemIconColorActive: colors.layout.sidebar.menuItemIconColorActive, + menuItemHeadingColor: colors.layout.sidebar.menuItemHeadingColor, + boxShadow: + '2px 0 3px rgba(15, 23, 42, .28), 1px 0 1px rgba(15, 23, 42, 0.52)', + width: '290px' + }, + header: { + height: '80px', + background: '#111629', + boxShadow: colors.shadows.cardSm, + textColor: '#F1F5F9' + }, + spacing: 9, + palette: { + common: { + black: colors.alpha.black[100], + white: colors.alpha.white[100] + }, + mode: 'dark', + primary: { + light: colors.primary.light, + main: colors.primary.main, + dark: colors.primary.dark + }, + secondary: { + light: colors.secondary.light, + main: colors.secondary.main, + dark: colors.secondary.dark + }, + error: { + light: colors.error.light, + main: colors.error.main, + dark: colors.error.dark, + contrastText: colors.alpha.white[100] + }, + success: { + light: colors.success.light, + main: colors.success.main, + dark: colors.success.dark, + contrastText: colors.alpha.white[100] + }, + info: { + light: colors.info.light, + main: colors.info.main, + dark: colors.info.dark, + contrastText: colors.alpha.white[100] + }, + warning: { + light: colors.warning.light, + main: colors.warning.main, + dark: colors.warning.dark, + contrastText: colors.alpha.white[100] + }, + text: { + primary: '#F1F5F9', + secondary: '#CBD5E1', + disabled: '#64748B' + }, + background: { + paper: '#111629', + default: '#0A0E27' + }, + action: { + active: '#06B6D4', + hover: alpha('#06B6D4', 0.1), + hoverOpacity: 0.1, + selected: alpha('#06B6D4', 0.1), + selectedOpacity: 0.1, + disabled: '#64748B', + disabledBackground: '#1E293B', + disabledOpacity: 0.38, + focus: alpha('#06B6D4', 0.2), + focusOpacity: 0.05, + activatedOpacity: 0.12 + }, + tonalOffset: 0.5 + }, + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 960, + lg: 1280, + xl: 1840 + } + }, + components: { + MuiBackdrop: { + styleOverrides: { + root: { + backgroundColor: alpha(darken(themeColors.primaryAlt, 0.4), 0.2), + backdropFilter: 'blur(2px)', + + '&.MuiBackdrop-invisible': { + backgroundColor: 'transparent', + backdropFilter: 'blur(2px)' + } + } + } + }, + MuiFormHelperText: { + styleOverrides: { + root: { + textTransform: 'none', + marginLeft: 8, + marginRight: 8, + fontWeight: 'bold' + } + } + }, + MuiCssBaseline: { + styleOverrides: { + 'html, body': { + width: '100%', + height: '100%' + }, + body: { + display: 'flex', + flexDirection: 'column', + minHeight: '100%', + width: '100%', + flex: 1 + }, + '#root': { + width: '100%', + height: '100%', + display: 'flex', + flex: 1, + flexDirection: 'column' + }, + html: { + display: 'flex', + flexDirection: 'column', + minHeight: '100%', + width: '100%', + MozOsxFontSmoothing: 'grayscale', + WebkitFontSmoothing: 'antialiased' + }, + '.child-popover .MuiPaper-root .MuiList-root': { + flexDirection: 'column' + }, + '#nprogress': { + pointerEvents: 'none' + }, + '#nprogress .bar': { + background: colors.primary.lighter + }, + '#nprogress .spinner-icon': { + borderTopColor: colors.primary.lighter, + borderLeftColor: colors.primary.lighter + }, + '#nprogress .peg': { + boxShadow: + '0 0 15px ' + + colors.primary.lighter + + ', 0 0 8px' + + colors.primary.light + }, + ':root': { + '--swiper-theme-color': colors.primary.main + }, + code: { + background: colors.info.lighter, + color: colors.info.dark, + borderRadius: 4, + padding: 4 + }, + '@keyframes pulse': { + '0%': { + transform: 'scale(.75)' + }, + '20%': { + transform: 'scale(1.1)' + }, + '40%': { + transform: 'scale(.75)' + }, + '60%': { + transform: 'scale(1.05)' + }, + '80%': { + transform: 'scale(.75)' + }, + '100%': { + transform: 'scale(.75)' + } + }, + '@keyframes ripple': { + '0%': { + transform: 'scale(.8)', + opacity: 1 + }, + '100%': { + transform: 'scale(2.8)', + opacity: 0 + } + }, + '@keyframes float': { + '0%': { + transform: 'translate(0%, 0%)' + }, + '100%': { + transform: 'translate(3%, 3%)' + } + }, + '::-webkit-scrollbar': { + width: '8px', + height: '8px' + }, + '::-webkit-scrollbar-track': { + backgroundColor: '#111629' + }, + '::-webkit-scrollbar-thumb': { + backgroundColor: '#475569', + borderRadius: '4px', + '&:hover': { + backgroundColor: '#64748B' + } + }, + 'scrollbar-color': '#475569 #111629 !important', + 'scrollbar-width': 'thin !important' + } + }, + MuiSelect: { + styleOverrides: { + select: { + color: '#F1F5F9', + backgroundColor: '#111629', + '&:focus': { + backgroundColor: '#1E293B' + } + }, + iconOutlined: { + color: '#CBD5E1' + }, + icon: { + top: 'calc(50% - 14px)', + color: '#CBD5E1' + } + } + }, + MuiOutlinedInput: { + styleOverrides: { + root: { + color: '#F1F5F9', + backgroundColor: 'transparent', + '& .MuiInputAdornment-positionEnd.MuiInputAdornment-outlined': { + paddingRight: 6 + }, + '&:hover .MuiOutlinedInput-notchedOutline': { + borderColor: '#06B6D4' + }, + '&.Mui-focused:hover .MuiOutlinedInput-notchedOutline': { + borderColor: '#06B6D4' + }, + '& input': { + color: '#F1F5F9' + } + } + } + }, + MuiListSubheader: { + styleOverrides: { + colorPrimary: { + fontWeight: 'bold', + lineHeight: '40px', + fontSize: 13, + background: colors.alpha.black[5], + color: colors.alpha.black[70] + } + } + }, + MuiCardHeader: { + styleOverrides: { + action: { + marginTop: -5, + marginBottom: -5 + }, + title: { + fontSize: 15 + } + } + }, + MuiRadio: { + styleOverrides: { + root: { + borderRadius: '50px' + } + } + }, + MuiChip: { + styleOverrides: { + colorSecondary: { + background: colors.alpha.black[5], + color: colors.alpha.black[100], + + '&:hover': { + background: colors.alpha.black[10] + } + }, + deleteIcon: { + color: colors.error.light, + + '&:hover': { + color: colors.error.main + } + } + } + }, + MuiAccordion: { + styleOverrides: { + root: { + boxShadow: 'none', + + '&.Mui-expanded': { + margin: 0 + }, + '&::before': { + display: 'none' + } + } + } + }, + MuiAvatar: { + styleOverrides: { + root: { + fontSize: 14, + fontWeight: 'bold' + }, + colorDefault: { + background: colors.alpha.black[30], + color: colors.alpha.white[100] + } + } + }, + MuiAvatarGroup: { + styleOverrides: { + root: { + alignItems: 'center' + }, + avatar: { + background: colors.alpha.black[10], + fontSize: 13, + color: colors.alpha.black[70], + fontWeight: 'bold', + + '&:first-of-type': { + border: 0, + background: 'transparent' + } + } + } + }, + MuiListItemAvatar: { + styleOverrides: { + alignItemsFlexStart: { + marginTop: 0 + } + } + }, + MuiPaginationItem: { + styleOverrides: { + page: { + fontSize: 13, + fontWeight: 'bold', + transition: 'all .2s' + }, + textPrimary: { + '&.Mui-selected': { + boxShadow: colors.shadows.primary + }, + '&.MuiButtonBase-root:hover': { + background: colors.alpha.black[5] + }, + '&.Mui-selected.MuiButtonBase-root:hover': { + background: colors.primary.main + } + } + } + }, + MuiButton: { + defaultProps: { + disableRipple: true + }, + styleOverrides: { + root: { + fontWeight: 'bold', + textTransform: 'none', + paddingLeft: 16, + paddingRight: 16, + + '.MuiSvgIcon-root': { + transition: 'all .2s' + } + }, + endIcon: { + marginRight: -8 + }, + containedSecondary: { + backgroundColor: colors.secondary.main, + color: colors.alpha.white[100], + border: '1px solid ' + colors.alpha.black[30] + }, + outlinedSecondary: { + backgroundColor: colors.alpha.white[100], + + '&:hover, &.MuiSelected': { + backgroundColor: colors.alpha.black[5], + color: colors.alpha.black[100] + } + }, + sizeSmall: { + padding: '6px 16px', + lineHeight: 1.5 + }, + sizeMedium: { + padding: '8px 20px' + }, + sizeLarge: { + padding: '11px 24px' + }, + textSizeSmall: { + padding: '7px 12px' + }, + textSizeMedium: { + padding: '9px 16px' + }, + textSizeLarge: { + padding: '12px 16px' + } + } + }, + MuiButtonBase: { + defaultProps: { + disableRipple: false + }, + styleOverrides: { + root: { + borderRadius: 6 + } + } + }, + MuiToggleButton: { + defaultProps: { + disableRipple: true + }, + styleOverrides: { + root: { + color: colors.primary.main, + background: colors.alpha.white[100], + transition: 'all .2s', + + '&:hover, &.Mui-selected, &.Mui-selected:hover': { + color: colors.alpha.white[100], + background: colors.primary.main + } + } + } + }, + MuiIconButton: { + styleOverrides: { + root: { + borderRadius: 8, + padding: 8, + + '& .MuiTouchRipple-root': { + borderRadius: 8 + } + }, + sizeSmall: { + padding: 4 + } + } + }, + MuiListItemText: { + styleOverrides: { + root: { + margin: 0, + color: '#F1F5F9', + transition: 'all .2s' + }, + primary: { + color: '#F1F5F9', + fontWeight: 500, + fontSize: '0.95rem', + transition: 'all .2s' + }, + secondary: { + color: '#94A3B8', + fontSize: '0.85rem' + } + } + }, + MuiListItemButton: { + styleOverrides: { + root: { + backgroundColor: '#111629', + color: '#F1F5F9', + transition: 'all .2s cubic-bezier(0.4, 0, 0.2, 1)', + '& .MuiTouchRipple-root': { + opacity: 0.15 + }, + '&:hover': { + backgroundColor: 'rgba(6, 182, 212, 0.08)', + paddingLeft: 18 + }, + '&.Mui-selected': { + backgroundColor: 'rgba(6, 182, 212, 0.15)', + color: '#06B6D4', + fontWeight: 600, + '&:hover': { + backgroundColor: 'rgba(6, 182, 212, 0.20)', + paddingLeft: 18 + } + }, + '& .MuiTypography-root': { + color: '#F1F5F9', + transition: 'all .2s' + }, + '&:hover .MuiTypography-root': { + color: '#06B6D4' + }, + '&.Mui-selected .MuiTypography-root': { + color: '#06B6D4' + } + } + } + }, + MuiDivider: { + styleOverrides: { + root: { + background: colors.alpha.black[10], + border: 0, + height: 1 + }, + vertical: { + height: 'auto', + width: 1, + + '&.MuiDivider-flexItem.MuiDivider-fullWidth': { + height: 'auto' + }, + '&.MuiDivider-absolute.MuiDivider-fullWidth': { + height: '100%' + } + }, + withChildren: { + '&:before, &:after': { + border: 0 + } + }, + wrapper: { + background: colors.alpha.white[100], + fontWeight: 'bold', + height: 24, + lineHeight: '24px', + marginTop: -12, + color: 'inherit', + textTransform: 'uppercase' + } + } + }, + MuiPaper: { + styleOverrides: { + root: { + padding: 0, + backgroundColor: '#111629' + }, + elevation0: { + boxShadow: 'none' + }, + elevation: { + boxShadow: colors.shadows.card, + backgroundColor: '#111629' + }, + elevation2: { + boxShadow: colors.shadows.cardSm, + backgroundColor: '#111629' + }, + elevation24: { + boxShadow: colors.shadows.cardLg, + backgroundColor: '#111629' + }, + outlined: { + boxShadow: colors.shadows.card, + backgroundColor: '#111629' + } + } + }, + MuiLink: { + defaultProps: { + underline: 'hover' + } + }, + MuiLinearProgress: { + styleOverrides: { + root: { + borderRadius: 6, + height: 6 + } + } + }, + MuiSlider: { + styleOverrides: { + root: { + '& .MuiSlider-valueLabelCircle, .MuiSlider-valueLabelLabel': { + transform: 'none' + }, + '& .MuiSlider-valueLabel': { + borderRadius: 6, + background: colors.alpha.black[100], + color: colors.alpha.white[100] + } + } + } + }, + MuiList: { + styleOverrides: { + root: { + padding: 0, + color: '#F1F5F9', + + '& .MuiListItem-button': { + transition: 'all .2s cubic-bezier(0.4, 0, 0.2, 1)', + color: '#F1F5F9', + + '& > .MuiSvgIcon-root': { + minWidth: 34, + color: '#94A3B8', + transition: 'all .2s' + }, + + '& .MuiTouchRipple-root': { + opacity: 0.15 + }, + + '&:hover': { + backgroundColor: 'rgba(6, 182, 212, 0.08)', + + '& > .MuiSvgIcon-root': { + color: '#06B6D4' + } + } + }, + '& .MuiListItem-root.MuiButtonBase-root.Mui-selected': { + backgroundColor: 'rgba(6, 182, 212, 0.15)', + color: '#06B6D4', + fontWeight: 600, + + '& > .MuiSvgIcon-root': { + color: '#06B6D4' + }, + + '&:hover': { + backgroundColor: 'rgba(6, 182, 212, 0.20)' + } + }, + '& .MuiMenuItem-root.MuiButtonBase-root:active': { + backgroundColor: 'rgba(6, 182, 212, 0.15)', + color: '#06B6D4' + }, + '& .MuiMenuItem-root.MuiButtonBase-root .MuiTouchRipple-root': { + opacity: 0.15 + } + }, + padding: { + padding: '8px 4px', + + '& .MuiListItem-button': { + borderRadius: 6, + margin: '4px 0', + paddingLeft: 16, + paddingRight: 16, + + '&:hover': { + backgroundColor: 'rgba(6, 182, 212, 0.08)' + } + } + } + } + }, + MuiTabs: { + styleOverrides: { + root: { + height: 38, + minHeight: 38, + overflow: 'visible' + }, + indicator: { + height: 38, + minHeight: 38, + borderRadius: 6, + border: '1px solid ' + colors.primary.dark, + boxShadow: '0px 2px 10px ' + colors.primary.light + }, + scrollableX: { + overflow: 'visible !important' + } + } + }, + MuiTab: { + styleOverrides: { + root: { + padding: 0, + height: 38, + minHeight: 38, + borderRadius: 6, + transition: 'color .2s', + textTransform: 'capitalize', + + '&.MuiButtonBase-root': { + minWidth: 'auto', + paddingLeft: 20, + paddingRight: 20, + marginRight: 4 + }, + '&.Mui-selected, &.Mui-selected:hover': { + color: colors.alpha.white[100], + zIndex: 5 + }, + '&:hover': { + color: colors.alpha.black[100] + } + } + } + }, + MuiMenu: { + styleOverrides: { + paper: { + padding: 0, + backgroundColor: '#111629', + backgroundImage: 'none', + border: '1px solid #1E293B', + boxShadow: '0 10px 40px rgba(0, 0, 0, 0.5)', + borderRadius: '8px' + }, + list: { + padding: '8px 4px', + + '& .MuiMenuItem-root.MuiButtonBase-root': { + fontSize: 14, + marginTop: 0, + marginBottom: 0, + marginX: 1, + padding: '10px 16px', + marginY: '3px', + transition: 'all .2s cubic-bezier(0.4, 0, 0.2, 1)', + color: '#CBD5E1', + borderRadius: '6px', + position: 'relative', + + '& .MuiTouchRipple-root': { + opacity: 0.1 + }, + + '&:hover': { + color: '#0A0E27', + background: 'linear-gradient(135deg, #06B6D4 0%, #0891B2 100%)', + transform: 'translateX(4px)' + }, + + '&:active, &.active, &.Mui-selected': { + color: '#0A0E27', + background: 'linear-gradient(135deg, #06B6D4 0%, #0891B2 100%)', + fontWeight: 600 + }, + + '&.Mui-selected:hover': { + background: 'linear-gradient(135deg, #06B6D4 0%, #0891B2 100%)' + } + } + } + } + }, + MuiMenuItem: { + styleOverrides: { + root: { + background: 'transparent', + color: '#CBD5E1', + transition: 'all .2s cubic-bezier(0.4, 0, 0.2, 1)', + + '&:hover': { + color: '#0A0E27', + background: 'linear-gradient(135deg, #06B6D4 0%, #0891B2 100%)', + paddingLeft: 20 + }, + + '&:active, &.active, &.Mui-selected': { + color: '#0A0E27', + background: 'linear-gradient(135deg, #06B6D4 0%, #0891B2 100%)', + fontWeight: 600 + }, + + '&.Mui-selected:hover': { + background: 'linear-gradient(135deg, #06B6D4 0%, #0891B2 100%)' + } + } + } + }, + MuiListItem: { + styleOverrides: { + root: { + '&.MuiButtonBase-root': { + color: colors.secondary.main, + + '&:hover, &:active, &.active, &.Mui-selected': { + color: colors.alpha.black[100], + background: lighten(colors.primary.lighter, 0.5) + } + } + } + } + }, + MuiAutocomplete: { + styleOverrides: { + tag: { + margin: 1 + }, + root: { + '.MuiAutocomplete-inputRoot.MuiOutlinedInput-root .MuiAutocomplete-endAdornment': + { + right: 14 + } + }, + clearIndicator: { + background: colors.error.lighter, + color: colors.error.main, + marginRight: 8, + + '&:hover': { + background: colors.error.lighter, + color: colors.error.dark + } + }, + popupIndicator: { + color: colors.alpha.black[50], + + '&:hover': { + background: colors.primary.lighter, + color: colors.primary.main + } + } + } + }, + MuiTablePagination: { + styleOverrides: { + toolbar: { + '& .MuiIconButton-root': { + padding: 8 + } + }, + select: { + '&:focus': { + backgroundColor: 'transparent' + } + } + } + }, + MuiToolbar: { + styleOverrides: { + root: { + minHeight: '0 !important', + padding: '0 !important' + } + } + }, + MuiTableRow: { + styleOverrides: { + head: { + background: '#1E293B' + }, + root: { + transition: 'background-color .2s', + + '&.MuiTableRow-hover:hover': { + backgroundColor: '#111629' + } + } + } + }, + MuiTableCell: { + styleOverrides: { + root: { + borderBottomColor: '#2D3E5F', + fontSize: 14, + color: '#F1F5F9', + '&.MuiTableCell-head': { + backgroundColor: '#111629 !important', + color: '#F1F5F9 !important' + } + }, + head: { + textTransform: 'uppercase', + fontSize: 13, + fontWeight: 'bold', + color: '#F1F5F9', + backgroundColor: '#111629' + }, + stickyHeader: { + backgroundColor: '#111629 !important', + color: '#F1F5F9 !important' + } + } + }, + MuiAlert: { + styleOverrides: { + message: { + lineHeight: 1.5, + fontSize: 14 + }, + standardInfo: { + color: colors.info.main + }, + action: { + color: colors.alpha.black[70] + } + } + }, + MuiTimelineDot: { + styleOverrides: { + root: { + margin: 0, + zIndex: 5, + position: 'absolute', + top: '50%', + marginTop: -6, + left: -6 + }, + outlined: { + backgroundColor: colors.alpha.white[100], + boxShadow: '0 0 0 6px ' + colors.alpha.white[100] + }, + outlinedPrimary: { + backgroundColor: colors.alpha.white[100], + boxShadow: '0 0 0 6px ' + colors.alpha.white[100] + } + } + }, + MuiTimelineConnector: { + styleOverrides: { + root: { + position: 'absolute', + height: '100%', + top: 0, + borderRadius: 50, + backgroundColor: colors.alpha.black[10] + } + } + }, + MuiTimelineItem: { + styleOverrides: { + root: { + minHeight: 0, + padding: '8px 0', + + '&:before': { + display: 'none' + } + }, + missingOppositeContent: { + '&:before': { + display: 'none' + } + } + } + }, + MuiTooltip: { + styleOverrides: { + tooltip: { + backgroundColor: alpha(colors.alpha.black['100'], 0.95), + padding: '8px 16px', + fontSize: 13 + }, + arrow: { + color: alpha(colors.alpha.black['100'], 0.95) + } + } + }, + MuiSwitch: { + styleOverrides: { + root: { + height: 33, + overflow: 'visible', + + '& .MuiButtonBase-root': { + position: 'absolute', + padding: 6, + transition: + 'left 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,transform 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms' + }, + '& .MuiIconButton-root': { + borderRadius: 100 + }, + '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': { + opacity: 0.3 + } + }, + thumb: { + border: '1px solid ' + colors.alpha.black[30], + boxShadow: + '0px 9px 14px ' + + colors.alpha.black[10] + + ', 0px 2px 2px ' + + colors.alpha.black[10] + }, + track: { + backgroundColor: colors.alpha.black[5], + border: '1px solid ' + colors.alpha.black[10], + boxShadow: 'inset 0px 1px 1px ' + colors.alpha.black[10], + opacity: 1 + }, + colorPrimary: { + '& .MuiSwitch-thumb': { + backgroundColor: colors.alpha.white[100] + }, + + '&.Mui-checked .MuiSwitch-thumb': { + backgroundColor: colors.primary.main + } + } + } + }, + MuiStepper: { + styleOverrides: { + root: { + paddingTop: 20, + paddingBottom: 20, + background: colors.alpha.black[5] + } + } + }, + MuiStepIcon: { + styleOverrides: { + root: { + '&.MuiStepIcon-completed': { + color: colors.success.main + } + } + } + }, + MuiDrawer: { + styleOverrides: { + paper: { + backgroundColor: '#0A0E27 !important', + backgroundImage: 'none !important', + color: '#F1F5F9', + '& .MuiButton-textPrimary': { + color: '#F1F5F9', + '&:hover': { + backgroundColor: '#1E293B' + } + }, + '& .MuiSvgIcon-root': { + color: '#CBD5E1' + } + } + } + }, + MuiTypography: { + defaultProps: { + variantMapping: { + h1: 'h1', + h2: 'h2', + h3: 'div', + h4: 'div', + h5: 'div', + h6: 'div', + subtitle1: 'div', + subtitle2: 'div', + body1: 'div', + body2: 'div' + } + }, + styleOverrides: { + gutterBottom: { + marginBottom: 4 + }, + paragraph: { + fontSize: 17, + lineHeight: 1.7 + }, + h1: { + color: '#F1F5F9' + }, + h2: { + color: '#F1F5F9' + }, + h3: { + color: '#F1F5F9' + }, + h4: { + color: '#E2E8F0' + }, + h5: { + color: '#E2E8F0' + }, + h6: { + color: '#E2E8F0 !important' + }, + subtitle1: { + color: '#CBD5E1' + }, + subtitle2: { + color: '#CBD5E1' + }, + body1: { + color: '#F1F5F9 !important' + }, + body2: { + color: '#CBD5E1 !important' + }, + caption: { + color: '#94A3B8' + } + } + } + }, + shape: { + borderRadius: 10 + }, + typography: { + fontFamily: + '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"', + h1: { + fontWeight: 700, + fontSize: 35, + color: '#F1F5F9' + }, + h2: { + fontWeight: 700, + fontSize: 30, + color: '#F1F5F9' + }, + h3: { + fontWeight: 700, + fontSize: 25, + lineHeight: 1.4, + color: '#F1F5F9' + }, + h4: { + fontWeight: 700, + fontSize: 16, + color: '#E2E8F0' + }, + h5: { + fontWeight: 700, + fontSize: 14, + color: '#E2E8F0' + }, + h6: { + fontSize: 15, + color: '#E2E8F0' + }, + body1: { + fontSize: 14, + color: '#F1F5F9' + }, + body2: { + fontSize: 14, + color: '#CBD5E1' + }, + button: { + fontWeight: 600 + }, + caption: { + fontSize: 13, + textTransform: 'uppercase', + color: colors.alpha.black[50] + }, + subtitle1: { + fontSize: 14, + color: colors.alpha.black[70] + }, + subtitle2: { + fontWeight: 400, + fontSize: 15, + color: colors.alpha.black[70] + }, + overline: { + fontSize: 13, + fontWeight: 700, + textTransform: 'uppercase' + } + }, + shadows: [ + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none' + ] +}); diff --git a/frontend/src/theme/schemes/PureDarkTheme.ts b/frontend/src/theme/schemes/PureDarkTheme.ts new file mode 100644 index 000000000..5849e402b --- /dev/null +++ b/frontend/src/theme/schemes/PureDarkTheme.ts @@ -0,0 +1,1364 @@ +import { alpha, createTheme, lighten, darken } from '@mui/material'; +import '@mui/lab/themeAugmentation'; +import { customColors } from '../../config'; + +const themeColors = { + primary: '#EC4899', + secondary: '#8B5CF6', + success: '#06B6D4', + warning: '#F59E0B', + error: '#EF4444', + info: '#3B82F6', + black: '#0F0F0F', + white: '#ffffff', + primaryAlt: '#BE185D', + ...customColors +}; + +const colors = { + gradients: { + blue1: 'linear-gradient(135deg, #6B73FF 0%, #000DFF 100%)', + blue2: 'linear-gradient(135deg, #ABDCFF 0%, #0396FF 100%)', + blue3: 'linear-gradient(127.55deg, #141E30 3.73%, #243B55 92.26%)', + blue4: 'linear-gradient(-20deg, #2b5876 0%, #4e4376 100%)', + blue5: 'linear-gradient(135deg, #97ABFF 10%, #123597 100%)', + orange1: 'linear-gradient(135deg, #FCCF31 0%, #F55555 100%)', + orange2: 'linear-gradient(135deg, #FFD3A5 0%, #FD6585 100%)', + orange3: 'linear-gradient(120deg, #f6d365 0%, #fda085 100%)', + purple1: 'linear-gradient(135deg, #43CBFF 0%, #9708CC 100%)', + purple3: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', + pink1: 'linear-gradient(135deg, #F6CEEC 0%, #D939CD 100%)', + pink2: 'linear-gradient(135deg, #F761A1 0%, #8C1BAB 100%)', + green1: 'linear-gradient(135deg, #FFF720 0%, #3CD500 100%)', + green2: 'linear-gradient(to bottom, #00b09b, #96c93d)', + black1: 'linear-gradient(100.66deg, #434343 6.56%, #000000 93.57%)', + black2: 'linear-gradient(60deg, #29323c 0%, #485563 100%)' + }, + shadows: { + success: + '0px 1px 4px rgba(6, 182, 212, 0.25), 0px 3px 12px 2px rgba(6, 182, 212, 0.35)', + error: + '0px 1px 4px rgba(239, 68, 68, 0.25), 0px 3px 12px 2px rgba(239, 68, 68, 0.35)', + info: '0px 1px 4px rgba(59, 130, 246, 0.25), 0px 3px 12px 2px rgba(59, 130, 246, 0.35)', + primary: + '0px 1px 4px rgba(236, 72, 153, 0.25), 0px 3px 12px 2px rgba(236, 72, 153, 0.35)', + warning: + '0px 1px 4px rgba(245, 158, 11, 0.25), 0px 3px 12px 2px rgba(245, 158, 11, 0.35)', + card: '0px 9px 16px rgba(0, 0, 0, 0.4), 0px 2px 2px rgba(0, 0, 0, 0.5)', + cardSm: + '0px 2px 3px rgba(0, 0, 0, 0.4), 0px 1px 1px rgba(0, 0, 0, 0.5)', + cardLg: + '0 5rem 14rem 0 rgb(0 0 0 / 60%), 0 0.8rem 2.3rem rgb(0 0 0 / 80%), 0 0.2rem 0.3rem rgb(0 0 0 / 70%)' + }, + layout: { + general: { + bodyBg: '#0F0F0F' + }, + sidebar: { + background: '#0F0F0F', + textColor: '#B0B5C3', + dividerBg: '#262626', + menuItemColor: '#D1D5DB', + menuItemColorActive: themeColors.primary, + menuItemBg: '#0F0F0F', + menuItemBgActive: '#3B1747', + menuItemIconColor: '#6B7280', + menuItemIconColorActive: themeColors.primary, + menuItemHeadingColor: '#E5E7EB' + } + }, + alpha: { + white: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + trueWhite: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + black: { + 5: alpha(themeColors.black, 0.02), + 10: alpha(themeColors.black, 0.1), + 30: alpha(themeColors.black, 0.3), + 50: alpha(themeColors.black, 0.5), + 70: alpha(themeColors.black, 0.7), + 100: themeColors.black + } + }, + secondary: { + lighter: lighten(themeColors.secondary, 0.85), + light: lighten(themeColors.secondary, 0.25), + main: themeColors.secondary, + dark: darken(themeColors.secondary, 0.2) + }, + primary: { + lighter: lighten(themeColors.primary, 0.85), + light: lighten(themeColors.primary, 0.3), + main: themeColors.primary, + dark: darken(themeColors.primary, 0.2) + }, + success: { + lighter: lighten(themeColors.success, 0.85), + light: lighten(themeColors.success, 0.3), + main: themeColors.success, + dark: darken(themeColors.success, 0.2) + }, + warning: { + lighter: lighten(themeColors.warning, 0.85), + light: lighten(themeColors.warning, 0.3), + main: themeColors.warning, + dark: darken(themeColors.warning, 0.2) + }, + error: { + lighter: lighten(themeColors.error, 0.85), + light: lighten(themeColors.error, 0.3), + main: themeColors.error, + dark: darken(themeColors.error, 0.2) + }, + info: { + lighter: lighten(themeColors.info, 0.85), + light: lighten(themeColors.info, 0.3), + main: themeColors.info, + dark: darken(themeColors.info, 0.2) + } +}; + +export const PureDarkTheme = createTheme({ + direction: 'ltr', + colors: { + gradients: { + blue1: colors.gradients.blue1, + blue2: colors.gradients.blue2, + blue3: colors.gradients.blue3, + blue4: colors.gradients.blue4, + blue5: colors.gradients.blue5, + orange1: colors.gradients.orange1, + orange2: colors.gradients.orange2, + orange3: colors.gradients.orange3, + purple1: colors.gradients.purple1, + purple3: colors.gradients.purple3, + pink1: colors.gradients.pink1, + pink2: colors.gradients.pink2, + green1: colors.gradients.green1, + green2: colors.gradients.green2, + black1: colors.gradients.black1, + black2: colors.gradients.black2 + }, + shadows: { + success: colors.shadows.success, + error: colors.shadows.error, + primary: colors.shadows.primary, + info: colors.shadows.info, + warning: colors.shadows.warning + }, + alpha: { + white: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + trueWhite: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + black: { + 5: alpha(themeColors.black, 0.02), + 10: alpha(themeColors.black, 0.1), + 30: alpha(themeColors.black, 0.3), + 50: alpha(themeColors.black, 0.5), + 70: alpha(themeColors.black, 0.7), + 100: themeColors.black + } + }, + secondary: { + lighter: alpha(themeColors.secondary, 0.1), + light: lighten(themeColors.secondary, 0.3), + main: themeColors.secondary, + dark: darken(themeColors.secondary, 0.2) + }, + primary: { + lighter: alpha(themeColors.primary, 0.1), + light: lighten(themeColors.primary, 0.3), + main: themeColors.primary, + dark: darken(themeColors.primary, 0.2) + }, + success: { + lighter: alpha(themeColors.success, 0.1), + light: lighten(themeColors.success, 0.3), + main: themeColors.success, + dark: darken(themeColors.success, 0.2) + }, + warning: { + lighter: alpha(themeColors.warning, 0.1), + light: lighten(themeColors.warning, 0.3), + main: themeColors.warning, + dark: darken(themeColors.warning, 0.2) + }, + error: { + lighter: alpha(themeColors.error, 0.1), + light: lighten(themeColors.error, 0.3), + main: themeColors.error, + dark: darken(themeColors.error, 0.2) + }, + info: { + lighter: alpha(themeColors.info, 0.1), + light: lighten(themeColors.info, 0.3), + main: themeColors.info, + dark: darken(themeColors.info, 0.2) + } + }, + general: { + reactFrameworkColor: '#00D8FF', + borderRadiusSm: '6px', + borderRadius: '10px', + borderRadiusLg: '12px', + borderRadiusXl: '16px' + }, + sidebar: { + background: colors.layout.sidebar.background, + textColor: colors.layout.sidebar.textColor, + dividerBg: colors.layout.sidebar.dividerBg, + menuItemColor: colors.layout.sidebar.menuItemColor, + menuItemColorActive: colors.layout.sidebar.menuItemColorActive, + menuItemBg: colors.layout.sidebar.menuItemBg, + menuItemBgActive: colors.layout.sidebar.menuItemBgActive, + menuItemIconColor: colors.layout.sidebar.menuItemIconColor, + menuItemIconColorActive: colors.layout.sidebar.menuItemIconColorActive, + menuItemHeadingColor: colors.layout.sidebar.menuItemHeadingColor, + boxShadow: + '2px 0 3px rgba(159, 162, 191, .18), 1px 0 1px rgba(159, 162, 191, 0.32)', + width: '290px' + }, + header: { + height: '80px', + background: '#1A1A1A', + boxShadow: colors.shadows.cardSm, + textColor: '#E5E7EB' + }, + spacing: 9, + palette: { + common: { + black: colors.alpha.black[100], + white: colors.alpha.white[100] + }, + mode: 'dark', + primary: { + light: colors.primary.light, + main: colors.primary.main, + dark: colors.primary.dark + }, + secondary: { + light: colors.secondary.light, + main: colors.secondary.main, + dark: colors.secondary.dark + }, + error: { + light: colors.error.light, + main: colors.error.main, + dark: colors.error.dark, + contrastText: colors.alpha.white[100] + }, + success: { + light: colors.success.light, + main: colors.success.main, + dark: colors.success.dark, + contrastText: colors.alpha.white[100] + }, + info: { + light: colors.info.light, + main: colors.info.main, + dark: colors.info.dark, + contrastText: colors.alpha.white[100] + }, + warning: { + light: colors.warning.light, + main: colors.warning.main, + dark: colors.warning.dark, + contrastText: colors.alpha.white[100] + }, + text: { + primary: '#E5E7EB', + secondary: '#9CA3AF', + disabled: '#6B7280' + }, + background: { + paper: '#1A1A1A', + default: '#0F0F0F' + }, + action: { + active: '#EC4899', + hover: alpha('#EC4899', 0.1), + hoverOpacity: 0.1, + selected: alpha('#EC4899', 0.1), + selectedOpacity: 0.1, + disabled: '#6B7280', + disabledBackground: '#262626', + disabledOpacity: 0.38, + focus: alpha('#EC4899', 0.2), + focusOpacity: 0.05, + activatedOpacity: 0.12 + }, + tonalOffset: 0.5 + }, + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 960, + lg: 1280, + xl: 1840 + } + }, + components: { + MuiBackdrop: { + styleOverrides: { + root: { + backgroundColor: alpha(darken(themeColors.primaryAlt, 0.4), 0.2), + backdropFilter: 'blur(2px)', + + '&.MuiBackdrop-invisible': { + backgroundColor: 'transparent', + backdropFilter: 'blur(2px)' + } + } + } + }, + MuiFormHelperText: { + styleOverrides: { + root: { + textTransform: 'none', + marginLeft: 8, + marginRight: 8, + fontWeight: 'bold' + } + } + }, + MuiCssBaseline: { + styleOverrides: { + 'html, body': { + width: '100%', + height: '100%' + }, + body: { + display: 'flex', + flexDirection: 'column', + minHeight: '100%', + width: '100%', + flex: 1 + }, + '#root': { + width: '100%', + height: '100%', + display: 'flex', + flex: 1, + flexDirection: 'column' + }, + html: { + display: 'flex', + flexDirection: 'column', + minHeight: '100%', + width: '100%', + MozOsxFontSmoothing: 'grayscale', + WebkitFontSmoothing: 'antialiased' + }, + '.child-popover .MuiPaper-root .MuiList-root': { + flexDirection: 'column' + }, + '#nprogress': { + pointerEvents: 'none' + }, + '#nprogress .bar': { + background: colors.primary.lighter + }, + '#nprogress .spinner-icon': { + borderTopColor: colors.primary.lighter, + borderLeftColor: colors.primary.lighter + }, + '#nprogress .peg': { + boxShadow: + '0 0 15px ' + + colors.primary.lighter + + ', 0 0 8px' + + colors.primary.light + }, + ':root': { + '--swiper-theme-color': colors.primary.main + }, + code: { + background: colors.info.lighter, + color: colors.info.dark, + borderRadius: 4, + padding: 4 + }, + '@keyframes pulse': { + '0%': { + transform: 'scale(.75)' + }, + '20%': { + transform: 'scale(1.1)' + }, + '40%': { + transform: 'scale(.75)' + }, + '60%': { + transform: 'scale(1.05)' + }, + '80%': { + transform: 'scale(.75)' + }, + '100%': { + transform: 'scale(.75)' + } + }, + '@keyframes ripple': { + '0%': { + transform: 'scale(.8)', + opacity: 1 + }, + '100%': { + transform: 'scale(2.8)', + opacity: 0 + } + }, + '@keyframes float': { + '0%': { + transform: 'translate(0%, 0%)' + }, + '100%': { + transform: 'translate(3%, 3%)' + } + } + } + }, + MuiSelect: { + styleOverrides: { + select: { + color: '#E5E7EB', + backgroundColor: '#1A1A1A', + '&:focus': { + backgroundColor: '#262626' + } + }, + iconOutlined: { + color: '#D1D5DB' + }, + icon: { + top: 'calc(50% - 14px)', + color: '#D1D5DB' + } + } + }, + MuiOutlinedInput: { + styleOverrides: { + root: { + color: '#E5E7EB', + backgroundColor: 'transparent', + '& .MuiInputAdornment-positionEnd.MuiInputAdornment-outlined': { + paddingRight: 6 + }, + '&:hover .MuiOutlinedInput-notchedOutline': { + borderColor: '#EC4899' + }, + '&.Mui-focused:hover .MuiOutlinedInput-notchedOutline': { + borderColor: '#EC4899' + }, + '& input': { + color: '#E5E7EB' + } + } + } + }, + MuiListSubheader: { + styleOverrides: { + colorPrimary: { + fontWeight: 'bold', + lineHeight: '40px', + fontSize: 13, + background: colors.alpha.black[5], + color: colors.alpha.black[70] + } + } + }, + MuiCardHeader: { + styleOverrides: { + action: { + marginTop: -5, + marginBottom: -5 + }, + title: { + fontSize: 15 + } + } + }, + MuiRadio: { + styleOverrides: { + root: { + borderRadius: '50px' + } + } + }, + MuiChip: { + styleOverrides: { + colorSecondary: { + background: colors.alpha.black[5], + color: colors.alpha.black[100], + + '&:hover': { + background: colors.alpha.black[10] + } + }, + deleteIcon: { + color: colors.error.light, + + '&:hover': { + color: colors.error.main + } + } + } + }, + MuiAccordion: { + styleOverrides: { + root: { + boxShadow: 'none', + + '&.Mui-expanded': { + margin: 0 + }, + '&::before': { + display: 'none' + } + } + } + }, + MuiAvatar: { + styleOverrides: { + root: { + fontSize: 14, + fontWeight: 'bold' + }, + colorDefault: { + background: colors.alpha.black[30], + color: colors.alpha.white[100] + } + } + }, + MuiAvatarGroup: { + styleOverrides: { + root: { + alignItems: 'center' + }, + avatar: { + background: colors.alpha.black[10], + fontSize: 13, + color: colors.alpha.black[70], + fontWeight: 'bold', + + '&:first-of-type': { + border: 0, + background: 'transparent' + } + } + } + }, + MuiListItemAvatar: { + styleOverrides: { + alignItemsFlexStart: { + marginTop: 0 + } + } + }, + MuiPaginationItem: { + styleOverrides: { + page: { + fontSize: 13, + fontWeight: 'bold', + transition: 'all .2s' + }, + textPrimary: { + '&.Mui-selected': { + boxShadow: colors.shadows.primary + }, + '&.MuiButtonBase-root:hover': { + background: colors.alpha.black[5] + }, + '&.Mui-selected.MuiButtonBase-root:hover': { + background: colors.primary.main + } + } + } + }, + MuiButton: { + defaultProps: { + disableRipple: true + }, + styleOverrides: { + root: { + fontWeight: 'bold', + textTransform: 'none', + paddingLeft: 16, + paddingRight: 16, + + '.MuiSvgIcon-root': { + transition: 'all .2s' + } + }, + endIcon: { + marginRight: -8 + }, + containedSecondary: { + backgroundColor: colors.secondary.main, + color: colors.alpha.white[100], + border: '1px solid ' + colors.alpha.black[30] + }, + outlinedSecondary: { + backgroundColor: colors.alpha.white[100], + + '&:hover, &.MuiSelected': { + backgroundColor: colors.alpha.black[5], + color: colors.alpha.black[100] + } + }, + sizeSmall: { + padding: '6px 16px', + lineHeight: 1.5 + }, + sizeMedium: { + padding: '8px 20px' + }, + sizeLarge: { + padding: '11px 24px' + }, + textSizeSmall: { + padding: '7px 12px' + }, + textSizeMedium: { + padding: '9px 16px' + }, + textSizeLarge: { + padding: '12px 16px' + } + } + }, + MuiButtonBase: { + defaultProps: { + disableRipple: false + }, + styleOverrides: { + root: { + borderRadius: 6 + } + } + }, + MuiToggleButton: { + defaultProps: { + disableRipple: true + }, + styleOverrides: { + root: { + color: colors.primary.main, + background: colors.alpha.white[100], + transition: 'all .2s', + + '&:hover, &.Mui-selected, &.Mui-selected:hover': { + color: colors.alpha.white[100], + background: colors.primary.main + } + } + } + }, + MuiIconButton: { + styleOverrides: { + root: { + borderRadius: 8, + padding: 8, + + '& .MuiTouchRipple-root': { + borderRadius: 8 + } + }, + sizeSmall: { + padding: 4 + } + } + }, + MuiListItemText: { + styleOverrides: { + root: { + margin: 0, + color: '#E5E7EB' + }, + primary: { + color: '#E5E7EB' + }, + secondary: { + color: '#D1D5DB' + } + } + }, + MuiListItemButton: { + styleOverrides: { + root: { + backgroundColor: '#1A1A1A', + color: '#E5E7EB', + '& .MuiTouchRipple-root': { + opacity: 0.3 + }, + '&:hover': { + backgroundColor: '#262626' + }, + '&.Mui-selected': { + backgroundColor: '#EC4899', + color: '#ffffff', + '&:hover': { + backgroundColor: '#EC4899' + } + }, + '& .MuiTypography-root': { + color: '#E5E7EB' + } + } + } + }, + MuiDivider: { + styleOverrides: { + root: { + background: colors.alpha.black[10], + border: 0, + height: 1 + }, + vertical: { + height: 'auto', + width: 1, + + '&.MuiDivider-flexItem.MuiDivider-fullWidth': { + height: 'auto' + }, + '&.MuiDivider-absolute.MuiDivider-fullWidth': { + height: '100%' + } + }, + withChildren: { + '&:before, &:after': { + border: 0 + } + }, + wrapper: { + background: colors.alpha.white[100], + fontWeight: 'bold', + height: 24, + lineHeight: '24px', + marginTop: -12, + color: 'inherit', + textTransform: 'uppercase' + } + } + }, + MuiPaper: { + styleOverrides: { + root: { + padding: 0, + backgroundColor: '#1A1A1A' + }, + elevation0: { + boxShadow: 'none' + }, + elevation: { + boxShadow: colors.shadows.card, + backgroundColor: '#1A1A1A' + }, + elevation2: { + boxShadow: colors.shadows.cardSm, + backgroundColor: '#1A1A1A' + }, + elevation24: { + boxShadow: colors.shadows.cardLg, + backgroundColor: '#1A1A1A' + }, + outlined: { + boxShadow: colors.shadows.card, + backgroundColor: '#1A1A1A' + } + } + }, + MuiLink: { + defaultProps: { + underline: 'hover' + } + }, + MuiLinearProgress: { + styleOverrides: { + root: { + borderRadius: 6, + height: 6 + } + } + }, + MuiSlider: { + styleOverrides: { + root: { + '& .MuiSlider-valueLabelCircle, .MuiSlider-valueLabelLabel': { + transform: 'none' + }, + '& .MuiSlider-valueLabel': { + borderRadius: 6, + background: colors.alpha.black[100], + color: colors.alpha.white[100] + } + } + } + }, + MuiList: { + styleOverrides: { + root: { + padding: 0, + color: '#E5E7EB', + + '& .MuiListItem-button': { + transition: 'all .2s', + color: '#E5E7EB', + + '& > .MuiSvgIcon-root': { + minWidth: 34 + }, + + '& .MuiTouchRipple-root': { + opacity: 0.2 + } + }, + '& .MuiListItem-root.MuiButtonBase-root.Mui-selected': { + backgroundColor: '#EC4899', + color: '#ffffff' + }, + '& .MuiMenuItem-root.MuiButtonBase-root:active': { + backgroundColor: '#EC4899', + color: '#ffffff' + }, + '& .MuiMenuItem-root.MuiButtonBase-root .MuiTouchRipple-root': { + opacity: 0.2 + } + }, + padding: { + padding: '12px', + + '& .MuiListItem-button': { + borderRadius: 6, + margin: '1px 0' + } + } + } + }, + MuiTabs: { + styleOverrides: { + root: { + height: 38, + minHeight: 38, + overflow: 'visible' + }, + indicator: { + height: 38, + minHeight: 38, + borderRadius: 6, + border: '1px solid ' + colors.primary.dark, + boxShadow: '0px 2px 10px ' + colors.primary.light + }, + scrollableX: { + overflow: 'visible !important' + } + } + }, + MuiTab: { + styleOverrides: { + root: { + padding: 0, + height: 38, + minHeight: 38, + borderRadius: 6, + transition: 'color .2s', + textTransform: 'capitalize', + + '&.MuiButtonBase-root': { + minWidth: 'auto', + paddingLeft: 20, + paddingRight: 20, + marginRight: 4 + }, + '&.Mui-selected, &.Mui-selected:hover': { + color: colors.alpha.white[100], + zIndex: 5 + }, + '&:hover': { + color: colors.alpha.black[100] + } + } + } + }, + MuiMenu: { + styleOverrides: { + paper: { + padding: 12 + }, + list: { + padding: 12, + + '& .MuiMenuItem-root.MuiButtonBase-root': { + fontSize: 14, + marginTop: 1, + marginBottom: 1, + transition: 'all .2s', + color: colors.alpha.black[70], + + '& .MuiTouchRipple-root': { + opacity: 0.2 + }, + + '&:hover, &:active, &.active, &.Mui-selected': { + color: colors.alpha.black[100], + background: alpha(colors.primary.lighter, 0.4) + } + } + } + } + }, + MuiMenuItem: { + styleOverrides: { + root: { + background: 'transparent', + color: '#D1D5DB', + transition: 'all .2s', + + '&:hover, &:active, &.active, &.Mui-selected': { + color: '#E5E7EB', + background: '#EC4899' + }, + '&.Mui-selected:hover': { + background: '#EC4899' + } + } + } + }, + MuiListItem: { + styleOverrides: { + root: { + '&.MuiButtonBase-root': { + color: colors.secondary.main, + + '&:hover, &:active, &.active, &.Mui-selected': { + color: colors.alpha.black[100], + background: lighten(colors.primary.lighter, 0.5) + } + } + } + } + }, + MuiAutocomplete: { + styleOverrides: { + tag: { + margin: 1 + }, + root: { + '.MuiAutocomplete-inputRoot.MuiOutlinedInput-root .MuiAutocomplete-endAdornment': + { + right: 14 + } + }, + clearIndicator: { + background: colors.error.lighter, + color: colors.error.main, + marginRight: 8, + + '&:hover': { + background: colors.error.lighter, + color: colors.error.dark + } + }, + popupIndicator: { + color: colors.alpha.black[50], + + '&:hover': { + background: colors.primary.lighter, + color: colors.primary.main + } + } + } + }, + MuiTablePagination: { + styleOverrides: { + toolbar: { + '& .MuiIconButton-root': { + padding: 8 + } + }, + select: { + '&:focus': { + backgroundColor: 'transparent' + } + } + } + }, + MuiToolbar: { + styleOverrides: { + root: { + minHeight: '0 !important', + padding: '0 !important' + } + } + }, + MuiTableRow: { + styleOverrides: { + head: { + background: '#262626' + }, + root: { + transition: 'background-color .2s', + + '&.MuiTableRow-hover:hover': { + backgroundColor: '#1A1A1A' + } + } + } + }, + MuiTableCell: { + styleOverrides: { + root: { + borderBottomColor: '#3B3B3B', + fontSize: 14, + color: '#E5E7EB', + '&.MuiTableCell-head': { + backgroundColor: '#1A1A1A !important', + color: '#E5E7EB !important' + } + }, + head: { + textTransform: 'uppercase', + fontSize: 13, + fontWeight: 'bold', + color: '#E5E7EB', + backgroundColor: '#1A1A1A' + }, + stickyHeader: { + backgroundColor: '#1A1A1A !important', + color: '#E5E7EB !important' + } + } + }, + MuiAlert: { + styleOverrides: { + message: { + lineHeight: 1.5, + fontSize: 14 + }, + standardInfo: { + color: colors.info.main + }, + action: { + color: colors.alpha.black[70] + } + } + }, + MuiTimelineDot: { + styleOverrides: { + root: { + margin: 0, + zIndex: 5, + position: 'absolute', + top: '50%', + marginTop: -6, + left: -6 + }, + outlined: { + backgroundColor: colors.alpha.white[100], + boxShadow: '0 0 0 6px ' + colors.alpha.white[100] + }, + outlinedPrimary: { + backgroundColor: colors.alpha.white[100], + boxShadow: '0 0 0 6px ' + colors.alpha.white[100] + } + } + }, + MuiTimelineConnector: { + styleOverrides: { + root: { + position: 'absolute', + height: '100%', + top: 0, + borderRadius: 50, + backgroundColor: colors.alpha.black[10] + } + } + }, + MuiTimelineItem: { + styleOverrides: { + root: { + minHeight: 0, + padding: '8px 0', + + '&:before': { + display: 'none' + } + }, + missingOppositeContent: { + '&:before': { + display: 'none' + } + } + } + }, + MuiTooltip: { + styleOverrides: { + tooltip: { + backgroundColor: alpha(colors.alpha.black['100'], 0.95), + padding: '8px 16px', + fontSize: 13 + }, + arrow: { + color: alpha(colors.alpha.black['100'], 0.95) + } + } + }, + MuiSwitch: { + styleOverrides: { + root: { + height: 33, + overflow: 'visible', + + '& .MuiButtonBase-root': { + position: 'absolute', + padding: 6, + transition: + 'left 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,transform 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms' + }, + '& .MuiIconButton-root': { + borderRadius: 100 + }, + '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': { + opacity: 0.3 + } + }, + thumb: { + border: '1px solid ' + colors.alpha.black[30], + boxShadow: + '0px 9px 14px ' + + colors.alpha.black[10] + + ', 0px 2px 2px ' + + colors.alpha.black[10] + }, + track: { + backgroundColor: colors.alpha.black[5], + border: '1px solid ' + colors.alpha.black[10], + boxShadow: 'inset 0px 1px 1px ' + colors.alpha.black[10], + opacity: 1 + }, + colorPrimary: { + '& .MuiSwitch-thumb': { + backgroundColor: colors.alpha.white[100] + }, + + '&.Mui-checked .MuiSwitch-thumb': { + backgroundColor: colors.primary.main + } + } + } + }, + MuiStepper: { + styleOverrides: { + root: { + paddingTop: 20, + paddingBottom: 20, + background: colors.alpha.black[5] + } + } + }, + MuiStepIcon: { + styleOverrides: { + root: { + '&.MuiStepIcon-completed': { + color: colors.success.main + } + } + } + }, + MuiDrawer: { + styleOverrides: { + paper: { + backgroundColor: '#0F0F0F !important', + backgroundImage: 'none !important', + color: '#E5E7EB', + '& .MuiButton-textPrimary': { + color: '#E5E7EB', + '&:hover': { + backgroundColor: '#262626' + } + }, + '& .MuiSvgIcon-root': { + color: '#D1D5DB' + } + } + } + }, + MuiTypography: { + defaultProps: { + variantMapping: { + h1: 'h1', + h2: 'h2', + h3: 'div', + h4: 'div', + h5: 'div', + h6: 'div', + subtitle1: 'div', + subtitle2: 'div', + body1: 'div', + body2: 'div' + } + }, + styleOverrides: { + gutterBottom: { + marginBottom: 4 + }, + paragraph: { + fontSize: 17, + lineHeight: 1.7 + }, + h1: { + color: '#E5E7EB' + }, + h2: { + color: '#E5E7EB' + }, + h3: { + color: '#E5E7EB' + }, + h4: { + color: '#D1D5DB' + }, + h5: { + color: '#D1D5DB' + }, + h6: { + color: '#E2E8F0 !important' + }, + subtitle1: { + color: '#D1D5DB' + }, + subtitle2: { + color: '#D1D5DB' + }, + body1: { + color: '#E5E7EB !important' + }, + body2: { + color: '#D1D5DB' + }, + caption: { + color: '#9CA3AF' + } + } + } + }, + shape: { + borderRadius: 10 + }, + typography: { + fontFamily: + '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"', + h1: { + fontWeight: 700, + fontSize: 35, + color: '#E5E7EB' + }, + h2: { + fontWeight: 700, + fontSize: 30, + color: '#E5E7EB' + }, + h3: { + fontWeight: 700, + fontSize: 25, + lineHeight: 1.4, + color: '#E5E7EB' + }, + h4: { + fontWeight: 700, + fontSize: 16, + color: '#D1D5DB' + }, + h5: { + fontWeight: 700, + fontSize: 14, + color: '#D1D5DB' + }, + h6: { + fontSize: 15, + color: '#E2E8F0' + }, + body1: { + fontSize: 14 + }, + body2: { + fontSize: 14 + }, + button: { + fontWeight: 600 + }, + caption: { + fontSize: 13, + textTransform: 'uppercase', + color: colors.alpha.black[50] + }, + subtitle1: { + fontSize: 14, + color: colors.alpha.black[70] + }, + subtitle2: { + fontWeight: 400, + fontSize: 15, + color: colors.alpha.black[70] + }, + overline: { + fontSize: 13, + fontWeight: 700, + textTransform: 'uppercase' + } + }, + shadows: [ + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none' + ] +}); diff --git a/frontend/src/theme/schemes/SkyView.ts b/frontend/src/theme/schemes/SkyView.ts new file mode 100644 index 000000000..46870174d --- /dev/null +++ b/frontend/src/theme/schemes/SkyView.ts @@ -0,0 +1,1302 @@ +import { alpha, createTheme, lighten, darken } from '@mui/material'; +import '@mui/lab/themeAugmentation'; +import { customColors } from '../../config'; + +const themeColors = { + primary: '#0EA5E9', + secondary: '#06B6D4', + success: '#10B981', + warning: '#F59E0B', + error: '#EF4444', + info: '#8B5CF6', + black: '#0F172A', + white: '#ffffff', + primaryAlt: '#0284C7', + ...customColors +}; + +const colors = { + gradients: { + blue1: 'linear-gradient(135deg, #6B73FF 0%, #000DFF 100%)', + blue2: 'linear-gradient(135deg, #ABDCFF 0%, #0396FF 100%)', + blue3: 'linear-gradient(127.55deg, #141E30 3.73%, #243B55 92.26%)', + blue4: 'linear-gradient(-20deg, #2b5876 0%, #4e4376 100%)', + blue5: 'linear-gradient(135deg, #97ABFF 10%, #123597 100%)', + orange1: 'linear-gradient(135deg, #FCCF31 0%, #F55555 100%)', + orange2: 'linear-gradient(135deg, #FFD3A5 0%, #FD6585 100%)', + orange3: 'linear-gradient(120deg, #f6d365 0%, #fda085 100%)', + purple1: 'linear-gradient(135deg, #43CBFF 0%, #9708CC 100%)', + purple3: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', + pink1: 'linear-gradient(135deg, #F6CEEC 0%, #D939CD 100%)', + pink2: 'linear-gradient(135deg, #F761A1 0%, #8C1BAB 100%)', + green1: 'linear-gradient(135deg, #FFF720 0%, #3CD500 100%)', + green2: 'linear-gradient(to bottom, #00b09b, #96c93d)', + black1: 'linear-gradient(100.66deg, #434343 6.56%, #000000 93.57%)', + black2: 'linear-gradient(60deg, #29323c 0%, #485563 100%)' + }, + shadows: { + success: + '0px 1px 4px rgba(68, 214, 0, 0.25), 0px 3px 12px 2px rgba(68, 214, 0, 0.35)', + error: + '0px 1px 4px rgba(255, 25, 67, 0.25), 0px 3px 12px 2px rgba(255, 25, 67, 0.35)', + info: '0px 1px 4px rgba(51, 194, 255, 0.25), 0px 3px 12px 2px rgba(51, 194, 255, 0.35)', + primary: + '0px 1px 4px rgba(85, 105, 255, 0.25), 0px 3px 12px 2px rgba(85, 105, 255, 0.35)', + warning: + '0px 1px 4px rgba(255, 163, 25, 0.25), 0px 3px 12px 2px rgba(255, 163, 25, 0.35)', + card: '0px 9px 16px rgba(159, 162, 191, .18), 0px 2px 2px rgba(159, 162, 191, 0.32)', + cardSm: + '0px 2px 3px rgba(159, 162, 191, .18), 0px 1px 1px rgba(159, 162, 191, 0.32)', + cardLg: + '0 5rem 14rem 0 rgb(255 255 255 / 30%), 0 0.8rem 2.3rem rgb(0 0 0 / 60%), 0 0.2rem 0.3rem rgb(0 0 0 / 45%)' + }, + layout: { + general: { + bodyBg: '#f2f5f9' + }, + sidebar: { + background: themeColors.white, + textColor: themeColors.secondary, + dividerBg: '#f2f5f9', + menuItemColor: '#242E6F', + menuItemColorActive: themeColors.primary, + menuItemBg: themeColors.white, + menuItemBgActive: '#f2f5f9', + menuItemIconColor: lighten(themeColors.secondary, 0.3), + menuItemIconColorActive: themeColors.primary, + menuItemHeadingColor: darken(themeColors.secondary, 0.3) + } + }, + alpha: { + white: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + trueWhite: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + black: { + 5: alpha(themeColors.black, 0.02), + 10: alpha(themeColors.black, 0.1), + 30: alpha(themeColors.black, 0.3), + 50: alpha(themeColors.black, 0.5), + 70: alpha(themeColors.black, 0.7), + 100: themeColors.black + } + }, + secondary: { + lighter: lighten(themeColors.secondary, 0.85), + light: lighten(themeColors.secondary, 0.25), + main: themeColors.secondary, + dark: darken(themeColors.secondary, 0.2) + }, + primary: { + lighter: lighten(themeColors.primary, 0.85), + light: lighten(themeColors.primary, 0.3), + main: themeColors.primary, + dark: darken(themeColors.primary, 0.2) + }, + success: { + lighter: lighten(themeColors.success, 0.85), + light: lighten(themeColors.success, 0.3), + main: themeColors.success, + dark: darken(themeColors.success, 0.2) + }, + warning: { + lighter: lighten(themeColors.warning, 0.85), + light: lighten(themeColors.warning, 0.3), + main: themeColors.warning, + dark: darken(themeColors.warning, 0.2) + }, + error: { + lighter: lighten(themeColors.error, 0.85), + light: lighten(themeColors.error, 0.3), + main: themeColors.error, + dark: darken(themeColors.error, 0.2) + }, + info: { + lighter: lighten(themeColors.info, 0.85), + light: lighten(themeColors.info, 0.3), + main: themeColors.info, + dark: darken(themeColors.info, 0.2) + } +}; + +export const SkyView = createTheme({ + direction: 'ltr', + colors: { + gradients: { + blue1: colors.gradients.blue1, + blue2: colors.gradients.blue2, + blue3: colors.gradients.blue3, + blue4: colors.gradients.blue4, + blue5: colors.gradients.blue5, + orange1: colors.gradients.orange1, + orange2: colors.gradients.orange2, + orange3: colors.gradients.orange3, + purple1: colors.gradients.purple1, + purple3: colors.gradients.purple3, + pink1: colors.gradients.pink1, + pink2: colors.gradients.pink2, + green1: colors.gradients.green1, + green2: colors.gradients.green2, + black1: colors.gradients.black1, + black2: colors.gradients.black2 + }, + shadows: { + success: colors.shadows.success, + error: colors.shadows.error, + primary: colors.shadows.primary, + info: colors.shadows.info, + warning: colors.shadows.warning + }, + alpha: { + white: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + trueWhite: { + 5: alpha(themeColors.white, 0.02), + 10: alpha(themeColors.white, 0.1), + 30: alpha(themeColors.white, 0.3), + 50: alpha(themeColors.white, 0.5), + 70: alpha(themeColors.white, 0.7), + 100: themeColors.white + }, + black: { + 5: alpha(themeColors.black, 0.02), + 10: alpha(themeColors.black, 0.1), + 30: alpha(themeColors.black, 0.3), + 50: alpha(themeColors.black, 0.5), + 70: alpha(themeColors.black, 0.7), + 100: themeColors.black + } + }, + secondary: { + lighter: alpha(themeColors.secondary, 0.1), + light: lighten(themeColors.secondary, 0.3), + main: themeColors.secondary, + dark: darken(themeColors.secondary, 0.2) + }, + primary: { + lighter: alpha(themeColors.primary, 0.1), + light: lighten(themeColors.primary, 0.3), + main: themeColors.primary, + dark: darken(themeColors.primary, 0.2) + }, + success: { + lighter: alpha(themeColors.success, 0.1), + light: lighten(themeColors.success, 0.3), + main: themeColors.success, + dark: darken(themeColors.success, 0.2) + }, + warning: { + lighter: alpha(themeColors.warning, 0.1), + light: lighten(themeColors.warning, 0.3), + main: themeColors.warning, + dark: darken(themeColors.warning, 0.2) + }, + error: { + lighter: alpha(themeColors.error, 0.1), + light: lighten(themeColors.error, 0.3), + main: themeColors.error, + dark: darken(themeColors.error, 0.2) + }, + info: { + lighter: alpha(themeColors.info, 0.1), + light: lighten(themeColors.info, 0.3), + main: themeColors.info, + dark: darken(themeColors.info, 0.2) + } + }, + general: { + reactFrameworkColor: '#00D8FF', + borderRadiusSm: '6px', + borderRadius: '10px', + borderRadiusLg: '12px', + borderRadiusXl: '16px' + }, + sidebar: { + background: colors.layout.sidebar.background, + textColor: colors.layout.sidebar.textColor, + dividerBg: colors.layout.sidebar.dividerBg, + menuItemColor: colors.layout.sidebar.menuItemColor, + menuItemColorActive: colors.layout.sidebar.menuItemColorActive, + menuItemBg: colors.layout.sidebar.menuItemBg, + menuItemBgActive: colors.layout.sidebar.menuItemBgActive, + menuItemIconColor: colors.layout.sidebar.menuItemIconColor, + menuItemIconColorActive: colors.layout.sidebar.menuItemIconColorActive, + menuItemHeadingColor: colors.layout.sidebar.menuItemHeadingColor, + boxShadow: + '2px 0 3px rgba(159, 162, 191, .18), 1px 0 1px rgba(159, 162, 191, 0.32)', + width: '290px' + }, + header: { + height: '80px', + background: colors.alpha.white[100], + boxShadow: colors.shadows.cardSm, + textColor: colors.secondary.main + }, + spacing: 9, + palette: { + common: { + black: colors.alpha.black[100], + white: colors.alpha.white[100] + }, + mode: 'light', + primary: { + light: colors.primary.light, + main: colors.primary.main, + dark: colors.primary.dark + }, + secondary: { + light: colors.secondary.light, + main: colors.secondary.main, + dark: colors.secondary.dark + }, + error: { + light: colors.error.light, + main: colors.error.main, + dark: colors.error.dark, + contrastText: colors.alpha.white[100] + }, + success: { + light: colors.success.light, + main: colors.success.main, + dark: colors.success.dark, + contrastText: colors.alpha.white[100] + }, + info: { + light: colors.info.light, + main: colors.info.main, + dark: colors.info.dark, + contrastText: colors.alpha.white[100] + }, + warning: { + light: colors.warning.light, + main: colors.warning.main, + dark: colors.warning.dark, + contrastText: colors.alpha.white[100] + }, + text: { + primary: colors.alpha.black[100], + secondary: colors.alpha.black[70], + disabled: colors.alpha.black[50] + }, + background: { + paper: colors.alpha.white[100], + default: colors.layout.general.bodyBg + }, + action: { + active: colors.alpha.black[100], + hover: colors.primary.lighter, + hoverOpacity: 0.1, + selected: colors.alpha.black[10], + selectedOpacity: 0.1, + disabled: colors.alpha.black[50], + disabledBackground: colors.alpha.black[5], + disabledOpacity: 0.38, + focus: colors.alpha.black[10], + focusOpacity: 0.05, + activatedOpacity: 0.12 + }, + tonalOffset: 0.5 + }, + breakpoints: { + values: { + xs: 0, + sm: 600, + md: 960, + lg: 1280, + xl: 1840 + } + }, + components: { + MuiBackdrop: { + styleOverrides: { + root: { + backgroundColor: alpha(darken(themeColors.primaryAlt, 0.4), 0.2), + backdropFilter: 'blur(2px)', + + '&.MuiBackdrop-invisible': { + backgroundColor: 'transparent', + backdropFilter: 'blur(2px)' + } + } + } + }, + MuiFormHelperText: { + styleOverrides: { + root: { + textTransform: 'none', + marginLeft: 8, + marginRight: 8, + fontWeight: 'bold' + } + } + }, + MuiCssBaseline: { + styleOverrides: { + 'html, body': { + width: '100%', + height: '100%' + }, + body: { + display: 'flex', + flexDirection: 'column', + minHeight: '100%', + width: '100%', + flex: 1 + }, + '#root': { + width: '100%', + height: '100%', + display: 'flex', + flex: 1, + flexDirection: 'column' + }, + html: { + display: 'flex', + flexDirection: 'column', + minHeight: '100%', + width: '100%', + MozOsxFontSmoothing: 'grayscale', + WebkitFontSmoothing: 'antialiased' + }, + '.child-popover .MuiPaper-root .MuiList-root': { + flexDirection: 'column' + }, + '#nprogress': { + pointerEvents: 'none' + }, + '#nprogress .bar': { + background: colors.primary.lighter + }, + '#nprogress .spinner-icon': { + borderTopColor: colors.primary.lighter, + borderLeftColor: colors.primary.lighter + }, + '#nprogress .peg': { + boxShadow: + '0 0 15px ' + + colors.primary.lighter + + ', 0 0 8px' + + colors.primary.light + }, + ':root': { + '--swiper-theme-color': colors.primary.main + }, + code: { + background: colors.info.lighter, + color: colors.info.dark, + borderRadius: 4, + padding: 4 + }, + '@keyframes pulse': { + '0%': { + transform: 'scale(.75)' + }, + '20%': { + transform: 'scale(1.1)' + }, + '40%': { + transform: 'scale(.75)' + }, + '60%': { + transform: 'scale(1.05)' + }, + '80%': { + transform: 'scale(.75)' + }, + '100%': { + transform: 'scale(.75)' + } + }, + '@keyframes ripple': { + '0%': { + transform: 'scale(.8)', + opacity: 1 + }, + '100%': { + transform: 'scale(2.8)', + opacity: 0 + } + }, + '@keyframes float': { + '0%': { + transform: 'translate(0%, 0%)' + }, + '100%': { + transform: 'translate(3%, 3%)' + } + } + } + }, + MuiSelect: { + styleOverrides: { + iconOutlined: { + color: themeColors.black + }, + icon: { + top: 'calc(50% - 14px)', + color: themeColors.black + } + } + }, + MuiOutlinedInput: { + styleOverrides: { + root: { + color: themeColors.black, + backgroundColor: 'transparent', + '& .MuiInputAdornment-positionEnd.MuiInputAdornment-outlined': { + paddingRight: 6 + }, + '&:hover .MuiOutlinedInput-notchedOutline': { + borderColor: colors.primary.main + }, + '&.Mui-focused:hover .MuiOutlinedInput-notchedOutline': { + borderColor: colors.primary.main + }, + '& input': { + color: themeColors.black + } + } + } + }, + MuiListSubheader: { + styleOverrides: { + colorPrimary: { + fontWeight: 'bold', + lineHeight: '40px', + fontSize: 13, + background: colors.alpha.black[5], + color: colors.alpha.black[70] + } + } + }, + MuiCardHeader: { + styleOverrides: { + action: { + marginTop: -5, + marginBottom: -5 + }, + title: { + fontSize: 15 + } + } + }, + MuiRadio: { + styleOverrides: { + root: { + borderRadius: '50px' + } + } + }, + MuiChip: { + styleOverrides: { + colorSecondary: { + background: colors.alpha.black[5], + color: colors.alpha.black[100], + + '&:hover': { + background: colors.alpha.black[10] + } + }, + deleteIcon: { + color: colors.error.light, + + '&:hover': { + color: colors.error.main + } + } + } + }, + MuiAccordion: { + styleOverrides: { + root: { + boxShadow: 'none', + + '&.Mui-expanded': { + margin: 0 + }, + '&::before': { + display: 'none' + } + } + } + }, + MuiAvatar: { + styleOverrides: { + root: { + fontSize: 14, + fontWeight: 'bold' + }, + colorDefault: { + background: colors.alpha.black[30], + color: colors.alpha.white[100] + } + } + }, + MuiAvatarGroup: { + styleOverrides: { + root: { + alignItems: 'center' + }, + avatar: { + background: colors.alpha.black[10], + fontSize: 13, + color: colors.alpha.black[70], + fontWeight: 'bold', + + '&:first-of-type': { + border: 0, + background: 'transparent' + } + } + } + }, + MuiListItemAvatar: { + styleOverrides: { + alignItemsFlexStart: { + marginTop: 0 + } + } + }, + MuiPaginationItem: { + styleOverrides: { + page: { + fontSize: 13, + fontWeight: 'bold', + transition: 'all .2s' + }, + textPrimary: { + '&.Mui-selected': { + boxShadow: colors.shadows.primary + }, + '&.MuiButtonBase-root:hover': { + background: colors.alpha.black[5] + }, + '&.Mui-selected.MuiButtonBase-root:hover': { + background: colors.primary.main + } + } + } + }, + MuiButton: { + defaultProps: { + disableRipple: true + }, + styleOverrides: { + root: { + fontWeight: 'bold', + textTransform: 'none', + paddingLeft: 16, + paddingRight: 16, + + '.MuiSvgIcon-root': { + transition: 'all .2s' + } + }, + endIcon: { + marginRight: -8 + }, + containedSecondary: { + backgroundColor: colors.secondary.main, + color: colors.alpha.white[100], + border: '1px solid ' + colors.alpha.black[30] + }, + outlinedSecondary: { + backgroundColor: colors.alpha.white[100], + + '&:hover, &.MuiSelected': { + backgroundColor: colors.alpha.black[5], + color: colors.alpha.black[100] + } + }, + sizeSmall: { + padding: '6px 16px', + lineHeight: 1.5 + }, + sizeMedium: { + padding: '8px 20px' + }, + sizeLarge: { + padding: '11px 24px' + }, + textSizeSmall: { + padding: '7px 12px' + }, + textSizeMedium: { + padding: '9px 16px' + }, + textSizeLarge: { + padding: '12px 16px' + } + } + }, + MuiButtonBase: { + defaultProps: { + disableRipple: false + }, + styleOverrides: { + root: { + borderRadius: 6 + } + } + }, + MuiToggleButton: { + defaultProps: { + disableRipple: true + }, + styleOverrides: { + root: { + color: colors.primary.main, + background: colors.alpha.white[100], + transition: 'all .2s', + + '&:hover, &.Mui-selected, &.Mui-selected:hover': { + color: colors.alpha.white[100], + background: colors.primary.main + } + } + } + }, + MuiIconButton: { + styleOverrides: { + root: { + borderRadius: 8, + padding: 8, + + '& .MuiTouchRipple-root': { + borderRadius: 8 + } + }, + sizeSmall: { + padding: 4 + } + } + }, + MuiListItemText: { + styleOverrides: { + root: { + margin: 0, + color: themeColors.black + }, + primary: { + color: themeColors.black + }, + secondary: { + color: themeColors.black + } + } + }, + MuiListItemButton: { + styleOverrides: { + root: { + '& .MuiTouchRipple-root': { + opacity: 0.3 + } + } + } + }, + MuiDivider: { + styleOverrides: { + root: { + background: colors.alpha.black[10], + border: 0, + height: 1 + }, + vertical: { + height: 'auto', + width: 1, + + '&.MuiDivider-flexItem.MuiDivider-fullWidth': { + height: 'auto' + }, + '&.MuiDivider-absolute.MuiDivider-fullWidth': { + height: '100%' + } + }, + withChildren: { + '&:before, &:after': { + border: 0 + } + }, + wrapper: { + background: colors.alpha.white[100], + fontWeight: 'bold', + height: 24, + lineHeight: '24px', + marginTop: -12, + color: 'inherit', + textTransform: 'uppercase' + } + } + }, + MuiPaper: { + styleOverrides: { + root: { + padding: 0, + backgroundColor: colors.alpha.white[100] + }, + elevation0: { + boxShadow: 'none' + }, + elevation: { + boxShadow: colors.shadows.card, + backgroundColor: colors.alpha.white[100] + }, + elevation2: { + boxShadow: colors.shadows.cardSm, + backgroundColor: colors.alpha.white[100] + }, + elevation24: { + boxShadow: colors.shadows.cardLg, + backgroundColor: colors.alpha.white[100] + }, + outlined: { + boxShadow: colors.shadows.card, + backgroundColor: colors.alpha.white[100] + } + } + }, + MuiLink: { + defaultProps: { + underline: 'hover' + } + }, + MuiLinearProgress: { + styleOverrides: { + root: { + borderRadius: 6, + height: 6 + } + } + }, + MuiSlider: { + styleOverrides: { + root: { + '& .MuiSlider-valueLabelCircle, .MuiSlider-valueLabelLabel': { + transform: 'none' + }, + '& .MuiSlider-valueLabel': { + borderRadius: 6, + background: colors.alpha.black[100], + color: colors.alpha.white[100] + } + } + } + }, + MuiList: { + styleOverrides: { + root: { + padding: 0, + color: themeColors.black, + + '& .MuiListItem-button': { + transition: 'all .2s', + color: themeColors.black, + + '& > .MuiSvgIcon-root': { + minWidth: 34 + }, + + '& .MuiTouchRipple-root': { + opacity: 0.2 + } + }, + '& .MuiListItem-root.MuiButtonBase-root.Mui-selected': { + backgroundColor: alpha(colors.primary.lighter, 0.4), + color: colors.alpha.white[100] + }, + '& .MuiMenuItem-root.MuiButtonBase-root:active': { + backgroundColor: alpha(colors.primary.lighter, 0.4), + color: colors.alpha.white[100] + }, + '& .MuiMenuItem-root.MuiButtonBase-root .MuiTouchRipple-root': { + opacity: 0.2 + } + }, + padding: { + padding: '12px', + + '& .MuiListItem-button': { + borderRadius: 6, + margin: '1px 0' + } + } + } + }, + MuiTabs: { + styleOverrides: { + root: { + height: 38, + minHeight: 38, + overflow: 'visible' + }, + indicator: { + height: 38, + minHeight: 38, + borderRadius: 6, + border: '1px solid ' + colors.primary.dark, + boxShadow: '0px 2px 10px ' + colors.primary.light + }, + scrollableX: { + overflow: 'visible !important' + } + } + }, + MuiTab: { + styleOverrides: { + root: { + padding: 0, + height: 38, + minHeight: 38, + borderRadius: 6, + transition: 'color .2s', + textTransform: 'capitalize', + + '&.MuiButtonBase-root': { + minWidth: 'auto', + paddingLeft: 20, + paddingRight: 20, + marginRight: 4 + }, + '&.Mui-selected, &.Mui-selected:hover': { + color: colors.alpha.white[100], + zIndex: 5 + }, + '&:hover': { + color: colors.alpha.black[100] + } + } + } + }, + MuiMenu: { + styleOverrides: { + paper: { + padding: 12 + }, + list: { + padding: 12, + + '& .MuiMenuItem-root.MuiButtonBase-root': { + fontSize: 14, + marginTop: 1, + marginBottom: 1, + transition: 'all .2s', + color: colors.alpha.black[70], + + '& .MuiTouchRipple-root': { + opacity: 0.2 + }, + + '&:hover, &:active, &.active, &.Mui-selected': { + color: colors.alpha.black[100], + background: alpha(colors.primary.lighter, 0.4) + } + } + } + } + }, + MuiMenuItem: { + styleOverrides: { + root: { + background: 'transparent', + color: themeColors.black, + transition: 'all .2s', + + '&:hover, &:active, &.active, &.Mui-selected': { + color: colors.alpha.white[100], + background: colors.primary.main + }, + '&.Mui-selected:hover': { + background: colors.primary.main + } + } + } + }, + MuiListItem: { + styleOverrides: { + root: { + '&.MuiButtonBase-root': { + color: colors.secondary.main, + + '&:hover, &:active, &.active, &.Mui-selected': { + color: colors.alpha.black[100], + background: lighten(colors.primary.lighter, 0.5) + } + } + } + } + }, + MuiAutocomplete: { + styleOverrides: { + tag: { + margin: 1 + }, + root: { + '.MuiAutocomplete-inputRoot.MuiOutlinedInput-root .MuiAutocomplete-endAdornment': + { + right: 14 + } + }, + clearIndicator: { + background: colors.error.lighter, + color: colors.error.main, + marginRight: 8, + + '&:hover': { + background: colors.error.lighter, + color: colors.error.dark + } + }, + popupIndicator: { + color: colors.alpha.black[50], + + '&:hover': { + background: colors.primary.lighter, + color: colors.primary.main + } + } + } + }, + MuiTablePagination: { + styleOverrides: { + toolbar: { + '& .MuiIconButton-root': { + padding: 8 + } + }, + select: { + '&:focus': { + backgroundColor: 'transparent' + } + } + } + }, + MuiToolbar: { + styleOverrides: { + root: { + minHeight: '0 !important', + padding: '0 !important' + } + } + }, + MuiTableRow: { + styleOverrides: { + head: { + background: colors.alpha.black[5] + }, + root: { + transition: 'background-color .2s', + + '&.MuiTableRow-hover:hover': { + backgroundColor: colors.alpha.black[5] + } + } + } + }, + MuiTableCell: { + styleOverrides: { + root: { + borderBottomColor: colors.alpha.black[10], + fontSize: 14, + '&.MuiTableCell-head': { + backgroundColor: colors.alpha.black[5], + color: colors.alpha.black[70] + } + }, + head: { + textTransform: 'uppercase', + fontSize: 13, + fontWeight: 'bold', + color: colors.alpha.black[70] + }, + stickyHeader: { + backgroundColor: colors.alpha.black[5] + ' !important', + color: colors.alpha.black[70] + ' !important' + } + } + }, + MuiAlert: { + styleOverrides: { + message: { + lineHeight: 1.5, + fontSize: 14 + }, + standardInfo: { + color: colors.info.main + }, + action: { + color: colors.alpha.black[70] + } + } + }, + MuiTimelineDot: { + styleOverrides: { + root: { + margin: 0, + zIndex: 5, + position: 'absolute', + top: '50%', + marginTop: -6, + left: -6 + }, + outlined: { + backgroundColor: colors.alpha.white[100], + boxShadow: '0 0 0 6px ' + colors.alpha.white[100] + }, + outlinedPrimary: { + backgroundColor: colors.alpha.white[100], + boxShadow: '0 0 0 6px ' + colors.alpha.white[100] + } + } + }, + MuiTimelineConnector: { + styleOverrides: { + root: { + position: 'absolute', + height: '100%', + top: 0, + borderRadius: 50, + backgroundColor: colors.alpha.black[10] + } + } + }, + MuiTimelineItem: { + styleOverrides: { + root: { + minHeight: 0, + padding: '8px 0', + + '&:before': { + display: 'none' + } + }, + missingOppositeContent: { + '&:before': { + display: 'none' + } + } + } + }, + MuiTooltip: { + styleOverrides: { + tooltip: { + backgroundColor: alpha(colors.alpha.black['100'], 0.95), + padding: '8px 16px', + fontSize: 13 + }, + arrow: { + color: alpha(colors.alpha.black['100'], 0.95) + } + } + }, + MuiSwitch: { + styleOverrides: { + root: { + height: 33, + overflow: 'visible', + + '& .MuiButtonBase-root': { + position: 'absolute', + padding: 6, + transition: + 'left 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,transform 150ms cubic-bezier(0.4, 0, 0.2, 1) 0ms' + }, + '& .MuiIconButton-root': { + borderRadius: 100 + }, + '& .MuiSwitch-switchBase.Mui-checked + .MuiSwitch-track': { + opacity: 0.3 + } + }, + thumb: { + border: '1px solid ' + colors.alpha.black[30], + boxShadow: + '0px 9px 14px ' + + colors.alpha.black[10] + + ', 0px 2px 2px ' + + colors.alpha.black[10] + }, + track: { + backgroundColor: colors.alpha.black[5], + border: '1px solid ' + colors.alpha.black[10], + boxShadow: 'inset 0px 1px 1px ' + colors.alpha.black[10], + opacity: 1 + }, + colorPrimary: { + '& .MuiSwitch-thumb': { + backgroundColor: colors.alpha.white[100] + }, + + '&.Mui-checked .MuiSwitch-thumb': { + backgroundColor: colors.primary.main + } + } + } + }, + MuiStepper: { + styleOverrides: { + root: { + paddingTop: 20, + paddingBottom: 20, + background: colors.alpha.black[5] + } + } + }, + MuiStepIcon: { + styleOverrides: { + root: { + '&.MuiStepIcon-completed': { + color: colors.success.main + } + } + } + }, + MuiDrawer: { + styleOverrides: { + paper: { + backgroundColor: '#f5f5f5 !important', + backgroundImage: 'none !important', + color: colors.alpha.black[100], + '& .MuiButton-textPrimary': { + color: colors.alpha.black[100], + '&:hover': { + backgroundColor: colors.alpha.black[5] + } + }, + '& .MuiSvgIcon-root': { + color: colors.alpha.black[70] + } + } + } + }, + MuiTypography: { + defaultProps: { + variantMapping: { + h1: 'h1', + h2: 'h2', + h3: 'div', + h4: 'div', + h5: 'div', + h6: 'div', + subtitle1: 'div', + subtitle2: 'div', + body1: 'div', + body2: 'div' + } + }, + styleOverrides: { + gutterBottom: { + marginBottom: 4 + }, + paragraph: { + fontSize: 17, + lineHeight: 1.7 + } + } + } + }, + shape: { + borderRadius: 10 + }, + typography: { + fontFamily: + '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"', + h1: { + fontWeight: 700, + fontSize: 35 + }, + h2: { + fontWeight: 700, + fontSize: 30 + }, + h3: { + fontWeight: 700, + fontSize: 25, + lineHeight: 1.4, + color: colors.alpha.black[100] + }, + h4: { + fontWeight: 700, + fontSize: 16 + }, + h5: { + fontWeight: 700, + fontSize: 14 + }, + h6: { + fontSize: 15 + }, + body1: { + fontSize: 14 + }, + body2: { + fontSize: 14 + }, + button: { + fontWeight: 600 + }, + caption: { + fontSize: 13, + textTransform: 'uppercase', + color: colors.alpha.black[50] + }, + subtitle1: { + fontSize: 14, + color: colors.alpha.black[70] + }, + subtitle2: { + fontWeight: 400, + fontSize: 15, + color: colors.alpha.black[70] + }, + overline: { + fontSize: 13, + fontWeight: 700, + textTransform: 'uppercase' + } + }, + shadows: [ + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none', + 'none' + ] +}); diff --git a/mobile/App.tsx b/mobile/App.tsx index 7108d827a..601924d0e 100644 --- a/mobile/App.tsx +++ b/mobile/App.tsx @@ -2,7 +2,6 @@ import { StatusBar } from 'expo-status-bar'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { PersistGate } from 'redux-persist/integration/react'; import useCachedResources from './hooks/useCachedResources'; -import useColorScheme from './hooks/useColorScheme'; import Navigation from './navigation'; import { Provider } from 'react-redux'; import store, { persistor } from './store'; @@ -15,11 +14,7 @@ import 'text-encoding'; import Constants from 'expo-constants'; -import { - MD3LightTheme as DefaultTheme, - Provider as PaperProvider, - useTheme -} from 'react-native-paper'; +import { Provider as PaperProvider } from 'react-native-paper'; import { useEffect, useRef, useState } from 'react'; import { Alert, Linking, LogBox } from 'react-native'; import { SheetProvider } from 'react-native-actions-sheet'; @@ -30,9 +25,12 @@ import { NotificationType } from './models/notification'; import { navigate } from './navigation/RootNavigation'; import subscriptionPlan from './slices/subscriptionPlan'; import { isNumeric } from './utils/validators'; -import { customTheme } from './custom-theme'; import { RootLayout } from './components/RootLayout'; import { Subscription } from 'expo-notifications'; +import { + ThemeModeProvider, + useThemeMode +} from './theme'; Notifications.setNotificationHandler({ handleNotification: async () => ({ @@ -44,9 +42,8 @@ Notifications.setNotificationHandler({ }) }); -export default function App() { - const isLoadingComplete = useCachedResources(); - const colorScheme = useColorScheme(); +function AppContent() { + const { theme, resolvedScheme } = useThemeMode(); const [notification, setNotification] = useState(null); const notificationListener = useRef(undefined); @@ -122,34 +119,44 @@ export default function App() { }; }, []); + return ( + + + + + + + + + + + + ); +} + +export default function App() { + const isLoadingComplete = useCachedResources(); + if (!isLoadingComplete) { return null; - } else { - return ( - - - - - - - - - - - - - - - - - - - - - - ); } + + return ( + + + + + + + + + + + + + + ); } diff --git a/mobile/components/BasicField.tsx b/mobile/components/BasicField.tsx index df4024528..7ecd727d6 100644 --- a/mobile/components/BasicField.tsx +++ b/mobile/components/BasicField.tsx @@ -1,5 +1,5 @@ import { View } from './Themed'; -import { Divider, Text, TouchableRipple } from 'react-native-paper'; +import { Divider, Text, TouchableRipple, useTheme } from 'react-native-paper'; import * as React from 'react'; import { Linking } from 'react-native'; @@ -12,6 +12,8 @@ export default function BasicField({ value: string | number; isLink?: boolean; }) { + const theme = useTheme(); + if (!value) return null; const handlePress = () => { @@ -39,7 +41,11 @@ export default function BasicField({ {isLink ? ( {value} diff --git a/mobile/components/CommentItem.tsx b/mobile/components/CommentItem.tsx index fdb6a8b13..e56e1dc61 100644 --- a/mobile/components/CommentItem.tsx +++ b/mobile/components/CommentItem.tsx @@ -163,7 +163,7 @@ export default function CommentItem({ style={{ padding: 12, borderRadius: 8, - backgroundColor: highlighted ? theme.colors.surface : 'white', + backgroundColor: theme.colors.surface, borderWidth: highlighted ? 2 : 1, borderColor: highlighted ? theme.colors.primary : theme.colors.outline, marginBottom: 8 @@ -233,12 +233,12 @@ export default function CommentItem({ {mentionKeyword && filteredUsers.length > 0 && ( {item.name} @@ -269,7 +269,7 @@ export default function CommentItem({ numberOfLines={2} style={{ borderWidth: 1, - borderColor: '#ccc', + borderColor: theme.colors.outline, borderRadius: 4 }} {...textInputProps} diff --git a/mobile/components/FileUpload.tsx b/mobile/components/FileUpload.tsx index dd7f284c3..f2e0595d6 100644 --- a/mobile/components/FileUpload.tsx +++ b/mobile/components/FileUpload.tsx @@ -216,7 +216,7 @@ export default function FileUpload({ alignItems: 'center' }} > - {title} + {title} @@ -252,7 +252,7 @@ export default function FileUpload({ paddingVertical: 1 // Optional: Add padding for separation }} > - + {file.name} Camera permission required. - Go back + Go back )} @@ -101,18 +101,21 @@ const styles = StyleSheet.create({ width: 72, height: 72, borderRadius: 36, - backgroundColor: 'white', borderWidth: 4, borderColor: 'rgba(255,255,255,0.5)' }, noAccess: { flex: 1, - backgroundColor: 'black', alignItems: 'center', - justifyContent: 'center' + justifyContent: 'center', + backgroundColor: '#fff' }, noAccessText: { - color: 'white', + color: '#000', fontSize: 16 + }, + goBackText: { + color: '#007AFF', + marginTop: 20 } }); diff --git a/mobile/components/LoadingDialog.tsx b/mobile/components/LoadingDialog.tsx index cc1685e55..f7f37bf19 100644 --- a/mobile/components/LoadingDialog.tsx +++ b/mobile/components/LoadingDialog.tsx @@ -18,7 +18,7 @@ export default function LoadingDialog({ visible }: { visible: boolean }) { {t('loading')} diff --git a/mobile/components/PartQuantities.tsx b/mobile/components/PartQuantities.tsx index ecb748809..051efa4be 100644 --- a/mobile/components/PartQuantities.tsx +++ b/mobile/components/PartQuantities.tsx @@ -115,7 +115,11 @@ export default function PartQuantities({ const renderModal = () => { return ( - + {t('quantity')} @@ -164,7 +168,7 @@ export default function PartQuantities({ padding: 7, borderRadius: 5, fontWeight: 'bold', - color: 'white' + color: theme.colors.onPrimary }} >{`${partQuantity.quantity}${partQuantity.part.unit ?? 'x'}`} ); diff --git a/mobile/components/actionSheets/CreateEntitiesSheet.tsx b/mobile/components/actionSheets/CreateEntitiesSheet.tsx index 21073f34f..9e8df807b 100644 --- a/mobile/components/actionSheets/CreateEntitiesSheet.tsx +++ b/mobile/components/actionSheets/CreateEntitiesSheet.tsx @@ -3,7 +3,7 @@ import ActionSheet, { SheetProps } from 'react-native-actions-sheet'; import { View } from 'react-native'; -import { Divider, List, Text } from 'react-native-paper'; +import { Divider, List, Text, useTheme } from 'react-native-paper'; import * as React from 'react'; import { useContext, useRef } from 'react'; import { RootStackParamList } from '../../types'; @@ -17,6 +17,7 @@ import { IconSource } from 'react-native-paper/lib/typescript/components/Icon'; export default function CreateEntitiesSheet( props: SheetProps<{ navigation: any }> ) { + const theme = useTheme(); const { t } = useTranslation(); const { hasCreatePermission } = useAuth(); const netInfo = useNetInfo(); @@ -72,9 +73,22 @@ export default function CreateEntitiesSheet( } ]; return ( - - - + + + {t('create')} @@ -85,9 +99,15 @@ export default function CreateEntitiesSheet( .map((entity, index) => ( } + left={() => ( + + )} onPress={() => { props.payload.navigation.navigate(entity.goTo); actionSheetRef.current.hide(); @@ -96,7 +116,7 @@ export default function CreateEntitiesSheet( ))} ) : ( - + {t('no_internet_connection')} )} diff --git a/mobile/components/actionSheets/CustomActionSheet.tsx b/mobile/components/actionSheets/CustomActionSheet.tsx index 81dbf1cc1..011997fbe 100644 --- a/mobile/components/actionSheets/CustomActionSheet.tsx +++ b/mobile/components/actionSheets/CustomActionSheet.tsx @@ -1,5 +1,5 @@ import { View } from 'react-native'; -import { Divider, List } from 'react-native-paper'; +import { Divider, List, useTheme } from 'react-native-paper'; import * as React from 'react'; import { useRef } from 'react'; import { IconSource } from 'react-native-paper/lib/typescript/components/Icon'; @@ -19,10 +19,20 @@ interface CustomActionSheetProps { export default function CustomActionSheet({ options }: CustomActionSheetProps) { const actionSheetRef = useRef(null); + const theme = useTheme(); return ( - - + + {options @@ -30,11 +40,19 @@ export default function CustomActionSheet({ options }: CustomActionSheetProps) { .map((entity, index) => ( ( - + )} onPress={async () => { await actionSheetRef.current?.hide(); diff --git a/mobile/components/actionSheets/DropDownSheet.tsx b/mobile/components/actionSheets/DropDownSheet.tsx index 9e23b55c8..23272848f 100644 --- a/mobile/components/actionSheets/DropDownSheet.tsx +++ b/mobile/components/actionSheets/DropDownSheet.tsx @@ -27,14 +27,28 @@ const DropDownSheet = ( }; return ( - - + + {items.map((item) => ( handleSelect(item.value)} style={{ - paddingVertical: 15 + paddingVertical: 15, + borderRadius: 8, + backgroundColor: + value === item.value + ? theme.colors.primaryContainer + : theme.colors.surface, + marginBottom: 5 }} > = ({ value }) => { const ref = useRef(null); - const theme = useTheme(); + const theme = useTheme() ?? MD3LightTheme; const [hasChanged, setHasChanged] = useState(false); const handleOK = (signature: string) => { @@ -40,9 +39,10 @@ const SignaturePad: React.FC = ({ setHasChanged(false); }; + const { colors } = theme; const style = `.m-signature-pad--footer .button { - background-color: ${theme.colors.primary}; - color: ${theme.colors.onPrimary}; + background-color: ${colors.primary}; + color: ${colors.onPrimary}; } body, html { height: 100%; @@ -57,7 +57,12 @@ const SignaturePad: React.FC = ({ return ( {label} - + = ({ message: t(type), description: text, color: getColor(type), - textStyle: { color: 'white' }, - titleStyle: { color: 'white' }, + textStyle: { color: theme.colors.onSurface }, + titleStyle: { color: theme.colors.onSurface }, type: type === 'error' ? 'danger' : type, onPress: action?.onPress }); diff --git a/mobile/custom-theme.ts b/mobile/custom-theme.ts index bfffb3e6c..af1546dcc 100644 --- a/mobile/custom-theme.ts +++ b/mobile/custom-theme.ts @@ -1,24 +1,48 @@ -import { MD3LightTheme as DefaultTheme, useTheme } from 'react-native-paper'; +import { MD3DarkTheme, MD3LightTheme, useTheme } from 'react-native-paper'; -export const customTheme = { - ...DefaultTheme, +const baseColors = { + primary: '#5569ff', + secondary: '#959be0', + tertiary: '#9DA1A1', + success: '#57CA22', + warning: '#FFA319', + error: '#FF1943', + info: '#33C2FF', + black: '#223354', + white: '#ffffff', + primaryAlt: '#000C57', + primaryContainer: '#333586', + tertiaryContainer: 'black' +}; + +export const lightTheme = { + ...MD3LightTheme, colors: { - ...DefaultTheme.colors, - primary: '#5569ff', - secondary: '#959be0', - tertiary: '#9DA1A1', + ...MD3LightTheme.colors, + ...baseColors, background: '#ebecf6', - secondaryContainer: '#7b7d93', - success: '#57CA22', - warning: '#FFA319', - error: '#FF1943', - info: '#33C2FF', - black: '#223354', - white: '#ffffff', - primaryAlt: '#000C57', - primaryContainer: '#333586', - tertiaryContainer: 'black', - grey: '#676b6b' + surface: '#ffffff', + onSurface: '#1f2937', + surfaceVariant: '#e5e7eb', + onSurfaceVariant: '#4b5563', + outline: '#9ca3af', + grey: '#6b7280' } }; -export const useAppTheme = () => useTheme(); + +export const darkTheme = { + ...MD3DarkTheme, + colors: { + ...MD3DarkTheme.colors, + ...baseColors, + background: '#121212', + surface: '#1e1e1e', + onSurface: '#f9fafb', + surfaceVariant: '#2c2c2c', + onSurfaceVariant: '#d1d5db', + outline: '#4b5563', + grey: '#d1d5db' + } +}; + +export const useAppTheme = () => useTheme(); diff --git a/mobile/i18n/translations/en.ts b/mobile/i18n/translations/en.ts index 9ec080bfd..792f59055 100644 --- a/mobile/i18n/translations/en.ts +++ b/mobile/i18n/translations/en.ts @@ -826,6 +826,10 @@ const locale = { acquisition_cost: 'Acquisition Cost', //settings general_settings: 'General Settings', + theme_selection: 'Theme selection', + theme_system: 'Follow system theme', + theme_light: 'Light theme', + theme_dark: 'Dark theme', request_form_configuration: 'Request form configuration', roles: 'Roles', checklists: 'Checklists', diff --git a/mobile/navigation/index.tsx b/mobile/navigation/index.tsx index a71bfde58..aabcec9b4 100644 --- a/mobile/navigation/index.tsx +++ b/mobile/navigation/index.tsx @@ -4,7 +4,7 @@ * */ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; -import { DefaultTheme, NavigationContainer } from '@react-navigation/native'; +import { DarkTheme, DefaultTheme, NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import * as React from 'react'; import { @@ -116,7 +116,7 @@ export default function Navigation({ {isInitialized ? ( isAuthenticated ? ( @@ -569,7 +569,7 @@ function BottomTabNavigator({ navigation }: RootTabScreenProps<'Home'>) { paddingTop: 6, paddingBottom: Platform.OS === 'ios' ? 18 : 10, borderTopWidth: 0, - shadowColor: '#000', + shadowColor: theme.colors.onSurface, shadowOpacity: 0.15, shadowRadius: 8, shadowOffset: { width: 0, height: -2 } diff --git a/mobile/screens/HomeScreen.tsx b/mobile/screens/HomeScreen.tsx index cc604353c..2e8b71147 100644 --- a/mobile/screens/HomeScreen.tsx +++ b/mobile/screens/HomeScreen.tsx @@ -39,7 +39,12 @@ export default function HomeScreen({ navigation }: RootTabScreenProps<'Home'>) { const { mobileOverview, loading } = useSelector((state) => state.woAnalytics); const iconButtonStyle = { ...styles.iconButton, - backgroundColor: theme.colors.background + backgroundColor: theme.colors.surface, + elevation: 2, + shadowColor: theme.colors.onSurface, + shadowOffset: { width: 0, height: 1 }, + shadowOpacity: 0.12, + shadowRadius: 2 }; const [assignedToMe, setAssignedToMe] = useState( userSettings?.statsForAssignedWorkOrders @@ -252,10 +257,18 @@ export default function HomeScreen({ navigation }: RootTabScreenProps<'Home'>) { flexDirection: 'row', justifyContent: 'space-between', borderRadius: 10, - alignItems: 'center' + alignItems: 'center', + backgroundColor: theme.colors.surfaceVariant, + borderWidth: 1, + borderColor: theme.colors.outline, + elevation: 2, + shadowColor: theme.colors.onSurface, + shadowOffset: { width: 0, height: 1 }, + shadowOpacity: 0.16, + shadowRadius: 3 }} > - + {t('only_assigned_to_me')} ) { marginTop: 20, paddingHorizontal: 10, paddingVertical: 5, - borderRadius: 10 + borderRadius: 10, + backgroundColor: 'transparent', + borderWidth: 1, + borderColor: theme.colors.outline, + elevation: 0, + shadowColor: 'transparent', + shadowOffset: { width: 0, height: 0 }, + shadowOpacity: 0, + shadowRadius: 0 }} > ) { justifyContent: 'flex-start' }} > - {stat.value} + {stat.value} diff --git a/mobile/screens/MoreEntitiesScreen.tsx b/mobile/screens/MoreEntitiesScreen.tsx index 29487b538..1036064fb 100644 --- a/mobile/screens/MoreEntitiesScreen.tsx +++ b/mobile/screens/MoreEntitiesScreen.tsx @@ -18,7 +18,6 @@ export default function MoreEntitiesScreen({ label: string; icon: IconSource; color: string; - backgroundColor: string; link: keyof RootStackParamList; visible: boolean; uiConfigKey?: keyof UiConfiguration; @@ -27,7 +26,6 @@ export default function MoreEntitiesScreen({ label: 'locations', icon: 'map-marker', color: '#2491d1', - backgroundColor: '#c8cfd3', link: 'Locations', visible: hasViewPermission(PermissionEntity.LOCATIONS), uiConfigKey: 'locations' @@ -37,7 +35,6 @@ export default function MoreEntitiesScreen({ icon: 'package-variant-closed', // @ts-ignore color: theme.colors.warning, - backgroundColor: '#d2d0c4', link: 'Assets', visible: hasViewPermission(PermissionEntity.ASSETS) }, @@ -45,7 +42,6 @@ export default function MoreEntitiesScreen({ label: 'parts', icon: 'archive-outline', color: '#8324d1', - backgroundColor: '#cfc8d3', link: 'Parts', visible: hasViewPermission(PermissionEntity.PARTS_AND_MULTIPARTS) }, @@ -53,7 +49,6 @@ export default function MoreEntitiesScreen({ label: 'meters', icon: 'gauge', color: '#d12444', - backgroundColor: '#d3c8ca', link: 'Meters', visible: hasViewPermission(PermissionEntity.METERS), uiConfigKey: 'meters' @@ -62,7 +57,6 @@ export default function MoreEntitiesScreen({ label: 'people_teams', icon: 'account', color: '#245bd1', - backgroundColor: '#c8ccd3', link: 'PeopleTeams', visible: hasViewPermission(PermissionEntity.PEOPLE_AND_TEAMS) }, @@ -71,12 +65,20 @@ export default function MoreEntitiesScreen({ icon: 'vector-circle', //@ts-ignore color: theme.colors.warning, - backgroundColor: '#d2d0c4', link: 'VendorsCustomers', visible: hasViewPermission(PermissionEntity.VENDORS_AND_CUSTOMERS), uiConfigKey: 'vendorsAndCustomers' } ]; + + const getColorBackground = (baseColor: string) => { + const hex = baseColor.replace('#', ''); + if (!/^([0-9a-fA-F]{6})$/.test(hex)) { + return theme.colors.surfaceVariant; + } + return theme.dark ? `#${hex}33` : `#${hex}22`; + }; + return ( ( + .map(({ label, icon, color, link }) => ( - {t(label)} + + {t(label)} + diff --git a/mobile/screens/NotFoundScreen.tsx b/mobile/screens/NotFoundScreen.tsx index 5c0e79789..adf17907d 100644 --- a/mobile/screens/NotFoundScreen.tsx +++ b/mobile/screens/NotFoundScreen.tsx @@ -1,11 +1,14 @@ import { StyleSheet, TouchableOpacity } from 'react-native'; import { Text, View } from '../components/Themed'; +import { useTheme } from 'react-native-paper'; import { RootStackScreenProps } from '../types'; export default function NotFoundScreen({ navigation }: RootStackScreenProps<'NotFound'>) { + const theme = useTheme(); + return ( This screen doesn't exist. @@ -13,7 +16,7 @@ export default function NotFoundScreen({ onPress={() => navigation.replace('Root')} style={styles.link} > - Go to home screen! + Go to home screen! ); @@ -35,7 +38,6 @@ const styles = StyleSheet.create({ paddingVertical: 15 }, linkText: { - fontSize: 14, - color: '#2e78b7' + fontSize: 14 } }); diff --git a/mobile/screens/NotificationsScreen.tsx b/mobile/screens/NotificationsScreen.tsx index b47f74759..d1fb2575b 100644 --- a/mobile/screens/NotificationsScreen.tsx +++ b/mobile/screens/NotificationsScreen.tsx @@ -89,7 +89,7 @@ export default function NotificationsScreen({ return ( )} style={{ backgroundColor: notification.seen - ? 'white' - : theme.colors.background + ? theme.colors.surface + : theme.colors.surfaceVariant }} key={notification.id} onPress={() => onReadNotification(notification)} @@ -131,7 +131,7 @@ export default function NotificationsScreen({ ) : ( ) { const theme = useTheme(); + const { themeMode, setThemeMode } = useThemeMode(); const { user, switchAccount, logout } = useAuth(); const [switchingAccount, setSwitchingAccount] = useState(false); const { t } = useTranslation(); const [versionPressCount, setVersionPressCount] = useState(0); const [openLogout, setOpenLogout] = useState(false); const [openDevInfo, setOpenDevInfo] = useState(false); + const [openThemeDialog, setOpenThemeDialog] = useState(false); const { showSnackBar } = useContext(CustomSnackBarContext); const [devMode, setDevMode] = useState(false); useEffect(() => { @@ -76,10 +80,44 @@ export default function SettingsScreen({ ); }; + + const renderThemeDialog = () => { + return ( + + setOpenThemeDialog(false)}> + {t('theme_selection')} + + setThemeMode(value as 'system' | 'light' | 'dark')} + value={themeMode} + > + + + + + + + + + + + ); + }; + return ( {renderConfirmLogout()} {renderDevInfo()} + {renderThemeDialog()} navigation.navigate('UserProfile')} /> + } + title={t('theme_selection')} + description={ + themeMode === 'system' + ? t('theme_system') + : themeMode === 'light' + ? t('theme_light') + : t('theme_dark') + } + onPress={() => setOpenThemeDialog(true)} + /> {user.parentSuperAccount && } diff --git a/mobile/screens/assets/AssetsScreen.tsx b/mobile/screens/assets/AssetsScreen.tsx index c60a8ff3b..aaeea8945 100644 --- a/mobile/screens/assets/AssetsScreen.tsx +++ b/mobile/screens/assets/AssetsScreen.tsx @@ -59,7 +59,7 @@ const AssetCard = ({ } key={asset.id} > - + ); diff --git a/mobile/screens/locations/LocationsScreen.tsx b/mobile/screens/locations/LocationsScreen.tsx index 817d8e0df..8a8c47c16 100644 --- a/mobile/screens/locations/LocationsScreen.tsx +++ b/mobile/screens/locations/LocationsScreen.tsx @@ -160,7 +160,7 @@ export default function LocationsScreen({ } key={location.id} > - + {`#${location.customId}`} @@ -255,7 +255,7 @@ export default function LocationsScreen({ ) : loadingGet ? null : ( ); diff --git a/mobile/screens/meters/MeterDetails.tsx b/mobile/screens/meters/MeterDetails.tsx index 2b1440fd2..8d58d8b85 100644 --- a/mobile/screens/meters/MeterDetails.tsx +++ b/mobile/screens/meters/MeterDetails.tsx @@ -147,7 +147,7 @@ export default function MeterDetails({ setOpenModal(false)} - style={{ backgroundColor: 'white' }} + style={{ backgroundColor: theme.colors.surface }} > {t('add_reading')} diff --git a/mobile/screens/meters/MetersScreen.tsx b/mobile/screens/meters/MetersScreen.tsx index 5832faf9f..7f41c49d6 100644 --- a/mobile/screens/meters/MetersScreen.tsx +++ b/mobile/screens/meters/MetersScreen.tsx @@ -136,7 +136,7 @@ export default function MetersScreen({ } key={meter.id} > - + {t('no_element_match_criteria')} @@ -220,7 +220,7 @@ const styles = StyleSheet.create({ alignItems: 'center' }, card: { - backgroundColor: 'white', + backgroundColor: 'transparent', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/modals/SelectAssetsModal.tsx b/mobile/screens/modals/SelectAssetsModal.tsx index faba8f29c..b21eee947 100644 --- a/mobile/screens/modals/SelectAssetsModal.tsx +++ b/mobile/screens/modals/SelectAssetsModal.tsx @@ -374,7 +374,6 @@ const styles = StyleSheet.create({ flex: 1 }, card: { - backgroundColor: 'white', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/modals/SelectBarcodeModal.tsx b/mobile/screens/modals/SelectBarcodeModal.tsx index 413881f83..090cebd0f 100644 --- a/mobile/screens/modals/SelectBarcodeModal.tsx +++ b/mobile/screens/modals/SelectBarcodeModal.tsx @@ -4,6 +4,7 @@ import { TouchableOpacity, useWindowDimensions } from 'react-native'; +import { useTheme } from 'react-native-paper'; import { View } from '../../components/Themed'; import * as React from 'react'; @@ -19,6 +20,7 @@ export default function SelectBarcodeModal({ }: RootStackScreenProps<'SelectBarcode'>) { const { onChange } = route.params; const { t } = useTranslation(); + const theme = useTheme(); const [scanned, setScanned] = useState(false); const [hasPermission, setHasPermission] = useState(null); const layout = useWindowDimensions(); @@ -59,7 +61,7 @@ export default function SelectBarcodeModal({ return ( - + - + - + - + - + - + ( ); @@ -319,7 +319,6 @@ const styles = StyleSheet.create({ flex: 1 }, card: { - backgroundColor: 'white', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/modals/SelectTeamsModal.tsx b/mobile/screens/modals/SelectTeamsModal.tsx index d693b4c6a..11c6bde4d 100644 --- a/mobile/screens/modals/SelectTeamsModal.tsx +++ b/mobile/screens/modals/SelectTeamsModal.tsx @@ -103,7 +103,9 @@ export default function SelectTeamsModal({ }} key={team.id} > - + - + {user.image ? ( @@ -180,7 +180,6 @@ const styles = StyleSheet.create({ flex: 1 }, card: { - backgroundColor: 'white', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/modals/SelectVendorsModal.tsx b/mobile/screens/modals/SelectVendorsModal.tsx index 8f01ee8ab..d75a47e5f 100644 --- a/mobile/screens/modals/SelectVendorsModal.tsx +++ b/mobile/screens/modals/SelectVendorsModal.tsx @@ -103,7 +103,9 @@ export default function SelectVendorsModal({ }} key={vendor.id} > - + - + {t('no_element_match_criteria')} @@ -223,7 +223,7 @@ const styles = StyleSheet.create({ alignItems: 'center' }, card: { - backgroundColor: 'white', + backgroundColor: 'transparent', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/parts/details/index.tsx b/mobile/screens/parts/details/index.tsx index 613508a20..5c17537e8 100644 --- a/mobile/screens/parts/details/index.tsx +++ b/mobile/screens/parts/details/index.tsx @@ -61,7 +61,7 @@ export default function PartDetailsHome({ ); @@ -120,7 +120,12 @@ export default function PartDetailsHome({ }; if (part) return ( - + {renderConfirmDelete()} ); diff --git a/mobile/screens/peopleTeams/People.tsx b/mobile/screens/peopleTeams/People.tsx index d3b9442ee..dd2767109 100644 --- a/mobile/screens/peopleTeams/People.tsx +++ b/mobile/screens/peopleTeams/People.tsx @@ -133,7 +133,7 @@ export default function People({ }); }} > - + {t('no_element_match_criteria')} @@ -222,7 +222,7 @@ const styles = StyleSheet.create({ alignItems: 'center' }, card: { - backgroundColor: 'white', + backgroundColor: 'transparent', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/peopleTeams/Teams.tsx b/mobile/screens/peopleTeams/Teams.tsx index fc843689e..d541110b5 100644 --- a/mobile/screens/peopleTeams/Teams.tsx +++ b/mobile/screens/peopleTeams/Teams.tsx @@ -159,7 +159,7 @@ export default function Teams({ )) ) : loadingGet ? null : ( {t('no_element_match_criteria')} @@ -189,7 +189,7 @@ const styles = StyleSheet.create({ alignItems: 'center' }, card: { - backgroundColor: 'white', + backgroundColor: 'transparent', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/peopleTeams/index.tsx b/mobile/screens/peopleTeams/index.tsx index afd5103cd..311aa7d75 100644 --- a/mobile/screens/peopleTeams/index.tsx +++ b/mobile/screens/peopleTeams/index.tsx @@ -31,7 +31,7 @@ export default function PeopleTeams( const renderTabBar = (props) => ( ); diff --git a/mobile/screens/requests/RequestDetails.tsx b/mobile/screens/requests/RequestDetails.tsx index 1177a7008..77b6794f7 100644 --- a/mobile/screens/requests/RequestDetails.tsx +++ b/mobile/screens/requests/RequestDetails.tsx @@ -237,7 +237,7 @@ export default function RequestDetails({ // @ts-ignore navigation.navigate(link.route, { id: link.id }); }} - style={{ marginTop: 20, padding: 20, backgroundColor: 'white' }} + style={{ marginTop: 20, padding: 20, backgroundColor: theme.colors.surface }} > {label} @@ -316,7 +316,7 @@ export default function RequestDetails({ /> ))} {request.audioDescription && ( - + {t('audio_description')} diff --git a/mobile/screens/requests/RequestsScreen.tsx b/mobile/screens/requests/RequestsScreen.tsx index 932ddfb96..98a8e55ec 100644 --- a/mobile/screens/requests/RequestsScreen.tsx +++ b/mobile/screens/requests/RequestsScreen.tsx @@ -235,7 +235,7 @@ export default function RequestsScreen({ - + {`#${request.customId}`} ) : ( {t('no_access_requests')} @@ -426,7 +426,7 @@ const styles = StyleSheet.create({ alignItems: 'center' }, card: { - backgroundColor: 'white', + backgroundColor: 'transparent', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/vendorsCustomers/CustomersScreen.tsx b/mobile/screens/vendorsCustomers/CustomersScreen.tsx index 143ebaab3..0b0da18b7 100644 --- a/mobile/screens/vendorsCustomers/CustomersScreen.tsx +++ b/mobile/screens/vendorsCustomers/CustomersScreen.tsx @@ -141,7 +141,7 @@ export default function CustomersScreen({ }) } > - + {t('no_element_match_criteria')} @@ -216,7 +216,7 @@ const styles = StyleSheet.create({ alignItems: 'center' }, card: { - backgroundColor: 'white', + backgroundColor: 'transparent', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/vendorsCustomers/VendorsScreen.tsx b/mobile/screens/vendorsCustomers/VendorsScreen.tsx index 69459ea39..c06b8bae1 100644 --- a/mobile/screens/vendorsCustomers/VendorsScreen.tsx +++ b/mobile/screens/vendorsCustomers/VendorsScreen.tsx @@ -128,7 +128,7 @@ export default function VendorsScreen({ }) } > - + {t('no_element_match_criteria')} @@ -203,7 +203,7 @@ const styles = StyleSheet.create({ alignItems: 'center' }, card: { - backgroundColor: 'white', + backgroundColor: 'transparent', marginBottom: 1, padding: 10 }, diff --git a/mobile/screens/vendorsCustomers/index.tsx b/mobile/screens/vendorsCustomers/index.tsx index 333d49783..93bcc2d48 100644 --- a/mobile/screens/vendorsCustomers/index.tsx +++ b/mobile/screens/vendorsCustomers/index.tsx @@ -31,7 +31,7 @@ export default function VendorsCustomers( const renderTabBar = (props) => ( ); diff --git a/mobile/screens/workOrders/EnumFilter.tsx b/mobile/screens/workOrders/EnumFilter.tsx index 60a9a6dd6..827fcb7ed 100644 --- a/mobile/screens/workOrders/EnumFilter.tsx +++ b/mobile/screens/workOrders/EnumFilter.tsx @@ -85,7 +85,7 @@ export default function EnumFilter({ setStatusesJustOnOpen(null); } }} - style={{ backgroundColor: 'white' }} + style={{ backgroundColor: theme.colors.surface }} > {t('select')} @@ -98,15 +98,17 @@ export default function EnumFilter({ display: 'flex', borderRadius: 5, flexDirection: 'row', - alignItems: 'center' + alignItems: 'center', + backgroundColor: theme.colors.surfaceVariant }} onPress={() => switchValue(index, option)} > switchValue(index, option)} + color={theme.colors.primary} /> - {t(option)} + {t(option)} ))} @@ -129,7 +131,7 @@ export default function EnumFilter({ ); }} style={{ - backgroundColor: isSelected ? theme.colors.primary : theme.colors.background, + backgroundColor: isSelected ? theme.colors.primary : theme.colors.surface, display: 'flex', flexDirection: 'row', alignItems: 'center', @@ -141,13 +143,13 @@ export default function EnumFilter({ > {renderDialog()} {t(fieldName)} diff --git a/mobile/screens/workOrders/QuickFilter.tsx b/mobile/screens/workOrders/QuickFilter.tsx index 5df808d1e..38b49eefa 100644 --- a/mobile/screens/workOrders/QuickFilter.tsx +++ b/mobile/screens/workOrders/QuickFilter.tsx @@ -51,7 +51,10 @@ export default function QuickFilter({ }} > {t(activeFilterField.field)} diff --git a/mobile/screens/workOrders/TasksScreen.tsx b/mobile/screens/workOrders/TasksScreen.tsx index d41b96bfa..ed5c911cf 100644 --- a/mobile/screens/workOrders/TasksScreen.tsx +++ b/mobile/screens/workOrders/TasksScreen.tsx @@ -6,6 +6,7 @@ import { useDispatch } from '../../store'; import { CustomSnackBarContext } from '../../contexts/CustomSnackBarContext'; import { ScrollView, StyleSheet } from 'react-native'; import SingleTask from '../../components/SingleTask'; +import { useAppTheme } from '../../custom-theme'; import { RootStackScreenProps } from '../../types'; import { addFiles } from '../../slices/file'; import * as ImagePicker from 'expo-image-picker'; @@ -132,8 +133,10 @@ export default function TasksScreen({ .catch(onImageUploadFailure); } }; + const theme = useAppTheme(); + return ( - + (null); + const shadowedCardStyle = [styles.shadowedCard, { shadowColor: theme.colors.onSurface }]; const [isImageViewerOpen, setIsImageViewerOpen] = useState(false); const dispatch = useDispatch(); const { partQuantitiesByWorkOrder, loadingPartQuantities } = useSelector( @@ -954,6 +955,7 @@ export default function WODetailsScreen({ {workOrder.signature && ( + - + )} - + @@ -1500,7 +1512,7 @@ const styles = StyleSheet.create({ borderRadius: 10, paddingHorizontal: 10, paddingVertical: 10, - shadowColor: '#000', + shadowColor: '#00000033', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.2, marginVertical: 10, diff --git a/mobile/screens/workOrders/WorkOrdersScreen.tsx b/mobile/screens/workOrders/WorkOrdersScreen.tsx index 3686f6cfb..41fcf78db 100644 --- a/mobile/screens/workOrders/WorkOrdersScreen.tsx +++ b/mobile/screens/workOrders/WorkOrdersScreen.tsx @@ -184,7 +184,7 @@ export default function WorkOrdersScreen({ - + {/* Header: Title, ID, and Status */} {`#${workOrder.customId}`} void; + resolvedScheme: Exclude; + theme: Theme; +} + +const ThemeModeContext = createContext({ + themeMode: 'system', + setThemeMode: () => {}, + resolvedScheme: 'light', + theme: lightTheme +}); + +export const ThemeModeProvider = ({ children }: { children: ReactNode }) => { + const systemScheme = (_useColorScheme() || 'light') as Exclude; + const [themeMode, setThemeModeState] = useState('system'); + const [isLoaded, setIsLoaded] = useState(false); + + useEffect(() => { + AsyncStorage.getItem(STORAGE_KEY) + .then((value) => { + if (value === 'system' || value === 'light' || value === 'dark') { + setThemeModeState(value); + } + }) + .finally(() => setIsLoaded(true)); + }, []); + + useEffect(() => { + if (!isLoaded) { + return; + } + AsyncStorage.setItem(STORAGE_KEY, themeMode).catch(() => { + // ignore storage failures + }); + }, [themeMode, isLoaded]); + + const resolvedScheme = themeMode === 'system' ? systemScheme : themeMode; + const theme = resolvedScheme === 'dark' ? darkTheme : lightTheme; + + const value = useMemo( + () => ({ + themeMode, + setThemeMode: setThemeModeState, + resolvedScheme, + theme + }), + [themeMode, resolvedScheme, theme] + ); + + if (!isLoaded) { + return null; + } + + return ( + + {children} + + ); +}; + +export const useThemeMode = () => useContext(ThemeModeContext);