From 0e290794a649424c9853d1958be8674ac91353c0 Mon Sep 17 00:00:00 2001 From: "Jakob L. Kreuze" Date: Sun, 15 Feb 2026 08:36:30 -0500 Subject: Integrate pagefind --- haunt.scm | 2 ++ jakob/builder/blog.scm | 5 +++-- jakob/builder/search.scm | 39 ++++++++++++++++++++++++++++++++ jakob/theme.scm | 2 +- static/js/search.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 jakob/builder/search.scm create mode 100644 static/js/search.js diff --git a/haunt.scm b/haunt.scm index c636a42..31d5596 100644 --- a/haunt.scm +++ b/haunt.scm @@ -27,6 +27,7 @@ (jakob builder index) (jakob builder outbox) (jakob builder projects) + (jakob builder search) (jakob reader html-prime) (jakob reader org-mode-prime) (jakob theme) @@ -53,6 +54,7 @@ #:builders (list (atom-feed #:max-entries 1024) (index) + (search) (blog) (blogroll) (outbox) diff --git a/jakob/builder/blog.scm b/jakob/builder/blog.scm index 94b77d5..bb5567c 100644 --- a/jakob/builder/blog.scm +++ b/jakob/builder/blog.scm @@ -55,9 +55,10 @@ (define (render-article post) "Return the SHTML for POST's contents." - #<(article (@ (class "update-entry")) + #<(article (@ (class "update-entry") + (data-pagefind-body "1")) (h1 (@ (class "section-header")) - ,(format #f "Blog :: ~a" (post-ref post 'title))) + ,(format #f "Blog :: ~a" (post-ref post 'title))) (div (@ (class "date-stamp")) (time (@ (datetime ,(date->string (post-date post) "~Y-~m-~d"))) ,(date->string (post-date post) "~B ~d, ~Y")) diff --git a/jakob/builder/search.scm b/jakob/builder/search.scm new file mode 100644 index 0000000..df8e94f --- /dev/null +++ b/jakob/builder/search.scm @@ -0,0 +1,39 @@ +;;; Copyright © 2019 - 2026 Jakob L. Kreuze +;;; +;;; This program is free software; you can redistribute it and/or +;;; modify it under the terms of the GNU General Public License as +;;; published by the Free Software Foundation; either version 3 of the +;;; License, or (at your option) any later version. +;;; +;;; This program is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;; General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with this program. If not, see +;;; . + +(define-module (jakob builder search) + #:use-module (haunt artifact) + #:use-module (haunt html) + #:use-module (jakob theme) + #:use-module (jakob utils sxml) + #:export (search)) + +(define (search) + "Return a Haunt build procedure to create an index page." + (lambda (site posts) + `(,(serialized-artifact "search.html" + (theme #:title "Search Results" + ;; #:description (description-from-post post) + ;; #:keywords (post-ref post 'tags) + ;; #:meta (if (not (eof-object? meta-tags)) meta-tags '()) + ;; #:scripts (if (not (eof-object? scripts)) scripts '()) + #:content `((main (@ (class "main-content")) + (section (@ (id "search-results")) + (h2 (@ (class "section-header")) "Search Results") + (div (@ (id "search-output")) + (noscript "Javascript must be enabled for search.")))) + ,(script "search.js"))) + sxml->html)))) diff --git a/jakob/theme.scm b/jakob/theme.scm index 0cfebd6..65aaf51 100644 --- a/jakob/theme.scm +++ b/jakob/theme.scm @@ -73,7 +73,7 @@ (class "module-title module-title-has-icon") (style ,(fugue-icon-path "magnifier"))) "Search") - (form (@ (action "/search") + (form (@ (action "/search.html") (method "GET") (role "search") (style "display: flex; gap: 5px;")) diff --git a/static/js/search.js b/static/js/search.js new file mode 100644 index 0000000..7037386 --- /dev/null +++ b/static/js/search.js @@ -0,0 +1,58 @@ +/* + * search.js -- Alternative search results processor for pagefind. + * Copyright © 2022 - 2026 Jakob L. Kreuze + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * . + */ + +window.addEventListener("load", async () => { + const pagefind = await import("/_pagefind/pagefind.js"); + pagefind.init(); + + const params = new URLSearchParams(window.location.search); + const query = params.get('q'); + const outputContainer = document.getElementById('search-output'); + + if (query) { + const search = await pagefind.search(query); + + if (search.results.length === 0) { + outputContainer.innerHTML = `

No results found for "${query}".

`; + return; + } + + outputContainer.innerHTML = `

+ Found ${search.results.length} result(s) for "${query}": +

`; + + for (let result of search.results) { + const data = await result.data(); + + const resultElement = document.createElement('article'); + resultElement.className = 'update-entry'; + console.log(data); + resultElement.innerHTML = ` +
+

${data.meta.title}

+
+

${data.excerpt} ...

+

view page →

+ `; + outputContainer.appendChild(resultElement); + } + } else { + outputContainer.innerHTML = `

Searching for '${query}'...

`; + } +}); -- cgit v1.3