mirror of
https://github.com/DefectingCat/DefectingCat.github.io
synced 2025-07-15 16:51:37 +00:00
Add dark mode state to global state.
* update mobile menu icon dark color * update post page dark mode
This commit is contained in:
@ -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) => (
|
||||
|
@ -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>
|
||||
|
@ -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: '',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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 }}>
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user