From 6dedd8ebbc8a25bcd34669201853861d836d12e6 Mon Sep 17 00:00:00 2001
From: Patrick Kollitsch <83281+davidsneighbour@users.noreply.github.com>
Date: Sun, 17 May 2026 08:08:31 +0000
Subject: [PATCH] feat: theme hooks and filters (#964)
---
layouts/_partials/hook.html | 5 +
config/_default/params.toml | 3
layouts/_partials/filter.html | 115 ++++++++++++++++++++++++++++
layouts/_partials/hooks/article/test.html | 1
layouts/_partials/func/debug-cli.html | 87 +++++++++++++++++++++
layouts/_partials/func/hooks/collector.html | 1
layouts/_partials/func/hooks/collector-dump.html | 5 +
layouts/_partials/hooks/article/section-link.html | 3
layouts/baseof.html | 3
layouts/single.html | 8 -
.vscode/custom-dictionary.txt | 4
11 files changed, 227 insertions(+), 8 deletions(-)
diff --git a/.vscode/custom-dictionary.txt b/.vscode/custom-dictionary.txt
index d049214..989bcbc 100644
--- a/.vscode/custom-dictionary.txt
+++ b/.vscode/custom-dictionary.txt
@@ -1,6 +1,8 @@
Ananke
demosite
Disqus
+Errorf
Kitchensink
licenselink
-Philibert
\ No newline at end of file
+Philibert
+Warnf
diff --git a/config/_default/params.toml b/config/_default/params.toml
index 5b68e47..612f05f 100644
--- a/config/_default/params.toml
+++ b/config/_default/params.toml
@@ -255,3 +255,6 @@
color = "#cd201f"
profile = "https://www.youtube.com/@%s"
icon = "youtube" # font awesome brand icon name
+
+[ananke.hooks]
+verbosity = "error" # debug, info, warning, error
\ No newline at end of file
diff --git a/layouts/_partials/filter.html b/layouts/_partials/filter.html
new file mode 100644
index 0000000..31df5cb
--- /dev/null
+++ b/layouts/_partials/filter.html
@@ -0,0 +1,115 @@
+{{- $input := . -}}
+{{- $context := collections.Dictionary -}}
+{{- $config := site.Params.ananke.hooks | compare.Default (collections.Dictionary) -}}
+{{- $disableMessages := $config.disable_messages | compare.Default (collections.Slice) -}}
+
+{{- $colourHook := "\033[38;2;170;153;255m" -}}
+{{- $colourUnused := "\033[38;2;204;119;102m" -}}
+{{- $colourReset := "\033[0m" -}}
+{{- $hookSlug := "FILTER" -}}
+
+{{- if reflect.IsMap . -}}
+ {{- with collections.Index . "__ananke_hook_slug" -}}
+ {{- $hookSlug = . -}}
+ {{- end -}}
+
+ {{- with collections.Index . "__ananke_hook_input" -}}
+ {{- $input = . -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if reflect.IsMap $input -}}
+ {{- $context = collections.Merge $context $input -}}
+ {{- $context = collections.Merge $context (collections.Dictionary "type" "full") -}}
+
+ {{- partials.Include "func/debug-cli.html" (collections.Dictionary
+ "message" (fmt.Printf "%s>>> %s: %s%s" $colourHook $hookSlug $context.hook $colourReset)
+ "severity" "info"
+ ) -}}
+
+ {{- partials.Include "func/debug-cli.html" (collections.Dictionary
+ "message" "hook is extended"
+ "severity" "debug"
+ ) -}}
+{{- else -}}
+ {{- $context = collections.Merge $context (collections.Dictionary
+ "hook" $input
+ "context" (collections.Dictionary)
+ "type" "simple"
+ ) -}}
+
+ {{- partials.Include "func/debug-cli.html" (collections.Dictionary
+ "message" (fmt.Printf "%s>>> %s: %s%s" $colourHook $hookSlug $context.hook $colourReset)
+ "severity" "info"
+ ) -}}
+
+ {{- partials.Include "func/debug-cli.html" (collections.Dictionary
+ "message" "hook is simple"
+ "severity" "debug"
+ ) -}}
+{{- end -}}
+
+{{- partials.Include "func/hooks/collector.html" (collections.Dictionary
+ "hook" $context.hook
+ "context" $context
+) -}}
+
+{{- $loaded := false -}}
+{{- $output := "" -}}
+
+{{- $partialName := fmt.Printf "hooks/%s.html" $context.hook -}}
+{{- $partialHook := fmt.Printf "_partials/%s" $partialName -}}
+
+{{- partials.Include "func/debug-cli.html" (collections.Dictionary
+ "message" (fmt.Printf "partial Name: %s" $partialName)
+ "severity" "debug"
+) -}}
+
+{{- $cache := false -}}
+
+{{- with $context.cache -}}
+ {{- $cache = . -}}
+{{- else -}}
+ {{- with $context.cached -}}
+ {{- $cache = . -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if templates.Exists $partialHook -}}
+ {{- if compare.Eq true $cache -}}
+ {{- $output = partials.IncludeCached $partialName $context.context $context.hook -}}
+
+ {{- partials.Include "func/debug-cli.html" (collections.Dictionary
+ "message" "included cached"
+ "severity" "debug"
+ ) -}}
+
+ {{- $loaded = true -}}
+ {{- else -}}
+ {{- $output = partials.Include $partialName $context.context -}}
+
+ {{- partials.Include "func/debug-cli.html" (collections.Dictionary
+ "message" "included uncached"
+ "severity" "debug"
+ ) -}}
+
+ {{- $loaded = true -}}
+ {{- end -}}
+{{- end -}}
+
+{{- if compare.Eq $loaded false -}}
+ {{- if not (collections.In $disableMessages "unused_hooks") -}}
+ {{- partials.Include "func/debug-cli.html" (collections.Dictionary
+ "message" (fmt.Printf "%s<<< %s: `%s` %sunused%s" $colourHook $hookSlug $context.hook $colourUnused $colourReset)
+ "context" $input
+ "severity" "info"
+ ) -}}
+ {{- end -}}
+{{- else -}}
+ {{- partials.Include "func/debug-cli.html" (collections.Dictionary
+ "message" (fmt.Printf "%s<<< %s: %s done%s" $colourHook $hookSlug $context.hook $colourReset)
+ "severity" "info"
+ ) -}}
+{{- end -}}
+
+{{- return $output -}}
\ No newline at end of file
diff --git a/layouts/_partials/func/debug-cli.html b/layouts/_partials/func/debug-cli.html
new file mode 100644
index 0000000..acd844d
--- /dev/null
+++ b/layouts/_partials/func/debug-cli.html
@@ -0,0 +1,87 @@
+{{- $config := site.Params.ananke.hooks | compare.Default (collections.Dictionary) -}}
+{{/*
+
+$config.namespace
+$config.ignoreErrors
+$config.verbosity
+
+*/}}
+{{/*
+[ananke.hooks]
+verbosity = "warning" # debug, info, warning, error
+
+@todo add and document hook ignoreErrors setting via config
+*/}}
+
+{{/*
+| Primary | `#AA99FF` | `170, 153, 255` |
+| Ananke | `#FF80BF` | `255, 128, 191` |
+| Comment | `#708CA9` | `112, 140, 169` |
+| Error | `#CC7766` | `204, 119, 102` |
+| Warning | `#CCCC66` | `204, 204, 102` |
+| Info | `#6ECC66` | `110, 204, 102` |
+*/}}
+
+{{- $colourPrimary := "\033[38;2;170;153;255m" -}}
+{{- $colourAnanke := "\033[38;2;255;128;191m" -}}
+{{- $colourComment := "\033[38;2;112;140;169m" -}}
+{{- $colourError := "\033[38;2;204;119;102m" -}}
+{{- $colourWarning := "\033[38;2;204;204;102m" -}}
+{{- $colourInfo := "\033[38;2;110;204;102m" -}}
+{{- $colourReset := "\033[0m" -}}
+
+{{- $namespace := $config.namespace | compare.Default "ananke" -}}
+{{- $severity := .severity | compare.Default "info" -}}
+{{- $severity = strings.ToLower $severity -}}
+{{- if or (compare.Eq $severity "warnings") (compare.Eq $severity "warn") -}}
+ {{- $severity = "warning" -}}
+{{- else if or (compare.Eq $severity "errors") (compare.Eq $severity "err") -}}
+ {{- $severity = "error" -}}
+{{- else if compare.Eq $severity "infos" -}}
+ {{- $severity = "info" -}}
+{{- end -}}
+
+{{- $verbosity := $config.verbosity | compare.Default "error" -}}
+{{- $verbosity = strings.ToLower $verbosity -}}
+{{- if or (compare.Eq $verbosity "warnings") (compare.Eq $verbosity "warn") -}}
+ {{- $verbosity = "warning" -}}
+{{- else if or (compare.Eq $verbosity "errors") (compare.Eq $verbosity "err") -}}
+ {{- $verbosity = "error" -}}
+{{- else if compare.Eq $verbosity "infos" -}}
+ {{- $verbosity = "info" -}}
+{{- else if not (or (compare.Eq $verbosity "debug") (compare.Eq $verbosity "info") (compare.Eq $verbosity "warning") (compare.Eq $verbosity "error")) -}}
+ {{- $verbosity = "error" -}}
+{{- end -}}
+
+{{- $shouldOutput := false -}}
+{{- if compare.Eq $verbosity "debug" -}}
+ {{- $shouldOutput = true -}}
+{{- else if and (compare.Eq $verbosity "info") (not (compare.Eq $severity "debug")) -}}
+ {{- $shouldOutput = true -}}
+{{- else if and (compare.Eq $verbosity "warning") (or (compare.Eq $severity "warning") (compare.Eq $severity "error")) -}}
+ {{- $shouldOutput = true -}}
+{{- else if and (compare.Eq $verbosity "error") (compare.Eq $severity "error") -}}
+ {{- $shouldOutput = true -}}
+{{- end -}}
+
+{{- $colourLevel := $colourInfo -}}
+{{- $severityLabel := "INFO" -}}
+
+{{- if compare.Eq $severity "warning" -}}
+ {{- $colourLevel = $colourWarning -}}
+ {{- $severityLabel = "WARN" -}}
+{{- else if compare.Eq $severity "error" -}}
+ {{- $colourLevel = $colourError -}}
+ {{- $severityLabel = "!ERR" -}}
+{{- else if compare.Eq $severity "debug" -}}
+ {{- $colourLevel = $colourComment -}}
+ {{- $severityLabel = "DEBG" -}}
+{{- end -}}
+
+{{- if $shouldOutput -}}
+ {{- if compare.Eq $severity "error" -}}
+ {{- fmt.Errorf (fmt.Printf "%s%s%s/%s%s %s%s%s" $colourAnanke $namespace $colourComment $colourLevel $severityLabel $colourComment .message $colourReset) -}}
+ {{- else -}}
+ {{- fmt.Warnf (fmt.Printf "%s%s%s/%s%s %s%s%s" $colourAnanke $namespace $colourComment $colourLevel $severityLabel $colourComment .message $colourReset) -}}
+ {{- end -}}
+{{- end -}}
diff --git a/layouts/_partials/func/hooks/collector-dump.html b/layouts/_partials/func/hooks/collector-dump.html
new file mode 100644
index 0000000..89ba998
--- /dev/null
+++ b/layouts/_partials/func/hooks/collector-dump.html
@@ -0,0 +1,5 @@
+{{- $scratch := page.Store.Get "ananke.hooks" -}}
+{{- partials.Include "func/debug-cli.html" (collections.Dictionary "message" "Hooks Collector" "severity" "debug") -}}
+{{- range $index, $item := $scratch -}}
+ {{- partials.Include "func/debug-cli.html" (collections.Dictionary "message" (printf "%d: %#v" $index $item) "severity" "debug") -}}
+{{- end -}}
diff --git a/layouts/_partials/func/hooks/collector.html b/layouts/_partials/func/hooks/collector.html
new file mode 100644
index 0000000..3fd5ea1
--- /dev/null
+++ b/layouts/_partials/func/hooks/collector.html
@@ -0,0 +1 @@
+{{- page.Store.Add "ananke.hooks" (slice .hook) -}}
diff --git a/layouts/_partials/hook.html b/layouts/_partials/hook.html
new file mode 100644
index 0000000..770b996
--- /dev/null
+++ b/layouts/_partials/hook.html
@@ -0,0 +1,5 @@
+{{/* "A hook is just a filter that outputs immediately!" he said and moved on with his life. */}}
+{{- partials.Include "filter.html" (collections.Dictionary
+ "__ananke_hook_input" .
+ "__ananke_hook_slug" "HOOK"
+) -}}
\ No newline at end of file
diff --git a/layouts/_partials/hooks/article/section-link.html b/layouts/_partials/hooks/article/section-link.html
new file mode 100644
index 0000000..827bf0d
--- /dev/null
+++ b/layouts/_partials/hooks/article/section-link.html
@@ -0,0 +1,3 @@
+<aside class="instapaper_ignoref b helvetica tracked ttu">
+ {{ .CurrentSection.Title }}
+</aside>
\ No newline at end of file
diff --git a/layouts/_partials/hooks/article/test.html b/layouts/_partials/hooks/article/test.html
new file mode 100644
index 0000000..1805de8
--- /dev/null
+++ b/layouts/_partials/hooks/article/test.html
@@ -0,0 +1 @@
+{{ return printf . "World" }}
\ No newline at end of file
diff --git a/layouts/baseof.html b/layouts/baseof.html
index 95d89e6..9932b8e 100644
--- a/layouts/baseof.html
+++ b/layouts/baseof.html
@@ -79,3 +79,6 @@
{{ block "footer" . }}{{ partials.IncludeCached "site-footer.html" . }}{{ end }}
</body>
</html>
+{{- with (templates.Defer (dict "key" "hooks-collector")) -}}
+ {{- partials.Include "func/hooks/collector-dump.html" . }}
+{{ end -}}
\ No newline at end of file
diff --git a/layouts/single.html b/layouts/single.html
index 9afbcf9..7ee50ad 100644
--- a/layouts/single.html
+++ b/layouts/single.html
@@ -17,13 +17,7 @@
<article class="{{ $post_class }} flex-l {{ if $needs_aside }}mw8{{ else }}mw7{{ end }} center ph3 flex-wrap justify-between">
<header class="mt4 w-100">
- <aside class="instapaper_ignoref b helvetica tracked ttu">
- {{/*
- CurrentSection allows us to use the section title instead of inferring from the folder.
- https://gohugo.io/variables/page/#section-variables-and-methods
- */}}
- {{ .CurrentSection.Title }}
- </aside>
+ {{- partials.Include "hook.html" ( dict "hook" "article/section-link" "context" . ) -}}
{{- partials.IncludeCached "social/share.html" . . -}}
<h1 class="f1 athelas mt3 mb1">
{{- .Title -}}
--
Gitblit v1.10.0