First commit
Delete exampleSite Add initial content, images & docker-compose.yml Use extend-head.html for analytics Set remote url to gitea.novicelab.io
This commit is contained in:
11
layouts/partials/analytics/fathom.html
Normal file
11
layouts/partials/analytics/fathom.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{{ if isset site.Params.fathomAnalytics "domain" }}
|
||||
<script
|
||||
defer
|
||||
src="https://{{ site.Params.fathomAnalytics.domain }}/script.js"
|
||||
data-site="{{ site.Params.fathomAnalytics.site }}"></script>
|
||||
{{ else }}
|
||||
<script
|
||||
defer
|
||||
src="https://cdn.usefathom.com/script.js"
|
||||
data-site="{{ site.Params.fathomAnalytics.site }}"></script>
|
||||
{{ end }}
|
||||
10
layouts/partials/analytics/ga.html
Normal file
10
layouts/partials/analytics/ga.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<script
|
||||
async
|
||||
src="https://www.googletagmanager.com/gtag/js?id={{ site.Config.Services.GoogleAnalytics.ID }}"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', '{{ site.Config.Services.GoogleAnalytics.ID }}');
|
||||
</script>
|
||||
12
layouts/partials/analytics/main.html
Normal file
12
layouts/partials/analytics/main.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{{ if site.Params.fathomAnalytics.site }}
|
||||
{{ partial "analytics/fathom.html" . }}
|
||||
{{ end }}
|
||||
{{ if site.Config.Services.GoogleAnalytics.ID }}
|
||||
{{ partial "analytics/ga.html" . }}
|
||||
{{ end }}
|
||||
{{ if site.Params.umamiAnalytics.websiteid }}
|
||||
{{ partial "analytics/umami.html" . }}
|
||||
{{ end }}
|
||||
{{ if site.Params.selineAnalytics.token }}
|
||||
{{ partial "analytics/seline.html" . }}
|
||||
{{ end }}
|
||||
21
layouts/partials/analytics/seline.html
Normal file
21
layouts/partials/analytics/seline.html
Normal file
@@ -0,0 +1,21 @@
|
||||
<script
|
||||
async
|
||||
src="https://cdn.seline.so/seline.js"
|
||||
data-token="{{ site.Params.selineAnalytics.token }}"
|
||||
data-id="seline-script"></script>
|
||||
|
||||
{{ if .Site.Params.selineAnalytics.enableTrackEvent | default true }}
|
||||
<script type="text/javascript">
|
||||
document.querySelector('script[data-id="seline-script"]').addEventListener("load", function () {
|
||||
const type = document.head.querySelector('meta[property = "og:type"]').getAttribute("content");
|
||||
let title = document.head.querySelector('meta[property = "og:title"]').getAttribute("content");
|
||||
let url = document.head.querySelector('meta[property = "og:url"]').getAttribute("content");
|
||||
|
||||
seline.track("user:" + type + ":" + title, {
|
||||
type: type,
|
||||
title: title,
|
||||
url: url,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{{ end }}
|
||||
27
layouts/partials/analytics/umami.html
Normal file
27
layouts/partials/analytics/umami.html
Normal file
@@ -0,0 +1,27 @@
|
||||
{{/* prettier-ignore-start */}}
|
||||
{{ if isset site.Params.umamiAnalytics "domain" }}
|
||||
<script
|
||||
data-id="umami-script"
|
||||
async
|
||||
src="https://{{ site.Params.umamiAnalytics.domain }}/{{ with site.Params.umamiAnalytics.scriptName }}{{ . }}{{ else }}script.js{{ end }}"
|
||||
data-website-id="{{ site.Params.umamiAnalytics.websiteid }}"
|
||||
{{ with site.Params.umamiAnalytics.dataDomains }}data-domains="{{ . }}"{{ end }}></script>
|
||||
{{ else }}
|
||||
<script
|
||||
data-id="umami-script"
|
||||
async
|
||||
src="https://analytics.umami.is/script.js"
|
||||
data-website-id="{{ site.Params.umamiAnalytics.websiteid }}"></script>
|
||||
{{ end }}
|
||||
{{/* prettier-ignore-end */}}
|
||||
|
||||
{{ if .Site.Params.umamiAnalytics.enableTrackEvent | default true }}
|
||||
<script type="text/javascript">
|
||||
document.querySelector('script[data-id="umami-script"]').addEventListener("load", function () {
|
||||
const type = document.head.querySelector('meta[property = "og:type"]').getAttribute("content");
|
||||
let title = document.head.querySelector('meta[property = "og:title"]').getAttribute("content");
|
||||
let url = document.head.querySelector('meta[property = "og:url"]').getAttribute("content");
|
||||
umami.track(type + ":" + title, { url: url });
|
||||
});
|
||||
</script>
|
||||
{{ end }}
|
||||
135
layouts/partials/article-link/_shortcode.html
Normal file
135
layouts/partials/article-link/_shortcode.html
Normal file
@@ -0,0 +1,135 @@
|
||||
{{/* Used by
|
||||
1. article shortcode
|
||||
|
||||
The four variants of article-link are very similar. Despite appearances, as of df859f:
|
||||
- _shortcode.html uses $page := $target, while the others use $page := .Page
|
||||
- card-related.html does not have the hideFeatureImage option, while the others do
|
||||
|
||||
$page is added intentionally to prevent small differences inside
|
||||
*/}}
|
||||
{{ $target := .target }}
|
||||
{{ $shortcodeShowSummary := .showSummary }}
|
||||
{{ $shortcodeCompactSummary := .compactSummary }}
|
||||
{{ $constrainItemsWidth := site.Params.list.constrainItemsWidth | default false }}
|
||||
{{ $disableImageOptimization := site.Store.Get "disableImageOptimization" }}
|
||||
|
||||
{{ $cardClasses := "flex flex-col md:flex-row relative" }}
|
||||
{{ $imgWrapperClasses := "" }}
|
||||
{{ $cardContentClasses := "" }}
|
||||
|
||||
{{ if site.Params.list.showCards }}
|
||||
{{ $cardClasses = printf "%s overflow-hidden rounded-lg border border-neutral-300 dark:border-neutral-600" $cardClasses }}
|
||||
{{ $imgWrapperClasses = "" }}
|
||||
{{ $cardContentClasses = printf "%s p-4 pt-2" $cardContentClasses }}
|
||||
{{ else }}
|
||||
{{ $cardClasses = printf "%s" $cardClasses }}
|
||||
{{ $imgWrapperClasses = printf "%s thumbnail-shadow md:mr-7" $imgWrapperClasses }}
|
||||
{{ $cardContentClasses = printf "%s mt-3 md:mt-0" $cardContentClasses }}
|
||||
{{ end }}
|
||||
|
||||
{{ if $constrainItemsWidth }}
|
||||
{{ $cardClasses = printf "%s max-w-prose" $cardClasses }}
|
||||
{{ end }}
|
||||
|
||||
{{ $page := $target }}
|
||||
{{ $featured := "" }}
|
||||
{{ $featuredURL := "" }}
|
||||
{{ if not $target.Params.hideFeatureImage }}
|
||||
{{/* frontmatter */}}
|
||||
{{ with $page }}
|
||||
{{ with .Params.featureimage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $featuredURL = . }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* page resources */}}
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $images := .Resources.ByType "image" }}
|
||||
{{ range slice "*feature*" "*cover*" "*thumbnail*" }}
|
||||
{{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* fallback to default */}}
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $default := site.Store.Get "defaultFeaturedImage" }}
|
||||
{{ if $default.url }}
|
||||
{{ $featuredURL = $default.url }}
|
||||
{{ else if $default.obj }}
|
||||
{{ $featured = $default.obj }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* generate image URL if not hotlink */}}
|
||||
{{ if not $featuredURL }}
|
||||
{{ with $featured }}
|
||||
{{ $featuredURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $featuredURL = (.Resize "600x").RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<article class="article-link--shortcode {{ $cardClasses }}">
|
||||
{{ with $featuredURL }}
|
||||
<div class="flex-none relative overflow-hidden {{ $imgWrapperClasses }} thumbnail">
|
||||
<img
|
||||
src="{{ . }}"
|
||||
role="presentation"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="not-prose absolute inset-0 w-full h-full object-cover">
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="{{ $cardContentClasses }}">
|
||||
<header class="items-center text-start text-xl font-semibold">
|
||||
<a
|
||||
{{ with $page.Params.externalUrl }}
|
||||
href="{{ . }}" target="_blank" rel="external"
|
||||
{{ else }}
|
||||
href="{{ $page.RelPermalink }}"
|
||||
{{ end }}
|
||||
class="not-prose before:absolute before:inset-0 decoration-primary-500 dark:text-neutral text-xl font-bold text-neutral-800 hover:underline hover:underline-offset-2">
|
||||
<h2>
|
||||
{{ $target.Title | emojify }}
|
||||
{{ if $target.Params.externalUrl }}
|
||||
<span class="cursor-default align-top text-xs text-neutral-400 dark:text-neutral-500">
|
||||
<span class="rtl:hidden">↗</span>
|
||||
<span class="ltr:hidden">↖</span>
|
||||
</span>
|
||||
{{ end }}
|
||||
</h2>
|
||||
</a>
|
||||
{{ if and $target.Draft site.Params.article.showDraftLabel }}
|
||||
<div class="ms-2">
|
||||
{{ partial "badge.html" (i18n "article.draft" | emojify) }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if templates.Exists "partials/extend-article-link.html" }}
|
||||
{{ partial "extend-article-link.html" $target }}
|
||||
{{ end }}
|
||||
</header>
|
||||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
{{ partial "article-meta/basic.html" $target }}
|
||||
</div>
|
||||
{{ if $shortcodeShowSummary | default $target.Params.showSummary | default site.Params.list.showSummary | default false }}
|
||||
{{ $compactSummary := $shortcodeCompactSummary | default $target.Params.compactSummary | default false }}
|
||||
<div
|
||||
class="article-link__summary prose dark:prose-invert max-w-fit mt-1 {{ if $compactSummary -}}
|
||||
line-clamp-3
|
||||
{{- end }}">
|
||||
{{ $target.Summary | plainify }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
</article>
|
||||
101
layouts/partials/article-link/card-related.html
Normal file
101
layouts/partials/article-link/card-related.html
Normal file
@@ -0,0 +1,101 @@
|
||||
{{/* Used by
|
||||
1. layouts/partials/related.html (related articles in single page)
|
||||
*/}}
|
||||
{{ $disableImageOptimization := site.Store.Get "disableImageOptimization" }}
|
||||
|
||||
{{ $page := .Page }}
|
||||
{{ $featured := "" }}
|
||||
{{ $featuredURL := "" }}
|
||||
{{/* frontmatter */}}
|
||||
{{ with $page }}
|
||||
{{ with .Params.featureimage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $featuredURL = . }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* page resources */}}
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $images := .Resources.ByType "image" }}
|
||||
{{ range slice "*feature*" "*cover*" "*thumbnail*" }}
|
||||
{{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* fallback to default */}}
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $default := site.Store.Get "defaultFeaturedImage" }}
|
||||
{{ if $default.url }}
|
||||
{{ $featuredURL = $default.url }}
|
||||
{{ else if $default.obj }}
|
||||
{{ $featured = $default.obj }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* generate image URL if not hotlink */}}
|
||||
{{ if not $featuredURL }}
|
||||
{{ with $featured }}
|
||||
{{ $featuredURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $featuredURL = (.Resize "600x").RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<article
|
||||
class="article-link--related relative min-h-full min-w-full overflow-hidden rounded-lg border border-neutral-300 dark:border-neutral-600">
|
||||
{{ with $featuredURL }}
|
||||
<div class="flex-none relative overflow-hidden thumbnail_card_related">
|
||||
<img
|
||||
src="{{ . }}"
|
||||
role="presentation"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
fetchpriority="low"
|
||||
class="not-prose absolute inset-0 w-full h-full object-cover">
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if and .Draft .Site.Params.article.showDraftLabel }}
|
||||
<span class="absolute top-0 right-0 m-2">
|
||||
{{ partial "badge.html" (i18n "article.draft" | emojify) }}
|
||||
</span>
|
||||
{{ end }}
|
||||
<div class="p-4">
|
||||
<header>
|
||||
<a
|
||||
{{ with $page.Params.externalUrl }}
|
||||
href="{{ . }}" target="_blank" rel="external"
|
||||
{{ else }}
|
||||
href="{{ $page.RelPermalink }}"
|
||||
{{ end }}
|
||||
class="not-prose before:absolute before:inset-0 decoration-primary-500 dark:text-neutral text-xl font-bold text-neutral-800 hover:underline hover:underline-offset-2">
|
||||
<h2>
|
||||
{{ .Title | emojify }}
|
||||
{{ if .Params.externalUrl }}
|
||||
<span class="cursor-default align-top text-xs text-neutral-400 dark:text-neutral-500">
|
||||
<span class="rtl:hidden">↗</span>
|
||||
<span class="ltr:hidden">↖</span>
|
||||
</span>
|
||||
{{ end }}
|
||||
</h2>
|
||||
</a>
|
||||
</header>
|
||||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
{{ partial "article-meta/basic.html" . }}
|
||||
</div>
|
||||
{{ if .Params.showSummary | default (.Site.Params.list.showSummary | default false) }}
|
||||
<div class="article-link__summary prose dark:prose-invert mt-1 line-clamp-5">
|
||||
{{ .Summary | plainify }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="px-6 pt-4 pb-2"></div>
|
||||
</article>
|
||||
104
layouts/partials/article-link/card.html
Normal file
104
layouts/partials/article-link/card.html
Normal file
@@ -0,0 +1,104 @@
|
||||
{{/* Used by
|
||||
1. list.html and term.html (when the cardView option is enabled)
|
||||
2. Recent articles template (when the cardView option is enabled)
|
||||
3. Shortcode list.html
|
||||
*/}}
|
||||
{{ $disableImageOptimization := site.Store.Get "disableImageOptimization" }}
|
||||
|
||||
{{ $page := .Page }}
|
||||
{{ $featured := "" }}
|
||||
{{ $featuredURL := "" }}
|
||||
{{ if not .Params.hideFeatureImage }}
|
||||
{{/* frontmatter */}}
|
||||
{{ with $page }}
|
||||
{{ with .Params.featureimage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $featuredURL = . }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* page resources */}}
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $images := .Resources.ByType "image" }}
|
||||
{{ range slice "*feature*" "*cover*" "*thumbnail*" }}
|
||||
{{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* fallback to default */}}
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $default := site.Store.Get "defaultFeaturedImage" }}
|
||||
{{ if $default.url }}
|
||||
{{ $featuredURL = $default.url }}
|
||||
{{ else if $default.obj }}
|
||||
{{ $featured = $default.obj }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* generate image URL if not hotlink */}}
|
||||
{{ if not $featuredURL }}
|
||||
{{ with $featured }}
|
||||
{{ $featuredURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $featuredURL = (.Resize "600x").RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<article
|
||||
class="article-link--card relative min-h-full min-w-full overflow-hidden rounded-lg border border-neutral-300 dark:border-neutral-600">
|
||||
{{ with $featuredURL }}
|
||||
<div class="flex-none relative overflow-hidden thumbnail_card">
|
||||
<img
|
||||
src="{{ . }}"
|
||||
role="presentation"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="not-prose absolute inset-0 w-full h-full object-cover">
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ if and .Draft .Site.Params.article.showDraftLabel }}
|
||||
<span class="absolute top-0 right-0 m-2">
|
||||
{{ partial "badge.html" (i18n "article.draft" | emojify) }}
|
||||
</span>
|
||||
{{ end }}
|
||||
<div class="p-4">
|
||||
<header>
|
||||
<a
|
||||
{{ with $page.Params.externalUrl }}
|
||||
href="{{ . }}" target="_blank" rel="external"
|
||||
{{ else }}
|
||||
href="{{ $page.RelPermalink }}"
|
||||
{{ end }}
|
||||
class="not-prose before:absolute before:inset-0 decoration-primary-500 dark:text-neutral text-xl font-bold text-neutral-800 hover:underline hover:underline-offset-2">
|
||||
<h2>
|
||||
{{ .Title | emojify }}
|
||||
{{ if .Params.externalUrl }}
|
||||
<span class="cursor-default align-top text-xs text-neutral-400 dark:text-neutral-500">
|
||||
<span class="rtl:hidden">↗</span>
|
||||
<span class="ltr:hidden">↖</span>
|
||||
</span>
|
||||
{{ end }}
|
||||
</h2>
|
||||
</a>
|
||||
</header>
|
||||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
{{ partial "article-meta/basic.html" . }}
|
||||
</div>
|
||||
{{ if .Params.showSummary | default (.Site.Params.list.showSummary | default false) }}
|
||||
<div class="article-link__summary prose dark:prose-invert mt-1 line-clamp-5">
|
||||
{{ .Summary | plainify }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="px-6 pt-4 pb-2"></div>
|
||||
</article>
|
||||
123
layouts/partials/article-link/simple.html
Normal file
123
layouts/partials/article-link/simple.html
Normal file
@@ -0,0 +1,123 @@
|
||||
{{/* Used by
|
||||
1. list.html and term.html (when the cardView option is not enabled)
|
||||
2. Recent articles template (when the cardView option is not enabled)
|
||||
3. Shortcode list.html
|
||||
*/}}
|
||||
{{ $constrainItemsWidth := site.Params.list.constrainItemsWidth | default false }}
|
||||
{{ $disableImageOptimization := site.Store.Get "disableImageOptimization" }}
|
||||
|
||||
{{ $cardClasses := "flex flex-col md:flex-row relative" }}
|
||||
{{ $imgWrapperClasses := "" }}
|
||||
{{ $cardContentClasses := "" }}
|
||||
|
||||
{{ if .Params.showCards | default site.Params.list.showCards }}
|
||||
{{ $cardClasses = printf "%s overflow-hidden rounded-lg border border-neutral-300 dark:border-neutral-600" $cardClasses }}
|
||||
{{ $imgWrapperClasses = "" }}
|
||||
{{ $cardContentClasses = printf "%s p-4" $cardContentClasses }}
|
||||
{{ else }}
|
||||
{{ $cardClasses = $cardClasses }}
|
||||
{{ $imgWrapperClasses = printf "%s thumbnail-shadow md:mr-7" $imgWrapperClasses }}
|
||||
{{ $cardContentClasses = printf "%s mt-3 md:mt-0" $cardContentClasses }}
|
||||
{{ end }}
|
||||
|
||||
{{ if $constrainItemsWidth }}
|
||||
{{ $cardClasses = printf "%s max-w-prose" $cardClasses }}
|
||||
{{ end }}
|
||||
|
||||
{{ $page := .Page }}
|
||||
{{ $featured := "" }}
|
||||
{{ $featuredURL := "" }}
|
||||
{{ if not .Params.hideFeatureImage }}
|
||||
{{/* frontmatter */}}
|
||||
{{ with $page }}
|
||||
{{ with .Params.featureimage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $featuredURL = . }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* page resources */}}
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $images := .Resources.ByType "image" }}
|
||||
{{ range slice "*feature*" "*cover*" "*thumbnail*" }}
|
||||
{{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* fallback to default */}}
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $default := site.Store.Get "defaultFeaturedImage" }}
|
||||
{{ if $default.url }}
|
||||
{{ $featuredURL = $default.url }}
|
||||
{{ else if $default.obj }}
|
||||
{{ $featured = $default.obj }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* generate image URL if not hotlink */}}
|
||||
{{ if not $featuredURL }}
|
||||
{{ with $featured }}
|
||||
{{ $featuredURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $featuredURL = (.Resize "600x").RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<article class="article-link--simple {{ $cardClasses }}">
|
||||
{{ with $featuredURL }}
|
||||
<div class="flex-none relative overflow-hidden {{ $imgWrapperClasses }} thumbnail">
|
||||
<img
|
||||
src="{{ . }}"
|
||||
role="presentation"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="not-prose absolute inset-0 w-full h-full object-cover">
|
||||
</div>
|
||||
{{ end }}
|
||||
<div class="{{ $cardContentClasses }}">
|
||||
<header class="items-center text-start text-xl font-semibold">
|
||||
<a
|
||||
{{ with $page.Params.externalUrl }}
|
||||
href="{{ . }}" target="_blank" rel="external"
|
||||
{{ else }}
|
||||
href="{{ $page.RelPermalink }}"
|
||||
{{ end }}
|
||||
class="not-prose before:absolute before:inset-0 decoration-primary-500 dark:text-neutral text-xl font-bold text-neutral-800 hover:underline hover:underline-offset-2">
|
||||
<h2>
|
||||
{{ .Title | emojify }}
|
||||
{{ if .Params.externalUrl }}
|
||||
<span class="cursor-default align-top text-xs text-neutral-400 dark:text-neutral-500">
|
||||
<span class="rtl:hidden">↗</span>
|
||||
<span class="ltr:hidden">↖</span>
|
||||
</span>
|
||||
{{ end }}
|
||||
</h2>
|
||||
</a>
|
||||
{{ if and .Draft .Site.Params.article.showDraftLabel }}
|
||||
<div class="ms-2">{{ partial "badge.html" (i18n "article.draft" | emojify) }}</div>
|
||||
{{ end }}
|
||||
{{ if templates.Exists "partials/extend-article-link.html" }}
|
||||
{{ partial "extend-article-link.html" . }}
|
||||
{{ end }}
|
||||
</header>
|
||||
<div class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
{{ partial "article-meta/basic.html" . }}
|
||||
</div>
|
||||
{{ if .Params.showSummary | default (site.Params.list.showSummary | default false) }}
|
||||
<div class="article-link__summary prose dark:prose-invert max-w-fit mt-1 line-clamp-3">
|
||||
{{ .Summary | plainify }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="px-6 pt-4 pb-2"></div>
|
||||
</article>
|
||||
125
layouts/partials/article-meta/basic.html
Normal file
125
layouts/partials/article-meta/basic.html
Normal file
@@ -0,0 +1,125 @@
|
||||
{{/* Determine the correct context and scope */}}
|
||||
{{/* This allows for different logic depending on where the partial is called */}}
|
||||
{{ $context := . }}
|
||||
{{ $scope := default nil }}
|
||||
|
||||
{{ if (reflect.IsMap . ) }}
|
||||
{{ $context = .context }}
|
||||
{{ $scope = cond (not .scope) nil .scope }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $context }}
|
||||
{{ $meta := newScratch }}
|
||||
|
||||
{{/* Gather partials for this context */}}
|
||||
{{ $shouldShowDate := false }}
|
||||
{{ if .Params.showDate | default (.Site.Params.article.showDate | default true) }}
|
||||
{{ $shouldShowDate = true }}
|
||||
{{ else }}
|
||||
{{ $shouldShowDate = false }}
|
||||
{{ end }}
|
||||
|
||||
{{ if (.Params.showDateOnlyInArticle | default (.Site.Params.article.showDateOnlyInArticle | default false)) }}
|
||||
{{ if (ne $scope "single") }}
|
||||
{{/* only takes effect when not called directly in the header of single.html */}}
|
||||
{{ $shouldShowDate = false }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if $shouldShowDate }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/date.html" .Date)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (.Params.showDateUpdated | default (.Site.Params.article.showDateUpdated | default false)) (ne (partial
|
||||
"functions/date.html" .Date) (partial "functions/date.html" .Lastmod)) (gt (.Lastmod | time.Format "2006") 1)
|
||||
}}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/date-updated.html" .Lastmod)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (.Params.showWordCount | default (.Site.Params.article.showWordCount | default false)) (ne .WordCount 0) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/word-count.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (.Params.showReadingTime | default (.Site.Params.article.showReadingTime | default true)) (ne .ReadingTime 0) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/reading-time.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (not .Params.externalURL) (.Params.showViews | default (.Site.Params.article.showViews | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/views.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (not .Params.externalURL) (.Params.showLikes | default (.Site.Params.article.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (not .Params.externalURL) (.Params.showLikes | default (.Site.Params.article.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes_button.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showEdit | default (.Site.Params.article.showEdit | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/edit.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showZenMode | default (.Site.Params.article.showZenMode | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/zen-mode.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{/* Output partials */}}
|
||||
{{ with ($meta.Get "partials") }}
|
||||
{{ delimit . "<span class=\"px-2 text-primary-500\">·</span>" | safeHTML }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Output draft label */}}
|
||||
{{ if and (eq $scope "single") (and .Draft .Site.Params.article.showDraftLabel) }}
|
||||
<span class="ps-2">{{ partial "badge.html" (i18n "article.draft" | emojify) }}</span>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ if .Params.showAuthorsBadges | default (.Site.Params.article.showAuthorsBadges | default false) }}
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{ range $taxonomy, $terms := .Site.Taxonomies }}
|
||||
{{ if (eq $taxonomy "authors") }}
|
||||
{{ if (gt (len ($context.GetTerms $taxonomy)) 0) }}
|
||||
{{ range $i, $a := $context.GetTerms $taxonomy }}
|
||||
{{ if not (eq $i 0) }}
|
||||
,
|
||||
{{ end }}
|
||||
<a href="{{ $a.RelPermalink }}" class="relative">{{ $a.LinkTitle }}</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{/* Output taxonomies */}}
|
||||
{{ if .Params.showTaxonomies | default (.Site.Params.article.showTaxonomies | default false) }}
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{ range $taxonomy, $terms := .Site.Taxonomies }}
|
||||
{{ if and (not (eq $taxonomy "authors")) (not (eq $taxonomy "series")) }}
|
||||
{{ if (gt (len ($context.GetTerms $taxonomy)) 0) }}
|
||||
{{ range $context.GetTerms $taxonomy }}
|
||||
<a class="relative mt-[0.5rem] me-2" href="{{ .RelPermalink }}">
|
||||
{{ partial "badge.html" .LinkTitle }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{/* Output only category */}}
|
||||
{{ if .Params.showCategoryOnly | default (.Site.Params.article.showCategoryOnly | default false) }}
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{ range (.GetTerms "categories") }}
|
||||
<a class="relative mt-[0.5rem] me-2" href="{{ .RelPermalink }}">
|
||||
{{ partial "badge.html" .LinkTitle }}
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
35
layouts/partials/article-meta/list.html
Normal file
35
layouts/partials/article-meta/list.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{{/* Determine the correct context and scope */}}
|
||||
{{/* This allows for different logic depending on where the partial is called */}}
|
||||
{{ $context := . }}
|
||||
{{ $scope := default nil }}
|
||||
|
||||
{{ if (reflect.IsMap . ) }}
|
||||
{{ $context = .context }}
|
||||
{{ $scope = cond (not .scope) nil .scope }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $context }}
|
||||
{{ $meta := newScratch }}
|
||||
|
||||
{{/* Gather partials for this context */}}
|
||||
|
||||
{{ if (.Params.showViews | default (.Site.Params.list.showViews | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/views.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if (.Params.showLikes | default (.Site.Params.list.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showLikes | default (.Site.Params.list.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes_button.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{/* Output partials */}}
|
||||
{{ with ($meta.Get "partials") }}
|
||||
{{ delimit . "<span class=\"px-2 text-primary-500\">·</span>" | safeHTML }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
35
layouts/partials/article-meta/taxonomy.html
Normal file
35
layouts/partials/article-meta/taxonomy.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{{/* Determine the correct context and scope */}}
|
||||
{{/* This allows for different logic depending on where the partial is called */}}
|
||||
{{ $context := . }}
|
||||
{{ $scope := default nil }}
|
||||
|
||||
{{ if (reflect.IsMap . ) }}
|
||||
{{ $context = .context }}
|
||||
{{ $scope = cond (not .scope) nil .scope }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $context }}
|
||||
{{ $meta := newScratch }}
|
||||
|
||||
{{/* Gather partials for this context */}}
|
||||
|
||||
{{ if (.Params.showViews | default (.Site.Params.taxonomy.showViews | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/views.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if (.Params.showLikes | default (.Site.Params.taxonomy.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showLikes | default (.Site.Params.taxonomy.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes_button.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{/* Output partials */}}
|
||||
{{ with ($meta.Get "partials") }}
|
||||
{{ delimit . "<span class=\"px-2 text-primary-500\">·</span>" | safeHTML }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
35
layouts/partials/article-meta/term.html
Normal file
35
layouts/partials/article-meta/term.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{{/* Determine the correct context and scope */}}
|
||||
{{/* This allows for different logic depending on where the partial is called */}}
|
||||
{{ $context := . }}
|
||||
{{ $scope := default nil }}
|
||||
|
||||
{{ if (reflect.IsMap . ) }}
|
||||
{{ $context = .context }}
|
||||
{{ $scope = cond (not .scope) nil .scope }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $context }}
|
||||
{{ $meta := newScratch }}
|
||||
|
||||
{{/* Gather partials for this context */}}
|
||||
|
||||
{{ if (.Params.showViews | default (.Site.Params.term.showViews | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/views.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if (.Params.showLikes | default (.Site.Params.term.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
{{ if and (eq $scope "single") (.Params.showLikes | default (.Site.Params.term.showLikes | default false)) }}
|
||||
{{ $meta.Add "partials" (slice (partial "meta/likes_button.html" .)) }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="flex flex-row flex-wrap items-center">
|
||||
{{/* Output partials */}}
|
||||
{{ with ($meta.Get "partials") }}
|
||||
{{ delimit . "<span class=\"px-2 text-primary-500\">·</span>" | safeHTML }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
47
layouts/partials/article-pagination.html
Normal file
47
layouts/partials/article-pagination.html
Normal file
@@ -0,0 +1,47 @@
|
||||
{{ if .Params.showPagination | default (.Site.Params.article.showPagination | default true) }}
|
||||
{{ if or .NextInSection .PrevInSection }}
|
||||
{{ $next := .NextInSection }}
|
||||
{{ $prev := .PrevInSection }}
|
||||
{{ if .Params.invertPagination | default (.Site.Params.article.invertPagination | default false) }}
|
||||
{{ $next = .PrevInSection }}
|
||||
{{ $prev = .NextInSection }}
|
||||
{{ end }}
|
||||
<div class="pt-8">
|
||||
<hr class="border-dotted border-neutral-300 dark:border-neutral-600">
|
||||
<div class="flex justify-between pt-3">
|
||||
<span class="flex flex-col">
|
||||
{{ if $prev }}
|
||||
<a
|
||||
class="flex text-neutral-700 hover:text-primary-600 dark:text-neutral dark:hover:text-primary-400"
|
||||
href="{{ $prev.RelPermalink }}">
|
||||
<span class="leading-6">
|
||||
<span class="inline-block rtl:rotate-180">←</span> {{ $prev.Title | emojify }}
|
||||
</span>
|
||||
</a>
|
||||
{{ if .Params.showDate | default (.Site.Params.article.showDate | default true) }}
|
||||
<span class="ms-6 mt-1 text-xs text-neutral-500 dark:text-neutral-400">
|
||||
{{ partial "meta/date.html" $prev.Date }}
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</span>
|
||||
<span class="flex flex-col items-end">
|
||||
{{ if $next }}
|
||||
<a
|
||||
class="flex text-right text-neutral-700 hover:text-primary-600 dark:text-neutral dark:hover:text-primary-400"
|
||||
href="{{ $next.RelPermalink }}">
|
||||
<span class="leading-6">
|
||||
{{ $next.Title | emojify }} <span class="inline-block rtl:rotate-180">→</span>
|
||||
</span>
|
||||
</a>
|
||||
{{ if .Params.showDate | default (.Site.Params.article.showDate | default true) }}
|
||||
<span class="me-6 mt-1 text-xs text-neutral-500 dark:text-neutral-400">
|
||||
{{ partial "meta/date.html" $next.Date }}
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
62
layouts/partials/author-extra.html
Normal file
62
layouts/partials/author-extra.html
Normal file
@@ -0,0 +1,62 @@
|
||||
{{ $disableImageOptimization := .Site.Params.disableImageOptimization | default false }}
|
||||
<div class="flex author author-extra mt-4">
|
||||
{{ with .data.image }}
|
||||
{{ $authorImage := "" }}
|
||||
{{ if or (hasPrefix . "http://") (hasPrefix . "https://") }}
|
||||
{{ $authorImage = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $authorImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ if $authorImage }}
|
||||
{{ $final := $authorImage }}
|
||||
{{ $squareImage := $authorImage }}
|
||||
{{ if not (or $disableImageOptimization (eq $authorImage.MediaType.SubType "svg")) }}
|
||||
{{ $final = $authorImage.Fill "192x192" }}
|
||||
{{ $shortSide := int (math.Min $authorImage.Width $authorImage.Height) }}
|
||||
{{ $squareImage = $authorImage.Crop (printf "%dx%d" $shortSide $shortSide ) }}
|
||||
{{ end }}
|
||||
<img
|
||||
class="!mt-0 !mb-0 h-24 w-24 rounded-full me-4"
|
||||
width="96"
|
||||
height="96"
|
||||
alt="{{ $.Site.Params.Author.name | default " Author" }}"
|
||||
src="{{ $final.RelPermalink }}"
|
||||
data-zoom-src="{{ $squareImage.RelPermalink }}">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<div class="place-self-center">
|
||||
{{ $link := .link }}
|
||||
{{ with .data.name | markdownify | emojify }}
|
||||
<div class="text-[0.6rem] uppercase leading-3 text-neutral-500 dark:text-neutral-400">
|
||||
{{ i18n "author.byline_title" | markdownify }}
|
||||
</div>
|
||||
<a
|
||||
{{ if $link }}href="{{ $link }}"{{ end }}
|
||||
class="font-semibold leading-6 text-neutral-800 dark:text-neutral-300">
|
||||
{{ . }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ with .data.bio | markdownify }}
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-400">{{ . }}</div>
|
||||
{{ end }}
|
||||
<div class="text-2xl sm:text-lg">
|
||||
<div class="flex flex-wrap text-neutral-400 dark:text-neutral-500">
|
||||
{{ range .data.social }}
|
||||
{{ range $name, $link := . }}
|
||||
<a
|
||||
class="px-1 hover:text-primary-700 dark:hover:text-primary-400"
|
||||
href="{{ $link }}"
|
||||
target="_blank"
|
||||
aria-label="{{ $name | title }}"
|
||||
title="{{ $name | title }}"
|
||||
rel="me noopener noreferrer">
|
||||
<span class="inline-block align-text-bottom">
|
||||
{{ partial "icon.html" $name }}
|
||||
</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
17
layouts/partials/author-links.html
Normal file
17
layouts/partials/author-links.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{{ with .Site.Params.Author.links }}
|
||||
<div class="flex flex-wrap text-neutral-400 dark:text-neutral-500">
|
||||
{{ range $links := . }}
|
||||
{{ range $name, $url := $links }}
|
||||
<a
|
||||
class="px-1 hover:text-primary-700 dark:hover:text-primary-400"
|
||||
href="{{ $url | safeURL }}"
|
||||
target="_blank"
|
||||
aria-label="{{ $name | title }}"
|
||||
title="{{ $name | title }}"
|
||||
rel="me noopener noreferrer"
|
||||
><span class="inline-block align-text-bottom">{{ partial "icon.html" $name }}</span></a
|
||||
>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
57
layouts/partials/author.html
Normal file
57
layouts/partials/author.html
Normal file
@@ -0,0 +1,57 @@
|
||||
{{ $disableImageOptimization := .Site.Params.disableImageOptimization | default false }}
|
||||
<div class="flex author">
|
||||
{{ with .Site.Params.Author.image }}
|
||||
{{ $authorImage := "" }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $authorImage = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $authorImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ if $authorImage }}
|
||||
{{ $final := $authorImage }}
|
||||
{{ $squareImage := $authorImage }}
|
||||
{{ if not (or $disableImageOptimization (eq $authorImage.MediaType.SubType "svg")) }}
|
||||
{{ $final = $authorImage.Fill "192x192" }}
|
||||
{{ $shortSide := int (math.Min $authorImage.Width $authorImage.Height) }}
|
||||
{{ $squareImage = $authorImage.Crop (printf "%dx%d" $shortSide $shortSide ) }}
|
||||
{{ end }}
|
||||
<img
|
||||
class="!mt-0 !mb-0 h-24 w-24 rounded-full me-4"
|
||||
width="96"
|
||||
height="96"
|
||||
alt="{{ $.Site.Params.Author.name | default " Author" }}"
|
||||
src="{{ $final.RelPermalink }}"
|
||||
data-zoom-src="{{ $squareImage.RelPermalink }}">
|
||||
{{ else }}
|
||||
{{ $authorImage := resources.GetRemote . }}
|
||||
{{ $final := $authorImage }}
|
||||
{{ $squareImage := $authorImage }}
|
||||
{{ if not $disableImageOptimization }}
|
||||
{{ $final = $authorImage.Fill "192x192" }}
|
||||
{{ $shortSide := int (math.Min $authorImage.Width $authorImage.Height) }}
|
||||
{{ $squareImage = $authorImage.Crop (printf "%dx%d" $shortSide $shortSide ) }}
|
||||
{{ end }}
|
||||
<img
|
||||
class="!mt-0 !mb-0 h-24 w-24 rounded-full me-4"
|
||||
width="96"
|
||||
height="96"
|
||||
alt="{{ $.Site.Params.Author.name | default " Author" }}"
|
||||
src="{{ $final.RelPermalink }}"
|
||||
data-zoom-src="{{ $squareImage.RelPermalink }}">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<div class="place-self-center">
|
||||
{{ with .Site.Params.Author.name | markdownify }}
|
||||
<div class="text-[0.6rem] uppercase leading-3 text-neutral-500 dark:text-neutral-400">
|
||||
{{ i18n "author.byline_title" | markdownify }}
|
||||
</div>
|
||||
<div class="font-semibold leading-6 text-neutral-800 dark:text-neutral-300">
|
||||
{{ . }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ with .Site.Params.Author.bio | markdownify }}
|
||||
<div class="text-sm text-neutral-700 dark:text-neutral-400">{{ . }}</div>
|
||||
{{ end }}
|
||||
<div class="text-2xl sm:text-lg">{{ partialCached "author-links.html" . }}</div>
|
||||
</div>
|
||||
</div>
|
||||
6
layouts/partials/badge.html
Normal file
6
layouts/partials/badge.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<span class="flex cursor-pointer">
|
||||
<span
|
||||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||||
{{ . }}
|
||||
</span>
|
||||
</span>
|
||||
19
layouts/partials/breadcrumbs.html
Normal file
19
layouts/partials/breadcrumbs.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<ol class="text-sm text-neutral-500 dark:text-neutral-400 print:hidden">
|
||||
{{ template "crumb" (dict "p1" . "p2" .) }}
|
||||
</ol>
|
||||
{{ define "crumb" }}
|
||||
{{ if .p1.Parent }}
|
||||
{{ template "crumb" (dict "p1" .p1.Parent "p2" .p2 ) }}
|
||||
{{ else if not .p1.IsHome }}
|
||||
{{ template "crumb" (dict "p1" .p1.Site.Home "p2" .p2 ) }}
|
||||
{{ end }}
|
||||
<li class="{{ if or (eq .p1 .p2) (.p1.IsHome) }}hidden{{ else }}inline{{ end }}">
|
||||
<a class="hover:underline decoration-neutral-300 dark:underline-neutral-600" href="{{ .p1.RelPermalink }}"
|
||||
>{{ if .p1.Title }}
|
||||
{{- .p1.Title -}}
|
||||
{{ else }}
|
||||
{{- .p1.Section -}}
|
||||
{{ end }}</a
|
||||
><span class="px-1 text-primary-500">/</span>
|
||||
</li>
|
||||
{{ end }}
|
||||
47
layouts/partials/contributors.html
Normal file
47
layouts/partials/contributors.html
Normal file
@@ -0,0 +1,47 @@
|
||||
{{ with site.Data.contributors }}
|
||||
<section class="contributors-section mt-12 mb-16">
|
||||
<div class="flex flex-col items-center mb-6">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-2xl text-neutral-800 dark:text-neutral-200">
|
||||
{{ partial "icon.html" "github" }}
|
||||
</span>
|
||||
<h2 class="text-2xl font-extrabold text-neutral-800 dark:text-neutral-200">
|
||||
{{ i18n "contributors.title" | default "Contributors" }}
|
||||
</h2>
|
||||
</div>
|
||||
<p class="text-neutral-600 dark:text-neutral-400 text-center">
|
||||
{{ i18n "contributors.description" | default (printf "%d amazing people have contributed to Blowfish" (len .)) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap justify-center gap-3">
|
||||
{{ range . }}
|
||||
<a
|
||||
href="{{ .profile_url }}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="group"
|
||||
title="{{ .username }} ({{ .contributions }} contributions)"
|
||||
aria-label="Contributor: {{ .username }}">
|
||||
<img
|
||||
class="nozoom h-10 w-10 rounded-full transition-all group-hover:scale-110 group-hover:ring-2 group-hover:ring-primary-500"
|
||||
src="{{ .avatar_url }}"
|
||||
alt="{{ .username }}"
|
||||
width="40"
|
||||
height="40"
|
||||
loading="lazy">
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex justify-center">
|
||||
<a
|
||||
href="https://github.com/nunocoracao/blowfish/graphs/contributors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-sm text-neutral-600 dark:text-neutral-400 hover:text-primary-500 transition-colors">
|
||||
{{ i18n "contributors.viewAll" | default "View all contributors on GitHub" }} →
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
8
layouts/partials/extend-footer.html
Normal file
8
layouts/partials/extend-footer.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{{/* example of extend-footer */}}
|
||||
{{/*
|
||||
<p class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
<a class="hover:underline hover:decoration-primary-400 hover:text-primary-500" rel="me" href="https://masto.ai/@blowfish">
|
||||
Follow me on Mastodon
|
||||
</a>
|
||||
</p>
|
||||
*/}}
|
||||
1
layouts/partials/extend-head.html
Normal file
1
layouts/partials/extend-head.html
Normal file
@@ -0,0 +1 @@
|
||||
<script defer src="https://umami.novicelab.io/script.js" data-website-id="6dc76b26-f911-4b0e-9827-6c2bfd49df04"></script>
|
||||
76
layouts/partials/footer.html
Normal file
76
layouts/partials/footer.html
Normal file
@@ -0,0 +1,76 @@
|
||||
<footer id="site-footer" class="py-10 print:hidden">
|
||||
{{/* Footer menu */}}
|
||||
{{ if .Site.Params.footer.showMenu | default true }}
|
||||
{{ if .Site.Menus.footer }}
|
||||
{{ $onlyIcon := true }}
|
||||
{{ range .Site.Menus.footer }}
|
||||
{{ if .Name }}
|
||||
{{ $onlyIcon = false }}
|
||||
{{ break }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ $navClass := printf "flex flex-row pb-4 text-base font-medium text-neutral-500 dark:text-neutral-400 %s" (cond $onlyIcon "overflow-x-auto py-2" "") }}
|
||||
{{ $ulClass := printf "flex list-none %s" (cond $onlyIcon "flex-row" "flex-col sm:flex-row") }}
|
||||
{{ $liClass := printf "flex mb-1 text-end sm:mb-0 sm:me-7 sm:last:me-0 %s" (cond $onlyIcon "me-4" "") }}
|
||||
<nav class="{{ $navClass }}">
|
||||
<ul class="{{ $ulClass }}">
|
||||
{{ range .Site.Menus.footer }}
|
||||
<li class=" {{ $liClass }}">
|
||||
<a
|
||||
class="decoration-primary-500 hover:underline hover:decoration-2 hover:underline-offset-2 flex items-center"
|
||||
href="{{ .URL }}"
|
||||
title="{{ .Title }}">
|
||||
{{ if .Pre }}
|
||||
<span {{ if and .Pre .Name }}class="mr-1"{{ end }}>
|
||||
{{ partial "icon.html" .Pre }}
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ .Name | markdownify }}
|
||||
</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</nav>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<div class="flex items-center justify-between">
|
||||
{{/* Copyright */}}
|
||||
{{ if .Site.Params.footer.showCopyright | default true }}
|
||||
<p class="text-sm text-neutral-500 dark:text-neutral-400">
|
||||
{{- with replace .Site.Params.copyright "{ year }" now.Year }}
|
||||
{{ . | markdownify }}
|
||||
{{- else }}
|
||||
©
|
||||
{{ now.Format "2006" }}
|
||||
{{ .Site.Params.Author.name | markdownify }}
|
||||
{{- end }}
|
||||
</p>
|
||||
{{ end }}
|
||||
|
||||
{{/* Theme attribution */}}
|
||||
{{ if .Site.Params.footer.showThemeAttribution | default true }}
|
||||
<p class="text-xs text-neutral-500 dark:text-neutral-400">
|
||||
{{ $hugo := printf `<a class="hover:underline hover:decoration-primary-400 hover:text-primary-500"
|
||||
href="https://gohugo.io/" target="_blank" rel="noopener noreferrer">Hugo</a>`
|
||||
}}
|
||||
{{ $blowfish := printf `<a class="hover:underline hover:decoration-primary-400 hover:text-primary-500"
|
||||
href="https://blowfish.page/" target="_blank" rel="noopener noreferrer">Blowfish</a>`
|
||||
}}
|
||||
{{ i18n "footer.powered_by" (dict "Hugo" $hugo "Theme" $blowfish) | safeHTML }}
|
||||
</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ if not .Site.Params.disableImageZoom | default true }}
|
||||
<script>
|
||||
mediumZoom(document.querySelectorAll("img:not(.nozoom)"), {
|
||||
margin: 24,
|
||||
background: "rgba(0,0,0,0.5)",
|
||||
scrollOffset: 0,
|
||||
});
|
||||
</script>
|
||||
{{ end }}
|
||||
{{/* Extend footer - eg. for extra scripts, etc. */}}
|
||||
{{ if templates.Exists "partials/extend-footer.html" }}
|
||||
{{ partialCached "extend-footer.html" . }}
|
||||
{{ end }}
|
||||
</footer>
|
||||
1
layouts/partials/functions/date.html
Normal file
1
layouts/partials/functions/date.html
Normal file
@@ -0,0 +1 @@
|
||||
{{ return time.Format (site.Language.Params.dateFormat | default ":date_long") . }}
|
||||
13
layouts/partials/functions/uid.html
Normal file
13
layouts/partials/functions/uid.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{{ $uid := .Page.RelPermalink }}
|
||||
{{ $ctx := . }}
|
||||
|
||||
{{ range seq 16 }}
|
||||
{{ with $ctx }}
|
||||
{{ $uid = printf "%s-%d" $uid .Ordinal }}
|
||||
{{ $ctx = .Parent }}
|
||||
{{ else }}
|
||||
{{ break }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ return md5 $uid }}
|
||||
210
layouts/partials/head.html
Normal file
210
layouts/partials/head.html
Normal file
@@ -0,0 +1,210 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
{{ with .Site.Language.Params.htmlCode | default .Site.LanguageCode }}
|
||||
<meta http-equiv="content-language" content="{{ . }}">
|
||||
{{ end }}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta name="theme-color">
|
||||
|
||||
{{/* Title */}}
|
||||
{{ if .IsHome }}
|
||||
<title>{{ .Site.Title | emojify }}</title>
|
||||
<meta name="title" content="{{ .Site.Title | emojify }}">
|
||||
{{ else }}
|
||||
<title>{{ .Title | emojify }} · {{ .Site.Title | emojify }}</title>
|
||||
<meta name="title" content="{{ .Title | emojify }} · {{ .Site.Title | emojify }}">
|
||||
{{ end }}
|
||||
|
||||
{{/* Metadata */}}
|
||||
{{ with (.Params.Summary | default .Params.Description) | default .Site.Params.description }}
|
||||
<meta name="description" content="{{ . }}">
|
||||
{{ end }}
|
||||
{{ with .Params.Tags | default .Site.Params.keywords }}
|
||||
<meta name="keywords" content="{{ range . }}{{ . }},{{ end }}">
|
||||
{{ end }}
|
||||
{{ with .Site.Params.robots }}
|
||||
<meta name="robots" content="{{ . }}">
|
||||
{{ end }}
|
||||
{{ with .Params.robots }}
|
||||
<meta name="robots" content="{{ . }}">
|
||||
{{ end }}
|
||||
<link rel="canonical" href="{{ .Permalink }}">
|
||||
{{ range .AlternativeOutputFormats }}
|
||||
{{ printf `
|
||||
<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .RelPermalink ($.Site.Title | emojify) |
|
||||
safeHTML
|
||||
}}
|
||||
{{ end }}
|
||||
|
||||
{{/* Me */}}
|
||||
{{ with .Site.Params.Author.name }}
|
||||
<meta name="author" content="{{ . }}">
|
||||
{{ end }}
|
||||
{{ with .Site.Params.Author.links }}
|
||||
{{ range $links := . }}
|
||||
{{ range $name, $url := $links }}
|
||||
{{ if not (strings.HasPrefix $url "mailto:") }}
|
||||
<link href="{{ $url }}" rel="me">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Social */}}
|
||||
{{ template "_internal/opengraph.html" . }}
|
||||
{{ template "_internal/twitter_cards.html" . }}
|
||||
{{/* Use defaultSocialImage if feature image does not exist */}}
|
||||
{{ $featureImage := "" }}
|
||||
{{ $pageImages := .Resources.ByType "image" }}
|
||||
{{ range slice "*featured*" "*cover*" "*thumbnail*" }}
|
||||
{{ if not $featureImage }}
|
||||
{{ $featureImage = $pageImages.GetMatch . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if not $featureImage }}
|
||||
{{ with .Site.Params.defaultSocialImage }}
|
||||
{{ $socialImage := "" }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $socialImage = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $socialImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ with $socialImage }}
|
||||
<meta name="twitter:image" content="{{ .RelPermalink | absURL }}">
|
||||
<meta property="og:image" content="{{ .RelPermalink | absURL }}">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Site Verification */}}
|
||||
{{ with .Site.Params.verification.google }}
|
||||
<meta name="google-site-verification" content="{{ . }}">
|
||||
{{ end }}
|
||||
{{ with .Site.Params.verification.bing }}
|
||||
<meta name="msvalidate.01" content="{{ . }}">
|
||||
{{ end }}
|
||||
{{ with .Site.Params.verification.pinterest }}
|
||||
<meta name="p:domain_verify" content="{{ . }}">
|
||||
{{ end }}
|
||||
{{ with .Site.Params.verification.yandex }}
|
||||
<meta name="yandex-verification" content="{{ . }}">
|
||||
{{ end }}
|
||||
{{ with .Site.Params.verification.fediverse }}
|
||||
<meta name="fediverse:creator" content="{{ . }}">
|
||||
{{ end }}
|
||||
|
||||
{{ $alg := .Site.Params.fingerprintAlgorithm | default "sha512" }}
|
||||
|
||||
{{/* CSS */}}
|
||||
{{ $cssResources := slice }}
|
||||
{{ $schemeName := .Site.Params.colorScheme | default "blowfish" }}
|
||||
{{ $cssScheme := resources.Get (printf "css/schemes/%s.css" (lower $schemeName)) | default (resources.Get "css/schemes/blowfish.css") }}
|
||||
{{ $cssResources = $cssResources | append $cssScheme }}
|
||||
{{ $cssResources = $cssResources | append (resources.Get "css/compiled/main.css") }}
|
||||
{{ with resources.Get "css/custom.css" }}
|
||||
{{ $cssResources = $cssResources | append . }}
|
||||
{{ end }}
|
||||
{{ if not .Site.Params.disableImageZoom | default true }}
|
||||
{{ $cssResources = $cssResources | append (resources.Get "lib/zoom/style.css") }}
|
||||
{{ end }}
|
||||
{{ $bundleCSS := $cssResources | resources.Concat "css/main.bundle.css" | resources.Minify | resources.Fingerprint $alg }}
|
||||
<link
|
||||
type="text/css"
|
||||
rel="stylesheet"
|
||||
href="{{ $bundleCSS.RelPermalink }}"
|
||||
integrity="{{ $bundleCSS.Data.Integrity }}">
|
||||
|
||||
{{/* JS loaded immediately */}}
|
||||
{{ $jsAppearance := resources.Get "js/appearance.js" | resources.ExecuteAsTemplate "js/appearance.js" . | resources.Minify | resources.Fingerprint $alg }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $jsAppearance.RelPermalink }}"
|
||||
integrity="{{ $jsAppearance.Data.Integrity }}"></script>
|
||||
{{ $enableA11y := .Site.Params.enableA11y | default false }}
|
||||
{{ if $enableA11y }}
|
||||
{{ $jsA11y := resources.Get "js/a11y.js" | resources.Minify | resources.Fingerprint $alg }}
|
||||
<script src="{{ $jsA11y.RelPermalink }}" integrity="{{ $jsA11y.Data.Integrity }}"></script>
|
||||
{{ end }}
|
||||
{{ $showZenMode := .Params.showZenMode | default (.Site.Params.article.showZenMode | default false) }}
|
||||
{{ $shouldIncludeZenMode := or $enableA11y $showZenMode }}
|
||||
{{ if and .IsPage $shouldIncludeZenMode }}
|
||||
{{ $jsZenMode := resources.Get "js/zen-mode.js" | resources.Minify | resources.Fingerprint $alg }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $jsZenMode.RelPermalink }}"
|
||||
integrity="{{ $jsZenMode.Data.Integrity }}"></script>
|
||||
{{ end }}
|
||||
{{ if not .Site.Params.disableImageZoom | default true }}
|
||||
{{ $zoomJS := resources.Get "lib/zoom/zoom.min.umd.js" | resources.Fingerprint $alg }}
|
||||
<script src="{{ $zoomJS.RelPermalink }}" integrity="{{ $zoomJS.Data.Integrity }}"></script>
|
||||
{{ end }}
|
||||
|
||||
{{/* JS deferred */}}
|
||||
{{ $jsResources := slice }}
|
||||
{{ if site.Params.footer.showScrollToTop | default true }}
|
||||
{{ $jsResources = $jsResources | append (resources.Get "js/scroll-to-top.js") }}
|
||||
{{ end }}
|
||||
{{ if .Site.Params.enableSearch | default false }}
|
||||
{{ $jsResources = $jsResources | append (resources.Get "lib/fuse/fuse.min.js") | append (resources.Get "js/search.js") }}
|
||||
{{ end }}
|
||||
{{ if .Site.Params.enableCodeCopy | default false }}
|
||||
{{ $jsResources = $jsResources | append (resources.Get "js/code.js") }}
|
||||
{{ end }}
|
||||
{{ if .Site.Params.rtl | default false }}
|
||||
{{ $jsResources = $jsResources | append (resources.Get "js/rtl.js") }}
|
||||
{{ end }}
|
||||
{{ $jsResources = $jsResources | append (resources.Get "js/katex-render.js") }}
|
||||
{{ $jsResources = $jsResources | append (resources.Get "js/print-support.js") }}
|
||||
{{ if $jsResources }}
|
||||
{{ $bundleJS := $jsResources | resources.Concat "js/main.bundle.js" | resources.Minify | resources.Fingerprint $alg }}
|
||||
<script
|
||||
defer
|
||||
type="text/javascript"
|
||||
id="script-bundle"
|
||||
src="{{ $bundleJS.RelPermalink }}"
|
||||
integrity="{{ $bundleJS.Data.Integrity }}"
|
||||
data-copy="{{ i18n "code.copy" }}"
|
||||
data-copied="{{ i18n "code.copied" }}"></script>
|
||||
{{ end }}
|
||||
|
||||
{{/* Conditional loaded resources */}}
|
||||
{{ partial "vendor.html" . }}
|
||||
|
||||
{{/* Icons */}}
|
||||
{{ if templates.Exists "partials/favicons.html" }}
|
||||
{{ partialCached "favicons.html" .Site }}
|
||||
{{ else }}
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ "apple-touch-icon.png" | relURL }}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{{ "favicon-32x32.png" | relURL }}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{{ "favicon-16x16.png" | relURL }}">
|
||||
<link rel="manifest" href="{{ "site.webmanifest" | relURL }}">
|
||||
{{ end }}
|
||||
|
||||
{{/* Schema */}}
|
||||
{{ partial "schema.html" . }}
|
||||
|
||||
{{/* Analytics */}}
|
||||
{{ if hugo.IsProduction }}
|
||||
{{ partial "analytics/main.html" . }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Extend head - eg. for custom analytics scripts, etc. */}}
|
||||
{{ if templates.Exists "partials/extend-head.html" }}
|
||||
{{ partialCached "extend-head.html" .Site }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Uncached extend head - Example: https://gohugo.io/methods/page/hasshortcode/ */}}
|
||||
{{ if templates.Exists "partials/extend-head-uncached.html" }}
|
||||
{{ partial "extend-head-uncached.html" . }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Advertisement */}}
|
||||
{{ with .Site.Params.advertisement.adsense }}
|
||||
<meta name="google-adsense-account" content="{{ . }}">
|
||||
<script
|
||||
async
|
||||
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client={{ . }}"
|
||||
crossorigin="anonymous"></script>
|
||||
{{ end }}
|
||||
</head>
|
||||
83
layouts/partials/header/basic.html
Normal file
83
layouts/partials/header/basic.html
Normal file
@@ -0,0 +1,83 @@
|
||||
<div class="main-menu flex items-center w-full gap-2 p-1 pl-0">
|
||||
{{ if .Site.Params.Logo }}
|
||||
{{ $logo := resources.Get .Site.Params.Logo }}
|
||||
{{ if $logo }}
|
||||
<div>
|
||||
<a href="{{ "" | relLangURL }}" class="flex">
|
||||
<span class="sr-only">{{ .Site.Title | markdownify }}</span>
|
||||
{{ if eq $logo.MediaType.SubType "svg" }}
|
||||
<span class="logo object-scale-down object-left nozoom">
|
||||
{{ $logo.Content | safeHTML }}
|
||||
</span>
|
||||
{{ else }}
|
||||
<img
|
||||
src="{{ $logo.RelPermalink }}"
|
||||
width="{{ div $logo.Width 2 }}"
|
||||
height="{{ div $logo.Height 2 }}"
|
||||
class="logo max-h-20 max-w-20 object-scale-down object-left nozoom"
|
||||
alt="">
|
||||
{{ end }}
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if not .Site.Params.disableTextInHeader | default true }}
|
||||
<a href="{{ "" | relLangURL }}" class="text-base font-medium truncate min-w-0 shrink">
|
||||
{{ .Site.Title | markdownify }}
|
||||
</a>
|
||||
{{ end }}
|
||||
<div class="flex items-center ms-auto">
|
||||
<div class="hidden md:flex">
|
||||
{{ partial "header/components/desktop-menu.html" . }}
|
||||
</div>
|
||||
<div class="flex md:hidden">
|
||||
{{ partial "header/components/mobile-menu.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ if .Site.Menus.subnavigation }}
|
||||
<div
|
||||
class="main-menu flex pb-3 flex-col items-end justify-between md:justify-start space-x-3 {{ if .Site.Params.Logo }}
|
||||
-mt-[15px]
|
||||
{{ end }}">
|
||||
<div class="hidden md:flex items-center space-x-5">
|
||||
{{ range .Site.Menus.subnavigation }}
|
||||
<a
|
||||
href="{{ .URL }}"
|
||||
{{ if or (strings.HasPrefix .URL "http:" ) (strings.HasPrefix .URL "https:" ) }}
|
||||
target="_blank"
|
||||
{{ end }}
|
||||
class="flex items-center bf-icon-color-hover">
|
||||
{{ if .Pre }}
|
||||
<span {{ if and .Pre .Name }}class="mr-1"{{ end }}>
|
||||
{{ partial "icon.html" .Pre }}
|
||||
</span>
|
||||
{{ end }}
|
||||
<span class="text-xs font-light" title="{{ .Title }}">
|
||||
{{ .Name | markdownify }}
|
||||
</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ if .Site.Params.highlightCurrentMenuArea }}
|
||||
<script>
|
||||
(function () {
|
||||
var mainmenu = document.querySelector(".main-menu");
|
||||
if (!mainmenu) return;
|
||||
|
||||
var path = window.location.pathname;
|
||||
var links = mainmenu.querySelectorAll('a[href="' + path + '"]');
|
||||
|
||||
links.forEach(function (link) {
|
||||
var targets = link.querySelectorAll("span");
|
||||
targets.forEach(function (el) {
|
||||
el.classList.add("active");
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{{ end }}
|
||||
88
layouts/partials/header/components/a11y.html
Normal file
88
layouts/partials/header/components/a11y.html
Normal file
@@ -0,0 +1,88 @@
|
||||
{{- $prefix := .prefix | default "" -}}
|
||||
<div class="flex items-center">
|
||||
<button
|
||||
id="{{ $prefix }}a11y-toggle"
|
||||
aria-label="Open accessibility panel"
|
||||
aria-expanded="false"
|
||||
type="button"
|
||||
class="bf-icon-color-hover"
|
||||
role="button"
|
||||
aria-pressed="false">
|
||||
{{ partial "icon.html" "a11y" }}
|
||||
</button>
|
||||
|
||||
<div id="{{ $prefix }}a11y-overlay" class="fixed inset-0 hidden" style="z-index:9999;"></div>
|
||||
|
||||
<div
|
||||
id="{{ $prefix }}a11y-panel"
|
||||
role="dialog"
|
||||
aria-labelledby="{{ $prefix }}a11y-panel-title"
|
||||
class="a11y-panel-enter fixed hidden p-6 top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-80 rounded-lg shadow-xl bg-neutral-50 dark:bg-neutral-800 border border-neutral-300 dark:border-neutral-700"
|
||||
style="min-width: 20rem; z-index:9999;">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h3
|
||||
id="{{ $prefix }}a11y-panel-title"
|
||||
class="text-lg font-semibold text-neutral-900 dark:text-neutral-100">
|
||||
{{ i18n "a11y.title" }}
|
||||
</h3>
|
||||
<button
|
||||
id="{{ $prefix }}a11y-close"
|
||||
class="text-neutral-500 hover:text-neutral-700 dark:text-neutral-400 dark:hover:text-neutral-200"
|
||||
aria-label="Close a11y panel">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="space-y-5">
|
||||
{{ $toggles := slice }}
|
||||
{{ $shouldDisableBlur := or site.Params.homepage.layoutBackgroundBlur site.Params.article.layoutBackgroundBlur site.Params.list.layoutBackgroundBlur }}
|
||||
{{ $shouldDisableBackgroundImage := or
|
||||
(eq site.Params.homepage.layout "background")
|
||||
(eq site.Params.article.heroStyle "background")
|
||||
(eq site.Params.list.heroStyle "background")
|
||||
(eq site.Params.taxonomy.heroStyle "background")
|
||||
(eq site.Params.term.heroStyle "background")
|
||||
}}
|
||||
{{ if $shouldDisableBlur }}
|
||||
{{ $toggles = $toggles | append (dict "id" (print $prefix "disable-blur") "label" (i18n "a11y.disable_blur")) }}
|
||||
{{ end }}
|
||||
{{ if $shouldDisableBackgroundImage }}
|
||||
{{ $toggles = $toggles | append (dict "id" (print $prefix "disable-images") "label" (i18n "a11y.disable_images")) }}
|
||||
{{ end }}
|
||||
{{- $toggles = $toggles | append
|
||||
(dict "id" (print $prefix "underline-links") "label" (i18n "a11y.show_link_underline"))
|
||||
(dict "id" (print $prefix "zen-mode") "label" (i18n "article.zen_mode_title.enable"))
|
||||
-}}
|
||||
|
||||
{{- range $toggles }}
|
||||
<div class="flex items-center justify-between">
|
||||
<label for="{{ .id }}" class="text-sm font-medium text-neutral-700 dark:text-neutral-300">
|
||||
{{ .label }}
|
||||
</label>
|
||||
<div class="ios-toggle">
|
||||
<input type="checkbox" id="{{ .id }}">
|
||||
</div>
|
||||
</div>
|
||||
{{- end }}
|
||||
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<label
|
||||
for="{{ $prefix }}font-size-select"
|
||||
class="text-sm font-medium text-neutral-700 dark:text-neutral-300">
|
||||
{{ i18n "a11y.font_size" }}
|
||||
</label>
|
||||
<select
|
||||
id="{{ $prefix }}font-size-select"
|
||||
class="border rounded-lg px-3 py-1.5 pr-8 text-neutral-900 text-sm dark:bg-neutral-700 dark:text-neutral-200 focus:ring-primary-500 focus:border-primary-500">
|
||||
{{ $fontSizes := slice "default" "12px" "14px" "16px" "18px" "20px" "22px" "24px" }}
|
||||
{{ range $fontSizes }}
|
||||
<option value="{{ . }}">{{ . }}</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
116
layouts/partials/header/components/desktop-menu.html
Normal file
116
layouts/partials/header/components/desktop-menu.html
Normal file
@@ -0,0 +1,116 @@
|
||||
<nav class="flex items-center gap-x-5 h-12">
|
||||
{{ if .Site.Menus.main }}
|
||||
{{ range .Site.Menus.main }}
|
||||
{{ template "DesktopMenu" . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ partial "header/components/translations.html" . }}
|
||||
{{ if .Site.Params.enableA11y | default false }}
|
||||
{{ partial "header/components/a11y.html" (dict "prefix" "desktop-") }}
|
||||
{{ end }}
|
||||
|
||||
{{ if .Site.Params.enableSearch | default false }}
|
||||
<button
|
||||
id="search-button"
|
||||
aria-label="Search"
|
||||
class="text-base bf-icon-color-hover"
|
||||
title="{{ i18n "search.open_button_title" }}">
|
||||
{{ partial "icon.html" "search" }}
|
||||
</button>
|
||||
{{ end }}
|
||||
|
||||
{{ if .Site.Params.footer.showAppearanceSwitcher | default false }}
|
||||
<div class="flex items-center">
|
||||
<button
|
||||
id="appearance-switcher"
|
||||
aria-label="Dark mode switcher"
|
||||
type="button"
|
||||
class="text-base bf-icon-color-hover">
|
||||
<div class="flex items-center justify-center dark:hidden">
|
||||
{{ partial "icon.html" "moon" }}
|
||||
</div>
|
||||
<div class="items-center justify-center hidden dark:flex">
|
||||
{{ partial "icon.html" "sun" }}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{{ end }}
|
||||
</nav>
|
||||
|
||||
{{ define "DesktopMenu" }}
|
||||
{{ if .HasChildren }}
|
||||
<div class="nested-menu">
|
||||
<div class="cursor-pointer flex items-center">
|
||||
<a
|
||||
{{ if .URL }}
|
||||
href="{{ .URL }}"
|
||||
{{ if or (strings.HasPrefix .URL "http:" ) (strings.HasPrefix .URL "https:" ) }}
|
||||
target="_blank"
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
tabindex="0"
|
||||
{{ end }}
|
||||
{{ with or .Name .Pre }}aria-label="{{ . }}"{{ end }}
|
||||
class="flex items-center text-base font-medium bf-icon-color-hover"
|
||||
title="{{ .Title }}">
|
||||
{{ if .Pre }}
|
||||
<span {{ if and .Pre .Name }}class="mr-1"{{ end }}>
|
||||
{{ partial "icon.html" .Pre }}
|
||||
</span>
|
||||
{{ end }}
|
||||
<span class="text-bg font-bg break-normal" title="{{ .Title }}">
|
||||
{{ .Name | markdownify }}
|
||||
</span>
|
||||
<span>
|
||||
{{ partial "icon.html" "chevron-down" }}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="menuhide">
|
||||
<div class="pt-2 p-5 mt-2 rounded-xl backdrop-blur shadow-2xl bg-neutral/25 dark:bg-neutral-800/25">
|
||||
<div class="flex flex-col space-y-3">
|
||||
{{ range .Children }}
|
||||
<a
|
||||
href="{{ .URL }}"
|
||||
{{ if or (strings.HasPrefix .URL "http:" ) (strings.HasPrefix .URL "https:" ) }}
|
||||
target="_blank"
|
||||
{{ end }}
|
||||
{{ with or .Name .Pre }}aria-label="{{ . }}"{{ end }}
|
||||
class="flex items-center bf-icon-color-hover">
|
||||
{{ if .Pre }}
|
||||
<span {{ if and .Pre .Name }}class="mr-1"{{ end }}>
|
||||
{{ partial "icon.html" .Pre }}
|
||||
</span>
|
||||
{{ end }}
|
||||
<span class="text-sm font-sm" title="{{ .Title }}">
|
||||
{{ .Name | markdownify }}
|
||||
</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ else }}
|
||||
<a
|
||||
href="{{ .URL }}"
|
||||
{{ if or (strings.HasPrefix .URL "http:" ) (strings.HasPrefix .URL "https:" ) }}
|
||||
target="_blank"
|
||||
{{ end }}
|
||||
class="flex items-center bf-icon-color-hover"
|
||||
{{ with or .Name .Pre }}aria-label="{{ . }}"{{ end }}
|
||||
title="{{ .Title }}">
|
||||
{{ if .Pre }}
|
||||
<span {{ if and .Pre .Name }}class="mr-1"{{ end }}>
|
||||
{{ partial "icon.html" .Pre }}
|
||||
</span>
|
||||
{{ end }}
|
||||
{{ if .Name }}
|
||||
<span class="text-base font-medium break-normal">
|
||||
{{ .Name | markdownify }}
|
||||
</span>
|
||||
{{ end }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
152
layouts/partials/header/components/mobile-menu.html
Normal file
152
layouts/partials/header/components/mobile-menu.html
Normal file
@@ -0,0 +1,152 @@
|
||||
<div class="flex items-center h-14 gap-4">
|
||||
{{ if .Site.Params.enableSearch | default false }}
|
||||
<button
|
||||
id="search-button-mobile"
|
||||
aria-label="Search"
|
||||
class="flex items-center justify-center bf-icon-color-hover"
|
||||
title="{{ i18n "search.open_button_title" }}">
|
||||
{{ partial "icon.html" "search" }}
|
||||
</button>
|
||||
{{ end }}
|
||||
|
||||
{{ if .Site.Params.footer.showAppearanceSwitcher | default false }}
|
||||
<button
|
||||
id="appearance-switcher-mobile"
|
||||
type="button"
|
||||
aria-label="Dark mode switcher"
|
||||
class="flex items-center justify-center text-neutral-900 hover:text-primary-600 dark:text-neutral-200 dark:hover:text-primary-400">
|
||||
<div class="dark:hidden">
|
||||
{{ partial "icon.html" "moon" }}
|
||||
</div>
|
||||
<div class="hidden dark:block">
|
||||
{{ partial "icon.html" "sun" }}
|
||||
</div>
|
||||
</button>
|
||||
{{ end }}
|
||||
|
||||
{{ if or
|
||||
.Site.Menus.main
|
||||
.Site.Menus.subnavigation
|
||||
.Site.Params.enableA11y
|
||||
}}
|
||||
<input type="checkbox" id="mobile-menu-toggle" autocomplete="off" class="hidden peer">
|
||||
<label for="mobile-menu-toggle" class="flex items-center justify-center cursor-pointer bf-icon-color-hover">
|
||||
{{ partial "icon.html" "bars" }}
|
||||
</label>
|
||||
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
style="scrollbar-gutter: stable;"
|
||||
class="fixed inset-0 z-50 invisible overflow-y-auto px-6 py-20 opacity-0 transition-[opacity,visibility] duration-300 peer-checked:visible peer-checked:opacity-100 bg-neutral-50/97 dark:bg-neutral-900/99
|
||||
{{ if site.Params.enableStyledScrollbar | default true }}bf-scrollbar{{ end }}">
|
||||
<label
|
||||
for="mobile-menu-toggle"
|
||||
class="fixed end-8 top-5 flex items-center justify-center z-50 h-12 w-12 cursor-pointer select-none rounded-full bf-icon-color-hover border bf-border-color bf-border-color-hover bg-neutral-50 dark:bg-neutral-900">
|
||||
{{ partial "icon.html" "xmark" }}
|
||||
</label>
|
||||
<nav class="mx-auto max-w-md space-y-6">
|
||||
{{ template "mobile-main-menu" . }}
|
||||
{{ template "mobile-subnavigation" . }}
|
||||
{{ template "mobile-footer-components" . }}
|
||||
</nav>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ define "mobile-main-menu" }}
|
||||
{{ range .Site.Menus.main }}
|
||||
{{ $submenuId := printf "fullscreen-submenu-%s" (.Identifier | default .Name | anchorize) }}
|
||||
<div class="px-2">
|
||||
<a
|
||||
href="{{ .URL }}"
|
||||
{{ with or .Name .Pre }}aria-label="{{ . }}"{{ end }}
|
||||
{{ if or (strings.HasPrefix .URL "http:" ) (strings.HasPrefix .URL "https:" ) }}
|
||||
target="_blank"
|
||||
{{ end }}
|
||||
class="flex items-center gap-4 group bf-icon-color-hover text-neutral-700 dark:text-neutral-200">
|
||||
{{ if .Pre }}
|
||||
<span class="flex items-center justify-center h-8 w-8 text-2xl">
|
||||
{{ partial "icon.html" .Pre }}
|
||||
</span>
|
||||
{{ end }}
|
||||
<span title="{{ .Title }}" class="text-2xl font-bold tracking-tight">
|
||||
{{ .Name | markdownify }}
|
||||
</span>
|
||||
{{ if .HasChildren }}
|
||||
<label
|
||||
for="{{ $submenuId }}"
|
||||
class="ms-auto flex items-center justify-center h-10 w-10 cursor-pointer rounded-lg bf-icon-color-hover border bf-border-color bf-border-color-hover">
|
||||
{{ partial "icon.html" "chevron-down" }}
|
||||
</label>
|
||||
{{ end }}
|
||||
</a>
|
||||
|
||||
{{ if .HasChildren }}
|
||||
<input checked type="checkbox" id="{{ $submenuId }}" autocomplete="off" class="hidden peer/full">
|
||||
|
||||
<div
|
||||
class="grid grid-rows-[0fr] transition-[grid-template-rows] duration-300 peer-checked/full:grid-rows-[1fr]">
|
||||
<div class="overflow-hidden">
|
||||
<div class="ms-7 mt-4">
|
||||
{{ range .Children }}
|
||||
<a
|
||||
href="{{ .URL }}"
|
||||
{{ with or .Name .Pre }}aria-label="{{ . }}"{{ end }}
|
||||
{{ if or (strings.HasPrefix .URL "http:" ) (strings.HasPrefix .URL "https:" ) }}
|
||||
target="_blank"
|
||||
{{ end }}
|
||||
class="flex items-center gap-3 p-2 group bf-icon-color-hover text-neutral-700 dark:text-neutral-200">
|
||||
{{ if .Pre }}
|
||||
<span class="flex items-center justify-center h-5 w-5">
|
||||
{{ partial "icon.html" .Pre }}
|
||||
</span>
|
||||
{{ end }}
|
||||
<span title="{{ .Title }}" class="text-lg">
|
||||
{{ .Name | markdownify }}
|
||||
</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "mobile-subnavigation" }}
|
||||
{{ if .Site.Menus.subnavigation }}
|
||||
<div class="flex flex-wrap gap-4 mt-8 pt-8 border-t bf-border-color">
|
||||
{{ range .Site.Menus.subnavigation }}
|
||||
<a
|
||||
href="{{ .URL }}"
|
||||
{{ with or .Name .Pre }}aria-label="{{ . }}"{{ end }}
|
||||
class="inline-flex items-center gap-2 px-2 py-2 bf-icon-color-hover rounded-full text-sm">
|
||||
{{ if .Pre }}
|
||||
<span class="flex items-center justify-center h-4 w-4">
|
||||
{{ partial "icon.html" .Pre }}
|
||||
</span>
|
||||
{{ end }}
|
||||
<span title="{{ .Title }}">{{ .Name | markdownify }}</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ define "mobile-footer-components" }}
|
||||
{{ if or
|
||||
hugo.IsMultilingual
|
||||
.Site.Params.enableA11y
|
||||
}}
|
||||
<div
|
||||
class="flex flex-wrap items-center [&_span]:text-2xl [&_.translation_button_.icon]:text-4xl! [&_.translation_button_span]:text-base! [&_.translation_.menuhide_span]:text-sm! gap-x-6 ps-2 mt-8 pt-8 border-t bf-border-color">
|
||||
{{ partial "header/components/translations.html" . }}
|
||||
|
||||
{{ if .Site.Params.enableA11y | default false }}
|
||||
{{ partial "header/components/a11y.html" (dict "prefix" "mobile-menu-") }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
23
layouts/partials/header/components/translations.html
Normal file
23
layouts/partials/header/components/translations.html
Normal file
@@ -0,0 +1,23 @@
|
||||
{{ if .IsTranslated }}
|
||||
<div class="translation nested-menu">
|
||||
<button class="cursor-pointer flex items-center">
|
||||
<span class="me-1">
|
||||
{{ partial "icon.html" "language" }}
|
||||
</span>
|
||||
<span class="text-sm font-medium bf-icon-color-hover" title="{{ .Title }}">
|
||||
{{- i18n "global.language" | markdownify -}}
|
||||
</span>
|
||||
</button>
|
||||
<ul class="menuhide">
|
||||
<li class="rounded-xl backdrop-blur shadow-2xl p-2 flex flex-col gap-1">
|
||||
{{ range .AllTranslations }}
|
||||
<a href="{{ .RelPermalink }}" class="flex items-center bf-icon-color-hover px-3 py-1">
|
||||
<span class="text-sm font-sm" title="{{ .Title }}">
|
||||
{{ .Language.Params.displayName | emojify }}
|
||||
</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{{ end }}
|
||||
16
layouts/partials/header/fixed-fill-blur.html
Normal file
16
layouts/partials/header/fixed-fill-blur.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<div class="min-h-[148px]"></div>
|
||||
<div class="fixed inset-x-0 z-100">
|
||||
<div
|
||||
id="menu-blur"
|
||||
class="absolute opacity-0 inset-x-0 top-0 h-full single_hero_background nozoom backdrop-blur-2xl backdrop-saturate-220 backdrop-brightness-112 dark:backdrop-saturate-180 dark:backdrop-brightness-95 bg-primary-200/80 bg-linear-60 dark:bg-primary-800/30 shadow-xl"></div>
|
||||
<div class="relative m-auto leading-7 max-w-7xl px-6 sm:px-14 md:px-24 lg:px-32">
|
||||
{{ partial "header/basic.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
{{ $backgroundBlur := resources.Get "js/background-blur.js" }}
|
||||
{{ $backgroundBlur = $backgroundBlur | resources.Minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $backgroundBlur.RelPermalink }}"
|
||||
integrity="{{ $backgroundBlur.Data.Integrity }}"
|
||||
data-blur-id="menu-blur"></script>
|
||||
6
layouts/partials/header/fixed-fill.html
Normal file
6
layouts/partials/header/fixed-fill.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<div class="min-h-[148px]"></div>
|
||||
<div class="fixed inset-x-0 bg-neutral dark:bg-neutral-800 z-100">
|
||||
<div class="relative m-auto leading-7 max-w-7xl px-6 sm:px-14 md:px-24 lg:px-32">
|
||||
{{ partial "header/basic.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
18
layouts/partials/header/fixed-gradient.html
Normal file
18
layouts/partials/header/fixed-gradient.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<div class="min-h-[148px]"></div>
|
||||
<div
|
||||
class="fixed inset-x-0 min-h-[130px] opacity-65 bg-gradient-to-b from-neutral from-60% dark:from-neutral-800 to-transparent mix-blend-normal z-80"></div>
|
||||
<div class="fixed inset-x-0 z-100">
|
||||
<div
|
||||
id="menu-blur"
|
||||
class="absolute opacity-0 inset-x-0 top-0 h-full single_hero_background nozoom backdrop-blur-2xl shadow-2xl"></div>
|
||||
<div class="relative m-auto leading-7 max-w-7xl px-6 sm:px-14 md:px-24 lg:px-32">
|
||||
{{ partial "header/basic.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
{{ $backgroundBlur := resources.Get "js/background-blur.js" }}
|
||||
{{ $backgroundBlur = $backgroundBlur | resources.Minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $backgroundBlur.RelPermalink }}"
|
||||
integrity="{{ $backgroundBlur.Data.Integrity }}"
|
||||
data-blur-id="menu-blur"></script>
|
||||
16
layouts/partials/header/fixed.html
Normal file
16
layouts/partials/header/fixed.html
Normal file
@@ -0,0 +1,16 @@
|
||||
<div class="min-h-[148px]"></div>
|
||||
<div class="fixed inset-x-0 z-100">
|
||||
<div
|
||||
id="menu-blur"
|
||||
class="absolute opacity-0 inset-x-0 top-0 h-full single_hero_background nozoom backdrop-blur-2xl shadow-2xl bg-neutral/25 dark:bg-neutral-800/25"></div>
|
||||
<div class="relative m-auto leading-7 max-w-7xl px-6 sm:px-14 md:px-24 lg:px-32">
|
||||
{{ partial "header/basic.html" . }}
|
||||
</div>
|
||||
</div>
|
||||
{{ $backgroundBlur := resources.Get "js/background-blur.js" }}
|
||||
{{ $backgroundBlur = $backgroundBlur | resources.Minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $backgroundBlur.RelPermalink }}"
|
||||
integrity="{{ $backgroundBlur.Data.Integrity }}"
|
||||
data-blur-id="menu-blur"></script>
|
||||
98
layouts/partials/hero/background.html
Normal file
98
layouts/partials/hero/background.html
Normal file
@@ -0,0 +1,98 @@
|
||||
{{ $disableImageOptimization := site.Store.Get "disableImageOptimization" }}
|
||||
|
||||
{{ $useDefault := false }}
|
||||
{{ $featured := "" }}
|
||||
{{ $featuredURL := "" }}
|
||||
{{ with .Params.featureimage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $featuredURL = . }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $images := .Resources.ByType "image" }}
|
||||
{{ range slice "*background*" "*feature*" "*cover*" "*thumbnail*" }}
|
||||
{{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $default := site.Store.Get "defaultBackgroundImage" }}
|
||||
{{ if $default.url }}
|
||||
{{ $featuredURL = $default.url }}
|
||||
{{ $useDefault = true }}
|
||||
{{ else if $default.obj }}
|
||||
{{ $featured = $default.obj }}
|
||||
{{ $useDefault = true }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* generate image URL if not hotlink */}}
|
||||
{{ if not $featuredURL }}
|
||||
{{ with $featured }}
|
||||
{{ $featuredURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $size := site.Store.Get "backgroundImageWidth" }}
|
||||
{{ $featuredURL = (.Resize $size).RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ $isParentList := eq (.Scratch.Get "scope") "list" }}
|
||||
{{ $shouldBlur := $.Params.layoutBackgroundBlur | default (or
|
||||
(and ($.Site.Params.article.layoutBackgroundBlur | default true) (not $isParentList))
|
||||
(and ($.Site.Params.list.layoutBackgroundBlur | default true) ($isParentList))
|
||||
)
|
||||
}}
|
||||
{{ $shouldAddHeaderSpace := $.Params.layoutBackgroundHeaderSpace | default (or
|
||||
(and ($.Site.Params.article.layoutBackgroundHeaderSpace | default true) (not $isParentList))
|
||||
(and ($.Site.Params.list.layoutBackgroundHeaderSpace | default true) ($isParentList))
|
||||
)
|
||||
}}
|
||||
|
||||
{{- with $featuredURL -}}
|
||||
{{ if $shouldAddHeaderSpace | default true }}
|
||||
<div id="hero" class="h-[150px] md:h-[200px]"></div>
|
||||
{{ end }}
|
||||
<div class="fixed inset-x-0 top-0 h-[800px] single_hero_background nozoom">
|
||||
{{ $style := "" }}
|
||||
{{ $defaultPosition := cond $useDefault site.Params.imagePosition false }}
|
||||
{{ with $.Params.imagePosition | default $defaultPosition }}
|
||||
{{ $style = printf "object-position: %s;" . }}
|
||||
{{ end }}
|
||||
<img
|
||||
id="background-image"
|
||||
src="{{ . }}"
|
||||
role="presentation"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
fetchpriority="high"
|
||||
class="absolute inset-0 w-full h-full object-cover"
|
||||
{{ if $style }}style="{{ $style | safeCSS }}"{{ end }}>
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-t from-neutral dark:from-neutral-800 to-transparent mix-blend-normal"></div>
|
||||
<div
|
||||
class="absolute inset-0 opacity-60 bg-gradient-to-t from-neutral dark:from-neutral-800 to-neutral-100 dark:to-neutral-800 mix-blend-normal"></div>
|
||||
</div>
|
||||
|
||||
{{ if $shouldBlur | default false }}
|
||||
<div
|
||||
id="background-blur"
|
||||
class="fixed opacity-0 inset-x-0 top-0 h-full single_hero_background nozoom backdrop-blur-xl bg-neutral-100/75 dark:bg-neutral-800/60"></div>
|
||||
{{ $backgroundBlur := resources.Get "js/background-blur.js" }}
|
||||
{{ $backgroundBlur = $backgroundBlur | resources.Minify | resources.Fingerprint ($.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $backgroundBlur.RelPermalink }}"
|
||||
integrity="{{ $backgroundBlur.Data.Integrity }}"
|
||||
data-blur-id="background-blur"
|
||||
data-image-id="background-image"
|
||||
data-image-url="{{ . }}"></script>
|
||||
{{ end }}
|
||||
{{- end -}}
|
||||
63
layouts/partials/hero/basic.html
Normal file
63
layouts/partials/hero/basic.html
Normal file
@@ -0,0 +1,63 @@
|
||||
{{ $disableImageOptimization := site.Store.Get "disableImageOptimization" }}
|
||||
|
||||
{{ $useDefault := false }}
|
||||
{{ $featured := "" }}
|
||||
{{ $featuredURL := "" }}
|
||||
{{ with .Params.featureimage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $featuredURL = . }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $images := .Resources.ByType "image" }}
|
||||
{{ range slice "*background*" "*feature*" "*cover*" "*thumbnail*" }}
|
||||
{{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $default := site.Store.Get "defaultBackgroundImage" }}
|
||||
{{ if $default.url }}
|
||||
{{ $featuredURL = $default.url }}
|
||||
{{ $useDefault = true }}
|
||||
{{ else if $default.obj }}
|
||||
{{ $featured = $default.obj }}
|
||||
{{ $useDefault = true }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* generate image URL if not hotlink */}}
|
||||
{{ if not $featuredURL }}
|
||||
{{ with $featured }}
|
||||
{{ $featuredURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $size := site.Store.Get "backgroundImageWidth" }}
|
||||
{{ $featuredURL = (.Resize $size).RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $featuredURL }}
|
||||
{{ $style := "" }}
|
||||
{{ $defaultPosition := cond $useDefault site.Params.imagePosition false }}
|
||||
{{ with $.Params.imagePosition | default $defaultPosition }}
|
||||
{{ $style = printf "object-position: %s;" . }}
|
||||
{{ end }}
|
||||
<div class="overflow-hidden h-36 md:h-56 lg:h-72">
|
||||
<img
|
||||
src="{{ . }}"
|
||||
role="presentation"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
fetchpriority="high"
|
||||
class="w-full h-full nozoom object-cover"
|
||||
{{ if $style }}style="{{ $style | safeCSS }}"{{ end }}>
|
||||
</div>
|
||||
{{ end }}
|
||||
76
layouts/partials/hero/big.html
Normal file
76
layouts/partials/hero/big.html
Normal file
@@ -0,0 +1,76 @@
|
||||
{{ $disableImageOptimization := site.Store.Get "disableImageOptimization" }}
|
||||
|
||||
{{ $useDefault := false }}
|
||||
{{ $featured := "" }}
|
||||
{{ $featuredURL := "" }}
|
||||
{{ with .Params.featureimage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $featuredURL = . }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $images := .Resources.ByType "image" }}
|
||||
{{ range slice "*background*" "*feature*" "*cover*" "*thumbnail*" }}
|
||||
{{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $default := site.Store.Get "defaultBackgroundImage" }}
|
||||
{{ if $default.url }}
|
||||
{{ $featuredURL = $default.url }}
|
||||
{{ $useDefault = true }}
|
||||
{{ else if $default.obj }}
|
||||
{{ $featured = $default.obj }}
|
||||
{{ $useDefault = true }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* generate image URL if not hotlink */}}
|
||||
{{ if not $featuredURL }}
|
||||
{{ with $featured }}
|
||||
{{ $featuredURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $size := site.Store.Get "backgroundImageWidth" }}
|
||||
{{ $featuredURL = (.Resize $size).RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ $caption := "" }}
|
||||
{{ if .Params.featureimagecaption }}
|
||||
{{- $caption = .Params.featureimagecaption -}}
|
||||
{{ end }}
|
||||
|
||||
{{- $alt := .Page.Title -}}
|
||||
{{- with .Page.Params.alt }}{{ $alt = . }}{{ end -}}
|
||||
|
||||
{{ with $featuredURL }}
|
||||
{{ $style := "" }}
|
||||
{{ $defaultPosition := cond $useDefault site.Params.imagePosition false }}
|
||||
{{ with $.Params.imagePosition | default $defaultPosition }}
|
||||
{{ $style = printf "object-position: %s;" . }}
|
||||
{{ end }}
|
||||
<figure>
|
||||
<img
|
||||
src="{{ . }}"
|
||||
alt="{{ $alt }}"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
fetchpriority="high"
|
||||
class="w-full rounded-lg single_hero_round nozoom"
|
||||
{{ if $style }}style="{{ $style | safeCSS }}"{{ end }}>
|
||||
{{ if $caption }}
|
||||
<figcaption class="text-sm text-neutral-700 dark:text-neutral-400 hover:underline text-center">
|
||||
{{ $caption | markdownify }}
|
||||
</figcaption>
|
||||
{{ end }}
|
||||
</figure>
|
||||
{{ end }}
|
||||
136
layouts/partials/hero/thumbAndBackground.html
Normal file
136
layouts/partials/hero/thumbAndBackground.html
Normal file
@@ -0,0 +1,136 @@
|
||||
{{ $disableImageOptimization := site.Store.Get "disableImageOptimization" }}
|
||||
|
||||
{{/* === Background === */}}
|
||||
{{ $useDefault := false }}
|
||||
{{ $images := .Resources.ByType "image" }}
|
||||
{{ $background := $images.GetMatch "*background*" }}
|
||||
{{ $backgroundURL := "" }}
|
||||
|
||||
{{ if not (or $background $backgroundURL) }}
|
||||
{{ $default := site.Store.Get "defaultBackgroundImage" }}
|
||||
{{ if $default.url }}
|
||||
{{ $backgroundURL = $default.url }}
|
||||
{{ $useDefault = true }}
|
||||
{{ else if $default.obj }}
|
||||
{{ $background = $default.obj }}
|
||||
{{ $useDefault = true }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not (or $background $backgroundURL) }}
|
||||
{{ range slice "*cover*" "*thumbnail*" "*feature*" }}
|
||||
{{ if not $background }}{{ $background = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* generate image URL if not hotlink */}}
|
||||
{{ if not $backgroundURL }}
|
||||
{{ with $background }}
|
||||
{{ $backgroundURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $size := site.Store.Get "backgroundImageWidth" }}
|
||||
{{ $backgroundURL = (.Resize $size).RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* === Featured === */}}
|
||||
{{ $featured := "" }}
|
||||
{{ $featuredURL := "" }}
|
||||
{{ with .Params.featureimage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $featuredURL = . }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $images := $.Resources.ByType "image" }}
|
||||
{{ range slice "*feature*" "*cover*" "*thumbnail*" "*background*" }}
|
||||
{{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not (or $featured $featuredURL) }}
|
||||
{{ $default := site.Store.Get "defaultFeaturedImage" }}
|
||||
{{ if $default.url }}
|
||||
{{ $featuredURL = $default.url }}
|
||||
{{ else if $default.obj }}
|
||||
{{ $featured = $default.obj }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* generate image URL if not hotlink */}}
|
||||
{{ if not $featuredURL }}
|
||||
{{ with $featured }}
|
||||
{{ $featuredURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $size := site.Store.Get "backgroundImageWidth" }}
|
||||
{{ $featuredURL = (.Resize $size).RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ $isParentList := eq (.Scratch.Get "scope") "list" }}
|
||||
{{ $shouldBlur := $.Params.layoutBackgroundBlur | default (or
|
||||
(and ($.Site.Params.article.layoutBackgroundBlur | default true) (not $isParentList))
|
||||
(and ($.Site.Params.list.layoutBackgroundBlur | default true) ($isParentList))
|
||||
)
|
||||
}}
|
||||
|
||||
{{ with $featuredURL }}
|
||||
<div class="overflow-hidden rounded-md h-36 md:h-56 lg:h-72 nozoom">
|
||||
<img
|
||||
src="{{ . }}"
|
||||
role="presentation"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
fetchpriority="high"
|
||||
class="w-full h-full nozoom object-cover"
|
||||
{{ with $.Params.imagePositionFeature }}style="object-position: {{ . }};"{{ end }}>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="single_hero_background nozoom fixed inset-x-0 top-0 h-[800px]">
|
||||
{{ with $backgroundURL }}
|
||||
{{ $style := "" }}
|
||||
{{ $defaultPosition := cond $useDefault site.Params.imagePosition false }}
|
||||
{{ with $.Params.imagePosition | default $defaultPosition }}
|
||||
{{ $style = printf "object-position: %s;" . }}
|
||||
{{ end }}
|
||||
<img
|
||||
id="background-image-main"
|
||||
src="{{ . }}"
|
||||
role="presentation"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
fetchpriority="high"
|
||||
class="absolute inset-0 h-full w-full object-cover"
|
||||
{{ if $style }}style="{{ $style | safeCSS }}"{{ end }}>
|
||||
{{ end }}
|
||||
<div
|
||||
class="from-neutral absolute inset-0 bg-gradient-to-t to-transparent mix-blend-normal dark:from-neutral-800"></div>
|
||||
<div
|
||||
class="from-neutral to-neutral absolute inset-0 bg-gradient-to-t opacity-30 mix-blend-normal dark:from-neutral-800 dark:to-neutral-800 dark:opacity-60"></div>
|
||||
</div>
|
||||
|
||||
{{ if $shouldBlur | default false }}
|
||||
<div
|
||||
id="background-blur"
|
||||
class="fixed opacity-0 inset-x-0 top-0 h-full single_hero_background nozoom backdrop-blur-xl bg-neutral-100/75 dark:bg-neutral-800/60"></div>
|
||||
{{ $backgroundBlur := resources.Get "js/background-blur.js" }}
|
||||
{{ $backgroundBlur = $backgroundBlur | resources.Minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $backgroundBlur.RelPermalink }}"
|
||||
integrity="{{ $backgroundBlur.Data.Integrity }}"
|
||||
data-blur-id="background-blur"
|
||||
data-image-id="background-image-main"
|
||||
{{ with $background }}data-image-url="{{ .RelPermalink }}"{{ end }}></script>
|
||||
{{ end }}
|
||||
118
layouts/partials/home/background.html
Normal file
118
layouts/partials/home/background.html
Normal file
@@ -0,0 +1,118 @@
|
||||
{{ $disableImageOptimization := .Site.Params.disableImageOptimization | default false }}
|
||||
<article class="prose dark:prose-invert max-w-full">
|
||||
<div class="relative">
|
||||
<div class="absolute inset-x-0 bottom-0 h-1/2"></div>
|
||||
<div class="mx-auto max-w-7xl p-0">
|
||||
<div class="relative sm:overflow-hidden">
|
||||
<div class="fixed inset-x-0 top-0 -z-10">
|
||||
{{ $useDefault := true }}
|
||||
{{ $homepageImage := "" }}
|
||||
{{ with .Site.Params.defaultBackgroundImage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $homepageImage = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $homepageImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ with .Site.Params.homepage.homepageImage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $homepageImage = resources.GetRemote . }}
|
||||
{{ $useDefault = false }}
|
||||
{{ else }}
|
||||
{{ $homepageImage = resources.Get . }}
|
||||
{{ $useDefault = false }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if $homepageImage }}
|
||||
{{ $style := "" }}
|
||||
{{ $defaultPosition := cond $useDefault site.Params.imagePosition false }}
|
||||
{{ with $.Params.imagePosition | default $defaultPosition }}
|
||||
{{ $style = printf "object-position: %s;" . }}
|
||||
{{ end }}
|
||||
<img
|
||||
id="background-image"
|
||||
class="nozoom mt-0 mr-0 mb-0 ml-0 h-[1000px] w-full object-cover"
|
||||
src="{{ $homepageImage.RelPermalink }}"
|
||||
role="presentation"
|
||||
{{ if $style }}style="{{ $style | safeCSS }}"{{ end }}>
|
||||
<div
|
||||
class="from-neutral absolute inset-0 h-[1000px] bg-gradient-to-t to-transparent mix-blend-normal dark:from-neutral-800"></div>
|
||||
<div
|
||||
class="from-neutral absolute inset-0 h-[1000px] bg-gradient-to-t to-neutral-100 opacity-60 mix-blend-normal dark:from-neutral-800 dark:to-neutral-800"></div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<div class="relative flex flex-col items-center justify-center px-1 py-1 text-center">
|
||||
{{ with .Site.Params.Author.image }}
|
||||
{{ $authorImage := "" }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $authorImage = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $authorImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ if $authorImage }}
|
||||
{{ $final := $authorImage }}
|
||||
{{ $squareImage := $authorImage }}
|
||||
{{ if not (or $disableImageOptimization (eq $authorImage.MediaType.SubType "svg")) }}
|
||||
{{ $final = $authorImage.Fill (print "288x288 q" ( $.Site.Params.Author.imagequality | default "96" )) }}
|
||||
{{ $shortSide := int (math.Min $authorImage.Width $authorImage.Height) }}
|
||||
{{ $squareImage = $authorImage.Crop (printf "%dx%d" $shortSide $shortSide ) }}
|
||||
{{ end }}
|
||||
<img
|
||||
class="mb-2 h-36 w-36 rounded-full"
|
||||
width="144"
|
||||
height="144"
|
||||
alt="{{ $.Site.Params.Author.name | default `Author` }}"
|
||||
src="{{ $final.RelPermalink }}"
|
||||
data-zoom-src="{{ $squareImage.RelPermalink }}">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<h1 class="mb-2 text-4xl font-extrabold text-neutral-800 dark:text-neutral-200">
|
||||
{{ .Site.Params.Author.name | default .Site.Title }}
|
||||
</h1>
|
||||
{{ with .Site.Params.Author.headline }}
|
||||
<h2 class="mt-0 mb-0 text-xl text-neutral-800 dark:text-neutral-300">
|
||||
{{ . | markdownify }}
|
||||
</h2>
|
||||
{{ end }}
|
||||
<div class="mt-3 mb-10 text-2xl">
|
||||
{{ with .Site.Params.Author.links }}
|
||||
<div class="flex flex-wrap">
|
||||
{{ range $links := . }}
|
||||
{{ range $name, $url := $links }}
|
||||
<a
|
||||
class="hover:text-primary-400 text-primary-800 dark:text-primary-200 px-1"
|
||||
href="{{ $url }}"
|
||||
target="_blank"
|
||||
aria-label="{{ $name | title }}"
|
||||
title="{{ $name | title }}"
|
||||
rel="me noopener noreferrer">
|
||||
{{ partial "icon.html" $name }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
<section class="prose dark:prose-invert w-full">{{ .Content }}</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<section>
|
||||
{{ partial "recent-articles/main.html" . }}
|
||||
</section>
|
||||
{{ if .Site.Params.homepage.layoutBackgroundBlur | default false }}
|
||||
<div
|
||||
id="background-blur"
|
||||
class="fixed opacity-0 inset-x-0 top-0 h-full single_hero_background nozoom backdrop-blur-xl bg-neutral-100/75 dark:bg-neutral-800/60"></div>
|
||||
{{ $backgroundBlur := resources.Get "js/background-blur.js" }}
|
||||
{{ $backgroundBlur = $backgroundBlur | resources.Minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $backgroundBlur.RelPermalink }}"
|
||||
integrity="{{ $backgroundBlur.Data.Integrity }}"
|
||||
data-blur-id="background-blur"
|
||||
data-image-id="background-image"
|
||||
{{ if $homepageImage }}data-image-url="{{ $homepageImage.RelPermalink }}"{{ end }}></script>
|
||||
{{ end }}
|
||||
53
layouts/partials/home/card.html
Normal file
53
layouts/partials/home/card.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<div class="relative pt-16 pb-32">
|
||||
<div aria-hidden="true" class="absolute inset-x-0 top-0 h-48 bg-gradient-to-b"></div>
|
||||
<div class="relative">
|
||||
<div class="lg:mx-auto lg:grid lg:max-w-7xl lg:grid-flow-col-dense lg:grid-cols-2 lg:gap-24 lg:px-8">
|
||||
<div class="mx-auto max-w-xl px-4 sm:px-6 lg:mx-0 lg:max-w-none lg:py-16 lg:px-0">
|
||||
<article class="max-w-full prose dark:prose-invert">
|
||||
{{ with .Title }}
|
||||
<header>
|
||||
<h1>{{ . | emojify }}</h1>
|
||||
</header>
|
||||
{{ end }}
|
||||
<section class="w-full">{{ .Content }}</section>
|
||||
</article>
|
||||
</div>
|
||||
<div class="mt-6 sm:mt-16 lg:mt-0 mx-auto max-w-xl px-4 sm:px-6 lg:mx-0 lg:max-w-none lg:py-16 lg:px-0">
|
||||
<div class="-me-48 md:-me-16 lg:relative lg:m-0 lg:h-full lg:px-0 w-full">
|
||||
{{ $useDefault := true }}
|
||||
{{ $homepageImage := "" }}
|
||||
{{ with .Site.Params.defaultBackgroundImage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $homepageImage = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $homepageImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ with .Site.Params.homepage.homepageImage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $homepageImage = resources.GetRemote . }}
|
||||
{{ $useDefault = false }}
|
||||
{{ else }}
|
||||
{{ $homepageImage = resources.Get . }}
|
||||
{{ $useDefault = false }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if $homepageImage }}
|
||||
{{ $style := "" }}
|
||||
{{ $defaultPosition := cond $useDefault site.Params.imagePosition false }}
|
||||
{{ with $.Params.imagePosition | default $defaultPosition }}
|
||||
{{ $style = printf "object-position: %s;" . }}
|
||||
{{ end }}
|
||||
<img
|
||||
class="w-full rounded-xl shadow-xl lg:absolute lg:h-full lg:w-auto lg:max-w-none"
|
||||
src="{{ $homepageImage.RelPermalink }}"
|
||||
{{ if $style }}style="{{ $style | safeCSS }}"{{ end }}>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<section>
|
||||
{{ partial "recent-articles/main.html" . }}
|
||||
</section>
|
||||
134
layouts/partials/home/hero.html
Normal file
134
layouts/partials/home/hero.html
Normal file
@@ -0,0 +1,134 @@
|
||||
{{ $disableImageOptimization := .Site.Params.disableImageOptimization | default false }}
|
||||
{{ $disableHeroImageFilter := .Site.Params.homepage.disableHeroImageFilter | default false }}
|
||||
<article class="max-w-full prose dark:prose-invert">
|
||||
<div class="relative">
|
||||
<div class="absolute inset-x-0 bottom-0 h-1/2"></div>
|
||||
<div class="mx-auto max-w-7xl p-0">
|
||||
<div class="relative shadow-xl sm:overflow-hidden rounded-2xl">
|
||||
<div class="absolute inset-0">
|
||||
{{ $useDefault := true }}
|
||||
{{ $homepageImage := "" }}
|
||||
{{ with .Site.Params.defaultBackgroundImage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $homepageImage = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $homepageImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ with .Site.Params.homepage.homepageImage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $homepageImage = resources.GetRemote . }}
|
||||
{{ $useDefault = false }}
|
||||
{{ else }}
|
||||
{{ $homepageImage = resources.Get . }}
|
||||
{{ $useDefault = false }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if $homepageImage }}
|
||||
{{ $style := "" }}
|
||||
{{ $defaultPosition := cond $useDefault site.Params.imagePosition false }}
|
||||
{{ with $.Params.imagePosition | default $defaultPosition }}
|
||||
{{ $style = printf "object-position: %s;" . }}
|
||||
{{ end }}
|
||||
<img
|
||||
class="h-full w-full object-cover nozoom mt-0 mr-0 mb-0 ml-0"
|
||||
src="{{ $homepageImage.RelPermalink }}"
|
||||
{{ if $style }}style="{{ $style | safeCSS }}"{{ end }}>
|
||||
{{ if not $disableHeroImageFilter }}
|
||||
<div
|
||||
class="absolute inset-0 bg-gradient-to-r from-primary-500 to-secondary-600 dark:from-primary-600 dark:to-secondary-800 mix-blend-multiply"></div>
|
||||
{{ else }}
|
||||
<div
|
||||
class="absolute inset-0 from-primary-500 to-secondary-600 dark:from-primary-600 dark:to-secondary-800 mix-blend-multiply"></div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
<div
|
||||
class="relative px-4 py-16 sm:px-6 sm:py-24 lg:py-32 lg:px-8 flex flex-col items-center justify-center text-center">
|
||||
{{ with .Site.Params.Author.image }}
|
||||
{{ $authorImage := "" }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $authorImage = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $authorImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ if $authorImage }}
|
||||
{{ $final := $authorImage }}
|
||||
{{ $squareImage := $authorImage }}
|
||||
{{ if not (or $disableImageOptimization (eq $authorImage.MediaType.SubType "svg")) }}
|
||||
{{ $final = $authorImage.Fill (print "288x288 q" ( $.Site.Params.Author.imagequality | default "96" )) }}
|
||||
{{ $shortSide := int (math.Min $authorImage.Width $authorImage.Height) }}
|
||||
{{ $squareImage = $authorImage.Crop (printf "%dx%d" $shortSide $shortSide ) }}
|
||||
{{ end }}
|
||||
<img
|
||||
class="mb-2 h-36 w-36 rounded-full"
|
||||
width="144"
|
||||
height="144"
|
||||
alt="{{ $.Site.Params.Author.name | default `Author` }}"
|
||||
src="{{ $final.RelPermalink }}"
|
||||
data-zoom-src="{{ $squareImage.RelPermalink }}">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if not $disableHeroImageFilter }}
|
||||
<h1 class="mb-2 text-4xl font-extrabold text-neutral-200">
|
||||
{{ .Site.Params.Author.name | default .Site.Title }}
|
||||
</h1>
|
||||
{{ with .Site.Params.Author.headline }}
|
||||
<h2 class="mt-0 mb-0 text-xl text-neutral-300">
|
||||
{{ . | markdownify }}
|
||||
</h2>
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<h1 class="mb-2 text-4xl font-extrabold text-neutral-800 dark:text-neutral-200">
|
||||
{{ .Site.Params.Author.name | default .Site.Title }}
|
||||
</h1>
|
||||
{{ with .Site.Params.Author.headline }}
|
||||
<h2 class="mt-0 mb-0 text-xl text-neutral-800 dark:text-neutral-300">
|
||||
{{ . | markdownify }}
|
||||
</h2>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<div class="mt-3 mb-10 text-2xl">
|
||||
{{ with .Site.Params.Author.links }}
|
||||
<div class="flex flex-wrap">
|
||||
{{ range $links := . }}
|
||||
{{ range $name, $url := $links }}
|
||||
{{ if not $disableHeroImageFilter }}
|
||||
<a
|
||||
class="px-1 hover:text-primary-400 text-primary-300"
|
||||
href="{{ $url }}"
|
||||
target="_blank"
|
||||
aria-label="{{ $name | title }}"
|
||||
title="{{ $name | title }}"
|
||||
rel="me noopener noreferrer">
|
||||
{{ partial "icon.html" $name }}
|
||||
</a>
|
||||
{{ else }}
|
||||
<a
|
||||
class="px-1 hover:text-primary-400 text-primary-800 dark:text-primary-200"
|
||||
href="{{ $url }}"
|
||||
target="_blank"
|
||||
aria-label="{{ $name | title }}"
|
||||
title="{{ $name | title }}"
|
||||
rel="me noopener noreferrer">
|
||||
{{ partial "icon.html" $name }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ if not $disableHeroImageFilter }}
|
||||
<section class="prose prose-invert w-full">{{ .Content }}</section>
|
||||
{{ else }}
|
||||
<section class="prose dark:prose-invert w-full">{{ .Content }}</section>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<section>
|
||||
{{ partial "recent-articles/main.html" . }}
|
||||
</section>
|
||||
11
layouts/partials/home/page.html
Normal file
11
layouts/partials/home/page.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<article class="max-w-full prose dark:prose-invert">
|
||||
{{ with .Title }}
|
||||
<header>
|
||||
<h1>{{ . | emojify }}</h1>
|
||||
</header>
|
||||
{{ end }}
|
||||
<section class="w-full">{{ .Content }}</section>
|
||||
</article>
|
||||
<section>
|
||||
{{ partial "recent-articles/main.html" . }}
|
||||
</section>
|
||||
47
layouts/partials/home/profile.html
Normal file
47
layouts/partials/home/profile.html
Normal file
@@ -0,0 +1,47 @@
|
||||
{{ $disableImageOptimization := .Site.Params.disableImageOptimization | default false }}
|
||||
<article
|
||||
class="{{ if not .Site.Params.homepage.showRecent }}
|
||||
h-full
|
||||
{{ end }} flex flex-col items-center justify-center text-center">
|
||||
<header class="relative px-1 py-1 flex flex-col items-center mb-3">
|
||||
{{ with .Site.Params.Author.image }}
|
||||
{{ $authorImage := "" }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $authorImage = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $authorImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ if $authorImage }}
|
||||
{{ $final := $authorImage }}
|
||||
{{ $squareImage := $authorImage }}
|
||||
{{ if not (or $disableImageOptimization (eq $authorImage.MediaType.SubType "svg")) }}
|
||||
{{ $final = $authorImage.Fill (print "288x288 q" ( $.Site.Params.Author.imagequality | default "96" )) }}
|
||||
{{ $shortSide := int (math.Min $authorImage.Width $authorImage.Height) }}
|
||||
{{ $squareImage = $authorImage.Crop (printf "%dx%d" $shortSide $shortSide ) }}
|
||||
{{ end }}
|
||||
<img
|
||||
class="mb-2 h-36 w-36 rounded-full"
|
||||
width="144"
|
||||
height="144"
|
||||
alt="{{ $.Site.Params.Author.name | default `Author` }}"
|
||||
src="{{ $final.RelPermalink }}"
|
||||
data-zoom-src="{{ $squareImage.RelPermalink }}">
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<h1 class="text-4xl font-extrabold">
|
||||
{{ .Site.Params.Author.name | default .Site.Title }}
|
||||
</h1>
|
||||
{{ with .Site.Params.Author.headline }}
|
||||
<h2 class="text-xl text-neutral-500 dark:text-neutral-400">
|
||||
{{ . | markdownify }}
|
||||
</h2>
|
||||
{{ end }}
|
||||
<div class="mt-1 text-2xl">
|
||||
{{ partialCached "author-links.html" . }}
|
||||
</div>
|
||||
</header>
|
||||
<section class="prose dark:prose-invert w-full">{{ .Content }}</section>
|
||||
</article>
|
||||
<section>
|
||||
{{ partial "recent-articles/main.html" . }}
|
||||
</section>
|
||||
@@ -0,0 +1,43 @@
|
||||
{{/*
|
||||
Copied from Hugo v0.146
|
||||
Source: https://github.com/gohugoio/hugo/blob/83cfdd78ca6469e6d7265323d9fad1448880e559/tpl/tplimpl/embedded/templates/_shortcodes/figure.html
|
||||
*/}}
|
||||
|
||||
<figure{{ with .Get "class" }} class="{{ . }}"{{ end }}>
|
||||
{{- if .Get "link" -}}
|
||||
<a href="{{ .Get "link" }}"{{ with .Get "target" }} target="{{ . }}"{{ end }}{{ with .Get "rel" }} rel="{{ . }}"{{ end }} class="inline-block">
|
||||
{{- end -}}
|
||||
|
||||
{{- $u := urls.Parse (.Get "src") -}}
|
||||
{{- $src := $u.String -}}
|
||||
{{- if not $u.IsAbs -}}
|
||||
{{- with or (.Page.Resources.Get $u.Path) (resources.Get $u.Path) -}}
|
||||
{{- $src = .RelPermalink -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
<img src="{{ $src }}"
|
||||
{{- if or (.Get "alt") (.Get "caption") }}
|
||||
alt="{{ with .Get "alt" }}{{ . }}{{ else }}{{ .Get "caption" | markdownify| plainify }}{{ end }}"
|
||||
{{- end -}}
|
||||
{{- with .Get "width" }} width="{{ . }}"{{ end -}}
|
||||
{{- with .Get "height" }} height="{{ . }}"{{ end -}}
|
||||
{{- with .Get "loading" }} loading="{{ . }}"{{ end -}}
|
||||
><!-- Closing img tag -->
|
||||
{{- if .Get "link" }}</a>{{ end -}}
|
||||
{{- if or (or (.Get "title") (.Get "caption")) (.Get "attr") -}}
|
||||
<figcaption>
|
||||
{{ with (.Get "title") -}}
|
||||
<h4>{{ . }}</h4>
|
||||
{{- end -}}
|
||||
{{- if or (.Get "caption") (.Get "attr") -}}<p>
|
||||
{{- .Get "caption" | markdownify -}}
|
||||
{{- with .Get "attrlink" }}
|
||||
<a href="{{ . }}">
|
||||
{{- end -}}
|
||||
{{- .Get "attr" | markdownify -}}
|
||||
{{- if .Get "attrlink" }}</a>{{ end }}</p>
|
||||
{{- end }}
|
||||
</figcaption>
|
||||
{{- end }}
|
||||
</figure>
|
||||
6
layouts/partials/icon.html
Normal file
6
layouts/partials/icon.html
Normal file
@@ -0,0 +1,6 @@
|
||||
{{- $icon := resources.Get (print "icons/" . ".svg") -}}
|
||||
{{- if $icon -}}
|
||||
<span class="relative block icon">
|
||||
{{- $icon.Content | safeHTML -}}
|
||||
</span>
|
||||
{{- end -}}
|
||||
34
layouts/partials/impls/hooks/admonition-maps.html
Normal file
34
layouts/partials/impls/hooks/admonition-maps.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{{- /* Override this file in your site to customize admonition type aliases and icon mappings */ -}}
|
||||
{{- return dict
|
||||
"typeMap" (dict
|
||||
"attention" "warning"
|
||||
"check" "success"
|
||||
"cite" "quote"
|
||||
"done" "success"
|
||||
"error" "danger"
|
||||
"fail" "failure"
|
||||
"faq" "question"
|
||||
"hint" "tip"
|
||||
"help" "question"
|
||||
"missing" "failure"
|
||||
"summary" "abstract"
|
||||
"tldr" "abstract"
|
||||
)
|
||||
"iconMap" (dict
|
||||
"abstract" "file-lines"
|
||||
"bug" "bug"
|
||||
"caution" "fire"
|
||||
"danger" "fire"
|
||||
"example" "list-ol"
|
||||
"failure" "xmark"
|
||||
"important" "star"
|
||||
"info" "circle-info"
|
||||
"note" "circle-info"
|
||||
"success" "check"
|
||||
"todo" "list-check"
|
||||
"tip" "lightbulb"
|
||||
"question" "circle-question"
|
||||
"quote" "quote-left"
|
||||
"warning" "triangle-exclamation"
|
||||
)
|
||||
-}}
|
||||
37
layouts/partials/init.html
Normal file
37
layouts/partials/init.html
Normal file
@@ -0,0 +1,37 @@
|
||||
{{/* disableImageOptimization */}}
|
||||
{{ site.Store.Set "disableImageOptimization" (site.Params.disableImageOptimization | default false) }}
|
||||
|
||||
{{/* defaultFeaturedImage */}}
|
||||
{{ $defaultFeaturedImage := "" }}
|
||||
{{ $defaultFeaturedImageURL := "" }}
|
||||
{{ with site.Params.defaultFeaturedImage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $defaultFeaturedImageURL = . }}
|
||||
{{ else }}
|
||||
{{ $defaultFeaturedImage = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $defaultFeaturedImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ site.Store.Set "defaultFeaturedImage" (dict "url" $defaultFeaturedImageURL "obj" $defaultFeaturedImage) }}
|
||||
|
||||
{{/* defaultBackgroundImage */}}
|
||||
{{ $defaultBackgroundImage := "" }}
|
||||
{{ $defaultBackgroundImageURL := "" }}
|
||||
{{ with site.Params.defaultBackgroundImage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ if site.Params.hotlinkFeatureImage }}
|
||||
{{ $defaultBackgroundImageURL = . }}
|
||||
{{ else }}
|
||||
{{ $defaultBackgroundImage = resources.GetRemote . }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
{{ $defaultBackgroundImage = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ site.Store.Set "defaultBackgroundImage" (dict "url" $defaultBackgroundImageURL "obj" $defaultBackgroundImage) }}
|
||||
|
||||
{{/* backgroundImageWidth */}}
|
||||
{{ site.Store.Set "backgroundImageWidth" (print (site.Params.backgroundImageWidth | default "1200") "x") }}
|
||||
4
layouts/partials/meta/date-updated.html
Normal file
4
layouts/partials/meta/date-updated.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<time datetime="{{ . | time.Format "2006-01-02T15:04:05-07:00" }}">
|
||||
{{- i18n "article.date_updated" (dict "Date" (partial "functions/date.html" .)) -}}
|
||||
</time>
|
||||
{{- /* Trim EOF */ -}}
|
||||
4
layouts/partials/meta/date.html
Normal file
4
layouts/partials/meta/date.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<time datetime="{{ . | time.Format "2006-01-02T15:04:05-07:00" }}">
|
||||
{{- i18n "article.date" (dict "Date" (partial "functions/date.html" .)) -}}
|
||||
</time>
|
||||
{{- /* Trim EOF */ -}}
|
||||
19
layouts/partials/meta/edit.html
Normal file
19
layouts/partials/meta/edit.html
Normal file
@@ -0,0 +1,19 @@
|
||||
{{ $url := .Params.editURL | default (.Site.Params.article.editURL | default "#") }}
|
||||
{{ $slash := "" }}
|
||||
{{ if .Params.editAppendPath | default ( .Site.Params.article.editAppendPath | default false ) }}
|
||||
{{ if ne (substr $url -1 1) "/" }}
|
||||
{{ $slash = "/" }}
|
||||
{{ end }}
|
||||
{{ $url = printf "%s%s%s" $url $slash (path.Join .File.Path) }}
|
||||
{{ end }}
|
||||
<span class="mb-[2px]">
|
||||
<a
|
||||
href="{{ $url }}"
|
||||
class="text-lg hover:text-primary-500"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
title="{{ i18n "article.edit_title" }}"
|
||||
><span class="inline-block align-text-bottom">{{ partial "icon.html" "edit" }}</span></a
|
||||
>
|
||||
</span>
|
||||
{{- /* Trim EOF */ -}}
|
||||
25
layouts/partials/meta/likes.html
Normal file
25
layouts/partials/meta/likes.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<span>
|
||||
{{ $id := "null" }}
|
||||
{{ if eq .Kind "taxonomy" }}
|
||||
{{ $id = delimit (slice "likes_taxonomy_" .Page.Data.Plural) "" }}
|
||||
{{ else if eq .Kind "term" }}
|
||||
{{ $id = delimit (slice "likes_term_" .Page.Data.Term) "" }}
|
||||
{{ else }}
|
||||
{{ $translations := .AllTranslations }}
|
||||
{{ with .File }}
|
||||
{{ $path := .Path }}
|
||||
{{ range $translations }}
|
||||
{{ $lang := print "." .Lang ".md" }}
|
||||
{{ $path = replace $path $lang ".md" }}
|
||||
{{ end }}
|
||||
{{ $id = delimit (slice "likes_" $path) "" }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<span
|
||||
id="{{ $id }}"
|
||||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||||
title="likes"
|
||||
>loading</span
|
||||
>
|
||||
<span class="inline-block align-text-bottom">{{ partial "icon.html" "heart" }}</span>
|
||||
</span>
|
||||
14
layouts/partials/meta/likes_button.html
Normal file
14
layouts/partials/meta/likes_button.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<span>
|
||||
<button
|
||||
id="button_likes"
|
||||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xs font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||||
<span id="button_likes_heart" class="inline-block align-text-bottom hidden"
|
||||
>{{ partial "icon.html" "heart" }}
|
||||
</span>
|
||||
<span id="button_likes_emtpty_heart" class="inline-block align-text-bottom"
|
||||
>{{ partial "icon.html" "heart-empty" }}</span
|
||||
>
|
||||
<span id="button_likes_text"> Like</span>
|
||||
</button>
|
||||
</span>
|
||||
{{- /* Trim EOF */ -}}
|
||||
4
layouts/partials/meta/reading-time.html
Normal file
4
layouts/partials/meta/reading-time.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<span title="{{ i18n "article.reading_time_title" }}">
|
||||
{{- i18n "article.reading_time" .ReadingTime | markdownify | emojify -}}
|
||||
</span>
|
||||
{{- /* Trim EOF */ -}}
|
||||
25
layouts/partials/meta/views.html
Normal file
25
layouts/partials/meta/views.html
Normal file
@@ -0,0 +1,25 @@
|
||||
<span>
|
||||
{{ $id := "null" }}
|
||||
{{ if eq .Kind "taxonomy" }}
|
||||
{{ $id = delimit (slice "views_taxonomy_" .Page.Data.Plural) "" }}
|
||||
{{ else if eq .Kind "term" }}
|
||||
{{ $id = delimit (slice "views_term_" .Page.Data.Term) "" }}
|
||||
{{ else }}
|
||||
{{ $translations := .AllTranslations }}
|
||||
{{ with .File }}
|
||||
{{ $path := .Path }}
|
||||
{{ range $translations }}
|
||||
{{ $lang := print "." .Lang ".md" }}
|
||||
{{ $path = replace $path $lang ".md" }}
|
||||
{{ end }}
|
||||
{{ $id = delimit (slice "views_" $path) "" }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<span
|
||||
id="{{ $id }}"
|
||||
class="animate-pulse inline-block text-transparent max-h-3 rounded-full -mt-[2px] align-middle bg-neutral-300 dark:bg-neutral-400"
|
||||
title="views"
|
||||
>loading</span
|
||||
>
|
||||
<span class="inline-block align-text-bottom">{{ partial "icon.html" "eye" }}</span>
|
||||
</span>
|
||||
4
layouts/partials/meta/word-count.html
Normal file
4
layouts/partials/meta/word-count.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<span>
|
||||
{{- i18n "article.word_count" .WordCount | markdownify -}}
|
||||
</span>
|
||||
{{- /* Trim EOF */ -}}
|
||||
10
layouts/partials/meta/zen-mode.html
Normal file
10
layouts/partials/meta/zen-mode.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<span class="mb-[2px]">
|
||||
<span
|
||||
id="zen-mode-button"
|
||||
class="text-lg hover:text-primary-500"
|
||||
title="{{ i18n "article.zen_mode_title.enable" }}"
|
||||
data-title-i18n-disable="{{ i18n "article.zen_mode_title.enable" }}"
|
||||
data-title-i18n-enable="{{ i18n "article.zen_mode_title.disable" }}">
|
||||
<span class="inline-block align-text-bottom">{{ partial "icon.html" "expand" }}</span>
|
||||
</span>
|
||||
</span>
|
||||
52
layouts/partials/pagination.html
Normal file
52
layouts/partials/pagination.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{{- if gt .Paginator.TotalPages 1 -}}
|
||||
<ul class="flex flex-row mt-8 justify-center">
|
||||
{{- .Scratch.Set "paginator.ellipsed" false -}}
|
||||
{{ if $.Paginator.HasPrev }}
|
||||
<li>
|
||||
<a
|
||||
href="{{ $.Paginator.Prev.URL }}"
|
||||
class="mx-1 block min-w-[1.8rem] rounded text-center hover:bg-primary-600 hover:text-neutral"
|
||||
rel="prev"
|
||||
>←</a
|
||||
>
|
||||
</li>
|
||||
{{ end }}
|
||||
{{- range $.Paginator.Pagers -}}
|
||||
{{- $right := sub .TotalPages .PageNumber -}}
|
||||
{{- $showNumber := or (le .PageNumber 1) (eq $right 0) -}}
|
||||
{{- $showNumber := or $showNumber (and (gt .PageNumber (sub $.Paginator.PageNumber 3)) (lt .PageNumber (add $.Paginator.PageNumber 3))) -}}
|
||||
{{- if $showNumber -}}
|
||||
{{- $.Scratch.Set "paginator.ellipsed" false -}}
|
||||
{{- $.Scratch.Set "paginator.shouldEllipse" false -}}
|
||||
{{- else -}}
|
||||
{{- $.Scratch.Set "paginator.shouldEllipse" (not ($.Scratch.Get "paginator.ellipsed") ) -}}
|
||||
{{- $.Scratch.Set "paginator.ellipsed" true -}}
|
||||
{{- end -}}
|
||||
{{- if $showNumber -}}
|
||||
<li>
|
||||
<a
|
||||
href="{{ .URL }}"
|
||||
class="{{ if eq . $.Paginator }}
|
||||
bg-primary-200 dark:bg-primary-400 dark:text-neutral-800
|
||||
{{ end }} mx-1 block min-w-[1.8rem] rounded text-center hover:bg-primary-600 hover:text-neutral"
|
||||
>{{ .PageNumber }}</a
|
||||
>
|
||||
</li>
|
||||
{{- else if ($.Scratch.Get "paginator.shouldEllipse") -}}
|
||||
<li class="page-item ">
|
||||
<span class="page-link" aria-hidden="true">…</span>
|
||||
</li>
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{ if $.Paginator.HasNext }}
|
||||
<li>
|
||||
<a
|
||||
href="{{ $.Paginator.Next.URL }}"
|
||||
class="mx-1 block min-w-[1.8rem] rounded text-center hover:bg-primary-600 hover:text-neutral"
|
||||
rel="next"
|
||||
>→</a
|
||||
>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{- end -}}
|
||||
47
layouts/partials/recent-articles-demo.html
Normal file
47
layouts/partials/recent-articles-demo.html
Normal file
@@ -0,0 +1,47 @@
|
||||
{{ $recentArticles := 5 }}
|
||||
{{ $showMoreLinkDest := "/posts/" }}
|
||||
{{ if index .Site.Params.homepage "showRecentItems" }}
|
||||
{{ $recentArticles = .Site.Params.homepage.showRecentItems }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<h2 class="mt-8 text-2xl font-extrabold mb-10">{{ i18n "shortcode.recent_articles" | emojify }}</h2>
|
||||
|
||||
<div class="flex mb-6 px-4 py-2 mb-8 text-base rounded-md bg-primary-100 dark:bg-primary-900">
|
||||
<span class="flex items-center justify-between grow dark:text-neutral-300">
|
||||
<span class="prose dark:prose-invert"
|
||||
>This is a demo of theme's list configurations: <code id="config">card view</code></span
|
||||
>
|
||||
<button
|
||||
id="switch-config-button"
|
||||
class="px-4 !text-neutral !no-underline rounded-md bg-primary-600 hover:!bg-primary-500 dark:bg-primary-800 dark:hover:!bg-primary-700">
|
||||
Switch config ↻
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div id="CardViewProse" class="h-full">
|
||||
{{ partial "recent-articles/cardview.html" . }}
|
||||
</div>
|
||||
|
||||
<div id="CardViewScreenWidth" class="hidden h-full">
|
||||
{{ partial "recent-articles/cardview-fullwidth.html" . }}
|
||||
</div>
|
||||
|
||||
<div id="NormalView" class="hidden h-full">
|
||||
{{ partial "recent-articles/list.html" . }}
|
||||
</div>
|
||||
|
||||
{{ if .Site.Params.homepage.showMoreLink | default false }}
|
||||
{{ if index .Site.Params.homepage "showRecentItems" }}
|
||||
{{ $showMoreLinkDest = .Site.Params.homepage.showMoreLinkDest }}
|
||||
{{ end }}
|
||||
<div class="mt-10 flex justify-center">
|
||||
<a href="{{ $showMoreLinkDest }}">
|
||||
<button
|
||||
class="bg-transparent hover:text-primary-500 prose dark:prose-invert font-semibold py-2 px-4 border border-primary-500 hover:border-transparent rounded">
|
||||
{{ i18n "recent.show_more" | markdownify }}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
13
layouts/partials/recent-articles/cardview-fullwidth.html
Normal file
13
layouts/partials/recent-articles/cardview-fullwidth.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{{ $recentArticles := 5 }}
|
||||
{{ $recentArticles = .Site.Params.homepage.showRecentItems }}
|
||||
|
||||
|
||||
<div class="relative w-screen max-w-[1600px] px-[30px] start-[calc(max(-50vw,-800px)+50%)]">
|
||||
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5">
|
||||
{{ range first $recentArticles (.Paginate (where .Site.RegularPages "Type" "in"
|
||||
.Site.Params.mainSections)).Pages
|
||||
}}
|
||||
{{ partial "article-link/card.html" . }}
|
||||
{{ end }}
|
||||
</section>
|
||||
</div>
|
||||
11
layouts/partials/recent-articles/cardview.html
Normal file
11
layouts/partials/recent-articles/cardview.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{{ $recentArticles := 5 }}
|
||||
{{ $recentArticles = .Site.Params.homepage.showRecentItems }}
|
||||
|
||||
|
||||
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
|
||||
{{ range first $recentArticles (.Paginate (where .Site.RegularPages "Type" "in"
|
||||
.Site.Params.mainSections)).Pages
|
||||
}}
|
||||
{{ partial "article-link/card.html" . }}
|
||||
{{ end }}
|
||||
</section>
|
||||
9
layouts/partials/recent-articles/list.html
Normal file
9
layouts/partials/recent-articles/list.html
Normal file
@@ -0,0 +1,9 @@
|
||||
{{ $recentArticles := 5 }}
|
||||
{{ $recentArticles = .Site.Params.homepage.showRecentItems }}
|
||||
|
||||
|
||||
<section class="space-y-10 w-full">
|
||||
{{ range first $recentArticles (.Paginate (where .Site.RegularPages "Type" "in" .Site.Params.mainSections)).Pages }}
|
||||
{{ partial "article-link/simple.html" . }}
|
||||
{{ end }}
|
||||
</section>
|
||||
30
layouts/partials/recent-articles/main.html
Normal file
30
layouts/partials/recent-articles/main.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{{ $recentArticles := 5 }}
|
||||
{{ $showMoreLinkDest := "/posts/" }}
|
||||
{{ if .Site.Params.homepage.showRecent | default false }}
|
||||
{{ if index .Site.Params.homepage "showRecentItems" }}
|
||||
{{ $recentArticles = .Site.Params.homepage.showRecentItems }}
|
||||
{{ end }}
|
||||
<h2 class="mt-8 text-2xl font-extrabold mb-10">{{ i18n "shortcode.recent_articles" | emojify }}</h2>
|
||||
|
||||
{{ if and .Site.Params.homepage.cardView (not .Site.Params.homepage.cardViewScreenWidth) | default false }}
|
||||
{{ partial "recent-articles/cardview.html" . }}
|
||||
{{ else if and .Site.Params.homepage.cardView .Site.Params.homepage.cardViewScreenWidth | default false }}
|
||||
{{ partial "recent-articles/cardview-fullwidth.html" . }}
|
||||
{{ else }}
|
||||
{{ partial "recent-articles/list.html" . }}
|
||||
{{ end }}
|
||||
|
||||
{{ if .Site.Params.homepage.showMoreLink | default false }}
|
||||
{{ if index .Site.Params.homepage "showRecentItems" }}
|
||||
{{ $showMoreLinkDest = .Site.Params.homepage.showMoreLinkDest }}
|
||||
{{ end }}
|
||||
<div class="mt-10 flex justify-center">
|
||||
<a href="{{ $showMoreLinkDest | relLangURL }}">
|
||||
<button
|
||||
class="bg-transparent hover:text-primary-500 prose dark:prose-invert font-semibold py-2 px-4 border border-primary-500 hover:border-transparent rounded">
|
||||
{{ i18n "recent.show_more" | markdownify }}
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
11
layouts/partials/related.html
Normal file
11
layouts/partials/related.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{{ if .Params.showRelatedContent | default (.Site.Params.article.showRelatedContent | default false) }}
|
||||
{{ $related := .Site.RegularPages.Related . | first .Site.Params.article.relatedContentLimit }}
|
||||
{{ with $related }}
|
||||
<h2 class="mt-8 text-2xl font-extrabold mb-10">{{ i18n "article.related_articles" | emojify }}</h2>
|
||||
<section class="w-full grid gap-4 sm:grid-cols-2 md:grid-cols-3">
|
||||
{{ range . }}
|
||||
{{ partial "article-link/card-related.html" . }}
|
||||
{{ end }}
|
||||
</section>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
73
layouts/partials/schema.html
Normal file
73
layouts/partials/schema.html
Normal file
@@ -0,0 +1,73 @@
|
||||
{{ if .IsHome -}}
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
"@id": {{ site.Home.Permalink | safeURL }},
|
||||
"name": "{{ .Site.Title | safeJS }}",
|
||||
{{ with .Site.Params.description }}"description": "{{ . | safeJS }}",{{ end }}
|
||||
{{ with .Site.LanguageCode }}"inLanguage": "{{ . }}",{{ end }}
|
||||
"url": {{ site.Home.Permalink | safeURL }},
|
||||
{{ with .Site.Params.keywords }}"keywords": {{ . }},{{ end }}
|
||||
"publisher" : {
|
||||
"@type": "Person",
|
||||
"name": "{{ .Site.Params.Author.name | safeJS }}"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{{ else }}
|
||||
{{- $iso8601 := "2006-01-02T15:04:05-07:00" -}}
|
||||
<script type="application/ld+json">
|
||||
[{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Article",
|
||||
"articleSection": "{{ (site.GetPage .Section).Title | safeJS }}",
|
||||
"name": "{{ .Title | safeJS }}",
|
||||
"headline": "{{ .Title | safeJS }}",
|
||||
{{ with .Description }}"description": "{{ . | safeJS }}",{{ end }}
|
||||
{{ with .Site.LanguageCode }}"inLanguage": "{{ . }}",{{ end }}
|
||||
"url" : {{ .Permalink }},
|
||||
"author" : {
|
||||
"@type": "Person",
|
||||
"name": "{{ .Site.Params.Author.name | safeJS }}"
|
||||
},
|
||||
{{ with .PublishDate }}"copyrightYear": "{{ .Format "2006" }}",{{ end }}
|
||||
{{ with .Date }}"dateCreated": "{{ .Format $iso8601 }}",{{ end }}
|
||||
{{ with .PublishDate }}"datePublished": "{{ .Format $iso8601 }}",{{ end }}
|
||||
{{ with .ExpiryDate }}"expires": "{{ .Format $iso8601 }}",{{ end }}
|
||||
{{ with .Lastmod }}"dateModified": "{{ .Format $iso8601 }}",{{ end }}
|
||||
{{ if .Keywords }}
|
||||
{{ with .Keywords }}"keywords": {{ . }},{{ end }}
|
||||
{{ else }}
|
||||
{{ with .Params.tags }}"keywords": {{ . }},{{ end }}
|
||||
{{ end }}
|
||||
"mainEntityOfPage": "true",
|
||||
"wordCount": "{{ .WordCount }}"
|
||||
}{{ if site.Params.enableStructuredBreadcrumbs | default false }},
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
"itemListElement": [
|
||||
{{- $position := 0 -}}
|
||||
{{- range .Ancestors -}}
|
||||
{{- if not .IsHome -}}
|
||||
{{- $position = add $position 1 -}}
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": {{ $position }},
|
||||
"name": "{{ .Title }}",
|
||||
"item": {{ .Permalink }}
|
||||
},
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- $position = add $position 1 -}}
|
||||
{
|
||||
"@type": "ListItem",
|
||||
"position": {{ $position }},
|
||||
"name": "{{ .Title }}",
|
||||
"item": {{ .Permalink }}
|
||||
}
|
||||
]
|
||||
}{{ end }}]
|
||||
</script>
|
||||
{{ end }}
|
||||
21
layouts/partials/scroll-to-top.html
Normal file
21
layouts/partials/scroll-to-top.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{{ $isRTL := .Site.Params.rtl | default false }}
|
||||
{{ $coffeeIsRight := and (eq (lower site.Params.buymeacoffee.globalWidgetPosition) "right") .Site.Params.buymeacoffee.globalWidget }}
|
||||
{{ if not $coffeeIsRight }}
|
||||
{{ $coffeeIsRight = false }}
|
||||
{{ end }}
|
||||
|
||||
{{ $needAvoidCoffee := ne $coffeeIsRight $isRTL }}
|
||||
{{ $toTopYOffset := cond $needAvoidCoffee "bottom-24" "bottom-6" }}
|
||||
|
||||
|
||||
<div
|
||||
id="scroll-to-top"
|
||||
class="fixed {{ $toTopYOffset }} end-6 z-50 transform translate-y-4 opacity-0 duration-200">
|
||||
<a
|
||||
href="#the-top"
|
||||
class="pointer-events-auto flex h-12 w-12 items-center justify-center rounded-full bg-neutral/50 text-xl text-neutral-700 hover:text-primary-600 dark:bg-neutral-800/50 dark:text-neutral dark:hover:text-primary-400"
|
||||
aria-label="{{ i18n "nav.scroll_to_top_title" }}"
|
||||
title="{{ i18n "nav.scroll_to_top_title" }}">
|
||||
↑
|
||||
</a>
|
||||
</div>
|
||||
43
layouts/partials/search.html
Normal file
43
layouts/partials/search.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<div
|
||||
id="search-wrapper"
|
||||
class="invisible fixed inset-0 flex h-screen w-screen cursor-default flex-col bg-neutral-500/50 p-4 backdrop-blur-sm dark:bg-neutral-900/50 sm:p-6 md:p-[10vh] lg:p-[12vh] z-500"
|
||||
data-url="{{ "" | absLangURL }}">
|
||||
<div
|
||||
id="search-modal"
|
||||
class="flex flex-col w-full max-w-3xl min-h-0 mx-auto border rounded-md shadow-lg top-20 border-neutral-200 bg-neutral dark:border-neutral-700 dark:bg-neutral-800">
|
||||
<header class="relative z-10 flex items-center justify-between flex-none px-2">
|
||||
<form class="flex items-center flex-auto min-w-0">
|
||||
<div class="flex items-center justify-center w-8 h-8 text-neutral-400">
|
||||
{{ partial "icon.html" "search" }}
|
||||
</div>
|
||||
<input
|
||||
type="search"
|
||||
id="search-query"
|
||||
class="flex flex-auto h-12 mx-1 bg-transparent appearance-none focus:outline-dotted focus:outline-2 focus:outline-transparent"
|
||||
placeholder="{{ i18n "search.input_placeholder" }}"
|
||||
tabindex="0">
|
||||
</form>
|
||||
<button
|
||||
id="close-search-button"
|
||||
class="flex items-center justify-center w-8 h-8 text-neutral-700 hover:text-primary-600 dark:text-neutral dark:hover:text-primary-400"
|
||||
title="{{ i18n "search.close_button_title" }}">
|
||||
{{ partial "icon.html" "xmark" }}
|
||||
</button>
|
||||
</header>
|
||||
<section class="flex-auto px-2 overflow-auto">
|
||||
<ul id="search-results">
|
||||
<!-- <li class="mb-2">
|
||||
<a class="flex items-center px-3 py-2 rounded-md appearance-none bg-neutral-100 dark:bg-neutral-700 focus:bg-primary-100 hover:bg-primary-100 dark:hover:bg-primary-900 dark:focus:bg-primary-900 focus:outline-dotted focus:outline-transparent focus:outline-2" href="${value.item.permalink}" tabindex="0">
|
||||
<div class="grow">
|
||||
<div class="-mb-1 text-lg font-bold">${value.item.title}</div>
|
||||
<div class="text-sm text-neutral-500 dark:text-neutral-400">${value.item.section}<span class="px-2 text-primary-500">·</span>${value.item.date}</span></div>
|
||||
<div class="text-sm italic">${value.item.summary}</div>
|
||||
</div>
|
||||
<div class="ml-2 ltr:block rtl:hidden text-neutral-500">→</div>
|
||||
<div class="mr-2 ltr:hidden rtl:block text-neutral-500">←</div>
|
||||
</a>
|
||||
</li> -->
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
5
layouts/partials/series/series-closed.html
Normal file
5
layouts/partials/series/series-closed.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{{ if .Params.series }}
|
||||
<details class="mt-2 mb-5 overflow-hidden rounded-lg ms-0 ps-5">
|
||||
{{ partial "series/series_base.html" . }}
|
||||
</details>
|
||||
{{ end }}
|
||||
7
layouts/partials/series/series.html
Normal file
7
layouts/partials/series/series.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{{ if .Params.series }}
|
||||
<details
|
||||
class="mt-2 mb-5 overflow-hidden rounded-lg ms-0 ps-5"
|
||||
{{ if .Params.seriesOpened | default (.Site.Params.article.seriesOpened | default false) }}open{{ end }}>
|
||||
{{ partial "series/series_base.html" . }}
|
||||
</details>
|
||||
{{ end }}
|
||||
25
layouts/partials/series/series_base.html
Normal file
25
layouts/partials/series/series_base.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{{ if .Params.series }}
|
||||
<summary
|
||||
class="py-1 text-lg font-semibold cursor-pointer bg-primary-200 text-neutral-800 -ms-5 ps-5 dark:bg-primary-800 dark:text-neutral-100">
|
||||
{{ index .Params.series 0 }} -
|
||||
{{ i18n "article.part_of_series" }}
|
||||
</summary>
|
||||
{{ $seriesName := strings.ToLower (index .Params.series 0) }}
|
||||
{{ range $post := sort (index .Site.Taxonomies.series $seriesName) "Params.series_order" }}
|
||||
{{ if eq $post.Permalink $.Page.Permalink }}
|
||||
<div
|
||||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||||
{{ i18n "article.part" }} {{ $post.Params.series_order }}:
|
||||
{{ i18n "article.this_article" }}
|
||||
</div>
|
||||
{{ else }}
|
||||
<div
|
||||
class="py-1 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||||
<a href="{{ $post.RelPermalink }}">
|
||||
{{ i18n "article.part" }} {{ $post.Params.series_order }}:
|
||||
{{ $post.Params.title }}
|
||||
</a>
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
17
layouts/partials/sharing-links.html
Normal file
17
layouts/partials/sharing-links.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{{ with .Params.sharingLinks | default (.Site.Params.article.sharingLinks | default false) }}
|
||||
{{ $links := site.Data.sharing }}
|
||||
<section class="flex flex-row flex-wrap justify-center pt-4 text-xl">
|
||||
{{ range . }}
|
||||
{{ with index $links . }}
|
||||
<a
|
||||
target="_blank"
|
||||
class="m-1 rounded bg-neutral-300 p-1.5 text-neutral-700 hover:bg-primary-500 hover:text-neutral dark:bg-neutral-700 dark:text-neutral-300 dark:hover:bg-primary-400 dark:hover:text-neutral-800"
|
||||
href="{{ printf .url $.Permalink $.Title }}"
|
||||
title="{{ i18n .title }}"
|
||||
aria-label="{{ i18n .title }}">
|
||||
{{ partial "icon.html" .icon }}
|
||||
</a>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</section>
|
||||
{{ end }}
|
||||
55
layouts/partials/sponsors.html
Normal file
55
layouts/partials/sponsors.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{{ with site.Data.sponsors }}
|
||||
<section class="sponsors-section mt-16 mb-8">
|
||||
<div class="flex flex-col items-center mb-6">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-2xl text-primary-500">
|
||||
{{ partial "icon.html" "heart" }}
|
||||
</span>
|
||||
<h2 class="text-2xl font-extrabold text-neutral-800 dark:text-neutral-200">
|
||||
{{ i18n "sponsors.title" | default "Sponsors" }}
|
||||
</h2>
|
||||
</div>
|
||||
<p class="text-neutral-600 dark:text-neutral-400 text-center max-w-md">
|
||||
{{ i18n "sponsors.description" | default "Special thanks to our sponsors who help make Blowfish possible." }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
{{ range . }}
|
||||
<a
|
||||
href="{{ .profile_url }}"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="group relative flex w-24 flex-col items-center"
|
||||
title="{{ .username }}"
|
||||
aria-label="Sponsor: {{ .username }}">
|
||||
<img
|
||||
class="nozoom h-16 w-16 rounded-full ring-2 ring-primary-500 transition-transform group-hover:scale-110"
|
||||
src="{{ .avatar_url }}"
|
||||
alt="{{ .username }}"
|
||||
width="64"
|
||||
height="64"
|
||||
loading="lazy">
|
||||
<span class="mt-2 block w-full truncate text-center text-sm text-neutral-600 transition-colors group-hover:text-primary-500 dark:text-neutral-400">
|
||||
@{{ .username }}
|
||||
</span>
|
||||
<span
|
||||
class="pointer-events-none absolute left-1/2 top-full z-10 mt-1 w-max max-w-48 -translate-x-1/2 rounded-md bg-neutral-900 px-2 py-1 text-xs text-white opacity-0 shadow-md transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100 group-hover:visible group-focus-within:visible dark:bg-neutral-100 dark:text-neutral-900 invisible">
|
||||
@{{ .username }}
|
||||
</span>
|
||||
</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
<div class="mt-8 flex justify-center">
|
||||
<a
|
||||
href="https://github.com/sponsors/nunocoracao"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-primary-600 text-white hover:bg-primary-500 transition-colors">
|
||||
<span>{{ partial "icon.html" "heart" }}</span>
|
||||
<span>{{ i18n "sponsors.cta" | default "Become a Sponsor" }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
{{ end }}
|
||||
67
layouts/partials/term-link/card.html
Normal file
67
layouts/partials/term-link/card.html
Normal file
@@ -0,0 +1,67 @@
|
||||
{{ $disableImageOptimization := .Page.Site.Params.disableImageOptimization | default false }}
|
||||
|
||||
{{ $featured := "" }}
|
||||
{{ $featuredURL := "" }}
|
||||
{{ with .Page.Params.featureimage }}
|
||||
{{ if or (strings.HasPrefix . "http:") (strings.HasPrefix . "https:") }}
|
||||
{{ $featured = resources.GetRemote . }}
|
||||
{{ else }}
|
||||
{{ $featured = resources.Get . }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if not $featured }}
|
||||
{{ $images := .Page.Resources.ByType "image" }}
|
||||
{{ range slice "*feature*" "*cover*" "*thumbnail*" }}
|
||||
{{ if not $featured }}{{ $featured = $images.GetMatch . }}{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ with $featured }}
|
||||
{{ $featuredURL = .RelPermalink }}
|
||||
{{ if not (or $disableImageOptimization (eq .MediaType.SubType "svg")) }}
|
||||
{{ $featuredURL = (.Resize "600x").RelPermalink }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
|
||||
<div class="min-w-full">
|
||||
<div class="border-neutral-200 dark:border-neutral-700 border-2 rounded overflow-hidden shadow-2xl relative">
|
||||
{{ with $featuredURL }}
|
||||
<figure class="not-prose flex-none relative overflow-hidden thumbnail_card">
|
||||
<img
|
||||
src="{{ . }}"
|
||||
alt="{{ $.Page.Title }}"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
fetchpriority="low"
|
||||
class="not-prose absolute inset-0 w-full h-full object-cover">
|
||||
</figure>
|
||||
{{ end }}
|
||||
{{ if site.Params.taxonomy.showTermCount | default true }}
|
||||
<span class="absolute bottom-0 right-0 m-2">
|
||||
<span class="flex">
|
||||
<span
|
||||
class="rounded-md border border-primary-400 px-1 py-[1px] text-xl font-normal text-primary-700 dark:border-primary-600 dark:text-primary-400">
|
||||
{{ .Count }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
{{ end }}
|
||||
<div class="px-6 py-4">
|
||||
<a
|
||||
{{ with .Page.Params.externalUrl }}
|
||||
href="{{ . }}" target="_blank" rel="external"
|
||||
{{ else }}
|
||||
href="{{ .Page.RelPermalink }}"
|
||||
{{ end }}
|
||||
class="not-prose before:absolute before:inset-0 decoration-primary-500 dark:text-neutral text-xl font-bold text-neutral-800 hover:underline hover:underline-offset-2">
|
||||
<div
|
||||
class="font-bold text-xl text-neutral-800 decoration-primary-500 hover:underline hover:underline-offset-2 dark:text-neutral">
|
||||
{{ .Page.Title | emojify }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="px-6 pt-4 pb-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
15
layouts/partials/term-link/text.html
Normal file
15
layouts/partials/term-link/text.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<article class="w-full px-2 my-3 overflow-hidden sm:w-1/2 md:w-1/3 lg:w-1/4 xl:w-1/4">
|
||||
<h2 class="flex items-center">
|
||||
<a
|
||||
class="text-xl font-medium decoration-primary-500 hover:underline hover:underline-offset-2"
|
||||
href="{{ .Page.RelPermalink }}"
|
||||
>{{ .Page.Title }}</a
|
||||
>
|
||||
{{ if site.Params.taxonomy.showTermCount | default true }}
|
||||
<span class="px-2 text-base text-primary-500">·</span>
|
||||
<span class="text-base text-neutral-400">
|
||||
{{ .Count }}
|
||||
</span>
|
||||
{{ end }}
|
||||
</h2>
|
||||
</article>
|
||||
125
layouts/partials/toc.html
Normal file
125
layouts/partials/toc.html
Normal file
@@ -0,0 +1,125 @@
|
||||
<details
|
||||
open
|
||||
id="TOCView"
|
||||
class="toc-right mt-0 overflow-y-auto overscroll-contain bf-scrollbar rounded-lg -ms-5 ps-5 pe-2 hidden lg:block">
|
||||
<summary
|
||||
class="block py-1 text-lg font-semibold cursor-pointer bg-neutral-100 text-neutral-800 -ms-5 ps-5 dark:bg-neutral-700 dark:text-neutral-100 lg:hidden">
|
||||
{{ i18n "article.table_of_contents" }}
|
||||
</summary>
|
||||
<div
|
||||
class="min-w-[220px] py-2 border-dotted border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||||
{{ .TableOfContents | emojify }}
|
||||
</div>
|
||||
</details>
|
||||
<details class="toc-inside mt-0 overflow-hidden rounded-lg -ms-5 ps-5 lg:hidden">
|
||||
<summary
|
||||
class="py-1 text-lg font-semibold cursor-pointer bg-neutral-100 text-neutral-800 -ms-5 ps-5 dark:bg-neutral-700 dark:text-neutral-100 lg:hidden">
|
||||
{{ i18n "article.table_of_contents" }}
|
||||
</summary>
|
||||
<div
|
||||
class="py-2 border-dotted border-neutral-300 border-s-1 -ms-5 ps-5 dark:border-neutral-600">
|
||||
{{ .TableOfContents | emojify }}
|
||||
</div>
|
||||
</details>
|
||||
|
||||
{{ if .Site.Params.smartTOC }}
|
||||
<script>
|
||||
(function () {
|
||||
'use strict'
|
||||
|
||||
const SCROLL_OFFSET_RATIO = 0.33
|
||||
const TOC_SELECTOR = '#TableOfContents'
|
||||
const ANCHOR_SELECTOR = '.anchor'
|
||||
const TOC_LINK_SELECTOR = 'a[href^="#"]'
|
||||
const NESTED_LIST_SELECTOR = 'li ul'
|
||||
const ACTIVE_CLASS = 'active'
|
||||
let isJumpingToAnchor = false
|
||||
|
||||
function getActiveAnchorId(anchors, offsetRatio) {
|
||||
const threshold = window.scrollY + window.innerHeight * offsetRatio
|
||||
const tocLinks = [...document.querySelectorAll('#TableOfContents a[href^="#"]')]
|
||||
const tocIds = new Set(tocLinks.map(link => link.getAttribute('href').substring(1)))
|
||||
|
||||
if (isJumpingToAnchor) {
|
||||
for (let i = 0; i < anchors.length; i++) {
|
||||
const anchor = anchors[i]
|
||||
if (!tocIds.has(anchor.id)) continue
|
||||
const top = anchor.getBoundingClientRect().top + window.scrollY
|
||||
if (Math.abs(window.scrollY - top) < 100) {
|
||||
return anchor.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = anchors.length - 1; i >= 0; i--) {
|
||||
const top = anchors[i].getBoundingClientRect().top + window.scrollY
|
||||
if (top <= threshold && tocIds.has(anchors[i].id)) {
|
||||
return anchors[i].id
|
||||
}
|
||||
}
|
||||
return anchors.find(anchor => tocIds.has(anchor.id))?.id || ''
|
||||
}
|
||||
|
||||
function updateTOC({ toc, anchors, links, scrollOffset, collapseInactive }) {
|
||||
const activeId = getActiveAnchorId(anchors, scrollOffset)
|
||||
if (!activeId) return
|
||||
|
||||
links.forEach(link => {
|
||||
const isActive = link.getAttribute('href') === `#${activeId}`
|
||||
link.classList.toggle(ACTIVE_CLASS, isActive)
|
||||
|
||||
if (collapseInactive) {
|
||||
const ul = link.closest('li')?.querySelector('ul')
|
||||
if (ul) ul.style.display = isActive ? '' : 'none'
|
||||
}
|
||||
})
|
||||
|
||||
if (collapseInactive) {
|
||||
const activeLink = toc.querySelector(`a[href="#${CSS.escape(activeId)}"]`)
|
||||
let el = activeLink
|
||||
while (el && el !== toc) {
|
||||
if (el.tagName === 'UL') el.style.display = ''
|
||||
if (el.tagName === 'LI') el.querySelector('ul')?.style.setProperty('display', '')
|
||||
el = el.parentElement
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initTOC() {
|
||||
const toc = document.querySelector(TOC_SELECTOR)
|
||||
if (!toc) return
|
||||
|
||||
const collapseInactive = {{ if site.Params.smartTOCHideUnfocusedChildren }}true{{ else }}false{{ end }}
|
||||
const anchors = [...document.querySelectorAll(ANCHOR_SELECTOR)]
|
||||
const links = [...toc.querySelectorAll(TOC_LINK_SELECTOR)]
|
||||
|
||||
if (collapseInactive) {
|
||||
toc.querySelectorAll(NESTED_LIST_SELECTOR).forEach(ul => ul.style.display = 'none')
|
||||
}
|
||||
|
||||
links.forEach(link => {
|
||||
link.addEventListener('click', () => {
|
||||
isJumpingToAnchor = true
|
||||
})
|
||||
})
|
||||
|
||||
const config = {
|
||||
toc,
|
||||
anchors,
|
||||
links,
|
||||
scrollOffset: SCROLL_OFFSET_RATIO,
|
||||
collapseInactive
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', () => updateTOC(config), { passive: true })
|
||||
window.addEventListener('hashchange', () => updateTOC(config), { passive: true })
|
||||
|
||||
updateTOC(config)
|
||||
}
|
||||
|
||||
document.readyState === 'loading'
|
||||
? document.addEventListener('DOMContentLoaded', initTOC)
|
||||
: initTOC()
|
||||
})()
|
||||
</script>
|
||||
{{ end }}
|
||||
195
layouts/partials/vendor.html
Normal file
195
layouts/partials/vendor.html
Normal file
@@ -0,0 +1,195 @@
|
||||
{{/* Mermaid */}}
|
||||
{{ if .Page.HasShortcode "mermaid" }}
|
||||
{{ $mermaidLib := resources.Get "lib/mermaid/mermaid.min.js" }}
|
||||
{{ $mermaidConfig := resources.Get "js/mermaid.js" }}
|
||||
{{ $mermaidConfig := $mermaidConfig | resources.Minify }}
|
||||
{{ $mermaidJS := slice $mermaidLib $mermaidConfig | resources.Concat "js/mermaid.bundle.js" | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
defer
|
||||
type="text/javascript"
|
||||
src="{{ $mermaidJS.RelPermalink }}"
|
||||
integrity="{{ $mermaidJS.Data.Integrity }}"></script>
|
||||
{{ end }}
|
||||
|
||||
{{/* Chart */}}
|
||||
{{ if .Page.HasShortcode "chart" }}
|
||||
{{ $chartLib := resources.Get "lib/chart/chart.min.js" }}
|
||||
{{ $chartConfig := resources.Get "js/chart.js" }}
|
||||
{{ $chartConfig := $chartConfig | resources.Minify }}
|
||||
{{ $chartJS := slice $chartLib $chartConfig | resources.Concat "js/chart.bundle.js" | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
defer
|
||||
type="text/javascript"
|
||||
src="{{ $chartJS.RelPermalink }}"
|
||||
integrity="{{ $chartJS.Data.Integrity }}"></script>
|
||||
{{ end }}
|
||||
|
||||
{{/* Katex */}}
|
||||
{{ if .Page.HasShortcode "katex" }}
|
||||
{{ $katexCSS := resources.Get "lib/katex/katex.min.css" }}
|
||||
{{ $katexCSS := $katexCSS | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<link
|
||||
type="text/css"
|
||||
rel="stylesheet"
|
||||
href="{{ $katexCSS.RelPermalink }}"
|
||||
integrity="{{ $katexCSS.Data.Integrity }}">
|
||||
{{ $katexLib := resources.Get "lib/katex/katex.min.js" }}
|
||||
{{ $katexRenderLib := resources.Get "lib/katex/auto-render.min.js" }}
|
||||
{{ $katexJS := slice $katexLib $katexRenderLib | resources.Concat "js/katex.bundle.js" | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
defer
|
||||
type="text/javascript"
|
||||
src="{{ $katexJS.RelPermalink }}"
|
||||
integrity="{{ $katexJS.Data.Integrity }}"
|
||||
id="katex-render"></script>
|
||||
{{ $katexFonts := resources.Match "lib/katex/fonts/*" }}
|
||||
{{ range $katexFonts }}
|
||||
<!-- {{ .RelPermalink }} -->
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* TypeIt */}}
|
||||
{{ if .Page.HasShortcode "typeit" }}
|
||||
{{ $typeitLib := resources.Get "lib/typeit/typeit.umd.js" | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script defer src="{{ $typeitLib.RelPermalink }}" integrity="{{ $typeitLib.Data.Integrity }}"></script>
|
||||
{{ end }}
|
||||
|
||||
{{/* Packery */}}
|
||||
{{ if .Page.HasShortcode "gallery" }}
|
||||
{{ $galleryCSS := resources.Get "css/components/gallery.css" }}
|
||||
{{ $galleryCSS = $galleryCSS | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<link
|
||||
type="text/css"
|
||||
rel="stylesheet"
|
||||
href="{{ $galleryCSS.RelPermalink }}"
|
||||
integrity="{{ $galleryCSS.Data.Integrity }}">
|
||||
{{ $packeryLib := resources.Get "lib/packery/packery.pkgd.min.js" }}
|
||||
{{ $packeryLib = $packeryLib | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
defer
|
||||
type="text/javascript"
|
||||
src="{{ $packeryLib.RelPermalink }}"
|
||||
integrity="{{ $packeryLib.Data.Integrity }}"></script>
|
||||
|
||||
{{ $jsShortcodeGallery := resources.Get "js/shortcodes/gallery.js" }}
|
||||
{{ $jsShortcodeGallery = $jsShortcodeGallery | resources.Minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $jsShortcodeGallery.RelPermalink }}"
|
||||
integrity="{{ $jsShortcodeGallery.Data.Integrity }}"></script>
|
||||
{{ end }}
|
||||
|
||||
{{/* tw-elements */}}
|
||||
{{ if or (.Page.HasShortcode "carousel") (.Page.HasShortcode "timeline") }}
|
||||
{{ $carouselCSS := resources.Get "css/components/carousel.css" }}
|
||||
{{ $carouselCSS = $carouselCSS | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<link
|
||||
type="text/css"
|
||||
rel="stylesheet"
|
||||
href="{{ $carouselCSS.RelPermalink }}"
|
||||
integrity="{{ $carouselCSS.Data.Integrity }}">
|
||||
{{ $twelementsLib := resources.Get "lib/tw-elements/index.min.js" }}
|
||||
{{ $twelementsLib = $twelementsLib | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
defer
|
||||
type="text/javascript"
|
||||
src="{{ $twelementsLib.RelPermalink }}"
|
||||
integrity="{{ $twelementsLib.Data.Integrity }}"></script>
|
||||
{{ end }}
|
||||
|
||||
{{/* youtubeLite */}}
|
||||
{{ if .Page.HasShortcode "youtubeLite" }}
|
||||
{{ $youtubeLiteCSS := resources.Get "lib/lite-youtube-embed/lite-yt-embed.css" }}
|
||||
{{ $youtubeLiteCSS = $youtubeLiteCSS | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<link
|
||||
type="text/css"
|
||||
rel="stylesheet"
|
||||
href="{{ $youtubeLiteCSS.RelPermalink }}"
|
||||
integrity="{{ $youtubeLiteCSS.Data.Integrity }}">
|
||||
{{ $youtubeLiteLib := resources.Get "lib/lite-youtube-embed/lite-yt-embed.js" }}
|
||||
{{ $youtubeLiteLib = $youtubeLiteLib | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="{{ $youtubeLiteLib.RelPermalink }}"
|
||||
integrity="{{ $youtubeLiteLib.Data.Integrity }}"></script>
|
||||
{{ end }}
|
||||
|
||||
{{/* Repo cards */}}
|
||||
{{ $repoCards := slice "codeberg" "forgejo" "gitea" "github" "hugging-face" }}
|
||||
{{ $hasRepoCards := false }}
|
||||
{{ range $repoCards }}
|
||||
{{ if $.Page.HasShortcode . }}
|
||||
{{ $hasRepoCards = true }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if $hasRepoCards }}
|
||||
{{ $repoColors := site.Data.repoColors }}
|
||||
{{ $cssRules := slice }}
|
||||
|
||||
{{/* default color */}}
|
||||
{{ $cssRules = $cssRules | append ".language-dot[data-language=\"default\"] { background-color: #0077b6; }" }}
|
||||
|
||||
{{/* Hugging Face model color */}}
|
||||
{{ $cssRules = $cssRules | append ".language-dot[data-language=\"model\"] { background-color: #ff6b35; }" }}
|
||||
|
||||
{{ range $lang, $color := $repoColors }}
|
||||
{{ $cssRules = $cssRules | append (printf ".language-dot[data-language=\"%s\"] { background-color: %s; }" $lang $color) }}
|
||||
{{ end }}
|
||||
{{ $repoCardCSS := resources.FromString "css/repo-cards.css" (delimit $cssRules "\n")
|
||||
| minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512")
|
||||
}}
|
||||
<link rel="stylesheet" href="{{ $repoCardCSS.RelPermalink }}" integrity="{{ $repoCardCSS.Data.Integrity }}">
|
||||
{{ end }}
|
||||
|
||||
{{/* tabs */}}
|
||||
{{ if .Page.HasShortcode "tabs" }}
|
||||
{{ $tabJS := resources.Get "js/shortcodes/tabs.js" }}
|
||||
{{ with $tabJS | minify | resources.Fingerprint (.Site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script src="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}" crossorigin="anonymous"></script>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{/* Firebase */}}
|
||||
{{ if site.Params.firebase.apiKey }}
|
||||
{{ $firebase := resources.Get "js/firebase.js" }}
|
||||
{{ $firebase = $firebase | resources.Minify | resources.Fingerprint (site.Params.fingerprintAlgorithm | default "sha512") }}
|
||||
<script type="module" src="{{ $firebase.RelPermalink }}" integrity="{{ $firebase.Data.Integrity }}"></script>
|
||||
|
||||
{{ if in (slice "page" "section") .Kind }}
|
||||
{{ $translations := .AllTranslations }}
|
||||
{{ with .File }}
|
||||
{{ $path := .Path }}
|
||||
{{ range $translations }}
|
||||
{{ $path = replace $path (print "." .Lang ".md") ".md" }}
|
||||
{{ end }}
|
||||
{{ partial "inline/firebase-config.html" (dict "views" (printf "views_%s" $path) "likes" (printf "likes_%s" $path)) }}
|
||||
{{ end }}
|
||||
{{ else if eq .Kind "term" }}
|
||||
{{ partial "inline/firebase-config.html" (dict "views" (printf "views_term_%s" .Data.Term) "likes" (printf "likes_term_%s" .Data.Term)) }}
|
||||
{{ else if eq .Kind "taxonomy" }}
|
||||
{{ partial "inline/firebase-config.html" (dict "views" (printf "views_taxonomy_%s" .Data.Plural) "likes" (printf "likes_taxonomy_%s" .Data.Plural)) }}
|
||||
{{ else if eq .Kind "home" }}
|
||||
{{ partial "inline/firebase-config.html" (dict "views" "views_home" "likes" "likes_home") }}
|
||||
{{ end }}
|
||||
|
||||
{{ end }}
|
||||
|
||||
{{ define "_partials/inline/firebase-config.html" }}
|
||||
<script id="firebase-config"
|
||||
type="application/json"
|
||||
data-views="{{ .views }}"
|
||||
data-likes="{{ .likes }}">
|
||||
{
|
||||
"config": {
|
||||
"apiKey": "{{ site.Params.firebase.apiKey }}",
|
||||
"authDomain": "{{ site.Params.firebase.authDomain }}",
|
||||
"projectId": "{{ site.Params.firebase.projectId }}",
|
||||
"storageBucket": "{{ site.Params.firebase.storageBucket }}",
|
||||
"messagingSenderId": "{{ site.Params.firebase.messagingSenderId }}",
|
||||
"appId": "{{ site.Params.firebase.appId }}",
|
||||
"measurementId": "{{ site.Params.firebase.measurementId }}"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{{ end }}
|
||||
Reference in New Issue
Block a user