Add Lotusdocs theme

This commit is contained in:
Abner Coimbre
2026-01-11 16:46:05 -08:00
parent d051d46d1f
commit 8a4d04db58
577 changed files with 40404 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
<nav aria-label="breadcrumb" class="d-inline-block pb-2 mt-1 mt-sm-0">
<ul id="breadcrumbs" class="breadcrumb bg-transparent mb-0" itemscope itemtype="https://schema.org/BreadcrumbList">
{{- $data := newScratch }}
{{ $docRoot := .FirstSection.Title }}
{{- range $index, $value := (after 1 .Ancestors.Reverse) }}
{{ if eq $docRoot .Title }}
<li class="breadcrumb-item text-capitalize active" aria-current="page" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
{{- $data.Set "counter" $index }}
{{- $data.Add "counter" 1 }}
<a itemprop="item" href="{{ .RelPermalink }}">
<i class="material-icons size-20 align-text-bottom" itemprop="name">Home</i>
</a>
<meta itemprop="position" content='{{ $data.Get "counter"}}' />
</li>
{{ else }}
<li class="breadcrumb-item text-capitalize" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
{{- $data.Add "counter" 1 }}
<a itemprop="item" href="{{ .RelPermalink }}">
<span itemprop="name">{{ .Title }}</span>
</a>
<meta itemprop="position" content='{{ $data.Get "counter"}}' />
</li>
{{ end }}
{{- end }}
{{ if eq .Title $docRoot }}
<li class="breadcrumb-item text-capitalize active" aria-current="page" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
{{- $data.Add "counter" 1 }}
<i class="material-icons size-20 align-text-bottom" itemprop="name">Home</i>
<meta itemprop="position" content='{{ $data.Get "counter"}}' />
</li>
{{ else }}
<li class="breadcrumb-item text-capitalize active" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
{{- $data.Add "counter" 1 }}
<span itemprop="name">{{ .Title }}</span>
<meta itemprop="position" content='{{ $data.Get "counter"}}' />
</li>
{{ end }}
</ul>
</nav>

View File

@@ -0,0 +1,37 @@
<hr class="doc-hr">
<div id="doc-nav" class="d-print-none">
{{ if or .Prev .Next -}}
<!-- https://www.feliciano.tech/blog/custom-sort-hugo-single-pages/ -->
{{ $pages := where .Site.RegularPages "Section" .Section -}}
<div class="row flex-xl-nowrap {{ if .Next }}{{ else }}flex-row-reverse{{ end }}">
{{ with $pages.Next . -}}
<div class="col-sm-6 pt-2 doc-next">
<a href="{{ .RelPermalink }}">
<div class="card h-100 my-1">
<div class="card-body py-2">
<p class="card-title fs-5 fw-semibold lh-base mb-0"><i class="material-icons align-middle">navigate_before</i> {{ .Title }}</p>
{{ if eq .Site.Params.docs.navDesc true -}}
<p class="card-text ms-2">{{ .Description | truncate (.Site.Params.docs.navDescTrunc | default 40) }}</p>
{{ end }}
</div>
</div>
</a>
</div>
{{ end -}}
{{ with $pages.Prev . -}}
<div class="col-sm-6 pt-2 doc-prev">
<a class="ms-auto" href="{{ .RelPermalink }}">
<div class="card h-100 my-1 text-end">
<div class="card-body py-2">
<p class="card-title fs-5 fw-semibold lh-base mb-0">{{ .Title }} <i class="material-icons align-middle">navigate_next</i></p>
{{ if eq .Site.Params.docs.navDesc true -}}
<p class="card-text me-2">{{ .Description | truncate (.Site.Params.docs.navDescTrunc | default 40) }}</p>
{{ end }}
</div>
</div>
</a>
</div>
{{ end -}}
</div>
{{ end -}}
</div>

View File

@@ -0,0 +1,16 @@
<!-- Footer Start -->
<footer class="shadow py-3 d-print-none">
<div class="container-fluid">
<div class="row align-items-center">
<div class="col">
<div class="text-sm-start text-center mx-md-2">
<p class="mb-0">
{{ $yearToken := (cond (isset .Site.Params (lower "copyrightYearToken")) $.Site.Params.copyrightYearToken ":YEAR:") }}
{{ replace $.Site.Params.footer.copyright $yearToken (string (now.Format "2006")) | markdownify }}
</p>
</div>
</div><!--end col-->
</div><!--end row-->
</div><!--end container-->
</footer><!--end footer-->
<!-- End -->

View File

@@ -0,0 +1,18 @@
<script>
window.addEventListener('DOMContentLoaded', function() {
// DocSearch Config
docsearch({
container: '#docsearch',
appId: '{{ .Site.Params.docsearch.appID }}',
apiKey: '{{ .Site.Params.docsearch.apiKey }}',
indexName: '{{ .Site.Params.docsearch.indexName }}',
placeholder: 'Search Documentation',
translations: {
button: {
buttonText: '{{ i18n "search_title" }}',
buttonAriaLabel: 'Search',
}
}
});
});
</script>

View File

@@ -0,0 +1,319 @@
{{ if eq .Site.Params.feedback.emoticonTpl true -}}
{{ $emoticons := slice "very_satisfied" "satisfied" "dissatisfied" "very_dissatisfied" }}
<div class="container d-flex align-items-center justify-content-center">
<div id="feedback-widget-emoticon" class="mt-4">
<div id="feedback-cta" class="d-flex justify-content-center py-1">
<span class="fs-6 align-self-center align-middle ms-2 me-0">
{{ i18n "feedback_helpful" | default "Was this page helpful?" }}
</span>
<div class="d-flex">
<div class="form-emoji d-flex ps-2">
{{ range $index, $value := $emoticons }}
<div class="radio-emoji">
<input type="radio" name="feedback-emoticon" autocomplete="off" value="{{ $value | humanize | title }}" id="radio_{{ $index }}" required>
<label class="d-flex justify-content-center align-items-center" for="radio_{{ $index }}">
{{ $emoticon := resources.Get ( printf "%s%s.svg" "images/icons/feedback/" $value ) }}
{{ $emoticon.Content | safeHTML }}
<!-- <i class="feedback-emoji material-icons">
sentiment_{{ $value }}
</i> -->
</label>
</div>
{{ end }}
</div>
</div>
</div>
<div id="feedback-emoji-end" class="d-flex justify-content-md-start justify-content-sm-center">
</div>
<div id="feedback-send">
<div id="text-wrapper">
<textarea id="textarea-emoji" cols="55" maxlength="500" rows="3" placeholder="(Optional) Try to be as specific and detailed as possible!" type="text" class="feedback-textarea-emoji p-2 mb-2"></textarea>
</div>
<div id="feedback-emoji-submit-container" class="d-flex justify-content-end">
<button type="button" id="feedback-emoji-submit-button" class="feedback-submit-emoji-btn btn btn-sm btn-primary mt-1 mb-2" role="button" type="submit" disabled>
{{ i18n "feedback_submit" | default "Submit" }}
</button>
</div>
</div>
</div>
</div>
<script>
const emojiTextWrapper = document.getElementById("text-wrapper");
const emojiRadios = document.querySelectorAll('input[name="feedback-emoticon"]');
const emojiContainer = document.getElementById("feedback-widget-emoticon");
const feedbackEmojiCta = document.getElementById("feedback-cta");
const feedbackEmojiSubmitContainer = document.getElementById("feedback-emoji-submit-container");
const feedbackEmojiSubmitBtn = document.getElementById("feedback-emoji-submit-button");
// Show emoji text area
emojiRadios.forEach(emojiRadio => {
emojiRadio.addEventListener('change', function(event) {
const emojiRadioID = event.target.id;
emojiContainer.style.borderRadius = '8px'
feedbackEmojiCta.classList.add("px-4");
emojiTextWrapper.classList.add("is-visible");
feedbackEmojiSubmitBtn.removeAttribute("disabled");
feedbackEmojiSubmitContainer.classList.add("is-visible");
// emojiTextWrapper.addEventListener('transitionend', function () {
// // do something!!!
// }
// );
})
});
// Submit emoticon feedback to Google or Plausible analytics
feedbackEmojiSubmitBtn.addEventListener('click', event => {
const result = document.getElementById("feedback-emoji-end");
const sendArea = document.getElementById("feedback-send");
const rating = document.querySelector('input[name="feedback-emoticon"]:checked').value;
const message = document.getElementById('textarea-emoji').value;
function success(e) {
feedbackEmojiCta.remove();
sendArea.remove();
result.innerHTML = '{{ .Site.Params.feedback.successMsg | default "Thank you for helping to improve our documentation!" }}';
result.classList.add("is-visible");
}
try {
{{ if .Site.Config.Services.GoogleAnalytics.ID -}}
{{ if not .Site.Params.feedback.eventDest | or (in .Site.Params.feedback.eventDest "google") -}}
gtag('event', '{{ replaceRE `( {1,})` "_" (.Site.Params.feedback.emoticonEventName | default "feedback" | lower) }}',
{
'rating': rating.replace(/\s+/g, '_').toLowerCase(),
'message': message,
'event_callback': success
}
),
{{ end -}}
{{ end -}}
{{ if .Site.Params.plausible.dataDomain -}}
{{ if not .Site.Params.feedback.eventDest | or (in .Site.Params.feedback.eventDest "plausible") -}}
plausible('{{ .Site.Params.feedback.emoticonEventName | default "Feedback" }}',
{
callback: success,
props:
{
rating: rating,
message: message
}
}
)
{{ end -}}
{{ end -}}
} catch (err) {
console.log(err);
feedbackEmojiCta.remove();
sendArea.remove();
result.innerHTML = '{{ .Site.Params.feedback.errorMsg | default "Sorry! There was an error while attempting to submit your feedback!" }}';
result.classList.add("is-visible");
}
// console.log("feedback submitted")
});
</script>
{{ else }}
<div id="feedback-widget" class="feedback-container pt-4">
<div id="feedback-init" class="d-flex justify-content-md-start justify-content-sm-center">
<span class="fs-5 fw-bold me-2 align-self-center">{{ i18n "feedback_helpful" | default "Was this page helpful?" }}</span>
<div class="d-flex">
<button id="posBtn" class="feedback-btn btn btn-primary btn-sm me-2" type="submit">
<span class="fs-6">
<i class="material-icons me-1 align-middle">thumb_up</i>
{{ i18n "feedback_yes" | default "Yes" }}
</span>
</button>
<button id="negBtn" class="feedback-btn btn btn-primary btn-sm me-2" type="submit">
<span class="fs-6">
<i class="material-icons me-1 align-middle">thumb_down</i>
{{ i18n "feedback_no" | default "No" }}
</span>
</button>
</div>
</div>
<div id="feedback-end" class="d-flex justify-content-md-start justify-content-sm-center fs-4 fw-bold me-2">
</div>
<div id="feedback-form-pos" data-type="positive" class="feedback-form justify-content-md-start justify-content-sm-center">
<p class="fw-bold fs-5">{{ .Site.Params.feedback.positiveFormTitle | default "What did you like?" }}</p>
{{ range $index, $value := .Site.Params.feedback.positiveForm }}
{{ $rating := (index . 0) }}
{{ $description := (index . 1) }}
<div class="form-check pb-1">
<input class="form-check-input" type="radio" name="feedback" autocomplete="off" value="{{ $rating | lower }}" id="radio{{ $index }}Pos" required>
<label class="form-check-label" for="radio{{ $index }}Pos">
{{ $rating }}
{{ if $description }}
<p class="feedback-radio-desc fw-normal mb-0">{{ $description }}</p>
{{ end }}
</label>
</div>
<div id="radio{{ $index }}PosTextContainer" class="feedback-textarea-container"></div>
{{ end }}
</div>
<div id="feedback-form-neg" data-type="negative" class="feedback-form justify-content-sm-center">
<p class="fw-bold fs-5">{{ .Site.Params.feedback.negativeFormTitle | default "What went wrong?" }}</p>
{{ range $index, $value := .Site.Params.feedback.negativeForm }}
{{ $rating := (index . 0) }}
{{ $description := (index . 1) }}
<div class="form-check pb-1">
<input class="form-check-input" type="radio" name="feedback" autocomplete="off" value="{{ $rating | lower }}" id="radio{{ $index }}Neg" required>
<label class="form-check-label" for="radio{{ $index }}Neg">
{{ $rating }}
{{ if $description }}
<p class="feedback-radio-desc fw-normal mb-0">{{ $description }}</p>
{{ end }}
</label>
</div>
<div id="radio{{ $index }}NegTextContainer" class="feedback-textarea-container"></div>
{{ end }}
</div>
<div id="feedback-submit-container">
<button id="feedback-submit-button" class="feedback-submit-btn btn btn-primary mt-3" role="button" type="submit" disabled>
<span class="fs-6">
{{ i18n "feedback_submit" | default "Submit" }}
</span>
</button>
</div>
</div>
<script>
// https://stackoverflow.com/a/29017547
const feedbackInit = document.getElementById("feedback-init");
const posBtn = document.getElementById("posBtn");
const negBtn = document.getElementById("negBtn");
const feedbackBtn = document.querySelectorAll('.feedback-btn');
const feedbackFormPos = document.getElementById("feedback-form-pos");
const feedbackFormNeg = document.getElementById("feedback-form-neg");
const feedbackSubmitBtn = document.getElementById("feedback-submit-button");
const feedbackSubmitContainer = document.getElementById("feedback-submit-container");
// Show feedback form
feedbackBtn.forEach(btn => {
btn.addEventListener('click', event => {
const btnID = btn.id
feedbackInit.style.opacity = '0'
feedbackInit.addEventListener('transitionend', function () {
feedbackInit.remove();
if (btnID == 'posBtn') {
feedbackFormPos.classList.add("is-visible");
feedbackFormNeg.remove();
feedbackSubmitContainer.classList.add("is-visible");
} else if (btnID == 'negBtn') {
feedbackFormNeg.classList.add("is-visible");
feedbackFormPos.remove();
feedbackSubmitContainer.classList.add("is-visible");
}
}
);
})
});
// Add text area box to the selected feedback radio
const Radios = document.querySelectorAll('input[name="feedback"]');
const textareas = document.querySelectorAll('.feedback-textarea-container');
Radios.forEach(radio => {
radio.addEventListener('change', function(event) {
const radioID = event.target.id;
const addOn = document.getElementById(radioID+"TextContainer");
// First, remove 'activeBox' class and <textarea> from all textarea containers
for (const textarea of textareas) {
while (textarea.firstChild) {
textarea.removeChild(textarea.firstChild);
}
}
addOn.innerHTML +='<textarea id="textarea" cols="55" maxlength="500" rows="3" placeholder="(Optional) Try to be as specific and detailed as possible!" type="text" class="feedback-textarea p-2 mb-2"></textarea>';
feedbackSubmitBtn.removeAttribute("disabled");
// console.log(radioID);
});
});
// Submit feedback to Google or Plausible analytics
feedbackSubmitBtn.addEventListener('click', event => {
const form = document.querySelector('.feedback-form');
const formType = form.getAttribute("data-type");
const result = document.getElementById("feedback-end");
const rating = document.querySelector('input[name="feedback"]:checked').value;
const message = document.getElementById('textarea').value;
function success(e) {
form.remove();
feedbackSubmitContainer.remove();
result.innerHTML = '{{ .Site.Params.feedback.successMsg | default "Thank you for helping to improve our documentation!" }}';
result.classList.add("is-visible");
}
try {
if (formType == "positive") {
{{ if .Site.Config.Services.GoogleAnalytics.ID -}}
{{ if not .Site.Params.feedback.eventDest | or (in .Site.Params.feedback.eventDest "google") -}}
gtag('event', '{{ replaceRE `( {1,})` "_" (.Site.Params.feedback.positiveEventName | default "Positive Feedback" | lower) }}',
{
'rating': rating,
'message': message,
'event_callback': success
}
),
{{ end -}}
{{ end -}}
{{ if .Site.Params.plausible.dataDomain -}}
{{ if not .Site.Params.feedback.eventDest | or (in .Site.Params.feedback.eventDest "plausible") -}}
plausible('{{ .Site.Params.feedback.positiveEventName | default "Positive Feedback" }}',
{
callback: success,
props:
{
rating: rating,
message: message
}
}
)
{{ end -}}
{{ end -}}
} else if (formType == "negative") {
{{ if .Site.Config.Services.GoogleAnalytics.ID -}}
{{ if not .Site.Params.feedback.eventDest | or (in .Site.Params.feedback.eventDest "google") -}}
gtag('event', '{{ replaceRE `( {1,})` "_" (.Site.Params.feedback.negativeEventName | default "Positive Feedback" | lower) }}',
{
'rating': rating,
'message': message,
'event_callback': success
}
),
{{ end -}}
{{ end -}}
{{ if .Site.Params.plausible.dataDomain -}}
{{ if not .Site.Params.feedback.eventDest | or (in .Site.Params.feedback.eventDest "plausible") -}}
plausible('{{ .Site.Params.feedback.negativeEventName | default "Negative Feedback" }}',
{
callback: success,
props:
{
rating: rating,
message: message
}
}
)
{{ end -}}
{{ end -}}
}
} catch (err) {
console.log(err);
form.remove();
feedbackSubmitContainer.remove();
result.innerHTML = '{{ .Site.Params.feedback.errorMsg | default "Sorry! There was an error while attempting to submit your feedback!" }}';
result.classList.add("is-visible");
}
// console.log("feedback submitted")
});
</script>
{{ end }}

View File

@@ -0,0 +1,215 @@
<script type="module">
var suggestions = document.getElementById('suggestions');
var search = document.getElementById('flexsearch');
const flexsearchContainer = document.getElementById('FlexSearchCollapse');
const hideFlexsearchBtn = document.getElementById('hideFlexsearch');
const configObject = { toggle: false }
const flexsearchContainerCollapse = new Collapse(flexsearchContainer, configObject) // initialized with no keyboard
if (search !== null) {
document.addEventListener('keydown', inputFocus);
flexsearchContainer.addEventListener('shown.bs.collapse', function () {
search.focus();
});
// hide search collapse containder by clicking outside (except top header)
var topHeader = document.getElementById("top-header");
document.addEventListener('click', function(elem) {
if (!flexsearchContainer.contains(elem.target) && !topHeader.contains(elem.target))
flexsearchContainerCollapse.hide();
});
}
hideFlexsearchBtn.addEventListener('click', () =>{
flexsearchContainerCollapse.hide()
})
function inputFocus(e) {
if (e.ctrlKey && e.key === '/') {
e.preventDefault();
flexsearchContainerCollapse.toggle();
}
if (e.key === 'Escape' ) {
search.blur();
// suggestions.classList.add('d-none');
flexsearchContainerCollapse.hide();
}
};
document.addEventListener('click', function(event) {
var isClickInsideElement = suggestions.contains(event.target);
if (!isClickInsideElement) {
suggestions.classList.add('d-none');
}
});
/*
Source:
- https://dev.to/shubhamprakash/trap-focus-using-javascript-6a3
*/
document.addEventListener('keydown',suggestionFocus);
function suggestionFocus(e) {
const suggestionsHidden = suggestions.classList.contains('d-none');
if (suggestionsHidden) return;
const focusableSuggestions= [...suggestions.querySelectorAll('a')];
if (focusableSuggestions.length === 0) return;
const index = focusableSuggestions.indexOf(document.activeElement);
if (e.key === "ArrowUp") {
e.preventDefault();
const nextIndex = index > 0 ? index - 1 : 0;
focusableSuggestions[nextIndex].focus();
}
else if (e.key === "ArrowDown") {
e.preventDefault();
const nextIndex= index + 1 < focusableSuggestions.length ? index + 1 : index;
focusableSuggestions[nextIndex].focus();
}
}
/*
Source:
- https://github.com/nextapps-de/flexsearch#index-documents-field-search
- https://raw.githack.com/nextapps-de/flexsearch/master/demo/autocomplete.html
*/
(function(){
var index = new FlexSearch.Document({
// charset: "latin:default",
tokenize: {{ .Site.Params.flexsearch.tokenize | default "forward" }},
minlength: {{ .Site.Params.flexsearch.minQueryChar | default 0}},
cache: {{ .Site.Params.flexsearch.cache | default 100 }},
optimize: {{ .Site.Params.flexsearch.optimize | default true }},
document: {
id: 'id',
store: [
"href", "title", "description"
],
index: ["title", "description", "content"]
}
});
// Not yet supported: https://github.com/nextapps-de/flexsearch#complex-documents
// var docs = [
// {{ range $index, $page := (where .Site.Pages "Section" "docs") -}}
// {
// id: {{ $index }},
// href: {{ .Permalink }},
// title: {{ .Title }},
// description: {{ .Params.description }},
// content: {{ .Content }}
// },
// {{ end -}}
// ];
// https://discourse.gohugo.io/t/range-length-or-last-element/3803/2
{{ $list := slice }}
{{- if and (isset .Site.Params.flexsearch "searchsectionsindex") (not (eq (len .Site.Params.flexsearch.searchSectionsIndex) 0)) }}
{{- if eq .Site.Params.flexsearch.searchSectionsIndex "ALL" }}
{{- $list = .Site.Pages }}
{{- else }}
{{- $list = (where .Site.Pages "Type" "in" .Site.Params.flexsearch.searchSectionsIndex) }}
{{- if (in .Site.Params.flexsearch.searchSectionsIndex "HomePage") }}
{{ $list = $list | append .Site.Home }}
{{- end }}
{{- end }}
{{- else }}
{{- $list = (where .Site.Pages "Section" ($.Scratch.Get "pathName")) }}
{{- end }}
{{ $len := (len $list) -}}
{{ range $index, $element := $list -}}
index.add(
{
id: {{ $index }},
href: "{{ .RelPermalink }}",
title: {{ .Title }},
{{ with .Description -}}
description: {{ . }},
{{ else -}}
description: {{ .Summary | htmlUnescape | plainify }},
{{ end -}}
content: {{ .Content | htmlUnescape | plainify }}
}
);
{{ end -}}
search.addEventListener('input', show_results, true);
function show_results(){
const maxResult = {{ .Site.Params.flexsearch.maxResult | default 5}};
const minlength = {{ .Site.Params.flexsearch.minQueryChar | default 0}};
var searchQuery = sanitizeHTML(this.value);
var results = index.search(searchQuery, {limit: maxResult, enrich: true});
// flatten results since index.search() returns results for each indexed field
const flatResults = new Map(); // keyed by href to dedupe results
for (const result of results.flatMap(r => r.result)) {
if (flatResults.has(result.doc.href)) continue;
flatResults.set(result.doc.href, result.doc);
}
suggestions.innerHTML = "";
suggestions.classList.remove('d-none');
// inform user of search query minimum character requirement
if (searchQuery.length < minlength) {
const minCharMessage = document.createElement('div')
minCharMessage.innerHTML = `Please type at least <strong>${minlength}</strong> characters`
minCharMessage.classList.add("suggestion__no-results");
suggestions.appendChild(minCharMessage);
return;
} else {
// inform user that no results were found
if (flatResults.size === 0 && searchQuery) {
const noResultsMessage = document.createElement('div')
noResultsMessage.innerHTML = {{ i18n "search_no_results" | default "No results for" }} + ` "<strong>${searchQuery}</strong>"`
noResultsMessage.classList.add("suggestion__no-results");
suggestions.appendChild(noResultsMessage);
return;
}
}
// construct a list of suggestions
for(const [href, doc] of flatResults) {
const entry = document.createElement('div');
suggestions.appendChild(entry);
const a = document.createElement('a');
a.href = href;
entry.appendChild(a);
const title = document.createElement('span');
title.textContent = doc.title;
title.classList.add("suggestion__title");
a.appendChild(title);
const description = document.createElement('span');
description.textContent = doc.description;
description.classList.add("suggestion__description");
a.appendChild(description);
suggestions.appendChild(entry);
if(suggestions.childElementCount == maxResult) break;
}
}
}());
</script>

View File

@@ -0,0 +1,57 @@
{{ $dayjs := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/dayjs.min.js") }}
{{ $relativeTime := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/relativeTime.min.js") }}
{{ $app := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/app.js") -}}
{{ $slice := slice $dayjs $relativeTime $app -}}
{{ if and (.Site.Params.docsearch.appID) (.Site.Params.docsearch.apiKey) -}}
{{ $docsearch := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/docsearch.min.js") }}
{{ $slice = $slice | append $docsearch -}}
{{ end }}
{{ if site.Params.docs.toc | default true }}
{{ if eq .Site.Params.docs.scrollSpy true -}}
{{ $simplescrollspy := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/simple-scrollspy.min.js") }}
{{ $slice = $slice | append $simplescrollspy -}}
{{ end -}}
{{ if eq .Site.Params.docs.scrollSpy true -}}
{{ $scrollspyScript := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/scrollspy-script.js") }}
{{ $scrollspyScript := $scrollspyScript | js.Build -}}
{{ $slice = $slice | append $scrollspyScript -}}
{{ end -}}
{{ end -}}
{{ if site.Params.docs.tocMobile | default true }}
{{ $tocmobilescrollspy := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/toc-mobile-scrollspy.js") }}
{{ $slice = $slice | append $tocmobilescrollspy -}}
{{ end -}}
{{ if eq .Site.Params.docs.prism true -}}
{{ $prism := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/prism.js") }}
{{- $opts := dict
"params" (dict "langPath" (urls.JoinPath .Site.BaseURL "docs/js/components/"))
-}}
{{ $prism := $prism | js.Build $opts -}}
{{ $slice = $slice | append $prism -}}
{{ end -}}
<!-- Bootstrap JS -->
{{ $js := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/bootstrap.js") }}
{{ $params := dict }}
{{ $sourceMap := cond hugo.IsProduction "" "inline" }}
{{ $opts := dict "sourceMap" $sourceMap "minify" hugo.IsProduction "target" "es2018" "params" $params }}
{{ $js = $js | js.Build $opts }}
{{ if hugo.IsProduction }}
{{ $js = $js | fingerprint "sha384" }}
{{ end }}
<script src="{{ $js.RelPermalink }}" {{ if hugo.IsProduction }}integrity="{{ $js.Data.Integrity }}"{{ end -}} defer></script>
{{ $js := $slice | resources.Concat (printf "/%s/%s" ($.Scratch.Get "pathName") "js/bundle.js") -}}
{{- if not hugo.IsServer }}
{{- $js := $js | minify | fingerprint "sha384" }}
<script type="text/javascript" src="{{ $js.Permalink }}" integrity="{{ $js.Data.Integrity }}" crossorigin="anonymous" defer></script>
{{- else }}
<script type="text/javascript" src="{{ $js.Permalink }}" defer></script>
{{- end }}

View File

@@ -0,0 +1,16 @@
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.getElementById("content"), {
// customised options
// • auto-render specific keys, e.g.:
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false},
{left: '\\(', right: '\\)', display: false},
{left: '\\[', right: '\\]', display: true}
],
// • rendering keys, e.g.:
throwOnError : false
});
});
</script>

View File

@@ -0,0 +1,47 @@
{{ $repoURL := slice .Site.Params.docs.repoURL }}
{{ $repoHostname := (urls.Parse (.Site.Params.docs.repoURL)).Hostname }}
{{ $filePath := replace .File.Path "\\" "/" }}
{{ $iconPath := "" }}
{{ if strings.Contains ($repoHostname | lower) "github" }}
{{ $repoURL = $repoURL | append "blob" (.Site.Params.docs.repoBranch | default "main") }}
{{ $iconPath = "images/social/github_icon.svg" }}
{{ else if strings.Contains ($repoHostname | lower) "gitlab" }}
{{ $repoURL = $repoURL | append "-/blob" (.Site.Params.docs.repoBranch | default "main") }}
{{ $iconPath = "images/social/gitlab_icon.svg" }}
{{ else if strings.Contains ($repoHostname | lower) "bitbucket" }}
{{ $repoURL = $repoURL | append "src" (.Site.Params.docs.repoBranch | default "master") }}
{{ $iconPath = "images/social/bitbucket_icon.svg" }}
{{ end }}
{{ $repoURL = $repoURL | append "content" .Site.LanguagePrefix $filePath }}
{{ $repoURL = delimit $repoURL "/" }}
{{ $editPageURL := replaceRE "(https?://)|(/)+" "$1$2" $repoURL }}
<div class="gitinfo d-flex flex-wrap justify-content-between align-items-center opacity-85 {{ if or .Site.Params.docs.lastMod .Site.Params.docs.editPage -}}pt-3{{ else }}visually-hidden{{ end }}">
{{ if .Site.Params.docs.editPage | default false -}}
<div id="edit-this-page" class="mt-1">
<a href="{{ $editPageURL }}" alt="{{ .Title }}" rel="noopener noreferrer" target="_blank">
<!-- <span class="material-icons size-20 align-text-bottom text-primary">edit</span> -->
<span class="me-1 align-text-bottom">
{{ with resources.Get $iconPath }}
{{ .Content | safeHTML }}
{{ end }}
</span>
Edit this page
<!-- <span class="material-icons size-20 align-text-bottom text-primary">open_in_new</span> -->
</a>
</div>
{{ end }}
{{ if .Site.Params.docs.lastMod | default false -}}
<div id="last-modified" class="mt-1">
<p class="mb-0 fw-semibold">Last updated <span
{{ if .Site.Params.docs.lastModRelative | default true -}}id="relativetime"{{ else }}{{ end }}
data-authdate="{{ dateFormat "2006-01-02T15:04:05Z0700" .GitInfo.AuthorDate }}"
{{ if .Site.Params.docs.lastModRelative | default true -}}title="{{ dateFormat "02 Jan 2006, 15:04 MST" .GitInfo.AuthorDate }}"{{ else }}{{ end }}>
{{ dateFormat "02 Jan 2006, 15:04 MST" .GitInfo.AuthorDate }}
</span>. <span class="material-icons size-20 align-text-bottom opacity-75">history</span>
</p>
</div>
{{ end }}
</div>

View File

@@ -0,0 +1,111 @@
<head>
<meta charset="utf-8" />
<title>
{{- $url := replace .Permalink ( printf "%s" .Site.BaseURL) "" }}
{{- if eq $url "/" }}
{{- .Site.Title }}
{{- else }}
{{- if .Params.heading }}
{{ .Params.heading }}
{{ else }}
{{- if eq .Title .Site.Title }}
{{- .Title }}
{{- else }}
{{- .Title }} | {{ .Site.Params.docs.Title | default (.Site.Title) }}
{{- end }}
{{- end }}
{{- end -}}
</title>
{{- if not hugo.IsProduction }}
<meta name="robots" content="noindex">
{{- end }}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{- with .Description | default ($.Param "description") }}
<meta name="description" content="{{ . }}">
{{- end }}
<meta name="keywords" content="Documentation, Hugo, Hugo Theme, Bootstrap" />
<meta name="author" content="Colin Wilson - Lotus Labs" />
<meta name="email" content="support@aigis.uk" />
<meta name="website" content="https://lotusdocs.dev" />
<meta name="Version" content="v0.1.0" />
<!-- favicon -->
{{ block "favicon" . }}{{ partialCached (printf "%s/%s" ($.Scratch.Get "pathName") "head/favicon.html") . }}{{ end }}
{{- partial (printf "%s/%s" ($.Scratch.Get "pathName") "head/opengraph") . }}
{{- partial (printf "%s/%s" ($.Scratch.Get "pathName") "head/twitter_cards") . }}
<!-- Atom feed autodiscovery -->
{{- with .Site.Title }}
<link rel="alternate" type="application/atom+xml" title="Atom feed for {{ . }}" href="/index.xml" />
{{- end }}
<!-- Dark Mode -->
{{ if eq .Site.Params.docs.darkMode true -}}
{{ $darkModeInit := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/darkmode-init.js") | js.Build | minify -}}
<script>{{ $darkModeInit.Content | safeJS }}</script>
{{ end -}}
<!-- FlexSearch -->
{{ if or (not (isset .Site.Params.flexsearch "enabled")) (eq .Site.Params.flexsearch.enabled true) -}}
{{ if and (.Site.Params.docsearch.appID) (.Site.Params.docsearch.apiKey) -}}
{{ else }}
{{ $flexSearch := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/flexsearch.bundle.js") }}
{{- if not hugo.IsServer }}
{{ $flexSearch := $flexSearch | minify | fingerprint "sha384" }}
<script type="text/javascript" src="{{ $flexSearch.Permalink }}" integrity="{{ $flexSearch.Data.Integrity }}" crossorigin="anonymous"></script>
{{ else }}
<script type="text/javascript" src="{{ $flexSearch.Permalink }}"></script>
{{ end }}
{{ end }}
{{ end }}
<!-- Google Fonts -->
{{- partialCached "google-fonts" . }}
<!-- Custom CSS -->
{{- $options := dict "enableSourceMap" true }}
{{- if hugo.IsProduction}}
{{- $options := dict "enableSourceMap" false "outputStyle" "compressed" }}
{{- end }}
{{- $style := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "scss/style.scss") }}
{{- $style = $style | resources.ExecuteAsTemplate (printf "/%s/%s" ($.Scratch.Get "pathName") "scss/style.scss") . | css.Sass $options }}
{{- if hugo.IsProduction }}
{{- $style = $style | minify | fingerprint "sha384" }}
{{- end -}}
<link rel="stylesheet" href="{{ $style.RelPermalink }}" {{ if hugo.IsProduction }}integrity="{{ $style.Data.Integrity }}"{{ end -}} crossorigin="anonymous">
<!-- Katex CSS -->
{{- if .Params.katex -}}
{{- $options := dict "enableSourceMap" true }}
{{- if hugo.IsProduction}}
{{- $options := dict "enableSourceMap" false "outputStyle" "compressed" }}
{{- end -}}
{{- $katexCSS := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "scss/katex.scss") }}
{{- $katexCSS = $katexCSS | resources.ExecuteAsTemplate (printf "/%s/%s" ($.Scratch.Get "pathName") "scss/katex.scss") . | css.Sass $options }}
{{- if hugo.IsProduction }}
{{- $katexCSS = $katexCSS | minify | fingerprint "sha384" }}
{{- end -}}
<link rel="stylesheet" href="{{ $katexCSS.RelPermalink }}" {{ if hugo.IsProduction }}integrity="{{ $katexCSS.Data.Integrity }}"{{ end -}} crossorigin="anonymous">
{{- end -}}
<!-- Katex JS -->
{{- if .Params.katex -}}
{{ $katex := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/katex.js") }}
{{ $katexAutoRender := resources.Get (printf "/%s/%s" ($.Scratch.Get "pathName") "js/auto-render.js") }}
{{ if hugo.IsProduction }}
{{ $katex = $katex | minify | fingerprint "sha384" }}
{{ $katexAutoRender = $katexAutoRender | minify | fingerprint "sha384" }}
{{- end -}}
<script src="{{ $katex.RelPermalink }}" {{ if hugo.IsProduction }}integrity="{{ $katex.Data.Integrity }}"{{ end -}} defer></script>
<script src="{{ $katexAutoRender.RelPermalink }}" {{ if hugo.IsProduction }}integrity="{{ $katexAutoRender.Data.Integrity }}"{{ end -}} defer></script>
{{ end -}}
<!-- Katex Config -->
{{ if .Params.katex }}
{{- partialCached (printf "%s/%s" ($.Scratch.Get "pathName") "footer/katex.html") . -}}
{{ end }}
<!-- Plausible Analytics Config -->
{{- if not hugo.IsServer }}
{{ if and (.Site.Params.plausible.scriptURL | default "https://plausible.io") (.Site.Params.plausible.dataDomain) -}}
{{- partialCached (printf "%s/%s" ($.Scratch.Get "pathName") "head/plausible") . }}
{{- end -}}
{{- end -}}
<!-- Google Analytics v4 Config -->
{{- if not hugo.IsServer }}
{{- if .Site.Config.Services.GoogleAnalytics.ID }}
{{- template "_internal/google_analytics.html" . -}}
{{- end -}}
{{- end -}}
</head>

View File

@@ -0,0 +1,18 @@
{{ if os.FileExists "static/favicon.ico" -}}
<link rel="icon" href="{{ "favicon.ico" | absURL }}" sizes="any">
{{ end -}}
{{ if os.FileExists "static/favicon.svg" -}}
<link rel="icon" type="image/svg+xml" href="{{ "favicon.svg" | absURL }}">
{{ end -}}
{{ if os.FileExists "static/apple-touch-icon.png" -}}
<link rel="apple-touch-icon" sizes="180x180" href="{{ "apple-touch-icon.png" | absURL }}">
{{ end -}}
{{ if os.FileExists "static/favicon-32x32.png" -}}
<link rel="icon" type="image/png" sizes="32x32" href="{{ "favicon-32x32.png" | absURL }}">
{{ end -}}
{{ if os.FileExists "static/favicon-16x16.png" -}}
<link rel="icon" type="image/png" sizes="16x16" href="{{ "favicon-16x16.png" | absURL }}">
{{ end -}}
{{ if os.FileExists "static/site.webmanifest" -}}
<link rel="manifest" crossorigin="use-credentials" href="{{ "site.webmanifest" | absURL }}">
{{ end -}}

View File

@@ -0,0 +1,73 @@
{{ $images := $.Resources.ByType "image" }}
{{ $featured := $images.GetMatch "*feature*" }}
{{ if not $featured }}{{ $featured = $images.GetMatch "{*cover*,*thumbnail*}" }}{{ end }}
{{ if not $featured }}
{{ $featured = resources.Get "/opengraph/card-base-2.png" }}
{{ $font := resources.Get "/opengraph/poppins-bold.ttf" }}
{{ $descPadding := 0 }}
{{ $title := $.LinkTitle }}
{{ $sizeTitle := 80 }}
{{ $sizeDesc := 50 }}
{{ if gt (len $title) 23 }}
{{ $sizeTitle = 60 }}
{{ end }}
{{ $textTitle := $title }}
{{ $textTitleOptions := dict
"color" "#2e2e2e"
"size" $sizeTitle
"lineSpacing" 10
"x" 65 "y" 180
"font" $font
}}
{{ $filters := slice (images.Text $textTitle $textTitleOptions) }}
{{ $logo := resources.Get "images/logos/logo.png" }}
{{ with $logo }}
{{ $logo = $logo.Resize "x60" }}
{{ $logoFilter := (images.Overlay $logo 65 110) }}
{{ $filters = $filters | append $logoFilter }}
{{ end }}
{{ if gt ($title | strings.RuneCount) 23 }}
{{ $descPadding = -30 }}
{{ if gt ($title | strings.RuneCount) 40 }}
{{ $descPadding = 40 }}
{{ end }}
{{ $sizeDesc = 45 }}
{{ end }}
{{ $description := $.Description }}
{{ with $description }}
{{ $textDesc := $description }}
{{ $textDescOptions := dict
"color" "#8e8e8e"
"size" $sizeDesc
"lineSpacing" 10
"x" 65 "y" (add 290 $descPadding)
"font" $font
}}
{{ $descFilter := (images.Text $textDesc $textDescOptions) }}
{{ $filters = $filters | append $descFilter }}
{{ end }}
{{ $textSiteTitle := $.Site.Title }}
{{ with $textSiteTitle }}
{{ $textSiteTitleOptions := dict
"color" "#5e5e5e"
"size" 35
"lineSpacing" 10
"x" 65 "y" 550
"font" $font
}}
{{ $siteTitleFilter := (images.Text $textSiteTitle $textSiteTitleOptions)}}
{{ $filters = $filters | append $siteTitleFilter }}
{{ end }}
{{ $featured = $featured | images.Filter $filters }}
{{ end }}
{{ return $featured }}

View File

@@ -0,0 +1,45 @@
<meta property="og:title" content="{{ .Title }}" />
<meta property="og:description" content="{{ with .Description }}{{ . }}{{ else }}{{if .IsPage}}{{ .Summary }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}{{ end }}" />
<meta property="og:type" content="{{ if .IsPage }}article{{ else }}website{{ end }}" />
<meta property="og:url" content="{{ .Permalink }}" />
{{- with $.Params.images -}}
{{- range first 6 . }}<meta property="og:image" content="{{ . | absURL }}" />{{ end -}}
{{- else -}}
{{- $images := $.Resources.ByType "image" -}}
{{- $featured := partial (printf "%s/%s" ($.Scratch.Get "pathName") "head/get-featured-image.html") . }}
{{- with $featured -}}
<meta property="og:image" content="{{ $featured.Permalink }}"/>
{{- else -}}
{{- with $.Site.Params.images }}<meta property="og:image" content="{{ index . 0 | absURL }}"/>{{ end -}}
{{- end -}}
{{- end -}}
{{- if .IsPage }}
{{- $iso8601 := "2006-01-02T15:04:05-07:00" -}}
<meta property="article:section" content="{{ .Section }}" />
{{ 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 }}
{{- end -}}
{{- with .Params.audio }}<meta property="og:audio" content="{{ . }}" />{{ end }}
{{- with .Params.locale }}<meta property="og:locale" content="{{ . }}" />{{ end }}
{{- with .Site.Params.title }}<meta property="og:site_name" content="{{ . }}" />{{ end }}
{{- with .Params.videos }}{{- range . }}
<meta property="og:video" content="{{ . | absURL }}" />
{{ end }}{{ end }}
{{- /* If it is part of a series, link to related articles */}}
{{- $permalink := .Permalink }}
{{- $siteSeries := .Site.Taxonomies.series }}
{{- if $siteSeries }}
{{ with .Params.series }}{{- range $name := . }}
{{- $series := index $siteSeries ($name | urlize) }}
{{- range $page := first 6 $series.Pages }}
{{- if ne $page.Permalink $permalink }}<meta property="og:see_also" content="{{ $page.Permalink }}" />{{ end }}
{{- end }}
{{ end }}{{ end }}
{{- end }}
{{- /* Facebook Page Admin ID for Domain Insights */}}
{{- with .Site.Params.facebook_admin }}<meta property="fb:admins" content="{{ . }}" />{{ end }}

View File

@@ -0,0 +1,2 @@
<script defer data-domain="{{ .Site.Params.plausible.dataDomain }}" {{ if .Site.Params.plausible.eventAPI }}data-api='{{ .Site.Params.plausible.eventAPI }}'{{ end }} src='{{ .Site.Params.plausible.scriptURL | default "https://plausible.io/js/script.js" }}'></script>
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>

View File

@@ -0,0 +1,23 @@
{{- with $.Params.images -}}
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="{{ index . 0 | absURL }}"/>
{{ else -}}
{{- $images := $.Resources.ByType "image" -}}
{{- $featured := partial (printf "%s/%s" ($.Scratch.Get "pathName") "head/get-featured-image.html") . }}
{{- with $featured -}}
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="{{ $featured.Permalink }}"/>
{{- else -}}
{{- with $.Site.Params.images -}}
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="{{ index . 0 | absURL }}"/>
{{ else -}}
<meta name="twitter:card" content="summary"/>
{{- end -}}
{{- 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 -}}"/>
{{ with .Site.Params.twitter -}}
<meta name="twitter:site" content="@{{ . }}"/>
{{ end -}}

View File

@@ -0,0 +1,21 @@
{{ $pageLang := .Page.Lang }}
{{ $translations := slice }}
{{ $docspath := $.Scratch.Get "pathName" }}
<!-- List available translations (excluding current page)-->
{{ range .Translations }}
<!-- Create 'available translations' slice -->
{{ $translations = $translations | append .Lang }}
<li><a class="dropdown-item" href="{{ .RelPermalink }}" role="button" rel="alternate" hreflang="{{ .Lang }}" lang="{{ .Lang }}">{{ .Language.LanguageName }}</a></li>
{{ end }}
<!-- List of configured languages without a translation for the current page (link to doc root) -->
{{ range .Site.Languages }}
{{ if ne $pageLang .Lang }}
<!-- If .Lang is in the 'available translations' slice, ignore it -->
{{ if in $translations .Lang }}
{{ else }}
<li><a class="dropdown-item" href="{{ .Lang | relURL }}/{{ $docspath }}" role="button" rel="alternate" hreflang="{{ .Lang }}" lang="{{ .Lang }}">{{ .LanguageName }}</a></li>
{{ end }}
{{ end }}
{{ end }}

View File

@@ -0,0 +1,8 @@
<link rel="preload" as="font" href="{{ "/docs/fonts/nunito-v25-latin-300.woff2" | absURL }}" type="font/woff2" crossorigin>
<link rel="preload" as="font" href="{{ "/docs/fonts/nunito-v25-latin-regular.woff2" | absURL }}" type="font/woff2" crossorigin>
<link rel="preload" as="font" href="{{ "/docs/fonts/nunito-v25-latin-500.woff2" | absURL }}" type="font/woff2" crossorigin>
<link rel="preload" as="font" href="{{ "/docs/fonts/nunito-v25-latin-600.woff2" | absURL }}" type="font/woff2" crossorigin>
<link rel="preload" as="font" href="{{ "/docs/fonts/nunito-v25-latin-700.woff2" | absURL }}" type="font/woff2" crossorigin>
<link rel="preload" as="font" href="{{ "/docs/fonts/source-code-pro-v22-latin-500.woff2" | absURL }}" type="font/woff2" crossorigin>
<link rel="preload" as="font" href="{{ "/docs/fonts/source-code-pro-v22-latin-700.woff2" | absURL }}" type="font/woff2" crossorigin>
<!-- <link rel="preload" as="font" href="{{ "/docs/fonts/material-symbols-outlined.woff2" | absURL }}" type="font/woff2" crossorigin> -->

View File

@@ -0,0 +1,116 @@
<!-- sidebar-wrapper -->
<nav id="sidebar" class="sidebar-wrapper">
<div class="sidebar-brand">
<a href='{{ with .Site.Params.docs.logoLinkURL }}{{ . }}{{ else }}{{ relLangURL "" }}{{ end }}' aria-label="HomePage" alt="HomePage">
{{ with resources.Get "images/logos/logo.svg" }}
{{ .Content | safeHTML }}
{{ end }}
</a>
</div>
<div class="sidebar-content" style="height: calc(100% - 131px);">
<ul class="sidebar-menu">
{{ $currentPage := . -}}
{{ $section := $currentPage.Section -}}
{{ range (where .Site.Sections.ByWeight "Section" "in" $section) }}
{{ $child_pages := union .Sections .Pages }}
{{ range $child_pages.ByWeight }}
{{ if or (.Sections) (.Pages) }}
{{ $active := in $currentPage.RelPermalink .RelPermalink }}
<li class="sidebar-dropdown {{ if eq .Site.Params.docs.sidebarIcons true -}}{{ else }}no-icon{{ end }} {{ if $active }}current active{{ end }}">
<button class="btn">
{{ if eq .Site.Params.docs.sidebarIcons true -}}
<i class="material-icons me-2">{{- .Params.icon | default "notes" }}</i>
{{ end }}
{{- .Title }}
</button>
<div class="sidebar-submenu {{ if $active }}d-block{{ end }}">
<ul>
{{ range .Pages }}
{{ $active := in $currentPage.RelPermalink .RelPermalink }}
{{ if .IsSection }}
<li class="sidebar-dropdown nested {{ if eq .Site.Params.docs.sidebarIcons true -}}{{ else }}no-icon{{ end }} {{ if $active }}current active{{ end }}">
<button class="btn">
{{ if eq .Site.Params.docs.sidebarIcons true -}}
<!-- <span class="material-icons me-2">{{- .Params.icon }}</span> -->
{{ end }}
{{- .Title }}
</button>
<div class="sidebar-submenu {{ if $active }}d-block{{ end }}">
<ul>
{{ range .Pages }}
{{ $active := in $currentPage.RelPermalink .RelPermalink }}
{{ if .IsSection }}
<li class="sidebar-dropdown nested {{ if eq .Site.Params.docs.sidebarIcons true -}}{{ else }}no-icon{{ end }} {{ if $active }}current active{{ end }}">
<button class="btn">
{{ if eq .Site.Params.docs.sidebarIcons true -}}
<!-- <span class="material-icons me-2">{{- .Params.icon }}</span> -->
{{ end }}
{{- .Title }}
</button>
<div class="sidebar-submenu {{ if $active }}d-block{{ end }}">
<ul>
{{ range .Pages }}
{{ $active := in $currentPage.RelPermalink .RelPermalink }}
{{ if .IsSection }}
<li class="sidebar-dropdown nested {{ if eq .Site.Params.docs.sidebarIcons true -}}{{ else }}no-icon{{ end }} {{ if $active }}current active{{ end }}">
<button class="btn">
{{ if eq .Site.Params.docs.sidebarIcons true -}}
<!-- <span class="material-icons me-2">{{- .Params.icon }}</span> -->
{{ end }}
{{- .Title }}
</button>
<div class="sidebar-submenu {{ if $active }}d-block{{ end }}">
<ul>
{{ range .Pages }}
{{ $active := in $currentPage.RelPermalink .RelPermalink }}
<li class="{{ if $active }}current{{ end }} {{ if eq .Site.Params.docs.sidebarIcons true -}}{{ else }}no-icon{{ end }}"><a class="sidebar-nested-link" href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}
</ul>
</div>
</li>
{{ else }}
<li class="{{ if $active }}current{{ end }} {{ if eq .Site.Params.docs.sidebarIcons true -}}{{ else }}no-icon{{ end }}"><a class="sidebar-nested-link" href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}
{{ end }}
</ul>
</div>
</li>
{{ else }}
<li class="{{ if $active }}current{{ end }} {{ if eq .Site.Params.docs.sidebarIcons true -}}{{ else }}no-icon{{ end }}"><a class="sidebar-nested-link" href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}
{{ end }}
</ul>
</div>
</li>
{{ else }}
<li class="{{ if $active }}current{{ end }} {{ if eq .Site.Params.docs.sidebarIcons true -}}{{ else }}no-icon{{ end }}"><a class="sidebar-nested-link" href="{{ .Permalink }}">{{ .Title }}</a></li>
{{ end }}
{{ end }}
</ul>
</div>
</li>
{{ else }}
{{ $active := in $currentPage.RelPermalink .RelPermalink }}
<li class="{{ if $active }}current{{ end }}">
<a class="sidebar-root-link" href="{{ .Permalink }}">
{{ if eq .Site.Params.docs.sidebarIcons true -}}
<i class="material-icons me-2">{{ .Params.icon }}</i>
{{ end }}
{{ .Title }}
</a>
</li>
{{ end }}
{{ end }}
{{ end }}
</ul>
<!-- sidebar-menu -->
</div>
<!-- Sidebar Footer -->
<ul class="sidebar-footer list-unstyled mb-0">
<!-- <li class="list-inline-item mb-0">
<a href="javascript:void(0)" data-bs-toggle="modal" data-bs-target="#lang-selector-popup" class="btn btn-primary m-1">Language</a>
</li> -->
</ul>
<!-- Sidebar Footer -->
</nav>
<!-- sidebar-wrapper -->

View File

@@ -0,0 +1,2 @@
{{ $toc := .TableOfContents }}
{{ replaceRE "<ul>" "<ul class=\"dropdown-menu\">" (replaceRE "<nav id=\"TableOfContents\">" "<nav id=\"toc-mobile\">" $toc) 1 | safeHTML }}

View File

@@ -0,0 +1,8 @@
<toc>
<div class="fw-bold text-uppercase mb-2">On this page</div>
{{ if eq .Site.Params.docs.scrollSpy true -}}
{{ .TableOfContents | replaceRE "<nav id=\"TableOfContents\">" "<nav id=\"toc\">" | safeHTML }}
{{ else -}}
{{ .TableOfContents }}
{{ end -}}
</toc>

View File

@@ -0,0 +1,129 @@
<!-- Top Header -->
<div id="top-header" class="top-header d-print-none">
<div class="header-bar d-flex justify-content-between">
<div class="d-flex align-items-center">
<a href='{{ with .Site.Params.docs.logoLinkURL }}{{ . }}{{ else }}{{ relLangURL "" }}{{ end }}' class="logo-icon me-3" aria-label="HomePage" alt="HomePage">
<div class="small">
{{ with resources.Get "images/logos/mark.svg" }}
{{ .Content | safeHTML }}
{{ end }}
</div>
<div class="big">
{{ with resources.Get "images/logos/logo.svg" }}
{{ .Content | safeHTML }}
{{ end }}
</div>
</a>
<button id="close-sidebar" class="btn btn-icon btn-soft">
<span class="material-icons size-20 menu-icon align-middle">menu</span>
</button>
{{ if and (.Site.Params.docsearch.appID) (.Site.Params.docsearch.apiKey) -}}
<span><div id="docsearch"></div></span>
{{ end }}
{{ if or (not (isset .Site.Params.flexsearch "enabled")) (eq .Site.Params.flexsearch.enabled true) -}}
{{ if and (.Site.Params.docsearch.appID) (.Site.Params.docsearch.apiKey) -}}
{{ else }}
<!-- <form class="flexsearch position-relative flex-grow-1 ms-2 me-lg-2 d-none">
<input id="flexsearch" class="form-control is-search" type="search" placeholder="{{ i18n "search_title" }}" aria-label="{{ i18n "search_title" }}" autocomplete="off">
<div id="suggestions" class="shadow bg-white rounded d-none"></div>
</form> -->
<button id="flexsearch-button" class="ms-3 btn btn-soft" data-bs-toggle="collapse" data-bs-target="#FlexSearchCollapse" aria-expanded="false" aria-controls="FlexSearchCollapse">
<span class="material-icons size-20 menu-icon align-middle">search</span>
<span class="flexsearch-button-placeholder ms-1 me-2 d-none d-sm-block">{{ i18n "search_title" }}</span>
<div class="d-none d-sm-block">
<span class="flexsearch-button-keys">
<kbd class="flexsearch-button-cmd-key">
<svg width="44" height="15"><path d="M2.118,11.5A1.519,1.519,0,0,1,1,11.042,1.583,1.583,0,0,1,1,8.815a1.519,1.519,0,0,1,1.113-.458h.715V6.643H2.118A1.519,1.519,0,0,1,1,6.185,1.519,1.519,0,0,1,.547,5.071,1.519,1.519,0,0,1,1,3.958,1.519,1.519,0,0,1,2.118,3.5a1.519,1.519,0,0,1,1.114.458A1.519,1.519,0,0,1,3.69,5.071v.715H5.4V5.071A1.564,1.564,0,0,1,6.976,3.5,1.564,1.564,0,0,1,8.547,5.071,1.564,1.564,0,0,1,6.976,6.643H6.261V8.357h.715a1.575,1.575,0,0,1,1.113,2.685,1.583,1.583,0,0,1-2.227,0A1.519,1.519,0,0,1,5.4,9.929V9.214H3.69v.715a1.519,1.519,0,0,1-.458,1.113A1.519,1.519,0,0,1,2.118,11.5Zm0-.857a.714.714,0,0,0,.715-.714V9.214H2.118a.715.715,0,1,0,0,1.429Zm4.858,0a.715.715,0,1,0,0-1.429H6.261v.715a.714.714,0,0,0,.715.714ZM3.69,8.357H5.4V6.643H3.69ZM2.118,5.786h.715V5.071a.714.714,0,0,0-.715-.714.715.715,0,0,0-.5,1.22A.686.686,0,0,0,2.118,5.786Zm4.143,0h.715a.715.715,0,0,0,.5-1.22.715.715,0,0,0-1.22.5Z" fill="currentColor"></path><path d="M12.4,11.475H11.344l3.879-7.95h1.056Z" fill="currentColor"></path><path d="M25.073,5.384l-.864.576a2.121,2.121,0,0,0-1.786-.923,2.207,2.207,0,0,0-2.266,2.326,2.206,2.206,0,0,0,2.266,2.325,2.1,2.1,0,0,0,1.782-.918l.84.617a3.108,3.108,0,0,1-2.622,1.293,3.217,3.217,0,0,1-3.349-3.317,3.217,3.217,0,0,1,3.349-3.317A3.046,3.046,0,0,1,25.073,5.384Z" fill="currentColor"></path><path d="M30.993,5.142h-2.07v5.419H27.891V5.142h-2.07V4.164h5.172Z" fill="currentColor"></path><path d="M34.67,4.164c1.471,0,2.266.658,2.266,1.851,0,1.087-.832,1.809-2.134,1.855l2.107,2.691h-1.28L33.591,7.87H33.07v2.691H32.038v-6.4Zm-1.6.969v1.8h1.572c.832,0,1.22-.3,1.22-.918s-.411-.882-1.22-.882Z" fill="currentColor"></path><path d="M42.883,10.561H38.31v-6.4h1.033V9.583h3.54Z" fill="currentColor"></path></svg>
</kbd>
<kbd class="flexsearch-button-key">
<svg width="15" height="15"><path d="M5.926,12.279H4.41L9.073,2.721H10.59Z" fill="currentColor"/></svg>
</kbd>
</span>
</div>
</button>
{{ end }}
{{ end -}}
</div>
<div class="d-flex align-items-center">
<ul class="list-unstyled mb-0">
{{ with $.Scratch.Get "social_list" }}
{{ range . }}
{{ $path := printf "images/social/%s.%s" . "svg" }}
<li class="list-inline-item mb-0">
<a href="{{ if eq . `rss` }} {{ `index.xml` | absURL }} {{ else if eq . `bluesky` }} https://bsky.app/profile/{{ index site.Params.social . }} {{ else }} https://{{ . }}.com/{{ index site.Params.social . }} {{ end }}" alt="{{ . }}" rel="noopener noreferrer" target="_blank">
<div class="btn btn-icon btn-default border-0">
{{ with resources.Get $path }}
{{ .Content | safeHTML }}
{{ end }}
</div>
</a>
</li>
{{ end }}
{{ end }}
</ul>
{{ if eq .Site.Params.docs.darkMode true -}}
<button id="mode" class="btn btn-icon btn-default ms-2" type="button" aria-label="Toggle user interface mode">
<span class="toggle-dark">
<svg xmlns="http://www.w3.org/2000/svg" height="30" width="30" viewBox="0 0 48 48" fill="currentColor">
<title>{{ i18n "enable_dark_mode" | default "Enable dark mode" }}</title>
<path d="M24 42q-7.5 0-12.75-5.25T6 24q0-7.5 5.25-12.75T24 6q.4 0 .85.025.45.025 1.15.075-1.8 1.6-2.8 3.95-1 2.35-1 4.95 0 4.5 3.15 7.65Q28.5 25.8 33 25.8q2.6 0 4.95-.925T41.9 22.3q.05.6.075.975Q42 23.65 42 24q0 7.5-5.25 12.75T24 42Zm0-3q5.45 0 9.5-3.375t5.05-7.925q-1.25.55-2.675.825Q34.45 28.8 33 28.8q-5.75 0-9.775-4.025T19.2 15q0-1.2.25-2.575.25-1.375.9-3.125-4.9 1.35-8.125 5.475Q9 18.9 9 24q0 6.25 4.375 10.625T24 39Zm-.2-14.85Z"/>
</svg>
</span>
<span class="toggle-light">
<svg xmlns="http://www.w3.org/2000/svg" height="30" width="30" viewBox="0 0 48 48" fill="currentColor">
<title>{{ i18n "enable_light_mode" | default "Enable light mode" }}</title>
<path d="M24 31q2.9 0 4.95-2.05Q31 26.9 31 24q0-2.9-2.05-4.95Q26.9 17 24 17q-2.9 0-4.95 2.05Q17 21.1 17 24q0 2.9 2.05 4.95Q21.1 31 24 31Zm0 3q-4.15 0-7.075-2.925T14 24q0-4.15 2.925-7.075T24 14q4.15 0 7.075 2.925T34 24q0 4.15-2.925 7.075T24 34ZM3.5 25.5q-.65 0-1.075-.425Q2 24.65 2 24q0-.65.425-1.075Q2.85 22.5 3.5 22.5h5q.65 0 1.075.425Q10 23.35 10 24q0 .65-.425 1.075-.425.425-1.075.425Zm36 0q-.65 0-1.075-.425Q38 24.65 38 24q0-.65.425-1.075.425-.425 1.075-.425h5q.65 0 1.075.425Q46 23.35 46 24q0 .65-.425 1.075-.425.425-1.075.425ZM24 10q-.65 0-1.075-.425Q22.5 9.15 22.5 8.5v-5q0-.65.425-1.075Q23.35 2 24 2q.65 0 1.075.425.425.425.425 1.075v5q0 .65-.425 1.075Q24.65 10 24 10Zm0 36q-.65 0-1.075-.425-.425-.425-.425-1.075v-5q0-.65.425-1.075Q23.35 38 24 38q.65 0 1.075.425.425.425.425 1.075v5q0 .65-.425 1.075Q24.65 46 24 46ZM12 14.1l-2.85-2.8q-.45-.45-.425-1.075.025-.625.425-1.075.45-.45 1.075-.45t1.075.45L14.1 12q.4.45.4 1.05 0 .6-.4 1-.4.45-1.025.45-.625 0-1.075-.4Zm24.7 24.75L33.9 36q-.4-.45-.4-1.075t.45-1.025q.4-.45 1-.45t1.05.45l2.85 2.8q.45.45.425 1.075-.025.625-.425 1.075-.45.45-1.075.45t-1.075-.45ZM33.9 14.1q-.45-.45-.45-1.05 0-.6.45-1.05l2.8-2.85q.45-.45 1.075-.425.625.025 1.075.425.45.45.45 1.075t-.45 1.075L36 14.1q-.4.4-1.025.4-.625 0-1.075-.4ZM9.15 38.85q-.45-.45-.45-1.075t.45-1.075L12 33.9q.45-.45 1.05-.45.6 0 1.05.45.45.45.45 1.05 0 .6-.45 1.05l-2.8 2.85q-.45.45-1.075.425-.625-.025-1.075-.425ZM24 24Z"/>
</svg>
</span>
</button>
{{ end -}}
{{ if hugo.IsMultilingual }}
<div class="dropdown">
<button class="btn btn-link btn-default dropdown-toggle ps-2" type="button" data-bs-toggle="dropdown" aria-expanded="false">
{{ site.Language.Lang | upper }}
</button>
<ul class="dropdown-menu text-end">
{{ partial (printf "%s/%s" ($.Scratch.Get "pathName") "i18nlist") . }}
</ul>
</div>
{{ end }}
</div>
</div>
<!-- FlexSearch Input Start -->
{{ if or (not (isset .Site.Params.flexsearch "enabled")) (eq .Site.Params.flexsearch.enabled true) -}}
{{ if and (.Site.Params.docsearch.appID) (.Site.Params.docsearch.apiKey) -}}
{{ else }}
<div class="collapse" id="FlexSearchCollapse">
<div class="flexsearch-container">
<div class="flexsearch-keymap">
<li>
<kbd class="flexsearch-button-cmd-key"><svg width="15" height="15" aria-label="Arrow down" role="img"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"><path d="M7.5 3.5v8M10.5 8.5l-3 3-3-3"></path></g></svg></kbd>
<kbd class="flexsearch-button-cmd-key"><svg width="15" height="15" aria-label="Arrow up" role="img"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"><path d="M7.5 11.5v-8M10.5 6.5l-3-3-3 3"></path></g></svg></kbd>
<span class="flexsearch-key-label">{{ i18n "search_navigate" | default "to navigate" }}</span>
</li>
<li>
<kbd class="flexsearch-button-cmd-key"><svg width="15" height="15" aria-label="Enter key" role="img"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"><path d="M12 3.53088v3c0 1-1 2-2 2H4M7 11.53088l-3-3 3-3"></path></g></svg></kbd>
<span class="flexsearch-key-label">{{ i18n "search_select" | default "to select" }}</span>
</li>
<li>
<kbd class="flexsearch-button-cmd-key"><svg width="15" height="15" aria-label="Escape key" role="img"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.2"><path d="M13.6167 8.936c-.1065.3583-.6883.962-1.4875.962-.7993 0-1.653-.9165-1.653-2.1258v-.5678c0-1.2548.7896-2.1016 1.653-2.1016.8634 0 1.3601.4778 1.4875 1.0724M9 6c-.1352-.4735-.7506-.9219-1.46-.8972-.7092.0246-1.344.57-1.344 1.2166s.4198.8812 1.3445.9805C8.465 7.3992 8.968 7.9337 9 8.5c.032.5663-.454 1.398-1.4595 1.398C6.6593 9.898 6 9 5.963 8.4851m-1.4748.5368c-.2635.5941-.8099.876-1.5443.876s-1.7073-.6248-1.7073-2.204v-.4603c0-1.0416.721-2.131 1.7073-2.131.9864 0 1.6425 1.031 1.5443 2.2492h-2.956"></path></g></svg></kbd>
<span class="flexsearch-key-label">{{ i18n "search_close" | default "to close" }}</span>
</li>
</div>
<form class="flexsearch position-relative flex-grow-1 ms-2 me-2">
<div class="d-flex flex-row">
<input id="flexsearch" class="form-control" type="search" placeholder="{{ i18n "search_title" }}" aria-label="{{ i18n "search_title" }}" autocomplete="off">
<button id="hideFlexsearch" type="button" class="ms-2 btn btn-soft">
{{ i18n "search_cancel" | default "cancel" }}
</button>
</div>
<div id="suggestions" class="shadow rounded-1 d-none"></div>
</form>
</div>
</div>
{{ end }}
{{ end }}
<!-- FlexSearch Input End -->
</div>
<!-- Top Header -->

View File

@@ -0,0 +1,22 @@
<!-- Footer Start -->
<footer class="footer footer-light footer-bar">
<div class="footer-py-30">
<div class="container text-center">
<div class="row align-items-center">
<div class="col-sm-6">
<div class="text-sm-start">
<p class="mb-0">
{{ $yearToken := (cond (isset .Site.Params (lower "copyrightYearToken")) $.Site.Params.copyrightYearToken ":YEAR:") }}
{{ replace $.Site.Params.footer.copyright $yearToken (string (now.Format "2006")) | markdownify }}
</p>
</div>
</div>
<div class="col-sm-6 mt-4 mt-sm-0 pt-2 pt-sm-0">
<!-- <p>Privacy</p> -->
</div><!--end col-->
</div><!--end row-->
</div><!--end container-->
</div>
</footer><!--end footer-->
<!-- Footer End -->

View File

@@ -0,0 +1,14 @@
{{ if .Site.Params.google_fonts }}
{{ $fonts := slice }}
{{ range .Site.Params.google_fonts }}
{{ $family := replace (index (.) 0) " " "+" }}
{{ $weights := replace (index (.) 1) " " "" }}
{{ $string := print $family ":" $weights }}
{{ $fonts = $fonts | append $string }}
{{ end }}
{{ $url_part := (delimit $fonts "|") | safeHTMLAttr }}
<link rel="preconnect" href="https://fonts.gstatic.com/" />
<link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin />
<link {{ printf "href=\"https://fonts.googleapis.com/css?family=%s%s\"" $url_part "&display=block" | safeHTMLAttr }} rel="stylesheet">
{{ else}}
{{ end }}

View File

@@ -0,0 +1,62 @@
<head>
<meta charset="utf-8" />
<title>{{- .Site.Title }}</title>
{{- if not hugo.IsProduction }}
<meta name="robots" content="noindex">
{{- end }}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="A Lightweight, Modern Documentation Theme for Hugo" />
<meta name="keywords" content="Documentation, Hugo, Hugo Theme, Bootstrap" />
<meta name="author" content="Colin Wilson - Lotus Labs" />
<meta name="email" content="support@aigis.uk" />
<meta name="website" content="https://lotusdocs.dev" />
<meta name="Version" content="v0.1.0" />
<!-- favicon -->
{{ block "head/favicon" . }}{{ partialCached "head/favicon.html" . }}{{ end }}
<!-- Google Fonts -->
{{- partial "google-fonts" . }}
<!-- Custom CSS -->
{{- $options := dict "enableSourceMap" true }}
{{- if hugo.IsProduction}}
{{- $options := dict "enableSourceMap" false "outputStyle" "compressed" }}
{{- end }}
{{- $style := resources.Get "/scss/style.scss" }}
{{- $style = $style | resources.ExecuteAsTemplate "/scss/style.scss" . | css.Sass $options }}
{{- if hugo.IsProduction }}
{{- $style = $style | minify | fingerprint "sha384" }}
{{- end -}}
<link rel="stylesheet" href="{{ $style.RelPermalink }}" {{ if hugo.IsProduction }}integrity="{{ $style.Data.Integrity }}"{{ end -}}/>
<!-- Bootstrap JS -->
{{ $js := resources.Get "js/bootstrap.js" }}
{{ $params := dict }}
{{ $sourceMap := cond hugo.IsProduction "" "inline" }}
{{ $opts := dict "sourceMap" $sourceMap "minify" hugo.IsProduction "target" "es2018" "params" $params }}
{{ $js = $js | js.Build $opts }}
{{ if hugo.IsProduction }}
{{ $js = $js | fingerprint "sha384" }}
{{ end }}
<script src="{{ $js.RelPermalink }}" {{ if hugo.IsProduction }}integrity="{{ $js.Data.Integrity }}"{{ end -}} defer></script>
<!-- Image Compare Viewer -->
{{ if ($.Scratch.Get "image_compare_enabled") }}
{{ $imagecompare := resources.Get "js/image-compare-viewer.min.js" }}
{{- if not hugo.IsServer }}
{{- $js := (slice $imagecompare) | resources.Concat "/js/image-compare.js" | minify | fingerprint "sha384" }}
<script type="text/javascript" src="{{ $js.Permalink }}" integrity="{{ $js.Data.Integrity }}"></script>
{{- else }}
{{- $js := (slice $imagecompare) | resources.Concat "/js/image-compare.js" }}
<script type="text/javascript" src="{{ $js.Permalink }}" {{ if hugo.IsProduction }}integrity="{{ $js.Data.Integrity }}"{{ end }}></script>
{{- end }}
{{- end }}
<!-- Plausible Analytics Config -->
{{- if not hugo.IsServer }}
{{ if and (.Site.Params.plausible.scriptURL) (.Site.Params.plausible.dataDomain) -}}
{{- partialCached "head/plausible" . }}
{{- end -}}
{{- end -}}
<!-- Google Analytics v4 Config -->
{{- if not hugo.IsServer }}
{{- if .Site.Config.Services.GoogleAnalytics.ID }}
{{- template "_internal/google_analytics.html" . -}}
{{- end -}}
{{- end -}}
</head>

View File

@@ -0,0 +1,18 @@
{{ if os.FileExists "static/favicon.ico" -}}
<link rel="icon" href="{{ "favicon.ico" | absURL }}" sizes="any">
{{ end -}}
{{ if os.FileExists "static/favicon.svg" -}}
<link rel="icon" type="image/svg+xml" href="{{ "favicon.svg" | absURL }}">
{{ end -}}
{{ if os.FileExists "static/apple-touch-icon.png" -}}
<link rel="apple-touch-icon" sizes="180x180" href="{{ "apple-touch-icon.png" | absURL }}">
{{ end -}}
{{ if os.FileExists "static/favicon-32x32.png" -}}
<link rel="icon" type="image/png" sizes="32x32" href="{{ "favicon-32x32.png" | absURL }}">
{{ end -}}
{{ if os.FileExists "static/favicon-16x16.png" -}}
<link rel="icon" type="image/png" sizes="16x16" href="{{ "favicon-16x16.png" | absURL }}">
{{ end -}}
{{ if os.FileExists "static/site.webmanifest" -}}
<link rel="manifest" crossorigin="use-credentials" href="{{ "site.webmanifest" | absURL }}">
{{ end -}}

View File

@@ -0,0 +1 @@
<script defer data-domain="{{ .Site.Params.plausible.dataDomain }}" {{ if .Site.Params.plausible.eventAPI }}data-api="{{ .Site.Params.plausible.eventAPI | default }}"{{ end }} src='{{ .Site.Params.plausible.scriptURL | default "plausible.io" }}'></script>

View File

@@ -0,0 +1,59 @@
<!-- Navbar Start -->
<header id="topnav">
<div class="container d-flex justify-content-between align-items-center">
<!-- Logo container-->
<a class="logo" aria-label="Home" href='{{ relLangURL "" }}'>
{{ with resources.Get "images/logos/mark.svg" }}
{{ .Content | safeHTML }}
{{ end }}
</a>
<!-- End Logo container-->
<div class="d-flex align-items-center">
<div id="navigation">
<!-- Navigation Menu -->
<ul class="navigation-menu nav-right">
{{- range .Site.Menus.primary }}
<li><a href="{{ relLangURL .URL }}">{{ .Name }}</a></li>
{{ end }}
</ul><!--end navigation menu-->
</div><!--end navigation-->
<!-- Social Links Start -->
{{ with $.Scratch.Get "social_list" }}
<ul class="social-link d-flex list-inline mb-0">
{{ range . }}
{{ $path := printf "images/social/%s.%s" . "svg" }}
<li class="list-inline-item mb-0">
<a href="{{ if eq . `rss` }} {{ `index.xml` | absURL }} {{ else if eq . `bluesky` }} https://bsky.app/profile/{{ index site.Params.social . }} {{ else }} https://{{ . }}.com/{{ index site.Params.social . }} {{ end }}" alt="{{ . }}" rel="noopener noreferrer" target="_blank">
<div class="btn btn-icon btn-landing border-0">
{{ with resources.Get $path }}
{{ .Content | safeHTML }}
{{ end }}
</div>
</a>
</li>
{{ end }}
</ul>
{{ end }}
<!-- Social Links End -->
<div class="menu-extras ms-3 me-2">
<div class="menu-item">
<!-- Mobile menu toggle-->
<button class="navbar-toggle btn btn-icon btn-soft-light" id="isToggle" aria-label="toggleMenu" onclick="toggleMenu()">
<div class="lines">
<span></span>
<span></span>
<span></span>
</div>
</button>
<!-- End mobile menu toggle-->
</div>
</div>
</div>
</div><!--end container-->
</header><!--end header-->
<!-- Navbar End -->

View File

@@ -0,0 +1,53 @@
{{ $sectionTitle := .Scratch.Get "sectionTitle" }}
{{ with (index .Site.Data.landing $sectionTitle) }}
{{ if eq .enable true }}
<!-- Features Start -->
<section id="{{ $sectionTitle }}">
<div class="container mt-100 mt-60">
<div class="row justify-content-center">
<div class="col-12 text-center">
<div class="section-title">
{{ with .title }}
<h4 class="title fw-bold mb-4">{{ . }}</h4>
{{ end }}
{{ with .subtitle }}
<p class="text-muted para-desc mb-4 pb-2 mx-auto">{{ . | markdownify }}</p>
{{ end }}
</div>
</div><!--end col-->
</div><!--end row-->
<div class="row">
<div class="col-lg-12">
<div class="row">
{{ range .items }}
<div class="col-md-4 col-12">
<div class="d-flex features feature-primary p-3">
<div class="{{ if .icon }}icon{{ else }}no-icon{{ end }} text-center rounded-3 text-primary me-3">
<i class="material-icons align-middle h4 mb-0">{{ .icon }}</i>
</div>
<div class="flex-1">
<h4 class="title">{{ .title }}</h4>
<p class="text-muted para mb-0">{{ .description | markdownify }}</p>
{{ with .ctaLink }}
<div class="mt-2">
<a href="{{ .url }}" class="mt-3 h6 text-primary">{{ .text | markdownify }} <i class="material-icons align-top">chevron_right</i></a>
</div>
{{ end }}
</div>
</div>
</div>
<!--end col-->
{{ end }}
</div>
<!--end row-->
</div>
<!--end col-->
</div>
<!--end row-->
</div>
<!--end container-->
</section>
<!-- features End -->
{{ end }}
{{ end }}

View File

@@ -0,0 +1,123 @@
{{ $sectionTitle := .Scratch.Get "sectionTitle" }}
{{ with (index .Site.Data.landing $sectionTitle) }}
{{ if eq .enable true }}
<!-- Hero Start -->
{{ with .backgroundImage }}
{{ $path := .path | default "images" }}
{{ $filename := .filename }}
{{ $pathDesktop := printf "%s/%s" $path $filename.desktop }}
{{ $pathMobile := printf "%s/%s" $path $filename.mobile }}
<style>
.hero {
{{ with $filename.desktop }}
{{ with resources.Get $pathDesktop }}
@media (min-width: 768px) {
background-image: url("{{ .RelPermalink }}");
}
{{ end }}
{{ end }}
{{ with $filename.mobile }}
{{ with resources.Get $pathMobile }}
background-image: url("{{ .RelPermalink }}");
{{ end }}
{{ end }}
}
</style>
{{ end }}
<section id="{{ $sectionTitle }}" class="d-table w-100 overflow-hidden hero">
<div class="container">
<div class="row mt-5 align-items-center">
<div class="col-lg-6 col-md-6">
<div class="title-heading">
{{ with .badge }}
<span class="badge {{ if eq .pill true }}rounded-pill{{ end }} bg-{{ if eq .soft true }}soft-{{ else }}hard-{{ end }}{{ .color }} mb-1">{{ .text }}</span>
{{ end }}
<h4 class="heading mt-0 mb-3">
{{ with .titleLogo }}
{{ $path := .path | default "images" }}
{{ $filename := .filename }}
{{ $height := .height | default "70px" }}
{{ $alt := .alt | default "logo image" }}
{{ $path := printf "%s/%s" $path $filename }}
{{ with $filename }}
<span>
{{ with $image := resources.Get $path }}
{{ if eq .MediaType.SubType "svg" }}
{{ .Content | safeHTML }}
{{ else }}
{{ with .Resize (printf "%dx%d webp q85 drawing Lanczos" .Width .Height) }}
<img src="{{ .RelPermalink }}" alt="{{ $alt }}" height="{{ $height }}">
{{ end }}
{{ end }}
{{ end }}
</span>
{{ end }}
{{ end }}
{{ with .title }}{{ . }}{{ end }}
</h4>
{{ with .subtitle }}
<p class="para-desc text-muted mb-0">{{ . | markdownify }}</p>
{{ end }}
<div class="mt-3">
{{ with .ctaButton }}
<a href="{{ relLangURL .url }}" class="btn btn-lg btn-primary me-2 mt-2">
{{ with .icon }}
<span class="material-icons align-middle">{{ . }}</span>
{{ end }}
{{ with .btnText }}
{{ . }}
{{ end }}
</a>
{{ end }}
{{ with .cta2Button }}
<a href="{{ relLangURL .url }}" class="btn btn-lg btn-outline-primary mt-2">
{{ with .icon }}
<span class="material-icons align-middle">{{ . }}</span>
{{ end }}
{{ with .btnText }}
{{ . }}
{{ end }}
</a>
{{ end }}
</div>
{{ with .info }}
<p class="text-muted mb-0 mt-3">{{ . | markdownify }}</p>
{{ end }}
</div>
</div>
<div class="col-lg-6 col-md-6 mt-4 pt-4 mt-sm-0 pt-sm-0">
{{ with .image }}
{{ $path := .path | default "images" }}
{{ $filename := .filename }}
{{ $alt := .alt | default "hero image" }}
{{ $boxShadow := .boxShadow | default false }}
{{ $rounded := .rounded | default false }}
{{ $path := printf "%s/%s" $path $filename }}
{{ with $filename }}
<div class="ms-lg-4">
<div class="classic-hero-image">
{{ with $image := resources.Get $path }}
{{ if eq .MediaType.SubType "svg" }}
{{ .Content | safeHTML }}
{{ else }}
{{ with .Resize (printf "%dx%d webp q85 drawing Lanczos" .Width .Height) }}
<img src="{{ .RelPermalink }}" class="{{ if $boxShadow }}shadow-lg{{ else }}{{ end }} mx-auto d-block {{ if $rounded }}rounded-top-4{{ else }}{{ end }}" width="{{ .Width }}" height="{{ .Height }}" alt="{{ $alt }}">
{{ end }}
{{ end }}
{{ end }}
</div>
</div>
{{ end }}
{{ end }}
</div><!--end col-->
</div><!--end row-->
</div> <!--end container-->
</section><!--end section-->
<!-- Hero End -->
{{ end }}
{{ end }}

View File

@@ -0,0 +1,68 @@
{{ $sectionTitle := .Scratch.Get "sectionTitle" }}
{{ with (index .Site.Data.landing $sectionTitle) }}
{{ if eq .enable true }}
<section id="{{ $sectionTitle }}">
<div class="container mt-100 mt-60">
<div class="row justify-content-center">
<div class="col-12 text-center">
<div class="section-title mb-4 pb-2">
{{ with .title }}
<h4 class="title fw-bold mb-4">{{ . }}</h4>
{{ end }}
{{ with .subtitle }}
<p class="text-muted para-desc mb-0 mx-auto">{{ . | markdownify }}</p>
{{ end }}
</div>
</div><!--end col-->
</div><!--end row-->
<div class="row justify-content-center">
<div class="col-lg-8 col-md-12 mt-3 pt-2 text-center">
<ul class="nav nav-pills nav-justified flex-column flex-sm-row rounded bg-primary" id="pills-tab-{{ $sectionTitle }}" role="tablist">
{{ range $index, $value := .items }}
<li class="nav-item">
<a class="nav-link rounded{{ if (eq $index 0) }} active{{ end }}" id="{{ anchorize .title }}-tab" data-bs-toggle="pill" href="#pills-{{ $sectionTitle }}-{{ anchorize .title }}" role="tab" aria-controls="pills-{{ anchorize .title }}" aria-selected="false">
<div class="text-center py-2">
<p class="mb-0 fs-6 fw-semibold">{{ .title }}</p>
</div>
</a><!--end nav link-->
</li><!--end nav item-->
{{ end }}
</ul><!--end nav pills-->
</div>
</div>
<div class="row">
<div class="col-12 mt-4 pt-2">
<div class="tab-content" id="pills-tab-{{ $sectionTitle }}Content">
{{ range $index, $value := .items }}
<div class="tab-pane fade show{{ if (eq $index 0) }} active{{ end }}" id="pills-{{ $sectionTitle }}-{{ anchorize .title }}" role="tabpanel" aria-labelledby="{{ anchorize .title }}-tab">
<div class="row align-items-center">
<div class="col-md-12">
{{ $title := .title }}
{{ $path := .imagePath | default "images" }}
{{ $imageBefore := .imageBefore }}
{{ $imageAfter := .imageAfter }}
{{ $pathBefore := printf "%s/%s" $path $imageBefore }}
{{ $pathAfter := printf "%s/%s" $path $imageAfter }}
{{ with and $imageBefore $imageAfter }}
<div id="{{ anchorize $title }}-compare" class="image-compare rounded-md border">
{{ with $imageBefore := resources.Get $pathBefore }}
<img src="{{ .RelPermalink }}" alt="{{ $imageBefore }}" />
{{ end }}
{{ with $imageAfter := resources.Get $pathAfter }}
<img src="{{ .RelPermalink }}" alt="{{ $imageAfter }}" />
{{ end }}
</div>
{{ end }}
</div><!--end col-->
</div><!--end row-->
</div><!--end teb pane-->
{{ end }}
</div><!--end tab content-->
</div><!--end col-->
</div><!--end row-->
</div><!--end container-->
</section>
{{ end }}
{{ end }}

View File

@@ -0,0 +1,61 @@
{{ $sectionTitle := .Scratch.Get "sectionTitle" }}
{{ with (index .Site.Data.landing $sectionTitle) }}
{{ if eq .enable true }}
<!-- Single-Right Start -->
<section id="{{ $sectionTitle }}">
<div class="container mt-100 mt-60">
<div class="row align-items-center">
<div class="col-lg-6 col-md-5 {{ if eq .imgOrder.desktop 1 }}order-md-first{{ else }}order-md-last{{ end }} {{ if eq .imgOrder.mobile 1 }}order-first{{ else }}order-last{{ end }}">
<div class="position-relative">
{{ with .image }}
{{ $path := .path | default "images" }}
{{ $filename := .filename }}
{{ $alt := .alt | default "feature image (right)" }}
{{ $path := printf "%s/%s" $path $filename }}
{{ with $filename }}
<div class="text-center text-md-start">
{{ with $image := resources.Get $path }}
{{ if eq .MediaType.SubType "svg" }}
{{ .Content | safeHTML }}
{{ else }}
{{ with .Resize (printf "%dx%d webp q85 drawing Lanczos" .Width .Height) }}
<img src="{{ .RelPermalink }}" class="img-fluid" width="{{ .Width }}" height="{{ .Height }}" alt="{{ $alt }}">
{{ end }}
{{ end }}
{{ end }}
</div>
{{ end }}
{{ end }}
</div>
</div><!--end col-->
<div class="col-lg-6 col-md-7 mt-5 mt-sm-0 {{ if eq .imgOrder.desktop 1 }}order-md-last{{ else }}order-md-first{{ end }} {{ if eq .imgOrder.mobile 1 }}order-last{{ else }}order-first{{ end }}">
<div class="section-title">
{{ with .title }}
<h1 class="title mb-3">{{ . }}</h1>
{{ end }}
{{ with .subtitle }}
<p class="para-desc text-muted">{{ . | markdownify }}</p>
{{ end }}
{{ if .list }}
<ul class="list-unstyled text-muted">
{{ range .list }}
<li class="mb-1"><span class="text-primary h5 me-2"><i class="material-icons align-middle size-20">{{ .icon }}</i></span>{{ .text | markdownify }}</li>
{{ end }}
</ul>
{{ end }}
{{ with .ctaButton }}
<div class="mt-4">
<a href="{{ .url }}" class="mt-3 h6 text-primary">{{ .text | markdownify }} <i class="material-icons align-middle mb-1">chevron_right</i></a>
</div>
{{ end }}
</div>
</div>
</div>
</div>
</section>
<!-- Single-Right End -->
{{ end }}
{{ end }}