歡迎來到第二週!
第一週我們完成了《喵語日誌》的 AI 基礎建設,包含貓咪 Persona、情緒分析、JSON Schema,以及 Gemini API 串接。
從今天開始,終於要把注意力放回使用者看得到的地方:前端介面。
今天正式進入 Vibe Coding 模式。簡單來說,Vibe Coding 就是先用自然語言描述產品需求,再請 AI 協助產生元件、樣式和互動邏輯,而不是一開始就自己手寫每一行 HTML 與 CSS。
這時候我們的角色,也會從逐行輸入程式碼的人,變成比較像產品指揮官:
今天的目標,就是把 Day 07 的對話頁 Wireframe,轉換成真正可以執行的 React + Tailwind CSS 對話視窗。
這次我使用 v0.dev 協助產生前端 UI,也可以使用其他 AI Code Assistant 來完成類似工作。
Prompt 的重點不是只說「幫我做一個漂亮的聊天視窗」,而是要把畫面需求拆清楚,讓 AI 知道需要哪些區域、資料和互動。
我使用的 Prompt 如下:
請幫我使用 React、TypeScript 與 Tailwind CSS,
建立一個貓咪主題的聊天對話視窗元件 ChatContainer.tsx。
這是一個名為《喵語日誌》的生活陪伴應用程式,
請使用溫暖、療癒、柔和的粉色系視覺風格。
畫面需要包含以下 4 個區域:
1. 頂部 Header
- 顯示圓形貓咪頭像,頭像中央顯示「喵」
- 顯示貓咪名稱「喵喵」
- 顯示綠色線上狀態燈
- 線上狀態燈加入簡單的脈動動畫
2. 對話訊息區
- 顯示使用者與喵喵的歷史訊息
- 使用者訊息靠右顯示,使用灰色背景
- 喵喵回應靠左顯示,搭配貓咪頭像與淡粉色背景
- 對話區可以垂直捲動
3. 情緒選擇器
- 在輸入框上方放置 5 個情緒按鈕
- 選項從 Rough 到 Great
- 使用者點擊後,按鈕需要顯示選取狀態
4. 底部輸入區
- 包含文字輸入框
- 右側放置圓形送出按鈕
- 送出按鈕使用 Send 圖示
- 輸入框與按鈕要適合手機畫面
這次的 Prompt 裡,我特別補充了「元件名稱」、「技術框架」、「畫面區塊」、「配色方向」和「互動需求」。
這些資訊越清楚,AI 產生的第一版結果通常就越接近我們想要的樣子。
AI 很快就產生了第一版元件。不過,Vibe Coding 並不是按下生成按鈕後就完全不用修改。
比較貼近實際的流程是:
描述需求
↓
AI 產生第一版
↓
放進自己的專案測試
↓
發現問題
↓
用自然語言要求 AI 修改
↓
再次測試
這次整合過程中,我遇到兩個比較典型的問題。
AI 產生的程式碼有時會預設使用 Next.js,因此可能看到:
"use client";
或是一些專屬於 Next.js 的元件和全域 CSS 變數。
但目前的專案是 Vite + React,所以我需要把不適用的部分移除,並改成目前專案可以直接使用的形式。
例如:
"use client"
App.tsx 中正常使用如果想使用送出圖示,可以安裝 lucide-react:
npm install lucide-react
Lucide 官方也提供 React 專用套件,可以直接匯入 Send 等圖示元件。
剛把程式碼貼進專案時,畫面雖然可以顯示,但 Tailwind 的樣式完全沒有套用。
檢查後發現,是 Tailwind CSS 還沒有正確整合到 Vite。
如果使用 Tailwind CSS v4,可以安裝官方 Vite 插件:
npm install tailwindcss @tailwindcss/vite
接著在 vite.config.ts 中加入:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [react(), tailwindcss()],
});
再到主要 CSS 檔案,例如 src/index.css,加入:
@import "tailwindcss";
這是 Tailwind 官方目前提供的 Vite 整合方式。
修改完成後重新啟動開發伺服器:
npm run dev
這時候圓角、陰影、背景色和間距就會正常顯示了。
排版與樣式修復完成後,對話視窗的畫面就正式呈現出來了!接下來整理一下最終的組件程式碼。
以下是整理後的對話視窗元件結構:
import { useState } from "react";
import { Send } from "lucide-react";
const MOODS = ["Rough", "Low", "Okay", "Good", "Great"];
export default function ChatContainer() {
const [messages, setMessages] = useState(INITIAL_MESSAGES);
const [input, setInput] = useState("");
const [mood, setMood] = useState<string | null>(null);
// 表單送出處理(先完成前端狀態互動)
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
if (!input.trim()) return;
setMessages((prev) => [
...prev,
{ id: Date.now(), role: "user", content: input },
]);
setInput("");
}
return (
<div className="mx-auto flex h-[600px] w-full max-w-md flex-col overflow-hidden rounded-3xl border border-pink-100 bg-white shadow-xl">
{/* 1. 頂部 Header:貓咪頭像與線上狀態動畫 */}
<header className="flex items-center gap-3 border-b border-pink-100 bg-pink-50/60 px-4 py-3">
<div className="flex h-11 w-11 items-center justify-center rounded-full bg-pink-200 text-xl">🐱</div>
<div>
<p className="font-semibold text-gray-800">喵喵</p>
<p className="flex items-center gap-1.5 text-xs text-gray-500">
<span className="h-2 w-2 animate-pulse rounded-full bg-green-500" /> 線上陪伴中
</p>
</div>
</header>
{/* 2. 對話訊息區:區分使用者(灰色靠右)與喵喵(粉色靠左) */}
<div className="flex-1 space-y-3 overflow-y-auto bg-gray-50/40 p-4">
{messages.map((msg) => (
<div
key={msg.id}
className={
msg.role === "user"
? "ml-auto max-w-[80%] rounded-2xl rounded-br-md bg-gray-200 px-4 py-3 text-sm text-gray-700"
: "mr-auto max-w-[80%] rounded-2xl rounded-bl-md bg-pink-100 px-4 py-3 text-sm text-gray-700"
}
>
{msg.content}
</div>
))}
</div>
{/* 3. 情緒選擇器 & 4. 底部輸入欄 */}
<div className="border-t border-pink-100 p-3">
{/* 情緒按鈕列表 */}
<div className="mb-3 flex gap-2 overflow-x-auto">
{MOODS.map((item) => (
<button
key={item}
onClick={() => setMood(item)}
className={`rounded-full border px-3 py-1 text-xs transition ${
mood === item ? "border-pink-500 bg-pink-500 text-white" : "border-pink-200 bg-white text-pink-600 hover:bg-pink-50"
}`}
>
{item}
</button>
))}
</div>
{/* 輸入框與 Send 圖示按鈕 */}
<form onSubmit={handleSubmit} className="flex items-center gap-2">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="跟喵喵說說今天的事..."
className="min-w-0 flex-1 rounded-full border border-pink-200 px-4 py-2 text-sm outline-none focus:border-pink-400"
/>
<button
type="submit"
disabled={!input.trim()}
className="rounded-full bg-pink-500 p-3 text-white transition hover:bg-pink-600 disabled:opacity-50"
>
<Send className="h-4 w-4" />
</button>
</form>
</div>
</div>
);
}
這段程式碼目前先完成前端互動原型:
目前送出後還沒有接回 Gemini API,這部分會在後續文章中整合。今天先把看得見、按得到、操作起來像一個聊天介面完成。
如果只下「幫我做一個貓咪聊天視窗」,AI 產出的風格會很隨機。這次直接指定 React + Tailwind CSS、粉色系主題、頂部狀態燈、對話框排版與 5 種情緒按鈕,第一版就呈現出高達 90% 的完整度,省去大量來回修正的時間。
Vibe Coding 不代表能無腦複製貼上。AI 常會帶入目前專案未安裝的套件(如 lucide-react)或 Next.js 專用語法(如 "use client")。因此我們仍需具備閱讀程式碼與 Debug 的能力,引導 AI 根據 Vite 專案環境進行精準微調。
過去要花半天手刻的 Flexbox 排版、圓角陰影與按鈕 Hover 狀態,現在幾分鐘內就能完成視覺原型。這讓我們能從繁瑣的 CSS 中解脫,把精力集中在真正重要的事——優化使用者體驗、情緒選擇互動與 Gemini API 的資料呈現。
今天我們正式解鎖 Vibe Coding 模式!透過精準 Prompt,成功打造出具備粉紅主題、訊息氣泡與情緒選擇器的《喵語日誌》對話視窗。這段實作證明:AI 能極速完成 UI 原型開發,但關鍵仍在於開發者清晰的需求描述與專案整合能力。
明天我們將為這個介面注入生命力!預計加入AI 打字中/喵喵思考中的加載效果與對話氣泡浮現動畫,並分享如何透過 CSS 動畫與溫暖舒壓的色彩計畫,大幅提升介面的親和力與療癒感!喵~