Clean and re-organize post table refactoring (#1000)

* Clean and re-organize post table refactoring

* Fix tests
This commit is contained in:
Charles Bochet
2023-07-30 18:26:32 -07:00
committed by GitHub
parent 86a2d67efd
commit ade5e52e55
336 changed files with 638 additions and 2757 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View 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>;
}

View 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,
};

View File

@ -0,0 +1,7 @@
export const animation = {
duration: {
instant: 0.075,
fast: 0.15,
normal: 0.3,
},
};

View 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),
};

View File

@ -0,0 +1,4 @@
export const blur = {
light: 'blur(6px)',
strong: 'blur(20px)',
};

View 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,
};

View 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)}`,
};

View 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})`;
}

View 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};
}
`;

View 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,
};

View 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,
},
};

View 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,
},
};

View 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,
};

View 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;

View 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,
};
}

View 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;
}