├── public ├── favicon.ico ├── logo192.png ├── logo512.png ├── robots.txt ├── manifest.json └── index.html ├── src ├── assets │ ├── icons │ │ ├── pokeball.png │ │ ├── pokemon │ │ │ └── types │ │ │ │ ├── bug.png │ │ │ │ ├── dark.png │ │ │ │ ├── fairy.png │ │ │ │ ├── fire.png │ │ │ │ ├── ghost.png │ │ │ │ ├── grass.png │ │ │ │ ├── ice.png │ │ │ │ ├── rock.png │ │ │ │ ├── steel.png │ │ │ │ ├── water.png │ │ │ │ ├── dragon.png │ │ │ │ ├── flying.png │ │ │ │ ├── ground.png │ │ │ │ ├── normal.png │ │ │ │ ├── poison.png │ │ │ │ ├── psychic.png │ │ │ │ ├── electric.png │ │ │ │ ├── fighting.png │ │ │ │ └── normal_la.png │ │ └── busqueda.svg │ └── screenshots │ │ ├── card.PNG │ │ ├── grid.PNG │ │ ├── search.PNG │ │ ├── card-venasaur.PNG │ │ └── card-blastoise.PNG ├── layout │ ├── container.jsx │ └── grid.jsx ├── components │ ├── footer.jsx │ ├── navbar.jsx │ ├── search.jsx │ ├── card.jsx │ └── modal.jsx ├── index.jsx ├── index.css ├── utils │ └── icons.js ├── colors.css ├── App.jsx └── App.css ├── .gitignore ├── package.json └── README.md /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/assets/icons/pokeball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokeball.png -------------------------------------------------------------------------------- /src/assets/screenshots/card.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/screenshots/card.PNG -------------------------------------------------------------------------------- /src/assets/screenshots/grid.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/screenshots/grid.PNG -------------------------------------------------------------------------------- /src/assets/screenshots/search.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/screenshots/search.PNG -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/bug.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/dark.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/fairy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/fairy.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/fire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/fire.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/ghost.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/ghost.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/grass.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/ice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/ice.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/rock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/rock.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/steel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/steel.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/water.png -------------------------------------------------------------------------------- /src/assets/screenshots/card-venasaur.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/screenshots/card-venasaur.PNG -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/dragon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/dragon.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/flying.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/flying.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/ground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/ground.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/normal.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/poison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/poison.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/psychic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/psychic.png -------------------------------------------------------------------------------- /src/assets/screenshots/card-blastoise.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/screenshots/card-blastoise.PNG -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/electric.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/electric.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/fighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/fighting.png -------------------------------------------------------------------------------- /src/assets/icons/pokemon/types/normal_la.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Onnichan/pokeapi-react/HEAD/src/assets/icons/pokemon/types/normal_la.png -------------------------------------------------------------------------------- /src/layout/container.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class Container extends React.Component{ 4 | 5 | render(){ 6 | return( 7 |
{this.props.children}
8 | ) 9 | } 10 | } -------------------------------------------------------------------------------- /src/components/footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class Footer extends React.Component{ 4 | 5 | render(){ 6 | return( 7 | 10 | ) 11 | } 12 | } -------------------------------------------------------------------------------- /src/index.jsx: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /src/components/navbar.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export default class Navbar extends React.Component{ 4 | 5 | render(){ 6 | return( 7 |
8 | {this.props.title} 9 |
10 | ) 11 | } 12 | } -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/layout/grid.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Card from '../components/card'; 3 | 4 | export default class Grid extends React.Component{ 5 | 6 | constructor(props){ 7 | super(props); 8 | this.handleButton = this.handleButton.bind(this); 9 | } 10 | 11 | handleButton(){ 12 | this.props.next(); 13 | } 14 | 15 | render(){ 16 | 17 | return( 18 |
19 |
20 | { 21 | this.props.pokemons.map(poke=> ( 22 | 23 | )) 24 | } 25 |
26 | { 27 | (this.props.pokemons.length >= 20) && 28 |
29 | 30 |
31 | } 32 |
33 | ) 34 | } 35 | } -------------------------------------------------------------------------------- /src/assets/icons/busqueda.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pokeapi", 3 | "homepage": "https://onnichan.github.io/pokeapi-react/", 4 | "version": "0.1.0", 5 | "private": true, 6 | "dependencies": { 7 | "@testing-library/jest-dom": "^5.16.4", 8 | "@testing-library/react": "^13.1.1", 9 | "@testing-library/user-event": "^13.5.0", 10 | "react": "^18.1.0", 11 | "react-dom": "^18.1.0", 12 | "react-scripts": "5.0.1", 13 | "web-vitals": "^2.1.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject", 20 | "deploy": "gh-pages -d build" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | }, 40 | "devDependencies": { 41 | "gh-pages": "^3.2.3" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/components/search.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import SearchIcon from '../assets/icons/busqueda.svg'; 3 | 4 | export default class Search extends React.Component{ 5 | 6 | constructor(props){ 7 | super(props); 8 | this.state = { 9 | search: '', 10 | } 11 | this.handleSearch = this.handleSearch.bind(this); 12 | this.handleClickSearch = this.handleClickSearch.bind(this); 13 | } 14 | 15 | handleSearch(e){ 16 | 17 | this.setState({ 18 | search: e.target.value, 19 | }) 20 | if(e.target.value.length === 0) this.props.onHandleSearch(null); 21 | 22 | } 23 | 24 | handleClickSearch(e){ 25 | if(e.keyCode === 13 || e.type === 'click'){ 26 | e.preventDefault(); 27 | this.props.onHandleSearch(this.state.search); 28 | } 29 | } 30 | 31 | render(){ 32 | return( 33 |
34 |
35 | 42 | 43 |
44 | 45 |
46 | ) 47 | } 48 | } -------------------------------------------------------------------------------- /src/components/card.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Modal from './modal'; 3 | import PokeballImage from '../assets/icons/pokeball.png'; 4 | import {searchIcon} from '../utils/icons'; 5 | 6 | export default class Card extends React.Component{ 7 | 8 | constructor(props){ 9 | super(props); 10 | this.state = { 11 | showModal: false, 12 | } 13 | this.handleModal = this.handleModal.bind(this); 14 | } 15 | 16 | handleModal(){ 17 | this.setState({ 18 | showModal: !this.state.showModal 19 | },()=> { 20 | document.body.classList.toggle('dark'); 21 | }) 22 | } 23 | 24 | render(){ 25 | 26 | const {pokemon} = this.props; 27 | 28 | return( 29 | <> 30 |
31 |
32 | 33 | {`#${pokemon.order}`} 34 |
35 |
36 | 37 | {pokemon.types[0].type.name} 38 |
39 |

{pokemon.name}

40 | 41 |
42 | { 43 | this.state.showModal && 44 | } 45 | 46 | ) 47 | } 48 | } -------------------------------------------------------------------------------- /src/utils/icons.js: -------------------------------------------------------------------------------- 1 | import bug from '../assets/icons/pokemon/types/bug.png'; 2 | import dark from '../assets/icons/pokemon/types/dark.png'; 3 | import dragon from '../assets/icons/pokemon/types/dragon.png'; 4 | import electric from '../assets/icons/pokemon/types/electric.png'; 5 | import fairy from '../assets/icons/pokemon/types/fairy.png'; 6 | import fighting from '../assets/icons/pokemon/types/fighting.png'; 7 | import fire from '../assets/icons/pokemon/types/fire.png'; 8 | import flying from '../assets/icons/pokemon/types/flying.png'; 9 | import ghost from '../assets/icons/pokemon/types/ghost.png'; 10 | import grass from '../assets/icons/pokemon/types/grass.png'; 11 | import ground from '../assets/icons/pokemon/types/ground.png'; 12 | import ice from '../assets/icons/pokemon/types/ice.png'; 13 | import normal from '../assets/icons/pokemon/types/normal.png'; 14 | import poison from '../assets/icons/pokemon/types/poison.png'; 15 | import psychic from '../assets/icons/pokemon/types/psychic.png'; 16 | import rock from '../assets/icons/pokemon/types/rock.png'; 17 | import steel from '../assets/icons/pokemon/types/steel.png'; 18 | import water from '../assets/icons/pokemon/types/water.png'; 19 | 20 | const icons = { 21 | bug: bug, 22 | dark: dark, 23 | dragon: dragon, 24 | electric: electric, 25 | fairy: fairy, 26 | fighting: fighting, 27 | fire: fire, 28 | flying: flying, 29 | ghost: ghost, 30 | grass: grass, 31 | ground: ground, 32 | ice: ice, 33 | normal: normal, 34 | poison: poison, 35 | psychic: psychic, 36 | rock: rock, 37 | steel: steel, 38 | water: water 39 | } 40 | 41 | export function searchIcon(search){ 42 | 43 | if(search){ 44 | search = Object.entries(icons).filter(icon => icon[0] === search); 45 | return search[0][1]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # POKEAPI ![Pokebola](https://cdn.emojidex.com/emoji/px32/Pokebola.png "Pokebola") 2 | 3 | In this project we use a Pokedex to show the info of a pokemon, searching by its name. To get this info we use an API to bring the data from [pokeapi](https://pokeapi.co) 4 | 5 | 6 | ## Technologies 7 | 8 | To build this app I used [ReactJS](https://reactjs.org/) v18, CSS, and HTML. 9 | 10 | ## Screenshots 11 | 12 | Here are some screenshots of the app's UI based on the components shown below 13 | 14 | ### Search Component 15 | ![Image](/src/assets/screenshots/search.PNG) 16 | 17 | ### Grid Component 18 | 19 | ![Image](/src/assets/screenshots/grid.PNG) 20 | 21 | ### Modal Component 22 | Charizard | Blastoise | Venusaur 23 | :-------------------------:|:-------------------------:|:-------------------------: 24 | ![Image](/src/assets/screenshots/card.PNG?raw=true) | ![Image](/src/assets/screenshots/card-blastoise.PNG?raw=true) | ![Image](/src/assets/screenshots/card-venasaur.PNG?raw=true) 25 | 26 | ## Demo 27 | 28 | You can see it deployed [here](https://onnichan.github.io/pokeapi-react/) 👈 29 | 30 | ## Do you want to use or run this project locally? 31 | 32 | Just follow this steps: 33 | 34 | 49 | 50 | 51 | ## Contact 52 | You can follow me on my [Linkedin](https://www.linkedin.com/in/walter-daniel-huaynapata-aguilar-391041197/). 53 | 54 | 55 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | PokeApi 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/colors.css: -------------------------------------------------------------------------------- 1 | :root{ 2 | --bg-light-color: #fff; 3 | --bg-dark-color: #000; 4 | --bg-after-color: rgba(14, 12, 14, 0.6); 5 | --bg-poke-color-light-normal: rgba(247, 243, 233, 0.928); 6 | --bg-poke-color-light-fighting: rgba(247, 216, 216, 0.886); 7 | --bg-poke-color-light-flying: rgba(247, 233, 242, 0.928); 8 | --bg-poke-color-light-poison: rgba(242, 233, 247, 0.928); 9 | --bg-poke-color-light-ground: rgba(247, 242, 233, 0.928); 10 | --bg-poke-color-light-rock: rgba(239, 221, 195, 0.796); 11 | --bg-poke-color-light-bug: rgba(234, 247, 233, 0.928); 12 | --bg-poke-color-light-ghost: rgba(245, 233, 247, 0.823); 13 | --bg-poke-color-light-steel: rgba(247, 243, 233, 0.928); 14 | --bg-poke-color-light-fire: rgba(247, 233, 233, 0.928); 15 | --bg-poke-color-light-water: rgba(176, 224, 238, 0.928); 16 | --bg-poke-color-light-grass: rgba(233, 247, 239, 0.928); 17 | --bg-poke-color-light-electric: rgba(247, 245, 233, 0.928); 18 | --bg-poke-color-light-psychic: rgba(247, 233, 243, 0.928); 19 | --bg-poke-color-light-ice: rgba(233, 238, 247, 0.928); 20 | --bg-poke-color-light-dragon: rgba(240, 233, 247, 0.928); 21 | --bg-poke-color-light-dark: rgba(148, 147, 144, 0.27); 22 | --bg-poke-color-light-fairy: rgba(247, 233, 244, 0.928); 23 | --bg-poke-color-light-unknown: rgba(247, 243, 233, 0.928); 24 | --bg-poke-color-light-shadow: rgba(247, 233, 243, 0.928); 25 | 26 | --bg-poke-color-dark-normal: rgba(235, 204, 142, 0.835); 27 | --bg-poke-color-dark-fighting: rgba(221, 88, 88, 0.835); 28 | --bg-poke-color-dark-flying: rgba(175, 100, 225, 0.667); 29 | --bg-poke-color-dark-poison: rgba(165, 92, 205, 0.835); 30 | --bg-poke-color-dark-ground: rgba(235, 207, 142, 0.511); 31 | --bg-poke-color-dark-rock: rgba(203, 140, 95, 0.749); 32 | --bg-poke-color-dark-bug: rgba(156, 235, 142, 0.835); 33 | --bg-poke-color-dark-ghost: rgba(203, 142, 235, 0.835); 34 | --bg-poke-color-dark-steel: rgba(145, 148, 146, 0.835); 35 | --bg-poke-color-dark-fire: rgba(235, 142, 142, 0.835); 36 | --bg-poke-color-dark-water: rgba(142, 235, 215, 0.835); 37 | --bg-poke-color-dark-grass: rgba(144, 232, 123, 0.835); 38 | --bg-poke-color-dark-electric: rgba(235, 230, 142, 0.835); 39 | --bg-poke-color-dark-psychic: rgba(235, 142, 221, 0.835); 40 | --bg-poke-color-dark-ice: rgba(142, 235, 234, 0.835); 41 | --bg-poke-color-dark-dragon: rgba(149, 95, 203, 0.831); 42 | --bg-poke-color-dark-dark: rgba(148, 147, 144, 0.928); 43 | --bg-poke-color-dark-fairy: rgba(235, 142, 230, 0.42); 44 | --bg-poke-color-dark-unknown: rgba(247, 243, 233, 0.928); 45 | --bg-poke-color-dark-shadow: rgba(247, 233, 243, 0.928); 46 | } -------------------------------------------------------------------------------- /src/App.jsx: -------------------------------------------------------------------------------- 1 | import Search from './components/search'; 2 | import Navbar from './components/navbar'; 3 | import Footer from './components/footer'; 4 | import Grid from './layout/grid'; 5 | import Container from './layout/container'; 6 | import React from 'react'; 7 | import './App.css'; 8 | 9 | export default class App extends React.Component{ 10 | 11 | constructor(props){ 12 | super(props); 13 | this.state = { 14 | pokemons: [], 15 | total: 0, 16 | notFound: false, 17 | search: [], 18 | searching: false, 19 | } 20 | this.handleSearch = this.handleSearch.bind(this); 21 | this.showPokemons = this.showPokemons.bind(this); 22 | this.nextPokemon = this.nextPokemon.bind(this); 23 | } 24 | 25 | async handleSearch(textSearch){ 26 | if(!textSearch) { 27 | this.setState({ 28 | search: [], 29 | notFound:false, 30 | }) 31 | return; 32 | } 33 | 34 | this.setState({ 35 | notFound: false, 36 | searching: true, 37 | }) 38 | const api = await fetch(`https://pokeapi.co/api/v2/pokemon/${textSearch.toLowerCase()}`); 39 | const data = await api.json().catch(()=> undefined); 40 | if(!data){ 41 | this.setState({ 42 | notFound: true, 43 | }) 44 | return; 45 | }else{ 46 | this.setState({ 47 | search: [data], 48 | }) 49 | } 50 | this.setState({ 51 | searching: false, 52 | }) 53 | } 54 | 55 | async showPokemons(limit = 20, offset = 0){ 56 | 57 | const api = await fetch(`https://pokeapi.co/api/v2/pokemon?limit=${limit}&offset=${offset}`); 58 | const data = await api.json(); 59 | const promises = await data.results.map(async pokemon => { 60 | const result = await fetch(pokemon.url); 61 | const res = await result.json(); 62 | return res; 63 | }); 64 | 65 | const results = await Promise.all(promises); 66 | 67 | this.setState(prev => ({ 68 | search: [], 69 | pokemons: [...prev.pokemons, ...results], 70 | notFound: false, 71 | total: prev.total + results.length, 72 | })); 73 | } 74 | 75 | nextPokemon(){ 76 | this.showPokemons(20,this.state.total); 77 | } 78 | 79 | componentDidMount(){ 80 | if(!this.state.searching){ 81 | this.showPokemons(); 82 | } 83 | } 84 | 85 | render(){ 86 | 87 | const poke = this.state.search.length > 0 ? this.state.search : this.state.pokemons; 88 | return ( 89 | <> 90 | 91 | 92 | 93 | { 94 | this.state.notFound ? ( 95 |
'Pokemon not found'
96 | ) : ( 97 | 98 | ) 99 | } 100 |
101 |
102 | 103 | ); 104 | } 105 | } 106 | 107 | -------------------------------------------------------------------------------- /src/components/modal.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {searchIcon} from '../utils/icons'; 3 | 4 | export default class Modal extends React.Component{ 5 | 6 | constructor(props){ 7 | super(props); 8 | this.handleModal = this.handleModal.bind(this); 9 | } 10 | 11 | handleModal(){ 12 | this.props.onHandleModal(); 13 | } 14 | render(){ 15 | const pokemon = this.props.pokemon; 16 | const colors = ['#FC6B6E','#2196F3','#094BE8','#2196F3','#3ED1E0','#CF9B48']; 17 | 18 | return( 19 |
20 | 21 |
22 |
23 |
24 | 25 | 26 | {/* {pokemon.types[0].type.name} */} 27 | 28 | { 29 | pokemon['past_types'].length > 0 && {pokemon['past_types'][0].generation.name} 30 | } 31 |
32 |
33 | Height: {pokemon.height} 34 | weight : {pokemon.weight} 35 | {/* { 36 | pokemon['past_types'].length > 0 && {pokemon['past_types'][0].generation.name} 37 | } */} 38 |
39 |
40 |
41 | 42 |

{pokemon.name}

43 |

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ex quaerat eligendi

44 |
45 |
46 |
47 |

Abilities

48 | { 49 | pokemon.abilities.map(({ability})=> ( 50 | {ability.name} 51 | )) 52 | } 53 |
54 |
55 |

Stats

56 | { 57 | pokemon.stats.map((stat, index)=> ( 58 |
59 |
60 | {stat.stat.name} 61 | {stat.base_stat} 62 |
63 |
64 | { 65 | stat.base_stat >= 100 ? 66 |
: 67 |
68 | } 69 |
70 |
71 | )) 72 | } 73 |
74 |
75 |
76 |
77 | ) 78 | } 79 | } -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | @import url('./colors.css'); 2 | 3 | *,::before,::after{ 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | body{ 10 | background-color: var(--bg-light-color); 11 | position: relative; 12 | /* overflow-x: hidden; */ 13 | } 14 | 15 | .container{ 16 | display: flex; 17 | flex-direction: column; 18 | min-height: 100vh; 19 | padding: 0 50px; 20 | } 21 | 22 | .navbar{ 23 | padding: 20px 0; 24 | margin-bottom: 30px; 25 | } 26 | 27 | .navbar__title{ 28 | display: block; 29 | text-align: center; 30 | font-weight: 700; 31 | font-size: 2.5em; 32 | text-shadow: 5px 5px 10px lightseagreen; 33 | } 34 | 35 | .search{ 36 | padding: 10px; 37 | border-color: 1px solid black; 38 | width: 100%; 39 | height: 60px; 40 | /* min-height: 60px; */ 41 | margin-bottom: 30px; 42 | display: flex; 43 | } 44 | 45 | .search__wrapper{ 46 | /* display: inline-block; */ 47 | width: 90%; 48 | height: 100%; 49 | position: relative; 50 | } 51 | 52 | .search__input{ 53 | outline: none; 54 | padding: 10px 10px 10px 40px; 55 | width: 100%; 56 | height: 100%; 57 | border-top-left-radius: 4px; 58 | border-bottom-left-radius: 4px; 59 | border: 1px solid gray; 60 | color: lightseagreen; 61 | } 62 | 63 | .search__input:focus{ 64 | border: 1px solid black; 65 | } 66 | 67 | .search__input::placeholder{ 68 | color: lightseagreen; 69 | font-weight: 700; 70 | } 71 | 72 | .search__icon{ 73 | position: absolute; 74 | left: 10px; 75 | top: 25%; 76 | bottom: 25%; 77 | height: 50%; 78 | } 79 | 80 | .search__button{ 81 | display: block; 82 | width: 10%; 83 | height: 100%; 84 | background-color: black; 85 | border: 1px solid transparent; 86 | font-weight: 700; 87 | color: white; 88 | } 89 | 90 | .search__button:hover{ 91 | cursor: pointer; 92 | } 93 | 94 | .grid{ 95 | padding-bottom: 40px; 96 | } 97 | 98 | .grid__pokemon{ 99 | display: grid; 100 | grid-template-columns: repeat(4, 1fr); 101 | grid-template-rows: repeat(5, 1fr); 102 | gap: 30px; 103 | padding: 10px; 104 | } 105 | 106 | .grid__button{ 107 | background-color: lightseagreen; 108 | padding: 10px 20px; 109 | border-radius: 10px; 110 | font-weight: 700; 111 | margin: 0 auto; 112 | outline: none; 113 | border: none; 114 | } 115 | 116 | .grid__wrapper-button{ 117 | padding-top: 20px; 118 | display: flex; 119 | align-items: center; 120 | position: relative; 121 | z-index: 7; 122 | } 123 | 124 | .grid__button:hover{ 125 | cursor: pointer; 126 | } 127 | 128 | .card{ 129 | display: flex; 130 | align-items: flex-end; 131 | justify-content: space-around; 132 | border-radius: 5px; 133 | position: relative; 134 | padding: 20px 0; /* rgba(233, 247, 239, 0.928); */ 135 | background-color: rgba(148, 147, 144, 0.27); 136 | } 137 | 138 | .card::after{ 139 | content: ''; 140 | position: absolute; 141 | width: 40px; 142 | height: 80px; 143 | top: 25%; 144 | right: 50px; 145 | background-color: rgba(255, 255, 255, 0.579); 146 | border-radius: 50%; 147 | transform: rotateZ(8deg); 148 | } 149 | 150 | /* .card::before{ 151 | content: ''; 152 | position: absolute; 153 | width: 150px; 154 | height: 150px; 155 | top: 60%; 156 | right: -90px; 157 | background-color: white; 158 | box-shadow: 1px 1px 10px white; 159 | border-radius: 50%; 160 | } */ 161 | 162 | .card:hover{ 163 | cursor: pointer; 164 | } 165 | 166 | .card__title{ 167 | display: flex; 168 | align-items: center; 169 | position: absolute; 170 | top: 6%; 171 | left: 5%; 172 | height: 15%; 173 | } 174 | 175 | .card__title-img{ 176 | display: block; 177 | width: 100%; 178 | height: 100%; 179 | } 180 | 181 | .card__title-text{ 182 | margin-left: 10px; 183 | font-weight: 500; 184 | } 185 | 186 | .card__badge{ 187 | position: absolute; 188 | top: 0; 189 | right: 0; 190 | padding: 2px 5px; 191 | border-radius: 5px; 192 | font-size: 0.8em; 193 | text-align: center; 194 | color: rgba(0, 0, 0, 0.739); 195 | font-weight: 700; 196 | 197 | display: flex; 198 | /* align-items: center; */ 199 | justify-content: flex-start; 200 | } 201 | 202 | .card__badge-Icon{ 203 | display: inline-block; 204 | margin-right: 10px; 205 | width: 20%; 206 | height: 100%; 207 | } 208 | 209 | .card__badge-text{ 210 | display: inline-block; 211 | text-align: center; 212 | } 213 | 214 | .card__image{ 215 | display: block; 216 | z-index: 2; 217 | width: 40%; 218 | height: 100%; 219 | } 220 | 221 | .modal{ 222 | background-color: rgba(247, 242, 242, 0.961); 223 | position: fixed; 224 | top: 50%; 225 | transform: translateY(-50%); 226 | left: 35%; 227 | right: 35%; 228 | color: black; 229 | z-index: 10; 230 | border-radius: 10px; 231 | } 232 | 233 | .modal__content{ 234 | display: flex; 235 | flex-direction: column; 236 | } 237 | 238 | .modal__content-features, 239 | .modal__content-description, 240 | .modal__content-other{ 241 | padding: 20px; 242 | } 243 | 244 | .modal__content-features{ 245 | border-top-left-radius: 10px; 246 | border-top-right-radius: 10px; 247 | margin-bottom: -94px; 248 | height: 150px; 249 | font-size: 0.9em; 250 | font-weight: 600; 251 | display: flex; 252 | justify-content: space-between; 253 | color: black; 254 | } 255 | 256 | .modal__content-featuresHabitat{ 257 | width: 100%; 258 | display: flex; 259 | } 260 | 261 | .modal__content-featuresImage{ 262 | width: 60px; 263 | height: 60px; 264 | display: block; 265 | } 266 | 267 | .modal__content-featuresRight, 268 | .modal__content-featuresLeft{ 269 | display: flex; 270 | flex-direction: column; 271 | row-gap: 10px; 272 | } 273 | 274 | .modal__content-features span:not(.modal__content-featuresHabitat){ 275 | /* background-color: #e3d7b2; */ 276 | border-radius: 5px; 277 | padding: 0 10px; 278 | border: 1px solid black; 279 | } 280 | 281 | .modal__content-description{ 282 | display: flex; 283 | flex-direction: column; 284 | align-items: center; 285 | } 286 | 287 | .modal__content-descriptionImage{ 288 | display: block; 289 | width: 40%; 290 | margin-bottom: -10px; 291 | border-radius: 50%; 292 | background-color: rgba(247, 242, 242, 0.961); 293 | } 294 | 295 | .modal__content-descriptionTitle{ 296 | font-size: 1.4em; 297 | text-transform: uppercase; 298 | } 299 | 300 | .modal__content-descriptionParagraph{ 301 | text-align: center; 302 | font-size: 0.8em; 303 | margin-top: 1em; 304 | } 305 | 306 | .modal__content-other{ 307 | display: flex; 308 | justify-content: space-around; 309 | gap: 20px; 310 | } 311 | 312 | .modal__content-otherBreadcrumbAbility{ 313 | display: flex; 314 | flex-direction: column; 315 | margin-top: 5px; 316 | } 317 | 318 | .modal__content-otherBreadcrumbAbilities{ 319 | margin-bottom: 10px; 320 | } 321 | 322 | .modal__content-otherStats{ 323 | width: 60%; 324 | } 325 | 326 | .modal__content-otherStatsTitle{ 327 | text-align: center; 328 | } 329 | 330 | .modal__content-otherStat{ 331 | display: flex; 332 | flex-direction: column; 333 | } 334 | 335 | .modal__content-otherStatContent{ 336 | font-size: 0.7em; 337 | display: flex; 338 | justify-content: space-between; 339 | } 340 | 341 | .modal__content-otherStatTimeLine{ 342 | background-color: gray; 343 | width: 100%; 344 | height: 0.4em; 345 | border-radius: 5px; 346 | margin-bottom: 5px; 347 | position: relative; 348 | } 349 | 350 | /* .modal__content-otherStatTimeLine::after{ 351 | content: ''; 352 | position: absolute; 353 | top: 0; 354 | left: 0; 355 | width: 50px; 356 | height: inherit; 357 | border-radius: 5px; 358 | background-color: black; 359 | z-index: 10; 360 | } */ 361 | 362 | .modal__content-otherStatTimeLineStat{ 363 | position: absolute; 364 | top: 0; 365 | left: 0; 366 | height: inherit; 367 | border-radius: 5px; 368 | background-color: black; 369 | z-index: 10; 370 | } 371 | 372 | .dark::after{ 373 | content: ''; 374 | position: absolute; 375 | top: 0; 376 | left: 0; 377 | right: 0; 378 | bottom: 0; 379 | background-color: var(--bg-after-color); 380 | z-index: 9; 381 | } 382 | 383 | .modal__close{ 384 | position: absolute; 385 | top: -25px; 386 | right: 10px; 387 | background-color: transparent; 388 | border: none; 389 | outline: none; 390 | z-index: 11; 391 | font-size: 1.1em; 392 | } 393 | 394 | .modal__close:hover{ 395 | cursor: pointer; 396 | } 397 | 398 | .footer{ 399 | margin-top: auto; 400 | background-color: var(--bg-dark-color); 401 | color: lightseagreen; 402 | padding: 12px 0; 403 | text-align: center; 404 | } 405 | 406 | @media only screen and (max-width: 1030px){ 407 | .grid__pokemon{ 408 | grid-template-columns: repeat(3, 1fr); 409 | } 410 | .card__image{ 411 | width: 40%; 412 | height: 100%; 413 | } 414 | 415 | .modal{ 416 | right: 27%; 417 | left: 27%; 418 | } 419 | } 420 | 421 | @media only screen and (max-width: 760px){ 422 | .grid__pokemon{ 423 | grid-template-columns: repeat(2, 1fr); 424 | } 425 | 426 | .card__image{ 427 | width: 40%; 428 | } 429 | 430 | .modal{ 431 | right: 15%; 432 | left: 15%; 433 | } 434 | 435 | .search__wrapper{ 436 | width: 80%; 437 | } 438 | 439 | .search__button{ 440 | width: 20%; 441 | } 442 | } 443 | 444 | @media only screen and (max-width: 550px){ 445 | .grid__pokemon{ 446 | grid-template-columns: 1fr; 447 | } 448 | 449 | .card__image{ 450 | width: 40%; 451 | height: 100%; 452 | } 453 | 454 | .modal{ 455 | right: 14%; 456 | left: 14%; 457 | } 458 | 459 | .search__wrapper{ 460 | width: 80%; 461 | } 462 | 463 | .search__button{ 464 | width: 20%; 465 | } 466 | } 467 | 468 | @media only screen and (max-width: 430px){ 469 | .grid__pokemon{ 470 | grid-template-columns: 1fr; 471 | } 472 | 473 | .card__image{ 474 | width: 40%; 475 | height: 100%; 476 | } 477 | 478 | .modal{ 479 | right: 0; 480 | left: 0; 481 | } 482 | 483 | .search__wrapper{ 484 | width: 80%; 485 | } 486 | 487 | .search__button{ 488 | width: 20%; 489 | } 490 | 491 | .container{ 492 | padding: 0; 493 | } 494 | } --------------------------------------------------------------------------------