diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 92b841f4..085413a4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -236,6 +236,10 @@ jobs: run: | tar -C "spec${baseURL}" --strip-components=1 -xzf openapi.tar.gz + - name: "🔍 pagefind indexing" + run: | + npm run pagefind -- --site "spec${baseURL}" + - name: "📦 Tarball creation" run: | cd spec diff --git a/README.md b/README.md index 0678713b..b147cc87 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,18 @@ We use a highly customized [Docsy](https://www.docsy.dev/) theme for our generat Awesome. If you're looking at making design-related changes to the spec site, please coordinate with us in [#matrix-docs:matrix.org](https://matrix.to/#/#matrix-docs:matrix.org) before opening a PR. +## Page search + +The spec uses [Pagefind](https://pagefind.app/) to provide a page search widget. To test this locally, you'll need to generate the +search index _after_ building the static site. + +``` +hugo build && npm run pagefind -- --site public && hugo serve +``` + +Note that while `hugo serve` supports hot reloading, changes made to the site content won't reflect in the search index without +rebuilding it. + ## Building the specification If for some reason you're not a CI/CD system and want to render a static version of the spec for yourself, follow the above diff --git a/assets/js/offline-search.js b/assets/js/offline-search.js new file mode 100644 index 00000000..1d2944d1 --- /dev/null +++ b/assets/js/offline-search.js @@ -0,0 +1,290 @@ +/* +Copyright 2026 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +/* +Adapted from [1] to combine Docsy's built-in search UI with the Pagefind +search backend. + + [1]: https://github.com/matrix-org/docsy/blob/71d103ebb20ace3d528178c4b6d92b6cc4f7fd53/assets/js/offline-search.js +*/ + +(function ($) { + "use strict"; + + $(document).ready(async function () { + // This is going to be loaded from ${deployment}/js/main.js so to use a relative path + // to the Pagefind script we need to navigate one level up. + const pagefind = await import("../pagefind/pagefind.js"); + const $searchInput = $(".td-search input"); + + // + // Lazily initialise Pagefind only when the user is about to start a search. + // + + $searchInput.focus(() => { + pagefind.init(); + }); + + // + // Set up search input handler. + // + + $searchInput.on("keypress", (event) => { + // Start searching only upon Enter. + if (event.which === 13) { + event.preventDefault(); + render($(event.target)); + return; + } + }); + + // Prevent reloading page by enter key on sidebar search. + $searchInput.closest("form").on("submit", () => { + return false; + }); + + // + // Callback for searching and rendering the results. + // + + const render = async ($targetSearchInput) => { + // + // Dispose any existing popover. + // + + disposePopover($targetSearchInput); + + // + // Check if we need to do a search at all. + // + + const searchQuery = $targetSearchInput.val(); + if (searchQuery === "") { + return; + } + + // + // Prepare the results popover. + // + + const $html = $("
"); + + // Add the header and close button. + $html.append($("
") + .css({ + display: "flex", + justifyContent: "space-between", + marginBottom: "1em", + }) + .append($("") + .text("Search results") + .css({ fontWeight: "bold" })) + .append($("