From c04a8d53c60240fc62cba02d845cc98b27aa89d4 Mon Sep 17 00:00:00 2001 From: nite07 Date: Fri, 29 Nov 2024 11:32:17 +0800 Subject: [PATCH] embed frontend files --- go.mod | 2 +- server/route.go | 49 ++++++++++++++++++++------- server/static/favicon.png | Bin 0 -> 11197 bytes server/templates/400.html | 7 ++++ server/templates/game.html | 36 +++++++++----------- server/templates/index.html | 30 ++++------------ server/templates/layouts/base.html | 40 +++++++++++----------- server/templates/layouts/footer.html | 7 ++-- server/templates/layouts/header.html | 17 +++++++--- server/templates/search.html | 10 ++++-- 10 files changed, 110 insertions(+), 88 deletions(-) create mode 100644 server/static/favicon.png create mode 100644 server/templates/400.html diff --git a/go.mod b/go.mod index e4b5602..be37580 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/bogdanfinn/tls-client v1.7.8 github.com/btcsuite/btcutil v1.0.2 github.com/gin-contrib/cors v1.7.2 + github.com/gin-contrib/multitemplate v1.0.1 github.com/gin-gonic/gin v1.10.0 github.com/redis/go-redis/v9 v9.7.0 github.com/robfig/cron/v3 v3.0.1 @@ -40,7 +41,6 @@ require ( github.com/cloudwego/iasm v0.2.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gabriel-vasile/mimetype v1.4.6 // indirect - github.com/gin-contrib/multitemplate v1.0.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect diff --git a/server/route.go b/server/route.go index 172a0ce..3c1dadf 100644 --- a/server/route.go +++ b/server/route.go @@ -1,6 +1,10 @@ package server import ( + "embed" + "errors" + "io/fs" + "net/http" "path/filepath" "pcgamedb/crawler" "pcgamedb/db" @@ -8,6 +12,7 @@ import ( "pcgamedb/server/handler" "pcgamedb/server/middleware" "strconv" + "strings" "github.com/gin-contrib/cors" "github.com/gin-contrib/multitemplate" @@ -21,6 +26,9 @@ import ( ginSwagger "github.com/swaggo/gin-swagger" ) +//go:embed templates templates/layouts static +var frontendFS embed.FS + func initRoute(app *gin.Engine) { app.Use(cors.New(cors.Config{ AllowAllOrigins: true, @@ -31,30 +39,49 @@ func initRoute(app *gin.Engine) { } func initFrontend(app *gin.Engine) { + // Load static files + staticFs, err := fs.Sub(frontendFS, "static") + if err != nil { + log.Logger.Fatal("Error loading static files", zap.Error(err)) + return + } + app.StaticFS("/static", http.FS(staticFs)) + // Load templates + // directly using templates app.LoadHTMLFiles() to load all templates leads to error + // because use templates with same name in different html file will case overridden + // so we need to load all templates manually and use multitemplate to render them r := multitemplate.NewRenderer() - app.Static("/static", "server/static") - - layoutFiles, err := filepath.Glob("server/templates/layouts/*.html") + layoutFiles, err := frontendFS.ReadDir("templates/layouts") if err != nil { log.Logger.Fatal("Error loading layout templates", zap.Error(err)) return } - rootFiles, err := filepath.Glob("server/templates/*.html") + rootFiles, err := frontendFS.ReadDir("templates") if err != nil { log.Logger.Fatal("Error loading root templates", zap.Error(err)) return } for _, rootFile := range rootFiles { - name := filepath.Base(rootFile) - r.AddFromFiles(name, append([]string{rootFile}, layoutFiles...)...) + if rootFile.IsDir() { + continue + } + name := filepath.Base(rootFile.Name()) + templateFiles := []string{"templates/" + name} + for _, layout := range layoutFiles { + if !layout.IsDir() { + templateFiles = append(templateFiles, "templates/layouts/"+layout.Name()) + } + } + r.AddFromFS(name, frontendFS, templateFiles...) } app.HTMLRender = r + // Load routes app.GET("/", func(ctx *gin.Context) { monthTop, err := crawler.GetSteam250MonthTop50Cache() if err != nil { @@ -102,8 +129,9 @@ func initFrontend(app *gin.Engine) { app.GET("/search", func(ctx *gin.Context) { key := ctx.Query("key") page := ctx.Query("page") + key = strings.TrimSpace(key) if len(key) < 2 { - ctx.HTML(400, "400.html", nil) + ctx.HTML(400, "400.html", errors.New("Search key should be at least 2 characters long")) return } if page == "" { @@ -111,12 +139,7 @@ func initFrontend(app *gin.Engine) { } pageInt, err := strconv.Atoi(page) if err != nil { - ctx.HTML(400, "400.html", nil) - return - } - - if key == "" { - ctx.HTML(400, "400.html", nil) + ctx.HTML(400, "400.html", err) return } games, totalPage, err := db.SearchGameInfos(key, pageInt, 10) diff --git a/server/static/favicon.png b/server/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..945d5582a3f09c6c864955695020fcf271e5e4a6 GIT binary patch literal 11197 zcmeHtXH-*N)3ym99U@&22$&mD5LBA=~AQzlond( zy+w*30TL+zsrlmbeSf~6@9+0HYn^q@nKS#^GuO(f+uVicIYw;b=ksPQhw z2A%-bOtbVqnL1a*_$F5j*7f8_ldHOX>W8XrC2Kev8e>wPHmj}*d2D~5@mCbuiH$^j1i|0iiskp8xd`Xl|oe3oa zHu#TjE4%Jt9cD(W>tDAe?|RL{!Mi{MMztccmiyI)Eav-U-csC?tKa^aTJK!%bl8}^ z&C{Gu@Y{{+L1ymo?SE6P%507?p4tiWl!!a^hJUwZJ)GvhUew{WZ$SxfJ#9zR$hl1uZ*+dp;?o%>YZ=HRf9eX0!|zA z&;RZCSYy}z^sP`KaruUfS5ZwesUfdsbe0l4vu@Ap>+fgyz1wqr0hk#OhVC1cth-ApoXiMlHY zVtGs^2S(rDRJ>35FYN=5∾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 U{#9uFyTw*hRY#>->1E{q0ofOa>i_@% literal 0 HcmV?d00001 diff --git a/server/templates/400.html b/server/templates/400.html new file mode 100644 index 0000000..5610811 --- /dev/null +++ b/server/templates/400.html @@ -0,0 +1,7 @@ +{{template "base" .}} +{{define "title"}}Bad Request{{end}} +{{define "styles"}} {{end}} +{{define "content"}} +Bad Request +{{.}} +{{end}} \ No newline at end of file diff --git a/server/templates/game.html b/server/templates/game.html index 09778ca..7018e16 100644 --- a/server/templates/game.html +++ b/server/templates/game.html @@ -1,6 +1,6 @@ {{template "base" .}} -{{define "title"}}{{.Name}} - 游戏详情{{end}} +{{define "title"}}{{.Name}} - Details{{end}} {{define "styles"}}