Skip to content

Commit cb068c7

Browse files
committed
feat: add global keyboard shortcut for search functionality
- Introduced `/zoeken` shortcut (`Ctrl/Cmd + K`) using `search-shortcut.js` for improved navigation. - Enhanced `/zoeken` integration with metadata support in JSON-LD for `SearchAction`. - Refined query handling in `pagefind-search.js` to update search parameters dynamically. - Removed redundant "Zoeken" link in the header for a cleaner UI. - Updated build and deployment scripts to align with changes.
1 parent e0787a4 commit cb068c7

8 files changed

Lines changed: 128 additions & 12 deletions

File tree

.github/workflows/static.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
${{ runner.os }}-hugo-
4242
4343
- name: Build Site
44-
run: npm run build:css
44+
run: npm run build
4545

4646
- name: Configure AWS credentials
4747
uses: aws-actions/configure-aws-credentials@61815dcd50bd041e203e49132bacad1fd04d2708 # v5
@@ -51,4 +51,4 @@ jobs:
5151
aws-region: eu-west-1
5252

5353
- name: Sync to S3
54-
run: aws s3 sync public/ s3://${{ secrets.S3_BUCKET_NAME }}/ --delete
54+
run: aws s3 sync public/ s3://${{ secrets.S3_BUCKET_NAME }}/ --delete

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
"scripts": {
55
"build": "hugo --minify && pagefind --site public",
66
"build:css": "npm run build",
7-
"dev": "pagefind --site public && hugo server --buildFuture --disableFastRender --buildDrafts --cleanDestinationDir"
7+
"pagefind": "pagefind --site public",
8+
"dev": "hugo --cleanDestinationDir --buildFuture --buildDrafts && pagefind --site public && hugo server --buildFuture --disableFastRender --buildDrafts"
89
},
910
"devDependencies": {
1011
"@tailwindcss/postcss": "^4.1.18",

static/js/pagefind-search.js

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ import * as pagefind from "/pagefind/pagefind.js";
99
return;
1010
}
1111

12+
if (
13+
window.location.search.indexOf("focus=1") !== -1 ||
14+
window.location.hash === "#search"
15+
) {
16+
window.requestAnimationFrame(function () {
17+
input.focus();
18+
});
19+
}
20+
1221
var formatter = new Intl.DateTimeFormat("nl-BE", {
1322
day: "numeric",
1423
month: "long",
@@ -17,6 +26,7 @@ import * as pagefind from "/pagefind/pagefind.js";
1726

1827
var debounceId = null;
1928
var activeSearch = 0;
29+
var debounceDelay = 250;
2030

2131
function setStatus(message) {
2232
statusEl.textContent = message;
@@ -39,6 +49,7 @@ import * as pagefind from "/pagefind/pagefind.js";
3949
.filter(Boolean);
4050
}
4151

52+
4253
function formatDate(value) {
4354
if (!value) {
4455
return "";
@@ -111,9 +122,27 @@ import * as pagefind from "/pagefind/pagefind.js";
111122
resultsEl.innerHTML = "";
112123
}
113124

114-
async function runSearch(query) {
125+
function updateQueryParam(query) {
126+
var params = new URLSearchParams(window.location.search);
127+
if (query) {
128+
params.set("q", query);
129+
} else {
130+
params.delete("q");
131+
}
132+
var next = window.location.pathname;
133+
var nextQuery = params.toString();
134+
if (nextQuery) {
135+
next += "?" + nextQuery;
136+
}
137+
window.history.replaceState(null, "", next);
138+
}
139+
140+
async function runSearch(query, fromInput) {
115141
var searchId = (activeSearch += 1);
116142
setStatus("Zoeken...");
143+
if (fromInput) {
144+
updateQueryParam(query);
145+
}
117146

118147
try {
119148
var search = await pagefind.search(query);
@@ -137,6 +166,7 @@ import * as pagefind from "/pagefind/pagefind.js";
137166

138167
resultsEl.innerHTML = "";
139168
resultsEl.appendChild(fragment);
169+
140170
setStatus(
141171
search.results.length +
142172
(search.results.length === 1 ? " resultaat" : " resultaten") +
@@ -155,6 +185,7 @@ import * as pagefind from "/pagefind/pagefind.js";
155185
if (!query) {
156186
activeSearch += 1;
157187
clearResults();
188+
updateQueryParam("");
158189
return;
159190
}
160191

@@ -163,7 +194,19 @@ import * as pagefind from "/pagefind/pagefind.js";
163194
}
164195

165196
debounceId = window.setTimeout(function () {
166-
runSearch(query);
167-
}, 150);
197+
runSearch(query, true);
198+
}, debounceDelay);
168199
});
200+
201+
function initializeFromQuery() {
202+
var params = new URLSearchParams(window.location.search);
203+
var query = params.get("q");
204+
if (!query) {
205+
return;
206+
}
207+
input.value = query;
208+
runSearch(query, false);
209+
}
210+
211+
initializeFromQuery();
169212
})();

static/js/search-shortcut.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
(function () {
2+
function isEditableTarget(target) {
3+
if (!target) {
4+
return false;
5+
}
6+
7+
var tag = target.tagName;
8+
if (!tag) {
9+
return false;
10+
}
11+
12+
var name = tag.toLowerCase();
13+
if (name === "input" || name === "textarea" || name === "select") {
14+
return true;
15+
}
16+
17+
return target.isContentEditable === true;
18+
}
19+
20+
function isMacPlatform() {
21+
var platform = navigator.platform || "";
22+
var userAgent = navigator.userAgent || "";
23+
return /Mac/.test(platform) || /Macintosh|Mac OS X/.test(userAgent);
24+
}
25+
26+
function handleShortcut(event) {
27+
if (event.defaultPrevented) {
28+
return;
29+
}
30+
31+
if (event.isComposing) {
32+
return;
33+
}
34+
35+
var isMac = isMacPlatform();
36+
var hasModifier = isMac ? event.metaKey : event.ctrlKey;
37+
if (!(hasModifier && event.key.toLowerCase() === "k")) {
38+
return;
39+
}
40+
41+
if (isEditableTarget(event.target)) {
42+
return;
43+
}
44+
45+
event.preventDefault();
46+
47+
var searchUrl =
48+
(document.body && document.body.getAttribute("data-search-url")) ||
49+
"/zoeken/";
50+
var searchPath = searchUrl.split("?")[0];
51+
52+
if (window.location.pathname === searchPath) {
53+
var input = document.querySelector("#search-input");
54+
if (input) {
55+
input.focus();
56+
}
57+
return;
58+
}
59+
60+
var target = searchUrl.indexOf("?") === -1 ? searchUrl + "?focus=1" : searchUrl + "&focus=1";
61+
window.location.assign(target);
62+
}
63+
64+
window.addEventListener("keydown", handleShortcut);
65+
})();

themes/custom/layouts/_default/baseof.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@
44
{{ partial "head.html" . }}
55
{{ block "head" . }}{{ end }}
66
</head>
7-
<body class="bg-slate-50 text-slate-900 antialiased dark:bg-slate-950 dark:text-slate-100">
7+
<body class="bg-slate-50 text-slate-900 antialiased dark:bg-slate-950 dark:text-slate-100" data-search-url="{{ "/zoeken/" | relURL }}"{{ if not (and .IsPage (eq .Section "posts")) }} data-pagefind-ignore{{ end }}>
88
<a class="sr-only focus-visible:not-sr-only focus-visible:absolute focus-visible:left-6 focus-visible:top-4 focus-visible:z-50 focus-visible:rounded focus-visible:bg-white focus-visible:px-3 focus-visible:py-2 focus-visible:text-sm focus-visible:font-semibold focus-visible:text-slate-900 focus-visible:shadow focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-900 dark:focus-visible:bg-slate-900 dark:focus-visible:text-slate-100 dark:focus-visible:outline-slate-100" href="#main">Ga naar inhoud</a>
99
{{ partial "header.html" . }}
10-
<main id="main" class="mx-auto max-w-3xl px-6 py-8" data-pagefind-body>
10+
<main id="main" class="mx-auto max-w-3xl px-6 py-8"{{ if and .IsPage (eq .Section "posts") }} data-pagefind-body{{ end }}>
1111
{{ block "main" . }}{{ end }}
1212
</main>
1313
{{ partial "footer.html" . }}
1414
{{ partial "cookie-banner.html" . }}
1515
{{ partial "cookie-preferences.html" . }}
1616
<script src="/js/cookie-consent.js" defer></script>
17+
<script src="/js/search-shortcut.js" defer></script>
1718
</body>
1819
</html>

themes/custom/layouts/partials/header.html

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@
1717
</a>
1818
<div class="ml-auto flex items-center gap-3 md:gap-4">
1919
{{ partial "nav.html" . }}
20-
<a
21-
class="inline-flex items-center rounded px-2 py-1 text-sm font-semibold text-slate-700 hover:text-moss hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-moss dark:text-slate-300 dark:hover:text-mustard dark:focus-visible:outline-moss"
22-
href="/zoeken/"
23-
>Zoeken</a>
2420
<button
2521
class="inline-flex items-center justify-center rounded-full border border-slate-200 bg-white p-2 text-slate-700 transition hover:border-slate-300 hover:text-slate-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-moss/70 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-50 motion-reduce:transition-none dark:border-slate-800 dark:bg-slate-900 dark:text-slate-200 dark:hover:border-slate-700 dark:hover:text-white dark:focus-visible:ring-moss/70 dark:focus-visible:ring-offset-slate-950"
2622
type="button"

themes/custom/layouts/partials/pagefind-meta.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@
99
{{- with .Params.tags -}}
1010
<meta data-pagefind-meta="tags:{{ delimit . ", " }}">
1111
{{- end -}}
12+
<meta data-pagefind-meta="kind:{{ .Kind }}">
13+
{{- with .Section -}}
14+
<meta data-pagefind-meta="section:{{ . }}">
15+
{{- end -}}
1216
<meta data-pagefind-meta="title:{{ .Title }}">

themes/custom/layouts/partials/schema-jsonld.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@
114114
"url" $siteURL
115115
"publisher" (dict "@id" $orgId)
116116
-}}
117+
{{- $searchTarget := printf "%szoeken/?q={search_term_string}" $siteURL -}}
118+
{{- $website = merge $website (dict "potentialAction" (dict
119+
"@type" "SearchAction"
120+
"target" $searchTarget
121+
"query-input" "required name=search_term_string"
122+
)) -}}
117123
{{- $nodes = $nodes | append $website -}}
118124

119125
{{- $siteDescription := .Site.Params.descriptionLong | default .Site.Params.description -}}

0 commit comments

Comments
 (0)