This commit is contained in:
tamakyi
2026-10-19 15:23:11 +08:00
parent 86dc8384bc
commit e9fba8b9ed
84 changed files with 34468 additions and 5386 deletions
+56 -1
View File
@@ -3,6 +3,7 @@ package templates
import (
"os"
"path/filepath"
"regexp"
"strings"
"testing"
"time"
@@ -72,6 +73,29 @@ func TestGenPreview(t *testing.T) {
writePreview(t, outDir, "preview-box-"+theme+".html", box, theme, "../static")
}
// 主题预览:与箱主页同一份数据,只是打开 sakura 主题(验证令牌覆盖与深色块)
themeBox := publicBaseData()
themeBox["VConsole"] = false
themeBox["ThemeSlug"] = "sakura"
themeBox["PageUser"].(map[string]interface{})["Background"] = bgURI
themeBox["PageUser"].(map[string]interface{})["Usernamecolor"] = "#3a2b30"
themeBox["PageUser"].(map[string]interface{})["Introcolor"] = "#6b545c"
themeCSS, err := os.ReadFile(filepath.Join("..", "static", "css", "themes", "sakura.css"))
if err != nil {
t.Fatalf("read theme css: %v", err)
}
for _, theme := range []string{"light", "dark"} {
page, err := renderToString(t, "question/list", themeBox)
if err != nil {
t.Fatalf("render themed list: %v", err)
}
// 预览页走 file://,把主题 css 内联进去(真实页面是一次带缓存的静态请求)。
// 用正则匹配:预览数据里没有 StaticVersion,v 参数为空串,不能按固定串替换。
link := regexp.MustCompile(`<link rel="stylesheet" href="/static/css/themes/sakura\.css\?v=[^"]*"/>`)
page = link.ReplaceAllString(page, "<style>"+string(themeCSS)+"</style>")
writePreview(t, outDir, "preview-theme-sakura-"+theme+".html", page, theme, "../static")
}
// 探索页:核对令牌替换后的卡片/列表配色
explore := voteBaseData()
explore["LangCode"] = "zh-CN"
@@ -102,6 +126,12 @@ func TestGenPreview(t *testing.T) {
// 设置页「内容防护」面板:核对是否与其它面板同样是白底卡片
profile := profileBaseData()
// 主题选择器(account 面板):用固定假数据,避免测试依赖 conf 的 [theme] 段
profile["Themes"] = []map[string]interface{}{
{"Slug": "default", "Swatch": ""},
{"Slug": "sakura", "Swatch": "linear-gradient(135deg, #fff6f8 0 55%, #e5678f 55% 100%)"},
}
profile["CurrentTheme"] = "sakura"
profile["ActiveProfileTab"] = "security"
profile["FeatureQuestion"] = nil
profile["FeatureChat"] = nil
@@ -113,6 +143,22 @@ func TestGenPreview(t *testing.T) {
}
writePreview(t, outDir, "preview-profile-"+theme+".html", page, theme, "../static")
}
// 设置页「账号」面板:主题选择器的实际排版(卡片在面板末尾)
profileAccount := profileBaseData()
profileAccount["Themes"] = profile["Themes"]
profileAccount["CurrentTheme"] = "sakura"
profileAccount["ActiveProfileTab"] = "account"
profileAccount["FeatureQuestion"] = nil
profileAccount["FeatureChat"] = nil
profileAccount["FeatureVote"] = nil
for _, theme := range []string{"light"} {
page, err := renderToString(t, "user/profile", profileAccount)
if err != nil {
t.Fatalf("render account profile: %v", err)
}
writePreview(t, outDir, "preview-profile-account-"+theme+".html", page, theme, "../static")
}
}
// writePreview 把 CDN 换成可直连的镜像、钉死主题,仅用于本地预览。
@@ -120,7 +166,16 @@ func writePreview(t *testing.T, dir, name, html, theme, staticPrefix string) {
t.Helper()
html = strings.ReplaceAll(html, "https://cdnjs.snrat.com/", "https://cdnjs.cloudflare.com/")
if theme == "dark" {
html = strings.Replace(html, `<html lang="zh-CN">`, `<html lang="zh-CN" data-theme="dark">`, 1)
// <html> 上可能还有 data-theme-style,只在这个开标签内判断/插入;
// 不能全文搜索 —— 内联的主题 css 里有 html[data-theme="dark"] 选择器
if i := strings.Index(html, "<html"); i >= 0 {
if j := strings.Index(html[i:], ">"); j > 0 {
tag := html[i : i+j]
if !strings.Contains(tag, "data-theme=") {
html = html[:i+j] + ` data-theme="dark"` + html[i+j:]
}
}
}
}
html = strings.ReplaceAll(html, `href="/favicon.ico"`, `href="`+staticPrefix+`/favicon.ico"`)
html = strings.Replace(html, `<title>`, `<title>预览 `+time.Now().Format("15:04")+` · `, 1)