Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add side navigation #154

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/components-css/side-navigation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- @license CC0-1.0 -->

# Kernteam side-navigation component
111 changes: 111 additions & 0 deletions packages/components-css/side-navigation/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* @license EUPL-1.2
* Copyright (c) 2024 Community for NL Design System
*/

.kernteam-side-navigation {
border-inline-end-color: var(--kernteam-side-navigation-border-inline-end-color);
border-inline-end-style: var(--kernteam-side-navigation-border-inline-end-style);
border-inline-end-width: var(--kernteam-side-navigation-border-inline-end-width);
display: flex;
flex-direction: column;
inline-size: var(--kernteam-side-navigation-inline-size);
transition: inline-size 200ms ease;
}

.kernteam-side-navigation--hidden {
inline-size: 48px;
}

.kernteam-side-navigation--hidden .kernteam-side-navigation__content {
overflow-x: hidden;
visibility: hidden;
}

.kernteam-side-navigation-nav {
flex-grow: 1;
}

.kernteam-side-navigation__toggle-button {
padding-inline-start: var(--kernteam-side-navigation-toggle-button-padding-inline-start);
}

.kernteam-menu-list {
--utrecht-link-color: var(--kernteam-menu-list-link-color);
--utrecht-link-text-decoration: none;
--utrecht-button-subtle-color: var(--utrecht-link-color);
--utrecht-button-focus-color: var(--kernteam-focus-color);
--utrecht-button-icon-size: 28px;

display: block;
list-style: none;
padding-block-end: 0;
padding-block-start: 0;
padding-inline-end: 0;
padding-inline-start: 0;
}

.kernteam-menu-list-item__label {
align-items: center;
display: inline-flex;
inline-size: 100%;
}

.kernteam-menu-list-item__label:hover {
background-color: var(--kernteam-menu-list-link-hover-background-color);
}

.kernteam-menu-list__icon-button {
cursor: pointer;
}

.kernteam-menu-list-item__link {
display: flex;
flex: 1;
line-height: 1.5;
margin-inline-start: 4px;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

voelt als een magic number, zou het moeten corresponderen met de witruimte binnen het icon voor 'Verberg'? die lijkt 2px te zijn?

padding-block: 0.75rem;
Copy link
Member

@hidde hidde Oct 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

als we block en inline beide zetten kunnen we beter de padding shorthand gebruiken

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Als de stylelint in te stellen is om non-logical-shorthands zoals padding alleen toe te staan met 1 length, dan is het okay.

Anders is het handiger om padding volledig te blokkeren.

padding-inline: 0.75rem;
}

.kernteam-menu-list-item__link--current {
background-color: var(--kernteam-menu-list-link-current-background-color);
border-inline-start-color: var(--kernteam-menu-list-link-border-inline-start-color);
border-inline-start-style: var(--kernteam-menu-list-link-border-inline-start-style);
border-inline-start-width: var(--kernteam-menu-list-link-border-inline-start-width);
margin-inline-start: 0;
}

.kernteam-menu-list-item__link:hover {
border-inline-start-color: var(--kernteam-menu-list-link-border-inline-start-color);
border-inline-start-style: var(--kernteam-menu-list-link-border-inline-start-style);
border-inline-start-width: var(--kernteam-menu-list-link-border-inline-start-width);
margin-inline-start: 0;
}

.kernteam-menu-list-item__link:focus-visible {
outline: var(--kernteam-focus-outline-width) var(--kernteam-focus-outline-style) var(--kernteam-focus-outline-color);
}

.kernteam-menu-list .kernteam-menu-list .kernteam-menu-list-item__link {
padding-inline-start: 24px;
}

.kernteam-menu-list .kernteam-menu-list .kernteam-menu-list .kernteam-menu-list-item__link {
padding-inline-start: 40px;
}

/* HACK: these fixes need to be made in utrecht too, or in a button implementation based on Utrecht CSS just for the website */
.utrecht-button:focus {
background-color: var(--_utrecht-button-background-color) !important;
border-color: var(--_utrecht-button-border-color) !important;
color: var(--_utrecht-button-color) !important;
scale: var(--utrecht-button-scale, 1) !important;
}

.utrecht-button:focus-visible {
background-color: var(--_utrecht-button-focus-background-color) !important;
border-color: var(--_utrecht-button-focus-border-color) !important;
color: var(--_utrecht-button-focus-color) !important;
scale: var(--utrecht-button-focus-scale, 1) !important;
}
2 changes: 2 additions & 0 deletions packages/components-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
"@babel/preset-typescript": "7.24.7",
"@babel/runtime": "7.24.7",
"@nl-design-system-kernteam/components-css": "workspace:*",
"@utrecht/component-library-react": "5.0.0",
"@tabler/icons-react": "3.12.0",
"@rollup/plugin-babel": "6.0.4",
"@rollup/plugin-commonjs": "26.0.1",
"@rollup/plugin-node-resolve": "15.2.3",
Expand Down
87 changes: 87 additions & 0 deletions packages/components-react/src/SideNavigation/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { IconArrowBarToLeft, IconArrowBarToRight, IconChevronDown, IconChevronUp } from '@tabler/icons-react';
import { Button, Link } from '@utrecht/component-library-react/dist/css-module';
import clsx from 'clsx';
import { HTMLAttributes, PropsWithChildren, useState } from 'react';
import '@nl-design-system-kernteam/components-css/side-navigation/index.scss';

export interface SideNavigationProps extends HTMLAttributes<HTMLElement> {
listItems: MenuListItemProps[];
}

export const SideNavigation = ({ className, listItems, ...restProps }: SideNavigationProps) => {
const [open, setOpen] = useState(true);

const sideNavClassname = clsx(className, 'kernteam-side-navigation', {
['kernteam-side-navigation--hidden']: !open,
});

return (
<div className={sideNavClassname} {...restProps}>
<Button
className={'kernteam-side-navigation__toggle-button'}
appearance={'subtle-button'}
onClick={() => setOpen(!open)}
>
{open ? (
<>
<IconArrowBarToLeft />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

laten we het icon visueel verberg en als presentational markeren

Copy link
Member

@Robbert Robbert Oct 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dat kan met de Icon component van Utrecht

Verberg
</>
) : (
<>
<IconArrowBarToRight />
</>
)}
</Button>
<div className={'kernteam-side-navigation__content'}>
<nav className={'kernteam-side-navigation-nav'}>
<ul className={'kernteam-menu-list'}>
{listItems?.map((item, index) => <MenuListItem key={index} {...item} />)}
</ul>
</nav>
</div>
</div>
);
};

export interface MenuListItemProps {
label: string;
href: string;
children?: MenuListItemProps[];
}

export const MenuListItem = (props: MenuListItemProps) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same als hierboven maar NavListItem

const [open, setOpen] = useState(false);

return (
<li className={'kernteam-menu-list-item'}>
<div className={'kernteam-menu-list-item__label'}>
<Link className={'kernteam-menu-list-item__link'} href={props.href}>
{props.label}
</Link>
{props.children && (
<Button appearance="subtle-button" className="kernteam-menu-list__icon-button" onClick={() => setOpen(!open)}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hier kunnen we het beste de expanded state exposen:

Suggested change
<Button appearance="subtle-button" className="kernteam-menu-list__icon-button" onClick={() => setOpen(!open)}>
<Button appearance="subtle-button" aria-expanded={open} className="kernteam-menu-list__icon-button" onClick={() => setOpen(!open)}>

<span className="utrecht-icon">{open ? <IconChevronDown /> : <IconChevronUp />}</span>
</Button>
)}
</div>
{props.children && open && (
<>
<MenuList>
{props.children.map((child, index) => (
<MenuListItem key={index} {...child} />
))}
</MenuList>
</>
)}
</li>
);
};

export const MenuList = ({ children, ...restProps }: PropsWithChildren) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hier NavList ipv MenuList gebruiken om verwarring met de menu role of het <menu> HTML element te voorkomen?

return (
<ul className={'kernteam-menu-list'} {...restProps}>
{children}
</ul>
);
};
1 change: 1 addition & 0 deletions packages/components-react/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { Button } from './Button';
export * from './SideNavigation';
7 changes: 5 additions & 2 deletions packages/storybook/config/ParameterArgsDecorator.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import type { Decorator } from '@storybook/react';
import { Document } from '@utrecht/component-library-react/dist/css-module';

export const ParameterArgsDecorator: Decorator = (Story, context) => {
// Hack to make current args for a story available in the transformSource of the docs addon
context.parameters['args'] = context.args;

return (
<div className="voorbeeld-theme">
<Story />
<div className="kernteam-theme">
<Document>
<Story />
</Document>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// import '@nl-design-system-unstable/voorbeeld-design-tokens/src/font.js';
import '@nl-design-system-unstable/voorbeeld-design-tokens/dist/index.css';
import '@nl-design-system-kernteam/design-tokens/dist/index.css';
import type { Preview } from '@storybook/react';
import { ParameterArgsDecorator } from './ParameterArgsDecorator';

Expand Down
4 changes: 2 additions & 2 deletions packages/storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
"@storybook/react": "8.1.11",
"@storybook/react-vite": "8.1.11",
"@storybook/theming": "8.1.11",
"@tabler/icons-react": "3.8.0",
"@tabler/icons-react": "3.12.0",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
"@utrecht/component-library-react": "4.0.0",
"@utrecht/component-library-react": "5.0.0",
"@utrecht/web-component-library-react": "1.1.1",
"@whitespace/storybook-addon-html": "6.1.1",
"react": "18.3.1",
Expand Down
94 changes: 94 additions & 0 deletions packages/storybook/src/css-side-navigation.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* @license CC0-1.0 */

import readme from '@nl-design-system-kernteam/components-css/side-navigation/README.md?raw';
import type { Meta, StoryObj } from '@storybook/react';
import { SideNavigation } from '../../components-react/src';

const meta = {
title: 'CSS Component/Side Navigation',
id: 'css-side-nav',
component: SideNavigation,
argTypes: {
children: {
name: 'Content',
description: 'Button text',
type: {
name: 'string',
required: true,
},
defaultValue: '',
},
},
args: {
children: 'Opslaan en verder',
},
tags: ['autodocs'],
parameters: {
docs: {
description: {
component: readme,
},
},
},
} satisfies Meta<typeof SideNavigation>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {
args: {
listItems: [
{
label: 'Introductie',
href: '/',
},
{
label: 'Stijl',
href: '/',
},
{
label: 'Formulieren',
href: '/',
children: [
{
label: 'Introductie formulieren',
href: '/',
},
{
label: 'Buttons',
href: '/',
},
{
label: 'Bevestigingspagina',
href: '/',
children: [
{
label: 'Voorbeelden',
href: '/',
},
{
label: 'Uitleg',
href: '/',
},
],
},
],
},
{
label: 'WCAG',
href: '/',
children: [
{
label: 'Introductie WCAG',
href: '/',
},
{
label: 'Lorum Ipsum',
href: '/',
},
],
},
],
},
};
2 changes: 1 addition & 1 deletion packages/storybook/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"skipLibCheck": true
},
"extends": "../../tsconfig.json",
"include": ["config/**/*.ts", "src/**/*.ts", "src/**/*.tsx"],
"include": ["config/**/*.ts", "config/**/*.tsx", "src/**/*.ts", "src/**/*.tsx"],
"exclude": ["**/node_modules/*"]
}
Loading