Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 127 additions & 27 deletions src/components/Search.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,61 @@

*/

import { useState } from "react";
import { SearchIcon } from "@chakra-ui/icons";
import { Input, InputGroup, InputLeftElement } from "@chakra-ui/react";
import { useEffect } from "react";
import { useState, useEffect } from "react";
import { SearchIcon, SmallCloseIcon } from "@chakra-ui/icons";
import {
Input,
InputGroup,
InputLeftElement,
InputRightElement,
Box,
Text,
List,
ListItem,
useColorModeValue,
} from "@chakra-ui/react";
import { motion, AnimatePresence } from "framer-motion";

const MotionSearchIcon = motion(SearchIcon);

export default function Search({ setCategoriesList, categoriesList }) {
const [searchField, setSearchField] = useState("");
const [filteredCount, setFilteredCount] = useState(categoriesList.length);
const [showSuggestions, setShowSuggestions] = useState(false);

const handleChange = (e) => {
setSearchField(e.target.value);
setShowSuggestions(true);
};

const handleClear = () => {
setSearchField("");
setCategoriesList(categoriesList);
setFilteredCount(categoriesList.length);
setShowSuggestions(false);
};

const formatString = (string) =>
string
.toLowerCase()
.normalize("NFD")
.replace(/\p{Diacritic}| /gu, "");

// Filter categories whenever searchField changes
useEffect(() => {
if (!searchField) setCategoriesList(categoriesList);
if (!searchField) {
setCategoriesList(categoriesList);
setFilteredCount(categoriesList.length);
return;
}
const categoriesBySearchTerm = categoriesList.filter((cat) => {
return formatString(cat.title).includes(formatString(searchField));
});
setCategoriesList(categoriesBySearchTerm);
}, [searchField]);
setFilteredCount(categoriesBySearchTerm.length);
}, [searchField, categoriesList, setCategoriesList]);

// Handle visual class for grid animation (legacy/existing logic)
useEffect(() => {
setTimeout(() => {
if (searchField.length !== 0) {
Expand All @@ -73,29 +106,96 @@ export default function Search({ setCategoriesList, categoriesList }) {
}, [searchField]);

function handleFocus() {
let homeGrid = document.querySelector(".home-grid");
let height = homeGrid.offsetHeight;
homeGrid.style.minHeight = height + "px";
let homeGrid = document.querySelector(".home-grid"); // Note: might be null if removed in previous step, checking existence
if (homeGrid) {
let height = homeGrid.offsetHeight;
homeGrid.style.minHeight = height + "px";
}
setShowSuggestions(true);
}

const suggestions = categoriesList.filter((cat) =>
formatString(cat.title).includes(formatString(searchField))
).slice(0, 5); // Limit suggestions

const suggestionsBg = useColorModeValue("white", "gray.700");
const suggestionsHoverBg = useColorModeValue("gray.100", "gray.600");

return (
<InputGroup
w={{ sm: "100%", md: "80%", lg: "60%", "2xl": "60%", "3xl": "50%" }}
>
<InputLeftElement
pointerEvents="none"
children={<SearchIcon color="black" />}
/>
<Input
onFocus={handleFocus}
color="black"
type="text"
placeholder=""
onChange={handleChange}
borderRadius={"2rem"}
focusBorderColor="initial"
bg="white"
/>
</InputGroup>
<Box w={{ sm: "100%", md: "80%", lg: "60%", "2xl": "60%", "3xl": "50%" }} position="relative" zIndex={10}>
<InputGroup>
<InputLeftElement pointerEvents="none">
<MotionSearchIcon
color="black"
animate={{ scale: searchField ? 1.2 : 1 }}
transition={{ type: "spring", stiffness: 300 }}
/>
</InputLeftElement>
<Input
onFocus={handleFocus}
onBlur={() => setTimeout(() => setShowSuggestions(false), 200)} // Delay to allow click
color="black"
type="text"
placeholder=""
value={searchField}
onChange={handleChange}
borderRadius={"2rem"}
focusBorderColor="blue.400"
_focus={{ boxShadow: "0 0 0 3px rgba(66, 153, 225, 0.6)" }}
bg="white"
/>
{searchField && (
<InputRightElement cursor="pointer" onClick={handleClear}>
<SmallCloseIcon color="gray.500" />
</InputRightElement>
)}
</InputGroup>

{/* Results Count */}
{searchField && (
<Text fontSize="xs" mt={1} ml={4} color="gray.500">
Found {filteredCount} result{filteredCount !== 1 ? "s" : ""}
</Text>
)}

{/* Autocomplete Suggestions */}
<AnimatePresence>
{showSuggestions && searchField && suggestions.length > 0 && (
<Box
as={motion.div}
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
position="absolute"
top="100%"
left={0}
right={0}
mt={2}
bg={suggestionsBg}
borderRadius="md"
boxShadow="lg"
overflow="hidden"
>
<List spacing={0}>
{suggestions.map((cat) => (
<ListItem
key={cat.title}
px={4}
py={2}
cursor="pointer"
_hover={{ bg: suggestionsHoverBg }}
onClick={() => {
setSearchField(cat.title);
setShowSuggestions(false);
}}
>
<Text fontSize="sm" color={useColorModeValue("black", "white")}>{cat.title}</Text>
</ListItem>
))}
</List>
</Box>
)}
</AnimatePresence>
</Box>
);
}
7 changes: 6 additions & 1 deletion src/pages/HomePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import { useState } from "react";
import { Categories } from "../assets/ConfigRoutes";
import MenuBox from "../components/MenuBox";
import Search from "../components/Search"; // Added import
import { Flex, Grid, Heading } from "@chakra-ui/react";

import { motion } from "framer-motion";
Expand Down Expand Up @@ -78,6 +79,8 @@ export default function HomePage() {
gap="3rem"
px={{ sm: "1rem", md: "0px" }}
>
<Search setCategoriesList={setCategoriesListForSearch} categoriesList={Categories} />

<Grid
as={motion.section}
initial="initial"
Expand All @@ -99,7 +102,9 @@ export default function HomePage() {
H αναζήτηση δεν επέστρεψε αποτελέσματα.
</Heading>
) : null}
{categoriesSortedAndWithoutHiddenPages.map((category) => (

{/* WE MUST USE THE FILTERED LIST HERE */}
{filterOutHiddenPages(sortToPlaceInDefinedOrder(categoriesListForSearch)).map((category) => (
<MenuBox category={category} key={category.title} />
))}
</Grid>
Expand Down