embed frontend files
This commit is contained in:
parent
2c969680e0
commit
c04a8d53c6
2
go.mod
2
go.mod
@ -9,6 +9,7 @@ require (
|
|||||||
github.com/bogdanfinn/tls-client v1.7.8
|
github.com/bogdanfinn/tls-client v1.7.8
|
||||||
github.com/btcsuite/btcutil v1.0.2
|
github.com/btcsuite/btcutil v1.0.2
|
||||||
github.com/gin-contrib/cors v1.7.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/gin-gonic/gin v1.10.0
|
||||||
github.com/redis/go-redis/v9 v9.7.0
|
github.com/redis/go-redis/v9 v9.7.0
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
@ -40,7 +41,6 @@ require (
|
|||||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.6 // 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/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"embed"
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"pcgamedb/crawler"
|
"pcgamedb/crawler"
|
||||||
"pcgamedb/db"
|
"pcgamedb/db"
|
||||||
@ -8,6 +12,7 @@ import (
|
|||||||
"pcgamedb/server/handler"
|
"pcgamedb/server/handler"
|
||||||
"pcgamedb/server/middleware"
|
"pcgamedb/server/middleware"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-contrib/cors"
|
"github.com/gin-contrib/cors"
|
||||||
"github.com/gin-contrib/multitemplate"
|
"github.com/gin-contrib/multitemplate"
|
||||||
@ -21,6 +26,9 @@ import (
|
|||||||
ginSwagger "github.com/swaggo/gin-swagger"
|
ginSwagger "github.com/swaggo/gin-swagger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:embed templates templates/layouts static
|
||||||
|
var frontendFS embed.FS
|
||||||
|
|
||||||
func initRoute(app *gin.Engine) {
|
func initRoute(app *gin.Engine) {
|
||||||
app.Use(cors.New(cors.Config{
|
app.Use(cors.New(cors.Config{
|
||||||
AllowAllOrigins: true,
|
AllowAllOrigins: true,
|
||||||
@ -31,30 +39,49 @@ func initRoute(app *gin.Engine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initFrontend(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()
|
r := multitemplate.NewRenderer()
|
||||||
|
|
||||||
app.Static("/static", "server/static")
|
layoutFiles, err := frontendFS.ReadDir("templates/layouts")
|
||||||
|
|
||||||
layoutFiles, err := filepath.Glob("server/templates/layouts/*.html")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logger.Fatal("Error loading layout templates", zap.Error(err))
|
log.Logger.Fatal("Error loading layout templates", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
rootFiles, err := filepath.Glob("server/templates/*.html")
|
rootFiles, err := frontendFS.ReadDir("templates")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logger.Fatal("Error loading root templates", zap.Error(err))
|
log.Logger.Fatal("Error loading root templates", zap.Error(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, rootFile := range rootFiles {
|
for _, rootFile := range rootFiles {
|
||||||
name := filepath.Base(rootFile)
|
if rootFile.IsDir() {
|
||||||
r.AddFromFiles(name, append([]string{rootFile}, layoutFiles...)...)
|
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
|
app.HTMLRender = r
|
||||||
|
|
||||||
|
// Load routes
|
||||||
app.GET("/", func(ctx *gin.Context) {
|
app.GET("/", func(ctx *gin.Context) {
|
||||||
monthTop, err := crawler.GetSteam250MonthTop50Cache()
|
monthTop, err := crawler.GetSteam250MonthTop50Cache()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -102,8 +129,9 @@ func initFrontend(app *gin.Engine) {
|
|||||||
app.GET("/search", func(ctx *gin.Context) {
|
app.GET("/search", func(ctx *gin.Context) {
|
||||||
key := ctx.Query("key")
|
key := ctx.Query("key")
|
||||||
page := ctx.Query("page")
|
page := ctx.Query("page")
|
||||||
|
key = strings.TrimSpace(key)
|
||||||
if len(key) < 2 {
|
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
|
return
|
||||||
}
|
}
|
||||||
if page == "" {
|
if page == "" {
|
||||||
@ -111,12 +139,7 @@ func initFrontend(app *gin.Engine) {
|
|||||||
}
|
}
|
||||||
pageInt, err := strconv.Atoi(page)
|
pageInt, err := strconv.Atoi(page)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.HTML(400, "400.html", nil)
|
ctx.HTML(400, "400.html", err)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if key == "" {
|
|
||||||
ctx.HTML(400, "400.html", nil)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
games, totalPage, err := db.SearchGameInfos(key, pageInt, 10)
|
games, totalPage, err := db.SearchGameInfos(key, pageInt, 10)
|
||||||
|
BIN
server/static/favicon.png
Normal file
BIN
server/static/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
7
server/templates/400.html
Normal file
7
server/templates/400.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{{template "base" .}}
|
||||||
|
{{define "title"}}Bad Request{{end}}
|
||||||
|
{{define "styles"}} {{end}}
|
||||||
|
{{define "content"}}
|
||||||
|
Bad Request
|
||||||
|
{{.}}
|
||||||
|
{{end}}
|
@ -1,6 +1,6 @@
|
|||||||
{{template "base" .}}
|
{{template "base" .}}
|
||||||
|
|
||||||
{{define "title"}}{{.Name}} - 游戏详情{{end}}
|
{{define "title"}}{{.Name}} - Details{{end}}
|
||||||
|
|
||||||
{{define "styles"}}
|
{{define "styles"}}
|
||||||
<style>
|
<style>
|
||||||
@ -54,7 +54,7 @@
|
|||||||
<img src="{{.Cover}}" class="img-fluid rounded game-cover" alt="{{.Name}}" />
|
<img src="{{.Cover}}" class="img-fluid rounded game-cover" alt="{{.Name}}" />
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="game-cover bg-secondary d-flex align-items-center justify-content-center rounded">
|
<div class="game-cover bg-secondary d-flex align-items-center justify-content-center rounded">
|
||||||
<span class="text-white">暂无封面</span>
|
<span class="text-white">No Image</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
{{if .Aliases}}
|
{{if .Aliases}}
|
||||||
<div>
|
<div>
|
||||||
<span class="info-label">别名:</span>
|
<span class="info-label">Aliases:</span>
|
||||||
{{range .Aliases}}
|
{{range .Aliases}}
|
||||||
<span class="tag">{{.}}</span>
|
<span class="tag">{{.}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -71,14 +71,14 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span class="info-label">开发商:</span>
|
<span class="info-label">Developers:</span>
|
||||||
{{range .Developers}}
|
{{range .Developers}}
|
||||||
<span class="tag">{{.}}</span>
|
<span class="tag">{{.}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<span class="info-label">发行商:</span>
|
<span class="info-label">Publishers:</span>
|
||||||
{{range .Publishers}}
|
{{range .Publishers}}
|
||||||
<span class="tag">{{.}}</span>
|
<span class="tag">{{.}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -86,7 +86,7 @@
|
|||||||
|
|
||||||
{{if .Languages}}
|
{{if .Languages}}
|
||||||
<div>
|
<div>
|
||||||
<span class="info-label">支持语言:</span>
|
<span class="info-label">Languages:</span>
|
||||||
{{range .Languages}}
|
{{range .Languages}}
|
||||||
<span class="tag">{{.}}</span>
|
<span class="tag">{{.}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -98,7 +98,7 @@
|
|||||||
{{end}} {{if .SteamID}}
|
{{end}} {{if .SteamID}}
|
||||||
<div>
|
<div>
|
||||||
<a href="https://store.steampowered.com/app/{{.SteamID}}" target="_blank" class="btn btn-primary">
|
<a href="https://store.steampowered.com/app/{{.SteamID}}" target="_blank" class="btn btn-primary">
|
||||||
在 Steam 上查看
|
Steam
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -112,7 +112,7 @@
|
|||||||
<div class="swiper-wrapper">
|
<div class="swiper-wrapper">
|
||||||
{{range .Screenshots}}
|
{{range .Screenshots}}
|
||||||
<div class="swiper-slide">
|
<div class="swiper-slide">
|
||||||
<img src="{{.}}" alt="游戏截图" />
|
<img src="{{.}}" alt="screenshot" />
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
@ -126,7 +126,7 @@
|
|||||||
<!-- Download Links -->
|
<!-- Download Links -->
|
||||||
{{if .Games}}
|
{{if .Games}}
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<h3 class="mb-3">下载链接</h3>
|
<h3 class="mb-3">Download</h3>
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
{{range .Games}}
|
{{range .Games}}
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@ -135,34 +135,30 @@
|
|||||||
<h5 class="card-title">{{.RawName}}</h5>
|
<h5 class="card-title">{{.RawName}}</h5>
|
||||||
{{if .Size}}
|
{{if .Size}}
|
||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
<small class="text-muted">文件大小:{{.Size}}</small>
|
<small class="text-muted">Size: {{.Size}}</small>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Author}}
|
{{if .Author}}
|
||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
<small class="text-muted">来源:{{.Author}}</small>
|
<small class="text-muted">Source: {{.Author}}</small>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .Password}}
|
{{if .Password}}
|
||||||
<div class="card-text">
|
<div class="card-text">
|
||||||
解压密码:<code>{{.Password}}</code>
|
<small class="text-muted">Unzip password: <code>{{.Password}}</code></small>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="mt-2 d-flex justify-content-between align-items-center">
|
<div class="mt-2 d-flex justify-content-between align-items-center">
|
||||||
<!-- <a href="{{.Download}}" class="btn btn-success" target="_blank">下载</a> -->
|
|
||||||
<div class="input-group" style="max-width: 300px;">
|
<div class="input-group" style="max-width: 300px;">
|
||||||
<input type="text" class="form-control form-control-sm" value="{{.Download}}" readonly>
|
<input type="text" class="form-control form-control-sm" value="{{.Download}}" readonly>
|
||||||
<button class="btn btn-outline-secondary btn-sm" type="button"
|
<button class="btn btn-outline-secondary btn-sm" type="button"
|
||||||
onclick="copyToClipboard(this.previousElementSibling)">
|
onclick="copyToClipboard(this.previousElementSibling)">
|
||||||
复制
|
Copy
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<a href="{{.Url}}" class="btn btn-outline-primary" target="_blank">详情页</a>
|
<a href="{{.Url}}" class="btn btn-outline-primary" target="_blank">Source Page</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer text-muted">
|
|
||||||
更新时间:{{.UpdatedAt.Format "2006-01-02 15:04:05"}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -196,7 +192,7 @@
|
|||||||
navigator.clipboard.writeText(input.value).then(() => {
|
navigator.clipboard.writeText(input.value).then(() => {
|
||||||
const button = input.nextElementSibling;
|
const button = input.nextElementSibling;
|
||||||
const originalText = button.textContent;
|
const originalText = button.textContent;
|
||||||
button.textContent = '已复制';
|
button.textContent = 'Copied';
|
||||||
button.classList.remove('btn-outline-secondary');
|
button.classList.remove('btn-outline-secondary');
|
||||||
button.classList.add('btn-success');
|
button.classList.add('btn-success');
|
||||||
|
|
||||||
@ -206,7 +202,7 @@
|
|||||||
button.classList.add('btn-outline-secondary');
|
button.classList.add('btn-outline-secondary');
|
||||||
}, 1500);
|
}, 1500);
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.error('复制失败:', err);
|
console.error('Failed to copy:', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -40,22 +40,6 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{define "content"}}
|
{{define "content"}}
|
||||||
<!-- Search Section -->
|
|
||||||
<div class="bg-light py-4">
|
|
||||||
<div class="container">
|
|
||||||
<form action="/search" method="GET">
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-md-8">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" name="key" placeholder="搜索游戏..." />
|
|
||||||
<button class="btn btn-primary" type="submit">搜索</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Games Grid -->
|
<!-- Games Grid -->
|
||||||
<div class="container py-4">
|
<div class="container py-4">
|
||||||
<h2 class="mb-4">Month Top</h2>
|
<h2 class="mb-4">Month Top</h2>
|
||||||
@ -67,7 +51,7 @@
|
|||||||
<img src="{{.Cover}}" class="card-img-top game-cover" alt="{{.Name}}" />
|
<img src="{{.Cover}}" class="card-img-top game-cover" alt="{{.Name}}" />
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="card-img-top game-cover bg-secondary d-flex align-items-center justify-content-center">
|
<div class="card-img-top game-cover bg-secondary d-flex align-items-center justify-content-center">
|
||||||
<span class="text-white">暂无图片</span>
|
<span class="text-white">No Image</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -75,7 +59,7 @@
|
|||||||
<p class="card-text game-description">{{.Description}}</p>
|
<p class="card-text game-description">{{.Description}}</p>
|
||||||
{{if .Publishers}}
|
{{if .Publishers}}
|
||||||
<div class="publishers mb-2">
|
<div class="publishers mb-2">
|
||||||
<small class="text-muted">发行商:</small>
|
<small class="text-muted">Publishers:</small>
|
||||||
{{range $index, $publisher := .Publishers}} {{if $index}}, {{end}}
|
{{range $index, $publisher := .Publishers}} {{if $index}}, {{end}}
|
||||||
<small class="text-muted">{{$publisher}}</small>
|
<small class="text-muted">{{$publisher}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -98,7 +82,7 @@
|
|||||||
<img src="{{.Cover}}" class="card-img-top game-cover" alt="{{.Name}}" />
|
<img src="{{.Cover}}" class="card-img-top game-cover" alt="{{.Name}}" />
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="card-img-top game-cover bg-secondary d-flex align-items-center justify-content-center">
|
<div class="card-img-top game-cover bg-secondary d-flex align-items-center justify-content-center">
|
||||||
<span class="text-white">暂无图片</span>
|
<span class="text-white">No Image</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -106,7 +90,7 @@
|
|||||||
<p class="card-text game-description">{{.Description}}</p>
|
<p class="card-text game-description">{{.Description}}</p>
|
||||||
{{if .Publishers}}
|
{{if .Publishers}}
|
||||||
<div class="publishers mb-2">
|
<div class="publishers mb-2">
|
||||||
<small class="text-muted">发行商:</small>
|
<small class="text-muted">Publishers:</small>
|
||||||
{{range $index, $publisher := .Publishers}} {{if $index}}, {{end}}
|
{{range $index, $publisher := .Publishers}} {{if $index}}, {{end}}
|
||||||
<small class="text-muted">{{$publisher}}</small>
|
<small class="text-muted">{{$publisher}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -120,7 +104,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container py-4">
|
<div class="container py-4">
|
||||||
<h2 class="mb-4">Best Of The Year</h2>
|
<h2 class="mb-4">Best of the Year</h2>
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
{{range .BestOfTheYear}}
|
{{range .BestOfTheYear}}
|
||||||
<div class="col-12 col-sm-6 col-md-4 col-lg-5-item">
|
<div class="col-12 col-sm-6 col-md-4 col-lg-5-item">
|
||||||
@ -129,7 +113,7 @@
|
|||||||
<img src="{{.Cover}}" class="card-img-top game-cover" alt="{{.Name}}" />
|
<img src="{{.Cover}}" class="card-img-top game-cover" alt="{{.Name}}" />
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="card-img-top game-cover bg-secondary d-flex align-items-center justify-content-center">
|
<div class="card-img-top game-cover bg-secondary d-flex align-items-center justify-content-center">
|
||||||
<span class="text-white">暂无图片</span>
|
<span class="text-white">No Image</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -137,7 +121,7 @@
|
|||||||
<p class="card-text game-description">{{.Description}}</p>
|
<p class="card-text game-description">{{.Description}}</p>
|
||||||
{{if .Publishers}}
|
{{if .Publishers}}
|
||||||
<div class="publishers mb-2">
|
<div class="publishers mb-2">
|
||||||
<small class="text-muted">发行商:</small>
|
<small class="text-muted">Publishers:</small>
|
||||||
{{range $index, $publisher := .Publishers}} {{if $index}}, {{end}}
|
{{range $index, $publisher := .Publishers}} {{if $index}}, {{end}}
|
||||||
<small class="text-muted">{{$publisher}}</small>
|
<small class="text-muted">{{$publisher}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -1,25 +1,23 @@
|
|||||||
{{define "base"}}
|
{{define "base"}}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN" data-bs-theme="dark">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>{{template "title" .}}</title>
|
<title>{{template "title" .}}</title>
|
||||||
<link
|
<link rel="icon" type="image/x-icon" href="/static/favicon.png">
|
||||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
|
||||||
rel="stylesheet"
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.css" />
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://cdn.jsdelivr.net/npm/swiper@8/swiper-bundle.min.css"
|
|
||||||
/>
|
|
||||||
{{block "styles" .}}{{end}}
|
{{block "styles" .}}{{end}}
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
{{template "header" .}} {{block "content" .}}{{end}} {{template "footer" .}}
|
{{template "header" .}} {{block "content" .}}{{end}} {{template "footer" .}}
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
{{block "scripts" .}}{{end}}
|
{{block "scripts" .}}{{end}}
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
{{end}}
|
{{end}}
|
@ -1,10 +1,11 @@
|
|||||||
{{define "footer"}}
|
{{define "footer"}}
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<footer class="bg-dark text-light py-4 mt-5">
|
<footer class="text-light py-4 mt-5">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<a href="https://git.nite07.com/nite/pcgamedb" target="_blank">开源仓库</a> | <a href="/api/swagger/index.html">API
|
<div><a href="https://git.nite07.com/nite/pcgamedb" target="_blank">Open Source</a> | <a
|
||||||
文档</a>
|
href="/api/swagger/index.html">API Doc</a></div>
|
||||||
|
<div>Made by <a href="https://www.nite07.com" target="_blank">Nite</a></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
@ -1,14 +1,21 @@
|
|||||||
{{define "header"}}
|
{{define "header"}}
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
<nav class="navbar navbar-expand-lg">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="/">游戏库</a>
|
<a class="navbar-brand" href="/">GameDB</a>
|
||||||
<div class="navbar-collapse" id="navbarNav">
|
<div class="navbar-collapse" id="navbarNav">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item">
|
<!-- <li class="nav-item"><a class="nav-link" href="https://www.nite07.com" target="_blank">Blog</a></li> -->
|
||||||
<a class="nav-link" href="https://www.nite07.com" target="_blank">博客</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<div class="ms-auto">
|
||||||
|
<form action="/search" method="GET" class="d-flex">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control" name="key" placeholder="Input full english name of game" />
|
||||||
|
<button class="btn btn-primary" type="submit">Search</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- Games Grid -->
|
<!-- Games Grid -->
|
||||||
<div class="container py-4">
|
<div class="container py-4">
|
||||||
|
{{if .Games}}
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
{{range .Games}}
|
{{range .Games}}
|
||||||
<div class="col-12 col-sm-6 col-md-4 col-lg-5-item">
|
<div class="col-12 col-sm-6 col-md-4 col-lg-5-item">
|
||||||
@ -55,7 +56,7 @@
|
|||||||
<img src="{{.Cover}}" class="card-img-top game-cover" alt="{{.Name}}" />
|
<img src="{{.Cover}}" class="card-img-top game-cover" alt="{{.Name}}" />
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="card-img-top game-cover bg-secondary d-flex align-items-center justify-content-center">
|
<div class="card-img-top game-cover bg-secondary d-flex align-items-center justify-content-center">
|
||||||
<span class="text-white">暂无图片</span>
|
<span class="text-white">No Image</span>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -63,7 +64,7 @@
|
|||||||
<p class="card-text game-description">{{.Description}}</p>
|
<p class="card-text game-description">{{.Description}}</p>
|
||||||
{{if .Publishers}}
|
{{if .Publishers}}
|
||||||
<div class="publishers mb-2">
|
<div class="publishers mb-2">
|
||||||
<small class="text-muted">发行商:</small>
|
<small class="text-muted">Publishers:</small>
|
||||||
{{range $index, $publisher := .Publishers}} {{if $index}}, {{end}}
|
{{range $index, $publisher := .Publishers}} {{if $index}}, {{end}}
|
||||||
<small class="text-muted">{{$publisher}}</small>
|
<small class="text-muted">{{$publisher}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
@ -74,6 +75,11 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
{{else}}
|
||||||
|
<div class="text-center py-5">
|
||||||
|
<h4 class="text-muted">No results found for "{{.Key}}"</h4>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<!-- Pagination -->
|
<!-- Pagination -->
|
||||||
<div class="container py-4">
|
<div class="container py-4">
|
||||||
|
Loading…
Reference in New Issue
Block a user