Repository: LeonidasEsteban/rick-and-morty-react Branch: master Commit: adbd895e62c2 Files: 30 Total size: 23.5 KB Directory structure: gitextract_vvocdbb4/ ├── .gitignore ├── README.md ├── package.json ├── public/ │ ├── index.html │ ├── manifest.json │ └── robots.txt └── src/ ├── App.css ├── App.js ├── App.test.js ├── api.js ├── character-context.js ├── character-description.js ├── character-image.js ├── character-name.js ├── character-placeholder.js ├── character.js ├── dot.js ├── global-styles.js ├── index.css ├── index.js ├── layout.js ├── learn-more.js ├── line.js ├── logo.js ├── navigation-item.js ├── next.js ├── nprogress.css ├── serviceWorker.js ├── setupTests.js └── social.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies /node_modules /.pnp .pnp.js # testing /coverage # production /build # misc .DS_Store .env.local .env.development.local .env.test.local .env.production.local npm-debug.log* yarn-debug.log* yarn-error.log* ================================================ FILE: README.md ================================================ # Rick And Morty App Web App using the rick and morty API in React.js - Live example -> https://leonidasesteban.github.io/rick-and-morty-react/ - Learn how to in Youtube -> https://youtu.be/3ylL1QgspEM ![](https://repository-images.githubusercontent.com/270150208/cd653200-a851-11ea-9d9c-910b66ca0006) ================================================ FILE: package.json ================================================ { "name": "rick-and-morty-react", "version": "0.1.0", "private": true, "homepage": "https://leonidasesteban.github.io/rick-and-morty-react/", "dependencies": { "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "gh-pages": "^3.1.0", "nprogress": "^0.2.0", "react": "^16.13.1", "react-dom": "^16.13.1", "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", "styled-components": "^5.1.1" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "predeploy": "npm run build", "deploy": "gh-pages -d build", "eject": "react-scripts eject" }, "eslintConfig": { "extends": "react-app" }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ================================================ FILE: public/index.html ================================================ React App
================================================ FILE: public/manifest.json ================================================ { "short_name": "React App", "name": "Create React App Sample", "icons": [ { "src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon" }, { "src": "logo192.png", "type": "image/png", "sizes": "192x192" }, { "src": "logo512.png", "type": "image/png", "sizes": "512x512" } ], "start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff" } ================================================ FILE: public/robots.txt ================================================ # https://www.robotstxt.org/robotstxt.html User-agent: * Disallow: ================================================ FILE: src/App.css ================================================ ================================================ FILE: src/App.js ================================================ import React from 'react'; import './nprogress.css'; import GlobalStyle from './global-styles' import { BrowserRouter as Router, Route, Switch } from 'react-router-dom' import Character from './character' function App() { return (
) } export default App; ================================================ FILE: src/App.test.js ================================================ import React from 'react'; import { render } from '@testing-library/react'; import App from './App'; test('renders learn react link', () => { const { getByText } = render(); const linkElement = getByText(/learn react/i); expect(linkElement).toBeInTheDocument(); }); ================================================ FILE: src/api.js ================================================ class API { async getCharacter(id) { const response = await fetch(`https://rickandmortyapi.com/api/character/${id}`) const data = await response.json() return data // .then((response) => response.json()) // .then((data) => data) } } const api = new API() export default api ================================================ FILE: src/character-context.js ================================================ import { createContext } from 'react' const CharacterContext = createContext() export default CharacterContext ================================================ FILE: src/character-description.js ================================================ import React from 'react' import styled from 'styled-components' const CharacterDescriptionStyled = styled.div` .character-label { background: #685128; padding: 1em; color: white; border-radius: 10px; text-align: left; font-size: 25px; font-weight: 400; /* display: inline-flex; */ } ` function CharacterDescription({ status, gender, species }) { return (

Género: {gender}

Especie: {species}

Status: {status}

) } export default CharacterDescription ================================================ FILE: src/character-image.js ================================================ import React from 'react' import styled from 'styled-components' const CharacterImageStyled = styled.img` max-width: 100%; border-radius: 50%; ` function CharacterImage({ image, name }) { return ( ) } export default CharacterImage ================================================ FILE: src/character-name.js ================================================ import React from 'react' import styled from 'styled-components' const CharacterNameStyled = styled.div` position: relative; font-size: 30px; h2:after { content: ""; width: 87px; height: 6px; background-color: #F7391C; display: inline-flex; position: absolute; left: calc(100% + 5px); top: 50%; } @media screen and (max-width: 1024px) { text-align: center; h2:after { left: 0; top: calc(100% - 20px); } } ` function CharacterName({ name }) { return (

{name}

) } export default CharacterName ================================================ FILE: src/character-placeholder.js ================================================ import React from 'react' import styled from 'styled-components' const CharacterPlaceholderStyled = styled.div` overflow: hidden; position: fixed; left: 0; right: 0; bottom: 0; top: 0; .character-name-placeholder { color: rgba(0,0,0,.1); font-size: 600px; text-transform: uppercase; justify-content: center; display: flex; align-items: center; z-index: 1; white-space: nowrap; position: absolute; left: 0; right: 0; bottom: 0; top: 0; } ` function CharacterPlaceholder({ name }) { return (

{name}

) } export default CharacterPlaceholder ================================================ FILE: src/character.js ================================================ import React, { useState, useEffect } from 'react' import styled from 'styled-components' import CharacterName from './character-name' import CharacterImage from './character-image' import CharacterDescription from './character-description' import CharacterPlaceholder from './character-placeholder' import Layout from './layout' import api from './api' import Next from './next' import CharacterContext from './character-context' const CharacterStyled = styled.div` ` function Character({ match }) { const [character, setCharacter] = useState({}) useEffect(() => { async function getCharacter() { setCharacter(await api.getCharacter(match.params.id || 1)) } getCharacter() }, [match.params.id]) return ( } name={} image={} description={} /> ); } export default Character ================================================ FILE: src/dot.js ================================================ import React from 'react' import styled from 'styled-components' const DotStyled = styled.span` width: 10px; height: 10px; background: black; border-radius: 50%; display: inline-flex; margin-inline: 5px; ` function Dot() { return ( ) } export default Dot ================================================ FILE: src/global-styles.js ================================================ import { createGlobalStyle } from 'styled-components' const GlobalStyle = createGlobalStyle` body { margin: 0; background: #00a5be; font-family: system-ui; overflow-x: hidden; background-image: url('./images/asset-red.svg'); background-position: left 200px top; background-repeat: no-repeat; } @media screen and (max-width: 1024px) { body { background-position: left 50px top; } } ` export default GlobalStyle ================================================ FILE: src/index.css ================================================ body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } ================================================ FILE: src/index.js ================================================ import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; ReactDOM.render( , document.getElementById('root') ); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister(); ================================================ FILE: src/layout.js ================================================ import React from 'react' import styled from 'styled-components' import Social from './social' import Logo from './logo' import Dot from './dot' import Line from './line' import LearnMore from './learn-more' import NavigationItem from './navigation-item' const LayoutStyled = styled.div` position: relative; z-index: 2; display: grid; height: calc(100vh - 8em); padding: 4em; grid-column-gap: 8em; grid-template-columns: 50px 1fr 1fr 200px; grid-template-rows: 230px 100px 1fr 1fr 1fr; grid-template-areas: "asset-top logo logo social" "name character-name avatar avatar" "about character-description avatar avatar" "asset-bottom character-text avatar avatar" "asset-bottom learn-more arrow other-line" ; .name-area { /* border: 1px solid blue; */ display: flex; align-items: center; grid-area: character-name; /* padding-inline-start: 1em; */ } .description-area { grid-area: character-description; } .image-area { grid-area: avatar; /* border: 1px solid red; */ display: flex; justify-content: center; align-items: center; } .next-area { grid-area: arrow; display: flex; } .social-area { grid-area: social; } .logo-area { grid-area: logo; } .learn-more-area { grid-area: learn-more; } .vertical-align { writing-mode: vertical-rl; display: flex; align-items: center; } .asset-top-area { grid-area: asset-top; } .asset-bottom-area { grid-area: asset-bottom; /* border: 1px solid green; */ justify-content: flex-end; } .navigation-area { writing-mode: vertical-rl; transform: rotate(180deg); display: flex; align-items: center; justify-content: center; &.name { grid-area: name; } &.about { grid-area: about; } } @media screen and (max-width: 1440px) { column-gap: 2em; } @media screen and (max-width: 1024px) { height: auto; padding: 2em 0; width: calc(100vw - 2em); margin: 0 auto; column-gap: 1em; grid-template-columns: 50px 1fr 1fr; grid-template-rows: repeat(6, auto); grid-template-areas: "logo logo logo" "name avatar avatar" "name character-name character-name" "about character-description character-description" "arrow arrow arrow" "social social social"; .name-area { margin-top: 1em; justify-content: center; } .social-area { text-align: center; margin-top: 2em; } .vertical-align { display:none; } .learn-more-area { display: none; } } ` function Layout({ name, image, description, next }) { return (
{name}
{image}
{description}
{next}
) } export default Layout ================================================ FILE: src/learn-more.js ================================================ import React from 'react' import styled from 'styled-components' const LearnMoreStyled = styled.p` display: flex; align-items: flex-end; font-size: 25px; text-transform: uppercase; background-image: url('./images/learn-more.svg'); background-repeat: no-repeat; background-position: left 170px bottom 5px; ` function LearnMore() { return ( Learn More ) } export default LearnMore ================================================ FILE: src/line.js ================================================ import React from 'react' import styled from 'styled-components' const LineStyled = styled.span` width: 2px; height: 150px; background: black; display: inline-flex; margin-inline: 15px; ` function Line() { return ( ) } export default Line ================================================ FILE: src/logo.js ================================================ import React from 'react' import styled from 'styled-components' const LogoStyled = styled.img` margin: 0 auto 2em; display: block; @media screen and (max-width: 1024px) { max-width: 100%; } ` function Logo() { return ( ) } export default Logo ================================================ FILE: src/navigation-item.js ================================================ import React from 'react' import styled from 'styled-components' const NavigationItemStyled = styled.a` text-decoration: none; color: black; font-size: 25px; text-transform: uppercase; ` function NavigationItem({ url, text }) { return ( {text} ) } export default NavigationItem ================================================ FILE: src/next.js ================================================ import React, { useContext } from 'react' import styled from 'styled-components' import CharacterContext from './character-context' // import api from './api' import NProgress from 'nprogress' import { useHistory } from 'react-router-dom' const NextStyled = styled.div` cursor: pointer; /* border: 1px solid red; */ background-image: url('./images/arrow.svg'); background-repeat: no-repeat; background-position: left bottom; flex: 1; @media screen and (max-width: 1024px) { user-select: none; height: 50px; background-position: center; } ` function Next() { const context = useContext(CharacterContext) const history = useHistory() async function handleClick() { NProgress.start() history.push(`${process.env.PUBLIC_URL}/${context.character.id + 1}`) // context.setCharacter(await api.getCharacter(context.character.id + 1)) NProgress.done() } return ( ) } export default Next ================================================ FILE: src/nprogress.css ================================================ /* Make clicks pass-through */ #nprogress { pointer-events: none; } #nprogress .bar { background: #f7391c; position: fixed; z-index: 1031; top: 0; left: 0; width: 100%; height: 2px; } /* Fancy blur effect */ #nprogress .peg { display: block; position: absolute; right: 0px; width: 100px; height: 100%; box-shadow: 0 0 10px #f7391c, 0 0 5px #f7391c; opacity: 1.0; -webkit-transform: rotate(3deg) translate(0px, -4px); -ms-transform: rotate(3deg) translate(0px, -4px); transform: rotate(3deg) translate(0px, -4px); } /* Remove these to get rid of the spinner */ #nprogress .spinner { display: block; position: fixed; z-index: 1031; top: 15px; right: 15px; } #nprogress .spinner-icon { width: 18px; height: 18px; box-sizing: border-box; border: solid 2px transparent; border-top-color: #f7391c; border-left-color: #f7391c; border-radius: 50%; -webkit-animation: nprogress-spinner 400ms linear infinite; animation: nprogress-spinner 400ms linear infinite; } .nprogress-custom-parent { overflow: hidden; position: relative; } .nprogress-custom-parent #nprogress .spinner, .nprogress-custom-parent #nprogress .bar { position: absolute; } @-webkit-keyframes nprogress-spinner { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); } } @keyframes nprogress-spinner { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } ================================================ FILE: src/serviceWorker.js ================================================ // This optional code is used to register a service worker. // register() is not called by default. // This lets the app load faster on subsequent visits in production, and gives // it offline capabilities. However, it also means that developers (and users) // will only see deployed updates on subsequent visits to a page, after all the // existing tabs open on the page have been closed, since previously cached // resources are updated in the background. // To learn more about the benefits of this model and instructions on how to // opt-in, read https://bit.ly/CRA-PWA const isLocalhost = Boolean( window.location.hostname === 'localhost' || // [::1] is the IPv6 localhost address. window.location.hostname === '[::1]' || // 127.0.0.0/8 are considered localhost for IPv4. window.location.hostname.match( /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ ) ); export function register(config) { if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { // The URL constructor is available in all browsers that support SW. const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); if (publicUrl.origin !== window.location.origin) { // Our service worker won't work if PUBLIC_URL is on a different origin // from what our page is served on. This might happen if a CDN is used to // serve assets; see https://github.com/facebook/create-react-app/issues/2374 return; } window.addEventListener('load', () => { const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; if (isLocalhost) { // This is running on localhost. Let's check if a service worker still exists or not. checkValidServiceWorker(swUrl, config); // Add some additional logging to localhost, pointing developers to the // service worker/PWA documentation. navigator.serviceWorker.ready.then(() => { console.log( 'This web app is being served cache-first by a service ' + 'worker. To learn more, visit https://bit.ly/CRA-PWA' ); }); } else { // Is not localhost. Just register service worker registerValidSW(swUrl, config); } }); } } function registerValidSW(swUrl, config) { navigator.serviceWorker .register(swUrl) .then(registration => { registration.onupdatefound = () => { const installingWorker = registration.installing; if (installingWorker == null) { return; } installingWorker.onstatechange = () => { if (installingWorker.state === 'installed') { if (navigator.serviceWorker.controller) { // At this point, the updated precached content has been fetched, // but the previous service worker will still serve the older // content until all client tabs are closed. console.log( 'New content is available and will be used when all ' + 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' ); // Execute callback if (config && config.onUpdate) { config.onUpdate(registration); } } else { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. console.log('Content is cached for offline use.'); // Execute callback if (config && config.onSuccess) { config.onSuccess(registration); } } } }; }; }) .catch(error => { console.error('Error during service worker registration:', error); }); } function checkValidServiceWorker(swUrl, config) { // Check if the service worker can be found. If it can't reload the page. fetch(swUrl, { headers: { 'Service-Worker': 'script' }, }) .then(response => { // Ensure service worker exists, and that we really are getting a JS file. const contentType = response.headers.get('content-type'); if ( response.status === 404 || (contentType != null && contentType.indexOf('javascript') === -1) ) { // No service worker found. Probably a different app. Reload the page. navigator.serviceWorker.ready.then(registration => { registration.unregister().then(() => { window.location.reload(); }); }); } else { // Service worker found. Proceed as normal. registerValidSW(swUrl, config); } }) .catch(() => { console.log( 'No internet connection found. App is running in offline mode.' ); }); } export function unregister() { if ('serviceWorker' in navigator) { navigator.serviceWorker.ready .then(registration => { registration.unregister(); }) .catch(error => { console.error(error.message); }); } } ================================================ FILE: src/setupTests.js ================================================ // jest-dom adds custom jest matchers for asserting on DOM nodes. // allows you to do things like: // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import '@testing-library/jest-dom/extend-expect'; ================================================ FILE: src/social.js ================================================ import React from 'react' import styled from 'styled-components' const SocialStyled = styled.div` a { text-decoration: none; } @media screen and (max-width: 1024px) { a { margin-left: 2em; } a:first-child { margin-left: 0; } } ` function Social() { return ( ) } export default Social