aboutsummaryrefslogtreecommitdiff
path: root/themes/simple
diff options
context:
space:
mode:
authorMitja Felicijan <m@mitjafelicijan.com>2023-06-29 18:40:17 +0200
committerMitja Felicijan <m@mitjafelicijan.com>2023-06-29 18:40:17 +0200
commit93d47662b2ce5a6dc4867687386c912e8cd13720 (patch)
treea609e947843bdd297121fd49a9e16e3dea2a1fd4 /themes/simple
parent89f8bc803364ca52ca0dee1a429261b9f3d9ed0e (diff)
downloadmitjafelicijan.com-93d47662b2ce5a6dc4867687386c912e8cd13720.tar.gz
Added search option with lunr.js
Diffstat (limited to 'themes/simple')
-rw-r--r--themes/simple/layouts/_default/index.json5
-rw-r--r--themes/simple/layouts/_default/index.xml (renamed from themes/simple/layouts/_default/rss.xml)0
-rw-r--r--themes/simple/layouts/_default/list.html13
-rw-r--r--themes/simple/layouts/_default/notes.html5
-rw-r--r--themes/simple/layouts/_default/single.html3
-rw-r--r--themes/simple/layouts/partials/head.html2
-rw-r--r--themes/simple/layouts/partials/navigation.html8
-rw-r--r--themes/simple/layouts/partials/search.html123
-rw-r--r--themes/simple/layouts/section/section.json5
-rw-r--r--themes/simple/layouts/section/section.xml (renamed from themes/simple/layouts/section/notes.xml)0
-rw-r--r--themes/simple/static/css/tailwind.css2
11 files changed, 163 insertions, 3 deletions
diff --git a/themes/simple/layouts/_default/index.json b/themes/simple/layouts/_default/index.json
new file mode 100644
index 0000000..b8f3786
--- /dev/null
+++ b/themes/simple/layouts/_default/index.json
@@ -0,0 +1,5 @@
1{{- $.Scratch.Add "index" slice -}}
2{{- range .Site.RegularPages -}}
3{{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "type" .Type "permalink" .RelPermalink "summary" .Summary) -}}
4{{- end -}}
5{{- $.Scratch.Get "index" | jsonify -}}
diff --git a/themes/simple/layouts/_default/rss.xml b/themes/simple/layouts/_default/index.xml
index 1f29133..1f29133 100644
--- a/themes/simple/layouts/_default/rss.xml
+++ b/themes/simple/layouts/_default/index.xml
diff --git a/themes/simple/layouts/_default/list.html b/themes/simple/layouts/_default/list.html
index 589d07b..232598d 100644
--- a/themes/simple/layouts/_default/list.html
+++ b/themes/simple/layouts/_default/list.html
@@ -1,6 +1,19 @@
1{{ define "main" }} 1{{ define "main" }}
2<main role="main" class="container-blog mx-auto px-6 md:p-0"> 2<main role="main" class="container-blog mx-auto px-6 md:p-0">
3 3
4 <!-- Search modal and results -->
5 {{ partial "search.html" . }}
6
7 <!-- Notes CTA -->
8 <a class="flex items-center gap-2 w-full bg-yellow-200 hover:cursor-pointer rounded mb-8 p-4" href="/notes.html">
9 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="hidden lg:block w-6 h-6">
10 <path stroke-linecap="round" stroke-linejoin="round" d="M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25" />
11 </svg>
12 <p>For interesting <span span class="italic font-medium">notes</span> and
13 small <span class="italic font-medium">experiments</span> I usually partake
14 in, check the Notes page.</p>
15 </a>
16
4 <h1 class="text-2xl font-bold mb-6">Blog posts</h1> 17 <h1 class="text-2xl font-bold mb-6">Blog posts</h1>
5 18
6 <!-- List of all blog posts --> 19 <!-- List of all blog posts -->
diff --git a/themes/simple/layouts/_default/notes.html b/themes/simple/layouts/_default/notes.html
index 27ac958..02560b0 100644
--- a/themes/simple/layouts/_default/notes.html
+++ b/themes/simple/layouts/_default/notes.html
@@ -1,12 +1,15 @@
1{{ define "main" }} 1{{ define "main" }}
2<main role="main" class="container-blog mx-auto px-6 md:p-0"> 2<main role="main" class="container-blog mx-auto px-6 md:p-0">
3 3
4 <!-- Search modal and results -->
5 {{ partial "search.html" . }}
6
4 <section class="mb-6"> 7 <section class="mb-6">
5 <h1 class="text-2xl font-bold mb-2">Notes, notes and notes</h1> 8 <h1 class="text-2xl font-bold mb-2">Notes, notes and notes</h1>
6 <p class="text-gray-600 italic"> 9 <p class="text-gray-600 italic">
7 Notes about things I learn, things I do, things I want to remember, 10 Notes about things I learn, things I do, things I want to remember,
8 but never do. You can subscribe to this 11 but never do. You can subscribe to this
9 <a href="/notes.xml" class="underline hover:bg-yellow-100">RSS feed</a> 12 <a href="/notes/index.xml" class="underline hover:bg-yellow-100">RSS feed</a>
10 which contains only the notes without the blog posts. 13 which contains only the notes without the blog posts.
11 </p> 14 </p>
12 </section> 15 </section>
diff --git a/themes/simple/layouts/_default/single.html b/themes/simple/layouts/_default/single.html
index 77354b7..cadfd7b 100644
--- a/themes/simple/layouts/_default/single.html
+++ b/themes/simple/layouts/_default/single.html
@@ -1,6 +1,9 @@
1{{ define "main" }} 1{{ define "main" }}
2<main role="main" class="container-blog mx-auto px-6 md:p-0"> 2<main role="main" class="container-blog mx-auto px-6 md:p-0">
3 3
4 <!-- Search modal and results -->
5 {{ partial "search.html" . }}
6
4 <!-- Single article --> 7 <!-- Single article -->
5 <article itemtype="http://schema.org/Article" class="single mb-12"> 8 <article itemtype="http://schema.org/Article" class="single mb-12">
6 <header class="mb-6"> 9 <header class="mb-6">
diff --git a/themes/simple/layouts/partials/head.html b/themes/simple/layouts/partials/head.html
index 6d40525..fc481fc 100644
--- a/themes/simple/layouts/partials/head.html
+++ b/themes/simple/layouts/partials/head.html
@@ -5,7 +5,7 @@
5<meta name="viewport" content="width=device-width, initial-scale=1.0"> 5<meta name="viewport" content="width=device-width, initial-scale=1.0">
6 6
7<link rel="alternate" type="application/rss+xml" href="/index.xml" title="{{ .Site.Author.name }}"> 7<link rel="alternate" type="application/rss+xml" href="/index.xml" title="{{ .Site.Author.name }}">
8<link rel="alternate" type="application/rss+xml" href="/notes.xml" title="{{ .Site.Author.name }} - Notes"> 8<link rel="alternate" type="application/rss+xml" href="/notes/index.xml" title="{{ .Site.Author.name }} - Notes">
9 9
10<link rel="stylesheet" href="/general/index.css?v={{ $cachebuster }}"> 10<link rel="stylesheet" href="/general/index.css?v={{ $cachebuster }}">
11 11
diff --git a/themes/simple/layouts/partials/navigation.html b/themes/simple/layouts/partials/navigation.html
index da42679..b65fe35 100644
--- a/themes/simple/layouts/partials/navigation.html
+++ b/themes/simple/layouts/partials/navigation.html
@@ -7,6 +7,14 @@
7 <nav itemscope itemtype="http://schema.org/SiteNavigationElement" class="flex items-center gap-1" role="toolbar"> 7 <nav itemscope itemtype="http://schema.org/SiteNavigationElement" class="flex items-center gap-1" role="toolbar">
8 <meta itemprop="name" content="Main Menu"> 8 <meta itemprop="name" content="Main Menu">
9 9
10 <!-- Search button -->
11 <span class="search-button flex gap-1 items-center text-gray-500 bg-gray-100 hover:bg-gray-200 rounded px-2 py-1 text-xs cursor-pointer mr-2 hidden" onclick="showSearchModal()">
12 <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor" class="w-4 h-4">
13 <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" />
14 </svg>
15 <span class="search-button-text uppercase font-bold"></span>
16 </span>
17
10 <a href="/notes.html" class="font-medium px-2 hover:bg-yellow-100">Notes</a> 18 <a href="/notes.html" class="font-medium px-2 hover:bg-yellow-100">Notes</a>
11 <a href="https://telegram.me/mitjafelicijan" target="_blank" rel="noopener nofollow" itemprop="url" class="font-medium px-2 hover:bg-yellow-100">Telegram</a> 19 <a href="https://telegram.me/mitjafelicijan" target="_blank" rel="noopener nofollow" itemprop="url" class="font-medium px-2 hover:bg-yellow-100">Telegram</a>
12 <a href="https://git.mitjafelicijan.com" target="_blank" rel="noopener nofollow" itemprop="url" class="font-medium px-2 hover:bg-yellow-100">Git</a> 20 <a href="https://git.mitjafelicijan.com" target="_blank" rel="noopener nofollow" itemprop="url" class="font-medium px-2 hover:bg-yellow-100">Git</a>
diff --git a/themes/simple/layouts/partials/search.html b/themes/simple/layouts/partials/search.html
new file mode 100644
index 0000000..3e31753
--- /dev/null
+++ b/themes/simple/layouts/partials/search.html
@@ -0,0 +1,123 @@
1<section class="search-modal mb-10 hidden">
2 <input class="bg-gray-100 w-full px-3 py-2 rounded outline-none" type="search" placeholder="Search here...">
3 <section class="results bg-white border border-gray-200 shadow-md p-2 flex flex-col gap-2 rounded mt-4 hidden"></section>
4</section>
5
6<script src="https://unpkg.com/lunr/lunr.js"></script>
7<script>
8 (async function() {
9 const debounceDelay = 700;
10
11 // Fetch search index generated by Hugo.
12 const req = await fetch('/index.json');
13 window.searchDocuments = await req.json();
14
15 window.searchIndex = lunr(function() {
16 this.ref('permalink');
17 this.field('title', { boost: 20 });
18 this.field('tags', { boost: 10 });
19 this.field('summary', { boost: 1 });
20
21 window.searchDocuments.forEach(function(doc) {
22 this.add(doc);
23 }, this);
24
25 console.log('Search index processed...');
26 })
27
28 // Connect DOM and search the index.
29 let cachedSearchTerm = null;
30 const searchModal = document.querySelector('.search-modal');
31 const searchInput = document.querySelector('.search-modal input');
32 const searchResults = document.querySelector('.search-modal .results');
33
34 // Display search modal.
35 window.showSearchModal = function() {
36 searchModal.classList.remove('hidden');
37 searchInput.focus();
38 }
39
40 // Detect OS and sets proper search button text.
41 const searchButtonElement = document.querySelector('.search-button');
42 const searchButtonTextElement = document.querySelector('.search-button-text');
43 if (searchButtonElement) {
44 let searchButtonText = 'ctrl+k';
45 if (navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
46 searchButtonText = 'cmd+k';
47 }
48 searchButtonTextElement.innerText = searchButtonText;
49 searchButtonElement.classList.remove('hidden');
50 }
51
52 // On keyboard shortcut shows search modal.
53 document.addEventListener('keydown', function(event) {
54 // Handles macOS CMD+k.
55 if ((event.ctrlKey || event.metaKey) && event.key === 'k') {
56 event.preventDefault();
57 showSearchModal();
58 }
59
60 // Handles Windows/Linux Ctrl+k.
61 if (event.ctrlKey && event.key === 'k') {
62 event.preventDefault();
63 showSearchModal();
64 }
65 });
66
67 // Debounce magic.
68 function debounce(func, delay) {
69 let timerId;
70 return function (...args) {
71 clearTimeout(timerId);
72 timerId = setTimeout(() => {
73 func.apply(this, args);
74 }, delay);
75 };
76 }
77
78 // Do the actual search.
79 searchInput.addEventListener('keyup', debounce((evt)=> {
80 const query = evt.target.value.trim().toLowerCase();
81 if (query.length && query != cachedSearchTerm) {
82 const results = searchIndex.search(query);
83
84 if (results.length == 0) {
85 searchResults.classList.add('hidden');
86 } else {
87 searchResults.innerText = '';
88 searchResults.classList.remove('hidden');
89 cachedSearchTerm = query;
90
91 results.forEach(resultItem => {
92 const item = window.searchDocuments.find(doc => doc.permalink === resultItem.ref);
93
94 const link = document.createElement('a');
95 link.href = item.permalink;
96 link.classList.add('hover:bg-gray-100', 'cursor-pointer', 'py-2', 'px-3', 'rounded');
97
98 const title = document.createElement('div');
99 title.classList.add('text-gray-800', 'font-medium');
100 title.innerHTML = item.title;
101 link.appendChild(title);
102
103 const meta = document.createElement('div');
104 meta.classList.add('text-gray-500', 'flex', 'items-center', 'gap-2');
105
106 const section = document.createElement('span');
107 section.classList.add('uppercase', 'text-xs', 'font-medium', 'bg-gray-200', 'px-1', 'rounded')
108 section.innerText = item.type;
109 meta.appendChild(section);
110
111 const summary = document.createElement('span');
112 const summaryText = item.summary.length > 80 ? `${item.summary.substring(0, 80)}...` : item.summary;
113 summary.innerHTML = summaryText;
114 meta.appendChild(summary);
115
116 link.appendChild(meta);
117 searchResults.appendChild(link);
118 });
119 }
120 }
121 }, debounceDelay));
122 })();
123</script>
diff --git a/themes/simple/layouts/section/section.json b/themes/simple/layouts/section/section.json
new file mode 100644
index 0000000..b8f3786
--- /dev/null
+++ b/themes/simple/layouts/section/section.json
@@ -0,0 +1,5 @@
1{{- $.Scratch.Add "index" slice -}}
2{{- range .Site.RegularPages -}}
3{{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "type" .Type "permalink" .RelPermalink "summary" .Summary) -}}
4{{- end -}}
5{{- $.Scratch.Get "index" | jsonify -}}
diff --git a/themes/simple/layouts/section/notes.xml b/themes/simple/layouts/section/section.xml
index 889cf08..889cf08 100644
--- a/themes/simple/layouts/section/notes.xml
+++ b/themes/simple/layouts/section/section.xml
diff --git a/themes/simple/static/css/tailwind.css b/themes/simple/static/css/tailwind.css
index 51b922c..7d04496 100644
--- a/themes/simple/static/css/tailwind.css
+++ b/themes/simple/static/css/tailwind.css
@@ -6,7 +6,7 @@
6 6
7/* Container */ 7/* Container */
8.container-blog { 8.container-blog {
9 max-width: 700px; 9 max-width: 740px;
10} 10}
11 11
12/* User text selection */ 12/* User text selection */