refactor: restructure repo into src/ site/ dist/ vendor/ packs/

Separate framework source from website:
- src/layers/ + src/main.css: CSS framework source (was assets/css/)
- site/: Hugo website (content/, layouts/, hugo.toml)
- dist/: built output (asw.css, asw.min.css)
- vendor/open-props/: vendored dependency with version tracking
- Hugo module mounts: dist/ → static, site runs from site/

Build: hugo --source site/ passes (105 pages).
npm run build produces dist/asw.css.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ludo 2026-04-11 15:12:42 +02:00
parent 5bf233348d
commit 910b0e42a6
Signed by: ludo
GPG key ID: F6E479DEFAB84D6E
71 changed files with 76 additions and 3 deletions

View file

@ -0,0 +1,13 @@
{{- /* render-footnotes.html
Replace Hugo's default <div class="footnotes"> with ASW-semantic markup.
Hugo v0.123.0+ render hook for the footnote block.
Ref: https://gohugo.io/render-hooks/footnotes/
*/ -}}
<footer data-role="footnotes">
<hr>
<ol>
{{- range .Items }}
<li id="{{ .ID }}">{{ .Content }}{{ .Return }}</li>
{{- end }}
</ol>
</footer>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode | default "en" }}">
<head>
{{- partial "head.html" . -}}
</head>
<body>
{{ partial "nav.html" . }}
{{ block "header" . }}{{ end }}
{{ block "content" . }}{{ end }}
<footer>
<small><a href="/">{{ .Site.Title }}</a> · {{ now.Format "2006" }}</small>
</footer>
</body>
</html>

View file

@ -0,0 +1,24 @@
{{ define "header" }}
<header>
<h1>{{ .Title }}</h1>
{{ with .Description }}<p>{{ . }}</p>{{ end }}
</header>
{{ end }}
{{ define "content" }}
<article role="main">
<section>
{{ range .Pages }}
<article>
<header>
<h2><a href="{{ .Permalink }}">{{ .Title }}</a></h2>
<p data-text="dim">
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "January 2006" }}</time>
</p>
</header>
{{ with .Summary }}<p>{{ . }}</p>{{ end }}
</article>
{{ end }}
</section>
</article>
{{ end }}

View file

@ -0,0 +1,23 @@
{{ define "header" }}
<header>
{{ with .Type }}<p data-text="eyebrow">{{ . }}</p>{{ end }}
<p data-text="dim">
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "January 2006" }}</time>
{{ with .Params.author }} · {{ . }}{{ end }}
</p>
{{ with .Params.tags }}
<p>{{ range . }}<a href="/tags/{{ . }}" data-text="tag">#{{ . }}</a> {{ end }}</p>
{{ end }}
</header>
{{ end }}
{{ define "content" }}
<article role="main">
{{ .Content }}
{{ with .Params.footer }}
<footer>
<small>{{ . }}</small>
</footer>
{{ end }}
</article>
{{ end }}

View file

@ -0,0 +1,90 @@
{{ define "header" }}
<header>
{{- if .Description -}}
<hgroup>
<h1>{{ .Title }}</h1>
<p>{{ .Description }}</p>
</hgroup>
{{- else -}}
<h1>{{ .Title }}</h1>
{{- end }}
</header>
{{ end }}
{{ define "content" }}
<section data-layout="console">
<nav aria-label="Documentation" data-nav="sidebar">
{{- $menu := index .Site.Menus "docs" -}}
{{- if $menu -}}
{{- range $menu -}}
{{- if .HasChildren -}}
<h3>{{ .Name }}</h3>
<ul>
{{- range .Children -}}
<li>
<a href="{{ .URL }}"
{{- if eq (relURL .URL) $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .Name -}}
</a>
</li>
{{- end -}}
</ul>
{{- else -}}
<ul>
<li>
<a href="{{ .URL }}"
{{- if eq (relURL .URL) $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .Name -}}
</a>
</li>
</ul>
{{- end -}}
{{- end -}}
{{- else -}}
{{- with .CurrentSection -}}
<h3>{{ .Title }}</h3>
<ul>
{{- range .RegularPages -}}
<li>
<a href="{{ .RelPermalink }}"
{{- if eq .RelPermalink $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .LinkTitle -}}
</a>
</li>
{{- end -}}
</ul>
{{- end -}}
{{- end -}}
</nav>
<article>
{{ .Content }}
{{- if or .PrevInSection .NextInSection -}}
<footer data-role="prev-next">
{{- with .NextInSection -}}
<a href="{{ .RelPermalink }}" rel="prev">
<span aria-hidden="true"></span> Previous
<span>{{ .LinkTitle }}</span>
</a>
{{- end -}}
{{- with .PrevInSection -}}
<a href="{{ .RelPermalink }}" rel="next">
Next <span aria-hidden="true"></span>
<span>{{ .LinkTitle }}</span>
</a>
{{- end -}}
</footer>
{{- end -}}
</article>
{{- with .TableOfContents -}}
<aside data-toc>
<h3>On this page</h3>
{{ . }}
</aside>
{{- end -}}
</section>
{{ end }}

View file

@ -0,0 +1,90 @@
{{ define "header" }}
<header>
{{- if .Description -}}
<hgroup>
<h1>{{ .Title }}</h1>
<p>{{ .Description }}</p>
</hgroup>
{{- else -}}
<h1>{{ .Title }}</h1>
{{- end }}
</header>
{{ end }}
{{ define "content" }}
<section data-layout="docs">
<nav aria-label="Documentation" data-nav="sidebar">
{{- $menu := index .Site.Menus "docs" -}}
{{- if $menu -}}
{{- range $menu -}}
{{- if .HasChildren -}}
<h3>{{ .Name }}</h3>
<ul>
{{- range .Children -}}
<li>
<a href="{{ .URL }}"
{{- if eq (relURL .URL) $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .Name -}}
</a>
</li>
{{- end -}}
</ul>
{{- else -}}
<ul>
<li>
<a href="{{ .URL }}"
{{- if eq (relURL .URL) $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .Name -}}
</a>
</li>
</ul>
{{- end -}}
{{- end -}}
{{- else -}}
{{- with .CurrentSection -}}
<h3>{{ .Title }}</h3>
<ul>
{{- range .RegularPages -}}
<li>
<a href="{{ .RelPermalink }}"
{{- if eq .RelPermalink $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .LinkTitle -}}
</a>
</li>
{{- end -}}
</ul>
{{- end -}}
{{- end -}}
</nav>
<article>
{{ .Content }}
{{- if or .PrevInSection .NextInSection -}}
<footer data-role="prev-next">
{{- with .NextInSection -}}
<a href="{{ .RelPermalink }}" rel="prev">
<span aria-hidden="true"></span> Previous
<span>{{ .LinkTitle }}</span>
</a>
{{- end -}}
{{- with .PrevInSection -}}
<a href="{{ .RelPermalink }}" rel="next">
Next <span aria-hidden="true"></span>
<span>{{ .LinkTitle }}</span>
</a>
{{- end -}}
</footer>
{{- end -}}
</article>
{{- with .TableOfContents -}}
<aside data-toc>
<h3>On this page</h3>
{{ . }}
</aside>
{{- end -}}
</section>
{{ end }}

View file

@ -0,0 +1,40 @@
{{ define "header" }}
<header>
<h1>{{ .Title }}</h1>
{{ with .Description }}<p data-abstract>{{ . }}</p>{{ end }}
{{- $hasDate := not .Date.IsZero -}}
{{- $hasAuthor := .Params.author -}}
{{- if or $hasDate $hasAuthor -}}
<p data-byline>
{{- if $hasDate -}}
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "January 2, 2006" }}</time>
{{- end -}}
{{- if and $hasDate $hasAuthor }} · {{ end -}}
{{- with .Params.author }}{{ . }}{{ end -}}
</p>
{{- end }}
{{- with .GetTerms "tags" }}
<nav data-role="tag-cloud" aria-label="Tags">
{{- range . }}
<a href="{{ .Permalink }}" data-tag="{{ .Name }}">{{ .Name }}</a>
{{- end }}
</nav>
{{- end }}
</header>
{{ end }}
{{ define "content" }}
<article role="main">
{{ .Content }}
{{- if or .PrevInSection .NextInSection }}
<footer>
{{- with .PrevInSection }}
<a href="{{ .RelPermalink }}" rel="prev">← {{ .LinkTitle }}</a>
{{- end }}
{{- with .NextInSection }}
<a href="{{ .RelPermalink }}" rel="next">{{ .LinkTitle }} →</a>
{{- end }}
</footer>
{{- end }}
</article>
{{ end }}

30
site/layouts/index.html Normal file
View file

@ -0,0 +1,30 @@
{{ define "title" }}{{ .Site.Title }}{{ end }}
{{ define "header" }}
<header>
<hgroup>
<h1>{{ .Site.Title }}</h1>
<p>{{ .Site.Params.description | default "An agent-first approach to web generation." }}</p>
</hgroup>
</header>
{{ end }}
{{ define "content" }}
<article role="main">
<section>
<h2>Recent</h2>
{{ range first 10 .Site.RegularPages }}
<article>
<header>
<h3><a href="{{ .Permalink }}">{{ .Title }}</a></h3>
<p data-text="dim">
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "January 2006" }}</time>
{{ with .Params.eyebrow }} · {{ . }}{{ end }}
</p>
</header>
{{ with .Summary }}<p>{{ . }}</p>{{ end }}
</article>
{{ end }}
</section>
</article>
{{ end }}

View file

@ -0,0 +1,95 @@
{{ define "header" }}
<header>
{{- if .Description -}}
<hgroup>
<h1>{{ .Title }}</h1>
<p>{{ .Description }}</p>
</hgroup>
{{- else -}}
<h1>{{ .Title }}</h1>
{{- end }}
</header>
{{ end }}
{{ define "content" }}
<section data-layout="docs">
<nav aria-label="Notes" data-nav="sidebar">
{{- $menuName := .Site.Params.notes_menu | default "notes" -}}
{{- $menu := index .Site.Menus $menuName -}}
{{- if $menu -}}
{{- range $menu -}}
{{- if .HasChildren -}}
<h3>{{ .Name }}</h3>
<ul>
{{- range .Children -}}
<li>
<a href="{{ .URL }}"
{{- if $.IsMenuCurrent $menuName . }} aria-current="page"{{ end -}}>
{{- .Name -}}
</a>
</li>
{{- end -}}
</ul>
{{- else -}}
<ul>
<li>
<a href="{{ .URL }}"
{{- if $.IsMenuCurrent $menuName . }} aria-current="page"{{ end -}}>
{{- .Name -}}
</a>
</li>
</ul>
{{- end -}}
{{- end -}}
{{- else -}}
{{- with .CurrentSection -}}
<h3>{{ .Title }}</h3>
<ul>
{{- range .RegularPages -}}
<li>
<a href="{{ .RelPermalink }}"
{{- if eq .RelPermalink $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .LinkTitle -}}
</a>
</li>
{{- end -}}
</ul>
{{- end -}}
{{- end -}}
</nav>
<article>
{{ .Content }}
{{- $prevURL := index .Params "prev-url" -}}
{{- $prevTitle := index .Params "prev-title" -}}
{{- $nextURL := index .Params "next-url" -}}
{{- $nextTitle := index .Params "next-title" -}}
{{- if or $prevURL $nextURL -}}
<footer data-role="prev-next">
{{- if $prevURL -}}
<a href="{{ $prevURL }}" rel="prev">
<span aria-hidden="true"></span> Previous
<span>{{ $prevTitle }}</span>
</a>
{{- end -}}
{{- if and $nextURL $nextTitle -}}
<a href="{{ $nextURL }}" rel="next">
Next <span aria-hidden="true"></span>
<span>{{ $nextTitle }}</span>
</a>
{{- end -}}
</footer>
{{- end -}}
</article>
{{- with .TableOfContents -}}
<aside data-toc>
<h3>On this page</h3>
{{ . }}
</aside>
{{- end -}}
</section>
{{ end }}

View file

@ -0,0 +1,11 @@
{{ define "header" }}{{ end }}
{{ define "content" }}
<main>
<header>
<h1>{{ .Title }}</h1>
{{- with .Description }}<p>{{ . }}</p>{{ end }}
</header>
{{ .Content }}
</main>
{{ end }}

View file

@ -0,0 +1,41 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="dark light">
<title>
{{- if .IsHome -}}
{{ .Site.Title }}
{{- else -}}
{{ .Title }} · {{ .Site.Title }}
{{- end -}}
</title>
{{- with .Description }}<meta name="description" content="{{ . }}">{{- end }}
{{- if not .Description }}{{- with .Site.Params.description }}<meta name="description" content="{{ . }}">{{- end }}{{- end }}
{{- /* ── Meta partials ─────────────────────────────────────────── */}}
{{- partial "meta/seo.html" . -}}
{{- partial "meta/og.html" . -}}
{{- partial "meta/ai-disclosure.html" . -}}
{{- partial "meta/json-ld.html" . -}}
{{- /* ── CSS ────────────────────────────────────────────────────── */}}
{{- if hugo.IsDevelopment }}
<link rel="stylesheet" href="/vendor/open-props.min.css">
<link rel="stylesheet" href="/vendor/media.min.css">
<link rel="stylesheet" href="/css/layers/00-reset.css">
<link rel="stylesheet" href="/css/layers/01-asw.css">
<link rel="stylesheet" href="/css/layers/02-semantic.css">
<link rel="stylesheet" href="/css/layers/03-components.css">
<link rel="stylesheet" href="/css/layers/04-data-attrs.css">
<link rel="stylesheet" href="/css/layers/05-utilities.css">
<link rel="stylesheet" href="/css/layers/06-charts.css">
<link rel="stylesheet" href="/css/layers/07-chroma.css">
<link rel="stylesheet" href="/css/layers/08-layout.css">
<link rel="stylesheet" href="/css/layers/08a-paper.css">
<link rel="stylesheet" href="/css/layers/09-landing.css">
{{- else }}
<link rel="stylesheet" href="/asw.css">
{{- end }}
{{- range .AlternativeOutputFormats -}}
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">
{{- end }}

View file

@ -0,0 +1,25 @@
{{- /*
partials/meta/ai-disclosure.html — AI-generated content disclosure
Emits the proposed W3C/WHATWG AI content disclosure meta tag and the
corresponding HTTP-equiv header that satisfies EU AI Act Article 50
obligations for AI-generated/AI-assisted web content.
The disclosure level is controlled per-page via front matter:
ai_content: "generated" — fully AI-generated content
ai_content: "assisted" — human-written with AI assistance (default)
ai_content: "reviewed" — AI-generated, human-reviewed and edited
ai_content: "none" — no AI involvement (suppresses the tag)
Site-wide default in hugo.toml:
[params]
ai_content = "assisted" # default for all pages
Reference:
https://github.com/nickvdyck/ai-content-disclosure
EU AI Act Article 50 (transparency obligations, Chapter IV)
*/ -}}
{{- $level := or .Params.ai_content .Site.Params.ai_content "assisted" -}}
{{- if ne $level "none" -}}
<meta name="ai-content-disclosure" content="{{ $level }}">
{{- end }}

View file

@ -0,0 +1,101 @@
{{- /*
partials/meta/json-ld.html — JSON-LD structured data (Schema.org)
Emits one <script type="application/ld+json"> block per page.
Uses dict → jsonify → safeHTML to avoid Hugo's JS-context escaping.
Schema selection:
Home page → WebSite (with SearchAction if params.search_url set)
Docs pages → TechArticle (front matter: type = "docs")
Dated pages → Article
Everything else → WebPage
BreadcrumbList appended when .Ancestors is non-empty.
Configure in hugo.toml:
[params]
author = "Trentuna" # publisher/author name
logo = "/images/logo.png" # site logo for publisher
search_url = "/search/?q={q}" # enables SearchAction on WebSite
*/ -}}
{{- $author := or .Site.Params.author .Site.Title -}}
{{- $logo := .Site.Params.logo | default "" -}}
{{- $desc := or .Description .Site.Params.description "" -}}
{{- $image := or .Params.image .Site.Params.og_image "" -}}
{{- if .IsHome -}}
{{- /* ── WebSite ──────────────────────────────────────────────────── */}}
{{- $data := dict
"@context" "https://schema.org"
"@type" "WebSite"
"name" .Site.Title
"url" .Site.BaseURL
"description" $desc
-}}
{{- with .Site.Params.search_url -}}
{{- $action := dict
"@type" "SearchAction"
"target" (dict "@type" "EntryPoint" "urlTemplate" (printf "%s%s" $.Site.BaseURL .))
"query-input" "required name=q"
-}}
{{- $data = merge $data (dict "potentialAction" $action) -}}
{{- end -}}
{{- printf "<script type=\"application/ld+json\">%s</script>" ($data | jsonify) | safeHTML -}}
{{- else -}}
{{- /* ── Article / TechArticle / WebPage ─────────────────────────── */}}
{{- $schemaType := "WebPage" -}}
{{- if and .IsPage (not .IsSection) -}}
{{- if eq .Params.type "docs" -}}
{{- $schemaType = "TechArticle" -}}
{{- else if .Date -}}
{{- $schemaType = "Article" -}}
{{- end -}}
{{- end -}}
{{- $publisher := dict "@type" "Organization" "name" $author -}}
{{- with $logo -}}
{{- $publisher = merge $publisher (dict "logo" (dict "@type" "ImageObject" "url" (. | absURL))) -}}
{{- end -}}
{{- $data := dict
"@context" "https://schema.org"
"@type" $schemaType
"headline" .Title
"description" $desc
"url" .Permalink
"author" $publisher
"publisher" $publisher
-}}
{{- with $image -}}
{{- $data = merge $data (dict "image" (. | absURL)) -}}
{{- end -}}
{{- if and .Date (not .IsSection) -}}
{{- $data = merge $data (dict
"datePublished" (.Date.Format "2006-01-02T15:04:05Z07:00")
"dateModified" (.Lastmod.Format "2006-01-02T15:04:05Z07:00")
) -}}
{{- end -}}
{{- /* BreadcrumbList: .Ancestors is nearest→root; iterate by index to reverse */}}
{{- with .Ancestors -}}
{{- $ancs := . -}}
{{- $len := len $ancs -}}
{{- $items := slice -}}
{{- range $i := seq $len -}}
{{- $a := index $ancs (sub $len $i) -}}
{{- $item := dict "@type" "ListItem" "position" $i "name" $a.Title "item" $a.Permalink -}}
{{- $items = $items | append $item -}}
{{- end -}}
{{- $last := dict "@type" "ListItem" "position" (add $len 1) "name" $.Title "item" $.Permalink -}}
{{- $items = $items | append $last -}}
{{- $crumb := dict "@type" "BreadcrumbList" "itemListElement" $items -}}
{{- $data = merge $data (dict "breadcrumb" $crumb) -}}
{{- end -}}
{{- printf "<script type=\"application/ld+json\">%s</script>" ($data | jsonify) | safeHTML -}}
{{- end }}

View file

@ -0,0 +1,41 @@
{{- /*
partials/meta/og.html — Open Graph + Twitter Card meta tags
og:title Page title (site title for home page)
og:description .Description → .Site.Params.description → ""
og:url .Permalink
og:type "website" (home) | "article" (everything else)
og:site_name .Site.Title
og:image .Params.image → .Site.Params.og_image → absent
twitter:card "summary_large_image" when image present, else "summary"
twitter:site .Site.Params.twitter (optional @handle)
Configure in hugo.toml:
[params]
og_image = "/images/og-default.png" # fallback OG image
twitter = "@yourhandle" # omit if not on Twitter/X
*/ -}}
{{- $title := cond .IsHome .Site.Title (printf "%s · %s" .Title .Site.Title) -}}
{{- $desc := or .Description .Site.Params.description "" -}}
{{- $image := or .Params.image .Site.Params.og_image "" -}}
{{- $type := cond .IsHome "website" "article" -}}
<meta property="og:title" content="{{ $title }}">
<meta property="og:description" content="{{ $desc }}">
<meta property="og:url" content="{{ .Permalink }}">
<meta property="og:type" content="{{ $type }}">
<meta property="og:site_name" content="{{ .Site.Title }}">
{{- with $image }}
<meta property="og:image" content="{{ . | absURL }}">
{{- end }}
{{- /* Twitter / X Card */}}
<meta name="twitter:card" content="{{ if $image }}summary_large_image{{ else }}summary{{ end }}">
<meta name="twitter:title" content="{{ $title }}">
<meta name="twitter:description" content="{{ $desc }}">
{{- with $image }}
<meta name="twitter:image" content="{{ . | absURL }}">
{{- end }}
{{- with .Site.Params.twitter }}
<meta name="twitter:site" content="{{ . }}">
{{- end }}

View file

@ -0,0 +1,16 @@
{{- /*
partials/meta/seo.html — canonical URL + robots directives
Outputs:
<link rel="canonical"> Always emitted; uses .Permalink (absolute).
<meta name="robots"> "noindex, nofollow" on draft/future pages,
"index, follow" otherwise.
No params required. Works from any page context.
*/ -}}
<link rel="canonical" href="{{ .Permalink }}">
{{- if or .Draft (gt .Date now) }}
<meta name="robots" content="noindex, nofollow">
{{- else }}
<meta name="robots" content="index, follow">
{{- end }}

View file

@ -0,0 +1,8 @@
<nav>
<ul><li><a href="/"><strong>{{ .Site.Title }}</strong></a></li></ul>
<ul>
{{- range .Site.Menus.main }}
<li><a href="{{ .URL }}"{{ if $.IsMenuCurrent "main" . }} aria-current="page"{{ end }}>{{ .Name }}</a></li>
{{- end }}
</ul>
</nav>

View file

@ -0,0 +1,21 @@
{{- /*
tag-nav.html — renders all site tags as a navigable tag cloud.
Usage in a layout:
{{ partial "tag-nav.html" . }}
Outputs: <nav data-role="tag-cloud"> with links to each tag page.
The (N) count shows how many pages have each tag.
*/ -}}
{{- $tags := .Site.Taxonomies.tags -}}
{{- if $tags }}
<nav data-role="tag-cloud" aria-label="Browse by tag">
{{- range $name, $pages := $tags }}
{{- $tagPage := site.GetPage (printf "/tags/%s" ($name | urlize)) }}
<a href="{{ if $tagPage }}{{ $tagPage.Permalink }}{{ else }}{{ print site.BaseURL "tags/" ($name | urlize) "/" }}{{ end }}" data-tag="{{ $name }}">
{{ $name -}}
<small>({{ len $pages }})</small>
</a>
{{- end }}
</nav>
{{- end }}

View file

@ -0,0 +1,16 @@
{{- /*
callout shortcode — wraps content in an ASW callout block.
Usage:
{{< callout note >}}
Content here. Markdown is rendered.
{{< /callout >}}
First positional param: callout type.
Valid types: note, warning, tip, info (maps to ASW data-callout attribute).
Default: note
*/ -}}
{{- $type := .Get 0 | default "note" -}}
<aside data-callout="{{ $type }}">
{{ .Inner | markdownify }}
</aside>

View file

@ -0,0 +1,20 @@
{{- /*
wikilink shortcode — renders an internal link with ASW data-wikilink attribute.
Usage:
{{< wikilink "Display Text" "/path/to/page/" >}}
Param 0 (required): display text
Param 1 (optional): href path. Defaults to /display-text-slugified/
Examples:
{{< wikilink "My Note" >}}
<a href="/my-note/" data-wikilink>My Note</a>
{{< wikilink "My Note" "/vault/my-note/" >}}
<a href="/vault/my-note/" data-wikilink>My Note</a>
*/ -}}
{{- $text := .Get 0 -}}
{{- $slug := $text | lower | replace " " "-" -}}
{{- $href := .Get 1 | default (printf "/%s/" $slug) -}}
<a href="{{ $href | relURL }}" data-wikilink>{{ $text }}</a>