Skip to content

Commit

Permalink
support clickable citation card with link (#444)
Browse files Browse the repository at this point in the history
J=CLIP-1332
TEST=auto,manual

ran `npm run test` and test manually on test-site
  • Loading branch information
anguyen-yext2 authored Jun 27, 2024
1 parent ae5fac2 commit 34f207c
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 60 deletions.
3 changes: 1 addition & 2 deletions docs/search-ui-react.citationprops.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ interface CitationProps

| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [citation](./search-ui-react.citationprops.citation.md) | | string | |
| [cssClasses](./search-ui-react.citationprops.cssclasses.md) | | [GenerativeDirectAnswerCssClasses](./search-ui-react.generativedirectanswercssclasses.md) | |
| [searchResults](./search-ui-react.citationprops.searchresults.md) | | Result\[\] | |
| [searchResult](./search-ui-react.citationprops.searchresult.md) | | Result | |

Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [CitationProps](./search-ui-react.citationprops.md) &gt; [citation](./search-ui-react.citationprops.citation.md)
[Home](./index.md) &gt; [@yext/search-ui-react](./search-ui-react.md) &gt; [CitationProps](./search-ui-react.citationprops.md) &gt; [searchResult](./search-ui-react.citationprops.searchresult.md)

## CitationProps.citation property
## CitationProps.searchResult property

**Signature:**

```typescript
citation: string;
searchResult: Result;
```
11 changes: 0 additions & 11 deletions docs/search-ui-react.citationprops.searchresults.md

This file was deleted.

4 changes: 2 additions & 2 deletions docs/search-ui-react.generativedirectanswer.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ Displays the AI generated answer of a generative direct answer.
**Signature:**

```typescript
declare function GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader, CitationCard }: GenerativeDirectAnswerProps): JSX.Element | null;
declare function GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader, CitationCard, }: GenerativeDirectAnswerProps): JSX.Element | null;
```

## Parameters

| Parameter | Type | Description |
| --- | --- | --- |
| { customCssClasses, answerHeader, citationsHeader, CitationCard } | [GenerativeDirectAnswerProps](./search-ui-react.generativedirectanswerprops.md) | |
| { customCssClasses, answerHeader, citationsHeader, CitationCard, } | [GenerativeDirectAnswerProps](./search-ui-react.generativedirectanswerprops.md) | |

**Returns:**

Expand Down
2 changes: 1 addition & 1 deletion docs/search-ui-react.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
| [Facets(props)](./search-ui-react.facets.md) | A component that displays all facets applicable to the current vertical search. |
| [FilterDivider({ className })](./search-ui-react.filterdivider.md) | A divider component used to separate NumericalFacets, HierarchicalFacets, StandardFacets, and StaticFilters. |
| [FilterSearch({ searchFields, label, placeholder, searchOnSelect, onSelect, onDropdownInputChange, afterDropdownInputFocus, sectioned, customCssClasses })](./search-ui-react.filtersearch.md) | A component which allows a user to search for filters associated with specific entities and fields. |
| [GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader, CitationCard })](./search-ui-react.generativedirectanswer.md) | Displays the AI generated answer of a generative direct answer. |
| [GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader, CitationCard, })](./search-ui-react.generativedirectanswer.md) | Displays the AI generated answer of a generative direct answer. |
| [Geolocation\_2({ geolocationOptions, radius, label, GeolocationIcon, handleClick, customCssClasses, })](./search-ui-react.geolocation_2.md) | A React Component which collects location information to create a location filter and perform a new search. |
| [getSearchIntents(searchActions)](./search-ui-react.getsearchintents.md) | Get search intents of the current query stored in headless using autocomplete request. |
| [getUserLocation(geolocationOptions)](./search-ui-react.getuserlocation.md) | Retrieves user's location using navigator.geolocation API. |
Expand Down
6 changes: 2 additions & 4 deletions etc/search-ui-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,10 @@ export interface CardProps<T = DefaultRawDataType> {

// @public
export interface CitationProps {
// (undocumented)
citation: string;
// (undocumented)
cssClasses: GenerativeDirectAnswerCssClasses;
// (undocumented)
searchResults: Result[];
searchResult: Result;
}

// @public
Expand Down Expand Up @@ -323,7 +321,7 @@ export interface FilterSearchProps {
export type FocusedItemData = Record<string, unknown>;

// @public
export function GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader, CitationCard }: GenerativeDirectAnswerProps): JSX.Element | null;
export function GenerativeDirectAnswer({ customCssClasses, answerHeader, citationsHeader, CitationCard, }: GenerativeDirectAnswerProps): JSX.Element | null;

// @public
export interface GenerativeDirectAnswerCssClasses {
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yext/search-ui-react",
"version": "1.7.0-beta.3",
"version": "1.7.0-beta.4",
"description": "A library of React Components for powering Yext Search integrations",
"author": "slapshot@yext.com",
"license": "BSD-3-Clause",
Expand Down
55 changes: 35 additions & 20 deletions src/components/GenerativeDirectAnswer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const builtInCssClasses: Readonly<GenerativeDirectAnswerCssClasses> = {
answerText: 'mt-4',
divider: 'border-b border-gray-200 w-full pb-6 mb-6',
citationsContainer: 'mt-4 flex overflow-x-auto gap-4',
citation: 'p-4 border border-gray-200 rounded-lg shadow-sm bg-slate-100 flex flex-col grow-0 shrink-0 basis-64 text-sm text-neutral overflow-x-auto',
citation: 'p-4 border border-gray-200 rounded-lg shadow-sm bg-slate-100 flex flex-col grow-0 shrink-0 basis-64 text-sm text-neutral overflow-x-auto cursor-pointer hover:border-indigo-500',
citationTitle: 'font-bold',
citationSnippet: 'line-clamp-2 text-ellipsis break-words'
};
Expand Down Expand Up @@ -65,7 +65,7 @@ export function GenerativeDirectAnswer({
customCssClasses,
answerHeader,
citationsHeader,
CitationCard
CitationCard,
}: GenerativeDirectAnswerProps): JSX.Element | null {
const cssClasses = useComposedCssClasses(builtInCssClasses, customCssClasses);

Expand Down Expand Up @@ -100,7 +100,13 @@ export function GenerativeDirectAnswer({
<div className={cssClasses.container}>
<Answer gdaResponse={gdaResponse} cssClasses={cssClasses} answerHeader={answerHeader}/>
<div className={cssClasses.divider} />
<Citations gdaResponse={gdaResponse} cssClasses={cssClasses} citationsHeader={citationsHeader} searchResults={searchResults} CitationCard={CitationCard}/>
<Citations
gdaResponse={gdaResponse}
cssClasses={cssClasses}
searchResults={searchResults}
citationsHeader={citationsHeader}
CitationCard={CitationCard}
/>
</div>
);
}
Expand Down Expand Up @@ -131,8 +137,8 @@ function Answer(props: AnswerProps) {
interface CitationsProps {
gdaResponse: GenerativeDirectAnswerResponse,
cssClasses: GenerativeDirectAnswerCssClasses,
citationsHeader?: string | JSX.Element,
searchResults: Result[],
citationsHeader?: string | JSX.Element,
CitationCard?: (props: CitationProps) => JSX.Element | null
}

Expand All @@ -143,20 +149,34 @@ function Citations(props: CitationsProps) {
const {
gdaResponse,
cssClasses,
citationsHeader = `Sources (${gdaResponse.citations.length})`,
searchResults,
citationsHeader = `Sources (${gdaResponse.citations.length})`,
CitationCard = Citation
} = props;
if (!gdaResponse.citations.length) {
return null;
}
const citationCards: JSX.Element[] = [];
gdaResponse.citations.forEach(
citation => {
const result: Result | undefined = searchResults.find(r => r.rawData.uid === citation);
if (result) {
citationCards.push(
<CitationCard
key={citation}
searchResult={result}
cssClasses={cssClasses}
/>
)
}
});

return <>
<div className={cssClasses.header}>
{citationsHeader}
</div>
<div className={cssClasses.citationsContainer}>
{gdaResponse.citations.map(
citation => <CitationCard key={citation} searchResults={searchResults} citation={citation} cssClasses={cssClasses} />)}
{citationCards}
</div>
</>;
}
Expand All @@ -167,24 +187,19 @@ function Citations(props: CitationsProps) {
* @public
*/
export interface CitationProps {
searchResults: Result[],
citation: string,
searchResult: Result,
cssClasses: GenerativeDirectAnswerCssClasses
}

function Citation(props: CitationProps) {
const {
searchResults,
citation,
searchResult,
cssClasses
} = props;
const rawResult: Result | undefined = searchResults.find(r => r.rawData.uid === citation);
if (!rawResult) {
return null;
}

return <div className={cssClasses.citation}>
<div className={cssClasses.citationTitle}>{rawResult.rawData.name}</div>
<div className={cssClasses.citationSnippet}>{rawResult.rawData.description}</div>
</div>;
return (
<a className={cssClasses.citation} href={typeof searchResult.rawData.link === 'string' ? searchResult.rawData.link : undefined}>
<div className={cssClasses.citationTitle}>{searchResult.rawData.name}</div>
<div className={cssClasses.citationSnippet}>{searchResult.rawData.description}</div>
</a>
);
}
25 changes: 11 additions & 14 deletions test-site/src/pages/UniversalPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,14 @@ const customSearchBarCss = {

function CustomCitationCard(props: CitationProps): JSX.Element | null {
const {
searchResults,
citation,
cssClasses
searchResult,
cssClasses,
} = props;
const rawResult: Result | undefined = searchResults.find((r: Result) => r.rawData.uid === citation);

if (!rawResult) {
return null;
}

return <div key={citation} className={cssClasses.citation}>
{typeof rawResult.rawData.id === 'string' && <div className={cssClasses.citationTitle}>{rawResult.rawData.id}</div>}
{typeof rawResult.rawData.type === 'string' && <div className={cssClasses.citationSnippet}>{rawResult.rawData.type}</div>}
</div>;
const citationLink = typeof searchResult.rawData.link === 'string' ? searchResult.rawData.link : undefined;
return <a className={cssClasses.citation} href={citationLink}>
{typeof searchResult.rawData.id === 'string' && <div className={cssClasses.citationTitle}>{searchResult.rawData.id}</div>}
{typeof searchResult.rawData.s_snippet === 'string' && <div className={cssClasses.citationSnippet}>{searchResult.rawData.s_snippet}</div>}
</a>;
}

export default function UniversalPage(): JSX.Element {
Expand All @@ -92,7 +86,10 @@ export default function UniversalPage(): JSX.Element {
customCssClasses={customSearchBarCss}
/>
<SpellCheck />
<GenerativeDirectAnswer answerHeader='A custom answer header' CitationCard={CustomCitationCard}/>
<GenerativeDirectAnswer
answerHeader='A custom answer header'
CitationCard={CustomCitationCard}
/>
<DirectAnswer />
<ResultsCount />
<UniversalResults
Expand Down

0 comments on commit 34f207c

Please sign in to comment.