feat: implement real search
This commit is contained in:
parent
9b964dd4f4
commit
0ad37ad433
|
@ -11,6 +11,7 @@ import { ChevronDownIcon, ChevronRightIcon } from "@heroicons/react/24/outline";
|
||||||
import { flushSync } from "react-dom";
|
import { flushSync } from "react-dom";
|
||||||
import {
|
import {
|
||||||
Link,
|
Link,
|
||||||
|
useFetcher,
|
||||||
useLocation,
|
useLocation,
|
||||||
useNavigate,
|
useNavigate,
|
||||||
useSearchParams,
|
useSearchParams,
|
||||||
|
@ -40,6 +41,8 @@ const SearchBar = ({ sites }: { sites: SiteList }) => {
|
||||||
const [dirtyInput, setDirtyInput] = useState(false);
|
const [dirtyInput, setDirtyInput] = useState(false);
|
||||||
const [results, setResults] = useState<SearchResult[]>([]);
|
const [results, setResults] = useState<SearchResult[]>([]);
|
||||||
|
|
||||||
|
const fetcher = useFetcher();
|
||||||
|
|
||||||
const handleSearch = useCallback(
|
const handleSearch = useCallback(
|
||||||
async (event: FormEvent<HTMLFormElement>) => {
|
async (event: FormEvent<HTMLFormElement>) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -50,22 +53,24 @@ const SearchBar = ({ sites }: { sites: SiteList }) => {
|
||||||
newSearchParams.set("q", query);
|
newSearchParams.set("q", query);
|
||||||
} else {
|
} else {
|
||||||
newSearchParams.delete("q");
|
newSearchParams.delete("q");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
navigate(`${pathname}?${newSearchParams.toString()}`);
|
navigate(`${pathname}?${newSearchParams.toString()}`);
|
||||||
|
|
||||||
// Perform search and update results state
|
fetcher.load(`/api/search?${newSearchParams}`);
|
||||||
// const searchResults = await fetchResults(query);
|
|
||||||
// Mock the search results
|
|
||||||
const searchResults = await getResults({ query });
|
|
||||||
|
|
||||||
setResults(searchResults);
|
|
||||||
setIsLoading(false);
|
|
||||||
setActiveInput(false);
|
|
||||||
},
|
},
|
||||||
[query, searchParams, navigate, pathname]
|
[query, searchParams, navigate, pathname]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (fetcher.data) {
|
||||||
|
setResults(fetcher.data as SearchResult[]);
|
||||||
|
setIsLoading(false);
|
||||||
|
setActiveInput(false);
|
||||||
|
}
|
||||||
|
}, [fetcher.data]);
|
||||||
|
|
||||||
const isActive = results.length > 0 || dirtyInput;
|
const isActive = results.length > 0 || dirtyInput;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -9,13 +9,10 @@ import {
|
||||||
} from "@remix-run/react";
|
} from "@remix-run/react";
|
||||||
import Header from "@/components/LayoutHeader"; // Adjust the import path as needed
|
import Header from "@/components/LayoutHeader"; // Adjust the import path as needed
|
||||||
import Footer from "@/components/LayoutFooter"; // Adjust the import path as needed
|
import Footer from "@/components/LayoutFooter"; // Adjust the import path as needed
|
||||||
import globalStyles from "../styles/global.scss?inline";
|
import globalStyles from "../styles/global.scss?url";
|
||||||
import { cssBundleHref } from "@remix-run/css-bundle"; // Adjust the import path as needed
|
|
||||||
|
|
||||||
export const links: LinksFunction = () => [
|
export const links: LinksFunction = () => [
|
||||||
{ rel: "stylesheet", href: globalStyles },
|
{ rel: "stylesheet", href: globalStyles },
|
||||||
|
|
||||||
...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []),
|
|
||||||
// Add your Google font links here
|
// Add your Google font links here
|
||||||
// Example: { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@400&display=swap" },
|
// Example: { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Be+Vietnam+Pro:wght@400&display=swap" },
|
||||||
// Example: { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Jaldi:wght@400&display=swap" },
|
// Example: { rel: "stylesheet", href: "https://fonts.googleapis.com/css2?family=Jaldi:wght@400&display=swap" },
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { type LoaderFunctionArgs } from "@remix-run/node";
|
||||||
|
import search from "@/lib/search.js";
|
||||||
|
|
||||||
|
export async function loader({ request }: LoaderFunctionArgs) {
|
||||||
|
const searchParams = new URL(request.url).searchParams;
|
||||||
|
|
||||||
|
const query = searchParams.get("q");
|
||||||
|
|
||||||
|
if (!query || !query.length) {
|
||||||
|
throw new Response("Invalid query", {
|
||||||
|
status: 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await search.index("articles").search(query);
|
||||||
|
|
||||||
|
return results.hits.map((item) => {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
timestamp: item.createdAt,
|
||||||
|
title: item.title,
|
||||||
|
description: "",
|
||||||
|
slug: item.slug,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue