From a6059bec1ba8b55e87b123a06d85b579788a5cd4 Mon Sep 17 00:00:00 2001 From: tamakyi Date: Mon, 19 Oct 2026 21:05:46 +0800 Subject: [PATCH] =?UTF-8?q?theme:=20=E5=90=AF=E5=8A=A8=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=9A=B4=E9=9C=B2=E6=9C=AA=E7=99=BB=E8=AE=B0=E7=9A=84=E4=B8=BB?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增主题后忘了写进 [theme] available,表现只是"设置页里找不到", 日志里没有任何痕迹。现在启动时会打: - info 主题注册表已加载 enabled=... - warn [theme] available 未登记以下主题 themes=shiroko available=... discover() 用 fs.Glob 扫内嵌 css/themes/*.css,按 slug 规则过滤掉 _scaffold.css。 示例配置补上 shiroko,文档补「部署后看不到主题」的两步排查。 --- .workbuddy/memory/2026-10-19.md | 13 +++++++++ .workbuddy/memory/MEMORY.md | 4 +++ conf/app.sample.ini | 2 ++ docs/theme-shiroko.md | 32 ++++++++++++++++++++++ internal/theme/theme.go | 47 +++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+) diff --git a/.workbuddy/memory/2026-10-19.md b/.workbuddy/memory/2026-10-19.md index 1169b9f..b4a5821 100644 --- a/.workbuddy/memory/2026-10-19.md +++ b/.workbuddy/memory/2026-10-19.md @@ -539,3 +539,16 @@ P1 剩余两项(首屏跟随系统深色、首页 Waline 懒加载)用户明 上次的 `Failed to authenticate user` 是临时态 —— 用户本机 Git for Windows 认证过之后 store 凭据恢复, 本轮 `git push origin main` 直接成功(`38cd41a..0c39aff`),`git rev-list --left-right --count origin/main...HEAD` = 0 0。 远端 8 个 shiroko 素材文件齐全。教训:**不要用一次 push 失败就断言无凭据**,先看一眼提交是否已存在、再试一次。 + +### 部署后「设置页找不到 shiroko」 + +线上实测:`/static/css/themes/shiroko.css?v=20261019m` 200 / 5038B 且与本地逐字节一致, +说明二进制确实带了新主题;但 `/user/profile` 渲染出来的主题单选只有 `""`、`default`、`sakura` +→ **根因是 `[theme] available` 白名单没登记 shiroko**(列表在 `theme.load()` 里按配置构建,启动时读一次)。 +- `internal/theme/theme.go` 新增 `reportRegistry()` / `discover()`:启动打 info「主题注册表已加载 enabled=...」, + 并把「css 在、但没登记」的主题以 warning 打出建议的 available 值。 + 没有这段时,这个故障在日志里完全没有痕迹,只能靠猜。 + `discover()` 用 `fs.Glob(static.FS, "css/themes/*.css")`,用 slugRe 过滤掉 `_scaffold.css`(下划线开头)。 +- `conf/app.sample.ini`:`available = default,sakura,shiroko` + 补充「没登记就不显示」的注释。 +- `docs/theme-shiroko.md` 补「部署后看不到主题」两段排查(先 curl css 看 200/404,再看 available)。 +- 排查口径:**先分「文件没发布」与「没登记」两类**,别一上来怀疑缓存;`StaticVersion` 只影响缓存,不影响列表。 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index 6c4c5af..4f689d2 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -169,6 +169,10 @@ 必须在任何 i18n 取词之前调用,否则先渲染出的提示会按访客语言。箱主未配语言时才回退访客/站点默认。 - 主题 = 一个 css 文件只覆盖令牌;新增主题不用改 Go/模板,放 `static/css/themes/.css` + `[theme] available` 登记即可(`static/fs.go` 已嵌整个目录)。底稿 `_scaffold.css`。 +- ⚠️ **`[theme] available` 是硬白名单,启动时读一次**:css 随二进制发布了但没登记,设置页就是看不到, + 现象和「部署没生效」一模一样。排查先分两类 —— `curl /static/css/themes/.css` 返回 200 说明文件在 + (那就是没登记),404 才是旧二进制;`StaticVersion` 只管缓存、不影响列表。 + 启动日志会打 `主题注册表已加载 enabled=...` 与 `[theme] available 未登记以下主题`(2026-10-19 加)。 - 带图片素材的主题把图放 `static/images/themes//`(`static/fs.go` 的 embed 已含 `images/themes`, 子目录自动覆盖;**新增别的顶层目录才要改清单**)。整页图用 16:9 + 竖版两张,靠 `@media` 切换 —— `--tb-page-image` 是 `cover`,贴着图片边缘放的插画会被按视口裁掉。 diff --git a/conf/app.sample.ini b/conf/app.sample.ini index f872d61..b939469 100644 --- a/conf/app.sample.ini +++ b/conf/app.sample.ini @@ -194,3 +194,5 @@ daily_message_limit_max = 999 ; 需要图片素材的,放 static/images/themes//(static/fs.go 已嵌 images/themes 目录)。 default = default available = default,sakura,shiroko +; ⚠️ 没登记在 available 里的主题,即使 css 已随二进制发布也不会出现在设置页; +; 启动日志会打出「[theme] available 未登记以下主题」提醒。,shiroko diff --git a/docs/theme-shiroko.md b/docs/theme-shiroko.md index 398d5e2..8ca58a4 100644 --- a/docs/theme-shiroko.md +++ b/docs/theme-shiroko.md @@ -93,3 +93,35 @@ available = default,sakura,shiroko 3. 换配色:改 `shiroko.css` 的令牌即可,插画是位图,换色需重新生成。 4. 新增素材不需要改 `static/fs.go`(已嵌整个 `images/themes` 目录);但改了 CSS 必须把 `conf.StaticVersion` +1,否则老访客吃缓存看不到变化。 + +## 部署后设置页看不到这个主题? + +先分两步确认,不要一上来就怀疑缓存: + +1. **文件是否随二进制发布了** —— 直接取一次静态资源: + + ```bash + curl -o /dev/null -w "%{http_code}\n" \ + https://<你的域名>/static/css/themes/shiroko.css?v= + ``` + + 返回 200 说明 css 已经嵌进去了;返回 404 说明部署的是旧二进制。 + +2. **是否登记进 `[theme] available`** —— 主题列表是启动时按白名单构建的, + css 在但没登记,设置页就看不到它。检查 `conf/app.ini`: + + ```ini + [theme] + default = default + available = default,sakura,shiroko + ``` + + 改完**重启**进程(`[theme]` 只在启动时读)。 + +启动日志会直接告诉你缺哪一行: + +``` +level=info msg="主题注册表已加载" enabled="default,sakura" +level=warning msg="[theme] available 未登记以下主题,它们不会出现在设置页" + available="default,sakura,shiroko" themes=shiroko +``` diff --git a/internal/theme/theme.go b/internal/theme/theme.go index 2bee689..c77b855 100644 --- a/internal/theme/theme.go +++ b/internal/theme/theme.go @@ -6,6 +6,7 @@ package theme import ( + "io/fs" "regexp" "strings" "sync" @@ -83,9 +84,55 @@ func build(defaultSlug, available string) ([]Theme, string, map[string]Theme) { logrus.WithField("theme", def).Warn("站点默认主题不可用,回退基础外观") def = "" } + + reportRegistry(list, bySlug) return list, def, bySlug } +// reportRegistry 把注册表状态写进启动日志。 +// 没有这段时,主题文件已随二进制发布、却忘了在 [theme] available 登记, +// 表现只是"设置页里找不到这个主题",从日志里完全看不出原因。 +func reportRegistry(list []Theme, bySlug map[string]Theme) { + enabled := make([]string, 0, len(list)) + for _, t := range list { + enabled = append(enabled, t.Slug) + } + logrus.WithField("enabled", strings.Join(enabled, ",")).Info("主题注册表已加载") + + var pending []string + for _, slug := range discover() { + if slug == DefaultSlug { + continue + } + if _, ok := bySlug[slug]; ok { + continue + } + pending = append(pending, slug) + } + if len(pending) > 0 { + logrus.WithFields(logrus.Fields{ + "themes": strings.Join(pending, ","), + "available": strings.Join(append(enabled, pending...), ","), + }).Warn("[theme] available 未登记以下主题,它们不会出现在设置页") + } +} + +// discover 列出内嵌的主题 css(不符合 slug 规则的模板文件如 _scaffold.css 会被跳过)。 +func discover() []string { + matches, err := fs.Glob(static.FS, themeCSSDir+"*.css") + if err != nil { + return nil + } + slugs := make([]string, 0, len(matches)) + for _, m := range matches { + slug := strings.TrimSuffix(strings.TrimPrefix(m, themeCSSDir), ".css") + if slugRe.MatchString(slug) { + slugs = append(slugs, slug) + } + } + return slugs +} + func normalize(slug string) string { slug = strings.ToLower(strings.TrimSpace(slug)) if !slugRe.MatchString(slug) {