Initial commit: Rapport Website (Hugo + Hextra)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
{{- /*
|
||||
Extracts all headings from a page and adds them to the scratchpad.
|
||||
|
||||
The keys can be obtained from the scratchpad by using the "keys" key.
|
||||
The titles can be obtained from the scratchpad by using the "titles" key.
|
||||
|
||||
The scratchpad must be initialized with empty slices before calling this function for the keys "keys" and "titles"
|
||||
|
||||
@param {any} target The element to extract headings from.
|
||||
@param {any} scratch The scratchpad to add the keys and titles to.
|
||||
|
||||
@example {{ partial "utils/extract-headings.html" (dict "target" $h1 "scratch" $s) }}
|
||||
*/ -}}
|
||||
|
||||
{{- range $heading := index .target.Headings -}}
|
||||
{{- if and (eq $heading.Level 0) (not $heading.Title) -}}
|
||||
{{- $.scratch.Add "keys" (slice $heading.Title) -}}
|
||||
{{- else -}}
|
||||
{{- $key := (printf "%s#%s" $heading.ID $heading.Title) -}}
|
||||
{{- $.scratch.Add "keys" (slice $key) -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- $title := (printf "<h%d>%s" $heading.Level $heading.Title) | htmlUnescape -}}
|
||||
{{- $.scratch.Add "titles" (slice $title) -}}
|
||||
|
||||
{{- partial "utils/extract-headings.html" (dict
|
||||
"target" $heading
|
||||
"scratch" $.scratch
|
||||
)
|
||||
}}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,21 @@
|
||||
{{/* This utility is used to get the file path from absolute, relative path or URL. */}}
|
||||
|
||||
{{- $path := .path -}}
|
||||
{{- $page := .page -}}
|
||||
|
||||
{{- $isLocal := not (urls.Parse $path).Scheme -}}
|
||||
{{- $isPage := and (eq $page.Kind "page") (not $page.BundleType) -}}
|
||||
{{- $startsWithSlash := hasPrefix $path "/" -}}
|
||||
{{- $startsWithRelative := hasPrefix $path "../" -}}
|
||||
|
||||
{{- if and $path $isLocal -}}
|
||||
{{- if $startsWithSlash -}}
|
||||
{{/* File under static directory */}}
|
||||
{{- $path = (relURL (strings.TrimPrefix "/" $path)) -}}
|
||||
{{- else if and $isPage (not $startsWithRelative) -}}
|
||||
{{/* File is a sibling to the individual page file */}}
|
||||
{{ $path = (printf "../%s" $path) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- return $path -}}
|
||||
@@ -0,0 +1,3 @@
|
||||
{{- with . -}}
|
||||
{{- . | time.Format (site.Params.dateFormat | default ":date_long") -}}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,93 @@
|
||||
{{- /*
|
||||
fragments.html - Split page content into searchable fragments
|
||||
|
||||
This partial processes a Hugo page and splits its content into fragments based on headings,
|
||||
creating a data structure suitable for search indexing. It supports different fragment types
|
||||
and handles hierarchical heading structures (h1, h2).
|
||||
|
||||
Parameters:
|
||||
- .context (Page): The Hugo page to process
|
||||
- .type (string): Fragment type - "content" (default), "heading", "title", or "summary"
|
||||
|
||||
Returns:
|
||||
- dict: Map of heading keys to content fragments
|
||||
|
||||
Example:
|
||||
Input page with content:
|
||||
# Introduction
|
||||
This is the intro text.
|
||||
## Setup
|
||||
Setup instructions here.
|
||||
# Configuration
|
||||
Config details here.
|
||||
|
||||
Output (type "content"):
|
||||
{
|
||||
"": "This is the intro text.",
|
||||
"intro#Introduction": "This is the intro text. Setup instructions here.",
|
||||
"setup#Setup": "Setup instructions here.",
|
||||
"config#Configuration": "Config details here."
|
||||
}
|
||||
|
||||
Fragment types:
|
||||
- "content": Splits page content by headings (default)
|
||||
- "heading": Returns heading keys with empty content
|
||||
- "title": Returns empty content (title handled elsewhere)
|
||||
- "summary": Returns page summary only
|
||||
*/ -}}
|
||||
|
||||
{{- /* Extract page context and fragment type */ -}}
|
||||
{{- $page := .context -}}
|
||||
{{- $type := .type | default "content" -}}
|
||||
|
||||
{{- /* Process all headings */ -}}
|
||||
{{- $s := newScratch -}}
|
||||
{{- $s.Set "keys" slice -}}
|
||||
{{- $s.Set "titles" slice -}}
|
||||
|
||||
{{- partial "utils/extract-headings.html" (dict "target" $page.Fragments "scratch" $s) -}}
|
||||
|
||||
{{- $headingKeys := $s.Get "keys" -}}
|
||||
{{- $headingTitles := $s.Get "titles" -}}
|
||||
|
||||
{{- $content := $page.Content | htmlUnescape -}}
|
||||
{{- $len := len $headingKeys -}}
|
||||
{{- $data := dict -}}
|
||||
|
||||
{{ if eq $type "content" }}
|
||||
{{/* Include full content of the page */}}
|
||||
{{ if eq $len 0 }}
|
||||
{{ $data = $data | merge (dict "" ($page.Plain | htmlUnescape | strings.TrimSpace)) }}
|
||||
{{ else }}
|
||||
{{/* Split the raw content from bottom to top */}}
|
||||
{{ range seq $len }}
|
||||
{{ $i := sub $len . }}
|
||||
{{ $headingKey := index $headingKeys $i }}
|
||||
{{ $headingTitle := index $headingTitles $i }}
|
||||
|
||||
{{ if eq $i 0 }}
|
||||
{{ $data = $data | merge (dict $headingKey ($content | plainify | htmlUnescape | strings.TrimSpace)) }}
|
||||
{{ else }}
|
||||
{{ $parts := split $content (printf "%s" $headingTitle) }}
|
||||
{{ $lastPart := index $parts (sub (len $parts) 1) }}
|
||||
|
||||
{{ $data = $data | merge (dict $headingKey ($lastPart | plainify | htmlUnescape | strings.TrimSpace)) }}
|
||||
{{ $content = strings.TrimSuffix $lastPart $content }}
|
||||
{{ $content = strings.TrimSuffix (printf "%s" $headingTitle) $content }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ else if (eq $type "heading" ) }}
|
||||
{{/* Put heading keys with empty content to the data object */}}
|
||||
{{ $data = dict "" "" }}
|
||||
{{ range $headingKeys }}
|
||||
{{ $data = $data | merge (dict . "") }}
|
||||
{{ end }}
|
||||
{{ else if (eq $type "title") }}
|
||||
{{/* Use empty data object since title is included in search-data.json */}}
|
||||
{{ $data = $data | merge (dict "" "") }}
|
||||
{{ else if (eq $type "summary" ) }}
|
||||
{{ $data = $data | merge (dict "" ($page.Summary | plainify | htmlUnescape | strings.TrimSpace)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ return $data }}
|
||||
@@ -0,0 +1,15 @@
|
||||
{{/*
|
||||
Returns the language direction using the supported Hugo API for the running version.
|
||||
|
||||
Hugo v0.158.0 deprecated Language.LanguageDirection in favor of Language.Direction.
|
||||
Keep the fallback so Hextra can continue supporting Hugo >= 0.146.0.
|
||||
*/}}
|
||||
{{- $language := . -}}
|
||||
{{- $direction := "" -}}
|
||||
{{- if ge (hugo.Version) "0.158.0" -}}
|
||||
{{- $direction = $language.Direction -}}
|
||||
{{- else -}}
|
||||
{{- $direction = $language.LanguageDirection -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- return $direction -}}
|
||||
@@ -0,0 +1,15 @@
|
||||
{{/*
|
||||
Returns the language label using the supported Hugo API for the running version.
|
||||
|
||||
Hugo v0.158.0 deprecated Language.LanguageName in favor of Language.Label.
|
||||
Keep the fallback so Hextra can continue supporting Hugo >= 0.146.0.
|
||||
*/}}
|
||||
{{- $language := . -}}
|
||||
{{- $label := "" -}}
|
||||
{{- if ge (hugo.Version) "0.158.0" -}}
|
||||
{{- $label = $language.Label -}}
|
||||
{{- else -}}
|
||||
{{- $label = $language.LanguageName -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- return $label -}}
|
||||
@@ -0,0 +1,15 @@
|
||||
{{/*
|
||||
Returns the language locale using the supported Hugo API for the running version.
|
||||
|
||||
Hugo v0.158.0 deprecated Language.LanguageCode in favor of Language.Locale.
|
||||
Keep the fallback so Hextra can continue supporting Hugo >= 0.146.0.
|
||||
*/}}
|
||||
{{- $language := . -}}
|
||||
{{- $locale := "" -}}
|
||||
{{- if ge (hugo.Version) "0.158.0" -}}
|
||||
{{- $locale = $language.Locale -}}
|
||||
{{- else -}}
|
||||
{{- $locale = $language.LanguageCode -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- return $locale -}}
|
||||
@@ -0,0 +1,14 @@
|
||||
{{/*
|
||||
Returns site data using the supported Hugo API for the running version.
|
||||
|
||||
Hugo v0.156.0 deprecated site.Data / .Site.Data in favor of hugo.Data.
|
||||
Keep the fallback so Hextra can continue supporting Hugo >= 0.146.0.
|
||||
*/}}
|
||||
{{- $siteData := dict -}}
|
||||
{{- if ge (hugo.Version) "0.156.0" -}}
|
||||
{{- $siteData = hugo.Data -}}
|
||||
{{- else -}}
|
||||
{{- $siteData = site.Data -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- return $siteData -}}
|
||||
@@ -0,0 +1,14 @@
|
||||
{{/*
|
||||
Returns all sites using the supported Hugo API for the running version.
|
||||
|
||||
Hugo v0.156.0 deprecated site.Sites / page.Sites in favor of hugo.Sites.
|
||||
Keep the fallback so Hextra can continue supporting Hugo >= 0.146.0.
|
||||
*/}}
|
||||
{{- $sites := slice -}}
|
||||
{{- if ge (hugo.Version) "0.156.0" -}}
|
||||
{{- $sites = hugo.Sites -}}
|
||||
{{- else -}}
|
||||
{{- $sites = site.Sites -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- return $sites -}}
|
||||
@@ -0,0 +1,79 @@
|
||||
{{/* Render raw svg icon from site data */}}
|
||||
{{- $siteData := partial "utils/hugo-compat/site-data.html" . -}}
|
||||
{{- $name := .name -}}
|
||||
{{- $icon := index $siteData.icons $name -}}
|
||||
{{- $isRemoteIcon := false -}}
|
||||
|
||||
{{- if not $icon -}}
|
||||
{{- $remoteProvider := "" -}}
|
||||
{{- $remoteName := "" -}}
|
||||
{{- if strings.Contains $name ":" -}}
|
||||
{{- $parts := split $name ":" -}}
|
||||
{{- if eq (len $parts) 2 -}}
|
||||
{{- $remoteProvider = index $parts 0 -}}
|
||||
{{- $remoteName = index $parts 1 -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- if and $remoteProvider $remoteName -}}
|
||||
{{- $remoteEnabled := true -}}
|
||||
{{- $remoteProviders := dict
|
||||
"lucide" (dict "url" "https://unpkg.com/lucide-static@1/icons/%s.svg")
|
||||
"tabler" (dict "url" "https://unpkg.com/@tabler/icons@3/icons/outline/%s.svg")
|
||||
"simple" (dict "url" "https://cdn.jsdelivr.net/npm/simple-icons@16/icons/%s.svg")
|
||||
-}}
|
||||
{{- with site.Params.icons.remote -}}
|
||||
{{- if isset . "enable" -}}
|
||||
{{- $remoteEnabled = .enable -}}
|
||||
{{- end -}}
|
||||
{{- with .providers -}}
|
||||
{{- $remoteProviders = merge $remoteProviders . -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- if $remoteEnabled -}}
|
||||
{{- if not (findRE "^[A-Za-z0-9_-]+$" $remoteProvider) -}}
|
||||
{{- errorf "invalid remote icon provider %q" $remoteProvider -}}
|
||||
{{- end -}}
|
||||
{{- if or (in $remoteName "..") (not (findRE "^[A-Za-z0-9._/-]+$" $remoteName)) -}}
|
||||
{{- errorf "invalid remote icon name %q" $remoteName -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- with index $remoteProviders $remoteProvider -}}
|
||||
{{- $remoteUrl := printf .url $remoteName -}}
|
||||
{{- with try (resources.GetRemote $remoteUrl) -}}
|
||||
{{- with .Err -}}
|
||||
{{- errorf "Could not retrieve remote icon %q from %s. Reason: %s." $name $remoteUrl . -}}
|
||||
{{- else with .Value -}}
|
||||
{{- $icon = .Content -}}
|
||||
{{- $isRemoteIcon = true -}}
|
||||
{{- if and (not (strings.Contains $icon "fill=")) (not (strings.Contains $icon "stroke=")) -}}
|
||||
{{- $icon = replaceRE "<svg" `<svg fill="currentColor"` $icon -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- if not $icon -}}
|
||||
{{ errorf "icon %q not found" $name }}
|
||||
{{- end -}}
|
||||
|
||||
{{- $icon = $icon | safeHTML -}}
|
||||
|
||||
{{- if $isRemoteIcon -}}
|
||||
{{- $icon = replaceRE `(<svg[^>]*?)\sclass=("[^"]*"|'[^']*'|[^\s>]+)` `$1` $icon -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- if .attributes -}}
|
||||
{{- $attributes := .attributes -}}
|
||||
{{- if $isRemoteIcon -}}
|
||||
{{- $icon = replaceRE `(<svg[^>]*?)\swidth=("[^"]*"|'[^']*'|[^\s>]+)` `$1` $icon -}}
|
||||
{{- $icon = replaceRE `(<svg[^>]*?)\sheight=("[^"]*"|'[^']*'|[^\s>]+)` `$1` $icon -}}
|
||||
{{- end -}}
|
||||
{{- $icon = replaceRE "<svg" (printf "<svg %s" $attributes) $icon -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- return ($icon | safeHTML) -}}
|
||||
@@ -0,0 +1,25 @@
|
||||
{{/* Get relative link of a page for given language */}}
|
||||
{{/* If not found, return the homepage of the language page */}}
|
||||
|
||||
{{ $page := .context }}
|
||||
{{ $lang := .lang }}
|
||||
|
||||
{{ $link := false }}
|
||||
|
||||
{{ range $page.AllTranslations }}
|
||||
{{ if eq .Language.Lang $lang }}
|
||||
{{ $link = .RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not $link }}
|
||||
{{ range where (partial "utils/hugo-compat/sites.html" .) ".Language.Lang" $lang }}
|
||||
{{ $link = .Home.RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not $link }}
|
||||
{{ $link = site.Home.RelPermalink }}
|
||||
{{ end }}
|
||||
|
||||
{{ return $link }}
|
||||
@@ -0,0 +1,11 @@
|
||||
{{ with .Description | plainify | htmlUnescape -}}
|
||||
{{ . -}}
|
||||
{{ else -}}
|
||||
{{ if .IsHome -}}
|
||||
{{ with .Site.Params.description | plainify | htmlUnescape -}}
|
||||
{{ . -}}
|
||||
{{ end -}}
|
||||
{{ else -}}
|
||||
{{ .Summary | plainify | htmlUnescape | chomp -}}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
@@ -0,0 +1,10 @@
|
||||
{{- with .Params.width -}}
|
||||
{{- $pageWidthValues := dict "normal" "80rem" "wide" "90rem" "full" "100%" -}}
|
||||
{{- $pageWidth := . -}}
|
||||
{{- $maxPageWidth := (index $pageWidthValues $pageWidth) | default (index $pageWidthValues "normal") -}}
|
||||
<style>
|
||||
:root {
|
||||
--hextra-max-page-width: {{ $maxPageWidth }};
|
||||
}
|
||||
</style>
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,32 @@
|
||||
{{- $page := .page -}}
|
||||
{{- $by := .by | default "weight" -}}
|
||||
{{- $order := .order | default "asc" -}}
|
||||
|
||||
{{- $pages := slice }}
|
||||
|
||||
{{- if eq $by "weight" }}
|
||||
{{- $pages = $page.Pages.ByWeight }}
|
||||
{{- else if eq $by "date" }}
|
||||
{{- $pages = $page.Pages.ByDate }}
|
||||
{{- else if eq $by "title" }}
|
||||
{{- $pages = $page.Pages.ByTitle }}
|
||||
{{- else if eq $by "expiryDate" }}
|
||||
{{- $pages = $page.Pages.ByExpiryDate }}
|
||||
{{- else if eq $by "publishDate" }}
|
||||
{{- $pages = $page.Pages.ByPublishDate }}
|
||||
{{- else if eq $by "lastmod" }}
|
||||
{{- $pages = $page.Pages.ByLastmod }}
|
||||
{{- else if eq $by "linkTitle" }}
|
||||
{{- $pages = $page.Pages.ByLinkTitle }}
|
||||
{{- else if eq $by "length" }}
|
||||
{{- $pages = $page.Pages.ByLength }}
|
||||
{{- else }}
|
||||
{{- warnf "sort-pages: unknown sort field %q" $by -}}
|
||||
{{- $pages = $page.Pages }}
|
||||
{{ end -}}
|
||||
|
||||
{{- if eq $order "desc" }}
|
||||
{{- $pages = $pages.Reverse }}
|
||||
{{- end -}}
|
||||
|
||||
{{- return $pages -}}
|
||||
@@ -0,0 +1,18 @@
|
||||
{{/*
|
||||
This utility replaces placeholders in a URL template string.
|
||||
|
||||
Usage:
|
||||
{{ partial "utils/template-url.html" (dict "template" .url "values" (dict "url" $pageURL "title" $pageTitle "markdown_url" $markdownURL)) }}
|
||||
|
||||
Placeholders use the format {key} and values are URL-encoded automatically.
|
||||
*/}}
|
||||
{{- $template := .template -}}
|
||||
{{- $values := .values | default dict -}}
|
||||
|
||||
{{- range $key, $value := $values -}}
|
||||
{{- $placeholder := printf "{%s}" $key -}}
|
||||
{{- $encoded := $value | urlquery -}}
|
||||
{{- $template = replace $template $placeholder $encoded -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- return $template -}}
|
||||
@@ -0,0 +1,19 @@
|
||||
{{/*
|
||||
This utility is used to retrieve the title of a page or section.
|
||||
If no title is set, it falls back to using the directory or file name.
|
||||
|
||||
Based on https://github.com/thegeeklab/hugo-geekdoc/blob/v0.44.0/layouts/partials/utils/title.html
|
||||
*/}}
|
||||
{{- $title := "" }}
|
||||
|
||||
{{ if .LinkTitle }}
|
||||
{{ $title = .LinkTitle }}
|
||||
{{ else if .Title }}
|
||||
{{ $title = .Title }}
|
||||
{{ else if and .IsSection .File }}
|
||||
{{ $title = path.Base .File.Dir | humanize | title }}
|
||||
{{ else if and .IsPage .File }}
|
||||
{{ $title = .File.BaseFileName | humanize | title }}
|
||||
{{ end }}
|
||||
|
||||
{{ return $title -}}
|
||||
Reference in New Issue
Block a user