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 "title":
return (
{matcher.inverse
? t("search.title_does_not_contain")
: t("search.title_contains")}
{matcher.title}
);
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 && (
)}
);
}