diff --git a/src/constants/algolia.js b/src/constants/algolia.js index 2433d5e809..82c6efd931 100644 --- a/src/constants/algolia.js +++ b/src/constants/algolia.js @@ -3,6 +3,6 @@ // setup (src/theme/SearchBar/algoliaInsights.ts, src/pages/search.tsx). module.exports = { ALGOLIA_APP_ID: 'T5D6KNJCQS', - ALGOLIA_SEARCH_API_KEY: '4a2fa646f476d7756a7cdc599b625bec', - ALGOLIA_INDEX_NAME: 'temporal', + ALGOLIA_SEARCH_API_KEY: '7f9927fa05ed55464439db9097050857', + ALGOLIA_INDEX_NAME: 'temporal-search-experiment', }; diff --git a/src/theme/SearchBar/GroupedHits.tsx b/src/theme/SearchBar/GroupedHits.tsx index 313941e43b..34ceae1937 100644 --- a/src/theme/SearchBar/GroupedHits.tsx +++ b/src/theme/SearchBar/GroupedHits.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { useHits } from 'react-instantsearch'; import { Hit } from './Hit'; +import { SDK_LANGUAGES } from './SDKLanguageFilter'; interface GroupedHitsProps { selectedIndex: number; @@ -9,6 +10,13 @@ interface GroupedHitsProps { export function GroupedHits({ selectedIndex, onNavigate }: GroupedHitsProps) { const { items, sendEvent } = useHits(); + const titleCounts = items.reduce((counts: Map, hit: any) => { + const title = hit.hierarchy?.[hit.type] || hit.hierarchy?.lvl1; + if (title) { + counts.set(title, (counts.get(title) || 0) + 1); + } + return counts; + }, new Map()); // Group hits by their top-level category (hierarchy.lvl0) const groupedByCategory = items.reduce((acc: any, hit: any) => { @@ -47,61 +55,93 @@ export function GroupedHits({ selectedIndex, onNavigate }: GroupedHitsProps) { return acc; }, {}); - const pageUrls = Object.keys(hitsByPage); + const pageGroups = Object.entries(hitsByPage).map(([pageUrl, { page, anchors }]: [string, any]) => ({ + pageUrl, + page, + anchors, + sdkLanguage: page?.sdk_language || anchors[0]?.sdk_language, + })); + const languageGroups = pageGroups.reduce((groups: Map, pageGroup) => { + const language = pageGroup.sdkLanguage || null; + groups.set(language, [...(groups.get(language) || []), pageGroup]); + return groups; + }, new Map()); + const languageLabel = (language: string) => SDK_LANGUAGES.find((sdk) => sdk.id === language)?.label || language; return (
-
- {category} -
+
{category}
- {pageUrls.map((pageUrl) => { - const { page, anchors } = hitsByPage[pageUrl]; - const pageTitle = page?.hierarchy?.lvl1 || anchors[0]?.hierarchy?.lvl1 || 'Untitled'; + {[null, ...[...languageGroups.keys()].filter(Boolean)].map((language) => { + const pages = languageGroups.get(language) || []; - // If there's no page hit but there are anchors, treat the first anchor as the "page" - const hasPageHit = !!page; - const firstAnchorAsPage = !hasPageHit && anchors.length > 0 ? anchors[0] : null; - const remainingAnchors = firstAnchorAsPage ? anchors.slice(1) : anchors; + if (pages.length === 0) { + return null; + } return ( -
- {/* Render page hit if it exists */} - {page && ( - - )} - {/* If no page hit, render first anchor as page-level item */} - {firstAnchorAsPage && ( - - )} - {/* Render remaining anchor hits as tree children */} - {remainingAnchors.map((anchor: any, anchorIndex: number) => ( - - ))} -
+ + {pages.map(({ pageUrl, page, anchors }: any) => { + const pageTitle = page?.hierarchy?.lvl1 || anchors[0]?.hierarchy?.lvl1 || 'Untitled'; + + // If there's no page hit but there are anchors, treat the first anchor as the "page" + const hasPageHit = !!page; + const firstAnchorAsPage = !hasPageHit && anchors.length > 0 ? anchors[0] : null; + const remainingAnchors = firstAnchorAsPage ? anchors.slice(1) : anchors; + + return ( +
+ {page && ( + 1 + } + sendEvent={sendEvent} + /> + )} + {firstAnchorAsPage && ( + 1 + } + sendEvent={sendEvent} + /> + )} + {remainingAnchors.map((anchor: any, anchorIndex: number) => ( + 1 + } + sendEvent={sendEvent} + /> + ))} +
+ ); + })} +
); })}
diff --git a/src/theme/SearchBar/Hit.tsx b/src/theme/SearchBar/Hit.tsx index 748df26956..905aec7da1 100644 --- a/src/theme/SearchBar/Hit.tsx +++ b/src/theme/SearchBar/Hit.tsx @@ -11,6 +11,8 @@ interface HitProps { isAnchor?: boolean; isLastAnchor?: boolean; parentTitle?: string; + languageLabel?: string; + showSinglePath?: boolean; sendEvent: (eventType: string, hit: any, eventName: string) => void; } @@ -30,11 +32,45 @@ function getHierarchyAttribute(hit: any): string { return 'hierarchy.lvl1'; } -export function Hit({ hit, isSelected, onNavigate, isAnchor, isLastAnchor, parentTitle, sendEvent }: HitProps) { +function getHierarchyPath( + hit: any, + hierarchyAttribute: string, + parentTitle?: string, + showSinglePath = false +): string[] { + const currentLevel = hierarchyAttribute.replace('hierarchy.', ''); + const resultTitle = hit.hierarchy?.[currentLevel]; + const levels = ['lvl0', 'lvl1', 'lvl2', 'lvl3', 'lvl4', 'lvl5', 'lvl6']; + const path = levels + .slice(0, levels.indexOf(currentLevel)) + .map((level) => hit.hierarchy?.[level]) + .filter((value) => value && value !== resultTitle); + + if (path.length > 1 || showSinglePath) { + return path; + } + + return parentTitle && parentTitle !== resultTitle ? [parentTitle] : []; +} + +export function Hit({ + hit, + isSelected, + onNavigate, + isAnchor, + isLastAnchor, + parentTitle, + languageLabel, + showSinglePath, + sendEvent, +}: HitProps) { const history = useHistory(); const hitRef = useRef(null); const hierarchyAttribute = getHierarchyAttribute(hit); + const hierarchyPath = getHierarchyPath(hit, hierarchyAttribute, parentTitle, showSinglePath); + const resultTitle = hit.hierarchy?.[hierarchyAttribute.replace('hierarchy.', '')] || ''; + const showLanguageLabel = languageLabel && !resultTitle.toLowerCase().includes(languageLabel.toLowerCase()); const handleClick = (e: React.MouseEvent) => { e.preventDefault(); @@ -68,7 +104,9 @@ export function Hit({ hit, isSelected, onNavigate, isAnchor, isLastAnchor, paren 'custom-search-hit', isSelected ? 'custom-search-hit--selected' : '', isAnchor ? 'custom-search-hit--anchor' : 'custom-search-hit--page', - ].filter(Boolean).join(' '); + ] + .filter(Boolean) + .join(' '); return (
+ {showLanguageLabel && - {languageLabel} SDK}
- {isAnchor && parentTitle && ( -
- {parentTitle} -
- )} - {!isAnchor && hit.content && ( + {hierarchyPath.length > 0 &&
{hierarchyPath.join(' > ')}
} + {hit.content && (
diff --git a/src/theme/SearchBar/styles.css b/src/theme/SearchBar/styles.css index a00445cdfc..6b2be82596 100644 --- a/src/theme/SearchBar/styles.css +++ b/src/theme/SearchBar/styles.css @@ -415,6 +415,11 @@ color: var(--temporal-dark); } +.custom-search-hit-language { + color: var(--temporal-text-muted); + font-weight: 400; +} + .custom-search-hit-path { font-size: 12px; color: var(--temporal-text-muted); @@ -505,7 +510,9 @@ .custom-search-language-filter-content { display: grid; grid-template-rows: 1fr; - transition: grid-template-rows 0.25s ease, opacity 0.2s ease; + transition: + grid-template-rows 0.25s ease, + opacity 0.2s ease; opacity: 1; } @@ -745,7 +752,9 @@ color: var(--ifm-font-color-base); outline: none; font-family: inherit; - transition: border-color 0.2s ease, box-shadow 0.2s ease; + transition: + border-color 0.2s ease, + box-shadow 0.2s ease; } .search-page-input:focus {