feat: update dependencies to k-ap v0.1.7 and add profileHref utility for user links
This commit is contained in:
@@ -1,4 +1,9 @@
|
||||
import Link from "next/link";
|
||||
import { User } from "@/lib/api";
|
||||
import { UserAvatar } from "@/components/user-avatar";
|
||||
import { formatDistanceToNow, format } from "date-fns";
|
||||
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||
import { profileHref } from "@/lib/utils";
|
||||
|
||||
function isSafeImageUrl(url: string): boolean {
|
||||
try {
|
||||
@@ -40,6 +45,7 @@ function StarRating({ rating, max = 5 }: { rating: number; max?: number }) {
|
||||
export function MovieCard({ meta, author, createdAt }: MovieCardProps) {
|
||||
const isWatchlist = meta.watchlistEntry === true;
|
||||
const year = meta.releaseYear ? ` (${meta.releaseYear})` : "";
|
||||
const timeAgo = formatDistanceToNow(createdAt, { addSuffix: true });
|
||||
const watchedDate = meta.watchedAt
|
||||
? new Date(meta.watchedAt).toLocaleDateString(undefined, {
|
||||
year: "numeric",
|
||||
@@ -49,57 +55,74 @@ export function MovieCard({ meta, author, createdAt }: MovieCardProps) {
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className="rounded-lg border bg-card overflow-hidden">
|
||||
<div className="flex gap-3 p-3">
|
||||
{/* Poster */}
|
||||
<div className="shrink-0 w-16 h-24 rounded overflow-hidden bg-muted">
|
||||
{meta.posterUrl && isSafeImageUrl(meta.posterUrl) ? (
|
||||
<img
|
||||
src={meta.posterUrl}
|
||||
alt={meta.movieTitle}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center text-muted-foreground text-xs text-center px-1">
|
||||
No poster
|
||||
</div>
|
||||
)}
|
||||
<Card className="transition-transform duration-200 hover:-translate-y-0.5 hover:shadow-fa-lg">
|
||||
<CardHeader className="flex flex-row items-center space-y-0 pb-3">
|
||||
<Link
|
||||
href={profileHref(author.username, author.local)}
|
||||
className="flex items-center gap-3 hover:opacity-80"
|
||||
>
|
||||
<UserAvatar src={author.avatarUrl} alt={author.displayName ?? author.username} />
|
||||
<div className="flex flex-col min-w-0">
|
||||
<span className="font-bold truncate">{author.displayName ?? author.username}</span>
|
||||
{!author.local && (
|
||||
<span className="text-xs text-muted-foreground/70 truncate">
|
||||
{author.username.startsWith("@") ? author.username : `@${author.username}`}
|
||||
</span>
|
||||
)}
|
||||
<time
|
||||
dateTime={createdAt.toISOString()}
|
||||
title={format(createdAt, "PPP p")}
|
||||
className="text-sm text-muted-foreground"
|
||||
>
|
||||
{timeAgo}
|
||||
</time>
|
||||
</div>
|
||||
</Link>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="pt-0">
|
||||
<div className="flex gap-3">
|
||||
<div className="shrink-0 w-16 h-24 rounded overflow-hidden bg-muted">
|
||||
{meta.posterUrl && isSafeImageUrl(meta.posterUrl) ? (
|
||||
<img
|
||||
src={meta.posterUrl}
|
||||
alt={meta.movieTitle}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center text-muted-foreground text-xs text-center px-1">
|
||||
No poster
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-semibold text-sm leading-tight">
|
||||
{meta.movieTitle}
|
||||
{year && <span className="font-normal text-muted-foreground">{year}</span>}
|
||||
</p>
|
||||
|
||||
{isWatchlist ? (
|
||||
<p className="text-xs text-muted-foreground mt-1">📋 Want to watch</p>
|
||||
) : (
|
||||
<>
|
||||
{meta.rating !== undefined && (
|
||||
<div className="mt-1">
|
||||
<StarRating rating={meta.rating} />
|
||||
</div>
|
||||
)}
|
||||
{watchedDate && (
|
||||
<p className="text-xs text-muted-foreground mt-1">Watched {watchedDate}</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{meta.comment && (
|
||||
<p className="text-sm mt-2 text-foreground/80 line-clamp-3">{meta.comment}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Info */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-semibold text-sm leading-tight">
|
||||
{meta.movieTitle}
|
||||
{year && <span className="font-normal text-muted-foreground">{year}</span>}
|
||||
</p>
|
||||
|
||||
{isWatchlist ? (
|
||||
<p className="text-xs text-muted-foreground mt-1">📋 Want to watch</p>
|
||||
) : (
|
||||
<>
|
||||
{meta.rating !== undefined && (
|
||||
<div className="mt-1">
|
||||
<StarRating rating={meta.rating} />
|
||||
</div>
|
||||
)}
|
||||
{watchedDate && (
|
||||
<p className="text-xs text-muted-foreground mt-1">Watched {watchedDate}</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{meta.comment && (
|
||||
<p className="text-sm mt-2 text-foreground/80 line-clamp-3">{meta.comment}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="px-3 py-2 border-t bg-muted/30 flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<span>@{author.username}</span>
|
||||
<span>·</span>
|
||||
<span>{createdAt.toLocaleDateString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user