qoder优化。
This commit is contained in:
@@ -44,7 +44,11 @@ func Home(c *gin.Context) {
|
||||
}
|
||||
|
||||
var items []models.Content
|
||||
db.Select("*").Limit(5).Find(&items, "type = ?", "post")
|
||||
result := db.Select("*").Limit(5).Find(&items, "type = ?", "post")
|
||||
if result.Error != nil {
|
||||
c.String(http.StatusInternalServerError, "Database error: "+result.Error.Error())
|
||||
return
|
||||
}
|
||||
|
||||
tpl := themeManager.GetTemplate("index")
|
||||
if tpl == nil {
|
||||
@@ -52,9 +56,13 @@ func Home(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||
tpl.Execute(c.Writer, gin.H{
|
||||
data := gin.H{
|
||||
"Items": items,
|
||||
"Title": "首页",
|
||||
})
|
||||
}
|
||||
|
||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||
if err := tpl.Execute(c.Writer, data); err != nil {
|
||||
c.String(http.StatusInternalServerError, "Template render error: "+err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,48 +139,40 @@ func fileExists(path string) (bool, error) {
|
||||
func (m *ThemeManager) parseTemplates(themePath string) (map[string]*template.Template, error) {
|
||||
templates := make(map[string]*template.Template)
|
||||
|
||||
// 加载公共基础模板(可选)
|
||||
baseTpl := template.New("base").Funcs(template.FuncMap{
|
||||
"safeHTML": func(s string) template.HTML { return template.HTML(s) },
|
||||
})
|
||||
|
||||
// 从主题目录加载模板
|
||||
tplDir := filepath.Join(themePath, "templates")
|
||||
|
||||
// 首先读取所有模板文件内容
|
||||
type tplFile struct {
|
||||
name string
|
||||
path string
|
||||
content []byte
|
||||
}
|
||||
var tplFiles []tplFile
|
||||
|
||||
err := filepath.WalkDir(tplDir, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err // 返回错误以停止 WalkDir
|
||||
return err
|
||||
}
|
||||
if d.IsDir() {
|
||||
return nil // 跳过目录
|
||||
return nil
|
||||
}
|
||||
|
||||
// 支持 .html 和 .tmpl 扩展名
|
||||
lowerPath := strings.ToLower(path)
|
||||
if !strings.HasSuffix(lowerPath, ".html") && !strings.HasSuffix(lowerPath, ".tmpl") {
|
||||
return nil // 非模板文件,跳过
|
||||
return nil
|
||||
}
|
||||
|
||||
// 读取模板内容
|
||||
content, err := readFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read template file %s: %w", path, err)
|
||||
}
|
||||
|
||||
// 生成模板名称(相对路径,不含扩展名)
|
||||
name := strings.TrimPrefix(path, tplDir+string(filepath.Separator))
|
||||
name = strings.TrimSuffix(name, filepath.Ext(name))
|
||||
|
||||
// 克隆基础模板并解析
|
||||
tpl, err := baseTpl.Clone()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to clone base template for %s: %w", name, err)
|
||||
}
|
||||
tpl, err = tpl.Parse(string(content))
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse error in %s (file: %s): %w", name, path, err)
|
||||
}
|
||||
|
||||
templates[name] = tpl
|
||||
tplFiles = append(tplFiles, tplFile{name: name, path: path, content: content})
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -188,10 +180,53 @@ func (m *ThemeManager) parseTemplates(themePath string) (map[string]*template.Te
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(templates) == 0 {
|
||||
if len(tplFiles) == 0 {
|
||||
return nil, ErrNoValidTemplates
|
||||
}
|
||||
|
||||
// 创建包含所有模板的根模板
|
||||
funcMap := template.FuncMap{
|
||||
"safeHTML": func(s string) template.HTML { return template.HTML(s) },
|
||||
}
|
||||
|
||||
// 首先解析基础模板(base.tmpl 和 header.tmpl)
|
||||
var baseContent strings.Builder
|
||||
for _, tf := range tplFiles {
|
||||
if tf.name == "base" || tf.name == "header" {
|
||||
baseContent.WriteString(string(tf.content))
|
||||
baseContent.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
rootTpl, err := template.New("root").Funcs(funcMap).Parse(baseContent.String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse base templates: %w", err)
|
||||
}
|
||||
|
||||
// 为每个页面模板单独解析,继承基础模板
|
||||
for _, tf := range tplFiles {
|
||||
// 跳过基础模板,它们已经在 rootTpl 中
|
||||
if tf.name == "base" || tf.name == "header" {
|
||||
templates[tf.name] = rootTpl
|
||||
continue
|
||||
}
|
||||
|
||||
// 克隆基础模板并添加页面特定内容
|
||||
tpl, err := rootTpl.Clone()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to clone base template for %s: %w", tf.name, err)
|
||||
}
|
||||
|
||||
// 解析页面特定内容,使用页面名称作为 define 名称
|
||||
pageContent := string(tf.content)
|
||||
_, err = tpl.Parse(pageContent)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse template %s: %w", tf.name, err)
|
||||
}
|
||||
|
||||
templates[tf.name] = tpl
|
||||
}
|
||||
|
||||
return templates, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package utils // 示例:插件接口
|
||||
import (
|
||||
"go_blog/models"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Plugin interface {
|
||||
OnArticleCreate(article *models.Article) // 文章创建钩子
|
||||
//OnArticleCreate(article *models.Article) // 文章创建钩子
|
||||
RegisterRoutes(r *gin.Engine) // 添加新路由
|
||||
}
|
||||
|
||||
|
||||
@@ -1,138 +1,27 @@
|
||||
<!-- templates/base.tmpl -->
|
||||
{{ define "base" }}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ .Title}}</title>
|
||||
<title>{{ .Title }}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<style type="text/css">
|
||||
body{
|
||||
background: #f8f8f8;
|
||||
}
|
||||
.layui-main {
|
||||
width: 1140px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.container {
|
||||
width: 1170px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.header .layui-nav {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding: 0;
|
||||
background: none;
|
||||
}
|
||||
.post-list {
|
||||
width: 75%;
|
||||
float: left;
|
||||
display: block;
|
||||
}
|
||||
.list-card {
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
padding: 20px 20px 10px 20px;
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 10px;
|
||||
height: 200px;
|
||||
}
|
||||
.sidebar {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.header {}
|
||||
body { background: #f8f8f8; margin: 0; padding: 0; }
|
||||
.layui-main { width: 1140px; margin: 0 auto; }
|
||||
.container { width: 1170px; margin: 0 auto; overflow: hidden; }
|
||||
.header .layui-nav { position: absolute; right: 0; top: 0; padding: 0; background: none; }
|
||||
.post-list { width: 75%; float: left; display: block; }
|
||||
.list-card { background: #fff; overflow: hidden; padding: 20px; position: relative; border-radius: 10px; margin-bottom: 10px; }
|
||||
.sidebar { float: left; width: 25%; padding-left: 20px; box-sizing: border-box; }
|
||||
.page-navigator { margin: 20px 0; }
|
||||
.pagination a { margin-right: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
{{ template "header" . }}
|
||||
|
||||
<main>{{ block "content" . }}{{ end }}</main>
|
||||
|
||||
<div class="page-navigator">
|
||||
共 {{ .Total }} 条,每页 {{ .PageSize }} 条,当前第 {{ .Page }} 页</div>
|
||||
<div class="pagination">
|
||||
{{ if .PrevPage }}
|
||||
<a href="/page/{{ .PrevPage }}">上一页</a>
|
||||
{{ end }}
|
||||
{{ if .NextPage }}
|
||||
<a href="/page/{{ .NextPage }}">下一页</a>
|
||||
{{ end }}
|
||||
<a href="/">首页</a>
|
||||
<a href="/page/{{ .Total }}">尾页</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar">
|
||||
<div class="column">
|
||||
<h3 class="title-sidebar"><i class="layui-icon"></i> 博客信息</h3>
|
||||
<div class="personal-information">
|
||||
<div class="user">
|
||||
<img src="https://www.hanxiaonuan.cn/usr/uploads/2021/07/3991382612.jpg" alt="韩小暖的博客的头像"
|
||||
class="rounded-circle avatar">
|
||||
<div class="p-2">
|
||||
<a class="user-name" target="_blank" href="https://www.hanxiaonuan.cn/">
|
||||
韩小暖的博客</a>
|
||||
<p class="introduction mt-1">这里是小暖的日常记录,欢迎!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="component">
|
||||
<form class="layui-form" id="search" method="post" action="https://www.hanxiaonuan.cn/"
|
||||
role="search">
|
||||
<div class="layui-inline input">
|
||||
<input type="text" id="s" name="s" class="layui-input" required="" lay-verify="required"
|
||||
placeholder="输入关键字搜索">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary"><i
|
||||
class="layui-icon"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h3 class="title-sidebar"><i class="layui-icon"></i> 栏目分类</h3>
|
||||
<ul class="layui-row layui-col-space5">
|
||||
<li class="layui-col-md12 layui-col-xs6"><a
|
||||
href="https://www.hanxiaonuan.cn/category/default/"><i class="layui-icon"></i>
|
||||
默认分类<span class="layui-badge layui-bg-gray">12</span></a></li>
|
||||
<li class="layui-col-md12 layui-col-xs6"><a href="https://www.hanxiaonuan.cn/category/zc/"><i
|
||||
class="layui-icon"></i> 日常随想<span class="layui-badge layui-bg-gray">2</span></a>
|
||||
</li>
|
||||
<li class="layui-col-md12 layui-col-xs6"><a
|
||||
href="https://www.hanxiaonuan.cn/category/%E5%85%B3%E4%BA%8E%E6%88%BF%E5%AD%90/"><i
|
||||
class="layui-icon"></i> 关于房子<span class="layui-badge layui-bg-gray">1</span></a>
|
||||
</li>
|
||||
<li class="layui-col-md12 layui-col-xs6"><a
|
||||
href="https://www.hanxiaonuan.cn/category/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"><i
|
||||
class="layui-icon"></i> 工作日志<span class="layui-badge layui-bg-gray">0</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tags">
|
||||
<h3 class="title-sidebar"><i class="layui-icon"></i>标签云</h3>
|
||||
<div>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-primary" style="color: rgb(231, 229, 26)"
|
||||
href="https://www.hanxiaonuan.cn/tag/%E5%B0%8F%E6%9A%96/" title="小暖">小暖</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-primary" style="color: rgb(125, 196, 207)"
|
||||
href="https://www.hanxiaonuan.cn/tag/%E6%84%9F%E6%82%9F/" title="感悟">感悟</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tags">
|
||||
<h3 class="title-sidebar"><i class="layui-icon"></i>系统</h3>
|
||||
<div>
|
||||
<li class="last"><a href="https://www.hanxiaonuan.cn/admin/">进入后台 (admin)</a></li>
|
||||
<li><a href="https://www.hanxiaonuan.cn/action/logout?_=5b09b0e1048bbd45bdddc56fc43667b2">退出</a>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container">
|
||||
<main>{{ block "content" . }}{{ end }}</main>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
{{ end }}
|
||||
@@ -1,102 +1,23 @@
|
||||
<!-- templates/about.html -->
|
||||
{{ define "content" }}
|
||||
<div class="container">
|
||||
|
||||
<div class="post-list">
|
||||
{{ range .Items }}
|
||||
<div class="list-card">
|
||||
<div><a href="/post/{{ .Cid }}">
|
||||
<h1>Title: {{ .Title }}</h1>
|
||||
</a>
|
||||
<p> Slug: {{ .Slug }}</p>
|
||||
<p>Text: {{ .Text }}</p>
|
||||
<div>Created: {{ .Created }},</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="page-navigator">
|
||||
共 {{ .Total }} 条,每页 {{ .PageSize }} 条,当前第 {{ .Page }} 页</div>
|
||||
<div class="pagination">
|
||||
{{ if .PrevPage }}
|
||||
<a href="/page/{{ .PrevPage }}">上一页</a>
|
||||
{{ end }}
|
||||
{{ if .NextPage }}
|
||||
<a href="/page/{{ .NextPage }}">下一页</a>
|
||||
{{ end }}
|
||||
<a href="/">首页</a>
|
||||
<a href="/page/{{ .Total }}">尾页</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar">
|
||||
<div class="column">
|
||||
<h3 class="title-sidebar"><i class="layui-icon"></i> 博客信息</h3>
|
||||
<div class="personal-information">
|
||||
<div class="user">
|
||||
<img src="https://www.hanxiaonuan.cn/usr/uploads/2021/07/3991382612.jpg" alt="韩小暖的博客的头像"
|
||||
class="rounded-circle avatar">
|
||||
<div class="p-2">
|
||||
<a class="user-name" target="_blank" href="https://www.hanxiaonuan.cn/">
|
||||
韩小暖的博客</a>
|
||||
<p class="introduction mt-1">这里是小暖的日常记录,欢迎!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="component">
|
||||
<form class="layui-form" id="search" method="post" action="https://www.hanxiaonuan.cn/"
|
||||
role="search">
|
||||
<div class="layui-inline input">
|
||||
<input type="text" id="s" name="s" class="layui-input" required="" lay-verify="required"
|
||||
placeholder="输入关键字搜索">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-primary"><i
|
||||
class="layui-icon"></i></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h3 class="title-sidebar"><i class="layui-icon"></i> 栏目分类</h3>
|
||||
<ul class="layui-row layui-col-space5">
|
||||
<li class="layui-col-md12 layui-col-xs6"><a
|
||||
href="https://www.hanxiaonuan.cn/category/default/"><i class="layui-icon"></i>
|
||||
默认分类<span class="layui-badge layui-bg-gray">12</span></a></li>
|
||||
<li class="layui-col-md12 layui-col-xs6"><a href="https://www.hanxiaonuan.cn/category/zc/"><i
|
||||
class="layui-icon"></i> 日常随想<span class="layui-badge layui-bg-gray">2</span></a>
|
||||
</li>
|
||||
<li class="layui-col-md12 layui-col-xs6"><a
|
||||
href="https://www.hanxiaonuan.cn/category/%E5%85%B3%E4%BA%8E%E6%88%BF%E5%AD%90/"><i
|
||||
class="layui-icon"></i> 关于房子<span class="layui-badge layui-bg-gray">1</span></a>
|
||||
</li>
|
||||
<li class="layui-col-md12 layui-col-xs6"><a
|
||||
href="https://www.hanxiaonuan.cn/category/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"><i
|
||||
class="layui-icon"></i> 工作日志<span class="layui-badge layui-bg-gray">0</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tags">
|
||||
<h3 class="title-sidebar"><i class="layui-icon"></i>标签云</h3>
|
||||
<div>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-primary" style="color: rgb(231, 229, 26)"
|
||||
href="https://www.hanxiaonuan.cn/tag/%E5%B0%8F%E6%9A%96/" title="小暖">小暖</a>
|
||||
<a class="layui-btn layui-btn-xs layui-btn-primary" style="color: rgb(125, 196, 207)"
|
||||
href="https://www.hanxiaonuan.cn/tag/%E6%84%9F%E6%82%9F/" title="感悟">感悟</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tags">
|
||||
<h3 class="title-sidebar"><i class="layui-icon"></i>系统</h3>
|
||||
<div>
|
||||
<li class="last"><a href="https://www.hanxiaonuan.cn/admin/">进入后台 (admin)</a></li>
|
||||
<li><a href="https://www.hanxiaonuan.cn/action/logout?_=5b09b0e1048bbd45bdddc56fc43667b2">退出</a>
|
||||
</li>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="post-list">
|
||||
{{ range .Items }}
|
||||
<div class="list-card">
|
||||
<a href="/post/{{ .Cid }}">
|
||||
<h2>{{ .Title }}</h2>
|
||||
</a>
|
||||
<p>{{ .Text }}</p>
|
||||
<small>创建于: {{ .Created }}</small>
|
||||
</div>
|
||||
|
||||
{{ else }}
|
||||
<div class="list-card">
|
||||
<p>暂无文章</p>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="sidebar">
|
||||
<h3>博客信息</h3>
|
||||
<p>欢迎访问个人博客</p>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
<!--继承基础模板内容-->
|
||||
{{ template "base.tmpl" . }}
|
||||
{{ template "base" . }}
|
||||
@@ -1,64 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Page 1</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<style type="text/css">
|
||||
.container {
|
||||
width: 1170px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.post-list {
|
||||
width: 75%;
|
||||
float: left;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
float: left;
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.header {}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="layui-col-md9 layui-col-lg9">
|
||||
<div class="title-article">
|
||||
<h1>{{.Title}}</h1>
|
||||
<div class="title-msg">
|
||||
<span><i class="layui-icon"></i> {{.AuthorID}} </span>
|
||||
<span><i class="layui-icon"></i> {{.Created}}</span>
|
||||
<span><i class="layui-icon"></i> {{.CommentsNum}}条</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text" itemprop="articleBody">
|
||||
{{.Text}}
|
||||
</div>
|
||||
<div class="tags-text">
|
||||
<i class="layui-icon"></i>标签:{{.Type}}
|
||||
</div>
|
||||
<div class="copy-text">
|
||||
<div>
|
||||
<p>非特殊说明,本博所有文章均为博主原创。</p>
|
||||
<p class="hidden-xs">如若转载,请注明出处: </p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="page-text">
|
||||
<div>
|
||||
<span class="layui-badge layui-bg-gray">上一篇</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="layui-badge layui-bg-gray">下一篇</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-text layui-form">
|
||||
</div>
|
||||
{{ define "content" }}
|
||||
<div class="post-list">
|
||||
<div class="list-card">
|
||||
<h1>{{ .Title }}</h1>
|
||||
<div class="meta">
|
||||
<span>作者: {{ .AuthorID }}</span> |
|
||||
<span>时间: {{ .Created }}</span> |
|
||||
<span>评论: {{ .CommentsNum }}</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="content">
|
||||
{{ .Text }}
|
||||
</div>
|
||||
<div class="tags">
|
||||
<span>标签: {{ .Type }}</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="nav">
|
||||
<a href="/">← 返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<div class="sidebar">
|
||||
<h3>文章详情</h3>
|
||||
<p><a href="/">返回首页</a></p>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ template "base" . }}
|
||||
|
||||
Reference in New Issue
Block a user