From ecd353f76d32ea01356bb4ea8c868dc89a001ef9 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Sat, 17 Apr 2021 22:33:48 +0000 Subject: [PATCH 1/5] chore(deps): update dependency @algolia/autocomplete-js to v1.0.0-alpha.45 --- frontend/package.json | 2 +- yarn.lock | 36 ++++++++++++------------------------ 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 82a6af0c1..fe726b5e3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,7 +18,7 @@ "postinstall": "[ -d dist/ ] || npm run build" }, "devDependencies": { - "@algolia/autocomplete-js": "1.0.0-alpha.44", + "@algolia/autocomplete-js": "1.0.0-alpha.45", "@algolia/autocomplete-preset-algolia": "1.0.0-alpha.45", "@algolia/autocomplete-theme-classic": "1.0.0-alpha.45", "@algolia/transporter": "4.8.6", diff --git a/yarn.lock b/yarn.lock index 45940a4e3..2c9ad135b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,30 +2,23 @@ # yarn lockfile v1 -"@algolia/autocomplete-core@1.0.0-alpha.44": - version "1.0.0-alpha.44" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.0.0-alpha.44.tgz#e626dba45f5f3950d6beb0ab055395ef0f7e8bb2" - integrity sha512-2iMXthldMIDXtlbg9omRKLgg1bLo2ZzINAEqwhNjUeyj1ceEyL1ck6FY0VnJpf2LsjmNthHCz2BuFk+nYUeDNA== +"@algolia/autocomplete-core@1.0.0-alpha.45": + version "1.0.0-alpha.45" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.0.0-alpha.45.tgz#424f8e2cfca6c4c3682fa02ce7d122ae2eb0f0d1" + integrity sha512-Lol3IZSscUmZgkrq6DCcvImj1YW4NNHr8IkcARHTDsJvKo+G+mu7LrBLjUD/XEQZy2MAE0JbxrkShecdEpdjTw== dependencies: - "@algolia/autocomplete-shared" "1.0.0-alpha.44" + "@algolia/autocomplete-shared" "1.0.0-alpha.45" -"@algolia/autocomplete-js@1.0.0-alpha.44": - version "1.0.0-alpha.44" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-js/-/autocomplete-js-1.0.0-alpha.44.tgz#a252bdbf7ab662dedcc05cfe53e318d6becd7bee" - integrity sha512-KmWhIvO/T5yS+kelZQrVMgAGKZKozoFHQM8VMrXK3a77i1uqTYFkg70HFIsiQ9kRGjB/EA0exNtm3/BwGkIIkw== +"@algolia/autocomplete-js@1.0.0-alpha.45": + version "1.0.0-alpha.45" + resolved "https://registry.yarnpkg.com/@algolia/autocomplete-js/-/autocomplete-js-1.0.0-alpha.45.tgz#b3835cbec368438f37637f065a11b375a92e300f" + integrity sha512-HAN3HzIstVGoL+ghtXtbg0i81Wn6rXag+CCdmniUuPIVTxsGLeSu4DK6AkZRpxoR8ozW+OeUj7tMnjziUZdhqw== dependencies: - "@algolia/autocomplete-core" "1.0.0-alpha.44" - "@algolia/autocomplete-preset-algolia" "1.0.0-alpha.44" - "@algolia/autocomplete-shared" "1.0.0-alpha.44" + "@algolia/autocomplete-core" "1.0.0-alpha.45" + "@algolia/autocomplete-preset-algolia" "1.0.0-alpha.45" + "@algolia/autocomplete-shared" "1.0.0-alpha.45" preact "^10.0.0" -"@algolia/autocomplete-preset-algolia@1.0.0-alpha.44": - version "1.0.0-alpha.44" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.0.0-alpha.44.tgz#0ea0b255d0be10fbe262e281472dd6e4619b62ba" - integrity sha512-DCHwo5ovzg9k2ejUolGNTLFnIA7GpsrkbNJTy1sFbMnYfBmeK8egZPZnEl7lBTr27OaZu7IkWpTepLVSztZyng== - dependencies: - "@algolia/autocomplete-shared" "1.0.0-alpha.44" - "@algolia/autocomplete-preset-algolia@1.0.0-alpha.45": version "1.0.0-alpha.45" resolved "https://registry.yarnpkg.com/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.0.0-alpha.45.tgz#da23c1cc799893a58b23726508080a9a3f845b0e" @@ -33,11 +26,6 @@ dependencies: "@algolia/autocomplete-shared" "1.0.0-alpha.45" -"@algolia/autocomplete-shared@1.0.0-alpha.44": - version "1.0.0-alpha.44" - resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.0.0-alpha.44.tgz#db13902ad1667e455711b77d08cae1a0feafaa48" - integrity sha512-2oQZPERYV+yNx/yoVWYjZZdOqsitJ5dfxXJjL18yczOXH6ujnsq+DTczSrX+RjzjQdVeJ1UAG053EJQF/FOiMg== - "@algolia/autocomplete-shared@1.0.0-alpha.45": version "1.0.0-alpha.45" resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.0.0-alpha.45.tgz#3540dbc31f3e6f0e976409d568939783d18b948e" From fca41b6f40db39e81cd34d2e35f02142837915c0 Mon Sep 17 00:00:00 2001 From: Sylvain Bellone Date: Mon, 19 Apr 2021 16:14:30 +0200 Subject: [PATCH 2/5] use new Component API to render elements --- .eslintrc.js | 2 + frontend/src/AutocompleteWrapper.ts | 66 ++------------------- frontend/src/templates.tsx | 92 +++++++++++++++++++++-------- frontend/src/types/record.ts | 3 - 4 files changed, 72 insertions(+), 91 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 4842d7c2f..69c66fccc 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -27,6 +27,8 @@ module.exports = { 'no-console': 'off', 'no-continue': 'off', 'no-loop-func': 'off', + // eslint-disable-next-line no-warning-comments + 'no-undef': 'off', // TODO: find how to remove "ESLint: 'JSX' is not defined." errors properly 'consistent-return': 'off', '@typescript-eslint/no-unused-vars': 'warn', diff --git a/frontend/src/AutocompleteWrapper.ts b/frontend/src/AutocompleteWrapper.ts index c1948bb85..1c1de2e35 100644 --- a/frontend/src/AutocompleteWrapper.ts +++ b/frontend/src/AutocompleteWrapper.ts @@ -1,17 +1,11 @@ -import { - autocomplete, - highlightHit, - snippetHit, -} from '@algolia/autocomplete-js'; +import { autocomplete } from '@algolia/autocomplete-js'; import type { - VNode, AutocompleteApi, AutocompleteSource, SourceTemplates, } from '@algolia/autocomplete-js'; import type { HighlightedHit } from '@algolia/autocomplete-preset-algolia'; import { getAlgoliaHits } from '@algolia/autocomplete-preset-algolia'; -import type { Hit } from '@algolia/client-search'; import algoliasearch from 'algoliasearch/lite'; import type { SearchClient } from 'algoliasearch/lite'; @@ -19,7 +13,7 @@ import type { SearchClient } from 'algoliasearch/lite'; import { version } from '../package.json'; import { templates } from './templates'; -import type { Options, AlgoliaRecord, HighlightedHierarchy } from './types'; +import type { Options, AlgoliaRecord } from './types'; class AutocompleteWrapper { private options; @@ -94,13 +88,8 @@ class AutocompleteWrapper { header() { return ''; }, - item({ item }) { - return templates.item( - item, - highlightHit({ hit: item, attribute: 'title' }), - getSuggestionSnippet(item), - getHighlightedHierarchy(item) - ); + item({ item, components }) { + return templates.item(item, components); }, footer() { if (poweredBy) { @@ -155,53 +144,6 @@ class AutocompleteWrapper { } } -function getSuggestionSnippet(hit: Hit): Array { - // If they are defined as `searchableAttributes`, 'description' and 'content' are always - // present in the `_snippetResult`, even if they don't match. - // So we need to have 1 check on the presence and 1 check on the match - const description = hit._snippetResult?.description; - const content = hit._snippetResult?.content; - - // Take in priority props that matches the search - if (description && description.matchLevel === 'full') { - return snippetHit({ hit, attribute: 'description' }); - } - if (content && content.matchLevel === 'full') { - return snippetHit({ hit, attribute: 'content' }); - } - - // Otherwise take the prop that was at least correctly returned - if (description && !content) { - return snippetHit({ hit, attribute: 'description' }); - } - if (content) { - return snippetHit({ hit, attribute: 'content' }); - } - - // Otherwise raw value or empty - const res = hit.description || hit.content || ''; - return [res]; -} - -function getHighlightedHierarchy( - hit: Hit -): HighlightedHierarchy | null { - if (!hit.hierarchy) { - return null; - } - const highlightedHierarchy: HighlightedHierarchy = {}; - for (let i = 0; i <= 6; ++i) { - if (!hit.hierarchy[`lvl${i}`]) { - continue; - } - highlightedHierarchy[`lvl${i}`] = highlightHit({ - hit, - attribute: ['hierarchy', `lvl${i}`], - }); - } - return highlightedHierarchy; -} - function addCss( css: string, $mainStyle: HTMLElement | null = null diff --git a/frontend/src/templates.tsx b/frontend/src/templates.tsx index ca30a46c7..07c08c9d7 100644 --- a/frontend/src/templates.tsx +++ b/frontend/src/templates.tsx @@ -1,6 +1,7 @@ -import type { VNode } from '@algolia/autocomplete-js'; +import type { AutocompleteComponents, VNode } from '@algolia/autocomplete-js'; +import type { Hit } from '@algolia/client-search'; -import type { AlgoliaRecord, HighlightedHierarchy } from './types'; +import type { AlgoliaRecord } from './types'; export const templates = { poweredBy: ({ hostname }: { hostname: string }): VNode => { @@ -19,13 +20,11 @@ export const templates = { }, item: ( - record: AlgoliaRecord, - title: Array, - description: Array, - hierarchy: HighlightedHierarchy | null - ): VNode => { + hit: AlgoliaRecord, + components: AutocompleteComponents + ): JSX.Element => { return ( - +
@@ -39,15 +38,19 @@ export const templates = {
-
{hierarchy?.lvl0 ?? title}
- {hierarchy && ( +
+ {hit.hierarchy?.lvl0 ?? ( + + )} +
+ {hit.hierarchy && (
- {hierarchyToBreadcrumbVNodes(hierarchy)} + {hierarchyToBreadcrumbs(hit, components)}
)} - {description && ( -
{description}
- )} +
+ {getSuggestionSnippet(hit, components)} +
@@ -56,26 +59,63 @@ export const templates = { }; /** - * Transform a highlighted hierarchy object into an array of VNode[]. + * Transform a highlighted hierarchy object into an array of Highlighted elements. * 3 levels max are returned. * - * @param hierarchy - An highlighted hierarchy, i.e. { lvl0: (string | VNode)[], lvl1: (string | VNode)[], lvl2: (string | VNode)[], ... }. - * @returns An array of VNode[], representing of the highlighted hierarchy starting from lvl1. - * Between each VNode[] we insert a ' > ' character to render them as breadcrumbs eventually. + * @param hit - A record with a hierarchy field ( { lvl0: string, lvl1: string, lvl2: string, ... } ). + * @param components - Autocomplete components. + * @returns An array of JSX.Elements | string, representing of the highlighted hierarchy starting from lvl1. + * Between each element, we insert a ' > ' character to render them as breadcrumbs eventually. */ -function hierarchyToBreadcrumbVNodes( - hierarchy: HighlightedHierarchy -): Array> { - const breadcrumbVNodeArray: Array> = []; +function hierarchyToBreadcrumbs( + hit: Hit, + components: AutocompleteComponents +): Array { + const breadcrumbArray: Array = []; let addedLevels = 0; + if (!hit.hierarchy) { + return breadcrumbArray; + } for (let i = 1; i < 7 && addedLevels < 3; ++i) { - if (hierarchy[`lvl${i}`] && hierarchy[`lvl${i}`].length > 0) { + if (hit.hierarchy[`lvl${i}`] && hit.hierarchy[`lvl${i}`].length > 0) { if (addedLevels > 0) { - breadcrumbVNodeArray.push(' > '); + breadcrumbArray.push(' > '); } - breadcrumbVNodeArray.push(hierarchy[`lvl${i}`]); + breadcrumbArray.push( + + ); ++addedLevels; } } - return breadcrumbVNodeArray; + return breadcrumbArray; +} + +function getSuggestionSnippet( + hit: Hit, + components: AutocompleteComponents +): JSX.Element | string { + // If they are defined as `searchableAttributes`, 'description' and 'content' are always + // present in the `_snippetResult`, even if they don't match. + // So we need to have 1 check on the presence and 1 check on the match + const description = hit._snippetResult?.description; + const content = hit._snippetResult?.content; + + // Take in priority props that matches the search + if (description && description.matchLevel === 'full') { + return ; + } + if (content && content.matchLevel === 'full') { + return ; + } + + // Otherwise take the prop that was at least correctly returned + if (description && !content) { + return ; + } + if (content) { + return ; + } + + // Otherwise raw value or empty + return hit.description || hit.content || ''; } diff --git a/frontend/src/types/record.ts b/frontend/src/types/record.ts index 3834b5a70..e44a59b20 100644 --- a/frontend/src/types/record.ts +++ b/frontend/src/types/record.ts @@ -1,5 +1,3 @@ -import type { VNode } from '@algolia/autocomplete-js'; - export type AlgoliaRecord = { objectID: string; @@ -25,4 +23,3 @@ export type AlgoliaRecord = { }; export type Hierarchy = { [lvl: string]: string }; -export type HighlightedHierarchy = { [lvl: string]: Array }; From b79626dbfd5dfaf001635ba1fb5cd6d7a6b02e4b Mon Sep 17 00:00:00 2001 From: Sylvain Bellone Date: Mon, 19 Apr 2021 16:36:21 +0200 Subject: [PATCH 3/5] eslint no-undef: warn instead of disabled --- .eslintrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 69c66fccc..364891a95 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -28,7 +28,7 @@ module.exports = { 'no-continue': 'off', 'no-loop-func': 'off', // eslint-disable-next-line no-warning-comments - 'no-undef': 'off', // TODO: find how to remove "ESLint: 'JSX' is not defined." errors properly + 'no-undef': 'warn', // TODO: find how to remove "ESLint: 'JSX' is not defined." errors properly 'consistent-return': 'off', '@typescript-eslint/no-unused-vars': 'warn', From 9b25499dea27247f9d4639d4bf0acb9e0a4c875e Mon Sep 17 00:00:00 2001 From: Sylvain Bellone Date: Mon, 19 Apr 2021 18:44:19 +0200 Subject: [PATCH 4/5] fix theme changes --- frontend/src/index.scss | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/index.scss b/frontend/src/index.scss index 0287d6859..37010d53f 100644 --- a/frontend/src/index.scss +++ b/frontend/src/index.scss @@ -40,12 +40,9 @@ $font-size: $font-size-m; .aa-Panel { min-width: 350px; z-index: 1100; + margin-top: $size-xs; - &::after { - background-image: none; - } .aa-PanelLayout { - margin-top: $size-xs; padding-top: 0; padding-bottom: 0; background-color: var(--color-background); @@ -54,6 +51,10 @@ $font-size: $font-size-m; border-left: solid 1px var(--color-selected); } } + + .aa-GradientBottom { + background-image: none; + } } .aa-Autocomplete, .aa-DetachedFormContainer { From 29ff71a1e86c062f6fe66160328937105a07cb11 Mon Sep 17 00:00:00 2001 From: Sylvain Bellone Date: Tue, 20 Apr 2021 18:20:33 +0200 Subject: [PATCH 5/5] fix clearButton CSS and set small input with debug:true --- frontend/src/index.scss | 4 ++++ public/index.html | 1 + 2 files changed, 5 insertions(+) diff --git a/frontend/src/index.scss b/frontend/src/index.scss index 37010d53f..84e168d89 100644 --- a/frontend/src/index.scss +++ b/frontend/src/index.scss @@ -88,7 +88,11 @@ $font-size: $font-size-m; } } .aa-InputWrapperSuffix { + height: var(--height); + .aa-ClearButton { + padding: 0; + &:hover, &:focus { color: var(--color-text); diff --git a/public/index.html b/public/index.html index 56aced30e..ad4406d19 100644 --- a/public/index.html +++ b/public/index.html @@ -179,6 +179,7 @@

Test content

colorSourceIcon: '#d6d6e7' }, detached: { mediaQuery: '(max-width: 900px)' }, + debug: true, });` .split('\n') .map((l) => l.replace(/^\s{8}/, ''))