FIT2CLOUD

refactor(portfolio): 改造默认页面路由及项目内容渲染逻辑

  • 将默认页面路由由 /projects 改为 /portfolio,详情页路径同步更新
  • 删除原 /projects 和 /projects/{slug} 模板,替换为 portfolio.html 和 portfolio-detail.html
  • 新增 ProjectCardRenderer,用于渲染项目卡片短码
  • 在 ProjectFinderImpl 中集成 ProjectCardRenderer,改写 renderContent 方法支持卡片渲染
  • PortfolioPageRouter 中统一注入 ProjectCardRenderer,模板名称及路由统一为 portfolio 相关
  • 默认模板项目链接和跳转地址修改为 /portfolio 前缀
  • UI 视图中相关跳转和调用路径更新为 /portfolio
  • 插件配置说明及 README 文档同步更新路由、渲染说明、示例代码
  • 增加相关单元测试覆盖卡片渲染及路由变更,保证兼容与功能完整性
  • 移除旧的项目详情页和列表页源码文件,简化维护成本
发布于查看详情

feat(menu): 为菜单项添加 Iconify 图标支持功能

  • 创建 annotation-setting.yaml 配置文件定义菜单图标注解
  • 在 header.html 中实现桌面端菜单图标的渲染逻辑
  • 在 footer.html 中实现页脚菜单图标的渲染逻辑
  • 在 mobile menu 中实现移动端各级菜单图标的渲染逻辑
  • 更新 CSS 样式文件添加菜单图标相关的样式定义
  • 修改主题配置文件中的自定义模板名称前缀为氢·简
  • 在主题文档中添加菜单图标功能的使用说明

Full Changelog: 1.0.0-beta4...1.0.0-beta5


Generated from 1.0.0-beta5

发布于查看详情

新增首页信息流按发布时间混入文章卡片
增加了全站 pjax 无刷新加载
删除无用调试事件输出

发布于查看详情

5.3.2

  • 优化 移动端适配 — Hero / 双图擦除 / video-reveal / Moments / Friends 页面响应式调整
  • 优化 双图擦除移动端触控半径自动适配
  • 修复 朋友圈、友链页面分页按钮位置
  • 新增 背景视频/图片模式,支持后台文件上传
  • 新增 双图擦除模式(图片叠加,鼠标扫过显示底图,柔边朦胧光照效果)
  • 新增 视频+双图擦除组合模式,视频与双图擦除丝滑过渡
  • 新增 Hero 区域粘性过渡,第一篇文章出现时标题自动淡出
  • 优化 首页大图与背景设置为统一配置组,后台管理更便捷
  • 优化 朋友圈、瞬间、友链页面分页按钮位置,始终位于内容块下方
  • 优化 双图擦除交互精度,支持触摸设备
发布于查看详情

统一身份认证

为多个 Halo 站点提供“身份中心 + 接入站”的单点登录能力。一个站点作为身份中心统一承接登录与授权,其它 Halo 站点作为接入站跳转到身份中心完成认证,并在回调后建立本站登录态、绑定本地用户、同步用户资料和映射本地角色。

功能演示

地址 账号/密码
演示站 demo/demo123.

交流群

点击链接加入群聊【halo博客-lywq插件】

插件介绍

halo-plugin-sso 适合一组 Halo 站点共用同一套账号体系的场景,例如主站、文档站、社区站、资源站分别部署,但希望用户只使用一个中心账号登录。

插件采用 Authorization Code + PKCE 的登录闭环:

  1. 接入站发起登录。
  2. 用户被跳转到身份中心授权端点。
  3. 身份中心确认用户登录状态和授权条件。
  4. 身份中心向接入站回调授权码。
  5. 接入站使用授权码换取 Token,拉取用户身份信息。
  6. 接入站绑定或创建本地 Halo 用户,映射角色并建立本地登录态。

当前能力包括:

  • 身份中心模式:管理接入站、签发授权码、提供 Token 和 UserInfo、下发中心标准角色。
  • 接入站模式:跳转身份中心登录、处理回调、绑定或创建本地用户、同步用户资料、映射本地角色。
  • 登录入口控制:接入站可选择自动跳转 SSO 登录,也可保留 Halo 默认登录页并手动选择“统一身份认证”。
  • 动态认证提供者信息:接入站登录页展示的 displayNamedescriptionlogowebsite 会从身份中心站点基础信息同步。
  • 角色映射:身份中心下发中心角色,接入站按映射规则转换为本站本地角色。
  • 审计日志:记录接入站登录成功、失败、失败原因,并支持筛选、聚合、手动清理和自动清理。
  • 用户绑定:记录中心账号与接入站本地用户的绑定关系。

适用环境

  • Halo >= 2.25.0
  • Java 21+
  • 一个可被接入站访问的身份中心站点地址,例如 https://auth.example.com
  • 接入站需要有稳定外部访问地址,例如 https://blog.example.com

生产环境建议使用 HTTPS。开发调试时可在插件设置中临时开启“开发环境允许 HTTP localhost”,但别把这个当生产方案,真上生产这么干就有点硬莽了。

快速开始

完整接入至少需要两个 Halo 站点:

  • 站点 A:身份中心。
  • 站点 B:接入站。

下面用:

  • 身份中心:https://auth.example.com
  • 接入站:https://blog.example.com

1. 安装插件

在身份中心站点和每个接入站点都安装并启用本插件。

构建插件:

./gradlew build

构建完成后,插件 JAR 位于:

build/libs/

将 JAR 上传到 Halo 后台插件管理并启用。

2. 配置身份中心

进入身份中心站点后台:

控制台 -> 插件 -> 统一身份认证 -> 设置

在“基础设置”中配置:

配置项 建议值 说明
运行模式 身份中心模式 当前站点负责统一登录和授权
中心标准角色 subscriberauthoreditor 只有选中的中心角色会下发给接入站
要求邮箱已验证 开启 未验证邮箱的中心用户不允许跨站登录

然后进入插件控制台页面:

控制台 -> 系统工具 -> 统一身份认证

在“接入站”区域创建一个接入站:

字段 示例 说明
接入站名称 我的博客 控制台展示用
站点地址 https://blog.example.com 接入站外部访问地址
Redirect URI https://blog.example.com/apis/public.sso.muyin.site/v1alpha1/client/callback 接入站回调地址
启用状态 开启 关闭后该接入站不能继续登录

创建成功后会得到:

  • Client ID
  • Client Secret

Client Secret 只展示一次,复制保存好。这个东西丢了就重新生成或重建接入站,别指望页面再掏出来给你看。

3. 配置接入站

进入接入站后台:

控制台 -> 插件 -> 统一身份认证 -> 设置

在“基础设置”中配置:

配置项 示例 说明
运行模式 接入站模式 当前站点负责跳转登录和建立本地登录态
身份中心地址 https://auth.example.com 身份中心站点外部地址
Client ID 从身份中心复制 对应身份中心创建的接入站
Client Secret 从身份中心复制 服务端换取 Token 使用
默认本地角色 guest 或其它低权限角色 未命中角色映射时使用
登录时同步用户资料 按需开启 同步邮箱、用户名、展示名称和头像
自动跳转 SSO 登录 按需开启 开启后访问 /login 自动跳转身份中心

接入站保存配置后,插件会定期从身份中心同步认证提供者信息。同步来源是身份中心 Halo 系统基础设置:

AuthProvider 字段 身份中心来源
displayName 站点标题
description 站点副标题
logo 站点 Logo,未配置时使用 favicon,再未配置时使用插件默认图标
website 站点外部访问地址

如果身份中心临时不可用,接入站会保留上一次同步成功的本地认证提供者信息,不会把登录入口改成空壳。

4. 配置角色映射

进入接入站插件控制台:

控制台 -> 系统工具 -> 统一身份认证 -> 角色映射

创建映射关系:

中心角色 本地角色 说明
subscriber guest 普通用户
author contributor 投稿或作者
editor editor 编辑

规则说明:

  • 身份中心只下发“中心标准角色”中允许的角色。
  • 接入站只按启用状态的映射规则转换角色。
  • 未命中映射时使用“默认本地角色”。
  • 已有本地用户登录时,插件会追加缺失角色,不会清空用户已有本地角色。

登录教程

自动 SSO 登录

适合希望接入站完全交给身份中心登录的场景。

  1. 在接入站插件设置中开启“自动跳转 SSO 登录”。
  2. 用户访问接入站 /login
  3. 插件自动跳转到身份中心授权页。
  4. 用户在身份中心登录。
  5. 登录成功后回到接入站,并建立接入站本地登录态。

如果需要临时访问接入站本地登录页,可以访问:

/login?sso_local=1

手动选择 SSO 登录

适合接入站需要同时保留本地登录和 SSO 登录的场景。

  1. 在接入站插件设置中关闭“自动跳转 SSO 登录”。
  2. 到 Halo 的认证提供者配置中启用 muyin-sso
  3. 用户访问接入站 /login
  4. 用户在登录页选择“统一身份认证”。
  5. 插件跳转身份中心完成登录。

手动入口由插件声明的 AuthProvider 提供:

metadata.name: muyin-sso
authenticationUrl: /apis/public.sso.muyin.site/v1alpha1/client/login

指定登录后返回地址

接入站登录入口支持 return_url 参数:

/apis/public.sso.muyin.site/v1alpha1/client/login?return_url=/archives/demo

登录完成后会回到指定地址。插件会校验返回地址,只允许本站相对路径,避免被拿去做开放重定向。这个地方不校验就等于给钓鱼链接递刀,不能省。

审计日志与清理

插件会记录接入站登录过程中的关键结果:

  • 登录成功。
  • 登录失败。
  • Client 校验失败。
  • Token 换取失败。
  • UserInfo 拉取失败。
  • 用户创建或绑定失败。
  • 角色映射结果。

在插件控制台的“审计日志”中可以:

  • 按结果筛选:success / failure
  • 按 Client ID 筛选。
  • 按关键词搜索 subject、email 或 message。
  • 查看最近失败原因聚合。
  • 按保留天数执行干跑预览或真实清理。
  • 查看最近一次清理状态和清理历史。

插件设置中可以开启“自动清理过期审计日志”。默认关闭,开启后后台任务会定期按保留天数清理过期日志。

公共接口

接入站和身份中心之间主要使用以下接口。

身份中心 OAuth API:

方法 路径 说明
GET /apis/public.sso.muyin.site/v1alpha1/oauth/authorize OAuth 授权端点
POST /apis/public.sso.muyin.site/v1alpha1/oauth/token 使用授权码换取 Token
GET /apis/public.sso.muyin.site/v1alpha1/oauth/userinfo 获取中心用户信息和中心角色
GET /apis/public.sso.muyin.site/v1alpha1/oauth/notice 授权拒绝提示页

公共辅助 API:

方法 路径 说明
GET /apis/public.sso.muyin.site/v1alpha1/metadata 获取身份中心认证提供者元信息
GET /apis/public.sso.muyin.site/v1alpha1/roles/list 获取身份中心可下发角色列表
GET /apis/public.sso.muyin.site/v1alpha1/client/login 接入站发起 SSO 登录
GET /apis/public.sso.muyin.site/v1alpha1/client/callback 接入站处理 SSO 回调

Console API 主要由插件后台页面调用,覆盖接入站管理、角色映射、用户绑定、审计日志和设置读取。开发调试时可查看:

api-docs/openapi/v3_0/ssoApis.json

常见问题

接入站登录后回调失败

优先检查身份中心中登记的 Redirect URI 是否和接入站实际地址完全一致。协议、域名、端口、路径都要一致。

标准回调路径为:

https://接入站域名/apis/public.sso.muyin.site/v1alpha1/client/callback

访问接入站 /login 没有跳转身份中心

检查接入站插件设置:

  • 运行模式必须是“接入站模式”。
  • 身份中心地址、Client ID、Client Secret 必须填写。
  • “自动跳转 SSO 登录”必须开启。

如果你关闭了自动跳转,需要在 Halo 认证提供者中启用 muyin-sso,然后在默认登录页手动选择“统一身份认证”。

手动 SSO 登录入口没有展示

检查 Halo 认证提供者配置中是否启用了 muyin-sso。插件声明 AuthProvider 不等于 Halo 一定展示它,展示与否由 Halo 的认证提供者启用状态控制。

接入站登录页展示的名称和 Logo 不对

接入站会从身份中心 /metadata 同步认证提供者信息。请检查:

  • 身份中心插件是否为“身份中心模式”。
  • 接入站能否访问身份中心地址。
  • 身份中心 Halo 系统基础设置中是否配置了标题、副标题、Logo、外部访问地址。
  • 身份中心站点外部地址是否正确,尤其是反向代理后的 https 地址。

用户登录成功但角色不符合预期

检查三处:

  1. 身份中心“中心标准角色”是否包含该用户角色。
  2. 接入站“角色映射”是否配置并启用。
  3. 接入站“默认本地角色”是否符合预期。

身份中心退出后接入站没有退出

这是当前设计,不是 bug。插件不做统一退出登录。身份中心退出只影响身份中心本地会话,不会强制接入站本地会话失效。

开发

本地开发依赖:

  • Java 21+
  • Node.js 18+
  • pnpm

启动 Halo 开发服务:

./gradlew haloServer

前端开发:

cd ui
pnpm install
pnpm dev

运行测试:

./gradlew test

构建插件:

./gradlew build

生成的插件 JAR 在:

build/libs/

许可证

GPL-3.0 © Lywq

发布于查看详情

为 Halo 提供现代化评论体验,支持富文本评论、图片上传、验证码、表情回应、举报、黑灰名单、精选/置顶、评论徽章与 AI 助手。

发布于查看详情
  • 新增公开通联网格清单接口,返回四位网格、呼号集合、通联时间、模式、频率与频段。
  • 网格清单按对方 QTH 中的 Maidenhead 网格聚合,6 位或 8 位统一截取四位,地区或地址类 QTH 自动跳过。
  • 补充公开接口限流、参数校验、服务层聚合与路由测试。
  • 同步结构化文档与后端 API 合同,版本号递增至 2.3.20。

Generated from v2.3.20

发布于查看详情

说明

fix: 修复文章无标题标签或纯图片时内容溢出问题

变更描述

🐛 问题修复

  • 修复文章内容溢出:解决了当文章页面不存在 h1/h2/h3 标题标签时(如纯图片文章、纯文字无标题文章),导致的内容区域布局溢出问题。
  • 增强样式兼容性:优化了文章详情页的渲染逻辑,确保在缺失标准标题结构的情况下,页面布局依然保持正常且自适应。
发布于查看详情

本次更新(v5.1.1)修复了友链自助提交功能中插件全局函数 ID 不匹配及 linkPageUrl 为空校验失败的问题,优化了体验

同时全面重写了自定义页面

适配了更多插件

发布于查看详情

Moesora 1.0.2

二次元少女风格的 Halo 2.x 博客主题。本次为问题修复版本。

🐛 修复

  • 修复文章同时使用两个或两个以上分类时,文章卡片底部分类标签之间间隙过大的问题(现已恢复为紧凑、右对齐排列)。

📦 安装 / 更新

下载下方的 moesora.zip,进入 Halo 后台 主题 → 主题管理:首次使用选「安装主题」上传;已安装的通过「升级」上传该压缩包即可。

✅ 适配

Halo 2.14.0 及以上版本。


完整说明见仓库 README。

发布于查看详情

新特性

  • 误报反馈功能 — 被拦截的评论可进行误报反馈,支持两种处理方式:
    • AI 回复:标记为通过 + 触发 AI 生成回复
    • 仅通过:仅标记为通过,不生成回复
  • 误报通过状态 — 新增 FALSE_POSITIVE 状态,“仅通过"的记录显示为"误报通过”,不显示"通过/拒绝"按钮
  • 触发 AI 回复按钮 — "误报通过"状态的记录可随时点击"触发AI回复"按钮补生成 AI 回复
  • 上下文优先判断原则 — 前置过滤 AI 提示词重写,遵循五条核心原则:上下文优先、口语化宽容、恶意导向判定、宁放勿杀、闲聊不算无意义

Bug 修复

  • 修复误报反馈"AI 回复"被前置过滤再次拦截processComment() 始终调用 preFilterService.check(),用户已确认为误报的评论会被再次拦截。新增 processFalsePositive() 方法跳过前置过滤和去重检查
  • 修复误报反馈"AI 回复"被去重检查拦截hasExistingReply() 找到已有的 FILTERED→PENDING 记录导致 AI 回复无法生成。processFalsePositive() 复用已有记录,不经过去重检查
  • 修复误报反馈"AI 回复"导致全站崩溃processComment() 同步等待 AI 生成完成,HTTP 请求长时间不返回。改为 .subscribe() 异步执行,API 立即返回
  • 修复误报反馈"仅通过"后显示通过/拒绝按钮 — "仅通过"将记录设为 status=PASS, published=false, reply="",导致显示"通过/拒绝"按钮且内容为空。改为 status=FALSE_POSITIVE
  • 修复 extractChoice 无匹配时返回原始文本 — AI 返回非预期文本时被误判为违规类别。改为返回空字符串触发安全拦截
  • 修复 approveOriginalComment 缺少乐观锁重试 — 并发更新 Comment/Reply 时可能静默失败。添加 Retry.backoff(3, 100ms) 重试

改进

  • 消除 checkBlockedCommenters 重复代码FilterService 新增 isCommenterBlocked(commentName) 公共方法,AiReplyOrchestrator 改为调用它
  • 前端批量操作防重复提交 — 批量通过/拒绝/删除按钮添加 batchLoading 状态,操作期间禁用按钮
发布于查看详情
  • 发信确认列表将“卡片备注”列调整为“备注”,同列展示业务备注与卡片备注。
  • 优化备注列排序逻辑,按业务备注和卡片备注的组合内容排序。
  • 清理 CardPrint 工具中冗余的 2026v4 含二维码改版预设文件。
  • 版本号递增至 2.3.19,并同步插件元数据与构建版本。

Generated from v2.3.19

发布于查看详情

更新较多,建议全新安装此主题!
v1.0.9: 功能增强与大规模优化

  • 热门文章小部件新增文章数配置(3-10篇),标签小部件新增零使用标签开关
  • 主题预设精简为 13 种,全部改为中文命名,新增 5 种更深配色
  • 默认配色改为 Earth 蓝色风格,删除深色主题预设选项
  • 修复分类页参数不匹配、小部件 null 值崩溃等多个严重 bug
  • 优化代码复用性、Shiki 代码高亮适配、性能与无障碍访问
  • 页面侧边栏开关,默认关闭居中显示
  • 撤销自定义代码注入功能,使用 Halo 后台自带功能
发布于查看详情

详情请参阅更新日志在 GitHub 上查看)。
Please refer to Changelog (view on GitHub) for details.

howiehz-higan-zh-hans.zip 为简体中文默认安装包,仅包含 .br
howiehz-higan-zh-hans-tiny.zip 为简体中文轻量安装包,移除默认字体资源,默认 logo 资源将替换为 1x1 占位图,不包含预压缩文件,且不注入 Mermaid / instant.page 运行时。
howiehz-higan-zh-hans-full-precompressed.zip 为简体中文完整预压缩包,包含 .gz / .br / .zst
howiehz-higan-en.zip is the English default package with .br only.
howiehz-higan-en-tiny.zip is the English tiny package that removes the default font assets, replaces the default logo asset with a 1x1 placeholder image, omits precompressed assets, and excludes Mermaid / instant.page runtime injection.
howiehz-higan-en-full-precompressed.zip is the English full precompressed package with .gz / .br / .zst.

发布于查看详情
  • 将收卡记录人工关联入口从审计查询页迁移到收卡业务三个子菜单的“已收卡片”操作列,审计菜单保持只读查询。
  • 收卡业务“已收卡片”支持对未关联发卡编号的收卡记录选择目标卡片并二次确认,保留线上换卡未匹配记录的创建卡片入口。
  • 在线打印工具封面打印新增国内卡片 / 国际卡片筛选,按去向国是否存在区分队列,并补充回归测试与文档。
  • 调整通知邮件模板祝语文案,同步默认模板资源与文档示例。
  • 版本号递增至 2.3.18,并同步插件元数据与构建版本。

Generated from v2.3.18

发布于查看详情

功能优化

  • 优化许可证检查时机,改为不在启动阶段检查,可以保证插件始终不会因为许可证异常导致已加密文章内容被公开
  • 文章口令验证改为使用密钥存储,避免文章元数据暴露导致口令暴露
发布于查看详情

功能优化

  • 优化许可证检查时机,改为不在启动阶段检查,可以保证插件始终不会因为许可证异常导致已加密文章内容被公开
  • 文章口令验证改为使用密钥存储,避免文章元数据暴露导致口令暴露
发布于查看详情

功能优化

  • 优化许可证检查时机,改为不在启动阶段检查,可以保证插件始终不会因为许可证异常导致已加密文章内容被公开
  • 文章口令验证改为使用密钥存储,避免文章元数据暴露导致口令暴露
发布于查看详情

功能优化

  • 优化许可证检查时机,改为不在启动阶段检查,可以保证插件始终不会因为许可证异常导致已加密文章内容被公开
  • 文章口令验证改为使用密钥存储,避免文章元数据暴露导致口令暴露
发布于查看详情

Moesora 1.0.1

二次元少女风格的 Halo 2.x 博客主题,首个公开发布版本 (。・ω・。)ノ♡
主色为樱花粉 #f9a8d4,可在后台自由更换。

✨ 功能特性

  • 二次元少女风格设计,主题色可自定义;浅色 / 深色 / 跟随系统三种配色,带切换与记忆
  • 完整 SEO:动态标题、描述、Open Graph、Twitter Card、JSON-LD、RSS 自动发现
  • 可选 Pjax 无刷新加载
  • 自包含图片灯箱(零依赖、不走 CDN):缩放 / 旋转 / 拖动 / 长图 / 双指 / 键盘
  • 高级代码块:语言标识、行号、折叠、一键复制(兼容非 HTTPS 复制回退)
  • 文章目录 TOC + 滚动高亮;CJK 感知字数统计与阅读时长
  • 评论:内置评论 / Twikoo / Waline,客户端已内置打包,无需额外 CDN
  • 相册:按后台分组以彩色标签切换展示,配合灯箱查看
  • 瞬间:彩色时间轴布局,可点赞、可展开评论气泡
  • 文章「赞赏支持」按钮兼作点赞:展开收款码的同时给文章点赞 +1
  • 侧边栏布局可选:三列 / 仅左 / 仅右
  • 正文视频 / 音频增强(mp4 / m3u8)、KaTeX 公式(深色适配)
  • 可选 PWA、打印样式、站外链接跳转确认、客户端随机几何头像
  • 留言墙、恋爱墙等自定义页面

📦 安装

下载下方的 moesora.zip,进入 Halo 后台 主题 → 主题管理 → 安装主题,上传该压缩包并启用即可。
更新时下载新版 moesora.zip,通过 主题 → 升级 上传安装包。

✅ 适配

Halo 2.14.0 及以上版本。

发布于查看详情

v1.1.2

Bug 修复

  • 修复 AI 分类完全不可用classifyWithChoiceclassifyWithChat 均使用了 GenerateTextRequest.Builder.system() 方法,而该方法在当前 AI Foundation 版本中不被支持或导致运行时错误,导致所有评论均被拦截并显示"AI分类服务不可用,安全拦截"。现改为将 system prompt 合并到 user prompt 中,与可用的 chat() 方法保持一致的调用方式
  • 修复 classifyWithChoice NPE.map() 返回 null 时触发 Reactor 内部 NullPointerException,改为 .flatMap() + Mono.empty() 正确触发 fallback

改进

  • 分类调用诊断日志增强 — 在 AiFoundationDelegateAiFoundationClientCommentPreFilterService 中增加关键诊断日志(分类开始、fallback 触发、分类结果、异常详情),便于排查分类链路问题
  • AI 分类空结果处理 — 当 AI 返回空字符串时单独拦截,区别于"服务不可用"场景

v1.1.1

改进

  • "无意义"分类范围收窄 — 与文章主题无关的闲聊、灌水、打招呼不再被判为"无意义",仅纯乱码和无意义字符堆砌(如随机符号、键盘乱敲)才归类为"无意义"
  • AI 分类降级方案 — 当 OutputSpec.choice 结构化输出不被模型支持时,自动退回到普通 chat 调用并从响应文本中提取分类值(classifyWithChat fallback)
发布于查看详情

问题修复

  • 修复表单切换显示形式保存后还原的问题。
  • 修复联系表单文件上传失败时错误提示被二次解析异常覆盖的问题。

功能优化

  • 延迟加载联系表单资源,减少无表单页面的资源开销。
发布于查看详情

release: v1.0.5

功能增强:

  • 阅读进度条
  • 图片预览组件(画廊模式、焦点陷阱、键盘导航、手势滑动)
  • 文章目录 TOC 自动生成与滚动高亮
  • 暗/亮/跟随系统配色,防 FOUC
  • SEO 优化(Open Graph、Twitter Card、JSON-LD、Canonical)
  • 字体 CDN 加载(fontsource jsDelivr)

Bug 修复:

  • 修复重复 id=content(main 改用 id=main-content)
  • 修复 FOUC 脚本顺序错误(阻塞脚本读取未设置的 window 变量)
  • 修复 CSS 非法 // 注释
  • 修复 focus trap 监听器泄漏
  • 修复图片预览 load/error listener 累积(AbortController)
  • 修复 destroyImagePreview closeTimer 未清理
  • 修复 x-data 字符串内插风险(改用 data-* 属性传递)
  • 修复嵌套 x-data 作用域 bug
  • 修复 JSON-LD image null URL 和 modified_time 字段
  • 修复 share.ts 定时器堆积与 clipboard 异常
  • 删除 github-markdown.css 44 行重复变量定义

无障碍:

  • skip-to-content 跳转链接
  • 完整 aria 属性
  • 焦点恢复防御(isConnected 检查)

i18n:

  • 删除 4 个未使用 key
  • 新增 4 个缺失 key
发布于查看详情
  • 支持同一卡片 ID 连续关联多条收卡记录,确认收卡不再自动进入结束收卡状态,只有点击“结束收卡”才关闭继续收卡入口。
  • 修复确认收卡匹配流程中可能提前创建未匹配收卡记录的问题,并补充收卡状态校验与回归测试。
  • 在线打印工具封面打印与打包确认改为显示所有未打包卡片,覆盖通联业务、线上换卡与线下换卡场景。
  • 通联业务制卡打印发射地址优先使用本台 MY_QTH,并更新对应预设字段。
  • 优化通联日志筛选、ADIF 导入兼容与覆盖导入相关页面和文档说明。

Generated from v2.3.17

发布于查看详情

新特性

  • 评论前置过滤(合规检测) — AI 回复前对评论进行合规性分类,识别广告/辱骂攻击/敏感内容/无意义内容,违规评论停止生成 AI 回复,节省 Token
  • 违规评论自动设为待审核 — 检测到违规评论时自动将原评论 approved 置为 false,进入待审核队列,前端不再展示该评论
  • FILTERED 日志状态 — 被拦截的评论生成"已拦截"状态记录,日志页支持按"已拦截"状态筛选
  • 拦截原因分类标签 — 日志页显示拦截分类标签(广告/辱骂攻击/敏感内容/无意义)和详细拦截原因(含评论内容摘要)
  • 安全优先策略 — AI 分类服务不可用或异常时,默认拦截评论而非放行,防止违规内容漏网

改进

  • AI Foundation 隔离加载 — 将 AI Foundation API 引用隔离到 AiFoundationDelegate 类,AiFoundationClient 不再直接引用 AI Foundation 类,修复未安装 AI Foundation 时插件无法启动的问题(NoClassDefFoundError
  • 对话场景精准处罚 — AI 对话场景下违规内容来自 Reply 时,仅取消通过该 Reply 而非父级 Comment,避免误伤
  • 升级配置自动迁移 — 从 v1.0.x 升级时自动将 preFilterEnabledfalse 迁移为 true(新默认值)

Bug 修复

  • 修复未安装 AI Foundation 时插件无法启动BeanDefinitionStoreException: Failed to parse AiFoundationClient,将 AI Foundation API 引用隔离到委托类
  • 修复前置过滤默认关闭preFilterEnabled 默认值从 false 改为 true,新安装和升级用户均默认启用
  • 修复 penalize() 遗漏 approved=null — Halo 评论创建时 approved 可能为 null,原代码仅处理 approved=true 的情况
发布于查看详情

保险箱插件

保险箱插件为 Halo 站点提供基于规则和密码的资源访问保护。命中规则后,访客会先进入解锁页,密码验证通过后插件写入带有效期的 HttpOnly Cookie,并自动跳回原资源。

交流群

点击链接加入群聊【halo博客-lywq插件】

功能

  • 控制台规则管理:创建、编辑、启停、删除保险箱规则,支持按关键词、启用状态和保护对象筛选。
  • 多类型保护对象:支持附件路径、指定前台路由、整站私密三类保护范围。
  • 路径模式匹配:支持精确路径、父路径覆盖子路径,以及 ***? 通配符。
  • 命中预览:输入 URL 或路径后,按后端实际逻辑展示候选规则、最终命中规则、优先级和匹配精确度。
  • 附件列表集成:在 Halo 附件列表操作菜单中可以直接为有固定访问地址的附件新增保险箱规则。
  • 公开解锁流程:受保护资源统一跳转到固定解锁页,主题可覆盖页面模板。
  • 权限控制:控制台规则查看和管理分别由 plugin:safebox:rule:viewplugin:safebox:rule:manage 控制;公开解锁接口自动授权匿名访问。

保护对象

类型 适用场景 说明
附件 ATTACHMENT 私密图片、PDF、压缩包等上传文件 只保护 /upload 下的资源。
指定路由 ROUTE 会员页、下载页、活动页等前台路径 保护命中的前台路由,不影响 Halo 管理后台和插件接口。
整站私密 SITE 临时闭站、内部站点、密码访问站点 默认按 /** 匹配,可通过排除路径放行部分页面。

插件内置排除以下路径,避免把后台、接口、登录页和静态资源锁死:

/safebox/**
/apis/**
/console/**
/uc/**
/login
/logout
/oauth2/**
/actuator/**
/plugins/**
/themes/**
/assets/**

规则字段

字段 说明
规则名称 控制台展示名称,也是解锁页默认标题来源。
规则说明 解锁页说明文案;为空时使用默认提示。
保护对象类型 ATTACHMENTROUTESITE 三选一。
保护路径 一行一个路径模式,也支持用逗号分隔。建议填写以 / 开头的 pathname,不要填写完整 URL。
排除路径 命中这些路径时直接放行,常用于整站私密下放开公开页面。
访问密码 创建时必填;更新时留空表示保留原密码。密码以加盐 SHA-256 哈希保存。
优先级 数字越大越先匹配。相同优先级下,路径越具体越先匹配。
解锁有效期 单位秒,最小 60 秒,默认 3600 秒。
启用状态 停用后该规则不参与命中。

匹配规则

插件会从启用规则中选择最终命中的一条规则:

  1. 先按保护对象类型过滤,例如附件规则只处理 /upload 下的资源。
  2. 再排除内置路径和规则自身的排除路径。
  3. 匹配保护路径;不包含通配符的路径会同时覆盖其子路径,例如 /docs 会命中 /docs/a.pdf
  4. 候选规则按 priority 倒序排列。
  5. priority 相同时,路径匹配越具体越优先。

访问行为:

  • GETHEAD 请求命中规则且未解锁时,会以 303 See Other 跳转到 /safebox/unlock?path=...
  • GETHEAD 请求命中规则且未解锁时,会返回 401 Unauthorized
  • 解锁成功后,插件会写入当前规则专属 Cookie,Cookie 有效期来自规则的 ttlSeconds
  • 待访问 URL 中的 query 和 fragment 不参与路径匹配,匹配时只使用 pathname。

常用示例:

/upload/private/report.pdf     # 保护单个附件
/upload/private/**             # 保护整个附件目录
/vip                           # 保护 /vip 及其子路径
/**                            # 整站私密
/public/**                     # 可作为整站私密的排除路径

使用流程

  1. 在 Halo 后台安装并启用插件。
  2. 进入控制台菜单「保险箱」创建规则。
  3. 选择保护对象类型,填写保护路径、访问密码、优先级和有效期。
  4. 在「资源路径命中预览」中输入真实 URL 或路径,确认最终命中规则。
  5. 前台访问命中资源时会跳转到 /safebox/unlock,验证成功后自动回到原资源。

如果只想保护某个附件,也可以在 Halo 附件列表中打开该附件的操作菜单,选择「新增保险箱规则」。附件没有固定访问地址时不能创建规则,因为插件需要稳定的访问路径才能进行匹配。

主题集成

主题不需要主动判断资源是否受保护,访问拦截由插件的 WebFilter 统一处理。主题侧主要做一件事:按自己的设计覆盖解锁页模板。

受保护资源会统一跳转到:

/safebox/unlock?path=/upload/example.png

主题可以在当前主题的模板目录中提供 safebox-unlock.html 覆盖插件内置解锁页;未提供时使用插件内置模板。

templates/
  safebox-unlock.html

解锁表单必须使用 POST 提交到 unlockAction,并保留 pathpassword 两个字段:

<!doctype html>
<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title th:text="${displayName} + ' - 访问验证'">访问验证</title>
</head>
<body>
  <main>
    <h1 th:text="${displayName}">受保护资源</h1>
    <p th:text="${description}">该资源已开启访问保护,请输入密码后继续访问。</p>
    <p th:if="${error != null and error != ''}" th:text="${error}">密码不正确。</p>

    <form method="post" th:action="${unlockAction}">
      <input type="hidden" name="path" th:value="${path}">
      <label for="password">访问密码</label>
      <input id="password" name="password" type="password" autocomplete="current-password" required>
      <button type="submit">解锁资源</button>
    </form>
  </main>
</body>
</html>

可用模板变量:

变量 说明
displayName 匹配规则名称;为空时为 受保护资源
description 匹配规则说明;为空时为默认提示。
path 待解锁资源路径,验证通过后会跳回该路径。
error 错误文案;密码错误时为 密码不正确。
unlockAction 解锁表单提交地址,当前为 /apis/public.safebox.muyin.site/v1alpha1/unlock
unlockPagePath 固定解锁页路径,当前为 /safebox/unlock
rule 匹配到的 SafeBoxRule 对象,可读取 rule.spec.displayNamerule.spec.description 等字段。

注意事项:

  • 不要改表单字段名,pathpassword 少一个都无法解锁。
  • 不需要 Finder API,也不需要主题自己调用校验接口。表单提交成功后,插件会写入 Cookie 并重定向回原资源。
  • 如果资源被 CDN、对象存储或反向代理绕过 Halo 直接返回,插件无法拦截。资源必须经过 Halo 应用层访问。
  • 整站私密场景下,建议为公开页面配置排除路径,避免把无需保护的入口也锁住。

开发环境

  • Java 21+
  • Node.js 18+
  • pnpm 10+
  • Halo 运行版本要求:>= 2.20.14

开发

# 启动 Halo 开发服务器
./gradlew haloServer

# 修改后热重载插件
./gradlew reload

# 开发前端资源
cd ui
pnpm install
pnpm dev

构建

./gradlew build

构建完成后,可以在 build/libs 目录找到插件 JAR 文件。

测试

./gradlew test

cd ui
pnpm test:unit
pnpm type-check

许可证

GPL-3.0 © Lywq


Generated from 1.0.0

发布于查看详情

全能右键

为 Halo 主题页面注入一套可配置的自定义右键菜单。插件通过 Halo 的 TemplateHeadProcessor 自动注入运行时资源,不需要改主题模板。

交流群

点击链接加入群聊【halo博客-lywq插件】

功能特性

  • 自定义右键菜单:支持通用、选中文本、链接、图片 4 类显示场景。
  • 内置常用动作:复制页面链接、复制标题和链接、复制选中文本、复制图片地址、打开图片、复制链接地址、打开链接、返回顶部、刷新页面、返回首页、搜索、自定义链接。
  • 可选插件联动:支持会员收藏、会员签到、友链自助提交。
  • 路径控制:支持启用路径、排除路径,并且排除规则优先。
  • 样式配置:支持浅色、深色、跟随系统,支持强调色、菜单宽度、圆角配置。
  • PJAX 兼容:监听 pjax:completepjax:endturbo:loadswup:contentReplaced 后重新初始化。
  • 编辑区域保护:可在输入框、文本域、可编辑区域保留浏览器原生右键菜单。

兼容要求

项目 要求
Halo >= 2.25.0
Java 21
Node.js 推荐 24,CI 使用 24
pnpm 推荐 10,项目锁定 pnpm@10.12.4

可选依赖:

插件 用途
PluginMember >= 1.1.4-alpha6 会员收藏、会员签到
LinksSubmit >= 2.3.5 申请友链

这些依赖是可选的。没装也能使用基础右键功能,只是对应菜单项会提示依赖不可用。

安装使用

  1. 从 GitHub Release 下载插件 JAR。
  2. 进入 Halo 控制台,打开“插件”页面。
  3. 上传并启用插件。
  4. 进入插件设置页,按需调整启用路径、菜单项和样式。
  5. 回到前台主题页面,右键检查菜单是否出现。

本地构建安装:

./gradlew build

构建产物位于 build/libs,上传生成的 JAR 即可。

配置说明

基本设置

配置项 说明 默认值
启用全能右键 总开关,关闭后不注入右键菜单 开启
启用路径 留空表示全站主题页面启用 []
排除路径 命中后不启用,优先级高于启用路径 /console/**/uc/**/apis/**
PJAX 兼容模式 前台路由切换后重新读取配置并初始化 开启
编辑区域保留系统右键 输入框、文本域、可编辑区域不拦截右键 开启

路径规则

支持以下写法:

写法 示例 含义
精确路径 /about 仅匹配 /about
递归匹配 /posts/** 匹配 /posts 以及 /posts/hello/posts/a/b
单层匹配 /photos/* 匹配 /photos/a,不匹配 /photos/a/b
路径变量 /archives/{slug} 匹配 /archives/hello

排除规则永远优先。比如启用路径配置 /posts/**,排除路径配置 /posts/private/**,那么 /posts/private/secret 不会启用菜单。

菜单项字段

字段 说明
enabled 是否启用当前菜单项
id 菜单项标识,留空会自动生成
label 菜单显示名称
action 点击后执行的动作
context 显示场景:commontextlinkimage
icon 图标,推荐使用 Iconify 名称,例如 ri:link
url 自定义链接动作使用
target 打开方式:_self_blank
order 排序值,越小越靠前

图标支持 Iconify 名称、http(s) 图片地址、站内绝对路径、data:image/* 和内联 SVG。默认菜单使用的部分 Remix Icon 会内置为 SVG,其他 Iconify 图标会从 https://api.iconify.design 加载。

内置动作

动作 显示场景建议 行为
copyPageLink common 复制当前页面链接
copyPageTitleLink common 复制当前页面标题和链接
copySelection text 复制当前选中的文本
copyImageUrl image 复制当前图片地址
openImage image 打开当前图片
copyLinkUrl link 复制当前链接地址
openLink link 打开当前链接
scrollTop common 平滑返回页面顶部
reload common 刷新当前页面
home common 跳转到 /
search commontext 有选中文本时跳转到 /search?keyword=...,否则跳转到 /search
customLink common 打开自定义链接
memberFavorite common 调用会员插件收藏能力
memberSignIn common 调用会员插件签到能力
openLinksSubmit common 打开友链自助提交弹窗

customLinkurl 支持占位符:

{url}        当前页面链接,已 URL 编码
{title}      当前页面标题,已 URL 编码
{selection}  当前选中文本,已 URL 编码

示例:

https://example.com/share?title={title}&url={url}

可选插件联动

会员收藏

memberFavorite 会优先使用当前 Halo 文章上下文作为收藏对象。插件会从主题模板变量 post 中读取:

  • metadata.name
  • spec.title
  • status.permalink
  • spec.cover

如果当前页面没有 post 变量,运行时会尝试读取页面中的 data-member-favorite-subject 作为备用文章标识。

会员签到

memberSignIn 会等待会员插件前台 API 就绪,再执行签到。用户未登录时会跳转到登录页。

友链自助提交

openLinksSubmit 会尝试调用 window.LinksSubmit.openLinksSubmitOverlay(),也兼容 window.openLinksSubmitOverlay()。如果主题页面没有注入友链弹窗,会提示“友链申请弹窗未注入”。

主题兼容说明

插件会向主题页面 <head> 注入:

  • /plugins/right-menu/assets/static/right-menu/right-menu.css
  • 内联 JSON 配置脚本 #right-menu-config
  • /plugins/right-menu/assets/static/right-menu/right-menu.js

默认不会在 /console/**/uc/**/apis/** 生效。右键菜单挂载在 document.body 下,层级较高,通常不需要主题额外适配。

如果菜单没有显示,优先检查:

  1. 插件是否启用。
  2. 当前路径是否被排除规则命中。
  3. 主题页面源码中是否存在 right-menu-configright-menu-runtime
  4. 浏览器控制台是否能访问 /plugins/right-menu/assets/static/right-menu/right-menu.js
  5. 当前右键位置是否在输入框、文本域或可编辑区域。

开发

启动 Halo 开发环境:

./gradlew haloServer

前端依赖安装与监听构建:

cd ui
pnpm install
pnpm dev

项目结构:

路径 说明
src/main/resources/plugin.yaml 插件元信息、Halo 版本要求、可选依赖
src/main/resources/extensions/settings.yaml 插件设置表单
src/main/resources/extensions/reverseProxy.yaml 静态资源反向代理
src/main/java/site/muyin/rightmenu/processor/RightMenuHeadProcessor.java 主题 <head> 注入入口
src/main/java/site/muyin/rightmenu/setting/RightMenuSetting.java 设置模型与默认菜单
src/main/java/site/muyin/rightmenu/support/RightMenuPathMatcher.java 路径匹配规则
src/main/java/site/muyin/rightmenu/support/RightMenuPostContextExtractor.java 文章上下文提取
src/main/java/site/muyin/rightmenu/template/RightMenuHtmlTpl.java 注入 HTML 片段生成
src/main/resources/static/right-menu/right-menu.js 前台运行时
src/main/resources/static/right-menu/right-menu.css 前台样式
ui/src/__tests__/right-menu-runtime.test.ts 前台运行时单元测试

常用命令:

# 后端单元测试
./gradlew test

# 后端 + 前端校验
./gradlew check

# 完整构建插件 JAR
./gradlew build

# 前端运行时测试
cd ui
pnpm test:unit

./gradlew build 会先执行 ui 模块的 assemble,再把前端产物复制到插件资源目录。

发布

  1. 更新 gradle.properties 中的 version
  2. 执行 ./gradlew check./gradlew build
  3. 创建 GitHub Release。
  4. CD 工作流会构建并上传插件产物;当前配置默认跳过 Halo 应用市场发布。

常见问题

菜单在控制台或用户中心不显示

这是默认行为。插件默认排除了 /console/**/uc/**,避免影响 Halo 后台和用户中心。

图片或链接菜单项不出现

菜单项按 context 判断是否显示。image 只在图片上右键出现,link 只在链接上右键出现,text 需要页面存在选中文本。

复制失败

插件优先使用 navigator.clipboard.writeText,失败后会回退到 document.execCommand('copy')。如果浏览器权限、非安全上下文或主题脚本拦截复制行为,仍可能失败。

Iconify 图标不显示

默认内置图标不依赖网络。非内置 Iconify 图标会请求 https://api.iconify.design,如果站点网络策略拦截该域名,建议改用站内图片路径或内联 SVG。

会员收藏提示没有可收藏的文章

当前页面需要是 Halo 文章页,并且主题上下文里存在 post 变量;或者页面中提供 data-member-favorite-subject 作为备用文章标识。

许可证

GPL-3.0 © Lywq

发布于查看详情

保险箱插件

保险箱插件为 Halo 站点提供基于规则和密码的资源访问保护。命中规则后,访客会先进入解锁页,密码验证通过后插件写入带有效期的 HttpOnly Cookie,并自动跳回原资源。

交流群

点击链接加入群聊【halo博客-lywq插件】

功能

  • 控制台规则管理:创建、编辑、启停、删除保险箱规则,支持按关键词、启用状态和保护对象筛选。
  • 多类型保护对象:支持附件路径、指定前台路由、整站私密三类保护范围。
  • 路径模式匹配:支持精确路径、父路径覆盖子路径,以及 ***? 通配符。
  • 命中预览:输入 URL 或路径后,按后端实际逻辑展示候选规则、最终命中规则、优先级和匹配精确度。
  • 附件列表集成:在 Halo 附件列表操作菜单中可以直接为有固定访问地址的附件新增保险箱规则。
  • 公开解锁流程:受保护资源统一跳转到固定解锁页,主题可覆盖页面模板。
  • 权限控制:控制台规则查看和管理分别由 plugin:safebox:rule:viewplugin:safebox:rule:manage 控制;公开解锁接口自动授权匿名访问。

保护对象

类型 适用场景 说明
附件 ATTACHMENT 私密图片、PDF、压缩包等上传文件 只保护 /upload 下的资源。
指定路由 ROUTE 会员页、下载页、活动页等前台路径 保护命中的前台路由,不影响 Halo 管理后台和插件接口。
整站私密 SITE 临时闭站、内部站点、密码访问站点 默认按 /** 匹配,可通过排除路径放行部分页面。

插件内置排除以下路径,避免把后台、接口、登录页和静态资源锁死:

/safebox/**
/apis/**
/console/**
/uc/**
/login
/logout
/oauth2/**
/actuator/**
/plugins/**
/themes/**
/assets/**

规则字段

字段 说明
规则名称 控制台展示名称,也是解锁页默认标题来源。
规则说明 解锁页说明文案;为空时使用默认提示。
保护对象类型 ATTACHMENTROUTESITE 三选一。
保护路径 一行一个路径模式,也支持用逗号分隔。建议填写以 / 开头的 pathname,不要填写完整 URL。
排除路径 命中这些路径时直接放行,常用于整站私密下放开公开页面。
访问密码 创建时必填;更新时留空表示保留原密码。密码以加盐 SHA-256 哈希保存。
优先级 数字越大越先匹配。相同优先级下,路径越具体越先匹配。
解锁有效期 单位秒,最小 60 秒,默认 3600 秒。
启用状态 停用后该规则不参与命中。

匹配规则

插件会从启用规则中选择最终命中的一条规则:

  1. 先按保护对象类型过滤,例如附件规则只处理 /upload 下的资源。
  2. 再排除内置路径和规则自身的排除路径。
  3. 匹配保护路径;不包含通配符的路径会同时覆盖其子路径,例如 /docs 会命中 /docs/a.pdf
  4. 候选规则按 priority 倒序排列。
  5. priority 相同时,路径匹配越具体越优先。

访问行为:

  • GETHEAD 请求命中规则且未解锁时,会以 303 See Other 跳转到 /safebox/unlock?path=...
  • GETHEAD 请求命中规则且未解锁时,会返回 401 Unauthorized
  • 解锁成功后,插件会写入当前规则专属 Cookie,Cookie 有效期来自规则的 ttlSeconds
  • 待访问 URL 中的 query 和 fragment 不参与路径匹配,匹配时只使用 pathname。

常用示例:

/upload/private/report.pdf     # 保护单个附件
/upload/private/**             # 保护整个附件目录
/vip                           # 保护 /vip 及其子路径
/**                            # 整站私密
/public/**                     # 可作为整站私密的排除路径

使用流程

  1. 在 Halo 后台安装并启用插件。
  2. 进入控制台菜单「保险箱」创建规则。
  3. 选择保护对象类型,填写保护路径、访问密码、优先级和有效期。
  4. 在「资源路径命中预览」中输入真实 URL 或路径,确认最终命中规则。
  5. 前台访问命中资源时会跳转到 /safebox/unlock,验证成功后自动回到原资源。

如果只想保护某个附件,也可以在 Halo 附件列表中打开该附件的操作菜单,选择「新增保险箱规则」。附件没有固定访问地址时不能创建规则,因为插件需要稳定的访问路径才能进行匹配。

主题集成

主题不需要主动判断资源是否受保护,访问拦截由插件的 WebFilter 统一处理。主题侧主要做一件事:按自己的设计覆盖解锁页模板。

受保护资源会统一跳转到:

/safebox/unlock?path=/upload/example.png

主题可以在当前主题的模板目录中提供 safebox-unlock.html 覆盖插件内置解锁页;未提供时使用插件内置模板。

templates/
  safebox-unlock.html

解锁表单必须使用 POST 提交到 unlockAction,并保留 pathpassword 两个字段:

<!doctype html>
<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title th:text="${displayName} + ' - 访问验证'">访问验证</title>
</head>
<body>
  <main>
    <h1 th:text="${displayName}">受保护资源</h1>
    <p th:text="${description}">该资源已开启访问保护,请输入密码后继续访问。</p>
    <p th:if="${error != null and error != ''}" th:text="${error}">密码不正确。</p>

    <form method="post" th:action="${unlockAction}">
      <input type="hidden" name="path" th:value="${path}">
      <label for="password">访问密码</label>
      <input id="password" name="password" type="password" autocomplete="current-password" required>
      <button type="submit">解锁资源</button>
    </form>
  </main>
</body>
</html>

可用模板变量:

变量 说明
displayName 匹配规则名称;为空时为 受保护资源
description 匹配规则说明;为空时为默认提示。
path 待解锁资源路径,验证通过后会跳回该路径。
error 错误文案;密码错误时为 密码不正确。
unlockAction 解锁表单提交地址,当前为 /apis/public.safebox.muyin.site/v1alpha1/unlock
unlockPagePath 固定解锁页路径,当前为 /safebox/unlock
rule 匹配到的 SafeBoxRule 对象,可读取 rule.spec.displayNamerule.spec.description 等字段。

注意事项:

  • 不要改表单字段名,pathpassword 少一个都无法解锁。
  • 不需要 Finder API,也不需要主题自己调用校验接口。表单提交成功后,插件会写入 Cookie 并重定向回原资源。
  • 如果资源被 CDN、对象存储或反向代理绕过 Halo 直接返回,插件无法拦截。资源必须经过 Halo 应用层访问。
  • 整站私密场景下,建议为公开页面配置排除路径,避免把无需保护的入口也锁住。

开发环境

  • Java 21+
  • Node.js 18+
  • pnpm 10+
  • Halo 运行版本要求:>= 2.20.14

开发

# 启动 Halo 开发服务器
./gradlew haloServer

# 修改后热重载插件
./gradlew reload

# 开发前端资源
cd ui
pnpm install
pnpm dev

构建

./gradlew build

构建完成后,可以在 build/libs 目录找到插件 JAR 文件。

测试

./gradlew test

cd ui
pnpm test:unit
pnpm type-check

许可证

GPL-3.0 © Lywq

发布于查看详情

Earthquake 首个正式版本。

布局与交互
响应式导航栏 md 断点,平板正确折叠为汉堡菜单
View Transitions 圆形扩散切换深色模式(可在主题设置开启)
文章列表交错淡入,默认单条布局
首页文章封面图可点击跳转

评论区
去掉白色卡片框,注入 --halo-cw-* 变量跟随主题与深色模式

样式系统
OKLCH 单变量配色,–hue 驱动全套语义 token,30+ 预设
原生 CSS(移除 SCSS/sass-embedded)
prefers-reduced-motion 无障碍守卫

发布于查看详情

本次更新将版本号推进至 v1.0.4。核心重点在于彻底解决多用户混杂对话时“完整对话”弹窗上下文不清晰的问题,并对插件的后台管理 UI 进行了全面重写与现代化升级。同时,修正了之前版本中遗失的部分配置功能,并深度优化了移动端适配体验。

✨ 新特性

  • 对话上下文引用模块:在「查看完整对话」弹窗中,为非首条消息增加了精美的引用摘要框(采用微信/iOS 聊天天气泡风格)。查看日志时,可以一眼看出 AI 是在回复哪位用户的哪句话。
  • 纯净的层级化回复:放弃了此前强行在 AI 回复内容中注入 Markdown 块的方案,改为在数据库中存储纯净文本,并严格利用 Halo 原生的层级字段。这保证了 AI 的回复在首页页面能 100% 完美兼容任意博客主题的原生 UI。

🎨 界面与响应式重构 / UI & UX Overhaul

  • 全面移除 Tailwind 依赖:由于 Halo 后台宿主环境的 UnoCSS 缓存机制会导致动态 Tailwind 类名失效(引发排版错乱),本次将彻底使用原生 Scoped CSS 进行重写。样式从此绝对稳定,不再受宿主环境干扰。
  • 现代化卡片与交互
    • AI 角色卡片升级:增加柔和阴影(Soft Shadow)、悬浮微动效、状态圆点,界面质感大幅提升。
    • 引用框升级:AI 气泡和用户气泡采用了不同透明度的自适应引用框,视觉层级更清晰。
  • 深度移动端适配 (Mobile-First)
    • 工具栏(搜索、筛选、批量操作)在手机端自动垂直堆叠折叠。
    • 对话弹窗及设置表单在手机端自动撑满宽度 (max-width: calc(100vw - 32px)),防止溢出屏幕。
    • 设置页面的 Tab 导航栏在移动端支持无缝横向滑动。

🔧 问题修复与优化

  • 恢复遗失功能:修复了上个测试版本中意外丢失的「AI 角色增删改查」、「数据清理面板」、「配置导入/导出」以及「Gravatar 头像实时预览」的完整功能代码。
  • 后端接口补充:优化了相关方法,向上溯源构建以支撑前端引用模块渲染。
发布于查看详情

性能优化

  • 内联 theme-color-init.js,减少首屏阻塞请求。
  • 调整欢迎页加载逻辑,去掉 body visibility:hidden 式的首屏隐藏方案。
  • 欢迎遮罩改为在 DOMContentLoaded 后更早结束,不再强依赖 window.load
  • 缩短欢迎页过渡动画时长,减少首屏等待感。
  • 首页背景图改为“本地默认图先显示,远程图异步替换”,避免远程接口拖慢 LCP。
  • 非关键 CSS 改为异步加载:
    • qweather-icons.css
    • lenis.css
    • aos.css
    • swiper-bundle.min.css
    • welcome.css
  • 字体图标改为延迟加载,降低首屏阻塞。
  • 若干非关键脚本改为 defer
    • APlayer.min.js
    • Meting2.min.js
    • cursor-init.js

字体显示优化

  • fontawesome.min.css 中的 font-displayblock 调整为 swap
  • qweather-icons.css 增加 font-display: swap
  • 优化字体加载策略,减少文本不可见时间。

文章页与侧栏修复

  • 相关文章无数据时,假链接占位改为普通文本占位。
  • 作者信息浮层链接补充可访问描述,避免被识别为“无描述链接”。

装备页面修复

  • 重写 equipments.html 的静态中文文案,修复乱码问题。
发布于查看详情

优化

  • 优化友链管理页面中审核时间的展示方式,修复时间文本过长时不换行导致布局异常的问题。

修复

  • 修复插件无关日志被错误输入或记录的问题,避免非插件功能日志干扰 AstraHub 插件日志内容。
发布于查看详情

详情请参阅更新日志在 GitHub 上查看)。
Please refer to Changelog (view on GitHub) for details.

howiehz-higan-zh-hans.zip 为简体中文默认安装包,仅包含 .br
howiehz-higan-zh-hans-tiny.zip 为简体中文轻量安装包,移除默认字体资源,默认 logo 资源将替换为 1x1 占位图,不包含预压缩文件,且不注入 Mermaid / instant.page 运行时。
howiehz-higan-zh-hans-full-precompressed.zip 为简体中文完整预压缩包,包含 .gz / .br / .zst
howiehz-higan-en.zip is the English default package with .br only.
howiehz-higan-en-tiny.zip is the English tiny package that removes the default font assets, replaces the default logo asset with a 1x1 placeholder image, omits precompressed assets, and excludes Mermaid / instant.page runtime injection.
howiehz-higan-en-full-precompressed.zip is the English full precompressed package with .gz / .br / .zst.

发布于查看详情

1.0.0

  • 首次发布 InkNest 主题。
  • 提供首页、文章、页面、分类、标签、归档、作者、友情链接和 404 页面模板。
  • 支持搜索插件入口、评论组件、友情链接插件、图片灯箱、代码复制、阅读进度和 SEO 元信息。
发布于查看详情

Quiet 首个正式版本,提供极简内容型博客主题的基础能力,包括浅色 / 暗色模式、首页最近更新、文章列表大小调节、文章目录、阅读进度、侧边栏模块、代码块复制、分类 / 标签 / 归档 / 作者页适配和响应式布局。

发布于查看详情

首次发布 InkNest 主题。
提供首页、文章、页面、分类、标签、归档、作者、友情链接和 404 页面模板。
支持搜索插件入口、评论组件、友情链接插件、图片灯箱、代码复制、阅读进度和 SEO 元信息。

发布于查看详情

新功能

  • 唤醒词 — 评论以唤醒词开头可唤醒指定角色回复,支持自定义唤醒词,可在未启用AI回评的页面使用唤醒词召唤AI,二级评论同样支持
  • 性别配置 — AI角色支持性别设置(男/女),AI回复时会保持对应性别身份
  • 语气风格 — 支持中性语气复选框,勾选后使用中性语气,取消勾选则跟随性别语气(女性温柔细腻/男性沉稳理性)
  • 身份提示词强化 — 角色身份信息前置到Prompt最开头(【核心身份】),安全规范中增加身份约束,确保AI始终保持角色身份

改进

  • 5级情感分析 — 从3级分类(正面/中性/负面)升级为5级分类(非常正面/正面/中性/负面/非常负面),情感判断更精细
  • 日志页面UI优化 — 批量操作按钮重写样式确保清晰可见;搜索框添加搜索图标;重置按钮添加图标和底色;评分与等级标签增加间距和底色;状态标签统一使用带底色样式
  • 移动端适配 — 仪表盘、配置、日志页面全面适配移动端
  • 页面链接显示 — 日志中新增独立页面(SinglePage)链接显示
  • ObjectMapper统一注入 — 改为Spring构造函数注入
  • 服务端过滤优化 — 日志列表查询改用 Queries.equal() 服务端过滤
  • 新增索引 — 为 AiCommentReply 扩展添加 spec.sentimentspec.publishedspec.postKind 索引

Bug 修复

  • 修复 Halo 插件上下文中 ObjectMapper Bean 不存在的问题
  • 修复 AI 回复仍说"没有性别"的问题(身份信息前置+安全规范强化)
  • 修复唤醒词无法唤醒的问题(HTML strip + trim + 日志级别 + 检查位置修正)
  • 修复二级评论唤醒词检查位置错误的问题
  • 修复 SinglePage 内容获取 404 错误
  • 修复 Post/SinglePage 不存在时 404 异常未捕获的问题
  • 修复 Sort 参数 null 警告

安装

  • 应用商店:插件 → 安装 → 应用市场搜索 AI回评 → 安装,或前往 Halo 应用商店 一键安装
  • 手动安装:下载下方 .jar 文件 → 插件 → 安装 → 本地上传

前置要求

  • Halo 2.25+
  • AI Foundation 插件(必须)
发布于查看详情

Quiet 首个正式版本,提供极简内容型博客主题的基础能力,包括浅色 / 暗色模式、首页最近更新、文章列表大小调节、文章目录、阅读进度、侧边栏模块、代码块复制、分类 / 标签 / 归档 / 作者页适配和响应式布局。

发布于查看详情

v2.0.4

新增 PJAX 无刷新切换引擎

站内页面切换时仅替换主体内容,保留全局持久层,解决切换页面时音乐播放组件中断、播放器重新初始化等问题,提升浏览体验。

新增 PJAX 启用/关闭功能

后台主题设置中可自由开启或关闭 PJAX 功能,适配不同站点需求。关闭后恢复传统整页跳转。

优化页面切换样式加载机制

PJAX 切换时会先加载新页面所需 CSS,再替换页面内容,避免出现短暂无样式页面、图标放大、布局闪烁等问题。

优化页面切换过渡

开启 PJAX 后自动使用页面切换遮罩,减少切页过程中的视觉突兀感。

优化全局资源加载

Font Awesome、AOS、Swiper 等关键样式改为稳定加载,降低冷加载和 PJAX 切页时的样式闪烁概率。

优化 PJAX 生命周期管理

增加页面进入与离开钩子,支持页面脚本在 PJAX 切换后重新初始化,并在离开页面时清理定时器、滚动监听、弹窗状态等资源。

优化滚动与动画组件兼容性

适配 Lenis 平滑滚动、AOS 动画、Swiper 轮播等组件在 PJAX 场景下的重新初始化与状态刷新。

发布于查看详情

v1.0.0-beta.2

改进

  • 改用 ExtensionGetter 集成 AI Foundation:通过 Halo 官方推荐的 ExtensionGetter.getEnabledExtension(AiModelService.class) 获取 AI 服务,替换原先的跨 ClassLoader 反射调用方式(Issue #1
  • 声明插件依赖:在 plugin.yaml 中声明可选插件依赖 ai-foundation?: "*",建立正确的插件依赖关系,插件在未安装 AI Foundation 时仍可正常加载
  • 应用市场推荐:新增 store.halo.run/recommended-apps 注解,安装本插件后可在应用市场推荐安装 AI Foundation 插件
  • 使用结构化输出:情感分析和内容审核改用 AI Foundation 的 OutputSpec.choice 结构化输出,替换原先的字符串匹配解析,分类更可靠
  • 使用 GenerateTextRequest:AI 调用改用 GenerateTextRequest 并设置 maxRetries=2,由 SDK 自动重试瞬时错误
  • 多轮对话上下文:AI 对话续接时自动获取之前的回复历史并注入到 Prompt 中,AI 能更好地理解对话上下文
  • 优化 AI 自审核评分机制:审核改为两阶段评估(安全检查 + 质量评分 1-5 分),评分映射到 0-100 分(0/30/50/70/85/100),替代原先的二值评分(0/100),评分更有区分度
  • 精简仪表盘:移除情感分布、近7日回复趋势、平均审核评分三个卡片,快捷操作精简为回复日志、插件设置、刷新数据
  • 重做设置页面:基本设置、AI角色设置、模型设置、Prompt设置、数据清理各为独立页面,通过标签栏切换
  • 优化设置页面布局:按钮统一排版并添加图标,侧边栏保存卡片高亮显示,新增"未保存"状态指示器
  • 优化日志页面:评分增加等级标签(优秀/良好/一般/较差),筛选下拉框修复文本与箭头重叠
  • 优化 AI Foundation 状态提示宽度:状态提示与内容区宽度一致
  • 优化插件文档:修复版本要求(2.23→2.25)、变量名({{conversation}}{{conversation_history}})、GitHub 链接(nxxy335sunny-335)、Cravatar 链接(cravatar.cncn.cravatar.com)等错误,补充缺失的配置项文档

Bug 修复

  • 修复自动发布后日志显示未发布generateAndPublishMono<Void> 的 empty 信号触发 switchIfEmpty 导致 publishReply 被调用两次,第二次覆盖 published=false
  • 修复 RateLimitService 线程泄漏:清理线程未在插件停止时关闭,实现 DisposableBean 正确释放资源
  • 修复 ReviewService 提示词不匹配:审核提示词要求"重新生成"但代码未使用重新生成的内容,移除误导性指令
  • 修复设置页面按钮图标文字对齐:通过 :deep(.btn-content) 设置 inline-flex 布局,图标和文字并排显示
  • 修复设置页面标签栏无法点击切换:替换不工作的 VTabbar 组件为自定义按钮实现
  • 修复设置页面配置区域布局错误:将标签栏移出 grid 容器,避免挤占配置区域宽度
  • 修复日志页面筛选下拉框文本与箭头重叠:将 px-3 改为 pl-3 pr-8 为下拉箭头预留空间
发布于查看详情

详情请参阅更新日志在 GitHub 上查看)。
Please refer to Changelog (view on GitHub) for details.

howiehz-higan-zh-hans.zip 为简体中文默认安装包,仅包含 .br
howiehz-higan-zh-hans-tiny.zip 为简体中文轻量安装包,移除默认字体资源,默认 logo 资源将替换为 1x1 占位图,不包含预压缩文件,且不注入 Mermaid / instant.page 运行时。
howiehz-higan-zh-hans-full-precompressed.zip 为简体中文完整预压缩包,包含 .gz / .br / .zst
howiehz-higan-en.zip is the English default package with .br only.
howiehz-higan-en-tiny.zip is the English tiny package that removes the default font assets, replaces the default logo asset with a 1x1 placeholder image, omits precompressed assets, and excludes Mermaid / instant.page runtime injection.
howiehz-higan-en-full-precompressed.zip is the English full precompressed package with .gz / .br / .zst.

发布于查看详情

What’s Changed
feat: 支持自定义目录(TOC)的显示层级和折叠层级 (#207) by @AirboZH in #208
Full Changelog: v1.4.9…v1.5.0

发布于查看详情

新特性

  • 卡片排序按照热门友链排序。

友链星球

  • 友链星球卡片改为热门推荐排序展示。
  • 新增星系排行皇冠标志,并支持鼠标悬浮查看排行计算方法。
  • 卡片新增星系名称展示,名称超过 10 个字自动省略。
  • 卡片新增“星系N”展示,用于显示关联星系数量。
  • 卡片 URL 支持点击跳转。
  • 卡片描述默认展示 15 个字,超出自动省略。
  • 移除卡片上的标签展示。
  • 移除卡片上的归属站点展示。
  • 操作按钮简化,同一张卡片只展示一个主要操作按钮。
  • 本站卡片合并进普通列表样式,不再使用独立特殊卡片。

友链邀请管理

  • 收紧友链管理列表各字段之间的间距,RSS 链接和邀请状态不再距离过远。
  • 原“已送达/投递状态”标志改为审核结果标志。
  • 已通过显示绿色打勾。
  • 已拒绝显示红色打叉。

稳定性与兼容

  • 修复友链星球虚拟滚动加载后闪现/消失的问题。
  • 修复收藏配置为空时可能导致页面异常的问题。

清理

  • 移除旧本站特殊卡片样式残留。
  • 移除旧投递状态展示函数和样式残留。
  • 移除未使用的友链星球普通背景样式残留。
  • 清理文件头异常 BOM。
  • 已通过前端构建和完整插件构建验证。
发布于查看详情

Tip

当前版本不再强制依赖于 AI Foundation 插件,但使用 AI 对话时仍旧需要,更新后仍旧需要重载主题设置。

新增功能

  • 为 AI 聊天接口增加安全防护,降低匿名恶意调用 AI 或 Agent 能力的风险。

功能优化

  • 不再强制依赖于 AI Foundation 插件,仅在开启 AI 对话时需要此插件。

Full Changelog: v2.0.1...v2.1.0


Generated from v2.1.0

发布于查看详情
  • 代码审查修复:基于全面代码审查,修复以下问题
  • 语法高亮保留:新增 splitHtmlLines() 方法,行号显示时完整保留 hljs 语法高亮结构,修复行号导致高亮失效的问题
  • Shiki 冲突检测:恢复 Shiki 高亮插件检测逻辑,当检测到 Shiki 存在时自动跳过高亮处理,避免双重样式冲突
  • 初始化合并:统一 observeCodeBlocks()observeImages() 调用,移除重复的模块 init() 调用,提升性能
  • 未使用变量清理:删除 pendingInit 未使用变量
  • CSS :has() 兼容:使用 @supports 特性查询,并为不支持 :has() 的浏览器提供 CSS fallback
  • JSDoc 完善:为所有关键函数添加完整的 JSDoc 注释,提升代码可维护性
  • 错误日志:添加复制按钮失败的错误日志输出
发布于查看详情
  • 开关独立:所有功能开关默认关闭,未启用的功能不再加载任何资源
  • 主题兼容:通过 CSS 变量统一管理配色,修复部分主题下代码文字不可读的问题
  • 移动端修复:移除 touchstart 绑定,避免点击双触发;底部折叠按钮严格依据状态显隐
  • 代码重构applyThemeColors 改为数据驱动(BASE_COLORS),processCode 拆分为 ensureWrapper/addHeader 子方法
  • 观察者优化observeCodeBlocks 仅在启用高亮或代码折叠时观察代码块,避免仅启用长图折叠时误装饰代码
  • 配置增强:亮色/暗色主题选择器均提供完整 14 种主题选项,支持反向配色
  • 日志清理:移除所有 console.log 调试日志,保留 console.warn 错误日志
发布于查看详情
  • 资源统一:统一 CSS 文件名为 code-enhance.css(不存在 .min.css 版本)
  • 开关独立修复:修复未开启代码高亮只开启其他选项时,前台仍加载代码高亮资源的问题
  • 条件注入优化:根据各功能开关条件性注入资源,避免加载未启用的功能模块
发布于查看详情
  • 配置项重命名enableCodeHighlight 重命名为 enableHighlight,语义更简洁
  • 代码重构:重构头部处理器,抽取 injectResourcesbuildPropertiesappendHljsResourcesappendConfigappendBaseResources 等方法,优化模板资源注入逻辑
  • 功能检查简化:新增 hasAnyFeatureEnabled() 方法,简化全功能禁用时的跳过判断
  • 模板匹配优化:抽取 hasContentVariable() 方法,简化内容模板判断逻辑
  • Logo 本地化:插件 Logo 路径从外链改为本地静态资源 static/images/dan.svg
  • 类注释完善:补充 CodeEnhanceHeadProcessor 类注释文档
  • 错误日志增强onErrorResume 改为记录完整异常堆栈
发布于查看详情

feat(core): 优化会员插件的积分和储值账户功能

  • 添加积分兑换作为默认合规路径的架构决策文档
  • 添加余额提现由显式开关控制的架构决策文档
  • 添加产品订单承载积分兑换的架构决策文档
  • 升级 halo 插件开发工具版本到 0.8.0
  • 配置 OpenAPI 使用现有服务器模式
  • 将前端代码中的余额相关显示名称改为可配置的储值账户名称
  • 在会员充值通知模板中使用动态的账户名称
  • 添加控制台端点用于获取会员插件设置
  • 更新后端接口描述从余额改为储值账户额度
  • 实现储值账户功能的启用验证逻辑
  • 添加储值账户相关的单元测试
  • 重构余额扣除服务方法以支持自定义显示名称
  • 在签到组件中集成可配置的余额显示名称
发布于查看详情

项目集(Portfolio)

CI
License
Halo

Halo CMS 插件 —— 统一管理和展示 GitHub、Gitee、产品、插件、工具等项目作品。

交流群

点击链接加入群聊【halo博客-lywq插件】

功能特性

  • 项目管理 — 在 Halo 控制台创建、编辑、删除项目,支持草稿 / 已发布 / 已归档三种状态
  • 多平台支持 — 内置 GitHub、Gitee、独立站点、私有项目等平台选项,可在设置中自定义扩展
  • 多类型分类 — 开源项目、产品、插件、网站、工具、类库,同样支持自定义
  • 技术栈 & 标签 — 每个项目可关联多个技术栈和展示标签,方便筛选和检索
  • 推荐项目 — 标记重点项目,在首页或侧边栏优先展示
  • 默认页面 — 开箱即用的 /projects 列表页和 /projects/{slug} 详情页,支持主题覆盖
  • Finder API — 注册 projectFinder,主题模板可直接调用,灵活控制渲染
  • 编辑器卡片 — 在 Halo 富文本编辑器中插入项目卡片,在文章中嵌入项目展示
  • Markdown 内容 — 项目详情支持 Markdown 编写,自动渲染为安全 HTML
  • RBAC 权限 — 内置查看 / 管理两级角色模板,支持细粒度权限控制
  • SEO 友好 — 自定义页面标题和描述,详情页自动生成 meta 信息

安装

方式一:从 Release 安装(推荐)

  1. 前往 Releases 下载最新 .jar 文件
  2. 在 Halo 控制台 → 插件管理 → 安装插件,上传 jar 文件
  3. 启用插件

方式二:从源码构建

git clone https://github.com/liuyiwuqing/plugin-portfolio.git
cd plugin-portfolio
./gradlew build

构建产物位于 build/libs/plugin-portfolio-*.jar,在 Halo 控制台上传安装。

配置

插件启用后,在 控制台 → 插件 → 项目集 → 设置 中可配置:

配置项 说明 默认值
启用默认展示页 开启后提供 /projects/projects/{slug} 路由 开启
默认每页数量 列表页每页显示项目数 12
默认 SEO 标题 页面 <title> 和 OG 标题 项目作品集
默认 SEO 描述 页面 <meta description> 集中展示开源项目、产品、插件、工具和其他开发作品。
平台选项 项目来源平台下拉选项 GitHub / Gitee / 独立站点 / 私有项目 / 其他
类型选项 项目类型下拉选项 开源项目 / 产品 / 插件 / 网站 / 工具 / 类库 / 其他

平台和类型选项支持自由增删改,value 建议使用小写英文、数字和下划线。

主题集成

Finder API

插件注册 projectFinder,在 Thymeleaf 模板中直接注入使用。Finder 只返回已发布项目。

方法列表

方法 返回值 说明
list(page, size) ListResult<Project> 分页获取项目
listBy(keyword, platform, type, tag, page, size) ListResult<Project> 按关键词、平台、类型、标签组合筛选
listByPlatform(platform, page, size) ListResult<Project> 按平台筛选
listByType(type, page, size) ListResult<Project> 按类型筛选
listByTechStack(techStack, page, size) ListResult<Project> 按技术栈筛选
listByTag(tag, page, size) ListResult<Project> 按展示标签筛选
featured(page, size) ListResult<Project> 获取推荐项目
recent(size) List<Project> 获取最近项目(不分页)
count() long 公开项目总数
options() ProjectOptions 获取平台和类型选项列表
setting() PortfolioSetting 获取插件通用设置
platformLabels() Map<String, String> 平台 value → label 映射表
typeLabels() Map<String, String> 类型 value → label 映射表
renderContent(project) String 将项目 Markdown 内容渲染为安全 HTML
listAll() Flux<Project> 获取全部公开项目流
getBySlug(slug) Mono<Project> 按 slug 获取单个项目

Thymeleaf 示例

展示推荐项目:

<th:block th:with="projects=${projectFinder.featured(1, 6)},
                   platformLabels=${projectFinder.platformLabels()},
                   typeLabels=${projectFinder.typeLabels()}">
  <div class="project-grid">
    <article th:each="project : ${projects.items}" class="project-card">
      <a th:href="@{/projects/{slug}(slug=${project.slug})}">
        <img th:if="${project.cover}" th:src="${project.cover}" th:alt="${project.title}" />
        <h3 th:text="${project.title}">项目标题</h3>
        <p th:text="${project.summary}">项目简介</p>
        <span th:text="${platformLabels[project.platform] ?: project.platform}">平台</span>
        <span th:text="${typeLabels[project.type] ?: project.type}">类型</span>
      </a>
    </article>
  </div>
</th:block>

渲染项目详情内容:

<div th:utext="${projectFinder.renderContent(project)}"></div>

按技术栈筛选:

<th:block th:with="projects=${projectFinder.listByTechStack('Vue', 1, 10)}">
  <div th:each="project : ${projects.items}">
    <a th:href="@{/projects/{slug}(slug=${project.slug})}" th:text="${project.title}">标题</a>
  </div>
</th:block>

默认页面

插件内置两个 Thymeleaf 模板:

路由 模板 说明
/projects projects.html 项目列表页,响应式网格布局,支持分页
/projects/{slug} project-detail.html 项目详情页,展示封面、元数据和 Markdown 内容

主题可通过提供同名模板覆盖默认页面。关闭设置中的「启用默认展示页」后,插件不再注册路由,完全由主题自行渲染。

编辑器项目卡片

在 Halo 富文本编辑器中,可通过工具栏或斜杠命令 / 插入「项目卡片」节点。选择一个已发布项目后,文章中会嵌入一个可交互的卡片组件。

卡片在前端渲染为 <portfolio-project-card data-slug="xxx"> 标签,发布时由插件自动替换为带样式的 HTML 卡片,包含封面、标题、摘要和元数据标签。

项目数据模型

每个项目(Project)包含以下字段:

字段 类型 必填 说明
title String 项目标题(最长 120 字符)
slug String URL 友好标识(最长 80 字符)
summary String - 项目摘要(最长 500 字符)
content String - 项目详情,支持 Markdown
cover String - 封面图 URL
platform String - 来源平台(如 github
type String - 项目类型(如 open_source
techStacks List<String> - 技术栈标签
tags List<String> - 展示标签
repoUrl String - 仓库地址
demoUrl String - 演示地址
docsUrl String - 文档地址
priority Integer - 排序值,越大越靠前
featured Boolean - 是否推荐
status Enum - DRAFT / PUBLISHED / ARCHIVED
createTime String - 创建时间
updateTime String - 更新时间

另有 sourceProviderrepoOwnerrepoName 字段为后续仓库同步功能预留。

开发

环境要求

  • Java 21+(Gradle toolchain 强制)
  • Node.js 20+
  • pnpm 10+

启动开发服务

# 终端 1:启动 Halo 开发服务器(含后端热重载)
./gradlew haloServer

# 终端 2:启动前端开发服务器(含 HMR)
cd ui
pnpm install
pnpm dev

Halo 开发服务器默认运行在 http://localhost:8090,前端开发服务器提供模块热替换。

项目结构

src/main/java/site/muyin/portfolio/
├── PortfolioPlugin.java          # 插件生命周期,注册 GVK 和索引
├── scheme/Project.java           # 核心数据模型
├── enums/                        # 枚举(项目状态)
├── model/                        # 数据传输对象
├── query/                        # 查询参数构建
├── setting/                      # 插件设置 POJO
├── service/                      # 业务逻辑接口
│   └── impl/                     # 业务逻辑实现
├── endpoint/                     # REST API(Console + Public)
│   └── routes/                   # 路由处理器
├── finders/                      # Finder API 接口
│   └── impl/                     # Finder API 实现
├── content/                      # 内容渲染(Markdown + 项目卡片)
└── router/                       # 默认页面路由

ui/src/
├── index.ts                      # 插件入口,注册路由和编辑器扩展
├── views/ProjectManagerView.vue  # 项目管理页面
├── api/portfolio.ts              # API 客户端和类型定义
├── editor/                       # TipTap 编辑器扩展
└── assets/                       # 静态资源

构建

# 完整构建(后端 + 前端)
./gradlew build

# 仅构建前端
cd ui && pnpm build

# 运行后端测试
./gradlew test

# 运行前端检查
cd ui && pnpm check

构建产物:build/libs/plugin-portfolio-*.jar

CI/CD

项目使用 GitHub Actions 自动化:

  • CIci.yaml)— 推送或 PR 到 main 分支时触发,执行构建和测试
  • CDcd.yaml)— 发布 GitHub Release 时触发,构建并产出插件 jar

技术栈

层级 技术
后端语言 Java 21
后端框架 Spring WebFlux(响应式)
插件平台 Halo Plugin SDK
构建工具 Gradle 9.4
前端框架 Vue 3(Composition API)
前端语言 TypeScript
前端构建 Rsbuild(基于 Rspack)
包管理 pnpm
Markdown CommonMark
测试 JUnit 5 / Vitest

许可证

GPL-3.0 © Lywq

发布于查看详情

Tip

此版本为重大更新,升级后请务必在插件设置中重载插件配置!!并且当前插件将会依赖于 AI Foundation 插件,请务必下载安装此插件。

Warning

不过由于架构的更新,由此带来的问题是,前端包的体积大了近十倍,尽管我已经尽力做了优化,但当前前端包的体积仍旧达到了 500kb,这可能会产生一些网络访问的问题。

当前版本开始,从底层架构开始完全重构此次插件,得益于架构的更新,现在 Live2d 将支持如下功能:

  1. 支持基于事件的驱动策略,可以在主题或任何地方使用事件订阅来触发 Live2d 功能。
  2. 支持 Cubism 2、4、5 版本,理论上基于此类架构的所有模型,如有问题请及时反馈。
  3. 对工具栏配置进行改动,将可以自定义 Live2d 右侧工具栏。
  4. 可以实时对 Live2d 的动作、表情等做渲染处理。
  5. 扩展更多的 Tips 事件。

并且从当前版本开始,插件的 AI 底层将基于 Halo Ai Foundation 插件。因此也将整体 AI 功能进行了重构,现在 Live2d 的 AI 功能将支持更多丰富的功能,例如:

  1. 支持更多的模型供应商。(由 Ai Foundation 插件提供)
  2. 支持用户使用 Live2d 进行 Agent 访问站点,功能包括:阅读当前站点上下文,打开某个页面、读取网站文章、页面、瞬间,访问网络资源,Halo 内容搜索,评论与留言辅助等等。

新增功能

  • 支持更多现代化的模型,支持基于 Cubism 2/4/5 版本的模型。
  • 支持主题或站长基于事件对模型进行驱动。
  • 支持站长自定义 Live2d 右侧工具栏。
  • 看板娘的位置将不再固定,允许用户自由拖拽 Live2d 看板娘的位置并进行保持,包括最小化后的按钮位置。
  • 可以实时对 Live2d 的动作、表情等做渲染处理。
  • 扩展更多的 Tips 事件,例如 loading 等。
  • 支持更多的模型供应商(由 Ai Foundation 插件提供)
  • 在原有 AI 对话的基础上,增加了支持用户的 Agent 访问,例如
    • 阅读当前站点上下文并总结。
    • Halo 内容搜索。
    • Halo 资源导航。
    • 评论与留言辅助。
    • 网络访问。
    • 自定义工具。

问题修复

  • 修复自动加载 tips 时总会出现报错的问题。
  • 解决加载时可能出现冲突导致加载无法出现的问题。
  • 解决模型在运行阶段会突然丢失部分模型体的问题。(需持续观察,如再次出现请及时反馈)。

功能优化

  • 将设置项中的 repeater 组件更换为更简洁的 Array 组件。
  • 优化了对话框的高度问题,现在对话框将不会遮挡住模型,即便它更改高度。
  • 优化了 AI 对话框的样式。
  • 优化了 AI 对话时的提示信息,现在不会立即出现提示了。
  • 取消了后端的日志打印,现在不会看到非常长的日志了。

项目重构

  • 使用更加现代化的 pixi.js 重构底层代码。
  • 使用 Ai Foundation 重构 AI 逻辑。

--- 光速发布的 2.0.1 版本 ---


Generated from v2.0.1

发布于查看详情

详情请参阅更新日志在 GitHub 上查看)。
Please refer to Changelog (view on GitHub) for details.

howiehz-higan-zh-hans.zip 为简体中文默认安装包,仅包含 .br
howiehz-higan-zh-hans-tiny.zip 为简体中文轻量安装包,移除默认字体资源,默认 logo 资源将替换为 1x1 占位图,不包含预压缩文件,且不注入 Mermaid / instant.page 运行时。
howiehz-higan-zh-hans-full-precompressed.zip 为简体中文完整预压缩包,包含 .gz / .br / .zst
howiehz-higan-en.zip is the English default package with .br only.
howiehz-higan-en-tiny.zip is the English tiny package that removes the default font assets, replaces the default logo asset with a 1x1 placeholder image, omits precompressed assets, and excludes Mermaid / instant.page runtime injection.
howiehz-higan-en-full-precompressed.zip is the English full precompressed package with .gz / .br / .zst.

发布于查看详情

feat(image): 添加共享图片列表显示模式支持网格和瀑布流布局

  • 实现了共享图片列表显示组件,支持网格模式和瀑布流模式
  • 添加了瀑布流模式的CSS网格密集布局实现
  • 集成了图片列表显示模式切换功能
  • 添加了存储用户选择显示模式的功能
  • 实现了瀑布流模式下基于图片比例的瓷砖尺寸计算
  • 更新了图片床选择器组件以使用新的共享显示组件
  • 添加了相关的单元测试和文档说明

Generated from v1.3.3

发布于查看详情

AI回评 v1.0.0-beta.1

基于 AI 的 Halo 博客评论自动回复插件,支持 AI 虚拟角色回复、自审核、自动发布和对话式连续回复。

新功能

  • AI Foundation 反射集成:通过运行时反射调用 AI Foundation 插件的 AiModelService,无需 pluginDependencies,彻底解决跨 ClassLoader 类加载问题
  • 草稿模式:关闭"自动发布"后,AI 回复将保存为草稿,需站长审核后才发布
  • 多 AI 角色支持:支持配置多个 AI 虚拟角色,每个角色有独立的提示词、头像和模型
  • 提示词预设:内置多种回复风格预设(专业型、幽默型、简洁型等),可自由组合
  • 每日回复趋势图:首页新增每日回复数量柱状图,支持 7 天/30 天/全部切换
  • 对话历史查看:支持查看 AI 回复的完整对话上下文

Bug 修复

  • 修复草稿模式下审批失败(“AI回复已存在,无法重复发布”)的问题
  • 修复批量审批时同样的去重检查冲突问题
  • 修复 AI Foundation 不可用的问题(PluginManager 无法通过 Spring 依赖注入获取)
  • 修复 DefaultSpringPlugin 包级私有类反射访问权限问题
  • 修复 CI 构建失败(gradlew 缺少执行权限)

改进

  • 审批逻辑优化:先查找已有 Reply 扩展再决定创建或更新
  • 移除不必要的 AiFoundationConfiguration 配置类
  • 前端 UI 优化:移除编辑功能、简化角色排序逻辑、清理无用代码

安装要求

  • Halo >= 2.25.0
  • AI Foundation 插件(用于 AI 模型服务)

注意事项

这是 Beta 版本,可能存在未发现的问题,建议在生产环境使用前充分测试。

发布于查看详情

Tip

此版本为重大更新,升级后请务必在插件设置中重载插件配置!!并且当前插件将会依赖于 AI Foundation 插件,请务必下载安装此插件。

Warning

不过由于架构的更新,由此带来的问题是,前端包的体积大了近十倍,尽管我已经尽力做了优化,但当前前端包的体积仍旧达到了 500kb,这可能会产生一些网络访问的问题。

当前版本开始,从底层架构开始完全重构此次插件,得益于架构的更新,现在 Live2d 将支持如下功能:

  1. 支持基于事件的驱动策略,可以在主题或任何地方使用事件订阅来触发 Live2d 功能。
  2. 支持 Cubism 2、4、5 版本,理论上基于此类架构的所有模型,如有问题请及时反馈。
  3. 对工具栏配置进行改动,将可以自定义 Live2d 右侧工具栏。
  4. 可以实时对 Live2d 的动作、表情等做渲染处理。
  5. 扩展更多的 Tips 事件。

并且从当前版本开始,插件的 AI 底层将基于 Halo Ai Foundation 插件。因此也将整体 AI 功能进行了重构,现在 Live2d 的 AI 功能将支持更多丰富的功能,例如:

  1. 支持更多的模型供应商。(由 Ai Foundation 插件提供)
  2. 支持用户使用 Live2d 进行 Agent 访问站点,功能包括:阅读当前站点上下文,打开某个页面、读取网站文章、页面、瞬间,访问网络资源,Halo 内容搜索,评论与留言辅助等等。

新增功能

  • 支持更多现代化的模型,支持基于 Cubism 2/4/5 版本的模型。
  • 支持主题或站长基于事件对模型进行驱动。
  • 支持站长自定义 Live2d 右侧工具栏。
  • 看板娘的位置将不再固定,允许用户自由拖拽 Live2d 看板娘的位置并进行保持,包括最小化后的按钮位置。
  • 可以实时对 Live2d 的动作、表情等做渲染处理。
  • 扩展更多的 Tips 事件,例如 loading 等。
  • 支持更多的模型供应商(由 Ai Foundation 插件提供)
  • 在原有 AI 对话的基础上,增加了支持用户的 Agent 访问,例如
    • 阅读当前站点上下文并总结。
    • Halo 内容搜索。
    • Halo 资源导航。
    • 评论与留言辅助。
    • 网络访问。
    • 自定义工具。

问题修复

  • 修复自动加载 tips 时总会出现报错的问题。
  • 解决加载时可能出现冲突导致加载无法出现的问题。
  • 解决模型在运行阶段会突然丢失部分模型体的问题。(需持续观察,如再次出现请及时反馈)。

功能优化

  • 将设置项中的 repeater 组件更换为更简洁的 Array 组件。
  • 优化了对话框的高度问题,现在对话框将不会遮挡住模型,即便它更改高度。
  • 优化了 AI 对话框的样式。
  • 优化了 AI 对话时的提示信息,现在不会立即出现提示了。
  • 取消了后端的日志打印,现在不会看到非常长的日志了。

项目重构

  • 使用更加现代化的 pixi.js 重构底层代码。
  • 使用 Ai Foundation 重构 AI 逻辑。

Generated from v2.0.0

发布于查看详情

详情请参阅更新日志在 GitHub 上查看)。
Please refer to Changelog (view on GitHub) for details.

howiehz-higan-zh-hans.zip 为简体中文默认安装包,仅包含 .br
howiehz-higan-zh-hans-tiny.zip 为简体中文轻量安装包,移除默认字体资源,默认 logo 资源将替换为 1x1 占位图,不包含预压缩文件,且不注入 Mermaid / instant.page 运行时。
howiehz-higan-zh-hans-full-precompressed.zip 为简体中文完整预压缩包,包含 .gz / .br / .zst
howiehz-higan-en.zip is the English default package with .br only.
howiehz-higan-en-tiny.zip is the English tiny package that removes the default font assets, replaces the default logo asset with a 1x1 placeholder image, omits precompressed assets, and excludes Mermaid / instant.page runtime injection.
howiehz-higan-en-full-precompressed.zip is the English full precompressed package with .gz / .br / .zst.

发布于查看详情

Halo 官方 AI 能力平台,统一接入主流大模型,为插件生态提供文本生成、嵌入向量、工具调用等智能化能力。

功能特性

  • 多提供商支持:内置 OpenAI、DeepSeek、Kimi(Moonshot)、SiliconFlow、豆包、文心一言、智谱 AI、Ollama、OpenAI-like、AIHubMix、Gitee 模力方舟、MiniMax、Xiaomi MiMo 等主流 AI 提供商
  • 统一模型管理:通过 Halo 控制台统一管理 AI 提供商和模型配置
  • 模型自动发现:支持从提供商自动拉取可用模型列表
  • 流式对话:支持 SSE 流式输出,适用于实时聊天场景
  • 工具调用:支持模型调用外部工具,适用于复杂任务编排
  • 文本嵌入:支持文本向量化,适用于语义搜索、RAG 等场景
  • 默认模型设置:支持配置系统默认的语言模型和嵌入模型
  • 模型测试 Playground:内置测试页面,支持验证文本生成、流式输出、工具调用、结构化输出等
  • Java SDK:通过 api 模块为其他 Halo 插件提供标准化的 AI 调用接口
发布于查看详情

新功能:
1:全新图库页:适配「图库管理」插件,照片网格 + 分组筛选 + 数字分页。
2:灯箱浏览:点击照片直接开灯箱查看大图,左右翻页/键盘切换/ESC 关闭。
3:EXIF 展示:灯箱底部显示设备、镜头、焦距、光圈、快门、ISO 等拍摄参数。
4:图片缩放:灯箱内滚轮/双击/按钮缩放(1-6 倍),支持拖动平移查看细节。

优化:
1:修复竖屏照片显示不全、灯箱被导航栏遮挡、翻页箭头被覆盖等问题。
2:图库页 SEO 优化(Open Graph / Twitter Card / 结构化数据)。
3:关于页、瞬间页照片统计改用图库管理插件数据源。
4:相册详情页补充照片标题显示。

依赖:图库页 /photos 需安装官方「图库管理」插件

发布于查看详情

1.修复阅读时间:首页用 postFinder.content 获取正文字数计算真实阅读时间,删除 index.ts/post.ts 的客户端覆盖逻辑(之前所有文章都显示 1 分钟阅读)

2.文章页分类标签从标题上方移至 meta 行(日期/阅读/评论旁),只显示第一个分类

3.侧边栏’最新文章’改为’热门文章’(按访问量排序),长标题单行省略号截断

发布于查看详情
  • 强化 XSS 防护:hljs 高亮流程使用 textContent 提取代码,未高亮场景下行号使用 escapeHtml() 转义
  • 修复异步竞态:Highlight.init() 异步加载时延迟启动 IntersectionObserver,避免 doHighlight 清空已装饰的行号
  • 代码审查优化:notContentTemplate 检查顺序调优,删除冗余方法,预计算选择器字符串
发布于查看详情
条 / 页