# WarmIsland 暖屿 暖如灯火,静如留白。暖屿以柔和的色调和舒缓的节奏回归内容本身,为记录与阅读留出一方安静从容的角落。 ![WarmIsland Preview](https://git.nxxy335.top/nxxy335/halo-theme-WarmIsland/raw/branch/main/WarmIsland%20Preview.webp) > 预览图随安装包分发(包根目录 `WarmIsland Preview.webp`)。 ## 环境要求 - Halo **2.27.0 及以上**(页面布局契约与微信读书页面依赖 2.27 的新能力) - 更低版本的 Halo 请使用主题 v1.1.x;v1.2.0 起内置纯 CSS 变量实现的主题配色系统 ## 安装 1. 下载最新 Release 的 ZIP 安装包 2. Halo 后台 → 主题管理 → 安装主题 → 上传 ZIP 3. 点击「启用」 从源码构建: ```bash git clone https://git.nxxy335.top/nxxy335/halo-theme-WarmIsland.git cd halo-theme-WarmIsland pnpm install pnpm release # build → snapshot → package ``` `pnpm build` 只生成 `templates/`,ZIP 由 `pnpm package` 输出到 `dist/warm-island-.zip`;安装包同时含 `docs/*.md` 与预览图,便于离线查阅。 > **升级后首页 404「Template index was not found」**:ZIP 中缺少 `templates/`(源码打包时漏了构建步骤),请换用完整安装包重新上传,详见 [FAQ 安装相关](https://nxxy335.top/WarmIsland/faq.html)。 > > **升级后整站没了样式**:Halo 页面缓存或反向代理仍留着上一版 HTML,其引用的哈希 CSS 已被删除。在后台执行一次「清理缓存」并刷新 CDN / Nginx 缓存即可;主题自 v1.2.1 起会把历史哈希资源一并打进安装包。 > > **改了主题或配色后部分页面不生效**:若安装了「页面静态缓存」插件,需手动点一次「刷新页面缓存」,详见 [FAQ](https://nxxy335.top/WarmIsland/faq.html)。 ## 特点 1. **响应式设计** — 桌面 / 移动端适配、暗色模式,移动端用动态视口单位适配地址栏 2. **插件兼容** — 适配 10 款常用 Halo 插件,提供页面布局契约,插件前台页面自动复用主题外观 3. **内置灯箱** — 随包自托管的 LightGallery(GPLv3),支持 EXIF 展示;安装 lightgallery.js 插件后自动让位 4. **可配置性** — 17 个设置分组、126 个配置项,几乎所有模块可独立开关 5. **性能优化** — 服务端字数统计(API 扩展包)、图片懒加载与响应式缩略图、首屏整屏吸附(仅边界接管,内容区保留原生滚动)、Hero 离屏停绘、CSS/HTML 压缩;详见[开发指南 - 性能与滚动顺滑](https://nxxy335.top/WarmIsland/customize/development.html) 6. **页面布局契约** — 提供 `templates/layout.html`,插件页面不再回退到 Halo 内置布局 ## 主要功能 ### 首页 - Hero 首屏:明暗双背景图、大标题 / 副标题独立配色、描述文案(默认「无」;API 字段默认预填 `https://v1.hitokoto.cn/`,仅「一言」模式生效,清空则使用内置本地句子库;可选自定义文案与自动刷新)、下滑箭头平滑滚动 - 欢迎弹窗:默认显示纯本地静态欢迎语,支持 5 种位置、会话去重开关;仅在显式配置自定义 IP 定位 API 时才显示访客所在地(见[外部资源与隐私](#外部资源与隐私)) - 滚动吸附:首屏与内容区之间滚轮 / 触摸自动吸附,进入内容区后恢复原生自由滚动 - 文章卡片:可配置显示字数(依赖 API 扩展包)、阅读量、分类、标签、摘要行数 ### 文章 - 目录(TOC):桌面端侧栏 + 移动端抽屉,滚动高亮、展开模式可选 - 代码高亮:由代码高亮插件 / API 扩展包输出,主题提供 Warm / Cold 两套本地配色 - 上下篇导航、相关推荐、分享按钮、赞赏、版权声明可独立开关;微信分享改为复制文章链接 - 字数与阅读时间:优先使用 API 扩展包的服务端统计,未安装时前端计算兜底 ### 全局 - 点击特效:核心价值观 / 爱心 / 烟花 / 粒子等 8 种效果可选,也可关闭 - 页脚全站统计:文章、分类、评论、访问、点赞、总字数,支持开关与统计项选择(默认开启) - 动效:呼吸动画、滚动渐入,可独立关闭 - 备案信息:ICP 与公网安备号,公网安备自动带徽标 ## 已适配插件 | 插件名称 | 插件标识 | 适配页面路由 | 说明 | |----------|---------|-------------|------| | [瞬间](https://halo.run/store/apps/app-SnwWD) | `PluginMoments` | `/moments` | 瞬间动态页面,支持点赞、评论、标签筛选、顶部封面 | | [图库](https://halo.run/store/apps/app-BmQJW) | `PluginPhotos` | `/photos` | 图片展示页面,支持分组、灯箱预览 | | [友情链接(链接管理)](https://halo.run/store/apps/app-hfbQg) | `PluginLinks` | `/links` | 友链展示页面,支持随机排列、随机传送门、评论区开关;同一插件的 RSS 订阅驱动「订阅」页面 | | [装备管理](https://github.com/chengzhongxue/plugin-equipment) | `equipment` | `/equipments` | 装备展示页面,按分组展示,支持封面图 | | [豆瓣](https://github.com/chengzhongxue/plugin-douban) | `plugin-douban` | `/douban` | 豆瓣记录页面,支持类型 / 状态 / 标签筛选,默认音乐;需插件 **v1.2.6+**(SQLite 数据结构) | | [Steam 信息展示](https://github.com/Tim0x0/halo-plugin-steam) | `PluginSteam` | `/steam` | Steam 游戏库页面,含用户资料、统计数据、最近游玩、游戏库分页 | | [微信读书](https://github.com/yeora26/halo-weread-plugin) | `halo-weread-plugin` | 自定义页面 | 书架展示页面,见下方「自定义页面模板」 | | [记得](https://github.com/yyliucha/plugin-important-dates) | `plugin-important-dates` | `/important-dates` | 重要日期 / 牵挂的人 / 爱车双视图页面,见下方「扩展页面」 | | [文章组件](https://github.com/acanyo/plugin-content-widgets) | `plugin-content-widgets` | 文章内 | 提示框、标签页、时间线等内容组件,主题已映射 `--xhhao-com-*` 变量,自动跟随明暗模式 | | [API 扩展包](https://github.com/HowieHz/halo-plugin-extra-api) | `extra-api` | 全站 | 服务端字数统计、中英文混排排版、可选服务端代码高亮 | > 插件需单独安装;未安装时对应页面或功能自动隐藏 / 降级,不会报错。 > > **「朋友圈」(`plugin-friends`)插件已不再提供**:原先的 feed / RSS 聚合能力由官方「链接管理」(PluginLinks)插件的订阅取代,对应下方的「订阅」自定义页面模板。主题保留 `friends.html` 与「朋友圈」设置分组仅用于兼容旧站点,新站点请勿再依赖;插件不可用时会显示空状态。 ## 自定义页面模板 在 Halo 后台「页面 → 新建 → 自定义模板」中选择使用(页面地址由 slug 决定,无固定路由): | 模板名 | 模板文件 | 说明 | |--------|---------|------| | 留言板 | `page_messageboard.html` | 留言墙页面,标题与副标题可配置 | | 订阅 | `page_subscriptions.html` | 博友文章订阅动态,由官方链接管理插件的 RSS 订阅提供,支持分页 / 下滑加载与列表 / 网格布局 | | 微信读书 | `weread.html` | 微信读书书架展示,依赖微信读书插件,访客免登录查看 | ## 灯箱集成 主题内置 LightGallery 2.9.0(GPLv3,与主题的 GPL-3.0 一致),为图片提供放大预览与 EXIF 展示。如安装 [lightgallery.js](https://www.lightgalleryjs.com/) 灯箱插件,内置灯箱自动禁用,改由插件接管。其路径匹配规则与 DOM 节点选择器: | 页面 | 路径匹配规则 | 匹配区域 DOM 节点 | |------|-------------|-------------------| | 文章详情页 | `/archives/*` | `.wi-post__body` | | 瞬间页 | `/moments` | `.wi-moments-page__content` | | 图库页 | `/photos` | `.wi-photos-page__grid` | | 自定义页面 | 用户自定义 | `.wi-page__body` | > 自定义页面的路径匹配由用户自行设定,此处仅提供 DOM 节点选择器 `.wi-page__body`。 ## 外部资源与隐私 默认配置下,主题不会自动向任何第三方服务发起请求:CSS、JS、字体(LXGW WenKai 本地分片)、图标、Logo 与一言句子库均来自站点自身的 `/themes/warm-island/assets/`,不经过 CDN,也不使用 `preconnect` / `dns-prefetch`。 ### 逐项说明 | 服务 / 资源 | 用途 | 涉及的数据类型 | 默认状态 | 关闭 / 替换方法 | | --- | --- | --- | --- | --- | | 主题自身静态资源 `/themes/warm-island/assets/*` | 样式、脚本、字体、图标、Logo、内置句子库 | 无(同域请求,不含用户数据) | 始终启用,渲染必需 | 不可关闭;均为随包自托管文件 | | 自定义一言 API `hero_hitokoto_api` | Hero 首屏随机句子 | 无请求体;发起 GET 时第三方可见访客 IP / User-Agent | **默认不启用**:「描述文案来源」默认「无」,一言元素不渲染,零请求;该字段默认预填 `https://v1.hitokoto.cn/`,仅在「一言」模式生效 | 主题设置 → Hero 首屏 → 描述来源改为「无」或「自定义」,或清空该字段回退到 `assets/data/hitokoto.json` 内置本地句子库 | | 自定义 IP 定位主 / 备选 API `welcome_popup_api` / `welcome_popup_fallback_api` | 欢迎弹窗显示「欢迎来自 XX 的朋友」 | **访客 IP** 与第三方返回的粗略地理位置 | **关闭**:两项均留空,弹窗只显示本地欢迎语;且欢迎弹窗开关本身默认关闭。可选接口见下方清单 | 主题设置 → 欢迎弹窗 → 关闭开关,或清空两个 API 字段 | | 分享按钮:QQ / 微博 / X / Facebook / Telegram | 分享文章到对应平台 | 文章 URL 与标题(写在目标站 URL 参数中) | 默认开启 `qq,wechat,weibo`;**仅在访客点击后**跳转,页面加载时不请求 | 主题设置 → 文章 → 关闭「显示分享按钮」,或在「分享渠道」取消勾选 | | 微信分享弹层 | 生成并复制文章链接 | 文章 URL(浏览器本地字符串,不发送) | 与分享按钮一致 | 同上;已移除二维码远程库,改为「复制链接」 | | 页脚备案 / Halo / 应用市场外链 | 备案信息、致谢、插件安装提示 | 无(访客主动点击才跳转) | 由站点配置决定,默认仅显示 Halo 致谢 | 主题设置 → 页脚 → 关闭对应显示项 | | 插件前台页面(豆瓣、Steam、微信读书、订阅动态等) | 展示插件提供的数据 | 由对应插件决定,主题不发起请求 | 安装并启用对应插件后才出现 | 卸载 / 停用对应插件;主题自动降级隐藏 | | 内置 LightGallery 灯箱 | 图片放大预览、EXIF 展示 | 无(本地打包,不联网) | 默认启用 | 安装 lightgallery.js 插件后主题自动让位 | #### 可选第三方接口地址(均为候选值,主题不预置请求) | 能力 | 设置项 | 可选地址 | | --- | --- | --- | | Hero 一言 | `hero_hitokoto_api` | `https://v1.hitokoto.cn/`(默认预填,仅「一言」模式生效;清空则使用内置本地句子库) | | IP 定位主接口 | `welcome_popup_api` | `https://myip.ipip.net/json` 或 `https://r.inews.qq.com/api/ip2city?otype=json` | | IP 定位备选接口 | `welcome_popup_fallback_api` | 同上两个地址任选其一,主接口失败时兜底 | **描述文案来源默认为「无」**,此时不渲染一言元素、不发起任何请求。API 字段默认预填 `https://v1.hitokoto.cn/`(仅「一言」模式生效);选择「一言」或「自定义」后若留空,则回退到主题内置的本地句子库(零外部请求)。只有填写后才会向该地址发起请求,第三方可见访客 IP / User-Agent,需自行在站点隐私说明中披露。 两个 IP 定位接口同样默认留空;填写后会把**访客 IP**发送给该第三方服务换取粗略地理位置,需自行在站点隐私说明中披露。 ### 隐私说明 | 项目 | 说明 | | --- | --- | | 收集的数据类型 | 默认配置下**无**。主题不读取、不上传用户信息、站点内容、访问日志或订单数据 | | 数据用途 | 仅用于页面渲染;自定义 API 场景下由管理员自行决定 | | 保存位置与期限 | 主题不写入数据库、不上传数据、不生成服务端日志。前端仅在访客本机使用 `sessionStorage`(欢迎弹窗「同会话仅显示一次」)与 `localStorage`(点赞状态),可随时清除浏览器站点数据 | | 是否传输到第三方 | 默认**否**(描述文案来源为「无」、欢迎弹窗关闭、两个 API 字段留空)。仅当管理员显式填写「自定义一言 API」或「自定义 IP 定位 API」时才会向该服务发起请求,其中 IP 定位会暴露访客 IP | | 关闭 / 撤销方式 | 见上表;清空相应设置项或关闭对应开关即可立即停止,无需重装主题 | | 遥测 / 统计 / 崩溃上报 / 广告 / AI 分析 / 跨站追踪 | **均不存在**。主题不含任何埋点、指纹或第三方统计脚本 | ### 自托管与许可 - **代码高亮**:主题不自带 Prism.js 运行时。语法高亮请安装 Halo 应用市场的代码高亮插件,或启用「API 扩展包」的服务端代码高亮;主题只提供两套自托管的 `.token` 配色(`assets/vendor/prism-warm.css` / `prism-cold.css`),由「文章 → 代码高亮主题」切换。 - **字体**:[霞鹜文楷 LXGW WenKai](https://github.com/lxgw/LxgwWenKai) 以 [SIL OFL 1.1](https://openfontlicense.org/) 发布,由 `cn-font-split` 切分为本地 woff2 分片随主题分发;字体来源与版权声明保留在 `public/assets/fonts/LXGWWenKai/result.css`,上游完整的版权声明、保留字体名条款与 **OFL 1.1 许可证全文**随包存放于 `public/assets/fonts/LXGWWenKai/OFL.txt`(构建后为 `templates/assets/fonts/LXGWWenKai/OFL.txt`)。上游附加许可允许把字体切分 / 转换为 WOFF2 用于网页字体交付。 - **灯箱**:LightGallery 2.9.0 以 GPLv3 发布,本主题同样采用 GPL-3.0,按开源许可条款使用(非商业授权)。 - **图标**:来源与协议见[图标与字体来源](#图标与字体来源)。 ## 开发 | 命令 | 作用 | | --- | --- | | `pnpm dev` | 监听文件变化并构建到 `templates/` | | `pnpm build` | 构建模板与静态资源,自动合并历史哈希资源 | | `pnpm snapshot` | 把本次构建的哈希资源快照进 `compat/assets`(发版前执行) | | `pnpm audit:external` | 外部资源、隐私与 README 链接审计(打包时自动执行) | | `pnpm smoke` | 点击特效脚本与 JSON-LD 冒烟测试 | | `pnpm package` | 打包 `dist/warm-island-.zip` | | `pnpm release` | 等价于 `build` → `snapshot` → `package` | 发版执行 `pnpm release`,并把 `compat/assets` 的新增文件一起提交。`pnpm package` 会校验模板、资源目录与版本号一致性并执行外部资源审计,任一不通过即报错。 ### 目录结构 ``` ├── src/ │ ├── components/ # 组件(导航、页脚、Hero、弹窗、特效等) │ ├── layouts/ # Layout.astro(含页面布局契约渲染模式) │ ├── pages/ # 页面模板(构建后输出到 templates/) │ └── styles/ # SCSS 样式(正文样式在 _content.scss,全局生效) ├── public/ │ ├── assets/data/ # 内置本地一言句子库(静态 JSON) │ ├── assets/fonts/ # LXGW WenKai 本地字体分片 + OFL.txt 许可证全文 │ ├── assets/vendor/ # 自托管的代码高亮配色 CSS │ └── assets/logo.png # 主题图标(唯一一份,256×256 压缩版) ├── compat/assets/ # 历史版本哈希静态资源,构建时合并进 templates/assets ├── scripts/ # 构建后置、资源快照、打包、外部资源与合规审计、冒烟测试 ├── templates/ # 构建产物,Halo 实际加载的模板 ├── settings.yaml # 后台设置项定义 └── theme.yaml # 主题清单与自定义页面模板注册 ``` ### 主题开发注意事项 - **静态资源文件名带内容哈希**:升级后旧文件被删除,被缓存的 HTML 仍会请求旧文件名并触发 500,所以每个版本的哈希文件都要留一份(见 `compat/assets` 与 `pnpm snapshot`) - **第三方资源一律自托管并标注许可**,不得引入远程脚本 / 样式 / 字体 / 预连接,`pnpm package` 会拦截回归 - **常规变量统一用 `th:text` / `th:attr` 转义输出**,`th:utext` 仅用于 Halo 已处理的 HTML 与管理员自定义内容;`target="_blank"` 一律带 `rel="noopener noreferrer"` - **不得把站点内容用 `th:utext` 拼进 `