mirror of https://github.com/jlelse/GoBlog
Taxonomies!
This commit is contained in:
parent
c98f3eaca2
commit
484da515aa
|
@ -40,6 +40,8 @@ type configBlog struct {
|
|||
Pagination int `mapstructure:"pagination"`
|
||||
// Sections
|
||||
Sections []string `mapstructure:"sections"`
|
||||
// Taxonomies
|
||||
Taxonomies []string `mapstructure:"taxonomies"`
|
||||
}
|
||||
|
||||
type configUser struct {
|
||||
|
@ -71,6 +73,7 @@ func initConfig() error {
|
|||
viper.SetDefault("blog.title", "My blog")
|
||||
viper.SetDefault("blog.pagination", 10)
|
||||
viper.SetDefault("blog.sections", []string{"posts"})
|
||||
viper.SetDefault("blog.taxonomies", []string{"tags"})
|
||||
viper.SetDefault("user.nick", "admin")
|
||||
viper.SetDefault("user.name", "Admin")
|
||||
viper.SetDefault("user.password", "secret")
|
||||
|
|
|
@ -38,6 +38,13 @@ func migrateDb() error {
|
|||
return err
|
||||
},
|
||||
},
|
||||
&migrator.Migration{
|
||||
Name: "00005",
|
||||
Func: func(tx *sql.Tx) error {
|
||||
_, err := tx.Exec("create table pp_tmp(id integer primary key autoincrement, path text not null, parameter text not null, value text); insert into pp_tmp(path, parameter, value) select path, parameter, value from post_parameters; drop table post_parameters; alter table pp_tmp rename to post_parameters;")
|
||||
return err
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -15,6 +15,8 @@ blog:
|
|||
title: My blog
|
||||
sections:
|
||||
- posts
|
||||
taxonomies:
|
||||
- tags
|
||||
user:
|
||||
nick: admin
|
||||
name: Admin
|
||||
|
|
8
go.mod
8
go.mod
|
@ -16,7 +16,7 @@ require (
|
|||
github.com/lib/pq v1.8.0 // indirect
|
||||
github.com/lopezator/migrator v0.3.0
|
||||
github.com/magiconair/properties v1.8.2 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.1
|
||||
github.com/mattn/go-sqlite3 v1.14.2
|
||||
github.com/miekg/dns v1.1.31 // indirect
|
||||
github.com/mitchellh/mapstructure v1.3.3 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
|
@ -27,16 +27,16 @@ require (
|
|||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/stretchr/testify v1.6.1 // indirect
|
||||
github.com/tdewolff/minify/v2 v2.8.0
|
||||
github.com/tdewolff/minify/v2 v2.9.1
|
||||
github.com/vcraescu/go-paginator v0.0.0-20200304054438-86d84f27c0b3
|
||||
github.com/yuin/goldmark v1.2.1
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 // indirect
|
||||
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 // indirect
|
||||
golang.org/x/sys v0.0.0-20200828194041-157a740278f4 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/ini.v1 v1.60.1 // indirect
|
||||
gopkg.in/ini.v1 v1.60.2 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
||||
)
|
||||
|
|
20
go.sum
20
go.sum
|
@ -277,8 +277,8 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
|
|||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
|
||||
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/mattn/go-sqlite3 v1.14.1 h1:AHx9Ra40wIzl+GelgX2X6AWxmT5tfxhI1PL0523HcSw=
|
||||
github.com/mattn/go-sqlite3 v1.14.1/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/mattn/go-sqlite3 v1.14.2 h1:A2EQLwjYf/hfYaM20FVjs1UewCTTFR7RmjEHkLjldIA=
|
||||
github.com/mattn/go-sqlite3 v1.14.2/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
|
||||
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
|
@ -405,10 +405,10 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd
|
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tdewolff/minify/v2 v2.8.0 h1:t3tOPWkTpKhsgxm3IM9Sy8hE2eIt30Oaa+2havJGGIE=
|
||||
github.com/tdewolff/minify/v2 v2.8.0/go.mod h1:6zN8VLhMfFxNrwHROcboYNo2+huPNu4SV8DPh3PUQ8E=
|
||||
github.com/tdewolff/parse/v2 v2.4.4 h1:uMdbQRtYbKR/msP9CbI7li9wK6pionYiH6s7ipltyGY=
|
||||
github.com/tdewolff/parse/v2 v2.4.4/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||
github.com/tdewolff/minify/v2 v2.9.1 h1:k6QEyGlg/Oh+6dZASJDM8dzSbKoCS5S4lp3tHk2AnAM=
|
||||
github.com/tdewolff/minify/v2 v2.9.1/go.mod h1:njYNbXhVTAhI1hARVHCbHAgRd44j+AEt0LdW+menKsY=
|
||||
github.com/tdewolff/parse/v2 v2.5.1 h1:1PxbcgMxb8RWH1nmeQjBC+lZIOTUEjiYQ3u8RpzndN0=
|
||||
github.com/tdewolff/parse/v2 v2.5.1/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||
github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY=
|
||||
|
@ -565,8 +565,8 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8 h1:AvbQYmiaaaza3cW3QXRyPo5kYgpFIzOAfeAAN7m3qQ4=
|
||||
golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200828194041-157a740278f4 h1:kCCpuwSAoYJPkNc6x0xT9yTtV4oKtARo4RGBQWOfg9E=
|
||||
golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
@ -676,8 +676,8 @@ gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.60.1 h1:P5y5shSkb0CFe44qEeMBgn8JLow09MP17jlJHanke5g=
|
||||
gopkg.in/ini.v1 v1.60.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.60.2 h1:7i8mqModL63zqi8nQn8Q3+0zvSCZy1AxhBgthKfi4WU=
|
||||
gopkg.in/ini.v1 v1.60.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw=
|
||||
gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
|
|
33
http.go
33
http.go
|
@ -85,20 +85,39 @@ func buildHandler() (http.Handler, error) {
|
|||
}
|
||||
}
|
||||
|
||||
paginationPath := "/page/{page}"
|
||||
|
||||
for _, section := range appConfig.Blog.Sections {
|
||||
if section != "" {
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/"+section, serveSection("/"+section, section))
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/"+section+"/page/{page}", serveSection("/"+section, section))
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/"+section+paginationPath, serveSection("/"+section, section))
|
||||
}
|
||||
}
|
||||
|
||||
for _, taxonomy := range appConfig.Blog.Taxonomies {
|
||||
if taxonomy != "" {
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/"+taxonomy, serveTaxonomy(taxonomy))
|
||||
values, err := allTaxonomyValues(taxonomy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, tv := range values {
|
||||
path := "/" + taxonomy + "/" + tv
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(path, serveTaxonomyValue(path, taxonomy, tv))
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(path+paginationPath, serveTaxonomyValue(path, taxonomy, tv))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
routePatterns := routesToStringSlice(r.Routes())
|
||||
if !routePatterns.has("/") {
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/", serveHome("/"))
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/page/{page}", serveHome("/"))
|
||||
} else if !routePatterns.has("/blog") {
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/blog", serveHome("/blog"))
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/blog/page/{page}", serveHome("/blog"))
|
||||
rootPath := "/"
|
||||
blogPath := "/blog"
|
||||
if !routePatterns.has(rootPath) {
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(rootPath, serveHome(rootPath))
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(paginationPath, serveHome(rootPath))
|
||||
} else if !routePatterns.has(blogPath) {
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(blogPath, serveHome(blogPath))
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(blogPath+paginationPath, serveHome(blogPath))
|
||||
}
|
||||
|
||||
r.With(minifier.Middleware).NotFound(serve404)
|
||||
|
|
88
posts.go
88
posts.go
|
@ -16,11 +16,11 @@ import (
|
|||
var errPostNotFound = errors.New("post not found")
|
||||
|
||||
type Post struct {
|
||||
Path string `json:"path"`
|
||||
Content string `json:"content"`
|
||||
Published string `json:"published"`
|
||||
Updated string `json:"updated"`
|
||||
Parameters map[string]string `json:"parameters"`
|
||||
Path string `json:"path"`
|
||||
Content string `json:"content"`
|
||||
Published string `json:"published"`
|
||||
Updated string `json:"updated"`
|
||||
Parameters map[string][]string `json:"parameters"`
|
||||
}
|
||||
|
||||
func servePost(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -62,24 +62,45 @@ func (p *postPaginationAdapter) Slice(offset, length int, data interface{}) erro
|
|||
panic("data has to be a pointer")
|
||||
}
|
||||
|
||||
posts, err := getPosts(p.context, &postsRequestConfig{
|
||||
sections: p.config.sections,
|
||||
offset: offset,
|
||||
limit: length,
|
||||
})
|
||||
modifiedConfig := *p.config
|
||||
modifiedConfig.offset = offset
|
||||
modifiedConfig.limit = length
|
||||
|
||||
posts, err := getPosts(p.context, &modifiedConfig)
|
||||
reflect.ValueOf(data).Elem().Set(reflect.ValueOf(&posts).Elem())
|
||||
return err
|
||||
}
|
||||
|
||||
func serveHome(path string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return serveIndex(path, "")
|
||||
return serveIndex(path, "", "", "")
|
||||
}
|
||||
|
||||
func serveSection(path, section string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return serveIndex(path, section)
|
||||
return serveIndex(path, section, "", "")
|
||||
}
|
||||
|
||||
func serveIndex(path string, section string) func(w http.ResponseWriter, r *http.Request) {
|
||||
func serveTaxonomy(taxonomy string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
allValues, err := allTaxonomyValues(taxonomy)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
render(w, templateTaxonomy, struct {
|
||||
Taxonomy string
|
||||
TaxonomyValues []string
|
||||
}{
|
||||
Taxonomy: taxonomy,
|
||||
TaxonomyValues: allValues,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func serveTaxonomyValue(path, taxonomy, value string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return serveIndex(path, "", taxonomy, value)
|
||||
}
|
||||
|
||||
func serveIndex(path, section, taxonomy, taxonomyValue string) func(w http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
pageNoString := chi.URLParam(r, "page")
|
||||
pageNo, _ := strconv.Atoi(pageNoString)
|
||||
|
@ -87,7 +108,11 @@ func serveIndex(path string, section string) func(w http.ResponseWriter, r *http
|
|||
if len(section) > 0 {
|
||||
sections = []string{section}
|
||||
}
|
||||
p := paginator.New(&postPaginationAdapter{context: r.Context(), config: &postsRequestConfig{sections: sections}}, appConfig.Blog.Pagination)
|
||||
p := paginator.New(&postPaginationAdapter{context: r.Context(), config: &postsRequestConfig{
|
||||
sections: sections,
|
||||
taxonomy: taxonomy,
|
||||
taxonomyValue: taxonomyValue,
|
||||
}}, appConfig.Blog.Pagination)
|
||||
p.SetPage(pageNo)
|
||||
var posts []*Post
|
||||
err := p.Results(&posts)
|
||||
|
@ -124,10 +149,12 @@ func getPost(context context.Context, path string) (*Post, error) {
|
|||
}
|
||||
|
||||
type postsRequestConfig struct {
|
||||
path string
|
||||
limit int
|
||||
offset int
|
||||
sections []string
|
||||
path string
|
||||
limit int
|
||||
offset int
|
||||
sections []string
|
||||
taxonomy string
|
||||
taxonomyValue string
|
||||
}
|
||||
|
||||
func getPosts(context context.Context, config *postsRequestConfig) (posts []*Post, err error) {
|
||||
|
@ -135,8 +162,11 @@ func getPosts(context context.Context, config *postsRequestConfig) (posts []*Pos
|
|||
var rows *sql.Rows
|
||||
defaultSelection := "select p.path, coalesce(content, ''), coalesce(published, ''), coalesce(updated, ''), coalesce(parameter, ''), coalesce(value, '') "
|
||||
postsTable := "posts"
|
||||
if len(config.sections) != 0 {
|
||||
postsTable = "(select * from posts where"
|
||||
if len(config.taxonomy) > 0 && len(config.taxonomyValue) > 0 {
|
||||
postsTable = "(select distinct p.* from " + postsTable + " p left outer join post_parameters pp on p.path = pp.path where pp.parameter = '" + config.taxonomy + "' and pp.value = '" + config.taxonomyValue + "')"
|
||||
}
|
||||
if len(config.sections) > 0 {
|
||||
postsTable = "(select * from " + postsTable + " where"
|
||||
for i, section := range config.sections {
|
||||
if i > 0 {
|
||||
postsTable += " or"
|
||||
|
@ -173,11 +203,11 @@ func getPosts(context context.Context, config *postsRequestConfig) (posts []*Pos
|
|||
if paths[post.Path] == 0 {
|
||||
index := len(posts)
|
||||
paths[post.Path] = index + 1
|
||||
post.Parameters = make(map[string]string)
|
||||
post.Parameters = make(map[string][]string)
|
||||
posts = append(posts, post)
|
||||
}
|
||||
if parameterName != "" && posts != nil {
|
||||
posts[paths[post.Path]-1].Parameters[parameterName] = parameterValue
|
||||
posts[paths[post.Path]-1].Parameters[parameterName] = append(posts[paths[post.Path]-1].Parameters[parameterName], parameterValue)
|
||||
}
|
||||
}
|
||||
return posts, nil
|
||||
|
@ -202,6 +232,20 @@ func allPostPaths() ([]string, error) {
|
|||
return postPaths, nil
|
||||
}
|
||||
|
||||
func allTaxonomyValues(taxonomy string) ([]string, error) {
|
||||
var values []string
|
||||
rows, err := appDb.Query("select distinct value from post_parameters where parameter = ? and value not null and value != ''", taxonomy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for rows.Next() {
|
||||
var value string
|
||||
_ = rows.Scan(&value)
|
||||
values = append(values, value)
|
||||
}
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func checkPost(post *Post) error {
|
||||
if post == nil {
|
||||
return errors.New("no post")
|
||||
|
|
12
render.go
12
render.go
|
@ -13,6 +13,7 @@ const templateError = "error"
|
|||
const templateRedirect = "redirect"
|
||||
const templateIndex = "index"
|
||||
const templateSummary = "summary"
|
||||
const templateTaxonomy = "taxonomy"
|
||||
|
||||
var templates map[string]*template.Template
|
||||
var templateFunctions template.FuncMap
|
||||
|
@ -30,7 +31,16 @@ func initRendering() {
|
|||
}
|
||||
return template.HTML(htmlContent)
|
||||
},
|
||||
// First parameter value
|
||||
"p": func(post Post, parameter string) string {
|
||||
if len(post.Parameters[parameter]) > 0 {
|
||||
return post.Parameters[parameter][0]
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
// All parameter values
|
||||
"ps": func(post Post, parameter string) []string {
|
||||
return post.Parameters[parameter]
|
||||
},
|
||||
"include": func(templateName string, data interface{}) (template.HTML, error) {
|
||||
|
@ -41,7 +51,7 @@ func initRendering() {
|
|||
}
|
||||
|
||||
templates = make(map[string]*template.Template)
|
||||
for _, name := range []string{templatePost, templateError, templateRedirect, templateIndex, templateSummary} {
|
||||
for _, name := range []string{templatePost, templateError, templateRedirect, templateIndex, templateSummary, templateTaxonomy} {
|
||||
templates[name] = loadTemplate(name)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{{ define "title" }}
|
||||
<title>{{ blog.Title }}</title>
|
||||
{{ end }}
|
||||
|
||||
{{ define "main" }}
|
||||
<main>
|
||||
<ul>
|
||||
{{ $taxonomy := .Taxonomy }}
|
||||
{{ range $i, $value := .TaxonomyValues }}<li><a href="/{{ $taxonomy }}/{{ . }}">{{ . }}</a></li>{{ end }}
|
||||
</ul>
|
||||
</main>
|
||||
{{ end }}
|
||||
|
||||
{{ define "taxonomy" }}
|
||||
{{ template "base" . }}
|
||||
{{ end }}
|
Loading…
Reference in New Issue