项目文件夹

文件
wehub-resource-sync 221778fa98
rowboat / apps/x Vitest suites (push) Has been cancelled
rowboat / apps/x Electron package smoke test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:33:34 +08:00

78 行
3.0 KiB
TypeScript

'use client';
import clsx from 'clsx';
import { SearchIcon } from "lucide-react";
import { tokens } from "@/app/styles/design-tokens";
export type TimeFilter = 'all' | 'today' | 'week' | 'month';
interface SearchInputProps {
value: string;
onChange: (value: string) => void;
onTimeFilterChange: (filter: TimeFilter) => void;
timeFilter: TimeFilter;
placeholder?: string;
}
export function SearchInput({
value,
onChange,
onTimeFilterChange,
timeFilter,
placeholder = "Search projects..."
}: SearchInputProps) {
return (
<div className="space-y-3">
<div className="relative">
<SearchIcon
size={16}
className={clsx(
"absolute left-3 top-1/2 -translate-y-1/2",
tokens.colors.light.text.tertiary,
tokens.colors.dark.text.tertiary
)}
/>
<input
type="text"
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder={placeholder}
className={clsx(
"w-full pl-9 pr-4 py-2",
tokens.typography.sizes.sm,
tokens.radius.md,
tokens.transitions.default,
"bg-gray-50 dark:bg-gray-800",
tokens.colors.light.text.primary,
tokens.colors.dark.text.primary,
"placeholder:text-gray-400 dark:placeholder:text-gray-500",
"border border-gray-200 dark:border-gray-700",
"focus:ring-2 focus:ring-indigo-500/50",
"focus:border-transparent"
)}
/>
</div>
<div className="flex gap-2">
{(['all', 'today', 'week', 'month'] as const).map(filter => (
<button
key={filter}
onClick={() => onTimeFilterChange(filter)}
className={clsx(
"px-3 py-1",
tokens.typography.sizes.sm,
tokens.typography.weights.medium,
tokens.radius.md,
tokens.transitions.default,
timeFilter === filter
? "bg-indigo-600 text-white"
: "bg-gray-50 dark:bg-gray-800 text-gray-600 dark:text-gray-400",
"hover:bg-gray-100 dark:hover:bg-gray-700",
"focus:outline-none focus:ring-2 focus:ring-indigo-500/50"
)}
>
{filter.charAt(0).toUpperCase() + filter.slice(1)}
</button>
))}
</div>
</div>
);
}