Add dark mode state to global state.

* update mobile menu icon dark color
* update post page dark mode
This commit is contained in:
DefectingCat
2022-01-19 17:38:02 +08:00
parent f4ab03e711
commit 7c21f3c607
6 changed files with 58 additions and 19 deletions

View File

@ -5,6 +5,7 @@ import UseAnimations from 'react-useanimations';
import menu3 from 'react-useanimations/lib/menu3';
import { IconType } from 'react-icons';
import dynamic from 'next/dynamic';
import useDarkMode from 'lib/hooks/useDarkMode';
const NavAvatar = dynamic(() => import('components/nav/NavAvatar'));
const NavMenuItem = dynamic(() => import('components/nav/NavMenuItem'));
@ -44,13 +45,15 @@ export const menus: MenuItem[] = [
];
const NavBar: FC = () => {
const { isDark } = useDarkMode();
const [menuIsOpen, setMenuIsOpen] = useState(false);
const iconRef = useRef<HTMLDivElement>(null);
const onToggle = useCallback(() => {
setMenuIsOpen((menuIsOpen) => !menuIsOpen);
}, []);
// Mobile menu icon must manually clicked to colse when click the menu item.
// Mobile menu icon must manually click to colse when click the menu item.
const handleMenuClick = useCallback(() => {
(iconRef.current?.children[0] as HTMLDivElement).click();
}, []);
@ -68,6 +71,7 @@ const NavBar: FC = () => {
animation={menu3}
speed={2}
onClick={onToggle}
strokeColor={isDark ? 'white' : 'black'}
/>
</div>
</div>
@ -78,10 +82,11 @@ const NavBar: FC = () => {
{ 'max-h-[500px]': menuIsOpen },
{ 'py-4': menuIsOpen },
{ 'max-h-0': !menuIsOpen },
'bg-white mx-[-1.5rem] px-6 mt-4 overflow-hidden',
'bg-white mx-[-1.5rem] px-6 mt-4 overflow-hidden',
'md:block md:bg-transparent md:mx-0 md:p-0',
'transition-all duration-500 h-auto ',
'md:max-h-max'
'md:max-h-max',
'dark:bg-rua-gray-800 md:dark:bg-transparent'
)}
>
{menus.map((menu) => (

View File

@ -14,7 +14,12 @@ interface Props {
const PostHeader: FC<Props> = ({ title, tags, date }) => {
return (
<header className={'mb-6'}>
<h1 className={'text-3xl md:text-4xl font-semibold text-gray-700 mb-4'}>
<h1
className={cn(
'text-3xl md:text-4xl font-semibold mb-4',
'text-gray-700 dark:text-gray-300'
)}
>
{title}
</h1>
@ -26,7 +31,7 @@ const PostHeader: FC<Props> = ({ title, tags, date }) => {
key={item}
className={cn(
'rounded-md bg-gray-100 px-2 py-1 inline text-sm',
'text-gray-700 mr-3'
'text-gray-700 mr-3 '
)}
>
{item}
@ -37,7 +42,7 @@ const PostHeader: FC<Props> = ({ title, tags, date }) => {
<div
className={cn(
'rounded-md bg-gray-100 px-2 py-1 inline text-sm',
'text-gray-700'
'text-gray-700 dark:text-gray-300 dark:bg-gray-500'
)}
>
{tags}
@ -45,7 +50,9 @@ const PostHeader: FC<Props> = ({ title, tags, date }) => {
)}
</div>
<div className={'flex items-center text-gray-600 text-sm'}>
<div
className={'flex items-center text-gray-600 dark:text-gray-400 text-sm'}
>
<FiCalendar className={'mr-2'} />
<DateFormater dateString={date} />
</div>

View File

@ -1,20 +1,24 @@
import { useEffect, useState } from 'react';
import { ActionKind, useRUAContext } from '../store';
const useDarkMode = () => {
const [isDark, setIsDark] = useState(false);
useEffect(() => {
setIsDark(document.documentElement.classList.contains('dark'));
}, []);
const { state, dispatch } = useRUAContext();
const { isDark } = state;
const toggleDark = () => {
if (isDark) {
document.documentElement.classList.remove('dark');
localStorage.setItem('rua-theme', 'light');
setIsDark(document.documentElement.classList.contains('dark'));
dispatch({
type: ActionKind.SETTHEME,
payload: '',
});
} else {
document.documentElement.classList.add('dark');
localStorage.setItem('rua-theme', 'dark');
setIsDark(document.documentElement.classList.contains('dark'));
dispatch({
type: ActionKind.SETTHEME,
payload: '',
});
}
};

View File

@ -1,8 +1,9 @@
import React, { FC, useReducer } from 'react';
import React, { FC, useEffect, useReducer } from 'react';
export enum ActionKind {
SETQUERY = 'SETQUERY',
SETPATH = 'SETPATH',
SETTHEME = 'SETTHEME',
}
type ReducerAction = {
@ -21,11 +22,17 @@ type State = {
* Back path to record where to go back.
*/
backPath: string;
/**
* Use document.documentElement.classList
*/
isDark: boolean;
};
const initialState: State = {
searchQuery: '',
backPath: '',
isDark: false,
};
const reducer = (state: State, action: ReducerAction): State => {
@ -35,6 +42,11 @@ const reducer = (state: State, action: ReducerAction): State => {
return { ...state, searchQuery: payload };
case ActionKind.SETPATH:
return { ...state, backPath: payload };
case ActionKind.SETTHEME:
return {
...state,
isDark: document.documentElement.classList.contains('dark'),
};
default:
throw new Error();
}
@ -51,6 +63,13 @@ const RUAContext = React.createContext<{
const RUAStore: FC = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
useEffect(() => {
dispatch({
type: ActionKind.SETTHEME,
payload: '',
});
}, []);
return (
<>
<RUAContext.Provider value={{ state, dispatch }}>

View File

@ -69,7 +69,7 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
<div
className={cn(
'grid grid-cols-12 gap-4 p-2 container mx-auto',
'grid grid-cols-12 gap-4 px-2 py-4 container mx-auto',
'md:py-8'
)}
>
@ -97,7 +97,11 @@ const Post = ({ postData }: InferGetStaticPropsType<typeof getStaticProps>) => {
</aside>
<main className={'md:col-span-10 col-span-12 lg:col-span-8'}>
<div className={'bg-white shadow-md rounded-lg overflow-hidden'}>
<div
className={
'bg-white dark:bg-rua-gray-800 shadow-md rounded-lg overflow-hidden'
}
>
{index_img && (
<div className="relative aspect-video">
<Image

View File

@ -4,7 +4,7 @@
}
#write {
@apply text-gray-600;
@apply text-gray-600 dark:text-gray-300;
}
#table-of-contents {
@ -247,7 +247,7 @@
#write code,
#write tt {
@apply bg-gray-100 rounded-md;
@apply bg-gray-100 dark:bg-gray-500 rounded-md;
padding: 0 4px;
font-size: 0.9em;
}