Ocean Keep Diving
透過與店家討論網站所需頁面、資訊架構與視覺風格,由我獨立完成資料彙整、路由規劃、UI 設計、網站開發、部署、網域設定、多國語言支援、SEO 優化、以及內容管理系統(CMS)的導入。
網站內容涵蓋潛水課程、教練介紹、價目資訊、活動行程與聯絡方式,並以可維護、可持續擴充為主要設計方向。
線上網址
技術棧
Next.js, React, Tailwind CSS, DaisyUI, Sanity, next-intl, Docker, Nginx, DigitalOcean, Cloudflare
內容管理系統(CMS)選擇
除了不常變動的固定內容,店家也希望能有寫文章、放文章的空間,而儘管資料結構整理的很好維護,能快速新增或是更新資料,但如果每次更動都需要開發者修改程式重新部署,會增加更多維護成本。
因此決定導入 Headless CMS,與我個人網站使用的 Strapi 不同,這次選擇的是 Sanity,主要是基於成本考量,另一方面也想藉此機會試試看別的系統。
Sanity 可以很簡單的修改 config,然後部署 studio 在他們的網頁上,店家只要在網頁上編輯文件,就可以馬上反應到店家官網。
Sanity 的 API query 會用到他們自家寫的 GROQ(Graph-Relational Object Queries)語法。GROQ 可以直接依照文件類型、欄位條件與排序規則篩選資料,並只回傳頁面實際需要的欄位。
範例:
const POSTS_QUERY = defineQuery(`*[
_type == "post"
&& defined(slug.current)
]|order(publishedAt desc)[0...24]{
_id,
title,
category,
slug,
publishedAt,
excerpt,
image
}`);
這段查詢會取得具有有效 slug 的文章,按照發布日期由新到舊排序,限制最多回傳 24 筆資料,並只選取文章列表所需的欄位。
網站架構
網站使用 Next.js 建立,並依照課程、教練、行事曆、文章及其他內容規劃路由。
共用的畫面區塊會拆分為可重複使用的 React 元件,內容則以結構化資料控制。新增相似頁面或調整網站資訊時,可以沿用既有元件與資料格式,避免重複實作相同的版面。
Next.js 也能在路由、Metadata 與伺服器端內容取得方面提供整合,使不同頁面可以根據實際內容產生對應的標題、描述與網址資訊。
多國語言
網站使用 next-intl 實作繁體中文、英文與日文版本,並根據語言建立對應路由。
導覽列、按鈕、頁面文字及 Metadata 等內容皆能依照目前語系顯示,使不同語言版本保持一致的網站結構與使用體驗。
SEO 優化
網站針對搜尋引擎收錄與分享預覽進行以下設定:
- 各頁面專屬的標題與描述
- Open Graph Metadata
- Canonical URL
- Sitemap
- Robots 設定
- 語意化 HTML 結構
- 多國語言頁面對應
- 圖片替代文字
- HTTP 重新導向至 HTTPS
部署與網域設定
網站以 Docker 建立部署環境,部署於 DigitalOcean,並使用 Nginx 作為反向代理伺服器。
Cloudflare 負責 DNS、HTTPS 與流量代理,另外完成裸網域、www 網域與 HTTP/HTTPS 之間的重新導向設定,確保使用者透過不同網址進入時,都會導向正確且安全的網站版本。
專案成果
這個專案從店家的實際需求出發,完整處理內容整理、資訊架構、設計、開發、部署與後續維護方式。
透過可重用元件、結構化資料與 CMS,網站能在維持一致視覺風格的同時,讓內容持續更新與擴充,降低店家未來維護網站的成本。