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 { IconMoon, IconSun } from '@douyinfe/semi-icons';
|
||||||
import { Button } from '@douyinfe/semi-ui';
|
import { Button } from '@douyinfe/semi-ui';
|
||||||
import { Tooltip } from 'components/tooltip';
|
import { Tooltip } from 'components/tooltip';
|
||||||
import { useTheme } from 'hooks/use-theme';
|
import { Theme as ThemeState } from 'hooks/use-theme';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export const Theme = () => {
|
export const Theme = () => {
|
||||||
const { theme, toggle } = useTheme();
|
const { theme, toggle } = ThemeState.useHook();
|
||||||
const Icon = theme === 'dark' ? IconSun : IconMoon;
|
const Icon = theme === 'dark' ? IconSun : IconMoon;
|
||||||
const text = theme === 'dark' ? '切换到亮色模式' : '切换到深色模式';
|
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';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
export enum Theme {
|
import { createGlobalHook } from './create-global-hook';
|
||||||
|
|
||||||
|
export enum ThemeEnum {
|
||||||
'dark' = 'dark',
|
'dark' = 'dark',
|
||||||
'light' = 'light',
|
'light' = 'light',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useTheme = () => {
|
const useThemeHook = () => {
|
||||||
const [theme, setTheme] = useState(Theme.light);
|
const [theme, setTheme] = useState(ThemeEnum.light);
|
||||||
|
|
||||||
const toggle = useCallback(() => {
|
const toggle = useCallback(() => {
|
||||||
const nextTheme = theme === 'dark' ? Theme.light : Theme.dark;
|
const nextTheme = theme === 'dark' ? ThemeEnum.light : ThemeEnum.dark;
|
||||||
setTheme(nextTheme);
|
setTheme(nextTheme);
|
||||||
}, [theme]);
|
}, [theme]);
|
||||||
|
|
||||||
|
@ -30,14 +32,18 @@ export const useTheme = () => {
|
||||||
|
|
||||||
function matchMode(e) {
|
function matchMode(e) {
|
||||||
if (e.matches) {
|
if (e.matches) {
|
||||||
setTheme(Theme.dark);
|
setTheme(ThemeEnum.dark);
|
||||||
} else {
|
} else {
|
||||||
setTheme(Theme.light);
|
setTheme(ThemeEnum.light);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
matchMode(mql);
|
matchMode(mql);
|
||||||
mql.addEventListener('change', matchMode);
|
mql.addEventListener('change', matchMode);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
mql.removeEventListener('change', matchMode);
|
||||||
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -45,3 +51,5 @@ export const useTheme = () => {
|
||||||
toggle,
|
toggle,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Theme = createGlobalHook<{ theme: ThemeEnum; toggle: () => void }>(useThemeHook);
|
||||||
|
|
|
@ -3,20 +3,20 @@ import 'viewerjs/dist/viewer.css';
|
||||||
import 'styles/globals.scss';
|
import 'styles/globals.scss';
|
||||||
import 'tiptap/core/styles/index.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 type { AppProps } from 'next/app';
|
||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
useTheme();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<Head>
|
||||||
<meta name="viewport" content="viewport-fit=cover" />
|
<meta name="viewport" content="viewport-fit=cover" />
|
||||||
</Head>
|
</Head>
|
||||||
<Component {...pageProps} />
|
<Theme.Provider>
|
||||||
|
<Component {...pageProps} />
|
||||||
|
</Theme.Provider>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { NodeViewContent, NodeViewWrapper } from '@tiptap/react';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { EmojiPicker } from 'components/emoji-picker';
|
import { EmojiPicker } from 'components/emoji-picker';
|
||||||
import { convertColorToRGBA } from 'helpers/color';
|
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 { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
@ -10,10 +10,10 @@ import styles from './index.module.scss';
|
||||||
export const CalloutWrapper = ({ editor, node, updateAttributes }) => {
|
export const CalloutWrapper = ({ editor, node, updateAttributes }) => {
|
||||||
const { isEditable } = editor;
|
const { isEditable } = editor;
|
||||||
const { emoji, textColor, borderColor, backgroundColor } = node.attrs;
|
const { emoji, textColor, borderColor, backgroundColor } = node.attrs;
|
||||||
const { theme } = useTheme();
|
const { theme } = Theme.useHook();
|
||||||
const backgroundColorOpacity = useMemo(() => {
|
const backgroundColorOpacity = useMemo(() => {
|
||||||
if (!backgroundColor) return backgroundColor;
|
if (!backgroundColor) return backgroundColor;
|
||||||
if (theme === Theme.dark) return convertColorToRGBA(backgroundColor, 0.85);
|
if (theme === ThemeEnum.dark) return convertColorToRGBA(backgroundColor, 0.75);
|
||||||
return backgroundColor;
|
return backgroundColor;
|
||||||
}, [backgroundColor, theme]);
|
}, [backgroundColor, theme]);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue