From 94840c1b0a9cef376d30ac39a0a89dfdd20ee3f4 Mon Sep 17 00:00:00 2001 From: goddonebianu Date: Tue, 24 Feb 2026 08:02:39 +0800 Subject: [PATCH] abstract range --- .../srt-player/VideoPlayer/VideoPanel.tsx | 2 +- .../srt-player/components/atoms/SeekBar.tsx | 2 +- src/components/ui/RangeInput.tsx | 45 ----------- src/components/ui/index.ts | 4 +- src/design-system/README.md | 18 ++++- src/design-system/base/range.tsx | 81 +++++++++++++++++++ src/design-system/lib/utils.ts | 20 +++++ 7 files changed, 121 insertions(+), 51 deletions(-) delete mode 100644 src/components/ui/RangeInput.tsx create mode 100644 src/design-system/base/range.tsx create mode 100644 src/design-system/lib/utils.ts diff --git a/src/app/(features)/srt-player/VideoPlayer/VideoPanel.tsx b/src/app/(features)/srt-player/VideoPlayer/VideoPanel.tsx index 26db463..063c313 100644 --- a/src/app/(features)/srt-player/VideoPlayer/VideoPanel.tsx +++ b/src/app/(features)/srt-player/VideoPlayer/VideoPanel.tsx @@ -1,7 +1,7 @@ import { useState, useRef, forwardRef, useEffect, useCallback } from "react"; import { SubtitleDisplay } from "./SubtitleDisplay"; import { LightButton } from "@/design-system/base/button"; -import { RangeInput } from "@/components/ui/RangeInput"; +import { RangeInput } from "@/design-system/base/range"; import { getIndex, parseSrt, getNearistIndex } from "../subtitle"; import { useTranslations } from "next-intl"; diff --git a/src/app/(features)/srt-player/components/atoms/SeekBar.tsx b/src/app/(features)/srt-player/components/atoms/SeekBar.tsx index 5dc0df7..bb0f732 100644 --- a/src/app/(features)/srt-player/components/atoms/SeekBar.tsx +++ b/src/app/(features)/srt-player/components/atoms/SeekBar.tsx @@ -2,7 +2,7 @@ import React from "react"; import { SeekBarProps } from "../../types/player"; -import { RangeInput } from "@/components/ui/RangeInput"; +import { RangeInput } from "@/design-system/base/range"; export function SeekBar({ value, max, onChange, disabled, className }: SeekBarProps) { return ( diff --git a/src/components/ui/RangeInput.tsx b/src/components/ui/RangeInput.tsx deleted file mode 100644 index 9dea32d..0000000 --- a/src/components/ui/RangeInput.tsx +++ /dev/null @@ -1,45 +0,0 @@ -"use client"; - -import React from "react"; - -interface RangeInputProps { - value: number; - max: number; - onChange: (value: number) => void; - disabled?: boolean; - className?: string; - min?: number; -} - -export function RangeInput({ - value, - max, - onChange, - disabled = false, - className = "", - min = 0, -}: RangeInputProps) { - const handleChange = React.useCallback((event: React.ChangeEvent) => { - const newValue = parseInt(event.target.value); - onChange(newValue); - }, [onChange]); - - const progressPercentage = ((value - min) / (max - min)) * 100; - - return ( - - ); -} diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 24bee35..35f8f2f 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -19,9 +19,7 @@ export { type ButtonSize, type ButtonProps } from '@/design-system/base/button'; - -// 业务特定组件 -export { RangeInput } from './RangeInput'; +export { RangeInput, Range, type RangeProps } from '@/design-system/base/range'; export { Container } from './Container'; export { PageLayout } from './PageLayout'; export { PageHeader } from './PageHeader'; diff --git a/src/design-system/README.md b/src/design-system/README.md index 85d8cf8..4e74daa 100644 --- a/src/design-system/README.md +++ b/src/design-system/README.md @@ -7,6 +7,7 @@ ``` src/design-system/ ├── lib/ # 工具函数 +│ └── utils.ts ├── base/ # 基础组件 │ ├── button.tsx │ ├── input.tsx @@ -15,7 +16,8 @@ src/design-system/ │ ├── checkbox.tsx │ ├── radio.tsx │ ├── switch.tsx -│ └── select.tsx +│ ├── select.tsx +│ └── range.tsx ├── feedback/ # 反馈组件 │ ├── alert.tsx │ ├── progress.tsx @@ -82,6 +84,7 @@ export function MyComponent() { | [Radio](#radio) | 单选按钮 | ✅ | | [Switch](#switch) | 开关 | ✅ | | [Select](#select) | 下拉选择框 | ✅ | +| [Range](#range) | 范围滑块 | ✅ | ### 反馈组件 @@ -232,6 +235,19 @@ import { Switch } from '@/design-system/base/switch'; ``` +### Range + +范围滑块组件。 + +```tsx +import { Range } from '@/design-system/base/range'; + + + +``` + +**别名**: `RangeInput`(向后兼容) + ### Alert 警告提示组件。 diff --git a/src/design-system/base/range.tsx b/src/design-system/base/range.tsx new file mode 100644 index 0000000..11cc017 --- /dev/null +++ b/src/design-system/base/range.tsx @@ -0,0 +1,81 @@ +"use client"; + +/** + * Range - 范围滑块组件 + * + * 支持自定义进度条颜色、禁用状态和样式覆盖的滑块输入组件。 + * + * @example + * ```tsx + * import { Range } from '@/design-system/base/range'; + * + * + * + * ``` + */ + +import * as React from "react"; +import { cn } from "@/design-system/lib/utils"; + +export interface RangeProps extends Omit, "onChange"> { + /** 当前值 */ + value: number; + /** 值变化回调 */ + onChange: (value: number) => void; + /** 最小值 (默认: 0) */ + min?: number; + /** 最大值 */ + max: number; +} + +export const Range = React.forwardRef( + ( + { + value, + min = 0, + max, + onChange, + disabled = false, + className, + ...props + }, + ref + ) => { + const handleChange = React.useCallback( + (event: React.ChangeEvent) => { + const newValue = parseInt(event.target.value); + onChange(newValue); + }, + [onChange] + ); + + const progressPercentage = ((value - min) / (max - min)) * 100; + + return ( + + ); + } +); + +Range.displayName = "Range"; + +// 向后兼容别名 +export const RangeInput = Range; diff --git a/src/design-system/lib/utils.ts b/src/design-system/lib/utils.ts new file mode 100644 index 0000000..dd4ad74 --- /dev/null +++ b/src/design-system/lib/utils.ts @@ -0,0 +1,20 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +/** + * 合并 Tailwind CSS 类名的工具函数 + * + * @example + * ```tsx + * import { cn } from '@/design-system/lib/utils'; + * + * const className = cn( + * 'base-class', + * isActive && 'active-class', + * 'another-class' + * ); + * ``` + */ +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +}