feat(about): Bento Grid layout + 7 content updates

Layout redesign:
- Add BentoGrid, BentoTile, DecoOrb components
- Add accent palette (purple/teal/mint/coral) to global tokens
- Rewrite about.astro using Bento Grid (12-col, surface variants)
- Decorative parallax blur orbs in 4 sections
- Value/process tiles use numerals 01-04 instead of emoji

Content updates per user feedback:
- Remove "Soloprenuer" emphasis
- Remove TOC ("เนื้อหาในหน้านี้") — not needed for short content
- Outsource + bot acknowledged as part of approach
- Replace AI stack with marketing intelligence tools
  (ad spy, SEO gap, trend tracking)
- No fabricated stat numbers — placeholders show "—"
  (only "5+ ปี" kept as verifiable, founded 2020)
- Post-delivery: small changes free, charge only for new features
- No Sprint methodology — flexible timeline, demo when ready

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Kunthawat Greethong
2026-06-08 19:06:55 +07:00
parent ca7f99ed41
commit 789473271e
6 changed files with 580 additions and 180 deletions

View File

@@ -0,0 +1,39 @@
---
/**
* BentoGrid — 12-column asymmetric bento grid container.
* Use <BentoTile> as children.
*
* Example:
* <BentoGrid>
* <BentoTile span={6} surface="yellow">...</BentoTile>
* <BentoTile span={4} surface="purple-soft">...</BentoTile>
* </BentoGrid>
*/
---
<div class="bento-grid stagger">
<slot />
</div>
<style>
.bento-grid {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-auto-rows: minmax(80px, auto);
gap: 16px;
position: relative;
}
@media (max-width: 1024px) {
.bento-grid {
grid-template-columns: repeat(6, 1fr);
}
}
@media (max-width: 640px) {
.bento-grid {
grid-template-columns: 1fr;
gap: 12px;
}
}
</style>

View File

@@ -0,0 +1,162 @@
---
/**
* BentoTile — a single bento grid cell.
*
* Props:
* span: 3 | 4 | 5 | 6 | 7 | 8 | 12 (default 6)
* rows: 1 | 2 | 3 (default 1)
* surface: 'white' | 'soft' | 'yellow' | 'purple' | 'purple-soft' | 'teal' | 'mint' | 'dark' | 'coral'
* minHeight: optional inline min-height CSS value
* eyebrow: optional small uppercase label above title
* title: optional H2 title
* reveal: boolean, animate on scroll into view (default true)
*
* Example:
* <BentoTile span={8} surface="yellow" eyebrow="วิธีทำงาน" title="ไม่ได้ทำงานแบบเดียวกับทุกที่">
* <p>...content...</p>
* </BentoTile>
*/
interface Props {
span?: 3 | 4 | 5 | 6 | 7 | 8 | 12;
rows?: 1 | 2 | 3;
surface?: 'white' | 'soft' | 'yellow' | 'purple' | 'purple-soft' | 'teal' | 'mint' | 'dark' | 'coral';
minHeight?: string;
eyebrow?: string;
title?: string;
reveal?: boolean;
class?: string;
}
const {
span = 6,
rows = 1,
surface = 'white',
minHeight,
eyebrow,
title,
reveal = true,
class: className = '',
} = Astro.props;
const spanClass = `span-${span}`;
const rowsClass = rows > 1 ? `rows-${rows}` : '';
const surfaceClass = `surface-${surface}`;
const revealClass = reveal ? 'reveal' : '';
---
<div
class:list={['bento-tile', spanClass, rowsClass, surfaceClass, revealClass, className]}
style={minHeight ? `min-height: ${minHeight};` : undefined}
>
{eyebrow && <div class:list={['tile-eyebrow', surface === 'dark' || surface === 'purple' || surface === 'teal' || surface === 'coral' ? 'inv' : '']}>{eyebrow}</div>}
{title && <h2 class:list={['tile-title', surface === 'dark' || surface === 'purple' || surface === 'teal' || surface === 'coral' ? 'light' : '']}>{title}</h2>}
<div class="tile-body">
<slot />
</div>
</div>
<style>
.bento-tile {
background: var(--color-white);
color: var(--color-black);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-xl);
padding: 32px;
position: relative;
overflow: hidden;
transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.4s ease;
transform-style: preserve-3d;
}
.bento-tile:hover {
transform: translateY(-4px);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.08);
}
/* Spans */
.span-3 { grid-column: span 3; }
.span-4 { grid-column: span 4; }
.span-5 { grid-column: span 5; }
.span-6 { grid-column: span 6; }
.span-7 { grid-column: span 7; }
.span-8 { grid-column: span 8; }
.span-12 { grid-column: span 12; }
.rows-2 { grid-row: span 2; }
.rows-3 { grid-row: span 3; }
@media (max-width: 1024px) {
.span-3, .span-4, .span-5 { grid-column: span 3; }
.span-6, .span-7, .span-8 { grid-column: span 6; }
.span-12 { grid-column: span 6; }
}
@media (max-width: 640px) {
[class*="span-"] { grid-column: span 1; }
.rows-2, .rows-3 { grid-row: span 1; }
}
/* Surface variants */
.surface-soft { background: var(--color-bg-soft); border-color: var(--color-gray-200); }
.surface-yellow { background: var(--color-primary); border-color: var(--color-primary); color: var(--color-black); }
.surface-purple { background: var(--color-purple); border-color: var(--color-purple); color: var(--color-white); }
.surface-purple-soft { background: var(--color-purple-soft); border-color: var(--color-purple-soft); }
.surface-teal { background: var(--color-teal); border-color: var(--color-teal); color: var(--color-white); }
.surface-mint { background: var(--color-mint-soft); border-color: var(--color-mint-soft); }
.surface-coral { background: var(--color-coral); border-color: var(--color-coral); color: var(--color-white); }
.surface-dark { background: var(--color-black); border-color: var(--color-black); color: var(--color-white); }
/* Typography */
.tile-eyebrow {
font-size: 11px;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 2px;
opacity: 0.7;
margin-bottom: 12px;
}
.tile-eyebrow.inv {
opacity: 1;
color: var(--color-primary);
}
.tile-title {
font-family: var(--font-display);
font-size: clamp(22px, 3vw, 36px);
font-weight: 900;
line-height: 1.1;
margin-bottom: 16px;
}
.tile-title.light { color: var(--color-white); }
.tile-body { font-size: 16px; line-height: 1.7; }
.tile-body :global(p) { margin-bottom: 12px; }
.tile-body :global(p:last-child) { margin-bottom: 0; }
.tile-body :global(ul) { padding-left: 20px; margin-top: 12px; }
.tile-body :global(li) { margin-bottom: 8px; }
.tile-body :global(strong) { font-weight: 800; }
/* Light text on dark/colored surface */
.surface-dark .tile-body,
.surface-purple .tile-body,
.surface-teal .tile-body,
.surface-coral .tile-body {
color: rgba(255, 255, 255, 0.95);
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.surface-dark .tile-body :global(strong),
.surface-purple .tile-body :global(strong),
.surface-teal .tile-body :global(strong),
.surface-coral .tile-body :global(strong) { color: var(--color-primary); }
/* Yellow tile — always black text */
.surface-yellow .tile-title,
.surface-yellow .tile-body,
.surface-yellow .tile-body :global(strong) { color: var(--color-black); }
.surface-yellow .tile-eyebrow { color: var(--color-black); opacity: 0.7; }
/* Checkmark list variant (for .surface-yellow with .checklist) */
.tile-body :global(.checklist) {
list-style: none;
padding: 0;
}
.tile-body :global(.checklist li) {
padding-left: 0;
}
</style>

View File

@@ -0,0 +1,68 @@
---
/**
* DecoOrb — decorative parallax blur orb for section backgrounds.
* Pure decoration, never blocks clicks, always behind content.
*
* Props:
* color: 'yellow' | 'soft' | 'purple' | 'mint' | 'teal' (default 'yellow')
* size: CSS dimension (default '400px')
* speed: parallax speed 0.01.0 (default 0.4)
* position: { top?, right?, bottom?, left? } CSS positions
* blur: CSS blur value (default '60px')
* opacity: CSS opacity 01 (default 0.5)
*
* Example:
* <DecoOrb color="yellow" size="500px" speed={0.4} position={{ top: '-100px', left: '-100px' }} />
*/
interface Props {
color?: 'yellow' | 'soft' | 'purple' | 'mint' | 'teal';
size?: string;
speed?: number;
position?: { top?: string; right?: string; bottom?: string; left?: string };
blur?: string;
opacity?: number;
}
const {
color = 'yellow',
size = '400px',
speed = 0.4,
position = {},
blur = '60px',
opacity = 0.5,
} = Astro.props;
const styleStr = [
`width: ${size};`,
`height: ${size};`,
`filter: blur(${blur});`,
`opacity: ${opacity};`,
position.top ? `top: ${position.top};` : '',
position.right ? `right: ${position.right};` : '',
position.bottom ? `bottom: ${position.bottom};` : '',
position.left ? `left: ${position.left};` : '',
].join(' ');
---
<div
class:list={['deco-orb', `orb-${color}`]}
data-parallax-speed={speed}
style={styleStr}
aria-hidden="true"
></div>
<style>
.deco-orb {
position: absolute;
border-radius: 50%;
pointer-events: none;
z-index: 0;
will-change: transform;
}
.orb-yellow { background: radial-gradient(circle, var(--color-primary) 0%, transparent 70%); }
.orb-soft { background: radial-gradient(circle, var(--color-primary-soft) 0%, transparent 70%); }
.orb-purple { background: radial-gradient(circle, var(--color-purple) 0%, transparent 70%); }
.orb-mint { background: radial-gradient(circle, var(--color-mint) 0%, transparent 70%); }
.orb-teal { background: radial-gradient(circle, var(--color-teal) 0%, transparent 70%); }
</style>

View File

@@ -0,0 +1,86 @@
---
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

@@ -3,7 +3,9 @@ import Base from '../layouts/Base.astro';
import Navigation from '../components/Navigation.astro'; import Navigation from '../components/Navigation.astro';
import Footer from '../components/Footer.astro'; import Footer from '../components/Footer.astro';
import PageHero from '../components/PageHero.astro'; import PageHero from '../components/PageHero.astro';
import Icon from '../components/Icon.astro'; import BentoGrid from '../components/BentoGrid.astro';
import BentoTile from '../components/BentoTile.astro';
import DecoOrb from '../components/DecoOrb.astro';
import { getEntry, render } from 'astro:content'; import { getEntry, render } from 'astro:content';
import type { CollectionEntry } from 'astro:content'; import type { CollectionEntry } from 'astro:content';
@@ -20,18 +22,59 @@ const { Content } = await render(about);
subtitle="บริษัท มอร์มินิมอร์ จำกัด — นโยบายของเราคือสร้างระบบที่ทำให้ลูกค้ามีกำไรมากขึ้น ไม่ใช่ทำเว็บไซต์ออกมาเยอะแล้วลืม เราเป็น Partner ที่นั่งทำงานข้างคุณจนระบบติดและใช้งานได้จริง" subtitle="บริษัท มอร์มินิมอร์ จำกัด — นโยบายของเราคือสร้างระบบที่ทำให้ลูกค้ามีกำไรมากขึ้น ไม่ใช่ทำเว็บไซต์ออกมาเยอะแล้วลืม เราเป็น Partner ที่นั่งทำงานข้างคุณจนระบบติดและใช้งานได้จริง"
/> />
<!-- ABOUT CONTENT (from about.md) --> <!-- ABOUT CONTENT (BENTO) -->
<section class="section"> <section class="section section-bento">
<div class="container"> <DecoOrb color="yellow" size="500px" speed={0.4} position={{ top: '-150px', left: '-150px' }} opacity={0.25} blur="80px" />
<article class="about-content"> <DecoOrb color="soft" size="400px" speed={0.3} position={{ bottom: '-100px', right: '-100px' }} opacity={0.4} blur="80px" />
<Content /> <div class="container" style="position: relative; z-index: 1;">
</article> <BentoGrid>
<BentoTile span={12} surface="soft" eyebrow="นโยบายของเรา" title="เป้าหมายคือเพิ่มกำไรให้ลูกค้า">
<p>เพราะถ้าลูกค้ามีกำไรมากขึ้น ลูกค้าก็จะสามารถใช้บริการเราต่อไปได้</p>
<p>ทุกระบบที่ส่งมอบต้องตอบคำถามเดียวให้ได้: <strong>"ลูกค้ามีกำไรเพิ่มขึ้นจริงไหม"</strong> — ไม่ใช่แค่ส่งงานตามสัญญา</p>
</BentoTile>
<BentoTile span={8} surface="yellow" eyebrow="วิธีทำงานของเรา" title="ไม่ได้ทำงานแบบเดียวกับทุกที่">
<p>เพราะลูกค้าแต่ละคนมีบริบท งบประมาณ และทีมต่างกัน</p>
<ul class="checklist">
<li>✅ <strong>งานที่ต้องใช้ความเชี่ยวชาญเฉพาะทาง</strong> — เราทำเอง เพราะถ้าไม่ทำเอง จะตอบคำถามลูกค้าไม่ได้</li>
<li>✅ <strong>งานที่ต้องทำซ้ำ ๆ ปริมาณเยอะ</strong> — เราใช้ bot หรือ outsource ให้คนเชี่ยวชาญ เพราะคนที่ทำเป็นอาชีพจะดีกว่า</li>
<li>✅ <strong>งานที่ต้องตอบลูกค้าตลอด 24 ชั่วโมง</strong> — bot ช่วยคัดกรองเบื้องต้น แล้วเราตามด้วยคน</li>
</ul>
<p style="margin-top: 16px;"><strong>สรุป:</strong> ผลงานที่ออกมาขึ้นอยู่กับบริบทของลูกค้า ไม่ใช่วิธีทำงานของเรา — เราเลือกวิธีที่ทำให้ลูกค้าได้ผลลัพธ์ที่ดีที่สุด ไม่ใช่วิธีที่เราถนัดที่สุด</p>
</BentoTile>
<BentoTile span={4} surface="purple-soft" eyebrow="ปี 2020" title="ก่อตั้งจากประสบการณ์ตรง">
<p>เห็น SME ไทยเสียเงินหลายแสนไปกับเว็บไซต์ "สวยแต่ไม่มีคนเข้า" และ AI tools "ว้าวแต่ใช้ไม่เป็น"</p>
</BentoTile>
<BentoTile span={6} surface="mint" eyebrow="เราเชื่ออะไร" title="หลักคิด 6 ข้อ">
<ul>
<li>เว็บสวยไม่ได้แปลว่าขายได้</li>
<li>AI ไม่ได้แทนทุกอย่าง — แต่ถ้ารู้จักใช้...</li>
<li>จ่ายแพงไม่ได้แปลว่าดี</li>
<li>"สิ่งที่ถูกต้อง" ไม่ใช่ "สิ่งที่ลูกค้าต้องการ" เสมอไป</li>
<li>ระบบที่คนใช้ไม่เป็น = เสียเงินเปล่า</li>
</ul>
</BentoTile>
<BentoTile span={6} surface="teal" eyebrow="เบื้องหลัง" title="Marketing intelligence ที่ใช้">
<p>นั่งทำงานที่บ้าน ใช้ MacBook ตัวเดียว แต่มีเครื่องมือที่ช่วยให้เข้าใจตลาดได้ลึกกว่าคนทั่วไป:</p>
<ul>
<li><strong>ระบบดูโฆษณาคู่แข่ง</strong> — ดูว่าคู่แข่งยิงโฆษณาอะไร คำไหน convert ดี</li>
<li><strong>วิเคราะห์ keyword + SEO gap</strong> — หาโอกาสที่คู่แข่งยังไม่ได้ทำ</li>
<li><strong>ติดตาม trend ตลาด</strong> — รู้ก่อนลูกค้าว่าตลาดกำลังไปทางไหน</li>
</ul>
<p style="margin-top: 12px;"><strong>Stack:</strong> JavaScript, Python, PHP, n8n, OpenAI API, Meta API, Google Analytics, Looker Studio</p>
</BentoTile>
</BentoGrid>
</div> </div>
</section> </section>
<!-- STORY SECTION --> <!-- STORY SECTION -->
<section class="section story-section"> <section class="section section-bento">
<div class="container"> <DecoOrb color="yellow" size="400px" speed={0.5} position={{ top: '10%', right: '-150px' }} opacity={0.3} blur="80px" />
<DecoOrb color="mint" size="300px" speed={0.3} position={{ bottom: '-100px', left: '-100px' }} opacity={0.2} blur="80px" />
<div class="container" style="position: relative; z-index: 1;">
<div class="story-grid"> <div class="story-grid">
<div class="story-content"> <div class="story-content">
<span class="section-badge">นโยบายของเรา</span> <span class="section-badge">นโยบายของเรา</span>
@@ -48,7 +91,7 @@ const { Content } = await render(about);
</p> </p>
<p class="story-text"> <p class="story-text">
<strong>ความต่างของเรา</strong> เราเขียนโค้ดเอง ไม่ใช่เอาไป Outsource เราตอบแชตเอง ไม่ใช่ใหBot ตอบลูกค้า เราวางแผนเอง ไม่ใช่ใช้ Template เดียวกับทุกคน <strong>วิธีทำงานของเรา</strong> เราไม่ได้ทำงานแบบเดียวกับทุกที่ — งานที่ต้องใช้ความเชี่ยวชาญเฉพาะทางเราทำเอง งานที่ต้องทำซ้ำ ๆ ปริมาณเยอะเราใชbot หรือ outsource ให้คนเชี่ยวชาญราะคนที่ทำเป็นอาชีพจะดีกว่า
</p> </p>
<div class="story-actions"> <div class="story-actions">
@@ -59,20 +102,20 @@ const { Content } = await render(about);
<div class="story-stats stagger-children"> <div class="story-stats stagger-children">
<div class="stat-card"> <div class="stat-card">
<span class="stat-number counter" data-from="0">40+</span> <span class="stat-number">—</span>
<span class="stat-label">ลูกค้าที่กลับมาใช้บริการซ้ำ</span> <span class="stat-label">ลูกค้าที่กลับมาใช้บริการซ้ำ</span>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<span class="stat-number counter" data-from="0">50+</span> <span class="stat-number">—</span>
<span class="stat-label">โปรเจกต์ที่ส่งมอบ</span> <span class="stat-label">โปรเจกต์ที่ส่งมอบ</span>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<span class="stat-number counter" data-from="0">5+</span> <span class="stat-number counter" data-from="0">5+</span>
<span class="stat-label">ปีของการทำงานหนัก</span> <span class="stat-label">ปีของการทำงานหนัก (ก่อตั้งปี 2020)</span>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<span class="stat-number counter" data-from="0">100%</span> <span class="stat-number">—</span>
<span class="stat-label">โค้ดโดยทีมเรา ไม่ Outsource</span> <span class="stat-label">อุตสาหกรรมที่รับ</span>
</div> </div>
</div> </div>
</div> </div>
@@ -81,7 +124,9 @@ const { Content } = await render(about);
<!-- VALUES SECTION (yellow accent cards on soft) --> <!-- VALUES SECTION (yellow accent cards on soft) -->
<section class="section section-soft values-section"> <section class="section section-soft values-section">
<div class="container"> <DecoOrb color="purple" size="500px" speed={0.4} position={{ top: '-200px', left: '20%' }} opacity={0.2} blur="100px" />
<DecoOrb color="soft" size="400px" speed={0.3} position={{ bottom: '-100px', right: '5%' }} opacity={0.4} blur="80px" />
<div class="container" style="position: relative; z-index: 1;">
<div class="section-header reveal"> <div class="section-header reveal">
<span class="section-badge">ค่านิยมของเรา</span> <span class="section-badge">ค่านิยมของเรา</span>
<h2 class="section-title"> <h2 class="section-title">
@@ -90,33 +135,25 @@ const { Content } = await render(about);
</div> </div>
<div class="values-grid stagger-children"> <div class="values-grid stagger-children">
<div class="value-card"> <div class="value-card value-card-yellow">
<div class="value-icon"> <div class="value-num">01</div>
<Icon name="target" />
</div>
<h3 class="value-title">เข้าใจธุรกิจก่อนเขียนโค้ด</h3> <h3 class="value-title">เข้าใจธุรกิจก่อนเขียนโค้ด</h3>
<p class="value-desc">30 นาทีแรกของทุกโปรเจกต์คือการถาม ไม่ใช่การ present เราถามจนเข้าใจว่าคุณขายให้ใคร กำไรเท่าไหร่ ปวดหัวตรงไหน แล้วค่อยแนะนำ solution</p> <p class="value-desc">30 นาทีแรกของทุกโปรเจกต์คือการถาม ไม่ใช่การ present เราถามจนเข้าใจว่าคุณขายให้ใคร กำไรเท่าไหร่ ปวดหัวตรงไหน แล้วค่อยแนะนำ solution</p>
</div> </div>
<div class="value-card"> <div class="value-card">
<div class="value-icon"> <div class="value-num">02</div>
<Icon name="users" />
</div>
<h3 class="value-title">เป็น Partner ไม่ใช่ Vendor</h3> <h3 class="value-title">เป็น Partner ไม่ใช่ Vendor</h3>
<p class="value-desc">เราแชร์ progress ทุกสัปดาห์ผ่าน LINE Group เดียวกับที่ลูกค้าใช้ คุณเห็นทุก decision ไม่มี hidden cost ไม่มี "อันนี้เพิ่มเงินนะ" ตอนใกล้ deliver</p> <p class="value-desc">เราแชร์ progress ทุกสัปดาห์ผ่าน LINE Group เดียวกับที่ลูกค้าใช้ คุณเห็นทุก decision ไม่มี hidden cost ไม่มี "อันนี้เพิ่มเงินนะ" ตอนใกล้ deliver</p>
</div> </div>
<div class="value-card"> <div class="value-card">
<div class="value-icon"> <div class="value-num">03</div>
<Icon name="clock" />
</div>
<h3 class="value-title">Deliver ตรงเวลา หรือบอกล่วงหน้า</h3> <h3 class="value-title">Deliver ตรงเวลา หรือบอกล่วงหน้า</h3>
<p class="value-desc">เราไม่สัญญา deadline แบบเลื่อนได้ ถ้าจะติด เราจะบอกก่อน 7 วัน ไม่ใช่บอกตอนส่งงาน เคสไหนที่เคยส่งช้า เราคืนเงิน Pro-rata</p> <p class="value-desc">เราไม่สัญญา deadline แบบเลื่อนได้ ถ้าจะติด เราจะบอกก่อน 7 วัน ไม่ใช่บอกตอนส่งงาน เคสไหนที่เคยส่งช้า เราคืนเงิน Pro-rata</p>
</div> </div>
<div class="value-card"> <div class="value-card">
<div class="value-icon"> <div class="value-num">04</div>
<Icon name="shield" />
</div>
<h3 class="value-title">ดูแลหลังส่งมอบ</h3> <h3 class="value-title">ดูแลหลังส่งมอบ</h3>
<p class="value-desc">เว็บไซต์ที่ส่งแล้วทิ้งเป็นเว็บตาย เราเลยมีแพ็คเกจดูแลรายเดือนเริ่ม 2,000 บาท รวมอัปเดตเนื้อหา ปรับ SEO แก้บั๊ก ตอบคำถามผ่าน LINE</p> <p class="value-desc">ปรับเล็ก ๆ น้อย ๆ ฟรี — คิดค่าใช้จ่ายเฉพาะ feature ใหม่หรือปรับแต่งครั้งใหญ่เท่านั้น</p>
</div> </div>
</div> </div>
</div> </div>
@@ -136,7 +173,9 @@ const { Content } = await render(about);
<!-- PROCESS SECTION (4 steps, white) --> <!-- PROCESS SECTION (4 steps, white) -->
<section class="section process-section"> <section class="section process-section">
<div class="container"> <DecoOrb color="soft" size="600px" speed={0.4} position={{ top: '-150px', right: '-100px' }} opacity={0.5} blur="80px" />
<DecoOrb color="yellow" size="300px" speed={0.3} position={{ bottom: '5%', left: '-100px' }} opacity={0.3} blur="80px" />
<div class="container" style="position: relative; z-index: 1;">
<div class="section-header reveal"> <div class="section-header reveal">
<span class="section-badge">กระบวนการทำงาน</span> <span class="section-badge">กระบวนการทำงาน</span>
<h2 class="section-title"> <h2 class="section-title">
@@ -146,7 +185,7 @@ const { Content } = await render(about);
</div> </div>
<div class="process-grid stagger-children"> <div class="process-grid stagger-children">
<div class="process-step"> <div class="process-step process-step-wide">
<span class="step-num">01</span> <span class="step-num">01</span>
<h3 class="step-title">ปรึกษาฟรี</h3> <h3 class="step-title">ปรึกษาฟรี</h3>
<p class="step-desc">3060 นาทีคุยกับเจ้าของธุรกิจ ฟัง pain points, เป้าหมาย, budget ให้คำแนะนำเบื้องต้นฟรี ไม่ผูก commitment</p> <p class="step-desc">3060 นาทีคุยกับเจ้าของธุรกิจ ฟัง pain points, เป้าหมาย, budget ให้คำแนะนำเบื้องต้นฟรี ไม่ผูก commitment</p>
@@ -154,17 +193,19 @@ const { Content } = await render(about);
<div class="process-step"> <div class="process-step">
<span class="step-num">02</span> <span class="step-num">02</span>
<h3 class="step-title">วางแผน</h3> <h3 class="step-title">วางแผน</h3>
<p class="step-desc">วิเคราะห์เชิงลึก ดูคู่แข่ง ส่ง Proposal เป็นเอกสาร PDF คุณอ่าน ถามคำถาม แก้ไข scope ได้ก่อนเซ็น</p> <p class="step-desc">วิเคราะห์เชิงลึก ดูคู่แข่ง ส่ง Proposal เป็น PDF คุณอ่าน ถามคำถาม แก้ไข scope ได้ก่อนเซ็น</p>
</div> </div>
<div class="process-step"> <div class="process-step process-step-teal">
<span class="step-num">03</span> <span class="step-num">03</span>
<h3 class="step-title">ดำเนินการ</h3> <h3 class="step-title">ดำเนินการ</h3>
<p class="step-desc">พัฒนาแบบ Sprint ส่ง demo ให้ทดสอบทุก 714 วัน เห็นงานจริง ไม่ใช่ "เดี๋ยวส่งทีเดียวตอนจบ"</p> <p class="step-desc">แจ้งความคืบหน้าเป็นช่วง ๆ ผ่าน LINE Group — demo เมื่อเราพร้อมส่งงานรอบใหญ่ ๆ ไม่ sprint ไม่ deadline ล็อก</p>
</div> </div>
<div class="process-step"> <div class="process-step process-step-yellow process-step-full">
<span class="step-num">04</span> <span class="step-num">04</span>
<h3 class="step-title">สนับสนุน</h3> <div>
<p class="step-desc">ส่งมอบงาน + อบรมทีม + มอบคู่มือ ติดตามผลทุกเดือน แนะนำสิ่งที่ควรปรับปรุง ต่อยอด หรือยกเลิก</p> <h3 class="step-title">ส่งมอบ + ดูแล</h3>
<p class="step-desc">ส่งมอบงาน + อบรมทีม + มอบคู่มือ หลังส่งมอบปรับเล็ก ๆ น้อย ๆ ฟรี — คิดค่าใช้จ่ายเฉพาะ feature ใหม่หรือปรับแต่งครั้งใหญ่</p>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -190,92 +231,125 @@ const { Content } = await render(about);
<style> <style>
.section-soft { background: var(--color-bg-alt); } .section-soft { background: var(--color-bg-alt); }
.section-yellow { background: var(--color-primary); } .section-yellow { background: var(--color-primary); }
.section-bento {
/* ABOUT CONTENT (from markdown) */ position: relative;
.about-content { overflow: hidden;
max-width: 760px;
margin: 0 auto;
font-size: 16px;
line-height: 1.8;
color: var(--color-gray-700);
} }
.about-content :global(h1) {
/* VALUES (keep existing classes) */
.values-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24px;
max-width: 900px;
margin: 0 auto;
}
.value-card {
background: var(--color-white);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-xl);
padding: 32px;
transition: all 0.3s ease;
}
.value-card:hover {
border-color: var(--color-primary);
transform: translateY(-4px);
box-shadow: var(--shadow-md);
}
.value-num {
font-family: var(--font-display); font-family: var(--font-display);
font-size: 36px; font-size: 22px;
font-weight: 900; font-weight: 900;
color: var(--color-black); color: var(--color-black);
margin-bottom: 24px; width: 64px;
height: 64px;
border: 2px solid var(--color-black);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
letter-spacing: -1px;
} }
.about-content :global(h2) { .value-card-yellow { background: var(--color-primary); border-color: var(--color-primary); }
.value-card-yellow .value-num { background: var(--color-black); color: var(--color-primary); border-color: var(--color-black); }
.value-title {
font-family: var(--font-display); font-family: var(--font-display);
font-size: 26px; font-size: 18px;
font-weight: 800; font-weight: 800;
color: var(--color-black); color: var(--color-black);
margin: 48px 0 16px; margin-bottom: 10px;
padding-top: 24px;
border-top: 1px solid var(--color-gray-200);
} }
.about-content :global(h3) { .value-desc {
font-size: 14px;
color: var(--color-gray-700);
line-height: 1.6;
}
.value-card-yellow .value-desc { color: rgba(0, 0, 0, 0.85); }
/* PROCESS (asymmetric bento) */
.process-section { background: var(--color-bg-alt); position: relative; overflow: hidden; }
.process-grid {
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-auto-rows: minmax(160px, auto);
gap: 16px;
}
.process-step {
background: var(--color-white);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-xl);
padding: 32px;
transition: all 0.3s ease;
grid-column: span 3;
display: flex;
flex-direction: column;
justify-content: center;
}
.process-step-wide { grid-column: span 3; }
.process-step-full { grid-column: span 6; flex-direction: row; align-items: center; gap: 32px; }
.process-step-full .step-num { margin-bottom: 0; }
.process-step-teal { background: var(--color-teal); border-color: var(--color-teal); color: var(--color-white); }
.process-step-teal .step-num { color: var(--color-primary); }
.process-step-teal .step-title { color: var(--color-white); }
.process-step-teal .step-desc { color: rgba(255, 255, 255, 0.92); }
.process-step-yellow { background: var(--color-primary); border-color: var(--color-primary); }
.process-step-yellow .step-num { color: var(--color-black); }
.process-step:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-md);
}
.step-num {
display: block;
font-family: var(--font-display);
font-size: clamp(48px, 5vw, 64px);
font-weight: 900;
color: var(--color-primary);
line-height: 1;
margin-bottom: 12px;
}
.step-title {
font-family: var(--font-display); font-family: var(--font-display);
font-size: 20px; font-size: 20px;
font-weight: 800; font-weight: 800;
color: var(--color-black); color: var(--color-black);
margin: 32px 0 12px; margin-bottom: 10px;
} }
.about-content :global(p) { .step-desc {
margin-bottom: 16px; font-size: 15px;
} color: var(--color-gray-700);
.about-content :global(strong) {
color: var(--color-black);
font-weight: 700;
}
.about-content :global(blockquote) {
border-left: 4px solid var(--color-primary);
padding: 16px 20px;
margin: 24px 0;
background: var(--color-bg-alt);
border-radius: 0 var(--radius-md) var(--radius-md) 0;
font-style: italic;
}
.about-content :global(ul),
.about-content :global(ol) {
padding-left: 24px;
margin-bottom: 16px;
}
.about-content :global(li) {
margin-bottom: 8px;
}
.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-desc {
font-size: 17px;
color: var(--color-gray-600);
line-height: 1.6; line-height: 1.6;
} }
/* STORY */ @media (max-width: 1024px) {
.story-section { background: var(--color-white); } .process-step, .process-step-wide { grid-column: span 6; }
}
@media (max-width: 640px) {
.process-step, .process-step-wide, .process-step-full { grid-column: span 6; flex-direction: column; align-items: flex-start; }
.values-grid { grid-template-columns: 1fr; }
}
/* STORY (keep existing) */
.story-grid { .story-grid {
display: grid; display: grid;
grid-template-columns: 1.3fr 0.7fr; grid-template-columns: 1.3fr 0.7fr;
@@ -302,7 +376,7 @@ const { Content } = await render(about);
} }
.stat-card { .stat-card {
padding: 24px; padding: 24px;
background: var(--color-bg-alt); background: var(--color-bg-soft);
border: 1px solid var(--color-gray-200); border: 1px solid var(--color-gray-200);
border-radius: var(--radius-xl); border-radius: var(--radius-xl);
transition: all 0.3s ease; transition: all 0.3s ease;
@@ -325,84 +399,35 @@ const { Content } = await render(about);
color: var(--color-gray-600); color: var(--color-gray-600);
margin-top: 8px; margin-top: 8px;
} }
.section-badge {
/* VALUES — 2x2 grid for visual balance with 4 cards */ display: inline-block;
.values-grid { background: var(--color-primary);
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 24px;
max-width: 900px;
margin: 0 auto;
}
.value-card {
background: var(--color-white);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-xl);
padding: 32px;
text-align: center;
transition: all 0.3s ease;
}
.value-card:hover {
border-color: var(--color-primary);
transform: translateY(-4px);
box-shadow: var(--shadow-md);
}
.value-icon { font-size: 40px; margin-bottom: 16px; }
.value-title {
font-family: var(--font-display);
font-size: 16px;
font-weight: 800;
color: var(--color-black); color: var(--color-black);
margin-bottom: 10px; padding: 8px 20px;
border-radius: var(--radius-full);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2px;
margin-bottom: 16px;
} }
.value-desc { .section-title {
font-size: 14px;
color: var(--color-gray-600);
line-height: 1.6;
}
/* PROCESS */
.process-section { background: var(--color-bg-alt); }
.process-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 24px;
}
.process-step {
background: var(--color-white);
border: 1px solid var(--color-gray-200);
border-radius: var(--radius-xl);
padding: 32px;
transition: all 0.3s ease;
}
.process-step:hover {
border-color: var(--color-primary);
transform: translateY(-4px);
box-shadow: var(--shadow-md);
}
.step-num {
display: block;
font-family: var(--font-display); font-family: var(--font-display);
font-size: 36px; font-size: clamp(28px, 4vw, 44px);
font-weight: 900; font-weight: 900;
color: var(--color-primary); line-height: 1.15;
line-height: 1;
margin-bottom: 12px;
}
.step-title {
font-family: var(--font-display);
font-size: 18px;
font-weight: 800;
color: var(--color-black); color: var(--color-black);
margin-bottom: 10px; margin-bottom: 16px;
} }
.step-desc { .section-title .highlight { color: var(--color-primary-dark); }
font-size: 14px; .section-desc {
font-size: 17px;
color: var(--color-gray-600); color: var(--color-gray-600);
line-height: 1.6; line-height: 1.6;
} }
.section-header { text-align: center; margin-bottom: 48px; }
/* PULL QUOTE (dark band) */ /* PULL QUOTE */
.section-dark-quote { .section-dark-quote {
background: var(--color-black); background: var(--color-black);
padding: 100px 0; padding: 100px 0;
@@ -452,15 +477,25 @@ const { Content } = await render(about);
flex-wrap: wrap; flex-wrap: wrap;
} }
/* RESPONSIVE */
@media (max-width: 1024px) { @media (max-width: 1024px) {
.story-grid { grid-template-columns: 1fr; gap: 40px; } .story-grid { grid-template-columns: 1fr; gap: 40px; }
.process-grid { grid-template-columns: repeat(2, 1fr); }
} }
@media (max-width: 640px) { @media (max-width: 640px) {
.story-actions, .cta-actions { flex-direction: column; } .story-actions, .cta-actions { flex-direction: column; }
.story-actions .btn, .cta-actions .btn { width: 100%; justify-content: center; } .story-actions .btn, .cta-actions .btn { width: 100%; justify-content: center; }
.values-grid { grid-template-columns: 1fr; }
.process-grid { grid-template-columns: 1fr; }
} }
</style> </style>
<script>
// Parallax orbs (use data-parallax-speed from DecoOrb)
const parallaxEls = document.querySelectorAll('[data-parallax-speed]');
function updateParallax() {
const scrolled = window.scrollY;
parallaxEls.forEach(el => {
const speed = parseFloat(el.getAttribute('data-parallax-speed') || '0.4');
const ty = scrolled * speed * -0.3;
el.style.transform = `translate3d(0, ${ty}px, 0)`;
});
}
window.addEventListener('scroll', () => requestAnimationFrame(updateParallax), { passive: true });
</script>

View File

@@ -15,6 +15,16 @@
--color-primary: #fed400; /* yellow accent */ --color-primary: #fed400; /* yellow accent */
--color-primary-dark: #e6c100; /* hover state */ --color-primary-dark: #e6c100; /* hover state */
--color-primary-light: #fff5b3; /* tint for subtle backgrounds */ --color-primary-light: #fff5b3; /* tint for subtle backgrounds */
--color-primary-soft: #fff4b3; /* bento tile surface */
/* Accent palette — for bento tile variety */
--color-purple: #7c3aed;
--color-purple-soft: #ede9fe;
--color-teal: #0d9488;
--color-teal-soft: #ccfbf1;
--color-mint: #10b981;
--color-mint-soft: #d1fae5;
--color-coral: #f97316;
--color-black: #0a0a0a; /* primary text */ --color-black: #0a0a0a; /* primary text */
--color-white: #ffffff; /* pure white */ --color-white: #ffffff; /* pure white */