- blog_paginate: 纯列表模式每页 50 条(list_per_page 可调),其余模式仍走 per_page - 图文(card)模式:卡片网格改为左图右文横排,小屏回退竖排;摘要放宽到 100 字 - 新增 covers:generate:复用 AI 设置的 LLM 配置调 /image_generation(默认 image-01), 为无封面文章批量生成封面存入 media cover 集合;支持 --all/--limit/--post/--style/--dry-run - AI 设置页新增图片模型、封面风格两项配置 - 修正 HomeViewModeTest:列表模式为纯标题(不再显示摘要),并断言每页 50 条与图文布局
90 lines
2.9 KiB
PHP
90 lines
2.9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
|
||
use App\Blog\Support\ThemeManager;
|
||
|
||
if (! function_exists('theme_view')) {
|
||
/**
|
||
* 渲染主题视图:激活主题目录已前置到全局视图路径,主题缺失时自动回退默认视图。
|
||
*/
|
||
function theme_view(string $view, array $data = []): \Illuminate\Contracts\View\View
|
||
{
|
||
return view($view, $data);
|
||
}
|
||
}
|
||
|
||
if (! function_exists('theme')) {
|
||
/**
|
||
* 主题辅助函数:theme() / theme('asset', 'style.css') / theme('var', 'key', default)
|
||
*/
|
||
function theme(?string $method = null, ...$args): mixed
|
||
{
|
||
$manager = app(ThemeManager::class);
|
||
|
||
return match ($method) {
|
||
'asset' => $manager->assetUrl($args[0] ?? '', $args[1] ?? null),
|
||
'var' => $manager->variable($args[0] ?? '', $args[1] ?? null),
|
||
'vars' => $manager->variables(),
|
||
'name' => $manager->active(),
|
||
default => $manager,
|
||
};
|
||
}
|
||
}
|
||
|
||
if (! function_exists('blog_paginate')) {
|
||
/**
|
||
* Front-end pager: fewer page chips so the sidebar column does not wrap under.
|
||
*/
|
||
function blog_paginate(\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Relations\Relation $query, ?int $perPage = null): \Illuminate\Contracts\Pagination\LengthAwarePaginator
|
||
{
|
||
// 纯列表模式每页固定 50 条(标题列表,信息密度高);其余模式走设置。
|
||
$perPage ??= \App\Blog\Support\HomeViewMode::current() === \App\Blog\Support\HomeViewMode::LIST
|
||
? (int) blog_setting('list_per_page', 50)
|
||
: null;
|
||
$perPage = max(1, (int) ($perPage ?? blog_setting('per_page', config('blog.per_page'))));
|
||
|
||
return $query->paginate($perPage)->onEachSide(1)->withQueryString();
|
||
}
|
||
}
|
||
|
||
if (! function_exists('blog_setting')) {
|
||
/**
|
||
* 读取博客设置(Setting 表,带缓存)。
|
||
*/
|
||
function blog_setting(string $key, mixed $default = null): mixed
|
||
{
|
||
return \App\Models\Setting::get($key, $default);
|
||
}
|
||
}
|
||
|
||
if (! function_exists('tracked_url')) {
|
||
/**
|
||
* 外链追踪钩子:核心视图统一调用,由插件(外链中转)改写为 /go/{hash};
|
||
* 插件停用时原样返回。站内链接等由插件自行判断。
|
||
*/
|
||
function tracked_url(string $url): string
|
||
{
|
||
return app(\App\Blog\Support\PluginManager::class)->applyFilters('link.redirect', $url);
|
||
}
|
||
}
|
||
|
||
if (! function_exists('comment_body')) {
|
||
/**
|
||
* 评论正文:转义 + 自动链接 URL(经 tracked_url 走中转,nofollow)。
|
||
*/
|
||
function comment_body(string $text): string
|
||
{
|
||
$text = e($text);
|
||
|
||
$text = preg_replace_callback(
|
||
'#(https?://[^\s<>"\'()]+)#i',
|
||
fn (array $m) => '<a href="'.e(tracked_url($m[1])).'" target="_blank" rel="nofollow noopener">'.$m[1].'</a>',
|
||
$text
|
||
);
|
||
|
||
return nl2br($text);
|
||
}
|
||
}
|