mcpField
D
dashboard

dashboard

github.com/mwguerra開発3671 回インストール26 週間前に更新
リポジトリ

dashboard について

FilamentPHP v4 のダッシュボードページを生成するスキルです。管理パネルの開発者向けに、単一・複数タブ、ウィジェット、ナビゲーション、タブのフォールバックを含む PHP と Blade のパターンを提供します。

主な機能

  1. 01PHP ページと Blade テンプレート
  2. 02単一タブと複数タブのレイアウト
  3. 03Livewire のリアクティブなタブ状態
  4. 04ウィジェット一覧と任意のコールアウト
  5. 05ナビゲーション設定とタブのフォールバック

活用シーン

  1. 01管理パネルのダッシュボードページ作成
  2. 02ウィジェットのタブ別整理
  3. 03色付きメッセージのページ追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mwguerra/claude-code-plugins --skill dashboard

インストール後、Claude Code で/dashboardを入力して読み込まれたか確認します。

詳細

FilamentPHP ダッシュボードページ生成スキル

概要

このスキルでは、一貫したパターンに沿った FilamentPHP v4 ダッシュボードページを生成します。

  • Filament\Pages\Page を継承します
  • シングルタブ(タブ UI なし)またはマルチタブのレイアウトに対応します
  • 色分けされたメッセージコールアウトを任意で含められます
  • 標準の Filament ウィジェットコンポーネントを使用してウィジェットをレンダリングします
  • $activeTab の状態を使用した Livewire のリアクティブなタブを実装します

ドキュメントの参照先

重要: ダッシュボードページを生成する前に、以下を確認してください。

  • /home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/docs/references/general/06-navigation/
  • /home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/docs/references/widgets/

パターンの構成

このスタイルのダッシュボードページは、次の 3 つの要素で構成されます。

  1. Filament Page クラス(PHP)

    • Filament\Pages\Page を継承します
    • $view を設定します
    • ナビゲーションメタデータ(アイコン/ラベル/グループ/順序)を宣言します
    • Livewire の公開状態 $activeTab を保持します
    • getTabs(): array と getActiveTabData(): ?array を提供します
  2. Blade ビュー(resources/views/filament/{panel}/pages/{slug}.blade.php)

    • タブナビゲーションをレンダリングします(マルチタブの場合は任意)
    • メッセージコールアウトをレンダリングします(色分け、任意)
    • 次を使用してウィジェットをレンダリングします:<x-filament-widgets::widgets :widgets="$activeTabData['widgets']" />
  3. ウィジェット(Filament Widgets)

    • 各タブは基本的に「ウィジェットのリスト」です
    • ウィジェットは ::class 文字列として指定します

タブスキーマの契約

各タブは次の配列スキーマに従う必要があります。

[
    'key' => 'overview',                     // Required: unique identifier
    'title' => 'Overview',                   // Required: display title
    'icon' => 'heroicon-o-chart-bar',        // Optional: Heroicon name
    'message' => '<strong>Note:</strong> ...', // Optional: HTML message
    'messageColor' => 'blue',                // Optional: blue|green|purple|orange|indigo|gray
    'widgets' => [                           // Optional: widget class references
        \App\Filament\Admin\Widgets\SomeWidget::class,
        \App\Filament\Admin\Widgets\AnotherWidget::class,
    ],
],

マルチタブダッシュボードページのテンプレート

PHP クラステンプレート
<?php

declare(strict_types=1);

namespace App\Filament\__PANEL__\Pages;

use BackedEnum;
use Filament\Pages\Page;

class __PAGE_CLASS__ extends Page
{
    protected static string $view = 'filament.__PANEL_LOWER__.pages.__VIEW_SLUG__';

    protected static string|BackedEnum|null $navigationIcon = '__HEROICON__';
    protected static ?string $navigationLabel = '__NAV_LABEL__';
    protected static \UnitEnum|string|null $navigationGroup = '__NAV_GROUP__';
    protected static ?int $navigationSort = __NAV_SORT__;

    public string $activeTab = '__DEFAULT_TAB_KEY__';

    /**
     * Get the tabs configuration for this dashboard page.
     *
     * @return array<int, array{
     *   key: string,
     *   title: string,
     *   icon?: string,
     *   message?: string,
     *   messageColor?: string,
     *   widgets?: array<int, class-string>
     * }>
     */
    public function getTabs(): array
    {
        return [
            [
                'key' => '__TAB_KEY__',
                'icon' => '__TAB_ICON__',
                'title' => '__TAB_TITLE__',
                'message' => '__TAB_MESSAGE_HTML__',
                'messageColor' => '__TAB_COLOR__',
                'widgets' => [
                    // \App\Filament\__PANEL__\Widgets\ExampleWidget::class,
                ],
            ],
            // Additional tabs...
        ];
    }

    /**
     * Get the data for the currently active tab.
     */
    public function getActiveTabData(): ?array
    {
        return collect($this->getTabs())->firstWhere('key', $this->activeTab);
    }
}
Blade ビューテンプレート(マルチタブ)
<x-filament-panels::page>
    @php
        $tabs = $this->getTabs();
        $activeTabData = $this->getActiveTabData();

        // If activeTab is invalid, fall back to first tab to avoid empty page.
        if (! $activeTabData && count($tabs) > 0) {
            $this->activeTab = $tabs[0]['key'];
            $activeTabData = $tabs[0];
        }
    @endphp

    <div class="space-y-6">
        {{-- Tabs Navigation --}}
        <div class="border-b border-gray-200 dark:border-gray-700">
            <nav class="-mb-px flex flex-wrap gap-x-8" aria-label="Tabs">
                @foreach($tabs as $tab)
                    <button
                        type="button"
                        wire:click="$set('activeTab', '{{ $tab['key'] }}')"
                        @class([
                            'flex items-center gap-2 whitespace-nowrap border-b-2 py-4 px-1 text-sm font-medium',
                            'border-primary-500 text-primary-600 dark:border-primary-400 dark:text-primary-400' => $activeTab === $tab['key'],
                            'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:text-gray-400 dark:hover:border-gray-600 dark:hover:text-gray-300' => $activeTab !== $tab['key'],
                        ])
                    >
                        @if(!empty($tab['icon']))
                            <x-filament::icon :icon="$tab['icon']" class="h-5 w-5" />
                        @endif

                        {{ $tab['title'] }}
                    </button>
                @endforeach
            </nav>
        </div>

        {{-- Tab Content --}}
        @if($activeTabData)
            <div class="space-y-6">
                @if(!empty($activeTabData['message']))
                    @php
                        $color = $activeTabData['messageColor'] ?? 'gray';
                    @endphp

                    <div @class([
                        'rounded-lg p-4 border',
                        'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800' => $color === 'blue',
                        'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800' => $color === 'green',
                        'bg-purple-50 dark:bg-purple-900/20 border-purple-200 dark:border-purple-800' => $color === 'purple',
                        'bg-orange-50 dark:bg-orange-900/20 border-orange-200 dark:border-orange-800' => $color === 'orange',
                        'bg-indigo-50 dark:bg-indigo-900/20 border-indigo-200 dark:border-indigo-800' => $color === 'indigo',
                        'bg-gray-50 dark:bg-gray-900/20 border-gray-200 dark:border-gray-800' => $color === 'gray',
                    ])>
                        <p @class([
                            'text-sm',
                            'text-blue-700 dark:text-blue-300' => $color === 'blue',
                            'text-green-700 dark:text-green-300' => $color === 'green',
                            'text-purple-700 dark:text-purple-300' => $color === 'purple',
                            'text-orange-700 dark:text-orange-300' => $color === 'orange',
                            'text-indigo-700 dark:text-indigo-300' => $color === 'indigo',
                            'text-gray-700 dark:text-gray-300' => $color === 'gray',
                        ])>
                            {!! $activeTabData['message'] !!}
                        </p>
                    </div>
                @endif

                @if(!empty($activeTabData['widgets']))
                    <x-filament-widgets::widgets :widgets="$activeTabData['widgets']" />
                @endif
            </div>
        @endif
    </div>
</x-filament-panels::page>

シングルタブダッシュボードページのテンプレート

ナビゲーションを表示せず、「1 つのタブ」のように動作するページを作成する場合に使用します。

PHP クラステンプレート(シングルタブ)
<?php

declare(strict_types=1);

namespace App\Filament\__PANEL__\Pages;

use BackedEnum;
use Filament\Pages\Page;

class __PAGE_CLASS__ extends Page
{
    protected static string $view = 'filament.__PANEL_LOWER__.pages.__VIEW_SLUG__';

    protected static string|BackedEnum|null $navigationIcon = '__HEROICON__';
    protected static ?string $navigationLabel = '__NAV_LABEL__';
    protected static \UnitEnum|string|null $navigationGroup = '__NAV_GROUP__';
    protected static ?int $navigationSort = __NAV_SORT__;

    public string $activeTab = 'main';

    /**
     * Get the tabs configuration (single tab for this page).
     *
     * @return array<int, array{
     *   key: string,
     *   title: string,
     *   message?: string,
     *   messageColor?: string,
     *   widgets?: array<int, class-string>
     * }>
     */
    public function getTabs(): array
    {
        return [
            [
                'key' => 'main',
                'title' => '__PAGE_TITLE__',
                'message' => '__MESSAGE_HTML__',
                'messageColor' => '__COLOR__',
                'widgets' => [
                    // \App\Filament\__PANEL__\Widgets\ExampleWidget::class,
                ],
            ],
        ];
    }

    /**
     * Get the data for the active tab (always the single main tab).
     */
    public function getActiveTabData(): ?array
    {
        return $this->getTabs()[0] ?? null;
    }
}
Blade ビューテンプレート(シングルタブ)
<x-filament-panels::page>
    @php
        $activeTabData = $this->getActiveTabData();
    @endphp

    <div class="space-y-6">
        @if($activeTabData)
            @if(!empty($activeTabData['message']))
                @php $color = $activeTabData['messageColor'] ?? 'gray'; @endphp

                <div @class([
                    'rounded-lg p-4 border',
                    'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800' => $color === 'blue',
                    'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800' => $color === 'green',
                    'bg-purple-50 dark:bg-purple-900/20 border-purple-200 dark:border-purple-800' => $color === 'purple',
                    'bg-orange-50 dark:bg-orange-900/20 border-orange-200 dark:border-orange-800' => $color === 'orange',
                    'bg-indigo-50 dark:bg-indigo-900/20 border-indigo-200 dark:border-indigo-800' => $color === 'indigo',
                    'bg-gray-50 dark:bg-gray-900/20 border-gray-200 dark:border-gray-800' => $color === 'gray',
                ])>
                    <p @class([
                        'text-sm',
                        'text-blue-700 dark:text-blue-300' => $color === 'blue',
                        'text-green-700 dark:text-green-300' => $color === 'green',
                        'text-purple-700 dark:text-purple-300' => $color === 'purple',
                        'text-orange-700 dark:text-orange-300' => $color === 'orange',
                        'text-indigo-700 dark:text-indigo-300' => $color === 'indigo',
                        'text-gray-700 dark:text-gray-300' => $color === 'gray',
                    ])>
                        {!! $activeTabData['message'] !!}
                    </p>
                </div>
            @endif

            @if(!empty($activeTabData['widgets']))
                <x-filament-widgets::widgets :widgets="$activeTabData['widgets']" />
            @endif
        @endif
    </div>
</x-filament-panels::page>

生成に必要な入力

ダッシュボードページを作成する際は、次の情報を収集するか、既定値を設定してください。

入力説明例
ページクラス名PascalCase のクラス名BillingDashboard
パネルパネル名(Admin、Support など)Admin
ビュースラッグBlade ファイルに使用する Kebab-case のスラッグbilling-dashboard
ナビゲーションラベルサイドバーに表示するテキストBilling
ナビゲーショングループサイドバー内のグループAnalytics
ナビゲーションアイコンHeroicon 名heroicon-o-chart-bar
ナビゲーションの順序数値の並び順10
モードsingle または multi タブmulti
タブタブ定義の配列上記のスキーマを参照
既定のタブキー最初にアクティブにするタブoverview

生成ワークフロー

1. 要件を解析する
  • ページ名とパネルを特定します
  • シングルタブかマルチタブかを判断します
  • ウィジェットを含めてタブを列挙します
2. PHP クラスを生成する
  • 適切なテンプレート(シングルまたはマルチ)を使用します
  • すべてのプレースホルダーを置き換えます
  • ウィジェットクラスへの参照を追加します
3. Blade ビューを生成する
  • 適切なテンプレート(シングルまたはマルチ)を使用します
  • ビューのパスをクラスの $view プロパティに合わせます
4. 出力を検証する
  • $view が Blade のパスと一致している
  • activeTab のキーが getTabs() に存在する
  • 各タブに key と title がある
  • ウィジェットが有効なクラス文字列である
  • activeTab が無効な場合、Blade がフォールバックする
  • メッセージに {!! !!} を使用するのは、信頼できる HTML の場合のみ

完全な例:アナリティクスダッシュボード

PHP クラス
<?php

declare(strict_types=1);

namespace App\Filament\Admin\Pages;

use BackedEnum;
use Filament\Pages\Page;

class Analytics extends Page
{
    protected static string $view = 'filament.admin.pages.analytics';

    protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-chart-bar';
    protected static ?string $navigationLabel = 'Analytics';
    protected static \UnitEnum|string|null $navigationGroup = 'Reports';
    protected static ?int $navigationSort = 10;

    public string $activeTab = 'overview';

    /**
     * @return array<int, array{
     *   key: string,
     *   title: string,
     *   icon?: string,
     *   message?: string,
     *   messageColor?: string,
     *   widgets?: array<int, class-string>
     * }>
     */
    public function getTabs(): array
    {
        return [
            [
                'key' => 'overview',
                'icon' => 'heroicon-o-home',
                'title' => 'Overview',
                'message' => '<strong>Overview:</strong> Key metrics and performance indicators at a glance.',
                'messageColor' => 'blue',
                'widgets' => [
                    \App\Filament\Admin\Widgets\StatsOverview::class,
                    \App\Filament\Admin\Widgets\RevenueChart::class,
                ],
            ],
            [
                'key' => 'users',
                'icon' => 'heroicon-o-users',
                'title' => 'Users',
                'message' => '<strong>User Analytics:</strong> Track user growth, engagement, and retention metrics.',
                'messageColor' => 'green',
                'widgets' => [
                    \App\Filament\Admin\Widgets\UserGrowthChart::class,
                    \App\Filament\Admin\Widgets\ActiveUsersWidget::class,
                ],
            ],
            [
                'key' => 'revenue',
                'icon' => 'heroicon-o-currency-dollar',
                'title' => 'Revenue',
                'message' => '<strong>Revenue Analytics:</strong> Monitor income streams and financial performance.',
                'messageColor' => 'purple',
                'widgets' => [
                    \App\Filament\Admin\Widgets\RevenueBreakdown::class,
                    \App\Filament\Admin\Widgets\TopProducts::class,
                ],
            ],
        ];
    }

    public function getActiveTabData(): ?array
    {
        return collect($this->getTabs())->firstWhere('key', $this->activeTab);
    }
}

規約

  • タブキーには snake_case または kebab-case を使用します(どちらかに統一してください)
  • $activeTab は getTabs() の key と一致している必要があります
  • message は {!! !!} でレンダリングされるため、信頼できる HTML のみを使用してください
  • ウィジェットは ::class 文字列として指定します
  • ナビゲーションアイコンには Heroicon 名を使用します(例:heroicon-o-chart-bar)
  • 使用できるメッセージの色:blue、green、purple、orange、indigo、gray

出力

生成されるダッシュボードページには、以下が含まれます。

  1. 完全な PHP ページクラス
  2. 完全な Blade ビューファイル
  3. 適切な名前空間とインポート
  4. ナビゲーション設定
  5. ウィジェットを含むタブ定義
  6. 色分けされたメッセージコールアウト
  7. 無効なタブに対するフォールバック処理

コメント