Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
114 lines
3.9 KiB
PHP
114 lines
3.9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace App\Filament\Pages;
|
||
|
||
use App\Domain\Theme\ThemeManager;
|
||
use App\Settings\GeneralSettings;
|
||
use BackedEnum;
|
||
use Filament\Actions\Action;
|
||
use Filament\Notifications\Notification;
|
||
use Filament\Pages\Page;
|
||
use Filament\Support\Icons\Heroicon;
|
||
use Illuminate\Support\Facades\Artisan;
|
||
use UnitEnum;
|
||
|
||
class ManageThemes extends Page
|
||
{
|
||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedSwatch;
|
||
|
||
protected static ?int $navigationSort = 80;
|
||
|
||
protected string $view = 'filament.pages.manage-themes';
|
||
|
||
public string $activeTheme = 'default';
|
||
|
||
/** @var array<int, array<string, mixed>> */
|
||
public array $themes = [];
|
||
|
||
public static function getNavigationGroup(): ?string
|
||
{
|
||
return __('admin.groups.system');
|
||
}
|
||
|
||
public static function getNavigationLabel(): string
|
||
{
|
||
return __('admin.nav.themes');
|
||
}
|
||
|
||
public function getTitle(): string
|
||
{
|
||
return __('admin.pages.themes_title');
|
||
}
|
||
|
||
public function mount(ThemeManager $themes, GeneralSettings $settings): void
|
||
{
|
||
$this->reload($themes, $settings);
|
||
}
|
||
|
||
public function activate(string $slug, ThemeManager $themes, GeneralSettings $settings): void
|
||
{
|
||
$themes->setActive($slug);
|
||
Artisan::call('themes:publish', ['theme' => $slug]);
|
||
$this->reload($themes, $settings);
|
||
|
||
$report = $themes->slotReport($slug);
|
||
$notification = Notification::make()->title(__('admin.pages.activate').':'.$slug);
|
||
|
||
if (($report['status'] ?? '') === 'full') {
|
||
$notification->success()->send();
|
||
|
||
return;
|
||
}
|
||
|
||
$notification
|
||
->warning()
|
||
->body(__('admin.messages.theme_slots_warn', [
|
||
'label' => $report['label'] ?? __('admin.slots.status_undeclared'),
|
||
]))
|
||
->send();
|
||
}
|
||
|
||
protected function reload(ThemeManager $themes, GeneralSettings $settings): void
|
||
{
|
||
$this->activeTheme = $settings->active_theme ?: 'default';
|
||
$this->themes = $themes->discover()->map(function (array $theme) use ($themes) {
|
||
$slug = (string) ($theme['slug'] ?? $theme['name'] ?? '');
|
||
$titleKey = 'admin.themes.'.$slug.'.title';
|
||
$descKey = 'admin.themes.'.$slug.'.description';
|
||
$previewFile = base_path('themes/'.$slug.'/assets/preview.svg');
|
||
$report = $theme['slot_report'] ?? $themes->slotReport($slug);
|
||
|
||
return [
|
||
'slug' => $slug,
|
||
'title' => __($titleKey) !== $titleKey ? __($titleKey) : ($theme['title'] ?? $slug),
|
||
'description' => __($descKey) !== $descKey ? __($descKey) : ($theme['description'] ?? ''),
|
||
'version' => $theme['version'] ?? '1.0.0',
|
||
'preview' => is_file($previewFile)
|
||
? url('/themes/'.$slug.'/preview.svg').'?v='.filemtime($previewFile)
|
||
: null,
|
||
'slots_status' => $report['status'] ?? 'undeclared',
|
||
'slots_label' => $report['label'] ?? __('admin.slots.status_undeclared'),
|
||
'slots_missing' => $report['missing_standard'] ?? [],
|
||
'slots_declared_count' => count($report['declared'] ?? []),
|
||
];
|
||
})->values()->all();
|
||
}
|
||
|
||
protected function getHeaderActions(): array
|
||
{
|
||
return [
|
||
Action::make('refresh')
|
||
->label(__('admin.pages.themes_refresh'))
|
||
->action(fn (ThemeManager $themes, GeneralSettings $settings) => $this->reload($themes, $settings)),
|
||
Action::make('publish')
|
||
->label(__('admin.pages.themes_publish'))
|
||
->action(function (): void {
|
||
Artisan::call('themes:publish');
|
||
Notification::make()->title(__('admin.pages.themes_publish'))->success()->send();
|
||
}),
|
||
];
|
||
}
|
||
}
|