1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
package templates
import (
"io/fs"
"website/internal/config"
)
var (
css string
)
func Setup() {
bytes, err := fs.ReadFile(Files, "style.css")
if err != nil {
panic(err)
}
css = string(bytes)
}
type PageSettings struct {
Title string
Path string
TitleAttrs templ.Attributes
BodyAttrs templ.Attributes
}
func extendClasses(cs string, attrs templ.Attributes) string {
if extras, exists := attrs["class"]; exists {
return templ.Classes(cs, extras).String()
} else {
return cs
}
}
templ menuItem(item config.MenuItem) {
<a
href={ templ.SafeURL(item.URL.String()) }
if item.URL.IsAbs() {
target="_blank"
}
>{ item.Name }</a>
}
templ Page(site *config.Config, page PageSettings) {
<!DOCTYPE html>
<html lang={ site.DefaultLanguage }>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{ page.Title }</title>
<link rel="alternate" type="application/atom+xml" title={ site.Title } href="/atom.xml"/>
@style(css)
</head>
<body { page.BodyAttrs... }>
<a class="skip" href="#main">Skip to main content</a>
<header>
<h2>
<a href="/" class={ extendClasses("title p-name", page.TitleAttrs) } { page.TitleAttrs... }>{ site.Title }</a>
</h2>
<nav>
for _, item := range site.Menus["main"] {
@menuItem(item)
}
</nav>
</header>
<main id="main">
{ children... }
</main>
<footer>
Content is
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
<a href="https://git.alanpearce.eu/website/">Site source code</a> is
<a href="https://opensource.org/licenses/MIT">MIT</a>
</footer>
@counter(site, page.Path, page.Title)
if site.InjectLiveReload {
<script defer>
new EventSource("/_/reload").onmessage = event => {
console.log("got message", event)
window.location.reload()
};
</script>
}
</body>
</html>
}
func mkURL(u config.URL, path string, title string) string {
q := u.Query()
q.Add("p", path)
q.Add("t", title)
u.RawQuery = q.Encode()
return u.String()
}
templ counter(config *config.Config, path string, title string) {
<script data-goatcounter={ config.GoatCounter.String() } async src="https://stats.alanpearce.eu/count.v4.js" crossorigin="anonymous" integrity="sha384-nRw6qfbWyJha9LhsOtSb2YJDyZdKvvCFh0fJYlkquSFjUxp9FVNugbfy8q1jdxI+"></script>
<noscript>
<img src={ string(templ.URL(mkURL(config.GoatCounter, path, title))) }/>
</noscript>
}
func style(css string) templ.Component {
return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
_, err = io.WriteString(w, "<style>\n"+css+"\n</style>")
return
})
}
|