GRV-Summit-Site/components/home/LastYearWinnerTip.tsx
Kirubel-Kibru-Yaltopia 06936e7a4f
Some checks are pending
Deploy to Cloudflare Workers (OpenNext) / deploy (push) Waiting to run
-
2026-05-21 21:04:53 +03:00

137 lines
4.4 KiB
TypeScript

"use client";
import { useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { ExternalLink, HandHeart } from "lucide-react";
import { getWinnerImpact, type LastYearWinner } from "@/content/last-year-winners";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
type Props = {
company: LastYearWinner;
className?: string;
};
function externalLinkProps(href: string) {
return href.startsWith("http") ? { target: "_blank" as const, rel: "noopener noreferrer" } : {};
}
function FounderPhoto({ company }: { company: LastYearWinner }) {
const [failed, setFailed] = useState(false);
const src = company.founderImageSrc;
if (src && !failed) {
return (
<Image
src={src}
alt=""
width={48}
height={48}
className="size-12 shrink-0 rounded-full border-2 border-[#1a5c38]/15 object-cover"
onError={() => setFailed(true)}
/>
);
}
const initials =
company.initials ??
(company.name
? company.name
.split(/\s+/)
.map((w) => w[0])
.join("")
.slice(0, 2)
.toUpperCase()
: "GR");
return (
<div
className="flex size-12 shrink-0 items-center justify-center rounded-full border-2 border-[#1a5c38]/15 bg-[#f0f5f2] text-sm font-bold text-[#1a5c38]"
aria-hidden
>
{initials}
</div>
);
}
export function LastYearWinnerTip({ company, className }: Props) {
const impact = getWinnerImpact(company);
const headline = impact.metrics.find((m) => m.highlight) ?? impact.metrics[0];
const supporting = impact.metrics.filter((m) => m !== headline).slice(0, 2);
const name = company.name ?? "GRV Summit alumni";
const viewHref = impact.links.view ?? impact.links.website;
const donateHref = impact.links.donate;
return (
<div className={cn("w-[min(calc(100vw-2rem),16.5rem)]", className)}>
<div className="flex gap-3 px-3 pt-3 pb-2">
<FounderPhoto company={company} />
<div className="min-w-0 flex-1">
<p className="truncate text-[11px] font-semibold uppercase tracking-wider text-[#1a5c38]">
{name}
</p>
{company.founderName ? (
<p className="truncate text-[10px] text-[#3d5248]/80">{company.founderName}</p>
) : null}
<p className="mt-1 line-clamp-2 text-[11px] leading-snug text-[#3d5248]">
{impact.summary}
</p>
</div>
</div>
{headline ? (
<div className="mx-3 mb-2 rounded-lg border border-[#1a5c38]/12 bg-[#f0f5f2] px-3 py-2.5 text-center">
<p className="text-[10px] font-bold uppercase tracking-wider text-[#1a5c38]/75">
{headline.label}
</p>
<p className="winner-impact-value mt-0.5 font-display text-2xl font-extrabold tracking-tight text-[#0d3d26]">
{headline.value}
</p>
</div>
) : null}
{supporting.length > 0 ? (
<dl className="grid grid-cols-2 gap-1.5 px-3 pb-2">
{supporting.map((m) => (
<div key={m.label} className="rounded-md bg-[#f7faf8] px-2 py-1.5 text-center">
<dt className="text-[9px] font-semibold uppercase tracking-wide text-[#1a5c38]/65">
{m.label}
</dt>
<dd className="text-xs font-bold text-[#0d3d26]">{m.value}</dd>
</div>
))}
</dl>
) : null}
{(viewHref || donateHref) && (
<div className="flex items-center justify-end gap-2 border-t border-[#1a5c38]/10 bg-[#f7faf8]/80 px-3 py-2">
{viewHref ? (
<Button
variant="outline"
size="icon-sm"
className="rounded-full border-[#1a5c38]/20 text-[#1a5c38] hover:bg-[#f0f5f2]"
asChild
>
<Link href={viewHref} aria-label="View startup" {...externalLinkProps(viewHref)}>
<ExternalLink className="size-4" />
</Link>
</Button>
) : null}
{donateHref ? (
<Button
size="icon-sm"
className="rounded-full bg-[#1a5c38] text-white hover:bg-[#0d3d26]"
asChild
>
<Link href={donateHref} aria-label="Donate" {...externalLinkProps(donateHref)}>
<HandHeart className="size-4" />
</Link>
</Button>
) : null}
</div>
)}
</div>
);
}