- plugins.md:requires 依赖强制校验行为、filament.post_form/post_table 后台注入(追加写法 + 示例)、Payment payable 商品化约定(payableLabel/payableUrl)、paywall 视图覆盖机制 - themes.md:新增付费墙覆盖章节(membership.paywall / paid-teaser,主题同名文件可覆盖) - README:插件段落补充依赖校验、后台注入钩子、订单商品化说明
162 lines
7.2 KiB
Markdown
162 lines
7.2 KiB
Markdown
# 主题(皮肤)开发指南
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
themes/{name}/
|
||
├── theme.json # 主题清单(必填)
|
||
├── views/ # Blade 视图(激活后前置到全局视图路径)
|
||
│ ├── partials/ # head / header / sidebar / footer 等公共片段
|
||
│ ├── index.blade.php
|
||
│ ├── show.blade.php
|
||
│ ├── list.blade.php
|
||
│ └── ... # 缺省视图自动回退默认主题(resources/views/)
|
||
└── assets/ # CSS / JS / 图片(/themes/{name}/assets/... 访问)
|
||
```
|
||
|
||
## theme.json
|
||
|
||
```json
|
||
{
|
||
"title": "主题标题",
|
||
"version": "1.0.0",
|
||
"description": "主题描述",
|
||
"author": "作者",
|
||
"screenshot": "screenshot.png",
|
||
"inject_points": ["head", "header", "sidebar_top", "sidebar_bottom", "content_top", "content_bottom", "post_content_top", "post_content_bottom", "footer", "body_end"]
|
||
}
|
||
```
|
||
|
||
## 视图解析规则
|
||
|
||
1. 激活主题的 `views/` 目录被**前置到全局视图路径**
|
||
2. 页面视图用 `@include('partials.header')` 等**按名字解析** → 主题有同名 partial 就用主题的,否则用默认主题的
|
||
3. 页面视图同理:主题提供 `index.blade.php` 则覆盖默认首页,否则用 `resources/views/index.blade.php`
|
||
|
||
所以做一个新皮肤通常只需要:`theme.json` + `assets/style.css` + 覆盖 `partials/`(head/header/sidebar/footer)+ 需要特别定制的页面视图。
|
||
|
||
## 布局结构(约定)
|
||
|
||
### 默认主题(resources/views/)
|
||
|
||
```blade
|
||
@include('partials.head') {{-- <head> 含 SEO meta --}}
|
||
<body>
|
||
@include('partials.header') {{-- 站点头 --}}
|
||
<div class="container main-layout"> {{-- 两栏容器 --}}
|
||
<main class="content">...页面内容...</main>
|
||
@include('partials.sidebar') {{-- 侧边栏(自动获得共享数据) --}}
|
||
</div>
|
||
@include('partials.footer') {{-- 页脚(含备案号) --}}
|
||
</body></html>
|
||
```
|
||
|
||
### sablog 主题(两栏经典风)
|
||
|
||
```blade
|
||
@include('partials.head')
|
||
<body>
|
||
@include('partials.header') {{-- 打开 <div id="outmain"> + header,自闭合 --}}
|
||
<div id="page"> {{-- 页面视图自己开闭 #page --}}
|
||
<div id="content">...内容...</div>
|
||
@include('partials.sidebar')
|
||
</div>{{-- #page --}}
|
||
@include('partials.footer') {{-- <div id="footer"> + 关闭 #outmain --}}
|
||
</body></html>
|
||
```
|
||
|
||
> 关键约定:**header 打开的容器由页面视图自闭合,footer 只负责自己打开的内容**。避免把 footer 渲染进 flex 容器导致错位(历史教训)。
|
||
|
||
## 页面视图清单(控制器会传的数据)
|
||
|
||
| 视图 | 控制器 | 变量 |
|
||
|------|--------|------|
|
||
| `index` | HomeController | `$posts`(分页) |
|
||
| `show` | PostController | `$post, $comments, $contentHtml` |
|
||
| `list` | Category/Archive | `$posts, $category? / $archiveTitle?` |
|
||
| `archives` | ArchiveController | `$archives` |
|
||
| `tags` | TagController | `$tags` |
|
||
| `tag` | TagController | `$tag, $posts` |
|
||
| `search` | SearchController | `$posts, $keyword` |
|
||
| `links` | LinkController | `$links` |
|
||
| `comments` | CommentController | `$comments` |
|
||
| `login` / `register` / `profile` | AuthController | — |
|
||
| `membership.index` / `membership.mine` | 会员插件 | `$plans / $subscriptions` |
|
||
| `membership.paywall` / `membership.paid-teaser` | 会员插件(付费墙) | `$post` |
|
||
| `payments.sandbox` / `payments.result` | 支付插件 | `$payment` |
|
||
|
||
## 付费墙(paywall)覆盖
|
||
|
||
启用会员插件后,付费文章的前台展示走两个视图(缺省在 `resources/views/membership/`):
|
||
|
||
- `membership.paywall`:整篇锁定(会员专享)时替代正文,含封面/标题/价格/解锁按钮
|
||
- `membership.paid-teaser`:正文内 `[paid]` 付费块的替换提示
|
||
|
||
主题可放同名文件自定义样式与文案,如 `themes/{name}/views/membership/paywall.blade.php`。视图内可用 `$post`,按钮建议沿用 `.btn` 类;`.paywall` / `.paid-teaser` 两套内置主题已带样式。
|
||
|
||
## 侧边栏共享数据(SidebarComposer 自动注入所有前台视图)
|
||
|
||
`$categories`、`$recentPosts`、`$recentComments`、`$hotTags`、`$links`、`$blogStats`、`$siteName`、`$siteDescription`、`$siteIcp`
|
||
|
||
## 主题辅助函数
|
||
|
||
```blade
|
||
{{ theme('asset', 'style.css') }} {{-- 主题资产 URL --}}
|
||
{{ theme('var', 'key', '默认值') }} {{-- 主题变量(后台可编辑) --}}
|
||
{{ theme('name') }} {{-- 当前主题名 --}}
|
||
```
|
||
|
||
## 资产
|
||
|
||
- 开发期:`GET /themes/{name}/assets/{path}` 流式返回(带缓存头)
|
||
- 生产:`php artisan theme:publish` 复制到 `public/themes/`,由 Web 服务器托管
|
||
|
||
## 内容注入点(广告 / 统计 / 临时链接)
|
||
|
||
主题视图内置 10 个注入点(Blade `@stack`),后台「主题注入」页管理:
|
||
|
||
| 注入点 | 位置 | 典型用途 |
|
||
|--------|------|----------|
|
||
| `theme:head` | `</head>` 前 | 统计代码、广告、验证 |
|
||
| `theme:header` | 页头下方 | 顶部横幅/公告 |
|
||
| `theme:sidebar_top` | 侧边栏顶部 | 首屏广告 |
|
||
| `theme:sidebar_bottom` | 侧边栏底部 | 广告/临时链接 |
|
||
| `theme:content_top` | 内容区顶部 | 列表/文章上方横幅 |
|
||
| `theme:content_bottom` | 内容区底部 | 分页后广告 |
|
||
| `theme:post_content_top` | 文章正文前 | 正文顶部广告 |
|
||
| `theme:post_content_bottom` | 文章正文后 | 正文底部广告 |
|
||
| `theme:footer` | 页脚前 | 版权上方声明 |
|
||
| `theme:body_end` | `</body>` 前 | 统计代码 |
|
||
|
||
特性:
|
||
- **同一位置可添加多条**注入块(名称 + HTML + 排序 + 启停),按排序渲染
|
||
- 插件可通过 filter `theme.inject.{point}` 追加
|
||
- 主题变量(stylevar 复活):后台「主题注入」→「主题变量」Tab,视图用 `{{ theme('var', 'key') }}` 引用任意 HTML
|
||
|
||
新主题须在对应 partial/视图放置 `@stack('theme:xxx')` 才能接收注入。
|
||
|
||
**声明注入点**:`theme.json` 的 `inject_points` 声明主题实现了哪些注入点(缺省视为全部支持),后台主题卡片会展示,切换主题时一目了然。
|
||
|
||
**多注入排序**:同一位置可添加多条,后台「主题注入」页按列表拖拽排序,保存后按顺序渲染。
|
||
|
||
## 预览图
|
||
|
||
`theme.json` 的 `screenshot` 指向 `assets/` 下的预览图(如 `screenshot.png`),后台主题管理以卡片形式展示。可用无头浏览器截图生成:`node` + playwright 打开站点首页保存为 `themes/{name}/assets/screenshot.png`。
|
||
|
||
## 移动端适配
|
||
|
||
主题 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),后台「主题管理」上传安装,或远程市场安装
|
||
- 不能删除当前激活的主题
|