about summary refs log tree commit diff stats
path: root/templates/page.templ
diff options
context:
space:
mode:
Diffstat (limited to 'templates/page.templ')
-rw-r--r--templates/page.templ116
1 files changed, 116 insertions, 0 deletions
diff --git a/templates/page.templ b/templates/page.templ
new file mode 100644
index 0000000..294b73e
--- /dev/null
+++ b/templates/page.templ
@@ -0,0 +1,116 @@
+package templates
+
+import (
+	"context"
+	"go.alanpearce.eu/website/internal/config"
+	"io"
+	"io/fs"
+	"net/url"
+)
+
+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(original config.URL, path string, title string) string {
+	ou := *original.URL
+	u := config.URL{
+		URL: &ou,
+	}
+	q := url.Values{}
+	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
+	})
+}