├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.js
├── components
├── Header.js
├── Header.module.scss
├── Layout.js
└── Layout.module.scss
├── index.js
├── pages
├── Home.js
├── PageCTA.js
├── PageOne.js
├── PageThree.js
└── PageTwo.js
└── styles
├── index.scss
└── variables.scss
/.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 | # Navbar
2 |
3 | A fully responsive and reusable header / navbar component built with React.
4 |
5 | ## CodeFocus Channel
6 |
7 | This project's build walkthrough video can be accessed on the CodeFocus youtube channel. Heres a link:
8 |
9 | ### `npm start`
10 |
11 | Runs the app in the development mode.
12 | Open http://localhost:3000 to view it in the browser.
13 |
14 | The page will reload if you make edits.
15 | You will also see any lint errors in the console.
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "navbar",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.14.1",
7 | "@testing-library/react": "^11.2.7",
8 | "@testing-library/user-event": "^12.8.3",
9 | "node-sass": "^6.0.1",
10 | "react": "^17.0.2",
11 | "react-dom": "^17.0.2",
12 | "react-icons": "^4.2.0",
13 | "react-router-dom": "^5.2.0",
14 | "react-scripts": "4.0.3",
15 | "web-vitals": "^1.1.2"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test",
21 | "eject": "react-scripts eject"
22 | },
23 | "eslintConfig": {
24 | "extends": [
25 | "react-app",
26 | "react-app/jest"
27 | ]
28 | },
29 | "browserslist": {
30 | "production": [
31 | ">0.2%",
32 | "not dead",
33 | "not op_mini all"
34 | ],
35 | "development": [
36 | "last 1 chrome version",
37 | "last 1 firefox version",
38 | "last 1 safari version"
39 | ]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeFocusChannel/navbar/4f73098fd5fd05e682955e1ea62ca2cc4bcfc40a/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/CodeFocusChannel/navbar/4f73098fd5fd05e682955e1ea62ca2cc4bcfc40a/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CodeFocusChannel/navbar/4f73098fd5fd05e682955e1ea62ca2cc4bcfc40a/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 Layout from "./components/Layout";
2 | import { Switch, Route } from "react-router-dom";
3 | import Home from "./pages/Home";
4 | import PageOne from "./pages/PageOne";
5 | import PageTwo from "./pages/PageTwo";
6 | import PageThree from "./pages/PageThree";
7 | import PageCTA from "./pages/PageCTA";
8 |
9 | function App() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | );
31 | }
32 |
33 | export default App;
34 |
--------------------------------------------------------------------------------
/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 |
3 | import { BiMenuAltRight } from "react-icons/bi";
4 | import { AiOutlineClose } from "react-icons/ai";
5 |
6 | import classes from "./Header.module.scss";
7 | import { Link, useHistory } from "react-router-dom";
8 |
9 | const Header = () => {
10 | const history = useHistory();
11 | const [menuOpen, setMenuOpen] = useState(false);
12 | const [size, setSize] = useState({
13 | width: undefined,
14 | height: undefined,
15 | });
16 |
17 | useEffect(() => {
18 | const handleResize = () => {
19 | setSize({
20 | width: window.innerWidth,
21 | height: window.innerHeight,
22 | });
23 | };
24 | window.addEventListener("resize", handleResize);
25 |
26 | return () => window.removeEventListener("resize", handleResize);
27 | }, []);
28 |
29 | useEffect(() => {
30 | if (size.width > 768 && menuOpen) {
31 | setMenuOpen(false);
32 | }
33 | }, [size.width, menuOpen]);
34 |
35 | const menuToggleHandler = () => {
36 | setMenuOpen((p) => !p);
37 | };
38 |
39 | const ctaClickHandler = () => {
40 | menuToggleHandler();
41 | history.push("/page-cta");
42 | };
43 |
44 | return (
45 |
46 |
47 |
48 | navbar
49 |
50 |
74 |
75 | {!menuOpen ? (
76 |
77 | ) : (
78 |
79 | )}
80 |
81 |
82 |
83 | );
84 | };
85 |
86 | export default Header;
87 |
--------------------------------------------------------------------------------
/src/components/Header.module.scss:
--------------------------------------------------------------------------------
1 | @import "./../styles/variables.scss";
2 |
3 | .header {
4 | background: $dark;
5 | width: 100%;
6 | height: $headerHeight;
7 | padding: 0 1.5rem;
8 | @include breakpoint(md) {
9 | padding: 0 3rem;
10 | }
11 | transition: 0.3s ease all;
12 |
13 | &__content {
14 | overflow: hidden;
15 | color: $light;
16 | margin: 0 auto;
17 | max-width: 1920px;
18 | height: 100%;
19 | display: flex;
20 | align-items: center;
21 | justify-content: space-between;
22 | position: relative;
23 | z-index: 100;
24 |
25 | &__logo {
26 | font-size: 2rem;
27 | font-weight: bold;
28 | text-decoration: none;
29 | color: $light;
30 | }
31 |
32 | &__nav {
33 | top: 0;
34 | right: 100%;
35 | bottom: 0;
36 | width: 100%;
37 | height: 100vh;
38 | position: fixed;
39 | display: flex;
40 | flex-direction: column;
41 | justify-content: center;
42 | align-items: center;
43 | text-align: center;
44 | background: rgba($dark, 0.9);
45 | backdrop-filter: blur(2px);
46 | transform: translate(0);
47 | transition: 0.3s ease transform;
48 |
49 | @include breakpoint(md) {
50 | transform: none;
51 | flex-direction: row;
52 | background: transparent;
53 | width: auto;
54 | height: 100%;
55 | position: static;
56 | }
57 | ul {
58 | list-style: none;
59 | padding: 0;
60 | display: flex;
61 | flex-direction: column;
62 | margin-bottom: $spacing-lg;
63 | @include breakpoint(md) {
64 | flex-direction: row;
65 | align-items: center;
66 | margin-bottom: 0;
67 | margin-right: calc(0.5rem + #{$spacing-md});
68 | }
69 | li {
70 | &:not(:last-child) {
71 | margin-bottom: $spacing-lg;
72 | @include breakpoint(md) {
73 | margin-bottom: 0;
74 | margin-right: $spacing-md;
75 | }
76 | }
77 | a {
78 | text-decoration: none;
79 | color: inherit;
80 | padding: 0.75rem 1.25rem;
81 | border-radius: $borderRadius;
82 | transition: 0.3s ease all;
83 |
84 | &:hover {
85 | background: rgba($light, 0.1);
86 | }
87 | &:active {
88 | border-radius: calc(#{$borderRadius} + 6px);
89 | background: linear-gradient(rgba($light, 0.1), rgba($light, 0.2));
90 | }
91 | }
92 | }
93 | }
94 | button {
95 | cursor: pointer;
96 | outline: none;
97 | padding: 0.75rem 1.25rem;
98 | border-radius: $borderRadius;
99 | font-size: 1rem;
100 | font-family: inherit;
101 | background: $primary;
102 | color: $dark;
103 | border: 1px solid transparent;
104 | transition: 0.3s ease all;
105 |
106 | &:hover {
107 | border-color: $primary;
108 | background: rgba($primary, 0.1);
109 | color: $primary;
110 | }
111 | &:active {
112 | border-color: $primary;
113 | background: linear-gradient(rgba($primary, 0.2), rgba($primary, 0.3));
114 | color: $primary;
115 | }
116 | }
117 |
118 | &.isMenu {
119 | transform: translate(100%);
120 | }
121 | }
122 |
123 | &__toggle {
124 | cursor: pointer;
125 | display: flex;
126 | align-items: center;
127 | font-size: 2rem;
128 | transition: 0.3s ease all;
129 | position: relative;
130 |
131 | &:hover {
132 | color: $primary;
133 | }
134 |
135 | @include breakpoint(md) {
136 | display: none;
137 | }
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/components/Layout.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Header from "./Header";
3 |
4 | import classes from "./Layout.module.scss";
5 |
6 | const Layout = ({ children }) => {
7 | return (
8 | <>
9 |
10 | {children}
11 | >
12 | );
13 | };
14 |
15 | export default Layout;
16 |
--------------------------------------------------------------------------------
/src/components/Layout.module.scss:
--------------------------------------------------------------------------------
1 | @import "./../styles/variables.scss";
2 |
3 | .container {
4 | height: calc(100vh - #{$headerHeight});
5 | background: $bg;
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 |
10 | h1 {
11 | padding: 1.5rem 2.5rem;
12 | background: linear-gradient(220deg, $primary, rgba($primary, 0.5));
13 | border-radius: $borderRadius calc(#{$borderRadius} * 10);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./styles/index.scss";
4 | import App from "./App";
5 | import { BrowserRouter as Router } from "react-router-dom";
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById("root")
12 | );
13 |
--------------------------------------------------------------------------------
/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const Home = () => {
4 | return Home
;
5 | };
6 |
7 | export default Home;
8 |
--------------------------------------------------------------------------------
/src/pages/PageCTA.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const PageCTA = () => {
4 | return CTA Page
;
5 | };
6 |
7 | export default PageCTA;
8 |
--------------------------------------------------------------------------------
/src/pages/PageOne.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const PageOne = () => {
4 | return Page One
;
5 | };
6 |
7 | export default PageOne;
8 |
--------------------------------------------------------------------------------
/src/pages/PageThree.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const PageThree = () => {
4 | return Page Three
;
5 | };
6 |
7 | export default PageThree;
8 |
--------------------------------------------------------------------------------
/src/pages/PageTwo.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const PageTwo = () => {
4 | return Page Two
;
5 | };
6 |
7 | export default PageTwo;
8 |
--------------------------------------------------------------------------------
/src/styles/index.scss:
--------------------------------------------------------------------------------
1 | @import "./variables.scss";
2 |
3 | * {
4 | box-sizing: border-box;
5 | margin: 0;
6 | }
7 |
8 | body {
9 | width: 100%;
10 | font-family: $Poppins;
11 | color: $dark;
12 | }
13 |
14 | #root {
15 | height: 100%;
16 | }
17 |
--------------------------------------------------------------------------------
/src/styles/variables.scss:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700;800&display=swap");
2 |
3 | $Poppins: "Poppins", sans-serif;
4 |
5 | // colors
6 | $dark: rgb(29, 29, 29);
7 | $light: #fff;
8 | $primary: rgb(162, 162, 246);
9 | $bg: rgb(244, 244, 255);
10 |
11 | // spacing
12 | $spacing-md: 16px;
13 | $spacing-lg: 32px;
14 |
15 | // border radius
16 | $borderRadius: 12px;
17 |
18 | // header height
19 | $headerHeight: 100px;
20 |
21 | @mixin breakpoint($point) {
22 | @if $point == md {
23 | // 768px
24 | @media (min-width: 48em) {
25 | @content;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------