diff --git a/package-lock.json b/package-lock.json
index e28e7226..b2995c76 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
"dotenv": "^16.4.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-icons": "^5.2.1",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.1",
"redux": "^5.0.1"
@@ -6709,6 +6710,14 @@
"react": "^18.3.1"
}
},
+ "node_modules/react-icons": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz",
+ "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
diff --git a/package.json b/package.json
index 3a0a7c04..7616426c 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"dotenv": "^16.4.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-icons": "^5.2.1",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.1",
"redux": "^5.0.1"
diff --git a/public/avatar.jpg b/public/avatar.jpg
new file mode 100644
index 00000000..f1ba6777
Binary files /dev/null and b/public/avatar.jpg differ
diff --git a/public/cart.png b/public/cart.png
new file mode 100644
index 00000000..4b621c72
Binary files /dev/null and b/public/cart.png differ
diff --git a/public/down.png b/public/down.png
new file mode 100644
index 00000000..757f34fb
Binary files /dev/null and b/public/down.png differ
diff --git a/public/edit.png b/public/edit.png
new file mode 100644
index 00000000..ece0eb72
Binary files /dev/null and b/public/edit.png differ
diff --git a/public/hamburger.png b/public/hamburger.png
new file mode 100644
index 00000000..87c88444
Binary files /dev/null and b/public/hamburger.png differ
diff --git a/public/heart.png b/public/heart.png
new file mode 100644
index 00000000..fd0ab902
Binary files /dev/null and b/public/heart.png differ
diff --git a/public/help.png b/public/help.png
new file mode 100644
index 00000000..9bcf4ab5
Binary files /dev/null and b/public/help.png differ
diff --git a/public/logo.png b/public/logo.png
new file mode 100644
index 00000000..aa929921
Binary files /dev/null and b/public/logo.png differ
diff --git a/public/moon.png b/public/moon.png
new file mode 100644
index 00000000..b8680814
Binary files /dev/null and b/public/moon.png differ
diff --git a/public/settings.png b/public/settings.png
new file mode 100644
index 00000000..bc7ae2b2
Binary files /dev/null and b/public/settings.png differ
diff --git a/public/signout.png b/public/signout.png
new file mode 100644
index 00000000..e59c6532
Binary files /dev/null and b/public/signout.png differ
diff --git a/public/user.png b/public/user.png
new file mode 100644
index 00000000..df33b675
Binary files /dev/null and b/public/user.png differ
diff --git a/src/__test__/navbar.test.tsx b/src/__test__/navbar.test.tsx
new file mode 100644
index 00000000..91c1012c
--- /dev/null
+++ b/src/__test__/navbar.test.tsx
@@ -0,0 +1,123 @@
+import { render, screen, fireEvent } from '@testing-library/react';
+import { MemoryRouter } from 'react-router-dom';
+import { describe, it, expect } from 'vitest';
+import Navbar from '@/components/Navbar';
+
+describe('Navbar Component', () => {
+ it('renders Navbar component', () => {
+ render(
+
+
+
+ );
+
+ const logo = screen.getByAltText(/logo/i);
+ expect(logo).toBeInTheDocument();
+
+ const title = screen.getByText(/dynamites/i);
+ expect(title).toBeInTheDocument();
+
+ const homeLink = screen.getByText(/Home/i);
+ expect(homeLink).toBeInTheDocument();
+
+ const shopLink = screen.getByText(/Shop/i);
+ expect(shopLink).toBeInTheDocument();
+
+ const aboutLink = screen.getByText(/About us/i);
+ expect(aboutLink).toBeInTheDocument();
+
+ const contactLink = screen.getAllByText(/Contact/i)[0];
+ expect(contactLink).toBeInTheDocument();
+
+ const cartIcon = screen.getByTitle('cart');
+ expect(cartIcon).toBeInTheDocument();
+
+ const avatar = screen.getByAltText(/profile/i);
+ expect(avatar).toBeInTheDocument();
+
+ const username = screen.getByText(/amanda green/i);
+ expect(username).toBeInTheDocument();
+ });
+
+ it('highlights the correct navigation link based on the current route', () => {
+ render(
+
+
+
+ );
+
+ expect(screen.getByText('Shop')).toHaveClass(
+ 'border-b-[2px] border-primary text-primary'
+ );
+ });
+
+ it('toggles menu on hamburger icon click', () => {
+ render(
+
+
+
+ );
+
+ const hamburgerIcon = screen.getByTitle('hamburger');
+ fireEvent.click(hamburgerIcon);
+
+ expect(screen.getAllByText(/home/i)[0]).toBeInTheDocument();
+ });
+
+ it('renders links with correct paths', () => {
+ render(
+
+
+
+ );
+
+ const homeLink = screen.getByText(/home/i);
+ expect(homeLink.closest('a')).toHaveAttribute('href', '/');
+
+ const shopLink = screen.getByText(/shop/i);
+ expect(shopLink.closest('a')).toHaveAttribute('href', '/shop');
+
+ const aboutLink = screen.getByText(/about us/i);
+ expect(aboutLink.closest('a')).toHaveAttribute('href', '/about');
+
+ const contactLink = screen.getAllByText(/contact/i)[0];
+ expect(contactLink.closest('a')).toHaveAttribute('href', '/contact');
+ });
+
+ it('displays cart item count', () => {
+ render(
+
+
+
+ );
+
+ const cartCount = screen.getByText(/5/i);
+ expect(cartCount).toBeInTheDocument();
+ });
+
+ it('renders profile options on avatar click', () => {
+ render(
+
+
+
+ );
+
+ const profileIcon = screen.getByTitle('toggleProfile');
+ fireEvent.click(profileIcon);
+
+ const editProfileOption = screen.getByText(/edit profile/i);
+ expect(editProfileOption).toBeInTheDocument();
+
+ const preferencesOption = screen.getByText(/preferences/i);
+ expect(preferencesOption).toBeInTheDocument();
+
+ const nightModeOption = screen.getByText(/night mode/i);
+ expect(nightModeOption).toBeInTheDocument();
+
+ const helpCenterOption = screen.getByText(/help center/i);
+ expect(helpCenterOption).toBeInTheDocument();
+
+ const signOutOption = screen.getByText(/sign out/i);
+ expect(signOutOption).toBeInTheDocument();
+ });
+});
diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx
new file mode 100644
index 00000000..b7cbb604
--- /dev/null
+++ b/src/components/Navbar.tsx
@@ -0,0 +1,153 @@
+import { Link, useLocation } from 'react-router-dom';
+import { useState } from 'react';
+import { LuShoppingCart } from 'react-icons/lu';
+import { FiHeart } from 'react-icons/fi';
+import { FaAngleDown } from 'react-icons/fa6';
+import { RxHamburgerMenu } from 'react-icons/rx';
+
+function Navbar() {
+ const location = useLocation();
+ const [toggleMenu, setToggleMenu] = useState(false);
+ const [toggleProfileMenu, setToggleProfileMenu] = useState(false);
+ return (
+
+
setToggleMenu(!toggleMenu)}
+ />
+
+
+
Dynamites
+
+
+
+
+
+
+
+
+
Amanda Green
+
setToggleProfileMenu(!toggleProfileMenu)}
+ />
+
+
+ {toggleMenu && (
+
+
Home
+
Shop
+
About
+
Contact
+
+
+
+
Edit profile
+
+
+
+
Preferences
+
+
+
+
+
+
Night mode
+
+
+
+
+
+
Help center
+
+
+
+
Sign out
+
+
+ )}
+ {toggleProfileMenu && (
+
+
+
+
+
Edit profile
+
+
+
+
Preferences
+
+
+
+
+
+
Night mode
+
+
+
+
+
+
Help center
+
+
+
+
Sign out
+
+
+ )}
+
+ );
+}
+
+export default Navbar;
diff --git a/src/layout/HomeLayout.tsx b/src/layout/HomeLayout.tsx
index 4917b997..bca7eabb 100644
--- a/src/layout/HomeLayout.tsx
+++ b/src/layout/HomeLayout.tsx
@@ -1,13 +1,16 @@
import { Outlet } from 'react-router-dom';
+import Navbar from '@/components/Navbar';
function HomeLayout() {
return (
-
Nav
+
+
+
-
Fotter
+
Footer
);
}
diff --git a/tailwind.config.js b/tailwind.config.js
index f63f318e..7b75751c 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -5,7 +5,7 @@ export default {
xs: '320px',
sm: '640px',
md: '768px',
- lg: '1440px',
+ lg: '1024px',
},
extend: {
colors: {
@@ -18,7 +18,9 @@ export default {
grayDark: '#CCD0D8',
grayLight: '#F3F4F6',
redBg: '#DC2627',
- black: '#171A1F',
+ textBlack: '#171A1F',
+ lightGrey: '#DEE1E6',
+ grey: '#565D6D',
},
fontFamily: {
Lexend: ['Lexend'],