diff --git a/src/App.tsx b/src/App.tsx index fc2d1278..9ca9b6dd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,29 +1,24 @@ -import { useAppContext } from "./contexts/AppContext"; - +import { Routes, Route, BrowserRouter } from "react-router-dom"; import Header from "./layouts/Header"; import Banner from "./layouts/Banner"; -import Sidebar from "./layouts/Sidebar"; import Footer from "./layouts/Footer"; - -import SnippetList from "./components/SnippetList"; +import HomePage from "./pages/HomePage.tsx"; +import SearchPage from "./pages/SearchPage.tsx"; const App = () => { - const { category } = useAppContext(); - return (
-
- -
- -
-

- {category ? category : "Select a category"} -

- -
-
-
); }; diff --git a/src/components/SearchFilters.tsx b/src/components/SearchFilters.tsx new file mode 100644 index 00000000..40a44358 --- /dev/null +++ b/src/components/SearchFilters.tsx @@ -0,0 +1,22 @@ +import { useCategories } from "../hooks/useCategories"; +import { useAppContext } from "../contexts/AppContext"; + +const SearchFilters = () => { + const { category, setCategory } = useAppContext(); + const { fetchedCategories } = useCategories(); + + return ( +
+ +
+ ); +}; + +export default SearchFilters; diff --git a/src/components/SearchInput.tsx b/src/components/SearchInput.tsx index 03ed5f90..c760cdf6 100644 --- a/src/components/SearchInput.tsx +++ b/src/components/SearchInput.tsx @@ -1,18 +1,63 @@ import { SearchIcon } from "./Icons"; +import { useState, useCallback } from "react"; +import { useSearchParams, useNavigate, useLocation } from "react-router-dom"; const SearchInput = () => { + const navigate = useNavigate(); + const location = useLocation(); + const [searchParams, setSearchParams] = useSearchParams(); + const [searchValue, setSearchValue] = useState(searchParams.get("q") || ""); + + const navigateToSearch = useCallback( + (query: string, isCompletedSearch = false) => { + const trimmedQuery = query.trim().toLowerCase(); + + if (!trimmedQuery) { + // Remove search params and navigate to home if query is empty + setSearchParams({}); + navigate("/", { replace: true }); + return; + } + + // Set the search params with the query + // Use replace: true for keypresses (when isCompletedSearch is false) + setSearchParams({ q: trimmedQuery }, { replace: !isCompletedSearch }); + + // Only navigate if we're not already on the search page + if (location.pathname !== "/search") { + navigate("/search", { + replace: isCompletedSearch || location.pathname === "/search", + }); + } + }, + [navigate, location.pathname, setSearchParams] + ); + return ( -
+
{ + e.preventDefault(); + navigateToSearch(searchValue, true); + }} + className="search-field" + > { + const newValue = e.target.value; + setSearchValue(newValue); + navigateToSearch(newValue, false); + }} + onBlur={() => navigateToSearch(searchValue, true)} placeholder="Search here..." autoComplete="off" /> -
+ ); }; diff --git a/src/components/SnippetList.tsx b/src/components/SnippetList.tsx index 6b4a5ce7..f1756f9e 100644 --- a/src/components/SnippetList.tsx +++ b/src/components/SnippetList.tsx @@ -1,22 +1,25 @@ -import { useState } from "react"; +import { useState, useMemo } from "react"; import { SnippetType } from "../types"; import { useAppContext } from "../contexts/AppContext"; import { useSnippets } from "../hooks/useSnippets"; import SnippetModal from "./SnippetModal"; -import { LeftAngleArrowIcon } from "./Icons"; -const SnippetList = () => { +const SnippetList = ({ query }: { query?: string | null }) => { const { language, snippet, setSnippet } = useAppContext(); - const { fetchedSnippets } = useSnippets(); + const { fetchedSnippets, loading } = useSnippets(); const [isModalOpen, setIsModalOpen] = useState(false); - if (!fetchedSnippets) - return ( -
- -
+ const filteredSnippets = useMemo(() => { + if (!query) return fetchedSnippets; + return fetchedSnippets.filter((snippet) => + snippet.title.toLowerCase().includes(query.toLowerCase()) ); + }, [fetchedSnippets, query]); + + if (loading) return
Loading...
; + if (!filteredSnippets || filteredSnippets.length === 0) + return
No results found for "{query}"
; const handleOpenModal = (activeSnippet: SnippetType) => { setIsModalOpen(true); @@ -31,7 +34,7 @@ const SnippetList = () => { return ( <>