134 lines
5.0 KiB
TypeScript
134 lines
5.0 KiB
TypeScript
import { ExternalLink, Plus, Tags } from "lucide-react";
|
|
import Link from "next/link";
|
|
|
|
import { StatsCard } from "@/components/dashboard/stats-card";
|
|
import { MotionFade } from "@/components/motion-fade";
|
|
import { PortfolioProjectActions } from "@/components/admin/portfolio-project-actions";
|
|
import { AppCard } from "@/components/ui/app-card";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Button } from "@/components/ui/button";
|
|
import { CardContent } from "@/components/ui/card";
|
|
import { getAdminAppPath } from "@/lib/admin-routing";
|
|
import { getSiteSettings } from "@/lib/app-config";
|
|
import { getLocalizedPath } from "@/lib/locale";
|
|
import { getLocalizedValue, type PortfolioCategoryView, type PortfolioProjectView } from "@/lib/portfolio";
|
|
|
|
type PortfolioProjectsOverviewProps = {
|
|
categories: PortfolioCategoryView[];
|
|
projects: PortfolioProjectView[];
|
|
selectedCategory: string;
|
|
selectedStatus: "all" | "draft" | "published";
|
|
};
|
|
|
|
const copy = {
|
|
all: "Alle",
|
|
newProject: "Neues Projekt",
|
|
newCategory: "Neues Kategorie",
|
|
openProject: "Ansehen",
|
|
untitled: "Unbenanntes Projekt",
|
|
empty: "Noch keine Projekte vorhanden.",
|
|
};
|
|
|
|
export async function PortfolioProjectsOverview({
|
|
categories,
|
|
projects,
|
|
selectedCategory,
|
|
}: PortfolioProjectsOverviewProps) {
|
|
const siteSettings = await getSiteSettings();
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex flex-col gap-4 xl:flex-row xl:items-end xl:justify-between">
|
|
<div className="grid gap-4 md:grid-cols-3 xl:min-w-[520px]">
|
|
<StatsCard title="Projects" value={String(projects.length)} />
|
|
<StatsCard title="Categories" value={String(categories.length)} />
|
|
<StatsCard
|
|
title="Published"
|
|
value={String(projects.filter((project) => project.isPublished).length)}
|
|
/>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap gap-2">
|
|
<Button asChild>
|
|
<Link href={getAdminAppPath("/portfolio/projects/new")}>
|
|
<Plus className="h-4 w-4" />
|
|
{copy.newProject}
|
|
</Link>
|
|
</Button>
|
|
<Button asChild variant="outline">
|
|
<Link href={getAdminAppPath("/portfolio/categories")}>
|
|
<Tags className="h-4 w-4" />
|
|
{copy.newCategory}
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap gap-2">
|
|
<Button asChild variant={selectedCategory === "" ? "default" : "outline"}>
|
|
<Link href={getAdminAppPath("/portfolio")}>{copy.all}</Link>
|
|
</Button>
|
|
{categories.map((category) => (
|
|
<Button
|
|
key={category.id}
|
|
asChild
|
|
variant={selectedCategory === category.id ? "default" : "outline"}
|
|
>
|
|
<Link href={`${getAdminAppPath("/portfolio")}?category=${category.id}`}>
|
|
{category.name.de || category.name.en || category.name.ar}
|
|
</Link>
|
|
</Button>
|
|
))}
|
|
</div>
|
|
|
|
<div className="grid gap-4">
|
|
{projects.map((project, index) => (
|
|
<MotionFade key={project.id} delay={0.06 + index * 0.03}>
|
|
<AppCard interactive>
|
|
<CardContent className="flex flex-col gap-4 p-5 lg:flex-row lg:items-center lg:justify-between">
|
|
<div className="space-y-2">
|
|
<div className="flex flex-wrap items-center gap-2">
|
|
<p className="text-xl font-semibold text-foreground">
|
|
{getLocalizedValue(project.title, "de") || copy.untitled}
|
|
</p>
|
|
<Badge variant={project.isPublished ? "success" : "warning"}>
|
|
{project.isPublished ? "Published" : "Draft"}
|
|
</Badge>
|
|
<Badge variant="outline">{project.viewMode}</Badge>
|
|
</div>
|
|
<div className="flex flex-wrap gap-2 text-sm text-muted-foreground">
|
|
<span>{project.category.name.de || project.category.name.en || project.category.name.ar}</span>
|
|
<span>{project.projectYear}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex flex-wrap gap-3">
|
|
<Button asChild variant="outline">
|
|
<Link
|
|
href={getLocalizedPath("de", `/portfolio/${project.slug}`, siteSettings.defaultLocale)}
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
>
|
|
<ExternalLink className="h-4 w-4" />
|
|
{copy.openProject}
|
|
</Link>
|
|
</Button>
|
|
<PortfolioProjectActions projectId={project.id} />
|
|
</div>
|
|
</CardContent>
|
|
</AppCard>
|
|
</MotionFade>
|
|
))}
|
|
|
|
{projects.length === 0 ? (
|
|
<AppCard>
|
|
<CardContent className="p-6 text-sm text-muted-foreground">
|
|
{copy.empty}
|
|
</CardContent>
|
|
</AppCard>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|