118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
"use client";
|
|
import { CitationProvider } from "@/components/context-citation";
|
|
import { ReferencesContainer } from "@/components/container-references";
|
|
import { CustomMDX } from "@/components/mdx-custom";
|
|
import { Breadcrumbs } from "./element-breadcrumbs";
|
|
import Link from "next/link";
|
|
import { Publication } from "@/lib/publications";
|
|
import { ProjectNavigation } from "./project-navigation";
|
|
import { Tag } from "lucide-react";
|
|
import Image from "next/image";
|
|
|
|
interface Post {
|
|
code: string;
|
|
frontmatter: {
|
|
title: string;
|
|
excerpt?: string;
|
|
teaser?: string;
|
|
tags?: string[];
|
|
icon?: string;
|
|
date?: string;
|
|
};
|
|
}
|
|
|
|
interface NavigationLink {
|
|
slug: string;
|
|
title: string;
|
|
}
|
|
interface ArticleProps {
|
|
post: Post;
|
|
publications: Publication[];
|
|
navigation?: { prev: NavigationLink | null; next: NavigationLink | null };
|
|
basePath: string;
|
|
}
|
|
|
|
export function Article({
|
|
post,
|
|
publications,
|
|
navigation,
|
|
basePath,
|
|
}: ArticleProps) {
|
|
return (
|
|
<CitationProvider publications={publications}>
|
|
<main className="flex flex-col min-h-[100dvh] space-y-10">
|
|
<section id="article">
|
|
<div className="mx-auto w-full max-w-4xl space-y-8 mt-12">
|
|
<div className="flex justify-between">
|
|
<Breadcrumbs
|
|
basePath={basePath}
|
|
baseLabel={basePath.charAt(0).toUpperCase() + basePath.slice(1)}
|
|
/>
|
|
{post.frontmatter.date && (
|
|
<time
|
|
className="text-sm text-muted-foreground"
|
|
dateTime={post.frontmatter.date}>
|
|
{new Date(post.frontmatter.date).toLocaleDateString("en-US", {
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "numeric",
|
|
})}
|
|
</time>
|
|
)}
|
|
</div>
|
|
<div className="space-y-2">
|
|
<h1 className="text-3xl font-bold tracking-tighter sm:text-5xl xl:text-6xl/none">
|
|
{post.frontmatter.title}
|
|
</h1>
|
|
{post.frontmatter.excerpt && (
|
|
<p className="text-muted-foreground">
|
|
{post.frontmatter.excerpt}
|
|
</p>
|
|
)}
|
|
</div>
|
|
<article className="prose prose-stone dark:prose-invert max-w-none overflow-hidden">
|
|
{post.frontmatter.icon && (
|
|
<div className="float-left mr-4 mb-2">
|
|
<Image
|
|
src={post.frontmatter.icon}
|
|
alt={`${post.frontmatter.title} icon`}
|
|
width={64}
|
|
height={64}
|
|
className="full"
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
<CustomMDX code={post.code} />
|
|
</article>
|
|
|
|
{post.frontmatter.tags && (
|
|
<div className="flex flex-wrap items-center gap-x-2 gap-y-1">
|
|
<Tag className="size-4 text-muted-foreground" />
|
|
{post.frontmatter.tags.map((tag: string) => (
|
|
<Link
|
|
key={tag}
|
|
href={`/tags/${tag}`}
|
|
className="px-3 py-1 text-sm font-medium bg-secondary text-secondary-foreground transition-colors hover:bg-primary hover:text-primary-foreground">
|
|
{tag}
|
|
</Link>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
<ReferencesContainer />
|
|
|
|
{navigation && (
|
|
<ProjectNavigation
|
|
prev={navigation.prev}
|
|
next={navigation.next}
|
|
basePath={basePath}
|
|
/>
|
|
)}
|
|
</div>
|
|
</section>
|
|
</main>
|
|
</CitationProvider>
|
|
);
|
|
}
|