From 56735804a127de3b064a32c983314f2dde219f4d Mon Sep 17 00:00:00 2001 From: ak Date: Tue, 11 Aug 2026 23:49:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Markdown=20=E6=AD=A3=E6=96=87=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=20TOC=EF=BC=88=E9=94=9A=E7=82=B9+=E6=8A=98=E5=8F=A0?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=EF=BC=89+=20=E7=A4=BE=E4=BA=A4=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=E6=89=A9=E5=85=85=E5=9B=BD=E5=86=85=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=EF=BC=88B=E7=AB=99/=E5=B0=8F=E7=BA=A2=E4=B9=A6/=E6=8A=96?= =?UTF-8?q?=E9=9F=B3/=E8=A7=86=E9=A2=91=E5=8F=B7/=E5=85=AC=E4=BC=97?= =?UTF-8?q?=E5=8F=B7/=E5=85=B6=E4=BB=96=EF=BC=89+=20=E4=BE=A7=E8=BE=B9?= =?UTF-8?q?=E6=A0=8F=E7=A4=BE=E4=BA=A4=E5=B1=95=E7=A4=BA=20+=20JSON-LD=20s?= =?UTF-8?q?ameAs=20=E5=85=A8=E5=B9=B3=E5=8F=B0=E8=81=9A=E5=90=88=20+=20?= =?UTF-8?q?=E9=A6=96=E9=A1=B5=20h1=EF=BC=88SEO=20=E8=AF=AD=E4=B9=89?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Blog/Controllers/PostController.php | 9 ++- app/Blog/Services/PostContentRenderer.php | 37 ++++++++++ app/Blog/Support/SocialLinks.php | 74 +++++++++++++++++++ app/Blog/View/Composers/SidebarComposer.php | 2 + app/Filament/Pages/BlogSettings.php | 18 ++++- docs/themes.md | 8 ++ .../src/Http/Middleware/SeoMiddleware.php | 12 +-- public/css/blog.css | 14 ++++ resources/views/index.blade.php | 1 + resources/views/partials/sidebar.blade.php | 13 ++++ resources/views/show.blade.php | 14 ++++ .../1n6cgFDKvpRbNyORiJ6Mw0Weft2QmebM.jpg | 1 + .../aLXedla7cUbfHtbtf9xJKS0tiSz9HZmVthumb.jpg | 1 + .../Lwq4etpt8ah13yUkL2uW04frmt0djgJZ.jpg | 1 + .../n58YiFKmhnkPEUXT9QNVkEmTm8xUMdeYthumb.jpg | 1 + .../6ZZ8LfuXMbAgThXmOYNSlHXAuSHr2jfPthumb.jpg | 1 + .../SuXcYgxLo0Ocem6t5UvX4HraEb6h8Iau.jpg | 1 + .../H3AV4lFVvs1h8AV2pOYGfONNKrtIBf2p.jpg | 1 + .../MUeIeQhR6gHyBi4s5GKhF2vmS3rJdYHkthumb.jpg | 1 + .../aDp9mFA0nfnefzimrF4QDAZPLXkwrGZ9thumb.jpg | 1 + .../eRLULIf57la3jKjjTYPxR45XSym1j9eb.jpg | 1 + themes/modern/assets/style.css | 12 +++ themes/sablog/assets/style.css | 10 +++ themes/sablog/views/index.blade.php | 1 + .../sablog/views/partials/sidebar.blade.php | 13 ++++ themes/sablog/views/show.blade.php | 14 ++++ 26 files changed, 249 insertions(+), 13 deletions(-) create mode 100644 app/Blog/Support/SocialLinks.php create mode 100644 storage/media-library/temp/6LhJG0YyxbFSpq0ArQG12VWbhU66PnKp/1n6cgFDKvpRbNyORiJ6Mw0Weft2QmebM.jpg create mode 100644 storage/media-library/temp/6LhJG0YyxbFSpq0ArQG12VWbhU66PnKp/aLXedla7cUbfHtbtf9xJKS0tiSz9HZmVthumb.jpg create mode 100644 storage/media-library/temp/VaCYikYnbOqIipT9L8rZa4vJh9yQNyXX/Lwq4etpt8ah13yUkL2uW04frmt0djgJZ.jpg create mode 100644 storage/media-library/temp/VaCYikYnbOqIipT9L8rZa4vJh9yQNyXX/n58YiFKmhnkPEUXT9QNVkEmTm8xUMdeYthumb.jpg create mode 100644 storage/media-library/temp/h2nAjDbfTLtNV6dXh093PyXr2NwwVG8s/6ZZ8LfuXMbAgThXmOYNSlHXAuSHr2jfPthumb.jpg create mode 100644 storage/media-library/temp/h2nAjDbfTLtNV6dXh093PyXr2NwwVG8s/SuXcYgxLo0Ocem6t5UvX4HraEb6h8Iau.jpg create mode 100644 storage/media-library/temp/jUlD0AtHd3KcbCcdj4FDkK9QKiwVLqa8/H3AV4lFVvs1h8AV2pOYGfONNKrtIBf2p.jpg create mode 100644 storage/media-library/temp/jUlD0AtHd3KcbCcdj4FDkK9QKiwVLqa8/MUeIeQhR6gHyBi4s5GKhF2vmS3rJdYHkthumb.jpg create mode 100644 storage/media-library/temp/kZkdYqqHYyQk2y8GjNjGfTXB3NnBbWyk/aDp9mFA0nfnefzimrF4QDAZPLXkwrGZ9thumb.jpg create mode 100644 storage/media-library/temp/kZkdYqqHYyQk2y8GjNjGfTXB3NnBbWyk/eRLULIf57la3jKjjTYPxR45XSym1j9eb.jpg diff --git a/app/Blog/Controllers/PostController.php b/app/Blog/Controllers/PostController.php index 1c685c5..e1af2df 100644 --- a/app/Blog/Controllers/PostController.php +++ b/app/Blog/Controllers/PostController.php @@ -32,9 +32,14 @@ class PostController extends Controller ->orderBy('created_at', (int) blog_setting('comment_order', 1) === 1 ? 'asc' : 'desc') ->paginate(20); - $contentHtml = $this->renderer->render($post); + $rendered = $this->renderer->renderWithToc($post); - return theme_view('show', compact('post', 'comments', 'contentHtml')); + return theme_view('show', [ + 'post' => $post, + 'comments' => $comments, + 'contentHtml' => $rendered['html'], + 'toc' => $rendered['toc'], + ]); } private function ensureReadable(Post $post): void diff --git a/app/Blog/Services/PostContentRenderer.php b/app/Blog/Services/PostContentRenderer.php index c0a9383..ee2e558 100644 --- a/app/Blog/Services/PostContentRenderer.php +++ b/app/Blog/Services/PostContentRenderer.php @@ -46,6 +46,43 @@ class PostContentRenderer return app(\App\Blog\Support\PluginManager::class)->applyFilters('post.rendered', $html, $post); } + /** + * 渲染并提取目录(TOC)。 + * + * @return array{html: string, toc: array} + */ + public function renderWithToc(Post $post): array + { + $html = $this->render($post); + + $toc = []; + $index = 0; + + $html = preg_replace_callback( + '/]*)>(.*?)<\/h\1>/is', + function (array $m) use (&$toc, &$index): string { + $level = (int) $m[1]; + $attrs = $m[2]; + $text = trim(strip_tags($m[3])); + $id = 'toc-'.(++$index); + + $toc[] = ['id' => $id, 'text' => $text, 'level' => $level]; + + // 已存在 id 则保留原 id,否则注入锚点 + if (preg_match('/id="([^"]+)"/', $attrs, $idMatch)) { + $toc[array_key_last($toc)]['id'] = $idMatch[1]; + + return $m[0]; + } + + return ''.$m[3].''; + }, + $html + ); + + return ['html' => $html, 'toc' => $toc]; + } + public function toHtml(string $markdown): string { return $this->converter->convert($markdown)->getContent(); diff --git a/app/Blog/Support/SocialLinks.php b/app/Blog/Support/SocialLinks.php new file mode 100644 index 0000000..6dc2afd --- /dev/null +++ b/app/Blog/Support/SocialLinks.php @@ -0,0 +1,74 @@ + 前端展示 + SEO sameAs。 + */ +class SocialLinks +{ + public const PLATFORMS = [ + 'social_weibo' => '微博', + 'social_zhihu' => '知乎', + 'social_bilibili' => '哔哩哔哩', + 'social_xiaohongshu' => '小红书', + 'social_douyin' => '抖音', + 'social_wechat_channel' => '视频号', + 'social_wechat_public' => '微信公众号', + 'social_github' => 'GitHub', + 'social_twitter' => 'Twitter / X', + 'social_facebook' => 'Facebook', + 'social_email' => '邮箱', + ]; + + /** + * 全部社交账号:['platform' => 平台名, 'value' => URL/名称, 'url' => 是否为外链]。 + */ + public static function all(): array + { + $items = []; + + foreach (self::PLATFORMS as $key => $platform) { + $value = trim((string) Setting::get($key, '')); + if ($value === '') { + continue; + } + $items[] = [ + 'platform' => $platform, + 'value' => $value, + 'url' => filter_var($value, FILTER_VALIDATE_URL) ? $value : null, + ]; + } + + // 其他平台(KeyValue) + $other = Setting::get('social_other', []); + $other = is_array($other) ? $other : (json_decode((string) $other, true) ?: []); + foreach ($other as $platform => $value) { + if (trim((string) $value) === '') { + continue; + } + $items[] = [ + 'platform' => (string) $platform, + 'value' => (string) $value, + 'url' => filter_var((string) $value, FILTER_VALIDATE_URL) ? (string) $value : null, + ]; + } + + return $items; + } + + /** + * 可进 JSON-LD sameAs 的 URL 列表。 + */ + public static function sameAs(): array + { + return array_values(array_unique(array_filter(array_map( + fn (array $item) => $item['url'], + self::all() + )))); + } +} diff --git a/app/Blog/View/Composers/SidebarComposer.php b/app/Blog/View/Composers/SidebarComposer.php index b7a88be..24081de 100644 --- a/app/Blog/View/Composers/SidebarComposer.php +++ b/app/Blog/View/Composers/SidebarComposer.php @@ -62,6 +62,8 @@ class SidebarComposer ]; })); + $view->with('socialLinks', \App\Blog\Support\SocialLinks::all()); + $view->with('siteName', blog_setting('site_name', config('blog.name'))); $view->with('siteDescription', blog_setting('site_description', config('blog.description'))); $view->with('siteIcp', blog_setting('site_icp', config('blog.icp'))); diff --git a/app/Filament/Pages/BlogSettings.php b/app/Filament/Pages/BlogSettings.php index 5cf3f87..fce4082 100644 --- a/app/Filament/Pages/BlogSettings.php +++ b/app/Filament/Pages/BlogSettings.php @@ -72,7 +72,13 @@ class BlogSettings extends Page 'social_twitter' => Setting::get('social_twitter', ''), 'social_facebook' => Setting::get('social_facebook', ''), 'social_zhihu' => Setting::get('social_zhihu', ''), + 'social_bilibili' => Setting::get('social_bilibili', ''), + 'social_xiaohongshu' => Setting::get('social_xiaohongshu', ''), + 'social_douyin' => Setting::get('social_douyin', ''), + 'social_wechat_channel' => Setting::get('social_wechat_channel', ''), + 'social_wechat_public' => Setting::get('social_wechat_public', ''), 'social_email' => Setting::get('social_email', ''), + 'social_other' => Setting::get('social_other', []), ]); } @@ -132,11 +138,21 @@ class BlogSettings extends Page ->columns(2) ->schema([ TextInput::make('social_weibo')->label('微博')->url()->placeholder('https://weibo.com/xxx'), + TextInput::make('social_zhihu')->label('知乎')->url()->placeholder('https://zhihu.com/people/xxx'), + TextInput::make('social_bilibili')->label('哔哩哔哩')->url()->placeholder('https://space.bilibili.com/xxx'), + TextInput::make('social_xiaohongshu')->label('小红书')->url()->placeholder('https://xiaohongshu.com/user/profile/xxx'), + TextInput::make('social_douyin')->label('抖音')->url()->placeholder('https://www.douyin.com/user/xxx'), + TextInput::make('social_wechat_channel')->label('视频号')->url()->placeholder('https://channels.weixin.qq.com/xxx'), + TextInput::make('social_wechat_public')->label('微信公众号')->placeholder('公众号名称 / 微信号(无外链时用于展示)'), TextInput::make('social_github')->label('GitHub')->url()->placeholder('https://github.com/xxx'), TextInput::make('social_twitter')->label('Twitter / X')->url()->placeholder('https://x.com/xxx'), TextInput::make('social_facebook')->label('Facebook')->url()->placeholder('https://facebook.com/xxx'), - TextInput::make('social_zhihu')->label('知乎')->url()->placeholder('https://zhihu.com/people/xxx'), TextInput::make('social_email')->label('邮箱')->email()->placeholder('contact@example.com'), + \Filament\Forms\Components\KeyValue::make('social_other') + ->label('其他平台') + ->keyLabel('平台名') + ->valueLabel('链接 / 名称') + ->columnSpanFull(), ]), Tab::make('维护') ->schema([ diff --git a/docs/themes.md b/docs/themes.md index a6e8db5..8b794cc 100644 --- a/docs/themes.md +++ b/docs/themes.md @@ -137,6 +137,14 @@ themes/{name}/ 主题 CSS 需自带 `@media (max-width: 768px)` 断点:容器改全宽、两栏改单栏、导航换行。内置 sablog / modern 已实现,新主题请参照。 +## TOC 目录 + +文章页自动为 Markdown 正文提取目录(h2-h6 生成锚点 + 折叠目录块)。主题需在 show 视图接收 `$toc` 变量并按 `.toc` / `.toc-level-N` 类样式化,或自行实现。 + +## 社交账号 + +后台「博客设置 → 社交账号」配置微博/知乎/B站/小红书/抖音/视频号/公众号/GitHub/X/Facebook/邮箱 + 自定义其他平台。数据经 `$socialLinks` 共享给所有前台视图(侧边栏可展示),URL 类账号同时输出到 JSON-LD `sameAs`。 + ## 打包与安装 - 目录打成 ZIP(根目录含 theme.json),后台「主题管理」上传安装,或远程市场安装 diff --git a/plugins/neatstudio.blog-seo/src/Http/Middleware/SeoMiddleware.php b/plugins/neatstudio.blog-seo/src/Http/Middleware/SeoMiddleware.php index ab36125..7de0866 100644 --- a/plugins/neatstudio.blog-seo/src/Http/Middleware/SeoMiddleware.php +++ b/plugins/neatstudio.blog-seo/src/Http/Middleware/SeoMiddleware.php @@ -101,19 +101,11 @@ class SeoMiddleware } /** - * 后台配置的社交账号 -> schema sameAs(Facebook / GitHub / Twitter 等平台识别)。 + * 后台配置的社交账号 -> schema sameAs(微博/公众号/抖音/小红书/GitHub 等全平台)。 */ private function socialLinks(): array { - $links = []; - - foreach (['social_weibo', 'social_github', 'social_twitter', 'social_facebook', 'social_zhihu'] as $key) { - if ($url = blog_setting($key, '')) { - $links[] = $url; - } - } - - return array_values(array_unique($links)); + return \App\Blog\Support\SocialLinks::sameAs(); } private function ogTags(Request $request, array $data): string diff --git a/public/css/blog.css b/public/css/blog.css index dcdfc3f..f7b3795 100644 --- a/public/css/blog.css +++ b/public/css/blog.css @@ -139,3 +139,17 @@ a:hover { color: #1a4fa8; } .site-footer { background: #fff; border-top: 1px solid #e5e7eb; padding: 20px 0; margin-top: 24px; text-align: center; font-size: 13px; color: #888; } .powered { margin-top: 4px; } + +/* TOC */ +.toc { background: #f8f9fa; border: 1px solid #e5e7eb; border-radius: 8px; padding: 12px 16px; margin: 0 0 18px; font-size: 14px; } +.toc summary { cursor: pointer; font-weight: 600; margin-bottom: 6px; } +.toc-list { list-style: none; } +.toc-list li { padding: 2px 0; } +.toc-list a { color: #555; } +.toc-list a:hover { color: #2d6cdf; } +.toc-level-2 { padding-left: 0; } +.toc-level-3 { padding-left: 14px; } +.toc-level-4, .toc-level-5, .toc-level-6 { padding-left: 28px; } + +/* 屏幕阅读器专用(SEO h1 隐藏) */ +.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php index 2981305..a84b267 100644 --- a/resources/views/index.blade.php +++ b/resources/views/index.blade.php @@ -3,6 +3,7 @@ @include('partials.header')
+

{{ $siteName }}

@if(session('success'))
{{ session('success') }}
@endif diff --git a/resources/views/partials/sidebar.blade.php b/resources/views/partials/sidebar.blade.php index ead45f0..4bb9c5b 100644 --- a/resources/views/partials/sidebar.blade.php +++ b/resources/views/partials/sidebar.blade.php @@ -62,6 +62,19 @@ +
+

社交账号

+ +
+

站点统计

    diff --git a/resources/views/show.blade.php b/resources/views/show.blade.php index d6adfc8..3295efc 100644 --- a/resources/views/show.blade.php +++ b/resources/views/show.blade.php @@ -16,6 +16,20 @@ @endif
    + @if(! empty($toc)) + + @endif @if($cover = $post->getFirstMedia('cover'))
    {{ $post->title }} diff --git a/storage/media-library/temp/6LhJG0YyxbFSpq0ArQG12VWbhU66PnKp/1n6cgFDKvpRbNyORiJ6Mw0Weft2QmebM.jpg b/storage/media-library/temp/6LhJG0YyxbFSpq0ArQG12VWbhU66PnKp/1n6cgFDKvpRbNyORiJ6Mw0Weft2QmebM.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/6LhJG0YyxbFSpq0ArQG12VWbhU66PnKp/1n6cgFDKvpRbNyORiJ6Mw0Weft2QmebM.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/storage/media-library/temp/6LhJG0YyxbFSpq0ArQG12VWbhU66PnKp/aLXedla7cUbfHtbtf9xJKS0tiSz9HZmVthumb.jpg b/storage/media-library/temp/6LhJG0YyxbFSpq0ArQG12VWbhU66PnKp/aLXedla7cUbfHtbtf9xJKS0tiSz9HZmVthumb.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/6LhJG0YyxbFSpq0ArQG12VWbhU66PnKp/aLXedla7cUbfHtbtf9xJKS0tiSz9HZmVthumb.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/storage/media-library/temp/VaCYikYnbOqIipT9L8rZa4vJh9yQNyXX/Lwq4etpt8ah13yUkL2uW04frmt0djgJZ.jpg b/storage/media-library/temp/VaCYikYnbOqIipT9L8rZa4vJh9yQNyXX/Lwq4etpt8ah13yUkL2uW04frmt0djgJZ.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/VaCYikYnbOqIipT9L8rZa4vJh9yQNyXX/Lwq4etpt8ah13yUkL2uW04frmt0djgJZ.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/storage/media-library/temp/VaCYikYnbOqIipT9L8rZa4vJh9yQNyXX/n58YiFKmhnkPEUXT9QNVkEmTm8xUMdeYthumb.jpg b/storage/media-library/temp/VaCYikYnbOqIipT9L8rZa4vJh9yQNyXX/n58YiFKmhnkPEUXT9QNVkEmTm8xUMdeYthumb.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/VaCYikYnbOqIipT9L8rZa4vJh9yQNyXX/n58YiFKmhnkPEUXT9QNVkEmTm8xUMdeYthumb.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/storage/media-library/temp/h2nAjDbfTLtNV6dXh093PyXr2NwwVG8s/6ZZ8LfuXMbAgThXmOYNSlHXAuSHr2jfPthumb.jpg b/storage/media-library/temp/h2nAjDbfTLtNV6dXh093PyXr2NwwVG8s/6ZZ8LfuXMbAgThXmOYNSlHXAuSHr2jfPthumb.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/h2nAjDbfTLtNV6dXh093PyXr2NwwVG8s/6ZZ8LfuXMbAgThXmOYNSlHXAuSHr2jfPthumb.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/storage/media-library/temp/h2nAjDbfTLtNV6dXh093PyXr2NwwVG8s/SuXcYgxLo0Ocem6t5UvX4HraEb6h8Iau.jpg b/storage/media-library/temp/h2nAjDbfTLtNV6dXh093PyXr2NwwVG8s/SuXcYgxLo0Ocem6t5UvX4HraEb6h8Iau.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/h2nAjDbfTLtNV6dXh093PyXr2NwwVG8s/SuXcYgxLo0Ocem6t5UvX4HraEb6h8Iau.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/storage/media-library/temp/jUlD0AtHd3KcbCcdj4FDkK9QKiwVLqa8/H3AV4lFVvs1h8AV2pOYGfONNKrtIBf2p.jpg b/storage/media-library/temp/jUlD0AtHd3KcbCcdj4FDkK9QKiwVLqa8/H3AV4lFVvs1h8AV2pOYGfONNKrtIBf2p.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/jUlD0AtHd3KcbCcdj4FDkK9QKiwVLqa8/H3AV4lFVvs1h8AV2pOYGfONNKrtIBf2p.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/storage/media-library/temp/jUlD0AtHd3KcbCcdj4FDkK9QKiwVLqa8/MUeIeQhR6gHyBi4s5GKhF2vmS3rJdYHkthumb.jpg b/storage/media-library/temp/jUlD0AtHd3KcbCcdj4FDkK9QKiwVLqa8/MUeIeQhR6gHyBi4s5GKhF2vmS3rJdYHkthumb.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/jUlD0AtHd3KcbCcdj4FDkK9QKiwVLqa8/MUeIeQhR6gHyBi4s5GKhF2vmS3rJdYHkthumb.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/storage/media-library/temp/kZkdYqqHYyQk2y8GjNjGfTXB3NnBbWyk/aDp9mFA0nfnefzimrF4QDAZPLXkwrGZ9thumb.jpg b/storage/media-library/temp/kZkdYqqHYyQk2y8GjNjGfTXB3NnBbWyk/aDp9mFA0nfnefzimrF4QDAZPLXkwrGZ9thumb.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/kZkdYqqHYyQk2y8GjNjGfTXB3NnBbWyk/aDp9mFA0nfnefzimrF4QDAZPLXkwrGZ9thumb.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/storage/media-library/temp/kZkdYqqHYyQk2y8GjNjGfTXB3NnBbWyk/eRLULIf57la3jKjjTYPxR45XSym1j9eb.jpg b/storage/media-library/temp/kZkdYqqHYyQk2y8GjNjGfTXB3NnBbWyk/eRLULIf57la3jKjjTYPxR45XSym1j9eb.jpg new file mode 100644 index 0000000..7e754f4 --- /dev/null +++ b/storage/media-library/temp/kZkdYqqHYyQk2y8GjNjGfTXB3NnBbWyk/eRLULIf57la3jKjjTYPxR45XSym1j9eb.jpg @@ -0,0 +1 @@ +fake-jpg \ No newline at end of file diff --git a/themes/modern/assets/style.css b/themes/modern/assets/style.css index 8613e42..b787b82 100644 --- a/themes/modern/assets/style.css +++ b/themes/modern/assets/style.css @@ -158,3 +158,15 @@ a:hover { opacity: 0.8; } .pagination-links { gap: 6px; } .pagination-links a, .pagination-links .current, .pagination-links .disabled { padding: 5px 10px; } } + +/* TOC */ +.toc { background: var(--bg); border: 1px solid var(--border); border-radius: 10px; padding: 14px 18px; margin: 0 0 18px; font-size: 14px; } +.toc summary { cursor: pointer; font-weight: 600; margin-bottom: 6px; } +.toc-list { list-style: none; } +.toc-list li { padding: 3px 0; } +.toc-list a { color: var(--muted); } +.toc-list a:hover { color: var(--accent); } +.toc-level-3 { padding-left: 14px; } +.toc-level-4, .toc-level-5, .toc-level-6 { padding-left: 28px; } + +.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } diff --git a/themes/sablog/assets/style.css b/themes/sablog/assets/style.css index 8911f7f..86104af 100644 --- a/themes/sablog/assets/style.css +++ b/themes/sablog/assets/style.css @@ -134,3 +134,13 @@ a:hover { color: #f60; text-decoration: underline; } .post-full .post-title { font-size: 22px; } .archive-posts { margin-left: 10px; } } + +/* TOC */ +.toc { background: #f7f9fb; border: 1px solid #d8dfe6; padding: 10px 14px; margin: 0 0 14px; font-size: 13px; } +.toc summary { cursor: pointer; font-weight: bold; margin-bottom: 4px; } +.toc-list { list-style: none; } +.toc-list li { padding: 2px 0; } +.toc-level-3 { padding-left: 14px; } +.toc-level-4, .toc-level-5, .toc-level-6 { padding-left: 28px; } + +.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } diff --git a/themes/sablog/views/index.blade.php b/themes/sablog/views/index.blade.php index 59b3fb9..79d395d 100644 --- a/themes/sablog/views/index.blade.php +++ b/themes/sablog/views/index.blade.php @@ -3,6 +3,7 @@ @include('partials.header')
    +

    {{ $siteName }}

    @if(session('success'))
    {{ session('success') }}
    @endif diff --git a/themes/sablog/views/partials/sidebar.blade.php b/themes/sablog/views/partials/sidebar.blade.php index 8423be3..f04969d 100644 --- a/themes/sablog/views/partials/sidebar.blade.php +++ b/themes/sablog/views/partials/sidebar.blade.php @@ -62,6 +62,19 @@
+
+

社交账号

+ +
+

统计

    diff --git a/themes/sablog/views/show.blade.php b/themes/sablog/views/show.blade.php index 82c6bd0..cb3bdc5 100644 --- a/themes/sablog/views/show.blade.php +++ b/themes/sablog/views/show.blade.php @@ -16,6 +16,20 @@ @endif
    + @if(! empty($toc)) + + @endif @if($cover = $post->getFirstMedia('cover'))
    {{ $post->title }}
    @endif