about summary refs log tree commit diff stats
path: root/templates
diff options
context:
space:
mode:
authorAlan Pearce2024-06-24 21:48:36 +0200
committerAlan Pearce2024-06-24 23:09:15 +0200
commita2feb8c63c80a1f52830f562af2deb2c6065eaae (patch)
tree448ed15c5fb91099ef29528c529a35d6151d98ee /templates
parent8623948592fa14958d340b006653fc57861c4fc4 (diff)
downloadwebsite-a2feb8c63c80a1f52830f562af2deb2c6065eaae.tar.lz
website-a2feb8c63c80a1f52830f562af2deb2c6065eaae.tar.zst
website-a2feb8c63c80a1f52830f562af2deb2c6065eaae.zip
move templ templates into separate package
Diffstat (limited to 'templates')
-rw-r--r--templates/404.templ13
-rw-r--r--templates/homepage.templ42
-rw-r--r--templates/list.templ51
-rw-r--r--templates/page.templ115
-rw-r--r--templates/post.templ51
-rw-r--r--templates/tags.templ23
6 files changed, 295 insertions, 0 deletions
diff --git a/templates/404.templ b/templates/404.templ
new file mode 100644
index 0000000..4b5e52a
--- /dev/null
+++ b/templates/404.templ
@@ -0,0 +1,13 @@
+package templates
+
+import "website/internal/config"
+
+templ NotFound(config config.Config, path string) {
+	@Page(config, PageSettings{
+		Title: "Not Found",
+		Path:  path,
+	}) {
+		<h1>404</h1>
+		<h2>ʕノ•ᴥ•ʔノ ︵ ┻━┻</h2>
+	}
+}
diff --git a/templates/homepage.templ b/templates/homepage.templ
new file mode 100644
index 0000000..0afbb2f
--- /dev/null
+++ b/templates/homepage.templ
@@ -0,0 +1,42 @@
+package templates
+
+import (
+	"website/internal/config"
+	"website/internal/content"
+)
+
+templ Homepage(config config.Config, posts []content.Post, content string) {
+	@Page(config, PageSettings{
+		Title: config.Title,
+		TitleAttrs: templ.Attributes{
+			"class": "p-name u-url",
+		},
+		Path: "/",
+		BodyAttrs: templ.Attributes{
+			"class": "h-card",
+		},
+	}) {
+		<div id="content">
+			@Unsafe(content)
+		</div>
+		<section>
+			<h2>Latest Posts</h2>
+			@list(posts[0:3])
+		</section>
+		<section>
+			<h2>Elsewhere on the Internet</h2>
+			<ul class="elsewhere">
+				<li>
+					<a class="u-email" rel="me" href={ templ.SafeURL("mailto:" + config.Email) }>
+						{ config.Email }
+					</a>
+				</li>
+				for _, link := range config.Menus["me"] {
+					<li>
+						<a class="u-url" rel="me" href={ templ.SafeURL(link.URL.String()) }>{ link.Name }</a>
+					</li>
+				}
+			</ul>
+		</section>
+	}
+}
diff --git a/templates/list.templ b/templates/list.templ
new file mode 100644
index 0000000..602c15c
--- /dev/null
+++ b/templates/list.templ
@@ -0,0 +1,51 @@
+package templates
+
+import (
+	"website/internal/config"
+	"website/internal/content"
+)
+
+templ TagPage(config config.Config, tag string, posts []content.Post, path string) {
+	@Page(config, PageSettings{
+		Title: tag,
+		Path:  path,
+		TitleAttrs: templ.Attributes{
+			"class": "p-author h-card",
+			"rel":   "author",
+		},
+	}) {
+		<div class="filter">
+			<h3 class="filter">#{ tag }</h3>
+			<small>
+				<a href="../">Remove filter</a>
+			</small>
+		</div>
+		@list(posts)
+	}
+}
+
+templ ListPage(config config.Config, posts []content.Post, path string) {
+	@Page(config, PageSettings{
+		Title: config.Title,
+		TitleAttrs: templ.Attributes{
+			"class": "p-author h-card",
+			"rel":   "author",
+		},
+		Path: path,
+	}) {
+		@list(posts)
+	}
+}
+
+templ list(posts []content.Post) {
+	<ul class="h-feed">
+		for _, post := range posts {
+			<li class="h-entry">
+				<span>
+					@postDate(post.Date)
+				</span>
+				<a class="p-name u-url" href={ templ.SafeURL(post.URL) }>{ post.Title }</a>
+			</li>
+		}
+	</ul>
+}
diff --git a/templates/page.templ b/templates/page.templ
new file mode 100644
index 0000000..08c17a0
--- /dev/null
+++ b/templates/page.templ
@@ -0,0 +1,115 @@
+package templates
+
+import (
+	"os"
+	"net/url"
+
+	"website/internal/config"
+)
+
+var (
+	css string
+)
+
+func init() {
+	bytes, err := os.ReadFile("templates/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(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(path string, title string) string {
+	u, err := url.Parse("https://alanpearce-eu.goatcounter.com/count")
+	if err != nil {
+		panic(err)
+	}
+	q := u.Query()
+	q.Add("p", path)
+	q.Add("t", title)
+	u.RawQuery = q.Encode()
+
+	return u.String()
+}
+
+templ counter(path string, title string) {
+	<script data-goatcounter="https://alanpearce-eu.goatcounter.com/count" async src="https://gc.zgo.at/count.v4.js" crossorigin="anonymous" integrity="sha384-nRw6qfbWyJha9LhsOtSb2YJDyZdKvvCFh0fJYlkquSFjUxp9FVNugbfy8q1jdxI+"></script>
+	<noscript>
+		<img src={ string(templ.URL(mkURL(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
+	})
+}
diff --git a/templates/post.templ b/templates/post.templ
new file mode 100644
index 0000000..5b09d4b
--- /dev/null
+++ b/templates/post.templ
@@ -0,0 +1,51 @@
+package templates
+
+import (
+	"time"
+	"website/internal/config"
+	"website/internal/content"
+)
+
+func Unsafe(html string) templ.Component {
+	return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) {
+		_, err = io.WriteString(w, html)
+		return
+	})
+}
+
+templ postDate(d time.Time) {
+	<time class="dt-published" datetime={ d.UTC().Format(time.RFC3339) }>
+		{ d.Format("2006-01-02") }
+	</time>
+}
+
+templ PostPage(config config.Config, post content.Post) {
+	@Page(config, PageSettings{
+		Title: post.Title,
+		TitleAttrs: templ.Attributes{
+			"class": "p-author h-card",
+			"rel":   "author",
+		},
+		Path: post.URL,
+	}) {
+		<article class="h-entry">
+			<h1 class="p-name">{ post.Title }</h1>
+			<p>
+				@postDate(post.Date)
+			</p>
+			<div class="e-content">
+				@Unsafe(post.Content)
+			</div>
+			<div class="tags">
+				Tags:
+				<ul class="p-categories tags">
+					for _, tag := range post.Taxonomies.Tags {
+						<li>
+							@tagLink(tag, templ.Attributes{"class": "p-category"})
+						</li>
+					}
+				</ul>
+			</div>
+		</article>
+	}
+}
diff --git a/templates/tags.templ b/templates/tags.templ
new file mode 100644
index 0000000..7218ca1
--- /dev/null
+++ b/templates/tags.templ
@@ -0,0 +1,23 @@
+package templates
+
+import "website/internal/config"
+
+templ tagLink(tag string, attrs templ.Attributes) {
+	<a { attrs... } href={ templ.SafeURL("/tags/" + tag) }>#{ tag }</a>
+}
+
+templ TagsPage(config config.Config, title string, tags []string, path string) {
+	@Page(config, PageSettings{
+		Title: title,
+		Path:  path,
+	}) {
+		<h3 class="filter">Tags</h3>
+		<ul class="tags">
+			for _, tag := range tags {
+				<li class="h-feed">
+					@tagLink(tag, templ.Attributes{})
+				</li>
+			}
+		</ul>
+	}
+}