dashboard について
FilamentPHP v4 のダッシュボードページを生成するスキルです。管理パネルの開発者向けに、単一・複数タブ、ウィジェット、ナビゲーション、タブのフォールバックを含む PHP と Blade のパターンを提供します。
主な機能
- 01PHP ページと Blade テンプレート
- 02単一タブと複数タブのレイアウト
- 03Livewire のリアクティブなタブ状態
- 04ウィジェット一覧と任意のコールアウト
- 05ナビゲーション設定とタブのフォールバック
活用シーン
- 01管理パネルのダッシュボードページ作成
- 02ウィジェットのタブ別整理
- 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 つの要素で構成されます。
-
Filament Page クラス(PHP)
Filament\Pages\Pageを継承します$viewを設定します- ナビゲーションメタデータ(アイコン/ラベル/グループ/順序)を宣言します
- Livewire の公開状態
$activeTabを保持します getTabs(): arrayとgetActiveTabData(): ?arrayを提供します
-
Blade ビュー(
resources/views/filament/{panel}/pages/{slug}.blade.php)- タブナビゲーションをレンダリングします(マルチタブの場合は任意)
- メッセージコールアウトをレンダリングします(色分け、任意)
- 次を使用してウィジェットをレンダリングします:
<x-filament-widgets::widgets :widgets="$activeTabData['widgets']" />
-
ウィジェット(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
出力
生成されるダッシュボードページには、以下が含まれます。
- 完全な PHP ページクラス
- 完全な Blade ビューファイル
- 適切な名前空間とインポート
- ナビゲーション設定
- ウィジェットを含むタブ定義
- 色分けされたメッセージコールアウト
- 無効なタブに対するフォールバック処理
コメント
Markdown 対応