Initial baseline: LaraBlog core with plugin commerce surface.

Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
This commit is contained in:
ak
2026-08-12 01:15:38 +08:00
commit 263b98b218
337 changed files with 31393 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
<?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();
}),
];
}
}