Files
MemeStudio/components/levels/level-table.tsx
2026-05-01 08:44:56 +08:00

106 lines
2.7 KiB
TypeScript

'use client'
import { useRef } from 'react'
import { useVirtualizer } from '@tanstack/react-virtual'
import { Level } from '@/types'
import { GRID_TEMPLATE, LevelRow } from './level-row'
interface LevelTableProps {
levels: Level[]
onEdit: (level: Level) => void
onDelete: (id: string) => void
}
const HEADER_COLUMNS = [
'序号',
'图片',
'答案',
'谐音梗',
'提示',
'创建时间',
'操作',
]
export function LevelTable({ levels, onEdit, onDelete }: LevelTableProps) {
const scrollRef = useRef<HTMLDivElement>(null)
const items = levels
const rowVirtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => scrollRef.current,
estimateSize: () => 64,
overscan: 10,
})
if (items.length === 0) {
return (
<div className="text-center py-12 text-gray-500">
<p></p>
<p className="text-sm mt-2">
&ldquo;&rdquo;
</p>
</div>
)
}
return (
<div className="space-y-2">
<div className="rounded-md border overflow-hidden bg-background">
{/* 表头 */}
<div
className="grid items-center gap-3 px-3 py-2 bg-muted/40 text-xs font-medium text-muted-foreground border-b"
style={{ gridTemplateColumns: GRID_TEMPLATE }}
>
{HEADER_COLUMNS.map((h, i) => (
<span key={i}>{h}</span>
))}
</div>
{/* 虚拟滚动 */}
<div
ref={scrollRef}
className="overflow-auto"
style={{ height: 'calc(100vh - 260px)' }}
>
<div
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
position: 'relative',
width: '100%',
}}
>
{rowVirtualizer.getVirtualItems().map((v) => {
const level = items[v.index]
return (
<div
key={level.id}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
transform: `translateY(${v.start}px)`,
}}
>
<LevelRow
level={level}
index={v.index}
onEdit={onEdit}
onDelete={onDelete}
/>
</div>
)
})}
</div>
</div>
</div>
<div className="px-2 text-xs text-muted-foreground">
{items.length} · /
</div>
</div>
)
}