forked from semi-23e/nextjs-todo-tutorial
Compare commits
3 Commits
main
...
implement-
| Author | SHA1 | Date | |
|---|---|---|---|
| a121cc9dfe | |||
| a6ff1b3ff5 | |||
| 375153224f |
268
README.md
268
README.md
@@ -1,262 +1,36 @@
|
|||||||
# 🎯 TODOアプリで学ぶ Next.js & Git/Gitea 実践開発
|
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||||
|
|
||||||
## 📚 このプロジェクトについて
|
## Getting Started
|
||||||
|
|
||||||
このリポジトリは、プログラミング初学者の皆さんが**実践的なWebアプリケーション開発スキル**を身につけるための学習教材です。TODOアプリという身近な題材を通じて、最新のWeb開発技術とチーム開発の基礎を学びます。
|
First, run the development server:
|
||||||
|
|
||||||
### 🚀 学べる技術スキル
|
|
||||||
|
|
||||||
#### 1. **モダンなWeb開発技術**
|
|
||||||
|
|
||||||
- **Next.js 15** - 最新のReactフレームワーク
|
|
||||||
- **TypeScript** - 型安全なJavaScript
|
|
||||||
- **Tailwind CSS v4** - 効率的なスタイリング
|
|
||||||
- **React 19** - 最新のUIライブラリ
|
|
||||||
|
|
||||||
#### 2. **実践的な開発スキル**
|
|
||||||
|
|
||||||
- バージョン管理(Git)
|
|
||||||
- チーム開発(Gitea)
|
|
||||||
- コードレビュー
|
|
||||||
- 問題解決能力
|
|
||||||
|
|
||||||
### 📊 学習時間の目安
|
|
||||||
|
|
||||||
- **TODOアプリ開発**: 15-20時間
|
|
||||||
- **Git/Gitea学習**: 18-25時間
|
|
||||||
- **合計**: 約30-45時間(1日2-3時間×2-3週間)
|
|
||||||
|
|
||||||
## 🗺️ 学習の進め方
|
|
||||||
|
|
||||||
### 推奨学習ルート
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph LR
|
|
||||||
A[環境構築] --> B[Git基礎]
|
|
||||||
B --> C[TODOアプリ Phase1-2]
|
|
||||||
C --> D[Git実践]
|
|
||||||
D --> E[TODOアプリ Phase3-5]
|
|
||||||
E --> F[Gitea連携]
|
|
||||||
F --> G[チーム開発体験]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 1: 環境を整える(2-3時間)
|
|
||||||
|
|
||||||
まずは開発環境を準備しましょう:
|
|
||||||
|
|
||||||
1. **WSL2のセットアップ**(Windows環境の場合)
|
|
||||||
- Ubuntuをインストール
|
|
||||||
- ターミナルの基本操作を覚える
|
|
||||||
|
|
||||||
2. **VSCodeのインストール**
|
|
||||||
- WSL拡張機能を追加
|
|
||||||
- 推奨拡張機能をインストール
|
|
||||||
|
|
||||||
3. **プロジェクトの起動確認**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 開発サーバーを起動
|
|
||||||
npm run dev
|
|
||||||
|
|
||||||
# ブラウザで http://localhost:3000 を開く
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: 2つのカリキュラムを並行して進める
|
|
||||||
|
|
||||||
#### 📱 TODOアプリ開発カリキュラム
|
|
||||||
|
|
||||||
**Phase 1: 基礎理解(2-3時間)**
|
|
||||||
|
|
||||||
- Next.jsプロジェクトの構造を理解
|
|
||||||
- 最初のコンポーネントを作成
|
|
||||||
- TypeScriptの基本を学ぶ
|
|
||||||
|
|
||||||
**Phase 2: UIの作成(3-4時間)**
|
|
||||||
|
|
||||||
- TODOリストの見た目を作る
|
|
||||||
- 入力フォームを追加
|
|
||||||
- Tailwind CSSでデザイン
|
|
||||||
|
|
||||||
**Phase 3: 機能実装(4-5時間)**
|
|
||||||
|
|
||||||
- ✅ TODO追加機能
|
|
||||||
- ✅ 完了/未完了の切り替え
|
|
||||||
- ✅ TODO削除機能
|
|
||||||
|
|
||||||
**Phase 4: 高度な機能(3-4時間)**
|
|
||||||
|
|
||||||
- ✏️ 編集機能
|
|
||||||
- 🔍 フィルター機能
|
|
||||||
- 💾 データの保存
|
|
||||||
|
|
||||||
**Phase 5: 仕上げ(2-3時間)**
|
|
||||||
|
|
||||||
- コンポーネントの整理
|
|
||||||
- エラー処理
|
|
||||||
- パフォーマンス改善
|
|
||||||
|
|
||||||
#### 🔀 Git/Gitea学習カリキュラム
|
|
||||||
|
|
||||||
**Phase 1: Git基礎(3-4時間)**
|
|
||||||
|
|
||||||
- バージョン管理の概念
|
|
||||||
- 基本コマンド(add, commit, push)
|
|
||||||
- VSCodeでのGit操作
|
|
||||||
|
|
||||||
**Phase 2: 実践的な使い方(4-5時間)**
|
|
||||||
|
|
||||||
- ブランチの作成と切り替え
|
|
||||||
- コンフリクトの解決
|
|
||||||
- 履歴の確認方法
|
|
||||||
|
|
||||||
**Phase 3: Gitea入門(3-4時間)**
|
|
||||||
|
|
||||||
- リポジトリの作成
|
|
||||||
- SSH鍵の設定
|
|
||||||
- プッシュとプル
|
|
||||||
|
|
||||||
**Phase 4: チーム開発体験(4-5時間)**
|
|
||||||
|
|
||||||
- Issue管理
|
|
||||||
- プルリクエスト
|
|
||||||
- コードレビュー
|
|
||||||
|
|
||||||
## ⚠️ 初心者がつまずきやすいポイント
|
|
||||||
|
|
||||||
### 1. TypeScriptのエラー対処法
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// よくあるエラー例
|
|
||||||
const [todos, setTodos] = useState([]); // ❌ 型が不明
|
|
||||||
|
|
||||||
// 解決方法
|
|
||||||
type Todo = {
|
|
||||||
id: number;
|
|
||||||
text: string;
|
|
||||||
completed: boolean;
|
|
||||||
};
|
|
||||||
const [todos, setTodos] = useState<Todo[]>([]); // ✅ 型を明示
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. WSL環境の注意点
|
|
||||||
|
|
||||||
- **ファイルの場所**: 必ず`~/projects/`以下で作業(Windows側の`C:\`は避ける)
|
|
||||||
- **改行コード**: LFに統一(CRLFは使わない)
|
|
||||||
- **パスの書き方**: `/home/username/projects/` のようにLinux形式で
|
|
||||||
|
|
||||||
### 3. Gitでよくある失敗
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# コミット前に必ず状態確認
|
npm run dev
|
||||||
git status
|
# or
|
||||||
|
yarn dev
|
||||||
# 間違えてコミットした場合
|
# or
|
||||||
git reset --soft HEAD~1 # 直前のコミットを取り消し
|
pnpm dev
|
||||||
|
# or
|
||||||
|
bun dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## 💡 学習のコツ
|
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||||
|
|
||||||
### 1. エラーは成長のチャンス
|
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||||
|
|
||||||
- エラーメッセージをよく読む
|
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||||
- 検索して解決方法を探す
|
|
||||||
- 質問する前に自分で試す
|
|
||||||
|
|
||||||
### 2. こまめにコミット
|
## Learn More
|
||||||
|
|
||||||
- 小さな機能ごとに保存
|
To learn more about Next.js, take a look at the following resources:
|
||||||
- 分かりやすいメッセージを書く
|
|
||||||
- 失敗を恐れない(いつでも戻せる)
|
|
||||||
|
|
||||||
### 3. 実際に手を動かす
|
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||||
|
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||||
|
|
||||||
- コピペではなく自分で入力
|
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||||
- 動作を確認しながら進める
|
|
||||||
- カスタマイズに挑戦する
|
|
||||||
|
|
||||||
## 🎓 学習のゴール
|
## Deploy on Vercel
|
||||||
|
|
||||||
このプロジェクトを完了すると、以下のスキルが身につきます:
|
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||||
|
|
||||||
### 技術スキル
|
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||||
|
|
||||||
- ✅ React/Next.jsでWebアプリが作れる
|
|
||||||
- ✅ TypeScriptで型安全なコードが書ける
|
|
||||||
- ✅ Gitでバージョン管理ができる
|
|
||||||
- ✅ チーム開発の基本がわかる
|
|
||||||
|
|
||||||
### ソフトスキル
|
|
||||||
|
|
||||||
- ✅ エラーを自力で解決できる
|
|
||||||
- ✅ ドキュメントを読んで理解できる
|
|
||||||
- ✅ 計画的に開発を進められる
|
|
||||||
- ✅ 他人のコードを読める
|
|
||||||
|
|
||||||
## 🚀 次のステップ
|
|
||||||
|
|
||||||
このプロジェクトを完了したら、以下に挑戦してみましょう:
|
|
||||||
|
|
||||||
1. **機能の拡張**
|
|
||||||
- カテゴリー機能
|
|
||||||
- 期限設定
|
|
||||||
- 優先度管理
|
|
||||||
|
|
||||||
2. **新しい技術の導入**
|
|
||||||
- データベース連携
|
|
||||||
- 認証機能
|
|
||||||
- API開発
|
|
||||||
|
|
||||||
3. **実践プロジェクト**
|
|
||||||
- オリジナルアプリの開発
|
|
||||||
- オープンソースへの貢献
|
|
||||||
- チーム開発への参加
|
|
||||||
|
|
||||||
## 📞 困ったときは
|
|
||||||
|
|
||||||
### よくある質問(FAQ)
|
|
||||||
|
|
||||||
**Q: npm run devでエラーが出る**
|
|
||||||
A: `node_modules`を削除して`npm install`を実行してください
|
|
||||||
|
|
||||||
**Q: TypeScriptの型エラーが解決できない**
|
|
||||||
A: 一時的に`any`型を使い、後で正しい型に修正しましょう
|
|
||||||
|
|
||||||
**Q: Gitでプッシュできない**
|
|
||||||
A: リモートの最新を取得(`git pull`)してから再度プッシュ
|
|
||||||
|
|
||||||
### サポート方法
|
|
||||||
|
|
||||||
1. **自己解決を試みる**(15分)
|
|
||||||
- エラーメッセージを読む
|
|
||||||
- 公式ドキュメントを確認
|
|
||||||
- Google/Stack Overflowで検索
|
|
||||||
|
|
||||||
2. **質問の準備**
|
|
||||||
- 何をしようとしたか
|
|
||||||
- どんなエラーが出たか
|
|
||||||
- 何を試したか
|
|
||||||
|
|
||||||
3. **質問する**
|
|
||||||
- 具体的に説明する
|
|
||||||
- コードやエラーを共有
|
|
||||||
- 解決後は共有する
|
|
||||||
|
|
||||||
## 📂 プロジェクト構成
|
|
||||||
|
|
||||||
```
|
|
||||||
nextjs-todo-tutorial/
|
|
||||||
├── src/app/ # アプリケーションコード
|
|
||||||
├── public/ # 静的ファイル
|
|
||||||
├── package.json # 依存関係
|
|
||||||
├── tsconfig.json # TypeScript設定
|
|
||||||
├── tailwind.config.ts # Tailwind設定
|
|
||||||
├── CLAUDE.md # AI支援用ドキュメント
|
|
||||||
├── todo-app-curriculum.md # TODOアプリカリキュラム詳細
|
|
||||||
└── git-gitea-curriculum.md # Git/Giteaカリキュラム詳細
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 最後に
|
|
||||||
|
|
||||||
プログラミング学習は山登りのようなものです。一歩一歩進めば、必ず頂上にたどり着けます。エラーや困難は成長のチャンス。楽しみながら、自分のペースで学習を進めてください。
|
|
||||||
|
|
||||||
**Happy Coding! 🎉**
|
|
||||||
|
|||||||
200
src/app/page.tsx
200
src/app/page.tsx
@@ -1,103 +1,115 @@
|
|||||||
import Image from "next/image";
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
// Todo型の定義
|
||||||
|
type Todo = {
|
||||||
|
id: number;
|
||||||
|
text: string;
|
||||||
|
completed: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
// 状態管理の準備(サンプルデータ付き)
|
||||||
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
|
const [todos, setTodos] = useState<Todo[]>([
|
||||||
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
|
{ id: 1, text: "TypeScriptを学ぶ", completed: false },
|
||||||
<Image
|
{ id: 2, text: "Reactの基礎を理解する", completed: true },
|
||||||
className="dark:invert"
|
{ id: 3, text: "TODOアプリを作る", completed: false },
|
||||||
src="/next.svg"
|
]);
|
||||||
alt="Next.js logo"
|
|
||||||
width={180}
|
|
||||||
height={38}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
|
|
||||||
<li className="mb-2 tracking-[-.01em]">
|
|
||||||
Get started by editing{" "}
|
|
||||||
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
|
|
||||||
src/app/page.tsx
|
|
||||||
</code>
|
|
||||||
.
|
|
||||||
</li>
|
|
||||||
<li className="tracking-[-.01em]">
|
|
||||||
Save and see your changes instantly.
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<div className="flex gap-4 items-center flex-col sm:flex-row">
|
// 入力中のテキストを管理
|
||||||
<a
|
const [inputText, setInputText] = useState("");
|
||||||
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
|
|
||||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
// TODO追加機能
|
||||||
target="_blank"
|
const handleAddTodo = (e: React.FormEvent) => {
|
||||||
rel="noopener noreferrer"
|
e.preventDefault(); // フォームのデフォルト動作を防ぐ
|
||||||
>
|
|
||||||
<Image
|
if (inputText.trim() === "") {
|
||||||
className="dark:invert"
|
return; // 空文字の場合は追加しない
|
||||||
src="/vercel.svg"
|
}
|
||||||
alt="Vercel logomark"
|
|
||||||
width={20}
|
const newTodo: Todo = {
|
||||||
height={20}
|
id: Date.now(), // 簡易的なID生成
|
||||||
|
text: inputText,
|
||||||
|
completed: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
setTodos([...todos, newTodo]); // 新しいTODOを配列に追加
|
||||||
|
setInputText(""); // 入力欄をクリア
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO完了状態の切り替え機能
|
||||||
|
const handleToggleTodo = (id: number) => {
|
||||||
|
setTodos(
|
||||||
|
todos.map((todo) =>
|
||||||
|
todo.id === id ? { ...todo, completed: !todo.completed } : todo
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO削除機能
|
||||||
|
const handleDeleteTodo = (id: number) => {
|
||||||
|
setTodos(todos.filter((todo) => todo.id !== id));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="min-h-screen p-8 bg-gray-50 dark:bg-gray-900">
|
||||||
|
<div className="max-w-4xl mx-auto">
|
||||||
|
<h1 className="text-4xl font-bold text-center text-gray-800 dark:text-gray-100 mb-8">
|
||||||
|
私のTODOアプリ
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{/* TODO入力フォーム */}
|
||||||
|
<div className="mb-8">
|
||||||
|
<form onSubmit={handleAddTodo} className="flex gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={inputText}
|
||||||
|
onChange={(e) => setInputText(e.target.value)}
|
||||||
|
placeholder="新しいTODOを入力..."
|
||||||
|
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-100"
|
||||||
/>
|
/>
|
||||||
Deploy now
|
<button
|
||||||
</a>
|
type="submit"
|
||||||
<a
|
className="px-6 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
|
||||||
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
|
|
||||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
>
|
||||||
Read our docs
|
追加
|
||||||
</a>
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* TODOリスト表示エリア */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
{todos.map((todo) => (
|
||||||
|
<div
|
||||||
|
key={todo.id}
|
||||||
|
className="flex items-center gap-3 p-4 bg-white dark:bg-gray-800 rounded-lg shadow-sm"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={todo.completed}
|
||||||
|
onChange={() => handleToggleTodo(todo.id)}
|
||||||
|
className="w-5 h-5 text-blue-500 rounded focus:ring-2 focus:ring-blue-500"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={`flex-1 ${
|
||||||
|
todo.completed
|
||||||
|
? "line-through text-gray-500 dark:text-gray-400"
|
||||||
|
: "text-gray-800 dark:text-gray-100"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{todo.text}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={() => handleDeleteTodo(todo.id)}
|
||||||
|
className="px-3 py-1 text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 rounded transition-colors"
|
||||||
|
>
|
||||||
|
削除
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
|
|
||||||
<a
|
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
||||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
aria-hidden
|
|
||||||
src="/file.svg"
|
|
||||||
alt="File icon"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Learn
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
||||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
aria-hidden
|
|
||||||
src="/window.svg"
|
|
||||||
alt="Window icon"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Examples
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
|
||||||
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
aria-hidden
|
|
||||||
src="/globe.svg"
|
|
||||||
alt="Globe icon"
|
|
||||||
width={16}
|
|
||||||
height={16}
|
|
||||||
/>
|
|
||||||
Go to nextjs.org →
|
|
||||||
</a>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user