Skip to content

Commit

Permalink
Merge branch 'develop' into feature/DES-488-hero-image
Browse files Browse the repository at this point in the history
  • Loading branch information
alimpens authored Dec 22, 2023
2 parents b9be0d3 + 34abcd0 commit 0949656
Show file tree
Hide file tree
Showing 41 changed files with 994 additions and 622 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
"@lerna-lite/run": "3.1.0",
"@lerna-lite/version": "3.1.0",
"@types/node": "20.10.5",
"@typescript-eslint/eslint-plugin": "6.14.0",
"@typescript-eslint/parser": "6.14.0",
"@typescript-eslint/eslint-plugin": "6.15.0",
"@typescript-eslint/parser": "6.15.0",
"conventional-changelog-conventionalcommits": "7.0.2",
"eslint": "8.56.0",
"eslint-config-prettier": "9.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/css/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@
"sass": "1.69.5"
},
"dependencies": {
"@utrecht/components": "2.0.0"
"@utrecht/components": "3.0.0"
}
}
14 changes: 14 additions & 0 deletions packages/css/src/components/header/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Header

A Header offers a container to display a City of Amsterdam logo, subsite title and page menu.

## Guidelines

- Use the Header when the site is hosted on amsterdam.nl or one of its subdomains.
- The page menu can contain a maximum of 5 items, including menu and search.
- When you have a long subsite title, use no or as little page menu items as possible.

## References

- A Header is a [landmark](https://www.w3.org/TR/wai-aria-practices-1.1/#aria_landmark_roles) and can be use to group navigation elements.
- [WCAG 3.2.3](https://wcag.com/designers/3-2-3-consistent-navigation/) Consistent Navigation: Navigation menus that appear on multiple pages are consistent.
85 changes: 85 additions & 0 deletions packages/css/src/components/header/header.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2023 Gemeente Amsterdam
*/

@import "../../common/breakpoint";

.amsterdam-header {
align-items: center;
display: flex;
flex-wrap: wrap;
padding-block: 1rem;
row-gap: 1.5rem;

@media screen and (min-width: $amsterdam-breakpoint-wide) {
column-gap: var(--amsterdam-header-column-gap);
flex-wrap: nowrap;
}
}

.amsterdam-header__logo {
flex: none;
outline-offset: var(--amsterdam-link-outline-offset);
}

.amsterdam-header__links {
display: none;

@media screen and (min-width: $amsterdam-breakpoint-medium) {
display: block;
flex: 10 0 auto;
}

@media screen and (min-width: $amsterdam-breakpoint-wide) {
order: 3;
}
}

.amsterdam-header__menu {
flex: 1;
padding-inline-start: var(--amsterdam-page-menu-column-gap);
text-align: end;

@media screen and (min-width: $amsterdam-breakpoint-wide) {
order: 4;
padding-inline-start: 0;
}
}

.amsterdam-header__title {
flex: 1 1 100%;

@media screen and (min-width: $amsterdam-breakpoint-wide) {
min-width: 0;
order: 2;

.amsterdam-header__title-heading {
display: block;
line-height: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: 100%;
}
}
}

// Temporary, will move to megamenu (and/or iconButton)
.amsterdam-header__menu-button {
background-color: transparent;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><path fill='%23004699' fill-rule='evenodd' d='M0 3.238h32V7.81H0V3.238zm0 10.476h32v4.572H0v-4.572zM0 24.19h32v4.572H0V24.19z'/></svg>");
background-position: center right;
background-repeat: no-repeat;
background-size: 19px 19px;
border: 0;
color: var(--amsterdam-page-menu-item-color);
font-family: var(--amsterdam-page-menu-item-font-family);
font-size: var(--amsterdam-page-menu-item-spacious-font-size);
font-weight: var(--amsterdam-page-menu-item-font-weight);
line-height: var(--amsterdam-page-menu-item-spacious-line-height);
margin-block: 0;
padding-inline: 0 30px;
text-align: center;
touch-action: manipulation;
}
1 change: 1 addition & 0 deletions packages/css/src/components/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

/* Append here */
@import "./overlap/overlap";
@import "./header/header";
@import "./mark/mark";
@import "./text-input/text-input";
@import "./search-field/search-field";
Expand Down
1 change: 1 addition & 0 deletions packages/css/src/components/logo/logo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

.amsterdam-logo {
display: block;
height: var(--amsterdam-logo-height);
}

Expand Down
20 changes: 2 additions & 18 deletions packages/css/src/components/page-menu/page-menu.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,11 @@
-webkit-text-size-adjust: 100%;
}

@mixin reset-button {
background-color: transparent;
border: 0;
margin-block: 0;
padding-inline: 0;
}

.amsterdam-page-menu {
align-items: center;
column-gap: var(--amsterdam-page-menu-column-gap);
display: flex;
flex-direction: row;
flex-wrap: wrap;
list-style: none;
row-gap: var(--amsterdam-page-menu-row-gap);

Expand All @@ -52,6 +44,7 @@
text-decoration-thickness: var(--amsterdam-page-menu-item-text-decoration-thickness);
text-underline-offset: var(--amsterdam-page-menu-item-text-underline-offset);
touch-action: manipulation;
white-space: nowrap;

.amsterdam-theme--compact & {
font-size: var(--amsterdam-page-menu-item-compact-font-size);
Expand All @@ -64,21 +57,12 @@
@include reset-item;
}

.amsterdam-page-menu__button {
cursor: pointer;

@include reset-item;
@include reset-button;
@include page-menu-item;
}

.amsterdam-page-menu__link:hover,
.amsterdam-page-menu__button:hover {
color: var(--amsterdam-page-menu-item-hover-color);
text-decoration-line: var(--amsterdam-page-menu-item-hover-text-decoration-line);
}

.amsterdam-page-menu__link svg,
.amsterdam-page-menu__button svg {
.amsterdam-page-menu__link svg {
color: currentColor;
}
6 changes: 2 additions & 4 deletions packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,8 @@
],
"dependencies": {
"@amsterdam/design-system-react-icons": "workspace:*",
"@utrecht/component-library-react": "2.0.0",
"clsx": "2.0.0",
"date-fns": "2.30.0"
"@utrecht/component-library-react": "3.0.0",
"clsx": "2.0.0"
},
"devDependencies": {
"@babel/core": "7.23.6",
Expand All @@ -51,7 +50,6 @@
"@testing-library/jest-dom": "6.1.5",
"@testing-library/react": "14.1.2",
"@testing-library/user-event": "14.5.1",
"@types/date-fns": "2.6.0",
"@types/jest": "29.5.11",
"@types/lodash": "4.14.202",
"@types/react": "18.2.45",
Expand Down
10 changes: 8 additions & 2 deletions packages/react/src/Grid/GridCell.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { render } from '@testing-library/react'
import { render, screen } from '@testing-library/react'
import { createRef } from 'react'
import { Grid } from './Grid'
import '@testing-library/jest-dom'
Expand Down Expand Up @@ -82,9 +82,15 @@ describe('Grid.Cell', () => {
)
})

it('renders the correct class name for the "all" value of span', () => {
it('renders the correct class name for the all value of span', () => {
const { container } = render(<Grid.Cell span="all" />)
const component = container.querySelector(':only-child')
expect(component).toHaveClass('amsterdam-grid__cell--span-all')
})

it('renders a custom tag', () => {
render(<Grid.Cell as="article" />)
const cell = screen.getByRole('article')
expect(cell).toBeInTheDocument()
})
})
13 changes: 9 additions & 4 deletions packages/react/src/Grid/GridCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@ type GridCellSpanAndStartProps = {
start?: GridColumnNumber | GridColumnNumbers
}

export type GridCellProps = (GridCellSpanAllProp | GridCellSpanAndStartProps) &
export type GridCellProps = {
as?: 'article' | 'div' | 'section'
} & (GridCellSpanAllProp | GridCellSpanAndStartProps) &
PropsWithChildren<HTMLAttributes<HTMLDivElement>>

export const GridCell = forwardRef(
({ children, className, span, start, ...restProps }: GridCellProps, ref: ForwardedRef<HTMLDivElement>) => (
<div {...restProps} ref={ref} className={clsx('amsterdam-grid__cell', gridCellClasses(span, start), className)}>
(
{ as: Tag = 'div', children, className, span, start, ...restProps }: GridCellProps,
ref: ForwardedRef<HTMLDivElement>,
) => (
<Tag {...restProps} ref={ref} className={clsx('amsterdam-grid__cell', gridCellClasses(span, start), className)}>
{children}
</div>
</Tag>
),
)

Expand Down
79 changes: 79 additions & 0 deletions packages/react/src/Header/Header.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { render, screen } from '@testing-library/react'
import { createRef } from 'react'
import { Header, HeaderProps } from './Header'
import '@testing-library/jest-dom'

describe('Header', () => {
const defaultProps: HeaderProps = {
logoLink: '/',
}

it('renders', () => {
render(<Header {...defaultProps} />)

const component = screen.getByRole('banner')

expect(component).toBeInTheDocument()
expect(component).toBeVisible()
})

it('renders a design system BEM class name', () => {
render(<Header {...defaultProps} />)

const component = screen.getByRole('banner')

expect(component).toHaveClass('amsterdam-header')
})

it('renders an additional class name', () => {
render(<Header {...defaultProps} className="extra" />)

const component = screen.getByRole('banner')

expect(component).toHaveClass('extra')
expect(component).toHaveClass('amsterdam-header')
})

it('supports ForwardRef in React', () => {
const ref = createRef<HTMLElement>()

render(<Header {...defaultProps} ref={ref} />)

const component = screen.getByRole('banner')

expect(ref.current).toBe(component)
})

it('renders with a logo link', () => {
render(<Header {...defaultProps} logoLink="/home" />)

const logoLink = screen.getByRole('link')

expect(logoLink).toHaveAttribute('href', '/home')
})

it('renders with a logo link title', () => {
render(<Header {...defaultProps} logoLinkTitle="Go to homepage" />)

const logoLinkTitle = screen.getByRole('link', { name: 'Go to homepage' })

expect(logoLinkTitle).toHaveTextContent('Go to homepage')
})

it('renders with links', () => {
const { container } = render(<Header {...defaultProps} links={<div>Menu Content</div>} />)

const menu = container.querySelector('.amsterdam-header__links')

expect(menu).toBeInTheDocument()
expect(menu).toHaveTextContent('Menu Content')
})

it('renders with menu button', () => {
render(<Header {...defaultProps} menu={<button>Menu Button</button>} />)

const menu = screen.getByRole('button')

expect(menu).toBeInTheDocument()
})
})
58 changes: 58 additions & 0 deletions packages/react/src/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* @license EUPL-1.2+
* Copyright (c) 2023 Gemeente Amsterdam
*/

import clsx from 'clsx'
import { ForwardedRef, forwardRef, HTMLAttributes, ReactNode } from 'react'
import { Heading } from '../Heading'
import { Logo } from '../Logo'
import type { LogoBrand } from '../Logo'
import { VisuallyHidden } from '../VisuallyHidden'

export interface HeaderProps extends HTMLAttributes<HTMLElement> {
logoBrand?: LogoBrand
logoLink?: string
logoLinkTitle?: string
title?: string
links?: ReactNode
menu?: ReactNode
}

export const Header = forwardRef(
(
{
className,
logoBrand = 'amsterdam',
logoLink = '/',
logoLinkTitle = 'Ga naar de homepage',
title,
links,
menu,
...restProps
}: HeaderProps,
ref: ForwardedRef<HTMLElement>,
) => {
return (
<>
<header {...restProps} ref={ref} className={clsx('amsterdam-header', className)}>
<a href={logoLink} className="amsterdam-header__logo">
<VisuallyHidden>{logoLinkTitle}</VisuallyHidden>
<Logo brand={logoBrand} />
</a>
{links && <div className="amsterdam-header__links">{links}</div>}
{menu && <div className="amsterdam-header__menu">{menu}</div>}
{title && (
<div className="amsterdam-header__title">
<Heading level={1} size="level-3" className="amsterdam-header__title-heading">
{title}
</Heading>
</div>
)}
</header>
</>
)
},
)

Header.displayName = 'Header'
3 changes: 3 additions & 0 deletions packages/react/src/Header/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# React Header component

[Header documentation](../../../css/src/header/README.md)
2 changes: 2 additions & 0 deletions packages/react/src/Header/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { Header } from './Header'
export type { HeaderProps } from './Header'
Loading

0 comments on commit 0949656

Please sign in to comment.