feat: 插件/主题管理卡片改用 Filament 原生组件+中文页面标题;注入点分三组管理(页面/侧边栏/文章);前台 sablog 主题全面语义化(header/nav/main/aside/section/footer)
This commit is contained in:
@@ -26,6 +26,8 @@ class BlogSettings extends Page
|
||||
|
||||
protected static ?string $navigationLabel = '博客设置';
|
||||
|
||||
protected static ?string $title = '博客设置';
|
||||
|
||||
protected string $view = 'filament.pages.blog-settings';
|
||||
|
||||
public array $data = [];
|
||||
|
||||
@@ -23,6 +23,8 @@ class Plugins extends Page
|
||||
|
||||
protected static ?string $navigationLabel = '插件管理';
|
||||
|
||||
protected static ?string $title = '插件管理';
|
||||
|
||||
protected string $view = 'filament.pages.plugins';
|
||||
|
||||
public $zip;
|
||||
|
||||
@@ -30,6 +30,8 @@ class ThemeInject extends Page
|
||||
|
||||
protected static ?string $navigationLabel = '主题注入';
|
||||
|
||||
protected static ?string $title = '主题注入';
|
||||
|
||||
protected string $view = 'filament.pages.theme-inject';
|
||||
|
||||
public array $data = [];
|
||||
@@ -44,27 +46,36 @@ class ThemeInject extends Page
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
{
|
||||
$tabs = [];
|
||||
$i = 0;
|
||||
$groups = [
|
||||
'页面级' => ['head', 'header', 'content_top', 'content_bottom', 'footer', 'body_end'],
|
||||
'侧边栏级' => ['sidebar_top', 'sidebar_bottom'],
|
||||
'文章级' => ['post_content_top', 'post_content_bottom'],
|
||||
];
|
||||
|
||||
foreach (ThemeInjector::POINTS as $point => $label) {
|
||||
$tabs[] = Tab::make(($i + 1).'. '.$label)
|
||||
->schema([
|
||||
Repeater::make("inject.{$point}")
|
||||
->label('注入块(可多条,拖拽排序,按顺序渲染)')
|
||||
->schema([
|
||||
TextInput::make('title')->label('名称')->placeholder('如:百度统计')->columnSpan(2),
|
||||
Textarea::make('html')->label('内容(HTML)')->rows(3)->columnSpanFull(),
|
||||
Toggle::make('enabled')->label('启用')->default(true),
|
||||
])
|
||||
->columns(3)
|
||||
->defaultItems(0)
|
||||
->collapsible()
|
||||
->reorderable()
|
||||
->reorderableWithButtons()
|
||||
->addActionLabel('添加一条'),
|
||||
]);
|
||||
$i++;
|
||||
$tabs = [];
|
||||
|
||||
foreach ($groups as $groupLabel => $points) {
|
||||
$sections = [];
|
||||
foreach ($points as $point) {
|
||||
$sections[] = \Filament\Schemas\Components\Section::make(ThemeInjector::POINTS[$point])
|
||||
->description($point)
|
||||
->schema([
|
||||
Repeater::make("inject.{$point}")
|
||||
->label('注入块(多条按拖拽顺序渲染)')
|
||||
->schema([
|
||||
TextInput::make('title')->label('名称')->placeholder('如:百度统计')->columnSpan(2),
|
||||
Textarea::make('html')->label('内容(HTML)')->rows(3)->columnSpanFull(),
|
||||
Toggle::make('enabled')->label('启用')->default(true),
|
||||
])
|
||||
->columns(3)
|
||||
->defaultItems(0)
|
||||
->collapsible()
|
||||
->reorderable()
|
||||
->reorderableWithButtons()
|
||||
->addActionLabel('添加一条'),
|
||||
]);
|
||||
}
|
||||
$tabs[] = Tab::make($groupLabel)->schema($sections);
|
||||
}
|
||||
|
||||
$tabs[] = Tab::make('主题变量(stylevar)')
|
||||
|
||||
@@ -21,6 +21,8 @@ class Themes extends Page
|
||||
|
||||
protected static ?string $navigationLabel = '主题管理';
|
||||
|
||||
protected static ?string $title = '主题管理';
|
||||
|
||||
protected string $view = 'filament.pages.themes';
|
||||
|
||||
public $zip;
|
||||
|
||||
@@ -2,35 +2,33 @@
|
||||
<x-filament::section heading="已安装插件">
|
||||
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
@forelse($this->plugins as $plugin)
|
||||
<div class="flex flex-col rounded-xl border border-gray-200 bg-white p-5 shadow-sm dark:border-white/10 dark:bg-white/5">
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<div class="flex h-11 w-11 shrink-0 items-center justify-center rounded-lg bg-primary-50 text-primary-600 dark:bg-primary-500/10">
|
||||
<x-filament::icon icon="heroicon-o-puzzle-piece" class="h-6 w-6" />
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<x-filament::section :compact="true">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-start justify-between gap-3">
|
||||
<x-filament::icon icon="heroicon-o-puzzle-piece" class="h-8 w-8 text-primary-600" />
|
||||
@if($plugin['enabled'])
|
||||
<x-filament::badge color="success">已启用</x-filament::badge>
|
||||
@else
|
||||
<x-filament::badge color="gray">已停用</x-filament::badge>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="mt-3 font-semibold">{{ $plugin['title'] }}</h3>
|
||||
<p class="mt-1 flex-1 text-sm text-gray-500 dark:text-gray-400">{{ $plugin['description'] }}</p>
|
||||
<p class="mt-1 text-xs text-gray-400">v{{ $plugin['version'] }} · {{ $plugin['vendor'] }}.{{ $plugin['name'] }}</p>
|
||||
<h3 class="mt-3 text-base font-semibold">{{ $plugin['title'] }}</h3>
|
||||
<p class="mt-1 flex-1 text-sm text-gray-500 dark:text-gray-400">{{ $plugin['description'] }}</p>
|
||||
<p class="mt-2 text-xs text-gray-400">v{{ $plugin['version'] }} · {{ $plugin['vendor'] }}.{{ $plugin['name'] }}</p>
|
||||
|
||||
<div class="mt-4 flex gap-2">
|
||||
@if($plugin['enabled'])
|
||||
<x-filament::button size="sm" color="gray" wire:click="disablePlugin('{{ $plugin['key'] }}')">停用</x-filament::button>
|
||||
@else
|
||||
<x-filament::button size="sm" color="success" wire:click="enablePlugin('{{ $plugin['key'] }}')">启用</x-filament::button>
|
||||
@endif
|
||||
@if(! in_array($plugin['key'], config('plugins.enabled', []), true))
|
||||
<x-filament::button size="sm" color="danger" wire:click="uninstallPlugin('{{ $plugin['key'] }}')" wire:confirm="确定卸载该插件?">卸载</x-filament::button>
|
||||
@endif
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
@if($plugin['enabled'])
|
||||
<x-filament::button size="sm" color="gray" wire:click="disablePlugin('{{ $plugin['key'] }}')">停用</x-filament::button>
|
||||
@else
|
||||
<x-filament::button size="sm" color="success" wire:click="enablePlugin('{{ $plugin['key'] }}')">启用</x-filament::button>
|
||||
@endif
|
||||
@if(! in_array($plugin['key'], config('plugins.enabled', []), true))
|
||||
<x-filament::button size="sm" color="danger" wire:click="uninstallPlugin('{{ $plugin['key'] }}')" wire:confirm="确定卸载该插件?">卸载</x-filament::button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-filament::section>
|
||||
@empty
|
||||
<p class="text-sm text-gray-500">暂无插件</p>
|
||||
@endforelse
|
||||
@@ -55,17 +53,17 @@
|
||||
</div>
|
||||
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||
@forelse($marketItems as $index => $item)
|
||||
<div class="flex flex-col rounded-xl border border-gray-200 bg-white p-5 shadow-sm dark:border-white/10 dark:bg-white/5">
|
||||
<div class="flex h-11 w-11 items-center justify-center rounded-lg bg-primary-50 text-primary-600 dark:bg-primary-500/10">
|
||||
<x-filament::icon icon="heroicon-o-cloud-arrow-down" class="h-6 w-6" />
|
||||
<x-filament::section :compact="true">
|
||||
<div class="flex flex-col">
|
||||
<x-filament::icon icon="heroicon-o-cloud-arrow-down" class="h-8 w-8 text-primary-600" />
|
||||
<h3 class="mt-3 text-base font-semibold">{{ $item['title'] ?? $item['name'] }}</h3>
|
||||
<p class="mt-1 flex-1 text-sm text-gray-500 dark:text-gray-400">{{ $item['description'] ?? '' }}</p>
|
||||
<p class="mt-2 text-xs text-gray-400">{{ $item['version'] ?? '' }} · {{ $item['author'] ?? '' }}</p>
|
||||
<div class="mt-4">
|
||||
<x-filament::button size="sm" color="primary" wire:click="installFromMarket({{ $index }})">安装</x-filament::button>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="mt-3 font-semibold">{{ $item['title'] ?? $item['name'] }}</h3>
|
||||
<p class="mt-1 flex-1 text-sm text-gray-500 dark:text-gray-400">{{ $item['description'] ?? '' }}</p>
|
||||
<p class="mt-1 text-xs text-gray-400">{{ $item['version'] ?? '' }} · {{ $item['author'] ?? '' }}</p>
|
||||
<div class="mt-4">
|
||||
<x-filament::button size="sm" color="primary" wire:click="installFromMarket({{ $index }})">安装</x-filament::button>
|
||||
</div>
|
||||
</div>
|
||||
</x-filament::section>
|
||||
@empty
|
||||
<p class="text-sm text-gray-500">点击「刷新市场」拉取可用插件/主题</p>
|
||||
@endforelse
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
<x-filament::section heading="主题列表">
|
||||
<div class="grid gap-5 sm:grid-cols-2 lg:grid-cols-3">
|
||||
@forelse($this->themes as $theme)
|
||||
<div class="flex flex-col overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm dark:border-white/10 dark:bg-white/5">
|
||||
<x-filament::section :compact="true" class="!p-0">
|
||||
<div class="flex flex-col">
|
||||
{{-- 主题预览图 --}}
|
||||
<div class="relative aspect-[4/3] overflow-hidden bg-gray-100 dark:bg-white/5">
|
||||
<div class="relative aspect-[4/3] overflow-hidden rounded-t-lg bg-gray-100 dark:bg-white/5">
|
||||
@if($theme['screenshot'])
|
||||
<img src="{{ theme('asset', $theme['screenshot'], $theme['name']) }}"
|
||||
alt="{{ $theme['title'] }} 预览"
|
||||
@@ -44,7 +45,8 @@
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-filament::section>
|
||||
@empty
|
||||
<p class="text-sm text-gray-500">暂无主题</p>
|
||||
@endforelse
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
+1
@@ -0,0 +1 @@
|
||||
fake-jpg
|
||||
@@ -2,7 +2,7 @@
|
||||
<body>
|
||||
@include('partials.header')
|
||||
<div id="page">
|
||||
<div id="content">
|
||||
<main id="content">
|
||||
@if(session('success'))
|
||||
<div class="alert alert-success">{{ session('success') }}</div>
|
||||
@endif
|
||||
@@ -17,7 +17,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
</div>
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>{{-- #page --}}
|
||||
@include('partials.footer')
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<body>
|
||||
@include('partials.header')
|
||||
<div id="page">
|
||||
<div id="content">
|
||||
<main id="content">
|
||||
<h1 class="list-title">{{ $archiveTitle ?? ($category->name ?? '文章列表') }}</h1>
|
||||
|
||||
@forelse($posts as $post)
|
||||
@@ -15,7 +15,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
</div>
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>{{-- #page --}}
|
||||
@include('partials.footer')
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@stack('theme:footer')
|
||||
<div id="footer">
|
||||
<footer id="footer">
|
||||
<p>© {{ date('Y') }} {{ $siteName }}
|
||||
@if($siteIcp)<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">{{ $siteIcp }}</a>@endif
|
||||
</p>
|
||||
<p>Powered by LaraLog · Laravel · Filament</p>
|
||||
</div>
|
||||
</footer>
|
||||
</div>{{-- #outmain --}}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<div id="outmain">
|
||||
<div id="header">
|
||||
<header id="header">
|
||||
<div class="logo">
|
||||
<a href="{{ route('home') }}">{{ $siteName }}</a>
|
||||
<p class="description">{{ $siteDescription }}</p>
|
||||
</div>
|
||||
@stack('theme:header')
|
||||
<div id="nav">
|
||||
<nav id="nav">
|
||||
<ul>
|
||||
<li class="{{ request()->routeIs('home') ? 'current_page_item' : '' }}"><a href="{{ route('home') }}">首页</a></li>
|
||||
<li class="{{ request()->routeIs('archives*') ? 'current_page_item' : '' }}"><a href="{{ route('archives') }}">归档</a></li>
|
||||
@@ -26,5 +26,5 @@
|
||||
<li><a href="{{ route('register') }}">注册</a></li>
|
||||
@endauth
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="sidebar">
|
||||
<aside class="sidebar">
|
||||
@stack('theme:sidebar_top')
|
||||
<div class="searchbox">
|
||||
<form action="{{ route('search') }}" method="get">
|
||||
@@ -7,7 +7,7 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="widget">
|
||||
<section class="widget">
|
||||
<h3>分类</h3>
|
||||
<ul>
|
||||
@forelse($categories as $category)
|
||||
@@ -16,9 +16,9 @@
|
||||
<li>暂无分类</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="widget">
|
||||
<section class="widget">
|
||||
<h3>最新文章</h3>
|
||||
<ul>
|
||||
@forelse($recentPosts as $post)
|
||||
@@ -27,9 +27,9 @@
|
||||
<li>暂无文章</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="widget">
|
||||
<section class="widget">
|
||||
<h3>最新评论</h3>
|
||||
<ul>
|
||||
@forelse($recentComments as $comment)
|
||||
@@ -38,9 +38,9 @@
|
||||
<li>暂无评论</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="widget">
|
||||
<section class="widget">
|
||||
<h3>标签</h3>
|
||||
<p class="tagcloud">
|
||||
@forelse($hotTags as $tag)
|
||||
@@ -49,9 +49,9 @@
|
||||
暂无标签
|
||||
@endforelse
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="widget">
|
||||
<section class="widget">
|
||||
<h3>友情链接</h3>
|
||||
<ul>
|
||||
@forelse($links as $link)
|
||||
@@ -60,15 +60,15 @@
|
||||
<li>暂无链接</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="widget">
|
||||
<section class="widget">
|
||||
<h3>统计</h3>
|
||||
<ul>
|
||||
<li>文章 {{ $blogStats['posts'] }} 篇</li>
|
||||
<li>评论 {{ $blogStats['comments'] }} 条</li>
|
||||
<li>标签 {{ $blogStats['tags'] }} 个</li>
|
||||
</ul>
|
||||
</div>
|
||||
@stack('theme:sidebar_bottom')
|
||||
|
||||
</section>
|
||||
@stack('theme:sidebar_bottom')
|
||||
</aside>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<body>
|
||||
@include('partials.header')
|
||||
<div id="page">
|
||||
<div id="content">
|
||||
<main id="content">
|
||||
<h1 class="list-title">搜索:{{ $keyword ?: '全部' }}</h1>
|
||||
<form action="{{ route('search') }}" method="get" class="search-form">
|
||||
<input type="search" name="q" value="{{ $keyword }}" placeholder="输入关键词搜索文章">
|
||||
@@ -17,7 +17,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
</div>
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>{{-- #page --}}
|
||||
@include('partials.footer')
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<body>
|
||||
@include('partials.header')
|
||||
<div id="page">
|
||||
<div id="content">
|
||||
<main id="content">
|
||||
@if(session('success'))
|
||||
<div class="alert alert-success">{{ session('success') }}</div>
|
||||
@endif
|
||||
@@ -83,7 +83,7 @@
|
||||
</form>
|
||||
</section>
|
||||
@endif
|
||||
</div>
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>{{-- #page --}}
|
||||
@include('partials.footer')
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<body>
|
||||
@include('partials.header')
|
||||
<div id="page">
|
||||
<div id="content">
|
||||
<main id="content">
|
||||
<h1 class="list-title">标签:{{ $tag->name }}</h1>
|
||||
|
||||
@forelse($posts as $post)
|
||||
@@ -13,7 +13,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
</div>
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>{{-- #page --}}
|
||||
@include('partials.footer')
|
||||
|
||||
Reference in New Issue
Block a user