cleanups
This commit is contained in:
parent
f8258a5754
commit
9f1d7c9da9
44
react-chap9/src/components/Users/AddUser.js
vendored
44
react-chap9/src/components/Users/AddUser.js
vendored
@ -1,38 +1,38 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
import React, { useState, useRef } from "react";
|
||||
|
||||
import Card from '../UI/Card';
|
||||
import Button from '../UI/Button';
|
||||
import ErrorModal from '../UI/ErrorModal';
|
||||
import Wrapper from '../Helpers/Wrapper';
|
||||
import classes from './AddUser.module.css';
|
||||
import Card from "../UI/Card";
|
||||
import Button from "../UI/Button";
|
||||
import ErrorModal from "../UI/ErrorModal";
|
||||
import Wrapper from "../Helpers/Wrapper";
|
||||
import classes from "./AddUser.module.css";
|
||||
|
||||
const AddUser = (props) => {
|
||||
const nameInputRef = useRef()
|
||||
const ageInputRef = useRef()
|
||||
const nameInputRef = useRef();
|
||||
const ageInputRef = useRef();
|
||||
|
||||
const [error, setError] = useState();
|
||||
|
||||
const addUserHandler = (event) => {
|
||||
event.preventDefault();
|
||||
const enteredName = nameInputRef.current.value
|
||||
const enteredUserAge = ageInputRef.current.value
|
||||
const enteredName = nameInputRef.current.value;
|
||||
const enteredUserAge = ageInputRef.current.value;
|
||||
if (enteredName.trim().length === 0 || enteredUserAge.trim().length === 0) {
|
||||
setError({
|
||||
title: 'Invalid input',
|
||||
message: 'Please enter a valid name and age (non-empty values).',
|
||||
title: "Invalid input",
|
||||
message: "Please enter a valid name and age (non-empty values).",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (+enteredUserAge < 1) {
|
||||
setError({
|
||||
title: 'Invalid age',
|
||||
message: 'Please enter a valid age (> 0).',
|
||||
title: "Invalid age",
|
||||
message: "Please enter a valid age (> 0).",
|
||||
});
|
||||
return;
|
||||
}
|
||||
props.onAddUser(enteredName, enteredUserAge);
|
||||
nameInputRef.current.value = ''
|
||||
ageInputRef.current.value = ''
|
||||
nameInputRef.current.value = "";
|
||||
ageInputRef.current.value = "";
|
||||
};
|
||||
|
||||
const errorHandler = () => {
|
||||
@ -51,17 +51,9 @@ const AddUser = (props) => {
|
||||
<Card className={classes.input}>
|
||||
<form onSubmit={addUserHandler}>
|
||||
<label htmlFor="username">Username</label>
|
||||
<input
|
||||
id="username"
|
||||
type="text"
|
||||
ref={nameInputRef}
|
||||
/>
|
||||
<input id="username" type="text" ref={nameInputRef} />
|
||||
<label htmlFor="age">Age (Years)</label>
|
||||
<input
|
||||
id="age"
|
||||
type="number"
|
||||
ref={ageInputRef}
|
||||
/>
|
||||
<input id="age" type="number" ref={ageInputRef} />
|
||||
<Button type="submit">Add User</Button>
|
||||
</form>
|
||||
</Card>
|
||||
|
1
side-effects/.eslintcache
Normal file
1
side-effects/.eslintcache
Normal file
@ -0,0 +1 @@
|
||||
[{"/Users/tyrel.souza/code/udemy/react-course/side-effects/src/index.js":"1","/Users/tyrel.souza/code/udemy/react-course/side-effects/src/App.js":"2","/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/Home/Home.js":"3","/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/Login/Login.js":"4","/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/MainHeader/MainHeader.js":"5","/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/MainHeader/Navigation.js":"6","/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/UI/Button/Button.js":"7","/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/UI/Card/Card.js":"8"},{"size":206,"mtime":1648642446000,"results":"9","hashOfConfig":"10"},{"size":1092,"mtime":1663864772540,"results":"11","hashOfConfig":"10"},{"size":250,"mtime":1648642446000,"results":"12","hashOfConfig":"10"},{"size":2410,"mtime":1663869709929,"results":"13","hashOfConfig":"10"},{"size":368,"mtime":1648642446000,"results":"14","hashOfConfig":"10"},{"size":571,"mtime":1648642446000,"results":"15","hashOfConfig":"10"},{"size":353,"mtime":1648642446000,"results":"16","hashOfConfig":"10"},{"size":218,"mtime":1648642446000,"results":"17","hashOfConfig":"10"},{"filePath":"18","messages":"19","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"vag9xb",{"filePath":"20","messages":"21","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"22","messages":"23","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"25","messages":"26","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"27","messages":"28","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"29","messages":"30","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"31","messages":"32","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},{"filePath":"33","messages":"34","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":"24"},"/Users/tyrel.souza/code/udemy/react-course/side-effects/src/index.js",[],"/Users/tyrel.souza/code/udemy/react-course/side-effects/src/App.js",[],"/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/Home/Home.js",[],["35","36"],"/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/Login/Login.js",[],"/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/MainHeader/MainHeader.js",[],"/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/MainHeader/Navigation.js",[],"/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/UI/Button/Button.js",[],"/Users/tyrel.souza/code/udemy/react-course/side-effects/src/components/UI/Card/Card.js",[],{"ruleId":"37","replacedBy":"38"},{"ruleId":"39","replacedBy":"40"},"no-native-reassign",["41"],"no-negated-in-lhs",["42"],"no-global-assign","no-unsafe-negation"]
|
38145
side-effects/package-lock.json
generated
Normal file
38145
side-effects/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
side-effects/package.json
Normal file
38
side-effects/package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "react-complete-guide",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "^5.11.6",
|
||||
"@testing-library/react": "^11.2.2",
|
||||
"@testing-library/user-event": "^12.5.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-scripts": "4.0.1",
|
||||
"web-vitals": "^0.2.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
BIN
side-effects/public/favicon.ico
Normal file
BIN
side-effects/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
43
side-effects/public/index.html
Normal file
43
side-effects/public/index.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
BIN
side-effects/public/logo192.png
Normal file
BIN
side-effects/public/logo192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
side-effects/public/logo512.png
Normal file
BIN
side-effects/public/logo512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
25
side-effects/public/manifest.json
Normal file
25
side-effects/public/manifest.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"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"
|
||||
}
|
3
side-effects/public/robots.txt
Normal file
3
side-effects/public/robots.txt
Normal file
@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
40
side-effects/src/App.js
Normal file
40
side-effects/src/App.js
Normal file
@ -0,0 +1,40 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import Login from "./components/Login/Login";
|
||||
import Home from "./components/Home/Home";
|
||||
import MainHeader from "./components/MainHeader/MainHeader";
|
||||
|
||||
function App() {
|
||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const storedUserLoggedInInformation = localStorage.getItem("isLoggedIn");
|
||||
if (storedUserLoggedInInformation === "1") {
|
||||
setIsLoggedIn(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const loginHandler = (email, password) => {
|
||||
// We should of course check email and password
|
||||
// But it's just a dummy/ demo anyways
|
||||
localStorage.setItem("isLoggedIn", "1");
|
||||
setIsLoggedIn(true);
|
||||
};
|
||||
|
||||
const logoutHandler = () => {
|
||||
localStorage.removeItem("isLoggedIn");
|
||||
setIsLoggedIn(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
|
||||
<main>
|
||||
{!isLoggedIn && <Login onLogin={loginHandler} />}
|
||||
{isLoggedIn && <Home onLogout={logoutHandler} />}
|
||||
</main>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
14
side-effects/src/components/Home/Home.js
Normal file
14
side-effects/src/components/Home/Home.js
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
|
||||
import Card from '../UI/Card/Card';
|
||||
import classes from './Home.module.css';
|
||||
|
||||
const Home = (props) => {
|
||||
return (
|
||||
<Card className={classes.home}>
|
||||
<h1>Welcome back!</h1>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
7
side-effects/src/components/Home/Home.module.css
Normal file
7
side-effects/src/components/Home/Home.module.css
Normal file
@ -0,0 +1,7 @@
|
||||
.home {
|
||||
width: 90%;
|
||||
max-width: 40rem;
|
||||
padding: 3rem;
|
||||
margin: 2rem auto;
|
||||
text-align: center;
|
||||
}
|
88
side-effects/src/components/Login/Login.js
Normal file
88
side-effects/src/components/Login/Login.js
Normal file
@ -0,0 +1,88 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
import Card from "../UI/Card/Card";
|
||||
import classes from "./Login.module.css";
|
||||
import Button from "../UI/Button/Button";
|
||||
|
||||
const Login = (props) => {
|
||||
const [enteredEmail, setEnteredEmail] = useState("");
|
||||
const [emailIsValid, setEmailIsValid] = useState();
|
||||
const [enteredPassword, setEnteredPassword] = useState("");
|
||||
const [passwordIsValid, setPasswordIsValid] = useState();
|
||||
const [formIsValid, setFormIsValid] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const identifier = setTimeout(() => {
|
||||
setFormIsValid(
|
||||
enteredEmail.includes("@") && enteredPassword.trim().length > 6
|
||||
);
|
||||
}, 500);
|
||||
|
||||
return () => {
|
||||
clearTimeout(identifier);
|
||||
};
|
||||
}, [enteredEmail, enteredPassword]);
|
||||
|
||||
const emailChangeHandler = (event) => {
|
||||
setEnteredEmail(event.target.value);
|
||||
};
|
||||
|
||||
const passwordChangeHandler = (event) => {
|
||||
setEnteredPassword(event.target.value);
|
||||
};
|
||||
|
||||
const validateEmailHandler = () => {
|
||||
setEmailIsValid(enteredEmail.includes("@"));
|
||||
};
|
||||
|
||||
const validatePasswordHandler = () => {
|
||||
setPasswordIsValid(enteredPassword.trim().length > 6);
|
||||
};
|
||||
|
||||
const submitHandler = (event) => {
|
||||
event.preventDefault();
|
||||
props.onLogin(enteredEmail, enteredPassword);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className={classes.login}>
|
||||
<form onSubmit={submitHandler}>
|
||||
<div
|
||||
className={`${classes.control} ${
|
||||
emailIsValid === false ? classes.invalid : ""
|
||||
}`}
|
||||
>
|
||||
<label htmlFor="email">E-Mail</label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
value={enteredEmail}
|
||||
onChange={emailChangeHandler}
|
||||
onBlur={validateEmailHandler}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={`${classes.control} ${
|
||||
passwordIsValid === false ? classes.invalid : ""
|
||||
}`}
|
||||
>
|
||||
<label htmlFor="password">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
value={enteredPassword}
|
||||
onChange={passwordChangeHandler}
|
||||
onBlur={validatePasswordHandler}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.actions}>
|
||||
<Button type="submit" className={classes.btn} disabled={!formIsValid}>
|
||||
Login
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default Login;
|
56
side-effects/src/components/Login/Login.module.css
Normal file
56
side-effects/src/components/Login/Login.module.css
Normal file
@ -0,0 +1,56 @@
|
||||
.login {
|
||||
width: 90%;
|
||||
max-width: 40rem;
|
||||
margin: 2rem auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.control {
|
||||
margin: 1rem 0;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.control label,
|
||||
.control input {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.control label {
|
||||
font-weight: bold;
|
||||
flex: 1;
|
||||
color: #464646;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.control input {
|
||||
flex: 3;
|
||||
font: inherit;
|
||||
padding: 0.35rem 0.35rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.control input:focus {
|
||||
outline: none;
|
||||
border-color: #4f005f;
|
||||
background: #f6dbfc;
|
||||
}
|
||||
|
||||
.control.invalid input {
|
||||
border-color: red;
|
||||
background: #fbdada;
|
||||
}
|
||||
|
||||
.actions {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.control {
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
}
|
15
side-effects/src/components/MainHeader/MainHeader.js
Normal file
15
side-effects/src/components/MainHeader/MainHeader.js
Normal file
@ -0,0 +1,15 @@
|
||||
import React from 'react';
|
||||
|
||||
import Navigation from './Navigation';
|
||||
import classes from './MainHeader.module.css';
|
||||
|
||||
const MainHeader = (props) => {
|
||||
return (
|
||||
<header className={classes['main-header']}>
|
||||
<h1>A Typical Page</h1>
|
||||
<Navigation isLoggedIn={props.isAuthenticated} onLogout={props.onLogout} />
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainHeader;
|
16
side-effects/src/components/MainHeader/MainHeader.module.css
Normal file
16
side-effects/src/components/MainHeader/MainHeader.module.css
Normal file
@ -0,0 +1,16 @@
|
||||
.main-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #741188;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.main-header h1 {
|
||||
color: white;
|
||||
}
|
29
side-effects/src/components/MainHeader/Navigation.js
Normal file
29
side-effects/src/components/MainHeader/Navigation.js
Normal file
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
|
||||
import classes from './Navigation.module.css';
|
||||
|
||||
const Navigation = (props) => {
|
||||
return (
|
||||
<nav className={classes.nav}>
|
||||
<ul>
|
||||
{props.isLoggedIn && (
|
||||
<li>
|
||||
<a href="/">Users</a>
|
||||
</li>
|
||||
)}
|
||||
{props.isLoggedIn && (
|
||||
<li>
|
||||
<a href="/">Admin</a>
|
||||
</li>
|
||||
)}
|
||||
{props.isLoggedIn && (
|
||||
<li>
|
||||
<button onClick={props.onLogout}>Logout</button>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navigation;
|
43
side-effects/src/components/MainHeader/Navigation.module.css
Normal file
43
side-effects/src/components/MainHeader/Navigation.module.css
Normal file
@ -0,0 +1,43 @@
|
||||
.nav ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav li {
|
||||
margin: 0;
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.nav a {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav a:hover,
|
||||
.nav a:active {
|
||||
color: #f3cafb;
|
||||
}
|
||||
|
||||
.nav button {
|
||||
font: inherit;
|
||||
background: #dd0db0;
|
||||
border: 1px solid #dd0db0;
|
||||
padding: 0.5rem 1.5rem;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.26);
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.nav button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.nav button:hover,
|
||||
.nav button:active {
|
||||
color: #f3cafb;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.26);
|
||||
}
|
18
side-effects/src/components/UI/Button/Button.js
Normal file
18
side-effects/src/components/UI/Button/Button.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
|
||||
import classes from './Button.module.css';
|
||||
|
||||
const Button = (props) => {
|
||||
return (
|
||||
<button
|
||||
type={props.type || 'button'}
|
||||
className={`${classes.button} ${props.className}`}
|
||||
onClick={props.onClick}
|
||||
disabled={props.disabled}
|
||||
>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
30
side-effects/src/components/UI/Button/Button.module.css
Normal file
30
side-effects/src/components/UI/Button/Button.module.css
Normal file
@ -0,0 +1,30 @@
|
||||
.button {
|
||||
font: inherit;
|
||||
border: 1px solid #4f005f;
|
||||
background: #4f005f;
|
||||
color: white;
|
||||
padding: 0.75rem 3.5rem;
|
||||
cursor: pointer;
|
||||
font-size: 1.15rem;
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.button:hover,
|
||||
.button:active {
|
||||
background: #741188;
|
||||
border-color: #741188;
|
||||
}
|
||||
|
||||
.button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button:disabled,
|
||||
button:focus:disabled,
|
||||
button:hover:disabled,
|
||||
button:active:disabled {
|
||||
background: #ccc;
|
||||
border-color: #ccc;
|
||||
color: #666666;
|
||||
cursor: not-allowed;
|
||||
}
|
11
side-effects/src/components/UI/Card/Card.js
Normal file
11
side-effects/src/components/UI/Card/Card.js
Normal file
@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
import classes from './Card.module.css';
|
||||
|
||||
const Card = (props) => {
|
||||
return (
|
||||
<div className={`${classes.card} ${props.className}`}>{props.children}</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Card;
|
5
side-effects/src/components/UI/Card/Card.module.css
Normal file
5
side-effects/src/components/UI/Card/Card.module.css
Normal file
@ -0,0 +1,5 @@
|
||||
.card {
|
||||
background: white;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
|
||||
border-radius: 10px;
|
||||
}
|
16
side-effects/src/index.css
Normal file
16
side-effects/src/index.css
Normal file
@ -0,0 +1,16 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
main {
|
||||
margin-top: 6rem;
|
||||
}
|
8
side-effects/src/index.js
Normal file
8
side-effects/src/index.js
Normal file
@ -0,0 +1,8 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(<App />);
|
Loading…
Reference in New Issue
Block a user