aboutsummaryrefslogtreecommitdiff
path: root/template
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2022-07-22 23:27:00 +0200
committerMitja Felicijan <mitja.felicijan@gmail.com>2022-07-22 23:27:00 +0200
commit45c89b984d3f2b3bf97c8c5ee52e62aa6a4af6dc (patch)
tree098417a178a0fe4e054722a84e696d4574c98b16 /template
parent773829d1848f1f18ef587ed5608dd72483c9be53 (diff)
downloadmitjafelicijan.com-45c89b984d3f2b3bf97c8c5ee52e62aa6a4af6dc.tar.gz
Added front end search
Diffstat (limited to 'template')
-rwxr-xr-xtemplate/_includes.html3
-rwxr-xr-xtemplate/_navigation.html2
-rw-r--r--template/_search.html6
-rwxr-xr-xtemplate/index.html4
-rwxr-xr-xtemplate/post.html2
-rwxr-xr-xtemplate/script.js145
-rwxr-xr-xtemplate/style.css145
7 files changed, 217 insertions, 90 deletions
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 @@
1<!-- user code --> 1<!-- user code -->
2 2
3<script src="/script.js?v=2022-01-30-01" async></script> 3<script src="/assets/general/elasticlunr.min.js"></script>
4<script src="/script.js?v=2022-07-22-02" async></script>
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 @@
13 <a href="/books.html">Books</a> 13 <a href="/books.html">Books</a>
14 14
15 <a href="/feed.rss" itemprop="url">RSS</a> 15 <a href="/feed.rss" itemprop="url">RSS</a>
16
17 <a class="cursor search-trigger">Search</a>
16 </nav> 18 </nav>
17 </header> 19 </header>
18</div> 20</div>
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 @@
1<div class="blur hidden"></div>
2
3<section class="search-form hidden">
4 <input type="search" placeholder="Search ...">
5 <ul></ul>
6</section>
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 @@
55 55
56 {{template "_footer.html"}} 56 {{template "_footer.html"}}
57 57
58 {{template "_includes.html"}}
59
60 {{template "_search.html"}}
61
58 </body> 62 </body>
59 63
60</html> 64</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 @@
69 69
70 {{template "_includes.html"}} 70 {{template "_includes.html"}}
71 71
72 {{template "_search.html"}}
73
72 {{template "_libraries.html"}} 74 {{template "_libraries.html"}}
73 75
74 </body> 76 </body>
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 () => {
25 }); 25 });
26 } 26 }
27 27
28 // comments code 28 // Search functionality
29 const commentsEndpoint = 'https://mitjafelicijan.com/comments-api'; 29
30 const commentsPlaceholder = document.querySelector('.comments'); 30 window.index = null;
31 31
32 if (commentsPlaceholder) { 32 const response = await fetch('/feed.json');
33 const guid = commentsPlaceholder.dataset.guid; 33 const feed = await response.json();
34 const name = commentsPlaceholder.querySelector('input'); 34
35 const comment = commentsPlaceholder.querySelector('textarea'); 35 window.index = elasticlunr(function () {
36 const submit = commentsPlaceholder.querySelector('button'); 36 this.addField('title');
37 const comments = commentsPlaceholder.querySelector('ul'); 37 this.addField('body');
38 38 this.setRef('id');
39 if (guid) { 39 });
40 await readAndRenderComments(guid, comments); 40
41 41 for (const item of feed.items) {
42 submit.addEventListener('click', async() => { 42 item.id = item.url;
43 submit.disabled = true; 43 window.index.addDoc({
44 await writeComments(guid, name.value, comment.value); 44 id: item.url,
45 45 title: item.title,
46 submit.disabled = false; 46 body: item.content_html,
47 name.value = ''; 47 url: item.url,
48 comment.value = ''; 48 });
49
50 await readAndRenderComments(guid, comments);
51 });
52 }
53 } 49 }
54 50
55 async function writeComments(guid, name, comment) { 51 const blur = document.querySelector('.blur');
56 const response = await fetch(commentsEndpoint, { 52 const searchForm = document.querySelector('.search-form');
57 method: 'POST', 53 const searchResultsList = document.querySelector('.search-form ul');
58 headers: { 54
59 'Accept': 'application/json', 55 function showSearchModal() {
60 'Content-Type': 'application/json' 56 blur.classList.remove('hidden');
61 }, 57 searchForm.classList.remove('hidden');
62 body: JSON.stringify({ 58
63 action: 'write', 59 // Clear search input.
64 guid, 60 searchForm.querySelector('input').value = '';
65 name, 61
66 comment, 62 // We need to clear the list before opening modal.
67 }) 63 searchResultsList.innerHTML = '';
68 }); 64
65 // Focus on search input.
66 searchForm.querySelector('input').focus();
69 } 67 }
70 68
71 async function readAndRenderComments(guid, commentsPlaceholder) { 69 document.querySelector('.search-trigger').addEventListener('click', async (evt) => {
72 const response = await fetch(commentsEndpoint, { 70 showSearchModal();
73 method: 'POST', 71 });
74 headers: { 72
75 'Accept': 'application/json', 73 document.onkeydown = function (e) {
76 'Content-Type': 'application/json' 74 // Show search modal on F key.
77 }, 75 if (blur.classList.contains('hidden')) {
78 body: JSON.stringify({ 76 if (e.key === 'f') {
79 action: 'read', 77 setTimeout(() => {
80 guid, 78 showSearchModal();
81 }) 79 }, 100);
82 }); 80 }
81 }
83 82
84 // remove all existing comments from list 83 // Hide search modal on escape key.
85 commentsPlaceholder.innerHTML = ''; 84 if (!blur.classList.contains('hidden')) {
86 85 if (e.key === 'Escape') {
87 const commentList = await response.json(); 86 blur.classList.add('hidden');
88 for (const comment of commentList.reverse()) { 87 searchForm.classList.add('hidden');
89 const date = new Date(comment.date).toLocaleDateString('en-US', { 88 }
90 year: 'numeric',
91 month: 'long',
92 day: 'numeric',
93 hour: 'numeric',
94 minute: 'numeric'
95 });
96
97 const commentElement = document.createElement('li');
98 commentElement.innerHTML = `<p><b>${comment.name}</b> - ${date}<p><p>${comment.comment}<p><hr>`;
99 commentsPlaceholder.appendChild(commentElement);
100 } 89 }
101 } 90 };
91
92 blur.addEventListener('click', async (evt) => {
93 evt.target.classList.add('hidden');
94 searchForm.classList.add('hidden');
95 });
96
97 document.querySelector('.search-form input').addEventListener('keyup', async (evt) => {
98 // Perform search.
99 const searchResults = window.index.search(evt.target.value);
100
101 // We need to clear the list before adding new results.
102 searchResultsList.innerHTML = '';
103
104 // Loop through the results and add them to the list.
105 for (const result of searchResults.slice(0, 9)) {
106 const listItem = document.createElement('li');
107 listItem.innerHTML = `<a href="${result.doc.url}">${result.doc.title}</a>`;
108 searchResultsList.appendChild(listItem);
109 }
110 });
102 111
103}); 112});
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 {
29 background: white; 29 background: white;
30 /*font-family: 'Times New Roman', Times, serif;*/ 30 /*font-family: 'Times New Roman', Times, serif;*/
31 /*font-family: 'IBM Plex Sans', sans-serif;*/ 31 /*font-family: 'IBM Plex Sans', sans-serif;*/
32 font-family: "SF Pro Text","SF Pro Icons","Helvetica Neue","Helvetica","Arial",sans-serif; 32 font-family: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
33 color: var(--base-color); 33 color: var(--base-color);
34 font-size: var(--base-font-size); 34 font-size: var(--base-font-size);
35 line-height: var(--base-line-heigh); 35 line-height: var(--base-line-heigh);
@@ -54,6 +54,10 @@ hr {
54 color: #000; 54 color: #000;
55} 55}
56 56
57.cursor {
58 cursor: pointer;
59}
60
57/* width of the page */ 61/* width of the page */
58 62
59.wrapper { 63.wrapper {
@@ -74,12 +78,35 @@ a:hover {
74 78
75/* headings */ 79/* headings */
76 80
77h1 { font-size: 220%; line-height: 1.2em; } 81h1 {
78h2 { font-size: 180%; line-height: 1.2em; } 82 font-size: 220%;
79h3 { font-size: 160%; line-height: 1.2em; } 83 line-height: 1.2em;
80h4 { font-size: 140%; line-height: 1.2em; } 84}
81h5 { font-size: 120%; line-height: 1.2em; } 85
82h6 { font-size: 100%; line-height: 1.2em; } 86h2 {
87 font-size: 180%;
88 line-height: 1.2em;
89}
90
91h3 {
92 font-size: 160%;
93 line-height: 1.2em;
94}
95
96h4 {
97 font-size: 140%;
98 line-height: 1.2em;
99}
100
101h5 {
102 font-size: 120%;
103 line-height: 1.2em;
104}
105
106h6 {
107 font-size: 100%;
108 line-height: 1.2em;
109}
83 110
84h1[itemtype="headline"] { 111h1[itemtype="headline"] {
85 padding-bottom: 0; 112 padding-bottom: 0;
@@ -95,12 +122,15 @@ table {
95 width: 100%; 122 width: 100%;
96} 123}
97 124
98table, th, td { 125table,
126th,
127td {
99 border: 1px solid black; 128 border: 1px solid black;
100 text-align: left; 129 text-align: left;
101} 130}
102 131
103th, td { 132th,
133td {
104 padding: 5px 10px; 134 padding: 5px 10px;
105} 135}
106 136
@@ -268,7 +298,7 @@ code {
268 font-weight: 500; 298 font-weight: 500;
269} 299}
270 300
271pre > code { 301pre>code {
272 background: unset; 302 background: unset;
273 padding: unset; 303 padding: unset;
274 304
@@ -285,7 +315,8 @@ pre {
285 margin-block-end: 40px; 315 margin-block-end: 40px;
286} 316}
287 317
288img, video { 318img,
319video {
289 max-width: 100%; 320 max-width: 100%;
290 margin: 30px auto; 321 margin: 30px auto;
291 display: block; 322 display: block;
@@ -357,14 +388,14 @@ audio {
357 388
358/* comments */ 389/* comments */
359 390
360.comments input{ 391.comments input {
361 width: 100%; 392 width: 100%;
362 font: var(--comment-form-font); 393 font: var(--comment-form-font);
363 border: 1px solid #bbb; 394 border: 1px solid #bbb;
364 padding: 5px; 395 padding: 5px;
365} 396}
366 397
367.comments textarea{ 398.comments textarea {
368 width: 100%; 399 width: 100%;
369 height: 100px; 400 height: 100px;
370 resize: vertical; 401 resize: vertical;
@@ -384,13 +415,69 @@ audio {
384 border-top: initial !important; 415 border-top: initial !important;
385} 416}
386 417
418/* search form */
419
420.search-form {
421 position: fixed;
422 top: 120px;
423 left: 50%;
424 margin-left: -250px;
425 width: 500px;
426 padding: 30px;
427 background: #eee;
428 border-radius: 5px;
429}
430
431.blur {
432 position: fixed;
433 top: 0;
434 left: 0;
435 right: 0;
436 bottom: 0;
437 backdrop-filter: blur(15px);
438}
439
440.hidden {
441 display: none;
442}
443
444.search-form input {
445 width: 100%;
446 margin-bottom: 20px;
447 border: 1px solid #ffffff;
448 padding: 5px 10px;
449 border-radius: 3px;
450 outline: none;
451}
452
453.search-form ul {
454 list-style-type: none;
455 padding: 0;
456 margin: 0;
457}
458
459.search-form ul li {
460 margin-bottom: 5px;
461}
462
387/* responsive */ 463/* responsive */
388 464
389@media only screen and (max-width: 960px) { 465@media only screen and (max-width: 960px) {
390 main { padding: 0 20px; } 466 main {
391 footer { padding: 0 20px; } 467 padding: 0 20px;
392 h1[itemtype="headline"] { font-size: 220%; } 468 }
393 .navigation header { padding: 0 20px; } 469
470 footer {
471 padding: 0 20px;
472 }
473
474 h1[itemtype="headline"] {
475 font-size: 220%;
476 }
477
478 .navigation header {
479 padding: 0 20px;
480 }
394 481
395 article img { 482 article img {
396 max-width: 100%; 483 max-width: 100%;
@@ -400,10 +487,26 @@ audio {
400} 487}
401 488
402@media only screen and (max-width: 600px) { 489@media only screen and (max-width: 600px) {
403 .navigation header { display: block; } 490 .navigation header {
404 .navigation header h3 { text-align: center; margin-bottom: 10px; } 491 display: block;
405 .navigation header nav { text-align: center; } 492 }
406 .post-list li a h2 { font-weight: 500; } 493
494 .navigation header h3 {
495 text-align: center;
496 margin-bottom: 10px;
497 }
498
499 .navigation header nav {
500 text-align: center;
501 }
502
503 .post-list li a h2 {
504 font-weight: 500;
505 }
506
507 .search-trigger {
508 display: none;
509 }
407} 510}
408 511
409/* light/dark mode */ 512/* light/dark mode */