首先是元件庫,目前用的最順手的是 MUI
,先把會用到的部分安裝。
pnpm add @mui/material @emotion/react @emotion/styled @mui/icons-material
MUI 主要是用 emotion 這個 CSS-in-JS 工具來產生樣式,基本不再另外開 css 檔案來寫樣式,所以先把目前模板預設的樣式表清除。
deleted: apps/ironman-nextjs/app/global.css
deleted: apps/ironman-nextjs/app/page.module.css
然後先在基本 layout 中引用 MUI 的 css 重置元件。
// apps/ironman-nextjs/app/layout.tsx
import CssBaseline from '@mui/material/CssBaseline';
//...
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<CssBaseline />
{children}
</body>
</html>
);
}
接著來準備一個應用列元件,開一個 components 目錄來放元件。
先直接用官方範例的應用列元件:App bar with responsive menu
這邊要注意的一點是目前 NextJS 預設元件都是 React Server Component ,但 emotion 作為一個 *CSS-in-JS 套件,*目前並不支援這個元件形式,所以要將有用到 emotion 的元件宣告為 Client Component。
MUI 目前將所有的元件都設定為 Client Component 了,所以可以直接使用,但自己重包過的元件要自己宣告。
// apps/ironman-nextjs/components/AppBar.tsx
'use client'; // 宣告為 Client Component
//...
function ResponsiveAppBar() {
...
}
export default ResponsiveAppBar;
將預設模板的頁面清空,引入元件:
// apps/ironman-nextjs/app/page.tsx
import React from 'react';
import AppBar from '@components/AppBar'; // @components 要在 tsconfig 設定 path 才能作用
export default async function Index() {
return (
<div>
<AppBar />
</div>
);
}
最後為了能編輯整體 MUI 元件的主題,先將 ThemeProvider 準備好。
// apps/ironman-nextjs/components/ThemeProvider.tsx
'use client'; // 一樣要宣告為 Client Component
import { purple } from '@mui/material/colors';
import {
ThemeProvider as MuiThemeProvider,
createTheme,
} from '@mui/material/styles';
const theme = createTheme({
palette: {
primary: {
main: purple[500], // 改變主題色
},
},
});
export default function ThemeProvider({
children,
}: {
children: React.ReactNode;
}) {
return <MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>;
}
套用到 layout 上
// apps/ironman-nextjs/app/layout.tsx
import CssBaseline from '@mui/material/CssBaseline';
import ThemeProvider from '@components/ThemeProvider';
// ...
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<CssBaseline />
<ThemeProvider>{children}</ThemeProvider>; {/* 加上 ThemeProvider */}
</body>
</html>
);
}