feat: restore sablog browse modes and clean imported HTML
Keep the public site readable after import (nbsp, highlighter, wrapping code, compact pager) and finish the admin extras already in this tree: sticky levels, preview, page cache, and live llms.txt. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -42,6 +42,7 @@ class BlogSettings extends Page
|
||||
// 外观
|
||||
'active_theme' => Setting::get('active_theme', config('themes.default')),
|
||||
'per_page' => Setting::get('per_page', config('blog.per_page')),
|
||||
'home_view_mode' => Setting::get('home_view_mode', config('blog.home_view_mode', 'list')),
|
||||
'list_shownum' => Setting::get('list_shownum', '50'),
|
||||
'listtime' => Setting::get('listtime', 'Y-m-d'),
|
||||
'normaltime' => Setting::get('normaltime', 'Y-m-d H:i'),
|
||||
@@ -102,6 +103,13 @@ class BlogSettings extends Page
|
||||
->columnSpanFull()
|
||||
->options(collect(app(\App\Blog\Support\ThemeManager::class)->all())->pluck('title', 'name')),
|
||||
TextInput::make('per_page')->label('首页每页文章数')->numeric(),
|
||||
Select::make('home_view_mode')
|
||||
->label('首页浏览模式')
|
||||
->options([
|
||||
'list' => '列表(标题 + 摘要)',
|
||||
'full' => '标准(全文)',
|
||||
])
|
||||
->helperText('前台右上角仍可临时切换,和老 sablog 的「标准 | 列表」一样'),
|
||||
TextInput::make('list_shownum')->label('列表每页数量')->numeric()->helperText('分类/标签/搜索等列表页'),
|
||||
TextInput::make('listtime')->label('列表时间格式')->placeholder('Y-m-d'),
|
||||
TextInput::make('normaltime')->label('详情时间格式')->placeholder('Y-m-d H:i'),
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use Filament\Pages\Page;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class Languages extends Page
|
||||
{
|
||||
protected static \UnitEnum|string|null $navigationGroup = '管理';
|
||||
|
||||
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-language';
|
||||
|
||||
protected static ?string $navigationLabel = '语言';
|
||||
|
||||
protected static ?string $title = '语言';
|
||||
|
||||
protected static ?string $slug = 'languages';
|
||||
|
||||
protected static ?int $navigationSort = 21;
|
||||
|
||||
protected string $view = 'filament.pages.languages';
|
||||
|
||||
/**
|
||||
* @return array{
|
||||
* locale: string,
|
||||
* fallback: string,
|
||||
* faker: string,
|
||||
* app_files: list<string>,
|
||||
* filament_locales: list<string>,
|
||||
* content_i18n: bool
|
||||
* }
|
||||
*/
|
||||
public function getInfoProperty(): array
|
||||
{
|
||||
return [
|
||||
'locale' => app()->getLocale(),
|
||||
'fallback' => (string) config('app.fallback_locale'),
|
||||
'faker' => (string) config('app.faker_locale'),
|
||||
'app_files' => $this->appLanguageFiles(),
|
||||
'filament_locales' => $this->filamentLocales(),
|
||||
'content_i18n' => false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function appLanguageFiles(): array
|
||||
{
|
||||
$found = [];
|
||||
|
||||
foreach (File::glob(lang_path('*.json')) as $file) {
|
||||
$found[] = basename((string) $file, '.json');
|
||||
}
|
||||
|
||||
foreach (File::directories(lang_path()) as $directory) {
|
||||
$name = basename($directory);
|
||||
if ($name === 'vendor') {
|
||||
continue;
|
||||
}
|
||||
$found[] = $name;
|
||||
}
|
||||
|
||||
$found = array_values(array_unique($found));
|
||||
sort($found);
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function filamentLocales(): array
|
||||
{
|
||||
$path = lang_path('vendor/filament');
|
||||
if (! File::isDirectory($path)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$locales = array_map(
|
||||
static fn (string $directory): string => basename($directory),
|
||||
File::directories($path)
|
||||
);
|
||||
sort($locales);
|
||||
|
||||
return $locales;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Pages;
|
||||
|
||||
use App\Blog\Support\PageCacheMiddleware;
|
||||
use App\Models\Setting;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Notifications\Notification;
|
||||
use Filament\Pages\Page;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class PageCache extends Page
|
||||
{
|
||||
protected static \UnitEnum|string|null $navigationGroup = '管理';
|
||||
|
||||
protected static string|\BackedEnum|null $navigationIcon = 'heroicon-o-bolt';
|
||||
|
||||
protected static ?string $navigationLabel = '页面缓存';
|
||||
|
||||
protected static ?string $title = '页面缓存';
|
||||
|
||||
protected static ?string $slug = 'page-cache';
|
||||
|
||||
protected static ?int $navigationSort = 20;
|
||||
|
||||
protected string $view = 'filament.pages.page-cache';
|
||||
|
||||
/**
|
||||
* @return array{hits: int, misses: int, count: int, rate: float, ttl: int}
|
||||
*/
|
||||
public function getStatsProperty(): array
|
||||
{
|
||||
return [
|
||||
...PageCacheMiddleware::stats(),
|
||||
'ttl' => (int) config('blog.page_cache_ttl', 300),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{key: string, url: string, cached_at: string}>
|
||||
*/
|
||||
public function getEntriesProperty(): array
|
||||
{
|
||||
return PageCacheMiddleware::entries();
|
||||
}
|
||||
|
||||
public function flushPageCache(): void
|
||||
{
|
||||
PageCacheMiddleware::flush();
|
||||
Notification::make()->title('前台页面缓存已清空')->success()->send();
|
||||
}
|
||||
|
||||
public function flushAllCache(): void
|
||||
{
|
||||
PageCacheMiddleware::flush();
|
||||
Setting::flushCache();
|
||||
Cache::flush();
|
||||
Notification::make()->title('全部缓存已清空')->success()->send();
|
||||
}
|
||||
|
||||
public function resetStats(): void
|
||||
{
|
||||
PageCacheMiddleware::resetStats();
|
||||
Notification::make()->title('命中统计已重置')->success()->send();
|
||||
}
|
||||
|
||||
public function forgetEntry(string $key): void
|
||||
{
|
||||
PageCacheMiddleware::forget($key);
|
||||
Notification::make()->title('已删除这条缓存')->success()->send();
|
||||
}
|
||||
|
||||
protected function getHeaderActions(): array
|
||||
{
|
||||
return [
|
||||
Action::make('resetStats')
|
||||
->label('重置统计')
|
||||
->color('gray')
|
||||
->action(fn () => $this->resetStats()),
|
||||
Action::make('flushPageCache')
|
||||
->label('清空前台缓存')
|
||||
->color('warning')
|
||||
->action(fn () => $this->flushPageCache()),
|
||||
Action::make('flushAllCache')
|
||||
->label('清空全部缓存')
|
||||
->color('danger')
|
||||
->requiresConfirmation()
|
||||
->action(fn () => $this->flushAllCache()),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user