Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ feat: add search functionality #250

Merged
merged 1 commit into from
Jan 8, 2024
Merged

✨ feat: add search functionality #250

merged 1 commit into from
Jan 8, 2024

Conversation

welpo
Copy link
Owner

@welpo welpo commented Jan 7, 2024

Summary

It's finally here! ✨ Local, accessible, multi-lingual search ✨ using Elasticlunr.

Some of my favourite features:

  • Text fragments: Selecting a search result scrolls to and highlights the search term on the destination page (see browser support). See the video below for a demo.

  • Stylised modal: The search modal has a blurred background and uses the --primary-color CSS variable to apply a gentle tint, making it compatible with skins.

  • Full keyboard navigation: Shortcuts for opening/closing the modal (Ctrl/Cmd + K), navigating results (arrow keys, Home/End, Page Up/Down, Enter) and Esc to close the modal. Tab is "trapped" between the search input and the clear button.

  • Multilingual: The modal text, titles, ARIA labels and the search itself support multiple languages.

  • Efficient index loading: The search index loads on mouseover of the search icon or upon modal activation, whichever happens first. If a user doesn't interact with a search element, the index isn't loaded.

  • Accessibility focus: The implementation leverages ARIA attributes and roles, prioritising accessibility to cater to a wider range of users.

  • Responsive design, of course. And it works with taps just as well as with keyboard or mouse.

  • Flexible search indexing: Search works as long as there's something indexed: works with just titles/paths/description/content and any combination of these.

  • Compatibility with multiple Zola versions: Supports Zola version 0.17.2 (current version in Debian stable) with workarounds for existing bugs.

  • Advanced snippet generation: Includes a custom snippet generation algorithm to provide top-tier context.

Related issue

Resolves #190 (at last).

Changes

  • i18n files get 5 new search-related strings
  • SCSS for the search elements
  • JavaScript for the search logic:
    • static/js/searchElasticlunr.js contains the main logic (the minified version is the one that loads, though)
    • Includes language stemmers in static/js/lunr.
  • Tera templates changes, particularly in header.html (loads JS) and footer.html (search modal loading, which is in templates/partials/search_modal.html
  • Documentation: README, projects/tabi, Mastering tabi post and JavaScript post.
Technical details — search flow

Logic below is written in static/js/searchElasticlunr.js.

1. Initiating the Search Process

  • Hovering over, tapping or clicking the Search Icon
    • Triggers loadSearchIndex.
    • Checks if the index is loaded; if not, fetches and loads it.
  • Pressing Cmd+K or Ctrl+K (or Clicking/Tapping the Search Icon)
    • Invokes toggleModalVisibility.
    • If the modal is hidden, openSearchModal is called.
    • Sets focus on the search input and loads the index if necessary.
  • Loading the Search Index
    • Checks if the search index is pre-loaded in the window object. If not, fetches it from a JSON file.
    • Index loading is asynchronous, optimizing UI responsiveness.

2. User Enters Search Query

  • Asynchronously handles user input, ensuring UI responsiveness.
  • Awaits searchIndexPromise to ensure the index is loaded.
  • Performs the search and processes results.
  • Dynamically updates search results as the user types.

3. Processing the Search Results

  • Iterates over results, creating a div for each.
  • Calls generateSnippet to create relevant snippets with highlighted search terms.
  • Appends each result to the results container.

4. Displaying the Results

  • Results are displayed in the results container.
  • updateResultText updates the result count.
  • Makes results selectable and interactive.

5. User Interaction with Results

  • Global keydown event listener enables keyboard navigation within results.
  • Manages selection and focus within the modal for accessibility.
  • Navigates to the linked page on 'Enter'.

6. Closing the Search Modal

  • Modal can be closed by clicking outside, pressing escape, or selecting a result.
  • closeModal hides the modal and clears search, managing focus return for accessibility.

7. Additional Utility Functions

  • Functions like getByteByBinary and substringByByte handle string processing for non-ASCII characters.

Accessibility

Several steps have been taken to ensure accessibility:

  1. Semantic HTML: The search modal uses semantic HTML elements, which aids in conveying the structure and purpose to assistive technologies.

  2. ARIA attributes: Extensive use of ARIA attributes, such as aria-labelledby, aria-hidden, aria-expanded, aria-controls, and aria-activedescendant, provide additional context, making the modal more accessible.

  3. Keyboard navigation: Implemented keyboard navigation within the search modal, allowing users to navigate and interact using the keyboard alone.

  4. Screen reader compatibility: The role attributes and ARIA labels enhance compatibility with screen readers, offering a better experience for visually impaired users.

  5. Colour contrast: Uses the same CSS variables as the rest of tabi, ensuring proper contrast.

  6. Focus keeping: When the search modal opens, focus shifts to the input field, and on closing, it returns to the last focused element before the modal was opened. This prevents keyboard and screen reader users from losing their place in the page.

I have tested this using macOS VoiceOver. @Almost-Senseless-Coder has stress-tested the accessibility features.

Video

Using keyboard navigation.

search demo

Type of change

  • Bug fix (fixes an issue without altering functionality)
  • New feature (adds non-breaking functionality)
  • Breaking change (alters existing functionality)
  • UI/UX improvement (enhances user interface without altering functionality)
  • Refactor (improves code quality without altering functionality)
  • Documentation update
  • Other (please describe below)

Checklist

  • I have verified the accessibility of my changes
  • I have tested all possible scenarios for this change — I haven't tested very large sites or Chinese/Japanese search. It should work, though.
  • I have updated theme.toml with a sane default for the feature
  • I have made corresponding changes to the documentation:
    • Updated config.toml comments
    • Updated theme.toml comments
    • Updated "Mastering tabi" post in English
    • (Optional) Updated "Mastering tabi" post in Spanish
    • (Optional) Updated "Mastering tabi" post in Catalan

Acknowledgements

@welpo welpo added the enhancement New feature or request label Jan 7, 2024
@welpo welpo merged commit 906bc9d into main Jan 8, 2024
1 check passed
@welpo welpo deleted the feat/search branch January 8, 2024 00:00
Smtbook pushed a commit to Smtbook/zola-theme-tabi that referenced this pull request Feb 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Integration of search functionality
1 participant