Remove unused UI components

This commit is contained in:
zhangchen
2026-03-28 02:07:50 +08:00
parent 75e3a4652e
commit 9cf78c6334
7 changed files with 0 additions and 255 deletions

View File

@@ -1,9 +0,0 @@
export { Button, buttonVariants } from './button'
export { Card, CardHeader, CardTitle, CardContent, CardFooter } from './card'
export { Badge, badgeVariants } from './badge'
export { Input } from './input'
export { Select } from './select'
export { Label } from './label'
export { Switch } from './switch'
export { Textarea } from './textarea'
export { ToastContainer, toast, dismissToast } from './toast'

View File

@@ -1,33 +0,0 @@
import * as React from 'react'
import { cn } from '@/lib/utils'
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
error?: boolean
}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, error, ...props }, ref) => {
return (
<input
type={type}
className={cn(
'flex h-9 w-full rounded-md px-3 py-2 text-sm',
'bg-[var(--bg-input)] border',
'text-[var(--text-primary)] placeholder:text-[var(--text-muted)]',
'transition-all duration-200',
'focus:outline-none focus:ring-2 focus:ring-[var(--accent)]/50 focus:border-[var(--accent)]',
'disabled:cursor-not-allowed disabled:opacity-50',
error
? 'border-red-500/50 focus:ring-red-500/50'
: 'border-[var(--border)]',
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = 'Input'
export { Input }

View File

@@ -1,28 +0,0 @@
import * as React from 'react'
import { cn } from '@/lib/utils'
export interface LabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {
required?: boolean
}
const Label = React.forwardRef<HTMLLabelElement, LabelProps>(
({ className, required, children, ...props }, ref) => {
return (
<label
ref={ref}
className={cn(
'text-xs font-medium text-[var(--text-secondary)]',
'transition-colors duration-200',
required && "after:content-['*'] after:text-red-400 after:ml-0.5",
className
)}
{...props}
>
{children}
</label>
)
}
)
Label.displayName = 'Label'
export { Label }

View File

@@ -1,28 +0,0 @@
import * as React from 'react'
import { cn } from '@/lib/utils'
export interface SelectProps extends React.SelectHTMLAttributes<HTMLSelectElement> {}
const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
({ className, ...props }, ref) => {
return (
<select
className={cn(
'flex h-9 w-full rounded-md px-3 py-2 text-sm',
'bg-[var(--bg-input)] border border-[var(--border)]',
'text-[var(--text-primary)]',
'transition-all duration-200',
'focus:outline-none focus:ring-2 focus:ring-[var(--accent)]/50 focus:border-[var(--accent)]',
'disabled:cursor-not-allowed disabled:opacity-50',
'appearance-none bg-[length:16px_16px] bg-[right_12px_center] bg-no-repeat',
className
)}
ref={ref}
{...props}
/>
)
}
)
Select.displayName = 'Select'
export { Select }

View File

@@ -1,41 +0,0 @@
import * as React from 'react'
import { cn } from '@/lib/utils'
interface SwitchProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
checked: boolean
onCheckedChange: (checked: boolean) => void
}
const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(
({ className, checked, onCheckedChange, disabled, ...props }, ref) => {
return (
<button
type="button"
role="switch"
aria-checked={checked}
ref={ref}
disabled={disabled}
onClick={() => onCheckedChange(!checked)}
className={cn(
'relative inline-flex h-5 w-9 shrink-0 cursor-pointer rounded-full border-2 border-transparent',
'transition-colors duration-200 ease-out',
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg-base)]',
'disabled:cursor-not-allowed disabled:opacity-50',
checked ? 'bg-[var(--accent)]' : 'bg-[var(--border)]',
className
)}
{...props}
>
<span
className={cn(
'pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow-lg transform transition-transform duration-200 ease-out',
checked ? 'translate-x-4' : 'translate-x-0'
)}
/>
</button>
)
}
)
Switch.displayName = 'Switch'
export { Switch }

View File

@@ -1,28 +0,0 @@
import * as React from 'react'
import { cn } from '@/lib/utils'
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
'flex min-h-[80px] w-full rounded-md px-3 py-2 text-sm',
'bg-[var(--bg-input)] border border-[var(--border)]',
'text-[var(--text-primary)] placeholder:text-[var(--text-muted)]',
'transition-all duration-200',
'focus:outline-none focus:ring-2 focus:ring-[var(--accent)]/50 focus:border-[var(--accent)]',
'disabled:cursor-not-allowed disabled:opacity-50',
'resize-none',
className
)}
ref={ref}
{...props}
/>
)
}
)
Textarea.displayName = 'Textarea'
export { Textarea }

View File

@@ -1,88 +0,0 @@
import { useEffect, useState } from 'react'
import { cn } from '@/lib/utils'
import { CheckCircle, XCircle, AlertCircle, X } from 'lucide-react'
type ToastType = 'success' | 'error' | 'warning' | 'info'
interface Toast {
id: string
type: ToastType
title: string
message?: string
}
const icons: Record<ToastType, React.ReactNode> = {
success: <CheckCircle className="h-5 w-5 text-emerald-400" />,
error: <XCircle className="h-5 w-5 text-red-400" />,
warning: <AlertCircle className="h-5 w-5 text-amber-400" />,
info: <AlertCircle className="h-5 w-5 text-blue-400" />,
}
const bgColors: Record<ToastType, string> = {
success: 'border-emerald-500/30 bg-emerald-500/10',
error: 'border-red-500/30 bg-red-500/10',
warning: 'border-amber-500/30 bg-amber-500/10',
info: 'border-blue-500/30 bg-blue-500/10',
}
let toastId = 0
const listeners: Set<(toasts: Toast[]) => void> = new Set()
let toasts: Toast[] = []
function notify(listeners: Set<any>, toasts: Toast[]) {
listeners.forEach(l => l([...toasts]))
}
export function toast(type: ToastType, title: string, message?: string) {
const id = String(++toastId)
toasts = [...toasts, { id, type, title, message }]
notify(listeners, toasts)
setTimeout(() => {
toasts = toasts.filter(t => t.id !== id)
notify(listeners, toasts)
}, 4000)
}
export function dismissToast(id: string) {
toasts = toasts.filter(t => t.id !== id)
notify(listeners, toasts)
}
export function ToastContainer() {
const [items, setItems] = useState<Toast[]>([])
useEffect(() => {
listeners.add(setItems)
return () => { listeners.delete(setItems) }
}, [])
return (
<div className="fixed bottom-4 right-4 z-50 flex flex-col gap-2">
{items.map((t) => (
<div
key={t.id}
className={cn(
'flex items-start gap-3 p-4 rounded-lg border backdrop-blur-sm',
'bg-[var(--bg-card)] shadow-lg',
'animate-in slide-in-from-right fade-in duration-300',
bgColors[t.type]
)}
>
{icons[t.type]}
<div className="flex-1">
<p className="text-sm font-medium text-[var(--text-primary)]">{t.title}</p>
{t.message && (
<p className="text-xs text-[var(--text-muted)] mt-1">{t.message}</p>
)}
</div>
<button
onClick={() => dismissToast(t.id)}
className="text-[var(--text-muted)] hover:text-[var(--text-primary)] transition-colors"
>
<X className="h-4 w-4" />
</button>
</div>
))}
</div>
)
}