版本:1.0.0 | 作者:FlintHub 功能:特殊日子让前台全站变灰(黑白悼念)—— 后台一键开关 + 可选日期区间(到点自动生效 / 自动失效)。
一、功能简介
1.1 生效判定
两层判定,全部 零 SQL(只读 Settings 内存缓存 + settings_cache.php 预加载):
总开关 = 关 ──────────────────────────────→ 不生效
│ 开
├─ 日期区间两端都留空 ────────────────→ 生效(纯手动)
├─ 今天 < 开始日期 ───────────────────→ 不生效
├─ 今天 > 结束日期 ───────────────────→ 不生效
└─ 其余 ──────────────────────────────→ 生效
只填一端 = 只限制单边(只填开始日期 → 从那天起一直生效)。
1.2 生效范围
仅前台(首页 / 论坛 / 帖子 / 博客 / 插件前台页)。
后台管理界面(/admin/*,含本插件自己的设置页)保持彩色。
1.3 变灰实现
html { filter: grayscale(100%); }
filter 是「渲染后滤镜」,作用于整棵渲染树 → 图片 / 视频 / SVG / 头像 / emoji
一并变灰,无需逐元素处理。
二、目录结构
plugins/mourning_mode/
├── plugin.json # 钩子清单 / 权限声明 / 后台入口
├── Plugin.php # 主类:设置读写 + 生效判定 + 生命周期 + 清缓存
├── AdminController.php # 后台控制器(单页:设置表单)
├── hook/
│ ├── layout_head_end.php # 按条件注入灰度样式表(零 SQL)
│ └── admin_route_register.php # 注册后台路由
├── views/
│ └── admin.php # 后台设置页视图
├── assets/
│ ├── style.css # 灰度规则(前台)
│ └── admin.css # 后台设置页样式
├── lang/{zh,en,zh_tw}.php # 三语语言包(25 键,键集合 / 键序一致)
└── 说明.md
无数据表、无独立库、无 data/ 目录 —— 本插件只有 3 个全局设置项,不占查询预算。
三、路由
| 方法 | 路径 | 控制器 | 说明 |
|---|---|---|---|
| GET | /admin/mourning-mode |
AdminController::index |
设置页 |
| POST | /admin/mourning-mode/save |
AdminController::save |
保存设置(PRG) |
无前台路由。 路由注册在 hook/admin_route_register.php,路径不写 /admin 前缀(核心自动补),
与 plugin.json 的 admin_url 保持一致。
四、设置项
| 键 | 默认 | 语义 |
|---|---|---|
mourning_mode_enabled |
'0' |
总开关,'1' = 启用 |
mourning_mode_start |
'' |
开始日期 YYYY-MM-DD,空 = 不限 |
mourning_mode_end |
'' |
结束日期 YYYY-MM-DD,空 = 不限 |
⚠️ Settings 是 string 语义(没有 bool / array 类型)→ 开关归一成 '0' / '1',
绝不把「关」存成空串(空串会被默认值回落逻辑吞掉)。
五、技术实现要点
5.1 为什么 filter 必须挂在 html 而不是 body
CSS Filter Effects 规范规定:filter 非 none 的元素会成为 fixed / absolute 后代的包含块,
但 document root element(html)是明确例外。
核心有 11 处 position: fixed(.thread-float-bar、图片灯箱、移动端侧栏等)。
挂到 body 上会让它们失去「相对视口」的定位基准 → 变成随页面滚动;挂 html 完全不受影响。
5.2 为什么灰度写在 CSS 文件而不是钩子里
零内联门禁把 <style 块与 style="" 属性同等对待(规范 §7.3)→
钩子只能输出 <link>,灰度值必须落在 assets/style.css。
5.3 挂载点选择
layout_head_end(app/Views/layouts/main.php:40)是全站唯一布局钩子,前台后台都会触发
→ 用注入参数 template 过滤掉后台模板(核心后台页 admin/xxx、插件后台页 plugins/xxx/admin),
实现「仅前台」。该钩子每页必跑,故判定链必须零 SQL。
5.4 缓存
开关 / 日期一变即调 Plugin::invalidatePageCache() 清 data/runtime/pages/*.html
(游客整页缓存会把「有没有那条 <link>」烘焙进去 → 不清就是「改了没生效」)。
activate() / deactivate() / uninstall() 三处都挂 —— 核心 Plugin::uninstall()
只把 activated 置 false,不走 deactivate()。
六、安装与启用
- 目录已就位于
plugins/mourning_mode/,plugin.json的activated默认true; - 首次请求时核心自动纳入(
plugins_cache.json由cacheFresh()自动重建,无需手工refresh()); - 后台「插件」列表出现「黑白悼念模式」→ 点「设置」进
/admin/mourning-mode。