diff --git a/src/components/Buttons/Darkmode.js b/src/components/Buttons/Darkmode.js new file mode 100644 index 0000000..924937c --- /dev/null +++ b/src/components/Buttons/Darkmode.js @@ -0,0 +1,15 @@ +import React, { useContext } from "react"; +import { ThemeContext } from "../../Context/themeContext"; +import sol from "../../Sun.png"; +import lua from "../../Moon.png"; + +function Darkmode() { + const { theme } = useContext(ThemeContext); + return theme.mode === "light" ? ( + <img src={lua} alt="lua icone" className="w-10"></img> + ) : ( + <img src={sol} alt="sol icone" className="w-10"></img> + ); +} + +export default Darkmode; diff --git a/src/components/Buttons/Language.js b/src/components/Buttons/Language.js new file mode 100644 index 0000000..466af3d --- /dev/null +++ b/src/components/Buttons/Language.js @@ -0,0 +1,86 @@ +import { useEffect, useRef, useState } from "react"; +import langugagesData from "../../data/languages.json"; + +const CustomSelect = ({ theme, language, setLanguage }) => { + const [isOpen, setIsOpen] = useState(false); + const selectRef = useRef(null); + + const handleSelect = (lang) => { + setLanguage(lang); + }; + useEffect(() => { + setIsOpen(false); + const handleClickOutside = (event) => { + if (selectRef.current && !selectRef.current.contains(event.target)) { + setIsOpen(false); + } + }; + + // Handle click events outside of dropdown Menu + document.addEventListener("mousedown", handleClickOutside); + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, []); + return ( + <div + ref={selectRef} + className="inline-block w-full md:w-40 focus:outline-none" + > + {/* Custom Select Button */} + <button + onClick={() => setIsOpen(!isOpen)} + className={`w-full flex justify-between items-center px-4 rounded-md border outline-none${ + theme.mode === "dark" + ? "bg-slate-500 opacity-55 hover:opacity-100 text-slate-200 " + : "bg-slate-200 opacity-55 hover:opacity-100 text-black" + } transition duration-200 ease-in-out`} + > + {language || "Escolha uma opção"} + <span className="ml-2 transform transition-transform duration-200 ease-in-out"> + {isOpen ? "▲" : "▼"} + </span> + </button> + + {/* Dropdown Menu */} + {isOpen && ( + <> + <span className="font-mono max-sm:hidden absolute z-50 text-[7px] left-1/6 lg:left-1/2 -bottom-1 lg:bottom-6 border-b-2 border-solid border-b-cyan-800"> + scroll + </span> + <ul + className={`absolute z-10 mt-[0.75rem] h-40 overflow-x-hidden grid grid-cols-2 gap-1 sm:grid-cols-4 overflow-y-scroll w-1/2 py-1 dark:bg-slate-700 border rounded-md shadow-lg transform ${ + isOpen ? "scale-100 opacity-100" : "scale-95 opacity-0" + } ${ + theme.mode === "dark" + ? "bg-slate-700 text-slate-200 border-slate-600" + : "bg-white text-black border-gray-300" + }`} + > + <li + className={`opacity-50 leading-9 cursor-pointer text-[8px] rounded-br-3xl border-b-2 border-r-2 border-r-slate-400 border-b-slate-500`} + disabled + > + Escolha uma opção + </li> + {langugagesData.languages.map((lang, index) => ( + <li + key={index} + onClick={() => handleSelect(lang)} + className={`p-2 cursor-pointer text-sm hover:text-white transition-colors duration-150 ${ + theme.mode === "dark" + ? "bg-slate-700 text-slate-200 hover:bg-indigo-500" + : "bg-slate-50 text-black hover:bg-indigo-100" + }`} + > + {lang} + </li> + ))} + </ul> + </> + )} + </div> + ); +}; + +export default CustomSelect; diff --git a/src/components/Header.js b/src/components/Header.js index aa5fdff..b1bad5f 100644 --- a/src/components/Header.js +++ b/src/components/Header.js @@ -1,15 +1,13 @@ import { Navbar, Container } from "react-bootstrap"; import "./Header.css"; -import { useContext, useState, useEffect } from "react"; -import langugagesData from "../data/languages.json"; +import { useContext, useState, useEffect, useRef } from "react"; import logo from "./../logo.png"; import logo_white from "./../logo-white.png"; import { useDebouncedCallback } from "use-debounce"; -import sol from '../Sun.png'; -import lua from '../Moon.png'; - // Context import { ThemeContext } from "../Context/themeContext"; +import Darkmode from "./Buttons/Darkmode"; +import CustomSelect from "./Buttons/Language"; const Header = ({ language, setLanguage, setInputSearch }) => { const { theme, changeTheme } = useContext(ThemeContext); @@ -24,6 +22,7 @@ const Header = ({ language, setLanguage, setInputSearch }) => { ); const handleInputSearch = (inputValue) => { + setInputExpanded(true); // Keep input expanded while typing setInput(inputValue); debouncedInput(inputValue); }; @@ -32,6 +31,12 @@ const Header = ({ language, setLanguage, setInputSearch }) => { setInputSearch(input); }, [input, setInputSearch]); + const [inputExpanded, setInputExpanded] = useState(false); // Control input expansion state + + const handleSearchClick = () => { + setInputExpanded((prev) => !prev); // Expand input when clicked + }; + return ( <Navbar id="header"> <Container className=" flex lg:flex-row flex-col justify-center items-center w-full px-4"> @@ -43,51 +48,45 @@ const Header = ({ language, setLanguage, setInputSearch }) => { )} </Navbar.Brand> - <div className="flex justify-center items-center gap-11 w-full"> + <div className="flex justify-around items-center gap-11 w-full"> <label className={`${ - theme.mode === "light" ? "bg-slate-200" : "bg-white" - } flex rounded-3xl p-2 h-11 md:w-[40rem] `} + theme.mode === "light" ? "bg-slate-200" : "bg-slate-500" + } flex rounded-3xl p-2 h-11 w-full md:w-[40rem]`} > - <select - value={language} // Ensure the dropdown reflects the current language - onChange={(e) => setLanguage(e.target.value)} - className="text-sm text-black outline-none bg-transparent rounded-md " - > - <option disabled>Escolha uma opção</option> - {langugagesData.languages.map((lang, index) => ( - <option - className=" p-1 rounded-md" - key={index} - value={lang} - > - {lang} - </option> - ))} - </select> + <CustomSelect + theme={theme} // Correctly pass theme directly + language={language} // Correctly pass language + setLanguage={setLanguage} // Correctly pass setLanguage + /> + {/* Project Search Bar */} <input - className="outline-transparent bg-transparent text-black border-l-2 border-black ml-2 pl-2" type="text" + className={`transition-all h-7 ml-2 border-solid border-l-2 border-l-violet-950 pl-2 duration-1000 ease-in-out focus:outline-none outline-none ${ + inputExpanded + ? "w-1/2 pl-5 border-b-slate-300 border-b-2 border-solid" + : "w-1/2" + } bg-transparent ${ + theme.mode === "dark" + ? "opacity-100 text-slate-200" + : "opacity-70 text-slate-800" + }`} placeholder="Search" - value={input} // Mirror the input state to the input field - onChange={(e) => handleInputSearch(e.target.value)} - ></input> + autoComplete="off" + onMouseEnter={handleSearchClick} + onMouseLeave={handleSearchClick} + onKeyUp={(e) => handleInputSearch(e.target.value)} + /> </label> - <div onClick={changeTheme} className={ - "cursor-pointer hover:scale-105 transition-all ease-linear duration-200" + - "d-none d-sm-block fa " + "cursor-pointer max-lg:!hidden hover:scale-105 transition-all ease-linear duration-200" } style={{ fontSize: "1.5rem" }} aria-hidden="true" > - {theme.mode === "light" ? ( - <img src={lua} alt="lua icone" className="w-10"></img> - ) : ( - <img src={sol} alt="sol icone" className="w-10"></img> - )} + <Darkmode /> </div> </div> </Container> diff --git a/src/components/Navigation.js b/src/components/Navigation.js index e7d33cc..b03cf9a 100644 --- a/src/components/Navigation.js +++ b/src/components/Navigation.js @@ -6,6 +6,7 @@ import Sort from "./Buttons/Sort"; //Context import { ThemeContext } from "../Context/themeContext"; import "./Navigation.css"; +import Darkmode from "./Buttons/Darkmode"; const Navigation = ({ setPageNumber, @@ -19,7 +20,7 @@ const Navigation = ({ hasFilters, removePagination, }) => { - const { theme } = useContext(ThemeContext); + const { theme, changeTheme } = useContext(ThemeContext); let paginationItems = []; const [selectedPage, setSelectedPage] = useState(); if (pageNumber <= 3) pushItems(1, 5); // First 3 pages @@ -93,16 +94,27 @@ const Navigation = ({ )} {hasFilters && ( - <div className="flex"> - <Filter - reducedState={reducedState} - setReducedState={setReducedState} - /> - <div className="h-full w-[1px] bg-black"></div> - <Sort - setSortByStars={setSortByStars} - setSortByForks={setSortByForks} - /> + <div className="flex flex-col items-center justify-center gap-3 sm:flex-row "> + <div className="flex gap-[1px]"> + <Filter + reducedState={reducedState} + setReducedState={setReducedState} + /> + <Sort + setSortByStars={setSortByStars} + setSortByForks={setSortByForks} + /> + </div> + <div + onClick={changeTheme} + className={ + "cursor-pointer sm:ml-10 max-lg:!block hidden hover:scale-105 transition-all ease-linear duration-200" + } + style={{ fontSize: "1.5rem" }} + aria-hidden="true" + > + <Darkmode /> + </div> </div> )} </Container>