UPD: initial architecture
CI / quality (push) Waiting to run

This commit is contained in:
Uklonil
2026-07-27 10:23:50 +02:00
parent 63fc0e6771
commit 3aeaed0af2
108 changed files with 11103 additions and 0 deletions
@@ -0,0 +1,74 @@
import { MessageCircle, Sparkles, Users } from "lucide-react";
import type { recommendationStrengthEnum } from "@/db/schema";
type Strength = (typeof recommendationStrengthEnum.enumValues)[number];
const labels: Record<Strength, string> = {
NORMAL: "Normal",
HIGH: "Highly recommended",
MUST_EXPERIENCE: "Must experience",
};
export function RecommendationCard({
recommendation,
}: {
recommendation: {
reason: string;
strength: Strength;
mediaItem: {
title: string;
type: string;
releaseYear: number | null;
posterUrl: string | null;
};
recommendedBy: { name: string; image: string | null };
statuses: { status: string }[];
comments: unknown[];
reactions: unknown[];
};
}) {
const interested = recommendation.statuses.filter((item) => item.status === "INTERESTED").length;
const completed = recommendation.statuses.filter((item) => item.status === "COMPLETED").length;
return (
<article className="rounded-xl border border-border bg-surface p-5 shadow-sm">
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span className="flex h-7 w-7 items-center justify-center rounded-full bg-primary/15 text-xs text-primary">
{recommendation.recommendedBy.name.slice(0, 1)}
</span>
<span>
<strong className="font-medium text-foreground">
{recommendation.recommendedBy.name}
</strong>{" "}
emitted a beacon
</span>
</div>
<div className="mt-4 flex gap-4">
<div
aria-label={`Poster placeholder for ${recommendation.mediaItem.title}`}
className="flex h-24 w-16 shrink-0 items-center justify-center rounded bg-muted text-center text-[10px] text-muted-foreground"
>
{recommendation.mediaItem.title}
</div>
<div>
<h2 className="font-semibold">{recommendation.mediaItem.title}</h2>
<p className="mt-1 text-sm text-muted-foreground">
{recommendation.mediaItem.type.replace("_", " ")} ·{" "}
{recommendation.mediaItem.releaseYear ?? "—"}
</p>
<p className="mt-3 text-sm leading-6">{recommendation.reason}</p>
<span className="mt-3 inline-flex items-center gap-1 rounded-full bg-primary/15 px-2.5 py-1 text-xs font-medium text-primary">
<Sparkles size={13} />
{labels[recommendation.strength]}
</span>
</div>
</div>
<footer className="mt-5 flex gap-4 border-t border-border pt-3 text-xs text-muted-foreground">
<span className="flex items-center gap-1">
<Users size={14} />
{interested} interested · {completed} completed
</span>
<span className="flex items-center gap-1">
<MessageCircle size={14} />
{recommendation.comments.length} comments
</span>
</footer>
</article>
);
}