From fadf9b69f17c3f0cc15e45c37d90205e067dd02a Mon Sep 17 00:00:00 2001 From: Abhas Bhattacharya Date: Mon, 19 Nov 2018 10:16:53 +0530 Subject: [PATCH] Add searchbox to filter recipes --- src/App.js | 7 ++- src/components/Header/header.js | 5 -- src/components/Recipes/recipes.css | 2 +- src/components/Recipes/recipes.js | 2 +- src/components/SearchBox/index.js | 3 ++ src/components/SearchBox/searchbox.css | 17 ++++++ src/components/SearchBox/searchbox.js | 72 ++++++++++++++++++++++++++ src/index.css | 4 ++ 8 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 src/components/SearchBox/index.js create mode 100644 src/components/SearchBox/searchbox.css create mode 100644 src/components/SearchBox/searchbox.js diff --git a/src/App.js b/src/App.js index f85c3b5..9999bba 100644 --- a/src/App.js +++ b/src/App.js @@ -1,7 +1,7 @@ import Header from './components/Header/header'; import Categories from './components/Categories'; import Recipes from './components/Recipes'; - +import SearchBox from './components/SearchBox'; import './App.css'; @@ -39,6 +39,11 @@ class App { ${ Header() } + ${ + SearchBox({ + recipes: this.data.recipes, + }) + } ${ Categories({ categories: this.data.categories, diff --git a/src/components/Header/header.js b/src/components/Header/header.js index 350af5d..eca1559 100644 --- a/src/components/Header/header.js +++ b/src/components/Header/header.js @@ -5,11 +5,6 @@ export default function Header() { return ( ` -
What would you like to eat? diff --git a/src/components/Recipes/recipes.css b/src/components/Recipes/recipes.css index 449569f..5ef090c 100644 --- a/src/components/Recipes/recipes.css +++ b/src/components/Recipes/recipes.css @@ -1,3 +1,3 @@ -.recipes-wrapper { +#recipes-wrapper { margin: 12px; } \ No newline at end of file diff --git a/src/components/Recipes/recipes.js b/src/components/Recipes/recipes.js index 336ff44..9bf0b41 100644 --- a/src/components/Recipes/recipes.js +++ b/src/components/Recipes/recipes.js @@ -5,7 +5,7 @@ import './recipes.css'; function Recipes(props) { return ( ` -
+
${ props.recipes.map((recipe) => ( RecipeCard({ diff --git a/src/components/SearchBox/index.js b/src/components/SearchBox/index.js new file mode 100644 index 0000000..590e5d5 --- /dev/null +++ b/src/components/SearchBox/index.js @@ -0,0 +1,3 @@ +import SearchBox from './searchbox'; + +export default SearchBox; diff --git a/src/components/SearchBox/searchbox.css b/src/components/SearchBox/searchbox.css new file mode 100644 index 0000000..66b59da --- /dev/null +++ b/src/components/SearchBox/searchbox.css @@ -0,0 +1,17 @@ +.search-box { + font-size: 18px; + display: flex; + align-items: center; + + margin: 12px; + border-bottom: 1px solid lightgray; +} + +.search-box-icon { + width: 32px; +} + +#search-input { + border: none; + width: calc(100% - 32px); +} diff --git a/src/components/SearchBox/searchbox.js b/src/components/SearchBox/searchbox.js new file mode 100644 index 0000000..abf7233 --- /dev/null +++ b/src/components/SearchBox/searchbox.js @@ -0,0 +1,72 @@ +import './searchbox.css'; + +function debounce(func, timeOut) { + var timeout; + return function () { + var context = this, args = arguments; + var later = function () { + timeout = undefined; + func.apply(context, args); + }; + + clearTimeout(timeout); + timeout = setTimeout(later, timeOut); + + var callNow = (timeout === undefined); + if (callNow) func.apply(context, args); + }; +}; + +export default function SearchBox(props) { + setTimeout(function () { + const recipesData = props.recipes; + + const searchInput = document.getElementById("search-input"); + const recipesWrapper = document.getElementById("recipes-wrapper"); + const allRecipeCards = [...document.getElementsByClassName("recipe-card")]; + + let lastFilteredRecipeCards = [...allRecipeCards]; + + function inputEventHandler(ev) { + ev.preventDefault(); + + const searchValue = searchInput.value.toLowerCase(); + + const filteredRecipeIndexes = recipesData.map((recipe, index) => { + const recipeName = recipe.name.toLowerCase(); + if (recipeName.indexOf(searchValue) > -1) { + return index; + } + return undefined; + }).filter((value) => value !== undefined); + + const filteredRecipeCards = filteredRecipeIndexes.map((recipeIndex) => { + return allRecipeCards[recipeIndex]; + }); + + lastFilteredRecipeCards.forEach(recipeCard => { + recipesWrapper.removeChild(recipeCard); + }); + + filteredRecipeCards.forEach(recipeCard => { + recipesWrapper.appendChild(recipeCard); + }); + + lastFilteredRecipeCards = filteredRecipeCards; + } + + searchInput.addEventListener('input', debounce(inputEventHandler, 500)); + }, + 100 + ); + + return ( + ` + + ` + ); +} diff --git a/src/index.css b/src/index.css index 3203122..a2ee48f 100644 --- a/src/index.css +++ b/src/index.css @@ -8,6 +8,10 @@ body { -moz-osx-font-smoothing: grayscale; } +input:focus { + outline: none +} + code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;