welpo / tabi

A modern Zola theme with search, multilingual support, optional JavaScript, a perfect Lighthouse score, and a focus on accessibility.
https://welpo.github.io/tabi/
MIT License
127 stars 38 forks source link

Integration of search functionality #190

Closed Almost-Senseless-Coder closed 10 months ago

Almost-Senseless-Coder commented 1 year ago

Feature Request

Summary

As tabi's documentation grows, including a search feature may be helpful. Tags, the archive, and the post listing are good, but may not be sufficient if the user looks for something specific.

Motivation

Zola already natively supports generating a search index and also already offers a search implementation. Personally, I don't like the implementation much - it could use some accessibility improvements - but it is good enough® in case Tabi wants to copy it. Then again, maybe offering a better representation of search results could be another benefit of Tabi.

Detailed Description

The search feature could getimplemented in two ways:

Either way, we'll need a search input and possibly a button to trigger the search, as well as a format how to display search results in an easy-to-navigate and useful fashion.

I can't really judge the visual aspects of Zola's search functionality, but at least to me it's not ideal the way it gets handled, as the dynamic generation of the search results impedes navigation of the page, they get just inserted at the top of the page, there's no obvious way to close them (apart from clearing the search input) and the search result structure isn't intuitive to a screen reader user.

welpo commented 1 year ago

I do feel like search is the one big feature that tabi is currently lacking.

To be honest, though, when I think of adding it, I get a bit overwhelmed. I feel like it's going to be a huge undertaking.

Anyway, I definitely think tabi would benefit from a search feature (both to search for docs and to provide this feature to sites using tabi).

I have not looked into it at all yet, but, to try and find a good reference, how's the accessibility/experience for these two search options?

If you have examples of good search experiences on other blog-like sites, that'd be great to have.

Almost-Senseless-Coder commented 1 year ago

The first is actually surprisingly accessible, the icon has an aria-label apparently. The only beef I have with it is that I can't close it on mobile, since it asks me to hit ESC. That's something minor though which we could easily fix on Tabi.

Question, though: Does it look like a modal dialog to you (i.e., a popup window which prevents interaction with the rest of the page until closed)? If so, it needs some redesigning and a few extra ARIA attributes, but that's manageable; I've written quite a few modal dialogs by now, so I'll gladly help with that.

The second one is straight forward and no fuss, works like a charm. Downside is that it only works in the blog section, so it wouldn't find, for instance, both projects and blog posts matching the search query. Whether that's a bug or a feature is debatable.

welpo commented 1 year ago

Does it look like a modal dialog to you (i.e., a popup window which prevents interaction with the rest of the page until closed)?

Indeed. Happy to hear it's accessible and that you could help with the modal dialog part!

You're right about the limitation regarding the second one (not being able to search on non-blog posts).

Definitely saving the first one as a reference, then! We'll see when I can muster up the courage to start working on this, though!

Almost-Senseless-Coder commented 1 year ago

At the risk of being unduly optimistic, thus triggering the wrath of the code gods...

I think most of the pieces are already available: Zola has build_search_index setting, the code for Zola's search interface is publicly available and https://github.com/weixsong/lunr-languages#in-a-web-browser contains the tools we need to search in languages other than English.

Combine that with the fact we can fine tune Zola's indexing behaviour in the [search] section of the config.toml and that we already know what we want the interface to look like an.... Well, as I said - personally I think the pieces are there. They "just" need to get put together.

I'll see if I can make some progress in that regard this weekend. No promises though! ^^

welpo commented 1 year ago

I like your optimism! Yeah, it's just about putting it all together.

One more piece: the search bar we both like is kbar, a "simple plug-n-play React component".

I don't know enough about React to calibrate how feasible it would be to turn that into normal JS to use in tabi/Zola. I'll ask my React-master friend.

Almost-Senseless-Coder commented 1 year ago

That should be pretty difficult. React components make assumptions about a website's structure, provide contexts, etc. That's not a concept you can easily replicate in vanilla JS (it is possible, but requires a complete rewrite of the code).

That said, I'm not sure if we even need kbar. Its primry purpose is to provide cmd+k functionality on a website, i.e., show a command menu when the user hits cmd+k.

That could be neat for tabi, obviously - having the language picker, light/dark mode toggle, search etc. all available from that menu - but I don't think it's really necessary, given Tabi only has 5 actions if you count the quick navigation buttons and hypothetical search feature.

Bottom line of this is: I personally wouldn't worry about kbar and just implement the search feature without it.

welpo commented 1 year ago

Yeah, my friend agrees with you.

He sent me this similar project which does use vanilla JS: https://github.com/ssleptsov/ninja-keys

It doesn't implement site search, as it's focused on commands for the site (like switching theme and all), which I'm not interested in. However, at the end of the day, it's a matter of changing what we search over (commands or pages).

The modal behaviour is almost identical to that of kbar, so that's another reference.

Almost-Senseless-Coder commented 1 year ago

That's easy enough to integrate.

I imagine that we check for build_search_index being present and set to trueto determine whether our users want to integrate search into the website. Then we do the actual filtering using search.js provided by Zola and populate the data variable of ninja keys with the result, rather than displaying the result in the page.

I'll see if I can get that implemented already during the weekend. If I make headway in that regard, I'll dush it to the fork.

Almost-Senseless-Coder commented 1 year ago

I've hit the first road block.

To enable searching, I need to include a file of the format lunr.<lang>.min.js, where <lang> may or may not exist - for instance lunr.es.min.js does exist, but lunr.ca.min.js does not.

The problem is that there apparently is no function to check whether a file exists, neither in tera, nor in zola. There isn't even a function to check a file's metadata (I thought of querying the file size as a hack, using the value 0 as "doesn't exist or in any rate isn't relevant").

Zola does generate "language aware" paths, sure, but this doesn't help me here. I could just include every lunrfile available and link to them all, swapping them out dynamically as needed in the JS, but that would grow Tabi's code footprint both sigificantly and unnecessarily.

Any ideas?

Almost-Senseless-Coder commented 1 year ago

The only workaround I've found is hard-coding all supported lunr locales, then mapping the lang and default_language against that list.

It requires including all lunr files in Tabi, but they will only get loaded as needed. So it grows the repo size, but not the ultimate size of the code that needs to get loaded by the visitors.

welpo commented 1 year ago

I've checked if a file exists for multilingual support with the load_data function, like this:

{# Check if the translated page or section exists #}
{%- set translation_exists = load_data(path=translated_filename, required=false) -%}

{# Get the page or section details #}
{%- if translation_exists -%}
    {%- if page.relative_path -%}
        {%- set translated_page = get_page(path=translated_filename, metadata_only=true) -%}
    {%- else -%}
        {%- set translated_page = get_section(path=translated_filename, metadata_only=true) -%}
    {%- endif -%}
{%- endif -%}
welpo commented 1 year ago

In context: https://github.com/welpo/tabi/blob/main/templates/partials/multilingual_tags.html

Almost-Senseless-Coder commented 1 year ago

I'm afraid there's a problem. load_data does not accept files of type js, and therefore always returns false/null.

Almost-Senseless-Coder commented 1 year ago

I've pushed the current version of the code to my fork of tabi, branch issue_#190. Maybe you can figure out a fix. As it stands, it imports the resources for default languages correctly - and default languages only.

welpo commented 1 year ago

Thanks so much!

I've taken a brief look, and noticed the Tera template tries to load the js files as search_index.' ~ language ~ '.min.js', but the .min part is not there, so it can't find the files.

More importantly, I'll take a look at the multilanguage part tomorrow. I'm pretty sure Abridge solved this, so I'll explore its codebase.

Jieiku commented 1 year ago

The javascript implementation works for multilingual. but if you are using the json index which is more efficient, then you will have to wait for the next iteration of Zola. I fixed a bug for this.

https://github.com/getzola/zola/issues/2193

https://github.com/getzola/zola/pull/2197

welpo commented 1 year ago

@Jieiku thanks for your input and fixing the Zola issue!

@Almost-Senseless-Coder sorry for the delay. This is how Abridge loads the search: head_js.html.

You wrote:

I could just include every lunrfile available and link to them all, swapping them out dynamically as needed in the JS, but that would grow Tabi's code footprint both sigificantly and unnecessarily.

I think this is fine? Abridge does have a bunch of search files for many languages, most of which aren't in the Abridge demo, check out its js folder. I assume it's necessary to offer this support at the theme level, for all possible languages.

So, in short, answering this point:

It requires including all lunr files in Tabi, but they will only get loaded as needed. So it grows the repo size, but not the ultimate size of the code that needs to get loaded by the visitors.

I think that's fine.