refactor: 修改配色方案逻辑,为之后的自定义主题插件留位置

pull/13/head
moonrailgun 4 years ago
parent 5db0a5410d
commit 747cca8e83

@ -1,11 +1,11 @@
import React from 'react';
import { CacheProvider } from '../cache/Provider';
import { DarkModeContextProvider } from '../contexts/DarkModeContext';
import { ColorSchemeContextProvider } from '../contexts/ColorSchemeContext';
export const TcProvider: React.FC = React.memo((props) => {
return (
<CacheProvider>
<DarkModeContextProvider>{props.children}</DarkModeContextProvider>
<ColorSchemeContextProvider>{props.children}</ColorSchemeContextProvider>
</CacheProvider>
);
});

@ -0,0 +1,32 @@
import React, { useContext } from 'react';
import { useStorage } from 'tailchat-shared';
const ColorSchemeContext = React.createContext<{
/**
* 'dark' | 'light' | 'auto' | string
*/
colorScheme: string;
setColorScheme: (colorScheme: string) => void;
}>({
colorScheme: 'dark',
setColorScheme: () => {},
});
ColorSchemeContext.displayName = 'ColorSchemeContext';
export const ColorSchemeContextProvider: React.FC = React.memo((props) => {
const [colorScheme = 'dark', { save: setColorScheme }] = useStorage(
'colorScheme',
'dark'
);
return (
<ColorSchemeContext.Provider value={{ colorScheme, setColorScheme }}>
{props.children}
</ColorSchemeContext.Provider>
);
});
ColorSchemeContextProvider.displayName = 'ColorSchemeContextProvider';
export function useColorScheme() {
return useContext(ColorSchemeContext);
}

@ -1,26 +0,0 @@
import React, { useContext } from 'react';
import { useStorage } from 'tailchat-shared';
const DarkModeContext = React.createContext<{
darkMode: boolean;
setDarkMode: (isDarkMode: boolean) => void;
}>({
darkMode: true,
setDarkMode: () => {},
});
DarkModeContext.displayName = 'DarkModeContext';
export const DarkModeContextProvider: React.FC = React.memo((props) => {
const [darkMode = true, { save: setDarkMode }] = useStorage('darkMode', true);
return (
<DarkModeContext.Provider value={{ darkMode, setDarkMode }}>
{props.children}
</DarkModeContext.Provider>
);
});
DarkModeContextProvider.displayName = 'DarkModeContextProvider';
export function useDarkMode() {
return useContext(DarkModeContext);
}

@ -1,3 +1,5 @@
export const t = (key: string) => {
return key;
};
export function onLanguageChange() {}

@ -34,7 +34,7 @@ export { buildPortal, DefaultEventEmitter } from './components/Portal';
export { TcProvider } from './components/Provider';
// contexts
export { useDarkMode } from './contexts/DarkModeContext';
export { useColorScheme } from './contexts/ColorSchemeContext';
// i18n
export { t, setLanguage, useTranslation } from './i18n';

@ -1,10 +1,10 @@
import React, { useCallback } from 'react';
import { BrowserRouter, Redirect, Route, Switch } from 'react-router-dom';
import { TcProvider, useDarkMode, useStorage } from 'tailchat-shared';
import { TcProvider, useColorScheme } from 'tailchat-shared';
import clsx from 'clsx';
import { Loadable } from './components/Loadable';
import { ConfigProvider as AntdProvider } from 'antd';
import { PortalHost } from './components/Portal';
import { parseColorScheme } from './utils/color-scheme-helper';
const MainRoute = Loadable(() =>
import('./routes/Main').then((module) => module.MainRoute)
@ -44,14 +44,19 @@ const AppProvider: React.FC = React.memo((props) => {
AppProvider.displayName = 'AppProvider';
export const AppContainer: React.FC = React.memo((props) => {
const { darkMode } = useDarkMode();
const { colorScheme } = useColorScheme();
const { isDarkMode, extraSchemeName } = parseColorScheme(colorScheme);
return (
<div
id="tailchat-app"
className={clsx('absolute inset-0 select-none', {
dark: darkMode,
})}
className={clsx(
'absolute inset-0 select-none',
{
dark: isDarkMode,
},
extraSchemeName
)}
>
{props.children}
</div>

@ -1,13 +1,13 @@
import DevContainer from '@/components/DevContainer';
import { FullModalField } from '@/components/FullModal/Field';
import { Select, Switch } from 'antd';
import { Select } from 'antd';
import React, { useCallback } from 'react';
import { showToasts, t, useDarkMode } from 'tailchat-shared';
import { showToasts, t, useColorScheme } from 'tailchat-shared';
import { useLanguage } from 'tailchat-shared';
export const SettingsSystem: React.FC = React.memo(() => {
const { language, setLanguage } = useLanguage();
const { darkMode, setDarkMode } = useDarkMode();
const { colorScheme, setColorScheme } = useColorScheme();
const handleChangeLanguage = useCallback(
(newLang: string) => {
@ -36,12 +36,18 @@ export const SettingsSystem: React.FC = React.memo(() => {
<DevContainer>
<FullModalField
title={t('暗黑模式')}
title={t('配色方案')}
content={
<Switch
checked={darkMode}
onChange={(checked) => setDarkMode(checked)}
/>
<Select
style={{ width: 300 }}
size="large"
value={colorScheme}
onChange={setColorScheme}
>
<Select.Option value="dark">{t('暗黑模式')}</Select.Option>
<Select.Option value="light">{t('亮色模式')}</Select.Option>
<Select.Option value="auto">{t('自动')}</Select.Option>
</Select>
}
/>
</DevContainer>

@ -0,0 +1,14 @@
import { parseColorScheme } from '../color-scheme-helper';
describe('parseColorScheme', () => {
test.each([
['dark', { isDarkMode: true, extraSchemeName: null }],
['light', { isDarkMode: false, extraSchemeName: null }],
['auto', { isDarkMode: true, extraSchemeName: null }],
['dark+miku', { isDarkMode: true, extraSchemeName: 'theme-miku' }],
['light+miku', { isDarkMode: false, extraSchemeName: 'theme-miku' }],
['miku', { isDarkMode: true, extraSchemeName: 'theme-miku' }],
])('%s', (input, output) => {
expect(parseColorScheme(input)).toEqual(output);
});
});

@ -0,0 +1,41 @@
import { isValidStr } from 'tailchat-shared';
/**
* dark
*/
export function parseColorScheme(colorScheme: string): {
isDarkMode: boolean;
extraSchemeName: string | null;
} {
if (colorScheme === 'dark') {
return {
isDarkMode: true,
extraSchemeName: null,
};
} else if (colorScheme === 'light') {
return {
isDarkMode: false,
extraSchemeName: null,
};
} else if (colorScheme === 'auto') {
return {
isDarkMode: window.matchMedia
? window.matchMedia('(prefers-color-scheme: dark)').matches
: true,
extraSchemeName: null,
};
} else {
// 可能是插件 for example: dark+miku
let [base, name] = colorScheme.split('+');
if (!isValidStr(name)) {
name = base;
base = 'dark';
}
return {
isDarkMode: base === 'dark',
extraSchemeName: `theme-${name}`,
};
}
}
Loading…
Cancel
Save