diff --git a/web/src/components/ui/charts/BusterChartLegend/LegendDot.tsx b/web/src/components/ui/charts/BusterChartLegend/LegendDot.tsx index cda3d1307..1a15afc4d 100644 --- a/web/src/components/ui/charts/BusterChartLegend/LegendDot.tsx +++ b/web/src/components/ui/charts/BusterChartLegend/LegendDot.tsx @@ -1,19 +1,62 @@ -import { createStyles } from 'antd-style'; import React, { useMemo } from 'react'; import { useMemoizedFn } from 'ahooks'; -import { BusterChartLegendItem } from './interfaces'; +import { type BusterChartLegendItem } from './interfaces'; import { ChartType } from '../interfaces'; import { Target } from '../../icons'; import { cn } from '@/lib/classMerge'; +import { cva, type VariantProps } from 'class-variance-authority'; -export const LegendItemDot: React.FC<{ - color: string | undefined; - inactive: boolean; - type: BusterChartLegendItem['type']; - onFocusItem?: () => void; - size?: 'sm' | 'md'; -}> = React.memo(({ color, type, inactive, onFocusItem, size = 'md' }) => { - const { styles, cx } = useStyles(); +const itemVariants = cva( + 'dot group relative flex items-center justify-center transition-all duration-300', + { + variants: { + size: { + sm: 'w-[8px] h-[12px]', + default: 'w-[18px] h-[12px]' + } + } + } +); + +const dotVariants = cva('bg-border transition-colors duration-100', { + variants: { + size: { + sm: '', + default: '' + }, + type: { + bar: 'w-[18px] h-[12px] rounded-sm', + line: 'w-[18px] h-[4px] rounded-sm', + scatter: 'w-[12px] h-[12px] rounded-full' + } + }, + + compoundVariants: [ + { + size: 'sm', + type: 'bar', + className: 'w-[8px] h-[8px] rounded-[1.5px]' + }, + { + size: 'sm', + type: 'line', + className: 'w-[8px] h-[2px] rounded-1.5px' + }, + { + size: 'sm', + type: 'scatter', + className: 'w-[8px] h-[8px]' + } + ] +}); +export const LegendItemDot: React.FC< + { + color: string | undefined; + inactive: boolean; + type: BusterChartLegendItem['type']; + onFocusItem?: () => void; + } & VariantProps +> = React.memo(({ color, type, inactive, onFocusItem, size = 'default' }) => { const hasFocusItem = onFocusItem !== undefined; const onClick = useMemoizedFn((e: React.MouseEvent) => { @@ -32,34 +75,28 @@ export const LegendItemDot: React.FC<{ }); const dotStyle = useMemo(() => { - if (type === ChartType.Line) return styles.lineChartDot; - if (type === ChartType.Scatter) return styles.scatterChartDot; - return styles.barChartDot; - }, [type]); + if (type === ChartType.Line) return dotVariants({ size, type: 'line' }); + if (type === ChartType.Scatter) return dotVariants({ size, type: 'scatter' }); + return dotVariants({ size, type: 'bar' }); + }, [type, size]); return ( -
+
{hasFocusItem && (
-
+ className="absolute hidden h-full w-full items-center justify-center overflow-hidden group-hover:flex"> +
@@ -70,66 +107,3 @@ export const LegendItemDot: React.FC<{ ); }); LegendItemDot.displayName = 'LegendItemDot'; - -const useStyles = createStyles(({ token, css }) => { - return { - container: css` - width: 18px; - height: 12px; - - &.sm { - width: 8px; - height: 12px; - } - - .focus-item { - border-radius: 4px; - &:hover { - background-color: ${token.colorBgElevated} !important; - } - } - `, - - dotcontainer: css` - background: ${token.colorBorder}; - `, - - barChartDot: css` - width: 18px; - height: 12px; - border-radius: 4px; - &.sm { - width: 8px; - height: 8px; - border-radius: 1.5px; - } - `, - lineChartDot: css` - width: 18px; - height: 4px; - border-radius: 4px; - &.sm { - width: 8px; - height: 2px; - } - `, - scatterChartDot: css` - width: 12px; - height: 12px; - border-radius: 100%; - &.sm { - width: 8px; - height: 8px; - } - `, - focusDot: css` - height: 12px; - width: 12px; - border-radius: 4px; - &.sm { - height: 8px; - width: 8px; - } - ` - }; -}); diff --git a/web/src/components/ui/charts/BusterChartLegend/LegendItem.tsx b/web/src/components/ui/charts/BusterChartLegend/LegendItem.tsx index 0142eb62b..639aebd95 100644 --- a/web/src/components/ui/charts/BusterChartLegend/LegendItem.tsx +++ b/web/src/components/ui/charts/BusterChartLegend/LegendItem.tsx @@ -127,7 +127,7 @@ const LegendItemStandard = React.memo( clickable: clickable })}> { border-color: ${token.colorBgContainerDisabled}; } ` - // legendItemHeadline: css` - // padding: 0px 8px; - // border-radius: 8px; - // height: 44px; - // overflow: hidden; - - // &.clickable { - // cursor: pointer; - // transition: background 0.125s ease; - // &:hover { - // background: ${token.controlItemBgHover}; - // } - // } - - // &.inactive { - // border-color: ${token.colorBgContainerDisabled}; - // } - // ` }; }); diff --git a/web/src/components/ui/charts/BusterChartLegend/stories/LegendDot.stories.tsx b/web/src/components/ui/charts/BusterChartLegend/stories/LegendDot.stories.tsx new file mode 100644 index 000000000..c653b8ad5 --- /dev/null +++ b/web/src/components/ui/charts/BusterChartLegend/stories/LegendDot.stories.tsx @@ -0,0 +1,82 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { LegendItemDot } from '../LegendDot'; +import { ChartType } from '../../interfaces'; + +const meta = { + title: 'Base/Charts/LegendDot', + component: LegendItemDot, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'], + argTypes: { + color: { control: 'color' }, + type: { + control: 'select', + options: [ChartType.Line, ChartType.Bar, ChartType.Scatter] + }, + inactive: { control: 'boolean' }, + size: { + control: 'select', + options: ['sm', 'default'] + } + } +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Bar: Story = { + args: { + color: '#1677ff', + type: ChartType.Bar, + inactive: false, + size: 'default' + } +}; + +export const Line: Story = { + args: { + color: '#1677ff', + type: ChartType.Line, + inactive: false, + size: 'default' + } +}; + +export const Scatter: Story = { + args: { + color: '#1677ff', + type: ChartType.Scatter, + inactive: false, + size: 'default' + } +}; + +export const Small: Story = { + args: { + color: '#1677ff', + type: ChartType.Bar, + inactive: false, + size: 'sm' + } +}; + +export const Inactive: Story = { + args: { + color: '#1677ff', + type: ChartType.Bar, + inactive: true, + size: 'default' + } +}; + +export const WithFocus: Story = { + args: { + color: '#1677ff', + type: ChartType.Bar, + inactive: false, + size: 'default', + onFocusItem: () => console.log('Focus item clicked') + } +};