Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
117 lines
4.5 KiB
Markdown
117 lines
4.5 KiB
Markdown
# 皮肤(主题)开发指南
|
||
|
||
## 目录格式
|
||
```
|
||
themes/{slug}/
|
||
theme.json # 元数据
|
||
assets/ # 静态资源(CSS/图片/预览)
|
||
style.css
|
||
preview.svg # 后台卡片预览(建议 16:10)
|
||
views/ # Blade,命名空间 theme::
|
||
layout.blade.php
|
||
home.blade.php
|
||
article.blade.php
|
||
...
|
||
```
|
||
|
||
### theme.json 示例
|
||
```json
|
||
{
|
||
"name": "my-theme",
|
||
"title": "我的皮肤",
|
||
"version": "1.0.0",
|
||
"description": "说明文字",
|
||
"slots": "*"
|
||
}
|
||
```
|
||
|
||
### 必须声明 `slots`
|
||
皮肤应在 `theme.json` 声明支持的注入槽(后台「皮肤」卡片会校验):
|
||
|
||
| 写法 | 含义 |
|
||
|---|---|
|
||
| `"slots": "*"` 或 `"all"` | 支持全部标准槽(推荐) |
|
||
| `"slots": ["head", "sidebar", "my_slot"]` | 显式列表;可混用 `"*"` 再加自定义槽 |
|
||
| 省略 `slots` | **不合规**:后台标「未声明」;启用时警告 |
|
||
|
||
校验还会扫 `views/**/*.blade.php` 里的 `@themeslot` / `ThemeSlot::render`(非 default 主题会把未覆盖的 default 视图算进有效槽)。声明了但视图未调用 →「声明与视图不一致」。
|
||
|
||
## 视图约定
|
||
- 使用 `@extends('theme::layout')`
|
||
- 控制器传:`$articles` / `$article` / `$categories` / `$settings` / `$seo`
|
||
- 静态资源 URL:`app(ThemeManager::class)->assetUrl('style.css')` → `/themes/{slug}/style.css`
|
||
- 文案:`__('frontend.nav.home')` 等,勿写死中英文
|
||
|
||
## 内容注入点(ThemeSlot)
|
||
|
||
主题应在固定位置调用 `@themeslot('槽名')`(或 `ThemeSlot::render('槽名')`)。
|
||
插件与后台「注入 / 广告 / 统计」都会写入同一套槽。
|
||
|
||
### 同一位置可多条
|
||
`Hook::gather('theme.{slot}')` 会按注册顺序把**后台片段 + 各插件**拼成一段 HTML。
|
||
同一槽塞 3 个插件广告 + 后台一段,都会出来(纵向叠放,由主题 CSS 决定外观)。
|
||
|
||
### 可控边界(换别人做的 theme)
|
||
| 可控 | 不可强控 |
|
||
|---|---|
|
||
| 标准槽名(API):`head` / `sidebar` / … | 像素级宽高、是否做成卡片 |
|
||
| 主题是否调用了 `@themeslot`(合规皮肤应全挂) | 侧栏在左还是右、主栏实际像素 |
|
||
| 建议尺寸写在 `ThemeSlot::catalog()` / 后台 helper | 第三方主题漏掉某个槽 → 该注入静默不显示 |
|
||
|
||
结论:**槽名是硬约定,版式是软建议**。别人做 theme 只要挂齐标准槽,内容就能到「大概那个位置」;精确到「300×250 居中」做不到,也不该做进核心。合规检查可后续做:扫描 views 是否包含全部标准 `@themeslot`。
|
||
|
||
尺寸/位置说明见 `ThemeSlot::catalog()`(后台「注入」Tab 的 helper 同步显示)。
|
||
|
||
| 槽名 | 典型用途 | 建议尺寸(软) |
|
||
|---|---|---|
|
||
| `head` | 统计 / 额外 CSS·JS | 无版面 |
|
||
| `body_start` / `body_end` | body 首尾脚本 | 无版面 |
|
||
| `header_after` | 页头横幅、公告 | 通栏高约 60–120px |
|
||
| `nav_after` | 导航后临时入口 | 文字链 |
|
||
| `content_before` / `content_after` | 主栏前后 | 主栏宽约 640–760px |
|
||
| `article_top` / `article_bottom` | 文章广告 | 主栏宽 × 90–250px |
|
||
| `sidebar_before` / `sidebar` / `sidebar_after` | 侧栏广告 / 临时链接 | 侧栏约 280–320px,多条叠放 |
|
||
| `footer_before` / `footer_after` | 页脚附加 | 通栏 |
|
||
|
||
### 后台怎么填
|
||
`/admin` → **站点设置** → Tab「注入 / 广告 / 统计」:
|
||
1. **统计代码** → `head`
|
||
2. **侧栏广告** → `sidebar`
|
||
3. **临时链接 HTML** → `sidebar_after`(可写 `<a href="...">活动</a>`)
|
||
4. **文章顶/底广告** → `article_top` / `article_bottom`
|
||
|
||
也可继续用 **站点片段(Stylevars)** 做纯文本侧栏块;友情链接仍走「友情链接」资源。
|
||
|
||
### 插件怎么注入
|
||
```php
|
||
use App\Domain\Plugin\Hook;
|
||
use App\Domain\Theme\ThemeSlot;
|
||
|
||
Hook::listen(ThemeSlot::event(ThemeSlot::SIDEBAR), function (string $html): string {
|
||
return $html.'<p><a href="/promo">活动页</a></p>';
|
||
});
|
||
```
|
||
|
||
### 主题里任意位置
|
||
在任意 Blade 加一行即可,例如正文中间:
|
||
|
||
```blade
|
||
@themeslot('article_top')
|
||
{{-- 或自定义新槽:插件 listen theme.my_slot,主题写 @themeslot('my_slot') --}}
|
||
```
|
||
|
||
新槽无需改核心:约定 `theme.{name}` 事件即可。
|
||
|
||
## 发布
|
||
```bash
|
||
php artisan themes:publish
|
||
# 或后台「皮肤」→ 启用 / 发布静态资源
|
||
```
|
||
资源复制到 `public/themes/{slug}/`。
|
||
|
||
## 回退
|
||
`ThemeManager` 先注册 `default` views,再 `prepend` 当前主题;缺视图自动回退 default。
|
||
|
||
## 切换
|
||
后台「皮肤」卡片启用,或改 Settings `general.active_theme`。
|