This commit is contained in:
gribse 2025-10-06 19:21:06 +02:00
parent 2fe0c9a830
commit 7b9c07b83e
1444 changed files with 11476 additions and 42112 deletions

View file

@ -0,0 +1,2 @@
{{- /* formats .Content headings by adding an anchor */ -}}
{{ . | replaceRE "(<h[1-6] id=\"([^\"]+)\".+)(</h[1-6]+>)" "${1}<a hidden class=\"anchor\" aria-hidden=\"true\" href=\"#${2}\">#</a>${3}" | safeHTML }}

9
layouts/partials/author.html Executable file
View file

@ -0,0 +1,9 @@
{{- if or .Params.author site.Params.author }}
{{- $author := (.Params.author | default site.Params.author) }}
{{- $author_type := (printf "%T" $author) }}
{{- if (or (eq $author_type "[]string") (eq $author_type "[]interface {}")) }}
{{- (delimit $author ", " ) }}
{{- else }}
{{- $author }}
{{- end }}
{{- end -}}

View file

@ -0,0 +1,19 @@
{{- if (.Param "ShowBreadCrumbs") -}}
<div class="breadcrumbs">
{{- $url := replace .Parent.Permalink (printf "%s" site.Home.Permalink) "" }}
{{- $lang_url := strings.TrimPrefix (printf "%s/" .Lang) $url -}}
<a href="{{ "" | absLangURL }}">{{ i18n "home" | default "Home" }}</a>
{{- $scratch := newScratch }}
{{- range $index, $element := split $lang_url "/" }}
{{- $scratch.Add "path" (printf "%s/" $element )}}
{{- $bc_pg := site.GetPage ($scratch.Get "path") -}}
{{- if (and ($bc_pg) (gt (len . ) 0))}}
{{- print "&nbsp;»&nbsp;" | safeHTML -}}<a href="{{ $bc_pg.Permalink }}">{{ $bc_pg.Name }}</a>
{{- end }}
{{- end -}}
</div>
{{- end -}}

34
layouts/partials/buttons.html Executable file
View file

@ -0,0 +1,34 @@
<style>
.buttons {
display: flex;
flex-wrap: wrap;
justify-content: center;
max-width: 100vw; /* Make the container as wide as the viewport */
gap: 3px;
margin: 20px 0 0 0; /* Remove any default margin */
padding: 0; /* Remove any default padding */
}
.button {
display: inline-block;
border: none;
margin: 0;
padding: 0;
border-radius: 0;
background: none;
image-rendering: auto;
image-rendering: crisp-edges;
image-rendering: pixelated;
image-rendering: -webkit-optimize-contrast;
}
</style>
<div class="buttons"> <!-- https://88x31.nl/ -->
<a href="https://www.mozilla.org/fr/firefox/new/"> <img class="button" src="/buttons/firefox-now.png" alt="Bouton Firefox" title="Ils ont été vilains tho"/></a>
<a href="https://www.blender.org/download/"> <img class="button" src="/buttons/get-blender-2.8.png" alt="Bouton Blender" title="Je connais les raccourcis clavier"/></a>
<a href="https://xkcd.com/1179/"> <img class="button" src="/buttons/iso-8601.png" alt="Bouton ISO 8601" title="Par pitié, tout le monde pareil"/></a>
<a href="https://notepad-plus-plus.org/"> <img class="button" src="/buttons/made-with-notepad++.png" alt="Bouton Notepad++" title="Je veux le même pour Linux"/></a>
<a href="https://polymc.org/"> <img class="button" src="/buttons/minecraft.png" alt="Bouton Minecraft" title="Tfarcenim TMTC"/></a>
<a href="https://teegarten-miniatures.ch/"> <img class="button" src="/buttons/tea-powered.png" alt="Bouton Tea Powered" title="Nan vraiment, j'aime bien le thé"/></a>
<a href="https://ubuntu.com/download"> <img class="button" src="/buttons/ubuntu.png" alt="Bouton Ubuntu" title="Ce site vous est servi depuis Ubuntu"/></a>
<a href="https://www.linuxmint.com/"> <img class="button" src="/buttons/devOnMintGreen.png" alt="Bouton Linux Mint" title="Ce site a été développé sur Linux Mint"/></a>
</div>

0
layouts/partials/comments.html Executable file
View file

65
layouts/partials/cover.html Executable file
View file

@ -0,0 +1,65 @@
{{- with .cxt}} {{/* Apply proper context from dict */}}
{{- if (and .Params.cover.image (not $.isHidden)) }}
<figure class="entry-cover">
{{- $loading := cond $.IsSingle "eager" "lazy" }}
{{- $addLink := (and site.Params.cover.linkFullImages $.IsSingle) }}
{{- $prod := (hugo.IsProduction | or (eq site.Params.env "production")) }}
{{- $alt := (.Params.cover.alt | default .Params.cover.caption | plainify) }}
{{- $responsiveImages := (.Params.cover.responsiveImages | default site.Params.cover.responsiveImages) | default true }}
{{- $pageBundleCover := (.Resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
{{- $globalResourcesCover := (resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
{{- $cover := (or $pageBundleCover $globalResourcesCover)}}
{{- /* We are not using the .Param.cover.relative to decide the location of image */}}
{{- /* If we have the image in pageBundle or globalResources we can process the image */}}
{{- $sizes := (slice "360" "480" "720" "1080" "1500") }}
{{- $processableFormats := (slice "jpg" "jpeg" "png" "tif" "bmp" "gif") -}}
{{- if hugo.IsExtended -}}
{{- $processableFormats = $processableFormats | append "webp" -}}
{{- end -}}
{{- $imgdl := (.Params.cover.image) | absURL }}
{{- if $cover -}}
{{- $imgdl = $cover.Permalink }}
{{- end -}}
{{- if $addLink }}
<a href="{{ $imgdl }}" target="_blank" rel="noopener noreferrer">
{{- end }}
{{- if $cover -}}
{{/* i.e it is present in page bundle */}}
{{- if (and (in $processableFormats $cover.MediaType.SubType) ($responsiveImages) (eq $prod true)) }}
<img loading="{{$loading}}"
srcset='{{- range $size := $sizes -}}
{{- if (ge $cover.Width $size) }}
{{- printf "%s %s" (($cover.Resize (printf "%sx" $size)).Permalink) (printf "%sw," $size) }}
{{- end }}
{{- end }}
{{- printf "%s %dw" ($cover.Permalink) ($cover.Width) }}'
src="{{ $cover.Permalink }}"
sizes="(min-width: 768px) 720px, 100vw"
width="{{ $cover.Width }}" height="{{ $cover.Height }}"
alt="{{ $alt }}">
{{- else }}{{/* Unprocessable image or responsive images disabled */}}
<img loading="{{ $loading }}" src="{{ $imgdl }}" alt="{{ $alt }}">
{{- end }}
{{- else }}
{{- /* For absolute urls and external links, no img processing here */}}
<img loading="{{ $loading }}" src="{{ $imgdl }}" alt="{{ $alt }}">
{{- end }}
{{- if $addLink }}
</a>
{{- end -}}
{{- /* Display Caption */}}
{{- if $.IsSingle }}
{{ with .Params.cover.caption -}}
<figcaption>{{ . | markdownify }}</figcaption>
{{- end }}
{{- end }}
</figure>
{{- end }}{{/* End image */}}
{{- end -}}{{/* End context */ -}}

View file

@ -0,0 +1,28 @@
<!--
Code volé chez lucien
https://git.shenanigans.cc/globuzma/blog/commit/695e63b275ca03ec53a099d68f274c9466d0539f
-->
<span class="small-text" id="data-used">0kB chargés</span>
<script>
window.addEventListener('load', function () {
let totalTransferSize = 0;
performance.getEntriesByType('resource').map((resource) => {
const data = resource.toJSON();
totalTransferSize += data.transferSize;
});
console.log((totalTransferSize / 1024)/1024)
console.log(totalTransferSize/(1024*1024))
sizeString = totalTransferSize + "B"
if( totalTransferSize / (1024*1024) > 1) {
sizeString = Math.round(100*totalTransferSize/(1024*1024))/100 + "MB"
} else if (totalTransferSize / 1024 > 1) {
sizeString = Math.round(100*totalTransferSize / 1024)/100 + "kB"
}
document.getElementById("data-used").innerHTML = "<em>" + sizeString + "</em> chargés"
})
</script>

View file

@ -0,0 +1,8 @@
{{- if and (or .Params.editPost.URL site.Params.editPost.URL) (not (.Param "editPost.disabled")) -}}
{{- $fileUrlPath := path.Join .File.Path }}
{{- if or .Params.author site.Params.author (.Param "ShowReadingTime") (not .Date.IsZero) .IsTranslated }}&nbsp;|&nbsp;{{- end -}}
<a href="{{ .Params.editPost.URL | default site.Params.editPost.URL }}{{ if .Params.editPost.appendFilePath | default ( site.Params.editPost.appendFilePath | default false ) }}/{{ $fileUrlPath }}{{ end }}" rel="noopener noreferrer" target="_blank">
{{- .Params.editPost.Text | default (site.Params.editPost.Text | default (i18n "edit_post" | default "Edit")) -}}
</a>
{{- end }}

View file

@ -0,0 +1,106 @@
<!-- Pour montrer des infos sur le livre sur la page -->
<style>
.encadre-livre {
width: 300px;
padding: 10px;
border: 1px solid #ccc;
float: right;
margin-left: 20px;
clear: right;
box-sizing: border-box;
overflow: hidden;
}
.encadre-livre .title {
text-align: center;
margin: 0 0 20px 0;
}
.encadre-livre figure img {
margin-left: auto;
margin-right: auto;
}
</style>
{{ $specs := .Page.Params.BookData }}
{{ if $specs }}
<div class="encadre-livre">
<h3 class="title">{{$specs.title}}</h3>
<figure>
{{- if $specs.cover -}}
<!-- First try to get the image as a page resource (for page bundles) -->
{{- $coverResource := .Page.Resources.GetMatch $specs.cover -}}
{{- if not $coverResource -}}
<!-- If not found in page resources, try the global assets directory -->
{{- $coverResource = resources.Get $specs.cover -}}
{{- end -}}
{{- if $coverResource -}}
{{- $thumbCover := $coverResource.Fit "200x200 webp q85" -}}
<img src="{{ $thumbCover.RelPermalink }}" alt="1ère de couverture de {{ $specs.title }} par {{ $specs.author }}">
{{- else -}}
<!-- Cover resource not found anywhere -->
<div class="error">Image non trouvée : {{ $specs.cover }}</div>
{{- end -}}
{{- else -}}
<!-- No cover specified in frontmatter -->
<div class="error">No cover image specified</div>
{{- end -}}
</figure>
<table>
<tbody>
{{ if $specs.publishDate }}
<tr>
<th>Date de publication</th>
<td>{{ $specs.publishDate }}</td>
</tr>
{{ end }}
{{ if $specs.author }}
<tr>
<th>Auteur</th>
<td>{{ $specs.author }}</td>
</tr>
{{ end }}
{{ if $specs.ISBN }}
<tr>
<th>ISBN</th>
<td>{{ $specs.ISBN }}</td>
</tr>
{{ end }}
{{ if $specs.worldCat }}
<tr>
<th colspan="2">
<a href="{{ $specs.worldCat }}">Lien WorldCat</a>
</th>
</tr>
{{ end }}
{{ if $specs.starGrade }}
<tr>
<th>Note perso</th>
<td>
{{ range seq 1 $specs.starGrade }}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 441" width="16px" height="16px">
<path d="M 48 261 L 228 430 L 48 261 L 228 430 Q 240 441 256 441 Q 272 441 284 430 L 464 261 L 464 261 Q 511 217 512 152 L 512 146 L 512 146 Q 511 92 478 54 Q 445 15 393 5 Q 358 0 325 10 Q 293 20 268 45 L 256 57 L 256 57 L 244 45 L 244 45 Q 219 20 187 10 Q 154 0 119 5 Q 67 15 34 54 Q 1 92 0 146 L 0 152 L 0 152 Q 1 217 48 261 L 48 261 Z" />
</svg>
{{ end }}
{{ if ne $specs.starGrade 5 }}
{{ range seq 1 (sub 5 $specs.starGrade) }}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 445" width="16px" height="16px">
<path d="M 226 433 L 223 431 L 226 433 L 223 431 L 48 268 L 48 268 Q 1 223 0 158 L 0 155 L 0 155 Q 1 101 34 61 Q 66 22 119 11 Q 181 0 231 35 Q 245 44 256 57 Q 262 50 270 44 Q 275 39 281 35 Q 281 35 281 35 Q 281 35 281 35 Q 331 0 393 10 Q 446 21 478 61 Q 511 101 512 155 L 512 158 L 512 158 Q 511 223 464 268 L 289 431 L 289 431 L 286 433 L 286 433 Q 273 445 256 445 Q 239 445 226 433 L 226 433 Z M 239 110 Q 239 110 238 109 L 238 109 L 238 109 Q 238 109 238 109 L 220 89 L 220 89 L 220 89 L 220 89 Q 220 89 220 89 Q 202 69 178 61 Q 154 53 128 58 Q 93 65 71 92 Q 49 118 48 155 L 48 158 L 48 158 Q 49 202 81 233 L 256 396 L 256 396 L 431 233 L 431 233 Q 463 202 464 158 L 464 155 L 464 155 Q 463 118 441 92 Q 419 65 384 58 Q 358 53 334 61 Q 310 69 292 89 Q 292 89 292 89 Q 292 89 292 89 L 274 109 L 274 109 Q 274 109 273 110 Q 273 110 273 110 Q 266 117 256 117 Q 246 117 239 110 L 239 110 Z" />
</svg>
{{ end }}
{{ end }}
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ else }}
<div class="notice warning">
<p>Pas d'informations trouvées :(</p>
</div>
{{ end }}

View file

@ -0,0 +1,108 @@
<!-- Pour montrer des infos sur la machine sur la page -->
<style>
.encadre-maec {
width: 300px;
padding: 10px;
border: 1px solid #ccc;
float: right;
margin-left: 20px;
clear: right;
box-sizing: border-box;
overflow: hidden;
}
.encadre-maec .title {
text-align: center;
margin: 0 0 20px 0;
}
.encadre-maec figure img {
margin-left: auto;
margin-right: auto;
}
</style>
{{ $specs := .Page.Params.machineSpecs }}
{{ if $specs }}
<div class="encadre-maec">
<h3 class="title">{{$specs.make}} {{$specs.model}}</h3>
<figure>
{{- if $specs.image -}}
<!-- First try to get the image as a page resource (for page bundles) -->
{{- $imageResource := .Page.Resources.GetMatch $specs.image -}}
{{- if not $imageResource -}}
<!-- If not found in page resources, try the global assets directory -->
{{- $imageResource = resources.Get $specs.image -}}
{{- end -}}
{{- if $imageResource -}}
{{- $thumbimage := $imageResource.Fit "200x200 webp q85" -}}
<img src="{{ $thumbimage.RelPermalink }}" alt="1ère de couverture de {{ $specs.title }} par {{ $specs.author }}">
{{- else -}}
<!-- image resource not found anywhere -->
<div class="error">Image non trouvée : {{ $specs.image }}</div>
{{- end -}}
{{- else -}}
<!-- No image specified in frontmatter -->
<div class="error">No image image specified</div>
{{- end -}}
</figure>
<table>
<tbody>
{{ if $specs.make }}
<tr>
<th>Marque</th>
<td>{{ $specs.make }}</td>
</tr>
{{ end }}
{{ if $specs.model }}
<tr>
<th>Modèle</th>
<td>{{ $specs.model }}</td>
</tr>
{{ end }}
{{ if $specs.type }}
<tr>
<th>Type</th>
<td>{{ $specs.type }}</td>
</tr>
{{ end }}
{{ if $specs.dateManufactured }}
<tr>
<th>Date de fabrication</th>
<td>{{ $specs.dateManufactured }}</td>
</tr>
{{ end }}
{{ if $specs.massKg }}
<tr>
<th>Masse</th>
<td>{{ $specs.massKg }} kg</td>
</tr>
{{ end }}
{{ if $specs.widthCm }}
<tr>
<th>Largeur</th>
<td>{{ $specs.widthCm }} cm</td>
</tr>
{{ end }}
{{ if $specs.serialNumber }}
<tr>
<th>N° de série</th>
<td>{{ $specs.serialNumber }}</td>
</tr>
{{ end }}
{{ if $specs.linkTpdb }}
<tr>
<th colspan="2">
<a href="{{ $specs.linkTpdb }}">Typewriter Database</a>
</th>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ else }}
<div class="notice warning">
<p>Pas d'informations trouvées :(</p>
</div>
{{ end }}

View file

@ -0,0 +1,3 @@
{{- /* Footer custom content area start */ -}}
{{- /* Insert any custom code web-analytics, resources, etc. here */ -}}
{{- /* Footer custom content area end */ -}}

View file

@ -0,0 +1,4 @@
{{- /* Head custom content area start */ -}}
{{- /* Insert any custom code (web-analytics, resources, etc.) - it will appear in the <head></head> section of every page. */ -}}
{{- /* Can be overwritten by partial with the same name in the global layouts. */ -}}
{{- /* Head custom content area end */ -}}

185
layouts/partials/footer.html Executable file
View file

@ -0,0 +1,185 @@
{{- if not (.Param "hideFooter") }}
<footer class="footer">
{{- if not site.Params.footer.hideCopyright }}
{{- if site.Copyright }}
<span>{{ site.Copyright | markdownify }}</span>
{{- else }}
<span>&copy; {{ now.Year }} <a href="{{ "" | absLangURL }}">{{ site.Title }}</a></span>
{{- end }}
{{- print " · "}}
{{- end }}
{{- with site.Params.footer.text }}
{{ . | markdownify }}
{{- print " · "}}
{{- end }}
{{- partial "donnees-chargement.html" -}}
{{- print " · "}}
<!-- Lord forgive me for I have sinned -->
<style>
.rss-icon path {
stroke: var(--primary);
}
.rss-link {
color: var(--primary);
}
</style>
<a href="/feed.xml" class="rss-link">
<svg width="16px" height="16px" stroke-width="2" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="rss-icon">
<path d="M12 19C12 14.8 9.2 12 5 12" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M19 19C19 10.6 13.4 5 5 5" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"></path>
<path d="M5 19.01L5.01 18.9989" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
<span>Flux RSS</span>
</a>
{{- print " · "}}
{{ with (readFile "data/gitinfo.txt") }}
{{ $raw := . }}
{{ $lines := slice }}
{{ range split (replace $raw "\r\n" "\n") "\n" }}
{{ if ne . "" }}
{{ $lines = $lines | append . }}
{{ end }}
{{ end }}
{{ if ge (len $lines) 4 }}
<span>
Mis à jour le {{ index $lines 0 }} à {{ index $lines 1 }}
</span>
{{ else }}
<span>Information de mise à jour non disponible</span>
{{ end }}
{{ else }}
<span>Fichier gitinfo non trouvé</span>
{{ end }}
</footer>
{{- end }}
{{- if (not site.Params.disableScrollToTop) }}
<a href="#top" aria-label="go to top" title="Go to Top (Alt + G)" class="top-link" id="top-link" accesskey="g">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 6" fill="currentColor">
<path d="M12 6H0l6-6z" />
</svg>
</a>
{{- end }}
{{- partial "extend_footer.html" . }}
<script>
let menu = document.getElementById('menu')
if (menu) {
menu.scrollLeft = localStorage.getItem("menu-scroll-position");
menu.onscroll = function () {
localStorage.setItem("menu-scroll-position", menu.scrollLeft);
}
}
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener("click", function (e) {
e.preventDefault();
var id = this.getAttribute("href").substr(1);
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView({
behavior: "smooth"
});
} else {
document.querySelector(`[id='${decodeURIComponent(id)}']`).scrollIntoView();
}
if (id === "top") {
history.replaceState(null, null, " ");
} else {
history.pushState(null, null, `#${id}`);
}
});
});
</script>
{{- if (not site.Params.disableScrollToTop) }}
<script>
var mybutton = document.getElementById("top-link");
window.onscroll = function () {
if (document.body.scrollTop > 800 || document.documentElement.scrollTop > 800) {
mybutton.style.visibility = "visible";
mybutton.style.opacity = "1";
} else {
mybutton.style.visibility = "hidden";
mybutton.style.opacity = "0";
}
};
</script>
{{- end }}
{{- if (not site.Params.disableThemeToggle) }}
<script>
document.getElementById("theme-toggle").addEventListener("click", () => {
if (document.body.className.includes("dark")) {
document.body.classList.remove('dark');
localStorage.setItem("pref-theme", 'light');
} else {
document.body.classList.add('dark');
localStorage.setItem("pref-theme", 'dark');
}
})
</script>
{{- end }}
{{- if (and (eq .Kind "page") (ne .Layout "archives") (ne .Layout "search") (.Param "ShowCodeCopyButtons")) }}
<script>
document.querySelectorAll('pre > code').forEach((codeblock) => {
const container = codeblock.parentNode.parentNode;
const copybutton = document.createElement('button');
copybutton.classList.add('copy-code');
copybutton.innerHTML = '{{- i18n "code_copy" | default "copy" }}';
function copyingDone() {
copybutton.innerHTML = '{{- i18n "code_copied" | default "copied!" }}';
setTimeout(() => {
copybutton.innerHTML = '{{- i18n "code_copy" | default "copy" }}';
}, 2000);
}
copybutton.addEventListener('click', (cb) => {
if ('clipboard' in navigator) {
navigator.clipboard.writeText(codeblock.textContent);
copyingDone();
return;
}
const range = document.createRange();
range.selectNodeContents(codeblock);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
try {
document.execCommand('copy');
copyingDone();
} catch (e) { };
selection.removeRange(range);
});
if (container.classList.contains("highlight")) {
container.appendChild(copybutton);
} else if (container.parentNode.firstChild == container) {
// td containing LineNos
} else if (codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName == "TABLE") {
// table containing LineNos and code
codeblock.parentNode.parentNode.parentNode.parentNode.parentNode.appendChild(copybutton);
} else {
// code blocks not having highlight as parent class
codeblock.parentNode.appendChild(copybutton);
}
});
</script>
{{- end }}

155
layouts/partials/head.html Executable file
View file

@ -0,0 +1,155 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
{{- if hugo.IsProduction | or (eq site.Params.env "production") | and (ne .Params.robotsNoIndex true) }}
<meta name="robots" content="index, follow">
{{- else }}
<meta name="robots" content="noindex, nofollow">
{{- end }}
{{- /* Title */}}
<title>{{ if .IsHome }}{{ else }}{{ if .Title }}{{ .Title }} | {{ end }}{{ end }}{{ site.Title }}</title>
{{- /* Meta */}}
{{- if .IsHome }}
{{ with site.Params.keywords -}}<meta name="keywords" content="{{- range $i, $e := . }}{{ if $i }}, {{ end }}{{ $e }}{{ end }}">{{ end }}
{{- else }}
<meta name="keywords" content="{{ if .Params.keywords -}}
{{- range $i, $e := .Params.keywords }}{{ if $i }}, {{ end }}{{ $e }}{{ end }} {{- else }}
{{- range $i, $e := .Params.tags }}{{ if $i }}, {{ end }}{{ $e }}{{ end }} {{- end -}}">
{{- end }}
<meta name="description" content="{{- with .Description }}{{ . }}{{- else }}{{- if or .IsPage .IsSection}}
{{- .Summary | default (printf "%s - %s" .Title site.Title) }}{{- else }}
{{- with site.Params.description }}{{ . }}{{- end }}{{- end }}{{- end -}}">
<meta name="author" content="{{ (partial "author.html" . ) }}">
<link rel="canonical" href="{{ if .Params.canonicalURL -}} {{ trim .Params.canonicalURL " " }} {{- else -}} {{ .Permalink }} {{- end }}">
{{- if site.Params.analytics.google.SiteVerificationTag }}
<meta name="google-site-verification" content="{{ site.Params.analytics.google.SiteVerificationTag }}">
{{- end }}
{{- if site.Params.analytics.yandex.SiteVerificationTag }}
<meta name="yandex-verification" content="{{ site.Params.analytics.yandex.SiteVerificationTag }}">
{{- end }}
{{- if site.Params.analytics.bing.SiteVerificationTag }}
<meta name="msvalidate.01" content="{{ site.Params.analytics.bing.SiteVerificationTag }}">
{{- end }}
{{- if site.Params.analytics.naver.SiteVerificationTag }}
<meta name="naver-site-verification" content="{{ site.Params.analytics.naver.SiteVerificationTag }}">
{{- end }}
{{- /* Styles */}}
{{- /* includes */}}
{{- $includes := slice }}
{{- $includes = $includes | append (" " | resources.FromString "includes-blank.css")}}
{{- if not (eq site.Params.assets.disableScrollBarStyle true) }}
{{- $ScrollStyle := (resources.Get "css/includes/scroll-bar.css") }}
{{- $includes = (append $ScrollStyle $includes) }}
{{- end }}
{{- $includes_all := $includes | resources.Concat "includes.css" }}
{{- $theme_vars := (resources.Get "css/core/theme-vars.css") }}
{{- $reset := (resources.Get "css/core/reset.css") }}
{{- $media := (resources.Get "css/core/zmedia.css") }}
{{- $common := (resources.Match "css/common/*.css") | resources.Concat "common.css" }}
{{- /* markup.highlight.noClasses should be set to `false` */}}
{{- $chroma_styles := (resources.Get "css/includes/chroma-styles.css") }}
{{- $chroma_mod := (resources.Get "css/includes/chroma-mod.css") }}
{{- /* order is important */}}
{{- $core := (slice $theme_vars $reset $common $chroma_styles $chroma_mod $includes_all $media) | resources.Concat "core.css" | resources.Minify }}
{{- $extended := (resources.Match "css/extended/*.css") | resources.Concat "extended.css" | resources.Minify }}
{{- /* bundle all required css */}}
{{- /* Add extended css after theme style */ -}}
{{- $stylesheet := (slice $core $extended) | resources.Concat "stylesheet.css" }}
{{- if not site.Params.assets.disableFingerprinting }}
{{- $stylesheet := $stylesheet | fingerprint }}
<link crossorigin="anonymous" href="{{ $stylesheet.RelPermalink }}" integrity="{{ $stylesheet.Data.Integrity }}" rel="preload stylesheet" as="style">
{{- else }}
<link crossorigin="anonymous" href="{{ $stylesheet.RelPermalink }}" rel="preload stylesheet" as="style">
{{- end }}
{{- /* Search */}}
{{- if (eq .Layout `search`) -}}
<link crossorigin="anonymous" rel="preload" as="fetch" href="../index.json">
{{- $fastsearch := resources.Get "js/fastsearch.js" | js.Build (dict "params" (dict "fuseOpts" site.Params.fuseOpts)) | resources.Minify }}
{{- $fusejs := resources.Get "js/fuse.basic.min.js" }}
{{- if not site.Params.assets.disableFingerprinting }}
{{- $search := (slice $fusejs $fastsearch ) | resources.Concat "search.js" | fingerprint }}
<script defer crossorigin="anonymous" src="{{ $search.RelPermalink }}" integrity="{{ $search.Data.Integrity }}"></script>
{{- else }}
{{- $search := (slice $fusejs $fastsearch ) | resources.Concat "search.js" }}
<script defer crossorigin="anonymous" src="{{ $search.RelPermalink }}"></script>
{{- end }}
{{- end -}}
{{- /* Favicons */}}
<link rel="icon" href="{{ site.Params.assets.favicon | default "favicon.ico" | absURL }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ site.Params.assets.favicon16x16 | default "favicon-16x16.png" | absURL }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ site.Params.assets.favicon32x32 | default "favicon-32x32.png" | absURL }}">
<link rel="apple-touch-icon" href="{{ site.Params.assets.apple_touch_icon | default "apple-touch-icon.png" | absURL }}">
<link rel="mask-icon" href="{{ site.Params.assets.safari_pinned_tab | default "safari-pinned-tab.svg" | absURL }}">
<meta name="theme-color" content="{{ site.Params.assets.theme_color | default "#2e2e33" }}">
<meta name="msapplication-TileColor" content="{{ site.Params.assets.msapplication_TileColor | default "#2e2e33" }}">
{{- /* RSS */}}
{{ range .AlternativeOutputFormats -}}
<link rel="{{ .Rel }}" type="{{ .MediaType.Type | html }}" href="{{ .Permalink | safeURL }}">
{{ end -}}
{{- range .AllTranslations -}}
<link rel="alternate" hreflang="{{ .Lang }}" href="{{ .Permalink }}">
{{ end -}}
<noscript>
<style>
#theme-toggle,
.top-link {
display: none;
}
</style>
{{- if (and (ne site.Params.defaultTheme "light") (ne site.Params.defaultTheme "dark")) }}
<style>
@media (prefers-color-scheme: dark) {
:root {
--theme: rgb(29, 30, 32);
--entry: rgb(46, 46, 51);
--primary: rgb(218, 218, 219);
--secondary: rgb(155, 156, 157);
--tertiary: rgb(65, 66, 68);
--content: rgb(196, 196, 197);
--code-block-bg: rgb(46, 46, 51);
--code-bg: rgb(55, 56, 62);
--border: rgb(51, 51, 51);
}
.list {
background: var(--theme);
}
.list:not(.dark)::-webkit-scrollbar-track {
background: 0 0;
}
.list:not(.dark)::-webkit-scrollbar-thumb {
border-color: var(--theme);
}
}
</style>
{{- end }}
</noscript>
{{- partial "extend_head.html" . -}}
{{- /* Misc */}}
{{- if hugo.IsProduction | or (eq site.Params.env "production") }}
{{- template "_internal/google_analytics.html" . }}
{{- template "partials/templates/opengraph.html" . }}
{{- template "partials/templates/twitter_cards.html" . }}
{{- template "partials/templates/schema_json.html" . }}
{{- end -}}

121
layouts/partials/header.html Executable file
View file

@ -0,0 +1,121 @@
{{- /* theme-toggle is enabled */}}
{{- if (not site.Params.disableThemeToggle) }}
{{- /* theme is light */}}
{{- if (eq site.Params.defaultTheme "light") }}
<script>
if (localStorage.getItem("pref-theme") === "dark") {
document.body.classList.add('dark');
}
</script>
{{- /* theme is dark */}}
{{- else if (eq site.Params.defaultTheme "dark") }}
<script>
if (localStorage.getItem("pref-theme") === "light") {
document.body.classList.remove('dark')
}
</script>
{{- else }}
{{- /* theme is auto */}}
<script>
if (localStorage.getItem("pref-theme") === "dark") {
document.body.classList.add('dark');
} else if (localStorage.getItem("pref-theme") === "light") {
document.body.classList.remove('dark')
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.body.classList.add('dark');
}
</script>
{{- end }}
{{- /* theme-toggle is disabled and theme is auto */}}
{{- else if (and (ne site.Params.defaultTheme "light") (ne site.Params.defaultTheme "dark"))}}
<script>
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.body.classList.add('dark');
}
</script>
{{- end }}
{{- if (not site.Params.disableThemeToggle) }}
<script>
// Initialize all theme toggle buttons when the DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
const themeToggles = document.querySelectorAll('.theme-toggle-button');
themeToggles.forEach(function(button) {
button.addEventListener('click', function() {
if (document.body.classList.contains('dark')) {
document.body.classList.remove('dark');
localStorage.setItem("pref-theme", "light");
} else {
document.body.classList.add('dark');
localStorage.setItem("pref-theme", "dark");
}
});
});
});
</script>
{{- end }}
<header class="header">
<nav class="nav">
<div class="logo">
{{- $label_text := (site.Params.label.text | default site.Title) }}
{{- if site.Title }}
<a href="{{ "" | absLangURL }}" accesskey="h" title="{{ $label_text }} (Alt + H)">
{{- if site.Params.label.icon }}
{{- $img := resources.Get site.Params.label.icon }}
{{- if $img }}
{{- $processableFormats := (slice "jpg" "jpeg" "png" "tif" "bmp" "gif") -}}
{{- if hugo.IsExtended -}}
{{- $processableFormats = $processableFormats | append "webp" -}}
{{- end -}}
{{- $prod := (hugo.IsProduction | or (eq site.Params.env "production")) }}
{{- if and (in $processableFormats $img.MediaType.SubType) (eq $prod true)}}
{{- if site.Params.label.iconHeight }}
{{- $img = $img.Resize (printf "x%d" site.Params.label.iconHeight) }}
{{ else }}
{{- $img = $img.Resize "x30" }}
{{- end }}
{{- end }}
<img src="{{ $img.Permalink }}" alt="" aria-label="logo"
height="{{- site.Params.label.iconHeight | default "30" -}}">
{{- else }}
<img src="{{- site.Params.label.icon | absURL -}}" alt="" aria-label="logo"
height="{{- site.Params.label.iconHeight | default "30" -}}">
{{- end -}}
{{- else if hasPrefix site.Params.label.iconSVG "<svg" }}
{{ site.Params.label.iconSVG | safeHTML }}
{{- end -}}
{{- $label_text -}}
<img src="/favicon.svg" alt="favicon" class="site-logo">
</a>
{{- end }}
</div>
{{- $currentPage := . }}
<!-- Desktop menu -->
<div class="menu-wrapper">
{{ partial "menu.html" }}
</div>
<!-- Hamburger Menu -->
<!-- Icon -->
<label for="menu-toggle" class="hamburger-menu" aria-label="Toggle menu">
<img src="/icons/hamburger-menu.svg" alt="Menu" width="24" height="24">
</label>
<!-- Hidden checkbox for toggling menu -->
<input type="checkbox" id="menu-toggle">
<!-- Menu overlay -->
<div class="menu-overlay">
<div class="mobile-menu">
<label for="menu-toggle" class="mobile-menu-close" aria-label="Close menu">
<img src="/icons/close-menu.svg" alt="Close Menu" width="24" height="24">
</label>
{{ partial "menu.html" }}
</div>
</div>
</nav>
</header>

13
layouts/partials/home_info.html Executable file
View file

@ -0,0 +1,13 @@
{{- with site.Params.homeInfoParams }}
<article class="first-entry home-info">
<header class="entry-header">
<h1>{{ .Title | markdownify }}</h1>
</header>
<div class="entry-content">
{{ .Content | markdownify }}
</div>
<footer class="entry-footer">
{{ partial "social_icons.html" (dict "align" site.Params.homeInfoParams.AlignSocialIconsTo) }}
</footer>
</article>
{{- end -}}

View file

@ -0,0 +1,58 @@
<div class="profile">
{{- with site.Params.profileMode }}
<div class="profile_inner">
{{- if .imageUrl -}}
{{- $img := "" }}
{{- if not (urls.Parse .imageUrl).IsAbs }}
{{- $img = resources.Get .imageUrl }}
{{- end }}
{{- if $img }}
{{- $processableFormats := (slice "jpg" "jpeg" "png" "tif" "bmp" "gif") -}}
{{- if hugo.IsExtended -}}
{{- $processableFormats = $processableFormats | append "webp" -}}
{{- end -}}
{{- $prod := (hugo.IsProduction | or (eq site.Params.env "production")) }}
{{- if and (in $processableFormats $img.MediaType.SubType) (eq $prod true)}}
{{- if (not (and (not .imageHeight) (not .imageWidth))) }}
{{- $img = $img.Resize (printf "%dx%d" .imageWidth .imageHeight) }}
{{- else if .imageHeight }}
{{- $img = $img.Resize (printf "x%d" .imageHeight) }}
{{ else if .imageWidth }}
{{- $img = $img.Resize (printf "%dx" .imageWidth) }}
{{ else }}
{{- $img = $img.Resize "150x150" }}
{{- end }}
{{- end }}
<img draggable="false" src="{{ $img.Permalink }}" alt="{{ .imageTitle | default "profile image" }}" title="{{ .imageTitle }}"
height="{{ .imageHeight | default 150 }}" width="{{ .imageWidth | default 150 }}" />
{{- else }}
<img draggable="false" src="{{ .imageUrl | absURL }}" alt="{{ .imageTitle | default "profile image" }}" title="{{ .imageTitle }}"
height="{{ .imageHeight | default 150 }}" width="{{ .imageWidth | default 150 }}" />
{{- end }}
{{- end }}
<h1>{{ .title | default site.Title | markdownify }}</h1>
<span>{{ .subtitle | markdownify }}</span>
{{- partial "social_icons.html" -}}
{{- with .buttons }}
<div class="buttons">
{{- range . }}
<a class="button" href="{{ trim .url " " }}" rel="noopener" title="{{ .name }}">
<span class="button-inner">
{{ .name }}
{{- if (findRE "://" .url) }}&nbsp;
<svg fill="none" shape-rendering="geometricPrecision" stroke="currentColor" stroke-linecap="round"
stroke-linejoin="round" stroke-width="2.5" viewBox="0 0 24 24" height="14" width="14">
<path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"></path>
<path d="M15 3h6v6"></path>
<path d="M10 14L21 3"></path>
</svg>
{{- end }}
</span>
</a>
{{- end }}
</div>
{{- end }}
</div>
{{- end}}
</div>

91
layouts/partials/menu.html Executable file
View file

@ -0,0 +1,91 @@
<ul class="menu">
<li>
<a href="/blog">
<img class="icon" src="/icons/bulle.svg" alt="Blog">
<span>Blog</span>
</a>
</li>
<li>
<a href="/collection">
<img class="icon" src="/favicon.svg" alt="Machines">
<span>Machines</span>
</a>
</li>
<li>
<a href="/livres">
<img class="icon" src="/icons/livre.svg" alt="Lectures">
<span>Lectures</span>
</a>
</li>
<li>
<a href="/liens">
<img class="icon" src="/icons/lien.svg" alt="Liens">
<span>Liens</span>
</a>
</li>
<li>
<a href="/a-propos">
<img class="icon" src="/icons/a-propos.svg" alt="A propos">
<span>A propos</span>
</a>
</li>
<li>
<a href="/contact">
<img class="icon" src="/icons/lettre.svg" alt="Contact">
<span>Contact</span>
</a>
</li>
<li>
<a href="/feed.xml">
<img class="icon" src="/icons/rss.svg" alt="RSS">
<span>RSS</span>
</a>
</li>
<li>
<div class="logo-switches">
{{- if (not site.Params.disableThemeToggle) }}
<button class="theme-toggle-button" accesskey="t" title="(Alt + T)" aria-label="Toggle theme">
<svg class="moon-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round">
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
</svg>
<svg class="sun-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="18" viewBox="0 0 24 24"
fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
stroke-linejoin="round">
<circle cx="12" cy="12" r="5"></circle>
<line x1="12" y1="1" x2="12" y2="3"></line>
<line x1="12" y1="21" x2="12" y2="23"></line>
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
<line x1="1" y1="12" x2="3" y2="12"></line>
<line x1="21" y1="12" x2="23" y2="12"></line>
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
</svg>
</button>
{{- end }}
{{- $lang := .Lang}}
{{- with site.Home.Translations }}
<ul class="lang-switch">
{{- range . -}}
{{- if ne $lang .Lang }}
<li>
<a href="{{- .Permalink -}}" title="{{ .Language.Params.languageAltTitle | default (.Language.LanguageName | emojify) | default (.Lang | title) }}"
aria-label="{{ .Language.LanguageName | default (.Lang | title) }}">
{{- if (and site.Params.displayFullLangName (.Language.LanguageName)) }}
{{- .Language.LanguageName | emojify -}}
{{- else }}
{{- .Lang | title -}}
{{- end -}}
</a>
</li>
{{- end -}}
{{- end}}
</ul>
{{- end }}
</div>
</li>
</ul>

View file

@ -0,0 +1,9 @@
{{ if and (.Params.canonicalURL) (.Params.ShowCanonicalLink ) -}}
{{ $url := urls.Parse .Params.canonicalURL }}
{{- if or .Params.author site.Params.author (.Param "ShowReadingTime") (not .Date.IsZero) .IsTranslated (or .Params.editPost.URL site.Params.editPost.URL) }}&nbsp;|&nbsp;{{- end -}}
<span>
{{- (site.Params.CanonicalLinkText | default .Params.CanonicalLinkText) | default "Originally published at" -}}
&nbsp;<a href="{{ trim .Params.canonicalURL " " }}" title="{{ trim .Params.canonicalURL " " }}" target="_blank" rel="noopener noreferrer">{{ $url.Host }}</a>
</span>
{{- end }}

23
layouts/partials/post_meta.html Executable file
View file

@ -0,0 +1,23 @@
{{- $scratch := newScratch }}
{{- if not .Date.IsZero -}}
{{- $scratch.Add "meta" (slice (printf "<span title='%s'>%s</span>" (.Date) (.Date | time.Format (default "January 2, 2006" site.Params.DateFormat)))) }}
{{- end }}
{{- if (.Param "ShowReadingTime") -}}
{{- $scratch.Add "meta" (slice (i18n "read_time" .ReadingTime | default (printf "%d min" .ReadingTime))) }}
{{- end }}
{{- if (.Param "ShowWordCount") -}}
{{- $scratch.Add "meta" (slice (i18n "words" .WordCount | default (printf "%d words" .WordCount))) }}
{{- end }}
{{- if not (.Param "hideAuthor") -}}
{{- with (partial "author.html" .) }}
{{- $scratch.Add "meta" (slice .) }}
{{- end }}
{{- end }}
{{- with ($scratch.Get "meta") }}
{{- delimit . "&nbsp;·&nbsp;" | safeHTML -}}
{{- end -}}

View file

@ -0,0 +1,19 @@
{{- $pages := where site.RegularPages "Type" "in" site.Params.mainSections }}
{{- if and (gt (len $pages) 1) (in $pages . ) }}
<nav class="paginav">
{{- with $pages.Next . }}
<a class="prev" href="{{ .Permalink }}">
<span class="title">« {{ i18n "prev_page" }}</span>
<br>
<span>{{- .Name -}}</span>
</a>
{{- end }}
{{- with $pages.Prev . }}
<a class="next" href="{{ .Permalink }}">
<span class="title">{{ i18n "next_page" }} »</span>
<br>
<span>{{- .Name -}}</span>
</a>
{{- end }}
</nav>
{{- end }}

View file

@ -0,0 +1,141 @@
{{ $direction := .direction | default "up" }}
{{ $context := .context }}
<div class="scrolling-posts-container">
<div class="scrolling-posts-inner">
<div class="scrolling-posts {{ $direction }}-scroll">
{{- $pages := first 20 (sort (where $context.Site.RegularPages "Section" "ne" "") "Date" "desc") -}}
{{- range (sort $pages "Date" "desc") -}}
{{- $image := .Resources.GetMatch (printf "%s" .Params.cover.image) -}}
{{- if $image -}}
{{- $fittedImage := $image.Fill "400x400 smart webp q95" -}}
{{- $optimizedBlurredImage := $fittedImage.Filter (images.GaussianBlur 3) -}}
<a href="{{ .RelPermalink }}" class="scrolling-posts-item" style="background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0.2)), url('{{ $optimizedBlurredImage.RelPermalink }}');">
<span class="section-badge">{{ .Section }}</span>
<span class="scrolling-posts-item-title">{{ .Title }}</span>
<p class="scrolling-posts-date">{{ .Date.Format "2006-01-02" }}</p>
</a>
{{- end -}}
{{- end -}}
</div>
<div class="scrolling-posts {{ $direction }}-scroll">
{{- $pages := first 20 (sort (where $context.Site.RegularPages "Section" "ne" "") "Date" "desc") -}}
{{- range (sort $pages "Date" "desc") -}}
{{- $image := .Resources.GetMatch (printf "%s" .Params.cover.image) -}}
{{- if $image -}}
{{- $fittedImage := $image.Fill "400x400 smart webp q95" -}}
{{- $optimizedBlurredImage := $fittedImage.Filter (images.GaussianBlur 3) -}}
<a href="{{ .RelPermalink }}" class="scrolling-posts-item" style="background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.8), rgba(255, 255, 255, 0.2)), url('{{ $optimizedBlurredImage.RelPermalink }}');">
<span class="section-badge">{{ .Section }}</span>
<span class="scrolling-posts-item-title">{{ .Title }}</span>
<p class="scrolling-posts-date">{{ .Date.Format "2006-01-02" }}</p>
</a>
{{- end -}}
{{- end -}}
</div>
</div>
</div>
<style>
.scrolling-posts-container {
width: 100%;
border: none;
overflow: hidden;
height: 100%;
}
.scrolling-posts-inner {
display: flex;
flex-direction: column;
white-space: nowrap;
padding: 0;
margin: 0;
}
.scrolling-posts {
display: flex;
flex-direction: column;
gap: 1rem;
}
.scrolling-posts > a:nth-child(1) {
margin-top: 1rem;
}
.scrolling-posts-item {
padding: 10px;
border: solid 1px #ccc;
background: var(--entry);
border-radius: var(--radius);
border: 1px solid var(--border);
height: 100px;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
}
.scrolling-posts-item-title {
font-size: 1em;
margin: 0;
color: #ccc;
font-weight: 400;
line-height: 1.5em;
text-decoration: none;
text-align: left;
overflow: hidden;
}
.scrolling-posts-date {
font-size: 0.8em;
color: #ccc;
margin: 0;
text-align: left;
}
.section-badge {
display: inline-block;
font-size: 0.8em;
padding: 2px 6px;
margin-right: 5px;
background-color: var(--theme);
border-radius: 3px;
color: var(--primary);
}
.up-scroll {
animation: scrollUp 50s linear infinite;
}
.down-scroll {
animation: scrollDown 50s linear infinite;
}
@keyframes scrollUp {
0% {
transform: translateY(0%);
}
100% {
transform: translateY(-100%);
}
}
@keyframes scrollDown {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(0);
}
}
</style>

View file

@ -0,0 +1,19 @@
{{ $n := 1 }} <!-- Change this value to set the number of posts to display -->
{{ range first $n (where .Site.RegularPages.ByDate.Reverse "Section" "blog") }}
{{- $image := .Resources.GetMatch (printf "%s" .Params.cover.image) -}}
{{- if $image -}}
{{- $optimizedImage := $image.Fill "100x100 webp q95 Center" -}}
<a href="{{ .RelPermalink }}" >
<h3>{{ .Title }}</h3>
<img src="{{ $optimizedImage.RelPermalink }}" alt="{{ .Title }} cover image"></img>
<small>{{ .Date.Format "January 2, 2006" }}</small>
<p>{{ .Summary | truncate 100 }}</p>
</a>
{{ end }}
{{ end }}

983
layouts/partials/svg.html Executable file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,47 @@
{{- $imgs := slice }}
{{- $imgParams := .Params.images }}
{{- $resources := .Resources.ByType "image" -}}
{{/* Find featured image resources if the images parameter is empty. */}}
{{- if not $imgParams }}
{{- $featured := $resources.GetMatch "*feature*" -}}
{{- if not $featured }}{{ $featured = $resources.GetMatch "{*cover*,*thumbnail*}" }}{{ end -}}
{{- with $featured }}
{{- $imgs = $imgs | append (dict
"Image" .
"RelPermalink" .RelPermalink
"Permalink" .Permalink) }}
{{- end }}
{{- end }}
{{/* Use the first one of site images as the fallback. */}}
{{- if and (not $imgParams) (not $imgs) }}
{{- with site.Params.images }}
{{- $imgParams = first 1 . }}
{{- end }}
{{- end }}
{{/* Parse page's images parameter. */}}
{{- range $imgParams }}
{{- $img := . }}
{{- $url := urls.Parse $img }}
{{- if eq $url.Scheme "" }}
{{/* Internal image. */}}
{{- with $resources.GetMatch $img -}}
{{/* Image resource. */}}
{{- $imgs = $imgs | append (dict
"Image" .
"RelPermalink" .RelPermalink
"Permalink" .Permalink) }}
{{- else }}
{{- $imgs = $imgs | append (dict
"RelPermalink" (relURL $img)
"Permalink" (absURL $img)
) }}
{{- end }}
{{- else }}
{{/* External image */}}
{{- $imgs = $imgs | append (dict
"RelPermalink" $img
"Permalink" $img
) }}
{{- end }}
{{- end }}
{{- return $imgs }}

View file

@ -0,0 +1,86 @@
<meta property="og:url" content="{{ .Permalink }}">
{{- with or site.Title site.Params.title | plainify }}
<meta property="og:site_name" content="{{ . }}">
{{- end }}
{{- with or .Title site.Title site.Params.title | plainify }}
<meta property="og:title" content="{{ . }}">
{{- end }}
{{- with or .Description .Summary site.Params.description | plainify | htmlUnescape | chomp }}
<meta property="og:description" content="{{ . }}">
{{- end }}
{{- with or .Params.locale site.Language.LanguageCode site.Language.Lang }}
<meta property="og:locale" content="{{ . }}">
{{- end }}
{{- if .IsPage }}
<meta property="og:type" content="article">
{{- with .Section }}
<meta property="article:section" content="{{ . }}">
{{- end }}
{{- $ISO8601 := "2006-01-02T15:04:05-07:00" }}
{{- with .PublishDate }}
<meta property="article:published_time" {{ .Format $ISO8601 | printf "content=%q" | safeHTMLAttr }}>
{{- end }}
{{- with .Lastmod }}
<meta property="article:modified_time" {{ .Format $ISO8601 | printf "content=%q" | safeHTMLAttr }}>
{{- end }}
{{- range .GetTerms "tags" | first 6 }}
<meta property="article:tag" content="{{ .Page.Title | plainify }}">
{{- end }}
{{- else }}
<meta property="og:type" content="website">
{{- end }}
{{- if .Params.cover.image -}}
{{- if (ne .Params.cover.relative true) }}
<meta property="og:image" content="{{ .Params.cover.image | absURL }}">
{{- else}}
<meta property="og:image" content="{{ (path.Join .RelPermalink .Params.cover.image ) | absURL }}">
{{- end}}
{{- else }}
{{- with partial "_funcs/get-page-images" . }}
{{- range . | first 6 }}
<meta property="og:image" content="{{ .Permalink }}">
{{- end }}
{{- end }}
{{- end }}
{{- with .Params.audio }}
{{- range . | first 6 }}
<meta property="og:audio" content="{{ . | absURL }}">
{{- end }}
{{- end }}
{{- with .Params.videos }}
{{- range . | first 6 }}
<meta property="og:video" content="{{ . | absURL }}">
{{- end }}
{{- end }}
{{- range .GetTerms "series" }}
{{- range .Pages | first 7 }}
{{- if ne $ . }}
<meta property="og:see_also" content="{{ .Permalink }}">
{{- end }}
{{- end }}
{{- end }}
{{- with site.Params.social }}
{{- if reflect.IsMap . }}
{{- with .facebook_app_id }}
<meta property="fb:app_id" content="{{ . }}">
{{- else }}
{{- with .facebook_admin }}
<meta property="fb:admins" content="{{ . }}">
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- with (.Param "social.fediverse_creator") }}
<meta name="fediverse:creator" content="{{ . }}">
{{- end }}

View file

@ -0,0 +1,128 @@
{{ if .IsHome }}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "{{- ( site.Params.schema.publisherType | default "Organization") | title -}}",
"name": {{ site.Title }},
"url": {{ site.Home.Permalink }},
"description": {{ site.Params.description | plainify | truncate 180 | safeHTML }},
{{- if (eq site.Params.schema.publisherType "Person") }}
"image": {{ site.Params.assets.favicon | default "favicon.ico" | absURL }},
{{- else }}
"logo": {{ site.Params.assets.favicon | default "favicon.ico" | absURL }},
{{- end }}
"sameAs": [
{{- if site.Params.schema.sameAs }}
{{ range $i, $e := site.Params.schema.sameAs }}{{ if $i }}, {{ end }}{{ trim $e " " }}{{ end }}
{{- else}}
{{ range $i, $e := site.Params.SocialIcons }}{{ if $i }}, {{ end }}{{ trim $e.url " " | safeURL }}{{ end }}
{{- end}}
]
}
</script>
{{- else if (or .IsPage .IsSection) }}
{{/* BreadcrumbList */}}
{{- $url := replace .Parent.Permalink ( printf "%s" site.Home.Permalink) "" }}
{{- $lang_url := strings.TrimPrefix ( printf "%s/" .Lang) $url }}
{{- $bc_list := (split $lang_url "/")}}
{{- $scratch := newScratch }}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{{- range $index, $element := $bc_list }}
{{- $scratch.Add "path" (printf "%s/" $element ) | safeJS }}
{{- $bc_pg := site.GetPage ($scratch.Get "path") -}}
{{- if (and ($bc_pg) (gt (len . ) 0))}}
{{- if (and $index)}}, {{end }}
{
"@type": "ListItem",
"position": {{ add 1 $index }},
"name": {{ $bc_pg.Name }},
"item": {{ $bc_pg.Permalink | safeHTML }}
}
{{- end }}
{{- end }}
{{- /* self-page addition */ -}}
{{- if (ge (len $bc_list) 2) }}, {{end }}
{
"@type": "ListItem",
"position": {{len $bc_list}},
"name": {{ .Name }},
"item": {{ .Permalink | safeHTML }}
}
]
}
</script>
{{- if .IsPage }}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": {{ .Title | plainify}},
"name": "{{ .Title | plainify }}",
"description": {{ with .Description | plainify }}{{ . }}{{ else }}{{ .Summary | plainify }}{{ end -}},
"keywords": [
{{- if .Params.keywords }}
{{ range $i, $e := .Params.keywords }}{{ if $i }}, {{ end }}{{ $e }}{{ end }}
{{- else }}
{{ range $i, $e := .Params.tags }}{{ if $i }}, {{ end }}{{ $e }}{{ end }}
{{- end }}
],
"articleBody": {{ .Content | safeJS | htmlUnescape | plainify }},
"wordCount" : "{{ .WordCount }}",
"inLanguage": {{ .Language.Lang | default "en-us" }},
{{ if .Params.cover.image -}}
"image":
{{- if (ne .Params.cover.relative true) -}}
{{ .Params.cover.image | absURL }},
{{- else -}}
{{ (path.Join .RelPermalink .Params.cover.image ) | absURL }},
{{- end}}
{{- else }}
{{- $images := partial "templates/_funcs/get-page-images" . -}}
{{- with index $images 0 -}}
"image": {{ .Permalink }},
{{- end }}
{{- end -}}
"datePublished": {{ .PublishDate }},
"dateModified": {{ .Lastmod }},
{{- with (.Params.author | default site.Params.author) }}
"author":
{{- if (or (eq (printf "%T" .) "[]string") (eq (printf "%T" .) "[]interface {}")) -}}
[{{- range $i, $v := . -}}
{{- if $i }}, {{end -}}
{
"@type": "Person",
"name": {{ $v }}
}
{{- end }}],
{{- else -}}
{
"@type": "Person",
"name": {{ . }}
},
{{- end -}}
{{- end }}
"mainEntityOfPage": {
"@type": "WebPage",
"@id": {{ .Permalink | safeHTML }}
},
"publisher": {
"@type": "{{- ( site.Params.schema.publisherType | default "Organization") | title -}}",
"name": {{ site.Title }},
"logo": {
"@type": "ImageObject",
"url": {{ site.Params.assets.favicon | default "favicon.ico" | absURL }}
}
}
}
</script>
{{- end }}{{/* .IsPage end */}}
{{- end -}}

View file

@ -0,0 +1,31 @@
{{- if .Params.cover.image -}}
<meta name="twitter:card" content="summary_large_image">
{{- if (ne $.Params.cover.relative true) }}
<meta name="twitter:image" content="{{ .Params.cover.image | absURL }}">
{{- else }}
<meta name="twitter:image" content="{{ (path.Join .RelPermalink .Params.cover.image ) | absURL }}">
{{- end}}
{{- else }}
{{- $images := partial "templates/_funcs/get-page-images" . -}}
{{- with index $images 0 -}}
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="{{ .Permalink }}">
{{- else -}}
<meta name="twitter:card" content="summary">
{{- end -}}
{{- end }}
<meta name="twitter:title" content="{{ .Title }}">
<meta name="twitter:description" content="{{ with .Description }}{{ . }}{{ else }}{{if .IsPage}}{{ .Summary }}{{ else }}{{ with site.Params.description }}{{ . }}{{ end }}{{ end }}{{ end -}}">
{{- $twitterSite := "" }}
{{- with site.Params.social }}
{{- if reflect.IsMap . }}
{{- with .twitter }}
{{- $content := . }}
{{- if not (strings.HasPrefix . "@") }}
{{- $content = printf "@%v" . }}
{{- end }}
<meta name="twitter:site" content="{{ $content }}">
{{- end }}
{{- end }}
{{- end }}

97
layouts/partials/toc.html Executable file
View file

@ -0,0 +1,97 @@
{{- $headers := findRE "<h[1-6].*?>(.|\n])+?</h[1-6]>" .Content -}}
{{- $has_headers := ge (len $headers) 1 -}}
{{- if $has_headers -}}
<div class="toc">
<details {{if (.Param "TocOpen") }} open{{ end }}>
<summary accesskey="c" title="(Alt + C)">
<span class="details">{{- i18n "toc" | default "Table of Contents" }}</span>
</summary>
<div class="inner">
{{- if (.Param "UseHugoToc") }}
{{- .TableOfContents -}}
{{- else }}
{{- $largest := 6 -}}
{{- range $headers -}}
{{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
{{- $headerLevel := len (seq $headerLevel) -}}
{{- if lt $headerLevel $largest -}}
{{- $largest = $headerLevel -}}
{{- end -}}
{{- end -}}
{{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}}
{{- $.Scratch.Set "bareul" slice -}}
<ul>
{{- range seq (sub $firstHeaderLevel $largest) -}}
<ul>
{{- $.Scratch.Add "bareul" (sub (add $largest .) 1) -}}
{{- end -}}
{{- range $i, $header := $headers -}}
{{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
{{- $headerLevel := len (seq $headerLevel) -}}
{{/* get id="xyz" */}}
{{- $id := index (findRE "(id=\"(.*?)\")" $header 9) 0 }}
{{- /* strip id="" to leave xyz, no way to get regex capturing groups in hugo */ -}}
{{- $cleanedID := replace (replace $id "id=\"" "") "\"" "" }}
{{- $header := replaceRE "<h[1-6].*?>((.|\n])+?)</h[1-6]>" "$1" $header -}}
{{- if ne $i 0 -}}
{{- $prevHeaderLevel := index (findRE "[1-6]" (index $headers (sub $i 1)) 1) 0 -}}
{{- $prevHeaderLevel := len (seq $prevHeaderLevel) -}}
{{- if gt $headerLevel $prevHeaderLevel -}}
{{- range seq $prevHeaderLevel (sub $headerLevel 1) -}}
<ul>
{{/* the first should not be recorded */}}
{{- if ne $prevHeaderLevel . -}}
{{- $.Scratch.Add "bareul" . -}}
{{- end -}}
{{- end -}}
{{- else -}}
</li>
{{- if lt $headerLevel $prevHeaderLevel -}}
{{- range seq (sub $prevHeaderLevel 1) -1 $headerLevel -}}
{{- if in ($.Scratch.Get "bareul") . -}}
</ul>
{{/* manually do pop item */}}
{{- $tmp := $.Scratch.Get "bareul" -}}
{{- $.Scratch.Delete "bareul" -}}
{{- $.Scratch.Set "bareul" slice}}
{{- range seq (sub (len $tmp) 1) -}}
{{- $.Scratch.Add "bareul" (index $tmp (sub . 1)) -}}
{{- end -}}
{{- else -}}
</ul>
</li>
{{- end -}}
{{- end -}}
{{- end -}}
{{- end }}
<li>
<a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify | safeHTML -}}">{{- $header | plainify | safeHTML -}}</a>
{{- else }}
<li>
<a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify | safeHTML -}}">{{- $header | plainify | safeHTML -}}</a>
{{- end -}}
{{- end -}}
<!-- {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}} -->
{{- $firstHeaderLevel := $largest }}
{{- $lastHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers (sub (len $headers) 1)) 1) 0)) }}
</li>
{{- range seq (sub $lastHeaderLevel $firstHeaderLevel) -}}
{{- if in ($.Scratch.Get "bareul") (add . $firstHeaderLevel) }}
</ul>
{{- else }}
</ul>
</li>
{{- end -}}
{{- end }}
</ul>
{{- end }}
</div>
</details>
</div>
{{- end }}

View file

@ -0,0 +1,19 @@
{{- if .IsTranslated -}}
{{- if (ne .Layout "search") }}
{{- if or .Params.author site.Params.author (.Param "ShowReadingTime") (not .Date.IsZero) }}&nbsp;|&nbsp;{{- end -}}
{{- end }}
{{- i18n "translations" | default "Translations" }}:
<ul class="i18n_list">
{{- range .Translations }}
<li>
<a href="{{ .Permalink }}">
{{- if (and site.Params.displayFullLangName (.Language.LanguageName)) }}
{{- .Language.LanguageName | emojify -}}
{{- else }}
{{- .Lang | title -}}
{{- end -}}
</a>
</li>
{{- end }}
</ul>
{{- end -}}