167 lines
4.7 KiB
Plaintext
167 lines
4.7 KiB
Plaintext
---
|
|
import PageShell from '../../components/PageShell.astro';
|
|
|
|
import { getCollection, render } from 'astro:content';
|
|
|
|
export async function getStaticPaths() {
|
|
const posts = await getCollection('blog', ({ data }) => !data.draft);
|
|
|
|
return posts.map((post) => ({
|
|
params: { slug: post.id },
|
|
props: { post },
|
|
}));
|
|
}
|
|
|
|
const { post } = Astro.props;
|
|
const { Content } = await render(post);
|
|
const siteUrl = new URL('/', Astro.site).toString();
|
|
|
|
// --- Date formatting ---
|
|
const formattedDate = new Intl.DateTimeFormat('th-TH', {
|
|
dateStyle: 'long',
|
|
}).format(post.data.pubDate);
|
|
|
|
// --- Image: og_image > heroImage > default logo ---
|
|
const ogImage = new URL(
|
|
post.data.og_image || post.data.heroImage || '/images/logos/logo-long-black.png',
|
|
Astro.site,
|
|
).toString();
|
|
|
|
// --- FAQPage auto-extraction ---
|
|
const rawBody = post.body || '';
|
|
const faqSectionRegex = /##\s*คำถามที่พบบ่อย\s*\n([\s\S]*?)(?=##\s|\Z)/;
|
|
const faqMatch = rawBody.match(faqSectionRegex);
|
|
const faqPairs: { question: string; answer: string }[] = faqMatch
|
|
? [...faqMatch[1].matchAll(/###\s+(.+?)\n\s*\n?(.+?)(?=\n###|\Z)/gs)]
|
|
.map(([, q, a]) => ({ question: q.trim(), answer: a.trim() }))
|
|
: [];
|
|
|
|
// --- Escaped body for JSON-LD safety ---
|
|
const safeBody = rawBody.replace(/<\//g, '<\\/');
|
|
|
|
// --- BlogPosting JSON-LD ---
|
|
const blogPostingJsonLd = JSON.stringify({
|
|
'@context': 'https://schema.org',
|
|
'@id': `${siteUrl}blog/${post.id}/#blogposting`,
|
|
'@type': 'BlogPosting',
|
|
headline: post.data.title,
|
|
description: post.data.description,
|
|
datePublished: post.data.pubDate.toISOString(),
|
|
dateModified: (post.data.updatedDate || post.data.pubDate).toISOString(),
|
|
...(post.data.author && {
|
|
author: { '@type': 'Person', name: post.data.author },
|
|
}),
|
|
...(post.data.reviewer && {
|
|
reviewedBy: { '@type': 'Person', name: post.data.reviewer },
|
|
}),
|
|
publisher: {
|
|
'@id': `${siteUrl}#organization`,
|
|
'@type': 'Organization',
|
|
name: 'MoreminiMore',
|
|
logo: {
|
|
'@type': 'ImageObject',
|
|
url: new URL('/images/logos/logo-long-black.png', Astro.site).toString(),
|
|
},
|
|
},
|
|
mainEntityOfPage: new URL(`/blog/${post.id}/`, Astro.site).toString(),
|
|
articleBody: safeBody,
|
|
});
|
|
|
|
// --- BreadcrumbList JSON-LD ---
|
|
const breadcrumbJsonLd = JSON.stringify({
|
|
'@context': 'https://schema.org',
|
|
'@id': `${siteUrl}blog/${post.id}/#breadcrumb`,
|
|
'@type': 'BreadcrumbList',
|
|
itemListElement: [
|
|
{
|
|
'@type': 'ListItem',
|
|
position: 1,
|
|
name: 'บทความ',
|
|
item: new URL('/blog/', Astro.site).toString(),
|
|
},
|
|
{
|
|
'@type': 'ListItem',
|
|
position: 2,
|
|
name: post.data.title,
|
|
},
|
|
],
|
|
});
|
|
|
|
// --- FAQPage JSON-LD ---
|
|
const faqPageJsonLd = faqPairs.length > 0
|
|
? JSON.stringify({
|
|
'@context': 'https://schema.org',
|
|
'@id': `${siteUrl}blog/${post.id}/#faq`,
|
|
'@type': 'FAQPage',
|
|
mainEntity: faqPairs.map(({ question, answer }) => ({
|
|
'@type': 'Question',
|
|
name: question,
|
|
acceptedAnswer: {
|
|
'@type': 'Answer',
|
|
text: answer,
|
|
},
|
|
})),
|
|
})
|
|
: '';
|
|
---
|
|
|
|
<PageShell
|
|
title={`${post.data.title} | MoreminiMore`}
|
|
description={post.data.description}
|
|
image={ogImage}
|
|
>
|
|
<!-- JSON-LD: BreadcrumbList -->
|
|
<script type="application/ld+json" set:html={breadcrumbJsonLd}>
|
|
</script>
|
|
|
|
<!-- JSON-LD: BlogPosting -->
|
|
<script type="application/ld+json" set:html={blogPostingJsonLd}>
|
|
</script>
|
|
|
|
<!-- JSON-LD: FAQPage (auto — only if FAQ section found) -->
|
|
{faqPageJsonLd && (
|
|
<script type="application/ld+json" set:html={faqPageJsonLd}>
|
|
</script>
|
|
)}
|
|
|
|
<article class="blog-article">
|
|
<header class="blog-article-hero scene scene-light" data-scene="light">
|
|
<div class="blog-article-heading">
|
|
<a class="blog-back-link" href="/blog/">← บทความทั้งหมด</a>
|
|
<div class="blog-article-meta">
|
|
<span class="eyebrow eyebrow-yellow">{post.data.category}</span>
|
|
<span class="eyebrow">{formattedDate}</span>
|
|
</div>
|
|
<h1>{post.data.title}</h1>
|
|
<p class="blog-article-lead">{post.data.description}</p>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="blog-feature-image">
|
|
<img src={post.data.heroImage || '/images/blog-placeholder.svg'} alt={post.data.title} />
|
|
</div>
|
|
|
|
<div class="blog-article-shell">
|
|
<div class="blog-prose">
|
|
<Content />
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</PageShell>
|
|
|
|
<style>
|
|
.blog-article-hero { padding-bottom: clamp(36px, 5vw, 64px); }
|
|
|
|
.blog-feature-image {
|
|
max-width: var(--container);
|
|
margin: 2rem auto 1rem;
|
|
padding: 0 1rem;
|
|
}
|
|
|
|
.blog-feature-image img {
|
|
width: 100%;
|
|
border-radius: 20px;
|
|
display: block;
|
|
}
|
|
</style>
|