blob: 1c26608e4dec1060bfd5a60b21f5da0d03903026 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
"use client";
import { api } from "@/lib/trpc";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import BookmarksGrid from "../bookmarks/components/BookmarksGrid";
import { Input } from "@/components/ui/input";
import Loading from "../bookmarks/loading";
import { keepPreviousData } from "@tanstack/react-query";
import { Search } from "lucide-react";
import { ActionButton } from "@/components/ui/action-button";
import { Suspense, useRef } from "react";
function SearchComp() {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
const searchQuery = searchParams.get("q") || "";
const { data, isPending, isPlaceholderData, error } =
api.bookmarks.searchBookmarks.useQuery(
{
text: searchQuery,
},
{
placeholderData: keepPreviousData,
},
);
if (error) {
throw error;
}
const inputRef: React.MutableRefObject<HTMLInputElement | null> =
useRef<HTMLInputElement | null>(null);
let timeoutId: NodeJS.Timeout | undefined;
// Debounce user input
const doSearch = () => {
if (!inputRef.current) {
return;
}
router.replace(`${pathname}?q=${inputRef.current.value}`);
};
const onInputChange = () => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
doSearch();
}, 200);
};
return (
<div className="container flex flex-col gap-3 p-4">
<div className="flex gap-2">
<Input
ref={inputRef}
placeholder="Search"
defaultValue={searchQuery}
onChange={onInputChange}
/>
<ActionButton
loading={isPending || isPlaceholderData}
onClick={doSearch}
>
<span className="flex gap-2">
<Search />
<span className="my-auto">Search</span>
</span>
</ActionButton>
</div>
<hr />
{data ? (
<BookmarksGrid
query={{ ids: data.bookmarks.map((b) => b.id) }}
bookmarks={data.bookmarks}
/>
) : (
<Loading />
)}
</div>
);
}
export default function SearchPage() {
return (
<Suspense>
<SearchComp />
</Suspense>
);
}
|