This commit is contained in:
@@ -76,14 +76,19 @@ body {
|
||||
* UNIVERSAL HOVER ANIMATION (Fill-up Effect)
|
||||
* Target: Nav spans, main links (except entries), social links, and share icons.
|
||||
* */
|
||||
|
||||
|
||||
nav #menu a span {
|
||||
position: relative;
|
||||
text-decoration: none !important;
|
||||
color: inherit;
|
||||
transition: color 0.3s ease;
|
||||
z-index: 1;
|
||||
display: inline-block;
|
||||
padding: 0 8px; /* Reduced vertical padding */
|
||||
padding: 8px; /* Reduced vertical padding */
|
||||
}
|
||||
|
||||
.entry-content {
|
||||
color: var(--primary)
|
||||
}
|
||||
|
||||
main a:not(.entry-link, .anchor),
|
||||
@@ -143,6 +148,7 @@ nav #menu a:hover span,
|
||||
main a:hover:not(.entry-link, .anchor),
|
||||
.social-icons a:hover,
|
||||
.share-buttons a:hover,
|
||||
#searchResults a:hover,
|
||||
.note-item a:hover .note-title,
|
||||
.note-item a:hover .note-date {
|
||||
color: var(--theme) !important;
|
||||
@@ -175,11 +181,12 @@ main h1 {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
||||
.post-tags a {
|
||||
background: var(--tertiary);
|
||||
color: var(--primary);
|
||||
padding: 4px 12px;
|
||||
border-radius: var(--radius);
|
||||
padding: 0px 8px;
|
||||
border-radius: 0px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
@@ -207,6 +214,28 @@ main h1 {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.breadcrumbs {
|
||||
margin-bottom: 2rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
.post-header .post-title {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--green);
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.post-description {
|
||||
font-style: italic;
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--secondary);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* main h1::before { */
|
||||
/* content: "#"; */
|
||||
/* color: var(--red); */
|
||||
@@ -271,6 +300,12 @@ main .post-entry:hover {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.delimiter {
|
||||
margin: 0 10px;
|
||||
font-weight: 800;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* *
|
||||
* POSTS SECTION - Same compact style as notes but with description
|
||||
* */
|
||||
@@ -301,6 +336,7 @@ main .post-entry:hover {
|
||||
color: inherit;
|
||||
transition: color 0.3s ease;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.post-item a::before {
|
||||
@@ -343,6 +379,14 @@ main .post-entry:hover {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Common list styles */
|
||||
.note-item a,
|
||||
.post-item a {
|
||||
display: flex !important;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* *
|
||||
* POST CONTENT SPACINGS
|
||||
* */
|
||||
@@ -378,11 +422,73 @@ main .post-entry:hover {
|
||||
}
|
||||
|
||||
.post-content code {
|
||||
font-size: 16px;
|
||||
background-color: var(--tertiary);
|
||||
color: var(--primary);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
padding: 0.6em;
|
||||
}
|
||||
|
||||
.post-content pre code {
|
||||
background-color: var(--entry) !important;
|
||||
}
|
||||
|
||||
.post-content blockquote p {
|
||||
margin: 0;
|
||||
padding: 0.5em 0em;
|
||||
}
|
||||
|
||||
/* *
|
||||
* SEARCH PAGE FIXES
|
||||
* */
|
||||
#searchResults .post-entry {
|
||||
border-radius: 0; /* Square borders like notes */
|
||||
padding: 0;
|
||||
border: 1px solid var(--tertiary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
#searchResults a {
|
||||
position: relative;
|
||||
display: flex !important;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 12px 15px;
|
||||
text-decoration: none !important;
|
||||
color: var(--primary);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#searchResults a .search-meta {
|
||||
margin-left: auto; /* Push date to the right */
|
||||
font-size: 0.85rem;
|
||||
color: var(--secondary);
|
||||
}
|
||||
|
||||
#searchResults a:hover .search-title,
|
||||
#searchResults a:hover .search-meta {
|
||||
color: var(--theme) !important;
|
||||
}
|
||||
|
||||
#searchResults a::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 0;
|
||||
background-color: var(--green);
|
||||
z-index: -1;
|
||||
transition: height 0.3s cubic-bezier(0.19, 1, 0.22, 1);
|
||||
}
|
||||
|
||||
#searchResults a:hover::before {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#searchResults a:hover {
|
||||
color: var(--theme) !important;
|
||||
}
|
||||
|
||||
153
assets/js/fastsearch.js
Normal file
153
assets/js/fastsearch.js
Normal file
@@ -0,0 +1,153 @@
|
||||
import * as params from '@params';
|
||||
|
||||
let fuse; // holds our search engine
|
||||
let resList = document.getElementById('searchResults');
|
||||
let sInput = document.getElementById('searchInput');
|
||||
let first, last, current_elem = null
|
||||
let resultsAvailable = false;
|
||||
|
||||
// load our search index
|
||||
window.onload = function () {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status === 200) {
|
||||
let data = JSON.parse(xhr.responseText);
|
||||
if (data) {
|
||||
// fuse.js options; check fuse.js website for details
|
||||
let options = {
|
||||
distance: 100,
|
||||
threshold: 0.4,
|
||||
ignoreLocation: true,
|
||||
keys: [
|
||||
'title',
|
||||
'permalink',
|
||||
'summary',
|
||||
'content'
|
||||
]
|
||||
};
|
||||
if (params.fuseOpts) {
|
||||
options = {
|
||||
isCaseSensitive: params.fuseOpts.iscasesensitive ?? false,
|
||||
includeScore: params.fuseOpts.includescore ?? false,
|
||||
includeMatches: params.fuseOpts.includematches ?? false,
|
||||
minMatchCharLength: params.fuseOpts.minmatchcharlength ?? 1,
|
||||
shouldSort: params.fuseOpts.shouldsort ?? true,
|
||||
findAllMatches: params.fuseOpts.findallmatches ?? false,
|
||||
keys: params.fuseOpts.keys ?? ['title', 'permalink', 'summary', 'content'],
|
||||
location: params.fuseOpts.location ?? 0,
|
||||
threshold: params.fuseOpts.threshold ?? 0.4,
|
||||
distance: params.fuseOpts.distance ?? 100,
|
||||
ignoreLocation: params.fuseOpts.ignorelocation ?? true
|
||||
}
|
||||
}
|
||||
fuse = new Fuse(data, options); // build the index from the json file
|
||||
}
|
||||
} else {
|
||||
console.log(xhr.responseText);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.open('GET', "../index.json");
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
function activeToggle(ae) {
|
||||
document.querySelectorAll('.focus').forEach(function (element) {
|
||||
// rm focus class
|
||||
element.classList.remove("focus")
|
||||
});
|
||||
if (ae) {
|
||||
ae.focus()
|
||||
document.activeElement = current_elem = ae;
|
||||
ae.parentElement.classList.add("focus")
|
||||
} else {
|
||||
document.activeElement.parentElement.classList.add("focus")
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
resultsAvailable = false;
|
||||
resList.innerHTML = sInput.value = ''; // clear inputbox and searchResults
|
||||
sInput.focus(); // shift focus to input box
|
||||
}
|
||||
|
||||
// execute search as each character is typed
|
||||
sInput.onkeyup = function (e) {
|
||||
// run a search query (for "term") every time a letter is typed
|
||||
// in the search box
|
||||
if (fuse) {
|
||||
let results;
|
||||
if (params.fuseOpts) {
|
||||
results = fuse.search(this.value.trim(), {limit: params.fuseOpts.limit}); // the actual query being run using fuse.js along with options
|
||||
} else {
|
||||
results = fuse.search(this.value.trim()); // the actual query being run using fuse.js
|
||||
}
|
||||
if (results.length !== 0) {
|
||||
// build our html if result exists
|
||||
let resultSet = ''; // our results bucket
|
||||
|
||||
for (let item in results) {
|
||||
resultSet += `<li class="post-entry"><a href="${results[item].item.permalink}" aria-label="${results[item].item.title}">` +
|
||||
`<div class="search-title"># ${results[item].item.title}</div>` +
|
||||
`<div class="search-meta"><span class="delimiter">•</span> ${results[item].item.date}</div></a></li>`
|
||||
}
|
||||
|
||||
resList.innerHTML = resultSet;
|
||||
resultsAvailable = true;
|
||||
first = resList.firstChild;
|
||||
last = resList.lastChild;
|
||||
} else {
|
||||
resultsAvailable = false;
|
||||
resList.innerHTML = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sInput.addEventListener('search', function (e) {
|
||||
// clicked on x
|
||||
if (!this.value) reset()
|
||||
})
|
||||
|
||||
// kb bindings
|
||||
document.onkeydown = function (e) {
|
||||
let key = e.key;
|
||||
let ae = document.activeElement;
|
||||
|
||||
let inbox = document.getElementById("searchbox").contains(ae)
|
||||
|
||||
if (ae === sInput) {
|
||||
let elements = document.getElementsByClassName('focus');
|
||||
while (elements.length > 0) {
|
||||
elements[0].classList.remove('focus');
|
||||
}
|
||||
} else if (current_elem) ae = current_elem;
|
||||
|
||||
if (key === "Escape") {
|
||||
reset()
|
||||
} else if (!resultsAvailable || !inbox) {
|
||||
return
|
||||
} else if (key === "ArrowDown") {
|
||||
e.preventDefault();
|
||||
if (ae == sInput) {
|
||||
// if the currently focused element is the search input, focus the <a> of first <li>
|
||||
activeToggle(resList.firstChild.lastChild);
|
||||
} else if (ae.parentElement != last) {
|
||||
// if the currently focused element's parent is last, do nothing
|
||||
// otherwise select the next search result
|
||||
activeToggle(ae.parentElement.nextSibling.lastChild);
|
||||
}
|
||||
} else if (key === "ArrowUp") {
|
||||
e.preventDefault();
|
||||
if (ae.parentElement == first) {
|
||||
// if the currently focused element is first item, go to input box
|
||||
activeToggle(sInput);
|
||||
} else if (ae != sInput) {
|
||||
// if the currently focused element is input box, do nothing
|
||||
// otherwise select the previous search result
|
||||
activeToggle(ae.parentElement.previousSibling.lastChild);
|
||||
}
|
||||
} else if (key === "ArrowRight") {
|
||||
ae.click(); // click on active link
|
||||
}
|
||||
}
|
||||
7
layouts/_default/index.json
Normal file
7
layouts/_default/index.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{{- $.Scratch.Add "index" slice -}}
|
||||
{{- range site.RegularPages -}}
|
||||
{{- if and (not .Params.searchHidden) (ne .Layout `archives`) (ne .Layout `search`) }}
|
||||
{{- $.Scratch.Add "index" (dict "title" .Title "content" .Plain "permalink" .Permalink "summary" .Summary "date" (.Date.Format "Jan 2, 2006")) -}}
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
{{- $.Scratch.Get "index" | jsonify -}}
|
||||
@@ -12,6 +12,7 @@
|
||||
<li class="note-item">
|
||||
<a href="{{ .Permalink }}">
|
||||
<span class="note-title"># {{ .Title }}</span>
|
||||
<span class="delimiter">•</span>
|
||||
<span class="note-date">{{ .Date.Format "Jan 2, 2006" }}</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
{{- 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">
|
||||
<a href="#top" aria-label="go to top" title="Go to Top" 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>
|
||||
|
||||
97
layouts/partials/toc.html
Normal file
97
layouts/partials/toc.html
Normal 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="">
|
||||
<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 }}
|
||||
@@ -12,6 +12,7 @@
|
||||
<li class="post-item">
|
||||
<a href="{{ .Permalink }}">
|
||||
<span class="post-title"># {{ .Title }}</span>
|
||||
<span class="delimiter">•</span>
|
||||
<span class="post-date">{{ .Date.Format "Jan 2, 2006" }}</span>
|
||||
</a>
|
||||
{{- if .Summary }}
|
||||
|
||||
Reference in New Issue
Block a user