從今天開始,我們正式邁入階段三:前端開發與 UI/UX 實作。
要讓產品擺脫「工程師審美」的黑白雜亂感,第一步不是直接刻頁面,而是打造一套統一且好擴充的 Design System(設計系統)。今天我們要運用 AI,快速結合 Tailwind CSS 與 shadcn/ui,設定好主題色系、字型與基礎 UI 組件庫!
傳統做法下,光是設定 CSS 變數、安裝 component library、微調暗黑模式(Dark Mode)與設計規範就要花上大半天。現在有了 AI,我們可以 command 它是「設計師 + 前端架構師」。
我們需要 AI 幫我們在 Next.js / React 專案中配置 shadcn/ui 的 CSS 變數,並建立一個具備「金融感(Financial Style)」的主題色系(以深翡翠綠/石墨灰為主色)。
你現在是一位資深 UI/UX 與前端工程師。請幫我為專案建立 Design System。
需求如下:
1. 使用 Tailwind CSS (v3/v4) 與 shadcn/ui。
2. 在 `globals.css` 中設定 CSS 變數,風格需為「現代高級金融風 (Modern Dark-friendly Finance Theme)」:
- 主色 (Primary):高質感翡翠綠 (Emerald Green)
- 背景色 (Background):柔和灰白 (Light Mode) / 深石墨灰 (Dark Mode)
- 輔助色 (Accent):暖金/橙黃(用於突顯重要財務提醒)
3. 封裝一個元件範例 `<FinancialStatCard />`:
- 包含標題、金額數字、漲跌幅 Badge、以及可選的 Icon。
- 套用 shadcn/ui 的 Card、Badge 元件與 Tailwind Class。
AI 給出了 CSS 變數與組件寫法:
// components/FinancialStatCard.tsx
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { ArrowUpIcon, ArrowDownIcon } from "lucide-react"
interface StatCardProps {
title: string
amount: number
changePercentage: number
}
export function FinancialStatCard({ title, amount, changePercentage }: StatCardProps) {
const isPositive = changePercentage >= 0
return (
<Card className="bg-card text-card-foreground shadow-sm">
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium text-muted-foreground">
{title}
</CardTitle>
<Badge variant={isPositive ? "default" : "destructive"}>
{isPositive ? <ArrowUpIcon className="h-4 w-4 mr-1" /> : <ArrowDownIcon className="h-4 w-4 mr-1" />}
{Math.abs(changePercentage)}%
</Badge>
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">${amount.toLocaleString()}</div>
</CardContent>
</Card>
)
}
這段產出看起來有模有樣,但一渲染在畫面上,立刻遇到了兩個經典的 Vibe Coding 踩坑點!
AI 在寫條件式 Class 時,使用了字串拼接:className={"text-2xl font-bold " + (isPositive ? "text-emerald-600" : "text-rose-600")}
這經常會因為 Tailwind 類名優先級沖突而導致樣式失效。此外,Formatting 金額(amount.toLocaleString())在 SSR(伺服器端渲染)與 CSR(用戶端渲染)時,若語系不一致會引發 Next.js 的 Hydration Mismatch Error!
AI 將漲跌幅 Badge 直接套用 variant="default"(預設主色)與 variant="destructive"(紅/警告色)。但我們的 Primary 是綠色,如果上漲用 default,跌落用 destructive,當主題切換成暗色模式時,綠色層級會跟背景文字嚴重撞色,對比度不足!
我們引導 AI 進行調整與優化:
clsx + tailwind-merge (cn 工具函式),規範所有動態 Class 名稱。'zh-TW' / 'USD'。修正後的程式碼:
import { cn } from "@/lib/utils" // 引入 cn 工具函式
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Badge } from "@/components/ui/badge"
import { TrendingUp, TrendingDown } from "lucide-react"
interface StatCardProps {
title: string
amount: number
changePercentage: number
currency?: string
}
export function FinancialStatCard({ title, amount, changePercentage, currency = 'NT$' }: StatCardProps) {
const isPositive = changePercentage >= 0
return (
<Card className="border-border/60 bg-background/95 backdrop-blur-sm shadow-md transition-all hover:shadow-lg">
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
{title}
</CardTitle>
<Badge
className={cn(
"font-mono text-xs flex items-center gap-0.5 px-2 py-0.5",
isPositive
? "bg-emerald-500/15 text-emerald-600 dark:text-emerald-400 border-emerald-500/20"
: "bg-rose-500/15 text-rose-600 dark:text-rose-400 border-rose-500/20"
)}
variant="outline"
>
{isPositive ? <TrendingUp className="h-3 w-3" /> : <TrendingDown className="h-3 w-3" />}
{isPositive ? '+' : ''}{changePercentage}%
</Badge>
</CardHeader>
<CardContent>
<div className="text-3xl font-extrabold tracking-tight font-mono">
<span className="text-sm font-normal text-muted-foreground mr-1">{currency}</span>
{amount.toLocaleString('zh-TW')}
</div>
</CardContent>
</Card>
)
}
globals.css 中用 HSL(或新版 OKLCH)定義 CSS 變數,並在 tailwind.config.js 引用。理解這個對接原理,比純粹叫 AI 「生成 UI」重要百倍!cn())建立可維護的系統。統一的 UI 視覺風格與基礎組件庫已經建立完成!明天 Day 13,我們將指示 AI 打造 App 的核心響應式 Layout 與 Navigation 側邊欄,正式呈現應用程式的大骨架!