import InfoTooltip from "@/components/ui/info-tooltip"; import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table"; import { useTranslation } from "@/lib/i18n/client"; import { match } from "@/lib/utils"; import { TextAndMatcher } from "@karakeep/shared/searchQueryParser"; import { Matcher } from "@karakeep/shared/types/search"; export default function QueryExplainerTooltip({ parsedSearchQuery, header, className, }: { header?: React.ReactNode; parsedSearchQuery: TextAndMatcher & { result: string }; className?: string; }) { const { t } = useTranslation(); if (parsedSearchQuery.result == "invalid") { return null; } const MatcherComp = ({ matcher }: { matcher: Matcher }) => { switch (matcher.type) { case "tagName": return ( {matcher.inverse ? t("search.does_not_have_tag") : t("search.has_tag")} {matcher.tagName} ); case "listName": return ( {matcher.inverse ? t("search.is_not_in_list") : t("search.is_in_list")} {matcher.listName} ); case "dateAfter": return ( {matcher.inverse ? t("search.not_created_on_or_after") : t("search.created_on_or_after")} {matcher.dateAfter.toDateString()} ); case "dateBefore": return ( {matcher.inverse ? t("search.not_created_on_or_before") : t("search.created_on_or_before")} {matcher.dateBefore.toDateString()} ); case "age": return ( {matcher.relativeDate.direction === "newer" ? t("search.created_within") : t("search.created_earlier_than")} {matcher.relativeDate.amount.toString() + (matcher.relativeDate.direction === "newer" ? { day: t("search.day_s"), week: t("search.week_s"), month: t("search.month_s"), year: t("search.year_s"), }[matcher.relativeDate.unit] : { day: t("search.day_s_ago"), week: t("search.week_s_ago"), month: t("search.month_s_ago"), year: t("search.year_s_ago"), }[matcher.relativeDate.unit])} ); case "favourited": return ( {matcher.favourited ? t("search.is_favorited") : t("search.is_not_favorited")} ); case "archived": return ( {matcher.archived ? t("search.is_archived") : t("search.is_not_archived")} ); case "tagged": return ( {matcher.tagged ? t("search.has_any_tag") : t("search.has_no_tags")} ); case "inlist": return ( {matcher.inList ? t("search.is_in_any_list") : t("search.is_not_in_any_list")} ); case "and": case "or": return ( {matcher.type === "and" ? t("search.and") : t("search.or")} {matcher.matchers.map((m, i) => ( ))}
); case "url": return ( {matcher.inverse ? t("search.url_does_not_contain") : t("search.url_contains")} {matcher.url} ); case "rssFeedName": return ( {matcher.inverse ? t("search.is_not_from_feed") : t("search.is_from_feed")} {matcher.feedName} ); case "type": return ( {matcher.inverse ? t("search.type_is_not") : t("search.type_is")} {match(matcher.typeName, { link: t("common.bookmark_types.link"), text: t("common.bookmark_types.text"), asset: t("common.bookmark_types.media"), })} ); default: { const _exhaustiveCheck: never = matcher; return null; } } }; return ( {header} {parsedSearchQuery.text && ( {t("search.full_text_search")} {parsedSearchQuery.text} )} {parsedSearchQuery.matcher && ( )}
); }