diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000..a547bf36d8d11 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/README.md b/README.md new file mode 100644 index 0000000000000..da9844432b833 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default tseslint.config({ + extends: [ + // Remove ...tseslint.configs.recommended and replace with this + ...tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + ...tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + ...tseslint.configs.stylisticTypeChecked, + ], + languageOptions: { + // other options... + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}) +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x' +import reactDom from 'eslint-plugin-react-dom' + +export default tseslint.config({ + plugins: { + // Add the react-x and react-dom plugins + 'react-x': reactX, + 'react-dom': reactDom, + }, + rules: { + // other rules... + // Enable its recommended typescript rules + ...reactX.configs['recommended-typescript'].rules, + ...reactDom.configs.recommended.rules, + }, +}) +``` diff --git a/biome.json b/biome.json new file mode 100644 index 0000000000000..363b7b7a8858e --- /dev/null +++ b/biome.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.0.5/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/component-refactor-plan.md b/component-refactor-plan.md new file mode 100644 index 0000000000000..2cb82d916b67e --- /dev/null +++ b/component-refactor-plan.md @@ -0,0 +1,271 @@ +# React コンポーネント分割 & CSS Modules 実装計画 + +## プロジェクト概要 +ホテル予約サイト(HOTEL PLANISPHERE)の単一コンポーネント(App.tsx)を細かい粒度で分割し、CSS ModulesによるスタイリングシステムをVite + React + TypeScript環境に適用する。 + +## 現在の状況 +- **App.tsx**: 168行 - 全機能が集約 +- **App.css**: 286行 - 全スタイル定義 +- **技術スタック**: React 19, TypeScript, Vite +- **機能**: レスポンシブデザイン対応のホテル宿泊プラン一覧 + +## コンポーネント分割設計 + +### アーキテクチャ図 +``` +App +├── Header +│ ├── Navigation +│ │ ├── HamburgerButton +│ │ └── NavigationMenu +├── Main +│ ├── PageTitle +│ ├── FeaturedPlan +│ │ └── PlanCard (featured) +│ └── PlanList +│ └── PlanCard (regular) × 6 +└── Footer +``` + +### コンポーネント詳細仕様 + +#### 1. Header コンポーネント +- **ファイル**: `src/components/Header/Header.tsx` +- **CSS**: `src/components/Header/Header.module.css` +- **役割**: サイトヘッダー全体の管理、タイトル表示 +- **子コンポーネント**: Navigation + +#### 2. Navigation コンポーネント +- **ファイル**: `src/components/Navigation/Navigation.tsx` +- **CSS**: `src/components/Navigation/Navigation.module.css` +- **役割**: ナビゲーション全体の状態管理 +- **State**: `isMenuOpen` (boolean) +- **子コンポーネント**: HamburgerButton, NavigationMenu + +#### 3. HamburgerButton コンポーネント +- **ファイル**: `src/components/Navigation/HamburgerButton/HamburgerButton.tsx` +- **CSS**: `src/components/Navigation/HamburgerButton/HamburgerButton.module.css` +- **Props**: + - `isOpen: boolean` + - `onClick: () => void` +- **役割**: モバイル用ハンバーガーメニューボタン + +#### 4. NavigationMenu コンポーネント +- **ファイル**: `src/components/Navigation/NavigationMenu/NavigationMenu.tsx` +- **CSS**: `src/components/Navigation/NavigationMenu/NavigationMenu.module.css` +- **Props**: + - `isOpen: boolean` +- **役割**: ナビゲーションメニューの表示制御 + +#### 5. PageTitle コンポーネント +- **ファイル**: `src/components/Main/PageTitle/PageTitle.tsx` +- **CSS**: `src/components/Main/PageTitle/PageTitle.module.css` +- **Props**: + - `title: string` +- **役割**: ページタイトルの表示 + +#### 6. FeaturedPlan コンポーネント +- **ファイル**: `src/components/Main/FeaturedPlan/FeaturedPlan.tsx` +- **CSS**: `src/components/Main/FeaturedPlan/FeaturedPlan.module.css` +- **役割**: おすすめプランセクションの管理 +- **子コンポーネント**: PlanCard (featured版) + +#### 7. PlanList コンポーネント +- **ファイル**: `src/components/Main/PlanList/PlanList.tsx` +- **CSS**: `src/components/Main/PlanList/PlanList.module.css` +- **Props**: + - `plans: Plan[]` +- **役割**: 通常プラン一覧の表示管理 +- **子コンポーネント**: PlanCard × 6 + +#### 8. PlanCard コンポーネント +- **ファイル**: `src/components/PlanCard/PlanCard.tsx` +- **CSS**: `src/components/PlanCard/PlanCard.module.css` +- **Props**: + - `plan: Plan` + - `isFeatured?: boolean` +- **役割**: 再利用可能なプランカード + +#### 9. Footer コンポーネント +- **ファイル**: `src/components/Footer/Footer.tsx` +- **CSS**: `src/components/Footer/Footer.module.css` +- **役割**: サイトフッター + +## CSS分割マッピング詳細 + +### 現在のApp.css (286行) → 各CSS Moduleへの分散 + +| 元のCSSセレクター | 行番号 | 移動先CSS Module | 新しいクラス名 | +|---|---|---|---| +| `.hotel-app` | 2-7 | App.module.css | `.container` | +| `header` | 9-15 | Header.module.css | `.header` | +| `header h1` | 17-23 | Header.module.css | `.title` | +| `nav` | 26-31 | Navigation.module.css | `.nav` | +| `.hamburger-button` | 34-44 | HamburgerButton.module.css | `.button` | +| `.hamburger-button span` | 46-54 | HamburgerButton.module.css | `.line` | +| `nav ul` | 56-62 | NavigationMenu.module.css | `.menu` | +| `nav ul li` | 64-67 | NavigationMenu.module.css | `.menuItem` | +| `nav ul li a` | 69-74 | NavigationMenu.module.css | `.menuLink` | +| `.login-btn` | 76-82 | NavigationMenu.module.css | `.loginButton` | +| `.active-link` | 84-86 | NavigationMenu.module.css | `.activeLink` | +| `main` | 89-94 | App.module.css | `.main` | +| `main h2` | 96-103 | PageTitle.module.css | `.title` | +| `.plan-list` | 106-113 | PlanList.module.css | `.grid` | +| `.plan-card` | 116-122 | PlanCard.module.css | `.card` | +| `.plan-column` | 125-127 | PlanList.module.css | `.column` | +| `.featured` | 129-135 | FeaturedPlan.module.css | `.container` | +| `.plan-header` | 137-141 | PlanCard.module.css | `.header` | +| `.plan-content` | 143-157 | PlanCard.module.css | `.content` | +| `.plan-content h3` | 147-152 | PlanCard.module.css | `.planTitle` | +| `.plan-content p` | 154-156 | PlanCard.module.css | `.planDetail` | +| `.plan-footer` | 158-163 | PlanCard.module.css | `.footer` | +| `.reserve-btn` | 166-180 | PlanCard.module.css | `.reserveButton` | +| `.reserve-btn:hover` | 182-184 | PlanCard.module.css | `.reserveButton:hover` | +| `footer` | 187-191 | Footer.module.css | `.footer` | +| `footer a` | 193-198 | Footer.module.css | `.link` | +| `footer p` | 200-203 | Footer.module.css | `.text` | + +### レスポンシブデザインの分散 + +#### タブレット向け(768px〜991px)- 209-248行 +- Header関連(211-223行) → Header.module.css +- HamburgerButton表示(225-228行) → HamburgerButton.module.css +- Navigation関連(230-242行) → Navigation.module.css, NavigationMenu.module.css +- PlanList関連(244-247行) → PlanList.module.css + +#### モバイル向け(767px以下)- 251-286行 +- NavigationMenu関連(253-258行) → NavigationMenu.module.css +- PlanList関連(260-263行) → PlanList.module.css +- PlanCard関連(265-276行) → PlanCard.module.css +- Main, Footer関連(278-285行) → App.module.css, Footer.module.css + +## 型定義 + +### Plan型 +```typescript +// src/types/plan.ts +export interface Plan { + id: string; + title: string; + price: string; + guests: string; + roomType: string; + isFeatured?: boolean; + badge?: string; +} +``` + +### CSS Modules型定義 +```typescript +// src/vite-env.d.ts に追加 +declare module '*.module.css' { + const classes: { [key: string]: string }; + export default classes; +} +``` + +## ディレクトリ構造 + +``` +src/ +├── components/ +│ ├── Header/ +│ │ ├── Header.tsx +│ │ └── Header.module.css +│ ├── Navigation/ +│ │ ├── Navigation.tsx +│ │ ├── Navigation.module.css +│ │ ├── HamburgerButton/ +│ │ │ ├── HamburgerButton.tsx +│ │ │ └── HamburgerButton.module.css +│ │ └── NavigationMenu/ +│ │ ├── NavigationMenu.tsx +│ │ └── NavigationMenu.module.css +│ ├── Main/ +│ │ ├── PageTitle/ +│ │ │ ├── PageTitle.tsx +│ │ │ └── PageTitle.module.css +│ │ ├── FeaturedPlan/ +│ │ │ ├── FeaturedPlan.tsx +│ │ │ └── FeaturedPlan.module.css +│ │ └── PlanList/ +│ │ ├── PlanList.tsx +│ │ └── PlanList.module.css +│ ├── PlanCard/ +│ │ ├── PlanCard.tsx +│ │ └── PlanCard.module.css +│ └── Footer/ +│ ├── Footer.tsx +│ └── Footer.module.css +├── types/ +│ └── plan.ts +├── App.tsx +├── App.module.css +├── main.tsx +└── vite-env.d.ts +``` + +## 実装フェーズ + +### フェーズ1: 基盤整備 +1. 型定義の作成 (`types/plan.ts`) +2. CSS Modules TypeScript設定 +3. プランデータの定義 + +### フェーズ2: リーフコンポーネント +1. **PlanCard** - 最も再利用されるコンポーネント +2. **HamburgerButton** - 単純なUI要素 +3. **PageTitle** - シンプルなプレゼンテーション + +### フェーズ3: 中間コンポーネント +1. **NavigationMenu** - メニューリスト管理 +2. **FeaturedPlan** - おすすめプランコンテナ +3. **PlanList** - プラン一覧管理 + +### フェーズ4: 上位コンポーネント +1. **Navigation** - 状態管理を含む +2. **Header** - ナビゲーションを含む +3. **Footer** - 独立したフッター + +### フェーズ5: 最終統合 +1. **App.tsx** の更新 - 全コンポーネント統合 +2. **App.css** の削除 +3. 動作確認とテスト + +## CSS Modules設定 + +### Vite設定追加 +```typescript +// vite.config.ts +export default defineConfig({ + plugins: [react()], + css: { + modules: { + localsConvention: 'camelCase' + } + } +}) +``` + +## 期待される効果 + +### 保守性向上 +- コンポーネントごとの責任分離 +- スタイルの局所化 +- 再利用性の向上 + +### 開発体験向上 +- TypeScript型安全性 +- クラス名の自動補完 +- 未使用スタイルの検出 + +### パフォーマンス向上 +- 必要なCSSのみバンドル +- コードスプリット対応 +- ツリーシェイキング効果 + +--- + +**作成日**: 2025/6/24 +**プロジェクト**: HOTEL PLANISPHERE +**技術スタック**: React 19 + TypeScript + Vite + CSS Modules \ No newline at end of file diff --git "a/docs/\350\252\262\351\241\2141-2.md" "b/docs/\350\252\262\351\241\2141-2.md" new file mode 100644 index 0000000000000..9b897073572c7 --- /dev/null +++ "b/docs/\350\252\262\351\241\2141-2.md" @@ -0,0 +1,12 @@ +お手本ページのDOM構造を見てみると`

`、`