├── .env.example ├── .gitignore ├── .prettierrc.json ├── README.md ├── package.json ├── pnpm-lock.yaml ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.js ├── components │ ├── layout │ │ ├── Alert.jsx │ │ ├── Footer.jsx │ │ ├── Navbar.jsx │ │ ├── Spinner.jsx │ │ └── assets │ │ │ └── spinner.gif │ ├── repos │ │ ├── RepoItem.jsx │ │ └── RepoList.jsx │ └── users │ │ ├── UserItem.jsx │ │ ├── UserResults.jsx │ │ └── UserSearch.jsx ├── context │ ├── alert │ │ ├── AlertContext.js │ │ └── AlertReducer.js │ └── github │ │ ├── GithubActions.js │ │ ├── GithubContext.js │ │ └── GithubReducer.js ├── index.css ├── index.js └── pages │ ├── About.jsx │ ├── Home.jsx │ ├── NotFound.jsx │ └── User.jsx └── tailwind.config.js /.env.example: -------------------------------------------------------------------------------- 1 | REACT_APP_GITHUB_URL = "https://api.github.com" 2 | REACT_APP_GITHUB_TOKEN="ADD_YOUR_TOKEN" -------------------------------------------------------------------------------- /.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 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "semi": false, 6 | "singleQuote": true, 7 | "bracketSpacing": true, 8 | "jsxSingleQuote": true, 9 | "trailingComma": "es5" 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Github Finder App 2 | 3 | App to search Github users and display their info. This is part of my React Front To Back 2022 course and is the most up to date version of this project. 4 | 5 | --- 6 | 7 | ### Bug Fixes, corrections and code FAQ 8 | 9 | The repository code here on the main branch has been updated due to bugs and issues found by students since the course was released. 10 | If you are looking for exact code from the course then please check out the [originalcoursecode branch](https://github.com/bradtraversy/github-finder-app/tree/originalcoursecode) of this repository. 11 | 12 | The updates here aim to be a reference and resource for common questions asked 13 | by students in the Udemy Q&A and for those wishing to make corrections to the 14 | project. 15 | 16 | #### Q: How do I remove the user stats scroll bars that show on mobile devices 17 | 18 | Code changes for this fix can be seen in [User.jsx](src/pages/User.jsx) 19 | 20 | #### BUG: I can't see the alert text 21 | 22 | Most likely you have the default light theme provided by DaisyUI. The theme is 23 | set based on a `prefers-colorscheme` media query, so you may have a light theme 24 | if you have a light browser theme or OS theme. In which case you won't see the 25 | text in the alert show. 26 | Code changes to fix this can be seen in [Alert.jsx](src/components/layout/Alert.jsx) 27 | The changes here use a [ DaisyUI Alert component ](https://daisyui.com/components/alert/) so will adapt with a change in theme. 28 | We also now conditionally set the element visibility to **'visible'** or 29 | **'hidden'** rather than conditionally render, which prevents content shift when 30 | the alert shows for a smoother UX. 31 | 32 | #### Q: Why doesn't Craco work? 33 | 34 | You don't need to use craco if you are using react-scripts version 5 or greater. 35 | 36 | When Brad recorded the course react-scripts was at version 4 and didn't support postcss, now react-scripts is at version 5 and does support postcss. 37 | So just check what version of react-scripts you have... 38 | 39 | npm list react-scripts 40 | 41 | If it's at version 5 or greater then follow the [ Tailwind version 3 ](https://tailwindcss.com/docs/guides/create-react-app) docs to setup. 42 | 43 | If react-scripts is at version 4 then follow the [ Tailwind version 2 ](https://v2.tailwindcss.com/docs/guides/create-react-app) docs to setup, which is what you see Brad doing in the course. 44 | 45 | #### BUG: Linking to users websites 46 | 47 | Some users from Github have already prefixed their websites with `http://` or 48 | `https://` so we need to check in [User.jsx](src/pages/User.jsx) if their 49 | website url starts with `http` before constructing the external link. 50 | Code changes can be see in [User.jsx](src/pages/User.jsx#L48) 51 | 52 | #### BUG: Light theme RepoItem background is too dark 53 | 54 | The theme is set based on a `prefers-colorscheme` media query, so you may have a light theme 55 | if you have a light browser theme or OS theme. 56 | When the browser's preferred color scheme is light, the gray background is too dark on the RepoItem component, and the content is not visible. 57 | 58 | Using `base-200` and `base-300` backgrounds, will make the component's background change according to the browser's preference. 59 | 60 | > Code changes can be seen in 61 | > [RepoItem.jsx](src/components/repos/RepoItem.jsx#L17) 62 | 63 | --- 64 | 65 | ## Usage 66 | 67 | Rename **_.env.example_** to **_.env_** 68 | 69 | You can use the Github API without a personal token, but if you want to use your token, add it to the .env file 70 | 71 | Learn how to create a token [here](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) 72 | 73 | ### Install Dependencies 74 | 75 | ``` 76 | npm install 77 | ``` 78 | 79 | ### Run 80 | 81 | ``` 82 | npm start 83 | ``` 84 | 85 | Tailwind UI created by [Hassib Moddasser](https://twitter.com/hassibmoddasser) 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-finder", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.5", 7 | "@testing-library/react": "^13.4.0", 8 | "@testing-library/user-event": "^14.4.3", 9 | "axios": "^1.3.2", 10 | "daisyui": "^2.50.0", 11 | "prop-types": "^15.8.1", 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0", 14 | "react-icons": "^4.7.1", 15 | "react-router-dom": "^6.8.1", 16 | "react-scripts": "5.0.1", 17 | "web-vitals": "^3.1.1" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": [ 27 | "react-app", 28 | "react-app/jest" 29 | ] 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.2%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | }, 43 | "devDependencies": { 44 | "tailwindcss": "^3.2.6" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradtraversy/github-finder-app/f0901777345a630e10f35c2ad8b8b1b7086fd74f/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Github Finder 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradtraversy/github-finder-app/f0901777345a630e10f35c2ad8b8b1b7086fd74f/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradtraversy/github-finder-app/f0901777345a630e10f35c2ad8b8b1b7086fd74f/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 { BrowserRouter as Router, Route, Routes } from 'react-router-dom' 2 | import Navbar from './components/layout/Navbar' 3 | import Footer from './components/layout/Footer' 4 | import Alert from './components/layout/Alert' 5 | import Home from './pages/Home' 6 | import About from './pages/About' 7 | import User from './pages/User' 8 | import NotFound from './pages/NotFound' 9 | import { GithubProvider } from './context/github/GithubContext' 10 | import { AlertProvider } from './context/alert/AlertContext' 11 | 12 | // NOTE: Alert is only used on the '/' route moving to that route we can prevent 13 | // content shift when alert shows by hiding and unhiding the Alert rather than 14 | // conditionally rendering 15 | 16 | function App() { 17 | return ( 18 | 19 | 20 | 21 |
22 | 23 | 24 |
25 | 26 | 30 | 31 | 32 | 33 | } 34 | /> 35 | } /> 36 | } /> 37 | } /> 38 | } /> 39 | 40 |
41 | 42 |
44 |
45 |
46 |
47 | ) 48 | } 49 | 50 | export default App 51 | -------------------------------------------------------------------------------- /src/components/layout/Alert.jsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import AlertContext from '../../context/alert/AlertContext' 3 | 4 | // NOTE: here we are using the alert component from DaisyUI which works better 5 | // with DaisyUI themes. If you have the Light theme from DaisyUI and can't see 6 | // the text in the alert then this is the change you need. 7 | // We also now conditionally hide the containing div rather than conditionally 8 | // render the alert, this prevents content shift when the alert shows. 9 | 10 | function Alert() { 11 | const { alert } = useContext(AlertContext) 12 | 13 | return ( 14 |
18 |
19 |
20 | 25 | 31 | 32 | {alert?.msg} 33 |
34 |
35 |
36 | ) 37 | } 38 | 39 | export default Alert 40 | -------------------------------------------------------------------------------- /src/components/layout/Footer.jsx: -------------------------------------------------------------------------------- 1 | function Footer() { 2 | const footerYear = new Date().getFullYear() 3 | 4 | return ( 5 | 21 | ) 22 | } 23 | 24 | export default Footer 25 | -------------------------------------------------------------------------------- /src/components/layout/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import { FaGithub } from 'react-icons/fa' 2 | import { Link } from 'react-router-dom' 3 | import PropTypes from 'prop-types' 4 | 5 | function Navbar({ title }) { 6 | return ( 7 | 28 | ) 29 | } 30 | 31 | Navbar.defaultProps = { 32 | title: 'Github Finder', 33 | } 34 | 35 | Navbar.propTypes = { 36 | title: PropTypes.string, 37 | } 38 | 39 | export default Navbar 40 | -------------------------------------------------------------------------------- /src/components/layout/Spinner.jsx: -------------------------------------------------------------------------------- 1 | import spinner from './assets/spinner.gif' 2 | 3 | function Spinner() { 4 | return ( 5 |
6 | Loading... 12 |
13 | ) 14 | } 15 | 16 | export default Spinner 17 | -------------------------------------------------------------------------------- /src/components/layout/assets/spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradtraversy/github-finder-app/f0901777345a630e10f35c2ad8b8b1b7086fd74f/src/components/layout/assets/spinner.gif -------------------------------------------------------------------------------- /src/components/repos/RepoItem.jsx: -------------------------------------------------------------------------------- 1 | import { FaEye, FaInfo, FaLink, FaStar, FaUtensils } from 'react-icons/fa' 2 | 3 | import PropTypes from 'prop-types' 4 | 5 | function RepoItem({ repo }) { 6 | const { 7 | name, 8 | description, 9 | html_url, 10 | forks, 11 | open_issues, 12 | watchers_count, 13 | stargazers_count, 14 | } = repo 15 | 16 | return ( 17 |
18 |
19 |

20 | 21 | {name} 22 | 23 |

24 |

{description}

25 |
26 |
27 | {watchers_count} 28 |
29 |
30 | {stargazers_count} 31 |
32 |
33 | {open_issues} 34 |
35 |
36 | {forks} 37 |
38 |
39 |
40 |
41 | ) 42 | } 43 | 44 | RepoItem.propTypes = { 45 | repo: PropTypes.object.isRequired, 46 | } 47 | 48 | export default RepoItem 49 | -------------------------------------------------------------------------------- /src/components/repos/RepoList.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types' 2 | import RepoItem from './RepoItem' 3 | 4 | function RepoList({ repos }) { 5 | return ( 6 |
7 |
8 |

9 | Latest Repositories 10 |

11 | {repos.map((repo) => ( 12 | 13 | ))} 14 |
15 |
16 | ) 17 | } 18 | 19 | RepoList.propTypes = { 20 | repos: PropTypes.array.isRequired, 21 | } 22 | 23 | export default RepoList 24 | -------------------------------------------------------------------------------- /src/components/users/UserItem.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'react-router-dom' 2 | import PropTypes from 'prop-types' 3 | 4 | function UserItem({ user: { login, avatar_url } }) { 5 | return ( 6 |
7 |
8 |
9 |
10 |
11 | Profile 12 |
13 |
14 |
15 |
16 |

{login}

17 | 21 | Visit Profile 22 | 23 |
24 |
25 |
26 | ) 27 | } 28 | 29 | UserItem.propTypes = { 30 | user: PropTypes.object.isRequired, 31 | } 32 | 33 | export default UserItem 34 | -------------------------------------------------------------------------------- /src/components/users/UserResults.jsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import Spinner from '../layout/Spinner' 3 | import UserItem from '../users/UserItem' 4 | import GithubContext from '../../context/github/GithubContext' 5 | 6 | function UserResults() { 7 | const { users, loading } = useContext(GithubContext) 8 | 9 | if (!loading) { 10 | return ( 11 |
12 | {users.map((user) => ( 13 | 14 | ))} 15 |
16 | ) 17 | } else { 18 | return 19 | } 20 | } 21 | 22 | export default UserResults 23 | -------------------------------------------------------------------------------- /src/components/users/UserSearch.jsx: -------------------------------------------------------------------------------- 1 | import { useState, useContext } from 'react' 2 | import GithubContext from '../../context/github/GithubContext' 3 | import AlertContext from '../../context/alert/AlertContext' 4 | import { searchUsers } from '../../context/github/GithubActions' 5 | 6 | function UserSearch() { 7 | const [text, setText] = useState('') 8 | 9 | const { users, dispatch } = useContext(GithubContext) 10 | const { setAlert } = useContext(AlertContext) 11 | 12 | const handleChange = (e) => setText(e.target.value) 13 | 14 | const handleSubmit = async (e) => { 15 | e.preventDefault() 16 | 17 | if (text === '') { 18 | setAlert('Please enter something', 'error') 19 | } else { 20 | dispatch({ type: 'SET_LOADING' }) 21 | const users = await searchUsers(text) 22 | dispatch({ type: 'GET_USERS', payload: users }) 23 | 24 | setText('') 25 | } 26 | } 27 | 28 | return ( 29 |
30 |
31 |
32 |
33 |
34 | 41 | 47 |
48 |
49 |
50 |
51 | {users.length > 0 && ( 52 |
53 | 59 |
60 | )} 61 |
62 | ) 63 | } 64 | 65 | export default UserSearch 66 | -------------------------------------------------------------------------------- /src/context/alert/AlertContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useReducer } from 'react' 2 | import alertReducer from './AlertReducer' 3 | 4 | const AlertContext = createContext() 5 | 6 | export const AlertProvider = ({ children }) => { 7 | const initialState = null 8 | 9 | const [state, dispatch] = useReducer(alertReducer, initialState) 10 | 11 | // Set an alert 12 | const setAlert = (msg, type) => { 13 | dispatch({ 14 | type: 'SET_ALERT', 15 | payload: { msg, type }, 16 | }) 17 | 18 | setTimeout(() => dispatch({ type: 'REMOVE_ALERT' }), 3000) 19 | } 20 | 21 | return ( 22 | 23 | {children} 24 | 25 | ) 26 | } 27 | 28 | export default AlertContext 29 | -------------------------------------------------------------------------------- /src/context/alert/AlertReducer.js: -------------------------------------------------------------------------------- 1 | const alertReducer = (state, action) => { 2 | switch (action.type) { 3 | case 'SET_ALERT': 4 | return action.payload 5 | case 'REMOVE_ALERT': 6 | return null 7 | default: 8 | return state 9 | } 10 | } 11 | 12 | export default alertReducer 13 | -------------------------------------------------------------------------------- /src/context/github/GithubActions.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | const GITHUB_URL = process.env.REACT_APP_GITHUB_URL 3 | const GITHUB_TOKEN = process.env.REACT_APP_GITHUB_TOKEN 4 | 5 | const github = axios.create({ 6 | baseURL: GITHUB_URL, 7 | headers: { Authorization: `token ${GITHUB_TOKEN}` }, 8 | }) 9 | 10 | // Get search results 11 | export const searchUsers = async (text) => { 12 | const params = new URLSearchParams({ 13 | q: text, 14 | }) 15 | 16 | const response = await github.get(`/search/users?${params}`) 17 | return response.data.items 18 | } 19 | 20 | // Get user and repos 21 | export const getUserAndRepos = async (login) => { 22 | const [user, repos] = await Promise.all([ 23 | github.get(`/users/${login}`), 24 | github.get(`/users/${login}/repos`), 25 | ]) 26 | 27 | return { user: user.data, repos: repos.data } 28 | } 29 | -------------------------------------------------------------------------------- /src/context/github/GithubContext.js: -------------------------------------------------------------------------------- 1 | import { createContext, useReducer } from 'react' 2 | import githubReducer from './GithubReducer' 3 | 4 | const GithubContext = createContext() 5 | 6 | export const GithubProvider = ({ children }) => { 7 | const initialState = { 8 | users: [], 9 | user: {}, 10 | repos: [], 11 | loading: false, 12 | } 13 | 14 | const [state, dispatch] = useReducer(githubReducer, initialState) 15 | 16 | return ( 17 | 23 | {children} 24 | 25 | ) 26 | } 27 | 28 | export default GithubContext 29 | -------------------------------------------------------------------------------- /src/context/github/GithubReducer.js: -------------------------------------------------------------------------------- 1 | const githubReducer = (state, action) => { 2 | switch (action.type) { 3 | case 'GET_USERS': 4 | return { 5 | ...state, 6 | users: action.payload, 7 | loading: false, 8 | } 9 | case 'GET_USER_AND_REPOS': 10 | return { 11 | ...state, 12 | user: action.payload.user, 13 | repos: action.payload.repos, 14 | loading: false, 15 | } 16 | case 'SET_LOADING': 17 | return { 18 | ...state, 19 | loading: true, 20 | } 21 | case 'CLEAR_USERS': 22 | return { 23 | ...state, 24 | users: [], 25 | } 26 | default: 27 | return state 28 | } 29 | } 30 | 31 | export default githubReducer 32 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .custom-card-image .card.image-full:before { 6 | border-radius: 0.5rem; 7 | opacity: 0.45; 8 | } 9 | -------------------------------------------------------------------------------- /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 | ReactDOM.createRoot(document.getElementById('root')).render() 7 | -------------------------------------------------------------------------------- /src/pages/About.jsx: -------------------------------------------------------------------------------- 1 | function About() { 2 | return ( 3 | <> 4 |

Github Finder

5 |

6 | A React app to search GitHub profiles and see profile details. This 7 | project is part of the 8 | 9 | {' '} 10 | React Front To Back 11 | {' '} 12 | Udemy course by 13 | 14 | Brad Traversy 15 | 16 | . 17 |

18 |

19 | Version 1.0.0 20 |

21 |

22 | Layout By: 23 | 24 | Hassib Moddasser 25 | 26 |

27 | 28 | ) 29 | } 30 | 31 | export default About 32 | -------------------------------------------------------------------------------- /src/pages/Home.jsx: -------------------------------------------------------------------------------- 1 | import UserResults from '../components/users/UserResults' 2 | import UserSearch from '../components/users/UserSearch' 3 | 4 | function Home() { 5 | return ( 6 | <> 7 | 8 | 9 | 10 | ) 11 | } 12 | 13 | export default Home 14 | -------------------------------------------------------------------------------- /src/pages/NotFound.jsx: -------------------------------------------------------------------------------- 1 | import { FaHome } from 'react-icons/fa' 2 | import { Link } from 'react-router-dom' 3 | 4 | function NotFound() { 5 | return ( 6 |
7 |
8 |
9 |

Oops!

10 |

404 - Page Not Found!

11 | 12 | 13 | Back To Home 14 | 15 |
16 |
17 |
18 | ) 19 | } 20 | 21 | export default NotFound 22 | -------------------------------------------------------------------------------- /src/pages/User.jsx: -------------------------------------------------------------------------------- 1 | import { FaCodepen, FaStore, FaUserFriends, FaUsers } from 'react-icons/fa' 2 | import { useEffect, useContext } from 'react' 3 | import { useParams, Link } from 'react-router-dom' 4 | import Spinner from '../components/layout/Spinner' 5 | import RepoList from '../components/repos/RepoList' 6 | import GithubContext from '../context/github/GithubContext' 7 | import { getUserAndRepos } from '../context/github/GithubActions' 8 | 9 | function User() { 10 | const { user, loading, repos, dispatch } = useContext(GithubContext) 11 | 12 | const params = useParams() 13 | 14 | useEffect(() => { 15 | dispatch({ type: 'SET_LOADING' }) 16 | const getUserData = async () => { 17 | const userData = await getUserAndRepos(params.login) 18 | dispatch({ type: 'GET_USER_AND_REPOS', payload: userData }) 19 | } 20 | 21 | getUserData() 22 | }, [dispatch, params.login]) 23 | 24 | const { 25 | name, 26 | type, 27 | avatar_url, 28 | location, 29 | bio, 30 | blog, 31 | twitter_username, 32 | login, 33 | html_url, 34 | followers, 35 | following, 36 | public_repos, 37 | public_gists, 38 | hireable, 39 | } = user 40 | 41 | if (loading) { 42 | return 43 | } 44 | 45 | // NOTE: check for valid url to users website 46 | 47 | const websiteUrl = blog?.startsWith('http') ? blog : 'https://' + blog 48 | 49 | // NOTE: code here has been fixed so that stats no longer show scroll bar on 50 | // mobile / small devices 51 | // https://www.udemy.com/course/react-front-to-back-2022/learn/lecture/29768968#questions/16902278 52 | 53 | // NOTE: if you are having problems with the name and login showing at the top 54 | // of the image then you need the className='flex-grow-0' on the

tag 55 | // default styling on

in daisyUI now has flex-grow-1 56 | 57 | return ( 58 | <> 59 |

60 |
61 | 62 | Back To Search 63 | 64 |
65 | 66 |
67 |
68 |
69 |
70 | 71 |
72 |
73 |

{name}

74 |

{login}

75 |
76 |
77 |
78 | 79 |
80 |
81 |

82 | {name} 83 |
{type}
84 | {hireable && ( 85 |
Hireable
86 | )} 87 |

88 |

{bio}

89 | 99 |
100 | 101 |
102 | {location && ( 103 |
104 |
Location
105 |
{location}
106 |
107 | )} 108 | {blog && ( 109 |
110 |
Website
111 | 116 |
117 | )} 118 | {twitter_username && ( 119 |
120 |
Twitter
121 | 130 |
131 | )} 132 |
133 |
134 |
135 | 136 |
137 |
138 |
139 |
140 | 141 |
142 |
Followers
143 |
144 | {followers} 145 |
146 |
147 | 148 |
149 |
150 | 151 |
152 |
Following
153 |
154 | {following} 155 |
156 |
157 | 158 |
159 |
160 | 161 |
162 |
Public Repos
163 |
164 | {public_repos} 165 |
166 |
167 | 168 |
169 |
170 | 171 |
172 |
Public Gists
173 |
174 | {public_gists} 175 |
176 |
177 |
178 |
179 | 180 | 181 |
182 | 183 | ) 184 | } 185 | 186 | export default User 187 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ['./src/**/*.{js,jsx,ts,tsx}', './public/index.html'], 3 | theme: { 4 | extend: {}, 5 | }, 6 | variants: { 7 | extend: {}, 8 | }, 9 | plugins: [require('daisyui')], 10 | } 11 | --------------------------------------------------------------------------------