Compare commits
51 Commits
3f1c0061c7
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f114a34a62 | ||
|
|
689a8924e6 | ||
|
|
2a3062357f | ||
|
|
1d893e1bcb | ||
|
|
61c2bd6924 | ||
|
|
fdb03f6117 | ||
|
|
0f244424c0 | ||
|
|
f827afb33f | ||
|
|
e279119f97 | ||
|
|
ceffb2a3f3 | ||
|
|
73d820412a | ||
|
|
40382bbf55 | ||
|
|
8b04c739e1 | ||
|
|
caab40d9a4 | ||
|
|
96caca4af6 | ||
|
|
5393cf611c | ||
|
|
b8ac07996e | ||
|
|
caa412dbe2 | ||
|
|
8c2bf3d303 | ||
|
|
154e3f2d91 | ||
|
|
b586464b5c | ||
|
|
1f859921cb | ||
|
|
582998a340 | ||
|
|
9eea9cbe6d | ||
|
|
ed03060ff7 | ||
|
|
45f548421d | ||
|
|
b54657f58a | ||
|
|
c334b8b650 | ||
|
|
dcd1d73f56 | ||
|
|
84e245a7bb | ||
|
|
5f05489316 | ||
|
|
d3421f4003 | ||
|
|
58c27d3bb3 | ||
|
|
f86c9b24c4 | ||
|
|
5ab00efd15 | ||
|
|
a7a0135727 | ||
|
|
9fca75044d | ||
|
|
57eaa9da8b | ||
|
|
746d51569b | ||
|
|
a1b1b16288 | ||
|
|
0ff6ae9020 | ||
|
|
f47949c4b3 | ||
|
|
c92d446ff7 | ||
|
|
bd1c979f1a | ||
|
|
9e7d27c03c | ||
|
|
b49931a87a | ||
|
|
525dc358a3 | ||
|
|
43f609a794 | ||
|
|
b5be45bcd6 | ||
|
|
789473271e | ||
|
|
ca7f99ed41 |
4
.gitignore
vendored
@@ -22,3 +22,7 @@ pnpm-debug.log*
|
||||
|
||||
# jetbrains setting folder
|
||||
.idea/
|
||||
.hermes/
|
||||
|
||||
# archive (large local files)
|
||||
_archive/
|
||||
|
||||
22
PLAN-REVIEW-LOG.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Plan Review Log: Footer Component + Remove Yellow Lines from Process Section
|
||||
Act 1 (grill) complete — plan locked with the user. MAX_ROUNDS=5.
|
||||
|
||||
## Round 1 — Codex
|
||||
พบ 10 issues (3 critical, 3 significant, 4 minor):
|
||||
1. 🔴 PageShell layout ignored — ควรแก้ผ่าน PageShell
|
||||
2. 🔴 Privacy/Terms pages ไม่มี — dead links
|
||||
3. 🔴 Liquid glass markup pattern ไม่ระบุ
|
||||
4. 🟡 service-proof-grid yellow accent missed
|
||||
5. 🟡 Mobile layout spec ambiguous
|
||||
6. 🟡 Step-flow visual cue removed without alternative
|
||||
7. 🟡 Missing semantic `<footer>` element
|
||||
8. 🟠 LINE URL unspecified
|
||||
9. 🟠 Logo dimensions omitted
|
||||
10. 🟠 z-index risk unresolved
|
||||
|
||||
### Claude's response
|
||||
แก้ทั้ง 10 ข้อใน PLAN.md revision
|
||||
|
||||
## Round 2 — Codex
|
||||
All 10 findings addressed. Minor note: footer ควรวางระหว่าง `</main>` กับ floating-cta (ไม่ใช่ inside `<main>`).
|
||||
VERDICT: APPROVED (2 rounds)
|
||||
71
PLAN.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Plan: Footer Component + Remove Yellow Lines from Process Section
|
||||
_Locked via grill — by Claude + Kunthawat — Revised Round 1_
|
||||
|
||||
## Goal
|
||||
สร้าง Footer component ใหม่ด้วย liquid glass style และลบเส้นสีเหลืองออกจาก How we work section
|
||||
|
||||
## Approach
|
||||
### 1. ลบเส้นสีเหลืองจาก Process Section (`src/styles/global.css`)
|
||||
- ลบ `.process-grid::before` (เส้นแนวนอนสีเหลือง) → `display: none`
|
||||
- ลบ `.process-grid article::after` (วงกลม ">" สีเหลืองระหว่าง step) → `display: none`
|
||||
- `.process-grid .step-number`: เปลี่ยน `background: var(--yellow)` → `background: rgb(255 255 255 / .5)` + ลบ yellow box-shadow
|
||||
- `.service-proof-grid .process-grid .step-number`: override สีเหลืองเหมือนกัน (scope เพิ่ม)
|
||||
- **หมายเหตุ:** step numbers (01, 02, 03, 04) ยังคงแสดง sequential flow อยู่แล้ว ไม่ต้องเพิ่ม connector แทน
|
||||
|
||||
### 2. สร้าง Footer Component (`src/components/Footer.astro`)
|
||||
- ใช้ `<footer>` semantic element
|
||||
- ใช้ liquid glass style (ต้องมี 3 child divs):
|
||||
```html
|
||||
<footer class="site-footer liquid-glass liquidGlass-wrapper">
|
||||
<div class="liquidGlass-effect" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-tint" aria-hidden="true"></div>
|
||||
<div class="liquidGlass-shine" aria-hidden="true"></div>
|
||||
<!-- content -->
|
||||
</footer>
|
||||
```
|
||||
- `position: relative; z-index: auto` (ไม่ทับ lead-panel z-index: 110)
|
||||
|
||||
### 3. เนื้อหา Footer
|
||||
**ซ้าย:**
|
||||
- โลโก้: `/images/logos/logo-long-black.png` (width="205" height="36")
|
||||
- คำอธิบาย: "ที่ปรึกษาเว็บไซต์ การตลาด และ AI สำหรับ SME"
|
||||
|
||||
**กลาง:**
|
||||
- ลิงก์: หน้าแรก / บริการ / ผลงาน / บล็อก / ติดต่อ / นโยบายความเป็นส่วนตัว / เงื่อนไขการใช้งาน
|
||||
|
||||
**ขวา:**
|
||||
- LINE: @moreminimore (link: https://line.me/ti/p/@moreminimore)
|
||||
- Email: contact@moreminimore.com
|
||||
|
||||
**ล่าง:**
|
||||
- Copyright: © {new Date().getFullYear()} MoreminiMore
|
||||
|
||||
### 4. Responsive
|
||||
- Desktop (>768px): 3 columns (grid-template-columns: 1fr 1fr 1fr)
|
||||
- Mobile (≤768px): vertical stack (flex-direction: column) — เรียง: โลโก้ → ลิงก์ → ติดต่อ → copyright
|
||||
|
||||
### 5. Integration Strategy
|
||||
- **PageShell pages** (about, services, blog, blog/[slug], contact, faq, portfolio, services/[slug]):
|
||||
เพิ่ม `<Footer />` import + render ใน `src/components/PageShell.astro` ก่อน `</main>` หรือก่อน `</body>`
|
||||
- **index.astro** (standalone, ไม่ใช้ PageShell):
|
||||
เพิ่ม `<Footer />` import + render ก่อน `</body>` โดยตรง
|
||||
|
||||
### 6. สร้าง Placeholder Pages
|
||||
- สร้าง `src/pages/privacy.astro` (placeholder — "นโยบายความเป็นส่วนตัว กำลังอัพเดท")
|
||||
- สร้าง `src/pages/terms.astro` (placeholder — "เงื่อนไขการใช้งาน กำลังอัพเดท")
|
||||
- ใช้ PageShell layout เหมือนหน้าอื่น
|
||||
|
||||
## Key decisions & tradeoffs
|
||||
- ใช้ liquid glass style เดียวกับ navbar เพื่อความ cohesive
|
||||
- ลบเส้นเหลืองทั้งหมด — step numbers ยังบ่งบอกลำดับอยู่
|
||||
- ใช้ dynamic year (`new Date().getFullYear()`) ใน copyright (Astro SSG → build-time inlined)
|
||||
- Footer ใน PageShell = แก้จุดเดียว ครอบคลุม 8 หน้า
|
||||
- z-index: auto (ไม่ทับ lead-panel)
|
||||
|
||||
## Risks / open questions
|
||||
- Privacy/Terms pages เป็น placeholder — ต้องเพิ่ม content ทีหลัง
|
||||
- Logo อาจต้องเปลี่ยนเป็นสีขาวเมื่ออยู่บนพื้นเข้ม (invert)
|
||||
|
||||
## Out of scope
|
||||
- ไม่แก้ไขหน้า Privacy/Terms content จริง
|
||||
- ไม่เพิ่ม social media icons (Facebook/X/LinkedIn)
|
||||
43
README.md
@@ -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).
|
||||
@@ -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
@@ -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`
|
||||
290
google-apps-script/lead-form.gs
Normal 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, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
function jsonResponse(data) {
|
||||
return ContentService
|
||||
.createTextOutput(JSON.stringify(data))
|
||||
.setMimeType(ContentService.MimeType.JSON);
|
||||
}
|
||||
6209
package-lock.json
generated
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
182
public/demos/a-orbital.html
Normal file
@@ -0,0 +1,182 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>A: Orbital — ระบบดาวเคราะห์</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #0a0f1a;
|
||||
color: #fff;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
min-height: 100vh; overflow: hidden;
|
||||
}
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
|
||||
.demo { position: relative; width: 650px; height: 580px; }
|
||||
|
||||
/* Canvas for orbital rings */
|
||||
canvas#orbitalCanvas {
|
||||
position: absolute; inset: 0; pointer-events: none; z-index: 1;
|
||||
}
|
||||
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d;
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute; border-radius: 50%;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center;
|
||||
text-align: center; backface-visibility: hidden;
|
||||
}
|
||||
|
||||
/* Center Sun */
|
||||
.sun {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 170px; height: 170px;
|
||||
background: radial-gradient(circle at 40% 35%, #fff7cc, #fed400 40%, #d4a000 100%);
|
||||
box-shadow: 0 0 60px rgba(254,212,0,0.6), 0 0 120px rgba(254,212,0,0.3), 0 0 200px rgba(254,180,0,0.15);
|
||||
z-index: 10; animation: sunPulse 3s ease-in-out infinite;
|
||||
}
|
||||
@keyframes sunPulse {
|
||||
0%, 100% { box-shadow: 0 0 60px rgba(254,212,0,0.6), 0 0 120px rgba(254,212,0,0.3), 0 0 200px rgba(254,180,0,0.15); }
|
||||
50% { box-shadow: 0 0 80px rgba(254,212,0,0.8), 0 0 150px rgba(254,212,0,0.4), 0 0 230px rgba(254,180,0,0.2); }
|
||||
}
|
||||
.sun .label { font-size: 2.8rem; font-weight: 900; color: #3a2e00; }
|
||||
.sun .sub { font-size: 0.75rem; color: #6b5500; margin-top: 4px; font-weight: 600; }
|
||||
|
||||
/* Orbiting planets */
|
||||
.planet {
|
||||
width: 110px; height: 110px;
|
||||
background: rgba(255,255,255,0.06);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1.5px solid rgba(255,255,255,0.2);
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.15);
|
||||
left: 50%; top: 50%;
|
||||
animation: orbit var(--orbit-dur) linear infinite;
|
||||
z-index: 5;
|
||||
}
|
||||
.planet:nth-child(2) { --orbit-dur: 12s; --radius: 230px; --angle: 0deg; --z: -40px; }
|
||||
.planet:nth-child(3) { --orbit-dur: 15s; --radius: 280px; --angle: 120deg; --z: -70px; }
|
||||
.planet:nth-child(4) { --orbit-dur: 18s; --radius: 330px; --angle: 240deg; --z: -100px; }
|
||||
|
||||
@keyframes orbit {
|
||||
0% { transform: translate(-50%, -50%) rotate(0deg) translateX(var(--radius)) rotate(0deg); }
|
||||
100% { transform: translate(-50%, -50%) rotate(360deg) translateX(var(--radius)) rotate(-360deg); }
|
||||
}
|
||||
|
||||
.planet .tag { font-size: 1rem; font-weight: 800; color: #fff; text-transform: uppercase; }
|
||||
.planet .desc { font-size: 0.7rem; color: rgba(255,255,255,0.6); margin-top: 4px; }
|
||||
|
||||
/* Connecting lines (drawn on canvas) */
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(255,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">A. Orbital — ระบบดาวเคราะห์โคจร</span>
|
||||
<div class="demo">
|
||||
<canvas id="orbitalCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node sun" data-node="center">
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node planet" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node planet" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุนและเวลา</span>
|
||||
</div>
|
||||
<div class="node planet" data-node="biz">
|
||||
<span class="tag">Business<br>Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('orbitalCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
function draw() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const sun = document.querySelector('[data-node="center"]');
|
||||
const planets = document.querySelectorAll('.planet');
|
||||
if (!sun) return;
|
||||
|
||||
const sunRect = sun.getBoundingClientRect();
|
||||
const sx = sunRect.left + sunRect.width/2 - rect.left;
|
||||
const sy = sunRect.top + sunRect.height/2 - rect.top;
|
||||
|
||||
// Draw orbital rings
|
||||
const sr = 85; // sun radius
|
||||
const radii = [230, 280, 330];
|
||||
radii.forEach((r, i) => {
|
||||
ctx.beginPath();
|
||||
ctx.ellipse(sx, sy, r, r * 0.45, 0, 0, Math.PI * 2);
|
||||
ctx.strokeStyle = `rgba(254,212,0,${0.15 - i * 0.03})`;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.setLineDash([8, 14]);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
});
|
||||
|
||||
// Draw connection lines
|
||||
planets.forEach(p => {
|
||||
const pRect = p.getBoundingClientRect();
|
||||
const px = pRect.left + pRect.width/2 - rect.left;
|
||||
const py = pRect.top + pRect.height/2 - rect.top;
|
||||
|
||||
const dx = px - sx, dy = py - sy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
const r = 85;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(sx + (dx/dist)*r, sy + (dy/dist)*r);
|
||||
ctx.lineTo(px - (dx/dist)*55, py - (dy/dist)*55);
|
||||
const grad = ctx.createLinearGradient(sx, sy, px, py);
|
||||
grad.addColorStop(0, 'rgba(254,212,0,0.7)');
|
||||
grad.addColorStop(1, 'rgba(254,212,0,0.15)');
|
||||
ctx.strokeStyle = grad;
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.stroke();
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
// Mouse parallax
|
||||
document.addEventListener('mousemove', e => {
|
||||
const x = (e.clientX / window.innerWidth - 0.5) * 8;
|
||||
const y = (e.clientY / window.innerHeight - 0.5) * -8;
|
||||
scene.style.transform = `rotateX(${y}deg) rotateY(${x}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
180
public/demos/b-energyflow.html
Normal file
@@ -0,0 +1,180 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>B: Energy Flow — กระแสพลังงาน</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #080d14;
|
||||
color: #fff; overflow: hidden;
|
||||
display: flex; align-items: center; justify-content: center; min-height: 100vh;
|
||||
}
|
||||
.demo { position: relative; width: 650px; height: 580px; }
|
||||
canvas#flowCanvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d;
|
||||
transition: transform 0.3s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; text-align: center;
|
||||
}
|
||||
|
||||
/* Core */
|
||||
.core {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 160px; height: 160px; border-radius: 50%;
|
||||
background: radial-gradient(circle at 35% 30%, #2a1a00, #100800);
|
||||
border: 2px solid rgba(254,212,0,0.8);
|
||||
box-shadow: 0 0 40px rgba(254,212,0,0.3), 0 0 80px rgba(254,180,0,0.1), inset 0 0 40px rgba(254,212,0,0.08);
|
||||
z-index: 10;
|
||||
animation: coreBeat 2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes coreBeat {
|
||||
0%, 100% { box-shadow: 0 0 40px rgba(254,212,0,0.3), 0 0 80px rgba(254,180,0,0.1), inset 0 0 40px rgba(254,212,0,0.08); }
|
||||
50% { box-shadow: 0 0 60px rgba(254,212,0,0.5), 0 0 100px rgba(254,180,0,0.2), inset 0 0 50px rgba(254,212,0,0.12); }
|
||||
}
|
||||
.core .label { font-size: 2.6rem; font-weight: 900; color: #fed400; }
|
||||
.core .sub { font-size: 0.7rem; color: rgba(254,212,0,0.5); margin-top: 4px; font-weight: 600; }
|
||||
|
||||
/* Satellites */
|
||||
.satellite {
|
||||
border-radius: 50%;
|
||||
background: rgba(255,255,255,0.04);
|
||||
backdrop-filter: blur(8px);
|
||||
border: 1px solid rgba(254,212,0,0.25);
|
||||
width: 120px; height: 120px;
|
||||
z-index: 5;
|
||||
left: 50%; top: 50%;
|
||||
}
|
||||
.satellite:nth-child(2) { transform: translate(-50%, -50%) translateY(-230px); animation: float1 4s ease-in-out infinite; }
|
||||
.satellite:nth-child(3) { transform: translate(-50%, -50%) translateX(220px) translateY(10px); animation: float2 4.5s ease-in-out infinite; }
|
||||
.satellite:nth-child(4) { transform: translate(-50%, -50%) translateX(-160px) translateY(190px); animation: float3 5s ease-in-out infinite; }
|
||||
@keyframes float1 { 0%,100%{ transform: translate(-50%,-50%) translateY(-230px); } 50%{ transform: translate(-50%,-50%) translateY(-245px); } }
|
||||
@keyframes float2 { 0%,100%{ transform: translate(-50%,-50%) translateX(220px) translateY(10px); } 50%{ transform: translate(-50%,-50%) translateX(235px) translateY(0px); } }
|
||||
@keyframes float3 { 0%,100%{ transform: translate(-50%,-50%) translateX(-160px) translateY(190px); } 50%{ transform: translate(-50%,-50%) translateX(-175px) translateY(205px); } }
|
||||
|
||||
.satellite .tag { font-size: 0.9rem; font-weight: 800; color: #fff; }
|
||||
.satellite .desc { font-size: 0.65rem; color: rgba(255,255,255,0.5); margin-top: 3px; }
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(255,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">B. Energy Flow — กระแสพลังงาน พร้อม particles</span>
|
||||
<div class="demo">
|
||||
<canvas id="flowCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node core" data-node="center">
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node satellite" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node satellite" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุนและเวลา</span>
|
||||
</div>
|
||||
<div class="node satellite" data-node="biz">
|
||||
<span class="tag">Business<br>Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('flowCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize();
|
||||
window.addEventListener('resize', resize);
|
||||
|
||||
// Particle system per connection
|
||||
const connections = [];
|
||||
let t = 0;
|
||||
|
||||
function draw() {
|
||||
t++;
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const sun = document.querySelector('[data-node="center"]');
|
||||
const sats = document.querySelectorAll('.satellite');
|
||||
if (!sun) { requestAnimationFrame(draw); return; }
|
||||
|
||||
const sr = sun.getBoundingClientRect();
|
||||
const sx = sr.left + sr.width/2 - rect.left;
|
||||
const sy = sr.top + sr.height/2 - rect.top;
|
||||
|
||||
sats.forEach((sat, i) => {
|
||||
const pr = sat.getBoundingClientRect();
|
||||
const px = pr.left + pr.width/2 - rect.left;
|
||||
const py = pr.top + pr.height/2 - rect.top;
|
||||
|
||||
const dx = px - sx, dy = py - sy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
// Draw stream line
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(sx + (dx/dist)*80, sy + (dy/dist)*80);
|
||||
ctx.lineTo(px - (dx/dist)*60, py - (dy/dist)*60);
|
||||
const grad = ctx.createLinearGradient(sx, sy, px, py);
|
||||
grad.addColorStop(0, 'rgba(254,212,0,0.6)');
|
||||
grad.addColorStop(0.5, 'rgba(254,212,0,0.3)');
|
||||
grad.addColorStop(1, 'rgba(254,212,0,0.1)');
|
||||
ctx.strokeStyle = grad;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Animated particles along the line
|
||||
const count = 12;
|
||||
for (let j = 0; j < count; j++) {
|
||||
const phase = (t * 0.03 + j / count + i * 0.33) % 1;
|
||||
const pp = phase < 0.5 ? phase * 2 : 2 - phase * 2;
|
||||
const x = sx + (dx/dist)*80 + dx * (1 - 80/dist - 60/dist) * phase;
|
||||
const y = sy + (dy/dist)*80 + dy * (1 - 80/dist - 60/dist) * phase;
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 2.5, 0, Math.PI*2);
|
||||
ctx.fillStyle = `rgba(254,230,100,${0.8 * pp})`;
|
||||
ctx.fill();
|
||||
// Glow
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 5, 0, Math.PI*2);
|
||||
ctx.fillStyle = `rgba(254,212,0,${0.25 * pp})`;
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', e => {
|
||||
const x = (e.clientX / window.innerWidth - 0.5) * 6;
|
||||
const y = (e.clientY / window.innerHeight - 0.5) * -6;
|
||||
scene.style.transform = `rotateX(${y}deg) rotateY(${x}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
179
public/demos/c-holographic.html
Normal file
@@ -0,0 +1,179 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>C: Holographic 3D — Hologram Sci-Fi</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #020810;
|
||||
color: #fff; overflow: hidden;
|
||||
display: flex; align-items: center; justify-content: center; min-height: 100vh;
|
||||
}
|
||||
|
||||
.demo { position: relative; width: 700px; height: 600px; }
|
||||
canvas#holoCanvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d; perspective: 1200px;
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; text-align: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Center hologram */
|
||||
.holo-core {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 170px; height: 170px;
|
||||
background: radial-gradient(circle at 40% 35%, rgba(0,255,255,0.15), rgba(0,200,255,0.05));
|
||||
border: 2px solid rgba(0,255,255,0.5);
|
||||
box-shadow: 0 0 50px rgba(0,255,255,0.2), 0 0 100px rgba(0,200,255,0.08), inset 0 0 30px rgba(0,255,255,0.05);
|
||||
z-index: 10;
|
||||
animation: holoPulse 2.5s ease-in-out infinite;
|
||||
}
|
||||
@keyframes holoPulse {
|
||||
0%, 100% { border-color: rgba(0,255,255,0.5); box-shadow: 0 0 50px rgba(0,255,255,0.2), 0 0 100px rgba(0,200,255,0.08); }
|
||||
50% { border-color: rgba(0,255,255,0.8); box-shadow: 0 0 70px rgba(0,255,255,0.35), 0 0 120px rgba(0,200,255,0.15); }
|
||||
}
|
||||
.holo-core .label { font-size: 2.8rem; font-weight: 900; color: #0ff; text-shadow: 0 0 20px rgba(0,255,255,0.5); }
|
||||
.holo-core .sub { font-size: 0.7rem; color: rgba(0,255,255,0.5); margin-top: 4px; font-weight: 600; }
|
||||
|
||||
/* Scanline effect */
|
||||
.holo-core::after {
|
||||
content: ''; position: absolute; inset: 0; border-radius: 50%;
|
||||
background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,255,255,0.03) 2px, rgba(0,255,255,0.03) 4px);
|
||||
pointer-events: none; z-index: 1;
|
||||
}
|
||||
|
||||
/* Satellites - holographic */
|
||||
.holo-sat {
|
||||
width: 115px; height: 115px;
|
||||
background: rgba(0,255,255,0.04);
|
||||
border: 1.5px solid rgba(0,255,255,0.35);
|
||||
box-shadow: 0 0 25px rgba(0,255,255,0.1), inset 0 0 20px rgba(0,255,255,0.04);
|
||||
z-index: 5;
|
||||
left: 50%; top: 50%;
|
||||
}
|
||||
.holo-sat::after {
|
||||
content: ''; position: absolute; inset: 0; border-radius: 50%;
|
||||
background: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,255,255,0.02) 2px, rgba(0,255,255,0.02) 4px);
|
||||
pointer-events: none;
|
||||
}
|
||||
.holo-sat:nth-child(2) { transform: translate(-50%,-50%) translate3d(-220px,-140px,-80px); animation: hfloat1 5s ease-in-out infinite; }
|
||||
.holo-sat:nth-child(3) { transform: translate(-50%,-50%) translate3d(180px,-20px,-30px); animation: hfloat2 6s ease-in-out infinite; }
|
||||
.holo-sat:nth-child(4) { transform: translate(-50%,-50%) translate3d(-100px,210px,-100px); animation: hfloat3 5.5s ease-in-out infinite; }
|
||||
@keyframes hfloat1 { 0%,100%{transform:translate(-50%,-50%) translate3d(-220px,-140px,-80px)} 50%{transform:translate(-50%,-50%) translate3d(-230px,-155px,-100px)} }
|
||||
@keyframes hfloat2 { 0%,100%{transform:translate(-50%,-50%) translate3d(180px,-20px,-30px)} 50%{transform:translate(-50%,-50%) translate3d(195px,-35px,-55px)} }
|
||||
@keyframes hfloat3 { 0%,100%{transform:translate(-50%,-50%) translate3d(-100px,210px,-100px)} 50%{transform:translate(-50%,-50%) translate3d(-115px,225px,-130px)} }
|
||||
|
||||
.holo-sat .tag { font-size: 0.9rem; font-weight: 800; color: #0ff; text-shadow: 0 0 10px rgba(0,255,255,0.4); }
|
||||
.holo-sat .desc { font-size: 0.65rem; color: rgba(0,255,255,0.5); margin-top: 3px; }
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(0,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">C. Holographic 3D — Hologram Sci-Fi</span>
|
||||
<div class="demo">
|
||||
<canvas id="holoCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node holo-core" data-node="center">
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node holo-sat" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node holo-sat" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุนและเวลา</span>
|
||||
</div>
|
||||
<div class="node holo-sat" data-node="biz">
|
||||
<span class="tag">Business<br>Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('holoCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize(); window.addEventListener('resize', resize);
|
||||
|
||||
let t = 0;
|
||||
function draw() {
|
||||
t++;
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const center = document.querySelector('[data-node="center"]');
|
||||
const sats = document.querySelectorAll('.holo-sat');
|
||||
if (!center) { requestAnimationFrame(draw); return; }
|
||||
|
||||
const cr = center.getBoundingClientRect();
|
||||
const cx = cr.left + cr.width/2 - rect.left;
|
||||
const cy = cr.top + cr.height/2 - rect.top;
|
||||
|
||||
sats.forEach((sat, i) => {
|
||||
const pr = sat.getBoundingClientRect();
|
||||
const px = pr.left + pr.width/2 - rect.left;
|
||||
const py = pr.top + pr.height/2 - rect.top;
|
||||
const dx = px - cx, dy = py - cy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
// Hologram beam line (dotted)
|
||||
ctx.beginPath();
|
||||
ctx.setLineDash([4, 8]);
|
||||
ctx.lineDashOffset = -t * 2;
|
||||
ctx.moveTo(cx + (dx/dist)*85, cy + (dy/dist)*85);
|
||||
ctx.lineTo(px - (dx/dist)*58, py - (dy/dist)*58);
|
||||
ctx.strokeStyle = 'rgba(0,255,255,0.3)';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
|
||||
// Glow nodes at intervals
|
||||
for (let j = 0; j < 5; j++) {
|
||||
const phase = ((t * 0.02 + j/5 + i*0.33) % 1);
|
||||
const x = cx + (dx/dist)*85 + dx * (1 - 85/dist - 58/dist) * phase;
|
||||
const y = cy + (dy/dist)*85 + dy * (1 - 85/dist - 58/dist) * phase;
|
||||
const alpha = Math.sin(phase * Math.PI);
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, 2, 0, Math.PI*2);
|
||||
ctx.fillStyle = `rgba(0,255,255,${0.6 * alpha})`;
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', e => {
|
||||
scene.style.transform = `rotateX(${(e.clientY/window.innerHeight-0.5)*-8}deg) rotateY(${(e.clientX/window.innerWidth-0.5)*8}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
208
public/demos/d-constellation.html
Normal file
@@ -0,0 +1,208 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>D: Constellation — แผนที่ดาว</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: radial-gradient(ellipse at center, #0d1520 0%, #040810 100%);
|
||||
color: #fff; overflow: hidden;
|
||||
display: flex; align-items: center; justify-content: center; min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Starfield background */
|
||||
.stars {
|
||||
position: fixed; inset: 0; z-index: 0; pointer-events: none;
|
||||
}
|
||||
|
||||
.demo { position: relative; width: 700px; height: 600px; z-index: 1; }
|
||||
canvas#constCanvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d;
|
||||
transition: transform 0.3s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; text-align: center;
|
||||
}
|
||||
|
||||
/* Polaris - main star */
|
||||
.star-main {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 150px; height: 150px; border-radius: 50%;
|
||||
background: radial-gradient(circle at 38% 35%, rgba(255,255,255,0.25), rgba(254,212,0,0.15) 50%, transparent 100%);
|
||||
z-index: 10;
|
||||
}
|
||||
.star-main .glow {
|
||||
position: absolute; inset: -30px; border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(254,212,0,0.08), transparent 70%);
|
||||
animation: starGlow 3s ease-in-out infinite;
|
||||
}
|
||||
@keyframes starGlow {
|
||||
0%, 100% { transform: scale(1); opacity: 0.5; }
|
||||
50% { transform: scale(1.15); opacity: 0.8; }
|
||||
}
|
||||
.star-main .label { font-size: 2.6rem; font-weight: 900; color: #fed400; text-shadow: 0 0 30px rgba(254,212,0,0.6); position: relative; z-index: 1; }
|
||||
.star-main .sub { font-size: 0.7rem; color: rgba(254,212,0,0.5); margin-top: 4px; font-weight: 600; position: relative; z-index: 1; }
|
||||
|
||||
/* Constellation stars */
|
||||
.c-star {
|
||||
width: 70px; height: 70px; border-radius: 50%;
|
||||
background: radial-gradient(circle at 40% 35%, rgba(255,255,255,0.15), transparent);
|
||||
z-index: 5;
|
||||
left: 50%; top: 50%;
|
||||
}
|
||||
/* Star twinkle */
|
||||
.c-star::before {
|
||||
content: ''; position: absolute; inset: -15px; border-radius: 50%;
|
||||
background: radial-gradient(circle, rgba(254,240,200,0.1), transparent 70%);
|
||||
animation: twinkle 4s ease-in-out infinite;
|
||||
}
|
||||
@keyframes twinkle {
|
||||
0%, 100% { opacity: 0.3; transform: scale(0.8); }
|
||||
50% { opacity: 0.7; transform: scale(1.15); }
|
||||
}
|
||||
|
||||
.c-star:nth-child(2)::before { animation-delay: 0s; }
|
||||
.c-star:nth-child(3)::before { animation-delay: 1.2s; }
|
||||
.c-star:nth-child(4)::before { animation-delay: 2.5s; }
|
||||
|
||||
/* Star points (4-point cross) */
|
||||
.c-star::after {
|
||||
content: ''; position: absolute; inset: -8px; border-radius: 50%;
|
||||
box-shadow:
|
||||
0 -25px 0 -8px rgba(254,240,200,0.3),
|
||||
0 25px 0 -8px rgba(254,240,200,0.3),
|
||||
-25px 0 0 -8px rgba(254,240,200,0.3),
|
||||
25px 0 0 -8px rgba(254,240,200,0.3);
|
||||
animation: starRotate 10s linear infinite;
|
||||
}
|
||||
@keyframes starRotate { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
|
||||
|
||||
.c-star:nth-child(2) { transform: translate(-50%,-50%) translate3d(-220px,-160px,-60px); }
|
||||
.c-star:nth-child(3) { transform: translate(-50%,-50%) translate3d(190px,-30px,-30px); }
|
||||
.c-star:nth-child(4) { transform: translate(-50%,-50%) translate3d(-120px,200px,-70px); }
|
||||
|
||||
.c-star .tag { font-size: 0.8rem; font-weight: 800; color: #fff; position: relative; z-index: 1; text-shadow: 0 0 15px rgba(255,255,255,0.4); }
|
||||
.c-star .desc { font-size: 0.6rem; color: rgba(255,255,255,0.5); margin-top: 2px; position: relative; z-index: 1; }
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(255,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">D. Constellation — แผนที่ดาว</span>
|
||||
|
||||
<!-- Starfield -->
|
||||
<svg class="stars" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<radialGradient id="s"><stop offset="0%" stop-color="#fff" stop-opacity="0.8"/><stop offset="100%" stop-color="#fff" stop-opacity="0"/></radialGradient>
|
||||
</defs>
|
||||
<circle cx="8%" cy="12%" r="1.5" fill="#fff" opacity="0.6"/><circle cx="15%" cy="8%" r="1" fill="#fff" opacity="0.3"/>
|
||||
<circle cx="22%" cy="18%" r="0.8" fill="#fff" opacity="0.5"/><circle cx="78%" cy="10%" r="1.2" fill="#fff" opacity="0.4"/>
|
||||
<circle cx="85%" cy="22%" r="1" fill="#fff" opacity="0.3"/><circle cx="92%" cy="8%" r="0.6" fill="#fff" opacity="0.7"/>
|
||||
<circle cx="6%" cy="85%" r="1" fill="#fff" opacity="0.4"/><circle cx="14%" cy="92%" r="0.8" fill="#fff" opacity="0.5"/>
|
||||
<circle cx="88%" cy="88%" r="1.3" fill="#fff" opacity="0.35"/><circle cx="95%" cy="78%" r="0.7" fill="#fff" opacity="0.6"/>
|
||||
<circle cx="42%" cy="5%" r="0.9" fill="#fff" opacity="0.45"/><circle cx="55%" cy="3%" r="0.5" fill="#fff" opacity="0.55"/>
|
||||
<circle cx="65%" cy="92%" r="1.1" fill="#fff" opacity="0.3"/><circle cx="35%" cy="95%" r="0.7" fill="#fff" opacity="0.5"/>
|
||||
</svg>
|
||||
|
||||
<div class="demo">
|
||||
<canvas id="constCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node star-main" data-node="center">
|
||||
<div class="glow"></div>
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node c-star" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node c-star" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุน</span>
|
||||
</div>
|
||||
<div class="node c-star" data-node="biz">
|
||||
<span class="tag">Business Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('constCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize(); window.addEventListener('resize', resize);
|
||||
|
||||
function draw() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const center = document.querySelector('[data-node="center"]');
|
||||
const stars = document.querySelectorAll('.c-star');
|
||||
if (!center) { requestAnimationFrame(draw); return; }
|
||||
|
||||
const cr = center.getBoundingClientRect();
|
||||
const cx = cr.left + cr.width/2 - rect.left;
|
||||
const cy = cr.top + cr.height/2 - rect.top;
|
||||
|
||||
// Draw constellation lines (thin, elegant)
|
||||
stars.forEach((star, i) => {
|
||||
const pr = star.getBoundingClientRect();
|
||||
const px = pr.left + pr.width/2 - rect.left;
|
||||
const py = pr.top + pr.height/2 - rect.top;
|
||||
const dx = px - cx, dy = py - cy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
// Constellation line
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(cx + (dx/dist)*75, cy + (dy/dist)*75);
|
||||
ctx.lineTo(px - (dx/dist)*35, py - (dy/dist)*35);
|
||||
ctx.strokeStyle = 'rgba(254,240,200,0.25)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.setLineDash([2, 6]);
|
||||
ctx.stroke();
|
||||
ctx.setLineDash([]);
|
||||
|
||||
// Tiny connecting stars along line
|
||||
for (let j = 0; j < 3; j++) {
|
||||
const p = 0.25 + j * 0.25;
|
||||
const sx = cx + (dx/dist)*75 + dx * (1 - 75/dist - 35/dist) * p;
|
||||
const sy = cy + (dy/dist)*75 + dy * (1 - 75/dist - 35/dist) * p;
|
||||
ctx.beginPath();
|
||||
ctx.arc(sx, sy, 1.2, 0, Math.PI*2);
|
||||
ctx.fillStyle = 'rgba(255,255,255,0.3)';
|
||||
ctx.fill();
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', e => {
|
||||
scene.style.transform = `rotateX(${(e.clientY/window.innerHeight-0.5)*-5}deg) rotateY(${(e.clientX/window.innerWidth-0.5)*5}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
197
public/demos/e-magnetic.html
Normal file
@@ -0,0 +1,197 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>E: Magnetic Field — สนามแม่เหล็ก</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #060a12;
|
||||
color: #fff; overflow: hidden;
|
||||
display: flex; align-items: center; justify-content: center; min-height: 100vh;
|
||||
}
|
||||
|
||||
.demo { position: relative; width: 700px; height: 600px; }
|
||||
canvas#magCanvas { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
|
||||
.scene {
|
||||
position: relative; width: 100%; height: 100%;
|
||||
transform-style: preserve-3d;
|
||||
transition: transform 0.3s ease-out;
|
||||
}
|
||||
|
||||
.node {
|
||||
position: absolute;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; text-align: center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Magnet core */
|
||||
.magnet {
|
||||
left: 50%; top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 170px; height: 170px;
|
||||
background: radial-gradient(circle at 40% 35%, #3a2000, #0d0500);
|
||||
border: 3px solid #fed400;
|
||||
box-shadow: 0 0 0 12px rgba(254,212,0,0.1), 0 0 60px rgba(254,212,0,0.3), 0 0 140px rgba(254,180,0,0.1);
|
||||
z-index: 10;
|
||||
animation: magnetPulse 2s ease-in-out infinite;
|
||||
}
|
||||
@keyframes magnetPulse {
|
||||
0%, 100% { box-shadow: 0 0 0 12px rgba(254,212,0,0.1), 0 0 60px rgba(254,212,0,0.3), 0 0 140px rgba(254,180,0,0.1); }
|
||||
50% { box-shadow: 0 0 0 18px rgba(254,212,0,0.15), 0 0 80px rgba(254,212,0,0.4), 0 0 160px rgba(254,180,0,0.15); }
|
||||
}
|
||||
.magnet .label { font-size: 2.6rem; font-weight: 900; color: #fed400; }
|
||||
.magnet .sub { font-size: 0.7rem; color: rgba(254,212,0,0.5); margin-top: 4px; font-weight: 600; }
|
||||
|
||||
/* Attracted nodes */
|
||||
.attract {
|
||||
width: 105px; height: 105px;
|
||||
background: rgba(254,212,0,0.04);
|
||||
border: 1.5px solid rgba(254,212,0,0.3);
|
||||
box-shadow: 0 0 20px rgba(254,212,0,0.08);
|
||||
z-index: 5;
|
||||
left: 50%; top: 50%;
|
||||
animation: attract 3s ease-in-out infinite alternate;
|
||||
}
|
||||
.attract:nth-child(2) {
|
||||
transform: translate(-50%,-50%) translate3d(-200px,-150px,-60px);
|
||||
animation-name: attract1;
|
||||
}
|
||||
.attract:nth-child(3) {
|
||||
transform: translate(-50%,-50%) translate3d(170px,-20px,-25px);
|
||||
animation-name: attract2;
|
||||
}
|
||||
.attract:nth-child(4) {
|
||||
transform: translate(-50%,-50%) translate3d(-100px,190px,-70px);
|
||||
animation-name: attract3;
|
||||
}
|
||||
|
||||
@keyframes attract1 {
|
||||
0% { transform: translate(-50%,-50%) translate3d(-220px,-160px,-80px); }
|
||||
100% { transform: translate(-50%,-50%) translate3d(-185px,-140px,-50px); }
|
||||
}
|
||||
@keyframes attract2 {
|
||||
0% { transform: translate(-50%,-50%) translate3d(185px,-25px,-35px); }
|
||||
100% { transform: translate(-50%,-50%) translate3d(155px,-15px,-20px); }
|
||||
}
|
||||
@keyframes attract3 {
|
||||
0% { transform: translate(-50%,-50%) translate3d(-120px,210px,-90px); }
|
||||
100% { transform: translate(-50%,-50%) translate3d(-90px,180px,-60px); }
|
||||
}
|
||||
|
||||
.attract .tag { font-size: 0.9rem; font-weight: 800; color: #fff; }
|
||||
.attract .desc { font-size: 0.65rem; color: rgba(255,255,255,0.5); margin-top: 3px; }
|
||||
|
||||
.title {
|
||||
position: fixed; top: 24px; left: 50%; transform: translateX(-50%);
|
||||
font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.2em;
|
||||
color: rgba(255,255,255,0.4); z-index: 100;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="title">E. Magnetic Field — สนามแม่เหล็กดึงดูด</span>
|
||||
<div class="demo">
|
||||
<canvas id="magCanvas"></canvas>
|
||||
<div class="scene" id="scene">
|
||||
<div class="node magnet" data-node="center">
|
||||
<span class="label">กำไร</span>
|
||||
<span class="sub">เป้าหมายของทุกธุรกิจ</span>
|
||||
</div>
|
||||
<div class="node attract" data-node="mkt">
|
||||
<span class="tag">Marketing</span>
|
||||
<span class="desc">เพิ่มรายได้</span>
|
||||
</div>
|
||||
<div class="node attract" data-node="ai">
|
||||
<span class="tag">AI</span>
|
||||
<span class="desc">ลดต้นทุนและเวลา</span>
|
||||
</div>
|
||||
<div class="node attract" data-node="biz">
|
||||
<span class="tag">Business<br>Knowledge</span>
|
||||
<span class="desc">ลดความเสี่ยง</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const canvas = document.getElementById('magCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const scene = document.getElementById('scene');
|
||||
|
||||
function resize() {
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width = rect.width;
|
||||
canvas.height = rect.height;
|
||||
}
|
||||
resize(); window.addEventListener('resize', resize);
|
||||
|
||||
let t = 0;
|
||||
function draw() {
|
||||
t++;
|
||||
const rect = canvas.parentElement.getBoundingClientRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const center = document.querySelector('[data-node="center"]');
|
||||
const nodes = document.querySelectorAll('.attract');
|
||||
if (!center) { requestAnimationFrame(draw); return; }
|
||||
|
||||
const cr = center.getBoundingClientRect();
|
||||
const cx = cr.left + cr.width/2 - rect.left;
|
||||
const cy = cr.top + cr.height/2 - rect.top;
|
||||
|
||||
// Magnetic field lines (ripple waves)
|
||||
for (let r = 0; r < 4; r++) {
|
||||
const radius = 95 + r * 30 + (t * 0.02) % 30;
|
||||
const alpha = Math.max(0, 0.25 - r * 0.06 - ((t * 0.02) % 30) / 120);
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx, cy, radius, 0, Math.PI*2);
|
||||
ctx.strokeStyle = `rgba(254,212,0,${alpha})`;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
// Connection lines with magnetic field arcs
|
||||
nodes.forEach((node, i) => {
|
||||
const pr = node.getBoundingClientRect();
|
||||
const px = pr.left + pr.width/2 - rect.left;
|
||||
const py = pr.top + pr.height/2 - rect.top;
|
||||
const dx = px - cx, dy = py - cy;
|
||||
const dist = Math.sqrt(dx*dx + dy*dy);
|
||||
|
||||
// Main connection
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(cx + (dx/dist)*85, cy + (dy/dist)*85);
|
||||
ctx.lineTo(px - (dx/dist)*53, py - (dy/dist)*53);
|
||||
ctx.strokeStyle = `rgba(254,212,0,0.4)`;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
|
||||
// Field curve arcs on both sides
|
||||
for (let side = -1; side <= 1; side += 2) {
|
||||
const offset = side * 15;
|
||||
const midX = cx + dx * 0.5 + (-dy/dist) * offset;
|
||||
const midY = cy + dy * 0.5 + (dx/dist) * offset;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(cx + (dx/dist)*85, cy + (dy/dist)*85);
|
||||
ctx.quadraticCurveTo(midX, midY, px - (dx/dist)*53, py - (dy/dist)*53);
|
||||
ctx.strokeStyle = `rgba(254,212,0,0.1)`;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.stroke();
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
document.addEventListener('mousemove', e => {
|
||||
scene.style.transform = `rotateX(${(e.clientY/window.innerHeight-0.5)*-6}deg) rotateY(${(e.clientX/window.innerWidth-0.5)*6}deg)`;
|
||||
});
|
||||
|
||||
draw();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
75
public/demos/index.html
Normal file
@@ -0,0 +1,75 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="th">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Hero Design Demos</title>
|
||||
<style>
|
||||
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@400;600;800;900&display=swap');
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: 'Kanit', system-ui, sans-serif;
|
||||
background: #0d1117;
|
||||
color: #fff;
|
||||
min-height: 100vh;
|
||||
padding: 48px 24px;
|
||||
}
|
||||
h1 { font-size: 2rem; text-align: center; margin-bottom: 8px; }
|
||||
h1 span { color: #fed400; }
|
||||
.sub { text-align: center; color: rgba(255,255,255,0.5); margin-bottom: 40px; font-size: 1rem; }
|
||||
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px; max-width: 1000px; margin: 0 auto; }
|
||||
.card {
|
||||
background: rgba(255,255,255,0.04);
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
border-radius: 16px;
|
||||
padding: 32px 24px;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
transition: all 0.3s ease;
|
||||
display: flex; flex-direction: column; gap: 12px;
|
||||
}
|
||||
.card:hover { background: rgba(254,212,0,0.06); border-color: rgba(254,212,0,0.3); transform: translateY(-2px); }
|
||||
.card .emoji { font-size: 3rem; }
|
||||
.card .name { font-size: 1.3rem; font-weight: 800; }
|
||||
.card .name span { color: #fed400; }
|
||||
.card .desc { font-size: 0.82rem; color: rgba(255,255,255,0.5); line-height: 1.5; }
|
||||
.card .tag { display: inline-block; font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.15em; color: rgba(254,212,0,0.6); border: 1px solid rgba(254,212,0,0.2); border-radius: 20px; padding: 4px 10px; width: fit-content; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hero Section — <span>5 Design Demos</span></h1>
|
||||
<p class="sub">เลือกดูแต่ละแนวคิดเพื่อเปรียบเทียบ</p>
|
||||
<div class="grid">
|
||||
<a href="a-orbital.html" class="card">
|
||||
<div class="emoji">🌌</div>
|
||||
<div class="name">A. <span>Orbital</span></div>
|
||||
<div class="tag">ระบบดาวเคราะห์โคจร</div>
|
||||
<div class="desc">กำไรเป็นดวงอาทิตย์เรืองแสง 3 ป้ายโคจรรอบด้วยวงแหวน orbital พร้อมหมุนอัตโนมัติ</div>
|
||||
</a>
|
||||
<a href="b-energyflow.html" class="card">
|
||||
<div class="emoji">⚡</div>
|
||||
<div class="name">B. <span>Energy Flow</span></div>
|
||||
<div class="tag">กระแสพลังงาน</div>
|
||||
<div class="desc">Particle วิ่งตามเส้นเชื่อมสีทอง เหมือนพลังงาน/ข้อมูลไหลเข้าสู่กำไร ดูมีชีวิตชีวา</div>
|
||||
</a>
|
||||
<a href="c-holographic.html" class="card">
|
||||
<div class="emoji">🌀</div>
|
||||
<div class="name">C. <span>Holographic 3D</span></div>
|
||||
<div class="tag">Hologram Sci-Fi</div>
|
||||
<div class="desc">โทน Cyan เรืองแสง พร้อม scanline และ beam เชื่อมต่อ ดูล้ำสมัย ดูแพง</div>
|
||||
</a>
|
||||
<a href="d-constellation.html" class="card">
|
||||
<div class="emoji">✨</div>
|
||||
<div class="name">D. <span>Constellation</span></div>
|
||||
<div class="tag">แผนที่ดาว</div>
|
||||
<div class="desc">โหนดเป็นดาวระยิบระยับ เส้นเชื่อมแบบกลุ่มดาว พื้นหลังมีดาวกระจาย ดูลึกลับสง่า</div>
|
||||
</a>
|
||||
<a href="e-magnetic.html" class="card">
|
||||
<div class="emoji">🧲</div>
|
||||
<div class="name">E. <span>Magnetic Field</span></div>
|
||||
<div class="tag">สนามแม่เหล็ก</div>
|
||||
<div class="desc">กำไรเป็นแม่เหล็กทรงพลัง มี ripple wave + field curve สื่อถึงการดึงดูดทุกอย่างสู่กำไร</div>
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 655 B |
@@ -1,9 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 128 128">
|
||||
<path d="M50.4 78.5a75.1 75.1 0 0 0-28.5 6.9l24.2-65.7c.7-2 1.9-3.2 3.4-3.2h29c1.5 0 2.7 1.2 3.4 3.2l24.2 65.7s-11.6-7-28.5-7L67 45.5c-.4-1.7-1.6-2.8-2.9-2.8-1.3 0-2.5 1.1-2.9 2.7L50.4 78.5Zm-1.1 28.2Zm-4.2-20.2c-2 6.6-.6 15.8 4.2 20.2a17.5 17.5 0 0 1 .2-.7 5.5 5.5 0 0 1 5.7-4.5c2.8.1 4.3 1.5 4.7 4.7.2 1.1.2 2.3.2 3.5v.4c0 2.7.7 5.2 2.2 7.4a13 13 0 0 0 5.7 4.9v-.3l-.2-.3c-1.8-5.6-.5-9.5 4.4-12.8l1.5-1a73 73 0 0 0 3.2-2.2 16 16 0 0 0 6.8-11.4c.3-2 .1-4-.6-6l-.8.6-1.6 1a37 37 0 0 1-22.4 2.7c-5-.7-9.7-2-13.2-6.2Z" />
|
||||
<style>
|
||||
path { fill: #000; }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path { fill: #FFF; }
|
||||
}
|
||||
</style>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 749 B |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
BIN
public/images/backgrounds/liquid-glass-bg.png
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 224 KiB |
|
Before Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 274 KiB |
|
Before Width: | Height: | Size: 285 KiB |
|
Before Width: | Height: | Size: 219 KiB |
|
Before Width: | Height: | Size: 396 KiB |
|
Before Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 268 KiB |
|
Before Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 241 KiB |
|
Before Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 270 KiB |
BIN
public/images/logos/logo-long-black.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 477 B After Width: | Height: | Size: 477 B |
|
Before Width: | Height: | Size: 406 KiB After Width: | Height: | Size: 406 KiB |
BIN
public/images/portfolio/dealplustech.png
Normal file
|
After Width: | Height: | Size: 768 KiB |
|
Before Width: | Height: | Size: 241 KiB |
|
Before Width: | Height: | Size: 285 KiB |
|
Before Width: | Height: | Size: 285 KiB |
|
Before Width: | Height: | Size: 268 KiB |
|
Before Width: | Height: | Size: 270 KiB |
19
redesign-input/README.md
Normal 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/`
|
||||
177
redesign-input/WEBSITE-CONTENT-EXTRACT.md
Normal 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`
|
||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
BIN
redesign-input/assets/logos/logo-long.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
6
redesign-input/assets/logos/logo.svg
Normal 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 |
15
redesign-input/assets/portfolio/DEALPLUSTECH.md
Normal 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.
|
||||
BIN
redesign-input/assets/portfolio/baofuling.png
Normal file
|
After Width: | Height: | Size: 706 KiB |
BIN
redesign-input/assets/portfolio/dataroot.png
Normal file
|
After Width: | Height: | Size: 406 KiB |
BIN
redesign-input/assets/portfolio/dealplustech.png
Normal file
|
After Width: | Height: | Size: 768 KiB |
BIN
redesign-input/assets/portfolio/jetindustries.png
Normal file
|
After Width: | Height: | Size: 911 KiB |
BIN
redesign-input/assets/portfolio/lawyernoom.png
Normal file
|
After Width: | Height: | Size: 475 KiB |
BIN
redesign-input/assets/portfolio/luadjob.png
Normal file
|
After Width: | Height: | Size: 496 KiB |
BIN
redesign-input/assets/portfolio/lungfinler.png
Normal file
|
After Width: | Height: | Size: 337 KiB |
BIN
redesign-input/assets/portfolio/trainersunny.png
Normal file
|
After Width: | Height: | Size: 849 KiB |
BIN
redesign-input/assets/portfolio/tuanthong.png
Normal file
|
After Width: | Height: | Size: 897 KiB |
BIN
redesign-input/assets/portfolio/underdog.png
Normal file
|
After Width: | Height: | Size: 724 KiB |
80
redesign-input/raw/BRAND-VOICE.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Brand Voice — MoreminiMore
|
||||
|
||||
> ใช้เป็นกระดาษทดเวลาเขียน content ทุกชิ้น ถ้าเขียนแล้วผิด vibe ให้กลับมาเช็คที่นี่
|
||||
|
||||
---
|
||||
|
||||
## หนึ่งประโยคที่คนต้องจำ
|
||||
|
||||
> **เป้าหมายของเราคือการเพิ่มกำไรให้ลูกค้า** เพราะถ้าลูกค้ามีกำไรมากขึ้น ลูกค้าก็จะสามารถใช้บริการเราต่อไปได้
|
||||
|
||||
---
|
||||
|
||||
## เราเป็นใครใน 1 บรรทัด
|
||||
|
||||
ที่ปรึกษาที่ทำเว็บ + ทำการตลาด + ทำ AI ในองค์กร **โดยใช้ข้อมูลจริงเป็นตัวตั้ง** ไม่ใช่ประสบการณ์ล้วน ๆ
|
||||
|
||||
---
|
||||
|
||||
## เสียงของเรา (10 ข้อ)
|
||||
|
||||
1. **ตรง แต่สุภาพ** — พูดตรง ๆ ว่าทำได้หรือทำไม่ได้ แต่ไม่ดุ ไม่หยาบ
|
||||
2. **เน้นข้อมูล** — เวลาพูดถึงผลงาน บอกตัวเลข ไม่ใช่ "ดีขึ้นมาก" แบบกำกวม
|
||||
3. **เล่าจากประสบการณ์จริง** — มีเคสพัง มีเคสสำเร็จ ไม่อวดว่าทำได้หมดทุกอย่าง
|
||||
4. **ห้ามใช้คำว่า "ครบวงจร" "ทันสมัย" "รวดเร็ว" "ไร้รอยต่อ" "เพิ่มประสิทธิภาพ"** — คำพวกนี้ทุก agency ใช้ ไม่ได้ทำให้เราต่าง
|
||||
5. **พูดถึงเรื่องที่เราไม่เชื่อด้วย** — เว็บสวยไม่ได้แปลว่าขายได้ / AI ไม่ได้แทนทุกอย่าง / จ่ายแพงไม่ได้แปลว่าดี
|
||||
6. **ยอมรับว่าเราเป็น soloprenuer** — แต่ห้ามขอโทษ ห้ามทำเป็นข้ออ่อน ให้ทำเป็นข้อได้เปรียบ: คุณคุยกับคนที่จะทำงานจริง ไม่ใช่ทีมขาย
|
||||
7. **ช่วงราคา** — ไม่ลงเว็บ แต่พร้อมบอกเมื่อถาม ถ้าลูกค้าถามแล้วเราไม่ตอบ = ลูกค้าหาย
|
||||
8. **Quote ลูกค้าใช้ของจริง** — เอาคำที่ลูกค้าพูดจริง ๆ มาวาง ไม่ใช่แต่งให้สวย
|
||||
9. **เน้นว่าเราเลือกช่องทางให้เหมาะกับสินค้า + กลุ่มเป้าหมาย** — ไม่ยิงทุกที่ ไม่ใช้ AI ระดับ Frontier กับทุกงาน
|
||||
10. **พูดถึง "เราเขียนโค้ดเอง" และ "เราตอบแชตเอง" โดยไม่ต้องโอ้อวด** — แค่บอกตรง ๆ ว่าเราไม่ outsource
|
||||
|
||||
---
|
||||
|
||||
## คำที่ห้ามใช้ (Banned Words)
|
||||
|
||||
| ❌ ห้าม | ✅ ใช้แทน |
|
||||
|---|---|
|
||||
| ครบวงจร | บอกชัดว่าทำอะไรบ้าง |
|
||||
| ทันสมัย | บอกว่าใช้เทคโนโลยีอะไร เช่น Astro / n8n / local LLM |
|
||||
| รวดเร็ว | บอกตัวเลข เช่น "ส่งมอบภายใน 14 วัน" |
|
||||
| ไร้รอยต่อ | อธิบายว่าเชื่อมต่อระบบอะไรยังไง |
|
||||
| เพิ่มประสิทธิภาพ | บอกตัวเลข เช่น "ลดเวลา 4 ชม./สัปดาห์" |
|
||||
| หลากหลาย | บอกว่ามีอะไรบ้าง |
|
||||
| มีคุณภาพ | บอกเกณฑ์วัด |
|
||||
|
||||
---
|
||||
|
||||
## คำที่ใช้บ่อย (ใช้ได้)
|
||||
|
||||
- "วางแผนจากข้อมูล" / "ใช้สถิติจริง"
|
||||
- "เราเขียนเอง / ทำเอง" / "ไม่ outsource"
|
||||
- "จ่ายเมื่อใช้ / เริ่มต้นที่..."
|
||||
- "ถ้าทำไม่ได้ จะบอกตรง ๆ"
|
||||
- "เคสเราเคยพังแบบนี้" (เล่าเคสจริง)
|
||||
|
||||
---
|
||||
|
||||
## Tone Examples
|
||||
|
||||
### ❌ ก่อนแก้ (AI-isms + ทั่วไปเกินไป)
|
||||
> เรามีบริการครบวงจร ทั้งเว็บไซต์ การตลาด และ AI เพื่อเพิ่มประสิทธิภาพให้ธุรกิจของคุณอย่างทันสมัยและรวดเร็ว
|
||||
|
||||
### ✅ หลังแก้ (เสียงของมอร์มินิมอร์)
|
||||
> เราทำเว็บ ทำการตลาด และวางระบบ AI ให้องค์กร — ทั้งหมดเริ่มจากดูข้อมูลของลูกค้าก่อน ไม่ใช่เดาจากประสบการณ์
|
||||
|
||||
---
|
||||
|
||||
### ❌ ก่อนแก้
|
||||
> เว็บไซต์ของเราสวยงาม ทันสมัย รองรับทุกอุปกรณ์
|
||||
|
||||
### ✅ หลังแก้
|
||||
> เว็บที่เราทำเน้นให้ขายได้ ไม่ใช่เน้นให้สวย — เพราะเว็บหลายเว็บที่ดูดีที่สุด ขายแย่ที่สุดก็มี
|
||||
|
||||
---
|
||||
|
||||
### ❌ ก่อนแก้
|
||||
> เราใช้ AI เพื่อเพิ่มประสิทธิภาพ
|
||||
|
||||
### ✅ หลังแก้
|
||||
> เราเลือกใช้ AI ตามงาน — งาน 80% ใช้ Model ราคาถูกก็พอ จะได้ไม่เปลืองเงินลูกค้า
|
||||
103
redesign-input/raw/moreminimore-content.md
Normal 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)
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "บริการ"
|
||||
category_icon: "💼"
|
||||
question: "มอร์มินิมอร์ทำอะไรบ้าง?"
|
||||
answer: "4 บริการหลัก — (1) รับทำเว็บไซต์ (Astro / WordPress) (2) ที่ปรึกษาการตลาดออนไลน์ (3) Automation / เชื่อมต่อระบบ (4) AI Consult ในองค์กร ทั้งหมดเริ่มจากดูข้อมูลของลูกค้าก่อน ไม่ใช่เดาว่าควรทำอะไร"
|
||||
---
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "บริการ"
|
||||
category_icon: "💼"
|
||||
question: "ถ้ามีงบน้อย ควรเริ่มจากอะไร?"
|
||||
answer: "ถ้ายังไม่มีเว็บและไม่มีกิจกรรมออนไลน์เลย → เริ่มจากเว็บไซต์ก่อน เพราะเป็นบริการที่ถูกที่สุด ถ้ามีเว็บแล้วและมีกิจกรรมออนไลน์ → Marketing Consult จะคุ้มกว่า ถ้ารู้สึกยุ่งมากมีแต่ความผิดพลาด → Automation จะตอบโจทย์สุด ถ้ามีระบบพร้อมแล้วอยากรีดยอดขายหรือป้องกันปัญหาพนักงานลาออก → AI Consult"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/003-services-fit.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "บริการ"
|
||||
category_icon: "💼"
|
||||
question: "เหมาะกับธุรกิจแบบไหน?"
|
||||
answer: "SME ที่ต้องการคนช่วยดูเรื่อง Online Marketing และระบบ IT ลูกค้าที่ไม่มีความรู้ IT มาก แต่จำเป็นต้องใช้ระบบ IT ในการทำงาน ไม่เหมาะกับ: องค์กรขนาดใหญ่ที่มีการเมืองเยอะ คนที่อยากได้ของฟรีหรือจ่ายน้อยแต่คาดหวังงานระดับแสน และกลุ่ม IT ทั่วไป (ยกเว้นขาย Software เฉพาะทาง เช่น ERP)"
|
||||
---
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "บริการ"
|
||||
category_icon: "💼"
|
||||
question: "รับงานอุตสาหกรรมเฉพาะไหม?"
|
||||
answer: "รับหลากหลาย แต่ไม่รับทุกอย่าง — เราเน้นงานที่วัดผลได้ ไม่ว่าจะเป็น E-commerce, บริการ, B2B, คลินิก, ร้านอาหาร, ผู้ผลิต, สถานศึกษา, ที่ปรึกษา ดูตัวอย่างงานได้ที่หน้า Portfolio ถ้าไม่แน่ใจว่าอุตสาหกรรมของคุณเหมาะ นัดคุย 30 นาทีฟรีได้เลย"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/005-price-start.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "ราคา"
|
||||
category_icon: "💰"
|
||||
question: "ราคาเริ่มต้นเท่าไหร่?"
|
||||
answer: "เว็บไซต์: Astro เริ่ม 5,000 บาท / WordPress เริ่ม 30,000 บาท (ขึ้นอยู่กับความซับซ้อน) · ที่ปรึกษา Marketing และ Automation: เริ่ม 10,000 บาท/เดือน · ที่ปรึกษา AI: เริ่ม 20,000 บาท/เดือน · Host: เริ่ม 5,000 บาท/ปี ราคาจะขึ้นอยู่กับ Requirement จริง บอกได้เมื่อคุยกัน"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/006-price-packages.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "ราคา"
|
||||
category_icon: "💰"
|
||||
question: "มีแพ็คเกจไหม?"
|
||||
answer: "ไม่มีแพ็คเกจตายตัว เพราะงานแต่ละชิ้นต่างกัน บางเว็บใช้เวลา 1 สัปดาห์ บางเว็บใช้ 3 เดือน เราจะส่ง Proposal เป็น PDF พร้อมรายละเอียดงาน ราคา ระยะเวลา ให้คุณอ่านก่อนเซ็น แก้ไข scope ได้"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/007-price-payment.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "ราคา"
|
||||
category_icon: "💰"
|
||||
question: "จ่ายยังไง?"
|
||||
answer: "เว็บไซต์: มัดจำ 50% ตอนเซ็น ที่เหลือจ่ายตอนส่งมอบ · ที่ปรึกษารายเดือน: จ่ายต้นเดือนของทุกเดือน เริ่มจ่ายเดือนแรกตอนเซ็นสัญญา ออกใบกำกับภาษีได้"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/008-price-hidden.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "ราคา"
|
||||
category_icon: "💰"
|
||||
question: "มีค่าใช้จ่ายแอบแฝงไหม?"
|
||||
answer: "ไม่มี — เราจะบอกทุกค่าใช้จ่ายใน Proposal ตั้งแต่ต้น ไม่มี \"อันนี้เพิ่มเงินนะ\" ตอนใกล้ส่งมอบ ถ้ามีงานเพิ่มจริง ๆ จะคุยและตกลงราคาก่อนทำ"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/009-time-website.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "ระยะเวลา"
|
||||
category_icon: "⏱️"
|
||||
question: "ทำเว็บเสร็จในกี่วัน?"
|
||||
answer: "Astro: 14-30 วัน · WordPress: 2-4 เดือน · ถ้าจะติด เราจะบอกก่อน 7 วัน ไม่ใช่บอกตอนส่งงาน — เคสไหนที่เคยส่งช้า เราคืนเงิน Pro-rata"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/010-time-seo.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "ระยะเวลา"
|
||||
category_icon: "⏱️"
|
||||
question: "SEO ใช้เวลาเห็นผลกี่เดือน?"
|
||||
answer: "SEO ปกติใช้เวลา 3-6 เดือนถึงจะเห็นผลชัด ขึ้นอยู่กับคีย์เวิร์ดและคู่แข่ง เราเคยมีเคสติดหน้า 1 Google ใน 4 เดือน แต่ก็มีเคสที่ใช้เวลานานกว่านั้น จะบอกคุณตรง ๆ ตั้งแต่แรกว่าคาดว่าเห็นผลเมื่อไหร่"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/011-time-rush.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "ระยะเวลา"
|
||||
category_icon: "⏱️"
|
||||
question: "งานด่วน ทำได้ไหม?"
|
||||
answer: "ทำได้ แต่จะคิดราคาเร่งด่วนเพิ่ม เพราะกระทบกับงานอื่นที่มีอยู่ เราจะบอกชัดว่าค่าเร่งเท่าไหร่ก่อนรับงาน"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/012-time-overrun.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "ระยะเวลา"
|
||||
category_icon: "⏱️"
|
||||
question: "ถ้างานล่าช้า คืนเงินไหม?"
|
||||
answer: "ถ้าเราส่งงานล่าช้าโดยไม่ได้แจ้งล่วงหน้า 7 วัน จะคืนเงิน Pro-rata ตามจริง เคสนี้เคยเกิดขึ้น 1-2 ครั้งในรอบหลายปี และคืนเงินไปแล้ว"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/013-ai-quality.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "AI & เทคนิค"
|
||||
category_icon: "🤖"
|
||||
question: "AI ใช้ของแพงหรือของถูก?"
|
||||
answer: "เราเลือกตามงาน ไม่ใช่เลือกของแพงสุดเสมอ งาน 80% ใช้ Model ราคาถูก (เช่น GPT-4o-mini, Haiku, Local LLM) ก็ได้ผล ส่วนงานที่ซับซ้อนมาก ๆ ค่อยใช้ของแพง วิธีนี้ช่วยลูกค้าประหยัดค่าใช้จ่ายได้มากกว่าครึ่ง"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/014-ai-technical.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "AI & เทคนิค"
|
||||
category_icon: "🤖"
|
||||
question: "ต้องมีความรู้เทคนิคไหม?"
|
||||
answer: "ไม่ต้อง เราดูแลตั้งแต่ต้นจนจบ ตั้งแต่วิเคราะห์ ออกแบบ พัฒนา ไปจนถึง Deploy และดูแลหลังขาย จะสอนการใช้งานจนทีมคุณใช้เป็น"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/015-ai-pdpa.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "AI & เทคนิค"
|
||||
category_icon: "🤖"
|
||||
question: "ข้อมูลปลอดภัยไหม (PDPA)?"
|
||||
answer: "ปลอดภัย สำหรับงานที่ต้องการความลับ เราใช้ Local LLM ที่รันในเครื่องของลูกค้า ข้อมูลไม่ออกไปไหน ส่วนงานทั่วไปใช้ API ของผู้ให้บริการที่เชื่อถือได้ พร้อมทำ NDA ได้"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/016-ai-which.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "AI & เทคนิค"
|
||||
category_icon: "🤖"
|
||||
question: "ควรใช้ AI ตัวไหน?"
|
||||
answer: "ขึ้นอยู่กับงาน ถ้าเป็นแชทบอททั่วไป ใช้ GPT-4o-mini หรือ Claude Haiku ก็พอ ถ้าเป็นงานวิเคราะห์ข้อมูล ใช้ GPT-4o หรือ Claude Sonnet ถ้าเป็นงานที่ต้องการความลับ ใช้ Local LLM (Llama, Qwen) เรามี AI Audit ฟรี ช่วยวิเคราะห์ว่าธุรกิจคุณควรใช้ AI ตัวไหน"
|
||||
---
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "หลังการขาย"
|
||||
category_icon: "🛠️"
|
||||
question: "มีประกันงานไหม?"
|
||||
answer: "มี — ถ้าเว็บมีปัญหาจากการพัฒนาของเรา จะแก้ไขให้ฟรี 30-90 วันหลังส่งมอบ (ขึ้นอยู่กับประเภทงาน) ถ้าเกิดจากการแก้ไขของลูกค้าเอง จะคิดค่าแก้ตามจริง"
|
||||
---
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "หลังการขาย"
|
||||
category_icon: "🛠️"
|
||||
question: "ติดต่อช่องทางไหน?"
|
||||
answer: "LINE OA: @moreminimore (ตอบเร็วที่สุด) · โทร: 080-995-5945 · Email: contact@moreminimore.com ทีมที่ตอบคือคนที่ทำงานให้คุณ ไม่ใช่ Bot ไม่ใช่คนอื่น"
|
||||
---
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "หลังการขาย"
|
||||
category_icon: "🛠️"
|
||||
question: "มีแพ็คเกจดูแลรายเดือนไหม?"
|
||||
answer: "มี เริ่ม 2,000 บาท/เดือน รวมอัปเดตเนื้อหา ปรับ SEO แก้บั๊ก ตอบคำถามผ่าน LINE ถ้าไม่เอาแพ็คเกจ ก็จ่ายเป็นงาน ๆ ไป แล้วแต่ความเหมาะ"
|
||||
---
|
||||
6
redesign-input/raw/src-content/faq/020-support-refund.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: "หลังการขาย"
|
||||
category_icon: "🛠️"
|
||||
question: "ถ้าไม่พอใจ ขอเงินคืนได้ไหม?"
|
||||
answer: "ภายใน 7 วันแรกหลังเริ่มงาน ถ้าคุณรู้สึกว่าไม่ใช่ ขอยกเลิกได้ จะคืนเงินตามส่วนงานที่ยังไม่ได้ทำ เราไม่ผูก commitment"
|
||||
---
|
||||
86
redesign-input/raw/src-content/pages/about.md
Normal 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 ใหม่ หรือปรับแต่งครั้งใหญ่ เราจะคิดค่าใช้จ่ายเป็นครั้ง ๆ ไปตามขอบเขตงาน
|
||||
69
redesign-input/raw/src-content/pages/home.md
Normal file
@@ -0,0 +1,69 @@
|
||||
---
|
||||
badge: "ที่ปรึกษาที่วางกลยุทธ์จากข้อมูล ไม่ใช่จากประสบการณ์ล้วน ๆ"
|
||||
title: "เว็บขายไม่ได้ โฆษณาเปลือง งานซ้ำเติมคน — เราแก้ให้ตรงจุด"
|
||||
subtitle: "รับทำเว็บ ที่ปรึกษาการตลาด และวางระบบ AI ในองค์กร เริ่มจากดูสถิติของคุณก่อน ไม่ใช่เดาว่าควรทำอะไร"
|
||||
problem_section_title: "4 ปัญหาที่เจอบ่อยที่สุด"
|
||||
problem_section_subtitle: "แต่ละข้อมีวิธีแก้ที่เจาะจง — เราไม่ได้บอกว่า 'เราทำได้หมด' แต่บอกว่า 'ถ้าเป็นแบบนี้ ทำแบบนี้'"
|
||||
service_section_title: "ทำอะไรได้บ้าง"
|
||||
service_section_subtitle: "เริ่มจากอันที่ปวดที่สุด ค่อยขยายไปอันอื่น"
|
||||
service_cta: "ดูบริการทั้งหมด"
|
||||
portfolio_section_badge: "ผลงานจริง ไม่ใช่ Mockup"
|
||||
portfolio_section_title: "ลูกค้าจริง ตัวเลขจริง"
|
||||
portfolio_section_subtitle: "คลิกดูเว็บจริงได้เลย"
|
||||
portfolio_cta: "ดูผลงานทั้งหมด"
|
||||
final_cta_title: "คุยกันก่อน 30 นาที ฟรี"
|
||||
final_cta_desc: "เราจะถามคำถาม 5 ข้อ แล้วบอกคุณได้เลยว่าควรเริ่มจากตรงไหน — จะบอกตรง ๆ ว่าทำได้หรือทำไม่ได้"
|
||||
final_cta_button: "นัดคุย 30 นาที"
|
||||
final_cta_line: "ทัก LINE: @moreminimore"
|
||||
final_cta_reassurance: "ไม่มี commitment · ไม่มี script sales · พูดตรง ๆ"
|
||||
---
|
||||
|
||||
# 4 ปัญหาที่ SME ไทยเจอบ่อยที่สุด
|
||||
|
||||
เราเจอปัญหาแบบนี้ซ้ำ ๆ กับลูกค้า 4 แบบ แต่ละแบบมีวิธีแก้ต่างกัน
|
||||
|
||||
## 1. ลงโฆษณาแล้วยอดไม่ขยับ
|
||||
|
||||
**อาการ:** คลิกเยอะ ยอดขายเท่าเดิม งบหม<E0B8AB>ไปกับคนที่ไม่ซื้อ
|
||||
|
||||
**สาเหตุส่วนใหญ่:** เลือกกลุ่มเป้าหมายผิด หรือยิงทุก Platform โดยไม่ดูว่าอันไหนคุ้ม
|
||||
|
||||
**เราแก้ยังไง:** ดูสถิติ 3 เดือนย้อนหลัง แยกว่า Platform ไหน Convert ดี ตัดอันที่เสียเงินเปล่า ปรับ Creative ให้ดึงดูดคนที่พร้อมจ่าย
|
||||
|
||||
> ตัวอย่าง: ลูกค้ารายหนึ่งเพิ่ม Impression 373% และเพิ่ม Click 114% ในเดือนแรก โดยใช้งบน้อยลง 28% — ดูเคสเต็มได้ที่หน้า Portfolio
|
||||
|
||||
## 2. เว็บมีคนเข้า แต่ไม่มีคนซื้อ
|
||||
|
||||
**อาการ:** Traffic เข้าพอสมควร แต่ไม่มีใครทัก ไม่มีใครโทร ตะกร้าค้าง
|
||||
|
||||
**สาเหตุส่วนใหญ่:** เว็บสวยแต่ไม่ได้ออกแบบมาให้คนซื้อ หรือมีจุดติดขัดที่ทำให้คนออกก่อนซื้อ
|
||||
|
||||
**เราแก้ยังไง:** ดู Heatmap ว่าคนเข้ามาแล้วทำอะไร ตรงไหนที่คนออก ตรงไหนที่คนค้าง ปรับจุดนั้น ๆ
|
||||
|
||||
> ตัวอย่าง: ลูกค้า B2B รายหนึ่งมีคนเข้าเว็บเยอะ แต่ไม่มี Lead — เพิ่ม Lead 2.4 เท่าใน 1 เดือน โดยไม่ต้องเพิ่มงบโฆษณา
|
||||
|
||||
## 3. งานซ้ำ ๆ ใช้เวลาคนเป็นชั่วโมงทุกวัน
|
||||
|
||||
**อาการ:** ทีมต้องคีย์ข้อมูล ทำรายงาน ตอบแชตเดิม ๆ จนไม่มีเวลาทำงานหลัก
|
||||
|
||||
**สาเหตุส่วนใหญ่:** ระบบเก่าที่ไม่ได้เชื่อมกัน หรือยังทำ Manual อยู่
|
||||
|
||||
**เราแก้ยังไง:** ดู Workflow ก่อน แล้วเลือกเครื่องมือที่เหมาะ — บางงานใช้ n8n บางงานเขียน Script บางงานใช้ AI
|
||||
|
||||
> ตัวอย่าง: บริษัทที่ปรึกษาขนาดเล็กใช้เวลาทำรายงาน 30+ ชม./เดือน — ลดเหลือ 2 ชม./เดือน
|
||||
|
||||
## 4. ใช้ AI แต่ไม่เห็นผล
|
||||
|
||||
**อาการ:** จ่ายแพง ใช้ AI ระดับ Frontier กับทุกงาน แต่ผลลัพธ์ไม่คุ้มเงิน
|
||||
|
||||
**สาเหตุส่วนใหญ่:** ใช้ AI ผิดแบบ — งานหลายอย่างใช้ Model ราคาถูกก็ได้ผลเท่า ๆ กัน
|
||||
|
||||
**เราแก้ยังไง:** เลือก AI ตามงาน ไม่ใช่เลือกของแพงสุด — เน้น Local LLM สำหรับงานที่ต้องการความลับ
|
||||
|
||||
> ตัวอย่าง: งาน 80% ของธุรกิจใช้ Model ราคาถูกได้ ประหยัดค่าใช้จ่ายได้มากกว่าครึ่ง
|
||||
|
||||
---
|
||||
|
||||
# เริ่มจากตรงไหนดี?
|
||||
|
||||
ถ้าไม่แน่ใจว่าปัญหาของคุณตรงกับข้อไหน — นัดคุย 30 นาทีฟรี เราจะช่วยดู
|
||||