Skip to content

Commit

Permalink
TopNavBar Component (#1033)
Browse files Browse the repository at this point in the history
* add colour for header border

* modify top header to match design

* add translations for topnavbar

* modify paragraph line height

* remove default ul, ol, and li styling and apply to TextRender

* add styling to list on homepage

* create TopNavBar, add animations to menu.css

* add TopNavBar to Layout.js

* apply correct fonts to TopNavBar

* replace margins in img/lang toggle with padding

* add aria labels, create unit test

* create story entry for TopNavBar

* augment TopNavBar unit test

* add featureflag for TopNavBar in Layout.js
  • Loading branch information
will0684 authored Jun 5, 2024
1 parent 373c5dc commit 357cecc
Show file tree
Hide file tree
Showing 15 changed files with 436 additions and 348 deletions.
142 changes: 142 additions & 0 deletions components/molecules/TopNavBar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import Link from "next/link";
import React, { useState } from "react";

export function TopNavBar({
homeLink,
homeLinkLabel,
updatesLink,
updatesLinkLabel,
projectsLink,
projectsLinkLabel,
navAriaLabel,
buttonAriaLabel,
}) {
const [isOpen, setIsOpen] = useState(false);
const [isTransitioningClosed, setIsTransitioningClosed] = useState(false);

//Handles the opening and closing of our nav
const handleClick = () => {
isOpen ? animateCloseMenu() : setIsOpen(!isOpen);
};

const animateCloseMenu = () => {
setIsTransitioningClosed(true);
setTimeout(() => {
setIsTransitioningClosed(false);
setIsOpen(!isOpen);
}, 250);
};

return (
<nav
aria-label={navAriaLabel}
className="bg-custom-gray-lightest min-h-[64px] flex justify-end"
>
{/* Desktop Nav Menu */}
<div className="hidden lg:flex w-full self-center justify-between layout-container">
<Link href={homeLink} className="font-body font-semibold text-h3">
{homeLinkLabel}
</Link>
<div className="lg:mr-16">
<Link href={projectsLink} className="font-body mr-10 text-p">
{projectsLinkLabel}
</Link>
<Link href={updatesLink} className="font-body text-p">
{updatesLinkLabel}
</Link>
</div>
</div>
{/* Mobile Nav Menu */}
<div className="static lg:hidden mt-5 flex flex-col w-full mr-4">
<button
aria-label={buttonAriaLabel}
aria-haspopup="true"
aria-expanded={isOpen ? "true" : "false"}
aria-controls="menu"
onClick={handleClick}
className="self-end"
>
{isOpen ? (
<div
className={`${
isTransitioningClosed ? "fade-out" : "fade-in"
} -mt-1 p-1.5`}
>
<svg
width="20"
height="20"
viewBox="0 0 17 17"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="exit-icon"
>
<path d="M11.3775 8.25L16.0683 3.55922C16.6439 2.98359 16.6439 2.05031 16.0683 1.47422L15.0258 0.431719C14.4502 -0.143906 13.5169 -0.143906 12.9408 0.431719L8.25 5.1225L3.55922 0.431719C2.98359 -0.143906 2.05031 -0.143906 1.47422 0.431719L0.431719 1.47422C-0.143906 2.04984 -0.143906 2.98312 0.431719 3.55922L5.1225 8.25L0.431719 12.9408C-0.143906 13.5164 -0.143906 14.4497 0.431719 15.0258L1.47422 16.0683C2.04984 16.6439 2.98359 16.6439 3.55922 16.0683L8.25 11.3775L12.9408 16.0683C13.5164 16.6439 14.4502 16.6439 15.0258 16.0683L16.0683 15.0258C16.6439 14.4502 16.6439 13.5169 16.0683 12.9408L11.3775 8.25Z" />
</svg>
</div>
) : (
<div className={`${isTransitioningClosed ? "fade-in" : ""} -mt-1`}>
<svg
width="32"
height="32"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M4 18L20 18"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
/>
<path
d="M4 12L20 12"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
/>
<path
d="M4 6L20 6"
stroke="#000000"
stroke-width="2"
stroke-linecap="round"
/>
</svg>
</div>
)}
</button>
{isOpen ? (
<ul
id="menu"
className={`${
isTransitioningClosed ? "fade-out" : "fade-in"
} absolute w-full flex flex-col mt-8 pb-4 bg-custom-gray-lightest drop-shadow-xl`}
>
<li
className={`${
isTransitioningClosed ? "decrease-margin" : "expand-margin"
} my-2 ml-4`}
>
<Link href={homeLink}>{homeLinkLabel}</Link>
</li>
<li
className={`${
isTransitioningClosed ? "decrease-margin" : "expand-margin"
} my-2 ml-4`}
>
<Link href={projectsLink}>{projectsLinkLabel}</Link>
</li>
<li
className={`${
isTransitioningClosed ? "decrease-margin" : "expand-margin"
} my-2 ml-4`}
>
<Link href={updatesLink}>{updatesLinkLabel}</Link>
</li>
</ul>
) : (
""
)}
</div>
</nav>
);
}
22 changes: 22 additions & 0 deletions components/molecules/TopNavBar.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";
import { TopNavBar } from "./TopNavBar";

export default {
title: "Components/Molecules/TopNavBar",
component: TopNavBar,
};

const Template = (args) => <TopNavBar {...args}></TopNavBar>;

export const Primary = Template.bind({});

Primary.args = {
homeLink: "#home",
homeLinkLabel: "Home",
updatesLink: "#updates",
updatesLinkLabel: "Updates",
projectsLink: "#projects",
projectsLinkLabel: "Projects",
navAriaLabel: "nav-aria-label",
buttonAriaLabel: "button-aria-label",
};
34 changes: 34 additions & 0 deletions components/molecules/TopNavBar.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* @jest-environment jsdom
*/
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import { axe, toHaveNoViolations } from "jest-axe";
import { Primary } from "./TopNavBar.stories";

expect.extend(toHaveNoViolations);

describe("TopNavBar", () => {
it("renders the TopNavBar with expected props on desktop", () => {
render(<Primary {...Primary.args} />);
expect(screen.getByLabelText("nav-aria-label")).toBeTruthy();
expect(screen.getByLabelText("button-aria-label")).toBeTruthy();
expect(screen.getByText("Home")).toBeTruthy();
expect(screen.getByText("Updates")).toBeTruthy();
});

it("renders the TopNavBar with expected props on mobile", () => {
render(<Primary {...Primary.args} />);
global.innerWidth = 500;
expect(screen.getByLabelText("nav-aria-label")).toBeTruthy();
expect(screen.getByLabelText("button-aria-label")).toBeTruthy();
expect(screen.getByText("Home")).toBeTruthy();
expect(screen.getByText("Updates")).toBeTruthy();
});

it("has no a11y violations", async () => {
const { container } = render(<Primary {...Primary.args} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
29 changes: 22 additions & 7 deletions components/organisms/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { DateModified } from "../atoms/DateModified";
import { Breadcrumb } from "../atoms/Breadcrumb";
import { Footer } from "../organisms/Footer";
import Feedback from "./Feedback";
import { TopNavBar } from "../molecules/TopNavBar";

/**
* Component which defines the layout of the page for all screen sizes
Expand Down Expand Up @@ -34,6 +35,7 @@ export const Layout = ({
typeof window !== "undefined" && window.location.origin
? window.location.href
: "";
const isTopNavBarActive = false;

return (
<div className="overflow-x-hidden">
Expand Down Expand Up @@ -63,9 +65,9 @@ export const Layout = ({
) : (
""
)}
<div className="layout-container flex-col flex lg:flex lg:flex-row justify-between mt-2">
<div className="layout-container lg:max-w-full pt-4 pb-3 !mx-0 !px-5 flex-col flex lg:flex lg:flex-row justify-between bg-custom-gray-lightest">
<div
className="flex flex-row justify-between items-center lg:mt-7 mt-1.5"
className="flex flex-row justify-between"
role="navigation"
aria-labelledby="officialSiteNav"
>
Expand All @@ -78,6 +80,7 @@ export const Layout = ({
alt={t("symbol")}
width="375"
height="35"
className="max-w-[280px]"
/>
</a>
<h3 className="sr-only">{t("languageSelection")}</h3>
Expand All @@ -86,27 +89,39 @@ export const Layout = ({
href={langUrl}
locale={language}
data-testid="languageLink1"
className="visible lg:invisible ml-6 sm:ml-16 underline font-body font-bold text-canada-footer-font lg:text-sm text-base hover:text-canada-footer-hover-font-blue"
className="block lg:hidden ml-6 -mt-1 sm:ml-16 underline underline-offset-[6px] font-body text-canada-footer-font lg:text-sm text-lg hover:text-canada-footer-hover-font-blue"
>
{language === "en" ? "EN" : "FR"}
</Link>
</div>
<div className="flex-col flex">
<div className="flex flex-col justify-center">
<Link
key={language}
href={langUrl}
locale={language}
data-testid="languageLink3"
className="lg:visible invisible pb-0 lg:pb-2 self-end underline font-body text-canada-footer-font hover:text-canada-footer-hover-font-blue"
className="flex lg:block hidden underline underline-offset-[5px] font-body text-canada-footer-font hover:text-canada-footer-hover-font-blue"
data-cy="toggle-language-link"
lang={language}
>
{language === "en" ? "English" : "Français"}
</Link>
</div>
</div>

<div className="layout-container mt-4 lg:mt-20">
<div className="border-b-[3px] border-multi-blue-blue35" />
{isTopNavBarActive ? (
<TopNavBar
homeLink={t("topNavBar.homeLink")}
homeLinkLabel={t("topNavBar.homeLinkLabel")}
updatesLink={t("topNavBar.updatesLink")}
updatesLinkLabel={t("topNavBar.updatesLinkLabel")}
projectsLink={t("topNavBar.projectsLink")}
projectsLinkLabel={t("topNavBar.projectsLinkLabel")}
navAriaLabel={t("topNavBar.ariaLabel")}
buttonAriaLabel={t("topNavBar.buttonAriaLabel")}
/>
) : null}
<div className="layout-container mt-4">
<Breadcrumb items={breadcrumbItems} />
</div>
</header>
Expand Down
2 changes: 1 addition & 1 deletion components/text_node_renderer/nodes/ListItem.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default function ListItem(props) {
return <li>{props.children}</li>;
return <li className="ml-10 text-[20px]">{props.children}</li>;
}
2 changes: 1 addition & 1 deletion components/text_node_renderer/nodes/OrderedList.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default function UnorderedList(props) {
return <ol>{props.children}</ol>;
return <ol className="list-decimal">{props.children}</ol>;
}
2 changes: 1 addition & 1 deletion components/text_node_renderer/nodes/UnorderedList.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default function UnorderedList(props) {
return <ul>{props.children}</ul>;
return <ul className="list-disc">{props.children}</ul>;
}
6 changes: 3 additions & 3 deletions pages/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,8 @@ export default function Home(props) {
: pageData.scFragments[0].scContentFr.json[4].content[0]
.value}{" "}
</p>
<ul>
<li>
<ul className="list-disc">
<li className="ml-10">
<p className="font-body">
{props.locale === "en"
? pageData.scFragments[0].scContentEn.json[5].content[0]
Expand All @@ -319,7 +319,7 @@ export default function Home(props) {
.content[0].value}{" "}
</p>
</li>
<li>
<li className="ml-10">
<p className="font-body">
{props.locale === "en"
? pageData.scFragments[0].scContentEn.json[5].content[1]
Expand Down
Loading

0 comments on commit 357cecc

Please sign in to comment.