Next.js 16 全棧實戰(二):引入 Shadcn UI 與構建 Dashboard 佈局

作者:低代碼佈道師
日期:2026年2月8日 上午12:01
來源:WeChat 原文

整理版優先睇

速讀 5 個重點 高亮

Shadcn UI 同 Vibe Coding 快速整好 Dashboard 佈局,跟住用 AI 微調 UI 細節。

整理版摘要

呢篇文章係 Next.js 16 全棧實戰系列第二篇,作者承接上一篇用 Trae 初始化嘅基礎,逐步教讀者點樣引入 Shadcn UI 呢個 React 組件庫,同埋規劃 App Router 嘅目錄結構。作者想解決嘅問題係:好多開發者慣用 Ant Design 呢類黑盒庫,想改樣式或者行為時好麻煩;而 Shadcn UI 係一個代碼生成器,可以畀你完全掌控組件源碼。整體結論係成功建立咗一個經典嘅左側固定側邊欄加右側內容自適應嘅 Dashboard 佈局,而且示範咗用 Trae 嘅 Vibe Coding 功能,透過自然語言提示詞快速調整 UI,例如加選中效果同調整 Logo 高度,提升開發效率。

實戰部分由安裝 Shadcn UI 開始,揀咗 Zinc 中性灰做主色,配合 Lucide React 圖標庫。然後規劃目錄:app/ui 放組件、app/lib 放工具函數、app/dashboard 放業務頁面。跟住手寫代碼,首先整 SideNav 組件,用 Link 實現無刷新跳轉;再透過 layout.tsx 共享佈局,令側邊欄喺頁面切換時保持狀態;最後建立工作台頁面,顯示模擬數據卡片。成個佈局用 Tailwind 嘅 md: 前綴實現響應式,移動端側邊欄會變頂部導航。

最後作者用 Trae 嘅「選中元素」功能,直接對 UI 元素落提示詞,例如「工作台增加一個選中效果」,AI 就自動改好代碼,再經代碼審查確認後接受…

  • Shadcn UI 嘅核心賣點係代碼生成器,唔係黑盒庫,開發者有 100% 控制權,可以隨意改組件原始碼。
  • 用 npx shadcn@latest init 初始化,揀 Zinc 中性灰色主題,然後裝 lucide-react 做圖標庫。
  • 目錄結構要分明:app/ui 放 UI 組件、app/lib 放工具函數、app/dashboard 放業務頁面,方便後期擴展。
  • 實戰用 Link 組件同 Tailwind 嘅 md: 前綴,整出左側固定、右邊自適應嘅 Dashboard 佈局,移動端會自動轉頂部導航。
  • 透過 Trae 嘅「選中元素」功能,直接用自然語言提示(例如「工作台增加選中效果」),AI 會自動改好代碼,經審查後接受修改。
整理重點

點解揀 Shadcn UI?

好多初學者習慣用 Ant Design 或者 Material UI,但呢啲庫係 npm 安裝嘅黑盒,想改樣式或者行為時要繞好多彎路。Shadcn UI 唔同,佢係一個代碼生成器,你執行命令之後,佢會將組件嘅源碼直接「複製」入你個項目度,咁你就可以隨意修改,擁有 100% 嘅控制權。

Shadcn UI 唔係 npm 套件,而係一組可以直接改原始碼嘅組件

整理重點

目錄結構規劃

喺 Next.js 16 App Router 入面,檔案放邊度好講究。為咗令項目後期唔會亂,最好一開始就起好「房間」:app/ui 專門放 UI 組件(側邊欄、卡片等),app/lib 放數據定義同工具函數,app/dashboard 放核心業務頁面——呢個文件夾底下嘅 page.tsx 只有登錄後先可以訪問。

用 app/ui、app/lib、app/dashboard 劃分職責,日後加功能就唔會亂

整理重點

實戰搭建 Dashboard 佈局

目標係整一個經典嘅「左側固定側邊欄 + 右側內容自適應」佈局。首先建立 app/ui/dashboard/sidenav.tsx,用 Next.js 嘅 <Link> 組件實現無刷新跳轉,再用 Tailwind 寫樣式。

側邊欄組件 (Sidenav) tsx
import Link from 'next/link';
import { LayoutDashboard, Building2, Users, ShieldCheck, Menu, GraduationCap, LogOut } from 'lucide-react';

const links = [
 { name: '工作台', href: '/dashboard', icon: LayoutDashboard },
 { name: '機構管理', href: '/dashboard/dept', icon: Building2 },
 { name: '人員管理', href: '/dashboard/user', icon: Users },
 { name: '角色管理', href: '/dashboard/role', icon: ShieldCheck },
 { name: '菜單配置', href: '/dashboard/menu', icon: Menu },
];

export default function SideNav() {
 return (
 <div className="flex h-full flex-col px-3 py-4 md:px-2">
 <Link className="mb-2 flex h-20 items-end justify-start rounded-md bg-zinc-900 p-4 md:h-40" href="/">
 <div className="w-32 text-white md:w-40 flex items-center gap-2">
 <GraduationCap className="h-8 w-8" />
 <span className="text-lg font-bold">教培管家</span>
 </div>
 </Link>
 <div className="flex grow flex-row justify-between space-x-2 md:flex-col md:space-x-0 md:space-y-2">
 {links.map((link) => {
 const LinkIcon = link.icon;
 return (
 <Link key={link.name} href={link.href}
 className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3">
 <LinkIcon className="w-6" />
 <p className="hidden md:block">{link.name}</p>
 </Link>
 );
 })}
 <div className="hidden h-auto w-full grow rounded-md bg-gray-50 md:block"></div>
 <form>
 <button className="flex h-[48px] w-full grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3">
 <LogOut className="w-6" />
 <div className="hidden md:block">退出登錄</div>
 </button>
 </form>
 </div>
 </div>
 );
}

跟住建立 app/dashboard/layout.tsx,用 Next.js 嘅 layout 特性共享側邊欄,切換頁面時側邊欄唔會重新渲染。

Dashboard 佈局檔案 (Layout) tsx
import SideNav from '@/app/ui/dashboard/sidenav';

export default function Layout({ children }: { children: React.ReactNode }) {
 return (
 <div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
 <div className="w-full flex-none md:w-64 bg-white border-r">
 <SideNav />
 </div>
 <div className="flex-grow p-6 md:overflow-y-auto md:p-12 bg-gray-50">
 {children}
 </div>
 </div>
 );
}

用 layout.tsx 包住側邊欄,頁面切換時側邊欄保持狀態,唔使重新加載

最後整一個簡單嘅工作台頁面 app/dashboard/page.tsx,放一啲模擬數據卡片,用嚟驗證佈局效果。

工作台頁面 tsx
export default function Page() {
 return (
 <div>
 <h1 className="text-2xl font-bold mb-4">工作台 Dashboard</h1>
 <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
 <div className="h-32 rounded-xl bg-white p-4 shadow-sm border border-gray-100">
 <p className="text-sm text-gray-500">總學員數</p>
 <p className="text-2xl font-bold">1,203</p>
 </div>
 <div className="h-32 rounded-xl bg-white p-4 shadow-sm border border-gray-100">
 <p className="text-sm text-gray-500">本月營收</p>
 <p className="text-2xl font-bold">¥ 45,231</p>
 </div>
 </div>
 </div>
 );
}
整理重點

Vibe Coding 調整 UI

默認生成嘅 UI 未必合心水,可以用 Trae 嘅「選中元素」功能來 vibe coding。喺 Trae 打開頁面,用選中元素點擊左側工作台菜單,右邊對話框會見到對應嘅 a 標籤,輸入提示詞「工作台增加一個選中效果」,AI 就會自動幫你修改代碼。

直接對 UI 元素講「工作台增加一個選中效果」,AI 就識幫你改好

改完之後點擊代碼審查,確認冇問題就接受修改。同樣方法,如果覺得 Logo 太高,只要講「調整到合適嘅高度」,AI 又會幫你搞掂。作者話:大模型多模態能力配合選中元素功能,只要你表達清楚意圖,就可以又好又快咁實現功能。

回顧之前嘅內容

喺上一篇,我哋用 Trae 成功初始化咗 Next.js 16 + Tailwind CSS 嘅項目環境,仲配置好 PostgreSQL 數據庫連接。

今篇目標:

  1. 安裝同配置 Shadcn UI(目前 React 生態最流行嘅組件庫)。
  2. 梳理 Next.js App Router 嘅文件目錄結構
  3. 手寫代碼:實現響應式嘅 側邊欄 (Sidebar) 和 Dashboard 佈局

1. 點解揀 Shadcn UI?

好多初學者習慣用 Ant Design 或 Material UI。但係 Shadcn UI 唔同,佢唔係一個透過 npm 安裝嘅黑盒庫,而係一個代碼生成器

當你行命令嗰陣,佢會將組件嘅源碼直接「複製」去你嘅項目度。

  • 優點
    你可以隨便修改組件代碼,擁有 100% 嘅控制權。
  • 風格
    極簡、現代,完美配合 Tailwind CSS。

1.1 初始化 Shadcn

打開 Trae 嘅終端,輸入:

npx shadcn@latest init

在這裏插入圖片描述

跟住以下選項進行配置(呢個係教培管家系統嘅設計風格):

Which color would you like to use as base color? › Zinc (中性灰,高級感)

在這裏插入圖片描述

初始化完成之後,你會發現項目根目錄多咗一個 components.json,且 lib/utils.ts 文件自動被創建咗(用嚟處理 CSS 類名合併)。

在這裏插入圖片描述
在這裏插入圖片描述

1.2 安裝基礎圖標庫

我哋需要一套靚嘅圖標,呢度用 Lucide React(Shadcn 官方推薦):

npminstall lucide-react

在這裏插入圖片描述

2. 目錄結構規劃

喺 Next.js 16 (App Router) 入面,文件放喺邊度好有講究。為咗保證項目後期唔亂,我哋先整好「房間」:

在 app 目錄下,創建以下文件夾:

  • app/ui
    存放所有嘅 UI 組件(側邊欄、卡片、按鈕等)。
  • app/lib
    存放數據定義、工具函數。
  • app/dashboard
    核心業務頁面(喺呢個文件夾下面嘅 page.tsx 只有登錄咗先可以訪問)。
在這裏插入圖片描述

3. 實戰:搭建 Dashboard 佈局

我哋要實現嘅係經典嘅 「左側固定側邊欄 + 右側內容自適應」 佈局。

3.1 第一步:編寫側邊欄組件 (SideNav)

新建文件 app/ui/dashboard/sidenav.tsx

我哋會用 Next.js 嘅 <Link> 組件嚟實現無刷新跳轉,用 Tailwind 實現樣式。

import Link from 'next/link';
import { 
  LayoutDashboard, 
  Building2, 
  Users, 
  ShieldCheck, 
  Menu, 
  GraduationCap, 
  LogOut 
} from 'lucide-react';

// 定義菜單數據(暫時寫死,後續會從數據庫讀取)
const links = [
  { name: '工作台', href: '/dashboard', icon: LayoutDashboard },
  { name: '機構管理', href: '/dashboard/dept', icon: Building2 },
  { name: '人員管理', href: '/dashboard/user', icon: Users },
  { name: '角色管理', href: '/dashboard/role', icon: ShieldCheck },
  { name: '菜單配置', href: '/dashboard/menu', icon: Menu },
];

export default function SideNav() {
  return (
    <div className="flex h-full flex-col px-3 py-4 md:px-2">
      {/* 1. Logo 區域 */}
      <Link
        className="mb-2 flex h-20 items-end justify-start rounded-md bg-zinc-900 p-4 md:h-40"
        href="/"
      >
        <div className="w-32 text-white md:w-40 flex items-center gap-2">
          <GraduationCap className="h-8 w-8" />
          <span className="text-lg font-bold">教培管家</span>
        </div>
      </Link>

      {/* 2. 導航連結區域 */}
      <div className="flex grow flex-row justify-between space-x-2 md:flex-col md:space-x-0 md:space-y-2">
        {links.map((link) => {
          const LinkIcon = link.icon;
          return (
            <Link
              key={link.name}
              href={link.href}
              className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
            >
              <LinkIcon className="w-6" />
              <p className="hidden md:block">{link.name}</p>
            </Link>
          );
        })}

        {/* 佔位符,把登出按鈕頂到底部 */}
        <div className="hidden h-auto w-full grow rounded-md bg-gray-50 md:block"></div>

        {/* 3. 登出按鈕 */}
        <form>
          <button className="flex h-[48px] w-full grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3">
            <LogOut className="w-6" />
            <div className="hidden md:block">退出登錄</div>
          </button>
        </form>
      </div>
    </div>
  );
}

AI 編程小技巧:
如果你唔明上面嘅 Tailwind 類名(例如 md:hidden),可以喺 Trae 嘅聊天框裏面揀中代碼問 Kimi:「解釋一下呢段代碼入面 Tailwind 類名嘅作用,特別係響應式部分。

在這裏插入圖片描述

3.2 第二步:創建佈局文件 (Layout)

Next.js 嘅 layout.tsx 係一個非常強大嘅特性。佢允許我哋喺多個頁面之間共享 UI(例如側邊欄),當頁面切換嗰陣,側邊欄唔會重新渲染,狀態會保留到。

新建文件 app/dashboard/layout.tsx

import SideNav from '@/app/ui/dashboard/sidenav';

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
      {/* 側邊欄區域:在移動端是頂部導航,在桌面端是左側固定 */}
      <div className="w-full flex-none md:w-64 bg-white border-r">
        <SideNav />
      </div>

      {/* 主內容區域:可滾動 */}
      <div className="flex-grow p-6 md:overflow-y-auto md:p-12 bg-gray-50">
        {children}
      </div>
    </div>
  );
}

在這裏插入圖片描述

3.3 第三步:創建第一個頁面

為咗驗證效果,我哋需要一個頁面。
新建 app/dashboard/page.tsx

export default function Page() {
  return (
    <div>
      <h1 className="text-2xl font-bold mb-4">工作台 Dashboard</h1>
      <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
        {/* 這裏以後放統計卡片 */}
        <div className="h-32 rounded-xl bg-white p-4 shadow-sm border border-gray-100">
           <p className="text-sm text-gray-500">總學員數</p>
           <p className="text-2xl font-bold">1,203</p>
        </div>
        <div className="h-32 rounded-xl bg-white p-4 shadow-sm border border-gray-100">
           <p className="text-sm text-gray-500">本月營收</p>
           <p className="text-2xl font-bold">¥ 45,231</p>
        </div>
      </div>
    </div>
  );
}

在這裏插入圖片描述

4. 見證奇蹟

而家,喺終端運行:

npm run dev

在這裏插入圖片描述

打開瀏覽器訪問 http://localhost:3000/dashboard

你應該會見到一個專業嘅後台管理界面:

  1. 左邊係黑色嘅 Logo 同埋灰色嘅導航菜單。
  2. 右邊係灰色嘅背景同白色嘅數據卡片。
  3. 試下縮細瀏覽器窗口,你會發現側邊欄自動變咗做頂部嘅移動端導航(呢個係 Tailwind md: 前綴嘅功勞)。
在這裏插入圖片描述

5 vibe coding

點講呢,默認生成嘅唔係幾好睇,我哋嚟 vibe coding 一下

先喺 trae 裏面打開我哋嘅頁面,然後用選中元素揀中我哋左邊嘅工作台菜單,咁樣右邊嘅對話框就可以見到一個 a 標籤,輸入提示詞

工作台增加一個選中的效果

在這裏插入圖片描述
撳發送嘅箭頭,叫 ai 幫我哋優化一下

ai 調整好咗之後,撳代碼審查,可以睇下佢幫我哋加咗啲咩
在這裏插入圖片描述
確認冇錯之後,撳剔號接受修改,再 refresh 頁面,當前工作台就會高亮顯示

在這裏插入圖片描述
再講我哋個 LOGO 有啲太高,我哋叫 AI 優化一下,同佢講調整到合適嘅高度
在這裏插入圖片描述
優化之後,睇起嚟就順眼好多
在這裏插入圖片描述
喺而家,大模型嘅多模態能力,結合 trae 嘅選中元素功能,組合埋一齊,只要你將意圖表達清楚,大模型就可以又快又好咁實現功能。

確認修改之後,我哋叫 kimi 將代碼提交去我哋嘅遠程倉庫度
在這裏插入圖片描述
有啲命令係需要我哋撳運行嘅,撳運行,一路跟住提示,就可以見到代碼被正確咁提交咗去倉庫度
在這裏插入圖片描述

下一步預告

而家嘅頁面雖然好靚,但數據係「死」嘅,菜單都係寫死嘅。

在 下一篇 入面,我哋會深入後端核心:

  1. 使用 Seed 腳本 填充數據庫(包含真實嘅部門、角色、菜單數據)。
  2. 學習點樣用 Next.js 嘅 Server Actions 從數據庫讀取數據。
  3. 令左邊菜單變成從數據庫動態加載嘅「生」菜單。

前情回顧

在上一篇中,我們使用 Trae 成功初始化了 Next.js 16 + Tailwind CSS 的項目環境,並配置好了 PostgreSQL 數據庫連接。

本篇目標:

  1. 安裝並配置 Shadcn UI(目前 React 生態最流行的組件庫)。
  2. 梳理 Next.js App Router 的文件目錄結構
  3. 手寫代碼:實現響應式的 側邊欄 (Sidebar) 和 Dashboard 佈局

1. 為什麼選擇 Shadcn UI?

很多初學者習慣用 Ant Design 或 Material UI。但 Shadcn UI 不同,它不是一個通過 npm 安裝的黑盒庫,而是一個代碼生成器

當你運行命令時,它會把組件的源碼直接“複製”到你的項目中。

  • 優點
    你可以隨意修改組件代碼,擁有 100% 的控制權。
  • 風格
    極簡、現代,完美契合 Tailwind CSS。

1.1 初始化 Shadcn

打開 Trae 的終端,輸入:

npx shadcn@latest init

在這裏插入圖片描述

按照以下選項進行配置(這是教培管家系統的設計風格):

Which color would you like to use as base color? › Zinc (中性灰,高級感)

在這裏插入圖片描述

初始化完成後,你會發現項目根目錄多了一個 components.json,且 lib/utils.ts 文件被自動創建了(用於處理 CSS 類名合併)。

在這裏插入圖片描述
在這裏插入圖片描述

1.2 安裝基礎圖標庫

我們需要一套漂亮的圖標,這裏使用 Lucide React(Shadcn 官方推薦):

npminstall lucide-react

在這裏插入圖片描述

2. 目錄結構規劃

在 Next.js 16 (App Router) 中,文件放哪裏很有講究。為了保證項目後期不亂,我們先建好“房間”:

在 app 目錄下,創建以下文件夾:

  • app/ui
    存放所有的 UI 組件(側邊欄、卡片、按鈕等)。
  • app/lib
    存放數據定義、工具函數。
  • app/dashboard
    核心業務頁面(在這個文件夾下的 page.tsx 只有登錄後才能訪問)。
在這裏插入圖片描述

3. 實戰:搭建 Dashboard 佈局

我們要實現的是經典的 “左側固定側邊欄 + 右側內容自適應” 佈局。

3.1 第一步:編寫側邊欄組件 (SideNav)

新建文件 app/ui/dashboard/sidenav.tsx

我們將使用 Next.js 的 <Link> 組件來實現無刷新跳轉,用 Tailwind 實現樣式。

import Link from 'next/link';
import { 
  LayoutDashboard, 
  Building2, 
  Users, 
  ShieldCheck, 
  Menu, 
  GraduationCap, 
  LogOut 
} from 'lucide-react';

// 定義菜單數據(暫時寫死,後續會從數據庫讀取)
const links = [
  { name: '工作台', href: '/dashboard', icon: LayoutDashboard },
  { name: '機構管理', href: '/dashboard/dept', icon: Building2 },
  { name: '人員管理', href: '/dashboard/user', icon: Users },
  { name: '角色管理', href: '/dashboard/role', icon: ShieldCheck },
  { name: '菜單配置', href: '/dashboard/menu', icon: Menu },
];

export default function SideNav() {
  return (
    <div className="flex h-full flex-col px-3 py-4 md:px-2">
      {/* 1. Logo 區域 */}
      <Link
        className="mb-2 flex h-20 items-end justify-start rounded-md bg-zinc-900 p-4 md:h-40"
        href="/"
      >
        <div className="w-32 text-white md:w-40 flex items-center gap-2">
          <GraduationCap className="h-8 w-8" />
          <span className="text-lg font-bold">教培管家</span>
        </div>
      </Link>

      {/* 2. 導航連結區域 */}
      <div className="flex grow flex-row justify-between space-x-2 md:flex-col md:space-x-0 md:space-y-2">
        {links.map((link) => {
          const LinkIcon = link.icon;
          return (
            <Link
              key={link.name}
              href={link.href}
              className="flex h-[48px] grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3"
            >
              <LinkIcon className="w-6" />
              <p className="hidden md:block">{link.name}</p>
            </Link>
          );
        })}

        {/* 佔位符,把登出按鈕頂到底部 */}
        <div className="hidden h-auto w-full grow rounded-md bg-gray-50 md:block"></div>

        {/* 3. 登出按鈕 */}
        <form>
          <button className="flex h-[48px] w-full grow items-center justify-center gap-2 rounded-md bg-gray-50 p-3 text-sm font-medium hover:bg-sky-100 hover:text-blue-600 md:flex-none md:justify-start md:p-2 md:px-3">
            <LogOut className="w-6" />
            <div className="hidden md:block">退出登錄</div>
          </button>
        </form>
      </div>
    </div>
  );
}

AI 編程小技巧:
如果你不理解上面的 Tailwind 類名(如 md:hidden),可以在 Trae 的聊天框裏選中代碼問 Kimi:“解釋一下這段代碼中 Tailwind 類名的作用,特別是響應式部分。

在這裏插入圖片描述

3.2 第二步:創建佈局文件 (Layout)

Next.js 的 layout.tsx 是一個非常強大的特性。它允許我們在多個頁面之間共享 UI(比如側邊欄),當頁面切換時,側邊欄不會重新渲染,狀態得以保留。

新建文件 app/dashboard/layout.tsx

import SideNav from '@/app/ui/dashboard/sidenav';

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex h-screen flex-col md:flex-row md:overflow-hidden">
      {/* 側邊欄區域:在移動端是頂部導航,在桌面端是左側固定 */}
      <div className="w-full flex-none md:w-64 bg-white border-r">
        <SideNav />
      </div>

      {/* 主內容區域:可滾動 */}
      <div className="flex-grow p-6 md:overflow-y-auto md:p-12 bg-gray-50">
        {children}
      </div>
    </div>
  );
}

在這裏插入圖片描述

3.3 第三步:創建第一個頁面

為了驗證效果,我們需要一個頁面。
新建 app/dashboard/page.tsx

export default function Page() {
  return (
    <div>
      <h1 className="text-2xl font-bold mb-4">工作台 Dashboard</h1>
      <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
        {/* 這裏以後放統計卡片 */}
        <div className="h-32 rounded-xl bg-white p-4 shadow-sm border border-gray-100">
           <p className="text-sm text-gray-500">總學員數</p>
           <p className="text-2xl font-bold">1,203</p>
        </div>
        <div className="h-32 rounded-xl bg-white p-4 shadow-sm border border-gray-100">
           <p className="text-sm text-gray-500">本月營收</p>
           <p className="text-2xl font-bold">¥ 45,231</p>
        </div>
      </div>
    </div>
  );
}

在這裏插入圖片描述

4. 見證奇蹟

現在,在終端運行:

npm run dev

在這裏插入圖片描述

打開瀏覽器訪問 http://localhost:3000/dashboard

你應該能看到一個專業的後台管理界面:

  1. 左側是黑色的 Logo 和 灰色的導航菜單。
  2. 右側是灰色的背景和白色的數據卡片。
  3. 嘗試縮小瀏覽器窗口,你會發現側邊欄自動變為了頂部的移動端導航(這是 Tailwind md: 前綴的功勞)。
在這裏插入圖片描述

5 vibe coding

怎麼說呢,默認生成的不是太好看,我們來vibe coding一下

先在trae裏打開我們的頁面,然後用選中元素選中我們左側的工作台菜單,這樣右邊的對話框可以看到一個a標籤,輸入提示詞

工作台增加一個選中的效果

在這裏插入圖片描述
點擊發送的箭頭,讓ai幫我們優化一下

ai調整好了之後,點擊代碼審查,可以看一下他幫我們加了什麼
在這裏插入圖片描述
確認無誤後,點擊對號接受修改,再次刷新頁面,當前工作台就高亮顯示了

在這裏插入圖片描述
再一個我們的LOGO有點過於高了,我們讓AI優化一下,告訴他調整到合適的高度
在這裏插入圖片描述
優化之後,看起來就順眼多了
在這裏插入圖片描述
在當下,大模型的多模態能力,結合trae的選中元素功能,組合起來,只要你把意圖表達明白,大模型就可以又好又快的實現功能。

確認修改後,我們讓kimi把代碼提交到我們的遠程倉庫裏
在這裏插入圖片描述
有些命令是需要我們點擊運行的,點運行,一路按照提示,就可以看到代碼被正確的提交到了倉庫裏
在這裏插入圖片描述

下一步預告

現在的頁面雖然好看,但數據是“死”的,菜單也是寫死的。

在 下一篇 中,我們將深入後端核心:

  1. 使用 Seed 腳本 填充數據庫(包含真實的部門、角色、菜單數據)。
  2. 學習如何用 Next.js 的 Server Actions 從數據庫讀取數據。
  3. 讓左側菜單變成從數據庫動態加載的“活”菜單。