91 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Tag 组件
*
* 统一的标签组件,适合后台筛选与分类展示
* 用于显示分类、类型等标签信息
* 支持少量语义色和尺寸(xs、sm、md、lg)
* 支持点击事件,可用于筛选等功能
*
* @created 2025-11-22
* @updated 2026-05-25 - 收敛为后台工作台风格
* @component
*/
'use client'
import { ReactNode } from 'react'
import { useThemeStyles, cn } from '@/lib/ui-styles'
interface TagProps {
children: ReactNode
color?: 'blue' | 'green' | 'orange' | 'purple' | 'indigo' | 'pink' | 'cyan'
size?: 'xs' | 'sm' | 'md' | 'lg'
className?: string
onClick?: () => void
selected?: boolean
}
export default function Tag({
children,
color = 'blue',
size = 'md',
className = '',
onClick,
selected = false,
}: TagProps) {
useThemeStyles()
const colorClasses: Record<NonNullable<TagProps['color']>, string> = {
blue: selected
? 'bg-slate-900 dark:bg-slate-100 text-white dark:text-slate-950 border-slate-900 dark:border-slate-100'
: 'bg-white dark:bg-slate-900 text-slate-700 dark:text-slate-200 border-slate-300 dark:border-slate-700 hover:bg-slate-50 dark:hover:bg-slate-800',
green: selected
? 'bg-emerald-700 dark:bg-emerald-500 text-white border-emerald-700 dark:border-emerald-500'
: 'bg-emerald-50 dark:bg-emerald-950/30 text-emerald-800 dark:text-emerald-200 border-emerald-200 dark:border-emerald-800 hover:bg-emerald-100 dark:hover:bg-emerald-950/50',
orange: selected
? 'bg-amber-700 dark:bg-amber-500 text-white dark:text-slate-950 border-amber-700 dark:border-amber-500'
: 'bg-amber-50 dark:bg-amber-950/30 text-amber-800 dark:text-amber-200 border-amber-200 dark:border-amber-800 hover:bg-amber-100 dark:hover:bg-amber-950/50',
purple: selected
? 'bg-slate-700 dark:bg-slate-200 text-white dark:text-slate-950 border-slate-700 dark:border-slate-200'
: 'bg-slate-50 dark:bg-slate-900 text-slate-700 dark:text-slate-200 border-slate-300 dark:border-slate-700 hover:bg-slate-100 dark:hover:bg-slate-800',
indigo: selected
? 'bg-slate-700 dark:bg-slate-200 text-white dark:text-slate-950 border-slate-700 dark:border-slate-200'
: 'bg-slate-50 dark:bg-slate-900 text-slate-700 dark:text-slate-200 border-slate-300 dark:border-slate-700 hover:bg-slate-100 dark:hover:bg-slate-800',
pink: selected
? 'bg-slate-700 dark:bg-slate-200 text-white dark:text-slate-950 border-slate-700 dark:border-slate-200'
: 'bg-slate-50 dark:bg-slate-900 text-slate-700 dark:text-slate-200 border-slate-300 dark:border-slate-700 hover:bg-slate-100 dark:hover:bg-slate-800',
cyan: selected
? 'bg-slate-700 dark:bg-slate-200 text-white dark:text-slate-950 border-slate-700 dark:border-slate-200'
: 'bg-slate-50 dark:bg-slate-900 text-slate-700 dark:text-slate-200 border-slate-300 dark:border-slate-700 hover:bg-slate-100 dark:hover:bg-slate-800',
}
const sizeClasses = {
xs: 'px-2.5 py-0.5 text-[11px] font-medium',
sm: 'px-3 py-1 text-xs font-medium',
md: 'px-4 py-1.5 text-sm font-medium',
lg: 'px-5 py-2 text-base font-medium',
} as const
const baseClasses = cn(
'inline-flex items-center justify-center',
'rounded-md border',
'transition-colors duration-200 ease-out',
onClick && 'cursor-pointer'
)
return (
<span
className={cn(
baseClasses,
colorClasses[color],
sizeClasses[size],
className
)}
onClick={onClick}
>
{children}
</span>
)
}