default() ->id('admin') ->path('admin') ->login() ->colors([ 'primary' => Color::Sky, ]) ->brandName(config('blog.name')) ->spa() ->sidebarWidth('13rem') ->maxContentWidth(\Filament\Support\Enums\Width::Full) ->userMenuItems([ // 工具:同步旧站数据(sablog 增量导入,约 1 分钟) \Filament\Actions\Action::make('sablog-import') ->label('同步旧站数据') ->icon('heroicon-o-arrow-path') ->color('info') ->requiresConfirmation() ->modalDescription('从旧 sablog 库增量导入文章/评论/标签等(幂等,不会产生重复),约需 1 分钟,期间请不要重复点击。') ->action(function (): void { $src = config('blog.sablog_source'); try { \Illuminate\Support\Facades\Artisan::call('sablog:import', [ '--host' => $src['host'], '--port' => $src['port'], '--database' => $src['database'], '--username' => $src['username'], '--password' => $src['password'], '--prefix' => $src['prefix'], ]); $output = trim(\Illuminate\Support\Facades\Artisan::output()); \App\Blog\Support\PageCacheMiddleware::flush(); \Filament\Notifications\Notification::make() ->title('旧站数据同步完成') ->body(\Illuminate\Support\Str::afterLast($output, '报告:') ?: $output) ->success() ->persistent() ->send(); } catch (\Throwable $e) { \Filament\Notifications\Notification::make() ->title('同步失败') ->body($e->getMessage()) ->danger() ->persistent() ->send(); } }), // 工具:清空缓存(Livewire action,即时通知) \Filament\Actions\Action::make('flush-page-cache') ->label('清空前台缓存') ->icon('heroicon-o-bolt') ->color('warning') ->action(function (): void { \App\Blog\Support\PageCacheMiddleware::flush(); \Filament\Notifications\Notification::make()->title('前台页面缓存已清空')->success()->send(); }), \Filament\Actions\Action::make('flush-all-cache') ->label('清空全部缓存') ->icon('heroicon-o-trash') ->color('danger') ->requiresConfirmation() ->action(function (): void { \App\Blog\Support\PageCacheMiddleware::flush(); \App\Models\Setting::flushCache(); \Illuminate\Support\Facades\Cache::flush(); \Filament\Notifications\Notification::make()->title('全部缓存已清空')->success()->send(); }), \Filament\Actions\Action::make('blog-settings') ->label('博客设置') ->icon('heroicon-o-cog-6-tooth') ->url(fn (): string => \App\Filament\Pages\BlogSettings::getUrl()), \Filament\Actions\Action::make('theme-inject') ->label('主题注入') ->icon('heroicon-o-squares-plus') ->url(fn (): string => \App\Filament\Pages\ThemeInject::getUrl()), ]) ->renderHook( PanelsRenderHook::USER_MENU_BEFORE, fn (): \Illuminate\Contracts\View\View => view('filament.hooks.topbar-tools') ) ->navigationGroups([ NavigationGroup::make('内容'), NavigationGroup::make('管理'), NavigationGroup::make('插件'), ]) ->discoverResources(in: app_path('Filament/Resources'), for: 'App\Filament\Resources') ->discoverPages(in: app_path('Filament/Pages'), for: 'App\Filament\Pages') ->pages([ Dashboard::class, ...\App\Blog\Support\PluginPages::pages(), ]) ->resources([ PostResource::class, CategoryResource::class, CommentResource::class, LinkResource::class, MediaResource::class, UserResource::class, ...\App\Blog\Support\PluginPages::resources(), ]) ->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets') ->widgets([ AccountWidget::class, ]) ->plugins([ MediaLibraryPlugin::make() ->navigationGroup((string) config('filament-media-library.navigation_group', '内容')), ]) ->middleware([ EncryptCookies::class, AddQueuedCookiesToResponse::class, StartSession::class, AuthenticateSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class, SubstituteBindings::class, DisableBladeIconComponents::class, DispatchServingFilamentEvent::class, ]) ->authMiddleware([ Authenticate::class, ]); } }