spb/spboucher.ai Public
spboucher.ai — personal website of Simon-Pierre Boucher.
TypeScript 93.4%
HTML 5.5%
CSS 1%
1/*2 app-card.tsx3 spboucher.ai Web4 Author: Simon-Pierre Boucher5 Mail: contact@spboucher.ai6*/78import Image from "next/image";9import Link from "next/link";10import { ArrowUpRight, Download, Github, Tag } from "lucide-react";1112import type { ZyquoApp } from "@/lib/apps";13import { buttonVariants } from "@/components/ui/button";14import {15 Card,16 CardContent,17 CardDescription,18 CardFooter,19 CardHeader,20 CardTitle,21} from "@/components/ui/card";22import { cn } from "@/lib/utils";2324export function AppCard({ app }: { app: ZyquoApp }) {25 return (26 <Card className="group flex h-full flex-col hover:-translate-y-1 hover:border-primary/25 hover:shadow-[var(--shadow-lift)]">27 <CardHeader className="flex-row items-center gap-4 space-y-0">28 <Image29 src={app.icon}30 alt={`${app.name} app icon`}31 width={64}32 height={64}33 className="h-16 w-16 shrink-0 rounded-[0.7rem] border border-border shadow-[var(--shadow-soft)] transition-transform duration-300 group-hover:scale-105"34 />35 <div className="min-w-0">36 <CardTitle className="text-lg">37 <span aria-hidden="true" className="mr-1.5">38 {app.emoji}39 </span>40 {app.name}41 </CardTitle>42 <CardDescription className="mt-1">{app.tagline}</CardDescription>43 </div>44 </CardHeader>45 <CardContent className="flex-1">46 <p className="text-sm text-muted-foreground">{app.description}</p>47 </CardContent>48 <CardFooter className="flex flex-wrap gap-2">49 <Link50 href={`/apps/${app.slug}`}51 className={cn(buttonVariants({ variant: "secondary", size: "sm" }))}52 >53 <ArrowUpRight aria-hidden="true" />54 Details55 </Link>56 <a57 href={app.repo}58 target="_blank"59 rel="noopener noreferrer"60 className={cn(buttonVariants({ variant: "outline", size: "sm" }))}61 >62 <Github aria-hidden="true" />63 GitHub Repo64 </a>65 <a66 href={app.release}67 target="_blank"68 rel="noopener noreferrer"69 className={cn(buttonVariants({ variant: "outline", size: "sm" }))}70 >71 <Tag aria-hidden="true" />72 Release73 </a>74 <a75 href={app.dmg}76 className={cn(buttonVariants({ variant: "default", size: "sm" }))}77 >78 <Download aria-hidden="true" />79 Download DMG80 </a>81 </CardFooter>82 </Card>83 );84}85