Files
blackbird/docs/dnfs_custom_themes.md
T

8.7 KiB
Raw Blame History

dnfs 自定义主题说明

树状笔记(dnfs)支持通过特殊节点自定义整个界面的样式:无需改代码、无需重新部署,发布一个节点即可换肤或深度改造界面,随时一键还原。

两类样式节点:

类型 表单选项 能力 适用场景
theme 主题变量 仅覆盖 CSS 变量(:root 换肤) 改配色、圆角、阴影,最稳妥
style 界面样式 注入任意 CSS 改布局、加特效、深度定制

1. 快速上手

发布步骤

  1. 登录后打开「树状笔记」,进入自己的目标节点(样式节点发布在谁拥有的节点下,权限见下)
  2. 在「节点操作」表单中,将节点类型选为 主题变量 或 界面样式
  3. 在「节点内容」中填写变量或 CSS(格式见后文)
  4. 可选:勾选「离开本节点后仍保持生效」(persist)
  5. 提交——内容经 AI 审核通过后即时生效

发布权限

  • 节点拥有者或管理员可发布样式节点(后端强制,前端面板仅做展示切换)
  • 在他人节点下提交样式节点会被拒绝(HTTP 403)
  • 根层(pid=0)无拥有者,仅管理员可在根层发布
  • 所有样式节点内容都会经过 AI 内容审核

生命周期

模式 生效范围 移除时机
默认(节点作用域) 进入该节点所在层时生效 切换/返回节点时自动还原
persist(勾选保持) 一旦访问即全局保持,跨节点生效 用户面板点「还原界面样式」,或停用对应节点
  • 每个样式节点卡片上有「停用样式/启用样式」与「审计源码」按钮,可逐个控制
  • 用户面板的「还原界面样式」一键清除全部注入样式(含 persist),本会话内 persist 样式不再自动注入(刷新页面恢复)

2. theme 节点(主题变量)

格式

「节点内容」中每行一个变量,分号可选:

--accent: #e8853a
--bg: #0a0f0a;

规则(后端强制)

  • 变量名:必须以 -- 开头,仅含字母/数字/-/_,长度 ≤ 64
  • 变量值:非空,长度 ≤ 256,不得包含 { } < >(防止逃逸 :root 上下文注入任意规则)
  • 条数:1 ~ 64 条
  • 未列出的变量保持站点默认值,可只覆盖关心的几项

可覆盖变量清单

默认值(亮色 / 系统暗色模式):

变量 亮色默认 暗色默认 作用
--bg #fdf6ee #1e1712 页面背景
--fg #4a3728 #f0e4d8 主文字
--fg-secondary #8c7260 #a08c78 次要文字
--card #ffffff #2a2119 卡片背景
--card-hover #fff7ef #342a20 卡片悬停背景
--border #f0e0cc #3e3228 边框
--border-light #f7ecdd #342a20 浅边框
--muted #b89b7a #8c7a66 弱化元素
--accent #e8853a #e8934a 品牌强调色
--accent-dark #cf6b1f #f0a060 强调色深阶
--accent-soft rgba(232,133,58,.10) rgba(232,147,74,.12) 强调色底衬
--accent-glow rgba(232,133,58,.25) rgba(232,147,74,.20) 强调色辉光
--error / --error-bg #d94f3d / #fef0ee #e8685a / #3a2220 错误
--success #5a9e6f #6fb87f 成功
--warning #d4922a #e0a84a 警告
--shadow-sm / --shadow-md 浅棕阴影 深黑阴影 投影
--radius-sm / --radius-md / --radius-lg 10px / 14px / 20px 同左 圆角

站点会随系统 prefers-color-scheme 切换亮/暗两套默认值;theme 节点注入的变量对两种模式同时生效(注入的 :root 规则优先级高于媒体查询默认值)。


3. style 节点(任意 CSS)

格式

「节点内容」直接填写 CSS 文本,上限 256KB。

安全边界

  • CSS 无法执行脚本,风险面仅为界面外观;滥用可随时一键还原
  • js 特效节点仍运行在 iframe 沙箱中,与样式节点互不影响

常用选择器参考

选择器 对应元素
.box 页面主容器(宽 90%,max-width 720px)
.card 节点卡片(含 :hover)
.card h3 卡片标题(点击进入子节点)
.card-owner / .owner-avatar / .owner-name 发帖人头像与昵称
.card-stats / .stat-item 观看/点赞/分享统计
.card-actions / .act-btn(.act-edit .act-move .act-del) 卡片操作按钮
.searchbox / .searchbox-input / .searchbox-btn 顶部搜索框
.userpanel / .minimap / .movebar 用户面板 / 右侧导航 / 底部移动条
.tag 导航标签
.node-form 底部节点编辑卡
.sp-code / .sp-actions / .sp-note 特殊节点卡片内元素
.footer 页脚
body::before / body::after 点阵底纹 / 顶部暖光(可被覆盖改背景效果)

编写注意事项

  • 层叠上下文:全屏覆盖层建议 z-index ≤ 9998(9999 被 js 特效 iframe 占用)
  • 不拦截交互:覆盖层务必加 pointer-events: none
  • 避免动画 transform 作用于卡片祖先:会使 position: fixed 后代(如 minimap、特效)定位异常
  • 修改 --accent-glow 等含 rgba() 的值在 theme 节点中是允许的(不含禁字符)

4. 示例

4.1 极客终端风

先发 theme 节点(磷光绿配色):

--bg: #0a0f0a
--fg: #33ff66
--fg-secondary: #1f9944
--card: #0d140d
--card-hover: #111a11
--border: #1a331f
--border-light: #142614
--muted: #2a6b3a
--accent: #33ff66
--accent-dark: #00cc44
--accent-soft: rgba(51, 255, 102, 0.08)
--accent-glow: rgba(51, 255, 102, 0.25)
--error: #ff4444
--error-bg: #2a0d0d
--success: #33ff66
--warning: #ffaa00

再发 style 节点(CRT 质感):

/* 全局等宽字体 */
body, .card, input, textarea, button, select {
  font-family: "JetBrains Mono", "Fira Code", Consolas, Menlo, monospace !important;
}
/* 磷光辉光 */
.card h3, .tag, .searchbox-input {
  text-shadow: 0 0 6px var(--accent-glow), 0 0 2px currentColor;
}
/* 卡片终端窗口化:左侧亮条 + 内发光 */
.card {
  border-left: 3px solid var(--accent);
  box-shadow: 0 0 18px rgba(51, 255, 102, 0.08),
              inset 0 0 40px rgba(51, 255, 102, 0.03);
}
/* 标题加 >_ 提示符 */
.card h3::before {
  content: ">_ ";
  color: var(--accent);
}
/* CRT 扫描线(不拦截点击,z-index 低于特效层 9999) */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9998;
  pointer-events: none;
  background: repeating-linear-gradient(
    0deg,
    rgba(0, 0, 0, 0.18) 0px, rgba(0, 0, 0, 0.18) 1px,
    transparent 1px, transparent 3px
  );
}
/* 链接呼吸辉光 */
a { transition: text-shadow 0.2s; }
a:hover { text-shadow: 0 0 8px var(--accent); }
/* 滚动条终端化 */
::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: var(--accent); }

4.2 暗夜蓝(仅 theme,最小改动)

--bg: #0d1117
--fg: #c9d1d9
--fg-secondary: #8b949e
--card: #161b22
--card-hover: #1c2129
--border: #30363d
--border-light: #21262d
--muted: #6e7681
--accent: #58a6ff
--accent-dark: #1f6feb
--accent-soft: rgba(88, 166, 255, 0.10)
--accent-glow: rgba(88, 166, 255, 0.25)

4.3 阅读优化(仅 style,隐藏干扰元素)

/* 隐藏统计与页脚,加宽版心,放大正文字号 */
.card-stats, .footer { display: none; }
.box { max-width: 860px; }
.card p { font-size: 1.05rem; line-height: 1.9; }
/* 卡片去边框,纯排版 */
.card { border: none; box-shadow: none; border-bottom: 1px solid var(--border-light); border-radius: 0; }

5. 常见问题

发布了但没生效? 样式节点经 AI 审核,审核未通过会提示「内容审核不通过」;通过后刷新页面生效。非节点拥有者在他人节点下发布会被 403 拒绝。

界面被改乱了怎么办? 左上角用户面板 →「还原界面样式」,立即恢复默认。或在对应卡片上点「停用样式」。

想让全站访客都看到主题? 发布时勾选「离开本节点后仍保持生效」(persist),并建议放在高层级节点中提高被访问到的概率。

样式节点之间冲突? 多个样式节点同时生效时按 DOM 注入顺序叠加,同特异性后者优先;可用卡片上的启停按钮逐个排查。

存量 image 节点显示异常? image 类型已移除,旧图片节点按原始文本显示,拥有者可编辑为 file 类型或删除。


相关源码:后端校验 dnfs2/src/dnfs2.cpp(validate_sp),前端渲染 fsys/public/js/dnfs.js(renderSpCss)。