Files
website/components/resume-card.tsx
2025-09-12 23:20:36 +02:00

111 lines
3.5 KiB
TypeScript

"use client";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Badge } from "@/components/ui/badge";
import { Card, CardHeader } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { motion } from "motion/react";
import { ChevronRightIcon } from "lucide-react";
import Link from "next/link";
import React from "react";
interface ResumeCardProps {
logoUrl: string;
altText: string;
title: string;
subtitle?: string;
href?: string;
badges?: readonly string[];
period: string;
description?: string;
}
export const ResumeCard = ({
logoUrl,
altText,
title,
subtitle,
href,
badges,
period,
description,
}: ResumeCardProps) => {
const [isExpanded, setIsExpanded] = React.useState(false);
const handleClick = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
if (description) {
e.preventDefault();
setIsExpanded(!isExpanded);
}
};
return (
<Link
href={href || "#"}
className="font-normal no-underline block cursor-pointer"
onClick={handleClick}
>
<Card className="flex flex-row items-center p-4 shadow-sm transition-all duration-300 ease-out hover:shadow-lg dark:shadow-[var(--shadow-glow)] dark:hover:shadow-[var(--shadow-glow-hover)]">
<div className="flex-none">
<Avatar className="size-12 m-auto bg-muted-background shadow-sm dark:shadow-[var(--shadow-glow)]">
<AvatarImage
src={logoUrl}
alt={altText}
className="object-contain"
/>
<AvatarFallback>{altText[0]}</AvatarFallback>
</Avatar>
</div>
<div className="flex-grow ml-4 items-center flex-col group">
<CardHeader className="px-0">
<div className="flex items-center justify-between gap-x-0 text-base">
<h3 className="inline-flex items-center justify-center font-semibold leading-none text-xs sm:text-sm">
{title}
{badges && (
<span className="inline-flex gap-x-1">
{badges.map((badge, index) => (
<Badge
variant="secondary"
className="align-middle text-xs"
key={index}
>
{badge}
</Badge>
))}
</span>
)}
<ChevronRightIcon
className={cn(
"size-4 translate-x-0 transform opacity-0 transition-all duration-300 ease-out group-hover:translate-x-1 group-hover:opacity-100",
isExpanded ? "rotate-90" : "rotate-0"
)}
/>
</h3>
<div className="text-xs sm:text-sm tabular-nums text-muted-foreground text-right">
{period}
</div>
</div>
{subtitle && <div className="font-sans text-xs">{subtitle}</div>}
</CardHeader>
{description && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{
opacity: isExpanded ? 1 : 0,
height: isExpanded ? "auto" : 0,
}}
transition={{
duration: 0.7,
ease: [0.16, 1, 0.3, 1],
}}
className="mt-2 text-xs sm:text-sm"
>
{description}
</motion.div>
)}
</div>
</Card>
</Link>
);
};