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

3
.gitignore vendored
View File

@@ -23,3 +23,6 @@ pnpm-debug.log*
# jetbrains setting folder
.idea/
.hermes/
# archive (large local files)
_archive/

View File

@@ -1,111 +0,0 @@
# Blog Topics — 5 เรื่องที่ควรเขียน
> เรียงตามลำดับที่ควรเขียน เริ่มจากเรื่องที่ "อยู่ในใจลูกค้ามากที่สุด" ก่อน
> แต่ละเรื่องมี: ที่มา (จากคำตอบข้อไหน) + โครงสร้าง outline + เหตุผลที่ควรเขียน
---
## 1. "SME ไทยเสียเงินหลายแสนกับโฆษณาที่ไม่มีใครซื้อ — เรื่องจริงจากคนทำ"
**ที่มา:** A6 (SME ไทยทำพลาดเรื่องเดิมซ้ำ ๆ) + เคส Dataroot + เคสเกือบพังเรื่องกลุ่มเป้าหมาย
**ทำไมต้องเขียน:** คือเคส flagship ของเรา เขียนครั้งเดียวใช้ได้หลายที่ — เว็บ, LinkedIn, ใบเสนอราคา
**Outline:**
- เริ่มจากเคส Dataroot: คลิกเยอะ ยอดไม่ขยับ งบหลายแสน/เดือน
- ดูสถิติย้อนหลัง → เจอว่าคลิกมาจากกลุ่มที่ไม่ซื้อ
- ปรับ 3 อย่าง: ตัดกลุ่ม, ปรับ Creative, ขยายช่องทาง
- ผลลัพธ์ (Impression ↑373%, Click ↑114%, Ad spend ↓28%)
- เคสเกือบพัง: ยิงไปกลุ่ม "คนสนใจเรื่องเงิน" → มีแต่คนมาขอกู้
- บทเรียน: ดู "คนที่จะซื้อ" ไม่ใช่ "คนที่คลิกง่าย"
**Length:** 1,500-2,000 คำ
---
## 2. "AI ไม่ได้แพงเสมอไป — งาน 80% ใช้ Model ถูกก็พอ ประหยัดได้ครึ่ง"
**ที่มา:** D15 (เรื่องที่ไม่เห็นด้วย) + A6 (SME ใช้ AI ผิดแบบ) + คำตอบ B7 (AI Consult)
**ทำไมต้องเขียน:** ลูกค้า SME ส่วนใหญ่กลัว "AI แพง" — ถ้าเขียนเรื่องนี้ได้ดี คือ lead magnet เลย
**Outline:**
- เปิดด้วย: "ถ้าคุณจ่าย GPT-4 ทุกครั้ง คุณกำลังเปลืองเงินเปล่า ๆ"
- งานแบ่งเป็น 3 ระดับ: งานทั่วไป, งานวิเคราะห์, งานเฉพาะทาง
- ตารางเปรียบเทียบ: งาน X ใช้ Model Y คุณภาพ Z ราคาเท่าไหร่
- ตัวอย่างจริง: ลูกค้าเคยใช้ GPT-4 ทุกงาน → ลดเหลือ GPT-4o-mini + Sonnet + Local LLM → ประหยัด 60%
- Local LLM คืออะไร + เหมาะกับงานแบบไหน (PDPA, ความลับ)
- วิธีเลือก Model: ถ้างานเป็น "ตอบคำถาม" → ใช้ของถูก / ถ้าเป็น "วิเคราะห์ข้อมูล" → ใช้ของกลาง
**Length:** 1,500-2,000 คำ
---
## 3. "เว็บสวย vs เว็บขายได้ — ทำไมหลายเว็บที่ดูรก ๆ ถึงขายดีกว่า"
**ที่มา:** D15 (เว็บสวยไม่ได้แปลว่าขายได้)
**ทำไมต้องเขียน:** ลูกค้า SME ส่วนใหญ่ตัดสิน agency ด้วย "ผลงานสวยไหม" — ถ้าเขียนเรื่องนี้ได้ ลูกค้าจะเริ่มคิดใหม่
**Outline:**
- ตัวอย่าง: เว็บ A ดูหรูหรา แต่ Conversion 0.5% / เว็บ B ดูเก่า แต่ Conversion 3.2%
- ทำไม: เว็บสวยเน้น "ภาพลักษณ์" / เว็บขายได้เน้น "ลูกค้าทำอะไรได้"
- หลักการเว็บที่ขายได้: Clear CTA, Trust signals, Friction ต่ำ, Mobile-first
- เคสของเรา: เว็บที่ดูไม่หรูแต่ขายได้ (Baofuling, Tuanthong, Jet Industries)
- "เว็บสวย vs เว็บขายได้ ไม่ได้แยกกันเสมอ — แต่ถ้าต้องเลือก เราเลือกขายได้"
**Length:** 1,200-1,500 คำ
---
## 4. "5 ค่าใช้จ่ายแฝงที่ทำให้ร้านออนไลน์ขาดทุน — แม้ยอดขายจะเติบโต"
**ที่มา:** เคสเกือบพังเรื่อง Platform fees + A6 (SME ทดลองตลาดใหม่โดยไม่คำนวณค่าใช้จ่ายแฝง)
**ทำไมต้องเขียน:** ลูกค้า E-commerce เจอปัญหานี้เยอะมาก แต่ไม่ค่อยมีใครเขียนเรื่องนี้
**Outline:**
- ค่าใช้จ่ายแฝง 5 อย่าง: ค่าธรรมเนียม Platform / ค่าจัดส่งที่แท้จริง / ค่าคืนสินค้า / ส่วนลดที่ไม่ได้คิด / ค่าโฆษณาต่อ Lead
- เคสจริง: ร้านค้าออนไลน์ขายดี ยอดเดือนละ 500,000 แต่เหลือกำไร 15,000
- วิธีคำนวณ: ทำ Spreadsheet ต้นทุนแท้จริง (เอา Template ไปด้วย)
- วิธีแก้: ปรับราคา + เพิ่มช่องทางขายตรง
- ผลลัพธ์: ลูกค้าเราเพิ่มกำไรต่อชิ้น 35% ใน 2 เดือน
**Length:** 1,500 คำ
---
## 5. "GEO คืออะไร และทำไม SEO แบบเดิมอาจไม่พอในยุค ChatGPT"
**ที่มา:** A6 (รูปแบบการตลาดใหม่ ๆ ที่จะเปลี่ยนไปในยุค AI) + C13 (กำลังเรียนรู้ SEO กับ GEO)
**ทำไมต้องเขียน:** ยังเป็นเรื่องใหม่สำหรับ SME ส่วนใหญ่ ถ้าเขียนก่อน คุณจะเป็น authority ในเรื่องนี้
**Outline:**
- เปิดด้วย: "ปี 2024 คนเริ่มถาม ChatGPT แทน Google — เว็บคุณอยู่ในคำตอบไหม?"
- SEO vs GEO: ต่างกันยังไง
- ตัวอย่าง: ถาม ChatGPT "ที่ปรึกษา AI ในไทย" — ได้คำตอบแบบไหน เว็บไหนถูกอ้างอิง
- 3 สิ่งที่ต้องทำเพื่อให้ AI อ้างอิงเว็บคุณ: โครงสร้างข้อมูล, Authority, Mention ในแหล่งอื่น
- เคสของเรา: ทำให้ลูกค้าโผล่ใน ChatGPT/Perplexity
- 2026 คือปีที่ GEO สำคัญกว่า SEO — เตรียมตัวยังไง
**Length:** 1,500-2,000 คำ
---
## เขียนยังไงให้ได้ผล
**Tone:** ตรง ๆ มีตัวเลข เล่าเคสจริง ไม่ขายของ — เหมือนคุยกับเพื่อนที่เป็น SME
**โครงสร้าง:** ปัญหา → ตัวอย่างจริง → วิธีแก้ → ผลลัพธ์ (ถ้ามี) → บทเรียน/ข้อคิด
**สิ่งที่ไม่ควรทำ:**
- ไม่ขายบริการตรง ๆ ใน blog — ให้คนอ่านแล้วเกิดความเชื่อถือ แล้วเขาจะกลับมาเอง
- ไม่ใช้ "ครบวงจร ทันสมัย" — ใช้ตัวเลขแทน
- ไม่อ้างอิง source ที่ไม่มีจริง
**SEO:** แต่ละ blog ควรมี:
- Title ที่มีคีย์เวิร์ด (เช่น "AI ไม่ได้แพงเสมอไป")
- Meta description ที่ดึงดูด
- Internal link ไปหน้า services/portfolio
- CTA ท้ายบทความ: "อยากให้ช่วยดูเคสของคุณ? นัดคุย 30 นาทีฟรี"

21
PLAN-REVIEW-LOG.md Normal file
View File

@@ -0,0 +1,21 @@
# Plan Review Log: MoreminiMore Homepage Rebuild
Act 1 grill complete — plan locked with user.
MAX_ROUNDS=5
## Act 1 Summary
- User clarified credibility priority: SME understanding > measurable business value > modern UX/coding impression.
- User clarified homepage must be company-site quality, not a one-page landing page.
- User clarified visual direction: subtle macOS-inspired liquid glass, hybrid light/dark rhythm, abstract business-map parallax, restrained motion.
- User clarified implementation preference: Astro static + vanilla JS first, Google Apps Script for low-volume lead handling.
- User clarified CTA wording: use "ปรึกษาฟรี" only, not "ปรึกษาฟรี 30 นาที".
- User clarified Dealplustech must be included in portfolio using a homepage screenshot.
- User requested a copy-ready Google Apps Script file plus detailed setup instructions.
## Act 2 Status
Not started.
No implementation has been done from this plan yet.

351
PLAN.md Normal file
View File

@@ -0,0 +1,351 @@
# Plan: MoreminiMore Homepage Rebuild
_Locked via grill — by Codex + Kunthawat_
## Goal
Rebuild the MoreminiMore company website from a clean slate, starting with the homepage only. The homepage must make SME owners feel that MoreminiMore is a friendly growth partner who understands real business problems, uses real data before recommending work, and can deliver modern, trustworthy websites and systems. The visual experience should feel modern and a little wow through restrained liquid-glass UI, layered parallax, and polished UX, but never become an effect demo or a tech showcase.
## Core Positioning
Priority of trust:
1. MoreminiMore understands SME businesses and their real problems.
2. MoreminiMore can help clients choose work that is more efficient, worthwhile, and suitable for their business.
3. MoreminiMore writes modern code in the UX sense: smooth, beautiful, easy to use, and subtly impressive.
Target customer priority:
1. Businesses that already have a website, ads, or tools, but feel the result is not worth the money or effort.
2. Businesses that do not yet have a good website or system and want to start correctly.
3. Businesses growing into AI/automation/workflow needs.
Brand role:
1. Growth partner for SMEs.
2. Business diagnosis partner.
3. Team that can implement real working solutions.
Tone:
- Friendly-first.
- Thai-first copy.
- English only for service names and necessary terms.
- No consultant-speak, no overly technical language, no fake metrics.
## Homepage Strategy
Hero strategy:
- Belief-led headline.
- Pain-led subheadline.
- Promise-led CTA/context.
Current hero copy direction:
> ธุรกิจไม่ควรเสียเงินกับสิ่งที่ยังไม่รู้ว่าคุ้มไหม
>
> เราช่วย SME ดูข้อมูลจริงก่อนตัดสินใจทำเว็บ การตลาด AI หรือระบบอัตโนมัติ เพื่อเลือกสิ่งที่ควรทำ อย่างมีประสิทธิภาพ และเหมาะสมกับลูกค้า
The final copy can be polished, especially the phrase "เหมาะสมกับลูกค้า", but the idea should stay intact.
Primary conversion priority:
1. ส่งโจทย์ธุรกิจให้เราดูก่อน
2. ดูเคส/ผลงานก่อน แล้วค่อยติดต่อ
3. ปรึกษาฟรี
Do not use "30 นาที" in CTA copy. Use "ปรึกษาฟรี" only.
Homepage v1 must not include a blog section. Blog content can stay preserved for later, but the homepage should focus on trust, diagnosis, proof, service clarity, portfolio quality, and conversion.
## Homepage Sections
Recommended homepage order:
1. Hero
- Belief-led headline.
- Friendly explanation.
- CTA to open problem form.
- Light abstract business-map background with subtle liquid glass.
2. Problem framing
- Explain that customers do not need to know which service they need.
- MoreminiMore will map the problem to the suitable service.
- CTA opens the same slide-over form.
3. Dataroot diagnosis story
- Dark diagnosis stage.
- Split case layout.
- Left side: narrative diagnosis.
- Right side: metric cards and relevant visual/screenshot.
- Use only real Dataroot metrics:
- +373% impression
- +114.2% click
- -28.3% ad spend
4. Outcome-first service cards
- Service name is still visible in English.
- Card headline should sell the outcome/problem solved, not the service label first.
- Desktop hover reveals "เหมาะกับปัญหาแบบไหน".
- Mobile shows essential information directly.
5. Portfolio preview
- Dark gallery stage.
- Featured + grid layout.
- Featured 1 should be Jet Industries for credibility.
- Featured 2 should be selected from the most visually strong portfolio screenshot after inspecting assets.
- Dataroot does not need to be the main portfolio feature because it has the diagnosis story.
- Portfolio role is mainly visual website quality, because most clients are website clients.
6. Mini process
- Short 4-step process:
1. เข้าใจธุรกิจ
2. ดูข้อมูล
3. เลือกทางที่คุ้ม
4. ลงมือและวัดผล
7. Final CTA
- Friendly, low-friction.
- Reopen form panel.
- Reinforce "ส่งโจทย์ให้เราดูก่อน".
## Problem Form
The primary CTA opens a form, not a separate contact page.
Placement and behavior:
- Desktop: glass slide-over panel from the right.
- Mobile: bottom sheet.
- Floating/sticky CTA appears after the hero, not immediately on first paint.
- Navigation also has a CTA.
Problem chips:
1. เว็บมีอยู่แล้ว แต่ไม่ค่อยมีลูกค้าทัก
2. ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม
3. มีคนทักมา แต่ไม่ใช่ลูกค้าที่ใช่
4. ทีมงานทำงานเดิม ๆ แต่ทำงานช้า หรือผิดพลาดบ่อย
5. อยากใช้ AI แต่ไม่รู้เริ่มตรงไหน
6. ยังไม่แน่ใจว่าควรแก้อะไรก่อน
Textarea:
- Must include a very short example because customers are assumed to be lazy and may not want to type.
- Example direction:
- "ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม อยากรู้ว่าควรแก้อะไรก่อน"
- "มีเว็บแล้ว แต่ลูกค้าไม่ค่อยทัก อยากรู้ว่าควรแก้เว็บหรือยิงแอดก่อน"
Contact fields:
- Name.
- Phone.
- Email.
- Phone or email must be provided, but both are not required.
- Labels must be explicit because non-technical customers may be confused by a single generic "contact channel" field.
Submission backend:
- Use Google Apps Script first because lead volume is expected to be low.
- Send notification email to Gmail/Google Workspace.
- Ideally also store leads in Google Sheet.
- Sender should be MoreminiMore-owned; customer contact should be used as reply-to where possible.
- Keep message clean to reduce spam risk.
- Provide the Google Apps Script as a copy-ready file because the user has not done this setup before.
- Current script artifact: `google-apps-script/lead-form.gs`.
- Current setup guide: `google-apps-script/SETUP.md`.
Post-submit UX:
- Stay in the panel.
- Show success message plus light diagnosis preview.
- Do not pretend to generate a complete diagnosis.
- Example direction: "จากปัญหาที่เลือก เราน่าจะเริ่มจากการดูเว็บ/แอด/ขั้นตอนทำงานก่อน แล้วจะติดต่อกลับทางเบอร์หรืออีเมลที่ให้ไว้"
## Navigation
This is a company website, not a one-page landing page.
Navigation should include:
- หน้าแรก
- บริการ
- ผลงาน
- เกี่ยวกับ
- FAQ and/or บทความ
- ติดต่อ / ส่งโจทย์ให้เราดู
Services submenu:
- Compact mega menu.
- Use English service names:
- Website Development
- Marketing Consult
- Automation Workflow
- AI Consult
- Include a short Thai explanation under each service name.
- Desktop supports hover, click, and keyboard.
- Mobile uses an accordion/list.
Nav visual behavior:
- Hybrid glass sticky nav.
- On hero: transparent/light glass.
- After scroll: compact stronger glass/solid for readability.
## Visual System
Overall mode:
- Hybrid light/dark.
- Light glass for friendly SME trust.
- Dark/premium stages for Dataroot diagnosis and portfolio.
Section atmosphere:
- Light hero.
- Dark Dataroot diagnosis.
- Light service/process/form context.
- Dark portfolio gallery.
Brand assets:
- Use existing logo.
- Use `#fed400` as accent only, not as a full-page wash.
- Use red `#d4553a` sparingly if useful.
- Avoid recreating the old yellow-heavy design.
Liquid glass:
- Subtle macOS-inspired.
- Use in key moments only:
- Navigation.
- CTA/form slide-over.
- Hero card/form/selected elements.
- Dataroot diagnosis cards.
- Possibly light service cards, but not every surface.
- Must preserve readability before effect.
Background and parallax:
- Main background concept: abstract business map.
- Use lines, nodes, soft grids, flow paths, and layered decision-map visuals.
- Hero should not rely on stock imagery.
- Portfolio sections can use real portfolio screenshots as the main visual material.
Motion:
- Desktop:
- Hero mouse parallax should be noticeable enough to feel dimensional.
- Scroll-driven scene changes are allowed.
- Use exactly 3 main background scenes:
1. Hero / light business map.
2. Dataroot / dark diagnosis stage.
3. Portfolio / dark gallery stage.
- Mobile:
- No mouse interaction.
- Use scroll parallax/reveal only.
- Keep performance conservative.
## Portfolio Rules
Portfolio role:
- Show website visual quality and execution.
- Most clients are website clients, not consulting clients.
- Consulting-heavy proof is mainly Dataroot.
- Dealplustech must be included in the website portfolio.
- URL: `https://www.dealplustech.co.th`
- Capture a homepage screenshot and use it as a portfolio image, matching the treatment of other portfolio clients.
- Dealplustech is both website work and consulting-adjacent, but should still appear as a website portfolio item.
Client context:
- Largest client: Jet Industries.
- Second largest: Dataroot.
- Most other clients are smaller.
Sorting priority:
1. Visual quality / modern feel.
2. Professional credibility.
3. SME relatability.
Featured portfolio:
- Featured 1: Jet Industries.
- Featured 2: choose visually strongest work after inspecting assets.
- Other projects in grid.
## Technical Approach
Stack:
- Astro static, rebuilt from scratch.
- Vanilla JS first.
- CSS first for liquid glass and layout.
- Use small vanilla scripts for:
- Mouse parallax.
- Scroll scene transitions.
- Slide-over/bottom sheet form.
- Form validation and submission.
- Do not use React by default.
- Add React only if a specific interaction becomes too complex for readable vanilla JS.
Implementation scope:
- Homepage-first.
- Do not build full route details in v1.
- Navigation may reference future routes, but implementation focus is homepage.
- Preserve extracted inputs in `redesign-input/`.
- Old code remains archived in `_archive/pre-redesign-2026-06-21/`.
Suggested initial implementation files after plan approval:
1. Recreate minimal Astro project files at root:
- `package.json`
- `astro.config.mjs`
- `tsconfig.json`
- `src/pages/index.astro`
- `src/styles/global.css`
- `src/scripts/home.js`
2. Copy required assets from `redesign-input/assets/` into `public/`.
3. Build homepage components either inline first or split only when repeated:
- Navigation
- Hero
- Problem CTA panel
- Dataroot case
- Service cards
- Portfolio preview
- Process
- Footer
4. Add Google Apps Script endpoint configuration as an environment/runtime variable if possible.
## Key Decisions & Tradeoffs
- Problem-first homepage, but service cards still exist because this is a company website.
- Friendly-first copy, but visual system must remain premium enough for Jet/Dataroot credibility.
- Use English service names in nav for professionalism, but Thai copy everywhere else for clarity.
- Use Google Apps Script before heavier transactional email infrastructure because lead volume is expected to be low.
- Use Astro static + vanilla JS to keep the site light and maintainable.
- Use effects only in high-impact places to avoid repeating the previous failure mode of design overwhelming the business message.
## Risks / Open Questions
- The exact visual quality of portfolio assets must be inspected before choosing Featured 2.
- Dealplustech needs a homepage screenshot before implementation can finalize portfolio assets.
- Google Apps Script deliverability depends on the Google account/domain setup. SPF/DKIM/DMARC should be checked before production.
- Navigation points to company-site routes, but homepage is the first implementation scope. Decide whether future routes should be placeholders, omitted, or added later.
- Need final decision on exact final hero copy during implementation polish.
## Out Of Scope For Homepage V1
- Full services pages.
- Full portfolio detail pages.
- Blog section on homepage.
- Full blog redesign.
- Heavy WebGL/canvas animation.
- Full React app or SPA rewrite.
- Invented metrics or testimonials.
- Reusing old design or old code structure as the main foundation.

View File

@@ -1,43 +0,0 @@
# Astro Starter Kit: Minimal
```sh
npm create astro@latest -- --template minimal
```
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```text
/
├── public/
├── src/
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

View File

@@ -1,166 +0,0 @@
/**
* MOREMINIMORE - Contact Form Backend (Google Apps Script)
* Per plan 2026-06-13 round 2 #4:
* Form submit → Apps Script doPost() → Google Sheet (log)
* → Email to contact@moreminimore.com
* → LINE Notify
*
* USER DEPLOYS THIS THEMSELVES (see README.md in same folder).
* 1. Create new Apps Script project at https://script.google.com
* 2. Paste this entire file into Code.gs
* 3. Set Script Properties (Project Settings → Script Properties):
* SHEET_ID — Google Sheet ID (from Sheet URL)
* LINE_NOTIFY_TOKEN — from https://notify-bot.line.me
* RECIPIENT_EMAIL — contact@moreminimore.com (or any email)
* 4. Create Google Sheet with these headers in row 1:
* timestamp | name | phone | email | service | message | variant | userAgent
* 5. Deploy → New deployment → Type: Web app
* Execute as: Me
* Who has access: Anyone
* Copy the deployment URL.
* 6. Add to moreminimore-astroreal/.env:
* PUBLIC_CONTACT_ENDPOINT=<paste deployment URL>
*/
/* ------------------------------------------------------------------ */
/* CONFIG — read from Script Properties (set in Project Settings) */
/* ------------------------------------------------------------------ */
function getConfig() {
const props = PropertiesService.getScriptProperties();
return {
SHEET_ID: props.getProperty('SHEET_ID'),
LINE_NOTIFY_TOKEN: props.getProperty('LINE_NOTIFY_TOKEN'),
RECIPIENT_EMAIL: props.getProperty('RECIPIENT_EMAIL') || 'contact@moreminimore.com',
};
}
/* ------------------------------------------------------------------ */
/* HANDLER — POST /exec (or /dev) */
/* ------------------------------------------------------------------ */
/**
* Handle form submission. Expects JSON body:
* {
* name, phone, email, service, message, variant, userAgent, submittedAt
* }
*/
function doPost(e) {
try {
const data = JSON.parse(e.postData.contents);
const config = getConfig();
// 1. Log to Google Sheet
let rowId = null;
if (config.SHEET_ID) {
const sheet = SpreadsheetApp.openById(config.SHEET_ID).getActiveSheet();
const row = sheet.appendRow([
new Date(), // timestamp
data.name || '',
data.phone || '',
data.email || '',
data.service || '',
data.message || '',
data.variant || 'full',
data.userAgent || '',
]);
rowId = row.getRange().getRow();
}
// 2. Send email
const subject = `[moreminimore contact] ${data.service || 'general'} — ${data.name || data.phone || 'unknown'}`;
const body = formatEmailBody(data);
MailApp.sendEmail({
to: config.RECIPIENT_EMAIL,
subject: subject,
body: body,
replyTo: data.email || undefined,
});
// 3. Send LINE Notify
if (config.LINE_NOTIFY_TOKEN) {
const lineMessage = formatLineMessage(data);
UrlFetchApp.fetch('https://notify-api.line.me/api/notify', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + config.LINE_NOTIFY_TOKEN,
'Content-Type': 'application/x-www-form-urlencoded',
},
payload: { message: lineMessage },
muteHttpExceptions: true,
});
}
return ContentService
.createTextOutput(JSON.stringify({ ok: true, id: rowId }))
.setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return ContentService
.createTextOutput(JSON.stringify({ ok: false, error: err.toString() }))
.setMimeType(ContentService.MimeType.JSON);
}
}
/* ------------------------------------------------------------------ */
/* FORMATTERS */
/* ------------------------------------------------------------------ */
function formatEmailBody(data) {
return [
'New contact form submission',
'',
'---',
'Name: ' + (data.name || '-'),
'Phone: ' + (data.phone || '-'),
'Email: ' + (data.email || '-'),
'Service: ' + (data.service || '-'),
'Variant: ' + (data.variant || 'full'),
'---',
'',
'Message:',
data.message || '(empty)',
'',
'---',
'Submitted: ' + (data.submittedAt || new Date().toISOString()),
'UserAgent: ' + (data.userAgent || 'unknown'),
].join('\n');
}
function formatLineMessage(data) {
const lines = [
'🔔 moreminimore contact',
'',
'👤 ' + (data.name || data.phone || 'unknown'),
'📞 ' + (data.phone || '-'),
'✉ ' + (data.email || '-'),
'🎯 ' + (data.service || 'general'),
];
if (data.message) {
lines.push('');
lines.push(data.message.length > 200 ? data.message.slice(0, 200) + '...' : data.message);
}
return lines.join('\n');
}
/* ------------------------------------------------------------------ */
/* TEST (optional — call testDoPost() from Apps Script editor) */
/* ------------------------------------------------------------------ */
function testDoPost() {
const mockEvent = {
postData: {
contents: JSON.stringify({
name: 'Test User',
phone: '080-123-4567',
email: 'test@example.com',
service: 'webdev',
message: 'This is a test message',
variant: 'full',
userAgent: 'test',
submittedAt: new Date().toISOString(),
}),
},
};
Logger.log(doPost(mockEvent).getContent());
}

View File

@@ -1,140 +0,0 @@
# Contact Form Backend — Google Apps Script
This is the backend for the contact form on the MoreminiMore website.
When someone submits the form, this Apps Script:
1. **Logs** the submission to a Google Sheet (audit trail)
2. **Emails** the submission to `contact@moreminimore.com` (your Google Workspace)
3. **Sends** a LINE Notify to your phone
The user (you) deploys this script. Hermes Agent cannot deploy it for you — it requires access to your Google account.
---
## Prerequisites
- A Google account (use `contact@moreminimore.com` or any Google Workspace account)
- A LINE Notify token (get one at <https://notify-bot.line.me/> — log in → My page → Generate token)
---
## Setup (5 minutes)
### Step 1: Create the Apps Script project
1. Go to <https://script.google.com/start>
2. Click **New project** (or "โปรเจ็กต์ใหม่" in Thai)
3. Rename the project (top-left) to `moreminimore-contact-form`
4. Delete the default `function myFunction() {}` code
5. Open `Code.gs` from this folder in your text editor
6. **Copy the entire contents** and **paste** into the Apps Script editor
7. Click 💾 (Save) or Ctrl+S
### Step 2: Set Script Properties
1. Click **Project Settings** (⚙️ gear icon on the left)
2. Scroll down to **Script Properties**
3. Click **Add script property** and add these 3:
| Property | Value | Where to get it |
|---|---|---|
| `SHEET_ID` | (Google Sheet ID) | See Step 3 below |
| `LINE_NOTIFY_TOKEN` | (LINE token) | <https://notify-bot.line.me/> → My page → Generate token → Copy |
| `RECIPIENT_EMAIL` | `contact@moreminimore.com` | Just type your email |
### Step 3: Create the Google Sheet
1. Go to <https://sheets.google.com/create>
2. Rename to `moreminimore-contact-log` (or whatever you like)
3. In row 1, add these headers (one per cell, A1 through H1):
```
timestamp | name | phone | email | service | message | variant | userAgent
```
4. **Get the Sheet ID** from the URL:
- URL looks like: `https://docs.google.com/spreadsheets/d/1aBcD...XyZ/edit`
- The `1aBcD...XyZ` part is the **SHEET_ID** — copy it
5. Paste it into Script Properties → `SHEET_ID` value
### Step 4: Test the script (optional but recommended)
1. In the Apps Script editor, select function `testDoPost` from the dropdown (next to the debug ▶ button)
2. Click **Run** (▶)
3. If prompted, authorize the script (review permissions → Allow)
4. Check:
- The Google Sheet has a new row at the bottom
- The recipient email got a new message
- Your LINE got a notification
5. Check **Execution log** (View → Logs) for any errors
### Step 5: Deploy as Web App
1. Click **Deploy** (top-right) → **New deployment**
2. Click the ⚙️ gear icon → select **Web app**
3. Configure:
- **Description**: `moreminimore contact form v1`
- **Execute as**: `Me (your-email@gmail.com)`
- **Who has access**: `Anyone` ← important, otherwise form can't reach it
4. Click **Deploy**
5. You may be asked to authorize again — click **Review permissions** → choose your account → **Allow**
6. **Copy the Web app URL** — it looks like:
```
https://script.google.com/macros/s/AKfycbz.../exec
```
### Step 6: Wire the URL into the website
1. Open `moreminimore-astroreal/.env` (create it if it doesn't exist)
2. Add this line (paste your URL):
```
PUBLIC_CONTACT_ENDPOINT=https://script.google.com/macros/s/AKfycbz.../exec
```
3. Save the file
4. Rebuild the site: `npm run build`
5. Deploy (or push to your host)
---
## Verifying it works
After deploy, visit the website, fill the form, hit submit.
You should see:
- ✅ Toast: "✓ ส่งแล้ว เราจะติดต่อกลับภายใน 24 ชม."
- ✅ New row in the Google Sheet
- ✅ Email in your inbox
- ✅ LINE notification on your phone
If something fails, check:
- **Apps Script Execution Log** (Executions tab on the left) — shows errors
- **Sheet ID** is correct (no extra spaces, full ID)
- **LINE token** is active (revoke + regenerate if needed)
- **"Who has access"** is set to `Anyone` on the deployment
---
## Updating the script later
When you change `Code.gs`:
1. Save in the editor
2. **Deploy** → **Manage deployments** → ✏️ (edit) → **Version: New version** → **Deploy**
3. The Web app URL stays the same — no need to update `.env`
---
## Security notes
- The web app URL is not secret — anyone who knows it can submit
- But it has no destructive power (only appends rows + sends email/notify to you)
- If you receive spam, you can revoke the LINE token + change the deployment URL
- Consider adding reCAPTCHA later if spam becomes a problem
---
## Cost
- **Google Apps Script**: free (1-hour quota, plenty for contact forms)
- **Google Sheets**: free up to 10M cells
- **MailApp**: free for ~100 emails/day per user
- **LINE Notify**: free, unlimited messages, but discontinued March 2025 in some regions — check status at <https://notify-bot.line.me/>
If LINE Notify is shut down, swap the LINE call for a Telegram bot or Discord webhook (same `UrlFetchApp.fetch` pattern).

View File

@@ -1,15 +1,8 @@
// @ts-check
import { defineConfig } from 'astro/config';
import react from "@astrojs/react";
import mdx from "@astrojs/mdx";
// All content is markdown → static output. No server runtime needed.
export default defineConfig({
output: "static",
integrations: [
react(),
mdx(),
],
image: { layout: "constrained", responsiveStyles: true },
devToolbar: { enabled: true },
output: 'static',
image: { layout: 'constrained', responsiveStyles: true },
devToolbar: { enabled: false },
});

153
google-apps-script/SETUP.md Normal file
View File

@@ -0,0 +1,153 @@
# Google Apps Script Lead Form Setup
ใช้ไฟล์นี้เพื่อตั้งระบบรับ lead จากฟอร์ม MoreminiMore แบบง่ายก่อน โดยให้ Google Apps Script บันทึกข้อมูลลง Google Sheet และส่งอีเมลแจ้งเตือนเข้า Gmail/Google Workspace
อ้างอิง official docs:
- Apps Script Web App deployment: https://developers.google.com/apps-script/guides/web
- Apps Script MailApp: https://developers.google.com/apps-script/reference/mail/mail-app
## สิ่งที่ต้องมี
- Google account หรือ Google Workspace account ที่จะใช้รับ lead
- แนะนำให้ใช้บัญชีของโดเมนบริษัท เช่น `contact@moreminimore.com`
- Google Sheet ใหม่ 1 ไฟล์ สำหรับเก็บ lead
## ขั้นตอนติดตั้ง
### 1. สร้าง Google Sheet
1. เข้า Google Drive
2. สร้าง Google Sheet ใหม่
3. ตั้งชื่อเช่น `MoreminiMore Website Leads`
4. ไม่ต้องสร้าง column เอง script จะสร้าง header ให้ตอนมี lead แรก
### 2. เปิด Apps Script จาก Sheet
1. ใน Google Sheet ไปที่ `Extensions`
2. เลือก `Apps Script`
3. จะเปิดหน้า Apps Script editor
4. ลบโค้ดเดิมใน `Code.gs`
5. Copy โค้ดทั้งหมดจาก `google-apps-script/lead-form.gs`
6. Paste ลงใน `Code.gs`
### 3. แก้อีเมลผู้รับ
ในไฟล์ `Code.gs` หา:
```js
const CONFIG = {
RECIPIENT_EMAIL: 'contact@moreminimore.com',
```
เปลี่ยน `RECIPIENT_EMAIL` เป็นอีเมลที่จะรับแจ้งเตือน lead
ถ้าใช้ `contact@moreminimore.com` อยู่แล้ว ไม่ต้องแก้
### 4. Save project
1. กด Save
2. ตั้งชื่อ project เช่น `MoreminiMore Lead Form`
### 5. Deploy เป็น Web App
ตาม official docs ของ Google ให้ deploy web app โดย:
1. มุมขวาบน กด `Deploy`
2. เลือก `New deployment`
3. ตรง `Select type` กด icon ตั้งค่า แล้วเลือก `Web app`
4. ตั้งค่า:
- Description: `MoreminiMore lead form endpoint`
- Execute as: `Me`
- Who has access: `Anyone`
5. กด `Deploy`
6. Google จะขอ authorize permissions
7. เลือก account ของคุณ
8. อนุญาตสิทธิ์ที่เกี่ยวกับ Google Sheets และส่งอีเมล
9. Copy `Web app URL` เก็บไว้
URL จะหน้าตาประมาณ:
```text
https://script.google.com/macros/s/xxxxxxxxxxxxxxxx/exec
```
### 6. ทดสอบ endpoint
เปิด URL ที่ copy มาใน browser ถ้าระบบทำงาน จะเห็น JSON ประมาณ:
```json
{"ok":true,"service":"MoreminiMore lead form"}
```
### 7. เอา URL ไปใส่ในเว็บ
ตอน implement หน้าเว็บ ให้ตั้งค่า URL นี้เป็น endpoint ของฟอร์ม
ข้อควรระวัง: Apps Script web app มักไม่เหมาะกับ fetch ที่ต้องอ่าน JSON response ข้ามโดเมนแบบเต็ม ๆ เพราะอาจติด CORS ได้ วิธีที่เหมาะกับ static site คือส่งข้อมูลแบบ simple POST หรือ `fetch(..., { mode: "no-cors" })` แล้วให้หน้าเว็บแสดง success state หลัง request ถูกส่งออกไป
ตัวอย่าง payload ที่เว็บควรส่ง:
```json
{
"name": "คุณเอ",
"phone": "0800000000",
"email": "owner@example.com",
"problems": ["ads_not_worth_it", "wrong_leads"],
"message": "ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม อยากรู้ว่าควรแก้อะไรก่อน",
"pageUrl": "https://moreminimore.com/",
"userAgent": "browser user agent"
}
```
## Problem Keys ที่ script รองรับ
| Key | ข้อความ |
| --- | --- |
| `website_no_leads` | เว็บมีอยู่แล้ว แต่ไม่ค่อยมีลูกค้าทัก |
| `ads_not_worth_it` | ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม |
| `wrong_leads` | มีคนทักมา แต่ไม่ใช่ลูกค้าที่ใช่ |
| `slow_or_error_work` | ทีมงานทำงานเดิม ๆ แต่ทำงานช้า หรือผิดพลาดบ่อย |
| `ai_not_sure` | อยากใช้ AI แต่ไม่รู้เริ่มตรงไหน |
| `not_sure` | ยังไม่แน่ใจว่าควรแก้อะไรก่อน |
## วิธีลดโอกาสเมลเข้าขยะ
Apps Script จะส่งเมลจากบัญชี Google ที่ deploy script ดังนั้นควร:
- ใช้บัญชี Google Workspace ของบริษัท ถ้ามี
- ตั้งค่า SPF/DKIM/DMARC ของโดเมนให้ถูกต้อง
- ใช้ subject ปกติ ไม่ spammy เช่น `มีโจทย์ธุรกิจใหม่จากเว็บไซต์ MoreminiMore`
- อย่าใช้ email ลูกค้าเป็น `From`
- ให้ script ใช้ email ลูกค้าเป็น `Reply-To` แทน
- เนื้อหาอีเมลควรเป็นข้อความสะอาด ไม่ใส่คำขายหรือ link เยอะ
## เวลาแก้ script หลัง deploy
ถ้าแก้โค้ดหลังจาก deploy แล้ว:
1. กด `Deploy`
2. เลือก `Manage deployments`
3. เลือก deployment เดิม
4. กด edit
5. เลือก version ใหม่ หรือ new version
6. กด deploy/update
ถ้าสร้าง deployment ใหม่ URL อาจเปลี่ยน ต้องเอา URL ใหม่ไปใส่ในเว็บอีกครั้ง
## Debug เบื้องต้น
ถ้า submit แล้วไม่เข้า Sheet:
1. เปิด Apps Script
2. ดูเมนู `Executions`
3. เปิด execution ล่าสุดเพื่อดู error
4. ตรวจว่า deploy เป็น `Who has access: Anyone`
5. ตรวจว่าใช้ URL ที่ลงท้าย `/exec` ไม่ใช่ `/dev`
ถ้าเข้า Sheet แต่ไม่ส่งเมล:
1. ตรวจสิทธิ์ MailApp ตอน authorize
2. ตรวจ `RECIPIENT_EMAIL`
3. ตรวจ quota ของ Google account
4. ดู error ใน `Executions`

View File

@@ -0,0 +1,290 @@
/**
* MoreminiMore lead form endpoint.
*
* Recommended setup:
* 1. Create a Google Sheet for leads.
* 2. Open Extensions > Apps Script.
* 3. Paste this entire file into Code.gs.
* 4. Update CONFIG.RECIPIENT_EMAIL.
* 5. Deploy as Web app.
*/
const CONFIG = {
RECIPIENT_EMAIL: 'contact@moreminimore.com',
SHEET_NAME: 'Leads',
TIMEZONE: 'Asia/Bangkok',
EMAIL_SUBJECT: 'มีโจทย์ธุรกิจใหม่จากเว็บไซต์ MoreminiMore',
};
const PROBLEM_LABELS = {
website_no_leads: 'เว็บมีอยู่แล้ว แต่ไม่ค่อยมีลูกค้าทัก',
ads_not_worth_it: 'ยิงแอดอยู่ แต่ยอดขายไม่คุ้ม',
wrong_leads: 'มีคนทักมา แต่ไม่ใช่ลูกค้าที่ใช่',
slow_or_error_work: 'ทีมงานทำงานเดิม ๆ แต่ทำงานช้า หรือผิดพลาดบ่อย',
ai_not_sure: 'อยากใช้ AI แต่ไม่รู้เริ่มตรงไหน',
not_sure: 'ยังไม่แน่ใจว่าควรแก้อะไรก่อน',
};
function doGet() {
return jsonResponse({
ok: true,
service: 'MoreminiMore lead form',
});
}
function doPost(e) {
try {
const data = parseRequest(e);
if (isSpam(data)) {
return jsonResponse({ ok: true, skipped: true });
}
const lead = normalizeLead(data);
const validation = validateLead(lead);
if (!validation.ok) {
return jsonResponse({
ok: false,
error: validation.error,
});
}
const lock = LockService.getScriptLock();
lock.waitLock(10000);
try {
appendLead(lead);
} finally {
lock.releaseLock();
}
sendLeadEmail(lead);
return jsonResponse({
ok: true,
message: 'Lead received',
diagnosis: buildLightDiagnosis(lead.problems),
});
} catch (error) {
console.error(error);
return jsonResponse({
ok: false,
error: 'ระบบรับข้อมูลมีปัญหา กรุณาลองใหม่อีกครั้ง',
});
}
}
function parseRequest(e) {
if (!e) return {};
const contentType = String(e.postData && e.postData.type || '').toLowerCase();
const raw = e.postData && e.postData.contents;
if (raw && contentType.indexOf('application/json') !== -1) {
return JSON.parse(raw);
}
if (raw && contentType.indexOf('text/plain') !== -1) {
try {
return JSON.parse(raw);
} catch (error) {
return e.parameter || {};
}
}
return e.parameter || {};
}
function normalizeLead(data) {
const problems = normalizeProblems(data.problems || data.problem || data.problemKeys);
return {
createdAt: Utilities.formatDate(new Date(), CONFIG.TIMEZONE, 'yyyy-MM-dd HH:mm:ss'),
name: cleanText(data.name),
phone: cleanText(data.phone),
email: cleanText(data.email).toLowerCase(),
message: cleanText(data.message || data.details || data.note),
problems,
pageUrl: cleanText(data.pageUrl || data.url),
userAgent: cleanText(data.userAgent),
};
}
function normalizeProblems(value) {
if (!value) return [];
if (Array.isArray(value)) {
return value.map(String).map(cleanText).filter(Boolean);
}
return String(value)
.split(',')
.map(cleanText)
.filter(Boolean);
}
function validateLead(lead) {
if (!lead.name) {
return { ok: false, error: 'กรุณาใส่ชื่อ' };
}
if (!lead.phone && !lead.email) {
return { ok: false, error: 'ใส่เบอร์โทรหรืออีเมลอย่างใดอย่างหนึ่งก็ได้' };
}
if (lead.email && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(lead.email)) {
return { ok: false, error: 'รูปแบบอีเมลไม่ถูกต้อง' };
}
if (lead.message.length > 2000) {
return { ok: false, error: 'รายละเอียดโจทย์ยาวเกินไป' };
}
return { ok: true };
}
function appendLead(lead) {
const sheet = getLeadSheet();
sheet.appendRow([
lead.createdAt,
lead.name,
lead.phone,
lead.email,
problemLabels(lead.problems).join(', '),
lead.message,
buildLightDiagnosis(lead.problems),
lead.pageUrl,
lead.userAgent,
]);
}
function getLeadSheet() {
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
let sheet = spreadsheet.getSheetByName(CONFIG.SHEET_NAME);
if (!sheet) {
sheet = spreadsheet.insertSheet(CONFIG.SHEET_NAME);
}
if (sheet.getLastRow() === 0) {
sheet.appendRow([
'วันที่ส่ง',
'ชื่อ',
'เบอร์โทร',
'อีเมล',
'ปัญหาที่เลือก',
'รายละเอียด',
'แนวทางเริ่มต้น',
'Page URL',
'User Agent',
]);
sheet.setFrozenRows(1);
}
return sheet;
}
function sendLeadEmail(lead) {
const labels = problemLabels(lead.problems);
const diagnosis = buildLightDiagnosis(lead.problems);
const plainBody = [
'มีโจทย์ธุรกิจใหม่จากเว็บไซต์ MoreminiMore',
'',
`ชื่อ: ${lead.name}`,
`เบอร์โทร: ${lead.phone || '-'}`,
`อีเมล: ${lead.email || '-'}`,
`ปัญหาที่เลือก: ${labels.length ? labels.join(', ') : '-'}`,
'',
'รายละเอียด:',
lead.message || '-',
'',
`แนวทางเริ่มต้น: ${diagnosis}`,
'',
`Page URL: ${lead.pageUrl || '-'}`,
`เวลาที่ส่ง: ${lead.createdAt}`,
].join('\n');
const htmlBody = `
<div style="font-family:Arial,sans-serif;line-height:1.6;color:#17120a">
<h2 style="margin:0 0 12px">มีโจทย์ธุรกิจใหม่จากเว็บไซต์ MoreminiMore</h2>
<p><strong>ชื่อ:</strong> ${escapeHtml(lead.name)}</p>
<p><strong>เบอร์โทร:</strong> ${escapeHtml(lead.phone || '-')}</p>
<p><strong>อีเมล:</strong> ${escapeHtml(lead.email || '-')}</p>
<p><strong>ปัญหาที่เลือก:</strong> ${escapeHtml(labels.length ? labels.join(', ') : '-')}</p>
<p><strong>รายละเอียด:</strong><br>${escapeHtml(lead.message || '-').replace(/\n/g, '<br>')}</p>
<p><strong>แนวทางเริ่มต้น:</strong> ${escapeHtml(diagnosis)}</p>
<hr>
<p style="color:#666;font-size:13px">
Page URL: ${escapeHtml(lead.pageUrl || '-')}<br>
เวลาที่ส่ง: ${escapeHtml(lead.createdAt)}
</p>
</div>
`;
const options = {
name: 'MoreminiMore Website',
htmlBody,
};
if (lead.email) {
options.replyTo = lead.email;
}
MailApp.sendEmail(CONFIG.RECIPIENT_EMAIL, CONFIG.EMAIL_SUBJECT, plainBody, options);
}
function buildLightDiagnosis(problemKeys) {
const keys = problemKeys || [];
if (keys.indexOf('ads_not_worth_it') !== -1 || keys.indexOf('wrong_leads') !== -1) {
return 'น่าจะเริ่มจากการดูข้อมูลแอด กลุ่มเป้าหมาย และคุณภาพลูกค้าที่ทักเข้ามาก่อน';
}
if (keys.indexOf('website_no_leads') !== -1) {
return 'น่าจะเริ่มจากการดูเว็บ เส้นทางลูกค้า และจุดที่ควรชวนให้ติดต่อก่อน';
}
if (keys.indexOf('slow_or_error_work') !== -1) {
return 'น่าจะเริ่มจากการดูขั้นตอนทำงานซ้ำ จุดที่ช้า และจุดที่ผิดพลาดบ่อยก่อน';
}
if (keys.indexOf('ai_not_sure') !== -1) {
return 'น่าจะเริ่มจากการดูงานจริงของทีมก่อน แล้วค่อยเลือกจุดที่ AI ช่วยได้อย่างเหมาะสม';
}
return 'เราจะเริ่มจากการทำความเข้าใจธุรกิจและข้อมูลที่มีอยู่ก่อน แล้วค่อยแนะนำทางที่คุ้มที่สุด';
}
function problemLabels(problemKeys) {
return (problemKeys || []).map(function (key) {
return PROBLEM_LABELS[key] || key;
});
}
function isSpam(data) {
return Boolean(data.website || data.company_url || data.url2);
}
function cleanText(value) {
return String(value || '')
.replace(/\r/g, '')
.trim()
.slice(0, 2000);
}
function escapeHtml(value) {
return String(value || '')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
function jsonResponse(data) {
return ContentService
.createTextOutput(JSON.stringify(data))
.setMimeType(ContentService.MimeType.JSON);
}

6122
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,8 @@
{
"name": "moreminimore-site",
"type": "module",
"version": "0.0.1",
"version": "1.0.0",
"private": true,
"engines": {
"node": ">=22.12.0"
},
@@ -12,10 +13,6 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^5.0.6",
"@astrojs/react": "^5.0.5",
"astro": "^6.2.2",
"react": "^19.2.5",
"react-dom": "^19.2.5"
"astro": "^6.2.2"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1 +0,0 @@
<svg fill="#0866FF" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Facebook</title><path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"/></svg>

Before

Width:  |  Height:  |  Size: 558 B

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 36 36" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1,0,0,1,-6,-6)">
<path d="M12.5,42L35.5,42C39.09,42 42,39.09 42,35.5L42,12.5C42,8.91 39.09,6 35.5,6L12.5,6C8.91,6 6,8.91 6,12.5L6,35.5C6,39.09 8.91,42 12.5,42Z" style="fill:rgb(0,195,0);fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,-6,-6)">
<path d="M37.113,22.417C37.113,16.552 31.233,11.78 24.006,11.78C16.779,11.78 10.898,16.552 10.898,22.417C10.898,27.675 15.561,32.079 21.86,32.912C22.287,33.004 22.868,33.194 23.015,33.558C23.147,33.889 23.101,34.408 23.057,34.743C23.057,34.743 22.904,35.668 22.87,35.865C22.813,36.196 22.607,37.161 24.005,36.572C25.404,35.983 31.553,32.127 34.303,28.961L34.302,28.961C36.203,26.879 37.113,24.764 37.113,22.417ZM18.875,25.907L16.271,25.907C15.892,25.907 15.584,25.599 15.584,25.219L15.584,20.01C15.584,19.631 15.892,19.323 16.271,19.323C16.65,19.323 16.958,19.631 16.958,20.01L16.958,24.531L18.875,24.531C19.254,24.531 19.562,24.839 19.562,25.218C19.562,25.598 19.254,25.907 18.875,25.907ZM21.568,25.219C21.568,25.598 21.26,25.907 20.881,25.907C20.502,25.907 20.194,25.599 20.194,25.219L20.194,20.01C20.194,19.631 20.502,19.323 20.881,19.323C21.26,19.323 21.568,19.631 21.568,20.01L21.568,25.219ZM27.838,25.219C27.838,25.516 27.65,25.778 27.368,25.871C27.297,25.895 27.223,25.907 27.15,25.907C26.935,25.907 26.73,25.804 26.601,25.632L23.932,21.997L23.932,25.219C23.932,25.598 23.624,25.907 23.244,25.907C22.865,25.907 22.556,25.599 22.556,25.219L22.556,20.01C22.556,19.714 22.745,19.452 23.026,19.358C23.097,19.334 23.17,19.323 23.244,19.323C23.458,19.323 23.664,19.426 23.793,19.598L26.463,23.233L26.463,20.01C26.463,19.631 26.772,19.323 27.151,19.323C27.53,19.323 27.838,19.631 27.838,20.01L27.838,25.219ZM32.052,21.927C32.431,21.927 32.74,22.235 32.74,22.615C32.74,22.994 32.432,23.302 32.052,23.302L30.135,23.302L30.135,24.532L32.052,24.532C32.431,24.532 32.74,24.84 32.74,25.219C32.74,25.598 32.431,25.907 32.052,25.907L29.448,25.907C29.07,25.907 28.761,25.599 28.761,25.219L28.761,20.011C28.761,19.632 29.069,19.324 29.448,19.324L32.052,19.324C32.431,19.324 32.74,19.632 32.74,20.011C32.74,20.39 32.432,20.698 32.052,20.698L30.135,20.698L30.135,21.928L32.052,21.928L32.052,21.927Z" style="fill:white;fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -1 +0,0 @@
<svg role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path fill="#00c300" d="M12.5,42h23c3.59,0,6.5-2.91,6.5-6.5v-23C42,8.91,39.09,6,35.5,6h-23C8.91,6,6,8.91,6,12.5v23C6,39.09,8.91,42,12.5,42z"/><path fill="#fff" d="M37.113,22.417c0-5.865-5.88-10.637-13.107-10.637s-13.108,4.772-13.108,10.637c0,5.258,4.663,9.662,10.962,10.495c0.427,0.092,1.008,0.282,1.155,0.646c0.132,0.331,0.086,0.85,0.042,1.185c0,0-0.153,0.925-0.187,1.122c-0.057,0.331-0.263,1.296,1.135,0.707c1.399-0.589,7.548-4.445,10.298-7.611h-0.001C36.203,26.879,37.113,24.764,37.113,22.417z M18.875,25.907h-2.604c-0.379,0-0.687-0.308-0.687-0.688V20.01c0-0.379,0.308-0.687,0.687-0.687c0.379,0,0.687,0.308,0.687,0.687v4.521h1.917c0.379,0,0.687,0.308,0.687,0.687C19.562,25.598,19.254,25.907,18.875,25.907z M21.568,25.219c0,0.379-0.308,0.688-0.687,0.688s-0.687-0.308-0.687-0.688V20.01c0-0.379,0.308-0.687,0.687-0.687s0.687,0.308,0.687,0.687V25.219z M27.838,25.219c0,0.297-0.188,0.559-0.47,0.652c-0.071,0.024-0.145,0.036-0.218,0.036c-0.215,0-0.42-0.103-0.549-0.275l-2.669-3.635v3.222c0,0.379-0.308,0.688-0.688,0.688c-0.379,0-0.688-0.308-0.688-0.688V20.01c0-0.296,0.189-0.558,0.47-0.652c0.071-0.024,0.144-0.035,0.218-0.035c0.214,0,0.42,0.103,0.549,0.275l2.67,3.635V20.01c0-0.379,0.309-0.687,0.688-0.687c0.379,0,0.687,0.308,0.687,0.687V25.219z M32.052,21.927c0.379,0,0.688,0.308,0.688,0.688c0,0.379-0.308,0.687-0.688,0.687h-1.917v1.23h1.917c0.379,0,0.688,0.308,0.688,0.687c0,0.379-0.309,0.688-0.688,0.688h-2.604c-0.378,0-0.687-0.308-0.687-0.688v-2.603c0-0.001,0-0.001,0-0.001c0,0,0-0.001,0-0.001v-2.601c0-0.001,0-0.001,0-0.002c0-0.379,0.308-0.687,0.687-0.687h2.604c0.379,0,0.688,0.308,0.688,0.687s-0.308,0.687-0.688,0.687h-1.917v1.23H32.052z"/></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1 +0,0 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#0A66C2"><title>LinkedIn</title><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>

Before

Width:  |  Height:  |  Size: 626 B

View File

@@ -1 +0,0 @@
<svg fill="#000000" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>X</title><path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"/></svg>

Before

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 477 B

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

View File

@@ -1,22 +0,0 @@
{
"name": "MoreminiMore",
"short_name": "MoreminiMore",
"description": "ที่ปรึกษาที่วางกลยุทธ์จากข้อมูล ไม่ใช่จากประสบการณ์ล้วน ๆ — รับทำเว็บ ที่ปรึกษาการตลาด และวางระบบ AI ในองค์กร",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#fed400",
"background_color": "#ffffff",
"display": "standalone",
"start_url": "/",
"lang": "th"
}

Binary file not shown.

View File

@@ -1,277 +0,0 @@
# คำถามสำหรับปรับปรุงเนื้อหาเว็บ moreminimore
> ตอบข้อไหนได้ก็ตอบ ข้อไหนไม่รู้หรือไม่อยากตอบก็เว้นว่างไว้
> พิมพ์สั้น ๆ ก็ได้ เช่น `A1: คนที่ทำเว็บแล้วดูแลต่อ ไม่ทิ้ง` — พอแล้ว เอาไปขยายต่อได้
>
> เมื่อเติมคำตอบเสร็จ ให้บอก path ของไฟล์นี้กลับมา เช่น `~/Desktop/questions-for-content.md` หรือ `moreminimore-astroreal/questions-for-content.md` หลัง `git push`
---
## 🔴 กลุ่ม A — ตัวตน & ตลาด (ตอบก่อนแตะปากกา)
เรื่องพื้นฐานที่ต้องชัดก่อนเขียนอะไร — ถ้าตอบไม่ได้สักข้อ ก็เป็นสัญญาณว่าเว็บยังเขียนไม่ได้
### A1 — คุณเป็นใครในมุมของลูกค้า
ถ้าเพื่อนที่เป็น SME ถามว่า "ทำไมต้องจ้างมอร์มินิมอร์ ทั้ง ๆ ที่มีตัวเลือกเยอะ" คุณตอบยังไงใน 1 ประโยค? (ไม่ใช่ประวัติ — เป็นสิ่งที่ทำให้คุณต่าง)
```
คำตอบ:
```
### A2 — ลูกค้าที่คุณชอบทำงานด้วยที่สุด
เป็นแบบไหน? (ขนาด, อุตสาหกรรม, ลักษณะนิสัย, งบประมาณคร่าว ๆ)
```
คำตอบ:
```
### A3 — ลูกค้าที่คุณไม่อยากรับ
เป็นแบบไหน? (จะเอาไปเขียนเป็นส่วน "ไม่เหมาะกับ" ในเว็บ — ทำให้คนที่ใช่อยากคุยมากขึ้น และลดเคสที่เสียเวลา)
```
คำตอบ:
```
### A4 — งานชิ้นที่ภูมิใจที่สุด
ชิ้นไหน และทำไม? (จะกลายเป็น portfolio flagship — อาจเล่าแบบเจาะลึก 1 หน้าเต็ม)
```
คำตอบ:
```
### A5 — งานชิ้นที่พังหรือเกือบพัง
เกิดอะไรขึ้น แก้ยังไง? (เอาไปเล่าเป็นบทเรียน — แบบนี้ลูกค้าจะเชื่อถือมากกว่า "ผลงานสวยหมด" เพราะดูจริงใจ)
```
คำตอบ:
```
### A6 — SME ไทยทำพลาดเรื่องเดิมซ้ำ ๆ เรื่องอะไร
ช่วง 5 ปีที่ผ่านมา คุณเห็นอะไรซ้ำ ๆ? (คำตอบจะกลายเป็นเสียงของคุณในเว็บ + ไอเดียเขียน blog ได้อีกหลายเรื่อง)
```
คำตอบ:
```
---
## 🟠 กลุ่ม B — เสนอคุณค่า (ตอบก่อนเขียน service page)
เพื่อให้ service page แต่ละหน้าไม่ซ้ำกัน และลูกค้าเห็นว่าต้องเลือกคุณยังไง
### B7 — บริการแต่ละตัวต่างกันตรงไหน
Web / Marketing / Automation / AI Consult — กระบวนการทำงานต่างกันยังไง? ไม่ใช่ "ส่งมอบอะไร" แต่ "ทำงานยังไง"
- **Web (Astro/WordPress)** — workflow เป็นยังไง กี่รอบ feedback ใช้ stack อะไร
```
คำตอบ:
```
- **Marketing** — ใช้ GA4 / Meta Pixel / SEO tools อะไร วัดผลยังไง
```
คำตอบ:
```
- **Automation** — ใช้ n8n / Make / Zapier / custom code เลือกยังไง
```
คำตอบ:
```
- **AI Consult** — ใช้ RAG / fine-tune / agent อะไร เหมาะกับ case ไหน
```
คำตอบ:
```
### B8 — ถ้าทำได้อย่างเดียว ควรเริ่มจากอะไร
ลูกค้ามีงบจำกัด ทำได้อย่างเดียว — อันไหนคุ้มสุด? (ตอบตรง ๆ ตามจริง ไม่ใช่คำตอบที่ขายดีที่สุด — ความจริงใจตรงนี้จะกลายเป็นเครื่องมือปิดการขาย)
```
คำตอบ:
```
### B9 — คิดค่าบริการยังไง
เหมาจ่าย / รายเดือน / เก็บตาม sprint / value-based? ช่วงราคาคร่าว ๆ ของแต่ละบริการ:
- **Web Development** — โปรเจกต์ทั่วไปอยู่ที่ ____ บาท
```
คำตอบ:
```
- **Marketing** — ค่า setup + รายเดือน
```
คำตอบ:
```
- **Automation** — ค่าพัฒนา + ค่าดูแล
```
คำตอบ:
```
- **AI Consult** — ค่า consult / ชั่วโมง / โปรเจกต์
```
คำตอบ:
```
### B10 — คำถาม 5 ข้อที่ถามลูกค้าในการคุยครั้งแรก
ตอนคุยกันครั้งแรก คุณถามอะไรบ้าง? (จะเอาไปใส่หน้า Contact เป็น "ก่อนคุย เตรียมคำตอบพวกนี้มา" — คนที่อ่านแล้วตอบได้ = lead ที่มีคุณภาพ)
```
คำตอบ:
```
---
## 🟡 กลุ่ม C — ความน่าเชื่อถือ (ตอบก่อนเขียน About / Portfolio)
ทำให้ soloprenuer กลายเป็นข้อได้เปรียบ ไม่ใช่จุดอ่อน
### C11 — เบื้องหลังการทำงานจริง
นั่งทำที่ไหน ใช้เครื่องอะไร stack/workflow แบบไหน — เล่าแบบที่คนอ่านแล้วเห็นภาพ "คนคนนี้จริงจัง"
```
คำตอบ:
```
### C12 — คำพูดลูกค้าที่จำไม่ลืม
เคยมีลูกค้าพูดอะไรที่ทำให้คุณจำได้? (quote แบบนี้แพ้ portfolio 10 หน้า — ถ้ามีหลาย quote บอกมาหลาย ๆ อันได้)
```
คำตอบ:
```
### C13 — กำลังเรียนรู้ / ทดลองอะไรอยู่
เช่น RAG, GEO, AI agent workflow, automation platform ใหม่ ๆ — ทำให้เห็นว่าคุณยังเดินหน้า ไม่หยุดนิ่ง
```
คำตอบ:
```
### C14 — ตัวเลขจริง ๆ ตอนนี้
ไม่ต้องสวย แค่ให้ calibrate เสียงและระดับความกล้าในการ claim:
- ทำมากี่ปี
- ส่งมอบกี่โปรเจกต์
- ลูกค้าซ้ำกี่คน
- ราคาเฉลี่ยต่อโปรเจกต์
- (ไม่ต้องเอาลงเว็บ แค่บอกผม)
```
คำตอบ:
```
---
## 🟢 กลุ่ม D — มุมมอง & เสียง (ตอบก่อนเขียนทุกหน้า)
เสียงที่จดจำได้ = มุมมองที่ชัด ไม่ใช่ถ้อยคำที่สวย
### D15 — เรื่องที่ไม่เห็นด้วยในวงการ
AI/Web agency ทำอะไรที่คุณคิดว่าผิด / เกินจำเป็น / หลอกลูกค้า? (ความเห็นต่าง = เสียงที่จดจำได้ เช่น "เราไม่เชื่อว่า SME ต้องมี chatbot ทุกเว็บ")
```
คำตอบ:
```
### D16 — 1 ประโยคที่อยากให้คนจำ
ถ้าเขียนเว็บได้แค่ 1 ประโยค อยากให้คนจำว่ามอร์มินิมอร์เป็นแบบไหน — ประโยคนั้นคืออะไร?
```
คำตอบ:
```
### D17 — โทนเสียงที่อยากให้เว็บเป็น
เลือก 1-2 ข้อ (หรือผสม):
- [ ] ตรง ๆ ดุ ๆ (เหมือนคุยกับเพื่อน)
- [ ] สุภาพ มืออาชีพ (เหมือนที่ปรึกษา)
- [ ] ขำ ๆ มีอารมณ์ขัน
- [ ] เน้นข้อมูล ไม่มีน้ำ
- [ ] เล่าเรื่อง เป็นกันเอง
- [ ] อื่น ๆ (บอกมา)
```
คำตอบ:
```
### D18 — เว็บที่ชอบ / vibe ที่อยากได้
เว็บคู่แข่ง หรือเว็บต่างประเทศที่ชอบ vibe คล้าย ๆ — ส่งลิงก์มากี่อันก็ได้ พร้อมเหตุผลสั้น ๆ ว่าชอบอะไร
```
คำตอบ:
```
---
## หลังได้คำตอบแล้ว จะทำอะไรต่อ
1. สรุป "เสียงของแบรนด์" ใน 1 หน้า (ไม่เกิน 10 ข้อ)
2. เขียน portfolio แต่ละชิ้นใหม่ — format: `[ชื่อ]. [อุตสาหกรรม]. [ปัญหา]. [สิ่งที่ทำ]. [ตัวเลข]. [เวลา]`
3. เขียน Home page copy ใหม่ — ลด 12 problem cards เหลือ 3-4 ที่เจ็บที่สุด พร้อมเฉลย
4. เขียน Service pages ใหม่ แยกตามเสียงและกระบวนการจริง
5. เขียน About page ใหม่ ให้ soloprenuer กลายเป็นข้อได้เปรียบ
6. เขียน FAQ จากคำถามที่ลูกค้าถามบ่อยจริง ๆ
7. วางแผน Blog topics 5 เรื่อง จากคำตอบ A6 + D15

Binary file not shown.

19
redesign-input/README.md Normal file
View File

@@ -0,0 +1,19 @@
# MoreminiMore Redesign Input
ชุดนี้คือข้อมูลที่ extract ออกจากเว็บเดิมก่อนรื้อใหม่ ใช้เป็นฐานสำหรับวางแผน redesign รอบถัดไป
## Files
- `WEBSITE-CONTENT-EXTRACT.md` - สรุปเนื้อหาเว็บที่ควรพกต่อไป
- `assets/logos/` - logo files ที่ใช้ได้ต่อ
- `assets/portfolio/` - ภาพผลงาน portfolio
- `raw/src-content/` - content collection เดิมแบบ raw
- `raw/src-data/` - data files เดิมแบบ raw
- `raw/BRAND-VOICE.md` - brand voice เดิม
- `raw/moreminimore-content.md` - planning/content draft เดิม
## Important Note
โค้ด implementation เก่า, build output, mockup, และไฟล์ทดลอง ถูกย้ายไปไว้ที่:
`_archive/pre-redesign-2026-06-21/`

View File

@@ -0,0 +1,177 @@
# MoreminiMore Website Content Extract
Extract date: 2026-06-21
เอกสารนี้ดึงเฉพาะเนื้อหาและ asset สำคัญจากเว็บเดิม เพื่อใช้วางแผนใหม่ ไม่ถือว่าเป็น design direction ใหม่
## Brand
- Brand name: MoreminiMore
- Business: ที่ปรึกษาด้านเว็บไซต์ การตลาดออนไลน์ AI และระบบอัตโนมัติสำหรับ SME ไทย
- Core promise: เพิ่มยอดขาย ลดต้นทุน ประหยัดเวลา
- Positioning: เริ่มจากดูข้อมูลจริงก่อน แล้วค่อยเลือกสิ่งที่ควรทำ
- Memorable line from brand voice: เป้าหมายของเราคือการเพิ่มกำไรให้ลูกค้า
- Tone: ตรง สุภาพ เน้นข้อมูล ไม่ขายฝัน ไม่ทำให้เทคโนโลยีดูยากเกินจำเป็น
- Primary CTA: ปรึกษาฟรี 30 นาที
- Secondary CTA: ดูผลงานจริง
## Contact
- 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
## Navigation Candidates
- หน้าแรก
- บริการ
- ผลงาน
- บทความ
- FAQ
- เกี่ยวกับ
- ติดต่อ
## Homepage Content To Preserve
### Hero
- Headline option currently used: เพิ่มยอดขาย ลดต้นทุน ประหยัดเวลา
- Supporting copy: ที่ปรึกษาด้านเว็บไซต์ การตลาดออนไลน์ AI และระบบอัตโนมัติสำหรับ SME ไทย เริ่มจากดูข้อมูลจริงก่อน แล้วค่อยเลือกสิ่งที่ควรทำ
### Data First Section
- Heading: เราใช้ข้อมูลจริง เพื่อวางแผนให้คุ้มกว่าเดิม
- Copy: ก่อนเสนอเว็บไซต์ แคมเปญ หรือระบบอัตโนมัติ เราดูข้อมูลจริงก่อนเสมอ ทั้งเว็บเดิม ช่องทางการตลาด พฤติกรรมลูกค้า ผู้สนใจที่ติดต่อเข้ามา และขั้นตอนทำงานของทีม
- Metrics:
- +373% impression จากเคส Dataroot
- +114.2% click หลังปรับกลุ่มเป้าหมาย
- -28.3% ad spend จากข้อมูลที่ยืนยันแล้ว
### Process
- ดูข้อมูล: เข้าใจตัวเลข เว็บไซต์ ช่องทางขาย และขั้นตอนทำงานเดิม
- เลือกทางที่คุ้ม: เลือกสิ่งที่ควรทำก่อนจากโจทย์จริง
- ลงมือทำ: สร้างเว็บ แคมเปญ ระบบอัตโนมัติ หรือวิธีใช้ AI ที่ใช้งานได้จริง
- วัดผลและปรับต่อ: ดูผลหลังใช้งาน แล้วปรับให้คุ้มขึ้น
### Final CTA
- Heading: ไม่แน่ใจว่าควรเริ่มตรงไหน คุยกับเราก่อน
- Copy: เล่าโจทย์ของธุรกิจคุณให้เราฟัง เราจะช่วยดูว่าควรเริ่มจากเว็บไซต์ การตลาด ระบบอัตโนมัติ หรือ AI
## Services
### Website Development
- Short: สร้างเว็บไซต์ที่โหลดไว แก้ไขง่าย วัดผลได้ และเป็นฐานหลักของการขายออนไลน์
- Hero title: เว็บไซต์ที่แก้เองได้ โหลดไว และพร้อมวัดผล
- Hero subtitle: สร้างเว็บไซต์ธุรกิจที่เป็นฐานหลักของการขายออนไลน์ พร้อม SEO โครงสร้างหน้า และช่องทางรับลูกค้าใหม่
- Problems:
- เว็บเดิมโหลดช้า
- แก้ไขเนื้อหาเองไม่ได้
- ไม่มีระบบวัดผล
- SEO และโครงสร้างหน้ายังไม่พร้อม
- ลูกค้าเข้าเว็บแล้วไม่รู้ว่าต้องทำอะไรต่อ
### Marketing Consult
- Short: ดูข้อมูลการตลาดเดิม แล้วปรับกลุ่มเป้าหมาย ช่องทาง และข้อความขายให้ใช้งบคุ้มขึ้น
- Hero title: การตลาดที่เริ่มจากข้อมูล ไม่ใช่ความรู้สึก
- Hero subtitle: เราช่วยดูข้อมูลการตลาดเดิม วิเคราะห์ช่องทาง กลุ่มเป้าหมาย และข้อความขาย เพื่อเลือกสิ่งที่ควรปรับให้ใช้งบคุ้มขึ้น
- Problems:
- ยิงแอดแล้วไม่คุ้ม
- ยอดขายไม่เพิ่มแม้ใช้งบมากขึ้น
- มีคนทักเข้ามา แต่ไม่ใช่ลูกค้าที่มีคุณภาพ
- ไม่รู้ว่าควรทำช่องทางไหนต่อ
- คอนเทนต์ไม่เชื่อมกับการขาย
### Automation Workflow
- Short: วางระบบทำงานอัตโนมัติสำหรับงานที่มีขั้นตอนแน่นอน ช่วยให้ทีมไม่ต้องเสียเวลากับงานซ้ำ
- Hero title: ลดงานซ้ำ ด้วยระบบการทำงานอัตโนมัติ
- Hero subtitle: เราช่วยวางระบบอัตโนมัติด้วยการเขียนแอปหรือเชื่อมต่อเครื่องมือที่มีอยู่ เพื่อให้งานที่มีขั้นตอนชัดเจนทำงานได้เร็วขึ้น และลดเวลาที่พนักงานต้องทำซ้ำ
- Problems:
- พนักงานต้อง copy/paste ข้อมูลซ้ำ
- งานมีขั้นตอนชัดเจน แต่ยังต้องทำมือ
- ข้อมูลกระจายหลายที่
- ผู้สนใจหรืองานเอกสารหลุดระหว่างทาง
- ผู้จัดการต้องตามงานเดิมซ้ำ ๆ
### AI Consult
- Short: ออกแบบวิธีใช้ AI ให้ทำงานร่วมกับพนักงาน และช่วยเก็บความรู้สำคัญไว้ในองค์กร
- Hero title: ให้ AI ทำงานร่วมกับพนักงาน และเก็บความรู้ไว้กับองค์กร
- Hero subtitle: เราช่วยออกแบบวิธีใช้ AI ให้เข้ากับงานจริงของทีม และค่อย ๆ เก็บความรู้จากพนักงาน เพื่อให้ความรู้สำคัญยังอยู่กับองค์กรแม้มีการเปลี่ยนคน
- Problems:
- ความรู้สำคัญอยู่กับพนักงานบางคน
- พนักงานใหม่ต้องใช้เวลานานในการเรียนรู้งาน
- คำถามซ้ำ ๆ ไม่มีแหล่งคำตอบกลาง
- เอกสารกระจัดกระจาย
- ใช้ AI แบบทดลอง แต่ยังไม่เชื่อมกับงานจริง
## Portfolio
| Name | URL | Category | Image |
| --- | --- | --- | --- |
| Dataroot | https://erp.dataroot.asia | ที่ปรึกษาการตลาด | `assets/portfolio/dataroot.png` |
| ทวนทอง 99 | https://tuanthong99.com | อีคอมเมิร์ซ | `assets/portfolio/tuanthong.png` |
| Underdog Marketing | https://underdog.run | Website Development | `assets/portfolio/underdog.png` |
| เทรนเนอร์ซันนี่ | https://trainersunny.com | Website Development | `assets/portfolio/trainersunny.png` |
| Lungfinler | https://lungfinler.com | Website Development | `assets/portfolio/lungfinler.png` |
| Jet Industries | https://jetindustries.co.th | Website Development | `assets/portfolio/jetindustries.png` |
| สำนักงานกฎหมาย ตถาตา | https://lawyernoom.com | Website Development | `assets/portfolio/lawyernoom.png` |
| Baofuling Shop | https://baofulingshop.com | อีคอมเมิร์ซ | `assets/portfolio/baofuling.png` |
| เลือดจระเข้วานิไทย | https://เลือดจระเข้วานิไทย.com | อีคอมเมิร์ซ | `assets/portfolio/luadjob.png` |
## Blog Content
Raw blog posts are preserved in `raw/src-content/blog/`.
- 5 วิธีใช้ AI เพิ่มยอดขายให้ธุรกิจของคุณ
- วิธีสร้าง Content ด้วย AI ที่ Google รัก
- AI สำหรับ SME ไทย: คู่มือฉบับสมบูรณ์
- Digital Transformation Guide
- Marketing Automation Guide
## FAQ Content
Raw FAQ entries are preserved in `raw/src-content/faq/`.
Categories found:
- บริการ
- ราคา
- เวลา
- AI
- Support
## Assets
### Logos
- `assets/logos/logo-long-black.png`
- `assets/logos/logo-long.png`
- `assets/logos/logo.svg`
### Portfolio Images
- `assets/portfolio/baofuling.png`
- `assets/portfolio/dataroot.png`
- `assets/portfolio/jetindustries.png`
- `assets/portfolio/lawyernoom.png`
- `assets/portfolio/luadjob.png`
- `assets/portfolio/lungfinler.png`
- `assets/portfolio/trainersunny.png`
- `assets/portfolio/tuanthong.png`
- `assets/portfolio/underdog.png`
## Raw Sources Preserved
- `raw/src-content/`
- `raw/src-data/`
- `raw/BRAND-VOICE.md`
- `raw/moreminimore-content.md`

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 40" fill="none">
<rect width="40" height="40" rx="8" fill="#fed400"/>
<text x="8" y="28" font-family="Kanit, sans-serif" font-weight="800" font-size="20" fill="#000">M</text>
<text x="52" y="26" font-family="Kanit, sans-serif" font-weight="600" font-size="18" fill="#000">M</text>
<text x="72" y="26" font-family="Noto Sans Thai, sans-serif" font-weight="500" font-size="14" fill="#000">oreMiniMore</text>
</svg>

After

Width:  |  Height:  |  Size: 477 B

View File

@@ -0,0 +1,15 @@
# Dealplustech Portfolio Asset
Dealplustech is included in the rebuilt website portfolio.
- URL: https://www.dealplustech.co.th
- Homepage screenshot captured: `dealplustech.png`
- Screenshot status: clean homepage capture with header/menu visible and cookie banner removed.
- Target style: same portfolio-image treatment as existing clients
- Output filename: `dealplustech.png`
Notes:
- Dealplustech is a new client.
- It should appear as website portfolio work.
- It can also support consulting-adjacent credibility, but should not replace Dataroot main diagnosis story.

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 768 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 849 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 KiB

View File

@@ -0,0 +1,103 @@
# MoreminiMore — เนื้อหาเว็บไซต์
## ข้อมูลบริษัท
- **ชื่อ**: MoreminiMore
- **ประเภทธุรกิจ**: ที่ปรึกษา AI + การตลาดออนไลน์ สำหรับ SME ไทย
- **จุดเด่น**: เริ่มจากดูสถิติจริง ไม่ใช่เดาว่าควรทำอะไร
- **สัญลักษณ์**: more**mini**more (mini = สีแดง #d4553a)
---
## Hero Section
- **Headline**: พาธุรกิจคุณ **บินสูง** ด้วยข้อมูล
- **Subheadline**: ที่ปรึกษา AI + การตลาดออนไลน์ สำหรับ SME ไทย — เริ่มจากดูสถิติของคุณก่อน
- **CTA 1**: ปรึกษาฟรี 30 นาที →
- **CTA 2**: ดูผลงานจริง
- **Trust badges**: ✓ ปรึกษาฟรี 30 นาที · ✓ ไม่มีผูกมัด · ✓ เห็นผลภายใน 30 วัน
---
## Section 1: ผลลัพธ์จริง
**หัวข้อ**: เราช่วย SME ไทย บินสูงขึ้น
**คำอธิบาย**: ไม่ใช่แค่ทำเว็บ — แต่ช่วยให้ธุรกิจเติบโตจริง ด้วยข้อมูลจริง
| ตัวเลข | หัวข้อ | รายละเอียด |
|--------|--------|-----------|
| +373% | เพิ่มยอดขาย | Dataroot +373% impression ใน 1 เดือน |
| 28% | ลดต้นทุน | ลดงบโฆษณา 28% โดยยอดขายไม่ลด |
| 5 ชม. | ประหยัดเวลา | AI + Automation ทำงานแทน 5 ชม./วัน |
---
## Section 2: Case Study / Dataroot
**หัวข้อ**: จากยิงโฆษณาแบบกว้าง สู่ผลลัพธ์ที่แม่นยำ
**Quote**: "เราไม่ได้ยิงโฆษณาเก่ง เราแค่ดูสถิติ"
### ขั้นตอน:
1. **วิเคราะห์ข้อมูล 3 เดือนย้อนหลัง** — ดูสถิติจริง ไม่ใช่เดา
2. **แยกกลุ่มเป้าหมาย: 4 segments** — ยิงให้แม่น ไม่ใช่ยิงให้กว้าง
3. **ได้ผลลัพธ์ +373% impression** — วัดผลได้จริง
### ตัวเลข:
- +373% IMPRESSION
- +114% CLICK
- 28% AD_SPEND
**CTA**: อ่านเคสเต็ม →
---
## Section 3: บริการ
**หัวข้อ**: เราทำอะไรได้บ้าง
| ไอคอน | บริการ | คำอธิบาย |
|--------|--------|----------|
| 🌐 | รับทำเว็บไซต์ | เว็บที่ Google รัก + โหลดเร็ว ไม่ใช่แค่สวย |
| 🤖 | ที่ปรึกษา AI | AI ที่ใช้ได้จริงกับธุรกิจ ไม่ใช่แค่ buzzword |
| 📈 | การตลาดออนไลน์ | SEO + Ads + Content ที่วัดผลได้ |
| ⚡ | Automation | ทำงานแทน 5 ชม./วัน ด้วย AI |
---
## Section 4: ขั้นตอนทำงาน
**หัวข้อ**: เราทำงานยังไง
| ขั้น | หัวข้อ | รายละเอียด |
|------|--------|-----------|
| 01 | ดูสถิติ | วิเคราะห์ข้อมูลปัจจุบัน — ไม่ใช่เดา |
| 02 | วางแผน | กลยุทธ์ที่เหมาะกับธุรกิจคุณ |
| 03 | ลงมือทำ | ทีมเราทำงานเอง — ไม่ outsource |
| 04 | วัดผล | รายงานผลลัพธ์จริง — ไม่ใช่ vanity metrics |
---
## Section 5: บล็อก
**หัวข้อ**: บทความล่าสุด
| ไอคอน | หัวข้อ | คำอธิบาย |
|--------|--------|----------|
| 📊 | 5 วิธีใช้ AI เพิ่มยอดขาย | เริ่มได้เลยวันนี้ |
| 🎯 | Content แบบไหน Google รัก | อัปเดต SEO 2026 |
| 🔧 | Automation 101 | เริ่มยังไงให้ได้ผล |
---
## Section 6: Contact
**หัวข้อ**: พร้อมที่จะบินสูงขึ้นหรือยัง?
**คำอธิบาย**: ปรึกษาฟรี 30 นาที — ไม่มีผูกมัด
**CTA 1**: ปรึกษาฟรี →
**CTA 2**: ดูผลงานจริง
---
## Navigation
- เกี่ยวกับ
- บริการ
- ผลงาน
- ปรึกษาฟรี → (CTA button)
---
## ภาษา
- **ภาษาไทย** ทั้งหมด
- **Font**: Kanit (หัวข้อ), Itim (เนื้อหา), JetBrains Mono (labels/eyebrow)

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