mirror of
https://github.com/runyanjake/cooking.git
synced 2026-03-26 09:53:17 -07:00
99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
import { notFound } from 'next/navigation';
|
|
import type { Metadata } from 'next';
|
|
import { compileMDX } from 'next-mdx-remote/rsc';
|
|
import remarkGfm from 'remark-gfm';
|
|
import { getRecipeByCategoryAndSlug, getAllRecipePaths } from '@/lib/recipes';
|
|
import RecipeCard from '@/components/RecipeCard';
|
|
import RecipePageLayout from '@/components/RecipePageLayout';
|
|
|
|
interface RecipePageProps {
|
|
params: Promise<{
|
|
category: string;
|
|
slug: string;
|
|
}>;
|
|
}
|
|
|
|
export async function generateStaticParams() {
|
|
const paths = getAllRecipePaths();
|
|
return paths.map((path) => ({
|
|
category: path.category,
|
|
slug: path.slug,
|
|
}));
|
|
}
|
|
|
|
export async function generateMetadata({ params }: RecipePageProps): Promise<Metadata> {
|
|
const { category, slug } = await params;
|
|
const recipe = getRecipeByCategoryAndSlug(category, slug);
|
|
|
|
if (!recipe) {
|
|
return {
|
|
title: 'Recipe Not Found',
|
|
};
|
|
}
|
|
|
|
return {
|
|
title: `${recipe.title} - Cooking`,
|
|
description: recipe.description,
|
|
keywords: recipe.tags,
|
|
openGraph: {
|
|
title: recipe.title,
|
|
description: recipe.description,
|
|
type: 'article',
|
|
},
|
|
};
|
|
}
|
|
|
|
export default async function RecipePage({ params }: RecipePageProps) {
|
|
const { category, slug } = await params;
|
|
const recipe = getRecipeByCategoryAndSlug(category, slug);
|
|
|
|
if (!recipe) {
|
|
notFound();
|
|
}
|
|
|
|
const folderPath = recipe.folderPath;
|
|
|
|
const { content } = await compileMDX({
|
|
source: recipe.content,
|
|
components: {
|
|
RecipeCard,
|
|
img: ({ src, alt }: { src?: string; alt?: string }) => {
|
|
const srcString = typeof src === 'string' ? src : '';
|
|
const imageSrc = srcString.startsWith('./')
|
|
? `/recipes/${folderPath}/${srcString.replace('./', '')}`.replace(/\\/g, '/')
|
|
: srcString;
|
|
return (
|
|
<img
|
|
src={imageSrc}
|
|
alt={alt || 'Recipe image'}
|
|
className="rounded-lg shadow-md w-full max-w-2xl mx-auto my-6 block"
|
|
loading="lazy"
|
|
/>
|
|
);
|
|
},
|
|
a: ({ href, children, ...props }: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (
|
|
<a
|
|
href={href}
|
|
className="text-blue-600 dark:text-blue-400 hover:underline"
|
|
target={href?.startsWith('http') ? '_blank' : undefined}
|
|
rel={href?.startsWith('http') ? 'noopener noreferrer' : undefined}
|
|
{...props}
|
|
>
|
|
{children}
|
|
</a>
|
|
),
|
|
},
|
|
options: {
|
|
mdxOptions: {
|
|
remarkPlugins: [remarkGfm],
|
|
},
|
|
},
|
|
});
|
|
|
|
return (
|
|
<RecipePageLayout recipe={recipe}>
|
|
{content}
|
|
</RecipePageLayout>
|
|
);
|
|
}
|