mirror of
https://github.com/navikt/aksel.git
synced 2026-10-13 01:02:02 +00:00
Compare commits
18
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c785316086 | ||
|
|
7087f160e8 | ||
|
|
235e48a843 | ||
|
|
93fc5dc6ae | ||
|
|
5c49902ffb | ||
|
|
c9c148e050 | ||
|
|
adf9de3c63 | ||
|
|
26612e371d | ||
|
|
b194506943 | ||
|
|
79dbffff1d | ||
|
|
0359934bb9 | ||
|
|
2723363fa0 | ||
|
|
d56bc72977 | ||
|
|
e203d669e1 | ||
|
|
90c06964a3 | ||
|
|
c35850a5e5 | ||
|
|
fd2ebe2629 | ||
|
|
206cdaa2ce |
No files matched your search
@@ -0,0 +1,8 @@
|
||||
.navds-accordion-anchor-menu {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
.navds-accordion-anchor-menu__title {
|
||||
margin-left: 1rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
.navds-accordion-menu__list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-weight: var(--navds-font-weight-bold);
|
||||
}
|
||||
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
font: inherit;
|
||||
text-align: inherit;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: var(--navds-font-weight-bold);
|
||||
color: var(--navds-color-text-link);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.navds-accordion-menu-collapsable .navds-accordion-menu__list,
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
font-weight: var(--navds-font-weight-regular);
|
||||
}
|
||||
|
||||
.navds-accordion-menu-item,
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
display: flex;
|
||||
padding: 0.75rem 1rem;
|
||||
line-height: 1.5rem; /* TODO: fix typography. */
|
||||
}
|
||||
|
||||
.navds-accordion-menu-collapsable__expand-icon {
|
||||
font-size: 1.5rem;
|
||||
color: var(--navds-color-text-link);
|
||||
flex-shrink: 0;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.navds-accordion-menu-collapsable--open
|
||||
> .navds-accordion-menu-collapsable__button
|
||||
> .navds-accordion-menu-collapsable__expand-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.navds-accordion-menu-collapsable .navds-accordion-menu-item,
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-item,
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
.navds-accordion-menu-item:focus,
|
||||
.navds-accordion-menu-collapsable__button:focus {
|
||||
outline: 3px solid var(--navds-text-focus);
|
||||
outline-offset: -3px;
|
||||
}
|
||||
|
||||
.navds-accordion-menu-item:hover,
|
||||
.navds-accordion-menu-collapsable__button:hover {
|
||||
background-color: var(--navds-color-gray-20);
|
||||
}
|
||||
|
||||
.navds-accordion-menu-item--active {
|
||||
box-shadow: inset 0.5rem 0 var(--navds-color-text-link);
|
||||
color: var(--navds-color-text);
|
||||
text-decoration: none;
|
||||
font-weight: var(--navds-font-weight-bold);
|
||||
}
|
||||
@@ -24,7 +24,6 @@
|
||||
.navds-accordion__chevron {
|
||||
width: 1.25em;
|
||||
height: 1.25em;
|
||||
transition: 300ms transform;
|
||||
transform: rotateZ(0deg);
|
||||
flex-shrink: 0;
|
||||
margin-left: 1rem;
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
@import "print.css";
|
||||
@import "utility.css";
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--navds-font-family);
|
||||
line-height: 1.375;
|
||||
@@ -16,3 +20,16 @@ body {
|
||||
a {
|
||||
color: var(--navds-color-text-link);
|
||||
}
|
||||
|
||||
/* https://web.dev/prefers-reduced-motion/ */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, ::before, ::after {
|
||||
animation-delay: -1ms !important;
|
||||
animation-duration: 1ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
background-attachment: initial !important;
|
||||
scroll-behavior: auto !important;
|
||||
transition-duration: 0s !important;
|
||||
transition-delay: 0s !important;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
@import "baseline/baseline.css";
|
||||
@import "accordion.css";
|
||||
@import "accordion-anchor-menu.css";
|
||||
@import "accordion-menu.css";
|
||||
@import "alert.css";
|
||||
@import "button.css";
|
||||
@import "content-container.css";
|
||||
@import "grid.css";
|
||||
@import "internal-header.css";
|
||||
@import "layout.css";
|
||||
@import "layouts.css";
|
||||
@import "link.css";
|
||||
@import "modal.css";
|
||||
@import "popover.css";
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
.navds-layout__container {
|
||||
display: grid;
|
||||
grid-gap: var(--navds-grid-gutter-small);
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.navds-layout__container--1-columns,
|
||||
.navds-layout__container--2-columns {
|
||||
max-width: 60rem;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns {
|
||||
max-width: 79.5rem;
|
||||
}
|
||||
|
||||
.navds-layout__section--white > * {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.navds-layout__section--padding > * {
|
||||
padding: var(--navds-layout-padding-small);
|
||||
}
|
||||
|
||||
.navds-layout__section--sticky > * {
|
||||
top: var(--navds-grid-gutter-small);
|
||||
position: sticky;
|
||||
}
|
||||
|
||||
.navds-layout__section--left,
|
||||
.navds-layout__section--main,
|
||||
.navds-layout__section--right {
|
||||
grid-column: span 12;
|
||||
}
|
||||
|
||||
@media (min-width: 448px) {
|
||||
.navds-layout__container {
|
||||
grid-gap: var(--navds-grid-gutter-medium-and-larger);
|
||||
}
|
||||
|
||||
.navds-layout__section--padding.navds-layout__section--left > *,
|
||||
.navds-layout__section--padding.navds-layout__section--main > *,
|
||||
.navds-layout__section--padding.navds-layout__section--right > * {
|
||||
padding: var(--navds-layout-padding-medium-and-larger);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 648px) {
|
||||
.navds-layout__container {
|
||||
grid-gap: var(--navds-grid-gutter-medium-and-larger);
|
||||
}
|
||||
|
||||
.navds-layout__section--padding.navds-layout__section--right > * {
|
||||
padding: var(--navds-layout-padding-small);
|
||||
}
|
||||
|
||||
/* prettier-ignore */
|
||||
.navds-layout__container--2-columns > .navds-layout__section--padding.navds-layout__section--left > * {
|
||||
padding: var(--navds-layout-padding-small);
|
||||
}
|
||||
|
||||
.navds-layout__container--1-columns > .navds-layout__section--main {
|
||||
grid-column: span 10;
|
||||
}
|
||||
|
||||
.navds-layout__container--2-columns > .navds-layout__section--left,
|
||||
.navds-layout__container--2-columns > .navds-layout__section--right {
|
||||
grid-row: 1;
|
||||
grid-column: span 4;
|
||||
}
|
||||
|
||||
.navds-layout__container--2-columns > .navds-layout__section--main {
|
||||
grid-row: 1;
|
||||
grid-column: span 8;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--left {
|
||||
grid-row: 1;
|
||||
grid-column: span 8;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--main {
|
||||
grid-row: 2;
|
||||
grid-column: span 8;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--right {
|
||||
grid-column: span 4;
|
||||
grid-row: 1 / span 2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.navds-layout__section--padding.navds-layout__section--left > * {
|
||||
padding: var(--navds-layout-padding-small);
|
||||
}
|
||||
|
||||
.navds-layout__container--1-columns > .navds-layout__section--main {
|
||||
grid-column: span 8;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--left {
|
||||
grid-row: 1;
|
||||
grid-column: span 3;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--main {
|
||||
grid-row: 1;
|
||||
grid-column: span 6;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--right {
|
||||
grid-row: 1;
|
||||
grid-column: span 3;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
/*****************
|
||||
* .navds-layout *
|
||||
*****************/
|
||||
|
||||
.navds-layout__container {
|
||||
display: grid;
|
||||
grid-gap: var(--navds-grid-gutter-small);
|
||||
grid-template-columns: repeat(12, minmax(0, 1fr));
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.navds-layout__container--1-columns,
|
||||
.navds-layout__container--2-columns {
|
||||
max-width: 60rem;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns {
|
||||
max-width: 79.5rem;
|
||||
}
|
||||
|
||||
.navds-layout__section--white > * {
|
||||
background: white;
|
||||
}
|
||||
|
||||
.navds-layout__section--padding > * {
|
||||
padding: var(--navds-layout-padding-small);
|
||||
}
|
||||
|
||||
.navds-layout__section--sticky > * {
|
||||
top: calc(var(--navds-grid-gutter-small) + var(--decorator-sticky-offset));
|
||||
position: sticky;
|
||||
}
|
||||
|
||||
.navds-layout__section > *:not(:last-child) {
|
||||
margin-bottom: var(--navds-layout-padding-small);
|
||||
}
|
||||
|
||||
.navds-layout__section--left,
|
||||
.navds-layout__section--main,
|
||||
.navds-layout__section--right {
|
||||
grid-column: span 12;
|
||||
}
|
||||
|
||||
@media (min-width: 448px) {
|
||||
.navds-layout__container {
|
||||
grid-gap: var(--navds-grid-gutter-medium-and-larger);
|
||||
}
|
||||
|
||||
.navds-layout__section > *:not(:last-child) {
|
||||
margin-bottom: var(--navds-grid-gutter-medium-and-larger);
|
||||
}
|
||||
|
||||
.navds-layout__section--padding.navds-layout__section--left > *,
|
||||
.navds-layout__section--padding.navds-layout__section--main > *,
|
||||
.navds-layout__section--padding.navds-layout__section--right > * {
|
||||
padding: var(--navds-layout-padding-medium-and-larger);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 648px) {
|
||||
.navds-layout__container {
|
||||
grid-gap: var(--navds-grid-gutter-medium-and-larger);
|
||||
}
|
||||
|
||||
.navds-layout__section--padding.navds-layout__section--right > * {
|
||||
padding: var(--navds-layout-padding-small);
|
||||
}
|
||||
|
||||
/* prettier-ignore */
|
||||
.navds-layout__container--2-columns > .navds-layout__section--padding.navds-layout__section--left > * {
|
||||
padding: var(--navds-layout-padding-small);
|
||||
}
|
||||
|
||||
.navds-layout__container--1-columns > .navds-layout__section--main {
|
||||
grid-column: span 10;
|
||||
}
|
||||
|
||||
.navds-layout__container--2-columns > .navds-layout__section--left,
|
||||
.navds-layout__container--2-columns > .navds-layout__section--right {
|
||||
grid-row: 1;
|
||||
grid-column: span 4;
|
||||
}
|
||||
|
||||
.navds-layout__container--2-columns > .navds-layout__section--main {
|
||||
grid-row: 1;
|
||||
grid-column: span 8;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--left {
|
||||
grid-row: 1;
|
||||
grid-column: span 8;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--main {
|
||||
grid-row: 2;
|
||||
grid-column: span 8;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--right {
|
||||
grid-column: span 4;
|
||||
grid-row: 1 / span 2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.navds-layout__section--padding.navds-layout__section--left > * {
|
||||
padding: var(--navds-layout-padding-small);
|
||||
}
|
||||
|
||||
.navds-layout__container--1-columns > .navds-layout__section--main {
|
||||
grid-column: span 8;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--left {
|
||||
grid-row: 1;
|
||||
grid-column: span 3;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--main {
|
||||
grid-row: 1;
|
||||
grid-column: span 6;
|
||||
}
|
||||
|
||||
.navds-layout__container--3-columns > .navds-layout__section--right {
|
||||
grid-row: 1;
|
||||
grid-column: span 3;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************
|
||||
* .navds-layout__header *
|
||||
************************/
|
||||
|
||||
.navds-layout__header {
|
||||
background: var(--navds-layout-background-white);
|
||||
}
|
||||
|
||||
.navds-layout__header-content {
|
||||
grid-column: span 12;
|
||||
}
|
||||
|
||||
.navds-layout__header-title {
|
||||
margin: 0.25rem 0.85rem;
|
||||
}
|
||||
|
||||
@media (min-width: 448px) {
|
||||
.navds-layout__header-title {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************
|
||||
* .navds-layout__body *
|
||||
************************/
|
||||
|
||||
.navds-layout__body {
|
||||
background: var(--navds-layout-background-gray);
|
||||
}
|
||||
|
||||
.navds-layout__body--white {
|
||||
background: var(--navds-layout-background-white);
|
||||
}
|
||||
|
||||
@media (min-width: 648px) {
|
||||
.navds-layout__body--2-columns.navds-layout__body--padding {
|
||||
padding-top: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
.navds-layout__body--3-columns.navds-layout__body--padding {
|
||||
padding-top: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************
|
||||
* .navds-layout__panel *
|
||||
************************/
|
||||
|
||||
.navds-layout__panel {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding: var(--navds-layout-padding-small);
|
||||
background: white;
|
||||
padding-top: 2.5rem;
|
||||
}
|
||||
|
||||
.navds-layout__panel--icon-margin {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.navds-layout__panel:not(:last-child) {
|
||||
margin-bottom: var(--navds-grid-gutter-small);
|
||||
}
|
||||
|
||||
.navds-layout__panel--highlight {
|
||||
box-shadow: rgb(102, 164, 220) 0 0 0 0.15rem;
|
||||
}
|
||||
|
||||
.navds-layout__panel-content {
|
||||
margin-top: 1.25rem;
|
||||
}
|
||||
|
||||
.navds-layout__panel-icon {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
top: -2rem;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.navds-layout__panel-icon svg,
|
||||
.navds-layout__panel-icon img {
|
||||
background: #c7dbed;
|
||||
border-radius: 2rem;
|
||||
padding: 1rem;
|
||||
height: 4rem;
|
||||
width: 4rem;
|
||||
}
|
||||
|
||||
.navds-layout__panel-title {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.navds-layout__panel-copy {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.navds-layout__panel-copy-icon {
|
||||
color: var(--navds-color-text-link);
|
||||
margin-right: 0.5rem;
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.navds-layout__panel-popover-content {
|
||||
margin: 0.5rem;
|
||||
}
|
||||
|
||||
.navds-layout__panel-copy-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
margin: 0 1rem 0 0;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 448px) {
|
||||
.navds-layout__panel {
|
||||
padding: var(--navds-layout-padding-medium-and-larger);
|
||||
}
|
||||
|
||||
.navds-layout__panel:not(:last-child) {
|
||||
margin-bottom: var(--navds-grid-gutter-medium-and-larger);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 448px) and (max-width: 959px) {
|
||||
.navds-layout__section .navds-accordion-anchor-menu__title {
|
||||
margin-left: 2.5rem;
|
||||
margin-right: 2.5rem;
|
||||
}
|
||||
.navds-layout__section .navds-accordion-menu-item,
|
||||
.navds-layout__section
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
padding-left: 2.5rem;
|
||||
padding-right: 2.5rem;
|
||||
}
|
||||
|
||||
.navds-layout__section
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-item,
|
||||
.navds-layout__section
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
padding-left: 3.5rem;
|
||||
padding-right: 3.5rem;
|
||||
}
|
||||
|
||||
.navds-layout__section
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-item,
|
||||
.navds-layout__section
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable
|
||||
.navds-accordion-menu-collapsable__button {
|
||||
padding-left: 4.5rem;
|
||||
padding-right: 4.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 648px) {
|
||||
/* prettier-ignore */
|
||||
.navds-layout__container--2-columns .navds-layout__panel--icon-margin:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 960px) {
|
||||
/* prettier-ignore */
|
||||
.navds-layout__container--3-columns .navds-layout__panel--icon-margin:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.navds-layout__panel--icon-margin:not(:first-child) {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.5",
|
||||
"private": false,
|
||||
"description": "Css for NAV Designsystem components",
|
||||
"author": "NAV Designsystem team",
|
||||
@@ -21,7 +21,7 @@
|
||||
"watch-css": "postcss -w --use postcss-import -o dist/index.css index.css"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^0.1.0",
|
||||
"@navikt/ds-tokens": "^0.1.2",
|
||||
"normalize.css": "^8.0.1",
|
||||
"postcss": "^8.2.7",
|
||||
"postcss-cli": "^8.3.1",
|
||||
|
||||
@@ -4,11 +4,6 @@
|
||||
box-shadow: 0 0.05rem 0.25rem 0.125rem rgba(0, 0, 0, 0.08);
|
||||
border: var(--navds-border-default);
|
||||
border-radius: 2px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.navds-popover--small {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.navds-popover--hidden {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-icons",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"private": false,
|
||||
"description": "NAVs egne ikoner i SVG og React format",
|
||||
"repository": {
|
||||
@@ -22,6 +22,7 @@
|
||||
"files": [
|
||||
"/cjs",
|
||||
"/esm",
|
||||
"/src",
|
||||
"/svg"
|
||||
],
|
||||
"scripts": {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import React, { forwardRef, HTMLAttributes } from "react";
|
||||
import { AccordionMenu as BaseAccordionMenu } from "../accordion-menu";
|
||||
import { Heading } from "../index";
|
||||
import { ActiveAnchorProvider } from "./ActiveAnchorStore";
|
||||
import cl from "classnames";
|
||||
|
||||
export interface AccordionAnchorMenuProps
|
||||
extends HTMLAttributes<HTMLDivElement> {
|
||||
title?: string;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const AccordionAnchorMenu = forwardRef<
|
||||
HTMLDivElement,
|
||||
AccordionAnchorMenuProps
|
||||
>(({ children, title, className, ...rest }, ref) => (
|
||||
<div
|
||||
className={cl("navds-accordion-anchor-menu", className)}
|
||||
ref={ref}
|
||||
{...rest}
|
||||
>
|
||||
{title && (
|
||||
<Heading
|
||||
level={2}
|
||||
size="medium"
|
||||
className="navds-accordion-anchor-menu__title"
|
||||
>
|
||||
{title}
|
||||
</Heading>
|
||||
)}
|
||||
<ActiveAnchorProvider>
|
||||
<BaseAccordionMenu aria-label={title || "Meny"}>
|
||||
{children}
|
||||
</BaseAccordionMenu>
|
||||
</ActiveAnchorProvider>
|
||||
</div>
|
||||
));
|
||||
|
||||
export default AccordionAnchorMenu;
|
||||
@@ -0,0 +1 @@
|
||||
export { AccordionMenuCollapsable as AccordionAnchorMenuCollapsable } from "../accordion-menu";
|
||||
@@ -0,0 +1,39 @@
|
||||
import React, { forwardRef, useEffect } from "react";
|
||||
import { AccordionMenuItem, AccordionMenuItemType } from "../accordion-menu";
|
||||
import { useStore } from "./ActiveAnchorStore";
|
||||
|
||||
const AccordionAnchorMenuItem: AccordionMenuItemType = forwardRef(
|
||||
(props, ref) => {
|
||||
const isAnchorActive = useIsAnchorActive(
|
||||
props.href && props.href.split("#")[1]
|
||||
);
|
||||
|
||||
return (
|
||||
<AccordionMenuItem
|
||||
{...props}
|
||||
ref={ref}
|
||||
active={props.active || isAnchorActive}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const useIsAnchorActive = (anchor: string | undefined) => {
|
||||
const { activeAnchor, registerAnchor, unregisterAnchor } = useStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (anchor) {
|
||||
const target = document.getElementById(anchor);
|
||||
if (target) {
|
||||
registerAnchor(anchor);
|
||||
return () => {
|
||||
unregisterAnchor(anchor);
|
||||
};
|
||||
}
|
||||
}
|
||||
}, [anchor, registerAnchor, unregisterAnchor]);
|
||||
|
||||
return (anchor && activeAnchor === anchor) || false;
|
||||
};
|
||||
|
||||
export default AccordionAnchorMenuItem;
|
||||
@@ -0,0 +1,69 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useState,
|
||||
useEffect,
|
||||
} from "react";
|
||||
|
||||
export interface ActiveAnchorStore {
|
||||
activeAnchor?: string;
|
||||
registerAnchor: (anchor: string) => void;
|
||||
unregisterAnchor: (anchor: string) => void;
|
||||
}
|
||||
|
||||
export const ActiveAnchorContext = createContext({} as ActiveAnchorStore);
|
||||
export const ActiveAnchorProvider = ({ children }) => {
|
||||
const [anchors, setAnchors] = useState<string[]>([]);
|
||||
const [activeAnchor, setActiveAnchor] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
const scrollListener = () => {
|
||||
const offset = 100;
|
||||
const lastPassedAnchor = anchors
|
||||
.map((anchor) => document.getElementById(anchor))
|
||||
.map((element: HTMLElement) => ({
|
||||
id: element.id,
|
||||
top: element.getBoundingClientRect().top - offset,
|
||||
scrolledToBottom:
|
||||
window.innerHeight + window.pageYOffset >=
|
||||
document.body.offsetHeight,
|
||||
}))
|
||||
.filter((element) => element.scrolledToBottom || element.top <= 0)
|
||||
.sort((a, b) => (a.top < b.top ? -1 : 1))
|
||||
.map((anchor) => anchor.id)
|
||||
.pop();
|
||||
|
||||
// Set active anchor and related url hash
|
||||
if (lastPassedAnchor && activeAnchor !== lastPassedAnchor) {
|
||||
const { href, hash } = window.location;
|
||||
const urlWithoutHash = href.replace(hash, "");
|
||||
const urlWithAnchor = `${urlWithoutHash}#${lastPassedAnchor}`;
|
||||
const title = document.title;
|
||||
window.history.pushState(lastPassedAnchor, title, urlWithAnchor);
|
||||
setActiveAnchor(lastPassedAnchor);
|
||||
}
|
||||
};
|
||||
window.addEventListener("scroll", scrollListener);
|
||||
return () => {
|
||||
window.removeEventListener("scroll", scrollListener);
|
||||
};
|
||||
}, [anchors, activeAnchor]);
|
||||
|
||||
return (
|
||||
<ActiveAnchorContext.Provider
|
||||
value={{
|
||||
activeAnchor,
|
||||
registerAnchor: useCallback((anchor) => {
|
||||
setAnchors((anchors) => [...anchors, anchor]);
|
||||
}, []),
|
||||
unregisterAnchor: useCallback((anchor) => {
|
||||
setAnchors((anchors) => anchors.filter((a) => a !== anchor));
|
||||
}, []),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ActiveAnchorContext.Provider>
|
||||
);
|
||||
};
|
||||
export const useStore = () => useContext(ActiveAnchorContext);
|
||||
@@ -0,0 +1,3 @@
|
||||
export { default as AccordionAnchorMenu } from "./AccordionAnchorMenu";
|
||||
export { AccordionAnchorMenuCollapsable } from "./AccordionAnchorMenuCollapsable";
|
||||
export { default as AccordionAnchorMenuItem } from "./AccordionAnchorMenuItem";
|
||||
@@ -0,0 +1,141 @@
|
||||
import * as React from "react";
|
||||
import {
|
||||
AccordionAnchorMenu as Menu,
|
||||
AccordionAnchorMenuCollapsable as Collapsable,
|
||||
AccordionAnchorMenuItem as Item,
|
||||
} from "../index";
|
||||
import { useEffect } from "react";
|
||||
import { ProductPageLayout } from "../../index";
|
||||
import { Right } from "../../layouts/stories/components/sections/Right";
|
||||
import { LightBulb, Telephone } from "@navikt/ds-icons";
|
||||
import { MainOne } from "../../layouts/stories/components/sections/Main";
|
||||
import { MainTwo } from "../../layouts/stories/components/sections/Main";
|
||||
import { MainThree } from "../../layouts/stories/components/sections/Main";
|
||||
import { Link, HashRouter as Router } from "react-router-dom";
|
||||
|
||||
export default {
|
||||
title: "ds-react/accordion-anchor-menu",
|
||||
component: { Menu },
|
||||
decorators: [
|
||||
(Story) => {
|
||||
useEffect(() => {
|
||||
document.getElementById("decorator-header").style.display = "block";
|
||||
document.getElementById("decorator-footer").style.display = "block";
|
||||
return () => {
|
||||
document.getElementById("decorator-header").style.display = "none";
|
||||
document.getElementById("decorator-footer").style.display = "none";
|
||||
};
|
||||
}, []);
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
},
|
||||
};
|
||||
|
||||
export const All = () => (
|
||||
<ProductPageLayout title={"Nunc et lorem"}>
|
||||
<ProductPageLayout.Section left sticky withPadding={false}>
|
||||
<Menu title={"Minima"} smoothScrollBehavior>
|
||||
<Item href={"#leo-quis"}>Leo quis</Item>
|
||||
<Collapsable title={"Proin accumsan"}>
|
||||
<Item href={"#nulla-pariatur"}>Nulla pariatur</Item>
|
||||
<Item href={"#luctus-justo"}>Luctus justo</Item>
|
||||
</Collapsable>
|
||||
<Item href={"#maecenas-in-pretium"}>Maecenas in pretium</Item>
|
||||
</Menu>
|
||||
</ProductPageLayout.Section>
|
||||
<ProductPageLayout.Section whiteBackground={false} withPadding={false}>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Leo quis"}
|
||||
anchor={"leo-quis"}
|
||||
highlight={true}
|
||||
icon={<LightBulb />}
|
||||
>
|
||||
<MainOne title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Proin accumsan"}
|
||||
anchor={"proin-accumsan"}
|
||||
>
|
||||
<MainTwo title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Maecenas in pretium"}
|
||||
anchor={"maecenas-in-pretium"}
|
||||
icon={<Telephone />}
|
||||
>
|
||||
<MainThree title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
</ProductPageLayout.Section>
|
||||
<ProductPageLayout.Section right sticky>
|
||||
<Right />
|
||||
</ProductPageLayout.Section>
|
||||
</ProductPageLayout>
|
||||
);
|
||||
|
||||
export const ReactRouter = () => (
|
||||
<ProductPageLayout title={"Nunc et lorem"}>
|
||||
<ProductPageLayout.Section left sticky withPadding={false}>
|
||||
<Menu>
|
||||
<Item component={Link} to="/link1">
|
||||
Leo quis
|
||||
</Item>
|
||||
<Collapsable title={"Proin accumsan"}>
|
||||
<Item component={Link} to="/link2">
|
||||
Nulla pariatur
|
||||
</Item>
|
||||
<Item component={Link} to="/link3">
|
||||
Luctus justo
|
||||
</Item>
|
||||
</Collapsable>
|
||||
<Collapsable title={"Sint cupidatat"}>
|
||||
<Item component={Link} to="/link4">
|
||||
Nulla pariatur
|
||||
</Item>
|
||||
<Item component={Link} to="/link5">
|
||||
Luctus justo
|
||||
</Item>
|
||||
</Collapsable>
|
||||
<Item component={Link} to="/link6">
|
||||
Maecenas in pretium
|
||||
</Item>
|
||||
</Menu>
|
||||
</ProductPageLayout.Section>
|
||||
<ProductPageLayout.Section whiteBackground={false} withPadding={false}>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Leo quis"}
|
||||
anchor={"leo-quis"}
|
||||
highlight={true}
|
||||
icon={<LightBulb />}
|
||||
>
|
||||
<MainOne title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Proin accumsan"}
|
||||
anchor={"proin-accumsan"}
|
||||
>
|
||||
<MainTwo title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Maecenas in pretium"}
|
||||
anchor={"maecenas-in-pretium"}
|
||||
icon={<Telephone />}
|
||||
>
|
||||
<MainThree title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
</ProductPageLayout.Section>
|
||||
<ProductPageLayout.Section right sticky>
|
||||
<Right />
|
||||
</ProductPageLayout.Section>
|
||||
</ProductPageLayout>
|
||||
);
|
||||
|
||||
ReactRouter.decorators = [
|
||||
(Story) => (
|
||||
<Router>
|
||||
<Story />
|
||||
</Router>
|
||||
),
|
||||
];
|
||||
@@ -0,0 +1,25 @@
|
||||
import React, { forwardRef, HTMLAttributes } from "react";
|
||||
import cl from "classnames";
|
||||
import MenuItems from "./MenuItems";
|
||||
|
||||
export interface AccordionMenuProps extends HTMLAttributes<HTMLElement> {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const AccordionMenu = forwardRef<HTMLElement, AccordionMenuProps>(
|
||||
({ children, className, ...rest }, ref) => {
|
||||
return (
|
||||
<nav
|
||||
role="navigation"
|
||||
ref={ref}
|
||||
className={cl("navds-accordion-menu", className)}
|
||||
{...rest}
|
||||
>
|
||||
<MenuItems>{children}</MenuItems>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default AccordionMenu;
|
||||
@@ -0,0 +1,44 @@
|
||||
import React, { forwardRef, HTMLAttributes, useState } from "react";
|
||||
import cl from "classnames";
|
||||
import { Expand } from "@navikt/ds-icons";
|
||||
import MenuItems from "./MenuItems";
|
||||
|
||||
export interface AccordionMenuCollapsableProps
|
||||
extends HTMLAttributes<HTMLDivElement> {
|
||||
title: string;
|
||||
defaultOpen?: boolean;
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const AccordionMenuCollapsable = forwardRef<
|
||||
HTMLDivElement,
|
||||
AccordionMenuCollapsableProps
|
||||
>(({ children, defaultOpen = false, title, className, ...rest }, ref) => {
|
||||
const [isOpen, setIsOpen] = useState(defaultOpen);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cl("navds-accordion-menu-collapsable", className, {
|
||||
"navds-accordion-menu-collapsable--open": isOpen,
|
||||
})}
|
||||
{...rest}
|
||||
>
|
||||
<button
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className="navds-accordion-menu-collapsable__button"
|
||||
>
|
||||
{title}
|
||||
<Expand
|
||||
role="img"
|
||||
aria-label={isOpen ? "Pil peker opp" : "Pil peker ned"}
|
||||
className="navds-accordion-menu-collapsable__expand-icon"
|
||||
/>
|
||||
</button>
|
||||
{isOpen && <MenuItems>{children}</MenuItems>}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default AccordionMenuCollapsable;
|
||||
@@ -0,0 +1,40 @@
|
||||
import React, { forwardRef } from "react";
|
||||
import { OverridableComponent } from "../util";
|
||||
import cl from "classnames";
|
||||
|
||||
export type AccordionMenuItemType = OverridableComponent<AccordionMenuItemProps>;
|
||||
|
||||
export interface AccordionMenuItemProps {
|
||||
props: {
|
||||
children: React.ReactNode;
|
||||
active?: boolean;
|
||||
} & React.HTMLAttributes<HTMLAnchorElement>;
|
||||
defaultComponent: "a";
|
||||
}
|
||||
|
||||
const AccordionMenuItem: AccordionMenuItemType = forwardRef(
|
||||
(
|
||||
{
|
||||
children,
|
||||
component: Component = "a",
|
||||
active = false,
|
||||
className,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<Component
|
||||
ref={ref}
|
||||
className={cl("navds-accordion-menu-item", className, {
|
||||
"navds-accordion-menu-item--active": active,
|
||||
})}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default AccordionMenuItem;
|
||||
@@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
const MenuItems = ({ children }) => (
|
||||
<ul className="navds-accordion-menu__list">
|
||||
{React.Children.toArray(children).map((child, i) => (
|
||||
<li key={i} className="navds-accordion-menu__list-item">
|
||||
{child}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
|
||||
export default MenuItems;
|
||||
@@ -0,0 +1,6 @@
|
||||
export { default as AccordionMenu } from "./AccordionMenu";
|
||||
export { default as AccordionMenuCollapsable } from "./AccordionMenuCollapsable";
|
||||
export {
|
||||
default as AccordionMenuItem,
|
||||
AccordionMenuItemType,
|
||||
} from "./AccordionMenuItem";
|
||||
@@ -0,0 +1,160 @@
|
||||
import * as React from "react";
|
||||
import {
|
||||
AccordionMenu,
|
||||
AccordionMenuItem as Item,
|
||||
AccordionMenuCollapsable as Collapsable,
|
||||
} from "../index";
|
||||
import { NavLink, HashRouter as Router } from "react-router-dom";
|
||||
|
||||
export default {
|
||||
title: "ds-react/accordion-menu",
|
||||
component: { AccordionMenu },
|
||||
parameters: {
|
||||
backgrounds: {
|
||||
default: "light",
|
||||
values: [
|
||||
{
|
||||
name: "light",
|
||||
value: "#F1F1F1",
|
||||
},
|
||||
{
|
||||
name: "white",
|
||||
value: "#fff",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const All = () => (
|
||||
<div
|
||||
style={{
|
||||
background: "white",
|
||||
maxWidth: 288,
|
||||
}}
|
||||
>
|
||||
<AccordionMenu>
|
||||
<Item href="#leo">Leo</Item>
|
||||
<Collapsable title="Proin">
|
||||
<Item href="#nulla" active>
|
||||
Nulla
|
||||
</Item>
|
||||
<Item href="#luctus">Luctus</Item>
|
||||
</Collapsable>
|
||||
<Collapsable title="Accumsan">
|
||||
<Item href="#justo" ariaCurrent="page">
|
||||
Justo
|
||||
</Item>
|
||||
<Item href="#pariatur" active ariaCurrent="page">
|
||||
Pariatur
|
||||
</Item>
|
||||
<Collapsable title="Proin">
|
||||
<Item href="#nulla" active>
|
||||
Nulla
|
||||
</Item>
|
||||
<Item href="#luctus">Luctus</Item>
|
||||
</Collapsable>
|
||||
</Collapsable>
|
||||
<Item href="#justo" active>
|
||||
Justo
|
||||
</Item>
|
||||
<Item href="#pariatur">Pariatur</Item>
|
||||
</AccordionMenu>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const ReactRouter = () => (
|
||||
<AccordionMenu>
|
||||
<Collapsable title="Nivå 1 – 3 rems høy">
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/1"
|
||||
>
|
||||
Nivå 2 innrykk 2 rems
|
||||
</Item>
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/2"
|
||||
>
|
||||
Subtitle 3
|
||||
</Item>
|
||||
</Collapsable>
|
||||
<Collapsable title="Skjema og søknad">
|
||||
<Collapsable title="Satser">
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/3"
|
||||
>
|
||||
Nivå 3 – 3 rems innrykk Har du rett til dagpenger når du mottar annen
|
||||
økonomisk støtte fra NAV?
|
||||
</Item>
|
||||
</Collapsable>
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/4"
|
||||
>
|
||||
Subtitle 2
|
||||
</Item>
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/5"
|
||||
>
|
||||
Subtitle 3
|
||||
</Item>
|
||||
</Collapsable>
|
||||
<Collapsable title="Sakbehandlingstider">
|
||||
<Collapsable title="Subtitle 4 Lang tittel på andre nivå lorem ipsum">
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/6"
|
||||
>
|
||||
Subtitle 5
|
||||
</Item>
|
||||
</Collapsable>
|
||||
</Collapsable>
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/7"
|
||||
>
|
||||
Internasjonalt
|
||||
</Item>
|
||||
<Collapsable title="Meld fra om endringer lang tittel på første nivå">
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/8"
|
||||
>
|
||||
Subtitle 6
|
||||
</Item>
|
||||
</Collapsable>
|
||||
<Item
|
||||
component={NavLink}
|
||||
activeClassName="navds-accordion-menu-item--active"
|
||||
to="/9"
|
||||
>
|
||||
Nivå 1
|
||||
</Item>
|
||||
</AccordionMenu>
|
||||
);
|
||||
|
||||
ReactRouter.decorators = [
|
||||
(Story) => (
|
||||
<Router>
|
||||
<div
|
||||
style={{
|
||||
background: "white",
|
||||
maxWidth: 288,
|
||||
}}
|
||||
>
|
||||
<Story />
|
||||
</div>
|
||||
</Router>
|
||||
),
|
||||
];
|
||||
@@ -1,3 +1,13 @@
|
||||
export {
|
||||
AccordionAnchorMenu,
|
||||
AccordionAnchorMenuCollapsable,
|
||||
AccordionAnchorMenuItem,
|
||||
} from "./accordion-anchor-menu";
|
||||
export {
|
||||
AccordionMenu,
|
||||
AccordionMenuCollapsable,
|
||||
AccordionMenuItem,
|
||||
} from "./accordion-menu";
|
||||
export { Accordion, AccordionProps } from "./accordion/index";
|
||||
export { Alert, AlertProps } from "./alert/index";
|
||||
export { Button, ButtonProps } from "./button/index";
|
||||
@@ -14,7 +24,11 @@ export {
|
||||
InternalHeaderUser,
|
||||
InternalHeaderUserProps,
|
||||
} from "./internal-header/index";
|
||||
export { Layout, LayoutProps, SectionProps } from "./layout/index";
|
||||
export {
|
||||
ProductPageLayout,
|
||||
ProductPageLayoutProps,
|
||||
ProductPageLayoutSectionProps,
|
||||
} from "./layouts/index";
|
||||
export { Link, LinkProps } from "./link/index";
|
||||
export { Modal, ModalProps } from "./modal/index";
|
||||
export { Popover, PopoverProps } from "./popover/index";
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import cl from "classnames";
|
||||
import React, {
|
||||
Children,
|
||||
forwardRef,
|
||||
ForwardRefExoticComponent,
|
||||
HTMLAttributes,
|
||||
} from "react";
|
||||
import { default as Section, SectionProps } from "./Section";
|
||||
|
||||
export interface LayoutWithSubComponents
|
||||
extends ForwardRefExoticComponent<LayoutProps> {
|
||||
Section: ForwardRefExoticComponent<SectionProps>;
|
||||
}
|
||||
|
||||
export interface LayoutProps extends HTMLAttributes<HTMLElement> {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const Layout = forwardRef<HTMLDivElement, LayoutProps>(
|
||||
({ children, className, ...rest }, ref) => {
|
||||
const columns = Children.count(children);
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cl(
|
||||
"navds-layout__container",
|
||||
`navds-layout__container--${columns}-columns`,
|
||||
className
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
) as LayoutWithSubComponents;
|
||||
|
||||
Layout.Section = Section;
|
||||
export default Layout;
|
||||
@@ -1,3 +0,0 @@
|
||||
export { default as Layout } from "./Layout";
|
||||
export * from "./Layout";
|
||||
export * from "./Section";
|
||||
@@ -1,94 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { useEffect } from "react";
|
||||
import { ContentContainer } from "../../index";
|
||||
import { Layout } from "../index";
|
||||
import { Left } from "./components/sections/Left";
|
||||
import { Main } from "./components/sections/Main";
|
||||
import { Right } from "./components/sections/Right";
|
||||
import "./components/styles.css";
|
||||
|
||||
export default {
|
||||
title: "ds-react/layout/Article",
|
||||
component: { Layout },
|
||||
decorators: [
|
||||
(Story) => {
|
||||
useEffect(() => {
|
||||
document.getElementById("decorator-header").style.display = "block";
|
||||
document.getElementById("decorator-footer").style.display = "block";
|
||||
return () => {
|
||||
document.getElementById("decorator-header").style.display = "none";
|
||||
document.getElementById("decorator-footer").style.display = "none";
|
||||
};
|
||||
}, []);
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
backgrounds: {
|
||||
default: "NAV gray",
|
||||
values: [
|
||||
{
|
||||
name: "NAV gray",
|
||||
value: "#f1f1f1",
|
||||
},
|
||||
{
|
||||
name: "white",
|
||||
value: "#ffffff",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ThreeColumns = () => (
|
||||
<ContentContainer>
|
||||
<Layout>
|
||||
<Layout.Section left sticky>
|
||||
<Left />
|
||||
</Layout.Section>
|
||||
<Layout.Section>
|
||||
<Main />
|
||||
</Layout.Section>
|
||||
<Layout.Section right sticky>
|
||||
<Right />
|
||||
</Layout.Section>
|
||||
</Layout>
|
||||
</ContentContainer>
|
||||
);
|
||||
|
||||
export const TwoColumnsLeft = () => (
|
||||
<ContentContainer>
|
||||
<Layout>
|
||||
<Layout.Section left sticky>
|
||||
<Left />
|
||||
</Layout.Section>
|
||||
<Layout.Section>
|
||||
<Main />
|
||||
</Layout.Section>
|
||||
</Layout>
|
||||
</ContentContainer>
|
||||
);
|
||||
|
||||
export const TwoColumnsRight = () => (
|
||||
<ContentContainer>
|
||||
<Layout>
|
||||
<Layout.Section>
|
||||
<Main />
|
||||
</Layout.Section>
|
||||
<Layout.Section right sticky>
|
||||
<Right />
|
||||
</Layout.Section>
|
||||
</Layout>
|
||||
</ContentContainer>
|
||||
);
|
||||
|
||||
export const OneColumn = () => (
|
||||
<ContentContainer>
|
||||
<Layout>
|
||||
<Layout.Section>
|
||||
<Main />
|
||||
</Layout.Section>
|
||||
</Layout>
|
||||
</ContentContainer>
|
||||
);
|
||||
@@ -1,108 +0,0 @@
|
||||
import * as React from "react";
|
||||
import {
|
||||
Button,
|
||||
Cell,
|
||||
Grid,
|
||||
Heading,
|
||||
Link,
|
||||
Paragraph,
|
||||
Alert,
|
||||
} from "../../../../index";
|
||||
|
||||
export const Main = () => (
|
||||
<div>
|
||||
<Heading className={"navds-story-section"} level={1} size={"xl"}>
|
||||
Quis autem
|
||||
</Heading>
|
||||
<Paragraph className={"section"}>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
|
||||
doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo
|
||||
inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
|
||||
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut
|
||||
fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem
|
||||
sequi nesciunt.
|
||||
</Paragraph>
|
||||
<Grid className={"section"}>
|
||||
<Cell xs={6}>
|
||||
<Link href={"#"}>Ea voluptate</Link>
|
||||
</Cell>
|
||||
<Cell xs={6}>
|
||||
<Link href={"#"}>Quis autem</Link>
|
||||
</Cell>
|
||||
</Grid>
|
||||
<Paragraph className={"section"}>
|
||||
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet,
|
||||
consectetur, adipisci velit, sed quia non numquam eius modi tempora
|
||||
incidunt ut labore et dolore magnam aliquam quaerat voluptatem.{" "}
|
||||
</Paragraph>
|
||||
<Alert variant="info" className={"section"}>
|
||||
Suspendisse potenti. Interdum et malesuada fames ac ante ipsum primis in
|
||||
faucibus.
|
||||
</Alert>
|
||||
<Paragraph className={"section"}>
|
||||
Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis
|
||||
suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem
|
||||
vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil
|
||||
molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla
|
||||
pariatur?
|
||||
</Paragraph>
|
||||
<Heading className={"section"} level={2} size={"xl"}>
|
||||
Nulla pariatur?
|
||||
</Heading>
|
||||
<Paragraph className={"section"}>
|
||||
Etiam viverra neque sit amet libero dapibus tincidunt. Pellentesque quis
|
||||
imperdiet erat. Morbi sodales bibendum volutpat. Sed malesuada risus
|
||||
lorem, in elementum purus commodo eget. Mauris maximus congue efficitur.
|
||||
Cras vestibulum id metus sed pellentesque.
|
||||
</Paragraph>
|
||||
|
||||
<table className={"section tabell tabell--stripet"}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Fornavn</th>
|
||||
<th>Etternavn</th>
|
||||
<th>Rolle</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>Jean-Luc</td>
|
||||
<td>Picard</td>
|
||||
<td>Kaptein</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>William</td>
|
||||
<td>Riker</td>
|
||||
<td>Kommandør</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>Geordi</td>
|
||||
<td>La Forge</td>
|
||||
<td>Sjefsingeniør</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<Paragraph className={"section"}>
|
||||
Curabitur a purus pretium, condimentum magna ac, pellentesque diam. Nulla
|
||||
facilisi. Nullam consequat, dui sed bibendum faucibus, metus mauris
|
||||
commodo tortor, eget mollis nunc augue eu elit. Ut nec fringilla odio, eu
|
||||
scelerisque tellus.
|
||||
</Paragraph>
|
||||
<Paragraph className={"section"}>
|
||||
Proin nec luctus justo. Pellentesque et dapibus libero. Phasellus non elit
|
||||
eget justo mattis venenatis. In hac habitasse platea dictumst. Proin nunc
|
||||
ipsum, ornare eu pretium in, aliquet non velit. Nullam efficitur tincidunt
|
||||
leo, vel tempus nibh consectetur sed. Etiam porttitor finibus erat varius
|
||||
rhoncus. Sed ac augue imperdiet, porta tellus vitae, aliquam est.
|
||||
</Paragraph>
|
||||
<Paragraph className={"section"}>
|
||||
Nunc eget consectetur felis, id scelerisque sapien. Ut id feugiat nulla,
|
||||
ut cursus sem. In viverra felis vitae aliquet finibus.
|
||||
</Paragraph>
|
||||
<Button>Søk ...</Button>
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,3 @@
|
||||
export { default as ProductPageLayout } from "./product-page/Layout";
|
||||
export { LayoutProps as ProductPageLayoutProps } from "./product-page/Layout";
|
||||
export { SectionProps as ProductPageLayoutSectionProps } from "./product-page/Section";
|
||||
@@ -0,0 +1,69 @@
|
||||
import React, { useEffect, Children, forwardRef } from "react";
|
||||
import { ForwardRefExoticComponent, HTMLAttributes } from "react";
|
||||
import { default as Section, SectionProps } from "./Section";
|
||||
import { default as Panel, PanelProps } from "./Panel";
|
||||
import { ContentContainer, Heading, OverridableComponent } from "../../";
|
||||
import cl from "classnames";
|
||||
|
||||
export interface LayoutWithSubComponents
|
||||
extends ForwardRefExoticComponent<LayoutProps> {
|
||||
Section: ForwardRefExoticComponent<SectionProps>;
|
||||
Panel: OverridableComponent<PanelProps>;
|
||||
}
|
||||
|
||||
export interface LayoutProps extends HTMLAttributes<HTMLElement> {
|
||||
title: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const Layout = forwardRef<HTMLDivElement, LayoutProps>(
|
||||
({ children, title, className, ...rest }, ref) => {
|
||||
const columns = Children.toArray(children).length;
|
||||
const classNames = cl(
|
||||
"navds-layout__container",
|
||||
`navds-layout__container--${columns}-columns`,
|
||||
className
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const layoutBody = document.getElementById("navds-layout-body");
|
||||
layoutBody?.classList.add(`navds-layout__body--${columns}-columns`);
|
||||
document.body.classList.add("navds-layout__body--white");
|
||||
return () => {
|
||||
layoutBody?.classList.remove(`navds-layout__body--${columns}-columns`);
|
||||
document.body.classList.remove("navds-layout__body--white");
|
||||
};
|
||||
}, [columns]);
|
||||
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<div id={"navds-layout-header"} className={"navds-layout__header"}>
|
||||
<ContentContainer>
|
||||
<div className={classNames} {...rest}>
|
||||
<div className={cl("navds-layout__header-content")}>
|
||||
<Heading
|
||||
size={"xxl"}
|
||||
className={cl("navds-layout__header-title")}
|
||||
level={1}
|
||||
>
|
||||
{title}
|
||||
</Heading>
|
||||
</div>
|
||||
</div>
|
||||
</ContentContainer>
|
||||
</div>
|
||||
<div id={"navds-layout-body"} className={"navds-layout__body"}>
|
||||
<ContentContainer>
|
||||
<div className={classNames} {...rest}>
|
||||
{children}
|
||||
</div>
|
||||
</ContentContainer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
) as LayoutWithSubComponents;
|
||||
|
||||
Layout.Section = Section;
|
||||
Layout.Panel = Panel;
|
||||
export default Layout;
|
||||
@@ -0,0 +1,101 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { forwardRef, ReactNode } from "react";
|
||||
import cl from "classnames";
|
||||
import { Button, Heading, Popover } from "../../";
|
||||
import { Attachment } from "@navikt/ds-icons";
|
||||
import { OverridableComponent } from "../../util";
|
||||
|
||||
export interface PanelProps {
|
||||
props: {
|
||||
title: string;
|
||||
icon?: ReactNode;
|
||||
highlight?: boolean;
|
||||
anchor?: string;
|
||||
whiteBackground?: boolean;
|
||||
withPadding?: boolean;
|
||||
} & React.HTMLAttributes<HTMLDivElement>;
|
||||
defaultComponent: "div";
|
||||
}
|
||||
|
||||
const Panel: OverridableComponent<PanelProps> = forwardRef(
|
||||
(
|
||||
{
|
||||
title,
|
||||
highlight,
|
||||
icon,
|
||||
anchor,
|
||||
component: Component = "div",
|
||||
className,
|
||||
children,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
||||
const [copied, setIsCopied] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
const header = document.getElementById("navds-layout-body");
|
||||
header?.classList.add("navds-layout__body--padding");
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Component
|
||||
ref={ref}
|
||||
id={anchor}
|
||||
className={cl(
|
||||
"navds-layout__panel",
|
||||
icon && "navds-layout__panel--icon-margin",
|
||||
highlight && "navds-layout__panel--highlight",
|
||||
className
|
||||
)}
|
||||
{...rest}
|
||||
>
|
||||
{icon && <div className={"navds-layout__panel-icon"}>{icon}</div>}
|
||||
<Heading size={"xl"} className={"navds-layout__panel-title"} level={2}>
|
||||
{title}
|
||||
</Heading>
|
||||
{anchor && (
|
||||
<div className={"navds-layout__panel-copy"}>
|
||||
<Button
|
||||
ref={(el) => setAnchorEl(el)}
|
||||
variant={"secondary"}
|
||||
className={"navds-layout__panel-copy-button"}
|
||||
onClick={() => {
|
||||
setIsCopied(true);
|
||||
const { href, hash } = window.location;
|
||||
const urlWithoutHash = href.replace(hash, "");
|
||||
copyToClipboard(`${urlWithoutHash}#${anchor}`);
|
||||
setTimeout(() => {
|
||||
setIsCopied(false);
|
||||
}, 1000);
|
||||
}}
|
||||
>
|
||||
<Attachment className={"navds-layout__panel-copy-icon"} />
|
||||
<span>Kopier lenke</span>
|
||||
</Button>
|
||||
<Popover anchorEl={anchorEl} open={copied} onClose={() => {}}>
|
||||
<div className="navds-layout__panel-popover-content">Kopiert</div>
|
||||
</Popover>
|
||||
</div>
|
||||
)}
|
||||
<div className={"navds-layout__panel-content"}>{children}</div>
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const copyToClipboard = (text: string) => {
|
||||
const textArea = document.createElement("textarea");
|
||||
textArea.value = text;
|
||||
textArea.style.top = "0";
|
||||
textArea.style.left = "0";
|
||||
textArea.style.position = "fixed";
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(textArea);
|
||||
};
|
||||
|
||||
export default Panel;
|
||||
File renamed without changes.
+4
-4
@@ -4,16 +4,16 @@ import { Button, Link } from "../../../../index";
|
||||
export const Left = () => (
|
||||
<ul className={"navds-story-menu"}>
|
||||
<li>
|
||||
<Link href={"#"}>Iusto odio dignissimos</Link>
|
||||
<Link href={"#leo-quis"}>Leo quis</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={"#"}>Nam libero tempore</Link>
|
||||
<Link href={"#proin-accumsan"}>Proin accumsan</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={"#"}>Reiciendis voluptatibus</Link>
|
||||
<Link href={"#nulla-pariatur"}>Nulla pariatur?</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href={"#"}>Earum rerum</Link>
|
||||
<Link href={"#maecenas-in-pretium"}>Maecenas in pretium</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Button>Søk ...</Button>
|
||||
@@ -0,0 +1,145 @@
|
||||
import * as React from "react";
|
||||
import {
|
||||
Button,
|
||||
Cell,
|
||||
Grid,
|
||||
Heading,
|
||||
Link,
|
||||
Paragraph,
|
||||
} from "../../../../index";
|
||||
import Snakkeboble from "nav-frontend-snakkeboble";
|
||||
|
||||
export const Main = ({ title = true }) => (
|
||||
<>
|
||||
<MainOne title={title} />
|
||||
<MainTwo title={title} />
|
||||
<MainThree title={title} />
|
||||
</>
|
||||
);
|
||||
|
||||
export const MainOne = ({ title = true }) => (
|
||||
<div>
|
||||
{title && (
|
||||
<Heading level={1} size={"xl"} id={"leo-quis"}>
|
||||
Leo quis
|
||||
</Heading>
|
||||
)}
|
||||
<Paragraph>
|
||||
Sed ullamcorper quam eget lorem volutpat, quis cursus risus fermentum.
|
||||
Quisque varius ornare nulla, ut condimentum sapien dapibus non. Nullam
|
||||
eget interdum nibh
|
||||
</Paragraph>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const MainTwo = ({ title = true }) => (
|
||||
<div>
|
||||
{title && (
|
||||
<Heading level={1} size={"xl"} id={"proin-accumsan"}>
|
||||
Proin accumsan
|
||||
</Heading>
|
||||
)}
|
||||
<Paragraph className={"section"}>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
|
||||
doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo
|
||||
inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
|
||||
</Paragraph>
|
||||
<Grid className={"section"}>
|
||||
<Cell xs={6}>
|
||||
<Link href={"#"}>Ea voluptate</Link>
|
||||
</Cell>
|
||||
<Cell xs={6}>
|
||||
<Link href={"#"}>Quis autem</Link>
|
||||
</Cell>
|
||||
</Grid>
|
||||
<Paragraph className={"section"}>
|
||||
Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet,
|
||||
consectetur, adipisci velit, sed quia non numquam eius modi tempora.
|
||||
</Paragraph>
|
||||
<Heading level={2} size={"large"} id={"nulla-pariatur"}>
|
||||
Nulla pariatur?
|
||||
</Heading>
|
||||
<Paragraph className={"section"}>
|
||||
Etiam viverra neque sit amet libero dapibus tincidunt. Pellentesque quis
|
||||
imperdiet erat. Morbi sodales bibendum volutpat.
|
||||
</Paragraph>
|
||||
<table className={"section tabell tabell--stripet"}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Fornavn</th>
|
||||
<th>Etternavn</th>
|
||||
<th>Rolle</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>Jean-Luc</td>
|
||||
<td>Picard</td>
|
||||
<td>Kaptein</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td>William</td>
|
||||
<td>Riker</td>
|
||||
<td>Kommandør</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>Geordi</td>
|
||||
<td>La Forge</td>
|
||||
<td>Sjefsingeniør</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<Paragraph className={"section"}>
|
||||
Curabitur a purus pretium, condimentum magna ac, pellentesque diam. Nulla
|
||||
facilisi. Nullam consequat, dui sed bibendum faucibus, metus mauris
|
||||
commodo tortor.
|
||||
</Paragraph>
|
||||
<Heading level={2} size={"large"} id={"luctus-justo"}>
|
||||
Luctus justo
|
||||
</Heading>
|
||||
<Paragraph className={"section"}>
|
||||
Nunc eget consectetur felis, id scelerisque sapien. Ut id feugiat nulla,
|
||||
ut cursus sem. In viverra felis vitae aliquet finibus.
|
||||
</Paragraph>
|
||||
<Button>Søk ...</Button>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const MainThree = ({ title = true }) => (
|
||||
<div>
|
||||
{title && (
|
||||
<Heading level={1} size={"xl"} id={"maecenas-in-pretium"}>
|
||||
Maecenas in pretium
|
||||
</Heading>
|
||||
)}
|
||||
<Paragraph>
|
||||
Sed ullamcorper quam eget lorem volutpat, quis cursus risus fermentum.
|
||||
Quisque varius ornare nulla, ut condimentum sapien dapibus non. Nullam
|
||||
eget interdum nibh
|
||||
</Paragraph>
|
||||
<Snakkeboble>Integer aliquam feugiat purus et imperdie</Snakkeboble>
|
||||
<Paragraph>
|
||||
Cras tempor eros sed dapibus egestas. Curabitur bibendum quam quis lectus
|
||||
pretium lacinia. Nunc consequat ac augue quis laoreet. Donec porta, erat
|
||||
vitae blandit egestas, arcu metus pharetra nulla, et laoreet risus purus
|
||||
convallis turpis.
|
||||
</Paragraph>
|
||||
<Snakkeboble pilHoyre={true}>
|
||||
Integer aliquam feugiat purus et imperdie
|
||||
</Snakkeboble>
|
||||
<Paragraph>
|
||||
Suspendisse potenti. Praesent at elit interdum, porttitor sem eget,
|
||||
blandit dolor. Nunc eget consectetur felis, id scelerisque sapien. Ut id
|
||||
feugiat nulla, ut cursus sem. In viverra felis vitae aliquet finibus.
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
Vivamus id mi lectus. Duis ac augue magna. Aliquam ut euismod dui. Duis
|
||||
consectetur, magna a malesuada tempus, elit urna fermentum arcu, at
|
||||
porttitor magna sapien id enim.
|
||||
</Paragraph>
|
||||
</div>
|
||||
);
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,102 @@
|
||||
import * as React from "react";
|
||||
import { useEffect } from "react";
|
||||
import { ProductPageLayout } from "../../index";
|
||||
import { Left } from "./components/sections/Left";
|
||||
import { Main, MainOne, MainTwo, MainThree } from "./components/sections/Main";
|
||||
import { Right } from "./components/sections/Right";
|
||||
import { LightBulb, Telephone } from "@navikt/ds-icons";
|
||||
import "./components/styles.css";
|
||||
|
||||
export default {
|
||||
title: "ds-react/layouts/ProductPage",
|
||||
component: ProductPageLayout,
|
||||
decorators: [
|
||||
(Story) => {
|
||||
useEffect(() => {
|
||||
document.getElementById("decorator-header").style.display = "block";
|
||||
document.getElementById("decorator-footer").style.display = "block";
|
||||
return () => {
|
||||
document.getElementById("decorator-header").style.display = "none";
|
||||
document.getElementById("decorator-footer").style.display = "none";
|
||||
};
|
||||
}, []);
|
||||
return <Story />;
|
||||
},
|
||||
],
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
},
|
||||
};
|
||||
|
||||
const title = "Nunc et lorem";
|
||||
export const ThreeColumns = () => (
|
||||
<ProductPageLayout title={title}>
|
||||
<ProductPageLayout.Section left sticky>
|
||||
<Left />
|
||||
</ProductPageLayout.Section>
|
||||
<ProductPageLayout.Section whiteBackground={false} withPadding={false}>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Leo quis"}
|
||||
anchor={"leo-quis"}
|
||||
highlight={true}
|
||||
icon={<LightBulb />}
|
||||
>
|
||||
<MainOne title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Proin accumsan"}
|
||||
anchor={"proin-accumsan"}
|
||||
>
|
||||
<MainTwo title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Maecenas in pretium"}
|
||||
anchor={"maecenas-in-pretium"}
|
||||
icon={<Telephone />}
|
||||
>
|
||||
<MainThree title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
</ProductPageLayout.Section>
|
||||
<ProductPageLayout.Section right sticky>
|
||||
<Right />
|
||||
</ProductPageLayout.Section>
|
||||
</ProductPageLayout>
|
||||
);
|
||||
|
||||
export const TwoColumnsLeft = () => (
|
||||
<ProductPageLayout title={title}>
|
||||
<ProductPageLayout.Section left sticky>
|
||||
<Left />
|
||||
</ProductPageLayout.Section>
|
||||
<ProductPageLayout.Section>
|
||||
<ProductPageLayout.Panel
|
||||
title={"Leo quis"}
|
||||
anchor={"leo-quis"}
|
||||
highlight={true}
|
||||
icon={<LightBulb />}
|
||||
>
|
||||
<MainOne title={false} />
|
||||
</ProductPageLayout.Panel>
|
||||
<Main />
|
||||
</ProductPageLayout.Section>
|
||||
</ProductPageLayout>
|
||||
);
|
||||
|
||||
export const TwoColumnsRight = () => (
|
||||
<ProductPageLayout title={title}>
|
||||
<ProductPageLayout.Section>
|
||||
<Main />
|
||||
</ProductPageLayout.Section>
|
||||
<ProductPageLayout.Section right sticky>
|
||||
<Right />
|
||||
</ProductPageLayout.Section>
|
||||
</ProductPageLayout>
|
||||
);
|
||||
|
||||
export const OneColumn = () => (
|
||||
<ProductPageLayout title={title}>
|
||||
<ProductPageLayout.Section>
|
||||
<Main />
|
||||
</ProductPageLayout.Section>
|
||||
</ProductPageLayout>
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "0.2.3",
|
||||
"version": "0.2.6",
|
||||
"private": false,
|
||||
"description": "NAV designsystem react components",
|
||||
"author": "NAV Designsystem team",
|
||||
@@ -28,11 +28,12 @@
|
||||
],
|
||||
"scripts": {
|
||||
"cjs-package": "copyfiles -f config/package.json cjs",
|
||||
"build": "tsc -p tsconfig.json && tsc -p tsconfig-esm.json && yarn cjs-package",
|
||||
"clean": "rm -rf cjs esm",
|
||||
"build": "yarn run clean && tsc && tsc -p tsconfig-esm.json && yarn cjs-package",
|
||||
"watch": "tsc --watch -p tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@navikt/ds-icons": "^0.2.0",
|
||||
"@navikt/ds-icons": "^0.2.1",
|
||||
"@popperjs/core": "^2.5.4",
|
||||
"classnames": "^2.2.6",
|
||||
"react-collapse": "^5.1.0",
|
||||
|
||||
@@ -36,11 +36,6 @@ export interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
||||
* @default "right"
|
||||
*/
|
||||
placement?: Placement;
|
||||
/**
|
||||
* Small reduces padding on popover content
|
||||
* @default "medium"
|
||||
*/
|
||||
size?: "medium" | "small";
|
||||
}
|
||||
|
||||
const useEventLister = (event: string, callback) =>
|
||||
@@ -60,7 +55,6 @@ const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
children,
|
||||
placement = "right",
|
||||
className,
|
||||
size = "medium",
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
@@ -138,7 +132,7 @@ const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
return (
|
||||
<div
|
||||
ref={mergedRef}
|
||||
className={cl("navds-popover", `navds-popover--${size}`, className, {
|
||||
className={cl("navds-popover", className, {
|
||||
"navds-popover--hidden": !open || !anchorEl,
|
||||
})}
|
||||
aria-live="polite"
|
||||
|
||||
@@ -27,7 +27,7 @@ const Template = (props) => {
|
||||
{props.placement}
|
||||
</div>
|
||||
<Popover {...props} anchorEl={anchorEl} onClose={() => {}} open>
|
||||
Contents
|
||||
<div style={{ margin: "1rem" }}>Contents</div>
|
||||
</Popover>
|
||||
</>
|
||||
);
|
||||
@@ -56,27 +56,3 @@ export const All = () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Small = () => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexWrap: "wrap",
|
||||
margin: "4rem 8rem 4rem 8rem",
|
||||
}}
|
||||
>
|
||||
{placements.map((placement) => (
|
||||
<div
|
||||
style={{
|
||||
width: "20%",
|
||||
height: "100px",
|
||||
margin: "4rem",
|
||||
}}
|
||||
>
|
||||
<Template placement={placement} size="small" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tokens",
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.2",
|
||||
"private": false,
|
||||
"description": "Auto-generated design-tokens for NAV design-systems framework",
|
||||
"author": "NAV Designsystem team",
|
||||
|
||||
@@ -25,8 +25,12 @@ module.exports = {
|
||||
white: { value: white },
|
||||
darkgray: { value: darkgray },
|
||||
gray: {
|
||||
40: { value: "#b7b1a9" },
|
||||
60: { value: "#78706a" },
|
||||
90: { value: "#262626" },
|
||||
80: { value: "#4F4F4F" },
|
||||
60: { value: "#6A6A6A" },
|
||||
40: { value: "#A0A0A0" },
|
||||
20: { value: "#C9C9C9" },
|
||||
10: { value: "#F1F1F1" },
|
||||
},
|
||||
...Object.entries(baseColors).reduce(
|
||||
(colors, [name, color]) => ({
|
||||
@@ -170,6 +174,10 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
layout: {
|
||||
background: {
|
||||
white: { value: "#FFFFFF" },
|
||||
gray: { value: "#F1F1F1" },
|
||||
},
|
||||
padding: {
|
||||
small: { value: "1rem" },
|
||||
mediumAndLarger: { value: "2.5rem" },
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Heading, Paragraph } from "@navikt/ds-react";
|
||||
import Bash from "./code/Bash";
|
||||
import Import from "./code/Import";
|
||||
import Preview from "./code-preview/Preview";
|
||||
import Npm from "./npm/Npm";
|
||||
import TableOfContents from "./table-of-contents/TableOfContents";
|
||||
|
||||
export default {
|
||||
h1: (props) => <Heading size="xxl" level={1} {...props} />,
|
||||
h2: (props) => <Heading size="large" level={2} {...props} />,
|
||||
h3: (props) => <Heading size="small" level={3} {...props} />,
|
||||
p: (props) => <Paragraph size="medium" {...props} />,
|
||||
Bash,
|
||||
Preview,
|
||||
Import,
|
||||
Npm,
|
||||
TableOfContents,
|
||||
};
|
||||
@@ -97,7 +97,6 @@ const Bash = ({
|
||||
>
|
||||
Kode er kopiert
|
||||
</Popover>
|
||||
)
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import Header from "./header/Header";
|
||||
import Sidebar from "./sidebar/Sidebar";
|
||||
import Mdx from "./MdxProvider";
|
||||
import Toc from "../toc/Toc";
|
||||
import { Grid, Cell, ContentContainer } from "@navikt/ds-react";
|
||||
import { useMediaQuery } from "react-responsive";
|
||||
import useKeypress from "react-use-keypress";
|
||||
@@ -10,9 +8,10 @@ import style from "./layout.module.css";
|
||||
|
||||
interface LayoutProps {
|
||||
children?: React.ReactNode;
|
||||
menu: any[];
|
||||
}
|
||||
|
||||
const Layout = ({ children }: LayoutProps) => {
|
||||
const Layout = ({ children, menu }: LayoutProps) => {
|
||||
const [sidebar, setSidebar] = useState(false);
|
||||
|
||||
const small = useMediaQuery({
|
||||
@@ -31,19 +30,17 @@ const Layout = ({ children }: LayoutProps) => {
|
||||
<div className={style.pageWrapper + " lightTheme"}>
|
||||
<Header sidebar={sidebar} onSidebarChange={(x) => setSidebar(x)} />
|
||||
<Sidebar
|
||||
menu={menu}
|
||||
sidebar={sidebar}
|
||||
small={small}
|
||||
onSidebarChange={(x) => setSidebar(x)}
|
||||
/>
|
||||
{/* TEMP UNTIL LAYOUT UPDATE */}
|
||||
<main className={style.contentWrapper}>
|
||||
<ContentContainer>
|
||||
<Grid>
|
||||
<Cell className={style.content} xs={12} sm={12} md={10} lg={7}>
|
||||
<Mdx>{children}</Mdx>
|
||||
</Cell>
|
||||
<Cell xs={12} sm={1} md={2} lg={1} />
|
||||
<Cell xs={12} sm={12} md={8} lg={4}>
|
||||
<Toc />
|
||||
<Cell className={style.content} xs={12} sm={12} md={12} lg={12}>
|
||||
{children}
|
||||
</Cell>
|
||||
</Grid>
|
||||
</ContentContainer>
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { MDXProvider } from "@mdx-js/react";
|
||||
import { Heading, Paragraph } from "@navikt/ds-react";
|
||||
import Bash from "../code/Bash";
|
||||
import Import from "../code/Import";
|
||||
import Preview from "../code-preview/Preview";
|
||||
import Npm from "../npm/Npm";
|
||||
/* import { Button } from "@navikt/ds-react"; */
|
||||
|
||||
const MdxWrapper = (props) => (
|
||||
<MDXProvider
|
||||
components={{
|
||||
h1: (props) => <Heading size="xxl" level={1} {...props} />,
|
||||
h2: (props) => <Heading size="large" level={2} {...props} />,
|
||||
h3: (props) => <Heading size="small" level={3} {...props} />,
|
||||
p: (props) => <Paragraph size="medium" {...props} />,
|
||||
Bash,
|
||||
Preview,
|
||||
Import,
|
||||
Npm,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export default MdxWrapper;
|
||||
@@ -91,6 +91,9 @@
|
||||
overflow: visible;
|
||||
margin: 0 auto 0 0;
|
||||
width: 100%;
|
||||
|
||||
/* TMP UNTIL LAYOUT UPDATE */
|
||||
max-width: 520px;
|
||||
}
|
||||
|
||||
.content {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
AccordionMenu,
|
||||
AccordionMenuCollapsable,
|
||||
AccordionMenuItem,
|
||||
} from "@navikt/ds-react";
|
||||
|
||||
const MenuLink = (node) => {
|
||||
const { asPath } = useRouter();
|
||||
|
||||
return (
|
||||
<Link href={node.pathName} passHref>
|
||||
<AccordionMenuItem active={asPath === node.pathName}>
|
||||
{node.title}
|
||||
</AccordionMenuItem>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
const mapToComponents = (node) =>
|
||||
node.children ? (
|
||||
<AccordionMenuCollapsable key={node.title} title={node.title}>
|
||||
{node.children.map(mapToComponents)}
|
||||
</AccordionMenuCollapsable>
|
||||
) : (
|
||||
<MenuLink key={node.title} {...node} />
|
||||
);
|
||||
|
||||
const Menu = ({ menu }) => (
|
||||
<AccordionMenu>{menu.map(mapToComponents)}</AccordionMenu>
|
||||
);
|
||||
|
||||
export default Menu;
|
||||
@@ -1,20 +1,21 @@
|
||||
import Link from "next/link";
|
||||
import cl from "classnames";
|
||||
import { Close } from "@navikt/ds-icons";
|
||||
import style from "../layout.module.css";
|
||||
import Menu from "./Menu";
|
||||
|
||||
interface SidebarProps {
|
||||
classname?: string;
|
||||
sidebar: boolean;
|
||||
small: boolean;
|
||||
onSidebarChange: (x: boolean) => void;
|
||||
menu: any[];
|
||||
}
|
||||
|
||||
const Sidebar = ({
|
||||
sidebar,
|
||||
small,
|
||||
onSidebarChange,
|
||||
...props
|
||||
menu = [],
|
||||
}: SidebarProps) => {
|
||||
return (
|
||||
<>
|
||||
@@ -40,9 +41,7 @@ const Sidebar = ({
|
||||
<Close />
|
||||
</button>
|
||||
)}
|
||||
<Link href="/">Home</Link>
|
||||
<Link href="/komponenter">Komponenter</Link>
|
||||
<Link href="/komponenter/button">Button</Link>
|
||||
<Menu menu={menu} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { useContext } from "react";
|
||||
import { Next } from "@navikt/ds-icons";
|
||||
import { Heading } from "@navikt/ds-react";
|
||||
import style from "./tableOfContents.module.css";
|
||||
import { PagePropsContext } from "../../pages/_app";
|
||||
|
||||
const TableOfContents = () => {
|
||||
const { tableOfContents } = useContext<any>(PagePropsContext);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading size="large" level={2}>
|
||||
Innhold
|
||||
</Heading>
|
||||
<ul className={style.ul}>
|
||||
{tableOfContents?.map(({ heading, slug }) => (
|
||||
<li key={slug} className={style.li}>
|
||||
<Next
|
||||
aria-label="Pil peker på lenke"
|
||||
focusable="false"
|
||||
role="img"
|
||||
aria-hidden
|
||||
/>
|
||||
<a href={`#${slug}`}>{heading}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableOfContents;
|
||||
@@ -0,0 +1,45 @@
|
||||
.ul {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
font-size: var(--navds-font-size-medium);
|
||||
line-height: var(--navds-font-line-height-medium);
|
||||
color: var(--navds-color-blue-50);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: margin 100ms linear;
|
||||
column-gap: 0.25rem;
|
||||
padding: 0.25rem 0;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.li > svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.li:hover {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.li > a {
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
.li:hover > a,
|
||||
.li:hover > svg {
|
||||
color: var(--navds-color-darkgray);
|
||||
transition: color 150ms linear;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.li > svg + a:focus {
|
||||
color: white;
|
||||
transition: color 0ms linear;
|
||||
background-color: var(--navds-color-blue-80);
|
||||
outline: none;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import style from "./toc.module.css";
|
||||
interface TocProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const Header = ({ className, ...props }: TocProps) => {
|
||||
return <nav className={style.toc}></nav>;
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -1,6 +0,0 @@
|
||||
.toc {
|
||||
background-color: var(--bg-secondary);
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
outline: var(--outline);
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
# Home
|
||||
---
|
||||
title: Button
|
||||
---
|
||||
|
||||
Hjemmeside
|
||||
# Button content
|
||||
|
||||
<Npm packName="@navikt/ds-react" imports="Button" />
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
title: Komponenter
|
||||
rank: 3
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Header
|
||||
---
|
||||
|
||||
# interne flater header
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
title: Interne flater
|
||||
---
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
title: Kom i gang
|
||||
rank: 1
|
||||
---
|
||||
|
||||
# Kom i gang content
|
||||
|
||||
<TableOfContents />
|
||||
|
||||
## Varianter
|
||||
|
||||
## Varianter
|
||||
|
||||
Deserunt nostrud anim nisi reprehenderit cillum commodo. Ullamco excepteur sit aute commodo duis. Elit magna laboris amet occaecat velit proident dolore nostrud. Qui ullamco tempor ex sunt veniam cillum et anim. Deserunt dolore voluptate dolor nulla commodo laboris ad. Sint excepteur eu velit consectetur nostrud non irure excepteur adipisicing.
|
||||
|
||||
## Størrelser
|
||||
|
||||
Non fugiat irure excepteur adipisicing nulla enim nisi. Ut dolore ullamco est commodo consectetur nisi pariatur labore incididunt. Aute ipsum magna nulla sunt labore do nulla laboris anim proident Lorem deserunt aute ea. Anim ea aute qui ullamco. Proident nostrud sunt sit minim excepteur esse. Lorem laboris ad dolore qui pariatur laborum sunt dolore laboris voluptate incididunt. Quis amet aliqua eu minim laboris id occaecat.
|
||||
|
||||
## Interne-flater
|
||||
|
||||
adad
|
||||
|
||||
## Tilgjengelighet
|
||||
|
||||
adasd
|
||||
|
||||
## Eksempler for bruk
|
||||
|
||||
Non fugiat irure excepteur adipisicing nulla enim nisi. Ut dolore ullamco est commodo consectetur nisi pariatur labore incididunt. Aute ipsum magna nulla sunt labore do nulla laboris anim proident Lorem deserunt aute ea. Anim ea aute qui ullamco. Proident nostrud sunt sit minim excepteur esse. Lorem laboris ad dolore qui pariatur laborum sunt dolore laboris voluptate incididunt. Quis amet aliqua eu minim laboris id occaecat.
|
||||
|
||||
## Prop-table
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
title: Retningslinjer
|
||||
rank: 2
|
||||
---
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: Typografi
|
||||
---
|
||||
|
||||
# Typografi content
|
||||
@@ -0,0 +1 @@
|
||||
# Hello, world
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
};
|
||||
+3
-10
@@ -1,10 +1,4 @@
|
||||
/* const withBundleAnalyzer = require("@next/bundle-analyzer")({
|
||||
enabled: process.env.ANALYZE === "true",
|
||||
}); */
|
||||
const glob = require("glob");
|
||||
const withMDX = require("@next/mdx")({
|
||||
extension: /\.mdx?$/,
|
||||
});
|
||||
|
||||
const loadPackage = () => {
|
||||
const navFrontend = glob.sync("../packages/**/package.json");
|
||||
@@ -17,9 +11,8 @@ const loadPackage = () => {
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = withMDX({
|
||||
pageExtensions: ["js", "jsx", "mdx"],
|
||||
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
|
||||
module.exports = {
|
||||
webpack: (config) => {
|
||||
config.module.rules.push({
|
||||
test: /\.svg$/,
|
||||
use: ["@svgr/webpack"],
|
||||
@@ -29,4 +22,4 @@ module.exports = withMDX({
|
||||
publicRuntimeConfig: {
|
||||
packages: loadPackage(),
|
||||
},
|
||||
});
|
||||
};
|
||||
+14
-7
@@ -5,7 +5,8 @@
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
"start": "next start",
|
||||
"test": "jest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/react": "^17.0.2",
|
||||
@@ -17,20 +18,26 @@
|
||||
"react-use-keypress": "^1.2.0",
|
||||
"classnames": "^2.2.6",
|
||||
"glob": "^7.1.6",
|
||||
"@next/mdx": "^10.0.8",
|
||||
"@mdx-js/loader": "^1.6.22",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
"remark-parse": "^9.0.0",
|
||||
"unified": "^9.2.1",
|
||||
"prismjs": "^1.23.0",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"@navikt/ds-css": "^0.2.0",
|
||||
"@navikt/ds-react": "^0.2.0"
|
||||
"@navikt/ds-css": "*",
|
||||
"@navikt/ds-react": "*",
|
||||
"next-mdx-remote": "^2.1.3",
|
||||
"github-slugger": "1.3.0",
|
||||
"remark-slug": "6.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^10.0.8",
|
||||
"@types/prettier": "^2.2.2",
|
||||
"@types/react-dom": "^17.0.2",
|
||||
"prettier": "2.2.1"
|
||||
"prettier": "2.2.1",
|
||||
"gray-matter": "^4.0.2",
|
||||
"jest": "^26.6.3",
|
||||
"ts-jest": "^26.5.4",
|
||||
"@types/jest": "^22.2.3"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"rules": {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import fs from "fs";
|
||||
import glob from "glob";
|
||||
import matter from "gray-matter";
|
||||
import hydrate from "next-mdx-remote/hydrate";
|
||||
import renderToString from "next-mdx-remote/render-to-string";
|
||||
import components from "../components/MDXComponents";
|
||||
import tableOfContents from "../src/table-of-contents";
|
||||
import mainMenu from "../src/main-menu";
|
||||
|
||||
const Page = ({ mdxSource }) => hydrate(mdxSource, { components });
|
||||
|
||||
export default Page;
|
||||
|
||||
export async function getStaticProps({ params: { path } }) {
|
||||
const { content } = matter(
|
||||
fs.readFileSync(`data/${path?.join("/") || "index"}.mdx`, "utf8")
|
||||
);
|
||||
|
||||
return {
|
||||
props: {
|
||||
mdxSource: await renderToString(content, {
|
||||
components,
|
||||
mdxOptions: {
|
||||
remarkPlugins: [require("remark-slug")],
|
||||
},
|
||||
}),
|
||||
menu: mainMenu(),
|
||||
tableOfContents: tableOfContents(content),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return {
|
||||
paths: [
|
||||
{ params: { path: [] } },
|
||||
...glob
|
||||
.sync("data/**/*.mdx")
|
||||
.filter((path) => !path.endsWith("index.mdx"))
|
||||
.map((path) => path.slice(5, -4).split("/"))
|
||||
.map((path) => ({ params: { path } })),
|
||||
],
|
||||
fallback: false,
|
||||
};
|
||||
}
|
||||
+6
-5
@@ -1,23 +1,24 @@
|
||||
import { createContext } from "react";
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import Layout from "../components/layout/Layout";
|
||||
import "../styles/theme.css";
|
||||
import "../styles/globals.css";
|
||||
import "../styles/prismjs.css";
|
||||
import "@navikt/ds-css";
|
||||
|
||||
export const PagePropsContext = createContext({});
|
||||
|
||||
const Website = ({ Component, pageProps }) => {
|
||||
const route = useRouter();
|
||||
return (
|
||||
<>
|
||||
<PagePropsContext.Provider value={pageProps}>
|
||||
<Head>
|
||||
<title>NAV Designsystem</title>
|
||||
<link rel="icon" href="/favicon-32x32.png" />
|
||||
</Head>
|
||||
<Layout route={route}>
|
||||
<Layout menu={pageProps.menu}>
|
||||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
</>
|
||||
</PagePropsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Getting-started
|
||||
|
||||
Kom i gang
|
||||
@@ -0,0 +1,45 @@
|
||||
import fs from "fs";
|
||||
import glob from "glob";
|
||||
import matter from "gray-matter";
|
||||
import pathsToTree from "../src/paths-to-tree";
|
||||
|
||||
export default () => {
|
||||
let tree = pathsToTree(
|
||||
glob.sync("data/**/*.mdx").filter((path) => !path.endsWith("index.mdx"))
|
||||
);
|
||||
|
||||
const populateNode = (node, parentPath) => {
|
||||
let metadata;
|
||||
if (node.name.endsWith(".mdx")) {
|
||||
metadata = matter(fs.readFileSync(`${parentPath}${node.name}`, "utf8"))
|
||||
.data;
|
||||
} else {
|
||||
const indexPath = `${parentPath}${node.name}/index.mdx`;
|
||||
if (fs.existsSync(indexPath)) {
|
||||
metadata = matter(fs.readFileSync(indexPath, "utf8")).data;
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata) {
|
||||
if (metadata.title) {
|
||||
node.title = metadata.title;
|
||||
}
|
||||
if (metadata.rank) {
|
||||
node.rank = metadata.rank;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.children) {
|
||||
node.children.forEach((child) =>
|
||||
populateNode(child, `${parentPath}${node.name}/`)
|
||||
);
|
||||
node.children.sort((a, b) => a.rank - b.rank);
|
||||
} else {
|
||||
node.pathName = `/${parentPath}${node.name}`.slice(5, -4);
|
||||
}
|
||||
};
|
||||
|
||||
tree.forEach((node) => populateNode(node, ""));
|
||||
|
||||
return tree[0].children;
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
export interface NavdsPage {
|
||||
pathName?: string;
|
||||
children?: NavdsPage[];
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const pages: NavdsPage[] = [
|
||||
{
|
||||
pathName: "/kom-i-gang",
|
||||
},
|
||||
{
|
||||
title: "Komponenter",
|
||||
children: [
|
||||
{ pathName: "/komponenter", title: "Kom i gang" },
|
||||
{ pathName: "/komponenter/alert" },
|
||||
{ pathName: "/komponenter/accordion" },
|
||||
{ pathName: "/komponenter/button" },
|
||||
{
|
||||
title: "Interne flater",
|
||||
children: [
|
||||
{ pathName: "/komponenter/interne-flater/header" },
|
||||
{ pathName: "/komponenter/interne-flater/copy-knapp" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Ikonpakke",
|
||||
children: [
|
||||
{ pathName: "/ikonpakke", title: "Ikonsøk" },
|
||||
{ pathName: "/ikonpakke/installering" },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Retningslinjer",
|
||||
children: [
|
||||
{ pathName: "/retningslinjer/farger" },
|
||||
{ pathName: "/retningslinjer/typografi" },
|
||||
{ pathName: "/retningslinjer/språk" },
|
||||
],
|
||||
},
|
||||
{
|
||||
pathName: "/kontakt",
|
||||
title: "Kontakt oss",
|
||||
},
|
||||
];
|
||||
|
||||
export default pages;
|
||||
@@ -0,0 +1,41 @@
|
||||
import pathsToTree from "./paths-to-tree";
|
||||
|
||||
test("empty list", () => {
|
||||
expect(pathsToTree([])).toEqual([]);
|
||||
});
|
||||
|
||||
test("single simple string", () => {
|
||||
expect(pathsToTree(["foo"])).toEqual([{ name: "foo" }]);
|
||||
});
|
||||
|
||||
test("two levels", () => {
|
||||
expect(pathsToTree(["foo/bar"])).toEqual([
|
||||
{
|
||||
name: "foo",
|
||||
children: [{ name: "bar" }],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test("two levels, two strings", () => {
|
||||
expect(pathsToTree(["foo", "foo/bar"])).toEqual([
|
||||
{
|
||||
name: "foo",
|
||||
children: [{ name: "bar" }],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test("three levels, three strings", () => {
|
||||
expect(pathsToTree(["foo", "foo/bar/baz", "foo/bar"])).toEqual([
|
||||
{
|
||||
name: "foo",
|
||||
children: [
|
||||
{
|
||||
name: "bar",
|
||||
children: [{ name: "baz" }],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
type Node = {
|
||||
name: string;
|
||||
children?: Node[];
|
||||
};
|
||||
|
||||
const pathsToTree: (paths: string[]) => Node[] = (paths: string[]) =>
|
||||
paths.reduce((list, path) => {
|
||||
path.split("/").reduce((list, name, i, a) => {
|
||||
let node = list.find((item) => item.name === name);
|
||||
if (!node) {
|
||||
node = { name };
|
||||
list.push(node);
|
||||
}
|
||||
if (!node.children && i !== a.length - 1) {
|
||||
node.children = [];
|
||||
}
|
||||
return node.children;
|
||||
}, list);
|
||||
return list;
|
||||
}, []);
|
||||
|
||||
export default pathsToTree;
|
||||
@@ -0,0 +1,18 @@
|
||||
import GithubSlugger from "github-slugger";
|
||||
import markdown from "remark-parse";
|
||||
import unified from "unified";
|
||||
|
||||
export default (content) => {
|
||||
const slugger = new GithubSlugger();
|
||||
|
||||
return unified()
|
||||
.use(markdown)
|
||||
.parse(content)
|
||||
.children.filter((node) => node.type === "heading")
|
||||
.filter((node) => node.depth === 2)
|
||||
.map((node) => node.children[0].value)
|
||||
.map((heading) => ({
|
||||
heading,
|
||||
slug: slugger.slug(heading),
|
||||
}));
|
||||
};
|
||||
@@ -3,6 +3,7 @@ body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: var(--bg-primary);
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
+7
-3
@@ -54,7 +54,10 @@
|
||||
]
|
||||
},
|
||||
"stylelint": {
|
||||
"extends": "stylelint-config-standard",
|
||||
"extends": [
|
||||
"stylelint-config-standard",
|
||||
"stylelint-config-prettier"
|
||||
],
|
||||
"rules": {
|
||||
"value-list-comma-newline-after": null,
|
||||
"declaration-colon-newline-after": null,
|
||||
@@ -135,15 +138,16 @@
|
||||
"less-loader": "^7.0.2",
|
||||
"mini-css-extract-plugin": "^1.3.0",
|
||||
"prettier": "2.2.1",
|
||||
"stylelint-config-prettier": "^8.0.2",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "^16.8.0 || ^17.0.0",
|
||||
"react-docgen-typescript": "^1.21.0",
|
||||
"react-is": "^16.13.1",
|
||||
"stylelint": "^13.7.2",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
"svg-url-loader": "^7.1.1",
|
||||
"typescript": "^3.7.3",
|
||||
"webpack": "^5.4.0",
|
||||
"webpack-cli": "^4.2.0",
|
||||
"react-docgen-typescript": "^1.21.0"
|
||||
"webpack-cli": "^4.2.0"
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ Legg til `import EkspanderbartPanel from 'nav-frontend-ekspanderbartpanel'`
|
||||
Bruker man `redux` har man mulighet til å lagre staten der, og kan (om man vil) bruke en `pure` versjon av panelet.
|
||||
Da må man selv alltid sende inn `apen`-propen.
|
||||
|
||||
Legg til `import { EkspanderbartpanelPure } from 'nav-frontend-ekspanderbartpanel'`
|
||||
Legg til `import { EkspanderbartpanelBase } from 'nav-frontend-ekspanderbartpanel'`
|
||||
|
||||
<!-- AUTO-GENERATED-CONTENT:START (DISCLAIMER) -->
|
||||
|
||||
|
||||
@@ -19,6 +19,11 @@ import Panel from "nav-frontend-paneler";
|
||||
vi bygger i NAV være universelt utformet slik at de aller fleste kan klare seg
|
||||
selv.
|
||||
</Ingress>
|
||||
<Ingress>
|
||||
Utdypende informasjon om hvordan håndtere universell utforming av IT i NAV
|
||||
finner du på{" "}
|
||||
<a href="https://navikt.github.io/uu/">https://navikt.github.io/uu/</a>
|
||||
</Ingress>
|
||||
|
||||
## Nødvendig for noen, bra for alle
|
||||
|
||||
@@ -144,7 +149,9 @@ Dette er noen av de viktigste tingene du bør huske på for å unngå de vanligs
|
||||
|
||||
### For designere
|
||||
|
||||
1. Bruk aktuell versjon av [NAVs komponent- og illustrasjonsbibliotek i Sketch](/resources/new-project#for-designere) når du designer.
|
||||
[Flere tips for produktdesignere](https://navikt.github.io/uu/hvordan-faa-det-til/tips-etter-rolle/Produktdesigner/) og [tjenestedesignere](https://navikt.github.io/uu/hvordan-faa-det-til/tips-etter-rolle/Tjenestedesigner/) finner du på uu-sidene.
|
||||
|
||||
1. Bruk aktuell versjon av [NAVs komponent- og illustrasjonsbibliotek](/resources/new-project#for-designere) når du designer.
|
||||
2. Design for grupper med spesielle behov («ytterkantene»). Spør deg selv: Hadde bestemoren min klart å bruke tjenesten? [Om inklusiv design (University of Cambridge)](http://www.inclusivedesigntoolkit.com/whatis/whatis.html)
|
||||
3. Husk [god kontrast](/resources/colors/accessibility#krav-til-kontrast), både på tekst, interaktive elementer, grafer og illustrasjoner.
|
||||
4. Husk [beskrivende alt-tekster](/accessibility/alt-text) på bilder, illustrasjoner og grafer.
|
||||
@@ -152,21 +159,23 @@ Dette er noen av de viktigste tingene du bør huske på for å unngå de vanligs
|
||||
6. Video: Husk å ha en tekstversjon som har samme innhold som videoen på siden, samt tekste video og bruk nyeste versjon av QBrick. Snart kommer en lovendring om at videoer også må være synstolket. Det betyr at man skal tilby en audiobeskrivelse av det som vises i videoen som ikke blir tydelig av selve lydsporet.
|
||||
7. Språk og begreper: Skriv så forståelig som mulig og test teksten på reelle brukere. Bruk beskrivende overskrifter, deloverskrifter og punktlister der det er hensiktsmessig. Husk å ha en hovedoverskrift som beskriver hovedinnholdet på siden. Les mer om [tekst og struktur (Difi)]([https://uu.difi.no/krav-og-regelverk/losningsforslag-web/tekst-og-struktur) og våre [retningslinjer for språk](https://design.nav.no/resources/language)
|
||||
8. Lenker: Skriv lenketekster slik at det er tydelig hvor lenken går. Ikke åpne lenker i ny fane/vindu. Se [retningslinjer for gode lenker](https://design.nav.no/components/lenke/accessibility).
|
||||
9. Lag gode og [beskrivende feilmeldinger (Difi)](https://uu.difi.no/krav-og-regelverk/losningsforslag-web/feilhandtering) og pass på at meldingene er i tråd med Designsystemet.
|
||||
10. Test med reelle brukere, også med personer som bruker hjelpemidler. Bruk Sanselaben i Sannergata (rom 5006).
|
||||
9. Lag gode og [beskrivende feilmeldinger (DigDir)](https://uu.difi.no/krav-og-regelverk/losningsforslag-web/feilhandtering) og pass på at meldingene er i tråd med Designsystemet.
|
||||
10. Test med reelle brukere, også med personer som bruker hjelpemidler. Bruk Sanselaben i Fyrstikkaleen.
|
||||
|
||||
### For utviklere
|
||||
|
||||
[Flere tips for utviklere(https://navikt.github.io/uu/hvordan-faa-det-til/tips-etter-rolle/Utvikler/) på uu-sidene.
|
||||
|
||||
1. Bruk [komponentene våre](/components).
|
||||
2. Sjekk at koderekkefølgen gjenspeiler den visuelle rekkefølgen.
|
||||
3. Test at alt kan betjenes med tastatur og at fokusmarkering flyttes i forventet rekkefølge.
|
||||
4. Bruk de [semantiske egenskapene i HTML (MDN)](https://developer.mozilla.org/en-US/docs/Glossary/Semantics).
|
||||
5. Sjekk at du har med [hopp-lenkene (W3)](https://www.w3.org/TR/WCAG21/#bypass-blocks) og at de fungerer.
|
||||
6. Sjekk at du har med [riktig <title> (W3)](https://www.w3.org/TR/WCAG21/#page-titled). Formen skal være `[hovedinnhold/overskrift på siden] - www.nav.no`
|
||||
7. Pass på riktig [overskriftshierarki (Difi)](https://uu.difi.no/krav-og-regelverk/losningsforslag-web/tekst-og-struktur)
|
||||
7. Pass på riktig [overskriftshierarki (DigDir)](https://uu.difi.no/krav-og-regelverk/losningsforslag-web/tekst-og-struktur)
|
||||
8. Sjekk at HTMLen din [validerer (W3)](https://validator.w3.org).
|
||||
9. Bruk [WAI-Aria (W3)](https://www.w3.org/WAI/standards-guidelines/aria) der standard HTML ikke er tilstrekkelig, for eksempel på [feilmeldinger](https://www.w3.org/TR/WCAG21/#status-messages)
|
||||
10. Bruk automatiserte testverktøy (som f.eks. [WAVE](https://wave.webaim.org) eller [Sortsite](https://www.powermapper.com/products/sortsite/)) aktivt og ofte.
|
||||
11. Test med skjermleser på egen hånd. Med for eksempel [ChromeVox](https://www.chromevox.com), [VoiceOver på Mac](https://webaim.org/articles/voiceover/), eller [TalkBack på Android](https://support.google.com/accessibility/android/answer/6283677?hl=en) er dette enklere enn du tror.
|
||||
12. Hvis mulig, bruk [NAV-ally](https://www.npmjs.com/package/nav-ally) i utviklingsprosessen.
|
||||
13. Test med reelle brukere, også med personer som bruker hjelpemidler. Bruk Sanselaben i Sannergata (rom 5006).
|
||||
12. Hvis mulig, bruk [automatisert testing](https://navikt.github.io/uu/hvordan-faa-det-til/UU-testing/automatisert-testing/) i utviklingsprosessen. Husk at dette dekker maks 20-30 prosent av potensielle feil.
|
||||
13. Test med reelle brukere, også med personer som bruker hjelpemidler. Bruk Sanselaben i Fyrstikkaleen.
|
||||
Reference in new issue
Block a user