创建主题修改成从现有主题作为模板。
This commit is contained in:
+31
-144
@@ -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 := `<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.Title}} - {{.SiteName}}</title>
|
||||
<meta name="description" content="{{.Description}}">
|
||||
<link rel="icon" href="/static/images/favicon.ico" type="image/x-icon">
|
||||
<link rel="stylesheet" href="/static/css/{{.Name}}.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="header">
|
||||
<div class="container">
|
||||
<h1 class="site-title">
|
||||
<a href="/">{{.SiteName}}</a>
|
||||
</h1>
|
||||
<p class="site-desc">{{.SiteDesc}}</p>
|
||||
<nav class="main-nav">
|
||||
<a href="/">首页</a>
|
||||
{{range .Pages}}
|
||||
<a href="/page/{{.Slug}}">{{.Title}}</a>
|
||||
{{end}}
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="main container">
|
||||
{{template "content" .}}
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p>© {{.Year}} {{.SiteName}}. Powered by GoBlog.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
os.WriteFile(filepath.Join(themePath, "base.html"), []byte(baseHTML), 0644)
|
||||
os.WriteFile(filepath.Join(themePath, "index.html"), []byte(`{{define "content"}}
|
||||
<div class="post-list">
|
||||
<h2>欢迎来到我的博客</h2>
|
||||
<p>这是一个新主题</p>
|
||||
</div>
|
||||
{{end}}
|
||||
`), 0644)
|
||||
os.WriteFile(filepath.Join(themePath, "post.html"), []byte(`{{define "content"}}
|
||||
<article class="post-detail">
|
||||
<h1>{{.Post.Title}}</h1>
|
||||
<div class="post-body">
|
||||
{{.Post.Content | html}}
|
||||
</div>
|
||||
</article>
|
||||
{{end}}
|
||||
`), 0644)
|
||||
os.WriteFile(filepath.Join(themePath, "page.html"), []byte(`{{define "content"}}
|
||||
<article class="page-detail">
|
||||
<h1>{{.Page.Title}}</h1>
|
||||
<div class="page-body">
|
||||
{{.Page.Content | html}}
|
||||
</div>
|
||||
</article>
|
||||
{{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{
|
||||
|
||||
+31
-7
@@ -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 = '<option value="">加载失败</option>';
|
||||
}
|
||||
const createCssEl = document.getElementById('theme-template');
|
||||
if (createCssEl) createCssEl.checked = true;
|
||||
}
|
||||
|
||||
// 隐藏创建主题弹窗
|
||||
@@ -1160,13 +1182,16 @@ async function handleCreateTheme(e) {
|
||||
|
||||
const themeName = document.getElementById('new-theme-name').value.trim();
|
||||
const template = document.getElementById('theme-template').value;
|
||||
const createCSS = document.getElementById('create-css').checked;
|
||||
|
||||
if (!themeName) {
|
||||
showThemeMessage('请输入主题名称', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!template) {
|
||||
showThemeMessage('请选择一个已有主题作为模板', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/themes/create`, {
|
||||
method: 'POST',
|
||||
@@ -1176,8 +1201,7 @@ async function handleCreateTheme(e) {
|
||||
},
|
||||
body: JSON.stringify({
|
||||
name: themeName,
|
||||
template: template,
|
||||
create_css: createCSS
|
||||
template: template
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
+2
-10
@@ -348,8 +348,8 @@
|
||||
<select id="theme-select" class="theme-selector">
|
||||
<option value="">加载中...</option>
|
||||
</select>
|
||||
<button class="btn-primary" onclick="switchTheme()">切换主题</button>
|
||||
</div>
|
||||
<button class="btn-primary" onclick="switchTheme()">切换主题</button>
|
||||
<div id="theme-message" class="theme-message"></div>
|
||||
</div>
|
||||
<div class="theme-list" id="theme-list">
|
||||
@@ -467,16 +467,8 @@
|
||||
<div class="form-group">
|
||||
<label>基于模板创建</label>
|
||||
<select id="theme-template">
|
||||
<option value="default">default(默认主题)</option>
|
||||
<option value="minimal">minimal(极简主题)</option>
|
||||
<option value="blank">blank(空白主题)</option>
|
||||
<option value="">加载中...</option>
|
||||
</select>
|
||||
<small>选择新主题的初始模板</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="create-css" checked> 创建样式文件
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button type="button" class="btn-secondary" onclick="hideThemeModal()">取消</button>
|
||||
|
||||
Reference in New Issue
Block a user