Add EmDash CMS blog + hero standardization + seed fix

- Add EmDash CMS integration with SQLite and local storage
- Add blog collection (seed/seed.json) with 3 sample posts
- Add /บทความ list page and /บทความ/[slug] detail page
- Add blog section to homepage
- Fix reserved field slugs (slug, published_at removed from fields)
- Fix date field mapping (publishedAt camelCase)
- Fix featured image URL for admin-uploaded images (meta.storageKey)
- Standardize all product page hero sections
- Update navigation with 'บทความ' link
- Configure Google OAuth provider
This commit is contained in:
Kunthawat Greethong
2026-06-01 15:44:02 +07:00
parent 825d3264b3
commit c8cf03a725
35 changed files with 5786 additions and 185 deletions

View File

@@ -1,5 +1,13 @@
---
import BaseLayout from '@/layouts/BaseLayout.astro';
import { getEmDashCollection } from 'emdash';
const { entries: articles, cacheHint } = await getEmDashCollection('blog', {
limit: 3,
orderBy: { published_at: 'desc' },
status: 'published',
});
Astro.cache.set(cacheHint);
---
<BaseLayout title="ดีล พลัส เทค - ระบบน้ำคุณภาพสูง ราคาโรงงาน" description="ดีล พลัส เทค จำกัด ผู้นำด้านระบบน้ำคุณภาพสูง ราคาโรงงาน ท่อ PPR ท่อ HDPE อุปกรณ์วาล์ว ปั๊มน้ำ เครื่องเชื่อมท่อ และอุปกรณ์โรงงานคุณภาพ">
@@ -304,6 +312,80 @@ import BaseLayout from '@/layouts/BaseLayout.astro';
</div>
</section>
<!-- บทความ Section -->
<section class="py-16 lg:py-24 bg-white">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-end justify-between mb-12">
<div>
<span class="inline-block px-4 py-1.5 bg-primary-100 text-primary-700 rounded-full text-sm font-medium mb-4">บทความ</span>
<h2 class="text-3xl lg:text-4xl font-bold text-slate-900">บทความล่าสุด</h2>
<p class="text-lg text-slate-600 mt-2">ความรู้และข้อมูลที่เป็นประโยชน์เกี่ยวกับระบบน้ำและอุปกรณ์</p>
</div>
<a href="/%E0%B8%9A%E0%B8%97%E0%B8%84%E0%B8%A7%E0%B8%B2%E0%B8%A1" class="hidden sm:inline-flex items-center gap-2 text-primary-600 hover:text-primary-700 font-semibold transition-colors">
ดูทั้งหมด
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
</svg>
</a>
</div>
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
{
articles.length > 0 ? articles.map(article => (
<a href={`/${encodeURI('บทความ')}/${encodeURIComponent(article.data.slug || article.id)}`} class="group block bg-white rounded-3xl overflow-hidden border border-slate-100 hover:border-primary-200 hover:shadow-xl transition-all duration-300">
<div class="aspect-[16/9] bg-slate-100 overflow-hidden">
{
(() => {
const img = article.data.featured_image;
const imgSrc = typeof img === 'string' ? img : img?.src || (img?.provider === 'local' && (img?.meta?.storageKey || img?.id) ? `/_emdash/api/media/file/${img.meta?.storageKey || img.id}` : null);
const imgAlt = typeof img === 'object' && img?.alt ? img.alt : article.data.title;
return imgSrc ? (
<img src={imgSrc} alt={imgAlt} class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500" loading="lazy" />
) : (
<div class="w-full h-full flex items-center justify-center text-slate-300">
<svg class="w-16 h-16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"/>
</svg>
</div>
);
})()
}
</div>
<div class="p-6">
<div class="flex items-center gap-3 text-sm text-slate-500 mb-3">
<time datetime={article.data.publishedAt}>{new Date(article.data.publishedAt).toLocaleDateString('th-TH', { year: 'numeric', month: 'long', day: 'numeric' })}</time>
{article.data.tags && (
<span class="px-2.5 py-0.5 bg-primary-50 text-primary-600 rounded-full text-xs font-medium">{article.data.tags}</span>
)}
</div>
<h3 class="text-lg font-bold text-slate-900 group-hover:text-primary-600 transition-colors mb-2 line-clamp-2">{article.data.title}</h3>
<p class="text-sm text-slate-600 line-clamp-2">{article.data.excerpt}</p>
</div>
</a>
)) : (
<div class="md:col-span-2 lg:col-span-3 text-center py-16">
<div class="text-slate-300 mb-4">
<svg class="w-16 h-16 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9a2 2 0 00-2-2h-2m-4-3H9M7 16h6M7 8h6v4H7V8z"/>
</svg>
</div>
<p class="text-lg text-slate-400">ยังไม่มีบทความในขณะนี้</p>
</div>
)
}
</div>
<div class="text-center mt-10 sm:hidden">
<a href="/%E0%B8%9A%E0%B8%97%E0%B8%84%E0%B8%A7%E0%B8%B2%E0%B8%A1" class="inline-flex items-center gap-2 text-primary-600 hover:text-primary-700 font-semibold transition-colors">
ดูบทความทั้งหมด
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 8l4 4m0 0l-4 4m4-4H3"/>
</svg>
</a>
</div>
</div>
</section>
<!-- CTA Section -->
<section class="py-16 lg:py-24 bg-gradient-to-br from-primary-700 via-primary-600 to-primary-800 text-white relative overflow-hidden">
<!-- Background Elements -->