M2: 主题系统(sablog经典+modern简约)+ 前台全部页面 + 老 URL 301 兼容 + markdown 双份导入
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace App\Blog\Support;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class ThemeManager
|
||||
{
|
||||
public function path(?string $theme = null): string
|
||||
{
|
||||
return config('themes.path').($theme ? '/'.$theme : '');
|
||||
}
|
||||
|
||||
public function active(): string
|
||||
{
|
||||
$active = Setting::get('active_theme', config('themes.default'));
|
||||
|
||||
return $this->exists($active) ? $active : config('themes.default');
|
||||
}
|
||||
|
||||
public function exists(string $theme): bool
|
||||
{
|
||||
return is_dir($this->path($theme)) && File::exists($this->path($theme).'/theme.json');
|
||||
}
|
||||
|
||||
public function manifest(string $theme): array
|
||||
{
|
||||
$file = $this->path($theme).'/theme.json';
|
||||
if (! File::exists($file)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return json_decode(File::get($file), true) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描主题目录,返回所有主题 manifest。
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
$themes = [];
|
||||
|
||||
foreach (File::directories(config('themes.path')) as $dir) {
|
||||
$name = basename($dir);
|
||||
if (! File::exists($dir.'/theme.json')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$manifest = $this->manifest($name);
|
||||
$themes[$name] = [
|
||||
'name' => $name,
|
||||
'title' => $manifest['title'] ?? $name,
|
||||
'version' => $manifest['version'] ?? '0.0.0',
|
||||
'description' => $manifest['description'] ?? '',
|
||||
'author' => $manifest['author'] ?? '',
|
||||
'screenshot' => $manifest['screenshot'] ?? null,
|
||||
'active' => $name === $this->active(),
|
||||
];
|
||||
}
|
||||
|
||||
return $themes;
|
||||
}
|
||||
|
||||
public function activate(string $theme): void
|
||||
{
|
||||
if (! $this->exists($theme)) {
|
||||
throw new \InvalidArgumentException("主题不存在: {$theme}");
|
||||
}
|
||||
|
||||
Setting::set('active_theme', $theme);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析主题下的一个视图名。
|
||||
* 优先使用激活主题的视图,缺失时回退到内置兜底视图(blog-default)。
|
||||
*/
|
||||
public function view(string $view): string
|
||||
{
|
||||
$active = $this->active();
|
||||
|
||||
if (view()->exists("theme.{$active}.{$view}")) {
|
||||
return "theme.{$active}.{$view}";
|
||||
}
|
||||
|
||||
return "blog-default::{$view}";
|
||||
}
|
||||
|
||||
public function assetUrl(string $path, ?string $theme = null): string
|
||||
{
|
||||
$theme = $theme ?? $this->active();
|
||||
|
||||
return url('/themes/'.$theme.'/assets/'.ltrim($path, '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 主题变量(原 sablog stylevars 的现代化替代:主题级自定义配置)。
|
||||
*/
|
||||
public function variables(?string $theme = null): array
|
||||
{
|
||||
$theme = $theme ?? $this->active();
|
||||
|
||||
$vars = Setting::get('theme_vars_'.$theme, []);
|
||||
|
||||
return is_array($vars) ? $vars : (json_decode((string) $vars, true) ?: []);
|
||||
}
|
||||
|
||||
public function variable(string $key, mixed $default = null, ?string $theme = null): mixed
|
||||
{
|
||||
return $this->variables($theme)[$key] ?? $default;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user