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

120 lines
3.7 KiB
TypeScript
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.
'use client'
import { Level } from '@/types'
import { Button } from '@/components/ui/button'
import { Pencil, Trash2 } from 'lucide-react'
import Image from 'next/image'
// 列宽定义header 和 row 必须保持一致。用 grid-template-columns 统一控制。
// 序号 | 图片 | 答案 | 谐音梗 | 提示 | 创建时间 | 操作
export const GRID_TEMPLATE =
'minmax(60px,60px) minmax(120px,120px) minmax(80px,1fr) minmax(100px,1fr) minmax(160px,2fr) minmax(100px,100px) minmax(100px,100px)'
interface LevelRowProps {
level: Level
index: number
onEdit: (level: Level) => void
onDelete: (id: string) => void
}
export function LevelRow({ level, index, onEdit, onDelete }: LevelRowProps) {
return (
<div
style={{ gridTemplateColumns: GRID_TEMPLATE }}
className="grid items-center gap-3 px-3 border-b bg-background text-sm min-h-[64px] hover:bg-muted/30 transition-colors"
>
{/* 序号:用数组 index + 1而不是 DB 里已弃用的 sortOrder */}
<span className="font-mono tabular-nums text-muted-foreground">
{index + 1}
</span>
{/* 图片 */}
<div className="flex gap-1.5">
<div className="relative w-12 h-12 rounded overflow-hidden bg-gray-100 flex-shrink-0">
{level.image1Url ? (
<Image
src={level.image1Url}
alt="图片1"
fill
className="object-cover"
sizes="48px"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-gray-400 text-[10px]">
</div>
)}
</div>
<div className="relative w-12 h-12 rounded overflow-hidden bg-gray-100 flex-shrink-0">
{level.image2Url ? (
<Image
src={level.image2Url}
alt="图片2"
fill
className="object-cover"
sizes="48px"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-gray-400 text-[10px]">
</div>
)}
</div>
</div>
{/* 答案 */}
<span className="font-medium truncate">{level.answer}</span>
{/* 谐音梗 */}
<span className="truncate">
{level.punchline ? (
<span className="text-orange-600">{level.punchline}</span>
) : (
<span className="text-muted-foreground"></span>
)}
</span>
{/* 提示 */}
<span className="truncate text-muted-foreground">
{(() => {
const hints = [level.hint1, level.hint2, level.hint3].filter(Boolean)
return hints.length > 0 ? hints.join('、') : '—'
})()}
</span>
{/* 创建时间 */}
<span className="text-muted-foreground whitespace-nowrap">
{new Date(level.createdAt).toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
})}
</span>
{/* 操作 */}
<div className="flex items-center gap-2">
<Button
variant="outline"
size="icon"
className="h-8 w-8"
onClick={() => onEdit(level)}
aria-label="编辑关卡"
title="编辑"
>
<Pencil className="h-3.5 w-3.5" />
</Button>
<Button
variant="outline"
size="icon"
className="h-8 w-8 border-red-200 text-red-600 hover:border-red-600 hover:bg-red-600 hover:text-white focus-visible:ring-red-500"
onClick={() => onDelete(level.id)}
aria-label="删除关卡"
title="删除"
>
<Trash2 className="h-3.5 w-3.5" />
</Button>
</div>
</div>
)
}