mirror of https://github.com/fantasticit/think.git
client: make useTheme global hook
This commit is contained in:
parent
87635e88cf
commit
a42acc4015
|
@ -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' ? '切换到亮色模式' : '切换到深色模式';
|
||||
|
||||
|
|
|
@ -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 };
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
Loading…
Reference in New Issue