aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/organisms/nav
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2023-10-25 17:23:53 +0200
committerArmand Philippot <git@armandphilippot.com>2023-11-11 18:15:27 +0100
commitc21a137e1991af1331fe5768fc6bac15ea9230b1 (patch)
tree80569408dbed888273a15d9ae543f553f2798a9b /src/components/organisms/nav
parent73e12fe8ae059ef70bbdf8716af421cb72aec76c (diff)
refactor(components): extract MainNav component from toolbar
Diffstat (limited to 'src/components/organisms/nav')
-rw-r--r--src/components/organisms/nav/index.ts1
-rw-r--r--src/components/organisms/nav/main-nav/index.ts1
-rw-r--r--src/components/organisms/nav/main-nav/main-nav.module.scss40
-rw-r--r--src/components/organisms/nav/main-nav/main-nav.stories.tsx71
-rw-r--r--src/components/organisms/nav/main-nav/main-nav.test.tsx18
-rw-r--r--src/components/organisms/nav/main-nav/main-nav.tsx47
6 files changed, 178 insertions, 0 deletions
diff --git a/src/components/organisms/nav/index.ts b/src/components/organisms/nav/index.ts
index ad899e0..957a64a 100644
--- a/src/components/organisms/nav/index.ts
+++ b/src/components/organisms/nav/index.ts
@@ -1,2 +1,3 @@
export * from './breadcrumbs';
+export * from './main-nav';
export * from './pagination';
diff --git a/src/components/organisms/nav/main-nav/index.ts b/src/components/organisms/nav/main-nav/index.ts
new file mode 100644
index 0000000..6b3662f
--- /dev/null
+++ b/src/components/organisms/nav/main-nav/index.ts
@@ -0,0 +1 @@
+export * from './main-nav';
diff --git a/src/components/organisms/nav/main-nav/main-nav.module.scss b/src/components/organisms/nav/main-nav/main-nav.module.scss
new file mode 100644
index 0000000..3f94678
--- /dev/null
+++ b/src/components/organisms/nav/main-nav/main-nav.module.scss
@@ -0,0 +1,40 @@
+@use "../../../../styles/abstracts/functions" as fun;
+@use "../../../../styles/abstracts/mixins" as mix;
+
+.modal {
+ @include mix.dimensions("md") {
+ padding: 0;
+ background: transparent;
+ border: none;
+ box-shadow: none;
+ }
+}
+
+.checkbox {
+ &:not(:checked) {
+ ~ .modal {
+ opacity: 0;
+ visibility: hidden;
+
+ @include mix.media("screen") {
+ @include mix.dimensions(null, "sm") {
+ transform: translateX(-100vw);
+ }
+
+ @include mix.dimensions("sm") {
+ transform: perspective(#{fun.convert-px(400)})
+ translate3d(0, 0, #{fun.convert-px(-400)});
+ transform-origin: 100% -50%;
+ }
+ }
+
+ @include mix.media("screen") {
+ @include mix.dimensions("md") {
+ opacity: 1;
+ visibility: visible;
+ transform: none;
+ }
+ }
+ }
+ }
+}
diff --git a/src/components/organisms/nav/main-nav/main-nav.stories.tsx b/src/components/organisms/nav/main-nav/main-nav.stories.tsx
new file mode 100644
index 0000000..6333f2c
--- /dev/null
+++ b/src/components/organisms/nav/main-nav/main-nav.stories.tsx
@@ -0,0 +1,71 @@
+import type { ComponentMeta, ComponentStory } from '@storybook/react';
+import { Icon } from '../../../atoms';
+import { MainNav } from './main-nav';
+
+/**
+ * MainNav - Storybook Meta
+ */
+export default {
+ title: 'Organisms/Nav/MainNav',
+ component: MainNav,
+ argTypes: {
+ items: {
+ description: 'The main nav items.',
+ type: {
+ name: 'object',
+ required: true,
+ value: {},
+ },
+ },
+ },
+} as ComponentMeta<typeof MainNav>;
+
+const Template: ComponentStory<typeof MainNav> = (args) => (
+ <MainNav {...args} />
+);
+
+/**
+ * MainNav Stories - Default
+ */
+export const Default = Template.bind({});
+Default.args = {
+ items: [
+ { id: 'home', label: 'Home', href: '#home' },
+ { id: 'blog', label: 'Blog', href: '#blog' },
+ { id: 'projects', label: 'Projects', href: '#projects' },
+ { id: 'contact', label: 'Contact', href: '#contact' },
+ ],
+};
+
+/**
+ * MainNav Stories - WithLogo
+ */
+export const WithLogo = Template.bind({});
+WithLogo.args = {
+ items: [
+ {
+ id: 'home',
+ label: 'Home',
+ href: '#home',
+ logo: <Icon aria-hidden shape="home" />,
+ },
+ {
+ id: 'blog',
+ label: 'Blog',
+ href: '#blog',
+ logo: <Icon aria-hidden shape="posts-stack" />,
+ },
+ {
+ id: 'projects',
+ label: 'Projects',
+ href: '#projects',
+ logo: <Icon aria-hidden shape="computer" />,
+ },
+ {
+ id: 'contact',
+ label: 'Contact',
+ href: '#contact',
+ logo: <Icon aria-hidden shape="envelop" />,
+ },
+ ],
+};
diff --git a/src/components/organisms/nav/main-nav/main-nav.test.tsx b/src/components/organisms/nav/main-nav/main-nav.test.tsx
new file mode 100644
index 0000000..86c1eb5
--- /dev/null
+++ b/src/components/organisms/nav/main-nav/main-nav.test.tsx
@@ -0,0 +1,18 @@
+import { describe, expect, it } from '@jest/globals';
+import { render, screen as rtlScreen } from '@testing-library/react';
+import { MainNav } from './main-nav';
+
+const items = [
+ { id: 'home', label: 'Home', href: '#home' },
+ { id: 'blog', label: 'Blog', href: '#blog' },
+ { id: 'projects', label: 'Projects', href: '#projects' },
+ { id: 'contact', label: 'Contact', href: '#contact' },
+];
+
+describe('MainNav', () => {
+ it('renders a list of nav items', () => {
+ render(<MainNav items={items} />);
+
+ expect(rtlScreen.getAllByRole('link')).toHaveLength(items.length);
+ });
+});
diff --git a/src/components/organisms/nav/main-nav/main-nav.tsx b/src/components/organisms/nav/main-nav/main-nav.tsx
new file mode 100644
index 0000000..5a19399
--- /dev/null
+++ b/src/components/organisms/nav/main-nav/main-nav.tsx
@@ -0,0 +1,47 @@
+import {
+ type ForwardRefRenderFunction,
+ type ReactNode,
+ forwardRef,
+} from 'react';
+import { Nav, type NavProps } from '../../../atoms';
+import { NavItem, NavLink, NavList } from '../../../molecules';
+
+export type MainNavItem = {
+ id: string;
+ href: string;
+ label: string;
+ logo?: ReactNode;
+};
+
+export type MainNavProps = Omit<NavProps, 'children'> & {
+ /**
+ * The main nav items.
+ */
+ items: MainNavItem[];
+};
+
+const MainNavWithRef: ForwardRefRenderFunction<HTMLElement, MainNavProps> = (
+ { className = '', items, ...props },
+ ref
+) => {
+ const wrapperClass = `${className}`;
+
+ return (
+ <Nav {...props} className={wrapperClass} ref={ref}>
+ <NavList isInline spacing="2xs">
+ {items.map(({ id, ...link }) => (
+ <NavItem key={id}>
+ <NavLink {...link} isStack variant="main" />
+ </NavItem>
+ ))}
+ </NavList>
+ </Nav>
+ );
+};
+
+/**
+ * MainNav component
+ *
+ * Render the main navigation.
+ */
+export const MainNav = forwardRef(MainNavWithRef);