80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
Card,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/components/ui/card";
|
|
import { cn } from "@/lib/utils";
|
|
import { ChevronRightIcon } from "lucide-react";
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import Markdown from "react-markdown";
|
|
|
|
// Interface is identical to ProjectCard but adds the 'venue'
|
|
interface Props {
|
|
title: string;
|
|
href: string; // Made href non-optional as research should always link somewhere
|
|
description: string;
|
|
dates: string;
|
|
venue?: string; // The new field for publication venue
|
|
tags: readonly string[];
|
|
image?: string;
|
|
video?: string;
|
|
className?: string;
|
|
}
|
|
|
|
export function ResearchCard({
|
|
title,
|
|
href,
|
|
description,
|
|
dates,
|
|
venue,
|
|
image,
|
|
video,
|
|
className,
|
|
}: Props) {
|
|
return (
|
|
<Link href={href} className={cn("block rounded-xl h-full cards", className)}>
|
|
<Card className="py-2 px-0 group flex h-full flex-col overflow-hidden border transition-shadow duration-300 ease-out hover:shadow-lg">
|
|
{video && (
|
|
<video
|
|
src={video}
|
|
autoPlay
|
|
loop
|
|
muted
|
|
playsInline
|
|
className="pointer-events-none w-full object-cover object-top"
|
|
style={{ height: "160px" }}
|
|
/>
|
|
)}
|
|
{image && (
|
|
<div className="relative w-full" style={{ height: "160px" }}>
|
|
<Image
|
|
src={image}
|
|
alt={title}
|
|
fill
|
|
className="object-cover object-center"
|
|
/>
|
|
</div>
|
|
)}
|
|
<CardHeader className="flex-1 px-4 pb-1">
|
|
<div className="space-y-1">
|
|
<CardTitle className="text-base flex items-start justify-between">
|
|
<span className="flex-1">{title}</span>
|
|
<ChevronRightIcon className="size-4 shrink-0 translate-x-0 transform opacity-0 transition-all duration-300 ease-out group-hover:translate-x-1 group-hover:opacity-100" />
|
|
</CardTitle>
|
|
<div className="flex items-center gap-x-2 text-xs text-muted-foreground mt-1">
|
|
{venue && <span className="font-semibold text-primary">{venue}</span>}
|
|
{venue && <span>•</span>}
|
|
<time>{dates}</time>
|
|
</div>
|
|
<div className="prose max-w-full text-pretty font-normal text-xs text-foreground dark:prose-invert">
|
|
<Markdown>{description}</Markdown>
|
|
</div>
|
|
</div>
|
|
</CardHeader>
|
|
</Card>
|
|
</Link>
|
|
);
|
|
} |