├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.js
├── ListPage.js
├── Post.js
├── SearchBar.js
├── api
└── axios.js
├── index.css
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # "React Search Filter Tutorial"
2 |
3 | ---
4 |
5 | ### Author Links
6 |
7 | 👋 Hello, I'm Dave Gray.
8 |
9 | ✅ [Check out my YouTube Channel with all of my tutorials](https://www.youtube.com/DaveGrayTeachesCode).
10 |
11 | 🚩 [Subscribe to my channel](https://bit.ly/3nGHmNn)
12 |
13 | ☕ [Buy Me A Coffee](https://buymeacoffee.com/DaveGray)
14 |
15 | 🚀 Follow Me:
16 |
17 | - [Twitter](https://twitter.com/yesdavidgray)
18 | - [LinkedIn](https://www.linkedin.com/in/davidagray/)
19 | - [Blog](https://yesdavidgray.com)
20 | - [Reddit](https://www.reddit.com/user/DaveOnEleven)
21 |
22 | ---
23 |
24 | ### Description
25 |
26 | 📺 [YouTube Video](https://youtu.be/ZoayCCDHFiI) for this repository.
27 |
28 | ---
29 |
30 | ### 💻 Source Code
31 |
32 | - 🔗 [React Search Filter Tutorial - Completed Source Code](https://github.com/gitdagray/react_search_filter)
33 |
34 | ---
35 |
36 | ### 🎓 Academic Honesty
37 |
38 | **DO NOT COPY FOR AN ASSIGNMENT** - Avoid plagiargism and adhere to the spirit of this [Academic Honesty Policy](https://www.freecodecamp.org/news/academic-honesty-policy/).
39 |
40 | ---
41 |
42 | ### 📚 Tutorial References
43 |
44 | - 🔗 [Use FontAwesome with React](https://fontawesome.com/docs/web/use-with/react/)
45 | - 🔗 [JSON Placeholder: Posts](https://jsonplaceholder.typicode.com/posts)
46 |
47 | ### ⚙ VS Code Extensions I Use:
48 |
49 | - 🔗 [ES7 React JS Snippets Extension](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets)
50 | - 🔗 [vscode-icons VS Code Extension](https://marketplace.visualstudio.com/items?itemName=vscode-icons-team.vscode-icons)
51 | - 🔗 [Github Themes VS Code Extension](https://marketplace.visualstudio.com/items?itemName=GitHub.github-vscode-theme)
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react_search_filter",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@fortawesome/fontawesome-svg-core": "^6.1.1",
7 | "@fortawesome/free-solid-svg-icons": "^6.1.1",
8 | "@fortawesome/react-fontawesome": "^0.2.0",
9 | "axios": "^0.27.2",
10 | "react": "^18.2.0",
11 | "react-dom": "^18.2.0",
12 | "react-scripts": "5.0.1"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": [
22 | "react-app",
23 | "react-app/jest"
24 | ]
25 | },
26 | "browserslist": {
27 | "production": [
28 | ">0.2%",
29 | "not dead",
30 | "not op_mini all"
31 | ],
32 | "development": [
33 | "last 1 chrome version",
34 | "last 1 firefox version",
35 | "last 1 safari version"
36 | ]
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitdagray/react_search_filter/752770507090f22b3957be9c68957b4da706bbbf/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitdagray/react_search_filter/752770507090f22b3957be9c68957b4da706bbbf/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gitdagray/react_search_filter/752770507090f22b3957be9c68957b4da706bbbf/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import { getPosts } from './api/axios'
2 | import { useState, useEffect } from 'react'
3 | import SearchBar from './SearchBar'
4 | import ListPage from './ListPage'
5 |
6 | function App() {
7 | const [posts, setPosts] = useState([])
8 | const [searchResults, setSearchResults] = useState([])
9 |
10 | useEffect(() => {
11 | getPosts().then(json => {
12 | setPosts(json)
13 | setSearchResults(json)
14 | })
15 | }, [])
16 |
17 |
18 |
19 | return (
20 | <>
21 |
22 |
23 | >
24 | )
25 | }
26 |
27 | export default App;
28 |
--------------------------------------------------------------------------------
/src/ListPage.js:
--------------------------------------------------------------------------------
1 | import Post from "./Post"
2 |
3 | const ListPage = ({ searchResults }) => {
4 |
5 | const results = searchResults.map(post => )
6 |
7 | const content = results?.length ? results : No Matching Posts
8 |
9 | return (
10 | {content}
11 | )
12 | }
13 | export default ListPage
--------------------------------------------------------------------------------
/src/Post.js:
--------------------------------------------------------------------------------
1 | const Post = ({ post }) => {
2 | return (
3 |
4 | {post.title}
5 | {post.body}
6 | Post ID: {post.id}
7 |
8 | )
9 | }
10 | export default Post
--------------------------------------------------------------------------------
/src/SearchBar.js:
--------------------------------------------------------------------------------
1 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
2 | import { faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons"
3 |
4 | const SearchBar = ({ posts, setSearchResults }) => {
5 | const handleSubmit = (e) => e.preventDefault()
6 |
7 | const handleSearchChange = (e) => {
8 | if (!e.target.value) return setSearchResults(posts)
9 |
10 | const resultsArray = posts.filter(post => post.title.includes(e.target.value) || post.body.includes(e.target.value))
11 |
12 | setSearchResults(resultsArray)
13 | }
14 |
15 | return (
16 |
29 | )
30 | }
31 | export default SearchBar
--------------------------------------------------------------------------------
/src/api/axios.js:
--------------------------------------------------------------------------------
1 | import axios from "axios"
2 |
3 | export const api = axios.create({
4 | baseURL: 'https://jsonplaceholder.typicode.com'
5 | })
6 |
7 | export const getPosts = async () => {
8 | const response = await api.get('/posts')
9 | return response.data
10 | }
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Nunito&display=swap");
2 |
3 | * {
4 | margin: 0;
5 | padding: 0;
6 | box-sizing: border-box;
7 | }
8 |
9 | input,
10 | button {
11 | font: inherit;
12 | }
13 |
14 | html {
15 | font-size: 1.5rem;
16 | }
17 |
18 | body {
19 | background-color: #000;
20 | font-family: 'Nunito', sans-serif;
21 | }
22 |
23 | p {
24 | color: whitesmoke;
25 | margin-top: 0.5em;
26 | }
27 |
28 | article {
29 | margin: 1em;
30 | padding: 1em;
31 | background-color: midnightblue;
32 | color: whitesmoke;
33 | border-radius: 15px;
34 | }
35 |
36 | img {
37 | border-radius: 15px;
38 | display: block;
39 | }
40 |
41 | header {
42 | background-color: gold;
43 | padding: 1em;
44 | display: flex;
45 | justify-content: center;
46 | align-items: center;
47 | }
48 |
49 | .search {
50 | width: 95%;
51 | border: 2px solid #000;
52 | border-radius: 2em;
53 | overflow: hidden;
54 | font-size: 1rem;
55 | display: flex;
56 | flex-flow: row nowrap;
57 | }
58 |
59 | .search:focus-within {
60 | box-shadow: 2px 2px 5px #000;
61 | }
62 |
63 | .search__button,
64 | .search__input {
65 | background-color: #fff;
66 | border: none;
67 | outline: none;
68 | }
69 |
70 | .search__input {
71 | padding: 1em;
72 | width: 85%;
73 | }
74 |
75 | .search__button {
76 | width: 15%;
77 | font-size: 1.5rem;
78 | padding-right: 0.5em;
79 | color: gray;
80 | display: grid;
81 | place-content: center;
82 | }
83 |
84 | @media (min-width: 576px) {
85 | .search {
86 | font-size: 1.5rem;
87 | }
88 |
89 | .search__button {
90 | font-size: 2rem;
91 | }
92 | }
93 |
94 | @media (min-width: 800px) {
95 | .search {
96 | width: 75%;
97 | font-size: 2rem;
98 | }
99 |
100 | .search__button {
101 | padding-right: 0.5em;
102 | font-size: 3rem;
103 | }
104 | }
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 |
6 | const root = ReactDOM.createRoot(document.getElementById('root'));
7 | root.render(
8 |
9 |
10 |
11 | );
--------------------------------------------------------------------------------