Skip to content

Commit

Permalink
Showing 7 changed files with 415 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/components/atoms/index.ts
Original file line number Diff line number Diff line change
@@ -18,3 +18,4 @@ export * from "./OakMaxWidth";
export * from "./OakCloudinaryImage";
export * from "./OakKbd";
export * from "./OakGlobalStyle";
export * from "./OakAnchorTarget";
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from "react";
import { Meta, StoryObj } from "@storybook/react";

import { OakTertiaryOLNav, OakTertiaryOLNavProps } from "./OakTertiaryOLNav";

const items: OakTertiaryOLNavProps = {
items: [
{
title: "Creating solid explanations and good modelling",
href: "#solid-explanations",
},
{
title: "Short item",
href: "#short-item",
},
{
title: "What is a lesson plan",
href: "#lesson-plan",
},
],
ariaLabel: "navigation",
title: "contents",
};
/**
*
* OakTertiaryOLNav is a styled ol list nav.
*
*/
const meta: Meta<typeof OakTertiaryOLNav> = {
component: OakTertiaryOLNav,
tags: ["autodocs"],
title: "components/organisms/teacher/OakTertiaryOLNav",
};
export default meta;

type Story = StoryObj<typeof OakTertiaryOLNav>;

export const Default: Story = {
render: (args) => <OakTertiaryOLNav {...args} />,
args: items,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React from "react";
import "@testing-library/jest-dom";
import { create } from "react-test-renderer";

import { OakTertiaryOLNav, OakTertiaryOLNavProps } from "./OakTertiaryOLNav";

import renderWithTheme from "@/test-helpers/renderWithTheme";
import { OakThemeProvider } from "@/components/atoms";
import { oakDefaultTheme } from "@/styles";

const baseProps: OakTertiaryOLNavProps = {
items: [
{ title: "Item 1", href: "#item1" },
{ title: "Item 2", href: "#item2" },
],
ariaLabel: "navigation",
};

describe("Component OakTertiaryOLNav", () => {
it("renders", () => {
const { getByTestId } = renderWithTheme(
<OakTertiaryOLNav {...baseProps} data-testid="test" />,
);
expect(getByTestId("test")).toBeInTheDocument();
});
it("conditionally renders the title", () => {
const { queryByText } = renderWithTheme(
<OakTertiaryOLNav {...baseProps} title="Contents" />,
);
expect(queryByText("Contents")).toBeInTheDocument();
});

it("renders items with correct title and href", () => {
const { getByText } = renderWithTheme(<OakTertiaryOLNav {...baseProps} />);
const link1 = getByText("Item 1");
const link2 = getByText("Item 2");
expect(link1.closest("a")).toHaveAttribute("href", "#item1");
expect(link2.closest("a")).toHaveAttribute("href", "#item2");
});
it("renders anchor target if passed as prop", () => {
const { getByTestId } = renderWithTheme(
<OakTertiaryOLNav
{...baseProps}
anchorTarget="target"
data-testid="test"
/>,
);
expect(getByTestId("test").querySelector("#target")).toBeInTheDocument();
});

it("matches snapshot", () => {
const tree = create(
<OakThemeProvider theme={oakDefaultTheme}>
<OakTertiaryOLNav {...baseProps} />,
</OakThemeProvider>,
).toJSON();
expect(tree).toMatchSnapshot();
});
});
116 changes: 116 additions & 0 deletions src/components/organisms/teacher/OakTertiaryOLNav/OakTertiaryOLNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React from "react";
import styled from "styled-components";

import { InternalLink } from "@/components/molecules/InternalLink";
import { parseColor } from "@/styles/helpers/parseColor";
import { parseDropShadow } from "@/styles/helpers/parseDropShadow";
import { OakLI } from "@/components/atoms/OakLI";
import { parseSpacing } from "@/styles/helpers/parseSpacing";
import { OakAnchorTarget, OakBox, OakSpan } from "@/components/atoms";

const StyledNav = styled.nav`
outline: none;
`;
const StyledOakLink = styled(InternalLink)`
text-decoration: none;
color: inherit;
width: 100%;
display: Flex;
width: 100%;
&:focus {
box-shadow: none;
}
&::before {
content: counter(list-counter);
min-width: 32px;
height: 32px;
border-radius: 50%;
background-color: ${parseColor("black")};
color: ${parseColor("white")};
text-align: center;
line-height: 32px;
margin-right: ${parseSpacing("space-between-xs")};
text-decoration: none;
}
&:hover::before {
background-color: ${parseColor("bg-btn-primary-hover")};
box-shadow: ${parseDropShadow("drop-shadow-lemon")};
text-decoration: none;
}
&:focus-within::before {
box-shadow: ${parseDropShadow("drop-shadow-centered-lemon")},
${parseDropShadow("drop-shadow-centered-grey")};
text-decoration: none;
}
&:active {
color: ${parseColor("black")};
}
&:active::before {
box-shadow: ${parseDropShadow("drop-shadow-lemon")},
${parseDropShadow("drop-shadow-grey")};
background-color: ${parseColor("black")};
}
`;

const StyledOL = styled.ol`
list-style: none;
padding: 0;
margin: 0;
text-decoration: none;
`;

const StyledOLItem = styled(OakLI)`
position: relative;
counter-increment: list-counter;
display: flex;
align-items: center;
margin-bottom: ${parseSpacing("space-between-xs")};
min-height: 40px;
&:last-child {
margin-bottom: 0;
}
&:hover {
text-decoration: underline;
color: ${parseColor("bg-btn-primary-hover")};
}
`;

export type OakTertiaryOLNavProps = {
title?: string;
items: { title: string; href: string }[];
ariaLabel?: string;
anchorTarget?: string;
};

export const OakTertiaryOLNav = ({
items,
ariaLabel,
title,
anchorTarget,
...rest
}: OakTertiaryOLNavProps) => {
return (
<StyledNav tabIndex={0} aria-label={ariaLabel} {...rest}>
{anchorTarget && <OakAnchorTarget id={anchorTarget} />}
{title && (
<OakBox $mb={"space-between-m"}>
<OakSpan $font={"heading-light-7"}>{"Contents"}</OakSpan>
</OakBox>
)}
<StyledOL role="list">
{items.map((item, index) => (
<StyledOLItem
aria-label={`list item ${index + 1}`}
$font={"heading-7"}
key={index}
>
<StyledOakLink href={item.href}>{item.title}</StyledOakLink>
</StyledOLItem>
))}
</StyledOL>
</StyledNav>
);
};
Loading

0 comments on commit 10611ae

Please sign in to comment.