client: make useTheme global hook

This commit is contained in:
fantasticit 2022-05-21 15:35:16 +08:00
parent 87635e88cf
commit a42acc4015
5 changed files with 56 additions and 15 deletions

View File

@ -1,11 +1,11 @@
import { IconMoon, IconSun } from '@douyinfe/semi-icons';
import { Button } from '@douyinfe/semi-ui';
import { Tooltip } from 'components/tooltip';
import { useTheme } from 'hooks/use-theme';
import { Theme as ThemeState } from 'hooks/use-theme';
import React from 'react';
export const Theme = () => {
const { theme, toggle } = useTheme();
const { theme, toggle } = ThemeState.useHook();
const Icon = theme === 'dark' ? IconSun : IconMoon;
const text = theme === 'dark' ? '切换到亮色模式' : '切换到深色模式';

View File

@ -0,0 +1,33 @@
import React, { createContext, useContext } from 'react';
const EMPTY = Symbol();
export interface ContainerProviderProps<State = void> {
initialState?: State;
children: React.ReactNode;
}
interface GlobalHook<Value, State> {
Provider: React.ComponentType<ContainerProviderProps<State>>;
useHook: () => Value;
}
export function createGlobalHook<Value, State = void>(hook): GlobalHook<Value, State> {
const Context = createContext<Value | typeof EMPTY>(EMPTY);
function Provider(props) {
const value = hook(props.initialState);
return <Context.Provider value={value}>{props.children}</Context.Provider>;
}
function useHook() {
const value = useContext(Context);
if (value === EMPTY) {
throw new Error('You forget to wrap component with<Context.Provider>');
}
return value;
}
return { Provider, useHook };
}

View File

@ -1,15 +1,17 @@
import { useCallback, useEffect, useState } from 'react';
export enum Theme {
import { createGlobalHook } from './create-global-hook';
export enum ThemeEnum {
'dark' = 'dark',
'light' = 'light',
}
export const useTheme = () => {
const [theme, setTheme] = useState(Theme.light);
const useThemeHook = () => {
const [theme, setTheme] = useState(ThemeEnum.light);
const toggle = useCallback(() => {
const nextTheme = theme === 'dark' ? Theme.light : Theme.dark;
const nextTheme = theme === 'dark' ? ThemeEnum.light : ThemeEnum.dark;
setTheme(nextTheme);
}, [theme]);
@ -30,14 +32,18 @@ export const useTheme = () => {
function matchMode(e) {
if (e.matches) {
setTheme(Theme.dark);
setTheme(ThemeEnum.dark);
} else {
setTheme(Theme.light);
setTheme(ThemeEnum.light);
}
}
matchMode(mql);
mql.addEventListener('change', matchMode);
return () => {
mql.removeEventListener('change', matchMode);
};
}, []);
return {
@ -45,3 +51,5 @@ export const useTheme = () => {
toggle,
};
};
export const Theme = createGlobalHook<{ theme: ThemeEnum; toggle: () => void }>(useThemeHook);

View File

@ -3,20 +3,20 @@ import 'viewerjs/dist/viewer.css';
import 'styles/globals.scss';
import 'tiptap/core/styles/index.scss';
import { useTheme } from 'hooks/use-theme';
import { Theme } from 'hooks/use-theme';
import type { AppProps } from 'next/app';
import Head from 'next/head';
import React from 'react';
function MyApp({ Component, pageProps }: AppProps) {
useTheme();
return (
<>
<Head>
<meta name="viewport" content="viewport-fit=cover" />
</Head>
<Component {...pageProps} />
<Theme.Provider>
<Component {...pageProps} />
</Theme.Provider>
</>
);
}

View File

@ -2,7 +2,7 @@ import { NodeViewContent, NodeViewWrapper } from '@tiptap/react';
import cls from 'classnames';
import { EmojiPicker } from 'components/emoji-picker';
import { convertColorToRGBA } from 'helpers/color';
import { Theme, useTheme } from 'hooks/use-theme';
import { Theme, ThemeEnum } from 'hooks/use-theme';
import { useCallback, useMemo } from 'react';
import styles from './index.module.scss';
@ -10,10 +10,10 @@ import styles from './index.module.scss';
export const CalloutWrapper = ({ editor, node, updateAttributes }) => {
const { isEditable } = editor;
const { emoji, textColor, borderColor, backgroundColor } = node.attrs;
const { theme } = useTheme();
const { theme } = Theme.useHook();
const backgroundColorOpacity = useMemo(() => {
if (!backgroundColor) return backgroundColor;
if (theme === Theme.dark) return convertColorToRGBA(backgroundColor, 0.85);
if (theme === ThemeEnum.dark) return convertColorToRGBA(backgroundColor, 0.75);
return backgroundColor;
}, [backgroundColor, theme]);