├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.js
├── data.js
├── final
├── App.js
├── components
│ ├── Navbar.js
│ └── StyledNavbar.js
├── data.js
└── pages
│ ├── About.js
│ ├── Dashboard.js
│ ├── Error.js
│ ├── Home.js
│ ├── Login.js
│ ├── Products.js
│ ├── ProtectedRoute.js
│ ├── SharedLayout.js
│ ├── SharedProductLayout.js
│ └── SingleProduct.js
├── index.css
├── index.js
└── pages
├── About.js
├── Dashboard.js
├── Error.js
├── Home.js
├── Login.js
├── Products.js
└── SingleProduct.js
/.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.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React Router 6
2 |
3 | #### React Course
4 |
5 | [My React Course](https://www.udemy.com/course/react-tutorial-and-projects-course/?referralCode=FEE6A921AF07E2563CEF)
6 |
7 | #### Support
8 |
9 | Find the App Useful? [You can always buy me a coffee](https://www.buymeacoffee.com/johnsmilga)
10 |
11 | #### Run Complete Project
12 |
13 | - index.js
14 |
15 | ```js
16 | // import App from './App';
17 | import App from './final/App';
18 | ```
19 |
20 | #### Docs
21 |
22 | [React Router Docs](https://reactrouter.com/docs/en/v6/getting-started/overview)
23 |
24 | #### Install
25 |
26 | ```sh
27 | npm install react-router-dom@6
28 | ```
29 |
30 | #### First Pages
31 |
32 | - App.js
33 |
34 | ```js
35 | import { BrowserRouter, Routes, Route } from 'react-router-dom';
36 |
37 | function App() {
38 | return (
39 |
40 |
41 | home page} />
42 |
46 | testing
47 |
48 | }
49 | />
50 |
51 |
52 | );
53 | }
54 |
55 | export default App;
56 | ```
57 |
58 | #### Components
59 |
60 | - App.js
61 |
62 | ```js
63 | import { BrowserRouter, Routes, Route } from 'react-router-dom';
64 | import Home from './pages/Home';
65 | import About from './pages/About';
66 | import Products from './pages/Products';
67 |
68 | function App() {
69 | return (
70 |
71 |
72 | } />
73 | } />
74 | } />
75 |
76 |
77 | );
78 | }
79 |
80 | export default App;
81 | ```
82 |
83 | #### Links
84 |
85 | - Home.js, About.js
86 |
87 | ```js
88 | import { Link } from 'react-router-dom';
89 |
90 | const Home = () => {
91 | return (
92 |
93 |
Home Page
94 |
95 | About
96 |
97 |
98 |
99 | );
100 | };
101 | export default Home;
102 | ```
103 |
104 | #### Error Page
105 |
106 | - App.js
107 |
108 | ```js
109 | function App() {
110 | return (
111 |
112 |
113 | } />
114 | } />
115 | } />
116 | } />
117 |
118 |
119 | );
120 | }
121 | ```
122 |
123 | - Error.js
124 |
125 | ```js
126 | import { Link } from 'react-router-dom';
127 |
128 | const Error = () => {
129 | return (
130 |
131 | 404
132 | page not found
133 | back home
134 |
135 | );
136 | };
137 | export default Error;
138 | ```
139 |
140 | #### Nested Pages
141 |
142 | - will refactor few times
143 |
144 | - App.js
145 |
146 | ```js
147 | function App() {
148 | return (
149 |
150 |
151 | }>
152 | } />
153 | } />
154 | } />
155 |
156 |
157 |
158 | );
159 | }
160 | ```
161 |
162 | #### Shared Layout
163 |
164 | - Home.js
165 |
166 | ```js
167 | import { Link, Outlet } from 'react-router-dom';
168 |
169 | const Home = () => {
170 | return (
171 |
172 | Home Page
173 |
174 |
175 | );
176 | };
177 | export default Home;
178 | ```
179 |
180 | #### Navbar
181 |
182 | - Navbar.js
183 |
184 | ```js
185 | import { Link } from 'react-router-dom';
186 |
187 | const Navbar = () => {
188 | return (
189 |
194 | );
195 | };
196 | export default Navbar;
197 | ```
198 |
199 | - Home.js
200 |
201 | ```js
202 | import { Link, Outlet } from 'react-router-dom';
203 | import Navbar from '../components/Navbar';
204 | const Home = () => {
205 | return (
206 | <>
207 |
208 |
211 | >
212 | );
213 | };
214 | export default Home;
215 | ```
216 |
217 | #### Index Routes
218 |
219 | - Index routes render in the parent routes outlet at the parent route's path.
220 | - Index routes match when a parent route matches but none of the other children match.
221 | - Index routes are the default child route for a parent route.
222 | - Index routes render when the user hasn't clicked one of the items in a navigation list yet.
223 |
224 | - copy Home.js content
225 | - SharedLayout.js
226 |
227 | ```js
228 | import { Link, Outlet } from 'react-router-dom';
229 | import Navbar from '../components/Navbar';
230 | const SharedLayout = () => {
231 | return (
232 | <>
233 |
234 |
237 | >
238 | );
239 | };
240 | export default SharedLayout;
241 | ```
242 |
243 | - Home.js
244 |
245 | ```js
246 | const Home = () => {
247 | return (
248 |
251 | );
252 | };
253 | export default Home;
254 | ```
255 |
256 | - App.js
257 |
258 | ```js
259 | function App() {
260 | return (
261 |
262 |
263 | }>
264 | } />
265 | } />
266 | } />
267 | } />
268 |
269 |
270 |
271 | );
272 | }
273 | ```
274 |
275 | #### NavLink (style)
276 |
277 | - StyledNavbar.js
278 |
279 | ```js
280 | import { NavLink } from 'react-router-dom';
281 |
282 | ;
292 | ```
293 |
294 | #### NavLink (className)
295 |
296 | - StyledNavbar.js
297 |
298 | ```js
299 |
307 | ```
308 |
309 | #### Reading URL Params
310 |
311 | - App.js
312 |
313 | ```js
314 | function App() {
315 | return (
316 |
317 |
318 | }>
319 | } />
320 | } />
321 | } />
322 | } />
323 | } />
324 |
325 |
326 |
327 | );
328 | }
329 | ```
330 |
331 | #### Single Product
332 |
333 | - SingleProduct.js
334 |
335 | ```js
336 | import { Link, useParams } from 'react-router-dom';
337 | import products from '../data';
338 | const SingleProduct = () => {
339 | const { productId } = useParams();
340 |
341 | return (
342 |
343 | {productId}
344 | back to products
345 |
346 | );
347 | };
348 |
349 | export default SingleProduct;
350 | ```
351 |
352 | #### Products Page
353 |
354 | - Products.js
355 |
356 | ```js
357 | import { Link } from 'react-router-dom';
358 | import products from '../data';
359 | const Products = () => {
360 | return (
361 |
362 | products
363 |
364 | {products.map((product) => {
365 | return (
366 |
367 | {product.name}
368 | more info
369 |
370 | );
371 | })}
372 |
373 |
374 | );
375 | };
376 |
377 | export default Products;
378 | ```
379 |
380 | #### Single Product
381 |
382 | - SingleProduct.js
383 |
384 | ```js
385 | import { Link, useParams } from 'react-router-dom';
386 | import products from '../data';
387 | const SingleProduct = () => {
388 | const { productId } = useParams();
389 | const product = products.find((product) => product.id === productId);
390 | const { image, name } = product;
391 |
392 | return (
393 |
394 |
395 | {name}
396 | back to products
397 |
398 | );
399 | };
400 |
401 | export default SingleProduct;
402 | ```
403 |
404 | #### useNavigate()
405 |
406 | [ (?.) or Optional Chaining Explained](https://youtu.be/PuEGrylM1x8)
407 |
408 | - App.js
409 |
410 | ```js
411 | function App() {
412 | const [user, setUser] = useState(null);
413 |
414 | return (
415 |
416 |
417 | }>
418 | } />
419 | } />
420 | } />
421 | } />
422 | } />
423 | } />
424 | } />
425 |
426 |
427 |
428 | );
429 | }
430 | ```
431 |
432 | - Login.js
433 |
434 | ```js
435 | import { useState } from 'react';
436 | import { useNavigate } from 'react-router-dom';
437 | const Login = ({ setUser }) => {
438 | const [name, setName] = useState('');
439 | const [email, setEmail] = useState('');
440 |
441 | const navigate = useNavigate();
442 |
443 | const handleSubmit = async (e) => {
444 | e.preventDefault();
445 | if (!name || !email) return;
446 | setUser({ name: name, email: email });
447 | navigate('/dashboard');
448 | };
449 |
450 | ```
451 |
452 | [ (?.) or Optional Chaining Explained](https://youtu.be/PuEGrylM1x8)
453 |
454 | - Dashboard.js
455 |
456 | ```js
457 | const Dashboard = ({ user }) => {
458 | return (
459 |
460 | Hello, {user?.name}
461 |
462 | );
463 | };
464 | export default Dashboard;
465 | ```
466 |
467 | #### Protected Route
468 |
469 | - App.js
470 |
471 | ```js
472 |
476 |
477 |
478 | }
479 | />
480 | ```
481 |
482 | - ProtectedRoute.js
483 |
484 | ```js
485 | import { Navigate } from 'react-router-dom';
486 |
487 | const ProtectedRoute = ({ children, user }) => {
488 | if (!user) {
489 | return ;
490 | }
491 | return children;
492 | };
493 |
494 | export default ProtectedRoute;
495 | ```
496 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-router",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.2",
7 | "@testing-library/react": "^12.1.4",
8 | "@testing-library/user-event": "^13.5.0",
9 | "react": "^17.0.2",
10 | "react-dom": "^17.0.2",
11 | "react-router-dom": "^6.2.2",
12 | "react-scripts": "5.0.0",
13 | "web-vitals": "^2.1.4"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject"
20 | },
21 | "eslintConfig": {
22 | "extends": [
23 | "react-app",
24 | "react-app/jest"
25 | ]
26 | },
27 | "browserslist": {
28 | "production": [
29 | ">0.2%",
30 | "not dead",
31 | "not op_mini all"
32 | ],
33 | "development": [
34 | "last 1 chrome version",
35 | "last 1 firefox version",
36 | "last 1 safari version"
37 | ]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-router-6-tutorial/7ec32a47862e454f7551a0b111dc569da8ce8d04/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-router-6-tutorial/7ec32a47862e454f7551a0b111dc569da8ce8d04/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-router-6-tutorial/7ec32a47862e454f7551a0b111dc569da8ce8d04/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 | function App() {
2 | return React Router 6 Tutorial
;
3 | }
4 |
5 | export default App;
6 |
--------------------------------------------------------------------------------
/src/data.js:
--------------------------------------------------------------------------------
1 | const products = [
2 | {
3 | id: 'recZkNf2kwmdBcqd0',
4 | name: 'accent chair',
5 | image:
6 | 'https://res.cloudinary.com/dt2g7mgtv/image/upload/v1681749482/react-comfy-store-products/iuYyO9RP_o_upinxq.jpg',
7 | },
8 | {
9 | id: 'recEHmzvupvT8ZONH',
10 | name: 'albany sectional',
11 |
12 | image:
13 | 'https://res.cloudinary.com/dt2g7mgtv/image/upload/v1681750782/react-comfy-store-products/product-2_lusrzx.jpg',
14 | },
15 | {
16 | id: 'rec5NBwZ5zCD9nfF0',
17 | name: 'albany table',
18 |
19 | image:
20 | 'https://res.cloudinary.com/dt2g7mgtv/image/upload/v1681750874/react-comfy-store-products/product-3_znpiqa.jpg',
21 | },
22 | {
23 | id: 'recd1jIVIEChmiwhe',
24 | name: 'armchair',
25 |
26 | image:
27 | 'https://res.cloudinary.com/dt2g7mgtv/image/upload/v1681750929/react-comfy-store-products/product-4_ebl6q1.jpg',
28 | },
29 | {
30 | id: 'recoM2MyHJGHLVi5l',
31 | name: 'bar stool',
32 | image:
33 | 'https://res.cloudinary.com/dt2g7mgtv/image/upload/v1681751026/react-comfy-store-products/product-5_n184nu.jpg',
34 | },
35 | ];
36 |
37 | export default products;
38 |
--------------------------------------------------------------------------------
/src/final/App.js:
--------------------------------------------------------------------------------
1 | import { BrowserRouter, Routes, Route } from 'react-router-dom';
2 | import { useState } from 'react';
3 | import Home from './pages/Home';
4 | import About from './pages/About';
5 | import Products from './pages/Products';
6 | import Error from './pages/Error';
7 | import SharedLayout from './pages/SharedLayout';
8 | import SingleProduct from './pages/SingleProduct';
9 | import Dashboard from './pages/Dashboard';
10 | import Login from './pages/Login';
11 | import ProtectedRoute from './pages/ProtectedRoute';
12 | import SharedProductLayout from './pages/SharedProductLayout';
13 | function App() {
14 | const [user, setUser] = useState(null);
15 | return (
16 |
17 |
18 | }>
19 | } />
20 | } />
21 |
22 | }>
23 | } />
24 | } />
25 |
26 |
27 | } />
28 |
32 |
33 |
34 | }
35 | />
36 | } />
37 |
38 |
39 |
40 | );
41 | }
42 |
43 | export default App;
44 |
--------------------------------------------------------------------------------
/src/final/components/Navbar.js:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom';
2 | const Navbar = () => {
3 | return (
4 |
9 | );
10 | };
11 | export default Navbar;
12 |
--------------------------------------------------------------------------------
/src/final/components/StyledNavbar.js:
--------------------------------------------------------------------------------
1 | import { NavLink } from 'react-router-dom';
2 | const Navbar = () => {
3 | return (
4 |
30 | );
31 | };
32 | export default Navbar;
33 |
--------------------------------------------------------------------------------
/src/final/data.js:
--------------------------------------------------------------------------------
1 | const products = [
2 | {
3 | id: 'recZkNf2kwmdBcqd0',
4 | name: 'accent chair',
5 | image:
6 | 'https://dl.airtable.com/.attachmentThumbnails/e8bc3791196535af65f40e36993b9e1f/438bd160',
7 | },
8 | {
9 | id: 'recEHmzvupvT8ZONH',
10 | name: 'albany sectional',
11 |
12 | image:
13 | 'https://dl.airtable.com/.attachmentThumbnails/0be1af59cf889899b5c9abb1e4db38a4/d631ac52',
14 | },
15 | {
16 | id: 'rec5NBwZ5zCD9nfF0',
17 | name: 'albany table',
18 |
19 | image:
20 | 'https://dl.airtable.com/.attachmentThumbnails/7478483f40a2f56662a87b304bd4e104/707d397f',
21 | },
22 | {
23 | id: 'recd1jIVIEChmiwhe',
24 | name: 'armchair',
25 |
26 | image:
27 | 'https://dl.airtable.com/.attachmentThumbnails/530c07c5ade5acd9934c8dd334458b86/cf91397f',
28 | },
29 | {
30 | id: 'recoM2MyHJGHLVi5l',
31 | name: 'bar stool',
32 | image:
33 | 'https://dl.airtable.com/.attachmentThumbnails/a6119fabf7256049cc0e8dbcdf536c9c/b0153f66',
34 | },
35 | ];
36 |
37 | export default products;
38 |
--------------------------------------------------------------------------------
/src/final/pages/About.js:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom';
2 | const About = () => {
3 | return (
4 |
5 | About
6 |
7 | Back Home
8 |
9 |
10 | );
11 | };
12 | export default About;
13 |
--------------------------------------------------------------------------------
/src/final/pages/Dashboard.js:
--------------------------------------------------------------------------------
1 | const Dashboard = ({ user }) => {
2 | return (
3 |
4 | Hello, {user?.name}
5 |
6 | );
7 | };
8 | export default Dashboard;
9 |
--------------------------------------------------------------------------------
/src/final/pages/Error.js:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom';
2 |
3 | const Error = () => {
4 | return (
5 |
6 | 404
7 | page not found
8 | back home
9 |
10 | );
11 | };
12 | export default Error;
13 |
--------------------------------------------------------------------------------
/src/final/pages/Home.js:
--------------------------------------------------------------------------------
1 | const Home = () => {
2 | return (
3 |
6 | );
7 | };
8 | export default Home;
9 |
--------------------------------------------------------------------------------
/src/final/pages/Login.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { useNavigate } from 'react-router-dom';
3 | const Login = ({ setUser }) => {
4 | const [name, setName] = useState('');
5 | const [email, setEmail] = useState('');
6 |
7 | const navigate = useNavigate();
8 |
9 | const handleSubmit = async (e) => {
10 | e.preventDefault();
11 | if (!name || !email) return;
12 | setUser({ name: name, email: email });
13 | navigate('/dashboard');
14 | };
15 |
16 | return (
17 |
49 | );
50 | };
51 | export default Login;
52 |
--------------------------------------------------------------------------------
/src/final/pages/Products.js:
--------------------------------------------------------------------------------
1 | import { Link } from 'react-router-dom';
2 | import products from '../data';
3 |
4 | const Products = () => {
5 | return (
6 |
7 |
8 | {products.map((product) => {
9 | return (
10 |
11 | {product.name}
12 | more info
13 |
14 | );
15 | })}
16 |
17 |
18 | );
19 | };
20 |
21 | export default Products;
22 |
--------------------------------------------------------------------------------
/src/final/pages/ProtectedRoute.js:
--------------------------------------------------------------------------------
1 | import { Navigate } from 'react-router-dom';
2 |
3 | const ProtectedRoute = ({ children, user }) => {
4 | if (!user) {
5 | return ;
6 | }
7 | return children;
8 | };
9 | export default ProtectedRoute;
10 |
--------------------------------------------------------------------------------
/src/final/pages/SharedLayout.js:
--------------------------------------------------------------------------------
1 | import { Link, Outlet } from 'react-router-dom';
2 | import Navbar from '../components/Navbar';
3 | import StyledNavbar from '../components/StyledNavbar';
4 | const Home = () => {
5 | return (
6 | <>
7 |
8 |
9 | >
10 | );
11 | };
12 | export default Home;
13 |
--------------------------------------------------------------------------------
/src/final/pages/SharedProductLayout.js:
--------------------------------------------------------------------------------
1 | import { Outlet } from 'react-router-dom';
2 | const Home = () => {
3 | return (
4 | <>
5 | products
6 |
7 | >
8 | );
9 | };
10 | export default Home;
11 |
--------------------------------------------------------------------------------
/src/final/pages/SingleProduct.js:
--------------------------------------------------------------------------------
1 | import { Link, useParams } from 'react-router-dom';
2 | import products from '../data';
3 | const SingleProduct = () => {
4 | const { productId } = useParams();
5 | const product = products.find((product) => product.id === productId);
6 | const { image, name } = product;
7 | return (
8 |
9 |
10 | {name}
11 | back to products
12 |
13 | );
14 | };
15 |
16 | export default SingleProduct;
17 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | *,
2 | ::after,
3 | ::before {
4 | box-sizing: border-box;
5 | }
6 | /* fonts */
7 | /* @import url("https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;600&family=Montserrat&display=swap"); */
8 |
9 | html {
10 | font-size: 100%;
11 | } /*16px*/
12 |
13 | :root {
14 | /* colors */
15 | --primary-100: #e2e0ff;
16 | --primary-200: #c1beff;
17 | --primary-300: #a29dff;
18 | --primary-400: #837dff;
19 | --primary-500: #645cff;
20 | --primary-600: #504acc;
21 | --primary-700: #3c3799;
22 | --primary-800: #282566;
23 | --primary-900: #141233;
24 |
25 | /* grey */
26 | --grey-50: #f8fafc;
27 | --grey-100: #f1f5f9;
28 | --grey-200: #e2e8f0;
29 | --grey-300: #cbd5e1;
30 | --grey-400: #94a3b8;
31 | --grey-500: #64748b;
32 | --grey-600: #475569;
33 | --grey-700: #334155;
34 | --grey-800: #1e293b;
35 | --grey-900: #0f172a;
36 | /* rest of the colors */
37 | --black: #222;
38 | --white: #fff;
39 | --red-light: #f8d7da;
40 | --red-dark: #842029;
41 | --green-light: #d1e7dd;
42 | --green-dark: #0f5132;
43 |
44 | /* fonts */
45 |
46 | --small-text: 0.875rem;
47 | --extra-small-text: 0.7em;
48 | /* rest of the vars */
49 | --backgroundColor: var(--grey-50);
50 | --textColor: var(--grey-900);
51 | --borderRadius: 0.25rem;
52 | --letterSpacing: 1px;
53 | --transition: 0.3s ease-in-out all;
54 | --max-width: 1120px;
55 | --fixed-width: 600px;
56 |
57 | /* box shadow*/
58 | --shadow-1: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
59 | --shadow-2: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
60 | 0 2px 4px -1px rgba(0, 0, 0, 0.06);
61 | --shadow-3: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
62 | 0 4px 6px -2px rgba(0, 0, 0, 0.05);
63 | --shadow-4: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
64 | 0 10px 10px -5px rgba(0, 0, 0, 0.04);
65 | }
66 |
67 | body {
68 | background: var(--backgroundColor);
69 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
70 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
71 | font-weight: 400;
72 | line-height: 1.75;
73 | color: var(--textColor);
74 | }
75 |
76 | p {
77 | margin-bottom: 1.5rem;
78 | max-width: 40em;
79 | }
80 |
81 | h1,
82 | h2,
83 | h3,
84 | h4,
85 | h5 {
86 | margin: 0;
87 | margin-bottom: 1.38rem;
88 | font-family: var(--headingFont);
89 | font-weight: 400;
90 | line-height: 1.3;
91 | text-transform: capitalize;
92 | letter-spacing: var(--letterSpacing);
93 | }
94 |
95 | h1 {
96 | margin-top: 0;
97 | font-size: 3.052rem;
98 | }
99 |
100 | h2 {
101 | font-size: 2.441rem;
102 | }
103 |
104 | h3 {
105 | font-size: 1.953rem;
106 | }
107 |
108 | h4 {
109 | font-size: 1.563rem;
110 | }
111 |
112 | h5 {
113 | font-size: 1.25rem;
114 | }
115 |
116 | small,
117 | .text-small {
118 | font-size: var(--small-text);
119 | }
120 |
121 | a {
122 | text-decoration: none;
123 | }
124 | ul {
125 | list-style-type: none;
126 | padding: 0;
127 | }
128 |
129 | .img {
130 | width: 100%;
131 | display: block;
132 | object-fit: cover;
133 | }
134 | /* buttons */
135 |
136 | .btn {
137 | cursor: pointer;
138 | color: var(--white);
139 | background: var(--primary-500);
140 | border: transparent;
141 | border-radius: var(--borderRadius);
142 | letter-spacing: var(--letterSpacing);
143 | padding: 0.375rem 0.75rem;
144 | box-shadow: var(--shadow-1);
145 | transition: var(--transition);
146 | text-transform: capitalize;
147 | display: inline-block;
148 | }
149 | .btn:hover {
150 | background: var(--primary-700);
151 | box-shadow: var(--shadow-3);
152 | }
153 | .btn-hipster {
154 | color: var(--primary-500);
155 | background: var(--primary-200);
156 | }
157 | .btn-hipster:hover {
158 | color: var(--primary-200);
159 | background: var(--primary-700);
160 | }
161 | .btn-block {
162 | width: 100%;
163 | }
164 |
165 | /* alerts */
166 | .alert {
167 | padding: 0.375rem 0.75rem;
168 | margin-bottom: 1rem;
169 | border-color: transparent;
170 | border-radius: var(--borderRadius);
171 | }
172 |
173 | .alert-danger {
174 | color: var(--red-dark);
175 | background: var(--red-light);
176 | }
177 | .alert-success {
178 | color: var(--green-dark);
179 | background: var(--green-light);
180 | }
181 | /* form */
182 |
183 | .form {
184 | width: 90vw;
185 | max-width: 400px;
186 | background: var(--white);
187 | border-radius: var(--borderRadius);
188 | box-shadow: var(--shadow-2);
189 | padding: 2rem 2.5rem;
190 | margin: 3rem 0;
191 | }
192 | .form-label {
193 | display: block;
194 | font-size: var(--small-text);
195 | margin-bottom: 0.5rem;
196 | text-transform: capitalize;
197 | letter-spacing: var(--letterSpacing);
198 | }
199 | .form-input,
200 | .form-textarea {
201 | width: 100%;
202 | padding: 0.375rem 0.75rem;
203 | border-radius: var(--borderRadius);
204 | background: var(--backgroundColor);
205 | border: 1px solid var(--grey-200);
206 | }
207 |
208 | .form-row {
209 | margin-bottom: 1rem;
210 | }
211 |
212 | .form-textarea {
213 | height: 7rem;
214 | }
215 | ::placeholder {
216 | font-family: inherit;
217 | color: var(--grey-400);
218 | }
219 | .form-alert {
220 | color: var(--red-dark);
221 | letter-spacing: var(--letterSpacing);
222 | text-transform: capitalize;
223 | }
224 | /* alert */
225 |
226 | @keyframes spinner {
227 | to {
228 | transform: rotate(360deg);
229 | }
230 | }
231 | .form h5 {
232 | text-align: center;
233 | }
234 | .form .btn {
235 | margin-top: 0.5rem;
236 | }
237 | .loading {
238 | width: 6rem;
239 | height: 6rem;
240 | border: 5px solid var(--grey-400);
241 | border-radius: 50%;
242 | border-top-color: var(--primary-500);
243 | animation: spinner 0.6s linear infinite;
244 | }
245 | .loading {
246 | margin: 0 auto;
247 | }
248 | /* title */
249 |
250 | .title {
251 | text-align: center;
252 | }
253 |
254 | .title-underline {
255 | background: var(--primary-500);
256 | width: 7rem;
257 | height: 0.25rem;
258 | margin: 0 auto;
259 | margin-top: -1rem;
260 | }
261 |
262 | .section {
263 | padding: 2rem 0;
264 | width: 90vw;
265 | max-width: var(--max-width);
266 | margin: 0 auto;
267 | }
268 |
269 | .navbar {
270 | width: 90vw;
271 | max-width: var(--max-width);
272 | margin: 0 auto;
273 | display: flex;
274 | gap: 1rem;
275 | }
276 |
277 | .link {
278 | color: var(--grey-500);
279 | }
280 |
281 | .active {
282 | color: var(--primary-500);
283 | }
284 | .products article {
285 | margin-bottom: 1rem;
286 | }
287 |
288 | .products h5 {
289 | margin-bottom: 0;
290 | }
291 |
292 | .product img {
293 | width: 200px;
294 | height: 150px;
295 | }
296 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | // import App from './final/App';
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
--------------------------------------------------------------------------------
/src/pages/About.js:
--------------------------------------------------------------------------------
1 | const About = () => {
2 | return (
3 |
6 | );
7 | };
8 | export default About;
9 |
--------------------------------------------------------------------------------
/src/pages/Dashboard.js:
--------------------------------------------------------------------------------
1 | const Dashboard = () => {
2 | return (
3 |
6 | );
7 | };
8 | export default Dashboard;
9 |
--------------------------------------------------------------------------------
/src/pages/Error.js:
--------------------------------------------------------------------------------
1 | const Error = () => {
2 | return (
3 |
6 | );
7 | };
8 | export default Error;
9 |
--------------------------------------------------------------------------------
/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | const Home = () => {
2 | return (
3 |
6 | );
7 | };
8 | export default Home;
9 |
--------------------------------------------------------------------------------
/src/pages/Login.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | const Login = () => {
3 | const [name, setName] = useState('');
4 | const [email, setEmail] = useState('');
5 |
6 | const handleSubmit = async (e) => {
7 | e.preventDefault();
8 | };
9 |
10 | return (
11 |
43 | );
44 | };
45 | export default Login;
46 |
--------------------------------------------------------------------------------
/src/pages/Products.js:
--------------------------------------------------------------------------------
1 | const Products = () => {
2 | return (
3 | <>
4 |
7 | >
8 | );
9 | };
10 |
11 | export default Products;
12 |
--------------------------------------------------------------------------------
/src/pages/SingleProduct.js:
--------------------------------------------------------------------------------
1 | const SingleProduct = () => {
2 | return (
3 |
6 | );
7 | };
8 |
9 | export default SingleProduct;
10 |
--------------------------------------------------------------------------------