feat: liquid glass UI, blob background, redesign home/portfolio/about pages

- Liquid glass effect on navbar/cards with backdrop-filter invert
- Animated blob gradient background (SVG-based)
- Portfolio section: scene-dark invert, show 5 items on home
- How Work section: step flow with numbers + connecting lines
- Hero: Decision snapshot replacing problem selector
- About page: inverted background with contrast fixes
- Fix parallax JS bundling via Astro
- Fix navbar fixed positioning after liquid glass CSS
- Submenu hover fix
- Clean up removed legacy files/assets
This commit is contained in:
Kunthawat Greethong
2026-06-23 11:40:37 +07:00
parent e279119f97
commit f827afb33f
188 changed files with 4577 additions and 15483 deletions

View File

@@ -1,129 +0,0 @@
---
/**
* MOREMINIMORE - BLOG CARD COMPONENT (LIGHT THEME)
*/
interface Props {
title: string;
excerpt: string;
image?: string;
date: Date;
slug: string;
category: string;
}
const { title, excerpt, image, date, slug, category } = Astro.props;
const formattedDate = date.toLocaleDateString('th-TH', { year: 'numeric', month: 'short', day: 'numeric' });
---
<a href={`/blog/${slug}`} class="blog-card">
<div class="blog-image">
{image && <img src={image} alt={title} loading="lazy" />}
</div>
<div class="blog-content">
<span class="blog-category">{category}</span>
<h3 class="blog-title">{title}</h3>
<p class="blog-excerpt">{excerpt}</p>
<div class="blog-footer">
<span class="blog-date">{formattedDate}</span>
<span class="blog-link">อ่านต่อ →</span>
</div>
</div>
</a>
<style>
.blog-card {
display: block;
background: var(--color-white);
border-radius: var(--radius-xl);
overflow: hidden;
border: 1px solid var(--color-gray-200);
transition: all 0.3s var(--ease-out-expo);
}
.blog-card:hover {
transform: translateY(-8px);
box-shadow: var(--shadow-md);
border-color: var(--color-primary);
}
.blog-image {
aspect-ratio: 16/9;
overflow: hidden;
background: var(--color-bg-soft);
}
.blog-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.blog-card:hover .blog-image img {
transform: scale(1.05);
}
.blog-content {
padding: 24px;
}
.blog-category {
display: inline-block;
background: var(--color-primary);
color: var(--color-black);
padding: 4px 12px;
border-radius: var(--radius-sm);
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 12px;
}
.blog-title {
font-family: var(--font-display);
font-size: 18px;
font-weight: 800;
color: var(--color-black);
margin-bottom: 12px;
line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.blog-excerpt {
font-size: 14px;
color: var(--color-gray-600);
line-height: 1.6;
margin-bottom: 16px;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
.blog-footer {
display: flex;
justify-content: space-between;
align-items: center;
}
.blog-date {
font-size: 12px;
color: var(--color-gray-500);
}
.blog-link {
font-size: 14px;
font-weight: 700;
color: var(--color-black);
transition: color 0.3s ease;
}
.blog-card:hover .blog-link {
color: var(--color-primary-dark);
}
</style>

View File

@@ -1,26 +0,0 @@
---
/**
* MOREMINIMORE - CALLOUT (from v6-callout · yellow pullquote)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 1054-1066
*
* Yellow gradient pullquote with <em> accent.
* Used as a philosophy statement between sections.
*
* Props:
* - text: string (supports <em> for accent)
* - attr?: string (attribution, default '— Moreminimore')
* - id?: string (default: 'callout')
*/
interface Props {
text: string;
attr?: string;
id?: string;
}
const { text, attr = '— Moreminimore', id = 'callout' } = Astro.props;
---
<div id={id} class="fx-callout fx-reveal">
<p class="fx-callout-text" set:html={text} />
<div class="fx-callout-attr">{attr}</div>
</div>

View File

@@ -1,102 +0,0 @@
---
/**
* MOREMINIMORE - CASESTUDY (from v6-case)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 873-919
*
* 2-col grid: image (left) + content (right, with stats + log + CTAs)
* Currently used for Dataroot flagship case study only.
* Hardcoded data — case_study body still lives in src/content/portfolio/dataroot.md
*
* Props:
* - client: string (e.g. 'Dataroot')
* - url?: string (link to client site)
* - image?: string (default: dataroot.png from /images/portfolio/)
* - stats: { value, label, coord }[] (default: Dataroot +373/+114/-28)
* - quote: string (large pullquote with <em>)
* - deck: string (subhead under quote)
* - logs: { ts, level, text }[] (default: 3-line timeline)
* - ctaPrimary?: { text, href } (default: อ่านเคสเต็ม → /portfolio)
* - ctaSecondary?: { text, href } (default: ดูผลงานอื่น → /portfolio)
* - id?: string (default: 'case')
*/
interface Stat {
value: string;
label: string;
coord: string;
}
interface Log {
ts: string;
level: 'INFO' | 'SUCCESS' | 'WARN';
text: string;
}
interface CTA {
text: string;
href: string;
}
interface Props {
client: string;
url?: string;
image?: string;
stats: Stat[];
quote: string;
deck: string;
logs: Log[];
ctaPrimary?: CTA;
ctaSecondary?: CTA;
id?: string;
}
const {
client,
url,
image = '/images/portfolio/dataroot.png',
stats,
quote,
deck,
logs,
ctaPrimary = { text: 'อ่านเคสเต็ม →', href: '/portfolio' },
ctaSecondary = { text: 'ดูผลงานอื่น', href: '/portfolio' },
id = 'case',
} = Astro.props;
---
<div id={id} class="fx-case fx-reveal">
<span class="fx-sparkle s2" style="top:12%;right:6%">✦</span>
<span class="fx-sparkle s4" style="bottom:16%;left:4%">◆</span>
<span class="fx-sparkle s5" style="top:50%;right:4%">✦</span>
<div class="fx-case-grid">
<div class="fx-case-image">
<a href={url || ctaPrimary.href}>
<img src={image} alt={client} loading="lazy" />
</a>
</div>
<div class="fx-case-content">
<div class="fx-case-stats">
{stats.map((stat) => (
<div class="fx-case-stat" data-coord={stat.coord}>
<div class="fx-case-stat-num" set:html={stat.value} />
<div class="fx-case-stat-label">{stat.label}</div>
</div>
))}
</div>
<h2 set:html={`"${quote}"`} />
<p class="fx-deck">{deck}</p>
<div class="fx-log fx-stagger">
{logs.map((log) => (
<div>
<span class="ts">{log.ts}</span>{' '}
<span class={log.level === 'INFO' ? 'info' : 'ok'}>{log.level}</span>{' '}
{log.text}
</div>
))}
</div>
<div class="fx-case-cta">
<a href={ctaPrimary.href} class="fx-btn coral">{ctaPrimary.text}</a>
<a href={ctaSecondary.href} class="fx-btn ghost">{ctaSecondary.text}</a>
</div>
</div>
</div>
</div>

View File

@@ -1,169 +0,0 @@
---
/**
* MOREMINIMORE - CONTACT FORM (from v6-contact · $ prompt form, enhanced)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 1453-1469
*
* Per plan 2026-06-13 round 2 #4: REAL working form with backend
* (Apps Script → Google Sheet + email + LINE Notify).
*
* Two variants:
* - 'prompt': 1 input + ENTER button (for home page) — terminal-style
* - 'full': 5 fields (name, phone, email, service, message) (for /contact)
*
* Submits to src/lib/contact-submit.ts → submitContact()
* which reads PUBLIC_CONTACT_ENDPOINT from .env (empty = dev mode).
*/
interface Props {
variant?: 'prompt' | 'full';
title?: string;
desc?: string;
id?: string;
}
const {
variant = 'full',
title = 'คุยกับเราก่อน 30 นาที ฟรี',
desc = 'เราจะแนะนำแนวทางเบื้องต้น — บอกตรง ๆ ว่าอะไรควรทำ ไม่ควรทำ',
id = 'contact',
} = Astro.props;
// Service options for full variant
const services = [
{ value: 'webdev', label: 'Website Development (Astro / WordPress)' },
{ value: 'ai-consult', label: 'AI Consult' },
{ value: 'automation', label: 'AI Automation' },
{ value: 'marketing', label: 'Online Marketing' },
{ value: 'other', label: 'อื่นๆ / ไม่แน่ใจ' },
];
---
<div id={id} class="fx-contact fx-reveal">
{variant === 'prompt' ? (
<>
<h2 class="fx-contact-title" set:html={title} />
<p class="fx-contact-desc" set:html={desc} />
<form class="fx-contact-form" data-contact-prompt>
<input
type="text"
name="prompt"
class="fx-contact-input"
placeholder="ชื่อ / เบอร์โทร / LINE"
required
/>
<button type="submit" class="fx-contact-submit">ส่งข้อความ</button>
</form>
<p class="fx-contact-hint">กดส่งเพื่อเริ่มคุยกับเรา — หรือ <a href="/contact">กรอกแบบฟอร์มเต็ม</a></p>
</>
) : (
<>
<h2 class="fx-contact-title" set:html={title} />
<p class="fx-contact-desc" set:html={desc} />
<form class="fx-contact-form-full" data-contact-full>
<div class="fx-contact-row">
<label class="fx-contact-field">
<span>ชื่อ <em>*</em></span>
<input type="text" name="name" required placeholder="สมชาย ใจดี" />
</label>
<label class="fx-contact-field">
<span>เบอร์โทร <em>*</em></span>
<input type="tel" name="phone" required placeholder="080-xxx-xxxx" />
</label>
</div>
<label class="fx-contact-field">
<span>อีเมล</span>
<input type="email" name="email" placeholder="you@example.com" />
</label>
<label class="fx-contact-field">
<span>สนใจบริการ</span>
<select name="service">
{services.map((s) => <option value={s.value}>{s.label}</option>)}
</select>
</label>
<label class="fx-contact-field">
<span>รายละเอียดเพิ่มเติม</span>
<textarea name="message" rows="4" placeholder="เล่าปัญหาหรือเป้าหมายที่อยากให้ช่วย..."></textarea>
</label>
<button type="submit" class="fx-contact-submit">ส่งข้อความ →</button>
</form>
</>
)}
<div class="fx-contact-toast" data-contact-toast hidden></div>
</div>
<script>
import { submitContact, isDevMode } from '../lib/contact-submit';
function showToast(el: HTMLElement, msg: string, type: 'ok' | 'err') {
el.textContent = msg;
el.className = `fx-contact-toast fx-contact-toast-${type}`;
el.hidden = false;
setTimeout(() => { el.hidden = true; }, 5000);
}
document.addEventListener('DOMContentLoaded', () => {
const isDev = isDevMode();
if (isDev) {
console.info('[contact] dev mode — submissions will log to console, not POST to server');
}
// Prompt form (1 input)
const promptForm = document.querySelector<HTMLFormElement>('[data-contact-prompt]');
promptForm?.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(promptForm);
const prompt = String(formData.get('prompt') ?? '');
// Smart-parse: detect if it's name, phone, or line
const looksLikePhone = /[\d-]{8,}/.test(prompt);
const data = {
name: looksLikePhone ? '' : prompt,
phone: looksLikePhone ? prompt : '',
email: '',
service: 'other',
message: prompt,
variant: 'prompt' as const,
};
const toast = document.querySelector<HTMLElement>('[data-contact-toast]');
if (toast) showToast(toast, 'กำลังส่ง...', 'ok');
const result = await submitContact(data);
if (toast) {
if (result.ok) {
showToast(toast, isDev ? '✓ ส่งแล้ว (dev mode)' : '✓ ส่งแล้ว เราจะติดต่อกลับภายใน 24 ชม.', 'ok');
promptForm.reset();
} else {
showToast(toast, '✗ ส่งไม่สำเร็จ กรุณาลองใหม่หรือทัก LINE: @moreminimore', 'err');
}
}
});
// Full form (5 fields)
const fullForm = document.querySelector<HTMLFormElement>('[data-contact-full]');
fullForm?.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(fullForm);
const data = {
name: String(formData.get('name') ?? ''),
phone: String(formData.get('phone') ?? ''),
email: String(formData.get('email') ?? ''),
service: String(formData.get('service') ?? 'other'),
message: String(formData.get('message') ?? ''),
variant: 'full' as const,
};
const toast = document.querySelector<HTMLElement>('[data-contact-toast]');
if (toast) showToast(toast, 'กำลังส่ง...', 'ok');
const result = await submitContact(data);
if (toast) {
if (result.ok) {
showToast(toast, isDev ? '✓ ส่งแล้ว (dev mode)' : '✓ ส่งแล้ว เราจะติดต่อกลับภายใน 24 ชม.', 'ok');
fullForm.reset();
} else {
showToast(toast, '✗ ส่งไม่สำเร็จ กรุณาลองใหม่หรือทัก LINE: @moreminimore', 'err');
}
}
});
});
</script>

View File

@@ -1,88 +0,0 @@
---
/**
* 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>

View File

@@ -1,82 +0,0 @@
---
/**
* MOREMINIMORE - FOOTER (from v6-footer)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 1516-1565
*
* 4-col sitemap: brand + services + company + contact
* Data bound from site settings + nav data (single source of truth)
*/
import { getEntry } from 'astro:content';
import type { CollectionEntry } from 'astro:content';
import { servicesDropdown, mainLinks } from '../data/nav';
const site = (await getEntry('settings', 'site')) as CollectionEntry<'settings'>;
const data = site?.data;
const currentYear = new Date().getFullYear();
// Company links (subset of mainLinks — exclude "หน้าแรก" and dropdown items)
const companyLinks = mainLinks
.filter((l) => !l.hasDropdown && l.href !== '/')
.map((l) => ({ label: l.label, href: l.href }));
// Contact links — built from settings
const contactLinks = [
{ label: 'ปรึกษาฟรี 30 นาที', href: '/contact' },
{ label: data?.email ?? 'contact@moreminimore.com', href: `mailto:${data?.email ?? 'contact@moreminimore.com'}`, isEmail: true },
{ label: 'LINE: ' + (data?.line_id ?? '@moreminimore'), href: data?.line ?? '#', isExternal: true },
{ label: data?.phone ?? '080-995-5945', href: `tel:${(data?.phone ?? '080-995-5945').replace(/-/g, '')}` },
];
---
<footer id="v6-footer-inner" class="fx-footer fx-reveal">
<div class="fx-footer-grid">
<div class="fx-footer-col">
<a href="/" class="fx-footer-logo">
<img src="/images/logo-long-black.png" alt="MOREMINIMORE" class="fx-footer-logo-img" />
</a>
<p class="fx-footer-tagline">ช่วยธุรกิจไทยเพิ่มกำไร ด้วย AI + Marketing + Automation</p>
</div>
<div class="fx-footer-col">
<h4>SERVICES</h4>
<ul>
{servicesDropdown.map((s) => (
<li><a href={s.href}>{s.label}</a></li>
))}
</ul>
</div>
<div class="fx-footer-col">
<h4>COMPANY</h4>
<ul>
{companyLinks.map((l) => (
<li><a href={l.href}>{l.label}</a></li>
))}
</ul>
</div>
<div class="fx-footer-col">
<h4>CONTACT</h4>
<ul>
{contactLinks.map((l) => (
<li>
<a href={l.href} target={l.isExternal ? '_blank' : undefined} rel={l.isExternal ? 'noopener' : undefined}>
{l.label}
</a>
</li>
))}
{data?.facebook && (
<li><a href={data.facebook} target="_blank" rel="noopener">Facebook</a></li>
)}
{data?.linkedin && (
<li><a href={data.linkedin} target="_blank" rel="noopener">LinkedIn</a></li>
)}
</ul>
</div>
</div>
<div class="fx-footer-bottom">
<span>© {currentYear} MOREMINIMORE</span>
<span>built with <em>Kanit</em> + Itim + JetBrains Mono</span>
</div>
</footer>

View File

@@ -1,123 +0,0 @@
---
/**
* MOREMINIMORE - HERO (from v6-hero · terminal+stats)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 772-820
*
* 2-col grid: text (left, with $ command + eyebrow) + 2x2 stats sidebar (right)
* Uses 5 sparkle decorations (✦ ◆ ·) for "Neon × Tech Grid" feel.
*
* Props:
* - eyebrow?: string (default: 'MOREMINIMORE / EST. 2024')
* - title?: string (default: from home.md badge)
* - lede?: string (default: 1-sentence pitch)
* - ctaPrimary?: { text, href } (default: ปรึกษาฟรี → /contact)
* - ctaSecondary?: { text, href } (default: ดูผลงานจริง → /portfolio)
* - stats?: { label, value, coral?: boolean }[] (default: 4 Dataroot stats)
* - id?: string (default: 'hero' — for anchor links)
*/
interface Stat {
label: string;
value: string;
coral?: boolean;
}
interface CTA {
text: string;
href: string;
}
interface Props {
eyebrow?: string;
title?: string;
lede?: string;
ctaPrimary?: CTA;
ctaSecondary?: CTA;
stats?: Stat[];
id?: string;
/** 3 results the user explicitly cares about: เพิ่มยอดขาย / ลดต้นทุน / ประหยัดเวลา */
results?: ResultItem[];
}
interface ResultItem {
icon: string; // SVG path or simple emoji
label: string;
example: string;
}
const {
eyebrow = 'MOREMINIMORE / AI + MARKETING CONSULTANT',
title = 'เพิ่มยอดขาย ลดต้นทุน ประหยัดเวลา',
lede = 'ที่ปรึกษา AI + การตลาดออนไลน์ สำหรับ SME ไทย — เริ่มจากดูสถิติของคุณก่อน ไม่ใช่เดาว่าควรทำอะไร',
ctaPrimary = { text: 'ปรึกษาฟรี 30 นาที →', href: '/contact' },
ctaSecondary = { text: 'ดูผลงานจริง', href: '/portfolio' },
stats = [
{ label: 'impression', value: '+373%' },
{ label: 'click', value: '+114%', coral: true },
{ label: 'ad_spend', value: '28%' },
{ label: 'period', value: '30d' },
],
results = [
{ icon: '📈', label: 'เพิ่มยอดขาย', example: 'Dataroot +373% impression ใน 1 เดือน' },
{ icon: '💰', label: 'ลดต้นทุน', example: 'ลดงบโฆษณา 28% โดยยอดขายไม่ลด' },
{ icon: '⏱', label: 'ประหยัดเวลา', example: 'AI + Automation ทำงานแทนพนักงาน 5 ชม./วัน' },
],
id = 'hero',
} = Astro.props;
// Split title into 2 lines at first comma/space — for fx-hero-title multi-line layout
const titleLines = title.split(/\s+/);
const half = Math.ceil(titleLines.length / 2);
const titleLine1 = titleLines.slice(0, half).join(' ');
const titleLine2 = titleLines.slice(half).join(' ');
---
<div id={id} class="fx-hero fx-reveal">
<span class="fx-sparkle" style="top:8%;left:6%">✦</span>
<span class="fx-sparkle s2" style="top:12%;right:8%">◆</span>
<span class="fx-sparkle s3" style="bottom:18%;left:10%">✦</span>
<span class="fx-sparkle s4" style="top:30%;right:4%">·</span>
<span class="fx-sparkle s5" style="bottom:8%;right:12%">◆</span>
<div class="fx-hero-grid">
<div class="fx-hero-content">
<span class="fx-hero-eyebrow">{eyebrow}</span>
<h1 class="fx-hero-title">
<span>{titleLine1}</span>
<span>{titleLine2}</span>
</h1>
<p class="fx-hero-lede" set:html={lede} />
<div class="fx-hero-cta">
<a href={ctaPrimary.href} class="fx-btn coral">{ctaPrimary.text}</a>
<a href={ctaSecondary.href} class="fx-btn ghost">{ctaSecondary.text}</a>
</div>
<p class="fx-hero-trustline">
<span style="color:var(--coral)">✓</span> ปรึกษาฟรี 30 นาที &nbsp;·&nbsp;
<span style="color:var(--coral)">✓</span> ไม่มีผูกมัด &nbsp;·&nbsp;
<span style="color:var(--coral)">✓</span> เห็นผล <em>ภายใน 30 วัน</em>
</p>
</div>
<div class="fx-hero-side">
{stats.map((stat, i) => (
<div class="fx-stat" data-coord={`00.${i + 1}`}>
<div class="fx-stat-label">{stat.label}</div>
<div class:list={['fx-stat-value', stat.coral && 'coral']}>
<Fragment set:html={stat.value} />
</div>
</div>
))}
</div>
</div>
{/* 3 results the user positions the business around */}
<div class="fx-hero-results">
{results.map((r) => (
<div class="fx-hero-result">
<span class="fx-hero-result-icon">{r.icon}</span>
<div>
<div class="fx-hero-result-label">{r.label}</div>
<div class="fx-hero-result-example">{r.example}</div>
</div>
</div>
))}
</div>
</div>

View File

@@ -1,62 +0,0 @@
---
/**
* MOREMINIMORE - ICON COMPONENT
* Lucide-style line icons. Use:
* <Icon name="phone" size={24} />
* <Icon name="message" color="yellow" size={32} />
*
* Icon catalog: ../icon-paths.ts
* Add new icons by appending to ICON_PATHS in that file.
*/
import { ICON_PATHS, type IconName } from './icon-paths';
interface Props {
name: IconName;
size?: number;
class?: string;
/** Brand tint: 'default' = currentColor, 'yellow' = brand yellow, 'dark' = black */
color?: 'default' | 'yellow' | 'dark';
strokeWidth?: number;
}
const {
name,
size = 24,
class: className = '',
color = 'default',
strokeWidth = 2,
} = Astro.props;
const colorMap = {
default: 'currentColor',
yellow: 'var(--color-primary)',
dark: 'var(--color-black)',
};
const paths = ICON_PATHS[name];
---
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={colorMap[color]}
stroke-width={strokeWidth}
stroke-linecap="round"
stroke-linejoin="round"
class={`icon icon-${name} ${className}`}
aria-hidden="true"
>
<Fragment set:html={paths} />
</svg>
<style>
.icon {
display: inline-block;
flex-shrink: 0;
vertical-align: middle;
}
</style>

View File

@@ -1,30 +0,0 @@
---
/**
* MOREMINIMORE - Marquee (from v6-marquee)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 590-609
*
* Log ticker — animates horizontally (marquee 40s linear infinite in fx-system.css)
* Content is hardcoded ticker entries (not dynamic) — same as v7-5 design
*
* Duplicate content to achieve seamless loop (track is rendered twice)
*/
const tickerEntries = [
{ ts: 'อัปเดต', text: '<span class="cmd">●</span> ปรึกษาฟรี <em>30 นาที</em> <span class="ok">✓</span>' },
{ ts: 'ผลงาน', text: 'Dataroot +373% Impression <span class="ok">✓</span>' },
{ ts: 'อัปเดต', text: '<span class="cmd">●</span> เคสใหม่: เลือดจระเข้วานิไทย <span class="ok">✓</span>' },
{ ts: 'ผลงาน', text: '9 case studies, 0 fabricated <span class="ok">✓</span>' },
];
---
<div id="v6-marquee-inner" class="fx-marquee">
<div class="fx-marquee-track">
{/* First copy */}
{tickerEntries.map((entry) => (
<span><span class="ts">{entry.ts}</span> <Fragment set:html={entry.text} /></span>
))}
{/* Second copy (duplicated for seamless loop) */}
{tickerEntries.map((entry) => (
<span><span class="ts">{entry.ts}</span> <Fragment set:html={entry.text} /></span>
))}
</div>
</div>

View File

@@ -1,82 +0,0 @@
---
/**
* MOREMINIMORE - NAVIGATION (from v6-nav, enhanced)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 662-684
*
* Per plan 2026-06-13 round 2:
* - v6-nav structure: logo + menu + CTA
* - Enhancement A: dropdown 'บริการ' (4 sub-items from servicesDropdown)
* - Enhancement C: add 'บทความ' link (blog) — not in original v6-nav
* - Social icons: not in v6-nav itself; they live in UtilityBar (per plan)
*
* Props:
* - currentPath: string — for active link highlighting (optional, defaults to Astro.url.pathname)
*/
import { mainLinks, servicesDropdown } from '../data/nav';
interface Props {
currentPath?: string;
}
const { currentPath = Astro.url.pathname } = Astro.props;
const isActive = (href: string) => {
if (href === '/') return currentPath === '/';
return currentPath.startsWith(href);
};
---
<nav id="v6-nav-inner" class="fx-nav">
<div class="fx-nav-inner">
<a href="/" class="fx-nav-logo">
<span class="fx-nav-logo-text">MOREMI<em>ni</em>MORE</span>
</a>
<ul class="fx-nav-menu">
{mainLinks.map((link) => (
<li class={link.hasDropdown ? 'fx-nav-has-dropdown' : ''}>
{link.hasDropdown ? (
<>
<a href={link.href} class:list={[isActive(link.href) && 'active']}>
{link.label}
</a>
<ul class="fx-nav-dropdown">
{servicesDropdown.map((service) => (
<li>
<a href={service.href} class:list={[isActive(service.href) && 'active']}>
{service.label}
</a>
</li>
))}
</ul>
</>
) : (
<a href={link.href} class:list={[isActive(link.href) && 'active']}>
{link.label}
</a>
)}
</li>
))}
</ul>
<a href="/contact" class="fx-nav-cta">ปรึกษาฟรี →</a>
</div>
</nav>
<script>
// Mobile menu toggle — only relevant on small screens
// Desktop uses hover for dropdown (handled by CSS)
document.addEventListener('DOMContentLoaded', () => {
const nav = document.getElementById('v6-nav-inner');
if (!nav) return;
// Find all items with dropdowns and add click-to-toggle for mobile
const dropdownItems = nav.querySelectorAll('.fx-nav-has-dropdown > a');
dropdownItems.forEach((trigger) => {
trigger.addEventListener('click', (e) => {
if (window.innerWidth <= 768) {
e.preventDefault();
const parent = trigger.parentElement;
if (parent) parent.classList.toggle('fx-nav-dropdown-open');
}
});
});
});
</script>

View File

@@ -0,0 +1,190 @@
---
import '../styles/global.css';
import { formEndpoint, problems, services } from '../data/site.js';
const {
title = 'MoreminiMore',
description = 'MoreminiMore ช่วย SME ดูข้อมูลจริงก่อนตัดสินใจทำเว็บ การตลาด AI หรือระบบอัตโนมัติ',
} = Astro.props;
---
<!doctype html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="description" content={description} />
<meta name="theme-color" content="#f8f5ea" />
<title>{title}</title>
</head>
<body>
<div class="background-stage" aria-hidden="true">
<svg class="coded-background" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice">
<defs>
<radialGradient id="Gradient1" cx="50%" cy="50%" fx="0.441602%" fy="50%" r=".5">
<animate attributeName="fx" dur="34s" values="0%;3%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(255, 0, 255, 1)" />
<stop offset="100%" stop-color="rgba(255, 0, 255, 0)" />
</radialGradient>
<radialGradient id="Gradient2" cx="50%" cy="50%" fx="2.68147%" fy="50%" r=".5">
<animate attributeName="fx" dur="23.5s" values="0%;3%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(255, 255, 0, 1)" />
<stop offset="100%" stop-color="rgba(255, 255, 0, 0)" />
</radialGradient>
<radialGradient id="Gradient3" cx="50%" cy="50%" fx="0.836536%" fy="50%" r=".5">
<animate attributeName="fx" dur="21.5s" values="0%;3%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(0, 255, 255, 1)" />
<stop offset="100%" stop-color="rgba(0, 255, 255, 0)" />
</radialGradient>
<radialGradient id="Gradient4" cx="50%" cy="50%" fx="4.56417%" fy="50%" r=".5">
<animate attributeName="fx" dur="23s" values="0%;5%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(0, 255, 0, 1)" />
<stop offset="100%" stop-color="rgba(0, 255, 0, 0)" />
</radialGradient>
<radialGradient id="Gradient5" cx="50%" cy="50%" fx="2.65405%" fy="50%" r=".5">
<animate attributeName="fx" dur="24.5s" values="0%;5%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(0, 0, 255, 1)" />
<stop offset="100%" stop-color="rgba(0, 0, 255, 0)" />
</radialGradient>
<radialGradient id="Gradient6" cx="50%" cy="50%" fx="0.981338%" fy="50%" r=".5">
<animate attributeName="fx" dur="25.5s" values="0%;5%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(255, 0, 0, 1)" />
<stop offset="100%" stop-color="rgba(255, 0, 0, 0)" />
</radialGradient>
</defs>
<rect x="13.744%" y="1.18473%" width="100%" height="100%" fill="url(#Gradient1)" transform="rotate(334.41 50 50)">
<animate attributeName="x" dur="20s" values="25%;0%;25%" repeatCount="indefinite" />
<animate attributeName="y" dur="21s" values="0%;25%;0%" repeatCount="indefinite" />
<animateTransform attributeName="transform" type="rotate" from="0 50 50" to="360 50 50" dur="7s" repeatCount="indefinite" />
</rect>
<rect x="-2.17916%" y="35.4267%" width="100%" height="100%" fill="url(#Gradient2)" transform="rotate(255.072 50 50)">
<animate attributeName="x" dur="23s" values="-25%;0%;-25%" repeatCount="indefinite" />
<animate attributeName="y" dur="24s" values="0%;50%;0%" repeatCount="indefinite" />
<animateTransform attributeName="transform" type="rotate" from="0 50 50" to="360 50 50" dur="12s" repeatCount="indefinite" />
</rect>
<rect x="9.00483%" y="14.5733%" width="100%" height="100%" fill="url(#Gradient3)" transform="rotate(139.903 50 50)">
<animate attributeName="x" dur="25s" values="0%;25%;0%" repeatCount="indefinite" />
<animate attributeName="y" dur="12s" values="0%;25%;0%" repeatCount="indefinite" />
<animateTransform attributeName="transform" type="rotate" from="360 50 50" to="0 50 50" dur="9s" repeatCount="indefinite" />
</rect>
</svg>
</div>
<a class="skip-link" href="#main">ข้ามไปยังเนื้อหา</a>
<header class="site-nav liquid-glass liquidGlass-wrapper" data-nav>
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<a class="brand" href="/" aria-label="MoreminiMore">
<img src="/images/logos/logo-long-black.png" width="205" height="36" alt="MoreminiMore" />
</a>
<button class="nav-toggle" type="button" aria-controls="nav-menu" aria-expanded="false" data-nav-toggle>
เมนู
</button>
<nav id="nav-menu" class="nav-menu" aria-label="เมนูหลัก" data-nav-menu>
<a href="/">หน้าแรก</a>
<div class="nav-service">
<button type="button" aria-expanded="false" data-service-toggle>บริการ</button>
<div class="service-mega" data-service-menu>
{services.map((service) => (
<a href={`/services/${service.slug}/`}>
<strong>{service.name}</strong>
<span>{service.headline}</span>
</a>
))}
</div>
</div>
<a href="/portfolio/">ผลงาน</a>
<a href="/about/">เกี่ยวกับ</a>
<a href="/blog/">บทความ</a>
<a href="/contact/">ติดต่อ</a>
</nav>
<button class="nav-cta" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
</header>
<main id="main">
<slot />
</main>
<button class="floating-cta" type="button" data-floating-cta data-open-lead>ส่งโจทย์ให้เราดู</button>
<div class="panel-backdrop" data-panel-backdrop data-close-lead></div>
<aside class="lead-panel liquid-glass liquidGlass-wrapper" aria-labelledby="lead-title" aria-hidden="true" data-lead-panel data-endpoint={formEndpoint}>
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<div class="panel-head">
<div>
<p class="eyebrow">ส่งโจทย์ให้เราดู</p>
<h2 id="lead-title">เลือกปัญหาที่ใกล้ที่สุด แล้วเล่าเพิ่มสั้น ๆ</h2>
</div>
<button type="button" class="panel-close" aria-label="ปิดฟอร์ม" data-close-lead>ปิด</button>
</div>
<form class="lead-form" data-lead-form>
<input class="honeypot" type="text" name="website" tabindex="-1" autocomplete="off" />
<fieldset>
<legend>ตอนนี้ติดเรื่องไหนอยู่?</legend>
<div class="chip-grid">
{problems.map(([value, label]) => (
<label class="chip">
<input type="checkbox" name="problems" value={value} />
<span>{label}</span>
</label>
))}
</div>
</fieldset>
<label>
เล่าเพิ่มสั้น ๆ
<textarea name="message" rows="4" placeholder="เช่น ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม อยากรู้ว่าควรแก้อะไรก่อน"></textarea>
</label>
<div class="field-row">
<label>
ชื่อ
<input name="name" type="text" autocomplete="name" required />
</label>
<label>
เบอร์โทร
<input name="phone" type="tel" autocomplete="tel" />
</label>
</div>
<label>
อีเมล
<input name="email" type="email" autocomplete="email" />
</label>
<p class="field-note">ใส่เบอร์โทรหรืออีเมลอย่างใดอย่างหนึ่งก็ได้</p>
<p class="form-status" data-form-status role="status"></p>
<button class="button button-primary" type="submit">ส่งโจทย์</button>
</form>
</aside>
<svg class="glass-filter" aria-hidden="true" focusable="false">
<filter id="glass-distortion" x="0%" y="0%" width="100%" height="100%" filterUnits="objectBoundingBox">
<feTurbulence type="fractalNoise" baseFrequency="0.01 0.01" numOctaves="1" seed="5" result="turbulence" />
<feComponentTransfer in="turbulence" result="mapped">
<feFuncR type="gamma" amplitude="1" exponent="10" offset="0.5" />
<feFuncG type="gamma" amplitude="0" exponent="1" offset="0" />
<feFuncB type="gamma" amplitude="0" exponent="1" offset="0.5" />
</feComponentTransfer>
<feGaussianBlur in="turbulence" stdDeviation="3" result="softMap" />
<feSpecularLighting in="softMap" surfaceScale="5" specularConstant="1" specularExponent="100" lighting-color="white" result="specLight">
<fePointLight x="-200" y="-200" z="300" />
</feSpecularLighting>
<feComposite in="specLight" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litImage" />
<feDisplacementMap in="SourceGraphic" in2="softMap" scale="150" xChannelSelector="R" yChannelSelector="G" />
</filter>
</svg>
<script>
import '../scripts/home.js';
</script>
</body>
</html>

View File

@@ -1,82 +0,0 @@
---
/**
* MOREMINIMORE - PORTFOLIO (from v6-portfolio · modal cards)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 1122-1152
*
* 2-1-1 modal grid: 1 large featured + 2 smaller cards.
* Per plan 2026-06-13 round 2: PINNED to 3 items (Dataroot → Luadjob → Jet).
* Reordering the array reorders the grid; first item is "featured" (large).
*
* Props:
* - id?: string (default: 'portfolio')
* - showHeader?: boolean (default: true)
*/
import { getCollection } from 'astro:content';
interface Props {
id?: string;
showHeader?: boolean;
}
const { id = 'portfolio', showHeader = true } = Astro.props;
// Pinned 3 (per user 2026-06-13 round 2 #2)
const FEATURED_SLUGS = ['dataroot', 'luadjob', 'jet-industries'] as const;
const all = await getCollection('portfolio');
const items = FEATURED_SLUGS
.map((slug) => all.find((p) => p.id === slug))
.filter((p): p is NonNullable<typeof p> => p !== undefined);
// Tag per item (top-right of card)
const tags = ['FLAGSHIP', 'E-COMMERCE', 'B2B'] as const;
// Short stats per item
const statsLabels = [
'+373% impression · -28% ad spend',
'E-commerce สมุนไพรไทย',
'โรงงาน B2B · เว็บทันสมัย',
];
// Background images (use local thumbnails; fall back to neutral)
const fallbackBg = '#FFD60A';
---
<div id={id} class="fx-portfolio fx-reveal">
{showHeader && (
<div class="fx-section-header">
<span class="fx-section-eyebrow">// portfolio</span>
<h2 class="fx-section-title">ผลงานจริง ไม่ใช่ Mockup</h2>
<p class="fx-section-lede">ลูกค้าจริง ตัวเลขจริง — คลิกดูเว็บจริงได้เลย</p>
</div>
)}
<div class="fx-portfolio-grid fx-stagger">
{items.map((item, i) => {
const nameParts = item.data.name.split(' ');
const nameDisplay = nameParts.length > 1
? nameParts[0] + '<em>' + nameParts.slice(1).join(' ') + '</em>'
: item.data.name;
const isFeatured = i === 0;
return (
<a
href={item.data.url ?? '/portfolio'}
target={item.data.url ? '_blank' : undefined}
rel={item.data.url ? 'noopener' : undefined}
class:list={['fx-portfolio-card', isFeatured && 'featured']}
data-path={item.id}
data-coord={`04.${String.fromCharCode(65 + i)}`}
>
<span class="fx-portfolio-tag">{tags[i] ?? 'CASE'}</span>
<img
src={item.data.thumbnail ?? '/images/portfolio/default.jpg'}
alt={item.data.name}
loading="lazy"
style={item.data.thumbnail ? '' : `background:${fallbackBg};min-height:200px`}
/>
<h3 class="fx-portfolio-name" set:html={nameDisplay} />
<div class="fx-portfolio-stats">{statsLabels[i] ?? item.data.category_label}</div>
</a>
);
})}
</div>
</div>

View File

@@ -1,182 +0,0 @@
---
/**
* MOREMINIMORE - PORTFOLIO CARD COMPONENT (LIGHT THEME)
*/
interface Props {
name: string;
url: string;
category: string;
category_label: string;
industry?: string;
thumbnail: string;
description: string;
what_we_did?: string;
result?: string;
}
const { name, url, category, category_label, industry, thumbnail, description, what_we_did, result } = Astro.props;
---
<a href={url || '#'} target="_blank" rel="noopener noreferrer" class="portfolio-card" data-category={category}
ontouchstart="this.classList.toggle('tapped')"
onclick="if(this.classList.contains('tapped')&&window.innerWidth<768){this.classList.remove('tapped');return false;}">
<div class="portfolio-image">
<img src={thumbnail} alt={name} loading="lazy" />
<div class="portfolio-overlay">
{what_we_did && <p class="overlay-did">{what_we_did}</p>}
<span class="visit-btn">
เยี่ยมชมเว็บไซต์
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/>
</svg>
</span>
</div>
</div>
<div class="portfolio-info">
{industry && <span class="portfolio-industry">{industry}</span>}
<span class="portfolio-category">{category_label}</span>
<h3 class="portfolio-name">{name}</h3>
{result && <p class="portfolio-result">→ {result}</p>}
{!what_we_did && description && <p class="portfolio-desc">{description}</p>}
</div>
</a>
<style>
/* ============================================
PORTFOLIO CARD (LIGHT THEME)
============================================ */
.portfolio-card {
display: block;
background: var(--color-white);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-xl);
overflow: hidden;
transition: all 0.4s var(--ease-out-expo);
}
.portfolio-card:hover {
transform: translateY(-8px);
box-shadow: var(--shadow-md);
border-color: var(--color-primary);
}
.portfolio-image {
position: relative;
aspect-ratio: 16/10;
overflow: hidden;
background: var(--color-bg-soft);
}
.portfolio-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.portfolio-card:hover .portfolio-image img {
transform: scale(1.05);
}
/* Yellow overlay on hover */
.portfolio-overlay {
position: absolute;
inset: 0;
background: rgba(254, 212, 0, 0.95);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 20px;
padding: 24px;
opacity: 0;
transition: opacity 0.3s ease;
}
.portfolio-card:hover .portfolio-overlay,
.portfolio-card.tapped .portfolio-overlay {
opacity: 1;
}
.overlay-did {
font-size: 13px;
line-height: 1.6;
color: var(--color-black);
text-align: center;
max-width: 280px;
}
.visit-btn {
display: inline-flex;
align-items: center;
gap: 10px;
background: var(--color-black);
color: var(--color-white);
padding: 14px 28px;
border-radius: var(--radius-full);
font-family: var(--font-display);
font-weight: 700;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 1px;
}
.visit-btn svg {
width: 18px;
height: 18px;
}
/* Info section */
.portfolio-info {
padding: 24px;
}
.portfolio-industry {
display: inline-block;
background: var(--color-primary);
color: var(--color-black);
padding: 4px 12px;
border-radius: var(--radius-sm);
font-size: 12px;
font-weight: 700;
margin-bottom: 8px;
}
.portfolio-category {
display: inline-block;
background: var(--color-bg-soft);
color: var(--color-gray-600);
padding: 4px 10px;
border-radius: var(--radius-sm);
font-size: 11px;
font-weight: 600;
margin-left: 8px;
margin-bottom: 8px;
}
.portfolio-name {
font-family: var(--font-display);
font-size: 18px;
font-weight: 800;
color: var(--color-black);
margin-bottom: 8px;
}
.portfolio-did,
.portfolio-desc {
font-size: 14px;
color: var(--color-gray-600);
line-height: 1.5;
margin-bottom: 4px;
}
.portfolio-result {
font-size: 14px;
color: var(--color-black);
font-weight: 600;
line-height: 1.5;
margin-top: 4px;
}
</style>

View File

@@ -1,68 +0,0 @@
---
/**
* MOREMINIMORE - PRICING (from v6-pricing · 3-tier adapted to 2-tier)
* Extracted from Desktop/moreminimore-mockup-v7-5.html lines 1273-1324
*
* Per plan 2026-06-13 round 2 #1: 2 webdev tiers only.
* - Astro: ฿5,000 (featured, yellow border-left)
* - WordPress: ฿30,000
*
* Component uses `repeat(auto-fit, minmax(280px, 1fr))` to gracefully
* accept 2 OR 3 tiers (in case user adds a Landing tier later).
*
* Props:
* - id?: string (default: 'pricing')
* - showHeader?: boolean (default: true)
*/
import { getCollection } from 'astro:content';
interface Props {
id?: string;
showHeader?: boolean;
}
const { id = 'pricing', showHeader = true } = Astro.props;
const allTiers = await getCollection('pricing');
const tiers = allTiers.sort((a, b) => (a.data.order ?? 99) - (b.data.order ?? 99));
const coordLetters = ['A', 'B', 'C', 'D'];
---
<div id={id} class="fx-pricing fx-reveal">
{showHeader && (
<div class="fx-section-header">
<span class="fx-section-eyebrow">// pricing</span>
<h2 class="fx-section-title">ราคาเว็บไซต์</h2>
<p class="fx-section-lede">เฉพาะ Website Development — บริการอื่นปรึกษาฟรีเพื่อประเมินราคา</p>
</div>
)}
<div class="fx-pricing-grid fx-stagger">
{tiers.map((tier, i) => {
const d = tier.data;
// Highlight last word in tier (v7-5 style: "เริ่ม<em>ต้น</em>")
const tierWords = d.tier.split(/(?=[^ก-๛]*$)/);
const tierDisplay = tierWords.length > 1
? tierWords[0] + '<em>' + tierWords.slice(1).join('') + '</em>'
: d.tier;
return (
<div
class:list={['fx-pricing-card', d.is_featured && 'featured']}
data-coord={`05.${coordLetters[i] ?? 'X'}`}
>
<div class="fx-pricing-tier" set:html={d.is_featured ? `★ <em>${d.tier}</em>` : tierDisplay} />
<h3 class="fx-pricing-name">{d.name}</h3>
<div class="fx-pricing-amount">{d.amount}</div>
<div class="fx-pricing-period">/ {d.period}</div>
<ul class="fx-pricing-features">
{d.features.map((f) => <li>{f}</li>)}
</ul>
<a href="/contact" class="fx-pricing-cta">
{d.is_featured ? 'เลือก' : 'เริ่มต้น'}<em> →</em>
</a>
</div>
);
})}
</div>
</div>

View File

@@ -1,57 +0,0 @@
---
/**
* MOREMINIMORE - PROCESS (from v6-process · 4-col flow)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 1198-1230
*
* 4 numbered cells with arrow connectors.
* Per plan 2026-06-13 round 2 #5: hardcoded (process IS MoreminiMore's flow,
* not user-editable content).
*
* Props:
* - id?: string (default: 'process')
* - showHeader?: boolean (default: true)
*/
interface Step {
num: string;
title: string;
cmd: string;
cmdArg: string;
coord: string;
}
interface Props {
id?: string;
showHeader?: boolean;
}
const { id = 'process', showHeader = true } = Astro.props;
const steps: Step[] = [
{ num: '01', title: 'ปรึกษา Requirement', cmd: '→ ขั้นตอนที่ 1', cmdArg: 'ฟรี 30 นาที', coord: 'P.1' },
{ num: '02', title: 'วิเคราะห์ธุรกิจคุณ', cmd: '→ ขั้นตอนที่ 2', cmdArg: 'ดูสถิติ + ตลาด', coord: 'P.2' },
{ num: '03', title: 'วางแผน + เลือกเครื่องมือ', cmd: '→ ขั้นตอนที่ 3', cmdArg: 'ตรงกับงบคุณ', coord: 'P.3' },
{ num: '04', title: 'ลงมือ + วัดผล', cmd: '→ ขั้นตอนที่ 4', cmdArg: 'เห็นผลภายใน 30 วัน', coord: 'P.4' },
];
---
<div id={id} class="fx-process fx-reveal">
{showHeader && (
<div class="fx-section-header">
<span class="fx-section-eyebrow">// process</span>
<h2 class="fx-section-title">ขั้นตอนการทำงาน</h2>
<p class="fx-section-lede">เริ่มจากคุย requirement ฟรี → ส่งมอบตามที่ตกลง</p>
</div>
)}
<div class="fx-process-grid fx-stagger">
{steps.map((step) => (
<div class="fx-process-step" data-coord={step.coord}>
<div class="fx-process-num">{step.num}</div>
<div class="fx-process-title">{step.title}</div>
<div class="fx-process-text">
{step.cmd} <em>{step.cmdArg}</em>
</div>
</div>
))}
</div>
</div>

View File

@@ -1,50 +0,0 @@
---
interface Props {
badge?: string;
title: string;
description?: string;
align?: "left" | "center";
}
const { badge, title, description, align = "center" } = Astro.props;
---
<div class={`section-header section-header-${align}`}>
{badge && <span class="section-badge">{badge}</span>}
<h2 class="section-title" set:html={title}></h2>
{description && <p class="section-desc" set:html={description}></p>}
</div>
<style>
.section-header {
margin-bottom: 60px;
}
.section-header-left { text-align: left; }
.section-header-center { text-align: center; }
.section-badge {
display: inline-block;
background: var(--color-primary);
color: var(--color-black);
padding: 6px 16px;
border-radius: 20px;
font-size: 13px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 16px;
}
.section-title {
font-size: clamp(28px, 4vw, 42px);
font-weight: 700;
color: var(--color-black);
line-height: 1.2;
}
.section-header-center .section-title { max-width: 600px; margin: 0 auto 16px; }
.section-desc {
font-size: 18px;
color: var(--color-medium-gray);
line-height: 1.6;
max-width: 600px;
}
.section-header-center .section-desc { margin: 0 auto; }
</style>

View File

@@ -1,171 +0,0 @@
---
/**
* MOREMINIMORE - SERVICE CARD COMPONENT (LIGHT THEME)
*/
interface Props {
title: string;
subtitle?: string;
image?: string;
link: string;
}
const { title, subtitle, image, link } = Astro.props;
---
<a href={link} class="service-card">
<div class="card-inner">
<!-- Image -->
<div class="card-image">
<img src={image || "/images/services/default.jpg"} alt={title} loading="lazy" />
</div>
<!-- Content -->
<div class="card-content">
<h3 class="card-title">{title}</h3>
{subtitle && <p class="card-subtitle">{subtitle}</p>}
</div>
<!-- Arrow -->
<div class="card-arrow">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</div>
</div>
</a>
<style>
/* ============================================
SERVICE CARD (LIGHT THEME)
============================================ */
.service-card {
display: block;
}
.card-inner {
position: relative;
background: var(--color-white);
border-radius: var(--radius-xl);
overflow: hidden;
box-shadow: var(--shadow-sm);
transition: all 0.4s var(--ease-out-expo);
border: 1px solid var(--color-gray-200);
}
.card-inner::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: var(--color-primary);
transform: scaleX(0);
transform-origin: left;
transition: transform 0.4s var(--ease-out-expo);
z-index: 2;
}
.service-card:hover .card-inner::before {
transform: scaleX(1);
}
.service-card:hover .card-inner {
box-shadow: var(--shadow-md);
transform: translateY(-8px);
border-color: var(--color-primary);
}
.service-card:hover .card-arrow {
transform: translateX(8px);
opacity: 1;
}
/* ============================================
IMAGE
============================================ */
.card-image {
position: relative;
aspect-ratio: 16/10;
overflow: hidden;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.4s ease;
}
.service-card:hover .card-image img {
transform: scale(1.08);
}
/* ============================================
CONTENT
============================================ */
.card-content {
padding: 28px 24px;
}
.card-title {
font-family: var(--font-display);
font-size: 20px;
font-weight: 800;
color: var(--color-black);
margin-bottom: 8px;
transition: color 0.3s ease;
}
.card-subtitle {
font-size: 14px;
line-height: 1.6;
color: var(--color-gray-600);
}
/* ============================================
ARROW (yellow, visible on hover)
============================================ */
.card-arrow {
position: absolute;
bottom: 24px;
right: 24px;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--color-primary);
border-radius: 50%;
opacity: 0;
transform: translateX(-10px);
transition: all 0.3s var(--ease-out-expo);
z-index: 2;
}
.card-arrow svg {
width: 20px;
height: 20px;
stroke: var(--color-black);
transition: stroke 0.3s ease;
}
/* ============================================
RESPONSIVE
============================================ */
@media (max-width: 640px) {
.card-content {
padding: 24px 20px;
}
.card-title {
font-size: 18px;
}
}
</style>

View File

@@ -1,79 +0,0 @@
---
/**
* MOREMINIMORE - SERVICES (from v6-services)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 962-1014
*
* 4 cards in 2x2 grid. Data bound to src/content/services/*-new.mdx (4 entries).
* Each card: number (01-04) + title (with <em> accent) + desc + 3 bullets.
*
* Features extracted heuristically from short_desc + objective.
* For richer features, services collection could be extended with `features: string[]`.
*
* Props:
* - id?: string (default: 'services')
* - limit?: number (default: 4)
* - showHeader?: boolean (default: true — renders section title)
*/
import { getCollection } from 'astro:content';
interface Props {
id?: string;
limit?: number;
showHeader?: boolean;
}
const { id = 'services', limit = 4, showHeader = true } = Astro.props;
// Filter to *-new.mdx files (4 main services) — exclude legacy files
const allServices = await getCollection('services');
const services = allServices
.filter((s) => s.id.endsWith('-new'))
.slice(0, limit);
// 3 hardcoded feature bullets per service — matches v7-5's 4 service cards
const featuresByTitle: Record<string, string[]> = {
'AI Consult': ['วิเคราะห์ workflow', 'เก็บความรู้พนักงาน', 'AI Chatbot ในองค์กร'],
'Online Marketing Consult': ['SEO + GEO + Ads', 'AI + n8n Automation', 'ตรงกลุ่มเป้าหมาย'],
'Automation Consult': ['n8n + LLM + Custom', 'เชื่อมระบบเดิม', 'Workflow อัตโนมัติ'],
'Website Development': ['Astro / WordPress', 'SEO + GEO', 'Server + SSL ฟรีปีแรก'],
};
const coordLetters = ['A', 'B', 'A', 'B'];
const coordNums = ['02', '02', '03', '03'];
---
<div id={id} class="fx-services fx-reveal">
{showHeader && (
<div class="fx-section-header">
<span class="fx-section-eyebrow">// services</span>
<h2 class="fx-section-title">เราทำอะไรได้บ้าง</h2>
<p class="fx-section-lede">เริ่มจากอันที่ปวดที่สุด ค่อยขยายไปอันอื่น</p>
</div>
)}
<div class="fx-services-grid fx-stagger">
{services.map((service, i) => {
const title = service.data.title;
const desc = service.data.short_desc ?? service.data.subtitle;
const features = featuresByTitle[title] ?? [];
// Highlight the first word + last word in title (v7-5 style)
const titleWords = title.split(' ');
const titleMid = titleWords.length > 1
? titleWords.map((w, idx) => idx === titleWords.length - 1 ? `<em>${w}</em>` : w).join(' ')
: title;
return (
<a
href={`/services/${service.id.replace(/-new$/, '')}`}
class="fx-service-card"
data-coord={`${coordNums[i]}.${coordLetters[i]}`}
>
<span class="fx-service-num">{String(i + 1).padStart(2, '0')}</span>
<h3 class="fx-service-title" set:html={titleMid} />
<p class="fx-service-desc">{desc}</p>
<ul class="fx-service-list">
{features.map((f) => <li>{f}</li>)}
</ul>
</a>
);
})}
</div>
</div>

View File

@@ -1,102 +0,0 @@
---
/**
* MOREMINIMORE - UtilityBar (from v6-utility)
* Extracted from Desktop/moreminomore-mockup-v7-5.html lines 571-589
*
* Top info bar — phone + clock + date + mode indicator + email + THEME TOGGLE
* Phone/email pulled from src/content/settings/site.md (single source of truth)
*
* Clock/date are updated by fx-animations.ts → fxClock() (id="fx-time", id="fx-date")
* Theme toggle: id="fx-theme-toggle" — click flips data-theme on <html> + saves to localStorage
*/
import { getEntry } from 'astro:content';
import type { CollectionEntry } from 'astro:content';
const site = (await getEntry('settings', 'site')) as CollectionEntry<'settings'>;
const phone = site?.data?.phone ?? '080-995-5945';
const email = site?.data?.email ?? 'contact@moreminimore.com';
---
<div id="v6-utility-inner" class="fx-utility-bar">
<div class="fx-utility-bar-left">
<span class="fx-utility-item">📞 <strong>{phone}</strong></span>
<span class="fx-utility-item" id="fx-time">⏱ — : — : —</span>
<span class="fx-utility-item" id="fx-date">📅 — — —</span>
</div>
<div class="fx-utility-bar-right">
<button
type="button"
class="fx-theme-toggle"
id="fx-theme-toggle"
aria-label="Toggle light/dark mode"
title="Toggle light/dark mode"
>
◐ auto
</button>
<a href={`mailto:${email}`} class="fx-utility-item" style="text-decoration:none">✉ {email}</a>
</div>
</div>
<script>
/**
* Theme toggle logic — runs on every page (mounted via UtilityBar.astro).
* States: 'light' | 'dark' | 'auto' (follows system)
* Persists to localStorage; default = auto (follow OS preference)
*/
type ThemeMode = 'light' | 'dark' | 'auto';
const STORAGE_KEY = 'moreminimore-theme';
function getStoredTheme(): ThemeMode {
try {
const stored = localStorage.getItem(STORAGE_KEY);
if (stored === 'light' || stored === 'dark' || stored === 'auto') return stored;
} catch (_) { /* localStorage blocked */ }
return 'auto';
}
function effectiveTheme(mode: ThemeMode): 'light' | 'dark' {
if (mode === 'auto') {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
return mode;
}
function applyTheme(mode: ThemeMode) {
const eff = effectiveTheme(mode);
// Use class instead of data-theme (Astro/Vite keeps .dark selectors)
if (eff === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
// Update button label to reflect current mode (button is the sole indicator)
const btn = document.getElementById('fx-theme-toggle');
if (btn) {
btn.textContent = mode === 'auto' ? '◐ auto' : mode === 'light' ? '☀ light' : '☾ dark';
}
}
function cycleTheme() {
const current = getStoredTheme();
const next: ThemeMode = current === 'light' ? 'dark' : current === 'dark' ? 'auto' : 'light';
try { localStorage.setItem(STORAGE_KEY, next); } catch (_) { /* ignore */ }
applyTheme(next);
}
// Initialize on load
applyTheme(getStoredTheme());
// Wire button (idempotent — fires on every page navigation)
document.addEventListener('DOMContentLoaded', () => {
const btn = document.getElementById('fx-theme-toggle');
if (btn && !btn.dataset.bound) {
btn.dataset.bound = 'true';
btn.addEventListener('click', cycleTheme);
}
});
// If user hasn't picked explicitly, follow OS changes live
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
if (getStoredTheme() === 'auto') applyTheme('auto');
});
</script>

View File

@@ -1,87 +0,0 @@
/**
* Lucide-style SVG icon paths for MoreminiMore.
* All paths use a 24x24 viewBox, stroke-width 2, rounded caps/joins.
* Source: adapted from lucide.dev (ISC licensed).
*
* Naming convention: semantic over visual (e.g. "message" not "speech-bubble").
* Add new icons by appending to ICON_PATHS.
*/
export const ICON_PATHS = {
// ===== Communication =====
message: '<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>',
phone: '<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0 1 22 16.92z"/>',
mail: '<rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 7-10 5L2 7"/>',
mapPin: '<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/>',
clock: '<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>',
send: '<path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/>',
smartphone: '<rect x="5" y="2" width="14" height="20" rx="2" ry="2"/><line x1="12" y1="18" x2="12.01" y2="18"/>',
clipboard: '<path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><rect x="8" y="2" width="8" height="4" rx="1" ry="1"/>',
wrench: '<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>',
megaphone: '<path d="m3 11 18-5v12L3 14v-3z"/><path d="M11.6 16.8a3 3 0 1 1-5.8-1.6"/>',
// ===== Trust & success =====
check: '<polyline points="20 6 9 17 4 12"/>',
checkCircle: '<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/>',
star: '<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>',
shield: '<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>',
award: '<circle cx="12" cy="8" r="6"/><polyline points="8.21 13.89 7 22 12 19 17 22 15.79 13.88"/>',
// ===== Problems / issues =====
alertTriangle: '<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>',
trendingDown: '<polyline points="22 17 13.5 8.5 8.5 13.5 2 7"/><polyline points="16 17 22 17 22 11"/>',
trendingUp: '<polyline points="22 7 13.5 15.5 8.5 10.5 2 17"/><polyline points="16 7 22 7 22 13"/>',
globe: '<circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>',
search: '<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>',
eye: '<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>',
help: '<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/>',
// ===== Business =====
briefcase: '<rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>',
building: '<rect x="4" y="2" width="16" height="20" rx="2" ry="2"/><path d="M9 22v-4h6v4"/><path d="M8 6h.01"/><path d="M16 6h.01"/><path d="M12 6h.01"/><path d="M12 10h.01"/><path d="M12 14h.01"/><path d="M16 10h.01"/><path d="M16 14h.01"/><path d="M8 10h.01"/><path d="M8 14h.01"/>',
factory: '<path d="M2 20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-7 5V8l-7 5V4a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z"/><path d="M17 18h1"/><path d="M12 18h1"/><path d="M7 18h1"/>',
store: '<path d="m2 7 4.41-4.41A2 2 0 0 1 7.83 2h8.34a2 2 0 0 1 1.42.59L22 7"/><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/><path d="M15 22v-4a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2v4"/><path d="M2 7h20"/><path d="M22 7v3a2 2 0 0 1-2 2a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 16 12a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 12 12a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 8 12a2.7 2.7 0 0 1-1.59-.63.7.7 0 0 0-.82 0A2.7 2.7 0 0 1 4 12a2 2 0 0 1-2-2V7"/>',
shoppingCart: '<circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/>',
// ===== Services =====
cog: '<path d="M12 20a1 1 0 0 0 .553-1.832l-1.215-.811a1 1 0 0 1 0-1.714l1.215-.811A1 1 0 0 0 12 13a8 8 0 1 1 0 6"/><circle cx="12" cy="12" r="3"/>',
layers: '<polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/>',
link: '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>',
server: '<rect x="2" y="2" width="20" height="8" rx="2" ry="2"/><rect x="2" y="14" width="20" height="8" rx="2" ry="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/>',
monitor: '<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/>',
box: '<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/>',
// ===== Money / pricing =====
dollarSign: '<line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>',
creditCard: '<rect x="1" y="4" width="22" height="16" rx="2" ry="2"/><line x1="1" y1="10" x2="23" y2="10"/>',
package: '<line x1="16.5" y1="9.4" x2="7.5" y2="4.21"/><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/>',
// ===== Marketing / data =====
barChart: '<line x1="12" y1="20" x2="12" y2="10"/><line x1="18" y1="20" x2="18" y2="4"/><line x1="6" y1="20" x2="6" y2="16"/>',
pieChart: '<path d="M21.21 15.89A10 10 0 1 1 8 2.83"/><path d="M22 12A10 10 0 0 0 12 2v10z"/>',
users: '<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
user: '<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>',
target: '<circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/>',
zap: '<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>',
// ===== Legal / education =====
scale: '<path d="M16 16h6"/><path d="M2 16h6"/><path d="M5 8c0-1.1.9-2 2-2h10a2 2 0 0 1 2 2v1a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V8z"/><path d="M12 6V2"/><path d="m3 9 3 7"/><path d="M21 9l-3 7"/><path d="M12 18v4"/>',
book: '<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>',
graduationCap: '<path d="M22 10v6M2 10l10-5 10 5-10 5z"/><path d="M6 12v5c0 1.1 2.7 3 6 3s6-1.9 6-3v-5"/>',
pen: '<path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/><path d="M2 2l7.586 7.586"/><circle cx="11" cy="11" r="2"/>',
// ===== AI / tech =====
bot: '<rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/><line x1="8" y1="16" x2="8" y2="16"/><line x1="16" y1="16" x2="16" y2="16"/>',
brain: '<path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z"/><path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z"/>',
cpu: '<rect x="4" y="4" width="16" height="16" rx="2" ry="2"/><rect x="9" y="9" width="6" height="6"/><line x1="9" y1="1" x2="9" y2="4"/><line x1="15" y1="1" x2="15" y2="4"/><line x1="9" y1="20" x2="9" y2="23"/><line x1="15" y1="20" x2="15" y2="23"/><line x1="20" y1="9" x2="23" y2="9"/><line x1="20" y1="14" x2="23" y2="14"/><line x1="1" y1="9" x2="4" y2="9"/><line x1="1" y1="14" x2="4" y2="14"/>',
workflow: '<rect x="3" y="3" width="6" height="6" rx="1"/><rect x="15" y="15" width="6" height="6" rx="1"/><path d="M9 6h6a3 3 0 0 1 3 3v6"/>',
bell: '<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/>',
// ===== Misc =====
refresh: '<polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>',
arrowRight: '<line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/>',
sparkles: '<path d="M12 3l1.9 5.8 5.8 1.9-5.8 1.9L12 18.4l-1.9-5.8L4.3 10.7l5.8-1.9L12 3z"/><path d="M19 14l1 3 3 1-3 1-1 3-1-3-3-1 3-1 1-3z"/>',
rocket: '<path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/>',
} as const;
export type IconName = keyof typeof ICON_PATHS;

View File

@@ -1,124 +1,18 @@
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
import { defineCollection } from 'astro:content';
import { z } from 'astro/zod';
// =============================================================================
// SERVICES — service detail pages
// =============================================================================
const services = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/services' }),
schema: z.object({
title: z.string(),
subtitle: z.string(),
badge: z.string(),
category: z.string(),
objective: z.string(),
short_desc: z.string().optional(), // NEW: short description
usp_free_server: z.string().optional(),
usp_content_edit: z.string().optional(),
}),
});
// =============================================================================
// PORTFOLIO — client work
// =============================================================================
const portfolio = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/portfolio' }),
schema: z.object({
name: z.string(),
url: z.string().optional(),
category: z.string(), // webdev | ecommerce | marketing | ai-consult | automation
category_label: z.string(),
industry: z.string().optional(), // industry for filtering
thumbnail: z.string().optional(), // optional now
description: z.string().optional(),
what_we_did: z.string().optional(),
result: z.string().optional(),
featured: z.boolean().optional(), // NEW: show on home page
order: z.number().optional(), // NEW: display order
case_study: z.boolean().optional(), // NEW: full case study body
}),
});
// =============================================================================
// PAGES — static page content (about, home, etc.)
// =============================================================================
const pages = defineCollection({
loader: glob({ pattern: '*.{md,mdx}', base: './src/content/pages' }),
schema: z.object({
title: z.string().optional(),
subtitle: z.string().optional(),
hero_badge: z.string().optional(),
badge: z.string().optional(),
}),
});
// =============================================================================
// FAQ
// =============================================================================
const faq = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/faq' }),
schema: z.object({
category: z.string(),
category_icon: z.string().optional(),
question: z.string(),
answer: z.string(),
}),
});
// =============================================================================
// SETTINGS — site identity & contact
// =============================================================================
const settings = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/settings' }),
schema: z.object({
site_name: z.string().optional(),
email: z.string().optional(),
phone: z.string().optional(),
address: z.string().optional(),
facebook: z.string().optional(),
line: z.string().optional(),
linkedin: z.string().optional(),
line_id: z.string().optional(),
}),
});
// =============================================================================
// BLOG (existing)
// =============================================================================
const blog = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/blog' }),
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
excerpt: z.string(),
image: z.string(),
date: z.date(),
description: z.string(),
pubDate: z.date(),
updatedDate: z.date().optional(),
category: z.string(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
// =============================================================================
// PRICING — webdev tiers only (per plan 2026-06-13 round 2 #1)
// 2 entries: astro (฿5,000 featured) + wordpress (฿30,000)
// =============================================================================
const pricing = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/pricing' }),
schema: z.object({
name: z.string(),
tier: z.string(),
amount: z.string(),
period: z.string(),
is_featured: z.boolean().optional(),
order: z.number().optional(),
features: z.array(z.string()),
}),
});
export const collections = {
services,
portfolio,
faq,
settings,
blog,
pages,
pricing,
};
export const collections = { blog };

View File

@@ -1,27 +0,0 @@
---
title: "5 วิธีใช้ AI เพิ่มยอดขายให้ธุรกิจของคุณ"
excerpt: "ค้นพบ 5 วิธีที่ AI สามารถช่วยเพิ่มยอดขายให้ธุรกิจ SMEs ไทย พร้อมตัวอย่างและแนวทางการนำไปใช้จริง"
image: "/images/blog/5-ways-ai-increase-sales.jpg"
date: 2026-03-11
category: "AI Business"
---
## วิธีที่ 1: ใช้ AI วิเคราะห์ลูกค้าและแนะนำสินค้าที่ตรงใจ
หนึ่งในความสามารถที่ทรงพลังที่สุดของ AI คือการวิเคราะห์ข้อมูลลูกค้าและค้นหารูปแบบที่มนุษย์อาจมองไม่เห็น AI สามารถวิเคราะห์ว่าลูกค้าแต่ละคนชอบสินค้าประเภทไหน ซื้อในช่วงเวลาไหน และมีพฤติกรรมการซื้ออย่างไร
## วิธีที่ 2: ใช้ Chatbot ดูแลลูกค้าตลอด 24 ชั่วโมง
ลูกค้าจำนวนมากต้องการได้รับคำตอบทันที ไม่ว่าจะกี่โมง แต่การจ้างพนักงานทำงาน 24 ชั่วโมงนั้นมีค่าใช้จ่ายสูง Chatbot ที่ใช้ AI สามารถตอบคำถามลูกค้าได้ตลอดเวลา โดยไม่ต้องเสียค่าล่วงเวลา
## วิธีที่ 3: ใช้ AI ส่งข้อความการตลาดในเวลาที่เหมาะสม
การส่งข้อความการตลาดไม่ใช่แค่การส่งออกไปเท่านั้น แต่ต้องส่งในเวลาที่ลูกค้ามีโอกาสอ่านและตอบสนองมากที่สุด AI สามารถวิเคราะห์ว่าลูกค้าแต่ละคนมีช่วงเวลาไหนที่เปิดอ่านข้อความบ่อยที่สุด และส่งในเวลานั้น
## วิธีที่ 4: ใช้ AI สร้างเนื้อหาการตลาด
เนื้อหาการตลาดที่ดีเป็นหัวใจสำคัญในการดึงดูดลูกค้า แต่การสร้างเนื้อหาที่มีคุณภาพตลอดเวลาต้องใช้เวลาและทรัพยากรมาก AI สามารถช่วยสร้างเนื้อหาได้เร็วขึ้น ไม่ว่าจะเป็นโพสต์เฟซบุ๊ก คำบรรยายสินค้า อีเมลการตลาด หรือบทความบล็อก
## วิธีที่ 5: ใช้ AI ทำนายแนวโน้มและวางแผนสินค้า
การมีสินค้าคงคลงเป็นสิ่งจำเป็นสำหรับธุรกิจค้าปลีก แต่การมีสินค้ามากเกินไปก็เป็นปัญหา AI สามารถวิเคราะห์ข้อมูลยอดขายในอดีต ฤดูกาล และปัจจัยอื่นๆ เพื่อทำนายว่าควรสั่งสินค้าเท่าไหร่ในแต่ละช่วง

View File

@@ -0,0 +1,24 @@
---
title: "ยิงแอดแล้วไม่คุ้ม อาจไม่ใช่เพราะยิงผิดแพลตฟอร์ม"
description: "บางครั้งปัญหาอยู่ที่ intent ของคนที่เข้ามา ข้อความหน้าเว็บ หรือการวัดผลที่ยังไม่บอกคุณภาพลูกค้า"
pubDate: 2026-06-19
category: "Marketing"
tags: ["marketing", "ads", "analytics"]
draft: false
---
เวลายิงแอดแล้วไม่คุ้ม หลายธุรกิจมักรีบสรุปว่าแพลตฟอร์มไม่ดี หรือควรย้ายงบไปช่องทางอื่นทันที
แต่บางครั้งปัญหาไม่ได้อยู่ที่แพลตฟอร์ม ปัญหาอาจอยู่ที่คนที่เข้ามายังไม่ใช่กลุ่มที่พร้อมซื้อ ข้อความในเว็บไม่ตอบสิ่งที่เขากังวล หรือทีมยังวัดแค่จำนวน lead โดยไม่ดูคุณภาพ
## อย่าดูแค่จำนวนคนทัก
จำนวนคนทักเยอะไม่ได้แปลว่างานการตลาดดีเสมอไป ถ้าคนที่ทักมาไม่ตรงกลุ่ม ใช้งบเยอะขึ้นก็อาจทำให้ทีมเหนื่อยขึ้นโดยยอดขายไม่เพิ่ม
ควรดูว่าลูกค้าที่ทักมามาจากคำค้นหรือข้อความแบบไหน มีคำถามอะไรซ้ำ และสุดท้ายกลุ่มไหนกลายเป็นยอดขายจริง
## จุดที่ควรตรวจพร้อมกัน
การยิงแอด เว็บ และขั้นตอนรับ lead ต้องดูร่วมกัน เพราะลูกค้าไม่ได้เห็นแค่โฆษณา เขายังอ่านหน้าเว็บ เปรียบเทียบความน่าเชื่อถือ และตัดสินใจจากประสบการณ์ทั้งหมด
ก่อนเพิ่มงบ ควรดูข้อมูลให้ชัดก่อนว่าควรแก้ที่ targeting, message, landing page หรือขั้นตอนติดตามลูกค้า

View File

@@ -1,22 +0,0 @@
---
title: "วิธีสร้าง Content ด้วย AI ที่ Google รัก"
excerpt: "เรียนรู้วิธีการใช้ AI ช่วยสร้างเนื้อหาการตลาดที่มีคุณภาพและได้รับการจัดอันดับดีจาก Google พร้อมเทคนิคและตัวอย่างจริง"
image: "/images/blog/ai-content-google-love.jpg"
date: 2026-03-10
category: "AI Content"
---
## ทำไม AI Content ต้องมีคุณภาพ
Google มีอัลกอริทึมที่ฉลาดมาก สามารถแยกแยะได้ว่าเนื้อหาที่สร้างโดย AI มีคุณภาพหรือไม่ เนื้อหาที่ไม่มีคุณค่า สร้างขึ้นแค่เพื่อใส่คีย์เวิร์ด จะถูกลงโทษและไม่ติดอันดับ
## วิธีใช้ AI สร้างเนื้อหาที่ดี
ใช้ AI เป็นผู้ช่วย ไม่ใช่ผู้เขียนทั้งหมด วิธีที่ดีที่สุดคือใช้ AI ช่วยในบางส่วน เช่น รวบรวมข้อมูล สร้างโครงสร้าง หรือเขียน draft แล้วนำมาปรับแก้ด้วยมนุษย์
## เทคนิคการสร้าง AI Content ที่มีคุณภาพ
1. **กำหนด outline ก่อน** - ให้ AI สร้างโครงสร้างก่อน แล้วค่อยเติมเนื้อหา
2. **เพิ่มมุมมองส่วนตัว** - เพิ่มประสบการณ์และตัวอย่างจริง
3. **ตรวจสอบข้อเท็จจริง** - AI อาจสร้างข้อมูลที่ไม่ถูกต้อง ต้องตรวจสอบเสมอ
4. **เพิ่มคุณค่า** - เพิ่มข้อมูลเชิงลึกและความเห็นส่วนตัว

View File

@@ -0,0 +1,24 @@
---
title: "AI สำหรับ SME ไทย: เริ่มจากงานที่เจ็บที่สุดก่อน"
description: "AI ไม่จำเป็นต้องเริ่มจากระบบใหญ่ เริ่มจากคำถามซ้ำ งานเอกสารซ้ำ หรือข้อมูลที่ทีมใช้ตัดสินใจก่อนจะคุ้มกว่า"
pubDate: 2026-06-22
category: "AI Consult"
tags: ["AI", "SME", "workflow"]
draft: false
---
หลายธุรกิจเริ่มสนใจ AI จากคำถามว่า "ควรใช้เครื่องมืออะไร" แต่คำถามที่คุ้มกว่ามักเป็น "งานไหนในทีมเจ็บที่สุด และเกิดซ้ำบ่อยที่สุด"
ถ้าเริ่มจากเครื่องมือก่อน ธุรกิจมักได้ระบบที่ดูน่าสนใจ แต่ทีมไม่ได้ใช้จริง เพราะมันไม่ได้แก้จุดที่เสียเวลา เสียโอกาส หรือทำให้ตัดสินใจช้า
## จุดเริ่มต้นที่ดีกว่า
เริ่มจากรวบรวมงานที่เกิดซ้ำ เช่น คำถามลูกค้าที่ตอบบ่อย เอกสารที่ต้องสรุปซ้ำ ข้อมูลขายที่ทีมต้องเปิดหลายที่ หรือขั้นตอนตรวจงานที่ใช้เวลามากเกินไป
จากนั้นค่อยดูว่างานนั้นเหมาะกับ AI แบบไหน: ช่วยร่าง ช่วยสรุป ช่วยจัดหมวดหมู่ ช่วยค้นข้อมูล หรือช่วยเป็นผู้ช่วยตัดสินใจเบื้องต้น
## สิ่งที่ควรวัด
อย่าวัดแค่ว่าใช้ AI แล้วดูทันสมัยขึ้น ให้วัดว่างานลดลงจริงไหม ความผิดพลาดลดลงไหม ทีมตอบลูกค้าเร็วขึ้นไหม และข้อมูลที่ใช้ตัดสินใจชัดขึ้นไหม
AI ที่ดีสำหรับ SME ไม่จำเป็นต้องใหญ่ที่สุด แต่ต้องเริ่มจากปัญหาที่ใช่ และทำให้ทีมทำงานง่ายขึ้นจริง

View File

@@ -1,27 +0,0 @@
---
title: "AI สำหรับ SME ไทย: คู่มือฉบับสมบูรณ์"
excerpt: "การใช้ AI สำหรับธุรกิจ SME ไทยเพื่อเพิ่มขีดความสามารถในการแข่งขัน พร้อมแนวทางปฏิบัติจริง"
image: "/images/blog/ai-for-sme-thailand.jpg"
date: 2026-03-08
category: "AI Business"
---
## ทำไม SME ต้องใช้ AI
AI ไม่ใช่เทคโนโลยีสำหรับบริษัทใหญ่เท่านั้น ธุรกิจ SME สามารถเริ่มใช้ประโยชน์จาก AI ได้ง่ายๆ ด้วยเครื่องมือที่เข้าถึงได้
## การเริ่มต้นใช้ AI สำหรับ SME
### 1. เริ่มจากปัญหาที่เจ็บปวดที่สุด
- ถ้าลูกค้าถามคำถามซ้ำๆ ให้ใช้ AI Chatbot
- ถ้าต้องส่งอีเมลหลายร้อย封 ให้ใช้ AI Email Automation
- ถ้าไม่มีเวลาสร้างเนื้อหา ให้ใช้ AI Content Generation
### 2. เลือกเครื่องมือที่เหมาะสม
- งบน้อย: เริ่มจากเครื่องมือฟรีหรือราคาถูก
- งบปานกลาง: ใช้บริการ AI as a Service
- งบมาก: พัฒนา AI เฉพาะทางสำหรับธุรกิจ
### 3. วัดผลและปรับปรุง
- ติดตาม KPI ก่อนและหลังใช้ AI
- ปรับปรุงอย่างต่อเนื่อง

View File

@@ -1,28 +0,0 @@
---
title: "คู่มือ Digital Transformation ฉบับสมบูรณ์"
excerpt: "การ transform ธุรกิจของคุณสู่ดิจิทัลอย่างครบวงจร ตั้งแต่การวางแผนจนถึงการ Implement"
image: "/images/blog/digital-transformation.jpg"
date: 2026-03-05
category: "Business"
---
## Digital Transformation คืออะไร
Digital Transformation คือการนำเทคโนโลยีดิจิทัลมาใช้ในทุกด้านของธุรกิจ เพื่อเพิ่มประสิทธิภาพและสร้างคุณค่าใหม่ให้กับลูกค้า
## ขั้นตอนการ Transform
### ขั้นที่ 1: วิเคราะห์สถานะปัจจุบัน
- ประเมินระดับดิจิทัลของธุรกิจ
- ระบุจุดอ่อนและโอกาส
- กำหนดเป้าหมายที่ชัดเจน
### ขั้นที่ 2: วางแผนกลยุทธ์
- เลือกเทคโนโลยีที่เหมาะสม
- กำหนด timeline และ budget
- วางแผนการเปลี่ยนแปลง
### ขั้นที่ 3: Implement
- เริ่มจากโครงการเล็กๆ
- ทดสอบและเรียนรู้
- ขยายผลอย่างค่อยเป็นค่อยไป

View File

@@ -1,34 +0,0 @@
---
title: "Marketing Automation: คู่มือเริ่มต้น"
excerpt: "เรียนรู้พื้นฐานของ Marketing Automation และวิธีเริ่มต้นใช้งานสำหรับธุรกิจของคุณ"
image: "/images/blog/marketing-automation-guide.jpg"
date: 2026-03-01
category: "Marketing"
---
## Marketing Automation คืออะไร
Marketing Automation คือการใช้ซอฟต์แวร์เพื่อ automate การตลาดซ้ำๆ เช่น การส่งอีเมล การโพสต์โซเชียลมีเดีย และการวิเคราะห์ข้อมูล
## ประโยชน์ของ Marketing Automation
1. **ประหยัดเวลา** - ทำงานอัตโนมัติแทนที่จะทำ manually
2. **เพิ่มประสิทธิภาพ** - ส่งข้อความที่เหมาะสมในเวลาที่เหมาะสม
3. **วัดผลได้** - ติดตามผลและปรับปรุงอย่างต่อเนื่อง
## เริ่มต้นอย่างไร
### 1. เลือกแพลตฟอร์มที่เหมาะสม
- งบน้อย: Mailchimp, HubSpot Free
- งบปานกลาง: ActiveCampaign, Marketo
- งบมาก: Salesforce, Oracle
### 2. กำหนดเป้าหมาย
- เพิ่มยอดขาย
- สร้าง leads
- รักษาลูกค้า
### 3. สร้าง workflow
- เริ่มจาก email autoresponder
- เพิ่ม lead scoring
- ขยายไปยัง multi-channel

View File

@@ -0,0 +1,24 @@
---
title: "Marketing Automation ควรช่วยลดงาน ไม่ใช่เพิ่มเครื่องมือ"
description: "ก่อนเลือกเครื่องมือ ควรดู workflow จริงก่อนว่าขั้นตอนไหนซ้ำ ช้า หรือผิดพลาดบ่อย แล้วค่อยออกแบบระบบช่วย"
pubDate: 2026-06-21
category: "Automation"
tags: ["automation", "marketing", "workflow"]
draft: false
---
Marketing Automation ที่ดีไม่ควรทำให้ทีมต้องดู dashboard เพิ่มอีกหลายหน้า หรือจำขั้นตอนใหม่จนเหนื่อยกว่าเดิม
เป้าหมายของ automation คือช่วยลดงานซ้ำ ลดการลืมติดตามลูกค้า และทำให้ทีมเห็นสถานะงานชัดขึ้น
## ก่อนเลือกเครื่องมือ ควรดู workflow
ลองไล่ตั้งแต่ลูกค้าทักเข้ามา ทีมรับข้อมูลอย่างไร เก็บไว้ที่ไหน ใครเป็นคนตามต่อ และมีจุดไหนที่ข้อมูลหล่นหรือซ้ำบ่อย
ถ้ายังไม่เห็น flow จริง การเลือกเครื่องมือก่อนอาจทำให้ระบบใหม่ไปซ้อนกับวิธีทำงานเดิม จนสุดท้ายทีมต้องทำงานสองรอบ
## Automation ที่ควรเริ่ม
เริ่มจากจุดเล็กที่กระทบยอดขายหรือเวลาทีม เช่น แจ้งเตือน lead ที่ยังไม่ได้ตาม เก็บข้อมูลจากฟอร์มเข้าที่เดียว หรือส่งสรุปงานให้ทีมทุกวันโดยไม่ต้องทำมือ
ระบบที่ดีควรทำให้ทีมรู้ว่าต้องทำอะไรต่อ ไม่ใช่แค่มีเครื่องมือเพิ่มในบริษัท

View File

@@ -0,0 +1,24 @@
---
title: "เว็บ SME ที่ดีควรถามได้ว่าลูกค้าควรทำอะไรต่อ"
description: "เว็บไซต์ไม่ใช่แค่หน้าแนะนำบริษัท แต่ควรช่วยให้ลูกค้าเข้าใจปัญหา เห็นทางเลือก และรู้ว่าควรติดต่อเรื่องอะไร"
pubDate: 2026-06-20
category: "Website"
tags: ["website", "SME", "conversion"]
draft: false
---
เว็บไซต์ธุรกิจไม่ควรเป็นแค่โบรชัวร์ออนไลน์ที่บอกว่าบริษัททำอะไร แต่ควรช่วยพาลูกค้าไปสู่การตัดสินใจที่ง่ายขึ้น
ลูกค้าหลายคนไม่ได้เริ่มจากการรู้ว่าต้องซื้ออะไร เขาเริ่มจากอาการ เช่น ยอดขายไม่โต เว็บไม่ค่อยมีคนทัก หรือไม่แน่ใจว่าบริการไหนเหมาะกับตัวเอง
## หน้าเว็บควรช่วยตอบคำถาม
เว็บที่ดีควรตอบให้ได้ว่า ปัญหานี้เหมาะกับบริการไหน ควรเริ่มคุยเรื่องอะไร ต้องเตรียมข้อมูลแบบไหน และทำไมควรเชื่อว่าทีมนี้ช่วยได้
ถ้าลูกค้าอ่านจบแล้วยังไม่รู้ว่าต้องทำอะไรต่อ เว็บอาจสวย แต่ยังไม่ได้ช่วยธุรกิจเท่าที่ควร
## CTA ต้องผูกกับปัญหา
ปุ่มติดต่อไม่จำเป็นต้องขายแรงเสมอไป สำหรับ SME หลายเคส CTA ที่ดีคือการชวนให้เล่าโจทย์ก่อน แล้วช่วยดูว่าควรเริ่มแก้ตรงไหน
เว็บจึงควรเป็นพื้นที่ช่วยคัดกรองและทำให้บทสนทนาแรกมีคุณภาพขึ้น

View File

@@ -1,6 +0,0 @@
---
category: "บริการ"
category_icon: "💼"
question: "มอร์มินิมอร์ทำอะไรบ้าง?"
answer: "4 บริการหลัก — (1) รับทำเว็บไซต์ (Astro / WordPress) (2) ที่ปรึกษาการตลาดออนไลน์ (3) Automation / เชื่อมต่อระบบ (4) AI Consult ในองค์กร ทั้งหมดเริ่มจากดูข้อมูลของลูกค้าก่อน ไม่ใช่เดาว่าควรทำอะไร"
---

View File

@@ -1,6 +0,0 @@
---
category: "บริการ"
category_icon: "💼"
question: "ถ้ามีงบน้อย ควรเริ่มจากอะไร?"
answer: "ถ้ายังไม่มีเว็บและไม่มีกิจกรรมออนไลน์เลย → เริ่มจากเว็บไซต์ก่อน เพราะเป็นบริการที่ถูกที่สุด ถ้ามีเว็บแล้วและมีกิจกรรมออนไลน์ → Marketing Consult จะคุ้มกว่า ถ้ารู้สึกยุ่งมากมีแต่ความผิดพลาด → Automation จะตอบโจทย์สุด ถ้ามีระบบพร้อมแล้วอยากรีดยอดขายหรือป้องกันปัญหาพนักงานลาออก → AI Consult"
---

View File

@@ -1,6 +0,0 @@
---
category: "บริการ"
category_icon: "💼"
question: "เหมาะกับธุรกิจแบบไหน?"
answer: "SME ที่ต้องการคนช่วยดูเรื่อง Online Marketing และระบบ IT ลูกค้าที่ไม่มีความรู้ IT มาก แต่จำเป็นต้องใช้ระบบ IT ในการทำงาน ไม่เหมาะกับ: องค์กรขนาดใหญ่ที่มีการเมืองเยอะ คนที่อยากได้ของฟรีหรือจ่ายน้อยแต่คาดหวังงานระดับแสน และกลุ่ม IT ทั่วไป (ยกเว้นขาย Software เฉพาะทาง เช่น ERP)"
---

View File

@@ -1,6 +0,0 @@
---
category: "บริการ"
category_icon: "💼"
question: "รับงานอุตสาหกรรมเฉพาะไหม?"
answer: "รับหลากหลาย แต่ไม่รับทุกอย่าง — เราเน้นงานที่วัดผลได้ ไม่ว่าจะเป็น E-commerce, บริการ, B2B, คลินิก, ร้านอาหาร, ผู้ผลิต, สถานศึกษา, ที่ปรึกษา ดูตัวอย่างงานได้ที่หน้า Portfolio ถ้าไม่แน่ใจว่าอุตสาหกรรมของคุณเหมาะ นัดคุย 30 นาทีฟรีได้เลย"
---

View File

@@ -1,6 +0,0 @@
---
category: "ราคา"
category_icon: "💰"
question: "ราคาเริ่มต้นเท่าไหร่?"
answer: "เว็บไซต์: Astro เริ่ม 5,000 บาท / WordPress เริ่ม 30,000 บาท (ขึ้นอยู่กับความซับซ้อน) · ที่ปรึกษา Marketing และ Automation: เริ่ม 10,000 บาท/เดือน · ที่ปรึกษา AI: เริ่ม 20,000 บาท/เดือน · Host: เริ่ม 5,000 บาท/ปี ราคาจะขึ้นอยู่กับ Requirement จริง บอกได้เมื่อคุยกัน"
---

View File

@@ -1,6 +0,0 @@
---
category: "ราคา"
category_icon: "💰"
question: "มีแพ็คเกจไหม?"
answer: "ไม่มีแพ็คเกจตายตัว เพราะงานแต่ละชิ้นต่างกัน บางเว็บใช้เวลา 1 สัปดาห์ บางเว็บใช้ 3 เดือน เราจะส่ง Proposal เป็น PDF พร้อมรายละเอียดงาน ราคา ระยะเวลา ให้คุณอ่านก่อนเซ็น แก้ไข scope ได้"
---

View File

@@ -1,6 +0,0 @@
---
category: "ราคา"
category_icon: "💰"
question: "จ่ายยังไง?"
answer: "เว็บไซต์: มัดจำ 50% ตอนเซ็น ที่เหลือจ่ายตอนส่งมอบ · ที่ปรึกษารายเดือน: จ่ายต้นเดือนของทุกเดือน เริ่มจ่ายเดือนแรกตอนเซ็นสัญญา ออกใบกำกับภาษีได้"
---

View File

@@ -1,6 +0,0 @@
---
category: "ราคา"
category_icon: "💰"
question: "มีค่าใช้จ่ายแอบแฝงไหม?"
answer: "ไม่มี — เราจะบอกทุกค่าใช้จ่ายใน Proposal ตั้งแต่ต้น ไม่มี \"อันนี้เพิ่มเงินนะ\" ตอนใกล้ส่งมอบ ถ้ามีงานเพิ่มจริง ๆ จะคุยและตกลงราคาก่อนทำ"
---

View File

@@ -1,6 +0,0 @@
---
category: "ระยะเวลา"
category_icon: "⏱️"
question: "ทำเว็บเสร็จในกี่วัน?"
answer: "Astro: 14-30 วัน · WordPress: 2-4 เดือน · ถ้าจะติด เราจะบอกก่อน 7 วัน ไม่ใช่บอกตอนส่งงาน — เคสไหนที่เคยส่งช้า เราคืนเงิน Pro-rata"
---

View File

@@ -1,6 +0,0 @@
---
category: "ระยะเวลา"
category_icon: "⏱️"
question: "SEO ใช้เวลาเห็นผลกี่เดือน?"
answer: "SEO ปกติใช้เวลา 3-6 เดือนถึงจะเห็นผลชัด ขึ้นอยู่กับคีย์เวิร์ดและคู่แข่ง เราเคยมีเคสติดหน้า 1 Google ใน 4 เดือน แต่ก็มีเคสที่ใช้เวลานานกว่านั้น จะบอกคุณตรง ๆ ตั้งแต่แรกว่าคาดว่าเห็นผลเมื่อไหร่"
---

View File

@@ -1,6 +0,0 @@
---
category: "ระยะเวลา"
category_icon: "⏱️"
question: "งานด่วน ทำได้ไหม?"
answer: "ทำได้ แต่จะคิดราคาเร่งด่วนเพิ่ม เพราะกระทบกับงานอื่นที่มีอยู่ เราจะบอกชัดว่าค่าเร่งเท่าไหร่ก่อนรับงาน"
---

View File

@@ -1,6 +0,0 @@
---
category: "ระยะเวลา"
category_icon: "⏱️"
question: "ถ้างานล่าช้า คืนเงินไหม?"
answer: "ถ้าเราส่งงานล่าช้าโดยไม่ได้แจ้งล่วงหน้า 7 วัน จะคืนเงิน Pro-rata ตามจริง เคสนี้เคยเกิดขึ้น 1-2 ครั้งในรอบหลายปี และคืนเงินไปแล้ว"
---

View File

@@ -1,6 +0,0 @@
---
category: "AI & เทคนิค"
category_icon: "🤖"
question: "AI ใช้ของแพงหรือของถูก?"
answer: "เราเลือกตามงาน ไม่ใช่เลือกของแพงสุดเสมอ งาน 80% ใช้ Model ราคาถูก (เช่น GPT-4o-mini, Haiku, Local LLM) ก็ได้ผล ส่วนงานที่ซับซ้อนมาก ๆ ค่อยใช้ของแพง วิธีนี้ช่วยลูกค้าประหยัดค่าใช้จ่ายได้มากกว่าครึ่ง"
---

View File

@@ -1,6 +0,0 @@
---
category: "AI & เทคนิค"
category_icon: "🤖"
question: "ต้องมีความรู้เทคนิคไหม?"
answer: "ไม่ต้อง เราดูแลตั้งแต่ต้นจนจบ ตั้งแต่วิเคราะห์ ออกแบบ พัฒนา ไปจนถึง Deploy และดูแลหลังขาย จะสอนการใช้งานจนทีมคุณใช้เป็น"
---

View File

@@ -1,6 +0,0 @@
---
category: "AI & เทคนิค"
category_icon: "🤖"
question: "ข้อมูลปลอดภัยไหม (PDPA)?"
answer: "ปลอดภัย สำหรับงานที่ต้องการความลับ เราใช้ Local LLM ที่รันในเครื่องของลูกค้า ข้อมูลไม่ออกไปไหน ส่วนงานทั่วไปใช้ API ของผู้ให้บริการที่เชื่อถือได้ พร้อมทำ NDA ได้"
---

View File

@@ -1,6 +0,0 @@
---
category: "AI & เทคนิค"
category_icon: "🤖"
question: "ควรใช้ AI ตัวไหน?"
answer: "ขึ้นอยู่กับงาน ถ้าเป็นแชทบอททั่วไป ใช้ GPT-4o-mini หรือ Claude Haiku ก็พอ ถ้าเป็นงานวิเคราะห์ข้อมูล ใช้ GPT-4o หรือ Claude Sonnet ถ้าเป็นงานที่ต้องการความลับ ใช้ Local LLM (Llama, Qwen) เรามี AI Audit ฟรี ช่วยวิเคราะห์ว่าธุรกิจคุณควรใช้ AI ตัวไหน"
---

View File

@@ -1,6 +0,0 @@
---
category: "หลังการขาย"
category_icon: "🛠️"
question: "มีประกันงานไหม?"
answer: "มี — ถ้าเว็บมีปัญหาจากการพัฒนาของเรา จะแก้ไขให้ฟรี 30-90 วันหลังส่งมอบ (ขึ้นอยู่กับประเภทงาน) ถ้าเกิดจากการแก้ไขของลูกค้าเอง จะคิดค่าแก้ตามจริง"
---

View File

@@ -1,6 +0,0 @@
---
category: "หลังการขาย"
category_icon: "🛠️"
question: "ติดต่อช่องทางไหน?"
answer: "LINE OA: @moreminimore (ตอบเร็วที่สุด) · โทร: 080-995-5945 · Email: contact@moreminimore.com ทีมที่ตอบคือคนที่ทำงานให้คุณ ไม่ใช่ Bot ไม่ใช่คนอื่น"
---

View File

@@ -1,6 +0,0 @@
---
category: "หลังการขาย"
category_icon: "🛠️"
question: "มีแพ็คเกจดูแลรายเดือนไหม?"
answer: "มี เริ่ม 2,000 บาท/เดือน รวมอัปเดตเนื้อหา ปรับ SEO แก้บั๊ก ตอบคำถามผ่าน LINE ถ้าไม่เอาแพ็คเกจ ก็จ่ายเป็นงาน ๆ ไป แล้วแต่ความเหมาะ"
---

View File

@@ -1,6 +0,0 @@
---
category: "หลังการขาย"
category_icon: "🛠️"
question: "ถ้าไม่พอใจ ขอเงินคืนได้ไหม?"
answer: "ภายใน 7 วันแรกหลังเริ่มงาน ถ้าคุณรู้สึกว่าไม่ใช่ ขอยกเลิกได้ จะคืนเงินตามส่วนงานที่ยังไม่ได้ทำ เราไม่ผูก commitment"
---

View File

@@ -1,86 +0,0 @@
---
title: "เกี่ยวกับเรา"
subtitle: "ที่ปรึกษาที่ทำงานเอง ไม่ใช่ทีมขายที่ส่งงานต่อ"
hero_badge: "เกี่ยวกับเรา"
---
# เกี่ยวกับมอร์มินิมอร์
## เริ่มจากตรงนี้
มอร์มินิมอร์ ก่อตั้งปี 2020 จากประสบการณ์ตรงที่เห็น SME ไทยเสียเงินหลายแสนไปกับ
- เว็บไซต์ที่ "สวยแต่ไม่มีคนเข้า"
- โฆษณาที่ "ยิงเยอะแต่ไม่มีคนซื้อ"
- AI tools ที่ "ว้าวแต่ใช้ไม่เป็น"
เราเลยตั้งใจว่าจะทำให้ต่าง
## นโยบายของเรา
**เป้าหมายของเราคือการเพิ่มกำไรให้ลูกค้า** เพราะถ้าลูกค้ามีกำไรมากขึ้น ลูกค้าก็จะสามารถใช้บริการเราต่อไปได้
ทุกระบบที่ส่งมอบต้องตอบคำถามเดียวให้ได้: **"ลูกค้ามีกำไรเพิ่มขึ้นจริงไหม"** — ไม่ใช่แค่ส่งงานตามสัญญา
## วิธีทำงานของเรา
เราไม่ได้ทำงานแบบเดียวกับทุกที่ — เพราะลูกค้าแต่ละคนมีบริบท งบประมาณ และทีมต่างกัน
- **งานที่ต้องใช้ความเชี่ยวชาญเฉพาะทาง** — เราจะทำเอง เพราะถ้าเราไม่ทำเอง เราจะตอบคำถามลูกค้าไม่ได้
- **งานที่ต้องทำซ้ำ ๆ ปริมาณเยอะ** — เราจะใช้ bot หรือ outsource ให้คนที่เชี่ยวชาญเฉพาะด้าน เพราะเรื่องบางเรื่อง คนที่ทำเป็นอาชีพจะทำได้ดีกว่า
- **งานที่ต้องตอบลูกค้าตลอด 24 ชั่วโมง** — เราจะใช้ bot ช่วยคัดกรองเบื้องต้น แล้วเราจะตามด้วยคน เพราะบางเรื่อง bot ตอบไม่ได้
สรุปคือ — **ผลงานที่ออกมาจะขึ้นอยู่กับบริบทของลูกค้า ไม่ใช่วิธีทำงานของเรา** เราเลือกวิธีที่จะทำให้ลูกค้าได้ผลลัพธ์ที่ดีที่สุด ไม่ใช่วิธีที่เราถนัดที่สุด
## เราเชื่ออะไร
- **เว็บสวยไม่ได้แปลว่าขายได้** — เว็บหลายเว็บที่ดูดีที่สุด ขายแย่ที่สุดก็มี
- **AI ไม่ได้แทนทุกอย่าง** — แต่ถ้ารู้จักใช้ จะประหยัดหรือเปิดโอกาสใหม่ที่คาดไม่ถึง
- **จ่ายแพงไม่ได้แปลว่าดี** — งาน 80% ใช้ของถูกได้ ส่วนที่เหลือค่อยใช้ของแพง
- **ทำเผื่อมากเกินไป** มักจะทำให้จ่ายเกินความจำเป็น
- **"สิ่งที่ถูกต้อง" ไม่ใช่ "สิ่งที่ลูกค้าต้องการ" เสมอไป** — เราเช็คเสมอว่าสิ่งที่เราจะทำตรงกับที่ลูกค้าต้องการจริงไหม
- **ระบบที่สุดยอดที่คนใช้ไม่เป็น = เสียเงินเปล่า** — เราเน้นให้คนใช้ได้จริง ไม่ใช่แค่ส่งของแพง ๆ
## เบื้องหลังการทำงาน
เรานั่งทำงานที่บ้าน ใช้ MacBook ตัวเดียว แต่มี **เครื่องมือด้าน marketing intelligence** ที่ช่วยให้เราเข้าใจตลาดได้ลึกกว่าคนทั่วไป:
- **ระบบดูโฆษณาคู่แข่ง** — ดูว่าคู่แข่งยิงโฆษณาอะไร คำไหน convert ดี งบประมาณเท่าไหร่ เพื่อให้ลูกค้าวางกลยุทธ์ได้โดยไม่ต้องเดา
- **ระบบวิเคราะห์ keyword + SEO gap** — หาโอกาสที่คู่แข่งยังไม่ได้ทำ เพื่อให้ลูกค้าได้ traffic ก่อน
- **ระบบติดตาม trend ตลาด** — รู้ว่าตลาดกำลังไปทางไหนก่อนที่ลูกค้าจะรู้ตัว
- **Stack:** JavaScript, Python, PHP, n8n, OpenAI API, Meta API, Google Analytics, Looker Studio — แล้วแต่งาน
## เรื่องเล่าจากลูกค้า
> "จ่ายไม่อั้นเปิดตลาดใหม่ให้ที"
> — ลูกค้าหลังขยายช่องทางการตลาดสำเร็จ
> "ผลตอบรับดีเกินคาดแฮะ"
> — ลูกค้าหลังปรับกลยุทธ์โฆษณา
> "ผมตามประชุมแต่ลูกค้าบอกว่า 'ไม่ต้องหรอก เพราะคนทักมาจนยุ่งไปหมดแล้ว'"
> — ลูกค้าหลังใช้ระบบจองออนไลน์/แชทบอททำงานแทน
> "พี่คนโทรมาเพิ่มขึ้นครับ แถมถามสินค้าที่ไม่เคยมีคนถามด้วย"
> — ลูกค้าหลัง SEO ติดอันดับและมีคนเข้าเว็บเพิ่ม
(เรื่องเล่าจากคำตอบลูกค้าจริง ที่ระบุไว้ในบริบทการสนทนาตอนเริ่มโปรเจกต์)
## ลูกค้าที่เหมาะกับเรา
- SME ที่ต้องการคนช่วยดูเรื่อง Online Marketing และระบบ IT
- ลูกค้าที่ไม่มีความรู้ IT มาก แต่จำเป็นต้องใช้ระบบ IT
- คนที่ต้องการที่ปรึกษาจริง ๆ ไม่ใช่คนมาขายของ
## ลูกค้าที่ไม่เหมาะ
- องค์กรขนาดใหญ่ที่ต้องการความเป็นทางการสูง + การเมืองเยอะ + ต้องสร้างภาพลักษณ์เกินตัว
- คนที่อยากได้ของฟรี หรือจ่ายน้อยระดับพัน แต่คาดหวังงานระดับแสน
- กลุ่ม IT ทั่วไป — เป็นคู่แข่งเกือบทั้งหมด ยกเว้นกลุ่มขาย Software เฉพาะทาง เช่น ERP
## กระบวนการทำงาน
1. **ปรึกษาฟรี 30-60 นาที** — คุยกับเจ้าของธุรกิจ ฟังปัญหา เป้าหมาย งบประมาณ ให้คำแนะนำเบื้องต้น ไม่ผูก commitment
2. **วางแผน + ส่ง Proposal** — วิเคราะห์เชิงลึก ดูคู่แข่ง ส่ง Proposal เป็น PDF คุณอ่าน ถามคำถาม แก้ไข scope ได้ก่อนเซ็น
3. **ดำเนินการ** — เราจะแจ้งความคืบหน้าของงานเป็นช่วง ๆ ผ่าน LINE Group ของโปรเจกต์ คุณเห็นว่าเราทำอะไรไปแล้วบ้าง และจะมี demo เมื่อเราพร้อมส่งงานรอบใหญ่ ๆ เท่านั้น — เราไม่อยากผูกมัดตัวเองกับ deadline แบบ sprint เพราะงานจริงไม่ได้แบ่งเป็นรอบสั้น ๆ ได้ตลอด
4. **ส่งมอบ + ดูแล** — ส่งมอบงาน + อบรมทีม + มอบคู่มือ หลังส่งมอบ ถ้ามีการปรับเปลี่ยนเล็ก ๆ น้อย ๆ หรือแก้ไขจุดบกพร่อง เราจะดูแลให้โดยไม่คิดค่าใช้จ่ายเพิ่ม ยกเว้นกรณีที่เป็นการสร้าง feature ใหม่ หรือปรับแต่งครั้งใหญ่ เราจะคิดค่าใช้จ่ายเป็นครั้ง ๆ ไปตามขอบเขตงาน

View File

@@ -1,69 +0,0 @@
---
badge: "ที่ปรึกษาที่วางกลยุทธ์จากข้อมูล ไม่ใช่จากประสบการณ์ล้วน ๆ"
title: "เว็บขายไม่ได้ โฆษณาเปลือง งานซ้ำเติมคน — เราแก้ให้ตรงจุด"
subtitle: "รับทำเว็บ ที่ปรึกษาการตลาด และวางระบบ AI ในองค์กร เริ่มจากดูสถิติของคุณก่อน ไม่ใช่เดาว่าควรทำอะไร"
problem_section_title: "4 ปัญหาที่เจอบ่อยที่สุด"
problem_section_subtitle: "แต่ละข้อมีวิธีแก้ที่เจาะจง — เราไม่ได้บอกว่า 'เราทำได้หมด' แต่บอกว่า 'ถ้าเป็นแบบนี้ ทำแบบนี้'"
service_section_title: "ทำอะไรได้บ้าง"
service_section_subtitle: "เริ่มจากอันที่ปวดที่สุด ค่อยขยายไปอันอื่น"
service_cta: "ดูบริการทั้งหมด"
portfolio_section_badge: "ผลงานจริง ไม่ใช่ Mockup"
portfolio_section_title: "ลูกค้าจริง ตัวเลขจริง"
portfolio_section_subtitle: "คลิกดูเว็บจริงได้เลย"
portfolio_cta: "ดูผลงานทั้งหมด"
final_cta_title: "คุยกันก่อน 30 นาที ฟรี"
final_cta_desc: "เราจะถามคำถาม 5 ข้อ แล้วบอกคุณได้เลยว่าควรเริ่มจากตรงไหน — จะบอกตรง ๆ ว่าทำได้หรือทำไม่ได้"
final_cta_button: "นัดคุย 30 นาที"
final_cta_line: "ทัก LINE: @moreminimore"
final_cta_reassurance: "ไม่มี commitment · ไม่มี script sales · พูดตรง ๆ"
---
# 4 ปัญหาที่ SME ไทยเจอบ่อยที่สุด
เราเจอปัญหาแบบนี้ซ้ำ ๆ กับลูกค้า 4 แบบ แต่ละแบบมีวิธีแก้ต่างกัน
## 1. ลงโฆษณาแล้วยอดไม่ขยับ
**อาการ:** คลิกเยอะ ยอดขายเท่าเดิม งบหม<E0B8AB>ไปกับคนที่ไม่ซื้อ
**สาเหตุส่วนใหญ่:** เลือกกลุ่มเป้าหมายผิด หรือยิงทุก Platform โดยไม่ดูว่าอันไหนคุ้ม
**เราแก้ยังไง:** ดูสถิติ 3 เดือนย้อนหลัง แยกว่า Platform ไหน Convert ดี ตัดอันที่เสียเงินเปล่า ปรับ Creative ให้ดึงดูดคนที่พร้อมจ่าย
> ตัวอย่าง: ลูกค้ารายหนึ่งเพิ่ม Impression 373% และเพิ่ม Click 114% ในเดือนแรก โดยใช้งบน้อยลง 28% — ดูเคสเต็มได้ที่หน้า Portfolio
## 2. เว็บมีคนเข้า แต่ไม่มีคนซื้อ
**อาการ:** Traffic เข้าพอสมควร แต่ไม่มีใครทัก ไม่มีใครโทร ตะกร้าค้าง
**สาเหตุส่วนใหญ่:** เว็บสวยแต่ไม่ได้ออกแบบมาให้คนซื้อ หรือมีจุดติดขัดที่ทำให้คนออกก่อนซื้อ
**เราแก้ยังไง:** ดู Heatmap ว่าคนเข้ามาแล้วทำอะไร ตรงไหนที่คนออก ตรงไหนที่คนค้าง ปรับจุดนั้น ๆ
> ตัวอย่าง: ลูกค้า B2B รายหนึ่งมีคนเข้าเว็บเยอะ แต่ไม่มี Lead — เพิ่ม Lead 2.4 เท่าใน 1 เดือน โดยไม่ต้องเพิ่มงบโฆษณา
## 3. งานซ้ำ ๆ ใช้เวลาคนเป็นชั่วโมงทุกวัน
**อาการ:** ทีมต้องคีย์ข้อมูล ทำรายงาน ตอบแชตเดิม ๆ จนไม่มีเวลาทำงานหลัก
**สาเหตุส่วนใหญ่:** ระบบเก่าที่ไม่ได้เชื่อมกัน หรือยังทำ Manual อยู่
**เราแก้ยังไง:** ดู Workflow ก่อน แล้วเลือกเครื่องมือที่เหมาะ — บางงานใช้ n8n บางงานเขียน Script บางงานใช้ AI
> ตัวอย่าง: บริษัทที่ปรึกษาขนาดเล็กใช้เวลาทำรายงาน 30+ ชม./เดือน — ลดเหลือ 2 ชม./เดือน
## 4. ใช้ AI แต่ไม่เห็นผล
**อาการ:** จ่ายแพง ใช้ AI ระดับ Frontier กับทุกงาน แต่ผลลัพธ์ไม่คุ้มเงิน
**สาเหตุส่วนใหญ่:** ใช้ AI ผิดแบบ — งานหลายอย่างใช้ Model ราคาถูกก็ได้ผลเท่า ๆ กัน
**เราแก้ยังไง:** เลือก AI ตามงาน ไม่ใช่เลือกของแพงสุด — เน้น Local LLM สำหรับงานที่ต้องการความลับ
> ตัวอย่าง: งาน 80% ของธุรกิจใช้ Model ราคาถูกได้ ประหยัดค่าใช้จ่ายได้มากกว่าครึ่ง
---
# เริ่มจากตรงไหนดี?
ถ้าไม่แน่ใจว่าปัญหาของคุณตรงกับข้อไหน — นัดคุย 30 นาทีฟรี เราจะช่วยดู

View File

@@ -1,12 +0,0 @@
---
name: "Baofuling Shop"
url: "https://baofulingshop.com"
category: "webdev"
category_label: "Website Development"
industry: "สินค้าความงาม"
what_we_did: "พัฒนาเว็บไซต์ E-commerce ขายสินค้าสกินแคร์ พร้อมระบบตะกร้า + ชำระเงิน"
result: "เว็บไซต์ขายของออนไลน์ครบวงจร ดูแลเองได้"
thumbnail: "/images/portfolio/baofuling.png"
featured: true
order: 19
---

View File

@@ -1,58 +0,0 @@
---
name: "Dataroot"
url: "https://erp.dataroot.asia"
category: "consult"
category_label: "Consult"
industry: "ตัวแทนจำหน่าย Odoo ERP ในไทย"
thumbnail: "/images/portfolio/dataroot.png"
description: "ตัวแทนจำหน่าย Odoo ERP ในไทย → วิเคราะห์กลุ่มเป้าหมาย + ปรับโครงสร้างแคมเปญ + ขยายช่องทาง Facebook"
what_we_did: "วิเคราะห์ข้อมูลโฆษณา 3 เดือน + เจาะกลุ่มเป้าหมายใหม่ + ขยายช่องทาง Facebook"
result: "Impression ↑373%, Click ↑114.2%, Ad spend ↓28.3%, Lead ใหม่จาก FB"
featured: true
order: 1
case_study: true
---
# Case Study: Dataroot (ตัวแทนจำหน่าย Odoo ERP)
> Flagship case study ของเรา — ผลลัพธ์ชัดเจน วัดผลได้ เป็นตัวอย่างของ "วางกลยุทธ์จากข้อมูล"
## บริบท
Dataroot เป็นตัวแทนจำหน่าย Odoo ERP ในไทย มีบริการอยู่แล้ว แต่โฆษณาเดิมยิงแบบกว้าง — คลิกเยอะ แต่คนที่สนใจจริง ๆ น้อย งบโฆษณากินเดือนละหลายแสนโดยไม่รู้ว่าเงินไปไหน
## ปัญหา
- ยิงโฆษณาแบบ "กลุ่มกว้าง" ได้คลิกเยอะ แต่คนที่กำลังมองหา ERP จริง ๆ น้อย
- ไม่มีการแยกว่าคลิกมาจากกลุ่มไหน จึงปรับอะไรไม่ถูก
- ค่าใช้จ่ายต่อ Lead สูงเกินจุดคุ้มทุน
## สิ่งที่เราทำ
เริ่มจากดูสถิติเดิม ไม่ใช่เริ่มจากอยากยิงอะไร
1. **วิเคราะห์ข้อมูล 3 เดือนย้อนหลัง** — แยกว่าคลิกมาจากกลุ่มอายุ/ความสนใจไหน แล้วกลุ่มไหนมี Lead คุณภาพ
2. **เจาะกลุ่มเป้าหมายใหม่** — ตัดกลุ่มที่คลิกเยอะแต่ไม่ซื้อออก เพิ่มงบให้กลุ่มที่ Convert ดี
3. **ปรับโครงสร้างแคมเปญ** — แยก Awareness / Consideration / Conversion ชัดเจน
4. **ขยายช่องทาง Facebook** — เพิ่มช่องทาง Lead ใหม่ที่ไม่เคยใช้
## ผลลัพธ์ (เดือนแรก)
| ตัวชี้วัด | ก่อน | หลัง (เดือนแรก) |
|---|---|---|
| Impression | 100% | **473%** ↑373% |
| Click | 100% | **214%** ↑114.2% |
| Ad spend | 100% | **71.7%** ↓28.3% |
| Lead ใหม่ (Facebook) | 0 | เริ่มมี |
**สรุป:** ใช้งบน้อยลงเกือบ 30% แต่คนเห็นโฆษณาเกือบ 5 เท่า และคนคลิกเพิ่มขึ้น 2 เท่า
## เคสเกือบพัง (เรียนรู้จากงานอื่น)
ในเคสอื่น ๆ เราเคยยิงโฆษณาไปกลุ่ม "คนสนใจเรื่องการเงิน" เพราะคิดว่าสินค้าลูกค้าเกี่ยวกับการลงทุน — ผลคือมีแต่คนมาขอกู้เงิน เพราะเข้าใจว่าลูกค้าเราเป็นสถาบันการเงิน
**บทเรียน:** การเลือกกลุ่มเป้าหมายต้องดู "คนที่จะซื้อ" ไม่ใช่ "คนที่คลิกง่าย"
## เว็บไซต์
[erp.dataroot.asia](https://erp.dataroot.asia) — เว็บปัจจุบันของ Dataroot

View File

@@ -1,12 +0,0 @@
---
name: "Jet Industries"
url: "https://jetindustries.co.th"
category: "webdev"
category_label: "Website Development"
industry: "โรงงาน / B2B"
what_we_did: "ออกแบบ + พัฒนาเว็บไซต์ B2B ทันสมัย"
result: "เว็บไซต์ที่สื่อสารตรงกับกลุ่มลูกค้า B2B สมัครใช้งานง่ายขึ้น"
thumbnail: "/images/portfolio/jetindustries.png"
featured: true
order: 18
---

View File

@@ -1,12 +0,0 @@
---
name: "สำนักงานกฎหมาย ตถาตา"
url: "https://lawyernoom.com"
category: "webdev"
category_label: "Website Development"
industry: "สำนักงานกฎหมาย"
what_we_did: "ออกแบบเว็บไซต์สำนักงานกฎหมาย น่าเชื่อถือ + SEO ท้องถิ่น"
result: "เว็บไซต์มืออาชีพที่สร้างความเชื่อมั่นให้ลูกความ"
thumbnail: "/images/portfolio/lawyernoom.png"
featured: true
order: 17
---

View File

@@ -1,12 +0,0 @@
---
name: "เลือดจระเข้วานิไทย"
url: "https://เลือดจระเข้วานิไทย.com"
category: "consult, webdev"
category_label: "Consult + Website Development"
industry: "สินค้าอุปโภค / สุขภาพ"
what_we_did: "พัฒนาเว็บไซต์ร้านค้าสมุนไพรและผลิตภัณฑ์เพื่อสุขภาพ"
result: "เว็บไซต์ร้านค้าออนไลน์สำหรับผลิตภัณฑ์สุขภาพ"
thumbnail: "/images/portfolio/luadjob.png"
featured: true
order: 16
---

View File

@@ -1,12 +0,0 @@
---
name: "Lungfinler"
url: "https://lungfinler.com"
category: "webdev"
category_label: "Website Development"
industry: "Digital Agency"
what_we_did: "ออกแบบ + พัฒนาเว็บไซต์เอเจนซี่ดิจิตอล พร้อมระบบ Portfolio และ Blog"
result: "เว็บไซต์เอเจนซี่ครบวงจร แสดงผลงานได้สวยงาม"
thumbnail: "/images/portfolio/lungfinler.png"
featured: true
order: 15
---

View File

@@ -1,12 +0,0 @@
---
name: "เทรนเนอร์ซันนี่"
url: "https://trainersunny.com"
category: "webdev"
category_label: "Website Development"
industry: "Personal Brand / การศึกษา"
what_we_did: "พัฒนาเว็บไซต์อบรมสัมมนาพัฒนาศักยภาพบุคลากร พร้อมระบบลงทะเบียน"
result: "เว็บไซต์อบรมที่ดูมืออาชีพ เพิ่มความน่าเชื่อถือ"
thumbnail: "/images/portfolio/trainersunny.png"
featured: true
order: 13
---

View File

@@ -1,12 +0,0 @@
---
name: "ทวนทอง 99"
url: "https://tuanthong99.com"
category: "webdev"
category_label: "Website Development"
industry: "สินค้าอุปโภคบริโภค"
what_we_did: "พัฒนาเว็บไซต์ขายของออนไลน์ + ระบบตะกร้า + จัดการสินค้าด้วยตัวเอง"
result: "เว็บไซต์ขายสินค้าอุปโภคบริโภค ดูแลเองได้ สะดวกรวดเร็ว"
thumbnail: "/images/portfolio/tuanthong.png"
featured: true
order: 11
---

View File

@@ -1,12 +0,0 @@
---
name: "Underdog Marketing"
url: "https://underdog.run"
category: "webdev"
category_label: "Website Development"
industry: "Marketing Agency"
what_we_did: "พัฒนาเว็บไซต์บล็อกบทความการตลาด พร้อมระบบ CMS จัดการเนื้อหา"
result: "แพลตฟอร์มบทความการตลาดที่ใช้งานง่าย SEO Friendly"
thumbnail: "/images/portfolio/underdog.png"
featured: true
order: 12
---

View File

@@ -1,18 +0,0 @@
---
name: "Astro"
tier: "แนะนำ"
amount: "฿5,000"
period: "starter"
is_featured: true
order: 1
features:
- "Responsive design (มือถือ + เดสก์ท็อป)"
- "SEO + GEO (ติด Google + ChatGPT/Perplexity)"
- "AI ช่วยสร้างเนื้อหา"
- "Server + SSL ฟรีปีแรก"
- "แก้ไขเนื้อหาฟรีตลอดอายุ Server"
---
# Astro Website (แนะนำ)
เว็บไซต์ที่ขายได้ ไม่ใช่เว็บที่สวย — เริ่มต้น 5,000 บาท พร้อม SEO + AI ช่วยเขียนเนื้อหา

View File

@@ -1,18 +0,0 @@
---
name: "WordPress"
tier: "ขั้นสูง"
amount: "฿30,000"
period: "advanced"
is_featured: false
order: 2
features:
- "ไม่จำกัดจำนวนหน้า"
- "ตะกร้า + ชำระเงิน (WooCommerce)"
- "Plugin + Theme ตามต้องการ"
- "หลังบ้านใช้ง่าย ไม่ต้องเขียนโค้ด"
- "Server + SSL ฟรีปีแรก"
---
# WordPress Website
เว็บไซต์ E-commerce หรือเว็บที่ต้องการ Plugin เยอะ — เริ่มต้น 30,000 บาท

View File

@@ -1,72 +0,0 @@
---
title: "AI Consult"
subtitle: "AI ที่ใช้ในองค์กร เน้นความคุ้มค่าและรักษาความลับ"
badge: "ที่ปรึกษาด้าน AI"
category: "tech-consult"
objective: "รักษาความรู้ขององค์กร"
short_desc: "เก็บความรู้และประสบการณ์ของพนักงานให้อยู่กับองค์กร ใช้ Local LLM สำหรับงานที่ต้องการความลับ"
---
# AI Consult
## เราทำ AI แบบนี้
AI ไม่ได้แทนทุกอย่างได้ แต่ถ้ารู้จักใช้ จะประหยัดหรือเปิดโอกาสใหม่ที่คาดไม่ถึง
**เราไม่ได้เลือก AI ที่แพงที่สุดเสมอไป** — งานหลายอย่างใช้ Model ราคาถูกก็ได้ผลเท่า ๆ กัน ช่วยประหยัดค่าใช้จ่ายได้มากกว่าครึ่ง
**เราเน้น Local LLM** สำหรับงานที่ต้องการความลับ — เพราะข้อมูลของลูกค้าเป็นเรื่องสำคัญ
## วัตถุประสงค์หลัก: เก็บความรู้ให้อยู่กับองค์กร (KM)
ถ้าพนักงานลาออกหรือเปลี่ยน พนักงานใหม่ที่เข้ามาจะเรียนรู้งานเองได้ไว ลดการลองผิดลองถูก ทำให้การทำงานไม่สะดุด ลดความผิดพลาดในระยะยาว
องค์กรจะพึ่งพนักงานที่มีความสามารถเฉพาะตัวน้อยลง เพราะข้อมูลการทำงานมีการเก็บเข้าคลังความรู้ตลอด
## AI เปรียบเสมือน "พี่เลี้ยง" ในองค์กร
- **พนักงานใหม่** ถาม AI ได้เลย เหมือนมีพี่เลี้ยงคอยแนะนำ
- **ผู้บริหาร** ถามข้อมูลเชิงลึก หรือตั้งค่าให้ AI รายงานตามเวลา/เหตุการณ์ที่กำหนด
- **ยิ่งพนักงานคุยกับ AI เยอะ** ยิ่งเก็บข้อมูลเชิงลึกได้มาก AI ก็ยิ่งฉลาดขึ้น
## ใช้ AI ตัวไหน? เราเลือกให้เหมาะกับงาน
| ประเภทงาน | AI ที่ใช้ | ทำไม |
|---|---|---|
| ตอบแชท/งานทั่วไป | Model ราคาถูก (Haiku, Mini, local) | ประหยัด ได้ผลพอ |
| วิเคราะห์ข้อมูล/เขียนรายงาน | Model ระดับกลาง | สมดุลระหว่างคุณภาพและราคา |
| งานที่ต้องการความลับ/PDPA | Local LLM | ข้อมูลไม่ออกจากเครื่อง |
| งานเฉพาะทางที่ซับซ้อนมาก | Model ระดับ Frontier | ใช้เฉพาะเมื่อจำเป็น |
## กระบวนการทำงาน
1. **AI Audit (ฟรี)** — วิเคราะห์ว่าธุรกิจควรใช้ AI ตัวไหน ตรงไหน
2. **วาง AI Strategy** — เลือกเครื่องมือ วาง Roadmap การใช้ AI ในองค์กร
3. **พัฒนา + Integrate** — เชื่อม AI เข้ากับ Workflow เดิม
4. **Train + ดูแล** — สอนทีมใช้ ปรับปรุงตามผลตอบรับ
## เมื่อไหร่ที่เหมาะกับเรา
- พนักงานเปลี่ยนบ่อย ความรู้สะสมหาย
- มีข้อมูลเยอะ แต่ใช้ไม่เป็น
- อยากใช้ AI แต่กังวลเรื่องความลับ/PDPA
- อยากลดเวลา Onboard พนักงานใหม่
- ผู้บริหารอยากได้ AI เหมือนเลขาส่วนตัว
## เมื่อไหร่ที่ไม่เหมาะ
- แค่อยากลองเล่น ChatGPT — ไม่ต้องจ้างเรา ใช้เองได้เลย
- คิดว่า AI แทนพนักงานได้ทุกอย่าง — ยังทำไม่ได้ AI เป็นเครื่องมือ ไม่ใช่คน
- มีข้อมูลน้อยมาก AI เรียนรู้ไม่ได้
## ตัวอย่างงาน
ดูตัวอย่างงานจริงทั้งหมดได้ที่หน้า Portfolio
## สิ่งที่กำลังทดลอง
- ระบบ Harness และ AI Memory ใหม่ ๆ
- Model ที่ถูกกว่า เพื่อให้ได้ผลลัพธ์ใกล้เคียง Model แพง
- รูปแบบการตลาดใหม่ ๆ เช่น SEO กับ GEO ในยุค AI
- ความเสี่ยงที่คนจะเชื่อ AI จนไม่สนใจว่าข้อมูลถูกหรือผิด — เรื่องนี้สำคัญ
- ช่องทางการขายใหม่ ๆ ที่นอกเหนือจากที่คนส่วนใหญ่ใช้

View File

@@ -1,79 +0,0 @@
---
title: "AI Consult"
subtitle: "Consult service for using AI to improve business workflow and knowledge management. ใช้ AI ให้เป็นประโยชน์สำหรับธุรกิจของคุณอย่างเต็มศักยภาพ"
badge: "Technology Consult"
category: "tech-consult"
objective: "ลดต้นทุนและเวลา"
usp_free_server: "ลูกค้าที่ใช้บริการ Consult จะได้รับ Server สำหรับ App และ AI ฟรี (สำหรับการใช้งานปกติ) หากต้องการใช้งานหนักหรือ Resource-intensive จะมีค่าใช้จ่ายเพิ่มเติม"
# Hero Section
hero_badge: "บริการ AI Consult ครบวงจร"
hero_title: "ใช้ AI ให้เป็นประโยชน์<br/><span class='highlight'>สำหรับธุรกิจของคุณ</span>"
hero_desc: "วางแผน AI Strategy, Chatbot ภาษาไทย, ระบบ Knowledge Management, AI วิเคราะห์ข้อมูล พร้อม AI Audit ฟรี"
# Why Choose Us
why_title: "ทำไมต้อง<span class='highlight'>AI?</span>"
why_desc: "AI ช่วยให้ธุรกิจทำงานได้เร็วขึ้น ลดต้นทุน และเพิ่มประสิทธิภาพในการบริการลูกค้า"
# What's Included
included_title: "AI ที่เราช่วยได้"
included_items:
- icon: "🤖"
title: "AI Chatbot"
desc: "Chatbot ภาษาไทย ตอบคำถามลูกค้า 24/7"
- icon: "📝"
title: "Knowledge Base"
desc: "ระบบจัดการความรู้ ค้นหาข้อมูลง่าย"
- icon: "📊"
title: "AI Analytics"
desc: "วิเคราะห์ข้อมูลและให้คำแนะนำ"
- icon: "🔍"
title: "AI Audit"
desc: "วิเคราะห์ว่าธุรกิจควรใช้ AI ตัวไหน"
# Target Audience
target_title: "เหมาะกับใคร?"
target_items:
- icon: "🏢"
title: "SME / ธุรกิจขนาดเล็ก"
desc: "ต้องการเริ่มต้นใช้ AI ในธุรกิจ"
- icon: "🏗️"
title: "บริษัท / องค์กร"
desc: "ต้องการนำ AI มาใช้ในการทำงาน"
- icon: "👥"
title: "ฝ่ายบริการลูกค้า"
desc: "ต้องการลดภาระงานฝ่ายบริการลูกค้า"
# FAQ
faq_title: "คำถาม<span class='highlight'>ที่พบบ่อย</span>"
faq_items:
- q: "AI ทำอะไรได้บ้างสำหรับธุรกิจ?"
a: "AI สามารถช่วยได้หลายอย่าง เช่น ตอบคำถามลูกค้าอัตโนมัติ วิเคราะห์ข้อมูล สร้างเนื้อหา จัดการข้อมูล ทำรายงาน และอื่น ๆ ขึ้นอยู่กับความต้องการของธุรกิจ"
- q: "ต้องมีความรู้ด้านเทคนิคไหม?"
a: "ไม่ต้องมีความรู้ด้านเทคนิคเลย เราดูแลทุกอย่างตั้งแต่ต้นจนจบ ตั้งแต่การวิเคราะห์ ออกแบบ พัฒนา ไปจนถึงการ deploy และดูแลหลังขาย"
- q: "AI ทำงานได้ภาษาไทยไหม?"
a: "ได้ เราใช้ AI ที่รองรับภาษาไทย รวมถึง Chatbot ที่เข้าใจภาษาไทยและสามารถตอบคำถามได้อย่างเป็นธรรมชาติ"
- q: "มีค่าใช้จ่ายเพิ่มเติมอะไรไหม?"
a: "ค่าบริการ Server สำหรับ AI ฟรีสำหรับการใช้งานปกติ หากต้องการใช้งานหนักหรือ Resource-intensive จะมีค่าใช้จ่ายเพิ่มเติม"
---
# Features
feature1_icon: "🧠"
feature1_title: "AI Strategy & Roadmap"
feature1_desc: "วางแผนการใช้ AI อย่างเป็นระบบเพื่อให้เห็นผลลัพธ์ที่ชัดเจน"
feature2_icon: "💬"
feature2_title: "AI Chatbot Implementation"
feature3_desc: "พัฒนาและ deploy AI Chatbot ที่เข้าใจภาษาไทยและตอบคำถามลูกค้าได้ 24/7"
feature3_icon: "📝"
feature3_title: "Knowledge Management"
feature3_desc: "สร้างระบบจัดการความรู้ด้วย AI ที่ช่วยให้การค้นหาและใช้งานข้อมูลง่ายขึ้น"
feature4_icon: "🎯"
feature4_title: "AI for Marketing"
feature4_desc: "ใช้ AI วิเคราะห์ลูกค้าและสร้างแคมเปญการตลาดที่มีประสิทธิภาพ"
feature5_icon: "🔍"
feature5_title: "AI Audit"
feature5_desc: "วิเคราะห์ว่าธุรกิจของคุณควรใช้ AI ตัวไหนและอย่างไร"
feature6_icon: "🚀"
feature6_title: "AI Implementation Support"
feature6_desc: "ดูแลและให้คำปรึกษาตลอดการ implement AI ในองค์กร"
---

View File

@@ -1,75 +0,0 @@
---
title: "Automation Consult"
subtitle: "ระบบอัตโนมัติที่ออกแบบเฉพาะธุรกิจคุณ ไม่ใช่ใช้ของสำเร็จรูป"
badge: "วางระบบ Automation"
category: "tech-consult"
objective: "ลดต้นทุนและเวลา"
short_desc: "เลือกเครื่องมือที่เหมาะกับงาน — n8n, Script เฉพาะทาง, หรือ AI วิเคราะห์"
---
# Automation Consult
## เราทำ Automation แบบนี้
เริ่มจากดู Workflow ปัจจุบันของคุณก่อน แล้วถามว่า "ขั้นตอนไหนที่ซ้ำ ทำมือ แล้วเสียเวลา"
แล้วค่อยเลือกเครื่องมือที่เหมาะ — ไม่ใช่ทุกงานต้องใช้เครื่องมือเดียวกัน
- **งานบางอย่าง** ใช้ n8n (Workflow automation)
- **งานบางอย่าง** เขียน Script เฉพาะทาง
- **งานบางอย่าง** ใช้ AI วิเคราะห์หรือตัดสินใจ
- **งานบางอย่าง** ใช้ทั้ง 3 อย่างผสมกัน
## บริการนี้เหมือนได้ AI Developer มาใช้
เราไม่ได้เขียนแอปทั้งแอป เราโฟกัสที่ **งานเฉพาะจุดที่ Developer ปกติไม่อยากทำ** — แต่เป็นงานที่กินเวลาทีมเยอะ
## กระบวนการทำงาน
1. **รับ Requirement + ศึกษา Workflow (1-2 สัปดาห์)** — ดูว่างานไหนทำซ้ำ ตรงไหนคอขวด
2. **เลือกเครื่องมือ + ออกแบบ (1-2 สัปดาห์)** — เลือก Tool ที่เหมาะ วางแผนว่าจะเชื่อมต่อระบบอะไร
3. **พัฒนา + ทดสอบ (2-6 สัปดาห์)** — พัฒนาแบบ Sprint ส่ง Demo ให้ทดสอบ
4. **Deploy + ดูแล (ต่อเนื่อง)** — ติดตั้งจริง สอนทีมใช้ ดูแลต่อ
## ประเภทงานที่ทำ
### งานเชื่อมต่อระบบ
- เชื่อม POS + บัญชี + สต็อก เข้าด้วยกัน
- เชื่อม CRM + Email + LINE OA
- เชื่อม Excel/Google Sheets กับระบบภายใน
### งาน Automate รายงาน
- รายงานยอดขายรายวัน/สัปดาห์/เดือน
- แจ้งเตือนอัตโนมัติเมื่อตัวเลขผิดปกติ
- ดึงข้อมูลจากหลายแหล่งมารวมในที่เดียว
### งาน Automate การสื่อสาร
- Chatbot LINE OA ตอบคำถามซ้ำ
- ตอบ DM อัตโนมัติ
- แจ้งเตือนลูกค้า/ทีม ตามเงื่อนไข
### งานเฉพาะทาง
- เขียน Script สำหรับงานเฉพาะของธุรกิจ
- AI วิเคราะห์ข้อมูล/รูปภาพ
- ระบบจอง/คิว/นัดหมาย
## เมื่อไหร่ที่เหมาะกับเรา
- ทีมเสียเวลากับงานซ้ำ ๆ เป็นชั่วโมงทุกวัน
- มีระบบหลายตัวที่ไม่คุยกัน
- อยากลดเวลาในการทำรายงาน/ตอบแชตซ้ำ
- มี Workflow ที่ชัดเจน แต่ขาดคนมาทำให้อัตโนมัติ
## เมื่อไหร่ที่ไม่เหมาะ
- Workflow ยังไม่ชัด ยังเปลี่ยนบ่อย — รอให้นิ่งก่อนแล้วค่อย Automate
- อยากได้ระบบใหม่ทั้งหมด — เราเชี่ยว Automate ของเดิม ไม่ใช่สร้างแอปทั้งแอป
- งานที่ต้องใช้ดุลยพินิจคนเยอะ ๆ — AI ยังทำแทนไม่ได้ทุกเรื่อง
## ตัวอย่างงาน
ดูตัวอย่างงานจริงทั้งหมดได้ที่หน้า Portfolio — มีเคสหลากหลายตั้งแต่คลินิก ร้านอาหาร สถานศึกษา ไปจนถึงที่ปรึกษา

View File

@@ -1,61 +0,0 @@
---
title: "Automation Consult"
subtitle: "Implement specific unique app and AI for business to do automation workflow. ลดต้นทุนและเพิ่มประสิทธิภาพด้วยระบบอัตโนมัติที่ออกแบบมาเฉพาะสำหรับธุรกิจของคุณ"
badge: "Technology Consult"
category: "tech-consult"
objective: "ลดต้นทุนและเวลา"
usp_free_server: "ลูกค้าที่ใช้บริการ Consult จะได้รับ Server สำหรับ App และ AI ฟรี (สำหรับการใช้งานปกติ) หากต้องการใช้งานหนักหรือ Resource-intensive จะมีค่าใช้จ่ายเพิ่มเติม"
# Hero Section
hero_badge: "บริการ AI Automation ครบวงจร"
hero_title: "ระบบเชื่อมข้อมูล<br/><span class='highlight'>วิเคราะห์ด้วย AI</span>"
hero_desc: "เชื่อมข้อมูลจากหลายแอปเข้าด้วยกัน วิเคราะห์ข้อมูล สร้างรายงาน แจ้งเตือนอัตโนมัติ พร้อม Chatbot ภายในองค์กร"
# Why Choose Us
why_title: "ทำไมต้อง<span class='highlight'>Automation?</span>"
why_desc: "AI Automation ช่วยลดงานที่ทำซ้ำ ๆ ประหยัดเวลาและลดข้อผิดพลาดจากงาน manual"
# Target Audience
target_title: "เหมาะกับใคร?"
target_items:
- icon: "🏢"
title: "SME / ธุรกิจขนาดเล็ก"
desc: "ต้องการเชื่อมข้อมูลจากหลายแหล่งเข้าด้วยกัน ลดงาน manual"
- icon: "👥"
title: "ทีมขาย / การตลาด"
desc: "ต้องการวิเคราะห์ข้อมูลลูกค้า สร้างรายงานอัตโนมัติ"
- icon: "📋"
title: "ฝ่ายบัญชี / การเงิน"
desc: "ต้องการเชื่อมข้อมูลบัญชี สร้างรายงานทางการเงินอัตโนมัติ"
# FAQ
faq_title: "คำถาม<span class='highlight'>ที่พบบ่อย</span>"
faq_items:
- q: "AI Automation ต่างจาก Marketing Automation อย่างไร?"
a: "AI Automation เน้นการทำ automation ภายในองค์กร เช่น ระบบเชื่อมข้อมูล วิเคราะห์ข้อมูล สร้างรายงาน ตอบคำถามภายใน ส่วน Marketing Automation เน้นการทำ automation ภายนอก เช่น การตลาดผ่าน Website, Social Media, Ads"
- q: "ต้องมีความรู้ด้านเทคนิคไหม?"
a: "ไม่ต้องมีความรู้ด้านเทคนิคเลย เราดูแลทุกอย่างตั้งแต่ต้นจนจบ"
- q: "ระบบที่มีอยู่แล้วเชื่อมได้ไหม?"
a: "ได้ เราสามารถเชื่อมต่อระบบที่มีอยู่เข้ากับ AI ได้ ไม่ว่าจะเป็น Excel, Google Sheets, CRM, ERP หรือระบบอื่น ๆ"
---
# Features
feature1_icon: "🤖"
feature1_title: "Workflow Automation"
feature1_desc: "ออกแบบและ implement ระบบ automation สำหรับงานที่ทำซ้ำๆ เช่น การประมวลผลออร์เดอร์ การจัดการ inventory"
feature2_icon: "📊"
feature2_title: "Business Process Optimization"
feature2_desc: "วิเคราะห์และปรับปรุงกระบวนการทำงานให้มีประสิทธิภาพมากขึ้นด้วยเทคโนโลยีล่าสุด"
feature3_icon: "🔗"
feature3_title: "System Integration"
feature3_desc: "เชื่อมต่อระบบต่างๆ ให้ทำงานร่วมกันอย่างราบรื่น เช่น CRM, ERP, E-commerce"
feature4_icon: "📱"
feature4_title: "Custom Application"
feature4_desc: "พัฒนา application เฉพาะทางสำหรับธุรกิจของคุณที่ไม่สามารถหาซื้อได้ทั่วไป"
feature5_icon: "🔒"
feature5_title: "Security & Compliance"
feature5_desc: "ตรวจสอบและปรับปรุงความปลอดภัยของระบบให้เป็นไปตามมาตรฐาน"
feature6_icon: "📈"
feature6_title: "Performance Monitoring"
feature6_desc: "ติดตามและวัดผลประสิทธิภาพของระบบแบบ real-time"
---

View File

@@ -1,61 +0,0 @@
---
title: "Online Marketing Consult"
subtitle: "วางกลยุทธ์จากข้อมูล ไม่ใช่จากประสบการณ์ล้วน ๆ"
badge: "ที่ปรึกษาการตลาดออนไลน์"
category: "marketing"
objective: "เพิ่มยอดขาย"
short_desc: "ดูสถิติก่อนยิงโฆษณา — เลือก Platform ที่คุ้ม ตัดอันที่เสียเงินเปล่า"
---
# Marketing Consult
## เราทำการตลาดแบบนี้
เราไม่ได้เริ่มจากอยากยิงโฆษณาอะไร เราเริ่มจากดูข้อมูลของลูกค้าก่อน — สถิติคนเข้าเว็บ สถิติคนคลิกโฆษณา ยอดขายแยกตามสินค้าและกลุ่มลูกค้า
แล้วค่อยวางกลยุทธ์ว่าจะยิงที่ไหน ใช้ Creative แบบไหน เจาะกลุ่มเป้าหมายใคร
**กลยุทธ์ของเราไม่ได้จำกัดอยู่แค่เว็บ Social Media หรือโฆษณา** — เรามองภาพรวมและวางแผนในทุกช่องทางให้สอดคล้องกัน เลือกช่องทางที่เหมาะกับสินค้าและกลุ่มเป้าหมายจริง ๆ
## กระบวนการทำงาน
1. **ตั้งระบบเก็บข้อมูล (1-2 สัปดาห์)** — GA4, Meta Pixel, ระบบแยกยอดขายตามสินค้า/กลุ่มสินค้า/กลุ่มลูกค้า (ถ้าทำได้)
2. **วิเคราะห์ + วางกลยุทธ์ (1-2 สัปดาห์)** — ดูว่าสินค้าไหนขายดี กลุ่มไหนซื้อ ช่องทางไหนคุ้ม → เขียนแผนกลยุทธ์
3. **ลงมือ + วัดผล (ต่อเนื่อง)** — ปรับ Creative, ปรับกลุ่มเป้าหมาย, ขยาย/ตัดช่องทาง พร้อมดูตัวเลขทุกสัปดาห์
4. **สอนทีม (ต่อเนื่อง)** — ถ้าทีมลูกค้าขาดความรู้ในเรื่องใด เราจะสอนเสริมให้ เพื่อให้ทำต่อได้ด้วยตัวเอง
## สิ่งที่เราทำ
- **วางแผนกลยุทธ์ช่องทาง** — เลือก Platform ที่เหมาะกับสินค้า ไม่ใช่ยิงทุกที่
- **เจาะกลุ่มเป้าหมาย** — ดูข้อมูลว่าใครซื้อจริง ไม่ใช่ใครคลิกง่าย
- **ปรับ Creative + Copy** — ให้ดึงดูดคนที่พร้อมจ่าย ไม่ใช่คนที่เทียบราคา
- **ปรับ Funnel** — ให้คนเข้ามาแล้วเดินต่อจนซื้อ
- **วัดผล + รายงาน** — ตัวเลขจริง ไม่ใช่ "ยอดดีขึ้น" แบบกำกวม
## เมื่อไหร่ที่เหมาะกับเรา
- มีเว็บไซต์และกิจกรรมออนไลน์อยู่แล้ว แต่ยอดไม่โต
- อยากเปลี่ยนจาก "ยิงแล้วหวัง" เป็น "ยิงแล้วรู้ว่าเกิดอะไรขึ้น"
- อยากให้ทีมเรียนรู้ไปด้วย ไม่ใช่จ้างเราตลอด
## เมื่อไหร่ที่ไม่เหมาะ
- งบน้อยมาก ไม่พอจะยิงโฆษณาเลย — เริ่มจาก SEO/Content ดีกว่า
- อยากได้ผลใน 1 สัปดาห์ — เราเน้นงานที่ยั่งยืน ไม่ใช่แค่ยิงให้ขายได้แล้วหยุด
- คิดว่า "ยิงเยอะ ๆ แล้วจะขายได้เอง" — ไม่จริงเสมอไป บางทียิงน้อยแต่ตรงกลุ่มดีกว่า
## ตัวอย่างงาน
- **Dataroot** (Flagship) — เพิ่ม Impression 373%, Click 114.2%, ลดงบโฆษณา 28.3% ในเดือนแรก — ดูเคสเต็มได้ที่หน้า Portfolio
ดูตัวอย่างงานจริงอื่น ๆ ทั้งหมดได้ที่หน้า Portfolio
## บทเรียนจากเคสที่เกือบพัง
เคยยิงโฆษณาไปกลุ่ม "คนสนใจเรื่องการเงิน" เพราะคิดว่าสินค้าลูกค้าเกี่ยวกับการลงทุน — ผลคือมีแต่คนมาขอกู้เงิน เพราะเข้าใจว่าลูกค้าเราเป็นสถาบันการเงิน
**บทเรียน:** เลือกกลุ่มเป้าหมายต้องดู "คนที่จะซื้อ" ไม่ใช่ "คนที่คลิกง่าย"
อีกเคส — ขายสินค้าบน Platform โดยไม่ได้คำนวณค่าธรรมเนียมแฝง (ค่าธรรมเนียม Platform, ค่าจัดส่ง, ค่าคืนสินค้า, ส่วนลด) ขายได้เยอะ แต่กำไรหายเกือบหมด
**บทเรียน:** ขายดี ≠ มีกำไร ต้องคำนวณต้นทุนแท้จริงก่อนวางแผน

View File

@@ -1,80 +0,0 @@
---
title: "Online Marketing Automation"
subtitle: "Use AI to help generate and manage marketing workflow. เพิ่มยอดขายด้วยระบบอัตโนมัติทางการตลาดที่ขับเคลื่อนด้วย AI"
badge: "Marketing Consult"
category: "marketing-consult"
objective: "เพิ่มยอดขาย"
# Hero Section
hero_badge: "บริการ Marketing Automation ครบวงจร"
hero_title: "การตลาดอัตโนมัติ<br/><span class='highlight'>ทุกช่องทาง</span><br/>พร้อม AI วิเคราะห์"
hero_desc: "ส่งข้อความอัตโนมัติ วิเคราะห์ข้อมูล SEO ติด Google ครอบคลุม Website, Social Media, Ads และ Email + GEO ติด ChatGPT, Perplexity, AI Search"
# Why Choose Us
why_title: "ทำไมต้อง<span class='highlight'>Marketing Automation?</span>"
why_desc: "ช่วยให้การตลาดเป็นอัตโนมัติ ประหยัดเวลา และเพิ่มประสิทธิภาพการขาย"
# What's Included
included_title: "ครอบคลุม<span class='highlight'>ทุกช่องทาง</span>"
included_items:
- icon: "🌐"
title: "Website + SEO"
desc: "เว็บไซต์ที่ติด Google และ AI Search พร้อมระบบจัดการเนื้อหา"
- icon: "📱"
title: "Social Media"
desc: "Facebook, LINE, IG อัตโนมัติ ส่งข้อความตรงกลุ่มเป้าหมาย"
- icon: "📊"
title: "Google Ads"
desc: "ควบคุมงบโฆษณา วิเคราะห์ผล เพิ่มประสิทธิภาพ ROI"
- icon: "📧"
title: "Email Marketing"
desc: "ส่งอีเมลอัตโนมัติ ติดตามลูกค้า ส่งโปรโมชั่นตรงเวลา"
# Target Audience
target_title: "เหมาะกับใคร?"
target_items:
- icon: "🏢"
title: "SME / ร้านค้าปลีก"
desc: "ธุรกิจท้องถิ่นที่ต้องการเพิ่มยอดขายออนไลน์"
- icon: "🛒"
title: "ร้านค้าออนไลน์"
desc: "E-commerce ที่ต้องการบริหารการตลาดอัตโนมัติ"
- icon: "🏗️"
title: "บริษัท / องค์กร"
desc: "บริษัทที่ต้องการระบบการตลาดที่มีประสิทธิภาพ"
# FAQ
faq_title: "คำถาม<span class='highlight'>ที่พบบ่อย</span>"
faq_items:
- q: "Marketing Automation ต่างจาก AI Automation อย่างไร?"
a: "AI Automation เน้นการทำ automation ภายในองค์กร เช่น ระบบตอบคำถาม การประมวลผลข้อมูล Marketing Automation เน้นการทำ automation ภายนอกองค์กร เช่น การตลาดผ่าน Website, Social Media, Ads, Email"
- q: "ราคารวมค่าโฆษณาด้วยไหม?"
a: "ไม่รวมค่าโฆษณา ลูกค้าเป็นเจ้าของบัญชีโฆษณาเองและจ่ายค่าโฆษณาแยกต่างหาก เราเป็นเพียง Agency ที่เข้าไปบริหารจัดการให้"
- q: "ต้องมีความรู้ด้านเทคนิคไหม?"
a: "ไม่ต้องมีความรู้ด้านเทคนิคเลย เราดูแลทุกอย่างตั้งแต่ต้นจนจบ คุณเพียงแค่ให้ข้อมูลและดูผลลัพธ์"
- q: "AI วิเคราะห์อะไรบ้าง?"
a: "AI วิเคราะห์พฤติกรรมลูกค้า หาช่องว่างทางการตลาด และนำเสนอวิธีปรับปรุง วิเคราะห์ผลแคมเปญ และอื่น ๆ ตามความเหมาะสม"
- q: "GEO คืออะไร?"
a: "GEO (Generative Engine Optimization) คือการปรับแต่งเนื้อหาให้ถูกอ้างอิงโดย AI Search Engine เช่น ChatGPT, Perplexity, Google AI Overviews ทำให้ธุรกิจของคุณปรากฏในคำตอบของ AI"
---
# Features
feature1_icon: "📧"
feature1_title: "Email Marketing Automation"
feature1_desc: "สร้าง email campaign อัตโนมัติด้วย AI ที่ personalize ข้อความตามพฤติกรรมลูกค้า"
feature2_icon: "💬"
feature2_title: "Social Media Automation"
feature2_desc: "กำหนดเวลาโพสต์และตอบสนองอัตโนมัติด้วย AI ที่เข้าใจบริบท"
feature3_icon: "🎯"
feature3_title: "Lead Generation AI"
feature3_desc: "ใช้ AI หาและให้คะแนน leads ที่มีโอกาส conversion สูงสุด"
feature4_icon: "📊"
feature4_title: "Marketing Analytics"
feature4_desc: "วิเคราะห์ข้อมูลการตลาดและให้คำแนะนำด้วย AI เพื่อปรับปรุง ROI"
feature5_icon: "🔄"
feature5_title: "Workflow Automation"
feature5_desc: "สร้าง marketing workflow อัตโนมัติตั้งแต่ lead จนถึง sale"
feature6_icon: "📱"
feature6_title: "Multi-channel Integration"
feature6_desc: "เชื่อมต่อทุกช่องทางการตลาดให้ทำงานร่วมกันอย่างไร้รอยต่อ"
---

View File

@@ -1,81 +0,0 @@
---
title: "Website Development"
subtitle: "เว็บไซต์ที่ขายได้ ไม่ใช่เว็บที่สวย"
badge: "พัฒนาเว็บไซต์"
category: "webdev"
objective: "ทำเว็บให้ขายได้"
short_desc: "เว็บไซต์ที่ออกแบบมาเพื่อให้คนซื้อ ไม่ใช่เพื่อให้คนชอบ — Astro สำหรับเว็บทั่วไป, WordPress สำหรับ E-commerce"
# ไม่ได้อยู่ใน Astro case study เพราะเป็น static frontmatter
---
# Website Development
## เราทำเว็บแบบนี้
เริ่มจากถามว่า "เว็บนี้ทำเพื่ออะไร" ก่อน — ขายของ? เก็บ Lead? สร้างความน่าเชื่อถือ? เพราะเว็บแต่ละแบบต้องออกแบบต่างกัน
เราไม่ได้เน้นให้เว็บสวย เราเน้นให้เว็บทำหน้าที่ของมันได้ เพราะเว็บหลายเว็บที่ดูดีที่สุด ขายแย่ที่สุดก็มี
## เลือกระบบตามงาน
### Astro — เว็บทั่วไป, Blog, เว็บบริษัท, Landing Page
**เหมาะกับ:** เว็บที่ไม่ซับซ้อน เน้นความเร็ว SEO และการโหลดเร็ว
**ระยะเวลา:** 14-30 วัน
**ได้อะไร:**
- เว็บไซต์ที่โหลดเร็วมาก (Google PageSpeed 90+)
- SEO พร้อมตั้งแต่วันแรก — ติด Google ได้เร็ว
- Chatbot AI ที่ปรับแก้เว็บไซต์ได้เอง (เฉพาะเว็บที่ใช้ Host ของเรา)
- ระบบแก้ไขเนื้อหาด้วย AI — คุยกับ AI ให้ช่วยเขียน/แก้บทความ
### WordPress — E-commerce, เว็บที่มีระบบหลังบ้านซับซ้อน
**เหมาะกับ:** เว็บที่ต้องมี Database เยอะ ระบบซับซ้อน หรือมี Design มาให้แล้ว
**ระยะเวลา:** 2-4 เดือน
**ได้อะไร:**
- ระบบหลังบ้านที่ลูกค้าแก้เองได้ (เพิ่มสินค้า แก้รูป เขียนบทความ)
- E-commerce ครบชุด (ตะกร้า, ชำระเงิน, ติดตามพัสดุ)
- Plugin เสริมได้ตามต้องการ
## กระบวนการทำงาน
1. **คุย Requirement (1-2 วัน)** — ถามว่าเว็บนี้ต้องทำอะไร ใครเป็นคนใช้ เน้นเรื่องอะไร
2. **วางโครง + ออกแบบ (3-7 วัน)** — ส่ง Proposal โครงสร้างเว็บ + Mockup ให้ดูก่อนเซ็น
3. **พัฒนา (10-20 วัน)** — ส่ง Demo ให้ดูทุกสัปดาห์ ไม่ใช่ส่งทีเดียวตอนจบ
4. **ทดสอบ + แก้ไข (3-5 วัน)** — ทดสอบจริง แก้ตามฟีดแบ็ค
5. **ส่งมอบ + อบรม (1 วัน)** — ส่งมอบ + สอนใช้งาน + มอบคู่มือ
## เมื่อไหร่ที่เหมาะกับเรา
- เว็บที่ต้องโหลดเร็ว ติด Google ง่าย
- เว็บที่ลูกค้าต้องแก้เนื้อหาเองได้บ่อย ๆ
- เว็บ E-commerce ที่ต้องการระบบครบ
## เมื่อไหร่ที่ไม่เหมาะ
- ต้องการเว็บ Landing Page ราคาถูก ๆ ไม่กี่พัน — เราไม่ทำ เราเน้นเว็บที่ต้องทำงานจริง
- ต้องการเว็บแบบเดียวกับที่อื่น — เราชอบออกแบบให้เหมาะกับงาน ไม่ใช่ใช้ Template เดียวกับทุกคน
- ต้องการเว็บที่ไม่ต้องดูแลต่อ — เราแนะนำให้มีแพ็คเกจดูแลรายเดือน เพราะเว็บที่ปล่อยทิ้งจะตาย
## ตัวอย่างงาน
ดูตัวอย่างงานจริงทั้งหมดได้ที่หน้า Portfolio
## คำถามที่ลูกค้าถามบ่อย
**แก้เว็บเองยากไหม?**
ไม่ยาก — สำหรับ Astro จะคุยกับ AI ให้ช่วยแก้เนื้อหา ส่วน WordPress มีระบบหลังบ้านใช้งานง่าย เปลี่ยนข้อความ รูป สินค้า ได้ด้วยตัวเอง
**มีค่าใช้จ่ายอะไรเพิ่มไหม?**
ค่า Host + โดเมนฟรีปีแรก ปีถัดไปคิดตามจริง — เริ่มต้น 5,000 บาท/ปี
**ทำเว็บ E-commerce ได้ไหม?**
ได้ ใช้ WordPress + WooCommerce พร้อมระบบชำระเงิน ติดตามพัสดุ ครบ
**GEO คืออะไร?**
Generative Engine Optimization — ปรับเว็บให้ถูกอ้างอิงโดย ChatGPT, Perplexity, Google AI Overviews ทำให้ธุรกิจปรากฏในคำตอบ AI

View File

@@ -1,87 +0,0 @@
---
title: "Website Development"
subtitle: "Implement website for business and integrate the website with marketing workflow. เว็บไซต์ที่ทันสมัย รวดเร็ว และเชื่อมต่อกับระบบการตลาดอย่างไร้รอยต่อ"
badge: "Marketing Consult"
category: "marketing-consult"
objective: "เพิ่มยอดขาย"
usp_content_edit: "ลูกค้าที่ใช้ Server ของเราจะได้รับบริการแก้ไขและเพิ่มเนื้อหาเว็บไซต์ฟรี! จ่ายเฉพาะเมื่อต้องการ Redesign ทั้งหมด หรือ Upgrade ฟีเจอร์ใหญ่ เช่น เพิ่มระบบ E-commerce"
# Hero Section
hero_badge: "บริการรับทำเว็บไซต์สำหรับ SME ไทย"
hero_title: "สร้างเว็บไซต์<br/><span class='highlight'>เปลี่ยนแปลงเองได้</span><br/>ด้วย AI"
hero_desc: "เว็บไซต์ที่คุณแก้ไขเองได้ง่าย ไม่ต้องรอเราทุกครั้ง พร้อม AI ช่วยสร้างเนื้อหาใหม่ ๆ ให้ทันที + GEO ติด ChatGPT, Perplexity, AI Search"
# Why Choose Us
why_title: "เว็บไซต์ที่<br/><span class='highlight'>คุณจัดการเองได้</span>"
why_desc: "เราสร้างเว็บไซต์ให้คุณสามารถจัดการเองได้ ไม่ต้องพึ่งเราทุกครั้ง ระบบหลังบ้านใช้ง่าย เปลี่ยนข้อความ รูปภาพ สินค้า ได้ด้วยตัวเอง"
# What's Included
included_title: "ทุกเว็บไซต์มาพร้อม<br/><span class='highlight'>ให้ครบ</span>"
included_items:
- "เว็บไซต์พร้อมใช้งาน"
- "SSL ฟรี"
- "โดเมน"
- "Analytics"
# Target Audience
target_title: "ธุรกิจทุกประเภท"
target_items:
- icon: "🏢"
title: "SME / ธุรกิจขนาดเล็ก"
desc: "ธุรกิจท้องถิ่น ร้านค้าปลีก บริการต่าง ๆ ที่ต้องการเว็บไซต์ในราคาที่เข้าถึงได้"
- icon: "🛒"
title: "ร้านค้าออนไลน์"
desc: "ธุรกิจ E-commerce ที่ต้องการขายสินค้าออนไลน์ พร้อมระบบตะกร้าและชำระเงินครบวงจร"
- icon: "🏗️"
title: "บริษัท / องค์กร"
desc: "บริษัทที่ต้องการเว็บไซต์องค์กร เว็บไซต์แนะนำบริษัท หรือเว็บไซต์ในระบบ Intranet"
# Technology Choice
tech_title: "เลือกระบบที่<span class='highlight'>เหมาะกับคุณ</span>"
tech_options:
- name: "Astro"
badge: "A"
desc: "เหมาะสำหรับเว็บไซต์ทั่วไป / Corporate เน้น AI และ SEO โหลดเร็ว ประสิทธิภาพสูง บล็อก / เว็บบริษัท"
duration: "ระยะเวลา: 14-30 วัน"
- name: "WordPress"
badge: "WP"
desc: "เหมาะสำหรับเว็บขายของ (E-commerce) เว็บไซต์ที่ซับซ้อน มีระบบหลังบ้านซับซ้อน ต้องการ Plugin เยอะ"
duration: "ระยะเวลา: 2-4 เดือน"
# FAQ
faq_title: "คำถาม<span class='highlight'>ที่พบบ่อย</span>"
faq_items:
- q: "แก้ไขเว็บเองยากไหม?"
a: "ไม่ยากเลย สำหรับ Astro การแก้ไขเนื้อหาจะเน้นการคุยกับ AI ให้ช่วยสร้างและปรับแต่งเนื้อหา ส่วน WordPress มาพร้อมระบบหลังบ้านที่มีหน้าตาการใช้งานง่าย คุณสามารถเปลี่ยนข้อความ รูปภาพ สินค้า ได้ด้วยตัวเองโดยไม่ต้องมีความรู้ทางเทคนิค"
- q: "มีค่าใช้จ่ายอะไรเพิ่มเติมไหม?"
a: "ค่าบริการ Server และโดเมนจะฟรีในปีแรก และจะมีค่าใช้จ่ายในปีถัดไป ค่าบริการ Server จะขึ้นอยู่กับความซับซ้อนของเว็บไซต์และจำนวนผู้เข้าชม"
- q: "Server ดูแลให้ไหม?"
a: "เราดูแลเรื่อง Server ให้ครบวงจร รวมถึงการปรับจูนระบบให้มีประสิทธิภาพสูงสุด ลูกค้าจะจ่ายค่า Server เพิ่มเฉพาะกรณีที่มีผู้เข้าเว็บใช้งานสูงมาก ระดับ 100,000 คนต่อเดือนขึ้นไป"
- q: "ทำเว็บขายของ (E-commerce) ได้ไหม?"
a: "ทำได้แน่นอน เราใช้ WordPress เป็นพื้นฐานในการพัฒนาเว็บไซต์ E-commerce พร้อมระบบตะกร้าสินค้า ชำระเงิน ติดตามสินค้า และระบบหลังบ้านจัดการสินค้าครบวงจร"
- q: "ต้องมีความรู้ทางเทคนิคไหม?"
a: "ไม่จำเป็นเลย เราดูแลทุกอย่างตั้งแต่ต้นจนจบ ตั้งแต่การออกแบบ พัฒนา ไปจนถึงการติดตั้งและส่งมอบ พร้อมทั้งอบรมการใช้งานให้ทีมของคุณสามารถใช้งานระบบได้อย่างมั่นใจ"
- q: "GEO คืออะไร?"
a: "GEO (Generative Engine Optimization) คือการปรับแต่งเนื้อหาและโครงสร้างเว็บไซต์ให้ถูกอ้างอิงโดย AI Search Engine เช่น ChatGPT, Perplexity, Google AI Overviews ทำให้ธุรกิจของคุณปรากฏในคำตอบของ AI"
---
# Features
feature1_icon: "⚡"
feature1_title: "Fast & Modern"
feature1_desc: "โหลดเร็ว รองรับการขยายตัวของธุรกิจ และใช้เทคโนโลยีล่าสุด"
feature2_icon: "📱"
feature2_title: "Responsive Design"
feature2_desc: "แสดงผลได้ดีบนทุกอุปกรณ์ ทั้ง mobile tablet และ desktop"
feature3_icon: "🎨"
feature3_title: "SEO Optimized"
feature3_desc: "ออกแบบมาเพื่อให้ Google ชอบ ช่วยให้ติดอันดับได้ง่ายขึ้น"
feature4_icon: "🔗"
feature4_title: "Marketing Integration"
feature4_desc: "เชื่อมต่อกับระบบ CRM, Email Marketing และ Analytics ได้อย่างไร้รอยต่อ"
feature5_icon: "📊"
feature5_title: "Analytics Dashboard"
feature5_desc: "ติดตามผู้เข้าชมและวัดผลได้แบบ real-time"
feature6_icon: "🔒"
feature6_title: "Security"
feature6_desc: "Security ระดับสูง ป้องกันการโจมตีและข้อมูลรั่วไหล"
---

View File

@@ -1,10 +0,0 @@
---
site_name: MoreminiMore
email: "contact@moreminimore.com"
phone: "080-995-5945"
address: "53 หมู่ 1 ต.บ้านแพ้ว อ.บ้านแพ้ว สมุทรสาคร 74120"
facebook: "https://www.facebook.com/moreminimore"
line: "https://line.me/ti/p/~539hdlul"
line_id: "@moreminimore"
linkedin: "https://www.linkedin.com/company/moreminimore"
---

View File

@@ -1,43 +0,0 @@
/**
* MOREMINIMORE - Nav data (single source of truth)
* Used by Navigation.astro and Footer.astro
*
* Per plan 2026-06-13 round 2:
* - Main menu: 7 items including 'บทความ' (blog) + 'FAQ' + 'ติดต่อ'
* - Services dropdown: 4 services (matched to content collection slugs)
* - Social: facebook, line, linkedin (from settings collection at runtime)
*
* Slugs match src/content/services/*-new.mdx:
* - ai-consult-new → /services/ai-consult
* - marketing-new → /services/marketing
* - automation-new → /services/automation
* - webdev-new → /services/webdev
*
* Href uses /services/{slug-without-new} to match the [slug].astro route.
*/
export const mainLinks = [
{ label: 'หน้าแรก', href: '/' },
{ label: 'บริการ', href: '/services', hasDropdown: true },
{ label: 'ผลงาน', href: '/portfolio' },
{ label: 'บทความ', href: '/blog' },
{ label: 'เกี่ยวกับ', href: '/about' },
{ label: 'FAQ', href: '/faq' },
{ label: 'ติดต่อ', href: '/contact' },
];
export const servicesDropdown = [
{ label: 'AI Consult', href: '/services/ai-consult' },
{ label: 'Marketing Automation', href: '/services/marketing' },
{ label: 'AI Automation', href: '/services/automation' },
{ label: 'Website Development', href: '/services/webdev' },
];
/**
* Social links are passed as props to the component
* (because they come from the settings collection which is loaded async)
*/
export interface SocialLinks {
facebook?: string;
line?: string;
linkedin?: string;
}

View File

@@ -1,74 +0,0 @@
export const portfolioItems = [
{
name: "Lungfinler",
url: "https://lungfinler.com",
category: "webdev",
category_label: "พัฒนาเว็บไซต์",
thumbnail: "/images/portfolio/lungfinler.png",
description: "Digital Agency - บริการด้านการสร้างแบรนด์ กราฟิกดีไซน์ และถ่ายภาพสินค้าคุณภาพสูง"
},
{
name: "Jet Industries",
url: "https://jetindustries.co.th",
category: "webdev",
category_label: "พัฒนาเว็บไซต์",
thumbnail: "/images/portfolio/jetindustries.png",
description: "ผู้ผลิตพลาสติกฉีดขึ้นรูปอย่างแม่นยำ (Precision Plastic Injection Molding) มีประสบการณ์กว่า 40 ปี"
},
{
name: "สำนักงานกฎหมาย ตถาตา",
url: "https://lawyernoom.com",
category: "webdev",
category_label: "พัฒนาเว็บไซต์",
thumbnail: "/images/portfolio/lawyernoom.png",
description: "สำนักงานกฎหมายโดย ทนายความ คมสัน ศรีวนิชย์ - บริการด้านคดีความ คดีแพ่ง คดีอาญา"
},
{
name: "Underdog Marketing",
url: "https://underdog.run",
category: "webdev",
category_label: "พัฒนาเว็บไซต์",
thumbnail: "/images/portfolio/underdog.png",
description: "บล็อกการตลาดและการขายสไตล์ ลุยไม่ยั้ง โดย บุ้ง ดีดติ่งหู"
},
{
name: "Baofuling Shop",
url: "https://baofulingshop.com",
category: "ecommerce",
category_label: "อีคอมเมิร์ซ",
thumbnail: "/images/portfolio/baofuling.png",
description: "ร้านค้าออนไลน์ครีมบัวหิมะและผลิตภัณฑ์ความงามจีน"
},
{
name: "เทรนเนอร์ซันนี่",
url: "https://trainersunny.com",
category: "webdev",
category_label: "พัฒนาเว็บไซต์",
thumbnail: "/images/portfolio/trainersunny.png",
description: "ผู้เชี่ยวชาญด้านการพัฒนาบุคลากรและ Soft Skill"
},
{
name: "เลือดจระเข้วานิไทย",
url: "https://เลือดจระเข้วานิไทย.com",
category: "ecommerce",
category_label: "อีคอมเมิร์ซ",
thumbnail: "/images/portfolio/luadjob.png",
description: "ตัวแทนจำหน่ายเลือดจระเข้วานิไทยอย่างเป็นทางการ"
},
{
name: "ทวนทอง 99",
url: "https://tuanthong99.com",
category: "ecommerce",
category_label: "อีคอมเมิร์ซ",
thumbnail: "/images/portfolio/tuanthong.png",
description: "ร้านค้าออนไลน์สมุนไพรไทยคุณภาพสูง"
},
{
name: "Dataroot",
url: "https://erp.dataroot.asia",
category: "marketing",
category_label: "ที่ปรึกษาการตลาด",
thumbnail: "/images/portfolio/dataroot.png",
description: "ตัวแทนจำหน่าย Odoo ERP ในประเทศไทย"
}
];

183
src/data/site.js Normal file
View File

@@ -0,0 +1,183 @@
export const formEndpoint = '';
export const problems = [
['website_no_leads', 'เว็บมีอยู่แล้ว แต่ไม่ค่อยมีลูกค้าทัก'],
['ads_not_worth_it', 'ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม'],
['wrong_leads', 'มีคนทักมา แต่ไม่ใช่ลูกค้าที่ใช่'],
['slow_or_error_work', 'ทีมงานทำงานเดิม ๆ แต่ทำงานช้า หรือผิดพลาดบ่อย'],
['ai_not_sure', 'อยากใช้ AI แต่ไม่รู้เริ่มตรงไหน'],
['not_sure', 'ยังไม่แน่ใจว่าควรแก้อะไรก่อน'],
];
export const services = [
{
name: 'Website Development',
slug: 'website-development',
badge: 'พัฒนาเว็บไซต์',
objective: 'ทำเว็บให้ขายได้',
headline: 'เว็บที่ช่วยให้ลูกค้ารู้ว่าควรทักเรื่องอะไร',
copy: 'เหมาะกับธุรกิจที่มีเว็บแล้วแต่ลูกค้ายังไม่ค่อยติดต่อ หรืออยากเริ่มเว็บใหม่ให้วัดผลได้ตั้งแต่วันแรก',
detail: 'เริ่มจากถามว่าเว็บนี้ทำเพื่ออะไร ขายของ เก็บ lead หรือสร้างความน่าเชื่อถือ แล้วออกแบบหน้าและข้อความให้ทำหน้าที่นั้นได้จริง',
painPoints: ['เว็บดูมีอยู่ แต่ลูกค้ายังไม่รู้ว่าควรทักเรื่องอะไร', 'หน้าเว็บไม่ช่วยคัด lead หรืออธิบายข้อเสนอให้ชัด', 'อยากเริ่มเว็บใหม่ให้พร้อมวัดผลตั้งแต่วันแรก'],
approach: ['วาง message และ flow จากโจทย์ธุรกิจ', 'ออกแบบหน้าให้ตอบคำถามลูกค้าก่อนตัดสินใจ', 'ทำเว็บ Astro หรือ WordPress ตามความเหมาะสมของงาน'],
deliverables: ['โครงหน้าและ copy หลัก', 'เว็บไซต์ responsive พร้อมใช้งาน', 'พื้นฐาน SEO และ analytics ที่จำเป็น'],
proof: 'เหมาะกับธุรกิจที่ต้องใช้เว็บไซต์เป็นฐานความน่าเชื่อถือและช่องทางรับ lead',
},
{
name: 'Marketing Consult',
slug: 'marketing-consult',
badge: 'ที่ปรึกษาการตลาดออนไลน์',
objective: 'เพิ่มยอดขาย',
headline: 'การตลาดที่ใช้งบคุ้มขึ้นจากข้อมูลจริง',
copy: 'เหมาะกับธุรกิจที่ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม หรือมีคนทักมาแล้วไม่ใช่ลูกค้าที่ควรได้',
detail: 'ดูสถิติคนเข้าเว็บ คนคลิกโฆษณา ยอดขาย และกลุ่มลูกค้าก่อน แล้วค่อยเลือกช่องทาง ข้อความ และงบประมาณที่ควรใช้',
painPoints: ['ยิงแอดแล้วมีคนคลิก แต่ยอดขายไม่คุ้ม', 'มี lead เข้ามา แต่คุณภาพลูกค้ายังไม่ตรง', 'ไม่แน่ใจว่างบควรอยู่ที่ช่องทางไหน'],
approach: ['ดูข้อมูลแอด เว็บ และยอดขายเท่าที่มี', 'แยกปัญหาระหว่าง traffic, offer, landing page และ sales process', 'เสนอสิ่งที่ควรปรับก่อนใช้งบเพิ่ม'],
deliverables: ['diagnosis จากข้อมูลจริง', 'แผนปรับกลุ่มเป้าหมายและข้อความ', 'แนวทางวัดผลที่ช่วยดูคุณภาพลูกค้า'],
proof: 'เหมาะกับธุรกิจที่มี activity การตลาดอยู่แล้ว แต่อยากรู้ว่าเงินหายไปตรงไหน',
},
{
name: 'Automation Workflow',
slug: 'automation-workflow',
badge: 'วางระบบอัตโนมัติ',
objective: 'ลดต้นทุนและเวลา',
headline: 'ระบบที่ลดงานช้าและงานผิดพลาด',
copy: 'เหมาะกับทีมที่ทำงานเดิม ๆ ซ้ำทุกวัน ใช้เวลานาน หรือมีจุดผิดพลาดที่แก้ไม่จบ',
detail: 'เริ่มจากดู workflow ปัจจุบันว่าอะไรซ้ำ ทำมือ หรือเสียเวลา แล้วเลือกว่าจะใช้ n8n ระบบเฉพาะทาง หรือ AI ช่วยในจุดไหน',
painPoints: ['ทีมทำงานซ้ำ ๆ และเสียเวลากับขั้นตอนเดิม', 'ข้อมูลกระจัดกระจาย ต้องคอย copy หรือส่งต่อเอง', 'งานผิดพลาดจากการทำมือเกิดซ้ำ'],
approach: ['วาด workflow ปัจจุบันให้เห็นจุดเสียเวลา', 'เลือก automation เฉพาะจุดที่คุ้มก่อน', 'ออกแบบให้ทีมใช้งานง่ายและตรวจสอบได้'],
deliverables: ['workflow map', 'ระบบ automation หรือ integration ตาม scope', 'คู่มือใช้งานและจุดตรวจสอบ'],
proof: 'เหมาะกับธุรกิจที่มีทีมทำงานซ้ำทุกวัน และอยากลดเวลาหรือความผิดพลาดก่อนขยายทีม',
},
{
name: 'AI Consult',
slug: 'ai-consult',
badge: 'ที่ปรึกษาด้าน AI',
objective: 'รักษาความรู้ขององค์กร',
headline: 'AI ที่ช่วยทีมทำงาน ไม่ใช่แค่ของเล่นใหม่',
copy: 'เหมาะกับธุรกิจที่อยากใช้ AI แต่ยังไม่แน่ใจว่างานไหนควรเริ่มก่อนและใช้อย่างไรให้ปลอดภัย',
detail: 'เลือกโมเดลและวิธีใช้ให้เหมาะกับงานจริง โดยเฉพาะงานที่ต้องรักษาความรู้และความลับขององค์กร',
painPoints: ['อยากใช้ AI แต่ยังไม่รู้ว่างานไหนคุ้มที่สุด', 'ทีมลองเครื่องมือหลายตัวแต่ยังไม่เชื่อมกับงานจริง', 'มีความรู้สำคัญอยู่กับคนหรือเอกสารกระจัดกระจาย'],
approach: ['เลือก use case ที่กระทบงานจริงก่อน', 'วางวิธีใช้ AI ที่เหมาะกับระดับความลับของข้อมูล', 'ช่วยทีมใช้ AI แบบตรวจสอบได้ ไม่ใช่ปล่อยให้เดาเอง'],
deliverables: ['AI use case roadmap', 'prototype หรือ workflow ที่ใช้ได้จริง', 'แนวทางรักษาความรู้และข้อมูลขององค์กร'],
proof: 'เหมาะกับองค์กรที่อยากใช้ AI เพื่อช่วยคนทำงาน ไม่ใช่แค่ซื้อเครื่องมือใหม่',
},
];
export const portfolio = [
{
name: 'Dataroot',
image: '/images/portfolio/dataroot.png',
href: 'https://erp.dataroot.asia',
tag: 'Marketing diagnosis',
description: 'เคสปรับการมองข้อมูลและกลุ่มเป้าหมายก่อนตัดสินใจใช้งบ',
featured: true,
},
{
name: 'Jet Industries',
image: '/images/portfolio/jetindustries.png',
href: 'https://jetindustries.co.th',
tag: 'Corporate website',
description: 'เว็บไซต์องค์กรผู้ผลิตพลาสติกฉีดขึ้นรูป ประสบการณ์กว่า 40 ปี',
featured: true,
},
{
name: 'เทรนเนอร์ซันนี่',
image: '/images/portfolio/trainersunny.png',
href: 'https://trainersunny.com',
tag: 'Personal brand',
description: 'เว็บไซต์ personal brand และหลักสูตรอบรมที่มีภาพจำชัด',
featured: true,
},
{
name: 'Dealplustech',
image: '/images/portfolio/dealplustech.png',
href: 'https://www.dealplustech.co.th',
tag: 'Website Development',
description: 'เว็บไซต์ระบบน้ำและสุขภัณฑ์คุณภาพสูงสำหรับโรงงานและบ้านเรือน',
},
{
name: 'Underdog Marketing',
image: '/images/portfolio/underdog.png',
href: 'https://underdog.run',
tag: 'Website Development',
description: 'แพลตฟอร์มบทความการตลาดที่ใช้งานง่ายและ SEO friendly',
},
{
name: 'ทวนทอง 99',
image: '/images/portfolio/tuanthong.png',
href: 'https://tuanthong99.com',
tag: 'E-commerce',
description: 'เว็บไซต์สินค้าอุปโภคบริโภคและสมุนไพรไทย',
},
{
name: 'สำนักงานกฎหมาย ตถาตา',
image: '/images/portfolio/lawyernoom.png',
href: 'https://lawyernoom.com',
tag: 'Website Development',
description: 'เว็บไซต์สำนักงานกฎหมายที่เน้นความน่าเชื่อถือ',
},
];
export const process = [
['เข้าใจธุรกิจ', 'ทำความรู้จักเป้าหมาย ลูกค้า และปัญหาที่เจอจริง'],
['ดูข้อมูล', 'เช็กเว็บ แอด ลูกค้า ขั้นตอนทำงาน หรือข้อมูลที่มีอยู่'],
['เลือกทางที่คุ้ม', 'เสนอสิ่งที่ควรทำก่อน ไม่ทำทุกอย่างพร้อมกัน'],
['ลงมือและวัดผล', 'ทำให้ใช้งานได้จริง แล้วดูผลเพื่อปรับต่อ'],
];
export const faqs = [
{
category: 'บริการ',
question: 'MoreminiMore ทำอะไรบ้าง?',
answer: 'เราช่วยเรื่องเว็บไซต์ การตลาดออนไลน์ ระบบอัตโนมัติ และ AI สำหรับ SME โดยเริ่มจากดูโจทย์และข้อมูลจริงก่อนเลือกวิธีทำ',
},
{
category: 'บริการ',
question: 'ถ้ามีงบน้อย ควรเริ่มจากอะไร?',
answer: 'ควรเริ่มจากปัญหาที่กระทบยอดขายหรือต้นทุนมากที่สุด ถ้ายังไม่มีเว็บให้เริ่มจากฐานข้อมูลและหน้าเว็บ ถ้ามีเว็บแล้วให้ดูคุณภาพ lead และข้อมูลแอดก่อน',
},
{
category: 'ราคา',
question: 'ราคาเริ่มต้นเท่าไหร่?',
answer: 'เว็บ Astro เริ่ม 5,000 บาท, WordPress เริ่ม 30,000 บาท, งานที่ปรึกษาเริ่มตามขอบเขตจริง เราจะบอกช่วงราคาหลังเข้าใจโจทย์มากพอ',
},
{
category: 'ระยะเวลา',
question: 'ทำเว็บใช้เวลานานแค่ไหน?',
answer: 'เว็บ Astro ส่วนใหญ่ใช้เวลาประมาณ 14-30 วัน ส่วน WordPress หรือระบบที่ซับซ้อนกว่านั้นใช้เวลามากขึ้นตามขอบเขตงาน',
},
{
category: 'วิธีทำงาน',
question: 'ต้องรู้ก่อนไหมว่าจะใช้บริการไหน?',
answer: 'ไม่จำเป็น เล่าโจทย์หรืออาการที่เจอก่อนก็ได้ แล้วเราจะช่วยดูว่าควรเริ่มจากบริการไหน',
},
{
category: 'หลังส่งมอบ',
question: 'มีประกันงานไหม?',
answer: 'มีการดูแลหลังส่งมอบสำหรับปัญหาที่เกิดจากงานของเรา ส่วนงานที่เปลี่ยนแปลงเพิ่มจากขอบเขตเดิมจะคุยกันตามจริงก่อนทำ',
},
];
export const posts = [
{
title: 'AI สำหรับ SME ไทย: เริ่มจากงานที่เจ็บที่สุดก่อน',
excerpt: 'AI ไม่จำเป็นต้องเริ่มจากระบบใหญ่ เริ่มจากคำถามซ้ำ งานเอกสารซ้ำ หรือข้อมูลที่ทีมใช้ตัดสินใจก่อนจะคุ้มกว่า',
category: 'AI Consult',
},
{
title: 'Marketing Automation ควรช่วยลดงาน ไม่ใช่เพิ่มเครื่องมือ',
excerpt: 'ก่อนเลือกเครื่องมือ ควรดู workflow จริงก่อนว่าขั้นตอนไหนซ้ำ ช้า หรือผิดพลาดบ่อย แล้วค่อยออกแบบระบบช่วย',
category: 'Automation',
},
{
title: 'เว็บ SME ที่ดีควรถามได้ว่าลูกค้าควรทำอะไรต่อ',
excerpt: 'เว็บไซต์ไม่ใช่แค่หน้าแนะนำบริษัท แต่ควรช่วยให้ลูกค้าเข้าใจปัญหา เห็นทางเลือก และรู้ว่าควรติดต่อเรื่องอะไร',
category: 'Website',
},
{
title: 'ยิงแอดแล้วไม่คุ้ม อาจไม่ใช่เพราะยิงผิดแพลตฟอร์ม',
excerpt: 'บางครั้งปัญหาอยู่ที่ intent ของคนที่เข้ามา ข้อความหน้าเว็บ หรือการวัดผลที่ยังไม่บอกคุณภาพลูกค้า',
category: 'Marketing',
},
];

View File

@@ -1,96 +0,0 @@
---
import "../styles/global.css";
import "../styles/fx-system.css";
import UtilityBar from "../components/UtilityBar.astro";
import Marquee from "../components/Marquee.astro";
import Navigation from "../components/Navigation.astro";
import Footer from "../components/Footer.astro";
interface Props {
title: string;
description?: string;
}
const {
title,
description = "MoreminiMore - รับทำเว็บไซต์ SEO AI Chatbot สำหรับธุรกิจไทย | เพิ่มยอดขาย ลดต้นทุน ด้วยเทคโนโลยีล้ำสมัย"
} = Astro.props;
---
<!doctype html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content={description} />
<meta name="theme-color" content="#fed400" />
<!-- Favicon (M logo: yellow square + black M) -->
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="48x48" href="/favicon-48x48.png" />
<link rel="icon" type="image/png" href="/favicon.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="192x192" href="/android-chrome-192x192.png" />
<link rel="icon" type="image/png" sizes="512x512" href="/android-chrome-512x512.png" />
<link rel="manifest" href="/site.webmanifest" />
<title>{title}</title>
<!-- Anti-flash theme: apply .dark class on <html> BEFORE first paint.
Reads localStorage 'moreminimore-theme' or falls back to OS preference.
If neither set, defaults to 'light' (matches v7-5 demo).
Inline (no defer) is intentional — must run synchronously.
NOTE: We use .dark class instead of data-theme="dark" because
Astro/Vite CSS optimizer strips [data-theme="..."] selectors
that don't match any static HTML (we set it dynamically via JS). -->
<script is:inline>
(function() {
try {
var stored = localStorage.getItem('moreminimore-theme');
var theme;
if (stored === 'light' || stored === 'dark') {
theme = stored;
} else {
// 'auto' or unset: follow system
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
// Use class instead of data-theme attribute (Vite/Astro keep .dark selectors)
if (theme === 'dark') {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
} catch (e) {
// localStorage blocked or no matchMedia — default light
document.documentElement.classList.remove('dark');
}
})();
</script>
</head>
<body>
<UtilityBar />
<Marquee />
<Navigation currentPath={Astro.url.pathname} />
<slot />
<Footer />
<!-- Global animations: initAnimations (legacy bento) + fxInit (v7-5 fx-*) -->
<script>
import { initAnimations } from '../lib/animations';
import { fxInit } from '../lib/fx-animations';
const start = () => {
initAnimations();
fxInit();
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', start);
} else {
start();
}
</script>
</body>
</html>

View File

@@ -1,419 +0,0 @@
/**
* MoreminiMore - Animation Library
* Reusable scroll/load animations. Lightweight, no dependencies.
*
* Usage in any .astro file:
* <script>import { initAnimations } from '../lib/animations';
* document.addEventListener('DOMContentLoaded', initAnimations);</script>
*
* Or for per-page targeted init:
* <script>import { revealOnScroll, counterUp } from '../lib/animations';
* revealOnScroll('.reveal');</script>
*/
/* ------------------------------------------------------------------ */
/* TYPES */
/* ------------------------------------------------------------------ */
interface RevealOptions {
threshold?: number;
rootMargin?: string;
once?: boolean;
delayMs?: number;
}
interface CounterOptions {
duration?: number;
easing?: (t: number) => number;
}
/* ------------------------------------------------------------------ */
/* ENTRANCE ANIMATIONS */
/* ------------------------------------------------------------------ */
/**
* Add .reveal class to any element you want to fade-in-up on scroll.
* Default: trigger at 15% visibility, slide up 30px, 700ms.
*/
export function revealOnScroll(
selector: string | string[] = '.reveal',
options: RevealOptions = {}
): void {
if (typeof window === 'undefined') return;
const els = collectElements(selector);
if (els.length === 0) return;
const opts: Required<RevealOptions> = {
threshold: options.threshold ?? 0,
rootMargin: options.rootMargin ?? '0px 0px 100px 0px',
once: options.once ?? true,
delayMs: options.delayMs ?? 0,
};
// SSR-safe fallback: if IntersectionObserver is unavailable, show everything.
if (typeof IntersectionObserver === 'undefined') {
els.forEach((el) => el.classList.add('revealed'));
return;
}
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const el = entry.target as HTMLElement;
setTimeout(() => el.classList.add('revealed'), opts.delayMs);
if (opts.once) observer.unobserve(el);
} else if (!opts.once) {
entry.target.classList.remove('revealed');
}
});
},
{ threshold: opts.threshold, rootMargin: opts.rootMargin }
);
const vh = window.innerHeight || document.documentElement.clientHeight;
els.forEach((el) => {
// FALLBACK: if already in view on load, apply immediately.
const r = el.getBoundingClientRect();
if (r.top < vh && r.bottom > 0) {
setTimeout(() => el.classList.add('revealed'), opts.delayMs);
if (opts.once) return; // don't observe
}
observer.observe(el);
});
}
/**
* Stagger-children reveal — children of the matched container fade in sequentially.
* Reads --stagger CSS var (in ms) from each child, or uses 100ms default.
*/
export function staggerReveal(
containerSelector: string,
childSelector: string = ':scope > *',
baseDelayMs: number = 0
): void {
if (typeof window === 'undefined') return;
const containers = collectElements(containerSelector);
if (containers.length === 0) return;
// Helper: apply reveal to one container's children.
const apply = (container: HTMLElement) => {
const children = container.querySelectorAll<HTMLElement>(childSelector);
children.forEach((child, i) => {
const stagger = Number(child.dataset.stagger) || i * 100;
setTimeout(() => child.classList.add('revealed'), baseDelayMs + stagger);
});
};
if (typeof IntersectionObserver === 'undefined') {
containers.forEach(apply);
return;
}
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
apply(entry.target as HTMLElement);
observer.unobserve(entry.target);
}
});
},
{ threshold: 0, rootMargin: '0px 0px 100px 0px' }
);
containers.forEach((c) => {
// FALLBACK: if the container is already in view on load, apply immediately.
// IO can miss elements that are in viewport at registration time on some browsers.
const r = c.getBoundingClientRect();
const vh = window.innerHeight || document.documentElement.clientHeight;
if (r.top < vh && r.bottom > 0) {
apply(c);
return; // do not observe — already revealed
}
observer.observe(c);
});
}
/* ------------------------------------------------------------------ */
/* KINETIC TYPOGRAPHY */
/* ------------------------------------------------------------------ */
/**
* Reveal each word of the matched headline with a staggered translate-up.
* Wraps each word in a .word-wrapper if not already, then animates.
*/
export function kineticHeadline(selector: string = '.kinetic-title'): void {
if (typeof window === 'undefined') return;
const headings = collectElements(selector);
if (headings.length === 0) return;
headings.forEach((heading) => {
// Skip if already processed
if (heading.dataset.kineticReady === 'true') return;
heading.dataset.kineticReady = 'true';
// Skip if text is empty / pure whitespace
if (!heading.textContent?.trim()) return;
const text = heading.textContent;
const words = text.split(/(\s+)/); // keep whitespace
heading.innerHTML = '';
let wordIndex = 0;
words.forEach((segment) => {
if (/^\s+$/.test(segment)) {
heading.appendChild(document.createTextNode(segment));
} else {
const wrapper = document.createElement('span');
wrapper.className = 'word-wrapper';
const inner = document.createElement('span');
inner.className = 'word';
inner.textContent = segment;
inner.style.setProperty('--delay', `${0.3 + wordIndex * 0.08}s`);
wrapper.appendChild(inner);
heading.appendChild(wrapper);
wordIndex++;
}
});
});
}
/* ------------------------------------------------------------------ */
/* COUNTER ANIMATION */
/* ------------------------------------------------------------------ */
/**
* Animate any element with a number to count up from 0 (or data-from) to the
* number in its text. Triggered when the element scrolls into view.
*
* Element: <span class="counter" data-from="0" data-suffix="+">50+</span>
*/
export function counterUp(
selector: string = '.counter',
options: CounterOptions = {}
): void {
if (typeof window === 'undefined') return;
const els = collectElements(selector);
if (els.length === 0) return;
const duration = options.duration ?? 1600;
const ease = options.easing ?? easeOutCubic;
if (typeof IntersectionObserver === 'undefined') {
els.forEach((el) => animateCounter(el as HTMLElement, duration, ease));
return;
}
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
animateCounter(entry.target as HTMLElement, duration, ease);
observer.unobserve(entry.target);
}
});
},
{ threshold: 0, rootMargin: '0px 0px 100px 0px' }
);
els.forEach((el) => {
// FALLBACK: if already in view on load, animate immediately.
const r = el.getBoundingClientRect();
const vh = window.innerHeight || document.documentElement.clientHeight;
if (r.top < vh && r.bottom > 0) {
animateCounter(el as HTMLElement, duration, ease);
return;
}
observer.observe(el);
});
}
function animateCounter(
el: HTMLElement,
duration: number,
ease: (t: number) => number
): void {
const raw = el.textContent?.trim() ?? '0';
const fromStr = el.dataset.from;
const from = fromStr ? parseFloat(fromStr) : 0;
// Extract leading number, ignore trailing chars (e.g. "50+", "5+", "5 ปี", "24/7")
const match = raw.match(/^([\d,.]+)(.*)$/);
if (!match) return;
const targetStr = match[1].replace(/,/g, '');
const target = parseFloat(targetStr);
const suffix = match[2] || '';
const prefix = el.dataset.prefix || '';
if (Number.isNaN(target)) return;
const start = performance.now();
const tick = (now: number) => {
const elapsed = now - start;
const progress = Math.min(elapsed / duration, 1);
const value = from + (target - from) * ease(progress);
// Preserve any decimal formatting from original
const decimals = (targetStr.split('.')[1] || '').length;
el.textContent = `${prefix}${formatNumber(value, decimals)}${suffix}`;
if (progress < 1) requestAnimationFrame(tick);
};
requestAnimationFrame(tick);
}
function formatNumber(n: number, decimals: number): string {
return n.toFixed(decimals);
}
function easeOutCubic(t: number): number {
return 1 - Math.pow(1 - t, 3);
}
/* ------------------------------------------------------------------ */
/* MAGNETIC BUTTON */
/* ------------------------------------------------------------------ */
/**
* Subtle hover-tracking effect for CTAs. Btn slightly tracks cursor position.
* Add `data-magnetic` attribute to any button.
*/
export function magneticButtons(selector: string = '[data-magnetic]'): void {
if (typeof window === 'undefined') return;
const btns = collectElements(selector);
if (btns.length === 0) return;
btns.forEach((btn) => {
if ((btn as HTMLElement).dataset.magneticReady === 'true') return;
(btn as HTMLElement).dataset.magneticReady = 'true';
const strength = 0.25;
btn.addEventListener('mousemove', (e: MouseEvent) => {
const rect = btn.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.height / 2;
(btn as HTMLElement).style.transform = `translate(${x * strength}px, ${y * strength}px)`;
});
btn.addEventListener('mouseleave', () => {
(btn as HTMLElement).style.transform = '';
});
});
}
/* ------------------------------------------------------------------ */
/* PARALLAX BACKGROUND */
/* ------------------------------------------------------------------ */
/**
* Apply a subtle parallax translateY to elements based on scroll position.
* Add `data-parallax="0.3"` (0-1) to set speed (default 0.3).
* Uses requestAnimationFrame + transform for 60fps.
*/
export function parallaxBackgrounds(selector: string = '[data-parallax]'): void {
if (typeof window === 'undefined') return;
const els = Array.from(document.querySelectorAll<HTMLElement>(selector));
if (els.length === 0) return;
// Use rAF for smooth 60fps
let ticking = false;
const update = () => {
if (ticking) return;
ticking = true;
requestAnimationFrame(() => {
const scrollY = window.scrollY;
els.forEach((el) => {
const rect = el.getBoundingClientRect();
const speed = parseFloat(el.dataset.parallax || '0.3');
// Only update if visible
if (rect.bottom > -200 && rect.top < window.innerHeight + 200) {
const offset = (rect.top - window.innerHeight) * speed;
el.style.transform = `translate3d(0, ${offset}px, 0)`;
}
});
ticking = false;
});
};
window.addEventListener('scroll', update, { passive: true });
update(); // initial
}
/* ------------------------------------------------------------------ */
/* PARALLAX SCROLL PROGRESS */
/* ------------------------------------------------------------------ */
/**
* Update CSS var --scroll-progress (0-100) on the document.
* Pair with a CSS rule like:
* .scroll-indicator { height: calc(var(--scroll-progress) * 1px); }
*/
export function scrollProgress(selector: string = '.scroll-indicator'): void {
if (typeof window === 'undefined') return;
const els = collectElements(selector);
if (els.length === 0) return;
const update = () => {
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
const progress = docHeight > 0 ? (window.scrollY / docHeight) * 100 : 0;
els.forEach((el) => {
el.style.setProperty('--scroll-progress', `${Math.min(progress, 100)}%`);
});
};
window.addEventListener('scroll', update, { passive: true });
update();
}
/* ------------------------------------------------------------------ */
/* ENTRY POINT — call from page script */
/* ------------------------------------------------------------------ */
/**
* Initialize all animations on the current page. Pass an options object
* to opt-out of any animation.
*/
export interface AnimationOptions {
reveal?: boolean;
stagger?: boolean;
kinetic?: boolean;
counters?: boolean;
magnetic?: boolean;
parallax?: boolean;
scrollProgress?: boolean;
}
export function initAnimations(
options: AnimationOptions = {}
): void {
const opts: Required<AnimationOptions> = {
reveal: true,
stagger: true,
kinetic: true,
counters: true,
magnetic: true,
parallax: true,
scrollProgress: true,
...options,
};
// Wait for next tick so the DOM is fully painted
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => initAnimations(options));
return;
}
if (opts.reveal) revealOnScroll();
if (opts.stagger) staggerReveal('.stagger-children');
if (opts.kinetic) kineticHeadline();
if (opts.counters) counterUp();
if (opts.magnetic) magneticButtons();
if (opts.parallax) parallaxBackgrounds();
if (opts.scrollProgress) scrollProgress();
}
/* ------------------------------------------------------------------ */
/* HELPERS */
/* ------------------------------------------------------------------ */
function collectElements(selector: string | string[]): HTMLElement[] {
const sels = Array.isArray(selector) ? selector : [selector];
const out: HTMLElement[] = [];
sels.forEach((s) => {
document.querySelectorAll<HTMLElement>(s).forEach((el) => out.push(el));
});
return out;
}

View File

@@ -1,75 +0,0 @@
/**
* MOREMINIMORE - Contact form submit handler
* Per plan 2026-06-13 round 2 #4: Real working form with Apps Script backend.
*
* Reads PUBLIC_CONTACT_ENDPOINT from .env (Astro env var).
* - Empty / missing → DEV MODE: log to console, return success (mock)
* - Set → POST JSON to endpoint
*
* Apps Script template lives in apps-script/contact-form/Code.gs
* (user deploys it themselves — see apps-script/contact-form/README.md)
*/
export interface ContactData {
name: string;
phone: string;
email: string;
service: string;
message: string;
variant: 'prompt' | 'full';
}
export interface SubmitResult {
ok: boolean;
error?: string;
id?: string;
devMode?: boolean;
}
/** Check if running in dev mode (no endpoint configured) */
export function isDevMode(): boolean {
const endpoint = import.meta.env.PUBLIC_CONTACT_ENDPOINT;
return !endpoint || endpoint.trim() === '';
}
/**
* Submit contact form data to Apps Script endpoint.
* In dev mode (no endpoint), logs to console and returns success.
*/
export async function submitContact(data: ContactData): Promise<SubmitResult> {
// Dev mode: mock success
if (isDevMode()) {
console.info('[contact-submit] DEV MODE — payload:', data);
// Simulate network latency
await new Promise((r) => setTimeout(r, 300));
return { ok: true, devMode: true };
}
// Production: POST to Apps Script
const endpoint = import.meta.env.PUBLIC_CONTACT_ENDPOINT as string;
try {
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
...data,
userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown',
submittedAt: new Date().toISOString(),
}),
// Apps Script web apps don't support CORS preflight reliably
// mode: 'no-cors' would prevent reading the response, so we accept opaque
});
if (!response.ok) {
return { ok: false, error: `HTTP ${response.status}` };
}
const result = (await response.json()) as { ok?: boolean; id?: string; error?: string };
if (result.ok) {
return { ok: true, id: result.id };
}
return { ok: false, error: result.error ?? 'Unknown error from server' };
} catch (err) {
return { ok: false, error: err instanceof Error ? err.message : String(err) };
}
}

View File

@@ -1,148 +0,0 @@
/**
* MOREMINIMORE FX-ANIMATIONS v1
* Extracted from Desktop/moreminomore-mockup-v7-5.html bottom script (lines 1567-1624)
*
* 3 utilities — all SSR-safe (no-op on server):
* 1. fxClock() — live Thai clock + Buddhist date for utility bar
* 2. fxReveal() — add .revealed to .fx-reveal elements on scroll
* 3. fxStagger() — add .staggered to .fx-stagger elements on scroll
*
* Note: these are SEPARATE from src/lib/animations.ts (which uses .reveal class).
* v7-5 design system uses .fx-reveal / .fx-stagger to avoid collision with the
* legacy bento animations.
*
* Usage in Base.astro or any .astro file:
* <script>
* import { fxInit } from '../lib/fx-animations';
* if (document.readyState === 'loading') {
* document.addEventListener('DOMContentLoaded', fxInit);
* } else {
* fxInit();
* }
* </script>
*/
/* ------------------------------------------------------------------ */
/* 1. LIVE CLOCK (utility bar) */
/* ------------------------------------------------------------------ */
/** Days in Thai (Buddhist calendar: Sun=0, Sat=6) */
const THAI_DAYS = ['อา.', 'จ.', 'อ.', 'พ.', 'พฤ.', 'ศ.', 'ส.'];
/** Months in Thai */
const THAI_MONTHS = ['ม.ค.', 'ก.พ.', 'มี.ค.', 'เม.ย.', 'พ.ค.', 'มิ.ย.', 'ก.ค.', 'ส.ค.', 'ก.ย.', 'ต.ค.', 'พ.ย.', 'ธ.ค.'];
/**
* Start the live clock. Looks for elements with id="fx-time" and id="fx-date".
* Sets text every second.
*/
export function fxClock(): void {
if (typeof window === 'undefined') return;
function update(): void {
const now = new Date();
const hh = String(now.getHours()).padStart(2, '0');
const mm = String(now.getMinutes()).padStart(2, '0');
const ss = String(now.getSeconds()).padStart(2, '0');
const time = '⏱ ' + hh + ':' + mm + ':' + ss;
const date = '📅 ' + THAI_DAYS[now.getDay()] + ' ' + now.getDate() + ' ' + THAI_MONTHS[now.getMonth()] + ' ' + (now.getFullYear() + 543);
const t = document.getElementById('fx-time');
const d = document.getElementById('fx-date');
if (t) t.textContent = time;
if (d) d.textContent = date;
}
update();
setInterval(update, 1000);
}
/* ------------------------------------------------------------------ */
/* 2. REVEAL-ON-SCROLL (.fx-reveal) */
/* ------------------------------------------------------------------ */
/**
* Add .revealed to .fx-reveal elements as they enter viewport.
* Includes 2 failsafes:
* - Force-reveal all after 1.5s (in case observer never fires)
* - Force-reveal all after 100ms (in case section is already in view)
*/
export function fxReveal(): void {
if (typeof window === 'undefined') return;
const reveals = document.querySelectorAll<HTMLElement>('.fx-reveal');
if (reveals.length === 0) return;
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('revealed');
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.05, rootMargin: '0px 0px -40px 0px' }
);
reveals.forEach((r) => observer.observe(r));
}
// Failsafe 1: force-reveal all after 1.5s
setTimeout(() => {
reveals.forEach((r) => r.classList.add('revealed'));
}, 1500);
// Failsafe 2: trigger immediately for visible sections (100ms)
setTimeout(() => {
reveals.forEach((r) => r.classList.add('revealed'));
}, 100);
}
/* ------------------------------------------------------------------ */
/* 3. STAGGER-ON-SCROLL (.fx-stagger) */
/* ------------------------------------------------------------------ */
/**
* Add .staggered to .fx-stagger elements as they enter viewport.
* Same failsafe pattern as fxReveal.
*/
export function fxStagger(): void {
if (typeof window === 'undefined') return;
const staggers = document.querySelectorAll<HTMLElement>('.fx-stagger');
if (staggers.length === 0) return;
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('staggered');
observer.unobserve(entry.target);
}
});
},
{ threshold: 0.05, rootMargin: '0px 0px -40px 0px' }
);
staggers.forEach((s) => observer.observe(s));
}
// Failsafes
setTimeout(() => {
staggers.forEach((s) => s.classList.add('staggered'));
}, 1500);
setTimeout(() => {
staggers.forEach((s) => s.classList.add('staggered'));
}, 100);
}
/* ------------------------------------------------------------------ */
/* CONVENIENCE: init all 3 in one call */
/* ------------------------------------------------------------------ */
/** Run all fx animations. Safe to call multiple times (idempotent via querySelector). */
export function fxInit(): void {
fxClock();
fxReveal();
fxStagger();
}

View File

@@ -1,7 +0,0 @@
{"t":0,"agent":"aa3cbfe","agent_type":"unknown","event":"agent_stop","success":true}
{"t":0,"agent":"af23dcd","agent_type":"unknown","event":"agent_stop","success":true}
{"t":0,"agent":"a734a6b","agent_type":"unknown","event":"agent_stop","success":true}
{"t":0,"agent":"a27cab4","agent_type":"unknown","event":"agent_stop","success":true}
{"t":0,"agent":"a7cb1f3","agent_type":"unknown","event":"agent_stop","success":true}
{"t":0,"agent":"aa9fb06","agent_type":"unknown","event":"agent_stop","success":true}
{"t":0,"agent":"aa710ef","agent_type":"unknown","event":"agent_stop","success":true}

View File

@@ -1,16 +0,0 @@
{
"created_at": "2026-05-13T03:22:24.370Z",
"trigger": "auto",
"active_modes": {},
"todo_summary": {
"pending": 0,
"in_progress": 0,
"completed": 0
},
"wisdom_exported": false,
"background_jobs": {
"active": [],
"recent": [],
"stats": null
}
}

View File

@@ -1,16 +0,0 @@
{
"created_at": "2026-05-13T03:38:42.949Z",
"trigger": "auto",
"active_modes": {},
"todo_summary": {
"pending": 0,
"in_progress": 0,
"completed": 0
},
"wisdom_exported": false,
"background_jobs": {
"active": [],
"recent": [],
"stats": null
}
}

View File

@@ -1,16 +0,0 @@
{
"created_at": "2026-05-13T14:16:02.791Z",
"trigger": "auto",
"active_modes": {},
"todo_summary": {
"pending": 0,
"in_progress": 0,
"completed": 0
},
"wisdom_exported": false,
"background_jobs": {
"active": [],
"recent": [],
"stats": null
}
}

View File

@@ -1,16 +0,0 @@
{
"created_at": "2026-05-14T01:41:35.232Z",
"trigger": "auto",
"active_modes": {},
"todo_summary": {
"pending": 0,
"in_progress": 0,
"completed": 0
},
"wisdom_exported": false,
"background_jobs": {
"active": [],
"recent": [],
"stats": null
}
}

View File

@@ -1,7 +0,0 @@
{
"tool_name": "Bash",
"tool_input_preview": "{\"command\":\"for path in \\\"/\\\" \\\"/portfolio\\\" \\\"/blog\\\" \\\"/services/ai\\\" \\\"/services/marketing\\\"; do echo -n \\\"$path: \\\"; curl -s -o /dev/null -w \\\"%{http_code}\\\\n\\\" \\\"http://localhost:4321${path}\\\"; d...",
"error": "Exit code 127",
"timestamp": "2026-05-14T02:15:35.813Z",
"retry_count": 1
}

View File

@@ -1,6 +0,0 @@
{
"session_id": "e5f480d6-2b75-4bfe-b154-b1e53e34e0a3",
"started_at": "2026-05-14T01:42:56.165Z",
"cwd": "/Users/kunthawatgreethong/Gitea/moreminimore-emdash/moreminimore-site/src/pages",
"pid": 65131
}

View File

@@ -1,7 +0,0 @@
{
"agents": [],
"total_spawned": 0,
"total_completed": 0,
"total_failed": 0,
"last_updated": "2026-05-14T02:36:34.781Z"
}

View File

@@ -1,56 +1,73 @@
---
/**
* MOREMINIMORE - ABOUT
* Per plan 2026-06-13: v6 Hero (with about data) + body content from <Content />
*/
import Base from '../layouts/Base.astro';
import Hero from '../components/Hero.astro';
import { getEntry, render } from 'astro:content';
import type { CollectionEntry } from 'astro:content';
const about = await getEntry('pages', 'about') as CollectionEntry<'pages'>;
const { Content } = await render(about);
import PageShell from '../components/PageShell.astro';
import { process } from '../data/site.js';
---
<Base title="เกี่ยวกับเรา | MoreminiMore | รับทำเว็บไซต์ SEO AI Chatbot">
<Hero
id="about-hero"
eyebrow="MOREMINIMORE / เกี่ยวกับเรา"
title="เริ่มจากตรงนี้ ที่ปรึกษาที่ทำงานเอง"
lede="บริษัท มอร์มินิมอร์ จำกัด — นโยบายของเราคือสร้างระบบที่ทำให้ลูกค้ามีกำไรมากขึ้น ไม่ใช่ทำเว็บไซต์ออกมาเยอะแล้วลืม"
ctaPrimary={{ text: 'ปรึกษาฟรี 30 นาที →', href: '/contact' }}
ctaSecondary={{ text: 'ดูผลงานจริง', href: '/portfolio' }}
showStats={false}
/>
<PageShell
title="เกี่ยวกับเรา | MoreminiMore"
description="รู้จัก MoreminiMore ที่ปรึกษาเว็บไซต์ การตลาด และ AI สำหรับ SME ที่เริ่มจากข้อมูลจริงก่อนเลือกสิ่งที่ควรทำ"
>
<section class="page-hero scene scene-light" data-scene="light">
<div class="page-hero-grid">
<div>
<p class="eyebrow">About MoreminiMore</p>
<h1>ที่ปรึกษาที่เริ่มจากคำถาม ไม่ใช่เริ่มจากขายแพ็กเกจ</h1>
</div>
<p class="hero-lead">
MoreminiMore ทำงานกับ SME ที่อยากใช้เว็บ การตลาด ระบบอัตโนมัติ และ AI ให้คุ้มขึ้น โดยดูข้อมูลและบริบทของธุรกิจก่อนตัดสินใจลงมือ
</p>
</div>
</section>
<article class="fx-prose">
<Content />
</article>
</Base>
<section class="page-section">
<div class="about-grid">
<article class="glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="eyebrow">Why we exist</p>
<h2>ธุรกิจไม่ควรเสียเงินกับสิ่งที่ยังไม่รู้ว่าคุ้มไหม</h2>
<p>
เราเห็น SME หลายรายจ่ายเงินกับเว็บที่สวยแต่ไม่มีคนทัก โฆษณาที่มีคนคลิกแต่ไม่เกิดยอดขาย หรือเครื่องมือ AI ที่ดูน่าตื่นเต้นแต่ไม่เข้ากับงานจริง จึงเลือกทำงานแบบดูโจทย์ก่อน แล้วค่อยเสนอสิ่งที่ควรทำ
</p>
</article>
<article class="glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="eyebrow">Policy</p>
<h2>เป้าหมายของเราคือการเพิ่มกำไรให้ลูกค้า</h2>
<p>
ถ้าลูกค้ามีกำไรมากขึ้น ลูกค้าก็อยู่ต่อได้ และเราก็ทำงานต่อได้ด้วย ทุกงานจึงต้องตอบให้ได้ว่าช่วยเพิ่มยอดขาย ลดต้นทุน ประหยัดเวลา หรือช่วยตัดสินใจได้ดีขึ้นอย่างไร
</p>
</article>
</div>
</section>
<style>
.fx-prose {
max-width: 760px;
margin: 0 auto;
padding: 64px 32px 96px;
font: 400 16px/1.7 'Kanit', sans-serif;
color: var(--ink);
}
.fx-prose :global(h1) { font: 800 36px/1.2 'Kanit', sans-serif; margin: 32px 0 16px; }
.fx-prose :global(h2) { font: 700 24px/1.3 'Kanit', sans-serif; margin: 32px 0 12px; }
.fx-prose :global(h3) { font: 600 18px/1.4 'Kanit', sans-serif; margin: 24px 0 8px; }
.fx-prose :global(p) { margin: 0 0 16px; }
.fx-prose :global(ul), .fx-prose :global(ol) { margin: 0 0 16px; padding-left: 24px; }
.fx-prose :global(li) { margin: 0 0 8px; }
.fx-prose :global(strong) { color: var(--coral); font-weight: 700; }
.fx-prose :global(em) { font-family: 'Itim', cursive; color: var(--coral); font-weight: 400; }
.fx-prose :global(blockquote) {
border-left: 4px solid var(--brand-yellow);
padding: 12px 20px;
margin: 24px 0;
background: var(--paper-2);
font: 400 18px/1.6 'Kanit', sans-serif;
}
.fx-prose :global(a) { color: var(--coral); text-decoration: underline; }
.fx-prose :global(a:hover) { background: var(--brand-yellow); }
</style>
<section class="page-section page-section-tight">
<div class="section-heading">
<p class="eyebrow">Process</p>
<h2>วิธีทำงานที่ลดการเดา</h2>
</div>
<div class="process-grid">
{process.map(([title, copy], index) => (
<article>
<span>{String(index + 1).padStart(2, '0')}</span>
<h3>{title}</h3>
<p>{copy}</p>
</article>
))}
</div>
</section>
<section class="final-cta">
<div class="glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="eyebrow">Talk to us</p>
<h2>เล่าโจทย์ของธุรกิจคุณก่อน แล้วค่อยดูว่าควรเริ่มตรงไหน</h2>
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
</div>
</section>
</PageShell>

42
src/pages/blog.astro Normal file
View File

@@ -0,0 +1,42 @@
---
import PageShell from '../components/PageShell.astro';
import { getCollection } from 'astro:content';
const posts = (await getCollection('blog', ({ data }) => !data.draft)).sort(
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
);
---
<PageShell
title="บทความ | MoreminiMore"
description="บทความจาก MoreminiMore เกี่ยวกับเว็บไซต์ การตลาดออนไลน์ ระบบอัตโนมัติ และ AI สำหรับ SME"
>
<section class="page-hero scene scene-light" data-scene="light">
<div class="page-hero-grid">
<div>
<p class="eyebrow">Blog</p>
<h1>บทความสำหรับธุรกิจที่อยากตัดสินใจจากข้อมูล</h1>
</div>
<p class="hero-lead">
รวมมุมมองเรื่องเว็บ การตลาด ระบบอัตโนมัติ และ AI แบบที่เน้นใช้งานจริงในธุรกิจ ไม่ใช่แค่ตามกระแส
</p>
</div>
</section>
<section class="page-section">
<div class="blog-grid">
{posts.map((post) => (
<article class="blog-card liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<span>{post.data.category}</span>
<h2>{post.data.title}</h2>
<p>{post.data.description}</p>
<a class="text-link" href={`/blog/${post.id}/`}>อ่านบทความ</a>
</article>
))}
</div>
</section>
</PageShell>

View File

@@ -1,307 +1,53 @@
---
import Base from '../../layouts/Base.astro';
import Hero from '../../components/Hero.astro';
import PageShell from '../../components/PageShell.astro';
import { getCollection, render } from 'astro:content';
const { slug } = Astro.params;
const allPosts = await getCollection('blog');
const post = allPosts.find(p => p.id === slug);
if (!post) {
return Astro.redirect('/404');
}
export async function getStaticPaths() {
const allPosts = await getCollection('blog');
return allPosts.map(post => ({
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 related = allPosts
.filter(p => p.id !== post.id)
.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf())
.slice(0, 3);
const formattedDate = post.data.date.toLocaleDateString('th-TH', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
// Surface rotation for related cards
const surfaces = ['soft', 'yellow', 'mint'] as const;
function surfaceFor(i: number) {
return surfaces[i % surfaces.length];
}
const formattedDate = new Intl.DateTimeFormat('th-TH', {
dateStyle: 'long',
}).format(post.data.pubDate);
---
<Base title={`${post.data.title} | MoreminiMore`}>
<Hero
eyebrow={post.data.category}
title={post.data.title}
lede={formattedDate}
showStats={false} />
{post.data.image && (
<section class="section section-bento article-image-section">
<div class="container" style="position: relative; z-index: 1;">
<div class="article-image">
<img src={post.data.image} alt={post.data.title} />
</div>
<PageShell title={`${post.data.title} | MoreminiMore`} description={post.data.description}>
<article class="blog-article">
<header class="blog-article-hero scene scene-light" data-scene="light">
<div class="blog-article-heading">
<a class="text-link" href="/blog/">บทความทั้งหมด</a>
<p class="eyebrow">{post.data.category} · {formattedDate}</p>
<h1>{post.data.title}</h1>
<p>{post.data.description}</p>
</div>
</section>
)}
</header>
<section class="section section-bento article-section">
<div class="container" style="position: relative; z-index: 1;">
<div class="bento-grid">
<div class="blog-article-shell">
<div class="blog-prose liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<Content />
</div>
</div>
</article>
<!-- Main article body — full width bento tile -->
<div class="bento-tile span-8 surface-white">
<div class="article-meta">
<span class="article-date">{formattedDate}</span>
</div>
<div class="article-body">
<Content />
</div>
</div>
<!-- Sidebar tile: about + contact stack -->
<div class="bento-tile span-4 surface-soft">
<p>ดิจิทัลเอเจนซี่ที่ช่วยให้ธุรกิจไทยเติบโตด้วยเทคโนโลยีสมัยใหม่</p>
<a href="/about" class="btn btn-outline-dark btn-sm">ดูเพิ่มเติม</a>
<div class="sidebar-divider"></div>
<span class="tile-eyebrow-sm">สนใจบริการ?</span>
<p style="margin-top: 8px;">ติดต่อเราได้เลย ปรึกษาฟรี!</p>
<div class="sidebar-actions">
<a href="/contact" class="btn btn-primary btn-sm">ติดต่อเรา</a>
<a href="tel:0809955945" class="btn btn-outline-dark btn-sm">080-995-5945</a>
</div>
</div>
</div>
<section class="final-cta">
<div class="glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="eyebrow">Next step</p>
<h2>อ่านแล้วเจอโจทย์คล้ายกัน ส่งปัญหามาให้เราช่วยดูก่อนได้</h2>
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
</div>
</section>
{related.length > 0 && (
<section class="section section-bento related-section">
<div class="container" style="position: relative; z-index: 1;">
<div class="section-header reveal">
<span class="section-badge">บทความที่เกี่ยวข้อง</span>
<h2 class="section-title">อ่านต่อ <span class="highlight">เนื้อหาใกล้เคียง</span></h2>
</div>
<div class="bento-grid">
{related.map((r, i) => (
<a href={`/blog/${r.id}`} class="related-link">
<div class="bento-tile span-4">
<div class="related-card-body">
{r.data.image && (
<div class="related-image">
<img src={r.data.image} alt={r.data.title} loading="lazy" />
</div>
)}
<span class="related-date">
{new Date(r.data.date).toLocaleDateString('th-TH', { year: 'numeric', month: 'long', day: 'numeric' })}
</span>
</div>
</div>
</a>
))}
</div>
</div>
</section>
)}
</Base>
<style>
.article-image-section { background: var(--color-white); padding-top: 40px; padding-bottom: 40px; }
.article-section { background: var(--color-white); }
.related-section { background: var(--color-bg-alt); }
.section-bento { position: relative; overflow: hidden; }
/* Article image (hero) */
.article-image {
width: 100%;
overflow: hidden;
border-radius: var(--radius-xl);
background: var(--color-bg-soft);
}
.article-image img {
width: 100%;
max-height: 500px;
object-fit: cover;
display: block;
}
/* Main article body */
.article-meta {
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid var(--color-gray-200);
}
.article-date {
font-size: 13px;
font-weight: 700;
color: var(--color-gray-600);
text-transform: uppercase;
letter-spacing: 1px;
}
.article-body {
font-size: 17px;
line-height: 1.8;
color: var(--color-gray-700);
}
.article-body :global(h2) {
font-family: var(--font-display);
font-size: 26px;
font-weight: 800;
color: var(--color-black);
margin: 36px 0 18px;
}
.article-body :global(h3) {
font-family: var(--font-display);
font-size: 20px;
font-weight: 800;
color: var(--color-black);
margin: 28px 0 14px;
}
.article-body :global(p) { margin-bottom: 18px; }
.article-body :global(ul), .article-body :global(ol) {
margin: 16px 0;
padding-left: 24px;
}
.article-body :global(li) { margin-bottom: 10px; }
.article-body :global(a) {
color: var(--color-primary-dark);
font-weight: 600;
}
.article-body :global(a:hover) { text-decoration: underline; }
.article-body :global(blockquote) {
border-left: 4px solid var(--color-primary);
padding-left: 20px;
margin: 28px 0;
font-style: italic;
color: var(--color-gray-700);
}
.article-body :global(img) {
border-radius: var(--radius-md);
margin: 20px 0;
max-width: 100%;
}
.article-body :global(strong) { color: var(--color-black); font-weight: 800; }
/* Sidebar (soft tile) */
.sidebar-divider {
height: 1px;
background: var(--color-gray-200);
margin: 24px 0;
}
.tile-eyebrow-sm {
font-size: 11px;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 2px;
opacity: 0.7;
display: block;
}
.sidebar-actions {
display: flex;
flex-direction: column;
gap: 8px;
margin-top: 12px;
}
.btn-sm {
padding: 10px 20px;
font-size: 13px;
border-radius: var(--radius-md);
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
display: inline-flex;
align-items: center;
justify-content: center;
}
/* Section header */
.section-header { text-align: center; margin-bottom: 48px; }
.section-badge {
display: inline-block;
background: var(--color-primary);
color: var(--color-black);
padding: 8px 20px;
border-radius: var(--radius-full);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2px;
margin-bottom: 16px;
}
.section-title {
font-family: var(--font-display);
font-size: clamp(28px, 4vw, 40px);
font-weight: 900;
color: var(--color-black);
}
.section-title .highlight { color: var(--color-primary-dark); }
/* Related cards */
.related-link {
display: block;
text-decoration: none;
color: inherit;
}
.related-card-body {
display: flex;
flex-direction: column;
gap: 12px;
}
.related-image {
aspect-ratio: 16/10;
overflow: hidden;
border-radius: var(--radius-md);
background: var(--color-bg-soft);
margin: -8px -8px 4px;
}
.related-image img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: transform 0.5s ease;
}
.related-link:hover .related-image img { transform: scale(1.06); }
.related-date {
font-size: 12px;
font-weight: 600;
opacity: 0.65;
}
@media (max-width: 640px) {
.article-body { font-size: 16px; }
}
</style>
<script>
</script>
</PageShell>

View File

@@ -1,270 +0,0 @@
---
import Base from '../../layouts/Base.astro';
import Hero from '../../components/Hero.astro';
import { getCollection } from 'astro:content';
const blogPosts = await getCollection('blog');
const sortedPosts = blogPosts.sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
// Surface color rotation for variety across the post grid
const surfaces = ['white', 'soft', 'yellow', 'mint', 'purple-soft', 'teal'] as const;
function surfaceFor(i: number) {
return surfaces[i % surfaces.length];
}
---
<Base title="บทความ | MoreminiMore - รับทำเว็บไซต์ SEO AI Chatbot">
<Hero
eyebrow="บทความ"
title="ความรู้ด้านดิจิทัล"
lede="เทคนิคและความรู้ใหม่ๆ สำหรับธุรกิจไทย — อ่านจบใน 5 นาที เน้นลงมือทำ ไม่ใช่ทฤษฎี"
showStats={false} />
{sortedPosts.length > 0 && (
<section class="section section-bento featured-section">
<div class="container" style="position: relative; z-index: 1;">
<a href={`/blog/${sortedPosts[0].id}`} class="featured-tile-link">
<div class="bento-grid">
<div class="bento-tile span-7 surface-white">
<div class="featured-content">
<div class="featured-image">
{sortedPosts[0].data.image && (
<img src={sortedPosts[0].data.image} alt={sortedPosts[0].data.title} loading="eager" />
)}
</div>
</div>
</div>
<div class="bento-tile span-5 surface-yellow">
<div class="featured-aside">
<p class="featured-excerpt">{sortedPosts[0].data.excerpt}</p>
<div class="featured-meta">
<span class="featured-date">
{new Date(sortedPosts[0].data.date).toLocaleDateString('th-TH', { year: 'numeric', month: 'long', day: 'numeric' })}
</span>
</div>
<span class="read-more">
อ่านต่อ
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</span>
</div>
</div>
</div>
</a>
</div>
</section>
)}
<section class="section section-bento blog-section">
<div class="container" style="position: relative; z-index: 1;">
<div class="section-header reveal">
<span class="section-badge">บทความทั้งหมด</span>
<h2 class="section-title">บทความ <span class="highlight">ล่าสุด</span></h2>
</div>
{sortedPosts.length > 1 && (
<div class="bento-grid">
{sortedPosts.slice(1).map((post, i) => (
<a href={`/blog/${post.id}`} class="post-tile-link">
<div class="bento-tile span-4 reveal">
<div class="post-card-body">
{post.data.image && (
<div class="post-image">
<img src={post.data.image} alt={post.data.title} loading="lazy" />
</div>
)}
<p class="post-excerpt">{post.data.excerpt}</p>
<span class="post-date">
{new Date(post.data.date).toLocaleDateString('th-TH', { year: 'numeric', month: 'long', day: 'numeric' })}
</span>
</div>
</div>
</a>
))}
</div>
)}
</div>
</section>
<section class="section section-yellow cta-section">
<div class="container">
<div class="cta-content reveal">
<h2 class="cta-title">ต้องการความช่วยเหลือ?</h2>
<p class="cta-desc">ปรึกษาฟรี! เราพร้อมช่วยวิเคราะห์และให้คำแนะนำ</p>
<div class="cta-actions">
<a href="/contact" class="btn btn-dark btn-lg">ติดต่อเรา →</a>
<a href="tel:0809955945" class="btn btn-outline-dark btn-lg">080-995-5945</a>
</div>
</div>
</div>
</section>
</Base>
<style>
.section-soft { background: var(--color-bg-alt); }
.section-yellow { background: var(--color-primary); }
.section-bento { position: relative; overflow: hidden; }
.featured-section { background: var(--color-bg-alt); padding-top: 60px; padding-bottom: 60px; }
.blog-section { background: var(--color-white); }
/* Make the whole featured tile clickable without breaking inner link */
.featured-tile-link {
display: block;
text-decoration: none;
color: inherit;
}
.featured-content { display: flex; flex-direction: column; gap: 16px; }
.featured-image {
aspect-ratio: 16/10;
overflow: hidden;
border-radius: var(--radius-md);
background: var(--color-bg-soft);
}
.featured-image img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.featured-aside {
display: flex;
flex-direction: column;
gap: 16px;
}
.featured-excerpt {
font-size: 16px;
line-height: 1.7;
color: var(--color-black);
}
.featured-meta { font-size: 13px; }
.featured-date {
font-weight: 700;
color: var(--color-black);
opacity: 0.7;
}
.read-more {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--color-black);
font-family: var(--font-display);
font-weight: 800;
font-size: 14px;
text-transform: uppercase;
letter-spacing: 1px;
}
.read-more svg { width: 18px; height: 18px; }
/* Post grid cards */
.post-tile-link {
display: block;
text-decoration: none;
color: inherit;
}
.post-card-body {
display: flex;
flex-direction: column;
gap: 12px;
height: 100%;
}
.post-image {
aspect-ratio: 16/10;
overflow: hidden;
border-radius: var(--radius-md);
background: var(--color-bg-soft);
margin: -8px -8px 4px;
}
.post-image img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: transform 0.5s ease;
}
.post-tile-link:hover .post-image img { transform: scale(1.06); }
.post-excerpt {
font-size: 14px;
line-height: 1.6;
color: inherit;
opacity: 0.85;
}
.post-date {
font-size: 12px;
font-weight: 600;
opacity: 0.6;
margin-top: auto;
}
/* Section header */
.section-header { text-align: center; margin-bottom: 48px; }
.section-badge {
display: inline-block;
background: var(--color-primary);
color: var(--color-black);
padding: 8px 20px;
border-radius: var(--radius-full);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2px;
margin-bottom: 16px;
}
.section-title {
font-family: var(--font-display);
font-size: clamp(28px, 4vw, 40px);
font-weight: 900;
color: var(--color-black);
}
.section-title .highlight { color: var(--color-primary-dark); }
/* CTA */
.cta-content { text-align: center; max-width: 700px; margin: 0 auto; }
.cta-title {
font-family: var(--font-display);
font-size: clamp(28px, 4vw, 44px);
font-weight: 900;
color: var(--color-black);
margin-bottom: 16px;
}
.cta-desc {
font-size: 18px;
color: rgba(0, 0, 0, 0.7);
margin-bottom: 32px;
}
.cta-actions {
display: flex;
gap: 16px;
justify-content: center;
flex-wrap: wrap;
}
/* Reduce padding on bento tiles that are link wrappers so the image breathes */
.post-tile-link :global(.bento-tile) { padding: 16px; }
@media (max-width: 640px) {
.cta-actions { flex-direction: column; }
.cta-actions .btn { width: 100%; justify-content: center; }
}
</style>
<script>
</script>

View File

@@ -1,495 +1,53 @@
---
import Base from '../layouts/Base.astro';
import Hero from '../components/Hero.astro';
import Icon from '../components/Icon.astro';
// Service options for the form — with lucide icon names
const serviceOptions = [
{ value: 'webdev', label: 'AI-Enhanced Website (เว็บ + Chatbot + SEO)', icon: 'globe' },
{ value: 'automation', label: 'AI Automation (Workflow + Chatbot)', icon: 'cog' },
{ value: 'marketing', label: 'Online Marketing Automation (Email + LINE + Facebook)', icon: 'megaphone' },
{ value: 'seo', label: 'SEO + AI Content System', icon: 'search' },
{ value: 'consult', label: 'Tech Consult (Server / Data Pipeline)', icon: 'server' },
{ value: 'audit', label: 'Audit เว็บไซต์เดิมฟรี 30 นาที', icon: 'briefcase' },
{ value: 'unsure', label: 'ยังไม่แน่ใจ — ช่วยแนะนำ', icon: 'help' },
];
import PageShell from '../components/PageShell.astro';
import { problems } from '../data/site.js';
---
<Base title="ติดต่อเรา | MoreminiMore | รับทำเว็บไซต์ SEO AI Chatbot">
<Hero
eyebrow="30 นาที · ไม่มีค่าใช้จ่าย · ไม่มี commitment"
title="คุยกับ คนจริง ๆ ไม่ใช่ Bot"
lede="ตอบกลับภายใน 2 ชั่วโมง · เลือกช่องทางที่คุณสะดวก — LINE, โทร, Email หรือฟอร์ม"
showStats={false} />
<!-- QUICK CHANNEL PICKER (BENTO) -->
<section class="section section-bento">
<div class="container" style="position: relative; z-index: 1;">
<div class="bento-grid">
<div class="bento-tile span-4 surface-yellow">
<div class="channel-icon"><Icon name="message" size={32} /></div>
<p>คนที่อยากคุยเร็ว ๆ แบบเป็นกันเอง</p>
<p class="meta">ตอบใน 30 นาที (เวลาทำการ)</p>
<a href="https://line.me/ti/p/~@539hdlul" target="_blank" rel="noopener" class="btn btn-dark" style="margin-top: 16px;">ทักเลย →</a>
</div>
<div class="bento-tile span-4 surface-soft">
<div class="channel-icon"><Icon name="phone" size={32} /></div>
<p>คนที่อยากคุยยาว ๆ 510 นาที ถามตอบสด</p>
<p class="meta">รับสายทันที หรือโทรกลับภายใน 2 ชม.</p>
<a href="tel:0809955945" class="btn btn-dark" style="margin-top: 16px;">โทรเลย →</a>
</div>
<div class="bento-tile span-4 surface-purple-soft">
<div class="channel-icon"><Icon name="mail" size={32} /></div>
<p>คนที่อยากส่งรายละเอียดโปรเจกต์ + ไฟล์แนบ</p>
<p class="meta">ตอบภายใน 1 วันทำการ</p>
<a href="mailto:contact@moreminimore.com" class="btn btn-dark" style="margin-top: 16px;">ส่งอีเมล →</a>
</div>
</div>
</div>
</section>
<!-- CONTACT FORM + INFO (BENTO) -->
<section class="section form-section section-bento">
<div class="container" style="position: relative; z-index: 1;">
<div class="bento-grid">
<!-- FORM — big tile on the left -->
<div class="bento-tile span-8 surface-white">
<p class="form-subtitle">เราจะตอบกลับภายใน 2 ชั่วโมง (เวลาทำการ)</p>
<form class="contact-form" id="contact-form">
<div class="form-row">
<div class="form-group">
<label for="name" class="form-label">ชื่อ-นามสกุล *</label>
<input type="text" id="name" name="name" required class="form-input" placeholder="สมชาย ใจดี" />
</div>
<div class="form-group">
<label for="email" class="form-label">อีเมล *</label>
<input type="email" id="email" name="email" required class="form-input" placeholder="example@yourcompany.com" />
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="phone" class="form-label">เบอร์โทรศัพท์ <span class="optional">(ใส่ถ้าอยากให้โทรกลับ)</span></label>
<input type="tel" id="phone" name="phone" class="form-input" placeholder="080-xxx-xxxx" />
</div>
<div class="form-group">
<label for="budget" class="form-label">งบประมาณโดยประมาณ</label>
<select id="budget" name="budget" class="form-input">
<option value="">เลือกช่วงงบ</option>
<option value="under-20k">ต่ำกว่า 20,000 บาท</option>
<option value="20k-50k">20,00050,000 บาท</option>
<option value="50k-150k">50,000150,000 บาท</option>
<option value="150k-500k">150,000500,000 บาท</option>
<option value="over-500k">500,000 บาทขึ้นไป</option>
<option value="unsure">ยังไม่ได้กำหนด</option>
</select>
</div>
</div>
<div class="form-group">
<label for="service" class="form-label">บริการที่สนใจ</label>
<select id="service" name="service" class="form-input">
<option value="">เลือกบริการ (ไม่บังคับ)</option>
{serviceOptions.map(opt => (
<option value={opt.value}>{opt.label}</option>
))}
</select>
</div>
<div class="form-group">
<label for="message" class="form-label">รายละเอียดโปรเจกต์ *</label>
<textarea id="message" name="message" rows="5" required class="form-input" placeholder="เล่าสั้น ๆ ว่าธุรกิจคุณทำอะไร ปวดหัวเรื่องอะไร อยากได้ผลลัพธ์แบบไหน (13 บรรทัดพอ)"></textarea>
</div>
<button type="submit" class="btn btn-primary btn-submit">
<span class="btn-text">ส่งข้อความ</span>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3">
<path d="M5 12h14M12 5l7 7-7 7"/>
</svg>
</button>
<p class="form-helper">ไม่มี spam · ไม่มีขายของ · เข้า inbox เราโดยตรง</p>
</form>
<!-- Success message (hidden by default) -->
<div class="form-success" id="form-success" hidden>
<div class="success-icon">
<Icon name="checkCircle" size={44} />
</div>
<h3>ส่งแล้ว!</h3>
<p>เราจะตอบกลับภายใน 2 ชั่วโมง (ในเวลาทำการ) ถ้าเร่งด่วน ทัก LINE @moreminimore ครับ</p>
</div>
</div>
<div class="bento-tile span-4 surface-yellow">
<div class="info-icon"><Icon name="phone" size={24} /></div>
<p>โทรคุยสดได้เลย</p>
<p class="meta">จ-ศ 09:00-18:00</p>
<a href="tel:0809955945" class="btn btn-dark" style="margin-top: 12px;">โทรเลย →</a>
</div>
<div class="bento-tile span-4 surface-purple-soft">
<div class="info-icon"><Icon name="mail" size={24} /></div>
<p>เหมาะกับส่งรายละเอียดโปรเจกต์ + ไฟล์แนบ</p>
<p class="meta">ตอบภายใน 1 วันทำการ</p>
<a href="mailto:contact@moreminimore.com" class="btn btn-dark" style="margin-top: 12px;">ส่งอีเมล →</a>
</div>
<div class="bento-tile span-4 surface-mint">
<div class="info-icon"><Icon name="message" size={24} /></div>
<p>เร็วที่สุด ตอบใน 30 นาที (เวลาทำการ)</p>
<p class="meta">นอกเวลา? ทักทิ้งไว้ได้</p>
<a href="https://line.me/ti/p/~@539hdlul" target="_blank" rel="noopener" class="btn btn-dark" style="margin-top: 12px;">ทักเลย →</a>
</div>
<div class="bento-tile span-12 surface-dark">
<div class="info-icon"><Icon name="clock" size={24} /></div>
<p>นอกเวลาทำการ? ทัก LINE ทิ้งไว้ได้ ตอบเช้าวันถัดไป</p>
<p class="meta" style="color: rgba(255,255,255,0.7);">53 หมู่ 1 ต.บ้านแพ้ว อ.บ้านแพ้ว สมุทรสาคร 74120 · นัดเจอล่วงหน้า</p>
</div>
</div>
</div>
</section>
<!-- WHAT HAPPENS NEXT (BENTO) -->
<section class="section section-soft section-bento">
<div class="container" style="position: relative; z-index: 1;">
<div class="section-header reveal">
<span class="section-badge">หลังส่งฟอร์ม</span>
<h2 class="section-title">3 ขั้นตอนถัดไป — <span class="highlight">ไม่มีอะไรซับซ้อน</span></h2>
<PageShell
title="ติดต่อ | MoreminiMore"
description="ติดต่อ MoreminiMore เพื่อส่งโจทย์เว็บไซต์ การตลาด ระบบอัตโนมัติ หรือ AI ให้เราช่วยดูว่าควรเริ่มตรงไหน"
>
<section class="page-hero scene scene-light" data-scene="light">
<div class="page-hero-grid">
<div>
<p class="eyebrow">Contact</p>
<h1>ส่งโจทย์ให้เราดู แล้วค่อยตัดสินใจว่าจะทำอะไร</h1>
</div>
<div class="bento-grid">
<div class="bento-tile span-4 surface-yellow">
<p>คนจริง (ไม่ใช่ Bot) จะตอบ — ถามคำถามเพิ่ม 23 ข้อ เพื่อเข้าใจปัญหาคุณ</p>
</div>
<div class="bento-tile span-4 surface-soft">
<p>คุยผ่าน Zoom / โทร / นัดเจอที่ออฟฟิศ (กรุงเทพ / สมุทรสาคร) — ไม่มี script sales</p>
</div>
<div class="bento-tile span-4 surface-purple-soft">
<p>เอกสาร PDF ที่ระบุ scope, timeline, ราคา — ไม่ชอบตรงไหนคุยกันแก้ได้</p>
</div>
</div>
<p class="next-closing">ถ้าไม่ตรง → เราจะบอกตรง ๆ ว่า "ไม่เหมาะ" และแนะนำทางเลือกอื่น</p>
<p class="hero-lead">
ไม่ต้องเตรียม brief สมบูรณ์ แค่เล่าว่าตอนนี้ธุรกิจติดตรงไหน เราจะช่วยดูว่าควรถามอะไรต่อและควรเริ่มจากจุดไหน
</p>
</div>
</section>
<!-- PRE-SUBMIT FAQ (BENTO) -->
<section class="section section-bento">
<div class="container" style="position: relative; z-index: 1;">
<div class="section-header reveal">
<span class="section-badge">ก่อนกดส่ง</span>
<h2 class="section-title">4 คำถามที่คนถาม <span class="highlight">ก่อน</span> กดส่งฟอร์ม</h2>
<section class="page-section contact-layout">
<div class="glass-panel liquid-glass liquidGlass-wrapper contact-card">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="eyebrow">Start here</p>
<h2>เลือกปัญหาที่ใกล้ที่สุด</h2>
<div class="contact-problem-list">
{problems.map(([, label]) => <span>{label}</span>)}
</div>
<div class="bento-grid">
<div class="bento-tile span-6 surface-soft">
<p>ไม่ คุยแล้วคุณไม่ชอบก็ไม่เป็นไร ไม่มี follow-up ไม่มีขายของเพิ่ม</p>
</div>
<div class="bento-tile span-6 surface-soft">
<p>ทัก LINE @moreminimore ตรง ๆ จะเร็วกว่า — หรือโทร 080-995-5945</p>
</div>
<div class="bento-tile span-6 surface-yellow">
<p>จันทร์-ศุกร์ 09:00-18:00 ปกติ ถ้าคุณต่างจังหวัด/ต่างประเทศ นัดนอกเวลาได้ บอกล่วงหน้า 12 วัน</p>
</div>
<div class="bento-tile span-6 surface-purple-soft">
<p>ไม่ต้องเตรียมอะไรเลย แค่บอกธุรกิจคุณทำอะไร ปวดหัวเรื่องอะไร งบประมาณเท่าไหร่ ที่เหลือเราถามเอง</p>
</div>
</div>
<button class="button button-primary" type="button" data-open-lead>เปิดฟอร์มส่งโจทย์</button>
</div>
</section>
<section class="section section-yellow cta-section">
<div class="container">
<div class="cta-content reveal">
<h2 class="cta-title">หรือจะ <span class="highlight">อ่านก่อน</span> ก็ได้</h2>
<p class="cta-desc">ไม่มี commitment ไม่มี pressure ไม่มีใครตาม</p>
<div class="cta-actions">
<a href="/services" class="btn btn-dark btn-lg">ดูบริการทั้งหมด</a>
<a href="/portfolio" class="btn btn-outline-dark btn-lg">ดูผลงาน</a>
<a href="/faq" class="btn btn-outline-dark btn-lg">ดู FAQ</a>
<aside class="contact-info">
<p class="eyebrow">Contact info</p>
<h2>ช่องทางติดต่อ</h2>
<dl>
<div>
<dt>Email</dt>
<dd><a href="mailto:contact@moreminimore.com">contact@moreminimore.com</a></dd>
</div>
</div>
</div>
<div>
<dt>Phone</dt>
<dd><a href="tel:+66809955945">080-995-5945</a></dd>
</div>
</dl>
<p>
ถ้าโจทย์ยังไม่ชัด ให้ส่งเป็นภาษาธรรมดาได้เลย เช่น เว็บมีคนเข้าแต่ไม่ค่อยมีคนทัก หรือยิงแอดแล้วไม่แน่ใจว่างบหายไปตรงไหน
</p>
</aside>
</section>
</Base>
<style>
.section-bento {
position: relative;
overflow: hidden;
}
.form-section { background: var(--color-bg-alt); }
.section-soft { background: var(--color-bg-alt); }
.section-yellow { background: var(--color-primary); }
/* Channel tiles */
.channel-icon { font-size: 40px; margin-bottom: 12px; color: var(--color-black); }
.meta {
font-size: 13px;
color: var(--color-gray-600);
margin-top: 4px;
}
.surface-yellow .meta { color: rgba(0, 0, 0, 0.7); }
.surface-purple-soft .meta { color: var(--color-gray-700); }
.surface-mint .meta { color: var(--color-gray-700); }
.surface-dark .meta { color: rgba(255, 255, 255, 0.75); }
/* Section header */
.section-header { text-align: center; margin-bottom: 48px; }
.section-badge {
display: inline-block;
background: var(--color-primary);
color: var(--color-black);
padding: 8px 20px;
border-radius: var(--radius-full);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2px;
margin-bottom: 16px;
}
.section-title {
font-family: var(--font-display);
font-size: clamp(28px, 4vw, 44px);
font-weight: 900;
line-height: 1.15;
color: var(--color-black);
margin-bottom: 16px;
}
.section-title .highlight { color: var(--color-primary-dark); }
/* Info icon (used inside separate info tiles) */
.info-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
background: var(--color-white);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-md);
margin-bottom: 12px;
color: var(--color-black);
}
.surface-dark .info-icon {
background: rgba(255, 255, 255, 0.12);
border-color: rgba(255, 255, 255, 0.2);
color: var(--color-primary);
}
.surface-yellow .info-icon {
background: var(--color-black);
border-color: var(--color-black);
color: var(--color-primary);
}
/* Form styles (kept, just slightly tightened) */
.form-subtitle {
font-size: 15px;
color: var(--color-gray-600);
margin-bottom: 24px;
line-height: 1.5;
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--color-gray-700);
margin-bottom: 8px;
}
.form-label .optional {
text-transform: none;
font-weight: 400;
color: var(--color-gray-500);
}
.form-input {
width: 100%;
padding: 14px 16px;
font-family: var(--font-body);
font-size: 15px;
color: var(--color-black);
background: var(--color-white);
border: 2px solid var(--color-gray-200);
border-radius: var(--radius-md);
transition: all 0.2s ease;
}
.form-input::placeholder { color: var(--color-gray-400); }
.form-input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(254, 212, 0, 0.15);
}
textarea.form-input { resize: vertical; min-height: 120px; }
.btn-submit {
width: 100%;
margin-top: 8px;
}
.form-helper {
text-align: center;
margin-top: 12px;
font-size: 13px;
color: var(--color-gray-500);
}
.form-success {
text-align: center;
padding: 60px 20px;
}
.success-icon {
font-size: 64px;
margin-bottom: 16px;
color: var(--color-primary-dark);
}
.form-success h3 {
font-family: var(--font-display);
font-size: 28px;
font-weight: 800;
color: var(--color-black);
margin-bottom: 12px;
}
.form-success p {
font-size: 16px;
color: var(--color-gray-600);
line-height: 1.6;
max-width: 400px;
margin: 0 auto;
}
/* Next step closing line */
.next-closing {
text-align: center;
margin-top: 32px;
font-size: 15px;
color: var(--color-gray-700);
}
/* CTA */
.cta-content { text-align: center; max-width: 700px; margin: 0 auto; }
.cta-title {
font-family: var(--font-display);
font-size: clamp(28px, 4vw, 44px);
font-weight: 900;
color: var(--color-black);
margin-bottom: 16px;
}
.cta-title .highlight { color: var(--color-black); text-decoration: underline; text-underline-offset: 6px; text-decoration-thickness: 4px; }
.cta-desc {
font-size: 18px;
color: rgba(0, 0, 0, 0.7);
margin-bottom: 32px;
}
.cta-actions {
display: flex;
gap: 16px;
justify-content: center;
flex-wrap: wrap;
}
@media (max-width: 1024px) {
.form-row { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
.cta-actions { flex-direction: column; }
.cta-actions .btn { width: 100%; justify-content: center; }
}
</style>
<script>
// Form submission — wire to contact-submit.ts (Apps Script backend)
// Per plan 2026-06-13 round 2 #4: real working form, not placeholder.
const form = document.getElementById('contact-form') as HTMLFormElement;
const success = document.getElementById('form-success');
form?.addEventListener('submit', async (e) => {
e.preventDefault();
const btn = form.querySelector('.btn-submit') as HTMLButtonElement;
const btnText = btn.querySelector('.btn-text');
const originalText = btnText?.textContent;
if (btnText) btnText.textContent = 'กำลังส่ง...';
btn.disabled = true;
// Lazy-load submitContact to keep main bundle small
const { submitContact, isDevMode } = await import('../lib/contact-submit');
const formData = new FormData(form);
const data = {
name: String(formData.get('name') ?? ''),
phone: String(formData.get('phone') ?? ''),
email: String(formData.get('email') ?? ''),
service: String(formData.get('service') ?? 'other'),
message: String(formData.get('message') ?? ''),
variant: 'full' as const,
};
const result = await submitContact(data);
if (result.ok) {
form.hidden = true;
if (success) success.hidden = false;
// Append dev-mode hint to success message
if (result.devMode) {
const hint = success?.querySelector('p');
if (hint) hint.textContent = '(dev mode — submission logged to console, not actually sent)';
}
success?.scrollIntoView({ behavior: 'smooth', block: 'center' });
} else {
alert('ส่งไม่สำเร็จ: ' + (result.error ?? 'unknown error') + '\n\nลองทัก LINE: @moreminimore หรือโทร 080-995-5945');
if (btnText) btnText.textContent = originalText;
btn.disabled = false;
}
});
</script>
</PageShell>

View File

@@ -1,314 +1,47 @@
---
import Base from '../layouts/Base.astro';
import Hero from '../components/Hero.astro';
import { getCollection } from 'astro:content';
const faqItems = await getCollection('faq');
const categories = ['บริการ', 'ราคา', 'ระยะเวลา', 'AI & เทคนิค', 'หลังการขาย'];
// Group FAQ items by category (preserve original order within each category)
const groupedFaq = categories
.map(cat => ({
category: cat,
items: faqItems.filter(f => f.data.category === cat),
}))
.filter(g => g.items.length > 0);
// Split each category's items into chunks of 2 (or 3 for the last chunk if odd count)
function chunkItems<T>(arr: T[], size: number): T[][] {
const chunks: T[][] = [];
for (let i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
}
// Pre-compute all FAQ tiles with assigned spans + surfaces for visual rhythm
// Rotation: yellow, soft, purple-soft, mint, teal, dark, coral, purple, mint
const surfaceRotation = ['yellow', 'soft', 'purple-soft', 'mint', 'teal', 'dark', 'coral', 'purple', 'mint'] as const;
// Span strategy for category tile pairs: 7+5, 5+7, 8+4, 4+8, 7+5 ... avoid 6+6
const spanPairs = [[7, 5], [5, 7], [8, 4], [4, 8], [7, 5]] as const;
interface FaqTile {
category: string;
items: typeof faqItems;
surface: typeof surfaceRotation[number];
span: 4 | 5 | 7 | 8;
tileIndex: number; // 0, 1 within category
isFirst: boolean;
isLast: boolean;
}
const faqTiles: FaqTile[] = [];
groupedFaq.forEach((group, gIdx) => {
const chunks = chunkItems(group.items, 2);
const pair = spanPairs[gIdx % spanPairs.length];
chunks.forEach((chunk, cIdx) => {
const tileSurface = surfaceRotation[faqTiles.length % surfaceRotation.length];
faqTiles.push({
category: group.category,
items: chunk,
surface: tileSurface,
span: (pair[cIdx] ?? 6) as 4 | 5 | 7 | 8,
tileIndex: cIdx,
isFirst: cIdx === 0,
isLast: cIdx === chunks.length - 1,
});
});
});
import PageShell from '../components/PageShell.astro';
import { faqs } from '../data/site.js';
---
<Base title="คำถามที่พบบ่อย | MoreminiMore | รับทำเว็บไซต์ SEO AI Chatbot">
<Hero
eyebrow="FAQ"
title="คำถามที่ลูกค้าถามบ่อยที่สุด"
lede="30+ คำถามที่รวบรวมจากแชต LINE จริง ๆ ไม่ใช่แต่งขึ้นเอง"
showStats={false} />
<!-- FAQ CATEGORIES (BENTO) -->
<section class="section section-bento">
<div class="container" style="position: relative; z-index: 1;">
<div class="bento-grid">
{faqTiles.map((tile) => (
<div class="bento-tile">
<div class="faq-list">
{tile.items.map((item) => (
<details class="faq-item">
<summary class="faq-question">
<span class="question-text">{item.data.question}</span>
<span class="faq-toggle">+</span>
</summary>
<div class="faq-answer">
<p>{item.data.answer}</p>
</div>
</details>
))}
</div>
</div>
))}
<!-- OTHER TOPICS — full-width tile with tag cloud -->
<div class="bento-tile span-12 surface-soft">
<div class="tag-cloud">
<span class="topic-tag">โฮสติ้ง</span>
<span class="topic-tag">โดเมน</span>
<span class="topic-tag">SSL</span>
<span class="topic-tag">ใบเสนอราคา</span>
<span class="topic-tag">ใบกำกับภาษี</span>
<span class="topic-tag">สัญญา</span>
<span class="topic-tag">NDA</span>
<span class="topic-tag">ลิขสิทธิ์งาน</span>
<span class="topic-tag">ทีมงาน</span>
<span class="topic-tag">ขนาดทีม</span>
<span class="topic-tag">ที่ตั้งบริษัท</span>
<span class="topic-tag">ตัวอย่างงาน</span>
<span class="topic-tag">ขอดูเว็บจริง</span>
<span class="topic-tag">นัดคุยนอกสถานที่</span>
</div>
</div>
</div>
</div>
</section>
<!-- QUICK CHANNELS (BENTO) -->
<section class="section section-bento">
<div class="container" style="position: relative; z-index: 1;">
<div class="section-header reveal">
<span class="section-badge">ช่องทางติดต่อ</span>
<h2 class="section-title">ไม่เจอคำตอบ? <span class="highlight">ถามตรง ๆ เลย</span></h2>
<PageShell
title="คำถามที่พบบ่อย | MoreminiMore"
description="คำถามที่พบบ่อยเกี่ยวกับบริการ เว็บไซต์ การตลาด ระบบอัตโนมัติ AI ราคา และวิธีทำงานของ MoreminiMore"
>
<section class="page-hero scene scene-light" data-scene="light">
<div class="page-hero-grid">
<div>
<p class="eyebrow">FAQ</p>
<h1>คำถามที่ควรถามก่อนเริ่มทำอะไรเพิ่ม</h1>
</div>
<div class="bento-grid">
<div class="bento-tile span-4 surface-yellow">
<p>คนที่อยากคุยเร็ว ๆ แบบเป็นกันเอง</p>
<p><strong>ตอบใน 30 นาที (เวลาทำการ)</strong></p>
<a href="https://line.me/ti/p/~@539hdlul" target="_blank" rel="noopener" class="btn btn-dark" style="margin-top: 16px;">ทักเลย →</a>
</div>
<div class="bento-tile span-4 surface-soft">
<p>คนที่อยากคุยยาว ๆ 510 นาที ถามตอบสด</p>
<p><strong>จ-ศ 09:00-18:00</strong></p>
<a href="tel:0809955945" class="btn btn-dark" style="margin-top: 16px;">โทรเลย →</a>
</div>
<div class="bento-tile span-4 surface-purple-soft">
<p>คนที่อยากส่งรายละเอียดโปรเจกต์ + ไฟล์แนบ</p>
<p><strong>ตอบภายใน 1 วัน</strong></p>
<a href="mailto:contact@moreminimore.com" class="btn btn-dark" style="margin-top: 16px;">ส่งอีเมล →</a>
</div>
</div>
<p class="hero-lead">
ถ้ายังไม่แน่ใจว่าควรทำเว็บ ยิงแอด วางระบบ หรือใช้ AI ก่อน คำตอบเหล่านี้จะช่วยให้เห็นภาพเบื้องต้น
</p>
</div>
</section>
<section class="section section-yellow cta-section">
<div class="container">
<div class="cta-content reveal">
<h2 class="cta-title">พร้อมคุยรายละเอียด?</h2>
<p class="cta-desc">นัดปรึกษาฟรี 30 นาที ผ่าน Zoom หรือนัดเจอที่ออฟฟิศ (กรุงเทพ/สมุทรสาคร)</p>
<div class="cta-actions">
<a href="/contact" class="btn btn-dark btn-lg">นัดปรึกษา →</a>
<a href="https://line.me/ti/p/~@539hdlul" target="_blank" rel="noopener" class="btn btn-outline-dark btn-lg">ทัก LINE ตอนนี้</a>
</div>
</div>
<section class="page-section">
<div class="faq-list">
{faqs.map((item) => (
<article class="faq-item liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<span>{item.category}</span>
<h2>{item.question}</h2>
<p>{item.answer}</p>
</article>
))}
</div>
</section>
</Base>
<style>
.section-bento {
position: relative;
overflow: hidden;
}
.faq-list { display: flex; flex-direction: column; gap: 10px; margin-top: 4px; }
.faq-item {
background: var(--color-white);
border-radius: var(--radius-md);
border: 1px solid var(--color-gray-200);
overflow: hidden;
transition: all 0.3s ease;
}
.faq-item[open] { border-color: var(--color-primary); }
.faq-item:hover { box-shadow: var(--shadow-sm); }
/* When inside a yellow surface, change item background to be visible */
.surface-yellow .faq-item { background: var(--color-white); }
.surface-yellow .faq-item[open] { border-color: var(--color-black); }
.faq-question {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 18px;
cursor: pointer;
list-style: none;
transition: background 0.2s ease;
}
.faq-question::-webkit-details-marker { display: none; }
.faq-question:hover { background: var(--color-bg-alt); }
.question-text {
flex: 1;
font-family: var(--font-display);
font-size: 15px;
font-weight: 700;
color: var(--color-black);
padding-right: 16px;
}
.faq-toggle {
font-size: 22px;
font-weight: 300;
color: var(--color-primary-dark);
flex-shrink: 0;
line-height: 1;
}
.faq-item[open] .faq-toggle { transform: rotate(45deg); }
.faq-answer {
padding: 0 18px 16px;
}
.faq-answer p {
font-size: 14px;
line-height: 1.7;
color: var(--color-gray-700);
white-space: pre-line;
}
/* Tag cloud */
.tag-cloud {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.topic-tag {
display: inline-block;
padding: 8px 16px;
background: var(--color-white);
color: var(--color-gray-700);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-full);
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
}
.topic-tag:hover {
background: var(--color-primary);
border-color: var(--color-primary);
color: var(--color-black);
}
/* Section header */
.section-header { text-align: center; margin-bottom: 48px; }
.section-badge {
display: inline-block;
background: var(--color-primary);
color: var(--color-black);
padding: 8px 20px;
border-radius: var(--radius-full);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2px;
margin-bottom: 16px;
}
.section-title {
font-family: var(--font-display);
font-size: clamp(28px, 4vw, 44px);
font-weight: 900;
line-height: 1.15;
color: var(--color-black);
margin-bottom: 16px;
}
.section-title .highlight { color: var(--color-primary-dark); }
.section-soft { background: var(--color-bg-alt); }
.section-yellow { background: var(--color-primary); }
/* CTA */
.cta-content { text-align: center; max-width: 700px; margin: 0 auto; }
.cta-title {
font-family: var(--font-display);
font-size: clamp(28px, 4vw, 44px);
font-weight: 900;
color: var(--color-black);
margin-bottom: 16px;
}
.cta-desc {
font-size: 18px;
color: rgba(0, 0, 0, 0.7);
margin-bottom: 32px;
}
.cta-actions {
display: flex;
gap: 16px;
justify-content: center;
flex-wrap: wrap;
}
@media (max-width: 640px) {
.cta-actions { flex-direction: column; }
.cta-actions .btn { width: 100%; justify-content: center; }
.faq-question { padding: 14px 16px; }
.question-text { font-size: 14px; }
}
</style>
<script>
</script>
<section class="final-cta">
<div class="glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="eyebrow">Still unsure?</p>
<h2>ถ้าคำถามของคุณไม่อยู่ในนี้ ส่งโจทย์มาให้เราดูได้</h2>
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
</div>
</section>
</PageShell>

View File

@@ -1,63 +1,453 @@
---
/**
* MOREMINIMORE - INDEX (home)
* Per plan 2026-06-13: 9 v6 sections in order
* 1. Hero (terminal+stats)
* 2. CaseStudy (Dataroot flagship)
* 3. Services (4 from collection)
* 4. Callout (yellow pullquote)
* 5. Portfolio (pinned 3)
* 6. Process (4-col hardcoded)
* 7. Pricing (2 webdev tiers)
* 8. Faq (top 4 from collection)
* 9. Contact (prompt form)
*/
import Base from '../layouts/Base.astro';
import Hero from '../components/Hero.astro';
import CaseStudy from '../components/CaseStudy.astro';
import Services from '../components/Services.astro';
import Callout from '../components/Callout.astro';
import Portfolio from '../components/Portfolio.astro';
import Process from '../components/Process.astro';
import Pricing from '../components/Pricing.astro';
import Faq from '../components/Faq.astro';
import Contact from '../components/Contact.astro';
import '../styles/global.css';
const formEndpoint = '';
const problems = [
['website_no_leads', 'เว็บมีอยู่แล้ว แต่ไม่ค่อยมีลูกค้าทัก'],
['ads_not_worth_it', 'ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม'],
['wrong_leads', 'มีคนทักมา แต่ไม่ใช่ลูกค้าที่ใช่'],
['slow_or_error_work', 'ทีมงานทำงานเดิม ๆ แต่ทำงานช้า หรือผิดพลาดบ่อย'],
['ai_not_sure', 'อยากใช้ AI แต่ไม่รู้เริ่มตรงไหน'],
['not_sure', 'ยังไม่แน่ใจว่าควรแก้อะไรก่อน'],
];
const services = [
{
name: 'Website Development',
slug: 'website-development',
headline: 'เว็บที่ช่วยให้ลูกค้ารู้ว่าควรทักเรื่องอะไร',
copy: 'เหมาะกับธุรกิจที่มีเว็บแล้วแต่ลูกค้ายังไม่ค่อยติดต่อ หรืออยากเริ่มเว็บใหม่ให้วัดผลได้ตั้งแต่วันแรก',
},
{
name: 'Marketing Consult',
slug: 'marketing-consult',
headline: 'การตลาดที่ใช้งบคุ้มขึ้นจากข้อมูลจริง',
copy: 'เหมาะกับธุรกิจที่ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม หรือมีคนทักมาแล้วไม่ใช่ลูกค้าที่ควรได้',
},
{
name: 'Automation Workflow',
slug: 'automation-workflow',
headline: 'ระบบที่ลดงานช้าและงานผิดพลาด',
copy: 'เหมาะกับทีมที่ทำงานเดิม ๆ ซ้ำทุกวัน ใช้เวลานาน หรือมีจุดผิดพลาดที่แก้ไม่จบ',
},
{
name: 'AI Consult',
slug: 'ai-consult',
headline: 'AI ที่ช่วยทีมทำงาน ไม่ใช่แค่ของเล่นใหม่',
copy: 'เหมาะกับธุรกิจที่อยากใช้ AI แต่ยังไม่แน่ใจว่างานไหนควรเริ่มก่อนและใช้อย่างไรให้ปลอดภัย',
},
];
const portfolio = [
{
name: 'Jet Industries',
image: '/images/portfolio/jetindustries.png',
href: 'https://jetindustries.co.th',
tag: 'Featured credibility',
description: 'เว็บไซต์องค์กรผู้ผลิตพลาสติกฉีดขึ้นรูป ประสบการณ์กว่า 40 ปี',
featured: true,
},
{
name: 'เทรนเนอร์ซันนี่',
image: '/images/portfolio/trainersunny.png',
href: 'https://trainersunny.com',
tag: 'Featured visual',
description: 'เว็บไซต์ personal brand และหลักสูตรอบรมที่มีภาพจำชัด',
featured: true,
},
{
name: 'Dealplustech',
image: '/images/portfolio/dealplustech.png',
href: 'https://www.dealplustech.co.th',
tag: 'Website Development',
description: 'เว็บไซต์ระบบน้ำและสุขภัณฑ์คุณภาพสูงสำหรับโรงงานและบ้านเรือน',
},
{
name: 'Underdog Marketing',
image: '/images/portfolio/underdog.png',
href: 'https://underdog.run',
tag: 'Website Development',
description: 'แพลตฟอร์มบทความการตลาดที่ใช้งานง่ายและ SEO friendly',
},
{
name: 'ทวนทอง 99',
image: '/images/portfolio/tuanthong.png',
href: 'https://tuanthong99.com',
tag: 'E-commerce',
description: 'เว็บไซต์สินค้าอุปโภคบริโภคและสมุนไพรไทย',
},
{
name: 'สำนักงานกฎหมาย ตถาตา',
image: '/images/portfolio/lawyernoom.png',
href: 'https://lawyernoom.com',
tag: 'Website Development',
description: 'เว็บไซต์สำนักงานกฎหมายที่เน้นความน่าเชื่อถือ',
},
];
const process = [
['เข้าใจธุรกิจ', 'ทำความรู้จักเป้าหมาย ลูกค้า และปัญหาที่เจอจริง'],
['ดูข้อมูล', 'เช็กเว็บ แอด ลูกค้า ขั้นตอนทำงาน หรือข้อมูลที่มีอยู่'],
['เลือกทางที่คุ้ม', 'เสนอสิ่งที่ควรทำก่อน ไม่ทำทุกอย่างพร้อมกัน'],
['ลงมือและวัดผล', 'ทำให้ใช้งานได้จริง แล้วดูผลเพื่อปรับต่อ'],
];
---
<Base title="MoreminiMore - ที่ปรึกษาเว็บ การตลาด และ AI สำหรับ SME ไทย">
<Hero />
<!doctype html>
<html lang="th">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="description" content="MoreminiMore ช่วย SME ดูข้อมูลจริงก่อนตัดสินใจทำเว็บ การตลาด AI หรือระบบอัตโนมัติ เพื่อเลือกสิ่งที่ควรทำให้คุ้มที่สุด" />
<meta name="theme-color" content="#f8f5ea" />
<title>MoreminiMore | ธุรกิจไม่ควรเสียเงินกับสิ่งที่ยังไม่รู้ว่าคุ้มไหม</title>
</head>
<body>
<div class="background-stage" aria-hidden="true">
<svg class="coded-background" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice">
<defs>
<radialGradient id="Gradient1Home" cx="50%" cy="50%" fx="0.441602%" fy="50%" r=".5">
<animate attributeName="fx" dur="34s" values="0%;3%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(255, 0, 255, 1)" />
<stop offset="100%" stop-color="rgba(255, 0, 255, 0)" />
</radialGradient>
<radialGradient id="Gradient2Home" cx="50%" cy="50%" fx="2.68147%" fy="50%" r=".5">
<animate attributeName="fx" dur="23.5s" values="0%;3%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(255, 255, 0, 1)" />
<stop offset="100%" stop-color="rgba(255, 255, 0, 0)" />
</radialGradient>
<radialGradient id="Gradient3Home" cx="50%" cy="50%" fx="0.836536%" fy="50%" r=".5">
<animate attributeName="fx" dur="21.5s" values="0%;3%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(0, 255, 255, 1)" />
<stop offset="100%" stop-color="rgba(0, 255, 255, 0)" />
</radialGradient>
<radialGradient id="Gradient4Home" cx="50%" cy="50%" fx="4.56417%" fy="50%" r=".5">
<animate attributeName="fx" dur="23s" values="0%;5%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(0, 255, 0, 1)" />
<stop offset="100%" stop-color="rgba(0, 255, 0, 0)" />
</radialGradient>
<radialGradient id="Gradient5Home" cx="50%" cy="50%" fx="2.65405%" fy="50%" r=".5">
<animate attributeName="fx" dur="24.5s" values="0%;5%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(0, 0, 255, 1)" />
<stop offset="100%" stop-color="rgba(0, 0, 255, 0)" />
</radialGradient>
<radialGradient id="Gradient6Home" cx="50%" cy="50%" fx="0.981338%" fy="50%" r=".5">
<animate attributeName="fx" dur="25.5s" values="0%;5%;0%" repeatCount="indefinite" />
<stop offset="0%" stop-color="rgba(255, 0, 0, 1)" />
<stop offset="100%" stop-color="rgba(255, 0, 0, 0)" />
</radialGradient>
</defs>
<CaseStudy
client="Dataroot"
url="https://erp.dataroot.asia"
image="/images/portfolio/dataroot.png"
stats={[
{ value: '+373<em>%</em>', label: 'impression', coord: 'A.1' },
{ value: '+114<em>%</em>', label: 'click', coord: 'A.2' },
{ value: '28<em>%</em>', label: 'ad_spend', coord: 'A.3' },
]}
quote="เราไม่ได้ยิงโฆษณาเก่ง <em>เราแค่ดูสถิติ</em>"
deck="Dataroot เดิมยิงโฆษณาแบบกว้าง — ได้คลิกเยอะ แต่ Lead คุณภาพน้อย"
logs={[
{ ts: 'ขั้นที่ 1', level: 'INFO', text: 'วิเคราะห์ข้อมูล 3 เดือนย้อนหลัง' },
{ ts: 'ขั้นที่ 2', level: 'SUCCESS', text: 'แยกกลุ่มเป้าหมาย: 4 segments' },
{ ts: 'ขั้นที่ 3', level: 'SUCCESS', text: 'ได้ผลลัพธ์ +373% impression' },
]}
ctaPrimary={{ text: 'อ่านเคสเต็ม →', href: '/portfolio' }}
ctaSecondary={{ text: 'ดูผลงานอื่น', href: '/portfolio' }}
/>
<rect x="13.744%" y="1.18473%" width="100%" height="100%" fill="url(#Gradient1Home)" transform="rotate(334.41 50 50)">
<animate attributeName="x" dur="20s" values="25%;0%;25%" repeatCount="indefinite" />
<animate attributeName="y" dur="21s" values="0%;25%;0%" repeatCount="indefinite" />
<animateTransform attributeName="transform" type="rotate" from="0 50 50" to="360 50 50" dur="7s" repeatCount="indefinite" />
</rect>
<rect x="-2.17916%" y="35.4267%" width="100%" height="100%" fill="url(#Gradient2Home)" transform="rotate(255.072 50 50)">
<animate attributeName="x" dur="23s" values="-25%;0%;-25%" repeatCount="indefinite" />
<animate attributeName="y" dur="24s" values="0%;50%;0%" repeatCount="indefinite" />
<animateTransform attributeName="transform" type="rotate" from="0 50 50" to="360 50 50" dur="12s" repeatCount="indefinite" />
</rect>
<rect x="9.00483%" y="14.5733%" width="100%" height="100%" fill="url(#Gradient3Home)" transform="rotate(139.903 50 50)">
<animate attributeName="x" dur="25s" values="0%;25%;0%" repeatCount="indefinite" />
<animate attributeName="y" dur="12s" values="0%;25%;0%" repeatCount="indefinite" />
<animateTransform attributeName="transform" type="rotate" from="360 50 50" to="0 50 50" dur="9s" repeatCount="indefinite" />
</rect>
</svg>
</div>
<a class="skip-link" href="#main">ข้ามไปยังเนื้อหา</a>
<Services />
<header class="site-nav liquid-glass liquidGlass-wrapper" data-nav>
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<a class="brand" href="/" aria-label="MoreminiMore">
<img src="/images/logos/logo-long-black.png" width="205" height="36" alt="MoreminiMore" />
</a>
<Callout text="การจ่ายเงินซื้อ AI ไม่ได้ทำให้ธุรกิจดีขึ้น — <em>การวางระบบให้ AI ทำงานแทนงานซ้ำ ๆ</em> ต่างหากที่ทำให้พนักงานมีเวลาไปทำงานที่สร้างมูลค่า" />
<button class="nav-toggle" type="button" aria-controls="nav-menu" aria-expanded="false" data-nav-toggle>
เมนู
</button>
<Portfolio />
<nav id="nav-menu" class="nav-menu" aria-label="เมนูหลัก" data-nav-menu>
<a href="/">หน้าแรก</a>
<div class="nav-service">
<button type="button" aria-expanded="false" data-service-toggle>บริการ</button>
<div class="service-mega" data-service-menu>
{services.map((service) => (
<a href={`/services/${service.slug}/`}>
<strong>{service.name}</strong>
<span>{service.headline}</span>
</a>
))}
</div>
</div>
<a href="/portfolio/">ผลงาน</a>
<a href="/about/">เกี่ยวกับ</a>
<a href="/blog/">บทความ</a>
<a href="/contact/">ติดต่อ</a>
</nav>
<Process />
<button class="nav-cta" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
</header>
<Pricing />
<main id="main">
<section id="home" class="hero scene scene-light" data-scene="light">
<div class="hero-grid">
<div class="hero-copy">
<p class="eyebrow">พาร์ทเนอร์สำหรับ SME ที่อยากตัดสินใจให้คุ้มขึ้น</p>
<h1 class="desktop-title">
<span>ธุรกิจไม่ควร</span>
<span>เสียเงินกับสิ่งที่ยัง</span>
<span>ไม่รู้ว่าคุ้มไหม</span>
</h1>
<h1 class="mobile-title" aria-hidden="true">
<span>ธุรกิจ</span>
<span>ไม่ควร</span>
<span>เสียเงิน</span>
<span>กับสิ่งที่ยัง</span>
<span>ไม่รู้ว่า</span>
<span>คุ้มไหม</span>
</h1>
<p class="hero-lead">
เราช่วย SME ดูข้อมูลจริงก่อนตัดสินใจทำเว็บ การตลาด AI หรือระบบอัตโนมัติ เพื่อเลือกสิ่งที่ควรทำอย่างมีประสิทธิภาพ และเหมาะกับธุรกิจของคุณ
</p>
<div class="hero-actions">
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
<a class="button button-secondary" href="#portfolio">ดูผลงานก่อน</a>
</div>
</div>
<Faq limit={4} />
<div class="hero-panel glass-panel liquid-glass liquidGlass-wrapper" data-depth-card>
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="panel-kicker">Decision snapshot</p>
<h2>หลังคุยกัน คุณจะเห็นภาพว่าอะไรควรทำก่อน</h2>
<div class="decision-preview" aria-label="ตัวอย่างสรุปหลังดูโจทย์">
<article>
<span>Do first</span>
<strong>แก้จุดที่ทำให้ลูกค้าไม่ทัก</strong>
</article>
<article>
<span>Hold</span>
<strong>ชะลอสิ่งที่ยังวัดผลไม่ได้</strong>
</article>
<article>
<span>Measure</span>
<strong>ตั้งสัญญาณว่าควรไปต่อหรือหยุด</strong>
</article>
</div>
<button class="text-link" type="button" data-open-lead>ขอให้ช่วยดูโจทย์</button>
</div>
</div>
</section>
<Contact variant="prompt" />
</Base>
<section class="problem-strip">
<div>
<p class="eyebrow">Problem first</p>
<h2>คุณเล่าปัญหา เราช่วยหา service ที่เหมาะสม</h2>
</div>
<p>
เว็บนี้ไม่เริ่มจากแพ็กเกจ เพราะธุรกิจแต่ละเจอปัญหาไม่เหมือนกัน ส่งโจทย์สั้น ๆ มาได้เลย แล้วเราจะช่วยดูว่าควรเริ่มจากเว็บ แอด ระบบทำงาน หรือ AI
</p>
</section>
<section id="dataroot" class="case-section scene scene-dark" data-scene="dark">
<div class="section-heading">
<p class="eyebrow">Diagnosis story</p>
<h2>Dataroot: ก่อนแก้ ต้องรู้ก่อนว่าข้อมูลกำลังบอกอะไร</h2>
</div>
<div class="case-grid">
<article class="case-story glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<div class="story-step">
<span>01</span>
<h3>ปัญหา</h3>
<p>ยิงโฆษณาและทำการตลาดอยู่แล้ว แต่ต้องดูให้ชัดว่าคนที่เข้ามาใช่ลูกค้าที่ควรได้หรือไม่</p>
</div>
<div class="story-step">
<span>02</span>
<h3>สิ่งที่พบ</h3>
<p>กลุ่มเป้าหมายและข้อความบางส่วนดึงความสนใจได้ แต่ยังไม่พาคนที่มี intent ตรงพอเข้ามา</p>
</div>
<div class="story-step">
<span>03</span>
<h3>สิ่งที่ปรับ</h3>
<p>ปรับการมองกลุ่มเป้าหมายและการวัดผลจากข้อมูลจริง ไม่ใช่เลือกจากสิ่งที่ดูน่าจะคลิกง่าย</p>
</div>
</article>
<div class="case-proof" data-depth-card>
<img src="/images/portfolio/dataroot.png" alt="Dataroot website screenshot" loading="lazy" />
<div class="metric-card">
<strong>+373%</strong>
<span>impression</span>
</div>
<div class="metric-card">
<strong>+114.2%</strong>
<span>click</span>
</div>
<div class="metric-card">
<strong>-28.3%</strong>
<span>ad spend</span>
</div>
</div>
</div>
</section>
<section id="services" class="services-section scene scene-light" data-scene="light">
<div class="section-heading">
<p class="eyebrow">Services</p>
<h2>บริการมีไว้ให้เราเลือกให้เหมาะกับปัญหา ไม่ใช่ให้คุณเดาเอง</h2>
</div>
<div class="service-grid">
{services.map((service) => (
<article class="service-card liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<span>{service.name}</span>
<h3>{service.headline}</h3>
<p>{service.copy}</p>
</article>
))}
</div>
</section>
<section id="portfolio" class="portfolio-section scene scene-dark" data-scene="dark">
<div class="section-heading">
<p class="eyebrow">Portfolio</p>
<h2>งานเว็บที่ต้องดูน่าเชื่อถือก่อน แล้วค่อยสวยแบบมีเหตุผล</h2>
<a class="section-link" href="/portfolio/">ดูผลงานทั้งหมด</a>
</div>
<div class="portfolio-grid">
{portfolio.slice(0, 5).map((item) => (
<a class:list={['portfolio-card', item.featured && 'featured']} href={item.href} target="_blank" rel="noopener">
<img src={item.image} alt={`${item.name} website screenshot`} loading={item.featured ? 'eager' : 'lazy'} />
<div>
<span>{item.tag}</span>
<h3>{item.name}</h3>
<p>{item.description}</p>
</div>
</a>
))}
</div>
<div class="portfolio-more">
<a class="button button-secondary" href="/portfolio/">ไปหน้า ผลงาน</a>
</div>
</section>
<section id="process" class="process-section">
<div class="section-heading">
<p class="eyebrow">How we work</p>
<h2>ไม่เริ่มจากขายของ เริ่มจากเข้าใจธุรกิจก่อน</h2>
</div>
<div class="process-grid">
{process.map(([title, copy], index) => (
<article>
<span class="step-number">{String(index + 1).padStart(2, '0')}</span>
<h3>{title}</h3>
<p>{copy}</p>
</article>
))}
</div>
</section>
<section class="final-cta">
<div class="glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="eyebrow">Start small</p>
<h2>ส่งโจทย์สั้น ๆ มาก่อนก็ได้ เดี๋ยวเราช่วยดูว่าควรเริ่มตรงไหน</h2>
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
</div>
</section>
</main>
<button class="floating-cta" type="button" data-floating-cta data-open-lead>ส่งโจทย์ให้เราดู</button>
<div class="panel-backdrop" data-panel-backdrop></div>
<aside class="lead-panel liquid-glass liquidGlass-wrapper" aria-labelledby="lead-title" aria-hidden="true" data-lead-panel data-endpoint={formEndpoint}>
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<div class="panel-head">
<div>
<p class="eyebrow">ส่งโจทย์ให้เราดู</p>
<h2 id="lead-title">เลือกปัญหาที่ใกล้ที่สุด แล้วเล่าเพิ่มสั้น ๆ</h2>
</div>
<button type="button" class="panel-close" aria-label="ปิดฟอร์ม" data-close-lead>ปิด</button>
</div>
<form class="lead-form" data-lead-form>
<input class="honeypot" type="text" name="website" tabindex="-1" autocomplete="off" />
<fieldset>
<legend>ตอนนี้ติดเรื่องไหนอยู่?</legend>
<div class="chip-grid">
{problems.map(([value, label]) => (
<label class="chip">
<input type="checkbox" name="problems" value={value} />
<span>{label}</span>
</label>
))}
</div>
</fieldset>
<label>
เล่าเพิ่มสั้น ๆ
<textarea name="message" rows="4" placeholder="เช่น ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม อยากรู้ว่าควรแก้อะไรก่อน"></textarea>
</label>
<div class="field-row">
<label>
ชื่อ
<input name="name" type="text" autocomplete="name" required />
</label>
<label>
เบอร์โทร
<input name="phone" type="tel" autocomplete="tel" />
</label>
</div>
<label>
อีเมล
<input name="email" type="email" autocomplete="email" />
</label>
<p class="field-note">ใส่เบอร์โทรหรืออีเมลอย่างใดอย่างหนึ่งก็ได้</p>
<p class="form-status" data-form-status role="status"></p>
<button class="button button-primary" type="submit">ส่งโจทย์</button>
</form>
</aside>
<svg class="glass-filter" aria-hidden="true" focusable="false">
<filter id="glass-distortion" x="0%" y="0%" width="100%" height="100%" filterUnits="objectBoundingBox">
<feTurbulence type="fractalNoise" baseFrequency="0.01 0.01" numOctaves="1" seed="5" result="turbulence" />
<feComponentTransfer in="turbulence" result="mapped">
<feFuncR type="gamma" amplitude="1" exponent="10" offset="0.5" />
<feFuncG type="gamma" amplitude="0" exponent="1" offset="0" />
<feFuncB type="gamma" amplitude="0" exponent="1" offset="0.5" />
</feComponentTransfer>
<feGaussianBlur in="turbulence" stdDeviation="3" result="softMap" />
<feSpecularLighting in="softMap" surfaceScale="5" specularConstant="1" specularExponent="100" lighting-color="white" result="specLight">
<fePointLight x="-200" y="-200" z="300" />
</feSpecularLighting>
<feComposite in="specLight" operator="arithmetic" k1="0" k2="1" k3="1" k4="0" result="litImage" />
<feDisplacementMap in="SourceGraphic" in2="softMap" scale="150" xChannelSelector="R" yChannelSelector="G" />
</filter>
</svg>
<script>
import '../scripts/home.js';
</script>
</body>
</html>

View File

@@ -1,73 +1,84 @@
---
/**
* MOREMINIMORE - PORTFOLIO
* Per plan 2026-06-13:
* 1. v6 Hero
* 2. v6 Portfolio (pinned 3: Dataroot / Luadjob / Jet)
* 3. Grid of all 9 remaining
*/
import Base from '../layouts/Base.astro';
import Hero from '../components/Hero.astro';
import Portfolio from '../components/Portfolio.astro';
import PortfolioCard from '../components/PortfolioCard.astro';
import Contact from '../components/Contact.astro';
import { getCollection } from 'astro:content';
const all = await getCollection('portfolio');
const realPortfolio = all.filter(p => p.data.url && p.data.url !== '');
// Pinned 3 (also shown in v6 Portfolio component)
const PINNED = ['dataroot', 'luadjob', 'jet-industries'];
const gridItems = realPortfolio.filter(p => !PINNED.includes(p.id));
import PageShell from '../components/PageShell.astro';
import { portfolio } from '../data/site.js';
---
<Base title="ผลงาน | MoreminiMore | รับทำเว็บไซต์ SEO AI Chatbot">
<Hero
id="portfolio-hero"
eyebrow="MOREMINIMORE / portfolio"
title="ผลงานจริง ไม่ใช่ Mockup ลูกค้าจริง ตัวเลขจริง"
lede="9 โปรเจกต์ · 5 อุตสาหกรรม — คลิกดูเว็บจริงได้เลย"
ctaPrimary={{ text: 'ปรึกษาฟรี →', href: '/contact' }}
ctaSecondary={{ text: 'ดูบริการ', href: '/services' }}
showStats={false}
/>
<Portfolio showHeader={false} />
<section class="fx-portfolio-grid-section">
<div class="fx-section-header">
<span class="fx-section-eyebrow">// more work</span>
<h2 class="fx-section-title">ผลงานอื่น ๆ</h2>
</div>
<div class="fx-portfolio-grid">
{gridItems.map(item => (
<PortfolioCard
name={item.data.name}
url={item.data.url || '#'}
category={item.data.category}
category_label={item.data.category_label}
industry={item.data.industry}
thumbnail={item.data.thumbnail}
description={item.data.description}
what_we_did={item.data.what_we_did}
result={item.data.result}
/>
))}
<PageShell
title="ผลงาน | MoreminiMore"
description="ผลงานเว็บไซต์และเคสธุรกิจจริงของ MoreminiMore สำหรับ SME ที่ต้องการตัดสินใจจากงานจริง"
>
<section class="page-hero scene scene-light" data-scene="light">
<div class="page-hero-grid">
<div>
<p class="eyebrow">Portfolio</p>
<h1>ผลงานจริงที่เปิดดูเว็บจริงได้</h1>
</div>
<p class="hero-lead">
เราเลือกโชว์งานที่ช่วยเล่าโจทย์ธุรกิจ ไม่ใช่แค่ภาพสวย เพราะงานที่ดีควรช่วยให้ลูกค้าตัดสินใจง่ายขึ้น
</p>
</div>
</section>
<Contact variant="prompt" />
</Base>
<section id="dataroot" class="case-section scene scene-dark" data-scene="dark">
<div class="section-heading">
<p class="eyebrow">Featured case</p>
<h2>Dataroot: ก่อนแก้ ต้องรู้ก่อนว่าข้อมูลกำลังบอกอะไร</h2>
</div>
<div class="case-grid">
<article class="case-story glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<div class="story-step">
<span>01</span>
<h3>ปัญหา</h3>
<p>ยิงโฆษณาและทำการตลาดอยู่แล้ว แต่ต้องดูให้ชัดว่าคนที่เข้ามาใช่ลูกค้าที่ควรได้หรือไม่</p>
</div>
<div class="story-step">
<span>02</span>
<h3>สิ่งที่พบ</h3>
<p>กลุ่มเป้าหมายและข้อความบางส่วนดึงความสนใจได้ แต่ยังไม่พาคนที่มี intent ตรงพอเข้ามา</p>
</div>
<div class="story-step">
<span>03</span>
<h3>สิ่งที่ปรับ</h3>
<p>ปรับการมองกลุ่มเป้าหมายและการวัดผลจากข้อมูลจริง ไม่ใช่เลือกจากสิ่งที่ดูน่าจะคลิกง่าย</p>
</div>
</article>
<div class="case-proof" data-depth-card>
<img src="/images/portfolio/dataroot.png" alt="Dataroot website screenshot" loading="lazy" />
<div class="metric-card">
<strong>+373%</strong>
<span>impression</span>
</div>
<div class="metric-card">
<strong>+114.2%</strong>
<span>click</span>
</div>
<div class="metric-card">
<strong>-28.3%</strong>
<span>ad spend</span>
</div>
</div>
</div>
</section>
<style>
.fx-portfolio-grid-section { padding: 64px 32px; background: var(--paper-2); }
.fx-portfolio-grid {
max-width: 1200px;
margin: 32px auto 0;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
@media (max-width: 1024px) { .fx-portfolio-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .fx-portfolio-grid { grid-template-columns: 1fr; } }
</style>
<section class="portfolio-section scene scene-dark" data-scene="dark">
<div class="section-heading">
<p class="eyebrow">Selected work</p>
<h2>เว็บที่มีโจทย์ต่างกัน จึงต้องออกแบบต่างกัน</h2>
</div>
<div class="portfolio-grid">
{portfolio.filter((item) => item.name !== 'Dataroot').map((item) => (
<a class={`portfolio-card ${item.featured ? 'featured' : ''}`} href={item.href} target="_blank" rel="noreferrer">
<img src={item.image} alt={`${item.name} website screenshot`} loading="lazy" />
<div>
<span>{item.tag}</span>
<h3>{item.name}</h3>
<p>{item.description}</p>
</div>
</a>
))}
</div>
</section>
</PageShell>

View File

@@ -1,161 +0,0 @@
---
import Base from '../layouts/Base.astro';
import Hero from '../components/Hero.astro';
---
<Base title="นโยบายความเป็นส่วนตัว | MoreminiMore - รับทำเว็บไซต์ SEO AI Chatbot">
<Hero
eyebrow="กฎหมาย"
title="นโยบายความเป็นส่วนตัว"
lede="มีผลบังคับใช้วันที่ 5 พฤษภาคม 2569"
showStats={false} />
<section class="section section-bento legal-section">
<div class="container" style="position: relative; z-index: 1;">
<div class="bento-grid">
<div class="bento-tile span-8 surface-white">
<div class="legal-body">
<p class="legal-intro">บริษัท มอร์มินิมอร์ จำกัด ให้ความสำคัญกับการคุ้มครองข้อมูลส่วนบุคคลของท่าน</p>
<div class="legal-block">
<h2>1. ข้อมูลส่วนบุคคลที่เราเก็บรวบรวม</h2>
<p>ข้อมูลส่วนบุคคลที่บริษัทฯ อาจเก็บรวบรวมจากท่าน อาจรวมถึง:</p>
<ul>
<li><strong>ข้อมูลส่วนบุคคลทั่วไป:</strong> ชื่อ-นามสกุล ที่อยู่อีเมล หมายเลขโทรศัพท์</li>
<li><strong>ข้อมูลการติดต่อ:</strong> ข้อมูลการติดต่อที่ท่านให้ไว้เมื่อลงทะเบียนหรือกรอกแบบฟอร์ม</li>
<li><strong>ข้อมูลการใช้งาน:</strong> IP address, ข้อมูลการเข้าชมเว็บไซต์, คุกกี้</li>
</ul>
</div>
<div class="legal-block">
<h2>2. วัตถุประสงค์ในการเก็บรวบรวมข้อมูล</h2>
<p>เราเก็บรวบรวมข้อมูลส่วนบุคคลเพื่อวัตถุประสงค์ดังต่อไปนี้:</p>
<ul>
<li>เพื่อให้บริการและดูแลลูกค้า</li>
<li>เพื่อติดต่อสื่อสารกับท่าน</li>
<li>เพื่อปรับปรุงการให้บริการ</li>
<li>เพื่อปฏิบัติตามกฎหมาย</li>
</ul>
</div>
<div class="legal-block">
<h2>3. การคุ้มครองข้อมูล</h2>
<p>เรามีมาตรการรักษาความปลอดภัยที่เหมาะสมเพื่อป้องกันการสูญหาย เข้าถึง ใช้ เปลี่ยนแปลง หรือเปิดเผยข้อมูลส่วนบุคคลโดยไม่ได้รับอนุญาต</p>
</div>
<div class="legal-block">
<h2>4. สิทธิของท่าน</h2>
<p>ท่านมีสิทธิในการเข้าถึง แก้ไข ลบ หรือระงับการใช้ข้อมูลส่วนบุคคลของท่าน กรุณาติดต่อเราผ่านช่องทางที่ระบุในเว็บไซต์</p>
</div>
</div>
</div>
<div class="bento-tile span-4 surface-purple-soft">
<div class="aside-body">
<p><strong>ชื่อเอกสาร:</strong> นโยบายความเป็นส่วนตัว</p>
<p><strong>มีผลบังคับใช้:</strong> 5 พฤษภาคม 2569</p>
<p><strong>จัดการโดย:</strong> MoreminiMore Co.,Ltd.</p>
<p style="margin-top: 20px;"><strong>หัวข้อทั้งหมด 4 ข้อ:</strong></p>
<ol class="toc-list">
<li>ข้อมูลส่วนบุคคลที่เราเก็บรวบรวม</li>
<li>วัตถุประสงค์ในการเก็บรวบรวมข้อมูล</li>
<li>การคุ้มครองข้อมูล</li>
<li>สิทธิของท่าน</li>
</ol>
</div>
</div>
</div>
</div>
</section>
</Base>
<style>
.legal-section { background: var(--color-white); }
.section-bento { position: relative; overflow: hidden; }
/* Body typography inside the prose tile */
.legal-body { font-size: 16px; line-height: 1.8; color: var(--color-gray-700); }
.legal-intro {
font-size: 17px;
color: var(--color-gray-700);
margin-bottom: 36px;
line-height: 1.7;
padding-bottom: 28px;
border-bottom: 1px solid var(--color-gray-200);
}
.legal-block { margin-bottom: 36px; }
.legal-block:last-child { margin-bottom: 0; }
.legal-block h2 {
font-family: var(--font-display);
font-size: 22px;
font-weight: 800;
margin-bottom: 14px;
color: var(--color-black);
}
.legal-block p {
font-size: 16px;
color: var(--color-gray-700);
line-height: 1.8;
margin-bottom: 12px;
}
.legal-block ul {
margin: 12px 0 12px 24px;
}
.legal-block li {
font-size: 16px;
color: var(--color-gray-700);
line-height: 1.8;
margin-bottom: 8px;
}
.legal-block strong { color: var(--color-black); }
/* Aside (purple-soft tile) */
.aside-body {
font-size: 15px;
line-height: 1.7;
color: var(--color-black);
}
.aside-body p { margin-bottom: 10px; }
.aside-body strong { font-weight: 800; }
.toc-list {
list-style: none;
padding: 0;
margin: 12px 0 0;
counter-reset: toc;
}
.toc-list li {
counter-increment: toc;
padding: 10px 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
font-weight: 600;
position: relative;
padding-left: 36px;
}
.toc-list li::before {
content: counter(toc, decimal-leading-zero);
position: absolute;
left: 0;
top: 10px;
font-family: var(--font-display);
font-weight: 900;
opacity: 0.6;
}
.toc-list li:last-child { border-bottom: none; }
@media (max-width: 640px) {
.legal-intro { font-size: 16px; }
.legal-block h2 { font-size: 20px; }
}
</style>
<script>
</script>

69
src/pages/services.astro Normal file
View File

@@ -0,0 +1,69 @@
---
import PageShell from '../components/PageShell.astro';
import { services, process } from '../data/site.js';
---
<PageShell
title="บริการ | MoreminiMore"
description="บริการของ MoreminiMore สำหรับ SME ที่ต้องการทำเว็บ การตลาด ระบบอัตโนมัติ และ AI โดยเริ่มจากข้อมูลจริงก่อนเลือกวิธีทำ"
>
<section class="page-hero scene scene-light" data-scene="light">
<div class="page-hero-grid">
<div>
<p class="eyebrow">Services</p>
<h1>เลือกบริการจากปัญหา ไม่ใช่จากชื่อแพ็กเกจ</h1>
</div>
<p class="hero-lead">
เราช่วยดูโจทย์ธุรกิจก่อน แล้วเลือกว่าควรเริ่มจากเว็บ การตลาด ระบบทำงาน หรือ AI จุดไหนคุ้มที่สุดสำหรับตอนนี้
</p>
</div>
</section>
<section class="page-section">
<div class="service-detail-grid">
{services.map((service) => (
<article id={service.slug} class="detail-card liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<span>{service.badge}</span>
<h2>{service.name}</h2>
<h3>{service.headline}</h3>
<p>{service.detail}</p>
<p class="detail-objective">เป้าหมายหลัก: {service.objective}</p>
<div class="detail-actions">
<a class="text-link" href={`/services/${service.slug}/`}>ดูรายละเอียดบริการนี้</a>
<button class="text-link" type="button" data-open-lead>ส่งโจทย์บริการนี้</button>
</div>
</article>
))}
</div>
</section>
<section class="page-section page-section-tight">
<div class="section-heading">
<p class="eyebrow">How we work</p>
<h2>ทำให้ง่ายต่อการตัดสินใจ ไม่ใช่ทำให้ดูเยอะ</h2>
</div>
<div class="process-grid">
{process.map(([title, copy], index) => (
<article>
<span>{String(index + 1).padStart(2, '0')}</span>
<h3>{title}</h3>
<p>{copy}</p>
</article>
))}
</div>
</section>
<section class="final-cta">
<div class="glass-panel liquid-glass liquidGlass-wrapper">
<div class="liquidGlass-effect" aria-hidden="true"></div>
<div class="liquidGlass-tint" aria-hidden="true"></div>
<div class="liquidGlass-shine" aria-hidden="true"></div>
<p class="eyebrow">Next step</p>
<h2>ไม่แน่ใจว่าควรเริ่มบริการไหน ส่งโจทย์มาให้เราดูก่อนได้</h2>
<button class="button button-primary" type="button" data-open-lead>ส่งโจทย์ให้เราดู</button>
</div>
</section>
</PageShell>

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +0,0 @@
---
/**
* MOREMINIMORE - SERVICES INDEX
* Per plan 2026-06-13: v6 Hero + v6 Services (4 cards from collection)
*/
import Base from '../../layouts/Base.astro';
import Hero from '../../components/Hero.astro';
import Services from '../../components/Services.astro';
import Contact from '../../components/Contact.astro';
---
<Base title="บริการ | MoreminiMore | รับทำเว็บไซต์ SEO AI Chatbot">
<Hero
id="services-hero"
eyebrow="MOREMINIMORE / services"
title="เราทำอะไรได้บ้าง เริ่มจากอันที่ปวดที่สุด"
lede="4 บริการหลัก — เลือกอันที่ตรงปัญหาคุณที่สุด เริ่มปรึกษาฟรี 30 นาทีเพื่อประเมินแนวทาง"
ctaPrimary={{ text: 'ปรึกษาฟรี →', href: '/contact' }}
ctaSecondary={{ text: 'ดูผลงานจริง', href: '/portfolio' }}
showStats={false}
/>
<Services id="services-list" />
<Contact variant="prompt" />
</Base>

View File

@@ -1,158 +0,0 @@
---
import Base from '../layouts/Base.astro';
import Hero from '../components/Hero.astro';
---
<Base title="เงื่อนไขการให้บริการ | MoreminiMore - รับทำเว็บไซต์ SEO AI Chatbot">
<Hero
eyebrow="กฎหมาย"
title="เงื่อนไขการให้บริการ"
lede="มีผลบังคับใช้วันที่ 5 พฤษภาคม 2569"
showStats={false} />
<section class="section section-bento legal-section">
<div class="container" style="position: relative; z-index: 1;">
<div class="bento-grid">
<div class="bento-tile span-8 surface-white">
<div class="legal-body">
<p class="legal-intro">ชื่อเว็บไซต์: MoreminiMore | เว็บไซต์: https://www.moreminimore.com | บริษัท: MoreminiMore Co.,Ltd.</p>
<div class="legal-block">
<h2>1. การยอมรับเงื่อนไข</h2>
<p>ด้วยการเข้าถึงและใช้งานเว็บไซต์ของบริษัท มอร์มินิมอร์ จำกัด ท่านยอมรับและตกลงที่จะถูกผูกมัดด้วยเงื่อนไขการให้บริการฉบับนี้</p>
</div>
<div class="legal-block">
<h2>2. การแก้ไขเงื่อนไข</h2>
<p>เราขอสงวนสิทธิในการแก้ไขเงื่อนไขนี้เมื่อใดก็ได้ การแก้ไขจะมีผลทันทีเมื่อโพสต์บนเว็บไซต์ ท่านควรตรวจสอบเงื่อนไขนี้เป็นประจำ</p>
</div>
<div class="legal-block">
<h2>3. บริการของเรา</h2>
<p>เราให้บริการพัฒนาเว็บไซต์ AI Automation และ Marketing Automation สำหรับธุรกิจไทย โดยมีรายละเอียดและขอบเขตงานตามที่ตกลงกันในสัญญา</p>
</div>
<div class="legal-block">
<h2>4. การชำระเงิน</h2>
<p>การชำระเงินจะเป็นไปตามเงื่อนไขที่กำหนดในใบเสนอราคาและสัญญา ลูกค้าตกลงชำระตามกำหนดเวลาที่ระบุ</p>
</div>
<div class="legal-block">
<h2>5. การรับประกัน</h2>
<p>เรารับประกันคุณภาพงานตามที่ระบุในสัญญา หากไม่พอใจในงาน เราพร้อมแก้ไขจนกว่าจะถูกใจตามเงื่อนไขที่กำหนด</p>
</div>
<div class="legal-block">
<h2>6. ข้อจำกัดความรับผิด</h2>
<p>ความรับผิดของบริษัทจะจำกัดอยู่ที่มูลค่าของงานที่ให้บริการตามที่ระบุในสัญญา</p>
</div>
<div class="legal-block">
<h2>7. ติดต่อเรา</h2>
<p>หากมีคำถามเกี่ยวกับเงื่อนไขการให้บริการ กรุณาติดต่อเราที่ contact@moreminimore.com หรือ 080-995-5945</p>
</div>
</div>
</div>
<div class="bento-tile span-4 surface-yellow">
<div class="aside-body">
<p><strong>ชื่อเอกสาร:</strong> เงื่อนไขการให้บริการ</p>
<p><strong>มีผลบังคับใช้:</strong> 5 พฤษภาคม 2569</p>
<p><strong>จัดการโดย:</strong> MoreminiMore Co.,Ltd.</p>
<p style="margin-top: 20px;"><strong>หัวข้อทั้งหมด 7 ข้อ:</strong></p>
<ol class="toc-list">
<li>การยอมรับเงื่อนไข</li>
<li>การแก้ไขเงื่อนไข</li>
<li>บริการของเรา</li>
<li>การชำระเงิน</li>
<li>การรับประกัน</li>
<li>ข้อจำกัดความรับผิด</li>
<li>ติดต่อเรา</li>
</ol>
</div>
</div>
</div>
</div>
</section>
</Base>
<style>
.legal-section { background: var(--color-white); }
.section-bento { position: relative; overflow: hidden; }
/* Body typography inside the prose tile */
.legal-body { font-size: 16px; line-height: 1.8; color: var(--color-gray-700); }
.legal-intro {
font-size: 17px;
color: var(--color-gray-700);
margin-bottom: 36px;
line-height: 1.7;
padding-bottom: 28px;
border-bottom: 1px solid var(--color-gray-200);
}
.legal-block { margin-bottom: 36px; }
.legal-block:last-child { margin-bottom: 0; }
.legal-block h2 {
font-family: var(--font-display);
font-size: 22px;
font-weight: 800;
margin-bottom: 14px;
color: var(--color-black);
}
.legal-block p {
font-size: 16px;
color: var(--color-gray-700);
line-height: 1.8;
margin-bottom: 12px;
}
/* Aside (yellow tile) */
.aside-body {
font-size: 15px;
line-height: 1.7;
color: var(--color-black);
}
.aside-body p { margin-bottom: 10px; }
.aside-body strong { font-weight: 800; }
.toc-list {
list-style: none;
padding: 0;
margin: 12px 0 0;
counter-reset: toc;
}
.toc-list li {
counter-increment: toc;
padding: 10px 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
font-weight: 600;
position: relative;
padding-left: 36px;
}
.toc-list li::before {
content: counter(toc, decimal-leading-zero);
position: absolute;
left: 0;
top: 10px;
font-family: var(--font-display);
font-weight: 900;
opacity: 0.6;
}
.toc-list li:last-child { border-bottom: none; }
@media (max-width: 640px) {
.legal-intro { font-size: 16px; }
.legal-block h2 { font-size: 20px; }
}
</style>
<script>
</script>

Some files were not shown because too many files have changed in this diff Show More