Repository Public
1/*2 ka-app-card.tsx3 spboucher.ai Web4 Author: Simon-Pierre Boucher5 Mail: contact@spboucher.ai6*/78import Link from "next/link";9import { ArrowUpRight, ExternalLink } from "lucide-react";1011import type { KaApp } from "@/lib/groupe-ka";12import { buttonVariants } from "@/components/ui/button";13import {14 Card,15 CardContent,16 CardDescription,17 CardFooter,18 CardHeader,19 CardTitle,20} from "@/components/ui/card";21import { cn } from "@/lib/utils";2223export function KaAppCard({ app }: { app: KaApp }) {24 return (25 <Card className="group flex h-full flex-col hover:-translate-y-1 hover:border-primary/25 hover:shadow-[var(--shadow-lift)]">26 <CardHeader className="flex-row items-center gap-4 space-y-0">27 {/* Official brand favicon (SVG) — plain <img>: next/image would route28 local SVGs through the optimizer, which requires dangerouslyAllowSVG. */}29 {/* eslint-disable-next-line @next/next/no-img-element */}30 <img31 src={app.icon}32 alt={`${app.name} icon`}33 width={56}34 height={56}35 className="h-14 w-14 shrink-0 rounded-[0.7rem] border border-border shadow-[var(--shadow-soft)] transition-transform duration-300 group-hover:scale-105"36 />37 <div className="min-w-0">38 <CardTitle className="text-lg">{app.name}</CardTitle>39 <CardDescription className="mt-1">{app.tagline}</CardDescription>40 </div>41 </CardHeader>42 <CardContent className="flex-1">43 <p className="text-sm text-muted-foreground">{app.description}</p>44 </CardContent>45 <CardFooter className="flex flex-wrap items-center justify-between gap-2">46 <span className="font-mono text-[0.68rem] uppercase tracking-[0.12em] text-muted-foreground">47 {app.domain}48 </span>49 <span className="flex gap-2">50 <Link51 href={`/projects/${app.slug}`}52 className={cn(buttonVariants({ variant: "secondary", size: "sm" }))}53 >54 <ArrowUpRight aria-hidden="true" />55 Details56 </Link>57 <a58 href={app.url}59 target="_blank"60 rel="noopener noreferrer"61 className={cn(buttonVariants({ variant: "outline", size: "sm" }))}62 >63 <ExternalLink aria-hidden="true" />64 Visit65 </a>66 </span>67 </CardFooter>68 </Card>69 );70}71