From b705b488b04522a0d21da989015c40461f120c6e Mon Sep 17 00:00:00 2001 From: "(quasar) nebula" Date: Tue, 30 Apr 2024 21:01:36 -0300 Subject: client: search results behavior stub --- .../dependencies/generateSearchSidebarBox.js | 2 +- src/search.js | 11 ++ src/static/css/site.css | 39 +++++- src/static/js/client.js | 136 +++++++++++++++++++++ src/util/searchSchema.js | 33 +++-- 5 files changed, 209 insertions(+), 12 deletions(-) diff --git a/src/content/dependencies/generateSearchSidebarBox.js b/src/content/dependencies/generateSearchSidebarBox.js index f2fddfa5..6632a4e8 100644 --- a/src/content/dependencies/generateSearchSidebarBox.js +++ b/src/content/dependencies/generateSearchSidebarBox.js @@ -9,7 +9,7 @@ export default { generate: (relations, {html}) => relations.sidebarBox.slots({ - attributes: {class: 'search-sidebar-box'}, + attributes: {class: 'wiki-search-sidebar-box'}, collapsible: false, content: [ diff --git a/src/search.js b/src/search.js index b82a77b8..34718b5c 100644 --- a/src/search.js +++ b/src/search.js @@ -70,12 +70,23 @@ async function populateSearchIndexes(indexes, wikiData) { indexes.tracks, track => ({ name: track.name, + color: track.color, album: track.album.name, + albumDirectory: track.album.directory, + artists: [ track.artistContribs.map(contrib => contrib.artist.name), ...track.artistContribs.map(contrib => contrib.artist.aliasNames) ].flat(), + additionalNames: track.additionalNames.map(entry => entry.name), + + artworkKind: + (track.hasUniqueCoverArt + ? 'track' + : track.album.hasCoverArt + ? 'album' + : 'none'), }) ); diff --git a/src/static/css/site.css b/src/static/css/site.css index 2dc06469..d2c121e6 100644 --- a/src/static/css/site.css +++ b/src/static/css/site.css @@ -462,7 +462,7 @@ summary .group-name { font-weight: normal; } -.search-sidebar-box { +.wiki-search-sidebar-box { padding: 2px; position: sticky; top: 5px; @@ -490,6 +490,43 @@ summary .group-name { color: inherit; } +.wiki-search-results-container hr { + border-color: var(--primary-color); + border-style: none none dotted none; +} + +.wiki-search-results-container { + margin-bottom: 5px; +} + +.wiki-search-result { + display: flex; + padding: 0 6px; + margin: 3px 0 5px 0; +} + +.wiki-search-result-name { + align-self: center; + flex-grow: 1; + padding-bottom: 2px; +} + +.wiki-search-result-image, +.wiki-search-result-image-placeholder { + align-self: flex-start; + width: 1.8em; + height: 1.8em; + margin-right: 6px; +} + +.wiki-search-result-image-placeholder { + display: inline-block; +} + +.wiki-search-results:not(:has(.wiki-search-result-image)) .wiki-search-result-image-placeholder { + display: none; +} + .wiki-search-input:focus { border: 1px solid var(--primary-color); } diff --git a/src/static/js/client.js b/src/static/js/client.js index a3d63719..0a4dc0ff 100644 --- a/src/static/js/client.js +++ b/src/static/js/client.js @@ -3456,6 +3456,142 @@ document.addEventListener('DOMContentLoaded', initSearch); window.searchAll = searchAll; +// Sidebar search box ------------------------------------- + +const sidebarSearchInfo = initInfo('sidebarSearchInfo', { + searchBox: null, + searchInput: null, + + resultsContainer: null, + results: null, +}); + +function getSidebarSearchReferences() { + const info = sidebarSearchInfo; + + info.searchBox = + document.querySelector('.wiki-search-sidebar-box'); + + info.searchInput = + document.querySelector('.wiki-search-input'); +} + +function mutateSidebarSearchContent() { + const info = sidebarSearchInfo; + + if (!info.searchBox) return; + + info.resultsContainer = + document.createElement('div'); + + info.resultsContainer.classList.add('wiki-search-results-container'); + + cssProp(info.resultsContainer, 'display', 'none'); + info.resultsContainer.appendChild(document.createElement('hr')); + + info.results = + document.createElement('div'); + + info.results.classList.add('wiki-search-results'); + + info.resultsContainer.appendChild(info.results); + + info.searchBox.appendChild(info.resultsContainer); +} + +function addSidebarSearchListeners() { + const info = sidebarSearchInfo; + + if (!info.searchInput) return; + + info.searchInput.addEventListener('change', domEvent => { + activateSidebarSearch(info.searchInput.value); + }); +} + +function activateSidebarSearch(query) { + showSidebarSearchResults(searchAll(query, {enrich: true})); +} + +function showSidebarSearchResults(results) { + const info = sidebarSearchInfo; + + const flatResults = + Object.entries(results) + .flatMap(([index, results]) => results + .flatMap(({field, result}) => result + .flatMap(({doc, id}) => ({ + index, + field, + reference: id ?? null, + directory: (id ? id.split(':')[1] : null), + data: doc, + })))); + + console.log(flatResults); + + while (info.results.firstChild) { + info.results.firstChild.remove(); + } + + cssProp(info.resultsContainer, 'display', 'block'); + + for (const result of flatResults) { + if (result.index !== 'tracks') continue; + + const link = document.createElement('a'); + link.classList.add('wiki-search-result'); + + link.setAttribute('href', openTrack(result.directory)); + cssProp(link, '--primary-color', result.data.color); + + const span = document.createElement('span'); + span.classList.add('wiki-search-result-name'); + + span.appendChild(document.createTextNode(result.data.name)); + + let image; + image = document.createElement('img'); + image.classList.add('wiki-search-result-image'); + + switch (result.data.artworkKind) { + case 'track': + image.setAttribute('src', rebase( + (`album-art` + + `/${result.data.albumDirectory}` + + `/${result.directory}` + + `.small.jpg`), + 'rebaseThumb')); + break; + + case 'album': + image.setAttribute('src', rebase( + (`album-art` + + `/${result.data.albumDirectory}` + + `/cover.small.jpg`), + 'rebaseThumb')); + break; + + default: + image = document.createElement('span'); + image.classList.add('wiki-search-result-image-placeholder'); + break; + } + + if (image) { + link.appendChild(image); + } + + link.appendChild(span); + + info.results.appendChild(link); + } +} + +clientSteps.getPageReferences.push(getSidebarSearchReferences); +clientSteps.mutatePageContent.push(mutateSidebarSearchContent); +clientSteps.addPageListeners.push(addSidebarSearchListeners); + // Sticky commentary sidebar ------------------------------ const albumCommentarySidebarInfo = initInfo('albumCommentarySidebarInfo', { diff --git a/src/util/searchSchema.js b/src/util/searchSchema.js index ce0e7a84..1628dbd4 100644 --- a/src/util/searchSchema.js +++ b/src/util/searchSchema.js @@ -3,28 +3,41 @@ export function makeSearchIndexes(FlexSearch) { const indexes = { albums: new FlexSearch.Document({ - id: "reference", - index: ["name", "groups"], + id: 'reference', + index: ['name', 'groups'], }), tracks: new FlexSearch.Document({ - id: "reference", - index: ["name", "album", "artists", "additionalNames"], + id: 'reference', + + index: [ + 'name', + 'album', + 'artists', + 'additionalNames', + ], + + store: [ + 'color', + 'name', + 'albumDirectory', + 'artworkKind', + ], }), artists: new FlexSearch.Document({ - id: "reference", - index: ["names"], + id: 'reference', + index: ['names'], }), groups: new FlexSearch.Document({ - id: "reference", - index: ["name", "description", "category"], + id: 'reference', + index: ['name', 'description', 'category'], }), flashes: new FlexSearch.Document({ - id: "reference", - index: ["name", "tracks", "contributors"], + id: 'reference', + index: ['name', 'tracks', 'contributors'], }), }; -- cgit 1.3.0-6-gf8a5