Clean and re-organize post table refactoring (#1000)
* Clean and re-organize post table refactoring * Fix tests
This commit is contained in:
BIN
front/src/modules/ui/theme/assets/dark-noise.jpg
Normal file
BIN
front/src/modules/ui/theme/assets/dark-noise.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
BIN
front/src/modules/ui/theme/assets/light-noise.png
Normal file
BIN
front/src/modules/ui/theme/assets/light-noise.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.4 KiB |
29
front/src/modules/ui/theme/components/AppThemeProvider.tsx
Normal file
29
front/src/modules/ui/theme/components/AppThemeProvider.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
|
||||
import { darkTheme, lightTheme } from '@/ui/theme/constants/theme';
|
||||
import { ColorScheme } from '~/generated/graphql';
|
||||
|
||||
import { useColorScheme } from '../hooks/useColorScheme';
|
||||
import { useSystemColorScheme } from '../hooks/useSystemColorScheme';
|
||||
|
||||
type OwnProps = {
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
const themes = {
|
||||
[ColorScheme.Dark]: darkTheme,
|
||||
[ColorScheme.Light]: lightTheme,
|
||||
};
|
||||
|
||||
export function AppThemeProvider({ children }: OwnProps) {
|
||||
const systemColorScheme = useSystemColorScheme();
|
||||
|
||||
const { colorScheme } = useColorScheme();
|
||||
|
||||
const theme =
|
||||
themes[
|
||||
colorScheme === ColorScheme.System ? systemColorScheme : colorScheme
|
||||
];
|
||||
|
||||
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
|
||||
}
|
||||
15
front/src/modules/ui/theme/constants/accent.ts
Normal file
15
front/src/modules/ui/theme/constants/accent.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { color } from './colors';
|
||||
|
||||
export const accentLight = {
|
||||
primary: color.blueAccent25,
|
||||
secondary: color.blueAccent20,
|
||||
tertiary: color.blueAccent15,
|
||||
quaternary: color.blueAccent10,
|
||||
};
|
||||
|
||||
export const accentDark = {
|
||||
primary: color.blueAccent75,
|
||||
secondary: color.blueAccent80,
|
||||
tertiary: color.blueAccent85,
|
||||
quaternary: color.blueAccent90,
|
||||
};
|
||||
7
front/src/modules/ui/theme/constants/animation.ts
Normal file
7
front/src/modules/ui/theme/constants/animation.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export const animation = {
|
||||
duration: {
|
||||
instant: 0.075,
|
||||
fast: 0.15,
|
||||
normal: 0.3,
|
||||
},
|
||||
};
|
||||
38
front/src/modules/ui/theme/constants/background.ts
Normal file
38
front/src/modules/ui/theme/constants/background.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import DarkNoise from '../assets/dark-noise.jpg';
|
||||
import LightNoise from '../assets/light-noise.png';
|
||||
|
||||
import { grayScale, rgba } from './colors';
|
||||
|
||||
export const backgroundLight = {
|
||||
noisy: `url(${LightNoise.toString()});`,
|
||||
primary: grayScale.gray0,
|
||||
secondary: grayScale.gray10,
|
||||
tertiary: grayScale.gray15,
|
||||
quaternary: grayScale.gray20,
|
||||
transparent: {
|
||||
primary: rgba(grayScale.gray0, 0.8),
|
||||
secondary: rgba(grayScale.gray10, 0.8),
|
||||
strong: rgba(grayScale.gray100, 0.16),
|
||||
medium: rgba(grayScale.gray100, 0.08),
|
||||
light: rgba(grayScale.gray100, 0.04),
|
||||
lighter: rgba(grayScale.gray100, 0.02),
|
||||
},
|
||||
overlay: rgba(grayScale.gray80, 0.8),
|
||||
};
|
||||
|
||||
export const backgroundDark = {
|
||||
noisy: `url(${DarkNoise.toString()});`,
|
||||
primary: grayScale.gray85,
|
||||
secondary: grayScale.gray80,
|
||||
tertiary: grayScale.gray75,
|
||||
quaternary: grayScale.gray70,
|
||||
transparent: {
|
||||
primary: rgba(grayScale.gray85, 0.8),
|
||||
secondary: rgba(grayScale.gray80, 0.8),
|
||||
strong: rgba(grayScale.gray0, 0.14),
|
||||
medium: rgba(grayScale.gray0, 0.1),
|
||||
light: rgba(grayScale.gray0, 0.06),
|
||||
lighter: rgba(grayScale.gray0, 0.03),
|
||||
},
|
||||
overlay: rgba(grayScale.gray80, 0.8),
|
||||
};
|
||||
4
front/src/modules/ui/theme/constants/blur.ts
Normal file
4
front/src/modules/ui/theme/constants/blur.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export const blur = {
|
||||
light: 'blur(6px)',
|
||||
strong: 'blur(20px)',
|
||||
};
|
||||
32
front/src/modules/ui/theme/constants/border.ts
Normal file
32
front/src/modules/ui/theme/constants/border.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { grayScale } from './colors';
|
||||
|
||||
const common = {
|
||||
radius: {
|
||||
xs: '2px',
|
||||
sm: '4px',
|
||||
md: '8px',
|
||||
rounded: '100%',
|
||||
},
|
||||
};
|
||||
|
||||
export const borderLight = {
|
||||
color: {
|
||||
strong: grayScale.gray25,
|
||||
medium: grayScale.gray20,
|
||||
light: grayScale.gray15,
|
||||
secondaryInverted: grayScale.gray50,
|
||||
inverted: grayScale.gray60,
|
||||
},
|
||||
...common,
|
||||
};
|
||||
|
||||
export const borderDark = {
|
||||
color: {
|
||||
strong: grayScale.gray55,
|
||||
medium: grayScale.gray65,
|
||||
light: grayScale.gray70,
|
||||
secondaryInverted: grayScale.gray35,
|
||||
inverted: grayScale.gray20,
|
||||
},
|
||||
...common,
|
||||
};
|
||||
25
front/src/modules/ui/theme/constants/boxShadow.ts
Normal file
25
front/src/modules/ui/theme/constants/boxShadow.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { grayScale, rgba } from './colors';
|
||||
|
||||
export const boxShadowLight = {
|
||||
extraLight: `0px 1px 0px 0px ${rgba(grayScale.gray100, 0.04)}`,
|
||||
light: `0px 2px 4px 0px ${rgba(
|
||||
grayScale.gray100,
|
||||
0.04,
|
||||
)}, 0px 0px 4px 0px ${rgba(grayScale.gray100, 0.08)}`,
|
||||
strong: `2px 4px 16px 0px ${rgba(
|
||||
grayScale.gray100,
|
||||
0.12,
|
||||
)}, 0px 2px 4px 0px ${rgba(grayScale.gray100, 0.04)}`,
|
||||
};
|
||||
|
||||
export const boxShadowDark = {
|
||||
extraLight: `0px 1px 0px 0px ${rgba(grayScale.gray100, 0.04)}`,
|
||||
light: `0px 2px 4px 0px ${rgba(
|
||||
grayScale.gray100,
|
||||
0.04,
|
||||
)}, 0px 0px 4px 0px ${rgba(grayScale.gray100, 0.08)}`,
|
||||
strong: `2px 4px 16px 0px ${rgba(
|
||||
grayScale.gray100,
|
||||
0.16,
|
||||
)}, 0px 2px 4px 0px ${rgba(grayScale.gray100, 0.08)}`,
|
||||
};
|
||||
131
front/src/modules/ui/theme/constants/colors.ts
Normal file
131
front/src/modules/ui/theme/constants/colors.ts
Normal file
@ -0,0 +1,131 @@
|
||||
import hexRgb from 'hex-rgb';
|
||||
|
||||
export const grayScale = {
|
||||
gray100: '#000000',
|
||||
gray90: '#141414',
|
||||
gray85: '#171717',
|
||||
gray80: '#1b1b1b',
|
||||
gray75: '#1d1d1d',
|
||||
gray70: '#222222',
|
||||
gray65: '#292929',
|
||||
gray60: '#333333',
|
||||
gray55: '#4c4c4c',
|
||||
gray50: '#666666',
|
||||
gray45: '#818181',
|
||||
gray40: '#999999',
|
||||
gray35: '#b3b3b3',
|
||||
gray30: '#cccccc',
|
||||
gray25: '#d6d6d6',
|
||||
gray20: '#ebebeb',
|
||||
gray15: '#f1f1f1',
|
||||
gray10: '#fcfcfc',
|
||||
gray0: '#ffffff',
|
||||
};
|
||||
|
||||
export const color: { [key: string]: string } = {
|
||||
yellow: '#ffd338',
|
||||
yellow80: '#2e2a1a',
|
||||
yellow70: '#453d1e',
|
||||
yellow60: '#746224',
|
||||
yellow50: '#b99b2e',
|
||||
yellow40: '#ffe074',
|
||||
yellow30: '#ffedaf',
|
||||
yellow20: '#fff6d7',
|
||||
yellow10: '#fffbeb',
|
||||
green: '#55ef3c',
|
||||
green80: '#1d2d1b',
|
||||
green70: '#23421e',
|
||||
green60: '#2a5822',
|
||||
green50: '#3f7d2e',
|
||||
green40: '#7edc6a',
|
||||
green30: '#b9f5a3',
|
||||
green20: '#e0fbd1',
|
||||
green10: '#f3fde9',
|
||||
turquoise: '#15de8f',
|
||||
turquoise80: '#1b2d26',
|
||||
turquoise70: '#1f3f2b',
|
||||
turquoise60: '#244f30',
|
||||
turquoise50: '#2e6d3d',
|
||||
turquoise40: '#5cbf7a',
|
||||
turquoise30: '#9af0b0',
|
||||
turquoise20: '#c9fbd9',
|
||||
turquoise10: '#e8fde9',
|
||||
sky: '#00e0ff',
|
||||
sky80: '#1a2d2e',
|
||||
sky70: '#1e3f40',
|
||||
sky60: '#224f50',
|
||||
sky50: '#2d6d6d',
|
||||
sky40: '#5ac0c0',
|
||||
sky30: '#97f0f0',
|
||||
sky20: '#c5fbfb',
|
||||
sky10: '#e4fdfd',
|
||||
blue: '#1961ed',
|
||||
blue80: '#1a1d2d',
|
||||
blue70: '#1e203f',
|
||||
blue60: '#22244f',
|
||||
blue50: '#2d2e6d',
|
||||
blue40: '#5a5ac0',
|
||||
blue30: '#9797f0',
|
||||
blue20: '#c5c5fb',
|
||||
blue10: '#e4e4fd',
|
||||
purple: '#915ffd',
|
||||
purple80: '#2d1d2d',
|
||||
purple70: '#3f203f',
|
||||
purple60: '#502250',
|
||||
purple50: '#6d2e6d',
|
||||
purple40: '#bf5ac0',
|
||||
purple30: '#f097f0',
|
||||
purple20: '#fbc5fb',
|
||||
purple10: '#fde4fd',
|
||||
pink: '#f54bd0',
|
||||
pink80: '#2d1a2d',
|
||||
pink70: '#3f1e3f',
|
||||
pink60: '#50224f',
|
||||
pink50: '#6d2d6d',
|
||||
pink40: '#bf5ac0',
|
||||
pink30: '#f097f0',
|
||||
pink20: '#fbc5fb',
|
||||
pink10: '#fde4fd',
|
||||
red: '#f83e3e',
|
||||
red80: '#2d1a1a',
|
||||
red70: '#3f1e1e',
|
||||
red60: '#502222',
|
||||
red50: '#6d2d2d',
|
||||
red40: '#bf5a5a',
|
||||
red30: '#f09797',
|
||||
red20: '#fbc5c5',
|
||||
red10: '#fde4e4',
|
||||
orange: '#ff7222',
|
||||
orange80: '#2d1a16',
|
||||
orange70: '#3f1e19',
|
||||
orange60: '#50221c',
|
||||
orange50: '#6d2d2d',
|
||||
orange40: '#bf5a5a',
|
||||
orange30: '#f09797',
|
||||
orange20: '#fbc5c5',
|
||||
orange10: '#fde4e4',
|
||||
// TODO: Why color are not matching with design?
|
||||
gray: grayScale.gray30,
|
||||
gray80: grayScale.gray70,
|
||||
gray70: grayScale.gray65,
|
||||
gray60: grayScale.gray55,
|
||||
gray50: grayScale.gray40,
|
||||
gray40: grayScale.gray25,
|
||||
gray30: grayScale.gray20,
|
||||
gray20: grayScale.gray15,
|
||||
gray10: grayScale.gray10,
|
||||
gray0: grayScale.gray0,
|
||||
blueAccent90: '#141a25',
|
||||
blueAccent85: '#151D2E',
|
||||
blueAccent80: '#152037',
|
||||
blueAccent75: '#16233F',
|
||||
blueAccent25: '#dae6fc',
|
||||
blueAccent20: '#e2ecfd',
|
||||
blueAccent15: '#edf2fe',
|
||||
blueAccent10: '#f5f9fd',
|
||||
};
|
||||
|
||||
export function rgba(hex: string, alpha: number) {
|
||||
const rgb = hexRgb(hex, { format: 'array' }).slice(0, -1).join(',');
|
||||
return `rgba(${rgb},${alpha})`;
|
||||
}
|
||||
37
front/src/modules/ui/theme/constants/effects.ts
Normal file
37
front/src/modules/ui/theme/constants/effects.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { css } from '@emotion/react';
|
||||
|
||||
import { ThemeType } from './theme';
|
||||
|
||||
export const overlayBackground = (props: { theme: ThemeType }) =>
|
||||
css`
|
||||
backdrop-filter: blur(8px);
|
||||
background: ${props.theme.background.transparent.secondary};
|
||||
box-shadow: ${props.theme.boxShadow.strong};
|
||||
`;
|
||||
|
||||
export const textInputStyle = (props: { theme: ThemeType }) =>
|
||||
css`
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: ${props.theme.font.color.primary};
|
||||
font-family: ${props.theme.font.family};
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
outline: none;
|
||||
padding: ${props.theme.spacing(0)} ${props.theme.spacing(2)};
|
||||
|
||||
&::placeholder,
|
||||
&::-webkit-input-placeholder {
|
||||
color: ${props.theme.font.color.light};
|
||||
font-family: ${props.theme.font.family};
|
||||
font-weight: ${props.theme.font.weight.medium};
|
||||
}
|
||||
`;
|
||||
|
||||
export const hoverBackground = (props: any) =>
|
||||
css`
|
||||
transition: background 0.1s ease;
|
||||
&:hover {
|
||||
background: ${props.theme.background.transparent.light};
|
||||
}
|
||||
`;
|
||||
43
front/src/modules/ui/theme/constants/font.ts
Normal file
43
front/src/modules/ui/theme/constants/font.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { grayScale } from './colors';
|
||||
|
||||
const common = {
|
||||
size: {
|
||||
xxs: '0.625rem',
|
||||
xs: '0.85rem',
|
||||
sm: '0.92rem',
|
||||
md: '1rem',
|
||||
lg: '1.23rem',
|
||||
xl: '1.54rem',
|
||||
xxl: '1.85rem',
|
||||
},
|
||||
weight: {
|
||||
regular: 400,
|
||||
medium: 500,
|
||||
semiBold: 600,
|
||||
},
|
||||
family: 'Inter, sans-serif',
|
||||
};
|
||||
|
||||
export const fontLight = {
|
||||
color: {
|
||||
primary: grayScale.gray60,
|
||||
secondary: grayScale.gray50,
|
||||
tertiary: grayScale.gray40,
|
||||
light: grayScale.gray35,
|
||||
extraLight: grayScale.gray30,
|
||||
inverted: grayScale.gray0,
|
||||
},
|
||||
...common,
|
||||
};
|
||||
|
||||
export const fontDark = {
|
||||
color: {
|
||||
primary: grayScale.gray20,
|
||||
secondary: grayScale.gray35,
|
||||
tertiary: grayScale.gray45,
|
||||
light: grayScale.gray50,
|
||||
extraLight: grayScale.gray55,
|
||||
inverted: grayScale.gray100,
|
||||
},
|
||||
...common,
|
||||
};
|
||||
13
front/src/modules/ui/theme/constants/icon.ts
Normal file
13
front/src/modules/ui/theme/constants/icon.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export const icon = {
|
||||
size: {
|
||||
sm: 14,
|
||||
md: 16,
|
||||
lg: 20,
|
||||
xl: 40,
|
||||
},
|
||||
stroke: {
|
||||
sm: 1.6,
|
||||
md: 2,
|
||||
lg: 2.5,
|
||||
},
|
||||
};
|
||||
55
front/src/modules/ui/theme/constants/tag.ts
Normal file
55
front/src/modules/ui/theme/constants/tag.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { color } from './colors';
|
||||
|
||||
export const tagLight: { [key: string]: { [key: string]: string } } = {
|
||||
text: {
|
||||
green: color.green60,
|
||||
turquoise: color.turquoise60,
|
||||
sky: color.sky60,
|
||||
blue: color.blue60,
|
||||
purple: color.purple60,
|
||||
pink: color.pink60,
|
||||
red: color.red60,
|
||||
orange: color.orange60,
|
||||
yellow: color.yellow60,
|
||||
gray: color.gray60,
|
||||
},
|
||||
background: {
|
||||
green: color.green20,
|
||||
turquoise: color.turquoise20,
|
||||
sky: color.sky20,
|
||||
blue: color.blue20,
|
||||
purple: color.purple20,
|
||||
pink: color.pink20,
|
||||
red: color.red20,
|
||||
orange: color.orange20,
|
||||
yellow: color.yellow20,
|
||||
gray: color.gray20,
|
||||
},
|
||||
};
|
||||
|
||||
export const tagDark = {
|
||||
text: {
|
||||
green: color.green10,
|
||||
turquoise: color.turquoise10,
|
||||
sky: color.sky10,
|
||||
blue: color.blue10,
|
||||
purple: color.purple10,
|
||||
pink: color.pink10,
|
||||
red: color.red10,
|
||||
orange: color.orange10,
|
||||
yellow: color.yellow10,
|
||||
gray: color.gray10,
|
||||
},
|
||||
background: {
|
||||
green: color.green60,
|
||||
turquoise: color.turquoise60,
|
||||
sky: color.sky60,
|
||||
blue: color.blue60,
|
||||
purple: color.purple60,
|
||||
pink: color.pink60,
|
||||
red: color.red60,
|
||||
orange: color.orange60,
|
||||
yellow: color.yellow60,
|
||||
gray: color.gray60,
|
||||
},
|
||||
};
|
||||
13
front/src/modules/ui/theme/constants/text.ts
Normal file
13
front/src/modules/ui/theme/constants/text.ts
Normal file
@ -0,0 +1,13 @@
|
||||
export const text = {
|
||||
lineHeight: {
|
||||
lg: 1.5,
|
||||
md: 1.2,
|
||||
},
|
||||
|
||||
iconSizeMedium: 16,
|
||||
iconSizeSmall: 14,
|
||||
|
||||
iconStrikeLight: 1.6,
|
||||
iconStrikeMedium: 2,
|
||||
iconStrikeBold: 2.5,
|
||||
};
|
||||
71
front/src/modules/ui/theme/constants/theme.ts
Normal file
71
front/src/modules/ui/theme/constants/theme.ts
Normal file
@ -0,0 +1,71 @@
|
||||
import { accentDark, accentLight } from './accent';
|
||||
import { animation } from './animation';
|
||||
import { backgroundDark, backgroundLight } from './background';
|
||||
import { blur } from './blur';
|
||||
import { borderDark, borderLight } from './border';
|
||||
import { boxShadowDark, boxShadowLight } from './boxShadow';
|
||||
import { color, grayScale } from './colors';
|
||||
import { fontDark, fontLight } from './font';
|
||||
import { icon } from './icon';
|
||||
import { tagDark, tagLight } from './tag';
|
||||
import { text } from './text';
|
||||
|
||||
const common = {
|
||||
color: color,
|
||||
grayScale: grayScale,
|
||||
icon: icon,
|
||||
text: text,
|
||||
blur: blur,
|
||||
animation: animation,
|
||||
snackBar: {
|
||||
success: {
|
||||
background: '#16A26B',
|
||||
color: '#D0F8E9',
|
||||
},
|
||||
error: {
|
||||
background: '#B43232',
|
||||
color: '#FED8D8',
|
||||
},
|
||||
info: {
|
||||
background: color.gray80,
|
||||
color: color.gray0,
|
||||
},
|
||||
},
|
||||
spacing: (multiplicator: number) => `${multiplicator * 4}px`,
|
||||
table: {
|
||||
horizontalCellMargin: '8px',
|
||||
checkboxColumnWidth: '32px',
|
||||
},
|
||||
rightDrawerWidth: '500px',
|
||||
clickableElementBackgroundTransition: 'background 0.1s ease',
|
||||
lastLayerZIndex: 2147483647,
|
||||
};
|
||||
|
||||
export const lightTheme = {
|
||||
...common,
|
||||
...{
|
||||
accent: accentLight,
|
||||
background: backgroundLight,
|
||||
border: borderLight,
|
||||
tag: tagLight,
|
||||
boxShadow: boxShadowLight,
|
||||
font: fontLight,
|
||||
name: 'light',
|
||||
},
|
||||
};
|
||||
export type ThemeType = typeof lightTheme;
|
||||
|
||||
export const darkTheme: ThemeType = {
|
||||
...common,
|
||||
...{
|
||||
accent: accentDark,
|
||||
background: backgroundDark,
|
||||
border: borderDark,
|
||||
tag: tagDark,
|
||||
boxShadow: boxShadowDark,
|
||||
font: fontDark,
|
||||
name: 'dark',
|
||||
},
|
||||
};
|
||||
|
||||
export const MOBILE_VIEWPORT = 768;
|
||||
67
front/src/modules/ui/theme/hooks/useColorScheme.ts
Normal file
67
front/src/modules/ui/theme/hooks/useColorScheme.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { ColorScheme, useUpdateUserMutation } from '~/generated/graphql';
|
||||
|
||||
export function useColorScheme() {
|
||||
const [currentUser] = useRecoilState(currentUserState);
|
||||
|
||||
const [updateUser] = useUpdateUserMutation();
|
||||
|
||||
const colorScheme = useMemo(() => {
|
||||
if (!currentUser?.settings?.colorScheme) {
|
||||
// Use system color scheme if user is not logged in or has no settings
|
||||
return ColorScheme.System;
|
||||
}
|
||||
|
||||
return currentUser.settings.colorScheme;
|
||||
}, [currentUser?.settings?.colorScheme]);
|
||||
|
||||
const setColorScheme = useCallback(
|
||||
async (value: ColorScheme) => {
|
||||
try {
|
||||
const result = await updateUser({
|
||||
variables: {
|
||||
where: {
|
||||
id: currentUser?.id,
|
||||
},
|
||||
data: {
|
||||
settings: {
|
||||
update: {
|
||||
colorScheme: value,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
optimisticResponse:
|
||||
currentUser && currentUser.settings
|
||||
? {
|
||||
__typename: 'Mutation',
|
||||
updateUser: {
|
||||
__typename: 'User',
|
||||
...currentUser,
|
||||
settings: {
|
||||
__typename: 'UserSettings',
|
||||
id: currentUser.settings.id,
|
||||
colorScheme: value,
|
||||
locale: currentUser.settings.locale,
|
||||
},
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
if (!result.data || result.errors) {
|
||||
throw result.errors;
|
||||
}
|
||||
} catch (err) {}
|
||||
},
|
||||
[currentUser, updateUser],
|
||||
);
|
||||
|
||||
return {
|
||||
colorScheme,
|
||||
setColorScheme,
|
||||
};
|
||||
}
|
||||
39
front/src/modules/ui/theme/hooks/useSystemColorScheme.ts
Normal file
39
front/src/modules/ui/theme/hooks/useSystemColorScheme.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { ColorScheme } from '~/generated/graphql';
|
||||
|
||||
export type SystemColorScheme = ColorScheme.Light | ColorScheme.Dark;
|
||||
|
||||
export function useSystemColorScheme(): SystemColorScheme {
|
||||
const mediaQuery = useMemo(
|
||||
() => window.matchMedia('(prefers-color-scheme: dark)'),
|
||||
[],
|
||||
);
|
||||
|
||||
const [preferredColorScheme, setPreferredColorScheme] =
|
||||
useState<SystemColorScheme>(
|
||||
!window.matchMedia || !mediaQuery.matches
|
||||
? ColorScheme.Light
|
||||
: ColorScheme.Dark,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!window.matchMedia) {
|
||||
return;
|
||||
}
|
||||
|
||||
function handleChange(event: MediaQueryListEvent): void {
|
||||
setPreferredColorScheme(
|
||||
event.matches ? ColorScheme.Dark : ColorScheme.Light,
|
||||
);
|
||||
}
|
||||
|
||||
mediaQuery.addEventListener('change', handleChange);
|
||||
|
||||
return () => {
|
||||
mediaQuery.removeEventListener('change', handleChange);
|
||||
};
|
||||
}, [mediaQuery]);
|
||||
|
||||
return preferredColorScheme;
|
||||
}
|
||||
Reference in New Issue
Block a user