303 lines
12 KiB
Markdown
303 lines
12 KiB
Markdown
# 盈豐太陽能工程有限公司 — 官網設計規格 (Design Spec)
|
||
|
||
- **日期**:2026-09-11
|
||
- **專案代號**:yingfungsolar
|
||
- **狀態**:已與客戶確認方向,待寫實作計劃
|
||
|
||
---
|
||
|
||
## 1. 背景與目標
|
||
|
||
為香港**村屋太陽能**興建公司「盈豐太陽能工程有限公司」建立一個可以**完全部署在 Cloudflare** 的網站,包含:
|
||
|
||
- 面向公眾的一頁式官網
|
||
- 一個 Blog 分頁(列表 + 文章頁)
|
||
- 一個後台 `/admin`,讓非技術人員管理 Blog 及首頁內容
|
||
|
||
設計要求:美觀、現代化、清爽。內容參考 BrightSun Solar(村屋及工廈太陽能),但**本網站只做村屋**,而且版面設計不參考該站。
|
||
|
||
### 非目標 (Out of scope)
|
||
|
||
- 不做工廈 / 農地太陽能內容
|
||
- 不做雙語(只做繁體中文)
|
||
- 不做聯絡表單(只做 WhatsApp / 電話 / Email 連結)
|
||
- 不做圖片上傳(先用佔位圖,後台以 URL 貼圖)
|
||
- 不做多頁公司介紹(關於我們等內容併入一頁式)
|
||
|
||
---
|
||
|
||
## 2. 技術架構
|
||
|
||
沿用現有 `cf-dash` 骨幹,路線 A:**Astro + React islands + Chakra UI**。
|
||
|
||
```
|
||
┌──────────────── Cloudflare Worker (一個 deploy) ────────────────┐
|
||
瀏覽器 → │ Astro 7 │
|
||
│ ├─ / SSR,讀 D1 → React island (Chakra UI) │
|
||
│ ├─ /blog SSR,讀 D1 │
|
||
│ ├─ /blog/[slug] SSR,讀 D1 + Markdown 渲染 │
|
||
│ ├─ /admin/* SSR,Astro 表單 + HMAC cookie auth │
|
||
│ ├─ /sitemap.xml SSR,讀 D1 │
|
||
│ └─ /robots.txt 靜態 │
|
||
│ │ │
|
||
│ D1 (SQLite) ← Drizzle ORM │
|
||
│ KV (CACHE) ← 內容版本快取 (可選) │
|
||
└────────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 技術選型
|
||
|
||
| 層 | 選用 | 說明 |
|
||
|---|---|---|
|
||
| 框架 | Astro 7 (`output: "static"` + per-page `prerender = false`) | 沿用現有 |
|
||
| Adapter | `@astrojs/cloudflare` | 沿用現有 |
|
||
| UI | `@chakra-ui/react` v3 + `@emotion/react`(只淺色模式,不引入 color mode 套件) | 新增 |
|
||
| React | React 19(由 `npx astro add react` 加入) | 新增 |
|
||
| DB | Cloudflare D1 (SQLite) | 沿用 |
|
||
| ORM | Drizzle | 沿用 |
|
||
| Auth | HMAC-signed cookie(`src/lib/auth.ts`) | 沿用 |
|
||
| Markdown | `marked`(`src/lib/markdown.ts`) | 沿用 |
|
||
|
||
### 關鍵渲染決策
|
||
|
||
1. **首頁改為 SSR**(`prerender = false`),因為首頁內容由 D1 提供、後台改完要即時生效。
|
||
- 用 `Cache-Control: public, s-maxage=60, stale-while-revalidate=300` 保持效能。
|
||
2. **每個頁面用單一 React root island**(`client:load`),入面包一個 `<Provider>`。
|
||
- 原因:Chakra 的 Provider 只需一個;避免多個 island 各自建立 Provider 造成樣式重複。
|
||
- Astro 會 SSR render 呢個 island(SEO 無損),再喺 client hydrate。
|
||
3. **Chakra v3 SSR 樣式注入**:**已用 spike 實測驗證可行**。
|
||
- Versions: Astro 7.3.2 + `@astrojs/react` 6.0.5 + React 19.3 + `@chakra-ui/react` 3.37 + `@emotion/react` 11.14。
|
||
- 實測結果:SSR 會將 critical CSS 以 inline `<style data-emotion>` 輸出(首屏即有樣式、零 FOUC);client hydrate 後 emotion 會自動把樣式整合到 `<head>`;**無 hydration error**,樣式正確。
|
||
- 因此採預設 `react()`(streaming),每個 island 由 `<ChakraProvider value={system}>` 包裹。
|
||
- 禁止使用 `client:only`(會失去 SEO)。
|
||
4. **Admin 沿用 Astro SSR 表單**(POST `formData`),不引入 React/Chakra,降低複雜度。
|
||
|
||
---
|
||
|
||
## 3. 資料庫設計 (Drizzle / D1)
|
||
|
||
### 3.1 `posts`(現有,擴充)
|
||
|
||
| 欄位 | 型別 | 說明 |
|
||
|---|---|---|
|
||
| `id` | text PK | UUID |
|
||
| `slug` | text unique | |
|
||
| `title` | text | |
|
||
| `excerpt` | text | |
|
||
| `content` | text | Markdown |
|
||
| `meta_description` | text | |
|
||
| `cover_image` | text | **新增**,封面圖 URL |
|
||
| `tags` | text | **新增**,逗號分隔(可選) |
|
||
| `status` | text | `draft` \| `published` |
|
||
| `published_at` | integer (timestamp_ms) | |
|
||
| `updated_at` | integer (timestamp_ms) | |
|
||
|
||
### 3.2 `site_settings`(新增,單例 key-value)
|
||
|
||
| 欄位 | 型別 | 說明 |
|
||
|---|---|---|
|
||
| `key` | text PK | 設定名稱 |
|
||
| `value` | text | 值(複雜值以 JSON 字串存放) |
|
||
| `updated_at` | integer (timestamp_ms) | |
|
||
|
||
種子 keys:
|
||
- 公司:`company_name`, `company_short_name`, `license_no`, `phone`, `whatsapp`, `email`, `address`, `facebook_url`
|
||
- Hero:`hero_eyebrow`, `hero_title`, `hero_subtitle`, `hero_primary_cta`, `hero_secondary_cta`, `hero_image`
|
||
- SEO:`seo_default_title`, `seo_default_description`, `og_image`
|
||
- 信任列:`trust_stats`(JSON 陣列)
|
||
|
||
### 3.3 `content_items`(新增,重複內容)
|
||
|
||
| 欄位 | 型別 | 說明 |
|
||
|---|---|---|
|
||
| `id` | text PK | UUID |
|
||
| `kind` | text | `service` \| `feature` \| `step` \| `faq` |
|
||
| `title` | text | 服務名 / 特色名 / 步驟名 / 問題 |
|
||
| `description` | text | 描述 / 答案 |
|
||
| `extra` | text | 可選(icon 名、步驟編號等) |
|
||
| `sort_order` | integer | 排序 |
|
||
| `status` | text | `draft` \| `published` |
|
||
| `updated_at` | integer (timestamp_ms) | |
|
||
|
||
- `service`:首頁服務卡(村屋太陽能相關)
|
||
- `feature`:為何揀我哋
|
||
- `step`:專業安裝流程(extra 放 `01`–`05`)
|
||
- `faq`:常見問題
|
||
|
||
### 3.4 `cases`(新增,完成案例)
|
||
|
||
| 欄位 | 型別 | 說明 |
|
||
|---|---|---|
|
||
| `id` | text PK | UUID |
|
||
| `title` | text | 例:大埔上碗窯 - 雙玻光伏板 航空鋁支架 |
|
||
| `location` | text | 例:大埔半山 |
|
||
| `completed_at` | text | 例:2026年2月 |
|
||
| `description` | text | |
|
||
| `image_url` | text | 佔位圖 URL |
|
||
| `sort_order` | integer | |
|
||
| `status` | text | `draft` \| `published` |
|
||
| `updated_at` | integer (timestamp_ms) | |
|
||
|
||
索引:`content_items(kind, status, sort_order)`、`cases(status, sort_order)`、`posts(status, published_at)`。
|
||
|
||
---
|
||
|
||
## 4. 路由與頁面
|
||
|
||
| 路徑 | 渲染 | 內容 |
|
||
|---|---|---|
|
||
| `/` | SSR | 一頁式官網 |
|
||
| `/blog` | SSR | 文章卡片列表 |
|
||
| `/blog/[slug]` | SSR | 文章頁(Markdown) |
|
||
| `/admin` | SSR | 儀表板:文章列表 + 內容管理入口 |
|
||
| `/admin/login` | SSR | 登入 |
|
||
| `/admin/logout` | SSR | 登出 |
|
||
| `/admin/post/[id]` | SSR | 新增/編輯文章 |
|
||
| `/admin/settings` | SSR | 公司 / 聯絡 / Hero / SEO 設定 |
|
||
| `/admin/content/[kind]` | SSR | 通用編輯器(service/feature/step/faq) |
|
||
| `/admin/cases` | SSR | 案例列表 |
|
||
| `/admin/cases/[id]` | SSR | 新增/編輯案例 |
|
||
| `/sitemap.xml` | SSR | 動態 |
|
||
| `/robots.txt` | 靜態 | |
|
||
|
||
### 4.1 首頁 section 順序
|
||
|
||
1. **Header**(sticky,玻璃感):Logo/公司名、錨點導覽(服務、案例、流程、常見問題、Blog)、WhatsApp CTA;手機版 hamburger drawer
|
||
2. **Hero**:眉題、主標題、副標、雙 CTA、主視覺圖、信任子彈點
|
||
3. **信任列**:電業承辦商牌照號、服務年資/案例數、客戶口碑
|
||
4. **服務**(村屋為主,3–4 卡)
|
||
5. **為何揀我哋**(feature,6 卡)
|
||
6. **專業安裝流程**(5 步 timeline)
|
||
7. **完成案例**(案例卡 + 圖)
|
||
8. **FAQ**(accordion)
|
||
9. **聯絡 CTA**:電話 / WhatsApp / Email / 地址
|
||
10. **Footer**
|
||
11. **浮動 WhatsApp 掣**
|
||
|
||
### 4.2 Blog
|
||
|
||
- 列表:卡片(封面圖、標題、摘要、日期),空狀態
|
||
- 文章頁:封面、標題、日期、Markdown prose、返回連結、SEO/OG
|
||
|
||
---
|
||
|
||
## 5. 設計系統(Chakra theme)
|
||
|
||
> **已過時**:2026-09-11 前台改為 editorial 極簡風(暖米白+琥珀金+明體標題),以 `2026-09-11-editorial-redesign-design.md` 為準。以下保留作歷史記錄。
|
||
|
||
檔案:`src/theme/system.ts`,用 `createSystem(defaultConfig, defineConfig(...))`。
|
||
|
||
### 色彩(清新天藍/綠色系)
|
||
|
||
| Token | 值 | 用途 |
|
||
|---|---|---|
|
||
| `brand`(主,綠) | `#0B8A5E` 為主,配 50–900 色階 | 主 CTA、標題點綴、標籤 |
|
||
| `sky`(副,天藍) | `#0BA5EC` / `#38BDF8` | 圖示、裝飾、漸層 |
|
||
| `bg` 頁面 | `#FFFFFF` | 主背景 |
|
||
| `bg.subtle` | `#F2F8F6` | 分段背景 |
|
||
| `fg` | `#0F1E1A` | 正文 |
|
||
| `fg.muted` | `#5B6B66` | 次要文字 |
|
||
| `border` | `#E2EDE9` | 卡片描邊 |
|
||
|
||
- 漸層:天藍 → 青綠(Hero 裝飾光暈)
|
||
- 語意 tokens:`bg`, `fg`, `border`, `brand.solid`, `brand.contrast`, `brand.muted`
|
||
|
||
### 字體
|
||
|
||
- `Noto Sans HK`(fallback:`PingFang HK`, system sans)
|
||
- 標題:700/800,負字距;內文:400/500,行高 1.75
|
||
|
||
### 形狀與動效
|
||
|
||
- 卡片:白底、圓角 `2xl`(16–24px)、柔和陰影、細描邊
|
||
- 按鈕:`brand.solid` 圓角、hover 微加深
|
||
- 動效:捲動淡入/上移,用 CSS + IntersectionObserver,不引入 framer-motion
|
||
|
||
### 圖像
|
||
|
||
- 全部先用高質佔位/AI 生成圖,經 `img` URL 提供
|
||
- 之後可經後台換成真實工程相
|
||
|
||
---
|
||
|
||
## 6. Admin 功能
|
||
|
||
- 沿用 Astro SSR 表單 + HMAC cookie;共用設計 token 的 CSS,令後台風格與前台一致
|
||
- **文章**:列表 / 新增 / 編輯 / 發布 / 刪除(現有,加封面圖欄)
|
||
- **設定** `/admin/settings`:公司資料、聯絡、Hero 文案、SEO 預設(分組表單)
|
||
- **內容** `/admin/content/[kind]`:通用編輯器,支援新增/編輯/刪除/上下排序;以 `kind` 切換 service/feature/step/faq
|
||
- **案例** `/admin/cases`:列表 + 編輯(含圖片 URL、地點、日期)
|
||
|
||
### 內容更新即時生效
|
||
|
||
- Admin 儲存 → 首頁 SSR 讀 D1(最長 60 秒邊緣快取後更新)
|
||
- (可選)儲存時 bump `CACHE` 內的 `content_version`,於 SSR 檢查以提早失效
|
||
|
||
---
|
||
|
||
## 7. SEO / 效能
|
||
|
||
- 沿用 `Base.astro` 的 canonical / OG / Twitter card;補上 `cover_image` 作 `og:image`
|
||
- `sitemap.xml` 加入 `/`、`/blog`、各文章
|
||
- `robots.txt` disallow `/admin`
|
||
- 首頁 SSR + s-maxage 邊緣快取
|
||
- 圖片 lazy load、`loading="lazy"`、尺寸標註
|
||
- 目標:Lighthouse SEO/Performance/Accessibility 良好
|
||
|
||
---
|
||
|
||
## 8. 部署(Cloudflare)
|
||
|
||
```bash
|
||
npx astro add react
|
||
npm i @chakra-ui/react @emotion/react
|
||
|
||
npx wrangler d1 create yingfung-solar-db # 將 database_id 填入 wrangler.jsonc
|
||
npx wrangler kv namespace create CACHE # 將 id 填入 wrangler.jsonc
|
||
npm run db:generate
|
||
npm run db:migrate # 雲端
|
||
npm run db:migrate:local # 本機
|
||
npx wrangler secret put ADMIN_PASSWORD
|
||
|
||
# 更新 astro.config.mjs site、src/config.ts、wrangler.jsonc vars
|
||
npm run deploy
|
||
```
|
||
|
||
- 需更新 `wrangler.jsonc` 的 `name`、`vars.SITE_NAME` 為盈豐太陽能
|
||
- `astro.config.mjs` 的 `site` 待客戶提供真域名
|
||
|
||
---
|
||
|
||
## 9. 分階段實作
|
||
|
||
1. **基建**:加 React + Chakra + Provider、theme、換 Base layout、驗證 SSR 樣式
|
||
2. **首頁 UI**:全部 section 組件(先佔位內容)
|
||
3. **資料層**:schema 擴充 + migration + seed(公司資料 + 樣本內容)
|
||
4. **Blog UI**:列表 + 文章頁翻新
|
||
5. **Admin**:settings / content items / cases 編輯器
|
||
6. **SEO / 效能**:sitemap、快取、Lighthouse
|
||
7. **部署**:D1/KV/secret、上線
|
||
|
||
---
|
||
|
||
## 10. 風險與對策
|
||
|
||
| 風險 | 對策 |
|
||
|---|---|
|
||
| Chakra v3 + Astro SSR 樣式注入 | **已實測通過**(見 §2.3);Astro 7 + React 19 + Chakra 3.37 無 hydration error |
|
||
| Astro 7 與 `@astrojs/react` / React 19 版本相容 | 用 `npx astro add react` 自動配對版本 |
|
||
| 多個 island 造成 Provider 重複 | 每頁只一個 React root island |
|
||
| 佔位圖版權 | 使用可商用來源或 AI 生成 |
|
||
| 接觸點資訊未齊 | 全部放 `site_settings`,客戶可於後台自行更新 |
|
||
|
||
---
|
||
|
||
## 11. 待客戶提供
|
||
|
||
- 真實電話 / WhatsApp 號碼
|
||
- 聯絡 Email
|
||
- 辦公地址
|
||
- 電業承辦商牌照號碼
|
||
- 真域名
|
||
- 真實工程相片(可後補)
|