Skip to content

Commit

Permalink
added the menu bar component (#31)
Browse files Browse the repository at this point in the history
Co-authored-by: Leesa Ward <[email protected]>
Co-authored-by: ben-AI-cybersec <[email protected]>
  • Loading branch information
3 people authored Oct 28, 2024
1 parent a46fb40 commit be69429
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/components/MenuBar/MenuBar.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { MenuBar } from './MenuBar';
import { action } from '@storybook/addon-actions'; // Use 'action' instead of 'fn'
import type { Meta, StoryObj } from '@storybook/react';
import { themeColorSubset } from '../../types';

const meta: Meta<typeof MenuBar> = {
title: 'Components/MenuBar',
component: MenuBar,
argTypes: {
color: { control: 'select', options: Object.keys(themeColorSubset) },
},
args: {
color: 'primary',
items: [
{ label: 'Home', link: '/', onClick: action('Home clicked') },
{ label: 'About', link: '/about', onClick: action('About clicked') },
{ label: 'Contact', link: '/contact', onClick: action('Contact clicked') },
],
},
};

export default meta;
type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
color: 'primary',
},
};

export const Secondary: Story = {
args: {
color: 'secondary',
},
};

export const WithCustomItems: Story = {
args: {
items: [
{ label: 'Services', link: '/services', onClick: action('Services clicked') },
{ label: 'Blog', link: '/blog', onClick: action('Blog clicked') },
],
},
};
52 changes: 52 additions & 0 deletions src/components/MenuBar/MenuBar.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import styled from 'styled-components';
import { ThemeColor } from '../../types';

type StyledMenuBarProps = {
$color: ThemeColor;
};

export const StyledMenuBar = styled.div<StyledMenuBarProps>`
display: flex;
align-items: center;
background-color: ${(props) => props.theme.colors[props.$color]};
padding: ${(props) => props.theme.spacing.md};
border-bottom: 1px solid ${(props) => props.theme.colors.subtle};
justify-content: space-between;
`;

export const MenuItem = styled.a`
color: ${(props) => props.theme.colors.dark};
margin: 0 ${(props) => props.theme.spacing.sm};
text-decoration: none;
font-size: ${(props) => props.theme.fontSizes.default};
&:hover {
text-decoration: underline;
}
@media (max-width: 768px) {
font-size: ${(props) => props.theme.fontSizes.sm};
}
`;

export const HamburgerIcon = styled.div`
cursor: pointer;
font-size: 1.5rem;
display: none;
@media (max-width: 768px) {
display: block;
}
`;

export const IconImage = styled.img`
width: 40px;
height: 40px;
margin-right: ${(props) => props.theme.spacing.md};
cursor: pointer;
@media (max-width: 768px) {
width: 30px;
height: 30px;
}
`;
28 changes: 28 additions & 0 deletions src/components/MenuBar/MenuBar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { screen, fireEvent } from '@testing-library/react';
import { renderWithDeps } from '../../../jest.utils';
import { MenuBar } from './MenuBar';

const mockClick = jest.fn();

describe('<MenuBar />', () => {
const menuItems = [
{ label: 'Home', link: '/', onClick: mockClick },
{ label: 'About', link: '/about', onClick: mockClick },
{ label: 'Contact', link: '/contact', onClick: mockClick },
];

it('renders the menu items', () => {
renderWithDeps(<MenuBar items={menuItems} />);

expect(screen.getByText('Home')).toBeVisible();
expect(screen.getByText('About')).toBeVisible();
expect(screen.getByText('Contact')).toBeVisible();
});

it('calls onClick when a menu item is clicked', () => {
renderWithDeps(<MenuBar items={menuItems} />);

fireEvent.click(screen.getByText('Home'));
expect(mockClick).toHaveBeenCalledTimes(1);
});
});
38 changes: 38 additions & 0 deletions src/components/MenuBar/MenuBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { FC } from 'react';
import { StyledMenuBar, MenuItem, HamburgerIcon, IconImage } from './MenuBar.style';
import { ThemeColor } from '../../types';

type MenuBarItem = {
label: string;
link: string;
onClick?: () => void;
};

type MenuBarProps = {
items: MenuBarItem[];
color?: ThemeColor; // Added color prop like in the Button component
};

export const MenuBar: FC<MenuBarProps> = ({ items, color = 'primary' }) => {
return (
<StyledMenuBar $color={color}>
<IconImage src="/icon.svg" alt="Menu Icon" />

<HamburgerIcon aria-label="Toggle menu"></HamburgerIcon>

<nav>
<ul>
{items.map((item, index) => (
<li key={index}>
<MenuItem href={item.link} onClick={item.onClick}>
{item.label}
</MenuItem>
</li>
))}
</ul>
</nav>
</StyledMenuBar>
);
};

export default MenuBar;

0 comments on commit be69429

Please sign in to comment.