From 736b7ef181e7859567a3ed9073f9bb3061c4633c Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sat, 6 Dec 2025 11:05:34 -0500 Subject: [PATCH 1/2] feat(orama): add SearchHit UI component --- .../Searchbox/DocumentLink/index.module.css | 31 --------- .../Common/Searchbox/DocumentLink/index.tsx | 11 +--- .../Common/Searchbox/SearchItem/index.tsx | 63 +++++++++---------- .../components/Common/Searchbox/index.tsx | 2 +- packages/ui-components/package.json | 2 +- .../Search/Results/Hit}/index.module.css | 24 ++++++- .../src/Common/Search/Results/Hit/index.tsx | 39 ++++++++++++ 7 files changed, 96 insertions(+), 76 deletions(-) delete mode 100644 apps/site/components/Common/Searchbox/DocumentLink/index.module.css rename {apps/site/components/Common/Searchbox/SearchItem => packages/ui-components/src/Common/Search/Results/Hit}/index.module.css (60%) create mode 100644 packages/ui-components/src/Common/Search/Results/Hit/index.tsx diff --git a/apps/site/components/Common/Searchbox/DocumentLink/index.module.css b/apps/site/components/Common/Searchbox/DocumentLink/index.module.css deleted file mode 100644 index d5a426fe2194f..0000000000000 --- a/apps/site/components/Common/Searchbox/DocumentLink/index.module.css +++ /dev/null @@ -1,31 +0,0 @@ -@reference "../../../../styles/index.css"; - -.documentLink { - @apply rounded-xl - bg-neutral-100 - px-4 - py-2 - text-neutral-900 - duration-300 - hover:bg-neutral-200 - focus:bg-neutral-200 - motion-safe:transition-colors - dark:bg-neutral-950 - dark:text-neutral-200 - hover:dark:bg-neutral-900 - focus:dark:bg-neutral-900; - - svg { - @apply size-5; - } -} - -.documentTitle { - @apply max-w-full - truncate - overflow-hidden - text-sm - font-semibold - text-ellipsis - whitespace-nowrap; -} diff --git a/apps/site/components/Common/Searchbox/DocumentLink/index.tsx b/apps/site/components/Common/Searchbox/DocumentLink/index.tsx index cfb3eec12c575..e78436a52895a 100644 --- a/apps/site/components/Common/Searchbox/DocumentLink/index.tsx +++ b/apps/site/components/Common/Searchbox/DocumentLink/index.tsx @@ -1,12 +1,11 @@ 'use client'; +import styles from '@node-core/ui-components/Common/Search/Results/Hit/index.module.css'; import Link from 'next/link'; import { useLocale } from 'next-intl'; import type { FC } from 'react'; -import styles from './index.module.css'; - export type Document = { path: string; siteSection: string; @@ -22,7 +21,7 @@ type DocumentLinkProps = { export const DocumentLink: FC = ({ document, - className = styles.documentLink, + className = styles.link, children, 'data-focus-on-arrow-nav': dataFocusOnArrowNav, ...props @@ -41,11 +40,7 @@ export const DocumentLink: FC = ({ data-focus-on-arrow-nav={dataFocusOnArrowNav} {...props} > - {children || ( - - {document.pageSectionTitle} - - )} + {children} ); }; diff --git a/apps/site/components/Common/Searchbox/SearchItem/index.tsx b/apps/site/components/Common/Searchbox/SearchItem/index.tsx index 2d42209174105..09c935713019a 100644 --- a/apps/site/components/Common/Searchbox/SearchItem/index.tsx +++ b/apps/site/components/Common/Searchbox/SearchItem/index.tsx @@ -1,41 +1,38 @@ -'use client'; - -import { DocumentTextIcon } from '@heroicons/react/24/outline'; -import { SearchResults } from '@orama/ui/components'; +import SearchHit from '@node-core/ui-components/Common/Search/Results/Hit'; +import { useLocale } from 'next-intl'; import type { Document } from '../DocumentLink'; -import type { FC } from 'react'; +import type { ComponentProps, FC } from 'react'; -import { DocumentLink } from '../DocumentLink'; import { getFormattedPath } from './utils'; -import styles from './index.module.css'; - -type SearchItemProps = { +type SearchItemProps = Omit< + ComponentProps, + 'document' | 'as' +> & { document: Document; - mode?: 'search' | 'chat'; }; -export const SearchItem: FC = ({ document, mode }) => ( - - - -
- {typeof document?.pageSectionTitle === 'string' && ( -

{document.pageSectionTitle}

- )} - {typeof document?.pageSectionTitle === 'string' && - typeof document?.path === 'string' && ( -

- {getFormattedPath(document.path, document.pageSectionTitle)} -

- )} -
-
-
-); +const SearchItem: FC = ({ document, ...props }) => { + const locale = useLocale(); + + const href = + document.siteSection?.toLowerCase() === 'docs' + ? `/${document.path}` + : `/${locale}/${document.path}`; + + return ( + + ); +}; + +export default SearchItem; diff --git a/apps/site/components/Common/Searchbox/index.tsx b/apps/site/components/Common/Searchbox/index.tsx index 00c2d6739b528..278f6703adda2 100644 --- a/apps/site/components/Common/Searchbox/index.tsx +++ b/apps/site/components/Common/Searchbox/index.tsx @@ -14,7 +14,7 @@ import type { FC } from 'react'; import { Footer } from './Footer'; import { oramaClient } from './orama-client'; -import { SearchItem } from './SearchItem'; +import SearchItem from './SearchItem'; import { SlidingChatPanel } from './SlidingChatPanel'; import styles from './index.module.css'; diff --git a/packages/ui-components/package.json b/packages/ui-components/package.json index 331502438805d..060106479a27d 100644 --- a/packages/ui-components/package.json +++ b/packages/ui-components/package.json @@ -1,6 +1,6 @@ { "name": "@node-core/ui-components", - "version": "1.4.0", + "version": "1.4.1", "type": "module", "exports": { "./*": [ diff --git a/apps/site/components/Common/Searchbox/SearchItem/index.module.css b/packages/ui-components/src/Common/Search/Results/Hit/index.module.css similarity index 60% rename from apps/site/components/Common/Searchbox/SearchItem/index.module.css rename to packages/ui-components/src/Common/Search/Results/Hit/index.module.css index 6db5acb033ecb..f55cef29f9e3c 100644 --- a/apps/site/components/Common/Searchbox/SearchItem/index.module.css +++ b/packages/ui-components/src/Common/Search/Results/Hit/index.module.css @@ -1,6 +1,6 @@ @reference "../../../../styles/index.css"; -.searchResultsItem { +.hit { > a { @apply flex items-center @@ -27,7 +27,27 @@ } } -.searchResultsItemDescription { +.link { + @apply rounded-xl + bg-neutral-100 + px-4 + py-2 + text-neutral-900 + duration-300 + hover:bg-neutral-200 + focus:bg-neutral-200 + motion-safe:transition-colors + dark:bg-neutral-950 + dark:text-neutral-200 + hover:dark:bg-neutral-900 + focus:dark:bg-neutral-900; + + svg { + @apply size-5; + } +} + +.hitDescription { @apply text-sm text-neutral-600 dark:text-neutral-700; diff --git a/packages/ui-components/src/Common/Search/Results/Hit/index.tsx b/packages/ui-components/src/Common/Search/Results/Hit/index.tsx new file mode 100644 index 0000000000000..973f679c224a6 --- /dev/null +++ b/packages/ui-components/src/Common/Search/Results/Hit/index.tsx @@ -0,0 +1,39 @@ +import { DocumentTextIcon } from '@heroicons/react/24/outline'; +import { SearchResults } from '@orama/ui/components'; + +import type { LinkLike } from '#ui/types'; +import type { FC } from 'react'; + +import styles from './index.module.css'; + +type HitProps = { + document: { + title?: string; + description?: string; + href: string; + }; + mode?: 'search' | 'chat'; + as?: LinkLike; +}; + +const Hit: FC = ({ document, mode = 'search', as: Link = 'a' }) => ( + + + +
+ {typeof document?.title === 'string' &&

{document.title}

} + {typeof document?.description === 'string' && ( +

{document.description}

+ )} +
+ +
+); + +export default Hit; From bab86e773837ec4850338403a9447a3348474655 Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sat, 6 Dec 2025 11:26:49 -0500 Subject: [PATCH 2/2] fixup! --- .../Common/Searchbox/DocumentLink/index.tsx | 9 ++--- .../Common/Searchbox/SearchItem/index.tsx | 12 +++--- .../Common/Searchbox/SearchItem/utils.ts | 7 ++++ .../Search/Results/Hit/index.module.css | 38 +++++-------------- .../src/Common/Search/Results/Hit/index.tsx | 2 +- 5 files changed, 26 insertions(+), 42 deletions(-) diff --git a/apps/site/components/Common/Searchbox/DocumentLink/index.tsx b/apps/site/components/Common/Searchbox/DocumentLink/index.tsx index e78436a52895a..1a7c1f8ad5492 100644 --- a/apps/site/components/Common/Searchbox/DocumentLink/index.tsx +++ b/apps/site/components/Common/Searchbox/DocumentLink/index.tsx @@ -6,6 +6,8 @@ import { useLocale } from 'next-intl'; import type { FC } from 'react'; +import { getDocumentHref } from '../SearchItem/utils'; + export type Document = { path: string; siteSection: string; @@ -28,14 +30,9 @@ export const DocumentLink: FC = ({ }) => { const locale = useLocale(); - const href = - document.siteSection?.toLowerCase() === 'docs' - ? `/${document.path}` - : `/${locale}/${document.path}`; - return ( , @@ -16,11 +18,6 @@ type SearchItemProps = Omit< const SearchItem: FC = ({ document, ...props }) => { const locale = useLocale(); - const href = - document.siteSection?.toLowerCase() === 'docs' - ? `/${document.path}` - : `/${locale}/${document.path}`; - return ( = ({ document, ...props }) => { description: document.pageSectionTitle && getFormattedPath(document.path, document.pageSectionTitle), - href, + href: getDocumentHref(document, locale), }} + as={Link as LinkLike} {...props} /> ); diff --git a/apps/site/components/Common/Searchbox/SearchItem/utils.ts b/apps/site/components/Common/Searchbox/SearchItem/utils.ts index 5fc41ceac70f1..ad4a9a4cc63bb 100644 --- a/apps/site/components/Common/Searchbox/SearchItem/utils.ts +++ b/apps/site/components/Common/Searchbox/SearchItem/utils.ts @@ -1,3 +1,5 @@ +import type { Document } from '../DocumentLink'; + export const uppercaseFirst = (word: string) => word.charAt(0).toUpperCase() + word.slice(1); @@ -9,3 +11,8 @@ export const getFormattedPath = (path: string, title: string) => .map(element => uppercaseFirst(element)) .filter(Boolean) .join(' > ')} — ${title}`; + +export const getDocumentHref = (document: Document, locale: string) => + document.siteSection?.toLowerCase() === 'docs' + ? `/${document.path}` + : `/${locale}/${document.path}`; diff --git a/packages/ui-components/src/Common/Search/Results/Hit/index.module.css b/packages/ui-components/src/Common/Search/Results/Hit/index.module.css index f55cef29f9e3c..95299a675e669 100644 --- a/packages/ui-components/src/Common/Search/Results/Hit/index.module.css +++ b/packages/ui-components/src/Common/Search/Results/Hit/index.module.css @@ -1,41 +1,23 @@ @reference "../../../../styles/index.css"; -.hit { - > a { - @apply flex - items-center - gap-4 - rounded-lg - border - border-transparent - px-2 - py-3 - text-sm - duration-300 - outline-none - hover:bg-neutral-300 - focus-visible:border-green-600 - focus-visible:bg-transparent - motion-safe:transition-colors - dark:bg-neutral-950 - dark:hover:bg-neutral-900; - } - - svg { - @apply size-5 - shrink-0; - } -} - .link { - @apply rounded-xl + @apply flex + items-center + gap-4 + rounded-xl + border + border-transparent bg-neutral-100 px-4 py-2 + text-sm text-neutral-900 duration-300 + outline-none hover:bg-neutral-200 focus:bg-neutral-200 + focus-visible:border-green-600 + focus-visible:bg-transparent motion-safe:transition-colors dark:bg-neutral-950 dark:text-neutral-200 diff --git a/packages/ui-components/src/Common/Search/Results/Hit/index.tsx b/packages/ui-components/src/Common/Search/Results/Hit/index.tsx index 973f679c224a6..9020c4c4c4f38 100644 --- a/packages/ui-components/src/Common/Search/Results/Hit/index.tsx +++ b/packages/ui-components/src/Common/Search/Results/Hit/index.tsx @@ -17,7 +17,7 @@ type HitProps = { }; const Hit: FC = ({ document, mode = 'search', as: Link = 'a' }) => ( - +