Changelog ccdc7d6
better search ux
3 files of code, design or docs +38 −20 lines
Code, design and documents 3 files
source-archive.json +26 −14
Not shown: a picture, a generated file, or past the length shown per change.
src/layouts/Base.astro +10 −6
@@ -85,5 +85,6 @@ const schemas = jsonld ? [jsonld].flat() : []; </form> <ol class="search-results" id="searchResults" role="listbox"></ol> - <p class="search-hint" id="searchHint">Type a country, a year or a few words. <span><kbd>↑</kbd><kbd>↓</kbd> to move, <kbd>↵</kbd> to open.</span></p> + <p class="search-none" id="searchNone" hidden></p> + <p class="search-hint" id="searchHint"><span id="searchCount" aria-live="polite"></span> <span><kbd>↑</kbd><kbd>↓</kbd> to move, <kbd>↵</kbd> to open.</span></p> </dialog> @@ -105,5 +106,5 @@ const schemas = jsonld ? [jsonld].flat() : []; (function () { var dialog = document.getElementById("siteSearch"), input = document.getElementById("searchInput"); - var list = document.getElementById("searchResults"), hint = document.getElementById("searchHint"); + var list = document.getElementById("searchResults"), hint = document.getElementById("searchHint"), none = document.getElementById("searchNone"), count = document.getElementById("searchCount"); var rows = null, fuse = null, loading = null, shown = [], active = 0; var KIND = { c: "Country", p: "Page", a: "Article", h: "History" }, ORDER = { c: 0, p: 1, a: 2, h: 3 }; @@ -116,16 +117,19 @@ const schemas = jsonld ? [jsonld].flat() : []; fuse = new got[1](rows, { keys: [{ name: "k", weight: 2 }, { name: "h", weight: 1 }], useExtendedSearch: true, ignoreLocation: true, threshold: 0.3, minMatchCharLength: 2, includeScore: true }); render(); - }).catch(function () { hint.textContent = "The search index could not be loaded."; }); + }).catch(function () { none.textContent = "The search index could not be loaded."; none.hidden = false; }); return loading; } function render() { var words = fold(input.value).split(/\s+/).filter(Boolean); - if (!fuse || !words.length) { shown = []; list.innerHTML = ""; hint.hidden = false; return; } + if (!fuse || !words.length) { shown = []; list.innerHTML = ""; count.textContent = ""; if (fuse) none.hidden = true; return; } // In Fuse's extended search, words separated by spaces must all match (each one fuzzily). var q = words.join(" "); function rank(x) { var r = x.item; return x.score + ORDER[r.t] * 0.05 + (r.k === q ? -1 : r.k.indexOf(q) === 0 ? -0.5 : 0); } var found = fuse.search(q).sort(function (a, b) { return rank(a) - rank(b) || a.item.i - b.item.i; }); - shown = found.slice(0, 40).map(function (x) { return x.item; }); active = 0; hint.hidden = shown.length > 0; - if (!shown.length) hint.textContent = "Nothing found for “" + input.value + "”."; + shown = found.slice(0, 40).map(function (x) { return x.item; }); active = 0; + // the line under the box appears only when a search comes back empty; the key hints stay put + none.hidden = shown.length > 0; + count.textContent = !found.length ? "" : found.length > shown.length ? "First " + shown.length + " of " + found.length + " results" : found.length + (found.length === 1 ? " result" : " results"); + if (!shown.length) none.textContent = "Nothing found for “" + input.value + "”."; list.innerHTML = shown.map(function (r, i) { return '<li role="option" id="sr' + i + '"' + (i === 0 ? ' aria-selected="true"' : "") + '><a href="' + esc(dialog.dataset.base + r.u) + '" tabindex="-1">' +
src/styles/global.css +2 −0
@@ -1316,3 +1316,5 @@ details.segrow .segrow-top > span, .segrow:not(details) .segrow-top > span { fon .search-hint { margin: 0; padding: 14px 16px; color: var(--muted); font-size: 13px; display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; } .search-hint kbd { margin-right: 3px; } +.search-none { margin: 0; padding: 22px 16px; color: var(--text-2); font-size: 14px; border-bottom: 1px solid var(--border); } +.search-none[hidden] { display: none; } .topbar .search-btn { margin-right: -12px; }