refactor: use "sidebar-tree" for entire rendering

chore: update example site content

chore: add configuration for footer

chore: allow disable footer completely

chore: navbar highlights if contains current page

chore: styling update for partial templates

chore: update steps to use markdown delimiter
This commit is contained in:
Xin
2023-08-14 21:56:26 +01:00
parent 7a2cca9181
commit ed14432f77
15 changed files with 178 additions and 140 deletions

View File

@ -4,20 +4,22 @@
<footer class="hextra-footer bg-gray-100 pb-[env(safe-area-inset-bottom)] dark:bg-neutral-900 print:bg-transparent">
{{- if $enableFooterSwitches }}
<div class="mx-auto flex max-w-[90rem] gap-2 py-2 px-4">
{{ partial "language-switch.html" (dict "context" .) }}
{{ partial "theme-toggle.html" }}
{{- partial "language-switch.html" (dict "context" .) -}}
{{- partial "theme-toggle.html" -}}
</div>
{{ end -}}
<hr class="dark:border-neutral-800" />
<div class="mx-auto flex max-w-[90rem] justify-center py-12 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)] text-gray-600 dark:text-gray-400 md:justify-start">
<div class="flex w-full flex-col items-center sm:items-start">
<div>
<a class="flex items-center gap-1 text-current" target="_blank" rel="noopener noreferrer" title="Hugo homepage" href="https://gohugo.io/">
<span>Powered by</span>
{{ partial "utils/icon.html" (dict "name" "hugo-full" "attributes" "height=20") }}
</a>
</div>
<p class="mt-6 text-xs">© 2023 Hextra Project.</p>
{{- if .Site.Params.footer.displayPoweredBy }}<div class="font-semibold">{{ template "theme-credit" . }}</div>{{ end -}}
{{- if .Site.Params.footer.displayCopyright }}<p class="mt-6 text-xs">{{ i18n "footer.copyright" }}</p>{{ end -}}
</div>
</div>
</footer>
{{- define "theme-credit" -}}
<a class="flex items-center gap-1 text-current" target="_blank" rel="noopener noreferrer" title="Hextra homepage" href="https://github.com/imfing/hextra">
<span class="mr-1">Powered by Hextra</span>
{{- partial "utils/icon.html" (dict "name" "hextra" "attributes" "height=1em") -}}
</a>
{{- end -}}

View File

@ -15,7 +15,7 @@
{{ range site.Languages }}
{{ $link := partial "utils/lang-link" (dict "lang" .Lang "context" $page) }}
<li class="flex flex-col">
<a href="{{ $link }}" class="text-gray-800 dark:text-gray-100 hover:bg-primary-50 hover:text-primary-600 relative cursor-pointer whitespace-nowrap py-1.5 transition-colors ltr:pl-3 ltr:pr-9 rtl:pr-3 rtl:pl-9">
<a href="{{ $link }}" class="text-gray-800 dark:text-gray-100 hover:bg-primary-50 hover:text-primary-600 hover:dark:bg-primary-500/10 hover:dark:text-primary-600 relative cursor-pointer whitespace-nowrap py-1.5 transition-colors ltr:pl-3 ltr:pr-9 rtl:pr-3 rtl:pl-9">
{{- .LanguageName -}}
{{- if eq .LanguageName site.Language.LanguageName -}}
<span class="absolute inset-y-0 flex items-center ltr:right-3 rtl:left-3">

View File

@ -5,36 +5,39 @@
<a class="flex items-center hover:opacity-75 ltr:mr-auto rtl:ml-auto" href="{{ .Site.Home.RelPermalink }}">
{{ partial "utils/icon.html" (dict "name" "hextra" "attributes" "height=20") }}
<span class="mx-2 font-extrabold hidden md:inline select-none" title="{{ .Site.Title }}">
{{ .Site.Title }}
{{- .Site.Title -}}
</span>
</a>
{{- $currentPage := . -}}
{{- range .Site.Menus.main -}}
{{- if eq .Params.type "search" -}}
{{ partial "search.html" (dict "params" .Params) }}
{{- partial "search.html" (dict "params" .Params) -}}
{{- else -}}
{{ $external := strings.HasPrefix .URL "http" }}
{{- $external := strings.HasPrefix .URL "http" -}}
{{/* Display icon menu item */}}
{{- if .Params.icon -}}
<a class="p-2 text-current" {{ if $external }}target="_blank" rel="noreferer"{{ end }} href="{{ .URL | safeURL }}">
{{ partial "utils/icon.html" (dict "name" .Params.icon "attributes" "height=24") }}
{{- partial "utils/icon.html" (dict "name" .Params.icon "attributes" "height=24") -}}
<span class="sr-only">{{ .Name }}</span>
</a>
{{- else -}}
{{- $active := or ($currentPage.HasMenuCurrent "main" .) ($currentPage.IsMenuCurrent "main" .) -}}
{{- $activeClass := cond $active "font-medium" "text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200" -}}
<a
href="{{ .URL | safeURL }}"
{{ if $external }}target="_blank" rel="noreferer"{{ end }}
class="text-sm contrast-more:text-gray-700 contrast-more:dark:text-gray-100 relative -ml-2 hidden whitespace-nowrap p-2 md:inline-block text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200"
class="text-sm contrast-more:text-gray-700 contrast-more:dark:text-gray-100 relative -ml-2 hidden whitespace-nowrap p-2 md:inline-block {{ $activeClass }}"
>
<span class="text-center">{{ .Name }}</span>
</a>
{{- end -}}
{{ end }}
{{ end }}
{{- end -}}
{{- end -}}
<button type="button" aria-label="Menu" class="hamburger-menu -mr-2 rounded p-2 active:bg-gray-400/20 md:hidden">
{{ partial "utils/icon.html" (dict "name" "menu" "attributes" "height=24") }}
{{- partial "utils/icon.html" (dict "name" "menu" "attributes" "height=24") -}}
</button>
</nav>
</div>

View File

@ -1,30 +1,30 @@
{{ $jsTheme := resources.Get "js/theme.js" }}
{{ $jsMenu := resources.Get "js/menu.js" }}
{{ $jsCodeCopy := resources.Get "js/code-copy.js" }}
{{ $jsTabs := resources.Get "js/tabs.js" }}
{{ $jsLang := resources.Get "js/lang.js" }}
{{- $jsTheme := resources.Get "js/theme.js" -}}
{{- $jsMenu := resources.Get "js/menu.js" -}}
{{- $jsCodeCopy := resources.Get "js/code-copy.js" -}}
{{- $jsTabs := resources.Get "js/tabs.js" -}}
{{- $jsLang := resources.Get "js/lang.js" -}}
{{ $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang | resources.Concat "js/main.js" }}
{{ if hugo.IsProduction }}
{{ $scripts = $scripts | minify | fingerprint }}
{{ end }}
{{- $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang | resources.Concat "js/main.js" -}}
{{- if hugo.IsProduction -}}
{{- $scripts = $scripts | minify | fingerprint -}}
{{- end -}}
<script defer src="{{ $scripts.RelPermalink }}" integrity="{{ $scripts.Data.Integrity }}"></script>
{{/* FlexSearch */}}
{{- if not site.Params.search.disabled -}}
{{ $jsSearchScript := printf "%s.search.js" .Language.Lang }}
{{ $jsSearch := resources.Get "js/flexsearch.js" | resources.ExecuteAsTemplate $jsSearchScript . }}
{{ if hugo.IsProduction }}
{{ $jsSearch = $jsSearch | minify | fingerprint }}
{{ end }}
{{ $flexSearchJS := resources.Get "vendor/flexsearch/flexsearch.bundle.min.js" | fingerprint }}
{{- $jsSearchScript := printf "%s.search.js" .Language.Lang -}}
{{- $jsSearch := resources.Get "js/flexsearch.js" | resources.ExecuteAsTemplate $jsSearchScript . -}}
{{- if hugo.IsProduction -}}
{{- $jsSearch = $jsSearch | minify | fingerprint -}}
{{- end -}}
{{- $flexSearchJS := resources.Get "vendor/flexsearch/flexsearch.bundle.min.js" | fingerprint -}}
<script defer src="{{ $flexSearchJS.RelPermalink }}" integrity="{{ $flexSearchJS.Data.Integrity }}"></script>
<script defer src="{{ $jsSearch.RelPermalink }}" integrity="{{ $jsSearch.Data.Integrity }}"></script>
{{- end -}}
{{/* Mermaid */}}
{{ if .Page.Store.Get "hasMermaid" -}}
{{ $mermaidJS := resources.Get "vendor/mermaid/mermaid.min.js" | fingerprint }}
{{- if .Page.Store.Get "hasMermaid" -}}
{{- $mermaidJS := resources.Get "vendor/mermaid/mermaid.min.js" | fingerprint -}}
<script defer src="{{ $mermaidJS.RelPermalink }}" integrity="{{ $mermaidJS.Data.Integrity }}"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
@ -32,20 +32,20 @@
mermaid.initialize({ startOnLoad: true, theme: theme });
});
</script>
{{ end }}
{{- end -}}
{{/* KaTex */}}
{{ if and (not site.Params.math.disabled) .Page.Params.math }}
{{ $katexCSS := resources.Get "vendor/katex/katex.min.css" | fingerprint }}
{{ $katexJS := resources.Get "vendor/katex/katex.min.js" | fingerprint }}
{{ $katexAutoRenderJS := resources.Get "vendor/katex/auto-render.min.js" | fingerprint }}
{{- if and (not site.Params.math.disabled) .Page.Params.math -}}
{{- $katexCSS := resources.Get "vendor/katex/katex.min.css" | fingerprint -}}
{{- $katexJS := resources.Get "vendor/katex/katex.min.js" | fingerprint -}}
{{- $katexAutoRenderJS := resources.Get "vendor/katex/auto-render.min.js" | fingerprint -}}
<link type="text/css" rel="stylesheet" href="{{ $katexCSS.RelPermalink }}" integrity="{{ $katexCSS.Data.Integrity }}" />
<script defer src="{{ $katexJS.RelPermalink }}" integrity="{{ $katexJS.Data.Integrity }}"></script>
<script defer src="{{ $katexAutoRenderJS.RelPermalink }}" integrity="{{ $katexAutoRenderJS.Data.Integrity }}"></script>
{{ $katexFonts := resources.Match "vendor/katex/fonts/*" }}
{{ range $katexFonts }}
{{- range $katexFonts -}}
{{ .Publish }}
{{ end }}
{{- end -}}
<script>
// TODO: make render options configurable
document.addEventListener("DOMContentLoaded", function () {

View File

@ -1,10 +1,10 @@
{{ $context := .context }}
{{ $disableSidebar := .disableSidebar | default false }}
{{ $sidebarClass := cond $disableSidebar "md:hidden xl:block" "md:sticky" }}
{{- $context := .context -}}
{{- $disableSidebar := .disableSidebar | default false -}}
{{- $sidebarClass := cond $disableSidebar "md:hidden xl:block" "md:sticky" -}}
{{ $navRoot := cond (eq site.Home.Type "docs") site.Home $context.FirstSection }}
{{ $navPages := union $navRoot.RegularPages $navRoot.Sections }}
{{ $pageURL := $context.RelPermalink }}
{{- $navRoot := cond (eq site.Home.Type "docs") site.Home $context.FirstSection -}}
{{- $navPages := union $navRoot.RegularPages $navRoot.Sections -}}
{{- $pageURL := $context.RelPermalink -}}
<aside class="sidebar-container flex flex-col print:hidden md:top-16 md:shrink-0 md:w-64 md:self-start max-md:[transform:translate3d(0,-100%,0)] {{ $sidebarClass }}">
@ -15,13 +15,13 @@
<div class="overflow-y-auto overflow-x-hidden p-4 grow md:h-[calc(100vh-var(--navbar-height)-var(--menu-height))]">
<ul class="flex flex-col gap-1 md:hidden">
<!-- Nav -->
{{- range site.Menus.main -}}
{{- range site.Menus.main }}
{{- if and .URL (and (ne .Params.type "search") (not .Params.icon)) -}}
<li>{{ template "sidebar-item-link" dict "active" false "title" .Name "link" .URL }}</li>
{{- end -}}
{{- end -}}
{{ template "sidebar-separator" }}
{{ template "sidebar-main" (dict "pages" $navPages "pageURL" $pageURL "toc" true) }}
{{ template "sidebar-separator" -}}
{{ template "sidebar-main" (dict "context" $navRoot "pageURL" $pageURL "toc" true) -}}
<!-- Sidebar footer -->
@ -32,15 +32,15 @@
</ul>
<!-- Sidebar on large screen -->
{{ if $disableSidebar -}}
{{- if $disableSidebar }}
<div class="max-xl:hidden h-0 w-64 shrink-0"></div>
{{ .context.Scratch.Set "enableFooterSwitches" true }}
{{ else }}
{{- else -}}
<ul class="flex flex-col gap-1 max-md:hidden">
{{ template "sidebar-main" (dict "pages" $navPages "pageURL" $pageURL) }}
{{ template "sidebar-main" (dict "context" $navRoot "pageURL" $pageURL) }}
{{ template "sidebar-footer" }}
</ul>
{{ end }}
{{ end -}}
</div>
{{/* Hide theme switch when sidebar is disabled */}}
{{ $switchesClass := cond $disableSidebar "md:hidden" "" }}
@ -51,57 +51,54 @@
</aside>
{{- define "sidebar-main" -}}
{{ $pages := .pages }}
{{ $context := .context }}
{{ $toc := .toc | default false }}
{{ $pageURL := .pageURL }}
{{- with $pages -}}
{{- range .ByWeight -}}
{{ template "sidebar-item" (dict "item" . "pageURL" $pageURL "toc" $toc) }}
{{ template "sidebar-tree" (dict "context" . "level" 1 "pageURL" $pageURL "toc" $toc) }}
{{- end -}}
{{ end }}
{{- end -}}
{{- define "sidebar-footer" -}}
{{- range site.Menus.sidebar -}}
{{ if eq .Params.type "separator" }}
<li class="[word-break:break-word] mt-5 mb-2 px-2 py-1.5 text-sm font-semibold text-gray-900 first:mt-0 dark:text-gray-100">
<span class="cursor-default">{{ .Name }}</span>
</li>
{{ else }}
<li>{{ template "sidebar-item-link" dict "active" false "title" .Name "link" .URL }}</li>
{{ end }}
{{- end -}}
{{ template "sidebar-tree" (dict "context" $context "level" 0 "pageURL" $pageURL "toc" $toc) }}
{{- end -}}
{{- define "sidebar-tree" -}}
{{ $pageURL := .pageURL }}
{{ $level := .level }}
{{ $toc := .toc | default false }}
{{- if ge .level 4 -}}
{{- return -}}
{{- end -}}
{{ if ge $level 4 }}
{{ return }}
{{ end }}
{{- $context := .context -}}
{{- $pageURL := .pageURL -}}
{{- $level := .level -}}
{{- $toc := .toc | default false -}}
{{ $items := union .context.RegularPages .context.Sections }}
{{ with $items }}
<div class="pt-1 ltr:pr-0">
<ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'>
{{ range $items.ByWeight }}
{{ $active := eq $pageURL .RelPermalink }}
{{ $title := .LinkTitle | default .File.BaseFileName }}
<li class="flex flex-col gap-1">
{{ template "sidebar-item-link" dict "active" $active "title" $title "link" .RelPermalink }}
{{ if and $toc $active }}
{{ template "sidebar-toc" dict "page" . }}
{{ end }}
</li>
{{ template "sidebar-tree" dict "context" . "pageURL" $pageURL "level" (add $level 1) }}
{{ end }}
</ul>
</div>
{{ end }}
{{- $items := union .context.RegularPages .context.Sections -}}
{{- with $items -}}
{{- if eq $level 0 -}}
{{- range $items.ByWeight }}
{{- $active := eq $pageURL .RelPermalink -}}
<li class="open">
{{- template "sidebar-item-link" dict "context" . "active" $active "title" .LinkTitle "link" .RelPermalink -}}
{{- if and $toc $active -}}
{{- template "sidebar-toc" dict "page" . -}}
{{- end -}}
{{- template "sidebar-tree" dict "context" . "pageURL" $pageURL "level" (add $level 1) -}}
</li>
{{- end -}}
{{- else -}}
<div class="pt-1 ltr:pr-0">
<ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'>
{{- range $items.ByWeight }}
{{- $active := eq $pageURL .RelPermalink -}}
{{- $title := .LinkTitle | default .File.BaseFileName -}}
<li class="flex flex-col gap-1">
{{- template "sidebar-item-link" dict "context" . "active" $active "title" $title "link" .RelPermalink -}}
{{- if and $toc $active -}}
{{ template "sidebar-toc" dict "page" . }}
{{- end }}
{{ template "sidebar-tree" dict "context" . "pageURL" $pageURL "level" (add $level 1) }}
</li>
{{- end -}}
</ul>
</div>
{{- end -}}
{{- end }}
{{- end -}}
{{- define "sidebar-toc" -}}
@ -126,13 +123,23 @@
{{ end }}
{{- end -}}
{{- define "sidebar-footer" -}}
{{- range site.Menus.sidebar -}}
{{ if eq .Params.type "separator" }}
<li class="[word-break:break-word] mt-5 mb-2 px-2 py-1.5 text-sm font-semibold text-gray-900 first:mt-0 dark:text-gray-100">
<span class="cursor-default">{{ .Name }}</span>
</li>
{{ else }}
<li>{{ template "sidebar-item-link" dict "active" false "title" .Name "link" .URL }}</li>
{{ end }}
{{- end -}}
{{- end -}}
{{- define "sidebar-item" }}
{{- $active := eq .pageURL .item.RelPermalink -}}
{{- $title := .item.LinkTitle | default .item.File.BaseFileName -}}
{{- $link := .item.RelPermalink -}}
{{- $toc := .toc | default false -}}
<li class="open">
{{ template "sidebar-item-link" dict "active" $active "title" $title "link" $link }}
{{ if and $toc $active }}
@ -144,7 +151,7 @@
{{- define "sidebar-item-link" -}}
{{ $external := strings.HasPrefix .link "http" }}
<a
class="flex cursor-pointer rounded px-2 py-1.5 text-sm transition-colors [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] [word-break:break-word]
class="flex items-center justify-between gap-2 cursor-pointer rounded px-2 py-1.5 text-sm transition-colors [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] [word-break:break-word]
{{- if .active }}
bg-primary-100 font-semibold text-primary-800 contrast-more:border contrast-more:border-primary-500 dark:bg-primary-400/10 dark:text-primary-600 contrast-more:dark:border-primary-500
{{- else }}

View File

@ -5,23 +5,21 @@
<nav class="hextra-toc order-last hidden w-64 shrink-0 xl:block print:hidden px-4" aria-label="table of contents">
{{ if $toc }}
{{- if $toc }}
<div class="sticky top-16 overflow-y-auto pr-4 pt-6 text-sm [hyphens:auto] max-h-[calc(100vh-4rem-env(safe-area-inset-bottom))] ltr:-mr-4 rtl:-ml-4">
{{ with .Fragments.Headings }}
{{- with .Fragments.Headings -}}
<p class="mb-4 font-semibold tracking-tight">{{ i18n "article.on_this_page" }}</p>
{{ range . }}
{{- range . -}}
<ul>
{{ with .Headings }}
{{ template "toc-subheading" (dict "headings" . "level" 0) }}
{{ end }}
{{- with .Headings -}}{{ template "toc-subheading" (dict "headings" . "level" 0) }}{{- end -}}
</ul>
{{ end }}
{{ end }}
{{- end -}}
{{- end -}}
{{ $borderClass := "mt-8 border-t bg-white pt-8 shadow-[0_-12px_16px_white] dark:bg-dark dark:shadow-[0_-12px_16px_#111]" }}
{{ if not .Fragments.Headings }}
{{ $borderClass = "" }}
{{ end }}
{{- $borderClass := "mt-8 border-t bg-white pt-8 shadow-[0_-12px_16px_white] dark:bg-dark dark:shadow-[0_-12px_16px_#111]" -}}
{{- if not .Fragments.Headings -}}
{{- $borderClass = "" -}}
{{- end -}}
{{/* TOC bottom part */}}
<div class="{{ $borderClass }} sticky bottom-0 flex flex-col items-start gap-2 pb-8 dark:border-neutral-800 contrast-more:border-t contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:border-neutral-400">
@ -33,31 +31,31 @@
{{- end -}}
</div>
</div>
{{ end }}
{{ end -}}
</nav>
{{/* TOC subheadings component. This is a recursive component that renders a list of headings. */}}
{{- define "toc-subheading" -}}
{{ $headings := .headings }}
{{ $level := .level }}
{{ if ge $level 6 }}
{{- $headings := .headings -}}
{{- $level := .level -}}
{{- if ge $level 6 -}}
{{ return }}
{{ end }}
{{- end -}}
{{ $padding := (mul $level 4) }}
{{ $class := cond (eq $level 0) "font-semibold" (printf "ltr:pl-%d rtl:pr-%d" $padding $padding) }}
{{- $padding := (mul $level 4) -}}
{{- $class := cond (eq $level 0) "font-semibold" (printf "ltr:pl-%d rtl:pr-%d" $padding $padding) -}}
{{ range $headings }}
{{ if .Title }}
{{- range $headings }}
{{- if .Title }}
<li class="my-2 scroll-my-6 scroll-py-6">
<a class="{{ $class }} inline-block text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-300 contrast-more:text-gray-900 contrast-more:underline contrast-more:dark:text-gray-50 w-full break-words" href="#{{ anchorize .ID }}">
{{ .Title }}
{{- .Title -}}
</a>
</li>
{{ end }}
{{ with .Headings }}
{{- end -}}
{{- with .Headings -}}
{{ template "toc-subheading" (dict "headings" . "level" (add $level 1)) }}
{{ end }}
{{- end -}}
{{ end }}
{{- end -}}
{{- end -}}