SiYuan v3.6.1 版本解析:外观主题内核 API/api/setting/setTheme与/api/ui/reloadTheme落地详解
【免费下载链接】siyuanAn open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间,让人与智能体在此协作项目地址: https://gitcode.com/GitHub_Trending/si/siyuan
SiYuan v3.6.1 是一次以"细节打磨"为主题的版本,围绕快速制卡撤销、数据库视图、发布服务安全、桌面端加载与退出同步等 10 项体验改进展开,同时为开发者新增了两个外观相关的内核 API:/api/setting/setTheme与/api/ui/reloadTheme。读完本文,你将完整掌握 v3.6.1 的全部变更点,并理解两个新 API 的参数结构、鉴权要求与内核侧的完整调用链(参数解析 → 配置落盘 → 广播刷新),可直接用于插件开发、主题脚本编写或自建 Agent 的场景化主题切换。
版本概述
v3.6.1 官方概括为"此版本改进了一些细节",变更分为三类:改进功能(10 项)、修复缺陷(1 项)、开发者(3 项)。该版本不引入新的大特性,重点在于修复已知问题、加固安全边界,并为内核 API 补齐了外观主题管理能力。变更清单见 v3.6.1 官方中文说明。
改进功能逐项解读
快速制卡的撤销逻辑
改进在使用"快速制卡"(闪卡)功能后执行撤销(Undo)的行为。此前撤销可能把制卡操作连带的块结构一并回滚、或回滚位置不符合预期,v3.6.1 修正了撤销操作与制卡产生块之间的关联处理,使撤销后的文档状态更符合用户直觉。
数据库(属性视图)相关改进
两项与数据库(Attribute View)相关的改进:
- 关联字段的默认图标:数据库中"关联"类型字段此前展示的默认图标不符合语义,本版本更换为更贴切的图标;
- 预览图片加载:改进了数据库中图片字段预览的加载逻辑,减少图片不显示或加载异常的情况。
其他体验改进
- 关闭用户指南笔记本的体验:用户指南是随工作区附带的示例笔记本,优化了其关闭流程,避免误操作导致的困惑;
- 块链接的导出:改进 Markdown / PDF 等导出格式中块引用链接的生成,使导出后的链接可正确指向被引用块;
- 停靠栏图标的持久性:在启用或禁用插件时,停靠栏(Dock)图标的状态不再被意外重置,插件卸载/安装后原有停靠布局得以保留;
- RTL 与行级公式:从右到左(RTL)语言环境下的文本方向不再错误地应用到行内数学公式,公式的渲染方向保持正常;
- 桌面端主窗口加载:优化了桌面客户端主窗口的加载过程;
- 退出时的数据同步:改进了应用退出瞬间的数据同步时机,降低退出过程中本地数据未落盘/未同步的风险。
安全修复
v3.6.1 修复了若干安全漏洞,并在改进项中专门"改进了发布服务的安全性"。发布(Publish)是 SiYuan 将工作区以只读站点形式对外发布的功能,属于直接暴露到公网的服务面,其安全加固对自托管用户尤为关键。结合仓库结构,发布相关的访问控制与密钥处理涉及 发布访问控制模型 与 发布配置,建议自托管并开启了发布服务的用户在升级到 v3.6.1 后核对发布配置(如访问密码、访问路径)。
安全类修复的具体技术细节通常不做公开披露,仓库中不附带该漏洞的说明文档,升级即可。
开发者:新增内核 API/api/setting/setTheme
这是 v3.6.1 对开发者最实质的贡献之一——此前内核缺少一个直接切换主题的 RPC 接口,插件或外部脚本只能改文件后再整体刷新。现在可以通过一次 POST 请求完成"选择主题 + 指定亮/暗模式 + 设置外观模式"。
路由与鉴权
路由注册位于 router.go:
ginServer.Handle("POST", "/api/setting/setTheme", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, setTheme)从三个中间件可以看出调用前提:
| 中间件 | 含义 |
|---|---|
model.CheckAuth | 需要携带有效认证(Authorization请求头或会话 Cookie) |
model.CheckAdminRole | 仅管理员角色可调用(普通只读访问不可) |
model.CheckReadonly | 只读模式下拒绝写操作 |
请求参数
处理函数setTheme位于 setting.go,接受 JSON 参数:
{ "theme": "daylight", "modes": [0, 1], "appearanceMode": "system" }参数规则(以源码为准):
theme(string,可选):主题名。为空时本次调用不切换主题;modes(int 数组,当theme非空时必填):0表示应用到浅色模式,1表示应用到深色模式,[0,1]表示两种模式都应用。取值只允许 0 或 1,出现其他值解析直接中断;若theme非空而modes为空,返回错误信息[modes] is required ([0] for light, [1] for dark, [0,1] for both);当theme为空时modes被静默忽略;appearanceMode(string,可选):外观模式,取值为light/dark/system三种之一,非法值返回invalid appearance mode错误。
示例调用(本地内核默认监听127.0.0.1:6806,Authorization替换为你的访问密码):
curl -X POST http://127.0.0.1:6806/api/setting/setTheme \ -H "Authorization: <你的访问密码>" \ -H "Content-Type: application/json" \ -d '{"theme": "midnight", "modes": [0, 1]}'内核侧实现:校验与落盘
setTheme校验通过后调用model.SetTheme(theme, modes, appearanceMode),其实现位于 appearance.go,核心逻辑:
if theme != "" { for _, mode := range modes { switch mode { case 0: if !containTheme(theme, Conf.Appearance.LightThemes) { return fmt.Errorf("theme [%s] not exists or not available for light mode", theme) } Conf.Appearance.ThemeLight = theme case 1: if !containTheme(theme, Conf.Appearance.DarkThemes) { return fmt.Errorf("theme [%s] not exists or not available for dark mode", theme) } Conf.Appearance.ThemeDark = theme } } } if appearanceMode != "" { switch appearanceMode { case "light": Conf.Appearance.ModeOS = false Conf.Appearance.Mode = 0 case "dark": Conf.Appearance.ModeOS = false Conf.Appearance.Mode = 1 case "system": Conf.Appearance.ModeOS = true default: return fmt.Errorf("invalid appearance mode: %s", appearanceMode) } }从实现可以看到两层设计:
- 主题存在性校验:
containTheme会检查目标主题是否真实存在于已加载的主题列表中,且分别匹配LightThemes/DarkThemes——也就是说一个主题能否用于浅色或深色模式,取决于该主题自身声明了哪种模式(主题目录内theme.json声明),而不是调用方随意指定; - 模式与跟随系统互斥:
light/dark会把ModeOS置为false并固定Mode为 0 或 1;system则把ModeOS置为true,让外观跟随操作系统。
主题列表的加载入口是LoadThemes(appearance.go),它读取主题目录(对应工作区外的themes目录,仓库内置主题为 daylight 与 midnight)。因此通过该 API 能切换到的主题,必须以主题目录的形式真实存在于当前 SiYuan 的主题路径下——这正是/api/ui/reloadTheme存在的意义(见下文)。
调用后的前端刷新
setTheme落盘完成后,setTheme处理函数还会执行:
model.InitAppearance() util.BroadcastByType("main", "setAppearance", 0, "", model.Conf.Appearance)即重新构建外观状态,并通过 WebSocket 广播setAppearance事件把完整的外观配置推给所有已连接的前端,客户端收到后即时换肤,无需刷新页面。这一"写配置 → 初始化外观 → 广播"的三段式与内核中同类外观接口(如setIcon,见 setting.go)保持一致,是 SiYuan 外观类 API 的统一范式。
开发者:新增内核 API/api/ui/reloadTheme
第二个新 API 用于在不重启内核的前提下重新扫描主题目录,路由注册见 router.go:
ginServer.Handle("POST", "/api/ui/reloadTheme", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, reloadTheme)处理函数位于 ui.go:
func reloadTheme(c *gin.Context) { ret := gulu.Ret.NewResult() defer c.JSON(http.StatusOK, ret) model.LoadThemes() util.BroadcastByType("main", "setAppearance", 0, "", model.Conf.Appearance) }逻辑很直接:调用LoadThemes()重新读取主题目录并刷新内存中的LightThemes/DarkThemes列表,随后广播setAppearance让前端同步。鉴权要求与setTheme相同。
两个 API 组合起来,就构成一条完整的"动态主题"链路:
拷贝/写入主题文件到 themes 目录 │ ▼ POST /api/ui/reloadTheme (重新扫描主题目录) │ ▼ POST /api/setting/setTheme (选择主题并指定亮/暗模式、外观模式) │ ▼ 前端收到 setAppearance 广播,即时换肤典型场景:插件安装主题包后,不必提示用户重启 SiYuan;或者定时脚本根据系统时段在浅色/深色主题间切换。注意该能力要求客户端以管理员角色访问,且目标主题文件本身合法(含theme.json声明、CSS 资源齐全),否则LoadThemes不会将其纳入可用列表,setTheme的containTheme校验会直接报错。
开发者:表情符号全量展示页
v3.6.1 还新增了一个静态 HTML 页面 emojis/index.html,用于可视化展示当前渲染内核支持的全部 emoji 短码。其实现引用了编辑器渲染库 Lute 的GetEmojis()接口:
<script src="../../stage/protyle/js/lute/lute.min.js"></script> ... const emoji = Lute.New().GetEmojis() Object.keys(emoji).forEach((key) => { const value = emoji[key].indexOf('http') > -1 ? `<img src="${emoji[key]}"/>` : emoji[key] emojiHTML += `<div class="emoji__item">${value} :${key}:</div>` })页面以网格形式渲染"emoji 图形 + 短码"配对(如:smile:),短码值若是外链图片则渲染为<img>。该页面对排查"某个 emoji 短码在当前版本是否可用、显示为何种图形"非常有用,也便于插件开发者确认:key:形式的 emoji 语法全集,无需再通过笔记逐一试探。配套的表情配置见 conf.json。
版本获取
v3.6.1 的发行包通过 SiYuan 官网下载页与 GitHub Releases 渠道发布(见原文档"下载"一节)。对于正在使用的用户,直接通过客户端内置更新或下载对应平台安装包覆盖升级即可;内核 API 的调用方(插件、脚本、Agent 工具)可在升级后按前文的路径与参数约定接入setTheme/reloadTheme,无需修改现有配置。
小结
v3.6.1 的变更虽以细节修复为主,但开发者侧的两个新 API 填补了内核外观管理的空缺:/api/setting/setTheme提供了带存在性校验、支持亮/暗模式分别指定、并联动系统跟随模式的完整主题切换能力;/api/ui/reloadTheme则打通了主题目录的热加载。两者都遵循 SiYuan 内核 API 的标准鉴权链(CheckAuth→CheckAdminRole→CheckReadonly)与"落盘 +setAppearance广播"的刷新范式,是插件生态和自动化脚本做主题管理的可靠落点。
【免费下载链接】siyuanAn open-source, privacy-first, self-hosted knowledge workspace where humans and AI agents work together 开源、隐私优先、自托管的知识工作空间,让人与智能体在此协作项目地址: https://gitcode.com/GitHub_Trending/si/siyuan
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考