casualroom/apps/fenghuo/web/components/articles/article-toolbar.tsx

141 lines
4.6 KiB
TypeScript
Executable File
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.

import { Badge } from '@nice/ui/components/badge';
import { Button } from '@nice/ui/components/button';
import { Input } from '@nice/ui/components/input';
import { Label } from '@nice/ui/components/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@nice/ui/components/select';
import { TabsList, TabsTrigger } from '@nice/ui/components/tabs';
import { IconSearch } from '@tabler/icons-react';
import { SORT_OPTIONS, BATCH_ACTIONS } from '@/lib/articles/constants';
import { TermSelect } from '../selector/term-select';
import { useArticlesContext } from './context';
export function ArticleToolbar() {
const {
filters,
selectedArticles,
batchAction,
stats,
updateFilters,
setBatchAction,
handleBatchAction,
resetSelection,
} = useArticlesContext();
return (
<div className="bg-background px-6 py-4 ">
<div className="flex items-center justify-between gap-4">
{/* 左侧:状态标签页 */}
<div className="flex items-center">
<TabsList className="grid w-auto grid-cols-5 h-9">
<TabsTrigger value="all" className="px-3 text-sm">
{' '}
<Badge variant="secondary" className="ml-1 text-xs">
{stats.all}
</Badge>
</TabsTrigger>
<TabsTrigger value="published" className="px-3 text-sm">
{' '}
<Badge variant="secondary" className="ml-1 text-xs">
{stats.published}
</Badge>
</TabsTrigger>
<TabsTrigger value="draft" className="px-3 text-sm">
稿{' '}
<Badge variant="secondary" className="ml-1 text-xs">
{stats.draft}
</Badge>
</TabsTrigger>
<TabsTrigger value="archived" className="px-3 text-sm">
{' '}
<Badge variant="secondary" className="ml-1 text-xs">
{stats.archived}
</Badge>
</TabsTrigger>
<TabsTrigger value="trash" className="px-3 text-sm">
{' '}
<Badge variant="secondary" className="ml-1 text-xs">
{stats.deleted}
</Badge>
</TabsTrigger>
</TabsList>
</div>
{/* 中间:批量操作 */}
<div className="flex items-center justify-center">
{selectedArticles.length > 0 && (
<div className="flex items-center gap-2">
<Badge variant="secondary" className="text-sm font-medium">
{selectedArticles.length}
</Badge>
<Select value={batchAction} onValueChange={setBatchAction}>
<SelectTrigger className="w-32 h-9">
<SelectValue placeholder="批量操作" />
</SelectTrigger>
<SelectContent>
{BATCH_ACTIONS.map((action) => (
<SelectItem key={action.value} value={action.value}>
<div className="flex items-center gap-2">
<action.icon className="h-3 w-3" />
{action.label}
</div>
</SelectItem>
))}
</SelectContent>
</Select>
<Button size="sm" onClick={handleBatchAction} disabled={!batchAction} className="h-9">
</Button>
<Button size="sm" variant="outline" onClick={resetSelection} className="h-9">
</Button>
</div>
)}
</div>
{/* 右侧:搜索、分类和排序 */}
<div className="flex items-center gap-3">
{/* 搜索和分类 */}
<div className="flex items-center gap-3">
<div className="relative w-64">
<IconSearch className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<Input
placeholder="搜索文章..."
value={filters.searchTerm}
onChange={(e) => updateFilters({ searchTerm: e.target.value })}
className="pl-10 h-9"
/>
</div>
<TermSelect
taxonomySlug="category"
value={filters.categoryFilter}
onValueChange={(value) => updateFilters({ categoryFilter: value as string })}
placeholder="全部分类"
className="h-9 w-32"
allowClear
/>
</div>
{/* 排序 */}
<div className="flex items-center gap-2">
<Label htmlFor="sort-select" className="text-sm font-medium text-muted-foreground whitespace-nowrap">
</Label>
<Select value={filters.sortBy} onValueChange={(value) => updateFilters({ sortBy: value })}>
<SelectTrigger id="sort-select" className="w-48 h-9">
<SelectValue />
</SelectTrigger>
<SelectContent>
{SORT_OPTIONS.map((option) => (
<SelectItem key={option.value} value={option.value}>
{option.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
</div>
</div>
);
}