Closed7

Refineを使用してshadcn/uiベースの管理画面をNext.jsで構築

RyukiRyuki

導入

管理画面を気合いで開発していたところ、インターンの子から「Refineというのがありますよ。」という話を教えてもらい、実際にRefineを使用した管理画面を開発してみる
https://refine.dev/

Refineとは?

簡単に管理画面を開発できるOSS。(現状の認識)
ローコードよりより詳細にかけて、Reactで動いているもの

実現したいこと

Shadcn UIで管理画面を開発していたのでShadcnのデザインにしたい。

RyukiRyuki

導入

Shadcn UIとRefineが実現できるか調べたら公式がドキュメントを出していた。
https://refine.dev/blog/shadcn-ui/#shadcn-with-refine-initializing-and-configuring-shadcn

このドキュメントではViteを使用した構築を紹介して居るが、自分が普段Next.jsでコードを書いて居るため、今回はNext.jsで構築していく。

プロジェクトファイルの作成

1. Refineを使用した初期化を実行

npm create refine-app@latest refine-shadcn

2. オプションの選択

DBはSupabaseを使用して居るので、Data ProviderはSupabaseを選択しました。

✔ Downloaded remote source successfully.
✔ Choose a project template · refine-nextjs
✔ What would you like to name your project?: · refine-shadcn-nextjs-example
✔ Choose your backend service to connect: · data-provider-supabase
✔ Do you want to use a UI Framework?: · no
✔ Do you want to add example pages?: · headless-example
✔ Choose a package manager: · npm
✔ Mind sharing your email? (We reach out to developers for free priority support, events, and SWAG kits. We never spam.) ·

時間が経つとプロジェクトの初期化が出来ました

Success! Created refine-shadcn-nextjs-example at /Users/sasaki/Documents/refine-shadcn-nextjs-example 🚀

Start developing by:

  › cd /Users/sasaki/Documents/refine-shadcn-nextjs-example
  › npm run dev

  › Join us at https://discord.gg/refine
RyukiRyuki

実行の確認

npm run devで実行を確認

http://localhost:3000/にアクセスすると何も表示がされない。
事前調査でログイン画面が出てくることは確認していたので、何かバグっていると考えています。

もしくはlocalhost:3000で変なクッキーがあるか。

http://localhost:3000/blog-posts1に直リンクしたら変なリダイレクトはなくなったのでOK。

追記
ログアウトしたら治った。Cookieが悪かったみたい

RyukiRyuki

Shadcn UI を使用出来るようにする

各種パッケージをインストール

下記のコマンドを実行
npm install -D tailwindcss postcss autoprefixer

TailwindCSSを初期化

下記のコマンドを実行
npx tailwindcss init -p

Shadcn UIを初期化

npx shadcn-ui@latest init

オプション

ファイルを見ると、CSSファイルの場所がデフォルトと違うので注意

✔ Would you like to use TypeScript (recommended)? … yes
✔ Which style would you like to use? › Default
✔ Which color would you like to use as base color? › Slate
✔ Where is your global CSS file? … src/app/styles/global.css
✔ Would you like to use CSS variables for colors? … yes
✔ Are you using a custom tailwind prefix eg. tw-? (Leave blank if not) … 
✔ Where is your tailwind.config.js located? … tailwind.config.js
✔ Configure the import alias for components: … @/components
✔ Configure the import alias for utils: … @/lib/utils
✔ Are you using React Server Components? … yes
✔ Write configuration to components.json. Proceed? … yes

global.cssに追記

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 222.2 84% 4.9%;

    --card: 0 0% 100%;
    --card-foreground: 222.2 84% 4.9%;

    --popover: 0 0% 100%;
    --popover-foreground: 222.2 84% 4.9%;

    --primary: 222.2 47.4% 11.2%;
    --primary-foreground: 210 40% 98%;

    --secondary: 210 40% 96.1%;
    --secondary-foreground: 222.2 47.4% 11.2%;

    --muted: 210 40% 96.1%;
    --muted-foreground: 215.4 16.3% 46.9%;

    --accent: 210 40% 96.1%;
    --accent-foreground: 222.2 47.4% 11.2%;

    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 210 40% 98%;

    --border: 214.3 31.8% 91.4%;
    --input: 214.3 31.8% 91.4%;
    --ring: 222.2 84% 4.9%;

    --radius: 0.5rem;
  }

  .dark {
    --background: 222.2 84% 4.9%;
    --foreground: 210 40% 98%;

    --card: 222.2 84% 4.9%;
    --card-foreground: 210 40% 98%;

    --popover: 222.2 84% 4.9%;
    --popover-foreground: 210 40% 98%;

    --primary: 210 40% 98%;
    --primary-foreground: 222.2 47.4% 11.2%;

    --secondary: 217.2 32.6% 17.5%;
    --secondary-foreground: 210 40% 98%;

    --muted: 217.2 32.6% 17.5%;
    --muted-foreground: 215 20.2% 65.1%;

    --accent: 217.2 32.6% 17.5%;
    --accent-foreground: 210 40% 98%;

    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 210 40% 98%;

    --border: 217.2 32.6% 17.5%;
    --input: 217.2 32.6% 17.5%;
    --ring: 212.7 26.8% 83.9%;
  }
}

@layer base {
  * {
    @apply border-border;
  }
  body {
    @apply bg-background text-foreground;
  }
}
RyukiRyuki

Shadcn UIのインストール & 動作確認

コンポーネントのダウンロード

npx shadcn-ui@latest add buttonを実行してButtonのコンポーネントをダウンロード

Logoutボタンを変更

@/app/components/menu/index.tsx
"use client";

import { useLogout, useMenu } from "@refinedev/core";
import Link from "next/link";
+ import {Button} from "@components/ui/button";

export const Menu = () => {
  const { mutate: logout } = useLogout();
  const { menuItems, selectedKey } = useMenu();

  return (
    <nav className="menu">
      <ul>
        {menuItems.map((item) => (
          <li key={item.key}>
            <Link
              href={item.route ?? "/"}
              className={selectedKey === item.key ? "active" : ""}
            >
              {item.label}
            </Link>
          </li>
        ))}
      </ul>
-      <button onClick={() => logout()}>Logout</button>
+      <Button onClick={() => logout()}>Logout</Button>
    </nav>
  );
};

完了したら環境を再起動してください。(勝手に適応されてなかったので)

デザインの変更を確認

http://localhost:3000/categoriesにアクセスするとButtonのデザインが変更されて居るのを確認

RyukiRyuki

TableをShadcn UIに切り替える

簡単にCategoryのページをShadcn UIのテーブルに変更する

global.cssを変更

Tableのstyleが適応されて居るので削除を行う。

@/styles/global.css
...code

-table {
-  border-spacing: 0;
-  border: 1px solid black;
-}
-
-table th,
-td {
-  margin: 0;
- padding: 0.5rem;
-  border-bottom: 1px solid black;
-  border-right: 1px solid black;
-}
-
-table tr:last-child td {
-  border-bottom: 0;
-}
-
-table th,
-td {
- margin: 0;
- padding: 0.5rem;
- border-bottom: 1px solid black;
- border-right: 1px solid black;
-}
-
-table th:last-child,
-td:last-child {
-  border-right: 0;
-}

...code

Shadcnのコンポーネントをダウンロード

npx shadcn-ui@latest add tableでTableのコンポーネントをダウンロード

TableをShadcnのコンポーネントに変更

Tableを切り替えていく

ファイル上部でコンポーネントをインポート

@/app/categories/page.tsx
import {
  Table,
  TableBody,
  TableCaption,
  TableCell,
  TableFooter,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"

テーブル部分のコードを以下に置換

@/app/categories/page.tsx
 <Table>
          <TableHeader>
            {getHeaderGroups().map((headerGroup) => (
              <TableRow key={headerGroup.id}>
                {headerGroup.headers.map((header) => (
                  <TableHead key={header.id}>
                    {!header.isPlaceholder &&
                      flexRender(
                        header.column.columnDef.header,
                        header.getContext()
                      )}
                  </TableHead>
                ))}
              </TableRow>
            ))}
          </TableHeader>
          <TableBody>
            {getRowModel().rows.map((row) => (
              <TableRow key={row.id}>
                {row.getVisibleCells().map((cell) => (
                  <TableCell key={cell.id}>
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </TableCell>
                ))}
              </TableRow>
            ))}
          </TableBody>
        </Table>

デザインの確認

http://localhost:3000/categoriesにアクセス

RyukiRyuki

基本的にフロントエンドを切り替えれば良さそう。
これにて調査終了かな。
そもそもRefineが何出来るかよくわかってないからそこの調査は必要。

このスクラップは5ヶ月前にクローズされました