filament-dashboard
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFilamentPHP Dashboard Page Generation Skill
FilamentPHP仪表盘页面生成技能
Overview
概述
This skill generates FilamentPHP v4 dashboard pages that follow a consistent pattern:
- Extends
Filament\Pages\Page - Supports single-tab (no tabs UI) or multi-tab layouts
- Includes optional color-coded message callouts
- Renders widgets using the standard Filament widgets component
- Uses Livewire reactive tabs with state
$activeTab
本技能生成遵循统一模式的FilamentPHP v4仪表盘页面:
- 继承
Filament\Pages\Page - 支持单标签(无标签UI)或多标签布局
- 包含可选的彩色编码消息提示框
- 使用标准Filament Widgets组件渲染Widget
- 结合Livewire响应式标签与状态
$activeTab
Documentation Reference
文档参考
CRITICAL: Before generating dashboard pages, read:
/home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/filament-docs/references/general/06-navigation//home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/filament-docs/references/widgets/
重要提示: 在生成仪表盘页面之前,请阅读:
/home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/filament-docs/references/general/06-navigation//home/mwguerra/projects/mwguerra/claude-code-plugins/filament-specialist/skills/filament-docs/references/widgets/
Pattern Architecture
架构模式
A dashboard page in this style has 3 pieces:
-
Filament Page class (PHP)
- Extends
Filament\Pages\Page - Sets
$view - Declares navigation metadata (icon/label/group/sort)
- Stores Livewire public state:
$activeTab - Provides and
getTabs(): arraygetActiveTabData(): ?array
- Extends
-
Blade view ()
resources/views/filament/{panel}/pages/{slug}.blade.php- Renders tabs navigation (optional, for multi-tab)
- Renders optional message callout (color-coded)
- Renders widgets using:
<x-filament-widgets::widgets :widgets="$activeTabData['widgets']" />
-
Widgets (Filament Widgets)
- Each tab is basically "a widget list"
- Widgets are referenced as strings
::class
该风格的仪表盘页面包含3个部分:
-
Filament Page类(PHP)
- 继承
Filament\Pages\Page - 设置属性
$view - 声明导航元数据(图标/标签/分组/排序)
- 存储Livewire公共状态:
$activeTab - 提供和
getTabs(): array方法getActiveTabData(): ?array
- 继承
-
Blade视图()
resources/views/filament/{panel}/pages/{slug}.blade.php- 渲染标签导航(可选,适用于多标签布局)
- 渲染可选的消息提示框(彩色编码)
- 使用渲染Widget
<x-filament-widgets::widgets :widgets="$activeTabData['widgets']" />
-
Widgets(Filament Widgets)
- 每个标签本质上是“一个Widget列表”
- Widget以字符串形式引用
::class
Tab Schema Contract
标签架构约定
Each tab must follow this array schema:
php
[
'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
[
'key' => 'overview', // 必填:唯一标识符
'title' => 'Overview', // 必填:显示标题
'icon' => 'heroicon-o-chart-bar', // 可选:Heroicon图标名称
'message' => '<strong>Note:</strong> ...', // 可选:HTML格式消息
'messageColor' => 'blue', // 可选:blue|green|purple|orange|indigo|gray
'widgets' => [ // 可选:Widget类引用
\App\Filament\Admin\Widgets\SomeWidget::class,
\App\Filament\Admin\Widgets\AnotherWidget::class,
],
],Multi-Tab Dashboard Page Template
多标签仪表盘页面模板
PHP Class Template
PHP类模板
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);
}
}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__';
/**
* 获取此仪表盘页面的标签配置。
*
* @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,
],
],
// 更多标签...
];
}
/**
* 获取当前激活标签的数据。
*/
public function getActiveTabData(): ?array
{
return collect($this->getTabs())->firstWhere('key', $this->activeTab);
}
}Blade View Template (Multi-Tab)
Blade视图模板(多标签)
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>blade
<x-filament-panels::page>
@php
$tabs = $this->getTabs();
$activeTabData = $this->getActiveTabData();
// 如果activeTab无效,回退到第一个标签以避免页面为空。
if (! $activeTabData && count($tabs) > 0) {
$this->activeTab = $tabs[0]['key'];
$activeTabData = $tabs[0];
}
@endphp
<div class="space-y-6">
{{-- 标签导航 --}}
<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>
{{-- 标签内容 --}}
@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>Single-Tab Dashboard Page Template
单标签仪表盘页面模板
Use this when you want a page that behaves like "one tab" without showing navigation.
当你需要一个表现得像“单个标签”且不显示导航的页面时,使用此模板。
PHP Class Template (Single-Tab)
PHP类模板(单标签)
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;
}
}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';
/**
* 获取标签配置(此页面为单个标签)。
*
* @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,
],
],
];
}
/**
* 获取激活标签的数据(始终为单个主标签)。
*/
public function getActiveTabData(): ?array
{
return $this->getTabs()[0] ?? null;
}
}Blade View Template (Single-Tab)
Blade视图模板(单标签)
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>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>Inputs Required for Generation
生成所需输入
When creating a dashboard page, collect or assume defaults for:
| Input | Description | Example |
|---|---|---|
| Page class name | PascalCase class name | |
| Panel | Panel name (Admin, Support, etc.) | |
| View slug | Kebab-case slug for blade file | |
| Navigation label | Display text in sidebar | |
| Navigation group | Group in sidebar | |
| Navigation icon | Heroicon name | |
| Navigation sort | Numeric sort order | |
| Mode | | |
| Tabs | Array of tab definitions | See schema above |
| Default tab key | First active tab | |
创建仪表盘页面时,需收集或使用默认值的参数:
| 输入项 | 描述 | 示例 |
|---|---|---|
| 页面类名称 | 大驼峰式类名 | |
| 面板 | 面板名称(如Admin、Support等) | |
| 视图别名 | Blade文件的短横线式别名 | |
| 导航标签 | 侧边栏显示文本 | |
| 导航分组 | 侧边栏分组 | |
| 导航图标 | Heroicon图标名称 | |
| 导航排序 | 数字排序顺序 | |
| 模式 | | |
| 标签 | 标签定义数组 | 参见上方架构 |
| 默认标签键 | 初始激活标签 | |
Generation Workflow
生成流程
1. Parse Requirements
1. 解析需求
- Identify page name and panel
- Determine single-tab vs multi-tab mode
- List tabs with their widgets
- 确定页面名称和面板
- 确定单标签或多标签模式
- 列出包含Widget的标签
2. Generate PHP Class
2. 生成PHP类
- Use appropriate template (single or multi)
- Replace all placeholders
- Add widget class references
- 使用对应模板(单标签或多标签)
- 替换所有占位符
- 添加Widget类引用
3. Generate Blade View
3. 生成Blade视图
- Use appropriate template (single or multi)
- Match view path to class property
$view
- 使用对应模板(单标签或多标签)
- 确保视图路径与类的属性匹配
$view
4. Verify Output
4. 验证输出
- matches the Blade path
$view - key exists in
activeTabgetTabs() - Each tab has and
keytitle - Widgets are valid class strings
- Blade falls back if invalid
activeTab - Message uses only with trusted HTML
{!! !!}
- 与Blade路径匹配
$view - 键存在于
activeTab中getTabs() - 每个标签都有和
keytitle - Widget是有效的类字符串
- 当无效时Blade会回退
activeTab - 消息仅在可信HTML中使用
{!! !!}
Complete Example: Analytics Dashboard
完整示例:分析仪表盘
PHP Class
PHP类
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);
}
}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);
}
}Conventions
约定
- Tab keys should use snake_case or kebab-case (be consistent)
- must match a
$activeTabfromkeygetTabs() - is rendered with
message— only use trusted HTML{!! !!} - Widgets are referenced as strings
::class - Navigation icons use Heroicon names (e.g., )
heroicon-o-chart-bar - Available message colors: ,
blue,green,purple,orange,indigogray
- 标签键应使用蛇形命名法或短横线命名法(保持一致)
- 必须与
$activeTab中的某个getTabs()匹配key - 消息使用渲染 — 仅使用可信HTML
{!! !!} - Widget以字符串形式引用
::class - 导航图标使用Heroicon名称(如)
heroicon-o-chart-bar - 可用消息颜色:,
blue,green,purple,orange,indigogray
Output
输出
Generated dashboard pages include:
- Complete PHP Page class
- Complete Blade view file
- Proper namespace and imports
- Navigation configuration
- Tab definitions with widgets
- Color-coded message callouts
- Fallback handling for invalid tabs
生成的仪表盘页面包含:
- 完整的PHP Page类
- 完整的Blade视图文件
- 正确的命名空间和导入
- 导航配置
- 包含Widget的标签定义
- 彩色编码的消息提示框
- 无效标签的回退处理