这可能是史上颜值最高的 Typecho 后台美化插件
目录
🎨 Admin Beautify (原Login Beautify)
Typecho 后台美化插件
✨ 介绍
功能特性
- 🎨 Material Design 3 风格 — 全面采用 MD3 设计规范
- 🌈 7 种主题色 — 紫、蓝、青、绿、橙、粉、红,一键切换
- 🌗 暗色模式 — 支持亮色 / 暗色 两种模式
- ✨ 过渡动画 — 丝滑的界面过渡动画,可开关
- 📌 导航栏位置 — 支持侧边栏(默认)和顶部导航栏两种布局
🔐 登录页美化 — 独立的登录页面美化,支持:
- 12+ 配色预设方案(紫、蓝、粉、绿、橙、红、青、靛蓝、日落渐变、海洋渐变等)
- 自定义主色 / 辅色
- 背景图片 + 可调虚化效果
- 站点名称显示 / 隐藏
- 独立的暗色模式控制
- 自定义 CSS / JS 注入
- ⚡ AJAX 导航 — 无刷新页面切换,后台操作更流畅
- 📱 PWA 响应式 APP — 安装到您的电脑/手机,流畅管理博客 (v2.1.0 加入)
- 🧩 兼容脚本设计 — 自动修复其他插件的排版和功能 (v2.1.0 加入)
📦 安装方法
- 前往 GitHub Releases 下载最新版本
- 解压后将
AdminBeautify文件夹上传至
/usr/plugins/- 后台进入
控制台 → 插件 → 启用 AdminBeautify
📸 截图预览
| 首页 | 插件管理 | 个人设置 |
|---|---|---|
![]() | ![]() | ![]() |
| 顶部导航栏(原版) | 文章编辑页面 | 文章管理 |
|---|---|---|
![]() | ![]() | ![]() |
| 插件仓库 | 移动端导航栏 |
|---|---|
![]() | ![]() |
❓ 常见问题
Q: 支持哪些版本的 Typecho?
本插件基于 Typecho 1.3.0 设计开发,建议使用该版本或更高版本。
Q: Typecho 1.2.1兼容吗?
已写 Typecho 1.2.1 兼容脚本(目前不够完善),请在 插件设置-兼容脚本 中开启,如果没有该脚本请点击同步Github按钮。
Q: 启用后后台样式异常怎么办?
请先清除浏览器缓存,确保加载最新的 CSS/JS 文件。如果仍有问题,请检查是否与其他后台美化插件冲突。
Q: 移动端显示效果如何?
插件内置了响应式设计,移动端会自动切换为顶部折叠菜单模式。
Q: 如何自定义登录页背景?
在插件设置中填入背景图片的 URL,并可调整虚化方式和虚化大小。
🧩 插件样式适配 (主题色/亮暗适配)
本节面向 其他 Typecho 插件的开发者,说明如何让你的插件原生兼容 Admin Beautify 的样式体系和暗色模式,而无需依赖兼容脚本。
一、暗色模式兼容
Admin Beautify 通过在 <html> 标签上切换 data-theme 属性来控制暗色模式:
data-theme="light" // 亮色
data-theme="dark" // 暗色推荐做法: 在你的插件 CSS 中,使用 [data-theme="dark"] 选择器覆盖暗色样式,而不是依赖 @media (prefers-color-scheme: dark)(因为 Admin Beautify 支持手动切换,不一定跟随系统)。
/* ✅ 推荐:跟随 Admin Beautify 的暗色切换 */
[data-theme="dark"] .my-plugin-card {
background: #1d1b20;
color: #e6e1e5;
border-color: rgba(255, 255, 255, .12);
}
/* ⚠️ 不推荐:仅跟随系统,无法响应手动切换 */
@media (prefers-color-scheme: dark) {
.my-plugin-card { background: #1d1b20; }
}二、CSS 自定义变量(Design Tokens)
Admin Beautify 在 :root 上注入了一套完整的 Material Design 3 色彩 Token,可直接在你的 CSS 中引用,颜色会随用户选择的主题色和亮/暗模式自动变化。
亮色模式变量
| 变量名 | 用途 | 示例值(默认紫色主题) |
|---|---|---|
--md-primary | 主色(按钮、强调) | #7D5260 |
--md-on-primary | 主色上的文字 | #FFFFFF |
--md-primary-container | 主色容器背景 | #FFD8E4 |
--md-on-primary-container | 主色容器上的文字 | #21005D |
--md-secondary | 次要色 | #625B71 |
--md-secondary-container | 次要色容器背景 | #E8DEF8 |
--md-tertiary | 第三色 | #7D5260 |
--md-surface | 页面/卡片背景 | #FFFBFE |
--md-surface-container-lowest | 最低层容器 | #FFFFFF |
--md-surface-container-low | 低层容器(卡片) | #F7F2FA |
--md-surface-container | 标准容器 | #F3EDF7 |
--md-surface-container-high | 高层容器 | #ECE6F0 |
--md-surface-container-highest | 最高层容器 | #E6E0E9 |
--md-on-surface | 主要文字色 | #1C1B1F |
--md-on-surface-variant | 次要文字色 | #49454F |
--md-outline | 边框/分割线 | #79747E |
--md-outline-variant | 浅色边框 | #CAC4D0 |
--md-error | 错误色 | #B3261E |
--md-error-container | 错误容器背景 | #F9DEDC |
暗色模式变量(data-theme="dark" 时自动生效)
Admin Beautify 在暗色模式下会将上述变量自动替换为暗色值(如 --md-primary 在暗色下变为 #D0BCFF),无需你额外处理,直接使用变量即可。
三、实践示例
/* 一个完全兼容 Admin Beautify 的插件卡片 */
.my-plugin-card {
background: var(--md-surface-container-low);
border: 1px solid var(--md-outline-variant);
border-radius: 16px;
padding: 16px;
color: var(--md-on-surface);
}
.my-plugin-card .title {
color: var(--md-on-surface);
font-weight: 600;
}
.my-plugin-card .subtitle {
color: var(--md-on-surface-variant);
font-size: 12px;
}
.my-plugin-card .primary-btn {
background: var(--md-primary);
color: var(--md-on-primary);
border-radius: 20px;
padding: 6px 16px;
border: none;
cursor: pointer;
}
/* 错误提示 */
.my-plugin-error {
background: var(--md-error-container);
color: var(--md-error);
border-radius: 8px;
padding: 8px 12px;
}由于 Admin Beautify 在亮色/暗色切换时会同步更新所有 CSS 变量的值,上述写法自动支持暗色模式,无需额外的 [data-theme="dark"] 覆盖规则。
四、回退值(Fallback)
为了让你的插件在 未安装 Admin Beautify 的环境下也能正常显示,建议始终为 CSS 变量提供 fallback:
.my-plugin-card {
/* var(变量, 回退值) */
background: var(--md-surface-container-low, #f7f2fa);
border-color: var(--md-outline-variant, #cac4d0);
color: var(--md-on-surface, #1c1b1f);
}
[data-theme="dark"] .my-plugin-card {
/* 无 Admin Beautify 时的暗色回退 */
background: var(--md-surface-container-low, #211f26);
border-color: var(--md-outline-variant, rgba(255,255,255,.12));
color: var(--md-on-surface, #e6e1e5);
}五、布局注意事项
| 注意点 | 说明 |
|---|---|
| 避免固定宽度 | Admin Beautify 支持侧边栏和顶部导航两种布局,内容区宽度会变化,建议用 max-width + width:100% |
position:fixed 弹窗 | 如需弹窗全屏覆盖,建议将弹窗 DOM 通过 JS appendChild 挂载到 document.body,否则可能被祖先元素的 transform / overflow:hidden 限制 |
| z-index 层级 | Admin Beautify 侧边栏 z-index 约为 1000,全局弹窗建议使用 z-index: 9999 以上 |
| 字体 | Admin Beautify 可选加载 Noto Sans SC,建议你的插件使用 font-family: inherit 跟随页面字体 |
🧩 兼容性脚本开发
目录:/asset/compat,此目录存放用于兼容其他 Typecho 插件的 JS 脚本文件。
工作原理
- AdminBeautify 会自动扫描本目录下的所有
.js文件 - 每个脚本的 元数据(名称、简介、适用插件等)将展示在 AdminBeautify 设置页面中
- 用户可在设置页面中 单独启用/禁用 每个脚本
- 每个 JS 文件应自行判断当前页面是否需要执行(通过 URL、DOM 等),避免影响其他页面
- 脚本在每次页面加载时执行一次(含 AdminBeautify AJAX 导航,见下文)
- 用户还可以在设置面板中添加 外部 JS 文件链接 来加载额外的兼容脚本
元数据格式(必须)
每个 JS 文件的 头部注释 中必须包含以下 @tag 元数据,AdminBeautify 会解析并展示:
/**
* @name 脚本名称
* @description 脚本简介说明
* @plugins Plugin1, Plugin2
* @version 1.0.0
* @author 作者名
*/| 标签 | 必填 | 说明 |
|---|---|---|
@name | 推荐 | 脚本名称(不填则使用文件名) |
@description | 推荐 | 一句话功能说明 |
@plugins | 推荐 | 适用的插件名称,多个用逗号分隔 |
@version | 可选 | 版本号 |
@author | 可选 | 作者 |
脚本结构
脚本模板
AdminBeautify 使用 AJAX 进行后台页面导航,不会完整重载页面。脚本只在首次页面加载时执行一次,若不处理 ab:pageload 事件,从其他页面 AJAX 跳转过来时修复将不会生效。
ab:pageload 事件说明:
| 属性 | 说明 |
|---|---|
| 触发时机 | history.pushState 之后,document.title 和 DOM 主内容区已完成替换 |
e.detail.url | 导航目标的完整 URL |
| 监听方式 | document.addEventListener('ab:pageload', fn) |
注意:ab:pageload 在每次 AJAX 导航后均会触发,包括 离开 目标页面时。修复函数应通过 URL 判断当前是否处于目标页面,并在离开时清理已注入的样式(保持幂等)。/**
* @name MyPlugin 兼容
* @description 修复 MyPlugin 在 AdminBeautify 下的排版问题
* @plugins MyPlugin
* @version 1.0.0
* @author YourName
*/
(function () {
'use strict';
var STYLE_ID = 'ab-compat-myplugin';
// ── 核心修复函数(幂等,可重复调用)
function applyFix(url) {
var isTarget = (url || '').indexOf('panel=MyPlugin') !== -1;
if (!isTarget) {
// 离开目标页面时清理已注入的样式
var old = document.getElementById(STYLE_ID);
if (old) old.remove();
return;
}
// 注入修复样式(幂等:已存在则跳过)
if (!document.getElementById(STYLE_ID)) {
var style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = '/* your CSS fixes */';
document.head.appendChild(style);
}
// 其他 DOM 修复操作...
}
// ── 初始执行(首次页面加载)
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
applyFix(window.location.href);
});
} else {
applyFix(window.location.href);
}
// ── 监听 AdminBeautify AJAX 导航事件 (必须,否则脚本不会生效)
// e.detail.url 是导航目标 URL;此时 document.title 和 DOM 主内容区已替换完毕。
document.addEventListener('ab:pageload', function (e) {
var url = (e && e.detail && e.detail.url) ? e.detail.url : window.location.href;
applyFix(url);
});
})();注意事项
- 必须判断页面:每个脚本必须先检测当前 URL 或 DOM,确定是目标页面才执行
- 支持 AJAX 导航:监听
ab:pageload事件以响应 AdminBeautify 的 AJAX 页面切换(推荐) - 保持幂等:修复函数可能被多次调用(首次加载 + 每次 AJAX 导航),需避免重复注入;离开目标页面时应清理已注入的样式
- 使用 IIFE:用
(function(){ ... })()包裹,避免全局变量污染 - 使用
'use strict':启用严格模式 - 兼容暗色模式:如有样式修复,注意处理
[data-theme="dark"] - 可用 CSS 变量:AdminBeautify 已定义大量 MD3 CSS 变量,如
--md-primary、--md-surface等
🔌 横幅通知API
AdminBeautify 提供了供第三方 Typecho 插件直接调用的 JavaScript 公开 API,无需自行实现通知样式。
AdminBeautify.showNotice(message, type?, duration?)
在页面顶部显示一条 MD3 Snackbar 风格的横幅通知。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
message | string | 必填 | 通知文本内容 |
type | string | 'info' | 通知类型:'info' \ 'success' \ 'warn' \ 'error' |
duration | number | 5000 | 自动消失时间(毫秒);传 0 则只能点击关闭 |
调用前提: AdminBeautify 插件已启用,且页面已加载 AdminBeautify.min.v*.js。
示例:
// 1. 普通提示(默认 info 风格,5 秒后消失)
AdminBeautify.showNotice('数据已同步');
// 2. 成功提示
AdminBeautify.showNotice('设置保存成功', 'success');
// 3. 错误提示,显示 8 秒
AdminBeautify.showNotice('连接服务器失败,请稍后重试', 'error', 8000);
// 4. 持久通知(不自动消失,需用户点击关闭)
AdminBeautify.showNotice('后台任务正在运行…', 'info', 0);在 PHP 插件中注入调用:
// 在插件的 renderFooter / action / panel 等方法中输出 inline script
echo '<script>
(function () {
function doNotice() {
if (window.AdminBeautify && typeof AdminBeautify.showNotice === "function") {
AdminBeautify.showNotice("' . $message . '", "success");
}
}
// 若 AB 已初始化则直接调用,否则等待 ab:pageload 事件
if (document.readyState !== "loading" && window.AdminBeautify) {
doNotice();
} else {
document.addEventListener("ab:pageload", doNotice, { once: true });
document.addEventListener("DOMContentLoaded", doNotice, { once: true });
}
})();
</script>';注意: 此 API 需要 AdminBeautify ≥ v2.1.26。调用前请通过 typeof AdminBeautify !== "undefined" 判断可用性。🔌 对话框API
概述
AdminBeautify (AB) 在 interceptNativeDialogs() 中覆写了 window.alert、window.confirm、window.prompt,将浏览器原生阻塞式对话框替换为 Material Design 3 风格的异步弹窗。
同步→异步断裂问题
// 浏览器原生:confirm() 阻塞执行,等用户操作后返回 true/false
if (!confirm('确定删除?')) return; // ✅ 正常
doDelete();
// AB 劫持后:confirm() 立即返回 false,然后才弹 MD3 对话框
if (!confirm('确定删除?')) return; // ❌ 永远走 return
doDelete();| 方法 | 原生行为 | AB 劫持后 |
|---|---|---|
alert(msg) | 阻塞,返回 undefined | 非阻塞,返回 undefined |
confirm(msg) | 阻塞,返回 true / false | 立即返回 false |
prompt(msg, def) | 阻塞,返回 string / null | 立即返回 null |
公开 API(v2.1.33+)
AB 提供了三个 Promise 化方法,直接调用内部 _open(),无需全局变量中转:
AdminBeautify.alert(message)
@param {string} message 消息文本(支持 \n,首行作标题)
@return {Promise<void>} 用户点击"好的"后 resolveAdminBeautify.confirm(message)
@param {string} message 消息文本
@return {Promise<boolean>} 确定→true, 取消/ESC/点遮罩→falseAdminBeautify.prompt(message [, defaultVal])
@param {string} message 消息文本
@param {string} defaultVal 输入框默认值(可选)
@return {Promise<string|null>} 确定→输入值, 取消→null使用示例
// confirm
AdminBeautify.confirm('确定删除?\n此操作不可撤销。').then(function(ok) {
if (!ok) return;
doDelete();
});
// prompt
AdminBeautify.prompt('输入新名称:', '默认值').then(function(name) {
if (!name || !name.trim()) return;
rename(name.trim());
});
// alert 链式
AdminBeautify.alert('保存成功').then(function() {
location.reload();
});原生引用
如需绕过 AB 弹窗,直接使用浏览器原生对话框:
AdminBeautify.nativeAlert(msg);
AdminBeautify.nativeConfirm(msg); // 返回 true/false(同步阻塞)
AdminBeautify.nativePrompt(msg, def); // 返回 string/null(同步阻塞)兼容旧版AB-Admin / 无AB-Admin环境
若需同时兼容新旧版本 AB 和无 AB 环境,可用三级降级封装:
function myDialog(type, msg, defVal) {
var AB = window.AdminBeautify;
// AB v2.1.33+ 公开 API
if (AB && typeof AB[type] === 'function') {
return AB[type](msg, defVal);
}
return new Promise(function(resolve) {
if (!AB) {
// 无 AB,原生同步
if (type === 'confirm') resolve(confirm(msg));
else if (type === 'prompt') resolve(prompt(msg, defVal));
else { alert(msg); resolve(); }
return;
}
// 旧版 AB,全局回调
if (type === 'confirm') {
window._abPendingConfirm = function(r) { resolve(!!r); };
window.confirm(msg);
} else if (type === 'prompt') {
window._abPendingPrompt = function(r) { resolve(r); };
window.prompt(msg, defVal || '');
} else {
window.alert(msg);
resolve();
}
});
}内部机制
window.confirm(msg)
│
├─ _parseMsg(msg) → { title: 第一行, body: 其余行 }
├─ _open({ type:'confirm', title, message, onConfirm, onCancel })
│ │
│ ├─ 创建 #ab-dialog-overlay + #ab-dialog-box
│ ├─ WAAPI 入场动画 (scale 0.85→1 / mobile: translateY)
│ ├─ 绑定 确定/取消/ESC/Enter/点击遮罩
│ └─ 用户操作 → 退场动画 → 调用 onConfirm(value) 或 onCancel()
│
└─ return false ← 同步立即返回,不等待用户异步回调通道
AB 暴露了两个全局变量作为回调桥梁:
// confirm 的异步结果
window._abPendingConfirm = function(result) { /* true 或 false */ };
// prompt 的异步结果
window._abPendingPrompt = function(result) { /* string 或 null */ };AB 的 window.confirm 覆写内部:
window.confirm = function(message) {
var p = _parseMsg(message);
_open({
type: 'confirm', title: p.title, message: p.body,
onConfirm: function() {
if (window._abPendingConfirm) {
var fn = window._abPendingConfirm;
window._abPendingConfirm = null;
fn(true);
}
},
onCancel: function() {
if (window._abPendingConfirm) {
var fn = window._abPendingConfirm;
window._abPendingConfirm = null;
fn(false);
}
}
});
return false; // ← 问题根源
};window.prompt 同理,内部调用 _abPendingPrompt(value) 或 _abPendingPrompt(null)。
_parseMsg 消息格式
function _parseMsg(message) {
var parts = ('' + message).split('\n');
return { title: parts[0], body: parts.slice(1).join('\n') };
}第一个 \n 前 → 对话框标题;之后内容 → 对话框正文。
附录:_parseMsg 消息格式规范
"标题文字\n正文内容第一行\n正文内容第二行"| 部分 | 在 AB 对话框中 | 对应 DOM |
|---|---|---|
\n 之前 | 标题(粗体 + 图标) | #ab-dialog-title |
\n 之后 | 正文 | #ab-dialog-msg |
无 \n | 全部作为标题,无正文 | 仅 #ab-dialog-title |
附录:AB 对话框 DOM 结构
#ab-dialog-overlay
└── #ab-dialog-box
├── #ab-dialog-host "🌐 hostname"
├── #ab-dialog-title 图标 + 标题
├── #ab-dialog-msg 正文(可选)
├── #ab-dialog-input-wrap 输入框(仅 prompt)
│ └── #ab-dialog-input
└── #ab-dialog-actions
├── #ab-dialog-cancel 取消按钮(confirm/prompt)
└── #ab-dialog-confirm 确定/好的 按钮附录:AB 对话框键盘快捷键
| 按键 | 行为 |
|---|---|
Enter | 等同点击「确定」按钮 |
Escape | confirm/prompt → 等同「取消」;alert → 等同「好的」 |
🔗 相关链接
采用 CC BY-NC-SA 4.0 协议授权,转载请注明来源。







