-
Notifications
You must be signed in to change notification settings - Fork 0
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<!-- @license CC0-1.0 --> | ||
|
||
# Kernteam side-navigation component |
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; | ||
padding-block: 0.75rem; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. als we block en inline beide zetten kunnen we beter de There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
} |
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 /> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. laten we het icon visueel verberg en als presentational markeren There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)}> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hier kunnen we het beste de expanded state exposen:
Suggested change
|
||||||
<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) => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hier NavList ipv MenuList gebruiken om verwarring met de |
||||||
return ( | ||||||
<ul className={'kernteam-menu-list'} {...restProps}> | ||||||
{children} | ||||||
</ul> | ||||||
); | ||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export { Button } from './Button'; | ||
export * from './SideNavigation'; |
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 |
---|---|---|
@@ -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: '/', | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
}; |
There was a problem hiding this comment.
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?