diff --git a/handlers/theme.go b/handlers/theme.go
index 8cac482..0eceb78 100644
--- a/handlers/theme.go
+++ b/handlers/theme.go
@@ -109,9 +109,8 @@ func SwitchTheme(c *gin.Context) {
// 创建新主题
func CreateTheme(c *gin.Context) {
type Request struct {
- Name string `json:"name" binding:"required"`
- Template string `json:"template"`
- CreateCSS bool `json:"create_css"`
+ Name string `json:"name" binding:"required"`
+ Template string `json:"template"`
}
var req Request
@@ -154,151 +153,39 @@ func CreateTheme(c *gin.Context) {
return
}
- // 如果指定了模板,复制模板文件
- if req.Template != "" && req.Template != "blank" {
- templateSrc := filepath.Join("templates", req.Template)
- if _, err := os.Stat(templateSrc); err == nil {
- // 复制模板文件
- files := []string{"base.html", "index.html", "post.html", "page.html"}
- for _, file := range files {
- srcFile := filepath.Join(templateSrc, file)
- dstFile := filepath.Join(themePath, file)
- if data, err := os.ReadFile(srcFile); err == nil {
- os.WriteFile(dstFile, data, 0644)
- }
- }
- }
- } else {
- // 创建空白模板
- baseHTML := `
-
-
-
- {{.Post.Title}}
-
- {{.Post.Content | html}}
-
-
-{{end}}
-`), 0644)
- os.WriteFile(filepath.Join(themePath, "page.html"), []byte(`{{define "content"}}
-
- {{.Page.Title}}
-
- {{.Page.Content | html}}
-
-
-{{end}}
-`), 0644)
+ // 创建新主题时必须选择已有主题作为模板
+ if req.Template == "" || req.Template == "blank" {
+ c.JSON(http.StatusBadRequest, gin.H{
+ "error": "必须选择一个已有主题作为模板",
+ })
+ return
}
- // 创建 CSS 文件
- if req.CreateCSS {
- cssPath := filepath.Join("static", "css", req.Name+".css")
- os.MkdirAll(filepath.Dir(cssPath), 0755)
+ // 验证所选模板是否存在并复制模板文件
+ templateSrc := filepath.Join("templates", req.Template)
+ if _, err := os.Stat(templateSrc); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{
+ "error": "所选模板不存在",
+ })
+ return
+ }
- cssContent := `/* ` + req.Name + ` Theme */
-/* 在此添加你的样式 */
+ // 复制模板文件
+ files := []string{"base.html", "index.html", "post.html", "page.html"}
+ for _, file := range files {
+ srcFile := filepath.Join(templateSrc, file)
+ dstFile := filepath.Join(themePath, file)
+ if data, err := os.ReadFile(srcFile); err == nil {
+ os.WriteFile(dstFile, data, 0644)
+ }
+ }
-body {
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
- margin: 0;
- padding: 0;
-}
-
-.container {
- max-width: 1200px;
- margin: 0 auto;
- padding: 0 20px;
-}
-
-.header {
- background: #fff;
- padding: 20px 0;
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
-}
-
-.site-title {
- margin: 0;
-}
-
-.site-title a {
- color: #333;
- text-decoration: none;
-}
-
-.site-desc {
- color: #666;
- margin: 10px 0 0;
-}
-
-.main-nav {
- margin-top: 15px;
-}
-
-.main-nav a {
- margin-right: 15px;
- color: #666;
- text-decoration: none;
-}
-
-.main {
- padding: 30px 0;
- min-height: 500px;
-}
-
-.footer {
- background: #f5f5f5;
- padding: 20px 0;
- text-align: center;
- color: #999;
-}
-`
- os.WriteFile(cssPath, []byte(cssContent), 0644)
+ // 复制模板的 CSS 文件
+ templateCSS := filepath.Join("static", "css", req.Template+".css")
+ if data, err := os.ReadFile(templateCSS); err == nil {
+ dstCSS := filepath.Join("static", "css", req.Name+".css")
+ os.MkdirAll(filepath.Dir(dstCSS), 0755)
+ os.WriteFile(dstCSS, data, 0644)
}
c.JSON(http.StatusOK, gin.H{
diff --git a/static/admin/app.js b/static/admin/app.js
index befc2c9..52a6e92 100644
--- a/static/admin/app.js
+++ b/static/admin/app.js
@@ -1135,11 +1135,33 @@ function showThemeMessage(message, type = 'info') {
}
// 显示创建主题弹窗
-function showCreateThemeModal() {
+async function showCreateThemeModal() {
+ // 打开创建主题模态框并动态加载现有主题作为模板选项
document.getElementById('theme-modal').classList.remove('hidden');
document.getElementById('new-theme-name').value = '';
- document.getElementById('theme-template').value = 'default';
- document.getElementById('create-css').checked = true;
+ const themeSelect = document.getElementById('theme-template');
+ try {
+ // 获取所有可用主题
+ const res = await fetch(`${API_BASE}/themes`, {
+ headers: getHeaders()
+ });
+ const themesData = await res.json();
+ themeSelect.innerHTML = '';
+ // 填充下拉列表
+ themesData.themes.forEach(theme => {
+ const option = document.createElement('option');
+ option.value = theme;
+ option.textContent = theme;
+ if (theme === currentTheme) {
+ option.selected = true;
+ }
+ themeSelect.appendChild(option);
+ });
+ } catch (err) {
+ themeSelect.innerHTML = '