d2-03-main-menu について
必須のエンティティ名と選択した機能に基づき、Angular アプリのランディングメニューを作成する開発スキルです。共通ルートテーブルとレスポンシブな Tailwind のカードグリッドも定めています。
主な機能
- 01選択した機能からメニュー項目を生成
- 02メニューをデフォルトのランディングルートに設定
- 03検索とフォームの共通ルートを設定
- 04レスポンシブな Tailwind カードグリッドを使用
活用シーン
- 01エンティティ型アプリのランディングメニューを作成
- 02対応する検索やレコード操作だけを表示
- 03メニュー、検索、フォーム各ページのルートを連携
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ softinter-chiangrai/ up-ai-skill-training --skill d2-03-main-menuインストール後、Claude Code で/d2-03-main-menuを入力して読み込まれたか確認します。
詳細
2日目・ステップ3 — 機能に応じてメニュー項目を表示するメインメニュー
開始前に、以下を確認してください:
- エンティティ名(PascalCase、例:
Product、Order、Employee)— 必須 - 利用可能な機能(
search、create、save、deleteから1つ以上選択)— 必須search:すべてのレコードを閲覧/一覧表示create:新しいレコードを作成save:データベースに保存(作成/編集時に使用)delete:レコードを削除
指定どおりに使用してください。選択した機能に基づいてメニューボタンが生成されます。
ルーティングの設定(app.routes.ts)— すべてのページの完全なルーティングテーブル:
- MenuComponent、すべてのSearchComponents、すべてのFormComponentsをインポートします
- メニューをデフォルト/ランディングページのルートとして追加します(パス:'')
- 各プログラムのエンティティルート(検索、作成、編集)を定義します
- このルーティングテーブルは、d2-03(メニュー)、d2-04(検索)、d2-05(フォーム)で共通して使用します
import { Routes } from '@angular/router';
import { MenuComponent } from './pages/menu/menu.component';
import { <Entity>SearchComponent } from './pages/<entity>-search/<entity>-search.component';
import { <Entity>FormComponent } from './pages/<entity>-form/<entity>-form.component';
// Add more imports for additional entities as needed
export const routes: Routes = [
// Landing page (menu comes first!)
{ path: '', component: MenuComponent },
// <Entity> CRUD routes
{ path: '<entity>', component: <Entity>SearchComponent }, // Search/list page
{ path: '<entity>/new', component: <Entity>FormComponent }, // Create new record
{ path: '<entity>/:id/edit', component: <Entity>FormComponent }, // Edit existing record
// Add more entity routes here for additional programs:
// { path: 'customer', component: CustomerSearchComponent },
// { path: 'customer/new', component: CustomerFormComponent },
// { path: 'customer/:id/edit', component: CustomerFormComponent },
];
ルートの使用方法:
- d2-03-main-menuは
{ path: '', component: MenuComponent }を使用します — ランディングページ - d2-04-search-delete-pageは
/<entity>ルートを使用し、router.navigate(['/<entity>/new'])およびrouter.navigate(['/<entity>', id, 'edit'])で遷移します - d2-05-form-pageは
/<entity>/newおよび/<entity>/:id/editルートを使用します
コンポーネントのTypeScript(機能に応じて表示):
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { CommonModule } from '@angular/common';
interface MenuItem {
name: string;
icon: string;
path: string;
}
interface Program {
name: string;
entity: string;
icon: string;
description: string;
capabilities: string[];
menuItems: MenuItem[];
}
@Component({
selector: 'app-menu',
standalone: true,
imports: [CommonModule],
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.css']
})
export class MenuComponent {
appTitle = 'CRUD Dashboard';
appSubtitle = 'Manage your data with ease';
programs: Program[] = [];
constructor(private router: Router) {
this.programs = [
{
name: '<Entity>',
entity: '<entity>',
icon: '📦',
description: 'Manage <entity> records',
capabilities: ['search', 'create', 'save', 'delete'],
menuItems: this.generateMenuItems('<entity>', ['search', 'create', 'save', 'delete'])
},
// Add more programs here:
// { name: 'Customer', entity: 'customer', icon: '👥', description: 'Manage customer data', capabilities: [...], menuItems: ... }
];
}
generateMenuItems(entity: string, capabilities: string[]): MenuItem[] {
const items: MenuItem[] = [];
if (capabilities.includes('search')) {
items.push({ name: 'Browse', icon: '📋', path: `/${entity}` });
}
if (capabilities.includes('create')) {
items.push({ name: 'Create', icon: '✚', path: `/${entity}/new` });
}
return items;
}
navigate(path: string) {
this.router.navigate([path]);
}
}
テンプレート(機能に応じたメニュー、レスポンシブなカードグリッド、標準的なTailwindクラス):
<div class="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 p-6">
<div class="max-w-6xl mx-auto mb-12">
<div class="text-center mb-8">
<h1 class="text-5xl font-bold text-gray-900">{{ appTitle }}</h1>
<p class="text-gray-600 text-xl mt-4">{{ appSubtitle }}</p>
</div>
</div>
<div class="max-w-6xl mx-auto">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
@for (program of programs; track program.entity) {
<div class="bg-white rounded-xl shadow-md hover:shadow-xl transition-shadow p-6">
<div class="flex items-center mb-4">
<span class="text-5xl mr-4">{{ program.icon }}</span>
<div>
<h3 class="text-2xl font-bold text-gray-900">{{ program.name }}</h3>
<p class="text-gray-600 text-sm">{{ program.description }}</p>
</div>
</div>
<div class="flex flex-wrap gap-2 mb-4">
@for (cap of program.capabilities; track cap) {
<span class="bg-gray-100 text-gray-700 text-xs font-semibold px-3 py-1 rounded-full">
{{ cap }}
</span>
}
</div>
<div class="border-b border-gray-200 my-4"></div>
<div class="flex flex-col gap-4">
@for (item of program.menuItems; track item.name) {
<button
(click)="navigate(item.path)"
[class]="item.name === 'Browse' ? 'w-full text-white font-semibold px-6 py-3 rounded-lg transition bg-blue-500 hover:bg-blue-600' : 'w-full text-white font-semibold px-6 py-3 rounded-lg transition bg-green-500 hover:bg-green-600'"
>
{{ item.icon }} {{ item.name }}
</button>
}
</div>
@if (program.menuItems.length === 0) {
<p class="text-gray-600 text-sm text-center">No actions available for this program.</p>
}
</div>
}
</div>
</div>
<div class="max-w-6xl mx-auto mt-12 text-center">
<p class="text-gray-600 text-sm">Built with Angular + Tailwind CSS</p>
</div>
</div>
デザインシステム(標準的なTailwind):
- スペーシング: p-6(パディング)、mb-4/8/12、gap-2/4/8
- 色: bg-blue-500/600、bg-green-500/600、text-gray-600、bg-gray-100
- シャドウ: shadow-md、hover:shadow-xl(カードの浮き上がり)
- タイポグラフィ: text-5xl/2xl、font-bold/semibold
- レイアウト: レスポンシブグリッド(1〜3列)、flex flex-col
- インタラクション: rounded-lg、transition、ホバー状態
コメント
Markdown 対応