shadcn試してみた

Material UIよりもなんかいいらしいという噂のshadcnというUIライブラリを聞いたので、どこが優れているのか気になったので試してみます！

# 初期設定
[公式ドキュメント](https://ui.shadcn.com/docs/installation/next)のNext.jsのインストールページを参考にやっていきます
```terminal
npx create-next-app@latest my-app --typescript --tailwind --eslint
```
新規Nextプロジェクトの作成
tailwindは必須なので、既存のプロジェクトにshadcnを導入する場合はtailwindも導入する必要があります
```text:フォルダ構成
my-app/
├── app/
│   ├── globals.css
│   ├── layout.tsx
│   └── page.tsx
├── components/
│   ├── ui/
│   │   └── 後々追加されていく
│   └── ...
├── lib/
│   └── utils.ts
├── components.json
├── tailwind.config.js
└── ...
```
```terminal
npx shadcn-ui@latest init
```
shadcnの初期設定
何個か質問が来ますが、基本的には全てEnterで問題ないかと思います

実行が終わるとルートディレクトリに`components.json`が追加されています
```json:components.json
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "default",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.js",
    "css": "app/globals.css",
    "baseColor": "slate",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils"
  }
}
```
先ほどの質問項目がまとまっています

フォントちょい変更
```diff_typescript:app/layout.tsx
import type { Metadata } from 'next'
+ import { Noto_Sans_JP } from 'next/font/google'
import './globals.css'

+ const notoSansJP = Noto_Sans_JP({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
+     <html lang="ja">
+       <body className={notoSansJP.className}>{children}</body>
    </html>
  )
}
```
# UIの追加
それではまず、Buttonを試してみます
```terminal
npx shadcn-ui@latest add button
```
`components/ui/button.tsx`が追加されます

```typescript:app/page.tsx
import { Button } from "@/components/ui/button";

export default function Home() {
  return (
    <main className="p-24">
      <Button>Click me</Button>
    </main>
  );
}
```
サイトを見てみると、ボタンが設置されているはずです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/6be949bd-d3c8-9ac6-b3be-5edaf0a47d20.png)
シンプルですが、shadcnのデザインができました
もっとカスタマイズするのは、[公式ドキュメント](https://ui.shadcn.com/docs/components/button)を参考にすると簡単にできました
```diff_typescript
import { Button } from "@/components/ui/button";
+ import { Mail } from "lucide-react";

export default function Home() {
  return (
    <main className="p-24">
      <Button>Click me</Button>
+       <Button>
+         <Mail className="mr-2 h-4 w-4" /> Login with Email
+       </Button>
    </main>
  );
}

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/4dfa379a-6caf-9592-58a5-7fa3031c7610.png)
Tailwindを使い慣れている人なら`button.tsx`も自由にカスタマイズできて便利かと思います

# 個人的いいとこ
- 新しく覚えることが少ない
    - ほぼほぼTailwind
    - コンポーネントのコード自体を追加してくれるから追加し終わったらあとは自分でいじれる
    - 最低限の初期設定方法やコンポーネントの追加方法さえやってしまえば、あとは、tailwindで細かいカスタマイズをできたり、独自のpropsの設定方法を直接コンポーネントを見れば設定できたりする
- バージョン管理が容易
    - 他のUIライブラリだと破壊的変更がある時がたまにあるそうですが、shadcnの場合はコード自体を追加しているので、破壊もクソもない
- 必要なもののみ追加
    - 必要なコンポーネントのみを追加するので、他のUIライブラリより軽いのかもしれません

# 個人的お遊びタイム
### ダークモード
ドキュメント
https://ui.shadcn.com/docs/dark-mode/next
もうあとはドキュメントコピペしてたらできます
```terminal
npm install next-themes
npx shadcn-ui@latest add dropdown-menu
```

```diff_typescript:app/page.tsx
+ "use client";
import { Mail } from "lucide-react";
+ import { Moon, Sun } from "lucide-react";
+ import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";
+ import {
+   DropdownMenu,
+   DropdownMenuContent,
+   DropdownMenuItem,
+   DropdownMenuTrigger,
+ } from "@/components/ui/dropdown-menu";

export default function Home() {
+   const { setTheme } = useTheme();
  return (
    <main className="p-24">
      <Button>Click me</Button>
      <Button>
        <Mail className="mr-2 h-4 w-4" /> Login with Email
      </Button>
      <h2>ダークモード</h2>
      <DropdownMenu>
        <DropdownMenuTrigger asChild>
          <Button variant="outline" size="icon">
            <Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
            <Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
            <span className="sr-only">Toggle theme</span>
          </Button>
        </DropdownMenuTrigger>
        <DropdownMenuContent align="end">
          <DropdownMenuItem onClick={() => setTheme("light")}>
            Light
          </DropdownMenuItem>
          <DropdownMenuItem onClick={() => setTheme("dark")}>
            Dark
          </DropdownMenuItem>
          <DropdownMenuItem onClick={() => setTheme("system")}>
            System
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
    </main>
  );
}
```
不格好ですが、実装できました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/b876152a-8ef6-8002-8805-37f7e626cdb3.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/ba97a426-9533-1381-5018-0174df27e009.png)

あざしたおわり〜〜