Compare commits

...

4 Commits

Author SHA1 Message Date
84a2cc7bdd add meals components 2023-03-18 11:52:06 +13:00
a326630df2 add cart button component 2023-03-18 11:42:23 +13:00
7f49cd68e2 add Header component 2023-03-18 11:01:39 +13:00
2c22f8223e simplify the app.js and index.js 2023-03-18 11:01:21 +13:00
14 changed files with 322 additions and 0 deletions

43
public/index.html Normal file
View 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>

17
src/App.js Normal file
View File

@ -0,0 +1,17 @@
import React from "react";
import Header from "./components/Layout/Header";
import Meals from "./components/Meals/Meals";
const App = () => {
return (
<>
<Header />
<main>
<Meals />
</main>
</>
);
};
export default App;

BIN
src/assets/meals.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

View File

@ -0,0 +1,15 @@
const CartIcon = () => {
return (
<svg
xmlns='http://www.w3.org/2000/svg'
viewBox='0 0 20 20'
fill='currentColor'
>
<path d='M3 1a1 1 0 000 2h1.22l.305 1.222a.997.997 0 00.01.042l1.358 5.43-.893.892C3.74 11.846 4.632 14 6.414 14H15a1 1 0 000-2H6.414l1-1H14a1 1 0 00.894-.553l3-6A1 1 0 0017 3H6.28l-.31-1.243A1 1 0 005 1H3zM16 16.5a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0zM6.5 18a1.5 1.5 0 100-3 1.5 1.5 0 000 3z' />
</svg>
);
};
export default CartIcon;

View File

@ -0,0 +1,21 @@
import React from "react";
import mealsImage from "../../assets/meals.jpg";
import classes from "./Header.module.css";
import HeaderCartButton from "./HeaderCartButton";
const Header = () => {
return (
<>
<header className={classes.header}>
<h1>ReactMeals</h1>
<HeaderCartButton />
</header>
<div className={classes["main-image"]}>
<img src={mealsImage} alt="A table full of delicious food!" />
</div>
</>
);
};
export default Header;

View File

@ -0,0 +1,29 @@
.header {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 5rem;
background-color: #8a2b06;
color: white;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 10%;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
z-index: 10;
}
.main-image {
width: 100%;
height: 25rem;
z-index: 0;
overflow: hidden;
}
.main-image img {
width: 110%;
height: 100%;
object-fit: cover;
transform: rotateZ(-5deg) translateY(-4rem) translateX(-1rem);
}

View File

@ -0,0 +1,16 @@
import CartIcon from "../Cart/CartIcon";
import classes from "./HeaderCartButton.module.css";
const HeaderCartButton = (props) => {
return (
<button className={classes.button}>
<span className={classes.icon}>
<CartIcon />
</span>
<span>Your Cart</span>
<span className={classes.badge}>3</span>
</button>
);
};
export default HeaderCartButton;

View File

@ -0,0 +1,60 @@
.button {
cursor: pointer;
font: inherit;
border: none;
background-color: #4d1601;
color: white;
padding: 0.75rem 3rem;
display: flex;
justify-content: space-around;
align-items: center;
border-radius: 25px;
font-weight: bold;
margin-right: 20%;
}
.button:hover,
.button:active {
background-color: #2c0d00;
}
.icon {
width: 1.35rem;
height: 1.35rem;
margin-right: 0.5rem;
}
.badge {
background-color: #b94517;
padding: 0.25rem 1rem;
border-radius: 25px;
margin-left: 1rem;
font-weight: bold;
}
.button:hover .badge,
.button:active .badge {
background-color: #92320c;
}
.bump {
animation: bump 300ms ease-out;
}
@keyframes bump {
0% {
transform: scale(1);
}
10% {
transform: scale(0.9);
}
30% {
transform: scale(1.1);
}
50% {
transform: scale(1.15);
}
100% {
transform: scale(1);
}
}

View File

@ -0,0 +1,40 @@
import classes from "./AvailableMeals.module.css";
const DUMMY_MEALS = [
{
id: "m1",
name: "Sushi",
description: "Finest fish and veggies",
price: 22.99,
},
{
id: "m2",
name: "Schnitzel",
description: "A german specialty!",
price: 16.5,
},
{
id: "m3",
name: "Barbecue Burger",
description: "American, raw, meaty",
price: 12.99,
},
{
id: "m4",
name: "Green Bowl",
description: "Healthy...and green...",
price: 18.99,
},
];
const AvailableMeals = () => {
const mealsList = DUMMY_MEALS.map((meal) => <li>{meal.name}</li>);
return (
<section className={classes.meals}>
<ul>{mealsList}</ul>
</section>
);
};
export default AvailableMeals;

View File

@ -0,0 +1,24 @@
.meals {
max-width: 60rem;
width: 90%;
margin: 2rem auto;
animation: meals-appear 1s ease-out forwards;
}
.meals ul {
list-style: none;
margin: 0;
padding: 0;
}
@keyframes meals-appear {
from {
opacity: 0;
transform: translateY(3rem);
}
to {
opacity: 1;
transform: translateY(0);
}
}

View File

@ -0,0 +1,13 @@
import MealsSummary from "./MealsSummary";
import AvailableMeals from "./AvailableMeals";
const Meals = () => {
return (
<>
<AvailableMeals />
<MealsSummary />
</>
);
};
export default Meals;

View File

@ -0,0 +1,19 @@
import classes from "./MealsSummary.module.css";
const MealsSummary = () => {
return (
<section className={classes.summary}>
<h2>Delicious Food, Delivered To You</h2>
<p>
Choose your favorite meal from our broad selection of available meals
and enjoy a delicious lunch or dinner at home.
</p>
<p>
All our meals are cooked with high-quality ingredients, just-in-time and
of course by experienced chefs!
</p>
</section>
);
};
export default MealsSummary;

View File

@ -0,0 +1,18 @@
.summary {
text-align: center;
max-width: 45rem;
width: 90%;
margin: auto;
margin-top: -10rem;
position: relative;
background-color: #383838;
color: white;
border-radius: 14px;
padding: 1rem;
box-shadow: 0 1px 18px 10px rgba(0, 0, 0, 0.25);
}
.summary h2 {
font-size: 2rem;
margin-top: 0;
}

7
src/index.js Normal file
View File

@ -0,0 +1,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById("root"));