new: Added post search module

This commit is contained in:
2024-12-17 16:15:51 +08:00
parent 474bf3e6bb
commit 9386306e7e
26 changed files with 590608 additions and 11 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
# Work dir and files
.idea
tmp
# Binaries for programs and plugins
*.exe

View File

@@ -29,11 +29,20 @@ site:
# post config
post:
toc_title: Content
# title and number of post displayed per page
recent_post:
title: Recent Posts
number: 10
archive:
title: Archive
number: 10
tag:
search:
title: Search
number: 10
category:
title: Category
number: 10
tag:
title: Tag
number: 10

View File

@@ -4,7 +4,9 @@ type mPost struct {
TocTitle string `yaml:"toc_title"`
RecentPost mRecentPost `yaml:"recent_post"`
Archive mArchive `yaml:"archive"`
Search mSearch `yaml:"search"`
Tag mTag `yaml:"tag"`
Category mCategory `yaml:"category"`
}
type mRecentPost struct {
@@ -17,6 +19,17 @@ type mArchive struct {
Number int `yaml:"number"`
}
type mTag struct {
Number int `yaml:"number"`
type mSearch struct {
Title string `yaml:"title"`
Number int `yaml:"number"`
}
type mTag struct {
Title string `yaml:"title"`
Number int `yaml:"number"`
}
type mCategory struct {
Title string `yaml:"title"`
Number int `yaml:"number"`
}

589032
data/dictionary.txt Normal file

File diff suppressed because it is too large Load Diff

1161
data/stop_tokens.txt Normal file

File diff suppressed because it is too large Load Diff

14
go.mod
View File

@@ -5,16 +5,27 @@ go 1.23
require (
github.com/88250/lute v1.7.6
github.com/gin-gonic/gin v1.10.0
github.com/huichen/wukong v0.0.0-20210824074240-ecbd39fa0b56
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d // indirect
github.com/alecthomas/chroma v0.10.0 // indirect
github.com/boltdb/bolt v1.3.1 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/cznic/fileutil v0.0.0-20181122101858-4d67cfea8c87 // indirect
github.com/cznic/internal v0.0.0-20181122101858-3279554c546e // indirect
github.com/cznic/kv v0.0.0-20181122101858-e9cdcade440e // indirect
github.com/cznic/lldb v1.1.0 // indirect
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8 // indirect
github.com/cznic/zappy v0.0.0-20181122101859-ca47d358d4b1 // indirect
github.com/dlclark/regexp2 v1.8.1 // indirect
github.com/edsrzf/mmap-go v1.0.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
@@ -22,6 +33,8 @@ require (
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/huichen/murmur v0.0.0-20130808212358-e0489551cf51 // indirect
github.com/huichen/sego v0.0.0-20210824061530-c87651ea5c76 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
@@ -29,6 +42,7 @@ require (
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect

34
go.sum
View File

@@ -1,7 +1,12 @@
github.com/88250/lute v1.7.6 h1:8F4i53POAR+oEkyClsdHYPU1A7Z8rdxfRfjarD+FL9w=
github.com/88250/lute v1.7.6/go.mod h1:+wUqx/1kdFDbWtxn9LYJlaCOAeol2pjSO6w+WJTVQsg=
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d h1:ir/IFJU5xbja5UaBEQLjcvn7aAU01nqU/NUyOBEU+ew=
github.com/adamzy/cedar-go v0.0.0-20170805034717-80a9c64b256d/go.mod h1:PRWNwWq0yifz6XDPZu48aSld8BWwBfr2JKB2bGWiEd4=
github.com/adamzy/sego v0.0.0-20151004184924-5eab9a44f8e8/go.mod h1:KQxo+Xesl2wLJ3yJcX443KaoWzXpbPzU1GNRyE8kNEY=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
@@ -10,12 +15,28 @@ github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cznic/fileutil v0.0.0-20181122101858-4d67cfea8c87 h1:94XgeeTZ+3Xi9zsdgBjP1Byx/wywCImjF8FzQ7OaKdU=
github.com/cznic/fileutil v0.0.0-20181122101858-4d67cfea8c87/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
github.com/cznic/internal v0.0.0-20181122101858-3279554c546e h1:58AcyflCe84EONph4gkyo3eDOEQcW5HIPfQBrD76W68=
github.com/cznic/internal v0.0.0-20181122101858-3279554c546e/go.mod h1:olo7eAdKwJdXxb55TKGLiJ6xt1H0/tiiRCWKVLmtjY4=
github.com/cznic/kv v0.0.0-20181122101858-e9cdcade440e h1:8ji4rZgRKWMQUJlPNEzfzCkX7yFAZFR829Mrh7PXxLA=
github.com/cznic/kv v0.0.0-20181122101858-e9cdcade440e/go.mod h1:J9vPsG5aOQu5A836WgCTIb9xkiB9w1birknxIQmyWXY=
github.com/cznic/lldb v1.1.0 h1:AIA+ham6TSJ+XkMe8imQ/g8KPzMUVWAwqUQQdtuMsHs=
github.com/cznic/lldb v1.1.0/go.mod h1:FIZVUmYUVhPwRiPzL8nD/mpFcJ/G7SSXjjXYG4uRI3A=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8 h1:LpMLYGyy67BoAFGda1NeOBQwqlv7nUXpm+rIVHGxZZ4=
github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
github.com/cznic/zappy v0.0.0-20181122101859-ca47d358d4b1 h1:ytLS5Cgkxq6jObotJ+a13nsejdqzLFPliDf8CQ8OkAA=
github.com/cznic/zappy v0.0.0-20181122101859-ca47d358d4b1/go.mod h1:Y1SNZ4dRUOKXshKUbwUapqNncRrho4mkjQebgEHZLj8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0=
github.com/dlclark/regexp2 v1.8.1/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/edsrzf/mmap-go v1.0.0 h1:CEBF7HpRnUCSJgGUb5h1Gm7e3VkmVDrR8lvWVLtrOFw=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
@@ -32,11 +53,21 @@ github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBEx
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g=
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
github.com/huichen/murmur v0.0.0-20130808212358-e0489551cf51 h1:86ZSBmeBzG7dWW2rx9imn5pVKgqe7YjWzZ9qhn4Z+9A=
github.com/huichen/murmur v0.0.0-20130808212358-e0489551cf51/go.mod h1:UKrDR4kaPWAPk8cJGrHoTgyI8OmHPNDjUxx/aOK4ySU=
github.com/huichen/sego v0.0.0-20210824061530-c87651ea5c76 h1:qNQ2+1IQT9Mor/vfEHePOQSbiapLoNI7sQmpxM7l1Ew=
github.com/huichen/sego v0.0.0-20210824061530-c87651ea5c76/go.mod h1:Fymg8+khR/cKSuIwqRxy/jmZg7PIPLk7CauXzrbcMUM=
github.com/huichen/wukong v0.0.0-20210824074240-ecbd39fa0b56 h1:6mWEcSQ1o+cF1gwjfSl6m3e66czIHA5M42pyLH3Wx+w=
github.com/huichen/wukong v0.0.0-20210824074240-ecbd39fa0b56/go.mod h1:u6SZwApV/nh7QnT+LeE7EIwjOPOeRGXR4meGHFoGAwM=
github.com/issue9/assert v1.4.1 h1:gUtOpMTeaE4JTe9kACma5foOHBvVt1p5XTFrULDwdXI=
github.com/issue9/assert v1.4.1/go.mod h1:Yktk83hAVl1SPSYtd9kjhBizuiBIqUQyj+D5SE2yjVY=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@@ -56,6 +87,8 @@ github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@@ -79,6 +112,7 @@ golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=

View File

@@ -10,6 +10,7 @@ import (
"github.com/88250/lute"
"github.com/gin-gonic/gin"
"github.com/huichen/wukong/engine"
)
type MApp struct {
@@ -17,10 +18,12 @@ type MApp struct {
Port int
Config *config.MConfig
lute *lute.Lute
engine *gin.Engine
lute *lute.Lute
engine *gin.Engine
searcher *engine.Engine
Posts []*model.MPost
Posts []*model.MPost
IndexedPosts map[uint64]*model.MPost
Tags map[string]string
TagsCount map[string]int
@@ -61,6 +64,8 @@ func NewMApp(cfg *config.MConfig) *MApp {
Port: cfg.Port,
Config: cfg,
IndexedPosts: make(map[uint64]*model.MPost),
Tags: make(map[string]string),
TagsCount: make(map[string]int),

View File

@@ -2,6 +2,8 @@ package mApp
import (
"encoding/json"
"fmt"
"github.com/huichen/wukong/types"
"html/template"
"io"
"net/http"
@@ -174,8 +176,8 @@ func (ma *MApp) TagHandler(ctx *gin.Context) {
"all_page": allPage,
},
"tagged_post": gin.H{
"title": fmt.Sprintf("%s - %s", ma.Config.MSite.Post.Tag.Title, tagName),
"posts": taggedPosts,
"tag_name": tagName,
"tag_hash": tagHash,
"tag_list": string(tagListJson),
},
@@ -253,8 +255,8 @@ func (ma *MApp) CategoryHandler(ctx *gin.Context) {
"all_page": allPage,
},
"categorized_post": gin.H{
"title": fmt.Sprintf("%s - %s", ma.Config.MSite.Post.Category.Title, categoryName),
"posts": categorizedPosts,
"category_name": categoryName,
"category_hash": categoryHash,
"tag_list": string(tagListJson),
},
@@ -330,6 +332,75 @@ func (ma *MApp) ArchiveHandler(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "archive.html", resData)
}
func (ma *MApp) SearchHandler(ctx *gin.Context) {
keyword := ctx.DefaultQuery("keyword", "")
if keyword == "" || len(ma.Posts) <= 1 {
ctx.Redirect(http.StatusFound, "/archive")
return
}
searchResult := ma.searcher.Search(types.SearchRequest{Text: keyword})
searchPosts := searchResult.Docs
page, _ := strconv.Atoi(ctx.DefaultQuery("page", "1"))
size := ma.Config.MSite.Post.Search.Number
var prePage, curPage, nxtPage, allPage int
allPage = (len(searchPosts) + size - 1) / size
if allPage > 0 {
if page <= 0 {
curPage = 1
} else if page > allPage {
curPage = allPage
} else {
curPage = page
}
} else {
curPage = 0
}
prePage = curPage - 1
nxtPage = curPage + 1
if prePage <= 0 {
prePage = curPage
}
if nxtPage > allPage {
nxtPage = allPage
}
var resultPosts []model.MPost
for _, searchPost := range searchPosts {
resultPosts = append(resultPosts, *ma.IndexedPosts[searchPost.DocId])
}
resData := gin.H{
"site_info": gin.H{
"logo": ma.Config.MSite.Info.Logo,
"title": ma.Config.MSite.Info.Title,
"author": ma.Config.MSite.Info.Author,
"language": ma.Config.MSite.Info.Language,
"copyright": template.HTML(ma.Config.MSite.Info.Copyright),
},
"menu": ma.Config.MSite.Menu,
"page_info": gin.H{
"pre_page": prePage,
"cur_page": curPage,
"nxt_page": nxtPage,
"all_page": allPage,
},
"search_post": gin.H{
"title": fmt.Sprintf("%s - %s", ma.Config.MSite.Post.Search.Title, keyword),
"posts": resultPosts,
"keyword": keyword,
},
}
ctx.HTML(http.StatusOK, "search.html", resData)
}
func (ma *MApp) UpdateBlogHandler(ctx *gin.Context) {
var err error
ma.resetStorage()
@@ -346,5 +417,8 @@ func (ma *MApp) UpdateBlogHandler(ctx *gin.Context) {
return
}
// parse post index
ma.loadPostIndex()
ctx.JSON(http.StatusOK, gin.H{"msg": "ok"})
}

View File

@@ -49,7 +49,7 @@ func (ma *MApp) loadMarkdownFiles() error {
func (ma *MApp) parseMarkdowns() error {
htmlPath := DST
for _, file := range ma.SrcFiles {
for index, file := range ma.SrcFiles {
// read markdown file
_mdFile, err := os.Open(file.Path)
if err != nil {
@@ -126,7 +126,11 @@ func (ma *MApp) parseMarkdowns() error {
post.Tags = nil
post.Categories = nil
// set post index
post.Index = uint64(index)
ma.Posts = append(ma.Posts, &post)
ma.IndexedPosts[post.Index] = &post
}
// sort Posts by date

View File

@@ -2,6 +2,7 @@ package mApp
func (ma *MApp) loadRoutes() {
ma.engine.GET("/", ma.IndexHandler)
ma.engine.GET("/search", ma.SearchHandler)
ma.engine.GET("/archive", ma.ArchiveHandler)
ma.engine.GET("/post/:hash", ma.PostHandler)
ma.engine.GET("/tag/:hash", ma.TagHandler)

32
internal/mApp/mSearch.go Normal file
View File

@@ -0,0 +1,32 @@
package mApp
import (
"io"
"os"
"github.com/huichen/wukong/engine"
"github.com/huichen/wukong/types"
)
func (ma *MApp) loadPostIndex() {
ma.searcher = &engine.Engine{}
ma.searcher.Init(types.EngineInitOptions{
UsePersistentStorage: true,
PersistentStorageFolder: "tmp",
StopTokenFile: "data/stop_tokens.txt",
SegmenterDictionaries: "data/dictionary.txt",
IndexerInitOptions: &types.IndexerInitOptions{
IndexType: types.LocationsIndex,
},
})
for _, post := range ma.Posts {
postFile, _ := os.OpenFile(post.HtmlPath, os.O_RDONLY, 0666)
postData, _ := io.ReadAll(postFile)
ma.searcher.IndexDocument(post.Index, types.DocumentIndexData{Content: string(postData)}, false)
}
ma.searcher.FlushIndex()
}

View File

@@ -7,6 +7,7 @@ import (
// MPost post metadata
type MPost struct {
Index uint64 `yaml:"index" json:"index"`
Title string `yaml:"title" json:"title"`
Cover string `yaml:"cover" json:"cover"`
Date string `yaml:"date" json:"date"`

View File

@@ -26,6 +26,12 @@ html, body {
background-color: var(--background-color);
}
input:focus {
border: none;
outline: none;
box-shadow: none;
}
a, a:link, a:visited, a:active {
text-decoration: none;
color: var(--primary-text-color);
@@ -102,3 +108,32 @@ a:hover {
border-radius: 4px;
border: var(--secondary-text-color) 1px dashed;
}
.search-wrap {
width: 300px;
height: 30px;
line-height: 30px;
display: flex;
}
.search-input {
width: 270px;
height: 30px;
line-height: 30px;
display: inline;
border: none;
border-radius: 4px;
}
.search-button {
width: 30px;
height: 30px;
display: inline;
border: none;
border-radius: 4px;
background: var(--secondary-color);
}
.search-button:hover {
background: var(--primary-color);
}

View File

@@ -0,0 +1,25 @@
.search-post-title {
color: var(--primary-color);
}
.search-post-item {
padding-top: 5px;
padding-bottom: 5px;
color: var(--primary-text-color);
list-style: none;
}
.search-post-item-wrap {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.search-post-item-date {
color: var(--secondary-text-color);
}
.search-post-pagination-item {
color: var(--secondary-text-color);
padding-right: 10px;
}

View File

@@ -1,4 +1,4 @@
.tagged-name {
.tagged-post-title {
color: var(--primary-color);
}

View File

@@ -0,0 +1,4 @@
function search() {
const keyword = document.getElementById("archive-search-input").value;
window.location.href = "/search?keyword=" + keyword;
}

View File

@@ -0,0 +1,4 @@
function search() {
const keyword = document.getElementById("index-search-input").value;
window.location.href = "/search?keyword=" + keyword;
}

View File

@@ -43,6 +43,10 @@ function goto(path) {
window.location.href = path;
}
function back() {
window.history.back();
}
function backToTop() {
window.scrollTo({
top: 0,

View File

@@ -0,0 +1,4 @@
function search() {
const keyword = document.getElementById("search-search-input").value;
window.location.href = "/search?keyword=" + keyword;
}

View File

@@ -38,6 +38,15 @@
{{ end }}
</div>
</div>
<div class="row pt-4">
<div class="search-wrap">
<input class="search-input" id="archive-search-input" type="text">
&nbsp;
<button class="search-button" onclick="search()">
<i class="fa-solid fa-magnifying-glass"></i>
</button>
</div>
</div>
</div>
@@ -107,6 +116,7 @@
{{ .site_info.copyright }}
</div>
<script src="../assets/js/archive.js"></script>
</body>
</html>

View File

@@ -44,7 +44,7 @@
<!-- body -->
<div class="container p-3">
<div class="row pt-lg-3">
<h4 class="categorized-post-title"># {{ .categorized_post.category_name }}</h4>
<h4 class="categorized-post-title"># {{ .categorized_post.title }}</h4>
<div class="col-12 col-lg-9">
<div>
{{ range $i, $v := .categorized_post.posts }}

View File

@@ -38,6 +38,15 @@
{{ end }}
</div>
</div>
<div class="row pt-4">
<div class="search-wrap">
<input class="search-input" id="index-search-input" type="text">
&nbsp;
<button class="search-button" onclick="search()">
<i class="fa-solid fa-magnifying-glass"></i>
</button>
</div>
</div>
</div>
<!-- body -->
@@ -86,6 +95,7 @@
{{ .site_info.copyright }}
</div>
<script src="../assets/js/index.js"></script>
</body>
</html>

View File

@@ -47,6 +47,9 @@
<span class="toc-box-menu-item" onclick="backToTop()">
<i class="fa-solid fa-circle-up"></i>
</span>
<span class="toc-box-menu-item" onclick="back()">
<i class="fa-solid fa-right-from-bracket"></i>
</span>
</div>
</div>

View File

@@ -0,0 +1,117 @@
{{ define "search.html" }}
<html lang="{{ .site_info.language }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .site_info.title }}</title>
<link rel="icon" type="image/x-icon" href="{{ .site_info.logo }}"/>
<link rel="stylesheet" href="../assets/css/lib/fontawesome.all.min.css">
<link rel="stylesheet" href="../assets/css/lib/bootstrap.min.css">
<link rel="stylesheet" href="../assets/css/global.css">
<link rel="stylesheet" href="../assets/css/search.css">
<script src="../assets/js/lib/jquery.min.js"></script>
<script src="../assets/js/lib/bootstrap.min.js"></script>
<script src="../assets/js/lib/fontawesome.all.min.js"></script>
</head>
<body>
<div class="root-container">
<!-- header -->
<div class="container p-3">
<div class="row pt-3 pt-md-4 pt-lg-5">
<div class="col main-logo">
<div class="main-logo-img" style="background-image: url('{{ .site_info.logo }}');"></div>
<div class="main-logo-txt">
{{ .site_info.title }}
</div>
</div>
</div>
</div>
<!-- menu -->
<div class="container p-3">
<div class="row pt-lg-3">
<div class="col mx-auto post-menu">
{{ range $i, $v := .menu.Items }}
<i class="{{ $v.Icon }} m-icon"></i>
<a class="main-menu-link" href="{{ $v.Url }}"> {{ $v.Name }} </a>
{{ end }}
</div>
</div>
<div class="row pt-4">
<div class="search-wrap">
<input class="search-input" id="search-search-input" type="text">
&nbsp;
<button class="search-button" onclick="search()">
<i class="fa-solid fa-magnifying-glass"></i>
</button>
</div>
</div>
</div>
<!-- body -->
<div class="container p-3">
<div class="row pt-lg-3">
<h4 class="search-post-title"># {{ .search_post.title }}</h4>
<div class="col-12 col-lg-9">
<div>
{{ range $i, $v := .search_post.posts }}
<div class="row search-post-item">
<div class="col search-post-item-wrap">
<span class="d-none d-md-inline search-post-item-date">{{ $v.Date }}&nbsp; | &nbsp;</span>
<span>
<a href="/post/{{ $v.HtmlHash }}">{{ $v.Title }}</a>
</span>
</div>
<div class="col d-none d-md-block search-post-item-wrap">
<span style="color: var(--secondary-text-color)">
[
{{ range $i2, $v2 := $v.TagHashes }}
<a href="/tag/{{ $v2.Hash }}" style="color: var(--secondary-text-color)">{{ $v2.Name }}</a>
{{ if lt (add $i2 1) (len $v.TagHashes) }}
,
{{ end }}
{{ end }}
]
</span>
</div>
</div>
{{ end }}
</div>
</div>
</div>
<div class="row pt-3 pt-lg-4">
<div class="col-12 col-md-8">
<div class="search-post-pagination">
<span class="search-post-pagination-item">
<a href="/search?page={{ .page_info.pre_page }}">
<
</a>
</span>
<span class="search-post-pagination-item">
{{ .page_info.cur_page }} &nbsp; / &nbsp; {{ .page_info.all_page }}
</span>
<span class="search-post-pagination-item">
<a href="/search?page={{ .page_info.nxt_page }}">
>
</a>
</span>
</div>
</div>
</div>
</div>
</div>
<!-- footer -->
<div class="footer">
{{ .site_info.copyright }}
</div>
<script src="../assets/js/search.js"></script>
</body>
</html>
{{ end }}

View File

@@ -44,7 +44,7 @@
<!-- body -->
<div class="container p-3">
<div class="row pt-lg-3">
<h4 class="tagged-name"># {{ .tagged_post.tag_name }}</h4>
<h4 class="tagged-post-title"># {{ .tagged_post.title }}</h4>
<div class="col-12 col-md-8">
<div>
{{ range $i, $v := .tagged_post.posts }}