feat: add theme hook and change color of stats chart
This commit is contained in:
parent
c180d1d5f1
commit
72e3753503
@ -22,6 +22,7 @@
|
||||
"axios": "^1.5.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"clsx": "^2.0.0",
|
||||
"colord": "^2.9.3",
|
||||
"compose-middleware": "^5.0.1",
|
||||
"compression": "^1.7.4",
|
||||
"dayjs": "^1.11.9",
|
||||
|
@ -28,6 +28,9 @@ dependencies:
|
||||
clsx:
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
colord:
|
||||
specifier: ^2.9.3
|
||||
version: 2.9.3
|
||||
compose-middleware:
|
||||
specifier: ^5.0.1
|
||||
version: 5.0.1
|
||||
@ -2519,6 +2522,10 @@ packages:
|
||||
color-string: 1.9.1
|
||||
dev: false
|
||||
|
||||
/colord@2.9.3:
|
||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||
dev: false
|
||||
|
||||
/combined-stream@1.0.8:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
@ -22,6 +22,7 @@ import {
|
||||
import { useEvent } from '../hooks/useEvent';
|
||||
import { MetricCard } from './MetricCard';
|
||||
import { formatNumber, formatShortTime } from '../utils/common';
|
||||
import { useTheme } from '../hooks/useTheme';
|
||||
|
||||
interface WebsiteOverviewProps {
|
||||
workspaceId: string;
|
||||
@ -212,8 +213,11 @@ export const StatsChart: React.FC<{
|
||||
data: { x: string; y: number; type: string }[];
|
||||
unit: DateUnit;
|
||||
}> = React.memo((props) => {
|
||||
const config: ColumnConfig = useMemo(
|
||||
() => ({
|
||||
const { colors } = useTheme();
|
||||
|
||||
const config = useMemo(
|
||||
() =>
|
||||
({
|
||||
data: props.data,
|
||||
isStack: true,
|
||||
xField: 'x',
|
||||
@ -229,6 +233,7 @@ export const StatsChart: React.FC<{
|
||||
tooltip: {
|
||||
title: (t) => formatDate(t),
|
||||
},
|
||||
color: [colors.chart.pv, colors.chart.uv],
|
||||
xAxis: {
|
||||
label: {
|
||||
autoHide: true,
|
||||
@ -236,7 +241,7 @@ export const StatsChart: React.FC<{
|
||||
formatter: (text) => formatDateWithUnit(text, props.unit),
|
||||
},
|
||||
},
|
||||
}),
|
||||
} as ColumnConfig),
|
||||
[props.data, props.unit]
|
||||
);
|
||||
|
||||
|
97
src/client/hooks/useTheme.ts
Normal file
97
src/client/hooks/useTheme.ts
Normal file
@ -0,0 +1,97 @@
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { colord } from 'colord';
|
||||
|
||||
const THEME_CONFIG = 'tianji.theme';
|
||||
|
||||
const THEME_COLORS = {
|
||||
light: {
|
||||
primary: '#2680eb',
|
||||
gray50: '#ffffff',
|
||||
gray75: '#fafafa',
|
||||
gray100: '#f5f5f5',
|
||||
gray200: '#eaeaea',
|
||||
gray300: '#e1e1e1',
|
||||
gray400: '#cacaca',
|
||||
gray500: '#b3b3b3',
|
||||
gray600: '#8e8e8e',
|
||||
gray700: '#6e6e6e',
|
||||
gray800: '#4b4b4b',
|
||||
gray900: '#2c2c2c',
|
||||
},
|
||||
dark: {
|
||||
primary: '#2680eb',
|
||||
gray50: '#252525',
|
||||
gray75: '#2f2f2f',
|
||||
gray100: '#323232',
|
||||
gray200: '#3e3e3e',
|
||||
gray300: '#4a4a4a',
|
||||
gray400: '#5a5a5a',
|
||||
gray500: '#6e6e6e',
|
||||
gray600: '#909090',
|
||||
gray700: '#b9b9b9',
|
||||
gray800: '#e3e3e3',
|
||||
gray900: '#ffffff',
|
||||
},
|
||||
};
|
||||
|
||||
type ValidTheme = keyof typeof THEME_COLORS;
|
||||
|
||||
function isValidTheme(theme: string | null): theme is ValidTheme {
|
||||
if (!theme) {
|
||||
return false;
|
||||
}
|
||||
return ['light', 'dark'].includes(theme);
|
||||
}
|
||||
|
||||
export function useTheme() {
|
||||
const defaultTheme: ValidTheme =
|
||||
typeof window !== 'undefined'
|
||||
? window?.matchMedia('(prefers-color-scheme: dark)')?.matches
|
||||
? 'dark'
|
||||
: 'light'
|
||||
: 'light';
|
||||
const customTheme = window.localStorage.getItem(THEME_CONFIG);
|
||||
const theme = isValidTheme(customTheme) ? customTheme : defaultTheme;
|
||||
|
||||
const primaryColor = useMemo(() => colord(THEME_COLORS[theme].primary), []);
|
||||
|
||||
const colors = useMemo(
|
||||
() => ({
|
||||
theme: {
|
||||
...THEME_COLORS[theme],
|
||||
},
|
||||
chart: {
|
||||
text: THEME_COLORS[theme].gray700,
|
||||
line: THEME_COLORS[theme].gray200,
|
||||
pv: primaryColor.alpha(0.4).toRgbString(),
|
||||
uv: primaryColor.alpha(0.6).toRgbString(),
|
||||
},
|
||||
map: {
|
||||
baseColor: THEME_COLORS[theme].primary,
|
||||
fillColor: THEME_COLORS[theme].gray100,
|
||||
strokeColor: THEME_COLORS[theme].primary,
|
||||
hoverColor: THEME_COLORS[theme].primary,
|
||||
},
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
function saveTheme(value: string) {
|
||||
window.localStorage.setItem(THEME_CONFIG, value);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
document.body.setAttribute('data-theme', theme);
|
||||
}, [theme]);
|
||||
|
||||
useEffect(() => {
|
||||
const url = new URL(window?.location?.href);
|
||||
const theme = url.searchParams.get('theme');
|
||||
|
||||
if (theme && ['light', 'dark'].includes(theme)) {
|
||||
saveTheme(theme);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return { theme, saveTheme, colors };
|
||||
}
|
Loading…
Reference in New Issue
Block a user