- 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
89 lines
3.1 KiB
Plaintext
89 lines
3.1 KiB
Plaintext
---
|
|
/**
|
|
* 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>
|