moving online

This commit is contained in:
QkoSad
2022-11-07 19:38:16 +02:00
parent 53737bce7f
commit 6b5c61de0b
34 changed files with 2005 additions and 144 deletions
-38
View File
@@ -1,38 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
+31 -21
View File
@@ -1,25 +1,35 @@
import logo from './logo.svg';
import './App.css';
import Home from "./pages/Home";
import About from "./pages/About";
import NotFound from "./pages/NotFound";
import Footer from "./components/layout/Footer";
import Navbar from "./components/layout/Navbar";
import Alert from "./components/layout/Alert";
import User from './pages/User'
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import { GithubProvider } from "./context/github/GithubContext";
import { AlertProvider } from "./context/alert/AlertContext";
function App() {
export default function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
<GithubProvider>
<AlertProvider>
<Router>
<div className="flex flex-col justify-between h-screen">
<Navbar />
<main className="container mx-auto px-3 pb-12">
<Alert />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/user/:login" element={<User />} />
<Route path="/notfound" element={<NotFound />} />
<Route path="/*" element={<NotFound />} />
</Routes>
</main>
<Footer />
</div>
</Router>
</AlertProvider>
</GithubProvider>
);
}
export default App;
-8
View File
@@ -1,8 +0,0 @@
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});
+31
View File
@@ -0,0 +1,31 @@
import { useContext } from "react";
import AlertContext from "../../context/alert/AlertContext";
function Alert() {
const { alert } = useContext(AlertContext);
return (
<div
className={`grid grid-cols-1 xl:grid-cols-2 lg:grid-cols-2 md:grid-cols-2 gap-8 mb-4`}
style={{ visibility: alert ? "visible" : "hidden" }}
>
<div className="alert alert-error">
<div>
<svg
fill="none"
viewBox="0 0 24 24"
className="w-6 h-6 stroke-current mr-3"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636"
></path>
</svg>
<strong>{alert?.msg}</strong>
</div>
</div>
</div>
);
}
export default Alert;
+22
View File
@@ -0,0 +1,22 @@
export default function Footer() {
const footerYear = new Date().getFullYear();
return (
<footer className="footer p-10 bg-gray-700 text-primary-content footer-center">
<div>
<svg
width="50"
height="50"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
fillRule="evenodd"
clipRule="evenodd"
className="inline-block fill-current"
>
<path d="M22.672 15.226l-2.432.811.841 2.515c.33 1.019-.209 2.127-1.23 2.456-1.15.325-2.148-.321-2.463-1.226l-.84-2.518-5.013 1.677.84 2.517c.391 1.203-.434 2.542-1.831 2.542-.88 0-1.601-.564-1.86-1.314l-.842-2.516-2.431.809c-1.135.328-2.145-.317-2.463-1.229-.329-1.018.211-2.127 1.231-2.456l2.432-.809-1.621-4.823-2.432.808c-1.355.384-2.558-.59-2.558-1.839 0-.817.509-1.582 1.327-1.846l2.433-.809-.842-2.515c-.33-1.02.211-2.129 1.232-2.458 1.02-.329 2.13.209 2.461 1.229l.842 2.515 5.011-1.677-.839-2.517c-.403-1.238.484-2.553 1.843-2.553.819 0 1.585.509 1.85 1.326l.841 2.517 2.431-.81c1.02-.33 2.131.211 2.461 1.229.332 1.018-.21 2.126-1.23 2.456l-2.433.809 1.622 4.823 2.433-.809c1.242-.401 2.557.484 2.557 1.838 0 .819-.51 1.583-1.328 1.847m-8.992-6.428l-5.01 1.675 1.619 4.828 5.011-1.674-1.62-4.829z"></path>
</svg>
<p>Copyright &copy; {footerYear} All rights reserved</p>
</div>
</footer>
);
}
+30
View File
@@ -0,0 +1,30 @@
import { FaGithub } from "react-icons/fa";
import { Link } from "react-router-dom";
import PropTypes from "prop-types";
function Navbar({ title }) {
return (
<nav className="navbar mb-12 shadow-lg bg-neutral text-neutral-content">
<div className="container mx-auto">
<div className="flex-none px-2 mx-2">
<FaGithub className="inline pr-2 text-3xl"/>
<Link to='/' className="text-ls font-bold aling-middle">
{title}
</Link>
</div>
<div className="flex-1 px-2 mx-2">
<div className="flex justify-end">
<Link to='/'className="btn btn-ghost btn-sm rouded-btn">Home</Link>
<Link to='/about'className="btn btn-ghost btn-sm rouded-btn">About</Link>
</div>
</div>
</div>
</nav>
);
}
Navbar.defaultProps = {
title: "Github Finder",
};
Navbar.propTypes = { title: PropTypes.string };
export default Navbar;
+14
View File
@@ -0,0 +1,14 @@
import spinner from "./assets/spinner.gif";
export default function Spinner() {
return (
<div className="w-100 mt-20">
<img
width={180}
src={spinner}
alt="Loading"
className="text-center mx-auto"
/>
</div>
);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

+48
View File
@@ -0,0 +1,48 @@
import { FaEye, FaInfo, FaLink, FaStar, FaUtensils } from 'react-icons/fa'
import PropTypes from 'prop-types'
function RepoItem({ repo }) {
const {
name,
description,
html_url,
forks,
open_issues,
watchers_count,
stargazers_count,
} = repo
return (
<div className='mb-2 rounded-md card bg-base-200 hover:bg-base-300'>
<div className='card-body'>
<h3 className='mb-2 text-xl font-semibold'>
<a href={html_url}>
<FaLink className='inline mr-1' /> {name}
</a>
</h3>
<p className='mb-3'>{description}</p>
<div>
<div className='mr-2 badge badge-info badge-lg'>
<FaEye className='mr-2' /> {watchers_count}
</div>
<div className='mr-2 badge badge-success badge-lg'>
<FaStar className='mr-2' /> {stargazers_count}
</div>
<div className='mr-2 badge badge-error badge-lg'>
<FaInfo className='mr-2' /> {open_issues}
</div>
<div className='mr-2 badge badge-warning badge-lg'>
<FaUtensils className='mr-2' /> {forks}
</div>
</div>
</div>
</div>
)
}
RepoItem.propTypes = {
repo: PropTypes.object.isRequired,
}
export default RepoItem
+21
View File
@@ -0,0 +1,21 @@
import RepoItem from "./RepoItem";
import PropTypes from "prop-types";
export default function RepoList({ repos }) {
return (
<div className="rounded-lg shadow-lg card-bg-base-100">
<div className="card-body">
<h2 className="text-3xl my-4 front-bold card-title">
Latest Repositories
</h2>
{repos.map((repo) => (
<RepoItem key={repo.id} repo={repo}/>
))}
</div>
</div>
);
}
RepoList.propTypes = {
repos: PropTypes.array.isRequired,
};
+31
View File
@@ -0,0 +1,31 @@
import { Link } from "react-router-dom";
import PropTypes from "prop-types";
export default function UserItem({ user: { login, avatar_url } }) {
return (
<div className="card shadow-md compact side bg-base-100">
<div className="flex=row items-center space-x-4 card-body">
<div>
<div className="avatar">
<div className="rounded-full shadow w-14 h-14">
<img src={avatar_url} alt="Profile" />
</div>
</div>
</div>
<div>
<h2 className="card-title"></h2>
<Link
className="text-base-content text-opacity-40"
to={`/user/${login}`}
>
Visit Profile
</Link>
</div>
</div>
</div>
);
}
UserItem.propTypes = {
user: PropTypes.object.isRequired,
};
+20
View File
@@ -0,0 +1,20 @@
import Spinner from "../layout/Spinner";
import UserItem from "./UserItem";
import { useContext } from "react";
import GithubContext from "../../context/github/GithubContext";
export default function UserResults() {
const { users, loading } = useContext(GithubContext);
if (!loading) {
return (
<div className="grid grid-cols-1 gap-8 xl:grid-cols-4 lg:grid-cols-3 md:grid-cols-2">
{users.map((user) => (
<UserItem key={user.id} user={user} />
))}
</div>
);
} else {
return <Spinner />;
}
}
+60
View File
@@ -0,0 +1,60 @@
import AlertContext from "../../context/alert/AlertContext";
import GithubContext from "../../context/github/GithubContext";
import { searchUsers } from "../../context/github/GithubActions";
import { useContext, useState } from "react";
export default function UserSearch() {
const [text, setText] = useState("");
const { users, dispatch } = useContext(GithubContext);
const { setAlert } = useContext(AlertContext);
const handleChange = (e) => setText(e.target.value);
const handleSubmit = async (e) => {
e.preventDefault();
if (text === "") {
setAlert("Please enter something", "error");
} else {
dispatch({ type: "SET_LOADING" });
const users = await searchUsers(text);
dispatch({ type: "GET_USERS", payload: users });
setText("");
}
};
return (
<div className="grid grid-cols-1 xl:grid-cols2- lg:grid-cols-2 md:grid-cols-2 mb-8 gap-8">
<div>
<form onSubmit={handleSubmit}>
<div className="form-control">
<div className="relative">
<input
type="text"
className="w-full pr-40 bg-gray-200 input input-lg text-black "
placeholder="Search"
onChange={handleChange}
value={text}
/>
<button
className="absolute top-0 right-0 rounded-l-none w-36 btn btn-lg"
type="submit"
>
Go
</button>
</div>
</div>
</form>
</div>
{users.length > 0 && (
<div>
<button
onClick={() => dispatch({ type: "CLEAR_USERS" })}
className="btn btn-ghost btn-lg"
>
Clear
</button>
</div>
)}
</div>
);
}
+22
View File
@@ -0,0 +1,22 @@
import { createContext, useReducer } from "react";
import alertReducer from "./AlertReducer";
const AlertContext = createContext();
export const AlertProvider = ({ children }) => {
const initialState = null;
const [state, dispatch] = useReducer(alertReducer, initialState);
const setAlert = (msg, type)=>{
dispatch({
type:"SET_ALERT",
payload:{msg,type}
})
setTimeout(()=> dispatch({type:"REMOVE_ALERT"}),3000)
}
return (
<AlertContext.Provider value={{ alert: state ,setAlert}}>
{children}
</AlertContext.Provider>
);
};
export default AlertContext;
+11
View File
@@ -0,0 +1,11 @@
const alertReducer = (state, action) => {
switch (action.type) {
case "SET_ALERT":
return action.payload;
case "REMOVE_ALERT":
return null;
default:
return state;
}
};
export default alertReducer;
+27
View File
@@ -0,0 +1,27 @@
import axios from 'axios'
const GITHUB_URL = process.env.REACT_APP_GITHUB_URL
const GITHUB_TOKEN = process.env.REACT_APP_GITHUB_TOKEN
const github = axios.create({
baseURL: GITHUB_URL,
headers: { Authorization: `token ${GITHUB_TOKEN}` },
})
export const searchUsers = async (text) => {
const params = new URLSearchParams({
q: text,
})
const response = await github.get(`/search/users?${params}`)
return response.data.items
}
export const getUserAndRepos = async (login) => {
const [user, repos] = await Promise.all([
github.get(`/users/${login}`),
github.get(`/users/${login}/repos`),
])
return { user: user.data, repos: repos.data }
}
+25
View File
@@ -0,0 +1,25 @@
import { createContext, useReducer } from "react";
import githubReducer from "./GithubReducer";
const GithubContext = createContext();
export const GithubProvider = ({ children }) => {
const initialState = {
users: [],
user:{},
repos:[],
loading: false,
};
const [state, dispatch] = useReducer(githubReducer, initialState);
return (
<GithubContext.Provider
value={{
...state,
dispatch,
}}
>
{children}
</GithubContext.Provider>
);
};
export default GithubContext;
+30
View File
@@ -0,0 +1,30 @@
const githubReducer = (state, action) => {
switch (action.type) {
case "GET_USERS":
return {
...state,
users: action.payload,
loading: false,
};
case "SET_LOADING":
return {
...state,
loading: true,
};
case "CLEAR_USERS":
return {
...state,
users: [],
};
case "GET_USER_AND_REPOS":
return{
...state,
user: action.payload.user,
repos: action.payload.repos,
loading: false
}
default:
return state;
}
};
export default githubReducer;
+6 -11
View File
@@ -1,13 +1,8 @@
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;
@tailwind base;
@tailwind components;
@tailwind utilities;
.custom-card-image .card.image-full:before {
border-radius: 0.5rem;
opacity: 0.45;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
-5
View File
@@ -2,7 +2,6 @@ import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
@@ -11,7 +10,3 @@ root.render(
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
+3
View File
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

+29
View File
@@ -0,0 +1,29 @@
export default function About() {
return (
<div>
<h1 className="text-6xl mb-4">Github Finder</h1>
<p className="mb-4 text-2xl font-light">
A React app to search GitHub profiles and see profile details. This
project is part of the
<a href="https://www.udemy.com/course/modern-react-front-to-back/">
{" "}
React Front To Back
</a>{" "}
Udemy course by
<strong>
<a href="https://traversymedia.com"> Brad Traversy</a>
</strong>
.
</p>
<p className="text-lg text-gray-400">
Version <span className="text-white">1.0.0</span>
</p>
<p className="text-lg text-gray-400">
Layout By:
<a className="text-white" href="https://twitter.com/hassibmoddasser">
Hassib Moddasser
</a>
</p>
</div>
);
}
+10
View File
@@ -0,0 +1,10 @@
import UserResults from "../components/users/UserResults";
import UserSearch from "../components/users/UserSearch";
export default function Home() {
return (
<>
<UserResults />
<UserSearch />
</>
);
}
+19
View File
@@ -0,0 +1,19 @@
import { FaHome } from "react-icons/fa";
import { Link } from "react-router-dom";
export default function NotFound() {
return (
<div className="hero">
<div className="text-center hero-content">
<div className="max-w-lg">
<h1 className="text-8xl font-bold mb-8">Oop!</h1>
<p className="text-5xl mb-8">404 - Page not found!</p>
<Link className="btn btn-primary btn-lg" to="/">
<FaHome className="mr-2" />
Back To Home
</Link>
</div>
</div>
</div>
);
}
+186
View File
@@ -0,0 +1,186 @@
import { FaCodepen, FaStore, FaUserFriends, FaUsers } from 'react-icons/fa'
import { useEffect, useContext } from 'react'
import { useParams, Link } from 'react-router-dom'
import Spinner from '../components/layout/Spinner'
import RepoList from '../components/repos/RepoList'
import GithubContext from '../context/github/GithubContext'
import { getUserAndRepos } from '../context/github/GithubActions'
function User() {
const { user, loading, repos, dispatch } = useContext(GithubContext)
const params = useParams()
useEffect(() => {
dispatch({ type: 'SET_LOADING' })
const getUserData = async () => {
const userData = await getUserAndRepos(params.login)
dispatch({ type: 'GET_USER_AND_REPOS', payload: userData })
}
getUserData()
}, [dispatch, params.login])
const {
name,
type,
avatar_url,
location,
bio,
blog,
twitter_username,
login,
html_url,
followers,
following,
public_repos,
public_gists,
hireable,
} = user
if (loading) {
return <Spinner />
}
// NOTE: check for valid url to users website
const websiteUrl = blog?.startsWith('http') ? blog : 'https://' + blog
// NOTE: code here has been fixed so that stats no longer show scroll bar on
// mobile / small devices
// https://www.udemy.com/course/react-front-to-back-2022/learn/lecture/29768968#questions/16902278
// NOTE: if you are having problems with the name and login showing at the top
// of the image then you need the className='flex-grow-0' on the <p> tag
// default styling on <p> in daisyUI now has flex-grow-1
return (
<>
<div className='w-full mx-auto lg:w-10/12'>
<div className='mb-4'>
<Link to='/' className='btn btn-ghost'>
Back To Search
</Link>
</div>
<div className='grid grid-cols-1 xl:grid-cols-3 lg:grid-cols-3 md:grid-cols-3 mb-8 md:gap-8'>
<div className='custom-card-image mb-6 md:mb-0'>
<div className='rounded-lg shadow-xl card image-full'>
<figure>
<img src={avatar_url} alt='' />
</figure>
<div className='card-body justify-end'>
<h2 className='card-title mb-0'>{name}</h2>
<p className='flex-grow-0'>{login}</p>
</div>
</div>
</div>
<div className='col-span-2'>
<div className='mb-6'>
<h1 className='text-3xl card-title'>
{name}
<div className='ml-2 mr-1 badge badge-success'>{type}</div>
{hireable && (
<div className='mx-1 badge badge-info'>Hireable</div>
)}
</h1>
<p>{bio}</p>
<div className='mt-4 card-actions'>
<a
href={html_url}
target='_blank'
rel='noreferrer'
className='btn btn-outline'
>
Visit Github Profile
</a>
</div>
</div>
<div className='w-full rounded-lg shadow-md bg-base-100 stats'>
{location && (
<div className='stat'>
<div className='stat-title text-md'>Location</div>
<div className='text-lg stat-value'>{location}</div>
</div>
)}
{blog && (
<div className='stat'>
<div className='stat-title text-md'>Website</div>
<div className='text-lg stat-value'>
<a href={websiteUrl} target='_blank' rel='noreferrer'>
{websiteUrl}
</a>
</div>
</div>
)}
{twitter_username && (
<div className='stat'>
<div className='stat-title text-md'>Twitter</div>
<div className='text-lg stat-value'>
<a
href={`https://twitter.com/${twitter_username}`}
target='_blank'
rel='noreferrer'
>
{twitter_username}
</a>
</div>
</div>
)}
</div>
</div>
</div>
<div className='w-full py-5 mb-6 rounded-lg shadow-md bg-base-100 stats'>
<div className='grid grid-cols-1 md:grid-cols-3'>
<div className='stat'>
<div className='stat-figure text-secondary'>
<FaUsers className='text-3xl md:text-5xl' />
</div>
<div className='stat-title pr-5'>Followers</div>
<div className='stat-value pr-5 text-3xl md:text-4xl'>
{followers}
</div>
</div>
<div className='stat'>
<div className='stat-figure text-secondary'>
<FaUserFriends className='text-3xl md:text-5xl' />
</div>
<div className='stat-title pr-5'>Following</div>
<div className='stat-value pr-5 text-3xl md:text-4xl'>
{following}
</div>
</div>
<div className='stat'>
<div className='stat-figure text-secondary'>
<FaCodepen className='text-3xl md:text-5xl' />
</div>
<div className='stat-title pr-5'>Public Repos</div>
<div className='stat-value pr-5 text-3xl md:text-4xl'>
{public_repos}
</div>
</div>
<div className='stat'>
<div className='stat-figure text-secondary'>
<FaStore className='text-3xl md:text-5xl' />
</div>
<div className='stat-title pr-5'>Public Gists</div>
<div className='stat-value pr-5 text-3xl md:text-4xl'>
{public_gists}
</div>
</div>
</div>
</div>
<RepoList repos={repos} />
</div>
</>
)
}
export default User
-13
View File
@@ -1,13 +0,0 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;
-5
View File
@@ -1,5 +0,0 @@
// 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';