新增功能:
- 主题发现模块:扫描 templates/ 目录下含 theme.json 的目录
- 站点设置新增 site.theme 键,DB 持久化 + 内存缓存
- 运行时切换主题:保存后即时重载 Gin 模板 + 静态资源哈希
- 管理后台 '外观主题' 页面:列表展示、选择、一键切换
- 动态静态资源服务:根据当前主题目录提供 CSS/JS
修复:
- account.html 残留孤儿 {{end}} 模板语法错误
- 动态静态资源 handler 误判 Gin *filepath 路径前缀为绝对路径
变更文件(12 modified + 3 new):
- cmd/server/main.go: 动态主题加载 + 运行时重载 + 动态静态服务
- internal/theme/discovery.go: 新增主题扫描
- internal/config/site_settings.go: ThemeName()
- internal/service/site_setting_service.go: ThemeReloader + UpdateTheme
- internal/controller/admin/: ISP 扩展 + GetThemes/UpdateTheme/ThemePage
- internal/controller/auth_controller.go: 准则路径动态化
- internal/router/: InjectThemeReloader + 新路由
- templates/: 外观主题页面 + JS + CSS + 子导航
This commit is contained in:
52
internal/theme/discovery.go
Normal file
52
internal/theme/discovery.go
Normal file
@ -0,0 +1,52 @@
|
||||
package theme
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// ThemeInfo 描述一个已安装的主题。
|
||||
type ThemeInfo struct {
|
||||
Dir string `json:"dir"` // 目录名(如 "MetaLab-2026")
|
||||
Name string `json:"name"` // 主题名称
|
||||
DisplayName string `json:"display_name"` // 展示名称
|
||||
Version string `json:"version"` // 版本号
|
||||
Author string `json:"author"` // 作者
|
||||
Description string `json:"description"` // 描述
|
||||
}
|
||||
|
||||
// DiscoverThemes 扫描 templates/ 目录,返回所有包含 theme.json 的主题列表。
|
||||
func DiscoverThemes(rootDir string) ([]ThemeInfo, error) {
|
||||
entries, err := os.ReadDir(rootDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var themes []ThemeInfo
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
themeJSON := filepath.Join(rootDir, entry.Name(), "theme.json")
|
||||
data, err := os.ReadFile(themeJSON) //nolint:gosec // 内部主题文件,非用户输入
|
||||
if err != nil {
|
||||
continue // 无 theme.json 则跳过
|
||||
}
|
||||
|
||||
var info ThemeInfo
|
||||
if err := json.Unmarshal(data, &info); err != nil {
|
||||
continue
|
||||
}
|
||||
info.Dir = entry.Name()
|
||||
themes = append(themes, info)
|
||||
}
|
||||
|
||||
// 按名称排序,保证稳定展示
|
||||
sort.Slice(themes, func(i, j int) bool {
|
||||
return themes[i].Name < themes[j].Name
|
||||
})
|
||||
|
||||
return themes, nil
|
||||
}
|
||||
Reference in New Issue
Block a user