From 45c89b984d3f2b3bf97c8c5ee52e62aa6a4af6dc Mon Sep 17 00:00:00 2001 From: Mitja Felicijan Date: Fri, 22 Jul 2022 23:27:00 +0200 Subject: Added front end search --- template/_includes.html | 3 +- template/_navigation.html | 2 + template/_search.html | 6 ++ template/index.html | 4 ++ template/post.html | 2 + template/script.js | 145 ++++++++++++++++++++++++---------------------- template/style.css | 145 +++++++++++++++++++++++++++++++++++++++------- 7 files changed, 217 insertions(+), 90 deletions(-) create mode 100644 template/_search.html (limited to 'template') diff --git a/template/_includes.html b/template/_includes.html index d16fa3d..8102a35 100755 --- a/template/_includes.html +++ b/template/_includes.html @@ -1,3 +1,4 @@ - + + diff --git a/template/_navigation.html b/template/_navigation.html index 85290a3..45a2a9e 100755 --- a/template/_navigation.html +++ b/template/_navigation.html @@ -13,6 +13,8 @@ Books + + Search diff --git a/template/_search.html b/template/_search.html new file mode 100644 index 0000000..997b35c --- /dev/null +++ b/template/_search.html @@ -0,0 +1,6 @@ + + + diff --git a/template/index.html b/template/index.html index 8c1cc6e..cb334e1 100755 --- a/template/index.html +++ b/template/index.html @@ -55,6 +55,10 @@ {{template "_footer.html"}} + {{template "_includes.html"}} + + {{template "_search.html"}} + diff --git a/template/post.html b/template/post.html index 564ed09..cf80b22 100755 --- a/template/post.html +++ b/template/post.html @@ -69,6 +69,8 @@ {{template "_includes.html"}} + {{template "_search.html"}} + {{template "_libraries.html"}} diff --git a/template/script.js b/template/script.js index 0e1291c..3c58403 100755 --- a/template/script.js +++ b/template/script.js @@ -25,79 +25,88 @@ window.addEventListener('load', async () => { }); } - // comments code - const commentsEndpoint = 'https://mitjafelicijan.com/comments-api'; - const commentsPlaceholder = document.querySelector('.comments'); - - if (commentsPlaceholder) { - const guid = commentsPlaceholder.dataset.guid; - const name = commentsPlaceholder.querySelector('input'); - const comment = commentsPlaceholder.querySelector('textarea'); - const submit = commentsPlaceholder.querySelector('button'); - const comments = commentsPlaceholder.querySelector('ul'); - - if (guid) { - await readAndRenderComments(guid, comments); - - submit.addEventListener('click', async() => { - submit.disabled = true; - await writeComments(guid, name.value, comment.value); - - submit.disabled = false; - name.value = ''; - comment.value = ''; - - await readAndRenderComments(guid, comments); - }); - } + // Search functionality + + window.index = null; + + const response = await fetch('/feed.json'); + const feed = await response.json(); + + window.index = elasticlunr(function () { + this.addField('title'); + this.addField('body'); + this.setRef('id'); + }); + + for (const item of feed.items) { + item.id = item.url; + window.index.addDoc({ + id: item.url, + title: item.title, + body: item.content_html, + url: item.url, + }); } - async function writeComments(guid, name, comment) { - const response = await fetch(commentsEndpoint, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - action: 'write', - guid, - name, - comment, - }) - }); + const blur = document.querySelector('.blur'); + const searchForm = document.querySelector('.search-form'); + const searchResultsList = document.querySelector('.search-form ul'); + + function showSearchModal() { + blur.classList.remove('hidden'); + searchForm.classList.remove('hidden'); + + // Clear search input. + searchForm.querySelector('input').value = ''; + + // We need to clear the list before opening modal. + searchResultsList.innerHTML = ''; + + // Focus on search input. + searchForm.querySelector('input').focus(); } - async function readAndRenderComments(guid, commentsPlaceholder) { - const response = await fetch(commentsEndpoint, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - action: 'read', - guid, - }) - }); + document.querySelector('.search-trigger').addEventListener('click', async (evt) => { + showSearchModal(); + }); + + document.onkeydown = function (e) { + // Show search modal on F key. + if (blur.classList.contains('hidden')) { + if (e.key === 'f') { + setTimeout(() => { + showSearchModal(); + }, 100); + } + } - // remove all existing comments from list - commentsPlaceholder.innerHTML = ''; - - const commentList = await response.json(); - for (const comment of commentList.reverse()) { - const date = new Date(comment.date).toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric', - hour: 'numeric', - minute: 'numeric' - }); - - const commentElement = document.createElement('li'); - commentElement.innerHTML = `

${comment.name} - ${date}

${comment.comment}


`; - commentsPlaceholder.appendChild(commentElement); + // Hide search modal on escape key. + if (!blur.classList.contains('hidden')) { + if (e.key === 'Escape') { + blur.classList.add('hidden'); + searchForm.classList.add('hidden'); + } } - } + }; + + blur.addEventListener('click', async (evt) => { + evt.target.classList.add('hidden'); + searchForm.classList.add('hidden'); + }); + + document.querySelector('.search-form input').addEventListener('keyup', async (evt) => { + // Perform search. + const searchResults = window.index.search(evt.target.value); + + // We need to clear the list before adding new results. + searchResultsList.innerHTML = ''; + + // Loop through the results and add them to the list. + for (const result of searchResults.slice(0, 9)) { + const listItem = document.createElement('li'); + listItem.innerHTML = `${result.doc.title}`; + searchResultsList.appendChild(listItem); + } + }); }); diff --git a/template/style.css b/template/style.css index af0d7bc..ebb2b26 100755 --- a/template/style.css +++ b/template/style.css @@ -29,7 +29,7 @@ body { background: white; /*font-family: 'Times New Roman', Times, serif;*/ /*font-family: 'IBM Plex Sans', sans-serif;*/ - font-family: "SF Pro Text","SF Pro Icons","Helvetica Neue","Helvetica","Arial",sans-serif; + font-family: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", "Helvetica", "Arial", sans-serif; color: var(--base-color); font-size: var(--base-font-size); line-height: var(--base-line-heigh); @@ -54,6 +54,10 @@ hr { color: #000; } +.cursor { + cursor: pointer; +} + /* width of the page */ .wrapper { @@ -74,12 +78,35 @@ a:hover { /* headings */ -h1 { font-size: 220%; line-height: 1.2em; } -h2 { font-size: 180%; line-height: 1.2em; } -h3 { font-size: 160%; line-height: 1.2em; } -h4 { font-size: 140%; line-height: 1.2em; } -h5 { font-size: 120%; line-height: 1.2em; } -h6 { font-size: 100%; line-height: 1.2em; } +h1 { + font-size: 220%; + line-height: 1.2em; +} + +h2 { + font-size: 180%; + line-height: 1.2em; +} + +h3 { + font-size: 160%; + line-height: 1.2em; +} + +h4 { + font-size: 140%; + line-height: 1.2em; +} + +h5 { + font-size: 120%; + line-height: 1.2em; +} + +h6 { + font-size: 100%; + line-height: 1.2em; +} h1[itemtype="headline"] { padding-bottom: 0; @@ -95,12 +122,15 @@ table { width: 100%; } -table, th, td { +table, +th, +td { border: 1px solid black; text-align: left; } -th, td { +th, +td { padding: 5px 10px; } @@ -268,7 +298,7 @@ code { font-weight: 500; } -pre > code { +pre>code { background: unset; padding: unset; @@ -285,7 +315,8 @@ pre { margin-block-end: 40px; } -img, video { +img, +video { max-width: 100%; margin: 30px auto; display: block; @@ -357,14 +388,14 @@ audio { /* comments */ -.comments input{ +.comments input { width: 100%; font: var(--comment-form-font); border: 1px solid #bbb; padding: 5px; } -.comments textarea{ +.comments textarea { width: 100%; height: 100px; resize: vertical; @@ -384,13 +415,69 @@ audio { border-top: initial !important; } +/* search form */ + +.search-form { + position: fixed; + top: 120px; + left: 50%; + margin-left: -250px; + width: 500px; + padding: 30px; + background: #eee; + border-radius: 5px; +} + +.blur { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + backdrop-filter: blur(15px); +} + +.hidden { + display: none; +} + +.search-form input { + width: 100%; + margin-bottom: 20px; + border: 1px solid #ffffff; + padding: 5px 10px; + border-radius: 3px; + outline: none; +} + +.search-form ul { + list-style-type: none; + padding: 0; + margin: 0; +} + +.search-form ul li { + margin-bottom: 5px; +} + /* responsive */ @media only screen and (max-width: 960px) { - main { padding: 0 20px; } - footer { padding: 0 20px; } - h1[itemtype="headline"] { font-size: 220%; } - .navigation header { padding: 0 20px; } + main { + padding: 0 20px; + } + + footer { + padding: 0 20px; + } + + h1[itemtype="headline"] { + font-size: 220%; + } + + .navigation header { + padding: 0 20px; + } article img { max-width: 100%; @@ -400,10 +487,26 @@ audio { } @media only screen and (max-width: 600px) { - .navigation header { display: block; } - .navigation header h3 { text-align: center; margin-bottom: 10px; } - .navigation header nav { text-align: center; } - .post-list li a h2 { font-weight: 500; } + .navigation header { + display: block; + } + + .navigation header h3 { + text-align: center; + margin-bottom: 10px; + } + + .navigation header nav { + text-align: center; + } + + .post-list li a h2 { + font-weight: 500; + } + + .search-trigger { + display: none; + } } /* light/dark mode */ -- cgit v1.2.3