feat: implementing experience page (#718)

* feat: add color scheme toggle
* feat: colorScheme stored in UserSettings model
* feat: add stories
* fix: AnimatePresence exit not working

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Jérémy M
2023-07-18 19:47:27 +02:00
committed by GitHub
parent 4ec93d4b6a
commit 19e165fc05
137 changed files with 2792 additions and 75 deletions

View File

@ -104,6 +104,7 @@ export const color = {
orange30: '#f09797',
orange20: '#fbc5c5',
orange10: '#fde4e4',
// TODO: Why color are not matching with design?
gray: grayScale.gray30,
gray80: grayScale.gray65,
gray70: grayScale.gray60,

View File

@ -1,14 +1,29 @@
import { ThemeProvider } from '@emotion/react';
import { darkTheme, lightTheme } from '@/ui/themes/themes';
import { browserPrefersDarkMode } from '~/utils';
import { ColorScheme } from '~/generated/graphql';
import { useColorScheme } from '../hooks/useColorScheme';
import { useSystemColorScheme } from '../hooks/useSystemColorScheme';
type OwnProps = {
children: JSX.Element;
};
export function AppThemeProvider({ children }: OwnProps) {
const selectedTheme = browserPrefersDarkMode() ? darkTheme : lightTheme;
const themes = {
[ColorScheme.Dark]: darkTheme,
[ColorScheme.Light]: lightTheme,
};
return <ThemeProvider theme={selectedTheme}>{children}</ThemeProvider>;
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,53 @@
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: {
set: value,
},
},
},
},
},
});
if (!result.data || result.errors) {
throw result.errors;
}
} catch (err) {}
},
[currentUser?.id, 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;
}