Files
larablog/docs/themes.md
T
ak 263b98b218 Initial baseline: LaraBlog core with plugin commerce surface.
Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
2026-08-12 01:15:38 +08:00

117 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 皮肤(主题)开发指南
## 目录格式
```
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` | 主栏前后 | 主栏宽约 640760px |
| `article_top` / `article_bottom` | 文章广告 | 主栏宽 × 90250px |
| `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`