Updated search params

This commit is contained in:
DrMint 2023-01-06 22:59:59 +01:00
parent 0d112f192b
commit cd7c163d6e
8 changed files with 172 additions and 94 deletions

View File

@ -1,4 +1,5 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { MaterialSymbol } from "material-symbols";
import { Popup } from "components/Containers/Popup"; import { Popup } from "components/Containers/Popup";
import { sendAnalytics } from "helpers/analytics"; import { sendAnalytics } from "helpers/analytics";
import { atoms } from "contexts/atoms"; import { atoms } from "contexts/atoms";
@ -46,16 +47,25 @@ export const SearchPopup = (): JSX.Element => {
const fetchLibraryItems = async () => { const fetchLibraryItems = async () => {
const searchResult = await meiliSearch(MeiliIndices.LIBRARY_ITEM, query, { const searchResult = await meiliSearch(MeiliIndices.LIBRARY_ITEM, query, {
limit: SEARCH_LIMIT, limit: SEARCH_LIMIT,
attributesToRetrieve: [
"title",
"subtitle",
"descriptions",
"id",
"slug",
"thumbnail",
"release_date",
"price",
"categories",
"metadata",
],
attributesToHighlight: ["title", "subtitle", "descriptions"],
attributesToCrop: ["descriptions"], attributesToCrop: ["descriptions"],
}); });
searchResult.hits = searchResult.hits.map((item) => { searchResult.hits = searchResult.hits.map((item) => {
if ( if (Object.keys(item._matchesPosition).some((match) => match.startsWith("descriptions"))) {
isDefined(item._formatted) &&
item._matchesPosition.descriptions &&
item._matchesPosition.descriptions.length > 0
) {
item._formatted.descriptions = filterDefined(item._formatted.descriptions).filter( item._formatted.descriptions = filterDefined(item._formatted.descriptions).filter(
(description) => description.includes("</mark>") (description) => containsHighlight(JSON.stringify(description))
); );
} }
return item; return item;
@ -65,16 +75,15 @@ export const SearchPopup = (): JSX.Element => {
const fetchContents = async () => { const fetchContents = async () => {
const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, { const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, {
attributesToCrop: ["translations.description"],
limit: SEARCH_LIMIT, limit: SEARCH_LIMIT,
attributesToRetrieve: ["translations", "id", "slug", "categories", "type", "thumbnail"],
attributesToHighlight: ["translations"],
attributesToCrop: ["translations.displayable_description"],
}); });
searchResult.hits = searchResult.hits.map((item) => { searchResult.hits = searchResult.hits.map((item) => {
if ( if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) {
Object.keys(item._matchesPosition).filter((match) => match.startsWith("translations"))
.length > 0
) {
item._formatted.translations = filterDefined(item._formatted.translations).filter( item._formatted.translations = filterDefined(item._formatted.translations).filter(
(translation) => JSON.stringify(translation).includes("</mark>") (translation) => containsHighlight(JSON.stringify(translation))
); );
} }
return item; return item;
@ -94,8 +103,8 @@ export const SearchPopup = (): JSX.Element => {
"duration", "duration",
"description", "description",
], ],
attributesToHighlight: ["title", "channel", "description"],
attributesToCrop: ["description"], attributesToCrop: ["description"],
sort: ["sortable_published_date:desc"],
}); });
setVideos(searchResult); setVideos(searchResult);
}; };
@ -106,9 +115,16 @@ export const SearchPopup = (): JSX.Element => {
attributesToRetrieve: ["translations", "thumbnail", "slug", "date", "categories"], attributesToRetrieve: ["translations", "thumbnail", "slug", "date", "categories"],
attributesToHighlight: ["translations.title", "translations.excerpt", "translations.body"], attributesToHighlight: ["translations.title", "translations.excerpt", "translations.body"],
attributesToCrop: ["translations.body"], attributesToCrop: ["translations.body"],
sort: ["sortable_date:desc"],
filter: ["hidden = false"], filter: ["hidden = false"],
}); });
searchResult.hits = searchResult.hits.map((item) => {
if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) {
item._formatted.translations = filterDefined(item._formatted.translations).filter(
(translation) => JSON.stringify(translation).includes("</mark>")
);
}
return item;
});
setPosts(searchResult); setPosts(searchResult);
}; };
@ -123,6 +139,17 @@ export const SearchPopup = (): JSX.Element => {
], ],
attributesToCrop: ["translations.displayable_description"], attributesToCrop: ["translations.displayable_description"],
}); });
searchResult.hits = searchResult.hits.map((item) => {
if (
Object.keys(item._matchesPosition).filter((match) => match.startsWith("translations"))
.length > 0
) {
item._formatted.translations = filterDefined(item._formatted.translations).filter(
(translation) => JSON.stringify(translation).includes("</mark>")
);
}
return item;
});
setWikiPages(searchResult); setWikiPages(searchResult);
}; };
@ -159,22 +186,27 @@ export const SearchPopup = (): JSX.Element => {
{isDefined(libraryItems) && ( {isDefined(libraryItems) && (
<SearchResultSection <SearchResultSection
title={langui.library} title={langui.library}
href={`/library?page=1&query=${query}&sort=0&primary=true&secondary=true&subitems=true&status=all`} icon="auto_stories"
href={`/library?page=1&query=${query}\
&sort=0&primary=true&secondary=true&subitems=true&status=all`}
totalHits={libraryItems.estimatedTotalHits}> totalHits={libraryItems.estimatedTotalHits}>
<div className="flex flex-wrap items-start gap-x-6 gap-y-8"> <div className="flex flex-wrap items-start gap-x-6 gap-y-8">
{libraryItems.hits.map((item) => ( {libraryItems.hits.map((item) => (
<PreviewCard <TranslatedPreviewCard
key={item.id} key={item.id}
className="w-52" className="w-56"
href={`/library/${item.slug}`} href={`/library/${item.slug}`}
title={item._formatted.title} translations={filterHasAttributes(item._formatted.descriptions, [
subtitle={item._formatted.subtitle} "language.data.attributes.code",
description={ ] as const).map((translation) => ({
item._matchesPosition.descriptions && language: translation.language.data.attributes.code,
item._matchesPosition.descriptions.length > 0 title: item.title,
? item._formatted.descriptions?.[0] subtitle: item.subtitle,
: undefined description: containsHighlight(translation.description)
} ? translation.description
: undefined,
}))}
fallback={{ title: item._formatted.title, subtitle: item._formatted.subtitle }}
thumbnail={item.thumbnail?.data?.attributes} thumbnail={item.thumbnail?.data?.attributes}
thumbnailAspectRatio="21/29.7" thumbnailAspectRatio="21/29.7"
thumbnailRounded={false} thumbnailRounded={false}
@ -201,18 +233,25 @@ export const SearchPopup = (): JSX.Element => {
{isDefined(contents) && ( {isDefined(contents) && (
<SearchResultSection <SearchResultSection
title={langui.contents} title={langui.contents}
icon="workspaces"
href={`/contents/all?page=1&query=${query}&sort=0`} href={`/contents/all?page=1&query=${query}&sort=0`}
totalHits={contents.estimatedTotalHits}> totalHits={contents.estimatedTotalHits}>
<div className="flex flex-wrap items-start gap-x-6 gap-y-8"> <div className="flex flex-wrap items-start gap-x-6 gap-y-8">
{contents.hits.map((item) => ( {contents.hits.map((item) => (
<PreviewCard <TranslatedPreviewCard
key={item.id} key={item.id}
className="w-56" className="w-56"
href={`/contents/${item.slug}`} href={`/contents/${item.slug}`}
pre_title={item._formatted.translations?.[0]?.pre_title} translations={filterHasAttributes(item._formatted.translations, [
title={item._formatted.translations?.[0]?.title} "language.data.attributes.code",
subtitle={item._formatted.translations?.[0]?.subtitle} ] as const).map(({ displayable_description, language, ...otherAttributes }) => ({
description={item._formatted.translations?.[0]?.description} ...otherAttributes,
description: containsHighlight(displayable_description)
? displayable_description
: undefined,
language: language.data.attributes.code,
}))}
fallback={{ title: prettySlug(item.slug) }}
thumbnail={item.thumbnail?.data?.attributes} thumbnail={item.thumbnail?.data?.attributes}
thumbnailAspectRatio="3/2" thumbnailAspectRatio="3/2"
thumbnailForceAspectRatio thumbnailForceAspectRatio
@ -238,7 +277,8 @@ export const SearchPopup = (): JSX.Element => {
{isDefined(wikiPages) && ( {isDefined(wikiPages) && (
<SearchResultSection <SearchResultSection
title={langui.wiki} title={langui.wiki}
href={"/wiki"} icon="travel_explore"
href={`/wiki?page=1&query=${query}`}
totalHits={wikiPages.estimatedTotalHits}> totalHits={wikiPages.estimatedTotalHits}>
<div className="flex flex-wrap items-start gap-x-6 gap-y-8"> <div className="flex flex-wrap items-start gap-x-6 gap-y-8">
{wikiPages.hits.map((item) => ( {wikiPages.hits.map((item) => (
@ -288,6 +328,7 @@ export const SearchPopup = (): JSX.Element => {
{isDefined(posts) && ( {isDefined(posts) && (
<SearchResultSection <SearchResultSection
title={langui.news} title={langui.news}
icon="newspaper"
href={`/news?page=1&query=${query}`} href={`/news?page=1&query=${query}`}
totalHits={posts.estimatedTotalHits}> totalHits={posts.estimatedTotalHits}>
<div className="flex flex-wrap items-start gap-x-6 gap-y-8"> <div className="flex flex-wrap items-start gap-x-6 gap-y-8">
@ -329,6 +370,7 @@ export const SearchPopup = (): JSX.Element => {
{isDefined(videos) && ( {isDefined(videos) && (
<SearchResultSection <SearchResultSection
title={langui.videos} title={langui.videos}
icon="movie"
href={`/archives/videos?page=1&query=${query}&sort=1&gone=`} href={`/archives/videos?page=1&query=${query}&sort=1&gone=`}
totalHits={videos.estimatedTotalHits}> totalHits={videos.estimatedTotalHits}>
<div className="flex flex-wrap items-start gap-x-6 gap-y-8"> <div className="flex flex-wrap items-start gap-x-6 gap-y-8">
@ -370,21 +412,34 @@ export const SearchPopup = (): JSX.Element => {
interface SearchResultSectionProps { interface SearchResultSectionProps {
title?: string | null; title?: string | null;
icon: MaterialSymbol;
href: string; href: string;
totalHits?: number; totalHits?: number;
children: React.ReactNode; children: React.ReactNode;
} }
const SearchResultSection = ({ title, href, totalHits, children }: SearchResultSectionProps) => ( const SearchResultSection = ({
title,
icon,
href,
totalHits,
children,
}: SearchResultSectionProps) => (
<> <>
{isDefined(totalHits) && totalHits > 0 && ( {isDefined(totalHits) && totalHits > 0 && (
<div> <div>
<div className="mb-6 grid place-content-start"> <div className="mb-6 grid place-content-start">
<UpPressable className="px-6 py-4" href={href}> <UpPressable
<p className="font-headers text-lg">{title}</p> className="grid grid-cols-[auto_1fr] place-items-center gap-6 px-6 py-4"
{isDefined(totalHits) && totalHits > SEARCH_LIMIT && ( href={href}>
<p className="text-sm">{`(showing ${SEARCH_LIMIT} out of ${totalHits} results)`}</p> <Ico icon={icon} className="!text-3xl" isFilled />
)} <div>
<p className="font-headers text-lg">{title}</p>
{isDefined(totalHits) && totalHits > SEARCH_LIMIT && (
/* TODO: Langui */
<p className="text-sm">{`(showing ${SEARCH_LIMIT} out of ${totalHits} results)`}</p>
)}
</div>
</UpPressable> </UpPressable>
</div> </div>
{children} {children}

View File

@ -123,8 +123,8 @@ const Channel = ({ channel, ...otherProps }: Props): JSX.Element => {
"duration", "duration",
"description", "description",
], ],
attributesToHighlight: ["title", "channel", "description"],
attributesToCrop: ["description"], attributesToCrop: ["description"],
attributesToHighlight: ["*"],
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined, sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
filter: [onlyShowGone ? "gone = true" : "", `channel_uid = ${channel.uid}`], filter: [onlyShowGone ? "gone = true" : "", `channel_uid = ${channel.uid}`],
}); });
@ -147,7 +147,6 @@ const Channel = ({ channel, ...otherProps }: Props): JSX.Element => {
useEffect(() => { useEffect(() => {
if (router.isReady) { if (router.isReady) {
console.log(router.query);
if (isDefined(router.query.page)) setPage(router.query.page); if (isDefined(router.query.page)) setPage(router.query.page);
if (isDefined(router.query.query)) setQuery(router.query.query); if (isDefined(router.query.query)) setQuery(router.query.query);
if (isDefined(router.query.sort)) setSortingMethod(router.query.sort); if (isDefined(router.query.sort)) setSortingMethod(router.query.sort);

View File

@ -117,8 +117,8 @@ const Videos = ({ ...otherProps }: Props): JSX.Element => {
"duration", "duration",
"description", "description",
], ],
attributesToHighlight: ["title", "channel", "description"],
attributesToCrop: ["description"], attributesToCrop: ["description"],
attributesToHighlight: ["*"],
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined, sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
filter: onlyShowGone ? ["gone = true"] : undefined, filter: onlyShowGone ? ["gone = true"] : undefined,
}); });
@ -141,7 +141,6 @@ const Videos = ({ ...otherProps }: Props): JSX.Element => {
useEffect(() => { useEffect(() => {
if (router.isReady) { if (router.isReady) {
console.log(router.query);
if (isDefined(router.query.page)) setPage(router.query.page); if (isDefined(router.query.page)) setPage(router.query.page);
if (isDefined(router.query.query)) setQuery(router.query.query); if (isDefined(router.query.query)) setQuery(router.query.query);
if (isDefined(router.query.sort)) setSortingMethod(router.query.sort); if (isDefined(router.query.sort)) setSortingMethod(router.query.sort);

View File

@ -109,7 +109,8 @@ const Video = ({ video, ...otherProps }: Props): JSX.Element => {
<h2 className="text-2xl">{langui.channel}</h2> <h2 className="text-2xl">{langui.channel}</h2>
<div> <div>
<Button <Button
href={`/archives/videos/c/${video.channel.data.attributes.uid}?page=1&query=&sort=1&gone=`} href={`/archives/videos/c/${video.channel.data.attributes.uid}\
?page=1&query=&sort=1&gone=`}
text={video.channel.data.attributes.title} text={video.channel.data.attributes.title}
/> />
<p> <p>

View File

@ -88,16 +88,15 @@ const Contents = (props: Props): JSX.Element => {
const fetchPosts = async () => { const fetchPosts = async () => {
const currentSortingMethod = sortingMethods[sortingMethod]; const currentSortingMethod = sortingMethods[sortingMethod];
const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, { const searchResult = await meiliSearch(MeiliIndices.CONTENT, query, {
attributesToCrop: ["translations.description"], attributesToRetrieve: ["translations", "id", "slug", "categories", "type", "thumbnail"],
attributesToHighlight: ["translations"],
attributesToCrop: ["translations.displayable_description"],
hitsPerPage: 25, hitsPerPage: 25,
page, page,
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined, sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
}); });
searchResult.hits = searchResult.hits.map((item) => { searchResult.hits = searchResult.hits.map((item) => {
if ( if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) {
Object.keys(item._matchesPosition).filter((match) => match.startsWith("translations"))
.length > 0
) {
item._formatted.translations = filterDefined(item._formatted.translations).filter( item._formatted.translations = filterDefined(item._formatted.translations).filter(
(translation) => containsHighlight(JSON.stringify(translation)) (translation) => containsHighlight(JSON.stringify(translation))
); );
@ -212,9 +211,11 @@ const Contents = (props: Props): JSX.Element => {
href={`/contents/${item.slug}`} href={`/contents/${item.slug}`}
translations={filterHasAttributes(item._formatted.translations, [ translations={filterHasAttributes(item._formatted.translations, [
"language.data.attributes.code", "language.data.attributes.code",
] as const).map(({ description, language, ...otherAttributes }) => ({ ] as const).map(({ displayable_description, language, ...otherAttributes }) => ({
...otherAttributes, ...otherAttributes,
description: containsHighlight(description) ? description : undefined, description: containsHighlight(displayable_description)
? displayable_description
: undefined,
language: language.data.attributes.code, language: language.data.attributes.code,
}))} }))}
fallback={{ title: prettySlug(item.slug) }} fallback={{ title: prettySlug(item.slug) }}

View File

@ -14,17 +14,23 @@ import { TextInput } from "components/Inputs/TextInput";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { useDeviceSupportsHover } from "hooks/useMediaQuery"; import { useDeviceSupportsHover } from "hooks/useMediaQuery";
import { ButtonGroup } from "components/Inputs/ButtonGroup"; import { ButtonGroup } from "components/Inputs/ButtonGroup";
import { filterDefined, isDefined, isDefinedAndNotEmpty, isUndefined } from "helpers/asserts"; import {
filterDefined,
filterHasAttributes,
isDefined,
isDefinedAndNotEmpty,
isUndefined,
} from "helpers/asserts";
import { getOpenGraph } from "helpers/openGraph"; import { getOpenGraph } from "helpers/openGraph";
import { HorizontalLine } from "components/HorizontalLine"; import { HorizontalLine } from "components/HorizontalLine";
import { getLangui } from "graphql/fetchLocalData"; import { getLangui } from "graphql/fetchLocalData";
import { sendAnalytics } from "helpers/analytics"; import { sendAnalytics } from "helpers/analytics";
import { atoms } from "contexts/atoms"; import { atoms } from "contexts/atoms";
import { useAtomGetter } from "helpers/atoms"; import { useAtomGetter } from "helpers/atoms";
import { CustomSearchResponse, meiliSearch } from "helpers/search"; import { containsHighlight, CustomSearchResponse, meiliSearch } from "helpers/search";
import { MeiliIndices, MeiliLibraryItem } from "shared/meilisearch-graphql-typings/meiliTypes"; import { MeiliIndices, MeiliLibraryItem } from "shared/meilisearch-graphql-typings/meiliTypes";
import { useTypedRouter } from "hooks/useTypedRouter"; import { useTypedRouter } from "hooks/useTypedRouter";
import { PreviewCard } from "components/PreviewCard"; import { TranslatedPreviewCard } from "components/PreviewCard";
import { prettyItemSubType } from "helpers/formatters"; import { prettyItemSubType } from "helpers/formatters";
import { isUntangibleGroupItem } from "helpers/libraryItem"; import { isUntangibleGroupItem } from "helpers/libraryItem";
import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs"; import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
@ -156,18 +162,27 @@ const Library = (props: Props): JSX.Element => {
const searchResult = await meiliSearch(MeiliIndices.LIBRARY_ITEM, query, { const searchResult = await meiliSearch(MeiliIndices.LIBRARY_ITEM, query, {
hitsPerPage: 25, hitsPerPage: 25,
page, page,
attributesToRetrieve: [
"title",
"subtitle",
"descriptions",
"id",
"slug",
"thumbnail",
"release_date",
"price",
"categories",
"metadata",
],
attributesToHighlight: ["title", "subtitle", "descriptions"],
attributesToCrop: ["descriptions"], attributesToCrop: ["descriptions"],
sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined, sort: isDefined(currentSortingMethod) ? [currentSortingMethod.meiliAttribute] : undefined,
filter, filter,
}); });
searchResult.hits = searchResult.hits.map((item) => { searchResult.hits = searchResult.hits.map((item) => {
if ( if (Object.keys(item._matchesPosition).some((match) => match.startsWith("descriptions"))) {
isDefined(item._formatted) &&
item._matchesPosition.descriptions &&
item._matchesPosition.descriptions.length > 0
) {
item._formatted.descriptions = filterDefined(item._formatted.descriptions).filter( item._formatted.descriptions = filterDefined(item._formatted.descriptions).filter(
(description) => description.includes("</mark>") (description) => containsHighlight(JSON.stringify(description))
); );
} }
return item; return item;
@ -188,16 +203,17 @@ const Library = (props: Props): JSX.Element => {
]); ]);
useEffect(() => { useEffect(() => {
if (router.isReady) console.log(router.query, filterUserStatus); if (router.isReady) {
router.updateQuery({ router.updateQuery({
page, page,
query, query,
sort: sortingMethod, sort: sortingMethod,
primary: showPrimaryItems, primary: showPrimaryItems,
secondary: showSecondaryItems, secondary: showSecondaryItems,
subitems: showSubitems, subitems: showSubitems,
status: fromLibraryItemUserStatusToString(filterUserStatus), status: fromLibraryItemUserStatusToString(filterUserStatus),
}); });
}
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [ }, [
page, page,
@ -212,7 +228,6 @@ const Library = (props: Props): JSX.Element => {
useEffect(() => { useEffect(() => {
if (router.isReady) { if (router.isReady) {
console.log(router.query);
if (isDefined(router.query.page)) setPage(router.query.page); if (isDefined(router.query.page)) setPage(router.query.page);
if (isDefined(router.query.query)) setQuery(router.query.query); if (isDefined(router.query.query)) setQuery(router.query.query);
if (isDefined(router.query.sort)) setSortingMethod(router.query.sort); if (isDefined(router.query.sort)) setSortingMethod(router.query.sort);
@ -387,16 +402,20 @@ const Library = (props: Props): JSX.Element => {
className="grid grid-cols-[repeat(auto-fill,_minmax(12rem,1fr))] items-end className="grid grid-cols-[repeat(auto-fill,_minmax(12rem,1fr))] items-end
gap-x-6 gap-y-8"> gap-x-6 gap-y-8">
{libraryItems?.hits.map((item) => ( {libraryItems?.hits.map((item) => (
<PreviewCard <TranslatedPreviewCard
key={item.id} key={item.id}
href={`/library/${item.slug}`} href={`/library/${item.slug}`}
title={item._formatted.title} translations={filterHasAttributes(item._formatted.descriptions, [
subtitle={item._formatted.subtitle} "language.data.attributes.code",
description={ ] as const).map((translation) => ({
item._matchesPosition.descriptions && item._matchesPosition.descriptions.length > 0 language: translation.language.data.attributes.code,
? item._formatted.descriptions?.[0] title: item.title,
: undefined subtitle: item.subtitle,
} description: containsHighlight(translation.description)
? translation.description
: undefined,
}))}
fallback={{ title: item._formatted.title, subtitle: item._formatted.subtitle }}
thumbnail={item.thumbnail?.data?.attributes} thumbnail={item.thumbnail?.data?.attributes}
thumbnailAspectRatio="21/29.7" thumbnailAspectRatio="21/29.7"
thumbnailRounded={false} thumbnailRounded={false}

View File

@ -11,7 +11,12 @@ import { WithLabel } from "components/Inputs/WithLabel";
import { TextInput } from "components/Inputs/TextInput"; import { TextInput } from "components/Inputs/TextInput";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { useDeviceSupportsHover } from "hooks/useMediaQuery"; import { useDeviceSupportsHover } from "hooks/useMediaQuery";
import { filterHasAttributes, isDefined, isDefinedAndNotEmpty } from "helpers/asserts"; import {
filterDefined,
filterHasAttributes,
isDefined,
isDefinedAndNotEmpty,
} from "helpers/asserts";
import { getOpenGraph } from "helpers/openGraph"; import { getOpenGraph } from "helpers/openGraph";
import { TranslatedPreviewCard } from "components/PreviewCard"; import { TranslatedPreviewCard } from "components/PreviewCard";
import { HorizontalLine } from "components/HorizontalLine"; import { HorizontalLine } from "components/HorizontalLine";
@ -78,6 +83,14 @@ const News = ({ ...otherProps }: Props): JSX.Element => {
sort: ["sortable_date:desc"], sort: ["sortable_date:desc"],
filter: ["hidden = false"], filter: ["hidden = false"],
}); });
searchResult.hits = searchResult.hits.map((item) => {
if (Object.keys(item._matchesPosition).some((match) => match.startsWith("translations"))) {
item._formatted.translations = filterDefined(item._formatted.translations).filter(
(translation) => JSON.stringify(translation).includes("</mark>")
);
}
return item;
});
setPosts(searchResult); setPosts(searchResult);
}; };
fetchPosts(); fetchPosts();

View File

@ -11,9 +11,8 @@ import {
WikiPageAttributesFragment, WikiPageAttributesFragment,
} from "./generated"; } from "./generated";
export interface MeiliLibraryItem extends Omit<LibraryItemAttributesFragment, "descriptions"> { export interface MeiliLibraryItem extends LibraryItemAttributesFragment {
id: string; id: string;
descriptions: string[];
sortable_name: string; sortable_name: string;
sortable_price: number | undefined; sortable_price: number | undefined;
sortable_date: number | undefined; sortable_date: number | undefined;
@ -23,20 +22,12 @@ export interface MeiliLibraryItem extends Omit<LibraryItemAttributesFragment, "d
export interface MeiliContent export interface MeiliContent
extends Omit<ContentAttributesFragment, "translations" | "updatedAt"> { extends Omit<ContentAttributesFragment, "translations" | "updatedAt"> {
id: string; id: string;
translations?: Array<{ translations: (Omit<
__typename?: "ComponentTranslationsTitle"; NonNullable<NonNullable<ContentAttributesFragment["translations"]>[number]>,
pre_title?: string | null; "text_set" | "description"
title: string; > & {
subtitle?: string | null; displayable_description?: string | null;
description?: string | null; })[];
language?: {
__typename?: "LanguageEntityResponse";
data?: {
__typename?: "LanguageEntity";
attributes?: { __typename?: "Language"; code: string } | null;
} | null;
} | null;
} | null> | null;
sortable_updated_date: number; sortable_updated_date: number;
} }