安全(P0) - 发布包签名:新增 scripts/package_keygen.php、scripts/package_verify.php、 ywxapp\service\PackageVerifier;FrameworkService::apply() 解压前强制验签 (ywxapp.framework_package_verify,默认开启) - JWT 收紧:config/jwt.php 移除公开默认密钥,JwtService::assertStrongSecret() 校验非空 / 长度≥32 / 已知弱值;.env.production.example 键名由 JWT_SECRET_KEY 修正为 JWT_SECRET - /api/v1/Article:免登录白名单收窄为只读接口,写操作字段白名单 + assertOwner() 越权校验 - 开发者令牌:查找接口不再回显明文、统一失败文案 + 限流 - TemplateInstaller:文件名白名单 + realpath 归一化 + 目录内断言,修复 Zip Slip;补 use ZipArchive - 后台登录:接入验证码、失败锁定与登录限流(config/ratelimit.php) - 缓存 / Session 驱动可由 .env 覆盖(CACHE_DRIVER / SESSION_TYPE),集群部署改 redis - paycenter 支付日志开关改为 PAY_LOG,不再跟随 APP_DEBUG 工程化 / 交付 - 新增 CHANGELOG.md 与 .env.production.example;composer.lock 入库锁定依赖版本 - 插件离线安装 CLI 增加 --uid,后台上传安装透传 uid,付费插件授权校验可通过 - 授权拒绝文案区分「未携带 uid」与「未找到有效授权」,便于排障 - .gitignore 放行 .env.production.example / .env.addon.example / .gitattributes / public/.htaccess 结构 - appmall 由 addon/appmall 迁移为独立应用 app/appmall(市场 / 开发者中心 / 审核 / 分润)
59 lines
3.4 KiB
CSS
59 lines
3.4 KiB
CSS
/* MyBlog 皮肤 —— 已与站点 layui 主题打通
|
||
激活方式:config/template.php 的 active_map 设 'blog' => 'myblog'
|
||
静态资源发布到:public/static/templates/myblog/theme.css
|
||
|
||
── 取值优先级(高 → 低)────────────────────────────────────────
|
||
① 模板自身配色:SkinVariables 注入的 --secondary / --body_bg / --font_family
|
||
(template.json 的 variables,后台「模板中心 → 配色」可单独覆盖本模板)
|
||
② 站点 layui 主题:--ywx-primary / --ywx-accent(config/theme.php,
|
||
由 ThemeInject 中间件全局注入,对所有页面生效)
|
||
③ 本皮肤自带的兜底默认值
|
||
|
||
── 重要 ──────────────────────────────────────────────────────
|
||
--theme 的定义统一放在 view/blog/frontend/layout.html 的 :root 里,
|
||
本文件**不要**再定义 --theme。
|
||
原因::root 上才能读到后台「基本设置」的 theme_color;若在 .myblog-skin
|
||
(body)上重定义,选择器层级更近,会把后台配置顶掉——这正是修复前
|
||
「后台改主色不生效」的原因。
|
||
这里一律用 var(--theme, 默认值) 消费,脱离 layout 使用时也不至于失效。
|
||
*/
|
||
.myblog-skin {
|
||
/* 站点主题优先,模板自身配色兜底: SkinVariables 会用 template.json 的默认值
|
||
恒定注入(即便后台没改过),若模板优先就会把站点主题顶掉、失去整站统一,
|
||
所以这里统一写成 var(--ywx-*, var(--模板变量, 皮肤默认))。
|
||
站点主题关闭时 --ywx-* 未定义,自然回落到这一层的模板个性化。 */
|
||
--theme-2: var(--ywx-accent, var(--secondary, #f0835a));
|
||
--theme-bg: var(--body_bg, #f5f7fa);
|
||
--theme-font: var(--font_family, -apple-system, 'Microsoft YaHei', sans-serif);
|
||
|
||
background: var(--theme-bg);
|
||
font-family: var(--theme-font);
|
||
}
|
||
|
||
.myblog-skin .fb-nav {
|
||
background: linear-gradient(90deg, var(--theme, #e0533d), var(--theme-2));
|
||
/* 阴影用中性色:主色变了不至于留下旧色调 */
|
||
box-shadow: 0 2px 10px rgba(0, 0, 0, .12);
|
||
}
|
||
.myblog-skin .fb-nav .logo,
|
||
.myblog-skin .fb-nav .menu a { color: #fff; }
|
||
.myblog-skin .fb-nav .menu a.active { border-bottom: 2px solid #fff; }
|
||
.myblog-skin .fb-main a { color: var(--theme, #e0533d); }
|
||
.myblog-skin .fb-footer { color: var(--theme, #e0533d); }
|
||
|
||
/* 让皮肤内的 layui 组件一同跟随主色(覆盖 layui 内置绿) */
|
||
.myblog-skin .layui-btn:not(.layui-btn-primary):not(.layui-btn-danger):not(.layui-btn-disabled) {
|
||
background-color: var(--theme, #e0533d);
|
||
}
|
||
.myblog-skin .layui-input:focus,
|
||
.myblog-skin .layui-textarea:focus {
|
||
border-color: var(--theme, #e0533d) !important;
|
||
}
|
||
.myblog-skin .layui-form-checkbox:hover i,
|
||
.myblog-skin .layui-form-radio:hover i { color: var(--theme, #e0533d); }
|
||
.myblog-skin .layui-nav .layui-nav-item a:hover,
|
||
.myblog-skin .layui-nav .layui-this a { color: var(--theme, #e0533d); }
|
||
.myblog-skin .layui-nav .layui-this:after { background-color: var(--theme, #e0533d); }
|
||
.myblog-skin .layui-form-onswitch { border-color: var(--theme, #e0533d); background-color: var(--theme, #e0533d); }
|
||
.myblog-skin .layui-laypage .layui-laypage-curr .layui-laypage-em { background-color: var(--theme, #e0533d); }
|