|
diff --git a/README.md b/README.md
|
| ... |
| 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) }} |
|
|
186 |
<li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> |
|
|
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 }} |
| 185 |
<li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> |
200 |
<li><a href="{{ .RelPermalink }}">{{ .Title }}</a></li> |
| 186 |
{{ end }} |
201 |
{{ end }} |
| 187 |
{{ end }} |
202 |
{{ end }} |
| ... |
|
diff --git a/filters.go b/filters.go
|
|
|
1 |
package main |
|
|
2 |
|
|
|
3 |
import ( |
|
|
4 |
"math/rand" |
|
|
5 |
"reflect" |
|
|
6 |
"time" |
|
|
7 |
) |
|
|
8 |
|
|
|
9 |
// firstN returns the first n items of a slice. |
|
|
10 |
func 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. |
|
|
22 |
func 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. |
|
|
35 |
func 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. |
|
|
54 |
func 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
|
| ... |
| 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 |
//go:embed "files/index.xml" |
87 |
//go:embed "files/index.xml" |
| 90 |
var EmbedTemplateFeed string |
88 |
var EmbedTemplateFeed string |
| 91 |
|
89 |
|
| 92 |
// firstN returns the first n items of a slice. |
|
|
| 93 |
func 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. |
|
|
| 105 |
func 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. |
|
|
| 118 |
func 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. |
| 137 |
func cleanHTMLTags(htmlString string) string { |
91 |
func cleanHTMLTags(htmlString string) string { |
| 138 |
p := bluemonday.StrictPolicy() |
92 |
p := bluemonday.StrictPolicy() |
| ... |
| 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 |
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 |
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 |
} |
| ... |