Files
gitlab-instance-0a899031_di…/app/[locale]/course/VideoCard.tsx
2026-03-08 04:30:57 -05:00

77 lines
2.6 KiB
TypeScript

"use client";
import { useCallback, useEffect, useState } from "react";
import { generateVideoPoster } from "./videoPoster";
type Lesson = {
id: string;
title: string;
duration: string;
videoUrl?: string;
};
type Props = {
lesson: Lesson;
completed?: boolean;
onComplete?: () => void;
};
export function VideoCard({ lesson, completed = false, onComplete }: Props) {
const [poster, setPoster] = useState<string | null>(null);
useEffect(() => {
setPoster(generateVideoPoster(lesson.title, lesson.id));
}, [lesson.title, lesson.id]);
const handleEnded = useCallback(() => {
onComplete?.();
}, [onComplete]);
return (
<article
className={`group overflow-hidden rounded-2xl border shadow-sm transition-all duration-200 hover:shadow-md ${
completed
? "border-emerald-200 bg-emerald-50/50 hover:border-emerald-300"
: "border-slate-100 bg-white hover:border-slate-200"
}`}
>
{/* 三级标题:视频上方,突出显示 */}
<div className="flex items-center gap-3 border-b border-slate-100 bg-white/80 px-4 py-3">
<span
className={`flex h-8 w-8 shrink-0 items-center justify-center rounded-lg text-xs font-bold ${
completed ? "bg-emerald-100 text-emerald-600" : "bg-sky-50 text-sky-600"
}`}
>
{lesson.id}
</span>
<h4 className="min-w-0 flex-1 text-base font-semibold leading-snug text-slate-800 line-clamp-2">
{lesson.title}
</h4>
</div>
<div className="relative aspect-video overflow-hidden bg-slate-900">
<video
src={lesson.videoUrl}
poster={poster ?? undefined}
controls
playsInline
onEnded={handleEnded}
className="h-full w-full object-contain transition-transform duration-300 group-hover:scale-[1.01]"
preload="metadata"
>
</video>
<span className="absolute bottom-2 right-2 rounded bg-black/60 px-2 py-0.5 text-xs font-medium tabular-nums text-white/90 backdrop-blur-sm">
{lesson.duration}
</span>
{completed && (
<span className="absolute top-2 right-2 flex h-8 w-8 items-center justify-center rounded-full bg-emerald-500 text-white shadow-md">
<svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="M5 13l4 4L19 7" />
</svg>
</span>
)}
</div>
</article>
);
}