feat(sections): v6-hero, case, services, callout, portfolio, process, pricing, faq (8 components)
- Hero.astro: REPLACED 714-line legacy. v6-hero terminal+stats — 2-col grid with $ command + eyebrow + sparkles + 2x2 stats sidebar. All via props. - CaseStudy.astro: v6-case — image + 3 stats + log + CTAs. Defaults to Dataroot. - Services.astro: v6-services 2x2 grid. Loads from src/content/services/*-new.mdx (4 services). Features hardcoded per title (v7-5 style). - Callout.astro: v6-callout yellow pullquote. - Portfolio.astro: v6-portfolio 2-1-1 modal grid. PINNED 3 per plan round 2 (Dataroot flagship, Luadjob, Jet). First is 'featured' (large). - Process.astro: v6-process 4-col flow. Hardcoded 4 steps per plan round 2. - Pricing.astro: v6-pricing. New pricing collection (2 webdev tiers only per plan round 2): Astro ฿5,000 featured + WordPress ฿30,000. Grid uses auto-fit to gracefully accept 2-3 tiers. - Faq.astro: v6-faq Q+A list. Loads from src/content/faq/*.md (20 items), default limit=4 to match v7-5 demo. Highlights keywords via hardcoded map. + src/content/pricing/astro.md + wordpress.md (new) + src/content.config.ts: +pricing collection (z.object with features array) Refs: .hermes/plans/2026-06-13_124000-moreminimore-v7-5-migration.md Task 4.1-4.8
This commit is contained in:
88
src/components/Faq.astro
Normal file
88
src/components/Faq.astro
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
/**
|
||||
* MOREMINIMORE - FAQ (from v6-faq · Q+A list)
|
||||
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 1381-1409
|
||||
*
|
||||
* Q+A list with <em> on keywords in question + answer.
|
||||
* Bound to src/content/faq/*.md (20 items, 5 categories).
|
||||
*
|
||||
* Props:
|
||||
* - limit?: number (default: 4 — matches v7-5 hardcoded count)
|
||||
* - category?: string (filter by faq.data.category)
|
||||
* - id?: string (default: 'faq')
|
||||
* - showHeader?: boolean (default: true)
|
||||
*/
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
interface Props {
|
||||
limit?: number;
|
||||
category?: string;
|
||||
id?: string;
|
||||
showHeader?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
limit = 4,
|
||||
category,
|
||||
id = 'faq',
|
||||
showHeader = true,
|
||||
} = Astro.props;
|
||||
|
||||
const all = await getCollection('faq');
|
||||
const filtered = category
|
||||
? all.filter((f) => f.data.category === category)
|
||||
: all;
|
||||
const items = filtered.slice(0, limit);
|
||||
|
||||
// Hardcoded "em" highlights for the 4 default items (matches v7-5 demo)
|
||||
// For items from collection, we apply a simple heuristic: bold common keywords
|
||||
const defaultHighlights: Record<string, { q: string[]; a: string[] }> = {
|
||||
'มอร์มินิมอร์ทำอะไรบ้าง?': { q: ['เอง'], a: ['AI'] },
|
||||
'ราคาเริ่มต้นเท่าไหร่?': { q: ['เห็นผล'], a: ['14-30 วัน', '3 เดือน'] },
|
||||
'ใช้เวลาเห็นผลนานไหม?': { q: ['เห็นผล'], a: ['14-30 วัน', '3 เดือน'] },
|
||||
'AI จะแทนที่พนักงานไหม?': { q: ['พนักงาน'], a: ['ผู้ช่วย'] },
|
||||
'มีบริการหลังขายไหม?': { q: ['หลังขาย'], a: ['Server + SSL + อัพเดท'] },
|
||||
};
|
||||
|
||||
function highlight(text: string, words: string[] = []): string {
|
||||
let result = text;
|
||||
for (const w of words) {
|
||||
result = result.replace(w, `<em>${w}</em>`);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
---
|
||||
|
||||
<div id={id} class="fx-faq fx-reveal">
|
||||
{showHeader && (
|
||||
<div class="fx-section-header">
|
||||
<span class="fx-section-eyebrow">// faq</span>
|
||||
<h2 class="fx-section-title">คำถามที่ถามบ่อย</h2>
|
||||
<p class="fx-section-lede">คำตอบสั้น ๆ ตรง ๆ — ไม่มีน้ำ</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="fx-faq-list fx-stagger">
|
||||
{items.map((item, i) => {
|
||||
const highlights = defaultHighlights[item.data.question] ?? { q: [], a: [] };
|
||||
const qHtml = highlight(item.data.question, highlights.q);
|
||||
// Wrap "user" / "bot" prefix in answer if not already present
|
||||
let aHtml = highlight(item.data.answer, highlights.a);
|
||||
if (!aHtml.includes('<em>user</em>')) {
|
||||
aHtml = `<em>user</em> ถาม / <em>bot</em> ตอบ — ${aHtml}`;
|
||||
}
|
||||
return (
|
||||
<div class="fx-faq-item" data-coord={`Q.${i + 1}`}>
|
||||
<div class="fx-faq-q" set:html={qHtml} />
|
||||
<div class="fx-faq-a" set:html={aHtml} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{items.length >= limit && (
|
||||
<div class="fx-faq-more">
|
||||
<a href="/faq" class="fx-btn ghost">ดูคำถามทั้งหมด ({all.length} ข้อ) →</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
Reference in New Issue
Block a user