import {
ArrowUpRight,
CalendarDays,
FolderKanban,
Tag,
UserRound,
} from "lucide-react";
import Image from "next/image";
import Link from "next/link";
import { MotionFade } from "@/components/motion-fade";
import { AppCard } from "@/components/ui/app-card";
import { Button } from "@/components/ui/button";
import { CardContent } from "@/components/ui/card";
import { getLocalizedPath, type AppLocale } from "@/lib/locale";
import {
getLocalizedValue,
resolvePortfolioProjectViewMode,
type PortfolioAssetView,
type PortfolioProjectView,
type PortfolioSectionView,
} from "@/lib/portfolio";
type PortfolioProjectDetailProps = {
item: PortfolioProjectView;
locale: AppLocale;
t: (key: "back" | "preview" | "openLink" | "gallery" | "download") => string;
};
function PortfolioImage({
src,
alt,
className,
width,
height,
}: {
src: string;
alt: string;
className: string;
width: number;
height: number;
}) {
return (
);
}
function ProjectMeta({
item,
locale,
}: {
item: PortfolioProjectView;
locale: AppLocale;
}) {
const metadata = [
{
icon: Tag,
label: getLocalizedValue(item.category.name, locale),
},
{
icon: CalendarDays,
label: String(item.projectYear),
},
{
icon: FolderKanban,
label: getLocalizedValue(item.serviceLabel, locale),
},
{
icon: UserRound,
label: item.clientName,
},
].filter((entry) => entry.label);
return (
{metadata.map((meta) => {
const Icon = meta.icon;
return (
{meta.label}
);
})}
);
}
function SectionBlock({
section,
locale,
t,
}: {
section: PortfolioSectionView;
locale: AppLocale;
t: PortfolioProjectDetailProps["t"];
}) {
const title = getLocalizedValue(section.title, locale);
const body = getLocalizedValue(section.body, locale);
if (section.type === "GALLERY") {
return (
{title}
{section.imagePath ? (
) : (
No image configured.
)}
);
}
if (section.type === "LINK") {
return (
{title}
{body ?
{body}
: null}
{section.linkUrl ? (
) : null}
);
}
return (
);
}
function AssetGallery({
assets,
locale,
t,
}: {
assets: PortfolioAssetView[];
locale: AppLocale;
t: PortfolioProjectDetailProps["t"];
}) {
if (assets.length === 0) {
return null;
}
return (
{assets.map((asset) => (
{asset.kind === "IMAGE" ? (
) : (
{getLocalizedValue(asset.alt, locale)}
)}
))}
);
}
function BadgeCount({ count }: { count: number }) {
return (
{count}
);
}
function ProjectHeader({
item,
locale,
t,
}: {
item: PortfolioProjectView;
locale: AppLocale;
t: PortfolioProjectDetailProps["t"];
}) {
return (
{getLocalizedValue(item.title, locale)}
{getLocalizedValue(item.summary, locale)}
{item.previewUrl ? (
) : null}
);
}
function GridTemplate({
item,
locale,
t,
}: PortfolioProjectDetailProps) {
return (
{item.coverImagePath ? (
) : null}
{item.sections.map((section, index) => (
))}
);
}
function StoryTemplate({
item,
locale,
t,
}: PortfolioProjectDetailProps) {
return (
{item.coverImagePath ? (
) : null}
{item.sections.map((section, index) => (
{String(index + 1).padStart(2, "0")}
))}
);
}
function CaseStudyTemplate({
item,
locale,
t,
}: PortfolioProjectDetailProps) {
const [challenge, solution, outcome, ...restSections] = item.sections;
const leadSections = [challenge, solution, outcome].filter(
(section): section is PortfolioSectionView => Boolean(section),
);
return (
{item.coverImagePath ? (
) : null}
{leadSections.map((section, index) => (
{index === 0 ? "Challenge" : index === 1 ? "Solution" : "Outcome"}
))}
Case Study Snapshot
{getLocalizedValue(item.title, locale)}
{getLocalizedValue(item.summary, locale)}
{restSections.length > 0 ? (
{restSections.map((section, index) => (
))}
) : null}
);
}
export function PortfolioProjectDetail({
item,
locale,
t,
}: PortfolioProjectDetailProps) {
const viewMode = resolvePortfolioProjectViewMode(item.viewMode);
if (viewMode === "STORY") {
return ;
}
if (viewMode === "CASE_STUDY") {
return ;
}
return ;
}