From 3df2c3dcd71cdd7ce2d56e32e78501d1a7ea7bf3 Mon Sep 17 00:00:00 2001 From: Marten Bjork Date: Tue, 5 Jul 2022 11:59:56 +0200 Subject: [PATCH 01/22] Clean up search result types --- .../components/GlobalSearch/GlobalSearch.tsx | 44 +++++--- polaris.shopify.com/src/types.ts | 61 ++++------- polaris.shopify.com/src/utils/search.ts | 103 ++++++++---------- 3 files changed, 91 insertions(+), 117 deletions(-) diff --git a/polaris.shopify.com/src/components/GlobalSearch/GlobalSearch.tsx b/polaris.shopify.com/src/components/GlobalSearch/GlobalSearch.tsx index f30acdbc136..857beac37ca 100644 --- a/polaris.shopify.com/src/components/GlobalSearch/GlobalSearch.tsx +++ b/polaris.shopify.com/src/components/GlobalSearch/GlobalSearch.tsx @@ -60,7 +60,7 @@ function GlobalSearch({}: Props) { if (searchResults) { Object.values(searchResults) - .sort((a, b) => a.maxScore - b.maxScore) + .sort((a, b) => a.topScore - b.topScore) .forEach((group) => { resultsInRenderedOrder = [...resultsInRenderedOrder, ...group.results]; }); @@ -217,7 +217,7 @@ function GlobalSearch({}: Props) { > {searchResults && Object.entries(searchResults) - .sort((a, b) => a[1].maxScore - b[1].maxScore) + .sort((a, b) => a[1].topScore - b[1].topScore) .map(([category]) => { const typedCategory = category as SearchResultCategory; @@ -233,9 +233,12 @@ function GlobalSearch({}: Props) { const { searchResultData } = getItemProps({ resultIndex, }); + if (!result.meta.Foundations) return null; + const { title, excerpt } = + result.meta.Foundations; return (
  • -

    {result.meta.title}

    -

    - {stripMarkdownLinks( - result.meta.excerpt - )} -

    +

    {title}

    +

    {stripMarkdownLinks(excerpt)}

  • @@ -270,13 +269,17 @@ function GlobalSearch({}: Props) { {results.map((result) => { resultIndex++; + if (!result.meta.Components) return null; + const { url } = result; + const { name, description, status } = + result.meta.Components; return ( ); @@ -303,10 +306,12 @@ function GlobalSearch({}: Props) { > {results.map((result) => { resultIndex++; + if (!result.meta.Tokens) return null; + const { token } = result.meta.Tokens; return ( ); @@ -324,10 +329,13 @@ function GlobalSearch({}: Props) { {results.map((result) => { resultIndex++; + if (!result.meta.Icons) return null; + const { url } = result; + const { icon } = result.meta.Icons; return ( router.push(result.url)} {...getItemProps({ resultIndex })} /> diff --git a/polaris.shopify.com/src/types.ts b/polaris.shopify.com/src/types.ts index e19de556852..913ab309344 100644 --- a/polaris.shopify.com/src/types.ts +++ b/polaris.shopify.com/src/types.ts @@ -19,53 +19,34 @@ export const searchResultCategories = [ export type SearchResultCategory = typeof searchResultCategories[number]; -interface BaseSearchResult { +export interface SearchResult { + category: SearchResultCategory; url: string; score: number; + meta: Partial<{ + Components: { + name: string; + description: string; + status?: Status; + }; + Foundations: { + title: string; + excerpt: string; + }; + Tokens: { + token: TokenPropertiesWithName; + }; + Icons: { icon: Icon }; + }>; } -export interface FoundationsSearchResult extends BaseSearchResult { - category: "Foundations"; - meta: { - title: string; - excerpt: string; - }; -} - -export interface ComponentsSearchResult extends BaseSearchResult { - category: "Components"; - meta: { - name: string; - description: string; - status?: Status; - }; -} - -export interface TokensSearchResult extends BaseSearchResult { - category: "Tokens"; - meta: { - token: TokenPropertiesWithName; - }; -} - -export interface IconsSearchResult extends BaseSearchResult { - category: "Icons"; - meta: { icon: Icon }; -} - -export type SearchResult = - | FoundationsSearchResult - | ComponentsSearchResult - | TokensSearchResult - | IconsSearchResult; - export type SearchResults = SearchResult[]; export type GroupedSearchResults = { - Foundations: { results: FoundationsSearchResult[]; maxScore: number }; - Components: { results: ComponentsSearchResult[]; maxScore: number }; - Tokens: { results: TokensSearchResult[]; maxScore: number }; - Icons: { results: IconsSearchResult[]; maxScore: number }; + [key in SearchResultCategory]: { + results: SearchResult[]; + topScore: number; + }; }; export type Icon = { diff --git a/polaris.shopify.com/src/utils/search.ts b/polaris.shopify.com/src/utils/search.ts index b7746344e10..87b8df57629 100644 --- a/polaris.shopify.com/src/utils/search.ts +++ b/polaris.shopify.com/src/utils/search.ts @@ -1,11 +1,7 @@ import { - SearchResultCategory, SearchResults, - ComponentsSearchResult, - FoundationsSearchResult, - IconsSearchResult, - TokensSearchResult, GroupedSearchResults, + searchResultCategories, } from "../types"; import { tokens, TokenProperties } from "@shopify/polaris-tokens"; import Fuse from "fuse.js"; @@ -41,9 +37,11 @@ components.forEach(({ frontMatter: { name, status }, intro }) => { score: 0, url: `/components/${slugify(name)}`, meta: { - name, - description: stripMarkdownLinks(intro), - status, + Components: { + name, + description: stripMarkdownLinks(intro), + status, + }, }, }); }); @@ -55,10 +53,12 @@ Object.entries(colorLight).forEach(([tokenName, tokenValue]) => { score: 0, url: `/tokens/colors#${tokenName}`, meta: { - token: { - name: tokenName, - description: tokenValue.description || "", - value: tokenValue.value, + Tokens: { + token: { + name: tokenName, + description: tokenValue.description || "", + value: tokenValue.value, + }, }, }, }); @@ -74,10 +74,12 @@ Object.entries(otherTokenGroups).forEach(([groupSlug, tokenGroup]) => { score: 0, url: `/tokens/${slugify(groupSlug)}#${tokenName}`, meta: { - token: { - name: tokenName, - description: tokenProperties.description || "", - value: tokenProperties.value, + Tokens: { + token: { + name: tokenName, + description: tokenProperties.description || "", + value: tokenProperties.value, + }, }, }, }); @@ -93,7 +95,9 @@ Object.keys(metadata).forEach((fileName) => { url: `/icons?icon=${fileName}`, score: 0, meta: { - icon: { fileName, keywords, name, description, set }, + Icons: { + icon: { fileName, keywords, name, description, set }, + }, }, }); }); @@ -107,8 +111,10 @@ foundations.forEach(({ frontMatter: { name }, intro, section }) => { score: 0, url, meta: { - title: name, - excerpt: intro, + Foundations: { + title: name, + excerpt: intro, + }, }, }); }); @@ -135,10 +141,10 @@ const fuse = new Fuse(results, { export function search(query: string): GroupedSearchResults { const groupedResults: GroupedSearchResults = { - Foundations: { results: [], maxScore: 0 }, - Components: { results: [], maxScore: 0 }, - Tokens: { results: [], maxScore: 0 }, - Icons: { results: [], maxScore: 0 }, + Foundations: { results: [], topScore: 0 }, + Components: { results: [], topScore: 0 }, + Tokens: { results: [], topScore: 0 }, + Icons: { results: [], topScore: 0 }, }; if (query.length > 0) { @@ -149,42 +155,21 @@ export function search(query: string): GroupedSearchResults { score: result.score || 0, })); - groupedResults["Foundations"].results = scoredResults - .filter((result) => result.category === "Foundations") - .map((result) => ({ - ...result, - score: result.score || 0, - })) - .slice(0, MAX_RESULTS["Foundations"]) as FoundationsSearchResult[]; - - groupedResults["Components"].results = scoredResults - .filter((result) => result.category === "Components") - .map((result) => ({ - ...result, - score: result.score || 0, - })) - .slice(0, MAX_RESULTS["Components"]) as ComponentsSearchResult[]; - - groupedResults["Tokens"].results = scoredResults - .filter((result) => result.category === "Tokens") - .map((result) => ({ - ...result, - score: result.score || 0, - })) - .slice(0, MAX_RESULTS["Tokens"]) as TokensSearchResult[]; - - groupedResults["Icons"].results = scoredResults - .filter((result) => result.category === "Icons") - .map((result) => ({ - ...result, - score: result.score || 0, - })) - .slice(0, MAX_RESULTS["Icons"]) as IconsSearchResult[]; - - Object.keys(groupedResults).forEach((category) => { - const typedCategory = category as SearchResultCategory; - groupedResults[typedCategory].maxScore = - groupedResults[typedCategory].results[0]?.score || 0; + searchResultCategories.forEach((category) => { + groupedResults[category].results = scoredResults + .filter((result) => result.category === category) + .map((result) => ({ ...result, score: result.score || 0 })) + .slice(0, MAX_RESULTS[category]); + }); + + searchResultCategories.forEach((category) => { + groupedResults[category] = { + ...groupedResults[category], + topScore: + groupedResults[category].results.length > 0 + ? groupedResults[category].results[0].score + : 0, + }; }); } From 8895190adcd0f72b374b54d1efdf921fa9163028 Mon Sep 17 00:00:00 2001 From: Marten Bjork Date: Tue, 5 Jul 2022 12:08:04 +0200 Subject: [PATCH 02/22] Fix fuse metadata keys --- polaris.shopify.com/src/utils/search.ts | 30 ++++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/polaris.shopify.com/src/utils/search.ts b/polaris.shopify.com/src/utils/search.ts index 87b8df57629..be36cbd7da9 100644 --- a/polaris.shopify.com/src/utils/search.ts +++ b/polaris.shopify.com/src/utils/search.ts @@ -121,17 +121,24 @@ foundations.forEach(({ frontMatter: { name }, intro, section }) => { const fuse = new Fuse(results, { keys: [ - { name: "meta.title", weight: 100 }, - { name: "meta.name", weight: 100 }, - { name: "meta.description", weight: 50 }, - { name: "meta.excerpt", weight: 50 }, - { name: "meta.token.name", weight: 200 }, - // { name: "meta.token.description", weight: 50 }, - { name: "meta.token.value", weight: 50 }, - { name: "meta.icon.fileName", weight: 50 }, - { name: "meta.icon.keywords", weight: 20 }, - { name: "meta.icon.set", weight: 20 }, - // { name: "meta.icon.description", weight: 50 }, + // Foundations + { name: "meta.Foundations.title", weight: 100 }, + { name: "meta.Foundations.excerpt", weight: 50 }, + + // Components + { name: "meta.Components.name", weight: 100 }, + { name: "meta.Components.description", weight: 50 }, + + // Tokens + { name: "meta.Tokens.token.name", weight: 200 }, + { name: "meta.Tokens.token.value", weight: 50 }, + + // Icons + { name: "meta.Icons.icon.fileName", weight: 50 }, + { name: "meta.Icons.icon.name", weight: 50 }, + { name: "meta.Icons.icon.keywords", weight: 20 }, + { name: "meta.Icons.icon.set", weight: 20 }, + { name: "meta.Icons.icon.description", weight: 50 }, ], includeScore: true, threshold: 0.5, @@ -148,6 +155,7 @@ export function search(query: string): GroupedSearchResults { }; if (query.length > 0) { + console.log(results); const fuseResults = fuse.search(query); const scoredResults: SearchResults = fuseResults.map((result) => ({ From e49a075f3bd7532726d5ef64cd231307ecaedcf8 Mon Sep 17 00:00:00 2001 From: Marten Bjork Date: Tue, 5 Jul 2022 12:08:48 +0200 Subject: [PATCH 03/22] Remove console log --- polaris.shopify.com/src/utils/search.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/polaris.shopify.com/src/utils/search.ts b/polaris.shopify.com/src/utils/search.ts index be36cbd7da9..ec4659a0c14 100644 --- a/polaris.shopify.com/src/utils/search.ts +++ b/polaris.shopify.com/src/utils/search.ts @@ -155,7 +155,6 @@ export function search(query: string): GroupedSearchResults { }; if (query.length > 0) { - console.log(results); const fuseResults = fuse.search(query); const scoredResults: SearchResults = fuseResults.map((result) => ({ From d3c2d840b3d349a20bb30a37c0337f2ce388515b Mon Sep 17 00:00:00 2001 From: Marten Bjork Date: Tue, 5 Jul 2022 14:22:41 +0200 Subject: [PATCH 04/22] Refactor global search --- .../ComponentGrid/ComponentGrid.module.scss | 2 +- .../ComponentGrid/ComponentGrid.tsx | 18 +- .../GlobalSearch/GlobalSearch.module.scss | 2 +- .../components/GlobalSearch/GlobalSearch.tsx | 422 +++++++++--------- .../components/IconGrid/IconGrid.module.scss | 2 +- .../src/components/IconGrid/IconGrid.tsx | 29 +- .../TokenList/TokenList.module.scss | 2 +- .../src/components/TokenList/TokenList.tsx | 28 +- polaris.shopify.com/src/types.ts | 14 +- polaris.shopify.com/src/utils/search.ts | 13 +- 10 files changed, 257 insertions(+), 275 deletions(-) diff --git a/polaris.shopify.com/src/components/ComponentGrid/ComponentGrid.module.scss b/polaris.shopify.com/src/components/ComponentGrid/ComponentGrid.module.scss index 8f660084ce1..075af9e06e1 100644 --- a/polaris.shopify.com/src/components/ComponentGrid/ComponentGrid.module.scss +++ b/polaris.shopify.com/src/components/ComponentGrid/ComponentGrid.module.scss @@ -30,7 +30,7 @@ } @media (hover: hover) { - &.isHighlighted a { + &[data-is-current-result="true"] { background: var(--search-highlight-color); } } diff --git a/polaris.shopify.com/src/components/ComponentGrid/ComponentGrid.tsx b/polaris.shopify.com/src/components/ComponentGrid/ComponentGrid.tsx index dc3239e849d..d00da137942 100644 --- a/polaris.shopify.com/src/components/ComponentGrid/ComponentGrid.tsx +++ b/polaris.shopify.com/src/components/ComponentGrid/ComponentGrid.tsx @@ -1,10 +1,10 @@ import Image from "../Image"; import Link from "next/link"; -import { SearchResultItem } from "../../types"; import { className, slugify } from "../../utils/various"; import { Status } from "../../types"; import styles from "./ComponentGrid.module.scss"; import StatusBadge from "../StatusBadge"; +import { useGlobalSearchResult } from "../GlobalSearch/GlobalSearch"; interface ComponentGridProps { children: React.ReactNode; @@ -14,7 +14,7 @@ function ComponentGrid({ children }: ComponentGridProps) { return
      {children}
    ; } -interface ComponentGridItemProps extends SearchResultItem { +interface ComponentGridItemProps { name: string; description: string; url: string; @@ -25,20 +25,14 @@ function ComponentGridItem({ name, description, url, - searchResultData, status, }: ComponentGridItemProps) { + const attributes = useGlobalSearchResult(); + return ( -
  • +
  • - +
    (); const [isOpen, setIsOpen] = useState(false); const [searchTerm, setSearchTerm] = useState(""); - const [activeDescendant, setActiveDescendant] = useState(0); + const [currentResultIndex, setCurrentResultIndex] = useState(0); const router = useRouter(); let resultsInRenderedOrder: SearchResults = []; @@ -84,16 +107,15 @@ function GlobalSearch({}: Props) { useEffect(() => { setSearchResults(search(searchTerm)); - setActiveDescendant(0); + setCurrentResultIndex(0); scrollToTop(); }, [searchTerm]); - useEffect(() => scrollIntoView(), [activeDescendant]); + useEffect(() => scrollIntoView(), [currentResultIndex]); useEffect(() => { - const handler = () => { - setIsOpen(false); - }; + const handler = () => setIsOpen(false); + router.events.on("beforeHistoryChange", handler); router.events.on("hashChangeComplete", handler); @@ -114,51 +136,28 @@ function GlobalSearch({}: Props) { ) => { switch (evt.code) { case "ArrowDown": - if (activeDescendant < searchResultsCount - 1) { - setActiveDescendant(activeDescendant + 1); + if (currentResultIndex < searchResultsCount - 1) { + setCurrentResultIndex(currentResultIndex + 1); evt.preventDefault(); } break; case "ArrowUp": - if (activeDescendant > 0) { - setActiveDescendant(activeDescendant - 1); + if (currentResultIndex > 0) { + setCurrentResultIndex(currentResultIndex - 1); evt.preventDefault(); } break; case "Enter": setIsOpen(false); - const url = resultsInRenderedOrder[activeDescendant].url; + const url = resultsInRenderedOrder[currentResultIndex].url; router.push(url); break; } }; - const getItemId = (resultIndex: number): string => { - return `result${slugify(resultsInRenderedOrder[resultIndex].url)}`; - }; - - const getItemProps = ({ - resultIndex, - }: { - resultIndex: number; - }): SearchResultItem => { - const isHighlighted = resultIndex === activeDescendant; - return { - searchResultData: { - isHighlighted, - itemAttributes: { - id: getItemId(resultIndex), - "data-is-active-descendant": isHighlighted, - }, - tabIndex: -1, - url: resultsInRenderedOrder[resultIndex].url, - }, - }; - }; - - let resultIndex = -1; + const currentItemId = resultsInRenderedOrder[currentResultIndex]?.id || ""; return ( <> @@ -174,188 +173,185 @@ function GlobalSearch({}: Props) { setIsOpen(false)}>
    - <> - - {isOpen && ( -
    -
    - -
    - - setSearchTerm(evt.target.value)} - role="combobox" - aria-controls="search-results" - aria-expanded={searchResultsCount > 0} - aria-activedescendant={ - searchResultsCount > 0 - ? getItemId(activeDescendant) - : undefined - } - onKeyDown={handleKeyboardNavigation} - autoComplete="off" - autoCorrect="off" - autoCapitalize="off" - spellCheck={false} - placeholder="Search" - /> - + + {isOpen && ( +
    +
    +
    - )} -
    - {searchResults && - Object.entries(searchResults) - .sort((a, b) => a[1].topScore - b[1].topScore) - .map(([category]) => { - const typedCategory = category as SearchResultCategory; - - switch (typedCategory) { - case "Foundations": - const results = searchResults[typedCategory].results; - if (results.length === 0) return null; - return ( - -
    - {results.map((result) => { - resultIndex++; - const { searchResultData } = getItemProps({ - resultIndex, - }); - if (!result.meta.Foundations) return null; - const { title, excerpt } = - result.meta.Foundations; - return ( -
  • - - -

    {title}

    -

    {stripMarkdownLinks(excerpt)}

    -
    - -
  • - ); - })} - - - ); - - case "Components": { - const results = searchResults[typedCategory].results; - if (results.length === 0) return null; - return ( - - - {results.map((result) => { - resultIndex++; - if (!result.meta.Components) return null; - const { url } = result; - const { name, description, status } = - result.meta.Components; - return ( - - ); - })} - - - ); - } - - case "Tokens": { - const results = searchResults[typedCategory].results; - if (results.length === 0) return null; - return ( - - - {results.map((result) => { - resultIndex++; - if (!result.meta.Tokens) return null; - const { token } = result.meta.Tokens; - return ( - - ); - })} - - - ); - } - - case "Icons": { - const results = searchResults[typedCategory].results; - if (results.length === 0) return null; - return ( - - - {results.map((result) => { - resultIndex++; - if (!result.meta.Icons) return null; - const { url } = result; - const { icon } = result.meta.Icons; - return ( - router.push(result.url)} - {...getItemProps({ resultIndex })} - /> - ); - })} - - - ); - } - } - })} + setSearchTerm(evt.target.value)} + role="combobox" + aria-controls="search-results" + aria-expanded={searchResultsCount > 0} + aria-activedescendant={currentItemId} + onKeyDown={handleKeyboardNavigation} + autoComplete="off" + autoCorrect="off" + autoCapitalize="off" + spellCheck={false} + placeholder="Search" + /> + - - + )} +
    + {searchResults && ( + + )} +
    + ); } +function SearchResults({ + searchResults, + currentItemId, +}: { + searchResults: GroupedSearchResults; + currentItemId: string; +}) { + const router = useRouter(); + return ( + <> + {Object.entries(searchResults) + .sort((a, b) => a[1].topScore - b[1].topScore) + .map(([category]) => { + const typedCategory = category as SearchResultCategory; + const results = searchResults[typedCategory].results; + if (results.length === 0) return null; + + switch (typedCategory) { + case "Foundations": + return ( + +
    + {results.map(({ id, url, meta }) => { + if (!meta.Foundations) return null; + const { title, excerpt } = meta.Foundations; + return ( + +
  • + + +

    {title}

    +

    {stripMarkdownLinks(excerpt)}

    +
    + +
  • +
    + ); + })} +
    +
    + ); + + case "Components": { + return ( + + + {results.map(({ id, url, meta }) => { + if (!meta.Components) return null; + const { name, description, status } = meta.Components; + return ( + + + + ); + })} + + + ); + } + + case "Tokens": { + return ( + + + {results.map(({ id, meta }) => { + if (!meta.Tokens) return null; + const { token, category } = meta.Tokens; + return ( + + + + ); + })} + + + ); + } + + case "Icons": { + return ( + + + {results.map(({ id, url, meta }) => { + if (!meta.Icons) return null; + const { icon } = meta.Icons; + return ( + + router.push(url)} + /> + + ); + })} + + + ); + } + } + })} + + ); +} + function SearchIcon() { return ( diff --git a/polaris.shopify.com/src/components/IconGrid/IconGrid.module.scss b/polaris.shopify.com/src/components/IconGrid/IconGrid.module.scss index 3b4bb0a9db8..c76370be810 100644 --- a/polaris.shopify.com/src/components/IconGrid/IconGrid.module.scss +++ b/polaris.shopify.com/src/components/IconGrid/IconGrid.module.scss @@ -30,7 +30,7 @@ } @media (hover: hover) { - &.isHighlighted button, + &[data-is-current-result="true"] button, &.isSelected button { background: var(--search-highlight-color); diff --git a/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx b/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx index 37fc7f65f80..6612c692b1c 100644 --- a/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx +++ b/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx @@ -1,5 +1,5 @@ import Image from "../Image"; -import { className } from "../../utils/various"; +import { className, slugify } from "../../utils/various"; import Tooltip from "../Tooltip"; const importedSvgs = require.context( "../../../../polaris-icons/icons", @@ -7,7 +7,8 @@ const importedSvgs = require.context( /\.svg$/ ); import styles from "./IconGrid.module.scss"; -import { Icon, SearchResultItem } from "../../types"; +import { Icon } from "../../types"; +import { useGlobalSearchResult } from "../GlobalSearch/GlobalSearch"; interface IconGridProps { children: React.ReactNode; @@ -17,28 +18,20 @@ function IconGrid({ children }: IconGridProps) { return
      {children}
    ; } -interface IconGridItemProps extends SearchResultItem { +interface IconGridItemProps { icon: Icon; onClick: (iconName: string) => void; isSelected?: boolean; } -function IconGridItem({ - icon, - onClick, - isSelected, - searchResultData, -}: IconGridItemProps) { +function IconGridItem({ icon, onClick, isSelected }: IconGridItemProps) { + const attributes = useGlobalSearchResult(); + return (
  • setIsOpen(false)}> -
    +
    {isOpen && ( @@ -223,31 +230,32 @@ function SearchResults({ return ( <> {searchResults.map(({ category, results }) => { + if (results.length === 0) return null; switch (category) { case "foundations": return ( -
    + {results.map(({ id, url, meta }) => { if (!meta.foundations) return null; - const { title, excerpt } = meta.foundations; + const { title, excerpt, category } = meta.foundations; + const icon = foundationsIcons[title]; return ( -
  • - - -

    {title}

    -

    {stripMarkdownLinks(excerpt)}

    -
    - -
  • + ); })} - + ); diff --git a/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx b/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx index 6612c692b1c..faaf1fbfa06 100644 --- a/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx +++ b/polaris.shopify.com/src/components/IconGrid/IconGrid.tsx @@ -25,13 +25,13 @@ interface IconGridItemProps { } function IconGridItem({ icon, onClick, isSelected }: IconGridItemProps) { - const attributes = useGlobalSearchResult(); + const searchAttributes = useGlobalSearchResult(); return (