import { CornerDownLeftIcon, SearchIcon } from "lucide-react"; import { FormEvent, useEffect, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogTitle } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { useAppSidebar } from "@/contexts/AppSidebarContext"; import { type MemoFilter, replaceFiltersByFactor, stringifyFilters, useMemoFilterContext } from "@/contexts/MemoFilterContext"; import useCurrentUser from "@/hooks/useCurrentUser"; import { useMemoViews } from "@/hooks/useUserQueries"; import { BUILTIN_TASKS_VIEW_ID, getMemoViewId, isMemoScopeRoute } from "@/lib/memo-views"; import { ROUTES } from "@/router/routes"; import { useTranslate } from "@/utils/i18n"; export const isQuickFindCollectionRoute = (pathname: string) => isMemoScopeRoute(pathname) || pathname.startsWith("/u/"); export const buildQuickFindFilters = (query: string, currentFilters: MemoFilter[], preserveCurrentScope: boolean): MemoFilter[] => { const words = Array.from(new Set(query.trim().split(/\s+/).filter(Boolean))); const contentFilters: MemoFilter[] = words.map((value) => ({ factor: "contentSearch", value })); return preserveCurrentScope ? replaceFiltersByFactor(currentFilters, "contentSearch", contentFilters) : contentFilters; }; const getScopeLabel = (pathname: string, t: ReturnType) => { if (pathname === ROUTES.ARCHIVED) return t("common.archived"); if (pathname === ROUTES.EXPLORE) return t("common.explore"); if (pathname.startsWith("/u/")) return t("common.profile"); return t("common.memos"); }; const QuickFindDialog = () => { const t = useTranslate(); const location = useLocation(); const navigate = useNavigate(); const currentUser = useCurrentUser(); const { data: memoViews = [] } = useMemoViews(currentUser?.name); const { filters, setFilters, setMemoView, memoView } = useMemoFilterContext(); const { quickFindOpen, setQuickFindOpen } = useAppSidebar(); const [query, setQuery] = useState(""); const collectionRoute = isQuickFindCollectionRoute(location.pathname); const viewApplies = isMemoScopeRoute(location.pathname); const selectedMemoView = viewApplies ? memoViews.find((item) => getMemoViewId(item.name) === memoView) : undefined; const scopeLabel = viewApplies && memoView === BUILTIN_TASKS_VIEW_ID ? t("common.tasks") : selectedMemoView?.title || getScopeLabel(location.pathname, t); useEffect(() => { const handleKeyDown = (event: KeyboardEvent) => { if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") { event.preventDefault(); setQuickFindOpen(true); } }; window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [setQuickFindOpen]); useEffect(() => { if (!quickFindOpen) return; setQuery( filters .filter((filter) => filter.factor === "contentSearch") .map((filter) => filter.value) .join(" "), ); }, [filters, quickFindOpen]); const submitQuery = () => { const nextFilters = buildQuickFindFilters(query, filters, collectionRoute); if (collectionRoute) { setFilters(nextFilters); } else { const filterQuery = stringifyFilters(nextFilters); setFilters(nextFilters); setMemoView(undefined); navigate(filterQuery ? `${ROUTES.HOME}?filter=${filterQuery}` : ROUTES.HOME); } setQuickFindOpen(false); }; const handleSubmit = (event: FormEvent) => { event.preventDefault(); submitQuery(); }; return ( {t("common.search")} {t("common.search")} {scopeLabel}
setQuery(event.target.value)} onKeyDown={(event) => { if (event.key !== "Enter") return; event.preventDefault(); submitQuery(); }} className="h-10 border-0 bg-transparent px-0 !text-[14px] shadow-none focus-visible:ring-0" placeholder={`${t("common.search")} ${scopeLabel}`} aria-label={`${t("common.search")} ${scopeLabel}`} />
); }; export default QuickFindDialog;