关于 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 页面类(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 小组件)
- 每个标签页本质上就是“一组小组件”
- 小组件以
::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>
单标签页仪表板页面模板
当你希望页面表现为“一个标签页”但不显示导航时,请使用此模板。
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 |
| 视图 slug | Blade 文件的 kebab-case slug | 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 Page 类
- 完整的 Blade 视图文件
- 正确的命名空间和导入项
- 导航配置
- 包含小部件的标签页定义
- 带颜色标识的消息提示框
- 对无效标签页的回退处理
评论
支持 Markdown