mirror of
https://github.com/tcsenpai/obsidiangarden_netlify.git
synced 2025-06-07 05:05:20 +00:00
200 lines
7.9 KiB
Plaintext
200 lines
7.9 KiB
Plaintext
<script>
|
|
document.addEventListener('DOMContentLoaded', init, false);
|
|
document.addEventListener('DOMContentLoaded', setCorrectShortcut, false);
|
|
|
|
window.toggleSearch=function(){
|
|
if(document.getElementById('globalsearch').classList.contains('active')){
|
|
document.getElementById('globalsearch').classList.remove('active');
|
|
}else{
|
|
document.getElementById('globalsearch').classList.add('active');
|
|
document.getElementById('term').focus();
|
|
}
|
|
}
|
|
|
|
const loadingSvg = `<svg width="100" height="100" viewBox="0 0 45 45" xmlns="http://www.w3.org/2000/svg" stroke="#d9d9d9">
|
|
<g fill="none" fill-rule="evenodd" transform="translate(1 1)" stroke-width="2">
|
|
<circle cx="22" cy="22" r="6" stroke-opacity="0">
|
|
<animate attributeName="r"
|
|
begin="1.5s" dur="3s"
|
|
values="6;22"
|
|
calcMode="linear"
|
|
repeatCount="indefinite" />
|
|
<animate attributeName="stroke-opacity"
|
|
begin="1.5s" dur="3s"
|
|
values="1;0" calcMode="linear"
|
|
repeatCount="indefinite" />
|
|
<animate attributeName="stroke-width"
|
|
begin="1.5s" dur="3s"
|
|
values="2;0" calcMode="linear"
|
|
repeatCount="indefinite" />
|
|
</circle>
|
|
<circle cx="22" cy="22" r="6" stroke-opacity="0">
|
|
<animate attributeName="r"
|
|
begin="3s" dur="3s"
|
|
values="6;22"
|
|
calcMode="linear"
|
|
repeatCount="indefinite" />
|
|
<animate attributeName="stroke-opacity"
|
|
begin="3s" dur="3s"
|
|
values="1;0" calcMode="linear"
|
|
repeatCount="indefinite" />
|
|
<animate attributeName="stroke-width"
|
|
begin="3s" dur="3s"
|
|
values="2;0" calcMode="linear"
|
|
repeatCount="indefinite" />
|
|
</circle>
|
|
<circle cx="22" cy="22" r="8">
|
|
<animate attributeName="r"
|
|
begin="0s" dur="1.5s"
|
|
values="6;1;2;3;4;5;6"
|
|
calcMode="linear"
|
|
repeatCount="indefinite" />
|
|
</circle>
|
|
</g>
|
|
</svg>`;
|
|
|
|
function debounce(func, wait, immediate) {
|
|
var timeout;
|
|
return function() {
|
|
var context = this, args = arguments;
|
|
var later = function() {
|
|
timeout = null;
|
|
if (!immediate) func.apply(context, args);
|
|
};
|
|
var callNow = immediate && !timeout;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
if (callNow) func.apply(context, args);
|
|
};
|
|
};
|
|
|
|
function setCorrectShortcut(){
|
|
if(navigator.platform.toUpperCase().indexOf('MAC')>=0){
|
|
document.querySelectorAll(".search-keys").forEach(x=>x.innerHTML = "⌘ + K");
|
|
}
|
|
}
|
|
|
|
async function init() {
|
|
|
|
//open searchmodal when ctrl + k is pressed, cmd + k on mac
|
|
document.addEventListener('keydown', (e) => {
|
|
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
|
|
e.preventDefault();
|
|
toggleSearch();
|
|
}
|
|
if (e.key === 'Escape') {
|
|
document.getElementById('globalsearch').classList.remove('active');
|
|
}
|
|
|
|
//navigate search results with arrow keys
|
|
if (document.getElementById('globalsearch').classList.contains('active')) {
|
|
if (e.key === 'ArrowDown') {
|
|
e.preventDefault();
|
|
let active = document.querySelector('.searchresult.active');
|
|
if (active) {
|
|
active.classList.remove('active');
|
|
if (active.nextElementSibling) {
|
|
active.nextElementSibling.classList.add('active');
|
|
} else {
|
|
document.querySelector('.searchresult').classList.add('active');
|
|
}
|
|
} else {
|
|
document.querySelector('.searchresult').classList.add('active');
|
|
}
|
|
|
|
let currentActive = document.querySelector('.searchresult.active');
|
|
if (currentActive) {
|
|
currentActive .scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'nearest',
|
|
inline: 'start',
|
|
});
|
|
}
|
|
}
|
|
if (e.key === 'ArrowUp') {
|
|
e.preventDefault();
|
|
let active = document.querySelector('.searchresult.active');
|
|
if (active) {
|
|
active.classList.remove('active');
|
|
if (active.previousElementSibling) {
|
|
active.previousElementSibling.classList.add('active');
|
|
} else {
|
|
document.querySelectorAll('.searchresult').forEach((el) => {
|
|
if (!el.nextElementSibling) {
|
|
el.classList.add('active');
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
document.querySelectorAll('.searchresult').forEach((el) => {
|
|
if (el.nextElementSibling) {
|
|
el.classList.add('active');
|
|
}
|
|
});
|
|
}
|
|
|
|
let currentActive = document.querySelector('.searchresult.active');
|
|
if (currentActive) {
|
|
currentActive .scrollIntoView({
|
|
behavior: 'smooth',
|
|
block: 'nearest',
|
|
inline: 'start',
|
|
});
|
|
}
|
|
|
|
}
|
|
if (e.key === 'Enter') {
|
|
e.preventDefault();
|
|
let active = document.querySelector('.searchresult.active');
|
|
if (active) {
|
|
window.location.href = active.querySelector("a").href;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
const debouncedSearch = debounce(search, 200, false);
|
|
field = document.querySelector('#term');
|
|
field.addEventListener('keydown', (e) => {
|
|
if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp') {
|
|
debouncedSearch();
|
|
}
|
|
});
|
|
resultsDiv = document.querySelector('#search-results');
|
|
|
|
const params = new URL(location.href).searchParams;
|
|
if (params.get('q')) {
|
|
field.setAttribute('value', params.get('q'));
|
|
toggleSearch();
|
|
search();
|
|
}
|
|
}
|
|
window.lastSearch = '';
|
|
async function search() {
|
|
let search = field
|
|
.value
|
|
.trim();
|
|
if (!search)
|
|
return;
|
|
if(search == lastSearch) return;
|
|
console.log(`search for ${search}`);
|
|
window.lastSearch = search;
|
|
|
|
resultsDiv.innerHTML = loadingSvg;
|
|
let searchRequest = await fetch(`/api/search?term=${encodeURIComponent(search)}`);
|
|
let results = await searchRequest.json();
|
|
let resultsHTML = '';
|
|
if (!results.length) {
|
|
resultsHTML += `<p>No results for "${search}"</p>`;
|
|
resultsDiv.innerHTML = resultsHTML;
|
|
return;
|
|
}
|
|
resultsHTML += '<div>';
|
|
// we need to add title, url from ref
|
|
results.forEach(r => {
|
|
resultsHTML += `<div class="searchresult"><a class="search-link" href="${r.url}">${r.title}</a><span onclick="window.location='${r.url}'">${r.content}</span></div>`;
|
|
});
|
|
resultsHTML += '</div>';
|
|
resultsDiv.innerHTML = resultsHTML;
|
|
}
|
|
</script> |