diff --git a/src/assets/styles/menu.less b/src/assets/styles/menu.less index e54340ad..8bacfe1c 100644 --- a/src/assets/styles/menu.less +++ b/src/assets/styles/menu.less @@ -1,7 +1,6 @@ .ant-pro-layout { .ant-pro-sider { .ant-layout-sider-children { - background-color: var(--color-fill-1); border-inline: none; border-radius: 0; // padding-inline: 16px; diff --git a/src/atoms/settings.ts b/src/atoms/settings.ts new file mode 100644 index 00000000..cba83bf7 --- /dev/null +++ b/src/atoms/settings.ts @@ -0,0 +1,21 @@ +import { atom } from 'jotai'; +import { atomWithStorage } from 'jotai/utils'; + +type UserSettings = { + theme: 'light' | 'realDark'; +}; + +export const userSettingsAtom = atomWithStorage('userSettings', { + theme: 'light' +}); + +export const userSettingsHelperAtom = atom( + (get) => get(userSettingsAtom), + (get, set, update: Partial) => { + const prev = get(userSettingsAtom); + set(userSettingsAtom, { + ...prev, + ...(update || {}) + }); + } +); diff --git a/src/components/card-wrapper/index.less b/src/components/card-wrapper/index.less index 95fffd55..592db7c4 100644 --- a/src/components/card-wrapper/index.less +++ b/src/components/card-wrapper/index.less @@ -3,5 +3,5 @@ background-color: var(--color-white-1); box-shadow: none; padding: 10px; - border: 1px solid var(--color-border-1); + border: 1px solid var(--ant-color-border); } diff --git a/src/components/echarts/bar-chart.tsx b/src/components/echarts/bar-chart.tsx index f55abfed..49d2af3b 100644 --- a/src/components/echarts/bar-chart.tsx +++ b/src/components/echarts/bar-chart.tsx @@ -1,16 +1,8 @@ import Chart from '@/components/echarts/chart'; -import { - barItemConfig, - grid, - legend, - title as titleConfig, - tooltip, - xAxis, - yAxis -} from '@/components/echarts/config'; +import useChartConfig from '@/components/echarts/config'; import EmptyData from '@/components/empty-data'; import _ from 'lodash'; -import { memo, useMemo } from 'react'; +import React, { memo, useMemo } from 'react'; import { ChartProps } from './types'; const BarChart: React.FC = (props) => { @@ -23,6 +15,15 @@ const BarChart: React.FC = (props) => { legendData, title } = props; + const { + barItemConfig, + grid, + legend, + title: titleConfig, + tooltip, + xAxis, + yAxis + } = useChartConfig(); const options = { title: { diff --git a/src/components/echarts/chart-tooltip.tsx b/src/components/echarts/chart-tooltip.tsx new file mode 100644 index 00000000..442c5c31 --- /dev/null +++ b/src/components/echarts/chart-tooltip.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import styled from 'styled-components'; + +const TooltipWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 4px; + font-size: 11px; + background-color: rgba(255, 255, 255, 80%); + min-width: 100px; + max-width: 360px; + + .tooltip-x-name { + font-size: var(--font-size-base); + color: var(--ant-color-text-tertiary); + } + + .tooltip-item { + color: var(--ant-color-text-secondary); + display: flex; + justify-content: space-between; + align-items: center; + + .tooltip-item-title { + margin-right: 2px; + } + + .tooltip-value { + margin-left: 10px; + color: var(--ant-color-text); + text-overflow: ellipsis; + overflow: hidden; + } + } +`; + +const ItemSymbol = styled.span<{ $color: string }>` + background-color: ${(props) => props.$color}; + display: inline-block; + marginright: 5px; + borderradius: 8px; + width: 8px; + height: 8px; +`; + +interface ChartTooltipProps { + params: any[]; + callback?: (val: any) => any; +} + +const ChartTooltip: React.FC = (props) => { + const { params, callback } = props; + console.log('params====', params); + return ( + + {params[0]?.axisValue} + <> + {params.map((item: any, index: number) => { + let value = callback?.(item.data.value) || item.data.value; + + return ( + + + + {item.seriesName}: + + {value} + + ); + })} + + + ); +}; +export default ChartTooltip; diff --git a/src/components/echarts/chart.tsx b/src/components/echarts/chart.tsx index bc2acd04..21f03e3f 100644 --- a/src/components/echarts/chart.tsx +++ b/src/components/echarts/chart.tsx @@ -1,5 +1,5 @@ import { throttle } from 'lodash'; -import { +import React, { forwardRef, useCallback, useEffect, @@ -36,13 +36,16 @@ const Chart: React.FC<{ chart.current?.resize(); }, []); - const setOption = useCallback((options: ECOption) => { - chart.current?.clear(); - chart.current?.setOption(options, { - notMerge: true, - lazyUpdate: true - }); - }, []); + const setOption = useCallback( + (options: ECOption) => { + chart.current?.clear(); + chart.current?.setOption(options, { + notMerge: true, + lazyUpdate: true + }); + }, + [options] + ); useEffect(() => { if (container.current) { @@ -79,17 +82,6 @@ const Chart: React.FC<{ }; }, []); - // resize on window resize - // useEffect(() => { - // const handleResize = throttle(() => { - // chart.current?.resize(); - // }, 100); - // window.addEventListener('resize', handleResize); - // return () => { - // window.removeEventListener('resize', handleResize); - // }; - // }, []); - return (
diff --git a/src/components/echarts/config.ts b/src/components/echarts/config.ts index f83fa28f..5dd3f6f4 100644 --- a/src/components/echarts/config.ts +++ b/src/components/echarts/config.ts @@ -1,8 +1,7 @@ +import useUserSettings from '@/hooks/use-user-settings'; +import { theme } from 'antd'; import { isFunction } from 'lodash'; -const chartColorMap = { - tickLineColor: 'rgba(217,217,217,0.5)', - axislabelColor: 'rgba(0, 0, 0, 0.4)' -}; +import { useMemo } from 'react'; const formatLargeNumber = (value: number) => { if (typeof value !== 'number' || isNaN(value)) { @@ -20,29 +19,6 @@ const formatLargeNumber = (value: number) => { } }; -export const tooltip = { - trigger: 'axis', - // axisPointer: { - // type: 'shadow' - // } - formatter(params: any, callback?: (val: any) => any) { - let result = `${params[0].axisValue}`; - params.forEach((item: any) => { - let value = isFunction(callback) - ? callback?.(item.data.value) - : item.data.value; - result += ` - - - ${item.seriesName}: - - ${value} - `; - }); - return `
${result}
`; - } -}; - export const grid = { left: 0, right: 20, @@ -50,159 +26,216 @@ export const grid = { containLabel: true }; -export const legend = { - itemWidth: 8, - itemHeight: 8 -}; +export default function useChartConfig() { + const { userSettings, isDarkTheme } = useUserSettings(); + const { useToken } = theme; + const { token, hashId } = useToken(); + console.log('token+++++++++++++++', token, hashId); -export const xAxis = { - type: 'category', - axisTick: { - show: true, - lineStyle: { - color: chartColorMap.tickLineColor - } - }, - axisLabel: { - color: chartColorMap.axislabelColor, - fontSize: 12 - }, - axisLine: { - show: false - } -}; + const chartColorMap = useMemo(() => { + return { + titleColor: token.colorText, + splitLineColor: token.colorBorder, + tickLineColor: token.colorSplit, + axislabelColor: token.colorTextTertiary, + gaugeSplitLineColor: 'rgba(255, 255, 255, 0.38)', + colorBgBase: token.colorBgBase + }; + }, [userSettings.theme]); -export const yAxis = { - // max: 100, - // min: 0, - nameTextStyle: { - padding: [0, 0, 0, -20] - }, - splitLine: { - show: true, - lineStyle: { - type: 'dashed' + const tooltip = { + trigger: 'axis', + backgroundColor: chartColorMap.colorBgBase, + borderColor: 'transparent', + formatter(params: any, callback?: (val: any) => any) { + let result = `${params[0].axisValue}`; + params.forEach((item: any) => { + let value = isFunction(callback) + ? callback?.(item.data.value) + : item.data.value; + result += ` + + + ${item.seriesName}: + + ${value} + `; + }); + return `
${result}
`; } - }, - axisLabel: { - color: chartColorMap.axislabelColor, - fontSize: 12, - formatter: formatLargeNumber - }, - axisTick: { - show: false - }, - type: 'value' -}; + }; -export const title = { - show: true, - left: 'center', - textStyle: { - fontSize: 12, - color: '#000' - // fontWeight: 500 - }, - text: '' -}; + const legend = { + itemWidth: 8, + itemHeight: 8, + padding: 0, + textStyle: { + color: chartColorMap.axislabelColor + } + }; -export const barItemConfig = { - type: 'bar', - barMaxWidth: 20, - barMinWidth: 8, - // stack: 'total', - barGap: '30%', - barCategoryGap: '50%' -}; + const xAxis = { + type: 'category', + axisTick: { + show: true, + lineStyle: { + color: chartColorMap.tickLineColor + } + }, + axisLabel: { + color: chartColorMap.axislabelColor, + fontSize: 12 + }, + axisLine: { + show: false + } + }; -export const lineItemConfig = { - type: 'line', - smooth: true, - showSymbol: false, - itemStyle: {}, - lineStyle: { - width: 1.5, - opacity: 0.7 - } -}; + const yAxis = { + // max: 100, + // min: 0, + nameTextStyle: { + padding: [0, 0, 0, -20] + }, + splitLine: { + show: true, + lineStyle: { + type: 'dashed', + color: chartColorMap.splitLineColor + } + }, + axisLabel: { + color: chartColorMap.axislabelColor, + fontSize: 12, + formatter: formatLargeNumber + }, + axisTick: { + show: false + }, + type: 'value' + }; -export const gaugeItemConfig = { - type: 'gauge', - radius: '88%', - center: ['50%', '65%'], - startAngle: 190, - endAngle: -10, - min: 0, - max: 100, - splitNumber: 5, - progress: { + const title = { show: true, - roundCap: false, - width: 12 - }, - pointer: { - length: '80%', - width: 4, - itemStyle: { - color: 'auto' - } - }, - axisLine: { - roundCap: false, - lineStyle: { - width: 12, - // color: [[1, 'rgba(221, 221, 221, 0.5)']], - color: [ - [0.5, 'rgba(84, 204, 152, 80%)'], - [0.8, 'rgba(250, 173, 20, 80%)'], - [1, 'rgba(255, 77, 79, 80%)'] - ] - } - }, - axisTick: { - distance: -12, - length: 6, - splitNumber: 5, - lineStyle: { - width: 1.5, - color: 'rgba(255, 255, 255, 1)' - } - }, - splitLine: { - distance: -12, - length: 12, + left: 'center', + textStyle: { + fontSize: 12, + color: chartColorMap.titleColor + }, + text: '' + }; + + const barItemConfig = { + type: 'bar', + barMaxWidth: 20, + barMinWidth: 8, + // stack: 'total', + barGap: '30%', + barCategoryGap: '50%' + }; + + const lineItemConfig = { + type: 'line', + smooth: true, + showSymbol: false, + itemStyle: {}, lineStyle: { width: 1.5, - color: 'rgba(255, 255, 255, 1)' + opacity: 0.7 } - }, - axisLabel: { - distance: 14, - color: 'rgba(0, 0, 0, .5)', - fontSize: 12 - }, - detail: { - lineHeight: 40, - height: 40, - offsetCenter: [5, 30], - valueAnimation: false, - fontSize: 20, - color: 'rgba(0, 0, 0, 0.88)', - formatter(value: any) { - return '{value|' + value + '}{unit|%}'; + }; + + const gaugeItemConfig = { + type: 'gauge', + radius: '88%', + center: ['50%', '65%'], + startAngle: 190, + endAngle: -10, + min: 0, + max: 100, + splitNumber: 5, + progress: { + show: true, + roundCap: false, + width: 12 + }, + pointer: { + length: '80%', + width: 4, + itemStyle: { + color: 'auto' + } + }, + axisLine: { + roundCap: false, + lineStyle: { + width: 12, + color: [ + [0.5, 'rgba(84, 204, 152, 80%)'], + [0.8, 'rgba(250, 173, 20, 80%)'], + [1, 'rgba(255, 77, 79, 80%)'] + ] + } }, - rich: { - value: { - fontSize: 16, - fontWeight: '500', - color: 'rgba(0, 0, 0, 0.88)' + axisTick: { + distance: -12, + length: 6, + splitNumber: 5, + lineStyle: { + width: 1.5, + color: chartColorMap.gaugeSplitLineColor + } + }, + splitLine: { + distance: -6, + length: 6, + lineStyle: { + width: 1.5, + color: chartColorMap.gaugeSplitLineColor + } + }, + axisLabel: { + distance: 14, + color: chartColorMap.axislabelColor, + fontSize: 12 + }, + detail: { + lineHeight: 40, + height: 40, + offsetCenter: [5, 30], + valueAnimation: false, + fontSize: 20, + color: chartColorMap.titleColor, + formatter(value: any) { + return '{value|' + value + '}{unit|%}'; }, - unit: { - fontSize: 14, - color: 'rgba(0, 0, 0, 0.88)', - fontWeight: '500', - padding: [0, 0, 0, 2] + rich: { + value: { + fontSize: 16, + fontWeight: '500', + color: chartColorMap.titleColor + }, + unit: { + fontSize: 14, + color: chartColorMap.titleColor, + fontWeight: '500', + padding: [0, 0, 0, 2] + } } } - } -}; + }; + + return { + tooltip, + grid, + legend, + xAxis, + yAxis, + title, + chartColorMap, + barItemConfig, + lineItemConfig, + gaugeItemConfig, + isDark: isDarkTheme + }; +} diff --git a/src/components/echarts/gauge.tsx b/src/components/echarts/gauge.tsx index f7e72ced..faf9f69c 100644 --- a/src/components/echarts/gauge.tsx +++ b/src/components/echarts/gauge.tsx @@ -1,15 +1,13 @@ import Chart from '@/components/echarts/chart'; -import { - gaugeItemConfig, - title as titleConfig -} from '@/components/echarts/config'; +import useChartConfig from '@/components/echarts/config'; import EmptyData from '@/components/empty-data'; -import { memo } from 'react'; +import React, { memo } from 'react'; import { ChartProps } from './types'; const GaugeChart: React.FC> = ( props ) => { + const { gaugeItemConfig, title: titleConfig } = useChartConfig(); const { value, height, width, labelFormatter, title, color } = props; if (!value && value !== 0) { return ; diff --git a/src/components/echarts/h-bar.tsx b/src/components/echarts/h-bar.tsx index 0f883446..2e93387c 100644 --- a/src/components/echarts/h-bar.tsx +++ b/src/components/echarts/h-bar.tsx @@ -1,15 +1,8 @@ import Chart from '@/components/echarts/chart'; -import { - grid, - legend, - title as titleConfig, - tooltip, - xAxis, - yAxis -} from '@/components/echarts/config'; +import useChartConfig from '@/components/echarts/config'; import EmptyData from '@/components/empty-data'; import _ from 'lodash'; -import { memo, useMemo } from 'react'; +import React, { memo, useMemo } from 'react'; import { ChartProps } from './types'; const BarChart: React.FC = (props) => { @@ -22,6 +15,14 @@ const BarChart: React.FC = (props) => { legendData, title } = props; + const { + grid, + legend, + title: titleConfig, + tooltip, + xAxis, + yAxis + } = useChartConfig(); const options = { title: { diff --git a/src/components/echarts/line-chart.tsx b/src/components/echarts/line-chart.tsx index e175f506..4744707f 100644 --- a/src/components/echarts/line-chart.tsx +++ b/src/components/echarts/line-chart.tsx @@ -1,16 +1,8 @@ import Chart from '@/components/echarts/chart'; -import { - grid, - legend, - lineItemConfig, - title as titleConfig, - tooltip, - xAxis, - yAxis -} from '@/components/echarts/config'; +import useChartConfig from '@/components/echarts/config'; import EmptyData from '@/components/empty-data'; import _ from 'lodash'; -import { memo, useMemo } from 'react'; +import React, { memo, useMemo } from 'react'; import { ChartProps } from './types'; const LineChart: React.FC = (props) => { @@ -26,6 +18,15 @@ const LineChart: React.FC = (props) => { smooth, title } = props; + const { + grid, + legend, + lineItemConfig, + title: titleConfig, + tooltip, + xAxis, + yAxis + } = useChartConfig(); const options = { title: { @@ -93,7 +94,7 @@ const LineChart: React.FC = (props) => { }, series: data }; - }, [seriesData, xAxisData, yAxisName, title, smooth, legendData]); + }, [seriesData, xAxisData, yAxisName, title, smooth, legendData, options]); return ( <> diff --git a/src/components/echarts/scatter.tsx b/src/components/echarts/scatter.tsx index 2801f04b..387217e1 100644 --- a/src/components/echarts/scatter.tsx +++ b/src/components/echarts/scatter.tsx @@ -1,89 +1,106 @@ import Chart from '@/components/echarts/chart'; -import { grid, title as titleConfig } from '@/components/echarts/config'; +import useChartConfig from '@/components/echarts/config'; import EmptyData from '@/components/empty-data'; import _ from 'lodash'; -import { memo, useCallback, useMemo, useRef } from 'react'; +import React, { memo, useCallback, useMemo, useRef } from 'react'; import { ChartProps } from './types'; -const options: any = { - animation: false, - grid: { - ...grid, - right: 10, - top: 10, - bottom: 2, - left: 2, - containLabel: true, - borderRadius: 4 - }, - xAxis: { - min: -1, - max: 1, - scale: false, - slient: true, - splitNumber: 15, - splitLine: { - lineStyle: { - color: '#F2F2F2' - } - }, - axisLine: { - show: true, - lineStyle: { - color: '#DCDCDC' - } - }, - axisTick: { - show: false - }, - axisLabel: { - show: true - }, - boundaryGap: [0.05, 0.05] - }, - yAxis: { - min: -1, - max: 1, - scale: false, - slient: true, - splitNumber: 10, - boundaryGap: [0.05, 0.05], - splitLine: { - lineStyle: { - color: '#F2F2F2' - } - }, - axisLine: { - show: true, - lineStyle: { - color: '#DCDCDC' - } - }, - axisTick: { - show: false - }, - axisLabel: { - show: true - } - }, - - symbol: 'roundRect', - label: { - show: true, - shadowColor: 'none', - textBorderColor: 'none', - formatter: (params: any) => { - return params.name; - } - }, - series: [] -}; - const Scatter: React.FC = (props) => { + const { grid, title: titleConfig, isDark, chartColorMap } = useChartConfig(); const { seriesData, xAxisData, height, width, showEmpty, title } = props; const chart = useRef(null); + const options = useMemo(() => { + const colorMap = isDark + ? { + split: chartColorMap.splitLineColor, + axis: chartColorMap.axislabelColor, + label: chartColorMap.axislabelColor + } + : { + split: '#F2F2F2', + axis: '#dcdcdc', + label: '#dcdcdc' + }; + + return { + animation: false, + grid: { + ...grid, + right: 10, + top: 10, + bottom: 2, + left: 2, + containLabel: true, + borderRadius: 4 + }, + xAxis: { + min: -1, + max: 1, + scale: false, + slient: true, + splitNumber: 15, + splitLine: { + lineStyle: { + color: colorMap.split + } + }, + axisLine: { + show: true, + lineStyle: { + color: colorMap.axis + } + }, + axisTick: { + show: false + }, + axisLabel: { + show: true, + color: colorMap.label + }, + boundaryGap: [0.05, 0.05] + }, + yAxis: { + min: -1, + max: 1, + scale: false, + slient: true, + splitNumber: 10, + boundaryGap: [0.05, 0.05], + splitLine: { + lineStyle: { + color: colorMap.split + } + }, + axisLine: { + show: true, + lineStyle: { + color: colorMap.axis + } + }, + axisTick: { + show: false + }, + axisLabel: { + show: true, + color: colorMap.label + } + }, + + symbol: 'roundRect', + label: { + show: true, + shadowColor: 'none', + textBorderColor: 'none', + formatter: (params: any) => { + return params.name; + } + }, + series: [] + }; + }, [isDark]); + const findOverlappingPoints = useCallback( (data: any[], currentPoint: any) => { const overlappingPoints = []; @@ -151,6 +168,8 @@ const Scatter: React.FC = (props) => { tooltip: { trigger: 'item', borderWidth: 0, + backgroundColor: chartColorMap.colorBgBase, + borderColor: 'transparent', formatter(params: any, callback?: (val: any) => any) { const dataList = findOverlappingPoints(seriseDataList, params.data); let result = ''; @@ -177,7 +196,7 @@ const Scatter: React.FC = (props) => { data: seriseDataList } }; - }, [seriesData, xAxisData, title, findOverlappingPoints]); + }, [seriesData, xAxisData, title, options, findOverlappingPoints]); return ( <> diff --git a/src/components/echarts/types.ts b/src/components/echarts/types.ts index 0b82ef47..4d1d15c5 100644 --- a/src/components/echarts/types.ts +++ b/src/components/echarts/types.ts @@ -4,7 +4,7 @@ export interface ChartProps { xAxisData: string[]; legendData?: string[]; labelFormatter?: (val?: any) => string; - tooltipValueFormatter?: (val?: any) => string; + tooltipValueFormatter?: (val: any) => string; height: string | number; width?: string | number; title?: string; diff --git a/src/components/footer/index.less b/src/components/footer/index.less index a1d30e55..baff50f9 100644 --- a/src/components/footer/index.less +++ b/src/components/footer/index.less @@ -6,7 +6,7 @@ padding: 20px 0; text-align: center; font-size: var(--font-size-middle); - color: var(--color-text-2); + color: var(--ant-color-text-secondary); .footer-content-left-text { display: flex; diff --git a/src/components/seal-form/components/label-info.less b/src/components/seal-form/components/label-info.less index c99281cc..cea6b5cd 100644 --- a/src/components/seal-form/components/label-info.less +++ b/src/components/seal-form/components/label-info.less @@ -2,7 +2,7 @@ display: flex; justify-content: flex-start; align-items: center; - color: rgba(0, 0, 0, 45%); + color: var(--ant-color-text-tertiary); font-size: var(--font-size-base); .note-info { diff --git a/src/components/seal-form/seal-slider.tsx b/src/components/seal-form/seal-slider.tsx index b0f95c19..c8c5733c 100644 --- a/src/components/seal-form/seal-slider.tsx +++ b/src/components/seal-form/seal-slider.tsx @@ -72,7 +72,7 @@ const SealSlider: React.FC = (props) => { ); }, [label, labelWidth, description, value, max, min, step, defaultValue]); return ( - + = (props) => { diff --git a/src/components/seal-table/index.tsx b/src/components/seal-table/index.tsx index 87914a9a..ccc27435 100644 --- a/src/components/seal-table/index.tsx +++ b/src/components/seal-table/index.tsx @@ -1,12 +1,24 @@ -import { Pagination, Spin, type PaginationProps } from 'antd'; +import { Pagination, Spin, theme, type PaginationProps } from 'antd'; import _ from 'lodash'; import React, { useMemo } from 'react'; +import styled from 'styled-components'; import Header from './components/header'; import HeaderPrefix from './components/header-prefix'; import TableBody from './components/table-body'; import './styles/index.less'; import { SealColumnProps, SealTableProps } from './types'; +const Wrapper = styled.div<{ $token: any }>` + --ant-table-cell-padding-inline: ${(props) => + props.$token.cellPaddingInline}px; + --ant-table-cell-padding-block: ${(props) => props.$token.cellPaddingBlock}px; + --ant-table-header-border-radius: ${(props) => + props.$token.headerBorderRadius}px; + --ant-table-header-split-color: ${(props) => props.$token.headerSplitColor}; + --ant-table-row-selected-bg: var(--ant-table-row-selected-bg); + --ant-table-row-selected-hover-bg: var(--ant-table-row-selected-hover-bg); +`; + const SealTable: React.FC = ( props ) => { @@ -32,7 +44,7 @@ const SealTable: React.FC = ( loadChildren, loadChildrenAPI } = props; - + const { token } = theme.useToken(); const parsedColumns = useMemo(() => { if (columns) return columns; @@ -122,7 +134,7 @@ const SealTable: React.FC = ( }; return ( - <> +
= ( >
)} - + ); }; diff --git a/src/components/seal-table/styles/index.less b/src/components/seal-table/styles/index.less index 3b747c86..89d2ac23 100644 --- a/src/components/seal-table/styles/index.less +++ b/src/components/seal-table/styles/index.less @@ -11,11 +11,10 @@ .header-row-wrapper { height: 50px; - // margin-bottom: 10px; display: flex; justify-content: flex-start; align-items: center; - background-color: var(--color-fill-sider); + background-color: var(--ant-color-fill-tertiary); border-radius: var(--ant-table-header-border-radius) var(--ant-table-header-border-radius) 0 0; @@ -29,17 +28,12 @@ } .row-box { - // margin-bottom: 20px; - // border-radius: var(--ant-table-header-border-radius); overflow: hidden; border-bottom: 1px solid var(--ant-color-split); - // box-shadow: var(--box-shadow-base); } .expanded-row { - // background-color: var(--color-white-1); padding: 16px; - // border: 1px solid var(--color-fill-1); border-top: 0; border-radius: 0 0 var(--ant-table-header-border-radius) var(--ant-table-header-border-radius); @@ -53,7 +47,6 @@ display: flex; justify-content: flex-start; align-items: center; - // background-color: var(--color-fill-sider); transition: all 0.2s ease; &:hover { diff --git a/src/config/theme/dark.ts b/src/config/theme/dark.ts new file mode 100644 index 00000000..7553ee0f --- /dev/null +++ b/src/config/theme/dark.ts @@ -0,0 +1,89 @@ +export default { + 'root-entry-name': 'variable', + cssVar: true, + hashed: false, + components: { + Input: { + inputFontSize: 14, + inputFontSizeLG: 14 + }, + Table: { + headerBorderRadius: 4, + cellPaddingInline: 16, + cellPaddingBlock: 6, + cellFontSize: 14, + rowSelectedHoverBg: 'rgb(24 25 27)', + rowHoverBg: 'rgb(24 25 27)', + rowSelectedBg: 'transparent' + }, + Button: { + contentFontSizeLG: 14, + primaryShadow: 'none', + defaultShadow: 'none', + dangerShadow: 'none' + }, + Tabs: { + titleFontSizeLG: 14, + cardBg: '#1D1E20' + }, + Menu: { + iconSize: 16, + iconMarginInlineEnd: 12, + itemBorderRadius: 4, + itemHeight: 44, + itemSelectedColor: '#007BFF', + darkItemSelectedBg: 'rgb(24 25 27)', + darkItemHoverBg: 'rgb(24 25 27)', + groupTitleColor: 'rgba(0,0,0,1)', + itemHoverColor: 'rgba(0,0,0,1)', + itemColor: 'rgba(0,0,0,1)', + itemHoverBg: 'rgb(24 25 27)', + itemActiveBg: 'rgb(24 25 27)' + }, + Progress: { + lineBorderRadius: 2 + }, + Select: { + optionSelectedBg: 'rgba(230, 230, 230, 88%)', + fontSizeLG: 14 + }, + Message: { + contentPadding: '12px 16px' + }, + Tooltip: { + colorBgSpotlight: '#1D1E20' + }, + Cascader: { + dropdownHeight: 240 + }, + Slider: { + handleSize: 8, + handleSizeHover: 8, + trackBg: 'rgba(0,0,0,0.15)', + handleColor: 'rgba(0,0,0,0.2)', + trackHoverBg: 'rgba(0,0,0,0.25)', + handleActiveColor: 'rgba(0,0,0,0.3)', + dotActiveBorderColor: 'rgba(0,0,0,0.25)', + handleActiveOutlineColor: 'rgba(0,0,0,0.25)', + dotBorderColor: 'rgba(0,0,0,0.25)' + } + }, + token: { + fontFamily: + "Helvetica Neue, -apple-system, BlinkMacSystemFont, Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'", + colorText: '#ccc', + colorPrimary: '#007BFF', + colorSuccess: '#54cc98', + borderRadius: 4, + borderRadiusSM: 2, + fontSize: 14, + motion: true, + colorFill: 'rgb(0,0,0)', + colorFillTertiary: '#1D1E20', + colorBgContainer: '#141414', + colorBgBase: '#000', + colorBorder: '#353535', + colorSplit: '#262626', + colorBorderSecondary: '#262626' + } +}; diff --git a/src/config/theme/index.ts b/src/config/theme/index.ts new file mode 100644 index 00000000..ea557392 --- /dev/null +++ b/src/config/theme/index.ts @@ -0,0 +1,7 @@ +import dark from './dark'; +import light from './light'; + +export default { + light, + dark +}; diff --git a/src/config/theme.ts b/src/config/theme/light.ts similarity index 91% rename from src/config/theme.ts rename to src/config/theme/light.ts index 828894b8..8ad5752d 100644 --- a/src/config/theme.ts +++ b/src/config/theme/light.ts @@ -8,6 +8,9 @@ export default { inputFontSizeLG: 14 }, Table: { + headerBorderRadius: 4, + cellPaddingInline: 16, + cellPaddingBlock: 6, cellFontSize: 14, rowSelectedHoverBg: 'rgb(249 249 249)', rowHoverBg: 'rgb(249 249 249)', @@ -70,7 +73,9 @@ export default { colorSuccess: '#54cc98', borderRadius: 4, borderRadiusSM: 2, + colorBgContainer: '#fff', fontSize: 14, - motion: true + motion: true, + colorFillTertiary: '#f4f5f4' } }; diff --git a/src/global.less b/src/global.less index 7a2f05ce..7d2ad2a8 100644 --- a/src/global.less +++ b/src/global.less @@ -5,15 +5,15 @@ html { --font-family: 'noto sans', sans-serif; - --ant-color-text-secondary: rgba(0, 0, 0, 65%); - --ant-color-text-tertiary: rgba(0, 0, 0, 45%); - --ant-color-text-quaternary: rgba(0, 0, 0, 25%); - --ant-color-fill: rgba(223, 168, 168, 15%); - --ant-color-fill-secondary: rgba(0, 0, 0, 6%); - --ant-color-fill-tertiary: rgba(0, 0, 0, 4%); - --ant-color-fill-quaternary: rgba(0, 0, 0, 2%); + // --ant-color-text-secondary: rgba(0, 0, 0, 65%); + // --ant-color-text-tertiary: rgba(0, 0, 0, 45%); + // --ant-color-text-quaternary: rgba(0, 0, 0, 25%); + // --ant-color-fill: rgba(223, 168, 168, 15%); + // --ant-color-fill-secondary: rgba(0, 0, 0, 6%); + // --ant-color-fill-tertiary: rgba(0, 0, 0, 4%); + // --ant-color-fill-quaternary: rgba(0, 0, 0, 2%); --color-text-light-1: rgba(255, 255, 255, 90%); - --color-fill-1: var(--ant-color-fill-tertiary); + --color-fill-1: var(--ant-color-bg-container); --color-scrollbar-thumb: rgba(193, 193, 193, 80%); --scrollbar-size: 6px; --scrollbar-handle-bg: rgba(0, 0, 0, 44%); @@ -22,7 +22,6 @@ html { --color-editor-dark: #282c34; --color-editor-light: #fafafa; --color-scrollbar-track: var(--ant-color-fill-tertiary); - --ant-color-text: #000; --color-bg-1: #f4f5f4; --color-scroll-bg: #d9d9d9; --color-fill-2: #fff; @@ -41,7 +40,7 @@ html { --border-radius-mini: 4px; --border-radius-2px: 2px; --color-white-1: rgba(255, 255, 255, 100%); - --color-fill-sider: #f4f5f4; + --color-fill-sider: var(--ant-color-fill-tertiary); --font-weight-500: 500; --font-weight-normal: 400; --font-weight-medium: 600; @@ -56,7 +55,6 @@ html { --color-white-light-4: rgba(255, 255, 255, 45%); --color-gray-fill-4: rgba(92, 92, 92, 45%); --color-gray-fill-3: rgba(92, 92, 92, 35%); - --color-text-1: var(--ant-color-text); --color-text-3: rgba(0, 0, 0, 45%); --color-text-2: rgba(0, 0, 0, 65%); --color-bg-light-1: #e6f6ff; @@ -73,20 +71,19 @@ html { --ant-color-error: #ff4d4f; --ant-box-shadow-secondary: 0 6px 16px 0 rgba(0, 0, 0, 8%), 0 3px 6px -4px rgba(0, 0, 0, 12%), 0 9px 28px 8px rgba(0, 0, 0, 5%); - --ant-table-cell-padding-inline: 16px; - --ant-table-cell-padding-block: 6px; - --ant-table-header-border-radius: 4px; - --ant-table-header-split-color: #f0f0f0; - --ant-table-row-selected-bg: #e6f6ff; - --ant-table-row-selected-hover-bg: rgb(249 249 249); - --ant-table-row-hover-bg: rgb(249 249 249); + --table-cell-padding-inline: var(--ant-table-cell-padding-inline); + --table-cell-padding-block: var(--ant-table-cell-padding-block); + --table-header-border-radius: var(--ant-table-header-border-radius); + --table-header-split-color: var(--ant-table-header-split-color); + --table-row-selected-bg: var(--ant-table-row-selected-bg); + --table-row-selected-hover-bg: var(--ant-table-row-selected-hover-bg); + --table-row-hover-bg: var(--ant-table-row-hover-bg); --color-chart-red: rgba(255, 77, 79, 80%); --color-chart-green: rgb(84, 204, 152, 80%); --color-chart-glod: rgba(250, 173, 20, 80%); --seal-transition-func: cubic-bezier(0, 0, 1, 1); --color-progress-green: rgba(84, 204, 152, 100%); --color-green-fill-light: rgb(243 251 248); - --color-border-1: rgba(217, 217, 217, 100%); --ant-rate-star-color: #fadb14; --color-fill-mask: rgba(255, 255, 255, 60%); --width-tooltip-max: 300px; @@ -159,8 +156,8 @@ html { } } -body * { - // font-weight: var(--font-weight-normal); +html[data-theme='realDark'] { + --color-white-1: #1d1e20; } body { @@ -224,22 +221,12 @@ body { border: none; padding-block: 0; height: 50px; - background-color: var(--color-fill-sider); + background-color: var(--ant-color-fill-tertiary); } tr > td { border-bottom: none; height: 68px; - - // &:first-child { - // border-top-left-radius: var(--table-td-radius); - // border-bottom-left-radius: var(--table-td-radius); - // } - - // &:last-child { - // border-top-right-radius: var(--table-td-radius); - // border-bottom-right-radius: var(--table-td-radius); - // } } } @@ -343,7 +330,7 @@ body { } .ant-pro-sider .ant-layout-sider-children { - background-color: var(--color-fill-sider); + background-color: var(--ant-color-fill-tertiary); // box-shadow: // 0px 1px 2px 0px rgb(0 0 0 / 30%), // 0px 2px 6px 2px rgb(0 0 0 / 15%); @@ -363,7 +350,6 @@ body { .ant-table-tbody { .ant-table-row { border-radius: var(--table-td-radius); - // background-color: var(--color-fill-sider); > td { background-color: unset; @@ -397,6 +383,7 @@ body { .ant-layout { min-height: 100vh; + background: var(--ant-color-bg-container); } .ant-pro-layout-bg-list { @@ -406,6 +393,7 @@ body { .ant-pro-layout-container { overflow-x: auto; min-height: 100vh; + background: var(--ant-color-bg-container); } .ant-pro-sider { @@ -725,8 +713,6 @@ body { } .ant-pro-page-container { - background: transparent; - .ant-page-header-heading { min-width: max-content; } @@ -857,12 +843,12 @@ body { flex-direction: column; gap: 4px; font-size: 11px; - background-color: rgba(255, 255, 255, 80%); + background-color: transparent; min-width: 100px; max-width: 360px; .tooltip-x-name { - font-size: var(--font-size-base); + font-size: var(--font-size-small); color: var(--ant-color-text-tertiary); } diff --git a/src/hooks/use-overlay-scroller.ts b/src/hooks/use-overlay-scroller.ts index 389ea7f4..f91a9e51 100644 --- a/src/hooks/use-overlay-scroller.ts +++ b/src/hooks/use-overlay-scroller.ts @@ -1,3 +1,5 @@ +import { userSettingsHelperAtom } from '@/atoms/settings'; +import { useAtom } from 'jotai'; import { throttle } from 'lodash'; import { UseOverlayScrollbarsParams, @@ -28,6 +30,7 @@ export default function useOverlayScroller(data?: { events?: any; defer?: boolean; }) { + const [useSettings] = useAtom(userSettingsHelperAtom); const { options, events, defer = true } = data || {}; const scrollEventElement = React.useRef(null); const instanceRef = React.useRef(null); @@ -44,7 +47,10 @@ export default function useOverlayScroller(data?: { x: 'hidden' }, scrollbars: { - theme: options?.theme || 'os-theme-dark', + theme: + options?.theme || useSettings.theme === 'light' + ? 'os-theme-dark' + : 'os-theme-light', autoHide: 'scroll', autoHideDelay: 600, clickScroll: 'instant' diff --git a/src/hooks/use-user-settings.ts b/src/hooks/use-user-settings.ts new file mode 100644 index 00000000..e5025b22 --- /dev/null +++ b/src/hooks/use-user-settings.ts @@ -0,0 +1,46 @@ +import { userSettingsHelperAtom } from '@/atoms/settings'; +import themeConfig from '@/config/theme'; +import { useAtom } from 'jotai'; +import { useEffect, useMemo } from 'react'; + +type Theme = 'light' | 'realDark'; + +export default function useUserSettings() { + const { light, dark } = themeConfig; + const [userSettings, setUserSettings] = useAtom(userSettingsHelperAtom); + + const setHtmlThemeAttr = (theme: string) => { + const html = document.querySelector('html'); + if (html) { + html.setAttribute('data-theme', theme); + } + }; + + const themeData = useMemo(() => { + return { + ...(userSettings.theme === 'realDark' ? dark : light) + }; + }, [userSettings.theme]); + + const isDarkTheme = useMemo(() => { + return userSettings.theme === 'realDark'; + }, [userSettings.theme]); + + const setTheme = (theme: Theme) => { + setHtmlThemeAttr(theme); + setUserSettings({ ...userSettings, theme: theme }); + }; + + useEffect(() => { + setHtmlThemeAttr(userSettings.theme); + }, [userSettings.theme]); + + return { + userSettings, + setUserSettings, + setTheme, + isDarkTheme, + themeData, + componentSize: 'large' + }; +} diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx index 9c8d7f13..90058d3b 100644 --- a/src/layouts/index.tsx +++ b/src/layouts/index.tsx @@ -7,9 +7,9 @@ import ShortCuts, { } from '@/components/short-cuts'; import VersionInfo, { modalConfig } from '@/components/version-info'; import routeCachekey from '@/config/route-cachekey'; -import theme from '@/config/theme'; import useBodyScroll from '@/hooks/use-body-scroll'; import useOverlayScroller from '@/hooks/use-overlay-scroller'; +import useUserSettings from '@/hooks/use-user-settings'; import { logout } from '@/pages/login/apis'; import { useAccessMarkedRoutes } from '@@/plugin-access'; import { useModel } from '@@/plugin-model'; @@ -99,6 +99,7 @@ export default (props: any) => { const { initialize: initialize } = useOverlayScroller({ defer: false }); + const { themeData, setTheme, userSettings } = useUserSettings(); const { saveScrollHeight, restoreScrollHeight } = useBodyScroll(); const { initialize: initializeMenu } = useOverlayScroller(); const [userInfo] = useAtom(userAtom); @@ -160,6 +161,7 @@ export default (props: any) => { } } }; + const runtimeConfig = { ...initialInfo, logout: async (userInfo) => { @@ -172,6 +174,10 @@ export default (props: any) => { showShortcuts: () => { return showShortcuts(); }, + toggleTheme: () => { + const newTheme = userSettings.theme === 'realDark' ? 'light' : 'realDark'; + setTheme(newTheme); + }, notFound: 404 not found }; @@ -288,7 +294,7 @@ export default (props: any) => { return dom; }, - [intl, showUpgrade] + [intl, showUpgrade, userSettings.theme] ); const itemRender = useCallback((route, _, routes) => { @@ -400,13 +406,12 @@ export default (props: any) => { }; return ( - -
+ ), children: [ + { + key: 'theme', + label: 'Appearance', + icon: , + onClick: () => { + opts.runtimeConfig.toggleTheme(); + } + }, { key: 'settings', label: ( diff --git a/src/pages/dashboard/components/over-view.less b/src/pages/dashboard/components/over-view.less index 5c0c9297..d93ca077 100644 --- a/src/pages/dashboard/components/over-view.less +++ b/src/pages/dashboard/components/over-view.less @@ -6,7 +6,7 @@ display: flex; justify-content: space-around; border-radius: var(--ant-border-radius-lg); - border: 1px solid var(--color-border-1); + border: 1px solid var(--ant-color-border); } } diff --git a/src/pages/dashboard/components/over-view.tsx b/src/pages/dashboard/components/over-view.tsx index 00ca4d03..f60f27b4 100644 --- a/src/pages/dashboard/components/over-view.tsx +++ b/src/pages/dashboard/components/over-view.tsx @@ -16,7 +16,7 @@ const renderCardItem = (data: { return (
diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index 3ac14df5..6822e453 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -1,6 +1,8 @@ import { userAtom } from '@/atoms/user'; import Footer from '@/components/footer'; +import useUserSettings from '@/hooks/use-user-settings'; import { useModel } from '@umijs/max'; +import { ConfigProvider } from 'antd'; import { useAtom } from 'jotai'; import { useEffect } from 'react'; import LoginForm from './components/login-form'; @@ -9,6 +11,7 @@ import styles from './components/styles.less'; import { checkDefaultPage } from './utils'; const Login = () => { + const { themeData } = useUserSettings(); const [userInfo, setUserInfo] = useAtom(userAtom); const { initialState, setInitialState } = useModel('@@initialState') || {}; @@ -33,7 +36,7 @@ const Login = () => { }, []); return ( - <> +
@@ -41,7 +44,7 @@ const Login = () => {
- +
); }; diff --git a/src/pages/playground/components/ground-embedding.tsx b/src/pages/playground/components/ground-embedding.tsx index 241495c3..f4242df9 100644 --- a/src/pages/playground/components/ground-embedding.tsx +++ b/src/pages/playground/components/ground-embedding.tsx @@ -48,8 +48,6 @@ interface MessageProps { const GroundEmbedding: React.FC = forwardRef((props, ref) => { const { modelList } = props; - const acceptType = - '.txt, .doc, .docx, .xls, .xlsx, .csv, .md, .pdf, .eml, .msg, .ppt, .pptx, .xml, .epub, .html'; const messageId = useRef(0); const intl = useIntl(); @@ -266,15 +264,6 @@ const GroundEmbedding: React.FC = forwardRef((props, ref) => { setShow(false); }; - const handleUpdateFileList = ( - files: { text: string; name: string; uid: number | string }[] - ) => { - console.log('files:', files); - setFileList((preList) => { - return [...preList, ...files]; - }); - }; - const handleScaleOutputSize = ( e: any, direction: string, @@ -445,18 +434,6 @@ const GroundEmbedding: React.FC = forwardRef((props, ref) => { [] ); - // useHotkeys( - // HotKeys.SUBMIT, - // (e: any) => { - // e.preventDefault(); - // handleSendMessage(); - // }, - // { - // enabled: !loading, - // preventDefault: true - // } - // ); - useEffect(() => { if (scroller.current) { initialize(scroller.current); diff --git a/src/pages/playground/style/input-list.less b/src/pages/playground/style/input-list.less index f3c6853c..f063923c 100644 --- a/src/pages/playground/style/input-list.less +++ b/src/pages/playground/style/input-list.less @@ -10,11 +10,11 @@ justify-content: space-between; padding: 0; padding-right: 6px; + overflow: hidden; cursor: pointer; transition: background-color 0.3s ease; border-radius: var(--border-radius-base); border: 1px solid var(--ant-color-border); - background-color: #fff; .btn-group { display: none; diff --git a/src/pages/playground/style/rerank.less b/src/pages/playground/style/rerank.less index 5a49f072..22825494 100644 --- a/src/pages/playground/style/rerank.less +++ b/src/pages/playground/style/rerank.less @@ -14,7 +14,6 @@ padding-top: 16px; position: sticky; top: 0; - background: var(--color-white-1); z-index: 100; align-items: center; } diff --git a/src/pages/usage/components/over-view.less b/src/pages/usage/components/over-view.less index e3b421ef..f7913aeb 100644 --- a/src/pages/usage/components/over-view.less +++ b/src/pages/usage/components/over-view.less @@ -6,7 +6,7 @@ display: flex; justify-content: space-around; border-radius: var(--ant-border-radius-lg); - border: 1px solid var(--color-border-1); + border: 1px solid var(--ant-color-border); } }