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:
@ -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,
|
||||
|
||||
@ -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>;
|
||||
}
|
||||
|
||||
53
front/src/modules/ui/themes/hooks/useColorScheme.ts
Normal file
53
front/src/modules/ui/themes/hooks/useColorScheme.ts
Normal 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,
|
||||
};
|
||||
}
|
||||
39
front/src/modules/ui/themes/hooks/useSystemColorScheme.ts
Normal file
39
front/src/modules/ui/themes/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