Add Pagefind search to the site - #3989
Merged
Merged
Conversation
Pagefind indexes the built HTML as a post-processing step, so the site keeps working as a set of static files with no search backend. It builds one index per language and the browser picks one by the page's `lang` attribute. A language with no index of its own falls back to whichever index holds the most pages, which is not a choice we control: Ukrainian currently has more pages than English. `SearchIndex` rewrites the bundle entry so those languages point at a fixed index instead. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pagefind indexes a whole page unless it is told otherwise, which would put the navigation, the table of contents and the footer into every excerpt. Marking the article element limits it to the content, and the recent-news and pagination blocks inside that element are marked as ignored for the same reason. Bulgarian is left out: Pagefind has neither stemming nor interface translations for it, so its pages get no `data-pagefind-body` and search there runs against English. Which languages those are now lives in _config.yml, so the layouts and `SearchIndex` cannot disagree about it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The button sits next to the language selector and opens a modal; Cmd+K or Ctrl+K opens it from anywhere. Below 640px the top bar has no room for it alongside the longer language names, so it moves into the mobile menu and the two buttons share one modal. Pagefind reads `<html lang>` for its own interface as well as for the index, so every translation gets its labels and result counts in its own language with no strings to add here. Bulgarian is pointed at English on both counts. Pagefind's dark palette hangs off `data-pf-theme`, which the theme toggle now sets from the same decision that sets `.dark`, and the brand sits on top of it through the `--pf-*` variables. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Covers the one thing that surprises people locally: the index is a post-processing step over `_site`, so `rake serve` has no search and there is a separate task for previewing it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Indexing hung off `rake build`, so `rake serve` served a site with no search at all and needed a second task to preview one. Moving it to a `post_write` hook means any path that writes the site ends with a matching index: `rake build`, `rake serve` and its regenerations, and the bare `jekyll build` the deploy workflow runs. `rake serve` only ever handed out whatever `_site` already held, since it called `Serve.process` without the `Build.process` the `jekyll serve` command pairs it with. It now runs both, the way the README has always described it. Pagefind indexes silently because this fires on every regeneration, and the hook reports one line instead. Without Node it says so and lets the build through, so editing content still only needs Ruby. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The include still told readers to run a `rake search-index` that no longer exists and that `rake serve` has no index, which is now the opposite of what happens. README implied a bare `rake build` survives a missing Node, when it stops at Tailwind well before the index step. The `rake test` description had listed a subset of its suites since before this branch and had fallen a further one behind. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
_config.yml and the site directories spell locales `zh_cn`, Pagefind keys its indexes `zh-cn`. The fallback was written under the config spelling, so `unsupported: [zh_cn]` would have left the browser looking up a key nobody wrote and falling back to the largest index, which is the failure this exists to prevent. Only `bg` and `en` are configured today, so nothing was broken yet, but README tells maintainers that adding a line here is all it takes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The admin page carries `layout: page` like any other, so search gave it a public entry point it never had before. A `searchable: false` in its front matter covers this case and any later page whose contents are not worth answering a search with. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Search results link with `?highlight=`, so a build whose index was skipped threw an unhandled rejection on each page a reader arrived at. Losing the highlight is the whole cost of that build already. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Only the skip path was tested, so nothing held `build` to returning the entry on success or raising when Pagefind exits non-zero. The `pagefind:` keyword was added for exactly this and a shell stub is enough to drive both. The file also reaches its subject through the load path now, the way the other tests for `lib` do. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A Bulgarian visitor typing Cyrillic got nothing back and no reason for it, which reads as a broken search rather than a language Pagefind cannot index. The modal now carries a line explaining that the search covers the English pages and to type in English. Only the languages under `search.unsupported` get the modal's parts written out; the rest keep the contents Pagefind builds for itself. The notice lives in _data/locales and falls back to English, so a second language needs only its own string. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The site has no search, so finding a particular release note or guide means guessing which page holds it or leaving for a search engine.
This adds Pagefind, which indexes the built HTML rather than the Markdown behind it, so search runs in the browser and the site stays a set of static files. A Jekyll
post_writehook runs it, sorake build,rake serveand the deploy workflow each end with an index matching the site they just wrote. Without Node the hook says it skipped and lets the build through.Pagefind splits the index by the
langattribute on<html>and loads the one matching the page, so a translation finds only its own pages and reads its own interface labels. Bulgarian is the exception, since Pagefind has neither stemming nor translations for it. Its pages stay out of the index and its search runs against English._config.ymlrecords that, and another language needs nothing more than a line here.Leaving that to Pagefind was not an option. It resolves a language with no index of its own to whichever index holds the most pages, and Ukrainian is one page behind English today.
One change beyond search.
rake servecalledServe.processwithout theBuild.processthatjekyll servepairs it with, so it only handed out whatever_sitealready held and never picked up an edit. It now runs both.