feat(website): add docs search#6496
Open
emmahodcroft wants to merge 9 commits into
Open
Conversation
505773b to
46b6cf6
Compare
Adds the missing minisearch entry to package-lock.json so `npm ci` no longer fails. yaml was already present as a transitive dep so this is mostly a no-op for yaml (just adds it to the root deps list).
46b6cf6 to
0bc96e1
Compare
Adds a MiniSearch-powered client-side search that's exposed as a bar
at the top of the docs and about menu.
- buildSearchIndex.ts pulls MDX content at build time via
import.meta.glob('?raw') so Vite bundles the source into the
server output. The {options, documents} payload is JSON.stringify-ed
once when the Node module loads; the HTTP route just hands the
precomputed string back, so there's no per-request work and no
need for Cache-Control / ETag headers.
- Frontmatter titles are parsed with the yaml lib.
- DocLayout.astro and AboutLayout.astro render <DocsSearch client:load />
above the existing DocsMenu.
This lands a feature that was originally drafted in pathoplexus PR
pathoplexus/pathoplexus#974; moving the impl to Loculus so downstream
consumers automatically get the same behaviour without overlay files.
theosanderson-agent
pushed a commit
to pathoplexus/pathoplexus
that referenced
this pull request
May 22, 2026
The DocsSearch component, buildSearchIndex util and search-index.json route all moved upstream in loculus-project/loculus#6496, which also wires the search bar into DocLayout and AboutLayout. Drop the overlaid copies here and bump loculusVersion to the new tip (b773fe7ab) so the sync pulls everything in.
- buildSearchIndex frontmatter regex tolerated only LF line endings, so mdx files saved with CRLF (e.g. pathoplexus' about/governance/data-submission.mdx) failed to parse and showed up as "Untitled". - DocsSearch was rendering a "Loading search..." line below the input while the index was loading, which shifted the page content as the text appeared and disappeared. Move that indicator into the absolutely-positioned results dropdown so it only renders when the user is actually searching (no CLS).
The bare input rendered the browser's default blue focus outline. Add focus:outline-none focus:ring-0 to suppress it, and give the surrounding wrapper a focus-within:border-primary-400 so the search bar still has a clear themed focus indicator.
…racter sanitization' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Member
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa7a73250a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
The content field is only fed into MiniSearch for text matching and is never rendered as HTML (search results show titles only), so the multi-pass HTML-comment sanitization Copilot autofixed wasn't buying any safety and CodeQL still flagged it. Removing the rule entirely keeps the function single-pass and resolves the alert.
website/AGENTS.md asks interactive elements to be wrapped with DisabledUntilHydrated (or gated on useClientFlag) so Playwright / hydration races can't drop early keystrokes. Wrap the search input accordingly. Codex review flagged this.
The index is computed once at module load, so it's essentially a static asset for the lifetime of the running server. Compute a sha1 ETag alongside the JSON, send Cache-Control: public, max-age=3600, and respond 304 to If-None-Match when the hash hasn't changed. Means browsers cache the index for an hour, and on revalidation we short-circuit to a 304 instead of re-sending the payload.
Member
|
@codex review |
|
Codex Review: Didn't find any major issues. 👍 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
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.
Why
So let's fix it. This adds a client-side search bar at the top of the
/docsand/aboutmenus.What's here
A MiniSearch-powered search across all MDX content in
src/pages/docs/**andsrc/pages/about/**:buildSearchIndex.tsusesimport.meta.glob('?raw')so Vite bundles the MDX content into the server output; the{options, documents}JSON payload isJSON.stringify-ed once at module load. The/search-index.jsonroute is a one-liner that hands the precomputed string back — no per-request work, no Cache-Control / ETag plumbing needed.Frontmatter is parsed with the
yamllibrary (tolerant of CRLF), so titles render correctly regardless of which OS authored the file.UI niceties picked up along the way:
DisabledUntilHydratedso Playwright / early keystrokes can't race hydration (perwebsite/AGENTS.md).focus-within:border-primary-400) so the input doesn't show the browser's default blue ring.Files
website/src/utils/buildSearchIndex.tsimport.meta.glob('?raw'), parses frontmatter withyaml, produces the JSON payload.website/src/pages/search-index.json.tswebsite/src/components/Navigation/DocsSearch.tsxwebsite/src/layouts/{Doc,About}Layout.astro<DocsSearch client:load />above the menu.website/package.json/package-lock.jsonminisearch+yaml.🚀 Preview: Add
previewlabel to enable