mirror of
https://github.com/navikt/aksel.git
synced 2026-10-16 18:52:02 +00:00
Compare commits
34
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0f334061b | ||
|
|
79bddd9caa | ||
|
|
4a68409898 | ||
|
|
786bff67ab | ||
|
|
8a17caea6c | ||
|
|
3f43d0bf3b | ||
|
|
26541984ac | ||
|
|
10303602aa | ||
|
|
42254543d8 | ||
|
|
81c84e4817 | ||
|
|
b441175028 | ||
|
|
75362a0dc1 | ||
|
|
d8732ffa0e | ||
|
|
0ea9155085 | ||
|
|
92b9687ed1 | ||
|
|
1c022b14c9 | ||
|
|
abdeb616d2 | ||
|
|
37165e9f38 | ||
|
|
d19920ca78 | ||
|
|
60d3481300 | ||
|
|
f486937439 | ||
|
|
c62058abc1 | ||
|
|
84d9b8260f | ||
|
|
c108063dcb | ||
|
|
2a8533ad56 | ||
|
|
9b990a2178 | ||
|
|
5fec1f24f4 | ||
|
|
c27c1cfe26 | ||
|
|
5a649d2282 | ||
|
|
baac9cc251 | ||
|
|
d924d523e4 | ||
|
|
fc5a77081d | ||
|
|
1f3477a3e9 | ||
|
|
925450cb73 |
No files matched your search
@@ -0,0 +1,22 @@
|
||||
name: Eksempel på bruk
|
||||
description: Send et eksempel på ting fra Aksel som er brukt i det fri (tokens, komponenter, maler, etc)
|
||||
title: "[Eksempel på bruk]: "
|
||||
labels: ["dokumentasjon 📖"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Takk for at du bidrar til Aksel!
|
||||
- type: input
|
||||
id: title
|
||||
attributes:
|
||||
label: Lenke til side
|
||||
description: Lenke til siden hvor eksemplet er
|
||||
placeholder:
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: examples
|
||||
attributes:
|
||||
label: Forklaring
|
||||
description: Forklar om det er noe man må gjøre for å se eksemplet, eller hvor på siden det ligger
|
||||
@@ -2,8 +2,6 @@ name: Ny komponent
|
||||
description: Send et ønske om en eller flere nye komponenter
|
||||
title: "[Ny komponent]: "
|
||||
labels: ["nytt ✨", "forespørsel 🥰", "komponenter 🧩"]
|
||||
assignees:
|
||||
- KenAJoh
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
@@ -2,8 +2,6 @@ name: Nytt ikon
|
||||
description: Send et ønske om et eller flere nye ikoner
|
||||
title: "[Nytt ikon]: "
|
||||
labels: ["nytt ✨", "ikoner 🖼", "forespørsel 🥰"]
|
||||
assignees:
|
||||
- KenAJoh
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
@@ -2,8 +2,6 @@ name: Innspill til komponent
|
||||
description: Send inn innspill til komponent
|
||||
title: "[Innspill til komponent]: "
|
||||
labels: ["forespørsel 🥰", "komponenter 🧩", "nytt ✨", "beta 🧪"]
|
||||
assignees:
|
||||
- KenAJoh
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
@@ -2,8 +2,6 @@ name: Innspill til ikon
|
||||
description: Send inn innspill til ikon
|
||||
title: "[Tilbakemelding på ikon]: "
|
||||
labels: ["forespørsel 🥰", "ikoner 🖼️"]
|
||||
assignees:
|
||||
- KenAJoh
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
+2
-1
@@ -151,4 +151,5 @@ playwright-report/
|
||||
backup-*.tar.gz
|
||||
sitemap-urls.json
|
||||
*.tar.gz
|
||||
searchindex.json
|
||||
searchindex.json
|
||||
aksel.nav.no/website/public/rss
|
||||
@@ -1,5 +1,15 @@
|
||||
# @navikt/aksel-icons
|
||||
|
||||
## 5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
## 5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
## 5.8.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-icons",
|
||||
"version": "5.9.0",
|
||||
"version": "5.10.2",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/ikoner",
|
||||
"repository": {
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @navikt/aksel-stylelint
|
||||
|
||||
## 5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
## 5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
## 5.8.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-stylelint",
|
||||
"version": "5.9.0",
|
||||
"version": "5.10.2",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
|
||||
"repository": {
|
||||
@@ -35,8 +35,8 @@
|
||||
"dev": "yarn watch:lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-css": "^5.9.0",
|
||||
"@navikt/ds-tokens": "^5.9.0",
|
||||
"@navikt/ds-css": "^5.10.2",
|
||||
"@navikt/ds-tokens": "^5.10.2",
|
||||
"@types/jest": "^29.0.0",
|
||||
"concurrently": "7.2.1",
|
||||
"copyfiles": "2.4.1",
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
# @navikt/aksel
|
||||
|
||||
## 5.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`79bddd9ca`](https://github.com/navikt/aksel/commit/79bddd9caa9467b60e1e0c1c15b16f76dccbc304)]:
|
||||
- @navikt/ds-css@5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.10.1
|
||||
|
||||
## 5.10.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`60d348130`](https://github.com/navikt/aksel/commit/60d34813009377a1a7d84bed6627c60524849957)]:
|
||||
- @navikt/ds-css@5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`925450cb7`](https://github.com/navikt/aksel/commit/925450cb73cd792cd3b6ad3ebf9f38ba022ee4df)]:
|
||||
- @navikt/ds-css@5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel",
|
||||
"version": "5.9.0",
|
||||
"version": "5.10.2",
|
||||
"description": "Aksel command line interface. Handles css-imports, codemods and more",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"license": "MIT",
|
||||
@@ -29,8 +29,8 @@
|
||||
},
|
||||
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
|
||||
"dependencies": {
|
||||
"@navikt/ds-css": "5.9.0",
|
||||
"axios": "1.3.6",
|
||||
"@navikt/ds-css": "5.10.2",
|
||||
"axios": "1.6.0",
|
||||
"chalk": "4.1.0",
|
||||
"clipboardy": "^2.3.0",
|
||||
"commander": "10.0.1",
|
||||
@@ -38,7 +38,7 @@
|
||||
"fast-glob": "3.2.11",
|
||||
"figlet": "1.6.0",
|
||||
"is-git-clean": "1.1.0",
|
||||
"jscodeshift": "0.13.1",
|
||||
"jscodeshift": "^0.15.1",
|
||||
"jscodeshift-add-imports": "1.0.10",
|
||||
"lodash": "4.17.21",
|
||||
"react-scanner": "^1.1.0"
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# @navikt/ds-css
|
||||
|
||||
## 5.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Primtives: CSS-import for primitives er nå mer spesifikk ([#2469](https://github.com/navikt/aksel/pull/2469))
|
||||
|
||||
## 5.10.1
|
||||
|
||||
## 5.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Primitives: Ny komponent `Page` og `Page.Block` ([#2456](https://github.com/navikt/aksel/pull/2456))
|
||||
|
||||
## 5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :lipstick: Modal: Bedre håndtering av mobiler i landskapsmodus ([#2444](https://github.com/navikt/aksel/pull/2444))
|
||||
|
||||
## 5.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -35,6 +35,10 @@ const StyleMappings = {
|
||||
component: "Box",
|
||||
main: primitivesCss,
|
||||
},
|
||||
{
|
||||
component: "Page",
|
||||
main: primitivesCss,
|
||||
},
|
||||
{
|
||||
component: "HGrid",
|
||||
main: primitivesCss,
|
||||
@@ -183,7 +187,7 @@ const StyleMappings = {
|
||||
{
|
||||
component: "DatePicker",
|
||||
main: "date.css",
|
||||
dependencies: [typoCss, primitivesCss, "button.css", "popover.css"],
|
||||
dependencies: [typoCss, "button.css", "popover.css", primitivesCss],
|
||||
},
|
||||
{
|
||||
component: "MonthPicker",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
@charset "UTF-8";
|
||||
@import "baseline/index.css";
|
||||
@import "typography.css";
|
||||
@import "primitives/index.css";
|
||||
@import "grid.css";
|
||||
@import "accordion.css";
|
||||
@import "alert.css";
|
||||
@@ -34,3 +33,4 @@
|
||||
@import "table.css";
|
||||
@import "tabs.css";
|
||||
@import "list.css";
|
||||
@import "primitives/index.css";
|
||||
@@ -59,12 +59,17 @@
|
||||
|
||||
@media (min-width: 480px) {
|
||||
.navds-modal {
|
||||
max-width: calc((100% - 6px) - 2em);
|
||||
max-height: calc((100% - 6px) - 2em);
|
||||
max-width: calc(100% - 6px - 2em);
|
||||
}
|
||||
|
||||
.navds-modal--autowidth {
|
||||
max-width: min(700px, calc((100% - 6px) - 2em));
|
||||
max-width: min(700px, calc(100% - 6px - 2em));
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-height: 480px) {
|
||||
.navds-modal {
|
||||
max-height: calc(100% - 6px - 2em);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "5.9.0",
|
||||
"version": "5.10.2",
|
||||
"description": "CSS for NAV Designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
@@ -27,7 +27,7 @@
|
||||
"css:get-version": "node config/get-version.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^5.9.0",
|
||||
"@navikt/ds-tokens": "^5.10.2",
|
||||
"cssnano": "6.0.0",
|
||||
"fast-glob": "3.2.11",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@import "box.css";
|
||||
@import "bleed.css";
|
||||
@import "page.css";
|
||||
@import "hgrid.css";
|
||||
@import "stack.css";
|
||||
@import "responsive.css";
|
||||
@@ -0,0 +1,50 @@
|
||||
.navds-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
min-height: 100lvh;
|
||||
|
||||
/* stylelint-disable-next-line csstools/value-no-unknown-custom-properties */
|
||||
background-color: var(--__ac-page-background);
|
||||
}
|
||||
|
||||
/* Page.Block */
|
||||
.navds-pageblock {
|
||||
margin-inline: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.navds-page__content--grow {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.navds-page__content--fullheight {
|
||||
min-height: 100vh;
|
||||
min-height: 100lvh;
|
||||
}
|
||||
|
||||
.navds-page__content--padding {
|
||||
padding-block-end: var(--a-spacing-8);
|
||||
}
|
||||
|
||||
.navds-pageblock--lg {
|
||||
max-width: 1024px;
|
||||
}
|
||||
|
||||
.navds-pageblock--xl {
|
||||
max-width: 1280px;
|
||||
}
|
||||
|
||||
.navds-pageblock--2xl {
|
||||
max-width: 1440px;
|
||||
}
|
||||
|
||||
.navds-pageblock--gutters {
|
||||
padding-inline: var(--a-spacing-4);
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.navds-pageblock--gutters {
|
||||
padding-inline: var(--a-spacing-12);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,55 @@
|
||||
# @navikt/ds-react
|
||||
|
||||
## 5.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- OverridableComponent: Fungerer nå bedre ved bruk av typeof <komponent> ([#2474](https://github.com/navikt/aksel/pull/2474))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.10.2
|
||||
- @navikt/aksel-icons@5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Table: Håndterer nå sjekk for interaktive elementer i ExpandableRow bedre ([#2461](https://github.com/navikt/aksel/pull/2461))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.10.1
|
||||
- @navikt/aksel-icons@5.10.1
|
||||
|
||||
## 5.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- Primitives: Ny komponent `Page` og `Page.Block` ([#2456](https://github.com/navikt/aksel/pull/2456))
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.10.0
|
||||
- @navikt/aksel-icons@5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- :bug: Datepicker lukker ikke lenger modalen den er i ([#2451](https://github.com/navikt/aksel/pull/2451))
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.9.2
|
||||
- @navikt/aksel-icons@5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-tokens@5.9.1
|
||||
- @navikt/aksel-icons@5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "5.9.0",
|
||||
"version": "5.10.2",
|
||||
"description": "Aksel react-components for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"license": "MIT",
|
||||
@@ -38,8 +38,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "0.25.4",
|
||||
"@navikt/aksel-icons": "^5.9.0",
|
||||
"@navikt/ds-tokens": "^5.9.0",
|
||||
"@navikt/aksel-icons": "^5.10.2",
|
||||
"@navikt/ds-tokens": "^5.10.2",
|
||||
"@radix-ui/react-tabs": "1.0.0",
|
||||
"@radix-ui/react-toggle-group": "1.0.0",
|
||||
"clsx": "^1.2.1",
|
||||
|
||||
@@ -437,28 +437,36 @@ export const ModalDemo = () => {
|
||||
toDate: new Date("Feb 23 2024"),
|
||||
onDateChange: console.log,
|
||||
});
|
||||
const [open, setOpen] = useState(true);
|
||||
|
||||
return (
|
||||
<Modal open header={{ heading: "Modal-demo" }}>
|
||||
<Modal.Body style={{ position: "relative" }}>
|
||||
<BodyLong spacing>
|
||||
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
|
||||
</BodyLong>
|
||||
<>
|
||||
<Button onClick={() => setOpen(!open)}>Open modal</Button>
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={() => setOpen(false)}
|
||||
header={{ heading: "Modal-demo" }}
|
||||
>
|
||||
<Modal.Body style={{ position: "relative" }}>
|
||||
<BodyLong spacing>
|
||||
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
|
||||
</BodyLong>
|
||||
|
||||
<DatePicker {...datepickerProps} dropdownCaption>
|
||||
<DatePicker.Input
|
||||
{...inputProps}
|
||||
label="Velg dato"
|
||||
description="Format: dd.mm.yyyy"
|
||||
/>
|
||||
</DatePicker>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button>Neste</Button>
|
||||
<Button variant="secondary">Tilbake</Button>
|
||||
<Button variant="tertiary">Avbryt</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
<DatePicker {...datepickerProps} dropdownCaption>
|
||||
<DatePicker.Input
|
||||
{...inputProps}
|
||||
label="Velg dato"
|
||||
description="Format: dd.mm.yyyy"
|
||||
/>
|
||||
</DatePicker>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button>Neste</Button>
|
||||
<Button variant="secondary">Tilbake</Button>
|
||||
<Button variant="tertiary">Avbryt</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
ModalDemo.parameters = { chromatic: { pauseAnimationAtEnd: true } };
|
||||
@@ -57,7 +57,10 @@ export const DateWrapper = ({
|
||||
<Modal
|
||||
ref={modalRef}
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
onClose={(event) => {
|
||||
event.stopPropagation();
|
||||
onClose();
|
||||
}}
|
||||
aria-label={modalLabel(locale, variant)}
|
||||
className={cl("navds-date__modal", {
|
||||
"navds-date__nested-modal": isInModal,
|
||||
|
||||
@@ -38,3 +38,4 @@ export * from "./layout/stack";
|
||||
export * from "./layout/grid";
|
||||
export * from "./layout/content-container";
|
||||
export * from "./layout/responsive";
|
||||
export * from "./layout/page";
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from "react";
|
||||
import type { Meta } from "@storybook/react";
|
||||
import React from "react";
|
||||
import { Box, HStack, VStack } from "../..";
|
||||
import { BodyLong } from "../../typography";
|
||||
import { Bleed } from "./Bleed";
|
||||
import { Box, HStack, VStack } from "../..";
|
||||
|
||||
export default {
|
||||
title: "ds-react/Primitives/Bleed",
|
||||
|
||||
@@ -0,0 +1,271 @@
|
||||
import bgColors from "@navikt/ds-tokens/src/colors-bg.json";
|
||||
import type { Meta, StoryFn } from "@storybook/react";
|
||||
import React, { useEffect } from "react";
|
||||
import { Box } from "../box";
|
||||
import { HGrid } from "../grid";
|
||||
import Page from "./Page";
|
||||
import { widths } from "./parts/PageBlock";
|
||||
|
||||
const meta: Meta = {
|
||||
title: "ds-react/Primitives/Page",
|
||||
component: Page,
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const Default: StoryFn = ({
|
||||
belowFold,
|
||||
background,
|
||||
width,
|
||||
gutters,
|
||||
contentBlockPadding,
|
||||
}) => (
|
||||
<Page
|
||||
footer={<Footer width={width} gutters={gutters} />}
|
||||
footerPosition={belowFold ? "belowFold" : undefined}
|
||||
background={background}
|
||||
contentBlockPadding={contentBlockPadding}
|
||||
>
|
||||
<Header width={width} gutters={gutters} />
|
||||
<Content width={width} gutters={gutters} />
|
||||
</Page>
|
||||
);
|
||||
|
||||
Default.argTypes = {
|
||||
width: {
|
||||
control: "radio",
|
||||
options: widths,
|
||||
},
|
||||
background: {
|
||||
control: "radio",
|
||||
options: Object.keys(bgColors.a),
|
||||
},
|
||||
belowFold: {
|
||||
control: "boolean",
|
||||
},
|
||||
gutters: {
|
||||
control: "boolean",
|
||||
},
|
||||
contentBlockPadding: {
|
||||
control: "radio",
|
||||
options: ["end", "none"],
|
||||
},
|
||||
};
|
||||
|
||||
Default.args = {
|
||||
belowFold: false,
|
||||
gutters: false,
|
||||
contentBlockPadding: "end",
|
||||
};
|
||||
|
||||
export const BelowFold: StoryFn = () => (
|
||||
<Page
|
||||
footer={<Footer />}
|
||||
footerPosition="belowFold"
|
||||
contentBlockPadding="end"
|
||||
>
|
||||
<Header />
|
||||
<Content />
|
||||
</Page>
|
||||
);
|
||||
|
||||
export const Background: StoryFn = () => (
|
||||
<HGrid columns={2} gap="4">
|
||||
<Page
|
||||
background="bg-default"
|
||||
footer={<div>footer</div>}
|
||||
contentBlockPadding="end"
|
||||
>
|
||||
<div>header</div>
|
||||
<div>content</div>
|
||||
</Page>
|
||||
<Page
|
||||
background="bg-subtle"
|
||||
footer={<div>footer</div>}
|
||||
contentBlockPadding="end"
|
||||
>
|
||||
<div>header</div>
|
||||
<div>content</div>
|
||||
</Page>
|
||||
</HGrid>
|
||||
);
|
||||
|
||||
export const ContentBlockPadding: StoryFn = () => (
|
||||
<HGrid columns={2} gap="6" align="start">
|
||||
<Page
|
||||
footer={<Footer width="lg" gutters />}
|
||||
contentBlockPadding="end"
|
||||
background="bg-subtle"
|
||||
>
|
||||
<Header width="lg" gutters />
|
||||
<Page.Block width="lg" gutters as="main">
|
||||
<Box background="surface-alt-3-subtle" style={{ height: "80vh" }}>
|
||||
Main
|
||||
</Box>
|
||||
</Page.Block>
|
||||
</Page>
|
||||
<Page
|
||||
footer={<Footer width="lg" gutters />}
|
||||
contentBlockPadding="none"
|
||||
background="bg-subtle"
|
||||
>
|
||||
<Header width="lg" gutters />
|
||||
<Page.Block width="lg" gutters as="main">
|
||||
<Box background="surface-alt-3-subtle" style={{ height: "80vh" }}>
|
||||
Main
|
||||
</Box>
|
||||
</Page.Block>
|
||||
</Page>
|
||||
</HGrid>
|
||||
);
|
||||
|
||||
export const Gutters: StoryFn = () => (
|
||||
<HGrid columns={2} gap="6" align="start">
|
||||
<Page footer={<Footer width="lg" gutters />} background="bg-subtle">
|
||||
<Header width="lg" gutters />
|
||||
<Page.Block width="lg" gutters as="main">
|
||||
<Box background="surface-alt-3-subtle" style={{ height: "80vh" }}>
|
||||
Main
|
||||
</Box>
|
||||
</Page.Block>
|
||||
</Page>
|
||||
<Page footer={<Footer width="lg" />} background="bg-subtle">
|
||||
<Header width="lg" />
|
||||
<Page.Block width="lg" as="main">
|
||||
<Box background="surface-alt-3-subtle" style={{ height: "80vh" }}>
|
||||
Main
|
||||
</Box>
|
||||
</Page.Block>
|
||||
</Page>
|
||||
</HGrid>
|
||||
);
|
||||
|
||||
Gutters.parameters = {
|
||||
chromatic: {
|
||||
modes: {
|
||||
mobile_portrait: {
|
||||
viewport: {
|
||||
width: 400,
|
||||
height: 850,
|
||||
},
|
||||
},
|
||||
desktop: {
|
||||
viewport: {
|
||||
width: 1280,
|
||||
height: 960,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const MILJO_URL = "https://www.nav.no/dekoratoren";
|
||||
|
||||
export const WithDecorator: StoryFn = () => {
|
||||
return (
|
||||
<Page
|
||||
contentBlockPadding="end"
|
||||
footerPosition="belowFold"
|
||||
footer={<div id="decorator-footer"></div>}
|
||||
>
|
||||
<div id="decorator-header"></div>
|
||||
<Content width="lg" gutters />
|
||||
<div
|
||||
id="decorator-env"
|
||||
data-src={`${MILJO_URL}/env?context=privatperson`}
|
||||
></div>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
WithDecorator.decorators = [
|
||||
(Story) => {
|
||||
useEffect(() => {
|
||||
const script = document.createElement("script");
|
||||
script.src = `${MILJO_URL}/client.js`;
|
||||
script.async = true;
|
||||
document.body.appendChild(script);
|
||||
|
||||
const styles = document.createElement("link");
|
||||
styles.href = `${MILJO_URL}/css/client.css`;
|
||||
styles.rel = "stylesheet";
|
||||
document.head.appendChild(styles);
|
||||
|
||||
return () => {
|
||||
document.body.removeChild(script);
|
||||
document.head.removeChild(styles);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return <Story />;
|
||||
},
|
||||
];
|
||||
|
||||
WithDecorator.parameters = {
|
||||
chromatic: {
|
||||
disable: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const OutsideBackground = () => {
|
||||
return (
|
||||
<Page
|
||||
contentBlockPadding="end"
|
||||
footer={
|
||||
<Box
|
||||
background="surface-alt-3-subtle"
|
||||
style={{ height: 100 }}
|
||||
as="footer"
|
||||
>
|
||||
<Page.Block width="lg" gutters>
|
||||
Footer
|
||||
</Page.Block>
|
||||
</Box>
|
||||
}
|
||||
>
|
||||
<Box background="surface-alt-1-subtle" style={{ height: 64 }} as="header">
|
||||
<Page.Block width="lg" gutters>
|
||||
Header
|
||||
</Page.Block>
|
||||
</Box>
|
||||
<Box background="surface-alt-2-subtle" style={{ height: 300 }} as="main">
|
||||
<Page.Block width="lg" gutters>
|
||||
main
|
||||
</Page.Block>
|
||||
</Box>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
function Header({ width = "lg", gutters = false }: any) {
|
||||
return (
|
||||
<Page.Block as="header" width={width} gutters={gutters}>
|
||||
<Box background="surface-alt-3-subtle" style={{ height: 64 }}>
|
||||
Header
|
||||
</Box>
|
||||
</Page.Block>
|
||||
);
|
||||
}
|
||||
|
||||
function Content({ width = "lg", gutters = false }: any) {
|
||||
return (
|
||||
<Page.Block width={width} gutters={gutters} as="main">
|
||||
<Box background="surface-alt-3-subtle" style={{ height: 300 }}>
|
||||
Main
|
||||
</Box>
|
||||
</Page.Block>
|
||||
);
|
||||
}
|
||||
|
||||
function Footer({ width = "lg", gutters = false }: any) {
|
||||
return (
|
||||
<Page.Block width={width} gutters={gutters} as="footer">
|
||||
<Box background="surface-alt-3-subtle" style={{ height: 100 }}>
|
||||
Footer
|
||||
</Box>
|
||||
</Page.Block>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import bgColors from "@navikt/ds-tokens/src/colors-bg.json";
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { OverridableComponent } from "../../util";
|
||||
import { PageBlock } from "./parts/PageBlock";
|
||||
|
||||
export interface PageProps extends React.HTMLAttributes<HTMLElement> {
|
||||
/**
|
||||
* Overrides html-tag
|
||||
* @default "div"
|
||||
*/
|
||||
as?: "div" | "body";
|
||||
/**
|
||||
* Background color. Accepts a color token.
|
||||
* @default bg-default
|
||||
*/
|
||||
background?: keyof typeof bgColors.a;
|
||||
/**
|
||||
* Allows better positioning of footer
|
||||
*/
|
||||
footer?: React.ReactNode;
|
||||
/**
|
||||
* Places footer below page-fold
|
||||
*/
|
||||
footerPosition?: "belowFold";
|
||||
/**
|
||||
* Adds a standardised padding of 4rem between content and footer
|
||||
* @default block-end
|
||||
*/
|
||||
contentBlockPadding?: "end" | "none";
|
||||
}
|
||||
|
||||
interface PageComponentType
|
||||
extends OverridableComponent<PageProps, HTMLElement> {
|
||||
Block: typeof PageBlock;
|
||||
}
|
||||
|
||||
export const PageComponent: OverridableComponent<PageProps, HTMLElement> =
|
||||
forwardRef(
|
||||
(
|
||||
{
|
||||
as: Component = "div",
|
||||
className,
|
||||
style: _style,
|
||||
footer,
|
||||
children,
|
||||
footerPosition,
|
||||
background = "bg-default",
|
||||
contentBlockPadding = "end",
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const style: React.CSSProperties = {
|
||||
..._style,
|
||||
"--__ac-page-background": `var(--a-${background})`,
|
||||
};
|
||||
|
||||
const belowFold = footerPosition === "belowFold";
|
||||
|
||||
return (
|
||||
<Component
|
||||
{...rest}
|
||||
className={cl("navds-page", className)}
|
||||
ref={ref}
|
||||
style={style}
|
||||
>
|
||||
<div
|
||||
className={cl({
|
||||
"navds-page__content--fullheight": belowFold,
|
||||
"navds-page__content--grow": !belowFold,
|
||||
"navds-page__content--padding": contentBlockPadding === "end",
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
{footer}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Page helps with establishing a top-level layout for your page
|
||||
*
|
||||
* @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/page)
|
||||
* @see 🏷️ {@link PageProps}
|
||||
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* <Page
|
||||
* footer={<Page.Block width="xl" gutters />}
|
||||
* >
|
||||
* <Page.Block width="xl" gutters />// Header
|
||||
* <Page.Block width="xl" gutters />// Content
|
||||
* </Page>
|
||||
* ```
|
||||
* @example
|
||||
* Footer placed below page-fold
|
||||
* ```jsx
|
||||
* <Page
|
||||
* footer={<Page.Block width="xl" gutters />}
|
||||
* footerPosition="belowFold"
|
||||
* >
|
||||
* <Page.Block width="xl" gutters />// Header
|
||||
* <Page.Block width="xl" gutters />// Content
|
||||
* </Page>
|
||||
* ```
|
||||
*/
|
||||
const Page = PageComponent as PageComponentType;
|
||||
|
||||
Page.Block = PageBlock;
|
||||
|
||||
export default Page;
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as Page, type PageProps } from "./Page";
|
||||
export { type PageBlockProps } from "./parts/PageBlock";
|
||||
@@ -0,0 +1,72 @@
|
||||
import cl from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import { OverridableComponent } from "../../../util/OverridableComponent";
|
||||
|
||||
export const widths = ["lg", "xl", "2xl"] as const;
|
||||
|
||||
export interface PageBlockProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
/**
|
||||
* Predefined max-width
|
||||
* @example
|
||||
* lg: 1024px
|
||||
* xl: 1280px
|
||||
* 2xl: 1440px
|
||||
* @default max-width: 100%;
|
||||
*/
|
||||
width?: (typeof widths)[number];
|
||||
/**
|
||||
* Adds a standardised responsive padding-inline
|
||||
* @example
|
||||
* 3rem on > md
|
||||
* 1rem on < md
|
||||
* @default false
|
||||
*/
|
||||
gutters?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Acts as a top-level container for defining max-width, gutters and horizontal centering
|
||||
*
|
||||
* @see [📝 Documentation](https://aksel.nav.no/komponenter/primitives/page)
|
||||
* @see 🏷️ {@link PageBlockProps}
|
||||
* @see [🤖 OverridableComponent](https://aksel.nav.no/grunnleggende/kode/overridablecomponent) support
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* <Page
|
||||
* footer={<Page.Block width="xl" gutters />}
|
||||
* >
|
||||
* <Page.Block width="xl" gutters />// Header
|
||||
* <Page.Block width="xl" gutters />// Content
|
||||
* </Page>
|
||||
* ```
|
||||
* @example
|
||||
* With background bleed
|
||||
* Wrapping `Page.Block` with `Box` allows the background-color to use full screen-width
|
||||
* ```jsx
|
||||
* <Page
|
||||
* footer={<Box background="..."><Page.Block width="xl" gutters /></Box>}
|
||||
* footerPosition="belowFold"
|
||||
* >
|
||||
* <Box background="..."><Page.Block width="xl" gutters /></Box>//Header
|
||||
* <Box background="..."><Page.Block width="xl" gutters /></Box>//Content
|
||||
* </Page>
|
||||
* ```
|
||||
*/
|
||||
export const PageBlock: OverridableComponent<PageBlockProps, HTMLDivElement> =
|
||||
forwardRef(
|
||||
({ as: Component = "div", gutters, className, width, ...rest }, ref) => {
|
||||
return (
|
||||
<Component
|
||||
{...rest}
|
||||
className={cl(
|
||||
"navds-pageblock",
|
||||
`navds-pageblock--${width}`,
|
||||
className,
|
||||
{ "navds-pageblock--gutters": gutters }
|
||||
)}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -1,17 +1,19 @@
|
||||
import { FileIcon } from "@navikt/aksel-icons";
|
||||
import { Meta, StoryFn } from "@storybook/react";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { BodyLong, Button, Heading, Tooltip } from "..";
|
||||
import Modal from "./Modal";
|
||||
|
||||
export default {
|
||||
const meta: Meta<typeof Modal> = {
|
||||
title: "ds-react/Modal",
|
||||
component: Modal,
|
||||
parameters: {
|
||||
chromatic: { pauseAnimationAtEnd: true },
|
||||
},
|
||||
};
|
||||
export default meta;
|
||||
|
||||
export const WithUseRef = () => {
|
||||
export const WithUseRef: StoryFn = () => {
|
||||
const ref = useRef<HTMLDialogElement>(null);
|
||||
const ref2 = useRef<HTMLDialogElement>(null);
|
||||
|
||||
@@ -87,7 +89,7 @@ export const WithUseRef = () => {
|
||||
};
|
||||
WithUseRef.storyName = "With useRef";
|
||||
|
||||
export const WithUseState = () => {
|
||||
export const WithUseState: StoryFn = () => {
|
||||
const [open, setOpen] = useState(true);
|
||||
const [open2, setOpen2] = useState(false);
|
||||
|
||||
@@ -140,36 +142,43 @@ export const WithUseState = () => {
|
||||
};
|
||||
WithUseState.storyName = "With useState";
|
||||
|
||||
export const EmptyHeader = () => (
|
||||
<div style={{ minWidth: "800px", minHeight: "600px" } /* For Chromatic */}>
|
||||
<Modal open>
|
||||
<Modal.Header />
|
||||
<Modal.Body>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
|
||||
occaecat cupidatat non proident, sunt in culpa qui officia deserunt
|
||||
mollit anim id est laborum.
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</div>
|
||||
export const EmptyHeader: StoryFn = () => (
|
||||
<Modal open>
|
||||
<Modal.Header />
|
||||
<Modal.Body>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
||||
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
|
||||
velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
|
||||
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
|
||||
est laborum.
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
export const Small = () => (
|
||||
export const Small: StoryFn = () => (
|
||||
<Modal open width="small" header={{ heading: "Simple header" }}>
|
||||
<Modal.Body>Lorem ipsum dolor sit amet.</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
Small.storyName = "Size = Small";
|
||||
|
||||
export const MediumWithPortal = () => (
|
||||
export const MediumWithPortal: StoryFn = () => (
|
||||
<Modal open portal width="medium" header={{ heading: "Simple header" }}>
|
||||
<Modal.Body>Lorem ipsum dolor sit amet.</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
MediumWithPortal.storyName = "Size = Medium (with portal)";
|
||||
|
||||
export const WithTooltip = () => {
|
||||
export const Large800: StoryFn = () => (
|
||||
<Modal open width={800} header={{ heading: "Simple header" }}>
|
||||
<Modal.Body>Lorem ipsum dolor sit amet.</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
Large800.storyName = "Size = 800px";
|
||||
|
||||
export const WithTooltip: StoryFn = () => {
|
||||
const ref = useRef<HTMLDialogElement>(null);
|
||||
|
||||
return (
|
||||
@@ -193,3 +202,66 @@ export const WithTooltip = () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ChromaticViewportTesting: StoryFn = () => (
|
||||
<div id="modal-story-wrapper" style={{ width: "100vw", height: "100vh" }}>
|
||||
<style>{`#storybook-root { padding: 0 !important }`}</style>
|
||||
<Modal
|
||||
open
|
||||
header={{ heading: "Chromatic Viewports Testing", label: "Test" }}
|
||||
>
|
||||
<Modal.Body>
|
||||
<BodyLong spacing>
|
||||
This story is tailored for testing the breakpoints with Chromatic.
|
||||
</BodyLong>
|
||||
<BodyLong spacing>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
||||
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
|
||||
minim veniam, quis nostrud exercitation ullamco laboris nisi ut
|
||||
aliquip ex ea commodo consequat.
|
||||
</BodyLong>
|
||||
<BodyLong spacing>
|
||||
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
|
||||
dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||
proident, sunt in culpa qui officia deserunt mollit anim id est
|
||||
laborum.
|
||||
</BodyLong>
|
||||
<BodyLong>
|
||||
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.
|
||||
</BodyLong>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
<Button>Primary</Button>
|
||||
<Button variant="secondary">Secondary</Button>
|
||||
<Button variant="tertiary">Tertiary</Button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
ChromaticViewportTesting.parameters = {
|
||||
chromatic: {
|
||||
modes: {
|
||||
mobile_portrait: {
|
||||
viewport: {
|
||||
width: 400,
|
||||
height: 850,
|
||||
},
|
||||
},
|
||||
mobile_landscape: {
|
||||
viewport: {
|
||||
width: 850,
|
||||
height: 400,
|
||||
},
|
||||
},
|
||||
desktop: {
|
||||
viewport: {
|
||||
width: 1280,
|
||||
height: 960,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -81,11 +81,8 @@ export const ExpandableRow: ExpandableRowType = forwardRef(
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
const onRowClick = (e) => {
|
||||
if (e.target.nodeName === "TD" || e.target.nodeName === "TH") {
|
||||
expansionHandler(e);
|
||||
}
|
||||
};
|
||||
const onRowClick = (e) =>
|
||||
!isInteractiveTarget(e.target) && expansionHandler(e);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -143,4 +140,19 @@ export const ExpandableRow: ExpandableRowType = forwardRef(
|
||||
}
|
||||
);
|
||||
|
||||
function isInteractiveTarget(elm: HTMLElement) {
|
||||
if (elm.nodeName === "TD" || elm.nodeName === "TH" || !elm.parentElement) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
["BUTTON", "DETAILS", "LABEL", "SELECT", "TEXTAREA", "INPUT", "A"].includes(
|
||||
elm.nodeName
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isInteractiveTarget(elm.parentElement);
|
||||
}
|
||||
|
||||
export default ExpandableRow;
|
||||
@@ -0,0 +1,100 @@
|
||||
import { expect, jest } from "@storybook/jest";
|
||||
import { userEvent, within } from "@storybook/testing-library";
|
||||
import React from "react";
|
||||
import { Table } from "../..";
|
||||
|
||||
export default {
|
||||
title: "ds-react/Table/Tests",
|
||||
component: Table,
|
||||
};
|
||||
|
||||
export const ClickableRowTest = {
|
||||
render: ({ onOpenChange }) => {
|
||||
return (
|
||||
<>
|
||||
<Table zebraStripes>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell aria-hidden />
|
||||
<Table.HeaderCell aria-hidden />
|
||||
<Table.HeaderCell aria-hidden />
|
||||
<Table.HeaderCell aria-hidden />
|
||||
<Table.HeaderCell aria-hidden />
|
||||
<Table.HeaderCell aria-hidden />
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.ExpandableRow
|
||||
content={<div>placeholder row 2</div>}
|
||||
togglePlacement="right"
|
||||
data-testid="row1"
|
||||
expandOnRowClick
|
||||
onOpenChange={onOpenChange}
|
||||
>
|
||||
<Table.DataCell>
|
||||
<div data-testid="cell1">Should be clickable</div>
|
||||
</Table.DataCell>
|
||||
<Table.DataCell data-testid="cell2">
|
||||
Should also be clickable
|
||||
</Table.DataCell>
|
||||
|
||||
<Table.DataCell>
|
||||
<button data-testid="cell3">Should not be clickable</button>
|
||||
</Table.DataCell>
|
||||
<Table.DataCell>
|
||||
<div>
|
||||
<div>
|
||||
<button data-testid="cell4">
|
||||
Nested should not be clickable
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Table.DataCell>
|
||||
<Table.DataCell>
|
||||
<div>
|
||||
<div>
|
||||
<button data-testid="cell4">
|
||||
<span>2x nested should not be clickable</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Table.DataCell>
|
||||
</Table.ExpandableRow>
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
},
|
||||
args: {
|
||||
onOpenChange: jest.fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
args.onOpenChange.mockClear();
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const cell1 = canvas.getByText("Should be clickable");
|
||||
const cell2 = canvas.getByText("Should also be clickable");
|
||||
const cell3 = canvas.getByText("Should not be clickable");
|
||||
const cell4 = canvas.getByText("Nested should not be clickable");
|
||||
const cell5 = canvas.getByText("2x nested should not be clickable");
|
||||
|
||||
await userEvent.click(cell1);
|
||||
expect(args.onOpenChange.mock.calls).toHaveLength(1);
|
||||
await userEvent.click(cell1);
|
||||
expect(args.onOpenChange.mock.calls).toHaveLength(2);
|
||||
|
||||
await userEvent.click(cell2);
|
||||
expect(args.onOpenChange.mock.calls).toHaveLength(3);
|
||||
await userEvent.click(cell2);
|
||||
expect(args.onOpenChange.mock.calls).toHaveLength(4);
|
||||
|
||||
await userEvent.click(cell3);
|
||||
expect(args.onOpenChange.mock.calls).toHaveLength(4);
|
||||
|
||||
await userEvent.click(cell4);
|
||||
expect(args.onOpenChange.mock.calls).toHaveLength(4);
|
||||
|
||||
await userEvent.click(cell5);
|
||||
expect(args.onOpenChange.mock.calls).toHaveLength(4);
|
||||
},
|
||||
};
|
||||
@@ -1,11 +1,28 @@
|
||||
import React from "react";
|
||||
|
||||
/**
|
||||
* This interface represents a component that can be overridden with different props and elements.
|
||||
* @template Component The type of the props for the component.
|
||||
* @template Element The type of the HTML element that the component renders.
|
||||
*/
|
||||
export interface OverridableComponent<Component, Element extends HTMLElement> {
|
||||
/**
|
||||
* This is a function type that takes props and returns a React functional component.
|
||||
* @param props The props for the component, which are a combination of the Component type and React.RefAttributes for the Element type.
|
||||
* @returns A React functional component.
|
||||
*/
|
||||
(props: Component & React.RefAttributes<Element>): ReturnType<React.FC>;
|
||||
|
||||
/**
|
||||
* This is a function type that takes props and returns a React functional component.
|
||||
* It allows for the 'as' prop to override the type of element that the component renders.
|
||||
* @template As The type of the element that the component should render as.
|
||||
* @param props The props for the component, which are a combination of the Component type, the 'as' prop, and any other props that are not part of the Component type or the 'as' prop.
|
||||
* @returns A React functional component.
|
||||
*/
|
||||
<As extends React.ElementType>(
|
||||
props: {
|
||||
as: As;
|
||||
as?: As;
|
||||
} & Component &
|
||||
Omit<React.ComponentPropsWithRef<As>, keyof Component | "as">
|
||||
): ReturnType<React.FC>;
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @navikt/ds-tailwind
|
||||
|
||||
## 5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
## 5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
## 5.8.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tailwind",
|
||||
"version": "5.9.0",
|
||||
"version": "5.10.2",
|
||||
"description": "Tailwind config based on @navikt/ds-tokens",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
@@ -22,7 +22,7 @@
|
||||
"directory": "@navikt/core/tailwind"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^5.9.0",
|
||||
"@navikt/ds-tokens": "^5.10.2",
|
||||
"@types/jest": "^29.0.0",
|
||||
"color": "4.2.3",
|
||||
"jest": "^29.0.0",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @navikt/ds-tokens
|
||||
|
||||
## 5.10.2
|
||||
|
||||
## 5.10.1
|
||||
|
||||
## 5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
## 5.8.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tokens",
|
||||
"version": "5.9.0",
|
||||
"version": "5.10.2",
|
||||
"description": "Design-tokens for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
|
||||
+431
-853
File diff suppressed because it is too large.
Load diff
@@ -4,7 +4,7 @@ ENV NODE_ENV production
|
||||
|
||||
WORKDIR /app
|
||||
COPY aksel.nav.no/website/.next/standalone ./
|
||||
COPY aksel.nav.no/website/next-logger.config.js ./
|
||||
COPY aksel.nav.no/website/config/next-logger.config.js ./
|
||||
|
||||
ENV NODE_OPTIONS '-r next-logger'
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Det publiserte studioet finner man på [aksel.nav.no/admin](https://aksel.nav.no
|
||||
|
||||
### Bidrag
|
||||
|
||||
Branch `main` blir pusher rett til prod -> aksel.nav.no. For å utvikle nye features kan branch `next` brukes, som ved push publiseres til devmiljø https://aksel.ekstern.dev.nav.no/. Kan også publisere andre branches til dev ved bruk av workflow-dispatch.
|
||||
Branch `main` pusher rett til prod -> aksel.nav.no. For å utvikle nye features kan branch `next` brukes, som ved push publiseres til devmiljø https://aksel.ekstern.dev.nav.no/. Kan også publisere andre branches til dev ved bruk av workflow-dispatch.
|
||||
|
||||
## Kode-eksempler
|
||||
|
||||
|
||||
@@ -12,14 +12,15 @@
|
||||
"test": "yarn workspace website test"
|
||||
},
|
||||
"workspaces": [
|
||||
"website"
|
||||
"website",
|
||||
"playroom"
|
||||
],
|
||||
"dependencies": {
|
||||
"@navikt/aksel-icons": "^5.9.0",
|
||||
"@navikt/ds-css": "^5.9.0",
|
||||
"@navikt/ds-react": "^5.9.0",
|
||||
"@navikt/ds-tailwind": "^5.9.0",
|
||||
"@navikt/ds-tokens": "^5.9.0"
|
||||
"@navikt/aksel-icons": "^5.10.2",
|
||||
"@navikt/ds-css": "^5.10.2",
|
||||
"@navikt/ds-react": "^5.10.2",
|
||||
"@navikt/ds-tailwind": "^5.10.2",
|
||||
"@navikt/ds-tokens": "^5.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier-plugin-tailwindcss": "^0.2.3"
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# playroom
|
||||
|
||||
https://github.com/seek-oss/playroom
|
||||
|
||||
This is the playroom / code sandbox that is built as a standalone static app, and then it's added to the aksel website through an iframe.
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @type {import('@babel/core').TransformOptions}
|
||||
*/
|
||||
module.exports = function (api) {
|
||||
const envName = api.env();
|
||||
const development = envName === "development" || envName === "test";
|
||||
return {
|
||||
presets: [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{ useBuiltIns: "entry", corejs: "3.0", bugfixes: true },
|
||||
],
|
||||
["@babel/preset-typescript"],
|
||||
["@babel/preset-react", { development, useBuiltIns: true }],
|
||||
],
|
||||
assumptions: {
|
||||
setPublicClassFields: true,
|
||||
privateFieldsAsProperties: true,
|
||||
// nothing accesses `document.all`:
|
||||
noDocumentAll: true,
|
||||
// nothing relies on class constructors invoked without `new` throwing:
|
||||
noClassCalls: true,
|
||||
// nothing should be relying on tagged template strings being frozen:
|
||||
mutableTemplateObject: true,
|
||||
// nothing is relying on Function.prototype.length:
|
||||
ignoreFunctionLength: true,
|
||||
// nothing is relying on mutable re-exported bindings:
|
||||
constantReexports: true,
|
||||
// don't bother marking Module records non-enumerable:
|
||||
enumerableModuleMeta: true,
|
||||
// nothing uses [[Symbol.toPrimitive]]:
|
||||
// (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive)
|
||||
ignoreToPrimitiveHint: true,
|
||||
// nothing relies on spread copying Symbol keys: ({...{ [Symbol()]: 1 }})
|
||||
objectRestNoSymbols: true,
|
||||
// nothing relies on `new (() => {})` throwing:
|
||||
noNewArrows: true,
|
||||
// transpile object spread to assignment instead of defineProperty():
|
||||
setSpreadProperties: true,
|
||||
// nothing should be using custom iterator protocol:
|
||||
skipForOfIteratorClosing: true,
|
||||
// nothing inherits from a constructor function with explicit return value:
|
||||
superIsCallableConstructor: true,
|
||||
// nothing relies on CJS-transpiled namespace imports having all properties prior to module execution completing:
|
||||
noIncompleteNsImportDetection: true,
|
||||
},
|
||||
babelrcRoots: ["."],
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "playroom",
|
||||
"scripts": {
|
||||
"start": "playroom start",
|
||||
"build:playroom": "playroom build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.23.2",
|
||||
"@babel/preset-react": "^7.22.15",
|
||||
"@babel/preset-typescript": "^7.23.2",
|
||||
"@navikt/ds-css": "^5.9.2",
|
||||
"@navikt/ds-react": "^5.9.2",
|
||||
"babel-loader": "^9.1.3",
|
||||
"babel-plugin-preval": "^5.1.0",
|
||||
"css-loader": "^6.8.1",
|
||||
"playroom": "^0.32.1",
|
||||
"style-loader": "^3.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Note: Hot module reloading for dev has been turned off for this environment
|
||||
// Why? We embed playroom in an iframe, and that iframe is loaded from the public asset folder
|
||||
// So we need to build into that public asset folder. Hence no dev mode and HMR
|
||||
// Workaround: restart the next dev server after each change to the playroom config and associated files.
|
||||
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
baseUrl: "./",
|
||||
components: path.resolve("./src/components.ts"),
|
||||
outputPath: path.resolve("./dist"),
|
||||
// Optional:
|
||||
title: "Aksel Sandbox",
|
||||
snippets: path.resolve("./src/snippets.ts"),
|
||||
widths: [480, 768, 1024, 1280],
|
||||
port: 9000,
|
||||
frameComponent: path.resolve("./src/FrameComponent.tsx"),
|
||||
useScope: path.resolve("./src/useScope.tsx"),
|
||||
openBrowser: false,
|
||||
paramType: "search", // default is 'hash'
|
||||
iframeSandbox: "allow-scripts allow-same-origin",
|
||||
exampleCode: `
|
||||
<Heading>This is a sandbox!</Heading>
|
||||
<HStack gap="10">
|
||||
<Box> box 1</Box> <Box> box 2</Box> <Box> box 3</Box>
|
||||
</HStack>
|
||||
<Button>test</Button>
|
||||
<BodyShort>This is a bodyshort</BodyShort>
|
||||
`,
|
||||
webpackConfig: () => ({
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|ts|tsx)$/,
|
||||
include: [path.resolve("./")],
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve("babel-loader"),
|
||||
options: {
|
||||
presets: [
|
||||
[
|
||||
require.resolve("@babel/preset-env"),
|
||||
{ shippedProposals: true },
|
||||
],
|
||||
require.resolve("@babel/preset-react"),
|
||||
require.resolve("@babel/preset-typescript"),
|
||||
],
|
||||
plugins: [require.resolve("babel-plugin-preval")],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
include: [require.resolve("@navikt/ds-css")],
|
||||
use: ["style-loader", "css-loader"],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
import "@navikt/ds-css";
|
||||
import * as React from "react";
|
||||
|
||||
const FrameComponent = ({ children }: { children: React.ReactNode }) => {
|
||||
return <div id="sandbox-wrapper">{children}</div>;
|
||||
};
|
||||
|
||||
export default FrameComponent;
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "@navikt/aksel-icons";
|
||||
export * from "@navikt/ds-react";
|
||||
@@ -0,0 +1,29 @@
|
||||
const snippets = [
|
||||
{
|
||||
group: "Templates",
|
||||
name: "Single Component",
|
||||
code: `<Button variant="primary">Button</Button>`,
|
||||
},
|
||||
{
|
||||
group: "Templates",
|
||||
name: "Multiple Components",
|
||||
code: ` <Button variant="primary">First</Button>
|
||||
<Button>Second</Button>`,
|
||||
},
|
||||
{
|
||||
group: "Templates",
|
||||
name: "Component with state",
|
||||
code: `{
|
||||
(() => {
|
||||
const [count, setCount] = React.useState(0);
|
||||
|
||||
return (
|
||||
<Button variant="primary" onClick={() => setCount(count + 1)}>Count: {count}</Button>
|
||||
)
|
||||
})()
|
||||
}
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
export default snippets;
|
||||
@@ -0,0 +1,2 @@
|
||||
public/sandbox
|
||||
test-results/
|
||||
@@ -1,8 +1,7 @@
|
||||
import type { StorybookConfig } from "@storybook/nextjs";
|
||||
|
||||
import { readFileSync } from "fs";
|
||||
import { join, dirname } from "path";
|
||||
import { loadCsf } from "@storybook/csf-tools";
|
||||
import type { StorybookConfig } from "@storybook/nextjs";
|
||||
import { readFileSync } from "fs";
|
||||
import { dirname, join } from "path";
|
||||
|
||||
/**
|
||||
* This function is used to resolve the absolute path of a package.
|
||||
|
||||
@@ -199,3 +199,20 @@ export const StorybookIcon = ({ ...props }) => (
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const CodeSandboxLogo = ({ ...props }) => (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
fill="none"
|
||||
viewBox="8 3 24 24"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M20.54 25a.681.681 0 00.158-.074l6.174-3.69c.734-.438 1.128-.885 1.128-2.084v-6.444c0-.248-.016-.447-.063-.629l-7.397 4.434zm-8.477-12.921l7.397 4.434V25a.514.514 0 01-.15-.074l-6.182-3.69c-.726-.438-1.128-.885-1.128-2.084v-6.444c0-.248.016-.447.063-.629zM20.004 7c.443 0 .9.143 1.359.406l.068.04 5.567 3.326c.155.088.284.177.394.282l.04.04-7.428 4.426-7.436-4.425c.11-.109.233-.198.378-.286l.063-.037 4.07-2.442h.002l1.488-.883c.434-.262.868-.415 1.296-.443l.071-.003z"
|
||||
></path>
|
||||
</svg>
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
|
||||
const Logo = (props) => (
|
||||
const AkselLogo = (props) => (
|
||||
<svg
|
||||
width="119"
|
||||
height="26"
|
||||
@@ -43,4 +43,4 @@ const Logo = (props) => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default Logo;
|
||||
export default AkselLogo;
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./Icons";
|
||||
File renamed without changes.
+2
-1
@@ -1,5 +1,5 @@
|
||||
import { dateStr } from "components/website-modules/utils/date-string";
|
||||
import { useEffect, useState } from "react";
|
||||
import { dateStr } from "@/utils";
|
||||
|
||||
export const useFormatedDate = (date: string) => {
|
||||
const [_date, setDate] = useState(null);
|
||||
@@ -8,5 +8,6 @@ export const useFormatedDate = (date: string) => {
|
||||
const handleDate = async () => setDate(await dateStr(date));
|
||||
handleDate();
|
||||
}, [date]);
|
||||
|
||||
return _date;
|
||||
};
|
||||
+1
-7
@@ -2,7 +2,7 @@ import { useEffect } from "react";
|
||||
|
||||
// https://stackoverflow.com/questions/38588346/anchor-a-tags-not-working-in-chrome-when-using/38588927#38588927
|
||||
// https://github.com/vercel/next.js/discussions/13134
|
||||
export function useScrollToHashOnPageLoad(): void {
|
||||
export function useHashScroll(): void {
|
||||
useEffect(() => {
|
||||
if (window.location.hash) {
|
||||
const hash = window.location.hash;
|
||||
@@ -13,9 +13,3 @@ export function useScrollToHashOnPageLoad(): void {
|
||||
}
|
||||
}, []);
|
||||
}
|
||||
|
||||
export const removeEmojies = (s: string) =>
|
||||
s.replace(
|
||||
/([\u2700-\u27BF]|[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2011-\u26FF]|\uD83E[\uDD10-\uDDFF])/g,
|
||||
""
|
||||
);
|
||||
File renamed without changes.
@@ -0,0 +1,13 @@
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
export const SanityDocIdContext = createContext<{ id?: string }>(null);
|
||||
|
||||
export function useSanityDocId() {
|
||||
const ctx = useContext(SanityDocIdContext);
|
||||
if (!ctx) {
|
||||
console.error(
|
||||
"useSanityDocId has to be used inside SanityDocIdContext.provider"
|
||||
);
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export * from "./assets";
|
||||
export * from "./website-modules/BreadCrumbs";
|
||||
export * from "./website-modules/toc/TOC";
|
||||
export * from "./website-modules/utils";
|
||||
@@ -1,18 +1,13 @@
|
||||
import { FigmaIcon, GithubIcon, SlackIcon } from "@/assets/Icons";
|
||||
import AkselLogo from "@/assets/Logo";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import { FigmaIcon, GithubIcon, SlackIcon } from "components/assets";
|
||||
import Logo from "components/assets/Logo";
|
||||
import dynamic from "next/dynamic";
|
||||
/* import FooterForm from "./FooterForm"; */
|
||||
|
||||
export const EditButton = dynamic(
|
||||
() => import("components/website-modules/EditButton"),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
);
|
||||
export const EditButton = dynamic(() => import("@/web/EditButton"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
/* FooterForm is disabled to better comply with policy */
|
||||
const Footer = () => {
|
||||
return (
|
||||
<footer
|
||||
@@ -26,7 +21,6 @@ const Footer = () => {
|
||||
<Snarveier />
|
||||
<SideLenker />
|
||||
<Kontakt />
|
||||
{/* <FooterForm /> */}
|
||||
</div>
|
||||
<EditButton />
|
||||
</footer>
|
||||
@@ -36,7 +30,7 @@ const Footer = () => {
|
||||
function LogoBlock() {
|
||||
return (
|
||||
<div>
|
||||
<Logo className="fill-white" />
|
||||
<AkselLogo className="fill-white" />
|
||||
<p className="mt-4">© {new Date().getFullYear()} NAV</p>
|
||||
<p>Arbeids- og velferdsetaten</p>
|
||||
</div>
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
import { Button, Label, Textarea } from "@navikt/ds-react";
|
||||
import { IdContext } from "components/website-modules/utils/contexts/id-context";
|
||||
import { FeedbackT } from "@/types";
|
||||
import { useRouter } from "next/router";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
|
||||
const FooterForm = () => {
|
||||
const idCtx = useContext(IdContext);
|
||||
|
||||
const [contactForm, setContactForm] = useState({
|
||||
content: "",
|
||||
hasWritten: false,
|
||||
});
|
||||
|
||||
const [contentError, setContentError] = useState({ content: "" });
|
||||
const [sent, setSent] = useState({ status: false });
|
||||
|
||||
const { asPath, basePath } = useRouter();
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
let fail = false;
|
||||
if (!contactForm?.content || contactForm?.content.trim().length === 0) {
|
||||
setContentError({
|
||||
...contentError,
|
||||
content: "Melding kan ikke være tom. Fyll inn meldingen.",
|
||||
});
|
||||
fail = true;
|
||||
}
|
||||
|
||||
if (fail) return;
|
||||
setContentError({ content: "" });
|
||||
|
||||
const body: FeedbackT = {
|
||||
message: contactForm.content,
|
||||
url: `${basePath}${asPath}`,
|
||||
type: "footer",
|
||||
docId: idCtx?.id,
|
||||
};
|
||||
|
||||
fetch("/api/feedback", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
setSent({ status: true });
|
||||
setContactForm({ content: "", hasWritten: false });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setSent({ status: false });
|
||||
setContactForm({ content: "", hasWritten: false });
|
||||
setContentError({ content: "" });
|
||||
}, [asPath]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="flex w-full max-w-md flex-col lg:col-span-2 xl:col-span-1"
|
||||
data-theme="dark"
|
||||
>
|
||||
<div aria-live="polite">
|
||||
{sent.status && (
|
||||
<Label spacing as="p">
|
||||
Meldingen er sendt til Aksel, takk for tilbakemeldingen!
|
||||
</Label>
|
||||
)}
|
||||
</div>
|
||||
{!sent.status && (
|
||||
<form onSubmit={(e) => handleSubmit(e)} className="w-full">
|
||||
<div className="mb-3 flex flex-col gap-4">
|
||||
<Textarea
|
||||
className="textarea-override"
|
||||
error={contentError.content}
|
||||
autoComplete="off"
|
||||
label="Gi oss en tilbakemelding"
|
||||
value={contactForm.content}
|
||||
onChange={(e) => {
|
||||
setContactForm({
|
||||
...contactForm,
|
||||
content: e.target.value,
|
||||
hasWritten: true,
|
||||
});
|
||||
e.target.value &&
|
||||
e.target.value.trim().length !== 0 &&
|
||||
setContentError({ ...contentError, content: "" });
|
||||
}}
|
||||
description="Ikke skriv inn personopplysninger"
|
||||
minRows={2}
|
||||
/>
|
||||
</div>
|
||||
<Button size="small">Send melding</Button>
|
||||
<style>{`.textarea-override {
|
||||
--ac-textarea-bg: var(--a-surface-default);
|
||||
--ac-textarea-text: var(--a-text-default);
|
||||
}`}</style>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default FooterForm;
|
||||
@@ -10,12 +10,12 @@ import { useState } from "react";
|
||||
const LinkElement = ({ name, href, onClick }) => {
|
||||
const { asPath } = useRouter();
|
||||
return (
|
||||
<li className="flex h-11 items-center">
|
||||
<li className="my-2 flex h-11 items-center">
|
||||
<Link
|
||||
href={href}
|
||||
passHref
|
||||
className={cl(
|
||||
"hover:bg-surface-action-subtle-hover focus-visible:shadow-focus-inset relative flex h-full w-full items-center rounded px-2 focus:outline-none",
|
||||
"hover:bg-surface-action-subtle-hover focus-visible:shadow-focus relative flex h-full w-full items-center rounded px-2 focus:outline-none",
|
||||
{
|
||||
"before:bg-surface-action-selected pl-4 font-semibold before:absolute before:left-0 before:h-6 before:w-1 before:rounded-full":
|
||||
asPath.startsWith(href),
|
||||
@@ -58,6 +58,7 @@ export const Hamburger = () => {
|
||||
onClose={() => setOpen(false)}
|
||||
header={{ heading: "Meny" }}
|
||||
width="small"
|
||||
closeOnBackdropClick
|
||||
>
|
||||
<Modal.Body>
|
||||
<nav aria-label="hovedmeny">
|
||||
@@ -82,6 +83,11 @@ export const Hamburger = () => {
|
||||
name="Komponenter"
|
||||
href="/komponenter"
|
||||
/>
|
||||
<LinkElement
|
||||
onClick={() => setOpen(false)}
|
||||
name="Mønster & Maler"
|
||||
href="/monster-maler"
|
||||
/>
|
||||
<LinkElement
|
||||
onClick={() => setOpen(false)}
|
||||
name="Blogg"
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
import AkselLogo from "@/assets/Logo";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { MagnifyingGlassIcon } from "@navikt/aksel-icons";
|
||||
import { Button } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import Logo from "components/assets/Logo";
|
||||
import { Hamburger } from "components/layout/header/Hamburger";
|
||||
import dynamic from "next/dynamic";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { Hamburger } from "./Hamburger";
|
||||
|
||||
export const GlobalSearch = dynamic(() => import("./search"), {
|
||||
loading: () => (
|
||||
<Button
|
||||
variant="primary"
|
||||
className="hover:bg-deepblue-700 bg-deepblue-600 h-11"
|
||||
aria-keyshortcuts="Control+b"
|
||||
icon={
|
||||
<MagnifyingGlassIcon
|
||||
className="pointer-events-none -mt-[1px] shrink-0 text-2xl"
|
||||
aria-label="Åpne meny"
|
||||
aria-hidden
|
||||
/>
|
||||
}
|
||||
iconPosition="left"
|
||||
>
|
||||
Søk
|
||||
</Button>
|
||||
),
|
||||
ssr: false,
|
||||
});
|
||||
export const GlobalSearch = dynamic(
|
||||
() => import("../../website-modules/search/Search"),
|
||||
{
|
||||
loading: () => (
|
||||
<Button
|
||||
variant="primary"
|
||||
className="hover:bg-deepblue-700 bg-deepblue-600 h-11"
|
||||
aria-keyshortcuts="Control+b"
|
||||
icon={
|
||||
<MagnifyingGlassIcon
|
||||
className="pointer-events-none -mt-[1px] shrink-0 text-2xl"
|
||||
aria-label="Åpne meny"
|
||||
aria-hidden
|
||||
/>
|
||||
}
|
||||
iconPosition="left"
|
||||
>
|
||||
Søk
|
||||
</Button>
|
||||
),
|
||||
ssr: false,
|
||||
}
|
||||
);
|
||||
|
||||
const LinkElement = ({ name, href, prefetch = undefined }) => {
|
||||
const { asPath } = useRouter();
|
||||
@@ -55,7 +58,7 @@ const LinkElement = ({ name, href, prefetch = undefined }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Header = ({
|
||||
const Header = ({
|
||||
variant = "default",
|
||||
}: {
|
||||
variant?: "blogg" | "subtle" | "default" | "transparent";
|
||||
@@ -90,7 +93,7 @@ export const Header = ({
|
||||
}
|
||||
className="focus-visible:shadow-focus grid h-full place-items-center rounded px-2 focus:outline-none"
|
||||
>
|
||||
<Logo className="text-deepblue-800" />
|
||||
<AkselLogo className="text-deepblue-800" />
|
||||
<span className="sr-only">Aksel</span>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -103,6 +106,7 @@ export const Header = ({
|
||||
<LinkElement name="Grunnleggende" href="/grunnleggende" />
|
||||
<LinkElement name="Ikoner" href="/ikoner" prefetch={false} />
|
||||
<LinkElement name="Komponenter" href="/komponenter" />
|
||||
<LinkElement name="Mønster & Maler" href="/monster-maler" />
|
||||
<LinkElement name="Bloggen" href="/produktbloggen" />
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -116,3 +120,5 @@ export const Header = ({
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -1 +0,0 @@
|
||||
export { default as Footer } from "./footer/Footer";
|
||||
@@ -1,136 +1,79 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { AkselSidebarT } from "@/types";
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
SparklesIcon,
|
||||
TestFlaskIcon,
|
||||
TrashIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import { Detail } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { SidebarT } from "@/types";
|
||||
import { StatusTag } from "@/web/StatusTag";
|
||||
import { Box, Label, Show } from "@navikt/ds-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { useSection } from "./useSection";
|
||||
|
||||
const NavItem = ({
|
||||
link,
|
||||
const Sidebar = ({
|
||||
kategori,
|
||||
links,
|
||||
}: {
|
||||
link: { heading: string; slug: string; kategori: string; tag?: string };
|
||||
kategori: "komponenter" | "grunnleggende" | "templates";
|
||||
links: SidebarT;
|
||||
}) => {
|
||||
const { asPath } = useRouter();
|
||||
const isActive = asPath.split("#")[0] === `/${link.slug}`;
|
||||
|
||||
return (
|
||||
<li>
|
||||
<Link
|
||||
aria-current={isActive ? "page" : undefined}
|
||||
href={`/${link.slug}`}
|
||||
onClick={(e) => {
|
||||
amplitudeLogNavigation("meny", e.currentTarget.getAttribute("href"));
|
||||
}}
|
||||
className={cl(
|
||||
"hover:text-deepblue-800 focus-visible:shadow-focus text-medium pr-05 relative flex overflow-hidden py-1 pl-4 leading-snug before:rounded-full hover:before:transition-colors focus:outline-none focus-visible:z-10 focus-visible:rounded-sm",
|
||||
{
|
||||
"before:border-l-border-action-selected before:absolute before:left-0 before:top-1/2 before:h-6 before:-translate-y-1/2 before:border-l-[4px]":
|
||||
isActive,
|
||||
"text-deepblue-800 font-semibold": isActive,
|
||||
"text-text-subtle": !isActive,
|
||||
"before:absolute before:left-0 before:top-0 before:h-full before:border-l before:border-l-gray-200 hover:before:top-1/2 hover:before:h-6 hover:before:min-h-[70%] hover:before:-translate-y-1/2 hover:before:border-l-2 hover:before:border-l-gray-400":
|
||||
!isActive,
|
||||
}
|
||||
)}
|
||||
<Show asChild above="md">
|
||||
<Box
|
||||
paddingBlock="0 8"
|
||||
paddingInline="2"
|
||||
aria-label={kategori}
|
||||
as="nav"
|
||||
className="w-sidebar shrink-0 self-start"
|
||||
>
|
||||
{link.heading}
|
||||
<span className="ml-auto capitalize">
|
||||
{link?.tag === "beta" && (
|
||||
<TestFlaskIcon
|
||||
aria-hidden
|
||||
className="text-violet-800"
|
||||
fontSize="1.25rem"
|
||||
/>
|
||||
)}
|
||||
{link?.tag === "new" && (
|
||||
<SparklesIcon
|
||||
aria-hidden
|
||||
className="text-lightblue-700"
|
||||
fontSize="1.25rem"
|
||||
/>
|
||||
)}
|
||||
{link?.tag === "deprecated" && (
|
||||
<TrashIcon
|
||||
aria-hidden
|
||||
className="text-text-default"
|
||||
fontSize="1.25rem"
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
<ul className="space-y-6">
|
||||
{links.map((section) => (
|
||||
<Section key={section.value} section={section} />
|
||||
))}
|
||||
</ul>
|
||||
</Box>
|
||||
</Show>
|
||||
);
|
||||
};
|
||||
|
||||
const Dropdown = ({
|
||||
title,
|
||||
links,
|
||||
}: {
|
||||
title: string;
|
||||
links: AkselSidebarT;
|
||||
}) => {
|
||||
const [open, setOpen] = useState(true);
|
||||
function Section({ section }: { section: SidebarT[number] }) {
|
||||
const { asPath } = useRouter();
|
||||
|
||||
const isActive = (slug: string) => {
|
||||
return asPath.split("#")[0] === `/${slug}`;
|
||||
};
|
||||
return (
|
||||
<li className="peer w-full peer-data-[open=true]:mt-6" data-open={open}>
|
||||
<button
|
||||
onClick={() => setOpen((x) => !x)}
|
||||
className="min-h-8 text-text-subtle hover:text-deepblue-800 group z-10 flex w-full cursor-pointer items-center justify-between focus:outline-none"
|
||||
aria-expanded={open}
|
||||
<li>
|
||||
<Label
|
||||
as="div"
|
||||
size="small"
|
||||
textColor="subtle"
|
||||
className="min-h-8 flex items-center px-4"
|
||||
>
|
||||
<Detail
|
||||
as="span"
|
||||
className="group-focus-visible:shadow-focus group-hover:bg-surface-neutral-subtle group-active:bg-surface-neutral-subtle-hover mt-6 flex w-full items-center justify-between rounded-sm pl-2 font-semibold transition-colors first:mt-0"
|
||||
>
|
||||
{title}
|
||||
<span className="flex h-6 w-6 items-center justify-center rounded">
|
||||
<ChevronDownIcon
|
||||
className={cl("text-base", { "rotate-180": open })}
|
||||
aria-hidden
|
||||
title={!open ? `åpne ${title}` : `lukk ${title}`}
|
||||
/>
|
||||
</span>
|
||||
</Detail>
|
||||
</button>
|
||||
|
||||
<ul hidden={!open} className="pl-2">
|
||||
{links.map((z) => (
|
||||
<NavItem link={z} key={z?.heading} />
|
||||
{section.title}
|
||||
</Label>
|
||||
<ul className="space-y-px pl-3">
|
||||
{section.pages.map((page) => (
|
||||
<li
|
||||
aria-current={isActive(page.slug) ? "page" : undefined}
|
||||
key={page.slug}
|
||||
data-active={isActive(page.slug)}
|
||||
className="rounded-medium hover:bg-surface-hover min-h-8 data-active:bg-surface-selected data-active:text-deepblue-800 data-active:shadow-xsmall data-active:font-semibold relative mx-2 flex items-center transition-[background-color] ease-out"
|
||||
>
|
||||
<Link
|
||||
prefetch={false}
|
||||
href={`/${page.slug}`}
|
||||
className="text-medium min-h-8 rounded-medium focus-visible:shadow-focus flex w-full items-center justify-between gap-2 break-words px-2 focus:outline-none focus-visible:z-10"
|
||||
onClick={(e) => {
|
||||
amplitudeLogNavigation(
|
||||
"meny",
|
||||
e.currentTarget.getAttribute("href")
|
||||
);
|
||||
}}
|
||||
>
|
||||
{page.heading}
|
||||
<StatusTag size="xsmall" status={page.tag} />
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export const Sidebar = ({
|
||||
kategori,
|
||||
links,
|
||||
}: {
|
||||
kategori: "Komponenter" | "Grunnleggende";
|
||||
links: AkselSidebarT;
|
||||
}) => {
|
||||
const sections = useSection({ kategori, links });
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="ds-sidebar"
|
||||
className="toc-ignore w-sidebar bg-surface-default z-[1002] hidden shrink-0 self-start overflow-x-auto pb-8 pl-6 pr-2 md:block"
|
||||
>
|
||||
<nav aria-label={kategori}>
|
||||
<ul>
|
||||
{sections.map((kat) => (
|
||||
<Dropdown links={kat.pages} title={kat.title} key={kat.title} />
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default Sidebar;
|
||||
@@ -1,52 +0,0 @@
|
||||
import { AkselSidebarT } from "@/types";
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
grunnleggendeKategorier,
|
||||
komponentKategorier,
|
||||
} from "../../../sanity/config";
|
||||
|
||||
export const useSection = ({
|
||||
kategori,
|
||||
links,
|
||||
}: {
|
||||
kategori: "Komponenter" | "Grunnleggende";
|
||||
links: AkselSidebarT;
|
||||
}) => {
|
||||
const sections = useMemo(
|
||||
() =>
|
||||
(kategori === "Komponenter"
|
||||
? komponentKategorier
|
||||
: grunnleggendeKategorier
|
||||
)
|
||||
.map((x) => ({
|
||||
...x,
|
||||
pages: links
|
||||
.filter((y) => y?.kategori === x.value)
|
||||
.sort((a, b) => {
|
||||
if (a?.tag === "deprecated" && b?.tag === "deprecated") {
|
||||
return 0;
|
||||
} else if (a?.tag === "deprecated") {
|
||||
return 1;
|
||||
} else if (b.tag === "deprecated") {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a.sidebarindex !== null || b.sidebarindex !== null) {
|
||||
if (a.sidebarindex !== null && b.sidebarindex !== null) {
|
||||
return a.sidebarindex - b.sidebarindex;
|
||||
} else if (a.sidebarindex !== null) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return a?.heading.localeCompare(b?.heading);
|
||||
}),
|
||||
}))
|
||||
.filter((x) => !(!x.pages || x.pages.length === 0)),
|
||||
[links, kategori]
|
||||
);
|
||||
|
||||
return sections;
|
||||
};
|
||||
+43
-50
@@ -1,7 +1,7 @@
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { WithSidebar } from "./WithSidebar";
|
||||
import { SanityBlockContent } from "@/sanity-block";
|
||||
import { getBlocks } from "@/sb-util";
|
||||
import type { Meta, StoryObj } from "@storybook/react";
|
||||
import { WithSidebar } from "./WithSidebar";
|
||||
|
||||
const meta = {
|
||||
title: "Layout/WithSidebar",
|
||||
@@ -24,40 +24,53 @@ const children = (
|
||||
</>
|
||||
);
|
||||
|
||||
const baseItem = { slug: "/123", tag: "beta" as const, sidebarindex: null };
|
||||
|
||||
const sidebar = [
|
||||
{
|
||||
pages: [
|
||||
{ ...baseItem, kategori: "primitives", heading: "f", sidebarindex: 0 },
|
||||
{ ...baseItem, kategori: "primitives", heading: "e", sidebarindex: 1 },
|
||||
{
|
||||
...baseItem,
|
||||
kategori: "primitives",
|
||||
heading: "d",
|
||||
tag: "deprecated" as const,
|
||||
sidebarindex: 2,
|
||||
},
|
||||
],
|
||||
title: "Primitives",
|
||||
value: "primitives",
|
||||
},
|
||||
{
|
||||
pages: [
|
||||
{ ...baseItem, kategori: "core", heading: "b" },
|
||||
{
|
||||
...baseItem,
|
||||
kategori: "core",
|
||||
heading: "c",
|
||||
tag: "deprecated" as const,
|
||||
},
|
||||
],
|
||||
title: "Core",
|
||||
value: "core",
|
||||
},
|
||||
];
|
||||
|
||||
export const KomponenterLanding: Story = {
|
||||
args: {
|
||||
children,
|
||||
pageType: {
|
||||
type: "Komponenter",
|
||||
type: "komponenter",
|
||||
title: "Heading",
|
||||
rootUrl: "/komponenter",
|
||||
rootTitle: "Komponenter",
|
||||
},
|
||||
pageProps: { content: "1" },
|
||||
variant: "landingPage",
|
||||
footer: "footer",
|
||||
intro: "intro",
|
||||
sidebar: [
|
||||
{
|
||||
heading: "Link 1",
|
||||
slug: "#",
|
||||
kategori: "core",
|
||||
tag: "ready",
|
||||
sidebarindex: null,
|
||||
},
|
||||
{
|
||||
heading: "Link 2",
|
||||
slug: "#",
|
||||
kategori: "primitives",
|
||||
tag: "ready",
|
||||
sidebarindex: null,
|
||||
},
|
||||
{
|
||||
heading: "Link e",
|
||||
slug: "#",
|
||||
kategori: "primitives",
|
||||
tag: "ready",
|
||||
sidebarindex: null,
|
||||
},
|
||||
],
|
||||
sidebar,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -65,35 +78,15 @@ export const Komponenter: Story = {
|
||||
args: {
|
||||
children,
|
||||
pageType: {
|
||||
type: "Komponenter",
|
||||
type: "komponenter",
|
||||
title: "Heading",
|
||||
rootUrl: "/komponenter",
|
||||
rootTitle: "Komponenter",
|
||||
},
|
||||
pageProps: { content: "1" },
|
||||
variant: "page",
|
||||
footer: "footer",
|
||||
intro: "intro",
|
||||
sidebar: [
|
||||
{
|
||||
heading: "Link 1",
|
||||
slug: "#",
|
||||
kategori: "core",
|
||||
tag: "ready",
|
||||
sidebarindex: null,
|
||||
},
|
||||
{
|
||||
heading: "Link 2",
|
||||
slug: "#",
|
||||
kategori: "primitives",
|
||||
tag: "ready",
|
||||
sidebarindex: null,
|
||||
},
|
||||
{
|
||||
heading: "Link 3",
|
||||
slug: "#",
|
||||
kategori: "primitives",
|
||||
tag: "ready",
|
||||
sidebarindex: null,
|
||||
},
|
||||
],
|
||||
sidebar,
|
||||
},
|
||||
};
|
||||
+23
-15
@@ -1,10 +1,10 @@
|
||||
import Sidebar from "@/layout/sidebar/Sidebar";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { AkselSidebarT } from "@/types";
|
||||
import { SidebarT, TableOfContentsT } from "@/types";
|
||||
import { capitalize } from "@/utils";
|
||||
import TableOfContents from "@/web/toc/TableOfContents";
|
||||
import { Box, Detail, Heading, Link } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { Sidebar } from "components/layout/sidebar/Sidebar";
|
||||
import { TableOfContentsv2 } from "components/website-modules/toc/TOCv2";
|
||||
import Image from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
|
||||
@@ -16,12 +16,16 @@ export const WithSidebar = ({
|
||||
pageProps,
|
||||
variant = "landingPage",
|
||||
footer,
|
||||
toc,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
sidebar: AkselSidebarT;
|
||||
sidebar: SidebarT;
|
||||
toc?: TableOfContentsT;
|
||||
pageType: {
|
||||
type: "Komponenter" | "Grunnleggende";
|
||||
type: "komponenter" | "grunnleggende" | "templates";
|
||||
title: string;
|
||||
rootUrl: string;
|
||||
rootTitle: string;
|
||||
};
|
||||
pageProps: any;
|
||||
intro?: React.ReactNode;
|
||||
@@ -29,13 +33,17 @@ export const WithSidebar = ({
|
||||
variant?: "page" | "landingPage";
|
||||
}) => {
|
||||
return (
|
||||
<Box background="bg-default" paddingBlock="6 24">
|
||||
<Box
|
||||
background="bg-default"
|
||||
paddingBlock="6 24"
|
||||
className="min-h-screen-header"
|
||||
>
|
||||
<div className="mx-auto flex w-full max-w-screen-2xl gap-6">
|
||||
<Sidebar kategori={pageType.type} links={sidebar} />
|
||||
<main
|
||||
tabIndex={-1}
|
||||
id="hovedinnhold"
|
||||
className="md:max-w-screen-sidebar relative z-0 w-full px-4 focus:outline-none sm:pl-6 sm:pr-6 md:pl-0"
|
||||
className="relative z-0 w-full px-4 focus:outline-none sm:pl-6 sm:pr-6 md:pl-0"
|
||||
>
|
||||
<div
|
||||
className={cl(
|
||||
@@ -52,13 +60,9 @@ export const WithSidebar = ({
|
||||
<div className="z-[1]">
|
||||
{variant === "page" && pageProps?.kategori && (
|
||||
<Detail as="div" className="mb-2">
|
||||
<NextLink
|
||||
href={`/${pageType.type.toLowerCase()}`}
|
||||
passHref
|
||||
legacyBehavior
|
||||
>
|
||||
<NextLink href={pageType.rootUrl} passHref legacyBehavior>
|
||||
<Link className="text-text-default">
|
||||
{capitalize(pageType.type)}
|
||||
{pageType.rootTitle}
|
||||
</Link>
|
||||
</NextLink>{" "}
|
||||
/ {capitalize(pageProps.kategori)}
|
||||
@@ -109,8 +113,12 @@ export const WithSidebar = ({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={cl("sm:px-6 md:px-10", { flex: variant === "page" })}>
|
||||
{variant === "page" && <TableOfContentsv2 />}
|
||||
<div
|
||||
className={cl("sm:px-6 md:px-10", {
|
||||
"flex gap-10": variant === "page",
|
||||
})}
|
||||
>
|
||||
{variant === "page" && toc && <TableOfContents toc={toc} />}
|
||||
<div className="w-full">
|
||||
{children}
|
||||
{footer && <div className="w-full">{footer}</div>}
|
||||
File renamed without changes.
File renamed without changes.
+1
-1
@@ -1,3 +1,3 @@
|
||||
export { amplitudeLogNavigation } from "./event-tracking";
|
||||
export { AmplitudeEvents } from "./events";
|
||||
export { amplitude } from "./useAmplitude";
|
||||
export { default as useAmplitudeInit, amplitude } from "./useAmplitude";
|
||||
+3
-2
@@ -29,10 +29,11 @@ const useAmplitudeInit = () => {
|
||||
useEffect(() => {
|
||||
const isProdUrl = () => window.location.host === "aksel.nav.no";
|
||||
const isExample = () => window.location.pathname.includes("eksempler/");
|
||||
const isTemplate = () => window.location.pathname.includes("templates/");
|
||||
const isPreview = () => !!document.getElementById("exit-preview-id");
|
||||
|
||||
const initAmplitude = async () => {
|
||||
if (isExample()) {
|
||||
if (isExample() || isTemplate()) {
|
||||
return;
|
||||
} else if (!isProdUrl()) {
|
||||
mockAmplitude();
|
||||
@@ -59,7 +60,7 @@ const useAmplitudeInit = () => {
|
||||
.forEach(([event, eventData]) => amplitude.track(event, eventData))
|
||||
)
|
||||
.catch(async () => {
|
||||
const { logger } = await import("logger");
|
||||
const { logger } = await import("../../config/logger");
|
||||
logger.error("Failed logging batched events");
|
||||
});
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import ErrorBoundary from "@/error-boundary";
|
||||
import { useFormatedDate } from "@/hooks/useFormatedDate";
|
||||
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import {
|
||||
@@ -7,10 +8,9 @@ import {
|
||||
ResolveSlugT,
|
||||
ResolveTemaT,
|
||||
} from "@/types";
|
||||
import { abbrName } from "@/utils";
|
||||
import { BodyShort, Detail, Heading } from "@navikt/ds-react";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import NextLink from "next/link";
|
||||
import { abbrName } from "../..";
|
||||
|
||||
type ArtikkelCardProps = ResolveContributorsSingleT<
|
||||
ResolveTemaT<ResolveSlugT<AkselGodPraksisDocT>>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import ErrorBoundary from "@/error-boundary";
|
||||
import { useFormatedDate } from "@/hooks/useFormatedDate";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
|
||||
import { getAuthors } from "@/utils";
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import NextLink from "next/link";
|
||||
|
||||
type BloggCardProps = {
|
||||
|
||||
@@ -15,8 +15,10 @@ export const Designsystem: Story = {
|
||||
args: {
|
||||
node: {
|
||||
title: "button",
|
||||
|
||||
dir: {
|
||||
title: "button",
|
||||
variant: "templates",
|
||||
filer: [
|
||||
{
|
||||
_key: getKey(),
|
||||
@@ -24,6 +26,9 @@ export const Designsystem: Story = {
|
||||
innhold:
|
||||
'import { Button } from "@navikt/ds-react";\n\nconst Example = () => {\n return (\n <div className="flex flex-wrap gap-2">\n <Button variant="primary">Primary</Button>\n <Button variant="secondary">Secondary</Button>\n <Button variant="tertiary">Tertiary</Button>\n <Button variant="danger">Danger</Button>\n </div>\n );\n};',
|
||||
navn: "default",
|
||||
title: "title",
|
||||
index: 1,
|
||||
sandboxBase64: "fakebase64",
|
||||
},
|
||||
{
|
||||
_key: getKey(),
|
||||
@@ -31,6 +36,9 @@ export const Designsystem: Story = {
|
||||
innhold:
|
||||
'import { Button } from "@navikt/ds-react";\n\nconst Example = () => {\n return (\n <div className="flex flex-wrap gap-2">\n <Button variant="primary-neutral">Primary</Button>\n <Button variant="secondary-neutral">Secondary</Button>\n <Button variant="tertiary-neutral">Tertiary</Button>\n </div>\n );\n};',
|
||||
navn: "neutral",
|
||||
title: "title",
|
||||
index: 1,
|
||||
sandboxBase64: "fakebase64",
|
||||
},
|
||||
{
|
||||
_key: getKey(),
|
||||
@@ -38,6 +46,9 @@ export const Designsystem: Story = {
|
||||
innhold:
|
||||
'import { PencilIcon } from "@navikt/aksel-icons";\nimport { Button } from "@navikt/ds-react";\n\nconst Example = () => {\n return (\n <div className="flex flex-wrap gap-2">\n <Button size="small" variant="primary" icon={<PencilIcon aria-hidden />}>\n Primary\n </Button>\n <Button size="small" variant="secondary">\n Secondary\n </Button>\n <Button size="small" variant="tertiary">\n Tertiary\n </Button>\n <Button size="small" variant="danger">\n Danger\n </Button>\n </div>\n );\n};',
|
||||
navn: "small",
|
||||
title: "title",
|
||||
index: 1,
|
||||
sandboxBase64: "fakebase64",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { capitalize } from "@/components";
|
||||
import SnippetLazy from "@/cms/code-snippet/SnippetLazy";
|
||||
import ErrorBoundary from "@/error-boundary";
|
||||
import { CodeExamplesT } from "@/types";
|
||||
import { capitalize } from "@/utils";
|
||||
import {
|
||||
ExternalLinkIcon,
|
||||
LaptopIcon,
|
||||
@@ -8,9 +9,9 @@ import {
|
||||
} from "@navikt/aksel-icons";
|
||||
import { BodyLong, Button, Chips, HStack } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import SnippetLazy from "components/sanity-modules/code-snippet/SnippetLazy";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Sandbox } from "./parts/Sandbox";
|
||||
import { CodeSandbox } from "./parts/CodeSandbox";
|
||||
|
||||
const iframePadding = 192;
|
||||
@@ -34,11 +35,19 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
iframeId
|
||||
) as HTMLIFrameElement;
|
||||
const exampleIframeDOM = exampleIframe?.contentDocument;
|
||||
const exampleWrapper = exampleIframeDOM?.getElementById("ds-example");
|
||||
|
||||
let exampleWrapper: HTMLElement;
|
||||
|
||||
if (node.dir.variant === "templates") {
|
||||
exampleWrapper = exampleIframeDOM?.getElementById("__next");
|
||||
} else {
|
||||
exampleWrapper = exampleIframeDOM?.getElementById("ds-example");
|
||||
}
|
||||
|
||||
if (exampleWrapper && exampleWrapper.offsetHeight) {
|
||||
const newHeight = iframePadding + exampleWrapper.offsetHeight;
|
||||
clearInterval(waitForExampleContentToRender);
|
||||
setFrameState(newHeight < 300 ? 300 : newHeight);
|
||||
setFrameState(Math.min(Math.max(newHeight, 300), 900));
|
||||
setUnloaded(false);
|
||||
}
|
||||
|
||||
@@ -75,7 +84,7 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
const fixName = (str: string) =>
|
||||
capitalize(
|
||||
str
|
||||
.replace(/[^\w]|_/g, " ")
|
||||
.replace(/[^\wæøå]|_/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim()
|
||||
) ?? str;
|
||||
@@ -85,6 +94,7 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
}
|
||||
|
||||
const active = activeExample ?? node?.dir?.filer?.[0]?.navn;
|
||||
const demoVariant = node.dir?.variant;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -107,7 +117,7 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
);
|
||||
}}
|
||||
>
|
||||
{fixName(fil.navn)}
|
||||
{fixName(fil.title)}
|
||||
</Chips.Toggle>
|
||||
);
|
||||
})}
|
||||
@@ -138,7 +148,7 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
)}
|
||||
>
|
||||
<iframe
|
||||
src={`/eksempler/${node.dir.title}/${fil.navn.replace(
|
||||
src={`/${demoVariant}/${node.dir.title}/${fil.navn.replace(
|
||||
".tsx",
|
||||
""
|
||||
)}`}
|
||||
@@ -148,7 +158,9 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
aria-label={`${node?.dir?.title} ${fil.navn} eksempel`}
|
||||
className={cl(
|
||||
"min-w-80 block w-full max-w-full resize-x bg-white shadow-[20px_0_20px_-20px_rgba(0,0,0,0.22)]",
|
||||
{ invisible: unloaded }
|
||||
{
|
||||
invisible: unloaded,
|
||||
}
|
||||
)}
|
||||
title="Kode-eksempler"
|
||||
ref={iframeRef}
|
||||
@@ -189,6 +201,9 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
</div>
|
||||
|
||||
<HStack gap="2">
|
||||
{fil?.sandboxEnabled && (
|
||||
<Sandbox code={fil?.sandboxBase64} />
|
||||
)}
|
||||
<CodeSandbox code={fil.innhold.trim()} />
|
||||
<Button
|
||||
variant="tertiary-neutral"
|
||||
@@ -199,10 +214,9 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
target="_blank"
|
||||
className="si-ignore"
|
||||
as="a"
|
||||
href={`/eksempler/${node.dir.title}/${fil.navn.replace(
|
||||
".tsx",
|
||||
""
|
||||
)}`}
|
||||
href={`/${demoVariant}/${
|
||||
node.dir.title
|
||||
}/${fil.navn.replace(".tsx", "")}`}
|
||||
/>
|
||||
</HStack>
|
||||
</HStack>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PencilIcon } from "@navikt/aksel-icons";
|
||||
import { CodeSandboxLogo } from "@/assets/Icons";
|
||||
import { Button } from "@navikt/ds-react";
|
||||
import { getParameters } from "codesandbox/lib/api/define";
|
||||
|
||||
@@ -58,11 +58,10 @@ export const CodeSandbox = ({ code }: { code: string }) => {
|
||||
<Button
|
||||
variant="tertiary-neutral"
|
||||
size="small"
|
||||
aria-label="Codesandbox"
|
||||
type="submit"
|
||||
icon={<PencilIcon aria-hidden fontSize="1.5rem" />}
|
||||
>
|
||||
CodeSandbox
|
||||
</Button>
|
||||
icon={<CodeSandboxLogo aria-hidden />}
|
||||
/>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import { PencilIcon } from "@navikt/aksel-icons";
|
||||
import { Button } from "@navikt/ds-react";
|
||||
|
||||
export const Sandbox = ({ code }: { code: string }) => {
|
||||
return (
|
||||
<Button
|
||||
href={`/sandbox/index.html?code=${code}`}
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
as="a"
|
||||
variant="tertiary-neutral"
|
||||
size="small"
|
||||
icon={<PencilIcon aria-hidden fontSize="1.5rem" />}
|
||||
>
|
||||
Sandbox
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
+1
-1
@@ -1,8 +1,8 @@
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { ArticleListT } from "@/types";
|
||||
import { StatusTag } from "@/web/StatusTag";
|
||||
import { Heading } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { StatusTag } from "components/website-modules/StatusTag";
|
||||
import Image from "next/legacy/image";
|
||||
import Nextlink from "next/link";
|
||||
|
||||
|
||||
+3
-3
@@ -1,14 +1,13 @@
|
||||
import ErrorBoundary from "@/error-boundary";
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { abbrName } from "@/utils";
|
||||
import { abbrName, getImage } from "@/utils";
|
||||
import { BodyShort, Detail, Heading } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import NextImage from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
import { Tag } from "./Tag";
|
||||
import { useFormatedDate } from "@/hooks/useFormatedDate";
|
||||
|
||||
export type ArticleT = {
|
||||
_key: string;
|
||||
@@ -43,6 +42,7 @@ const Card = ({ article, visible, index }: CardProps) => {
|
||||
"ds_artikkel",
|
||||
"komponent_artikkel",
|
||||
"aksel_blogg",
|
||||
"templates_artikkel",
|
||||
].includes(article._type);
|
||||
|
||||
return (
|
||||
|
||||
+2
-3
@@ -1,14 +1,13 @@
|
||||
import { amplitudeLogNavigation } from "@/logging";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { getAuthors } from "@/utils";
|
||||
import { getAuthors, getImage } from "@/utils";
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import Image from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
import { ArticleT } from "./Card";
|
||||
import { Tag } from "./Tag";
|
||||
import { useFormatedDate } from "@/hooks/useFormatedDate";
|
||||
|
||||
export const Highlight = ({
|
||||
article,
|
||||
|
||||
+21
-2
@@ -1,4 +1,4 @@
|
||||
import { Heading, Label, Tag as DsTag } from "@navikt/ds-react";
|
||||
import { Tag as DsTag, Heading, Label } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
|
||||
export const Tag = ({
|
||||
@@ -65,7 +65,26 @@ export const Tag = ({
|
||||
<Comp className="text-deepblue-600 flex items-center gap-3">
|
||||
Grunnleggende
|
||||
{beta && (
|
||||
<DsTag variant="alt1" size="small">
|
||||
<DsTag
|
||||
variant="alt1"
|
||||
size="small"
|
||||
className="border-violet-300 bg-violet-50"
|
||||
>
|
||||
Beta
|
||||
</DsTag>
|
||||
)}
|
||||
</Comp>
|
||||
);
|
||||
case "templates_artikkel":
|
||||
return (
|
||||
<Comp className="text-deepblue-600 flex items-center gap-3">
|
||||
Mønster og Maler
|
||||
{beta && (
|
||||
<DsTag
|
||||
variant="alt1"
|
||||
size="small"
|
||||
className="border-violet-300 bg-violet-50"
|
||||
>
|
||||
Beta
|
||||
</DsTag>
|
||||
)}
|
||||
|
||||
@@ -9,11 +9,11 @@ export const DtList = ({ prop, parent }: { prop: any; parent: string }) => {
|
||||
return (
|
||||
<Detail
|
||||
as="div"
|
||||
className="block overflow-x-auto border border-t-0 border-gray-300 p-2 font-mono first-of-type:border-t last-of-type:rounded-b"
|
||||
className="block overflow-x-auto border border-t-0 border-gray-300 p-2 first-of-type:border-t last-of-type:rounded-b"
|
||||
>
|
||||
<dt>
|
||||
{!prop.defaultValue ? (
|
||||
<span className="font-semibold">{`${prop.name}${
|
||||
<span className="font-mono font-semibold">{`${prop.name}${
|
||||
prop?.required ? "" : "?"
|
||||
} `}</span>
|
||||
) : (
|
||||
@@ -22,21 +22,21 @@ export const DtList = ({ prop, parent }: { prop: any; parent: string }) => {
|
||||
arrow={false}
|
||||
delay={0}
|
||||
>
|
||||
<span className="mr-2 cursor-pointer border-b border-dashed border-gray-600 font-semibold">{`${
|
||||
<span className="mr-2 cursor-pointer border-b border-dashed border-gray-600 font-mono font-semibold">{`${
|
||||
prop.name
|
||||
}${prop?.required ? "" : "?"}`}</span>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<span>{prop.type ? <>{Highlighter({ type: prop.type })}</> : ""}</span>
|
||||
<span className="font-mono">
|
||||
{prop.type ? <>{Highlighter({ type: prop.type })}</> : ""}
|
||||
</span>
|
||||
</dt>
|
||||
{prop.description && (
|
||||
<dd className="whitespace-pre-wrap font-sans text-base">
|
||||
{prop.description}
|
||||
</dd>
|
||||
<dd className="whitespace-pre-wrap text-base">{prop.description}</dd>
|
||||
)}
|
||||
{prop.name === "ref" && prop.type.includes("Ref<") && (
|
||||
<dd className="font-sans text-base">
|
||||
<dd className="text-base">
|
||||
{`${parent} extends ${prop.type.slice(
|
||||
prop.type.indexOf("<") + 1,
|
||||
prop.type.lastIndexOf(">")
|
||||
|
||||
@@ -14,7 +14,7 @@ const PropTable = ({ komponent }: PropTableProps) => {
|
||||
size="xsmall"
|
||||
level="3"
|
||||
className="scroll-m-8 rounded-t-lg border border-b-0 border-gray-300 bg-gray-50 p-2"
|
||||
id={`${komponent._key}`}
|
||||
id={komponent._key}
|
||||
>
|
||||
{komponent?.title ? komponent.title : "Props"}
|
||||
</Heading>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import ErrorBoundary from "@/error-boundary";
|
||||
import { UUTableT } from "@/types";
|
||||
import KBD from "components/website-modules/KBD";
|
||||
import KBD from "@/web/KBD";
|
||||
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
import { AkselTable, AkselTableRow } from "@/web/Table";
|
||||
import React from "react";
|
||||
|
||||
type UUTableProps = { node: UUTableT };
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import ErrorBoundary from "@/error-boundary";
|
||||
import { TokenTableT } from "@/types";
|
||||
import { AkselTable, AkselTableRow } from "@/web/Table";
|
||||
import core from "@navikt/ds-css/tokens.json";
|
||||
import { Bleed, BodyLong, CopyButton, Label, Link } from "@navikt/ds-react";
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
import NextLink from "next/link";
|
||||
import ShowMore from "./parts/ShowMore";
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { CheckmarkIcon, ClipboardIcon } from "@navikt/aksel-icons";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import cl from "clsx";
|
||||
|
||||
export const Copy = ({ text, copyText }) => {
|
||||
const [active, setActive] = useState(false);
|
||||
const [canfade, setCanfade] = useState(false);
|
||||
const timeoutRef = useRef<number>();
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
timeoutRef.current && clearTimeout(timeoutRef.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleClick = () => {
|
||||
timeoutRef.current && clearTimeout(timeoutRef.current);
|
||||
setCanfade(true);
|
||||
navigator.clipboard.writeText(copyText);
|
||||
setActive(true);
|
||||
|
||||
timeoutRef.current = window.setTimeout(() => {
|
||||
setActive(false);
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
aria-live="polite"
|
||||
className="py-05 focus-visible:shadow-focus min-h-8 text-medium hover:bg-surface-neutral-subtle-hover group rounded px-1 leading-none focus:outline-none"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span className="inline-flex flex-row-reverse items-center gap-1">
|
||||
<span>
|
||||
{active ? (
|
||||
<CheckmarkIcon title="Kopiert" className="animate-textbounce" />
|
||||
) : (
|
||||
<ClipboardIcon
|
||||
title="Kopier css-variabel"
|
||||
className={cl(canfade && "animate-fadeIn")}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
<span aria-live="polite">{text}</span>
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
+1
-1
@@ -1,3 +1,4 @@
|
||||
import { AkselTable, AkselTableRow } from "@/web/Table";
|
||||
import {
|
||||
LaptopIcon,
|
||||
MobileIcon,
|
||||
@@ -6,7 +7,6 @@ import {
|
||||
TabletIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
|
||||
export const BreakpointsView = ({ cat }: { cat: string }) => {
|
||||
const breakpoints = docs[cat];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AkselTable, AkselTableRow } from "@/web/Table";
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { sanitizeName } from "../utilities";
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
|
||||
export const FontView = ({ cat }: { cat: string }) => {
|
||||
const fonts = docs[cat];
|
||||
|
||||
+7
-2
@@ -1,7 +1,7 @@
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { Grid } from "../Grid";
|
||||
import { getColorString, sanitizeName } from "../utilities";
|
||||
import { Copy } from "../Copy";
|
||||
import { CopyButton } from "@navikt/ds-react";
|
||||
|
||||
export const GlobalView = ({ cat }: { cat: string }) => {
|
||||
const colors: { name: string; value: string }[] = docs[cat];
|
||||
@@ -21,7 +21,12 @@ export const GlobalView = ({ cat }: { cat: string }) => {
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy text={sanitizeName(x.name)} copyText={x.name} />
|
||||
<CopyButton
|
||||
text={sanitizeName(x.name)}
|
||||
copyText={x.name}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{getColorString(x.value)}
|
||||
|
||||
+20
-8
@@ -2,9 +2,9 @@ import { PersonCircleIcon } from "@navikt/aksel-icons";
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import Link from "next/link";
|
||||
import color from "tinycolor2";
|
||||
import { Copy } from "../Copy";
|
||||
import { Grid } from "../Grid";
|
||||
import { getColorString, getGlobalReference, sanitizeName } from "../utilities";
|
||||
import { CopyButton } from "@navikt/ds-react";
|
||||
|
||||
export const SemanticView = ({ cat }: { cat: string }) => {
|
||||
const colors = docs[cat];
|
||||
@@ -31,9 +31,11 @@ export const SemanticView = ({ cat }: { cat: string }) => {
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("text-", ""))}
|
||||
<CopyButton
|
||||
copyText={x.name}
|
||||
text={sanitizeName(x.name.replace("text-", ""))}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
@@ -80,9 +82,11 @@ export const SemanticView = ({ cat }: { cat: string }) => {
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
<CopyButton
|
||||
text={sanitizeName(x.name.replace("icon-", ""))}
|
||||
copyText={x.name}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
@@ -121,9 +125,11 @@ export const SemanticView = ({ cat }: { cat: string }) => {
|
||||
/>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
<CopyButton
|
||||
text={sanitizeName(x.name.replace("border-", ""))}
|
||||
copyText={x.name}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
@@ -191,9 +197,11 @@ export const SemanticView = ({ cat }: { cat: string }) => {
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
<CopyButton
|
||||
text={sanitizeName(x.name.replace("surface-", ""))}
|
||||
copyText={x.name}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
@@ -243,9 +251,11 @@ export const SemanticView = ({ cat }: { cat: string }) => {
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
<CopyButton
|
||||
text={sanitizeName(x.name.replace("surface-", ""))}
|
||||
copyText={x.name}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
@@ -286,9 +296,11 @@ export const SemanticView = ({ cat }: { cat: string }) => {
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
<CopyButton
|
||||
text={sanitizeName(x.name.replace("surface-", ""))}
|
||||
copyText={x.name}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
|
||||
+4
-2
@@ -1,7 +1,7 @@
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { Copy } from "../Copy";
|
||||
import { Grid } from "../Grid";
|
||||
import { sanitizeName } from "../utilities";
|
||||
import { CopyButton } from "@navikt/ds-react";
|
||||
|
||||
export const ShadowView = ({ cat }: { cat: string }) => {
|
||||
const shadows = docs[cat];
|
||||
@@ -19,9 +19,11 @@ export const ShadowView = ({ cat }: { cat: string }) => {
|
||||
/>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
<CopyButton
|
||||
text={sanitizeName(x.name.replace("shadow-", ""))}
|
||||
copyText={x.name}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
|
||||
+4
-2
@@ -1,7 +1,7 @@
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { Copy } from "../Copy";
|
||||
import { Grid } from "../Grid";
|
||||
import { sanitizeName } from "../utilities";
|
||||
import { CopyButton } from "@navikt/ds-react";
|
||||
|
||||
export const ShapesView = ({ cat }: { cat: string }) => {
|
||||
const shapes = docs[cat];
|
||||
@@ -17,9 +17,11 @@ export const ShapesView = ({ cat }: { cat: string }) => {
|
||||
/>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
<CopyButton
|
||||
text={sanitizeName(x.name.replace("border-radius-", ""))}
|
||||
copyText={x.name}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { AkselTable, AkselTableRow } from "@/web/Table";
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
|
||||
export const SpacingView = ({ cat }: { cat: string }) => {
|
||||
const spacings = docs[cat];
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
import { CopyButton } from "@navikt/ds-react";
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import cl from "clsx";
|
||||
import { Copy } from "../Copy";
|
||||
import { Grid } from "../Grid";
|
||||
import { sanitizeName } from "../utilities";
|
||||
|
||||
@@ -36,9 +36,11 @@ export const ZindexView = ({ cat }: { cat: string }) => {
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
<CopyButton
|
||||
text={sanitizeName(token.name.replace("z-index-", ""))}
|
||||
copyText={token.name}
|
||||
size="small"
|
||||
iconPosition="right"
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 573 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user