fix: compact material library search and filter toolbar

This commit is contained in:
WuYongJie 2026-10-07 15:53:11 +08:00
parent 24fe0de19d
commit 73c1e98309
2 changed files with 33 additions and 30 deletions

View File

@ -1391,24 +1391,25 @@ export default function MaterialLibraryPage() {
<main className="container mx-auto max-w-7xl px-4 py-6">
{/* Header Section */}
<div className="mb-8">
<div className="flex justify-end items-center mb-6">
<div className="flex items-center gap-3">
<div className="min-w-0 flex-1">
<SearchBar
value={searchKeyword}
onChange={handleSearchChange}
placeholder="搜索素材 ID、SPU、任务号、店铺、场景或作者"
isSearching={isSearchPending}
/>
</div>
<button
type="button"
onClick={() => setShowUploadModal(true)}
className="rounded-xl bg-[#247fd3] px-6 py-3 font-medium text-white shadow-[0_8px_22px_rgba(36,127,211,0.20)] transition-colors hover:bg-[#176fc1]"
className="inline-flex h-12 shrink-0 items-center whitespace-nowrap rounded-xl bg-[#247fd3] px-3 text-sm font-medium text-white shadow-[0_8px_22px_rgba(36,127,211,0.20)] transition-colors hover:bg-[#176fc1] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1677ff] focus-visible:ring-offset-2 sm:px-6 sm:text-base"
>
<span className="mr-2">+</span>
上传素材
</button>
</div>
{/* Search Bar - 实时搜索 */}
<SearchBar
value={searchKeyword}
onChange={handleSearchChange}
placeholder="搜索素材 ID、SPU、任务号、店铺、场景或作者"
isSearching={isSearchPending}
/>
{/* 筛选面板组件 */}
<FilterPanel
selectedMaterialType={selectedMaterialType}

View File

@ -256,8 +256,8 @@ function FilterPanel(props: FilterPanelProps) {
return (
<>
<div className="relative z-10 mb-4">
<div className="flex flex-wrap items-end justify-between gap-x-4 gap-y-3 border-b border-[#e7e8ea]">
<div ref={rowRef} className="relative min-w-0 basis-full sm:basis-auto sm:flex-1">
<div className="border-b border-[#e7e8ea]">
<div ref={rowRef} className="relative min-w-0">
<div className="flex items-end gap-x-8" aria-busy={facetsLoading}>
{renderTypeTab('全部', totals.materialType, selectedMaterialType === '', () => setSelectedMaterialType(''))}
{visibleTypes.map((type) => (
@ -322,35 +322,37 @@ function FilterPanel(props: FilterPanelProps) {
</div>
</div>
</div>
</div>
</div>
<div className="mb-4 flex flex-wrap items-center justify-between gap-x-3 gap-y-1">
<p className="shrink-0 whitespace-nowrap text-[13px] text-[#86898e]">
共 <span className="font-en text-[15px] font-medium tabular-nums tracking-[0.06em] text-[#1a1c1d]">{facetsLoading ? '…' : materialsCount.toLocaleString('zh-CN')}</span> 条
{selectedMaterialType && <span className="sr-only">{facetsLoading ? '计数加载中' : `${materialsCount} 个素材`}</span>}
</p>
<div className="ml-auto flex flex-wrap items-center justify-end gap-x-2 gap-y-1 sm:gap-x-4">
<button
type="button"
onClick={() => setIsFilterCollapsed(!isFilterCollapsed)}
aria-label={isFilterCollapsed ? '展开更多筛选' : '收起筛选'}
aria-expanded={!isFilterCollapsed}
aria-controls="material-filter-fields"
className="mb-2 inline-flex min-h-9 shrink-0 items-center gap-2 whitespace-nowrap rounded-lg px-3 text-sm text-[#52565b] transition-colors hover:bg-white hover:text-[#1a1c1d] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1677ff]"
className="inline-flex min-h-11 shrink-0 items-center gap-1.5 whitespace-nowrap rounded-lg px-2 text-[13px] text-[#52565b] transition-colors hover:bg-white hover:text-[#1a1c1d] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1677ff]"
>
<SlidersHorizontal className="h-4 w-4" aria-hidden="true" />
{isFilterCollapsed ? '展开更多筛选' : '收起筛选'}
{isFilterCollapsed && activeFilterCount > 0 && <span className="ml-1.5 font-en text-[11px] text-[#5a66b8]">{activeFilterCount}</span>}
</button>
</div>
</div>
<div className="mb-4 flex flex-wrap items-baseline justify-between gap-3">
<p className="text-[13px] text-[#86898e]">
共 <span className="font-en text-[15px] font-medium tabular-nums tracking-[0.06em] text-[#1a1c1d]">{facetsLoading ? '…' : materialsCount.toLocaleString('zh-CN')}</span> 条
{selectedMaterialType && <span className="sr-only">{facetsLoading ? '计数加载中' : `${materialsCount} 个素材`}</span>}
</p>
<div className="flex items-center gap-4 text-[13px]" role="group" aria-labelledby="materials-sort-label">
<h2 id="materials-sort-label" className="sr-only">排序方式</h2>
<button onClick={() => handleSortChange('createdAt')} className={`flex items-center gap-1 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1a1c1d]/70 focus-visible:ring-offset-2 rounded-sm ${sortBy === 'createdAt' ? 'text-[#1a1c1d]' : 'text-[#86898e] hover:text-[#1a1c1d]'}`}>
{sortBy === 'createdAt' && sortOrder === 'asc' ? '最早上传' : '最新上传'}
{sortBy === 'createdAt' && <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d={sortOrder === 'desc' ? 'M19 9l-7 7-7-7' : 'M5 15l7-7 7 7'} /></svg>}
</button>
<button onClick={() => handleSortChange('downloadCount')} className={`flex items-center gap-1 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1a1c1d]/70 focus-visible:ring-offset-2 rounded-sm ${sortBy === 'downloadCount' ? 'text-[#1a1c1d]' : 'text-[#86898e] hover:text-[#1a1c1d]'}`}>
{sortBy === 'downloadCount' && sortOrder === 'asc' ? '下载最少' : '下载最多'}
{sortBy === 'downloadCount' && <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d={sortOrder === 'desc' ? 'M19 9l-7 7-7-7' : 'M5 15l7-7 7 7'} /></svg>}
</button>
<div className="flex shrink-0 items-center gap-3 text-[13px] sm:gap-4" role="group" aria-labelledby="materials-sort-label">
<h2 id="materials-sort-label" className="sr-only">排序方式</h2>
<button onClick={() => handleSortChange('createdAt')} className={`flex min-h-11 items-center gap-1 whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1a1c1d]/70 focus-visible:ring-offset-2 rounded-sm ${sortBy === 'createdAt' ? 'text-[#1a1c1d]' : 'text-[#86898e] hover:text-[#1a1c1d]'}`}>
{sortBy === 'createdAt' && sortOrder === 'asc' ? '最早上传' : '最新上传'}
{sortBy === 'createdAt' && <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d={sortOrder === 'desc' ? 'M19 9l-7 7-7-7' : 'M5 15l7-7 7 7'} /></svg>}
</button>
<button onClick={() => handleSortChange('downloadCount')} className={`flex min-h-11 items-center gap-1 whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#1a1c1d]/70 focus-visible:ring-offset-2 rounded-sm ${sortBy === 'downloadCount' ? 'text-[#1a1c1d]' : 'text-[#86898e] hover:text-[#1a1c1d]'}`}>
{sortBy === 'downloadCount' && sortOrder === 'asc' ? '下载最少' : '下载最多'}
{sortBy === 'downloadCount' && <svg className="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d={sortOrder === 'desc' ? 'M19 9l-7 7-7-7' : 'M5 15l7-7 7 7'} /></svg>}
</button>
</div>
</div>
</div>
{!isFilterCollapsed && (