Update to current version
All checks were successful
Building & Deploying Website / Deploy-Website (push) Successful in 12s

This commit is contained in:
2025-11-05 23:14:41 +01:00
parent a8304db3e2
commit 05f0b104d4
300 changed files with 40464 additions and 6492 deletions

View File

@@ -0,0 +1,7 @@
<section class="container centered">
<div class="error">
<h1>404</h1>
<h2>{{ i18n "page_not_found" }}</h2>
<p>{{ i18n "page_does_not_exist" }}<br />{{ i18n "head_back" .Site.BaseURL | safeHTML }}</p>
</div>
</section>

View File

@@ -0,0 +1,13 @@
<script type="text/javascript">
!function(T,l,y){var S=T.location,k="script",D="connectionString",C="ingestionendpoint",I="disableExceptionTracking",E="ai.device.",b="toLowerCase",w="crossOrigin",N="POST",e="appInsightsSDK",t=y.name||"appInsights";(y.name||T[e])&&(T[e]=t);var n=T[t]||function(d){var g=!1,f=!1,m={initialize:!0,queue:[],sv:"5",version:2,config:d};function v(e,t){var n={},a="Browser";return n[E+"id"]=a[b](),n[E+"type"]=a,n["ai.operation.name"]=S&&S.pathname||"_unknown_",n["ai.internal.sdkVersion"]="javascript:snippet_"+(m.sv||m.version),{time:function(){var e=new Date;function t(e){var t=""+e;return 1===t.length&&(t="0"+t),t}return e.getUTCFullYear()+"-"+t(1+e.getUTCMonth())+"-"+t(e.getUTCDate())+"T"+t(e.getUTCHours())+":"+t(e.getUTCMinutes())+":"+t(e.getUTCSeconds())+"."+((e.getUTCMilliseconds()/1e3).toFixed(3)+"").slice(2,5)+"Z"}(),name:"Microsoft.ApplicationInsights."+e.replace(/-/g,"")+"."+t,sampleRate:100,tags:n,data:{baseData:{ver:2}}}}var h=d.url||y.src;if(h){function a(e){var t,n,a,i,r,o,s,c,u,p,l;g=!0,m.queue=[],f||(f=!0,t=h,s=function(){var e={},t=d.connectionString;if(t)for(var n=t.split(";"),a=0;a<n.length;a++){var i=n[a].split("=");2===i.length&&(e[i[0][b]()]=i[1])}if(!e[C]){var r=e.endpointsuffix,o=r?e.location:null;e[C]="https://"+(o?o+".":"")+"dc."+(r||"services.visualstudio.com")}return e}(),c=s[D]||d[D]||"",u=s[C],p=u?u+"/v2/track":d.endpointUrl,(l=[]).push((n="SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details)",a=t,i=p,(o=(r=v(c,"Exception")).data).baseType="ExceptionData",o.baseData.exceptions=[{typeName:"SDKLoadFailed",message:n.replace(/\./g,"-"),hasFullStack:!1,stack:n+"\nSnippet failed to load ["+a+"] -- Telemetry is disabled\nHelp Link: https://go.microsoft.com/fwlink/?linkid=2128109\nHost: "+(S&&S.pathname||"_unknown_")+"\nEndpoint: "+i,parsedStack:[]}],r)),l.push(function(e,t,n,a){var i=v(c,"Message"),r=i.data;r.baseType="MessageData";var o=r.baseData;return o.message='AI (Internal): 99 message:"'+("SDK LOAD Failure: Failed to load Application Insights SDK script (See stack for details) ("+n+")").replace(/\"/g,"")+'"',o.properties={endpoint:a},i}(0,0,t,p)),function(e,t){if(JSON){var n=T.fetch;if(n&&!y.useXhr)n(t,{method:N,body:JSON.stringify(e),mode:"cors"});else if(XMLHttpRequest){var a=new XMLHttpRequest;a.open(N,t),a.setRequestHeader("Content-type","application/json"),a.send(JSON.stringify(e))}}}(l,p))}function i(e,t){f||setTimeout(function(){!t&&m.core||a()},500)}var e=function(){var n=l.createElement(k);n.src=h;var e=y[w];return!e&&""!==e||"undefined"==n[w]||(n[w]=e),n.onload=i,n.onerror=a,n.onreadystatechange=function(e,t){"loaded"!==n.readyState&&"complete"!==n.readyState||i(0,t)},n}();y.ld<0?l.getElementsByTagName("head")[0].appendChild(e):setTimeout(function(){l.getElementsByTagName(k)[0].parentNode.appendChild(e)},y.ld||0)}try{m.cookie=l.cookie}catch(p){}function t(e){for(;e.length;)!function(t){m[t]=function(){var e=arguments;g||m.queue.push(function(){m[t].apply(m,e)})}}(e.pop())}var n="track",r="TrackPage",o="TrackEvent";t([n+"Event",n+"PageView",n+"Exception",n+"Trace",n+"DependencyData",n+"Metric",n+"PageViewPerformance","start"+r,"stop"+r,"start"+o,"stop"+o,"addTelemetryInitializer","setAuthenticatedUserContext","clearAuthenticatedUserContext","flush"]),m.SeverityLevel={Verbose:0,Information:1,Warning:2,Error:3,Critical:4};var s=(d.extensionConfig||{}).ApplicationInsightsAnalytics||{};if(!0!==d[I]&&!0!==s[I]){var c="onerror";t(["_"+c]);var u=T[c];T[c]=function(e,t,n,a,i){var r=u&&u(e,t,n,a,i);return!0!==r&&m["_"+c]({message:e,url:t,lineNumber:n,columnNumber:a,error:i}),r},d.autoExceptionInstrumented=!0}return m}(y.cfg);function a(){y.onInit&&y.onInit(n)}(T[t]=n).queue&&0===n.queue.length?(n.queue.push(a),n.trackPageView({})):a()}(window,document,{
src: "https://js.monitor.azure.com/scripts/b/ai.2.min.js", // The SDK URL Source
// name: "appInsights", // Global SDK Instance name defaults to "appInsights" when not supplied
// ld: 0, // Defines the load delay (in ms) before attempting to load the sdk. -1 = block page load and add to head. (default) = 0ms load after timeout,
// useXhr: 1, // Use XHR instead of fetch to report failures (if available),
crossOrigin: "anonymous", // When supplied this will add the provided value as the cross origin attribute on the script tag
// onInit: null, // Once the application insights instance has loaded and initialized this callback function will be called with 1 argument -- the sdk instance (DO NOT ADD anything to the sdk.queue -- As they won't get called)
cfg: { // Application Insights Configuration
connectionString: "{{ $.Site.Params.applicationInsights.connectionString }}"
/* ...Other Configuration Options... */
}});
</script>

View File

@@ -0,0 +1,11 @@
<!-- Baidu Analytics -->
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?{{ $.Site.Params.baidu.token }}";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
<!-- End Baidu Web Analytics -->

View File

@@ -0,0 +1 @@
<script async data-id="{{ $.Site.Params.clicky.id }}" src="//static.getclicky.com/js"></script>

View File

@@ -0,0 +1,4 @@
<!-- Cloudflare Web Analytics -->
<script defer src='https://static.cloudflareinsights.com/beacon.min.js'
data-cf-beacon='{"token": "{{ $.Site.Params.cloudflare.token }}"}'></script>
<!-- End Cloudflare Web Analytics -->

View File

@@ -0,0 +1,13 @@
<script>
(function(f, a, t, h, o, m){
a[h]=a[h]||function(){
(a[h].q=a[h].q||[]).push(arguments)
};
o=f.createElement('script'),
m=f.getElementsByTagName('script')[0];
o.async=1; o.src=t; o.id='fathom-script';
m.parentNode.insertBefore(o,m)
})(document, window, '//{{ .Site.Params.fathomAnalytics.serverURL | default "cdn.usefathom.com" }}/tracker.js', 'fathom');
fathom('set', 'siteId', '{{ .Site.Params.fathomAnalytics.siteID }}');
fathom('trackPageview');
</script>

View File

@@ -0,0 +1,2 @@
<script data-goatcounter="https://{{ $.Site.Params.goatCounter.code }}.goatcounter.com/count"
async src="//gc.zgo.at/count.js"></script>

View File

@@ -0,0 +1,9 @@
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{ $.Site.Params.googleTagManager.id }}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{{ $.Site.Params.googleTagManager.id }}');
</script>

View File

@@ -0,0 +1,13 @@
<script type="application/javascript">
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="https://{{ $.Site.Params.matomo.serverURL }}/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '{{ $.Site.Params.matomo.siteID | default "1" }}']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>

View File

@@ -0,0 +1,8 @@
<script
async
defer
data-host="https://microanalytics.io"
data-dnt="{{ .Site.Params.microAnalytics.dnt | default "true" }}"
src="https://microanalytics.io/js/script.js"
id="{{ .Site.Params.microAnalytics.id }}">
</script>

View File

@@ -0,0 +1,5 @@
<script
defer
data-site-id="{{ .Site.Params.onedollarstats.id }}"
src="https://assets.onedollarstats.com/tracker.js"
></script>

View File

@@ -0,0 +1,3 @@
<script async defer type="text/javascript" src="https://api.pirsch.io/pirsch.js"
id="pirschjs"
data-code="{{ .Site.Params.pirsch.code }}"></script>

View File

@@ -0,0 +1 @@
<script async defer data-domain="{{ .Site.Params.plausibleAnalytics.domain }}" src="https://{{ .Site.Params.plausibleAnalytics.serverURL | default "plausible.io" }}/js/script{{if .Site.Params.plausibleAnalytics.fileDownloadsTracking}}.file-downloads{{end}}{{if .Site.Params.plausibleAnalytics.outboundLinksTracking}}.outbound-links{{end}}.js"></script>

View File

@@ -0,0 +1,3 @@
<!-- Umami Analytics START -->
<script async defer data-website-id="{{ .Site.Params.umami.siteID }}" src="{{ .Site.Params.umami.scriptURL }}"></script>
<!-- Umami Analytics END -->

View File

@@ -0,0 +1,4 @@
<script>
window.si = window.si || function () { (window.siq = window.siq || []).push(arguments); };
</script>
<script defer src="{{ .Site.BaseURL }}/_vercel/speed-insights/script.js"></script>

View File

@@ -0,0 +1,5 @@
<script async defer
src='https://{{ .Site.Params.wideAngleAnalytics.serverURL | default "stats.wideangle.co" }}/script/{{ .Site.Params.wideAngleAnalytics.siteID}}.js'
data-waa-fingerprint='{{ .Site.Params.wideAngleAnalytics.fingerprint | default "false" }}'
data-waa-dnt-supress='{{ .Site.Params.wideAngleAnalytics.supressDNT | default "false" }}'>
</script>

View File

@@ -0,0 +1,14 @@
<!-- Yandex.Metrika counter -->
<script type="text/javascript" >
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym({{ $.Site.Params.yandexMetrika.id }}, "init", {
clickmap:true,
trackLinks:true,
accurateTrackBounce:true
});
</script>
<noscript><div><img src="https://mc.yandex.ru/watch/{{ $.Site.Params.yandexMetrika.id }}" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter -->

View File

@@ -0,0 +1,5 @@
{{/*
This extension point occurs just before the end of each page's <body> tag.
You can add further theme extensions or customizations here if needed.
*/}}

View File

@@ -0,0 +1 @@
{{ printf `<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests; block-all-mixed-content; default-src 'self'; child-src %s; font-src %s; form-action %s; frame-src %s; img-src %s; object-src %s; style-src %s; script-src %s; connect-src %s;">` (delimit .Site.Params.csp.childsrc " ") (delimit .Site.Params.csp.fontsrc " ") (delimit .Site.Params.csp.formaction " ") (delimit .Site.Params.csp.framesrc " ") (delimit .Site.Params.csp.imgsrc " ") (delimit .Site.Params.csp.objectsrc " ") (delimit .Site.Params.csp.stylesrc " ") (delimit .Site.Params.csp.scriptsrc " ") (delimit .Site.Params.csp.connectsrc " ") | safeHTML }}

View File

@@ -0,0 +1,7 @@
{{ if not .Site.Params.hideColorSchemeToggle }}
<div class="float-container">
<a id="dark-mode-toggle" class="colorscheme-toggle">
<i class="fa-solid fa-adjust fa-fw" aria-hidden="true"></i>
</a>
</div>
{{ end }}

View File

@@ -0,0 +1,19 @@
<footer class="footer">
<section class="container">
©
{{ if (and .Site.Params.since (lt .Site.Params.since now.Year)) }}
{{ .Site.Params.since }} -
{{ end }}
{{ now.Year }}
{{ with .Site.Params.author }} {{ . }} {{ end }}
·
{{ if (and .Site.Params.license) }}
{{ i18n "licensed_under" }} {{ .Site.Params.license | safeHTML }}
·
{{ end }}
{{ i18n "powered_by" }} <a href="https://gohugo.io/" target="_blank" rel="noopener">Hugo</a> & <a href="https://github.com/luizdepra/hugo-coder/" target="_blank" rel="noopener">Coder</a>.
{{ if (and .Site.Params.commit .GitInfo) }}
[<a href="{{ .Site.Params.commit }}/{{ .GitInfo.Hash }}" target="_blank" rel="noopener">{{ .GitInfo.AbbreviatedHash }}</a>]
{{ end }}
</section>
</footer>

View File

@@ -0,0 +1,21 @@
{{ partial "head/meta-tags.html" . }}
{{ if .Params.canonicalUrl }}
<link rel="canonical" href="{{ .Params.canonicalUrl }}">
{{ else }}
<link rel="canonical" href="{{ .Permalink }}">
{{ end }}
{{ partialCached "head/theme-styles.html" . }}
{{ partialCached "head/color-scheme.html" . }}
{{ partialCached "head/custom-styles.html" . }}
{{ partialCached "head/custom-icons.html" . }}
{{ partial "head/alternative-output-formats.html" . }}
{{ if .IsHome }}{{ partial "head/hugo-generator.html" . }}{{ end }}
{{ partial "head/extensions.html" . }}

View File

@@ -0,0 +1,3 @@
{{ range .AlternativeOutputFormats -}}
{{ printf `<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .RelPermalink $.Site.Title | safeHTML }}
{{ end -}}

View File

@@ -0,0 +1,11 @@
{{ if or (eq .Site.Params.colorScheme "auto") (eq .Site.Params.colorScheme "dark") }}
{{ if hugo.IsServer }}
{{ $cssOpts := (dict "targetPath" "css/coder-dark.css" "enableSourceMap" true ) }}
{{ $styles := resources.Get "scss/coder-dark.scss" | resources.ExecuteAsTemplate "style.coder-dark.css" . | toCSS $cssOpts }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
{{ else }}
{{ $cssOpts := (dict "targetPath" "css/coder-dark.css" ) }}
{{ $styles := resources.Get "scss/coder-dark.scss" | resources.ExecuteAsTemplate "style.coder-dark.css" . | toCSS $cssOpts | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
{{ end }}
{{ end }}

View File

@@ -0,0 +1,9 @@
<link rel="icon" type="image/svg+xml" href="{{ .Site.Params.faviconSVG | default "/images/favicon.svg" | relURL }}" sizes="any">
<link rel="icon" type="image/png" href="{{ .Site.Params.favicon_32 | default "/images/favicon-32x32.png" | relURL }}" sizes="32x32">
<link rel="icon" type="image/png" href="{{ .Site.Params.favicon_16 | default "/images/favicon-16x16.png" | relURL }}" sizes="16x16">
<link rel="apple-touch-icon" href="{{ .Site.Params.touchicon | default "/images/apple-touch-icon.png" | relURL }}">
<link rel="apple-touch-icon" sizes="180x180" href="{{ .Site.Params.touchicon | default "/images/apple-touch-icon.png" | relURL }}">
<link rel="manifest" href="{{ .Site.Params.manifest | default "/site.webmanifest" | relURL }}">
<link rel="mask-icon" href="{{ .Site.Params.mask_icon | default "/images/safari-pinned-tab.svg" | relURL }}" color="{{ .Site.Params.mask_icon_color | default "#5bbad5" }}">

View File

@@ -0,0 +1,21 @@
{{ range .Site.Params.customCSS }}
{{ if hugo.IsServer }}
{{ $styles := resources.Get . }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
{{ else }}
{{ $styles := resources.Get . | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
{{ end }}
{{ end }}
{{ range .Site.Params.customSCSS }}
{{/* We don't change the targetPath to because it's transparent to users */}}
{{ if hugo.IsServer }}
{{ $cssOpts := (dict "enableSourceMap" true ) }}
{{ $styles := resources.Get . | toCSS $cssOpts }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
{{ else }}
{{ $styles := resources.Get . | toCSS | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
{{ end }}
{{ end }}

View File

@@ -0,0 +1,4 @@
{{/*
You can add further theme extensions or customizations here if they should
appear in <head>.
*/}}

View File

@@ -0,0 +1 @@
{{ hugo.Generator }}

View File

@@ -0,0 +1,16 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
{{ if .Site.Params.csp }}
{{ partial "csp.html" . }}
{{ end }}
{{ with .Site.Params.author }}
<meta name="author" content="{{ . }}">{{ end }}
<meta name="description" content="{{ .Description | default (.Summary | default .Site.Params.description ) }}">
<meta name="keywords" content="{{ (delimit .Keywords ", ") | default .Site.Params.keywords }}">
{{ if or .Params.fediverseCreator .Site.Params.fediverseCreator }}<meta name="fediverse:creator" content="{{ .Params.fediverseCreator | default .Site.Params.fediverseCreator }}" />{{end}}
{{ template "_internal/twitter_cards.html" . }}
{{ template "_internal/opengraph.html" . }}

View File

@@ -0,0 +1,25 @@
<link rel="preload" href="/fonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/fonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin>
{{ if hugo.IsServer }}
{{ $cssOpts := (dict "targetPath" "css/coder.css" "enableSourceMap" true ) }}
{{ $styles := resources.Get "scss/coder.scss" | resources.ExecuteAsTemplate "style.coder.css" . | toCSS $cssOpts }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
{{ else }}
{{ $cssOpts := (dict "targetPath" "css/coder.css" ) }}
{{ $styles := resources.Get "scss/coder.scss" | resources.ExecuteAsTemplate "style.coder.css" . | toCSS $cssOpts | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
{{ end }}
{{ if .Site.Params.rtl }}
{{ if hugo.IsServer }}
{{ $cssOpts := (dict "targetPath" "css/coder-rtl.css" "enableSourceMap" true ) }}
{{ $styles := resources.Get "scss/coder-rtl.scss" | resources.ExecuteAsTemplate "style.coder-rtl.css" . | toCSS $cssOpts }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" media="screen">
{{ else }}
{{ $cssOpts := (dict "targetPath" "css/coder-rtl.css" ) }}
{{ $styles := resources.Get "scss/coder-rtl.scss" | resources.ExecuteAsTemplate "style.coder-rtl.css" . | toCSS $cssOpts | resources.Minify | resources.Fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}" crossorigin="anonymous" media="screen" />
{{ end }}
{{ end }}

View File

@@ -0,0 +1,41 @@
<nav class="navigation">
<section class="container">
{{ with .Site }}
<a class="navigation-title" href="{{ absLangURL "" }}">
{{ .Title }}
</a>
{{ end }}
{{ if or .Site.Menus.main hugo.IsMultilingual }}
<input type="checkbox" id="menu-toggle" />
<label class="menu-button float-right" for="menu-toggle">
<i class="fa-solid fa-bars fa-fw" aria-hidden="true"></i>
</label>
<ul class="navigation-list">
{{ with .Site.Menus.main}}
{{ range sort . }}
<li class="navigation-item">
<a class="navigation-link {{ .Params.class }}" href="{{ index (apply (slice .URL) (.Params.urlFunc | default "relLangURL") ".") 0 }}">{{ .Name }}</a>
</li>
{{ end }}
{{ end }}
{{ if hugo.IsMultilingual }}
{{ $node := . }}
{{ .Scratch.Set "separator" true }}
{{ range (default .Site.Home.AllTranslations .Translations) }}
{{ if ne $.Site.Language .Language }}
{{ if $node.Scratch.Get "separator" }}
<li class="navigation-item menu-separator">
<span>|</span>
</li>
{{ $node.Scratch.Set "separator" false }}
{{ end }}
<li class="navigation-item">
<a href="{{ .RelPermalink }}">{{ .Language.LanguageName | emojify }}</a>
</li>
{{ end }}
{{ end }}
{{ end }}
</ul>
{{ end }}
</section>
</nav>

View File

@@ -0,0 +1,11 @@
<section class="container centered">
<div class="about">
{{ partialCached "home/avatar.html" . }}
{{ partialCached "home/author.html" . }}
{{ partialCached "home/social.html" . }}
</div>
{{ partialCached "home/extensions.html" . }}
</section>

View File

@@ -0,0 +1,6 @@
<h1>{{ .Site.Params.author }}</h1>
{{ if reflect.IsSlice .Site.Params.info }}
<h2>{{ range .Site.Params.info }}{{ . | markdownify }}<br>{{ end}}</h2>
{{ else }}
<h2>{{ .Site.Params.info | markdownify }}</h2>
{{ end }}

View File

@@ -0,0 +1,8 @@
{{ if and (isset .Site.Params "avatarurl") (not (isset .Site.Params "gravatar")) }}
{{ with .Site.Params.avatarURL }}
<div class="avatar"><img src="{{ . | relURL }}" alt="avatar"></div>
{{ end }}
{{ end }}
{{ with .Site.Params.gravatar }}
<div class="avatar"><img src="https://www.gravatar.com/avatar/{{md5 .}}?s=240&d=mp" alt="gravatar"></div>
{{ end }}

View File

@@ -0,0 +1,4 @@
{{/*
You can add further theme extensions or customizations here if they should
appear in after the "about" section.
*/}}

View File

@@ -0,0 +1,17 @@
{{ with .Site.Params.social }}
<ul>
{{ range sort . "weight" }}
{{ if .icon }}
<li>
<a href="{{ .url | safeURL }}" aria-label="{{ .name }}" {{ if .rel }}rel="{{ .rel }}"{{ end }} {{ if .target }}target="{{ .target }}"{{ end }} {{ if .type }}type="{{ .type }}"{{ end }}>
<i class="{{ .icon }}" aria-hidden="true"></i>
</a>
</li>
{{ else }}
<li>
<a href="{{ .url | safeURL }}" aria-label="{{ .name }}" {{ if .rel }}rel="{{ .rel }}"{{ end }} {{ if .target }}target="{{ .target }}"{{ end }}>{{ .name }}</a>
</li>
{{ end }}
{{ end }}
</ul>
{{ end }}

View File

@@ -0,0 +1,23 @@
<section class="container list">
<header>
<h1 class="title">
<a class="title-link" href="{{ .Permalink | safeURL }}">
{{- if eq .Kind "term" -}}
{{- i18n .Data.Plural 1 | title -}}
{{- print ": " -}}
{{- end -}}
{{- i18n (lower .Title) | default .Title | title -}}
</a>
</h1>
</header>
{{ .Content }}
<ul>
{{ range .Paginator.Pages }}
<li>
<span class="date">{{ .Date | time.Format (.Site.Params.dateFormat | default "January 2, 2006" ) }}</span>
<a class="title" href="{{ .Params.externalLink | default .RelPermalink }}">{{ .Title }}</a>
</li>
{{ end }}
</ul>
{{ partial "pagination.html" . }}
</section>

View File

@@ -0,0 +1,13 @@
<section class="container page">
<article>
<header>
<h1 class="title">
<a class="title-link" href="{{ .Permalink | safeURL }}">
{{ .Title }}
</a>
</h1>
</header>
{{ .Content }}
</article>
</section>

View File

@@ -0,0 +1,48 @@
{{ $paginator := .Paginator }}
{{ $adjacent_links := 2 }}
{{ $max_links := (add (mul $adjacent_links 2) 1) }}
{{ $lower_limit := (add $adjacent_links 1) }}
{{ $upper_limit := (sub $paginator.TotalPages $adjacent_links) }}
{{ if gt $paginator.TotalPages 1 }}
<ul class="pagination">
{{ if $paginator.HasPrev }}
{{ if ne $paginator.PageNumber 1 }}
<li><a href="{{ $paginator.First.URL }}">&laquo;</a></li>
{{ end }}
<li class="hidden"><a href="{{ $paginator.Prev.URL }}">&lsaquo;</a></li>
{{ end }}
{{ range $paginator.Pagers }}
{{ $.Scratch.Set "page_number_flag" false }}
{{ if gt $paginator.TotalPages $max_links }}
{{ if le $paginator.PageNumber $lower_limit }}
{{ if le .PageNumber $max_links }}
{{ $.Scratch.Set "page_number_flag" true }}
{{ end }}
{{ else if ge $paginator.PageNumber $upper_limit }}
{{ if gt .PageNumber (sub $paginator.TotalPages $max_links) }}
{{ $.Scratch.Set "page_number_flag" true }}
{{ end }}
{{ else }}
{{ if and ( ge .PageNumber (sub $paginator.PageNumber $adjacent_links) ) ( le .PageNumber (add $paginator.PageNumber $adjacent_links) ) }}
{{ $.Scratch.Set "page_number_flag" true }}
{{ end }}
{{ end }}
{{ else }}
{{ $.Scratch.Set "page_number_flag" true }}
{{ end }}
{{ if eq ($.Scratch.Get "page_number_flag") true }}
{{ if eq . $paginator }}
<li>{{ .PageNumber }}</li>
{{ else }}
<li><a href="{{ .URL }}">{{ .PageNumber }}</a></li>
{{ end }}
{{ end }}
{{ end }}
{{ if $paginator.HasNext }}
<li class="hidden"><a href="{{ $paginator.Next.URL }}">&rsaquo;</a></li>
{{ if ne $paginator.PageNumber $paginator.TotalPages }}
<li><a href="{{ $paginator.Last.URL }}">&raquo;</a></li>
{{ end }}
{{ end }}
</ul>
{{ end }}

View File

@@ -0,0 +1,4 @@
{{- if and (isset .Site.Params "commentourl") (not (eq .Site.Params.commentoURL "" )) (eq (.Params.disableComments | default false) false) -}}
<div id="commento"></div>
<script src="{{ .Site.Params.commentoURL }}/js/commento.js"></script>
{{- end -}}

View File

@@ -0,0 +1,16 @@
{{- if isset .Site.Params "cusdis" -}}
{{- if and (isset .Site.Params.cusdis "data_app_id") (eq (.Params.disableComments | default false) false) -}}
<div class="comments">
<h4>Comments:</h4>
<div id="cusdis_thread"
data-host="https://cusdis.com"
data-app-id="{{ .Site.Params.cusdis.data_app_id }}"
data-page-id="{{ .File.UniqueID }}"
data-page-url="{{ .Permalink }}"
data-page-title="{{ .Title }}">
</div>
<script async defer src="https://cusdis.com/js/cusdis.es.js"></script>
</div>
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,26 @@
{{- if and (not (eq (.Site.Config.Services.Disqus.Shortname | default "") "")) (eq (.Params.disableComments | default false) false) -}}
<div id="disqus_thread"></div>
<script>
window.disqus_config = function () {
{{with .Params.disqus_identifier }}this.page.identifier = '{{ . }}';{{end}}
{{with .Params.disqus_title }}this.page.title = '{{ . }}';{{end}}
{{with .Params.disqus_url }}this.page.url = '{{ . | html }}';{{end}}
};
(function() {
if (["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1) {
document.getElementById('disqus_thread').innerHTML = 'Disqus comments not available by default when the website is previewed locally.';
return;
}
var d = document, s = d.createElement('script'); s.async = true;
s.src = '//' + {{ .Site.Config.Services.Disqus.Shortname }} + '.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
// Disqus theme switching
document.addEventListener('themeChanged', function (e) {
if (document.readyState == 'complete') {
DISQUS.reset({ reload: true, config: disqus_config });
}
});
</script>
{{- end -}}

View File

@@ -0,0 +1,33 @@
{{- if isset .Site.Params "giscus" -}}
{{- if and (isset .Site.Params.giscus "repo") (not (eq .Site.Params.giscus.repo "" )) (eq (.Params.disableComments | default false) false) -}}
<div class="comments">
<script>
let getTheme = window.localStorage && window.localStorage.getItem("colorscheme");
getTheme = getTheme == null ? '{{$.Site.Params.giscus.theme}}' : getTheme;
let s = document.createElement('script');
s.src = 'https://giscus.app/client.js';
s.setAttribute('data-repo', '{{ .Site.Params.giscus.repo }}');
s.setAttribute('data-repo-id', '{{ .Site.Params.giscus.repoID }}');
s.setAttribute('data-category', '{{ .Site.Params.giscus.category }}');
s.setAttribute('data-category-id', '{{ .Site.Params.giscus.categoryID }}');
s.setAttribute('data-mapping', '{{ default "pathname" .Site.Params.giscus.mapping }}');
s.setAttribute('data-term', '{{ .Site.Params.giscus.term }}');
s.setAttribute('data-strict', '{{ default "0" .Site.Params.giscus.strict }}');
s.setAttribute('data-reactions-enabled', '{{ default "1" .Site.Params.giscus.reactionsEnabled }}');
s.setAttribute('data-emit-metadata', '{{ default "0" .Site.Params.giscus.emitMetadata }}');
s.setAttribute('data-input-position', '{{ default "bottom" .Site.Params.giscus.inputPosition }}');
s.setAttribute('data-theme', getTheme);
s.setAttribute('data-lang', '{{ default "en" .Site.Params.giscus.lang }}');
s.setAttribute('data-loading', '{{ .Site.Params.giscus.loading }}');
s.setAttribute('crossorigin', 'anonymous');
s.setAttribute('async', '');
document.querySelector('div.comments').innerHTML = '';
document.querySelector('div.comments').appendChild(s);
</script>
</div>
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,108 @@
{{- if isset .Site.Params "mastodon" -}}
{{- with .Site.Params.mastodon -}}
<div class="article-content">
<h2>Comments</h2>
<p>You can use your Mastodon account to reply to this <a class="link" href="https://{{ .host }}/@{{ .username }}/{{ .statusID }}">post</a>. Learn how this is implemented <a class="link" href="https://carlschwan.eu/2020/12/29/adding-comments-to-your-static-blog-with-mastodon/">here.</a></p>
<p><button id="replyButton" href="https://{{ .host }}/@{{ .username }}/{{ .statusID }}">Reply</button></p>
<p id="mastodon-comments-list"><button id="load-comment">Load comments</button></p>
<dialog id="toot-reply" class="mastodon" data-component="dialog">
<h3>Reply to {{ .username }}'s post</h3>
<p>
With an account on the Fediverse or Mastodon, you can respond to this post.
Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.
</p>
<p>Copy and paste this URL into the search field of your favourite Fediverse app or the web interface of your Mastodon server.</p>
<div class="copypaste">
<input type="text" readonly="" value="https://{{ .host }}/@{{ .username }}/{{ .statusID }}">
<button class="button" id="copyButton">Copy</button>
<button class="button" id="cancelButton">Close</button>
</div>
</dialog>
<noscript>You need JavaScript to view the comments.</noscript>
<script src="{{ .purifyCDN }}"></script>
<script type="text/javascript">
const dialog = document.querySelector('dialog');
document.getElementById('replyButton').addEventListener('click', () => {
dialog.showModal();
});
document.getElementById('copyButton').addEventListener('click', () => {
navigator.clipboard.writeText('https://{{ .host }}/@{{ .username }}/{{ .statusID }}');
});
document.getElementById('cancelButton').addEventListener('click', () => {
dialog.close();
});
dialog.addEventListener('keydown', e => {
if (e.key === 'Escape') dialog.close();
});
const dateOptions = {
year: "numeric",
month: "numeric",
day: "numeric",
hour: "numeric",
minute: "numeric",
};
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
document.getElementById("load-comment").addEventListener("click", function() {
document.getElementById("load-comment").innerHTML = "Loading";
fetch('https://{{ .host }}/api/v1/statuses/{{ .statusID }}/context')
.then(function(response) {
return response.json();
})
.then(function(data) {
if(data['descendants'] &&
Array.isArray(data['descendants']) &&
data['descendants'].length > 0) {
document.getElementById('mastodon-comments-list').innerHTML = "";
data['descendants'].forEach(function(reply) {
reply.account.display_name = escapeHtml(reply.account.display_name);
reply.account.reply_class = reply.in_reply_to_id == "{{ .statusID }}" ? "reply-original" : "reply-child";
reply.created_date = new Date(reply.created_at);
reply.account.emojis.forEach(emoji => {
reply.account.display_name = reply.account.display_name.replace(`:${emoji.shortcode}:`,
`<img src="${escapeHtml(emoji.static_url)}" alt="Emoji ${emoji.shortcode}" height="20" width="20" />`);
});
mastodonComment =
`
<div class="mastodon-wrapper">
<div class="comment-level ${reply.account.reply_class}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="currentColor" stroke="currentColor" d="m 307,477.17986 c -11.5,-5.1 -19,-16.6 -19,-29.2 v -64 H 176 C 78.8,383.97986 -4.6936293e-8,305.17986 -4.6936293e-8,207.97986 -4.6936293e-8,94.679854 81.5,44.079854 100.2,33.879854 c 2.5,-1.4 5.3,-1.9 8.1,-1.9 10.9,0 19.7,8.9 19.7,19.7 0,7.5 -4.3,14.4 -9.8,19.5 -9.4,8.8 -22.2,26.4 -22.2,56.700006 0,53 43,96 96,96 h 96 v -64 c 0,-12.6 7.4,-24.1 19,-29.2 11.6,-5.1 25,-3 34.4,5.4 l 160,144 c 6.7,6.2 10.6,14.8 10.6,23.9 0,9.1 -3.9,17.7 -10.6,23.8 l -160,144 c -9.4,8.5 -22.9,10.6 -34.4,5.4 z" />
</svg></div>
<div class="mastodon-comment">
<div class="comment">
<div class="comment-avatar"><img src="${escapeHtml(reply.account.avatar_static)}" alt=""></div>
<div class="comment-author">
<div class="comment-author-name"><a href="${reply.account.url}" rel="nofollow">${reply.account.display_name}</a></div>
<div class="comment-author-reply"><a href="${reply.account.url}" rel="nofollow">${escapeHtml(reply.account.acct)}</a></div>
</div>
<div class="comment-author-date">${reply.created_date.toLocaleString(navigator.language, dateOptions)}</div>
</div>
<div class="comment-content">${reply.content}</div>
</div>
</div>
`;
document.getElementById('mastodon-comments-list').appendChild(DOMPurify.sanitize(mastodonComment, {'RETURN_DOM_FRAGMENT': true}));
});
} else {
document.getElementById('mastodon-comments-list').innerHTML = "<p>Not comments found</p>";
}
});
});
</script>
</div>
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,19 @@
{{- if or (.Params.math) (.Site.Params.math) (.Params.katex) (.Site.Params.katex) -}}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.css"
integrity="sha384-vKruj+a13U8yHIkAyGgK1J3ArTLzrFGBbBc0tDp4ad/EyewESeXE/Iv67Aj8gKZ0" crossorigin="anonymous">
{{/* The loading of KaTeX is deferred to speed up page rendering */}}
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/katex.min.js"
integrity="sha384-PwRUT/YqbnEjkZO0zZxNqcxACrXe+j766U2amXcgMg5457rve2Y7I6ZJSm2A0mS4" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.4/dist/contrib/auto-render.min.js"
integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"
onload="renderMathInElement(document.body,
{
delimiters: [
{left: '$$', right: '$$', display:true},
{left: '$', right: '$', display:false},
{left: '\\(', right: '\\)', display: false},
{left: '\\[', right: '\\]', display: true}
]
}
);"></script>
{{- end -}}

View File

@@ -0,0 +1,30 @@
{{ $currentPageUrl := .RelPermalink }}
{{ if .Params.series }}
<section class="see-also">
{{ range .Params.series }}
{{ $name := . | anchorize }}
{{ $series := index $.Site.Taxonomies.series $name }}
{{ if gt (len $series.Pages) 1 }}
<h3 id="{{ i18n "see_also" | default "See also in" | anchorize }}-{{ anchorize . | safeURL }}">
{{ i18n "see_also" | default "See also in" }} {{ . }}
<a class="heading-link" href="#{{ i18n "see_also" | default "See also in" | anchorize }}-{{ anchorize . | safeURL }}">
<i class="fa-solid fa-link" aria-hidden="true" title="{{ i18n "link_to_heading" | default "Link to heading" }}"></i>
<span class="sr-only">{{ i18n "link_to_heading" | default "Link to heading" }}</span>
</a>
</h3>
<nav>
<ul>
{{ $maxItems := $.Site.Params.maxSeeAlsoItems | default 5 }}
{{ range first (add $maxItems 1) $series.Pages }}
{{ if ne .RelPermalink $currentPageUrl }}
<li>
<a href="{{ .Params.externalLink | default .RelPermalink }}">{{ .Title }}</a>
</li>
{{ end }}
{{ end }}
</ul>
</nav>
{{ end }}
{{ end }}
</section>
{{ end }}

View File

@@ -0,0 +1,22 @@
{{- if isset .Site.Params "telegram" -}}
{{- if and (isset .Site.Params.telegram "siteid") (not (eq .Site.Params.telegram.siteID "" )) (eq (.Params.disableComments | default false) false) -}}
<div class="comments">
<script>
let s = document.createElement('script');
s.src = 'https://comments.app/js/widget.js?3';
s.setAttribute('data-comments-app-website', '{{ .Site.Params.telegram.siteID }}');
s.setAttribute('data-limit', '{{ .Site.Params.telegram.limit }}');
s.setAttribute('data-height', '{{ .Site.Params.telegram.height }}');
s.setAttribute('data-color', '{{ .Site.Params.telegram.color }}');
s.setAttribute('data-dislikes', '{{ .Site.Params.telegram.dislikes }}');
s.setAttribute('data-outlined', '{{ .Site.Params.telegram.outlined }}');
s.setAttribute('data-colorful', '{{ .Site.Params.telegram.colorful }}');
s.setAttribute('data-dark', '{{ .Site.Params.telegram.dark }}');
document.querySelector('div.comments').innerHTML = '';
document.querySelector('div.comments').appendChild(s);
</script>
</div>
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,32 @@
{{- if isset .Site.Params "utterances" -}}
{{- if and (isset .Site.Params.utterances "repo") (not (eq .Site.Params.utterances.repo "" )) (eq (.Params.disableComments | default false) false) -}}
<div class="comments">
<script>
let getTheme = window.localStorage && window.localStorage.getItem("colorscheme");
let themeInParams = '{{$.Site.Params.utterances.theme}}';
if (getTheme == null) {
if (themeInParams !== '' && themeInParams !== 'auto') {
getTheme = themeInParams;
}
else {
getTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? "dark" : "light";
}
}
let theme = getTheme === 'dark' ? 'github-dark' : 'github-light';
let s = document.createElement('script');
s.src = 'https://utteranc.es/client.js';
s.setAttribute('repo', '{{ .Site.Params.utterances.repo }}');
s.setAttribute('issue-term', '{{ default "title" .Site.Params.utterances.issueTerm }}');
s.setAttribute('theme', theme);
s.setAttribute('crossorigin', 'anonymous');
s.setAttribute('async', '');
document.querySelector('div.comments').innerHTML = '';
document.querySelector('div.comments').appendChild(s);
</script>
</div>
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,9 @@
<div class="authors">
<i class="fa-solid fa-user" aria-hidden="true"></i>
{{- range $index, $el := . -}}
{{- if gt $index 0 }}
<span class="separator"></span>
{{- end }}
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
{{- end -}}
</div>

View File

@@ -0,0 +1,9 @@
<div class="categories">
<i class="fa-solid fa-folder" aria-hidden="true"></i>
{{- range $index, $el := . -}}
{{- if gt $index 0 }}
<span class="separator"></span>
{{- end }}
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
{{- end -}}
</div>

View File

@@ -0,0 +1,11 @@
<div class="tags">
<i class="fa-solid fa-tag" aria-hidden="true"></i>
{{- range $index, $el := . -}}
{{- if gt $index 0 }}
<span class="separator"></span>
{{- end }}
<span class="tag">
<a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>
</span>
{{- end -}}
</div>

View File

@@ -0,0 +1,29 @@
<section class="container taxonomy">
<header>
<h1 class="title">
<a class="title-link" href="{{ .Permalink | safeURL }}">
{{- if eq .Kind "term" -}}
{{- i18n .Data.Plural | title -}}
{{- print ": " -}}
{{- end -}}
{{- i18n (lower .Title) | default .Title | title -}}
</a>
</h1>
</header>
{{ .Content }}
<ul>
{{ $type := .Type }}
{{ range $key, $value := .Data.Terms.Alphabetical }}
{{ $name := .Name }}
{{ $count := .Count }}
{{ with $.Site.GetPage (printf "/%s/%s" $type $name) }}
<li>
<span class="taxonomy-element">
<a href="{{ .Permalink }}">{{ .Name }}</a>
<sup>{{ $count }}</sup>
</span>
</li>
{{ end }}
{{ end }}
</ul>
</section>