aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md21
-rw-r--r--filters.go69
-rw-r--r--main.go65
3 files changed, 96 insertions, 59 deletions
diff --git a/README.md b/README.md
index df1417d..e2dbd71 100644
--- a/README.md
+++ b/README.md
@@ -163,28 +163,43 @@ Payload {
163- first (gets first N posts) 163- first (gets first N posts)
164- last (gets last N posts) 164- last (gets last N posts)
165- random (gets random N posts) 165- random (gets random N posts)
166- filterbytype (get just the posts with specific type)
166 167
167```html 168```html
168<!-- First 10 pages --> 169<!-- First 10 pages -->
169{{ range first 10 .Pages }} 170{{ range .Pages | first 10 }}
170 {{ if and (eq .Type "post") (not .Draft) }} 171 {{ if and (eq .Type "post") (not .Draft) }}
171 <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> 172 <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
172 {{ end }} 173 {{ end }}
173{{ end }} 174{{ end }}
174 175
175<!-- Last 10 pages --> 176<!-- Last 10 pages -->
176{{ range last 10 .Pages }} 177{{ range .Pages | last 10 }}
177 {{ if and (eq .Type "post") (not .Draft) }} 178 {{ if and (eq .Type "post") (not .Draft) }}
178 <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> 179 <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
179 {{ end }} 180 {{ end }}
180{{ end }} 181{{ end }}
181 182
182<!-- Random 10 pages --> 183<!-- Random 10 pages -->
183{{ range random 10 .Pages }} 184{{ range .Pages | random 10 }}
184 {{ if and (eq .Type "post") (not .Draft) }} 185 {{ if and (eq .Type "post") (not .Draft) }}
185 <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> 186 <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
186 {{ end }} 187 {{ end }}
187{{ end }} 188{{ end }}
189
190<!-- Filter by type -->
191{{ range .Pages | filterbytype "post" }}
192 {{ if not .Draft }}
193 <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
194 {{ end }}
195{{ end }}
196
197<!-- Chain multiple together -->
198{{ range .Pages | filterbytype "post" | random 20 | first 5 }}
199 {{ if not .Draft }}
200 <li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li>
201 {{ end }}
202{{ end }}
188``` 203```
189 204
190## Additional material 205## Additional material
diff --git a/filters.go b/filters.go
new file mode 100644
index 0000000..bb57599
--- /dev/null
+++ b/filters.go
@@ -0,0 +1,69 @@
1package main
2
3import (
4 "math/rand"
5 "reflect"
6 "time"
7)
8
9// firstN returns the first n items of a slice.
10func firstN(n int, items interface{}) interface{} {
11 v := reflect.ValueOf(items)
12 if v.Kind() != reflect.Slice {
13 panic("firstN: not a slice")
14 }
15 if v.Len() < n {
16 return items
17 }
18 return v.Slice(0, n).Interface()
19}
20
21// lastN returns the last n items of any slice.
22func lastN(n int, items interface{}) interface{} {
23 v := reflect.ValueOf(items)
24 if v.Kind() != reflect.Slice {
25 panic("lastN: not a slice")
26 }
27 l := v.Len()
28 if l < n {
29 return items
30 }
31 return v.Slice(l-n, l).Interface()
32}
33
34// randomN returns n random items of any slice.
35func randomN(n int, items interface{}) interface{} {
36 v := reflect.ValueOf(items)
37 if v.Kind() != reflect.Slice {
38 panic("randomN: not a slice")
39 }
40 l := v.Len()
41 if l < n {
42 return items
43 }
44 rand.Seed(time.Now().UnixNano())
45 indices := rand.Perm(l)[:n]
46 result := reflect.MakeSlice(v.Type(), n, n)
47 for i, idx := range indices {
48 result.Index(i).Set(v.Index(idx))
49 }
50 return result.Interface()
51}
52
53// filterByType filters pages by their type.
54func filterByType(pageType string, pages interface{}) interface{} {
55 v := reflect.ValueOf(pages)
56 if v.Kind() != reflect.Slice {
57 panic("filterByType: not a slice")
58 }
59
60 var filtered []interface{}
61 for i := 0; i < v.Len(); i++ {
62 page := v.Index(i).Interface().(Page)
63 if page.Type == pageType {
64 filtered = append(filtered, page)
65 }
66 }
67 return filtered
68}
69
diff --git a/main.go b/main.go
index 2824041..9871d1c 100644
--- a/main.go
+++ b/main.go
@@ -5,12 +5,10 @@ import (
5 "fmt" 5 "fmt"
6 "html/template" 6 "html/template"
7 "log" 7 "log"
8 "math/rand"
9 "net/http" 8 "net/http"
10 "os" 9 "os"
11 "path" 10 "path"
12 "path/filepath" 11 "path/filepath"
13 "reflect"
14 "sort" 12 "sort"
15 "strings" 13 "strings"
16 "time" 14 "time"
@@ -89,50 +87,6 @@ var EmbedTemplatePost string
89//go:embed "files/index.xml" 87//go:embed "files/index.xml"
90var EmbedTemplateFeed string 88var EmbedTemplateFeed string
91 89
92// firstN returns the first n items of a slice.
93func firstN(n int, items interface{}) interface{} {
94 v := reflect.ValueOf(items)
95 if v.Kind() != reflect.Slice {
96 panic("firstN: not a slice")
97 }
98 if v.Len() < n {
99 return items
100 }
101 return v.Slice(0, n).Interface()
102}
103
104// lastN returns the last n items of any slice.
105func lastN(n int, items interface{}) interface{} {
106 v := reflect.ValueOf(items)
107 if v.Kind() != reflect.Slice {
108 panic("lastN: not a slice")
109 }
110 l := v.Len()
111 if l < n {
112 return items
113 }
114 return v.Slice(l-n, l).Interface()
115}
116
117// randomN returns n random items of any slice.
118func randomN(n int, items interface{}) interface{} {
119 v := reflect.ValueOf(items)
120 if v.Kind() != reflect.Slice {
121 panic("randomN: not a slice")
122 }
123 l := v.Len()
124 if l < n {
125 return items
126 }
127 rand.Seed(time.Now().UnixNano())
128 indices := rand.Perm(l)[:n]
129 result := reflect.MakeSlice(v.Type(), n, n)
130 for i, idx := range indices {
131 result.Index(i).Set(v.Index(idx))
132 }
133 return result.Interface()
134}
135
136// Function to clean HTML tags using bluemonday. 90// Function to clean HTML tags using bluemonday.
137func cleanHTMLTags(htmlString string) string { 91func cleanHTMLTags(htmlString string) string {
138 p := bluemonday.StrictPolicy() 92 p := bluemonday.StrictPolicy()
@@ -318,6 +272,13 @@ func buildProject(projectRoot string) {
318 return 272 return
319 } 273 }
320 274
275 filters := template.FuncMap{
276 "first": firstN,
277 "last": lastN,
278 "random": randomN,
279 "filterbytype": filterByType,
280 }
281
321 // Generate HTML files for all pages. 282 // Generate HTML files for all pages.
322 for _, page := range pages { 283 for _, page := range pages {
323 outFilepath := path.Join(projectRoot, "public", page.Meta["url"].(string)) 284 outFilepath := path.Join(projectRoot, "public", page.Meta["url"].(string))
@@ -330,11 +291,7 @@ func buildProject(projectRoot string) {
330 templates = append([]string{templatePathname}, templates...) 291 templates = append([]string{templatePathname}, templates...)
331 templates = append([]string{baseTemplatePathname}, templates...) 292 templates = append([]string{baseTemplatePathname}, templates...)
332 293
333 t, err := template.New("base.html").Funcs(template.FuncMap{ 294 t, err := template.New("base.html").Funcs(filters).ParseFiles(templates...)
334 "first": firstN,
335 "last": lastN,
336 "random": randomN,
337 }).ParseFiles(templates...)
338 if err != nil { 295 if err != nil {
339 panic(err) 296 panic(err)
340 } 297 }
@@ -385,11 +342,7 @@ func buildProject(projectRoot string) {
385 templates = append([]string{templatePathname}, templates...) 342 templates = append([]string{templatePathname}, templates...)
386 templates = append([]string{baseTemplatePathname}, templates...) 343 templates = append([]string{baseTemplatePathname}, templates...)
387 344
388 t, err := template.New("base.html").Funcs(template.FuncMap{ 345 t, err := template.New("base.html").Funcs(filters).ParseFiles(templates...)
389 "first": firstN,
390 "last": lastN,
391 "random": randomN,
392 }).ParseFiles(templates...)
393 if err != nil { 346 if err != nil {
394 panic(err) 347 panic(err)
395 } 348 }