Initial commit: New industrial design with green theme
This commit is contained in:
133
src/app/blog/[slug]/page.tsx
Normal file
133
src/app/blog/[slug]/page.tsx
Normal file
@@ -0,0 +1,133 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import matter from 'gray-matter';
|
||||
import { remark } from 'remark';
|
||||
import html from 'remark-html';
|
||||
|
||||
interface Props {
|
||||
params: { slug: string };
|
||||
}
|
||||
|
||||
async function getPost(slug: string) {
|
||||
const blogDir = path.join(process.cwd(), 'src/content/blog');
|
||||
const filePath = path.join(blogDir, `${slug}.md`);
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
||||
const { data, content } = matter(fileContent);
|
||||
|
||||
const processedContent = await remark()
|
||||
.use(html, { sanitize: false })
|
||||
.process(content);
|
||||
const contentHtml = processedContent.toString();
|
||||
|
||||
return {
|
||||
slug,
|
||||
title: data.title || 'ไม่มีชื่อ',
|
||||
excerpt: data.excerpt || '',
|
||||
date: data.date || new Date().toISOString(),
|
||||
author: data.author || 'ดีลพลัสเทค',
|
||||
category: data.category || 'ทั่วไป',
|
||||
image: data.image || '/images/2021/03/ppr-pipe_000C.jpg',
|
||||
content: contentHtml,
|
||||
};
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: Props) {
|
||||
const post = await getPost(params.slug);
|
||||
if (!post) return { title: 'ไม่พบบทความ' };
|
||||
|
||||
return {
|
||||
title: post.title,
|
||||
description: post.excerpt,
|
||||
};
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const blogDir = path.join(process.cwd(), 'src/content/blog');
|
||||
const files = fs.readdirSync(blogDir).filter(f => f.endsWith('.md'));
|
||||
|
||||
return files.map(filename => ({
|
||||
slug: filename.replace('.md', ''),
|
||||
}));
|
||||
}
|
||||
|
||||
export default async function BlogPostPage({ params }: Props) {
|
||||
const post = await getPost(params.slug);
|
||||
|
||||
if (!post) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="pt-32 pb-16">
|
||||
<article className="container mx-auto px-4">
|
||||
{/* Header */}
|
||||
<header className="max-w-3xl mx-auto mb-8">
|
||||
<Link
|
||||
href="/blog"
|
||||
className="inline-flex items-center text-primary-600 hover:text-primary-700 mb-4"
|
||||
>
|
||||
<svg className="w-4 h-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
กลับไปหน้าบทความ
|
||||
</Link>
|
||||
|
||||
<span className="industrial-badge">{post.category}</span>
|
||||
|
||||
<h1 className="text-3xl md:text-4xl lg:text-5xl font-bold text-secondary-900 mt-4 mb-4">
|
||||
{post.title}
|
||||
</h1>
|
||||
|
||||
<div className="flex items-center gap-4 text-secondary-600">
|
||||
<span>{post.author}</span>
|
||||
<span>•</span>
|
||||
<time>
|
||||
{new Date(post.date).toLocaleDateString('th-TH', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})}
|
||||
</time>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Featured Image */}
|
||||
<div className="relative aspect-video max-w-4xl mx-auto rounded-xl overflow-hidden mb-8">
|
||||
<Image
|
||||
src={post.image}
|
||||
alt={post.title}
|
||||
fill
|
||||
className="object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div
|
||||
className="max-w-3xl mx-auto prose prose-lg prose-headings:font-bold prose-headings:text-secondary-900 prose-p:text-secondary-600 prose-a:text-primary-600 prose-strong:text-secondary-900"
|
||||
dangerouslySetInnerHTML={{ __html: post.content }}
|
||||
/>
|
||||
|
||||
{/* CTA */}
|
||||
<div className="max-w-3xl mx-auto mt-12 bg-secondary-800 rounded-2xl p-8 text-center">
|
||||
<h2 className="text-2xl font-bold text-white mb-4">
|
||||
สนใจสินค้าหรือบริการ?
|
||||
</h2>
|
||||
<p className="text-secondary-300 mb-6">
|
||||
ติดต่อเราเพื่อรับคำปรึกษาและใบเสนอราคาฟรี
|
||||
</p>
|
||||
<Link href="/contact-us" className="btn-primary">
|
||||
ติดต่อเรา
|
||||
</Link>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user