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 页面类(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 小组件)

    • 每个标签页本质上就是“一组小组件”
    • 小组件以 ::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
视图 slugBlade 文件的 kebab-case slugbilling-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 Page 类
  2. 完整的 Blade 视图文件
  3. 正确的命名空间和导入项
  4. 导航配置
  5. 包含小部件的标签页定义
  6. 带颜色标识的消息提示框
  7. 对无效标签页的回退处理

评论

支持 Markdown