Reactでローカル用ガントチャートアプリ作成までの備忘録②
Next.jsでガントチャートアプリを作っていきます。
npx create-next-app@latest next-gantt
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like your code inside a `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to use Turbopack for `next dev`? … No / Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No / Yes
shadcnを入れていきます。
ちなみに今回はreact19を使用します。
npx shadcn@latest init
上のコマンドを実行して以下のように選択しました。
要約するとテーマはSlateで--legacy-peer-depsオプションでインストールしています。
✔ Preflight checks.
✔ Verifying framework. Found Next.js.
✔ Validating Tailwind CSS.
✔ Validating import alias.
✔ Which style would you like to use? › Default
✔ Which color would you like to use as the base color? › Slate
✔ Would you like to use CSS variables for theming? … no / yes
✔ Writing components.json.
✔ Checking registry.
✔ Updating tailwind.config.ts
✔ Updating app/globals.css
Installing dependencies.
It looks like you are using React 19.
Some packages may fail to install due to peer dependency issues in npm (see https://ui.shadcn.com/react-19).
✔ How would you like to proceed? › Use --legacy-peer-deps
✔ Installing dependencies.
✔ Created 1 file:
- lib/utils.ts
Success! Project initialization completed.
You may now add components.
ここの対応はshadcnの公式にも記述しています。
実行した後にcomponents.jsonが生成されています。
16行目あたりに以下のように記述されているので
shadcnからコンポーネントをインストールされると以下のところに入ります。
"ui": "@/components/ui",
とりあえずボタンを表示してみます。
npx shadcn@latest add
色々なコンポーネントが表示されるのでスペースを押して
選択した後にエンターでダウンロードします。
ここでもforceかlegacyか聞かれますがlegacyを選択します。
✔ How would you like to proceed? › Use --legacy-peer-deps
今回は試しにボタンを入れてapp直下のpage.tsxを以下のように記述してみます。
import { Button } from "@/components/ui/button";
export default function Home() {
return (
<div className="flex flex-col items-center justify-center min-h-screen py-2">
<Button className="font-bold">shadcn テストボタン</Button>
</div>
);
}
以下のようになっていればOKです。
これで準備OKです。
前回の記事で紹介した「gantt-task-react」をインストールします。
私はreact19を使用しているのでlegacyオプションをつけないとエラーが出るのでオプションをつけました。
npm i gantt-task-react --legacy-peer-deps
とりあえず公式のコードを見て、少し変更して動作確認します。
それが以下になります。
最近話題のdeepseek先生に手伝ってもらいました。
"use client";
import { Button } from "@/components/ui/button";
import { Gantt, Task, ViewMode } from "gantt-task-react";
import "gantt-task-react/dist/index.css"; // CSSファイルをインポート。これを忘れていると真っ黒のガントチャートになる…
export default function Home() {
const tasks: Task[] = [
{
start: new Date(2020, 1, 1),
end: new Date(2020, 1, 2),
name: "Idea",
id: "Task 0",
type: "task",
progress: 45,
isDisabled: true,
styles: { progressColor: "#ffbb54", progressSelectedColor: "#ff9e0d" },
},
];
return (
<div className="flex flex-col items-center justify-center min-h-screen py-2">
<div className="flex flex-col items-center w-full p-4 space-y-4">
<Button className="font-bold">shadcn テストボタン</Button>
{/* Gantt コンポーネントのサイズを制限 */}
<div className="w-full max-w-4xl overflow-x-auto">
<Gantt
tasks={tasks}
viewMode={ViewMode.Day} // 表示モードを調整
columnWidth={60} // カラムの幅を調整
rowHeight={40} // 行の高さを調整
fontSize="12" // フォントサイズを調整
/>
</div>
</div>
</div>
);
}
npm run dev
以上で動作確認をして下のように表示されていればOKです。
ここで少しファイル分割を行います。
componentsディレクトリ直下に「GanttView.tsx」を作成して
以下のように記述します。
import { Gantt, Task, ViewMode } from "gantt-task-react";
import React from "react";
import "gantt-task-react/dist/index.css"; // CSSファイルをインポート
const GanttView = () => {
const tasks: Task[] = [
{
start: new Date(2020, 1, 1),
end: new Date(2020, 1, 2),
name: "Idea",
id: "Task 0",
type: "task",
progress: 45,
isDisabled: true,
styles: { progressColor: "#ffbb54", progressSelectedColor: "#ff9e0d" },
},
];
return (
<div className="w-full max-w-4xl overflow-x-auto">
<Gantt
tasks={tasks}
viewMode={ViewMode.Day} // 表示モードを調整
columnWidth={60} // カラムの幅を調整
rowHeight={40} // 行の高さを調整
fontSize="12" // フォントサイズを調整
/>
</div>
);
};
export default GanttView;
なのでpage.tsxは以下のようになります。
"use client";
import GanttView from "@/components/GanttView";
import { Button } from "@/components/ui/button";
export default function Home() {
return (
<div className="flex flex-col items-center justify-center min-h-screen py-2">
<div className="flex flex-col items-center w-full p-4 space-y-4">
<Button className="font-bold">shadcn テストボタン</Button>
<GanttView />
</div>
</div>
);
}
この分割をしてエラーが出なければOKです。
次はボタンを押した時にタスクを追加するダイアログが欲しいので実装していきます。
もちろんshadcnのダイアログを使用していきます。(modalが好きな人はそちらで)
npx shadcn@latest add dialog
最初はダイアログを表示するだけを実装したいのでshadcnの公式サイトを見てサンプルコードを使います。
今回も少し編集しています。
shadcnのdialogを編集したい方は以下の記事が参考になりそうです。
componentsディレクトリ直下にTaskAddDialog.tsxを作成します。
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog";
import { Button } from "./ui/button";
// TaskAddDialogPropsの型定義
// page.tsxからはisOpenとonRequestCloseを受け取る
interface TaskAddDialogProps {
isOpen: boolean;
onRequestClose?: () => void;
}
const TaskAddDialog = ({ isOpen, onRequestClose }: TaskAddDialogProps) => {
return (
<Dialog open={isOpen} onOpenChange={onRequestClose}>
<DialogContent>
<DialogHeader>
<DialogTitle>ここにダイアログのタイトルを入力</DialogTitle>
<DialogDescription>ここに説明文などを入力</DialogDescription>
</DialogHeader>
{/* 閉じるボタン追加 */}
<DialogClose asChild>
<Button type="button" variant="secondary">
Close
</Button>
</DialogClose>
</DialogContent>
</Dialog>
);
};
export default TaskAddDialog;
何度も申し訳ないですがpage.tsxを以下のようにします。
"use client";
import GanttView from "@/components/GanttView";
import TaskAddDialog from "@/components/TaskAddDialog";
import { Button } from "@/components/ui/button";
import { useState } from "react";
export default function Home() {
// ダイアログを開くための状態を管理
const [isOpen, setIsOpen] = useState(false);
return (
<div className="flex flex-col items-center justify-center min-h-screen py-2">
<div className="flex flex-col items-center w-full p-4 space-y-4">
<Button
className="font-bold"
onClick={() => {
setIsOpen(true);
}}
>
shadcn テストボタン
</Button>
<GanttView />
<TaskAddDialog
isOpen={isOpen}
onRequestClose={() => {
setIsOpen(false);
}}
/>
</div>
</div>
);
}
これでダイアログが表示されたらOKです。
あとはダイアログの入力画面の実装や、削除、更新などの実装ぐらいかと思います。
役に立つか分かりませんが次はその辺の実装を行います。
Discussion