Compare commits

..
Author SHA1 Message Date
github-actions[bot]andgithub-actions[bot] 5fec1f24f4 Version Packages (#2452)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-11-02 22:03:10 +01:00
Halvor Haugan c27c1cfe26 🐛 Datepicker lukker ikke lenger modalen den er i (#2451) 2023-11-02 21:59:06 +01:00
Ken 5a649d2282 🐛 Kunne ikke se preview av mønster forside (#2449) 2023-11-02 15:11:34 +01:00
Ken baac9cc251 [aksel.nav.no] Sidemaler for Mønster og maler (#2438)
* 🎉 Sanity-schema for mønster og maler

* 🎨 La til mønster og maler i sanity structure

* 🎨 Støtte for templates i søk

* 🎨 Sidemaler for Mønster og Maler

* 🎨 Riktig håndtering av breadcrumbs

* 🐛 Fikset story

* 🐛 Fikset search-indeksering

* 🐛 Fikset search-test

* 🐛 Fikset typo

* [aksel.nav.no] Refaktorert synking av eksempler/templates mellom kode og sanity (#2442)

* 🎨 Template pages

* 🔥 Fjernet templates fra logging

* ♻️ Refaktorert example-generering

* ✅ extractArgs tests

* ✅ filter-code tester

* ✅ Ny code-parsing tester

* 🚚 Flyttet filer

* 🎨 Oppdaterer sanity remote

* 🎨 sanity schema for templates

* 🎨 Schema for metadata in templates

* 🎨 henter nå ut metadata fra templates

* 🎨 Flyttet createId funksjon

* 🚚 rename folder

* 🎨 schema for templates i sanity

* 🐛 Fjernet dryrun fra oppdatering

* 🎨 Make sure to delete old documents after updating

* 🐛 Riktige typer for version-schema

* [aksel.nav.no] Integrert mønster og maler templates inn på aksel (#2447)

* 🎨 Template pages

* 🔥 Fjernet templates fra logging

* ♻️ Refaktorert example-generering

* ✅ extractArgs tests

* ✅ filter-code tester

* ✅ Ny code-parsing tester

* 🚚 Flyttet filer

* 🎨 Oppdaterer sanity remote

* 🎨 sanity schema for templates

* 🎨 Schema for metadata in templates

* 🎨 henter nå ut metadata fra templates

* 🎨 Flyttet createId funksjon

* 🚚 rename folder

* 🎨 schema for templates i sanity

* 🐛 Fjernet dryrun fra oppdatering

* 🎨 Make sure to delete old documents after updating

* 🐛 Riktige typer for version-schema

* 🎨 Kan nå vise eksempler på side

* 🎨 Automatisk visning av changelog

* 📝 typo

* 📝 Rename fra changelog til Endringer

* 🐛 Fikset story-typer

* 🎨 Forsideblokk for templates

* 🐛 feil riktekst ble brukt
2023-11-02 11:47:57 +01:00
Sjur d924d523e4 Update in-the-wild.yml (#2448)
Tok bort "assignees"
2023-11-02 10:38:51 +01:00
Sjur fc5a77081d Create in-the-wild.yml (#2445)
Issue template for å ta imot eksempler fra folk
2023-11-02 10:01:49 +01:00
github-actions[bot]andgithub-actions[bot] 1f3477a3e9 Version Packages (#2446)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-11-02 09:55:38 +01:00
Halvor Haugan 925450cb73 💄 Modal: Bedre håndtering av mobiler i landskapsmodus (#2444) 2023-11-02 09:30:19 +01:00
78 changed files with 1678 additions and 697 deletions

No files matched your search

+22
View File
@@ -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
+4
View File
@@ -1,5 +1,9 @@
# @navikt/aksel-icons
## 5.9.2
## 5.9.1
## 5.9.0
## 5.8.0
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-icons",
"version": "5.9.0",
"version": "5.9.2",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/ikoner",
"repository": {
+4
View File
@@ -1,5 +1,9 @@
# @navikt/aksel-stylelint
## 5.9.2
## 5.9.1
## 5.9.0
## 5.8.0
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-stylelint",
"version": "5.9.0",
"version": "5.9.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.9.2",
"@navikt/ds-tokens": "^5.9.2",
"@types/jest": "^29.0.0",
"concurrently": "7.2.1",
"copyfiles": "2.4.1",
+14
View File
@@ -1,5 +1,19 @@
# @navikt/aksel
## 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
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel",
"version": "5.9.0",
"version": "5.9.2",
"description": "Aksel command line interface. Handles css-imports, codemods and more",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -29,7 +29,7 @@
},
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
"dependencies": {
"@navikt/ds-css": "5.9.0",
"@navikt/ds-css": "5.9.2",
"axios": "1.3.6",
"chalk": "4.1.0",
"clipboardy": "^2.3.0",
+8
View File
@@ -1,5 +1,13 @@
# @navikt/ds-css
## 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
+8 -3
View File
@@ -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);
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "5.9.0",
"version": "5.9.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.9.2",
"cssnano": "6.0.0",
"fast-glob": "3.2.11",
"lodash": "4.17.21",
+18
View File
@@ -1,5 +1,23 @@
# @navikt/ds-react
## 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
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "5.9.0",
"version": "5.9.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.9.2",
"@navikt/ds-tokens": "^5.9.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,
+93 -21
View File
@@ -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,
},
},
},
},
};
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-tailwind
## 5.9.2
## 5.9.1
## 5.9.0
## 5.8.0
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tailwind",
"version": "5.9.0",
"version": "5.9.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.9.2",
"@types/jest": "^29.0.0",
"color": "4.2.3",
"jest": "^29.0.0",
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-tokens
## 5.9.2
## 5.9.1
## 5.9.0
## 5.8.0
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tokens",
"version": "5.9.0",
"version": "5.9.2",
"description": "Design-tokens for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
+268 -256
View File
File diff suppressed because it is too large. Load diff
+5 -5
View File
@@ -15,11 +15,11 @@
"website"
],
"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.9.2",
"@navikt/ds-css": "^5.9.2",
"@navikt/ds-react": "^5.9.2",
"@navikt/ds-tailwind": "^5.9.2",
"@navikt/ds-tokens": "^5.9.2"
},
"devDependencies": {
"prettier-plugin-tailwindcss": "^0.2.3"
+3 -4
View File
@@ -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.
@@ -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",
@@ -28,8 +28,10 @@ export const KomponenterLanding: Story = {
args: {
children,
pageType: {
type: "Komponenter",
type: "komponenter",
title: "Heading",
rootUrl: "/komponenter",
rootTitle: "Komponenter",
},
pageProps: { content: "1" },
variant: "landingPage",
@@ -65,8 +67,10 @@ export const Komponenter: Story = {
args: {
children,
pageType: {
type: "Komponenter",
type: "komponenter",
title: "Heading",
rootUrl: "/komponenter",
rootTitle: "Komponenter",
},
pageProps: { content: "1" },
variant: "page",
@@ -20,8 +20,10 @@ export const WithSidebar = ({
children: React.ReactNode;
sidebar: AkselSidebarT;
pageType: {
type: "Komponenter" | "Grunnleggende";
type: "komponenter" | "grunnleggende" | "templates";
title: string;
rootUrl: string;
rootTitle: string;
};
pageProps: any;
intro?: React.ReactNode;
@@ -29,7 +31,11 @@ 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
@@ -52,13 +58,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)}
@@ -95,6 +95,7 @@ describe("createSearchResult", () => {
aksel_blogg: 1,
aksel_prinsipp: 1,
aksel_standalone: 1,
templates_artikkel: 0,
};
const actual: SearchResultsT = createSearchResult(result, rawResults);
expect(actual.hits).toEqual(expected);
@@ -29,6 +29,9 @@ export function createSearchResult(
.length,
aksel_blogg: rawResults.filter((x: any) => x.item._type === "aksel_blogg")
.length,
templates_artikkel: rawResults.filter(
(x: any) => x.item._type === "templates_artikkel"
).length,
aksel_prinsipp: rawResults.filter(
(x: any) => x.item._type === "aksel_prinsipp"
).length,
@@ -114,7 +114,7 @@ export const Sidebar = ({
kategori,
links,
}: {
kategori: "Komponenter" | "Grunnleggende";
kategori: "komponenter" | "grunnleggende" | "templates";
links: AkselSidebarT;
}) => {
const sections = useSection({ kategori, links });
@@ -1,23 +1,17 @@
import { AkselSidebarT } from "@/types";
import { useMemo } from "react";
import {
grunnleggendeKategorier,
komponentKategorier,
} from "../../../sanity/config";
import { sanityCategoryLookup } from "../../../sanity/config";
export const useSection = ({
kategori,
links,
}: {
kategori: "Komponenter" | "Grunnleggende";
kategori: "komponenter" | "grunnleggende" | "templates";
links: AkselSidebarT;
}) => {
const sections = useMemo(
() =>
(kategori === "Komponenter"
? komponentKategorier
: grunnleggendeKategorier
)
sanityCategoryLookup(kategori)
.map((x) => ({
...x,
pages: links
@@ -15,8 +15,10 @@ export const Designsystem: Story = {
args: {
node: {
title: "button",
dir: {
title: "button",
variant: "templates",
filer: [
{
_key: getKey(),
@@ -24,6 +26,7 @@ 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",
index: 1,
},
{
_key: getKey(),
@@ -31,6 +34,7 @@ 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",
index: 1,
},
{
_key: getKey(),
@@ -38,6 +42,7 @@ 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",
index: 1,
},
],
},
@@ -75,7 +75,7 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
const fixName = (str: string) =>
capitalize(
str
.replace(/[^\w]|_/g, " ")
.replace(/[^\wæøå]|_/g, " ")
.replace(/\s+/g, " ")
.trim()
) ?? str;
@@ -43,6 +43,7 @@ const Card = ({ article, visible, index }: CardProps) => {
"ds_artikkel",
"komponent_artikkel",
"aksel_blogg",
"templates_artikkel",
].includes(article._type);
return (
@@ -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>
)}
@@ -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();
+1 -1
View File
@@ -17,7 +17,7 @@
"e2e:ci-full": "ts-node ./e2e/genUrls.ts && FULL_TEST=true yarn start-server-and-test start http://localhost:3000 playwright",
"update:props": "ts-node --project tsconfig.tsnode.json ./scripts/update-props",
"update:tokens": "ts-node --project tsconfig.tsnode.json ./scripts/update-tokens",
"update:eksempler": "ts-node --project tsconfig.tsnode.json ./scripts/examples/update-sanity",
"update:eksempler": "ts-node --project tsconfig.tsnode.json ./scripts/update-examples/update-sanity",
"update:changelog": "ts-node --project tsconfig.tsnode.json ./scripts/changelog",
"update:sanity": "yarn update:tokens && yarn update:props && yarn update:eksempler && yarn update:changelog",
"analyze": "cross-env ANALYZE=true yarn build",
+2 -1
View File
@@ -1,6 +1,6 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { createClient } from "next-sanity";
import { clientConfig } from "../../sanity/config";
import type { NextApiRequest, NextApiResponse } from "next";
const previewClient = createClient({
...clientConfig,
@@ -23,6 +23,7 @@ const landingPages = [
"god-praksis",
"produktbloggen",
"prinsipper",
"monster-maler",
];
export default async function preview(
@@ -40,7 +40,7 @@ export const query = `{
${destructureBlocks}
},
},
"seo": *[_type == "komponenter_landingsside"][0].seo.image,
"seo": *[_type == "grunnleggende_landingsside"][0].seo.image,
${sidebarQuery}
}`;
@@ -102,7 +102,12 @@ const Page = ({ page, sidebar, seo, publishDate }: PageProps["props"]) => {
<Header />
<WithSidebar
sidebar={sidebar}
pageType={{ type: "Grunnleggende", title: page?.heading }}
pageType={{
type: "grunnleggende",
title: page?.heading,
rootUrl: "/grunnleggende",
rootTitle: "Grunnleggende",
}}
intro={
<Detail as="div">
<div className="mt-2 flex flex-wrap items-center gap-3">
@@ -62,7 +62,12 @@ const Page = ({ page, sidebar, links }: PageProps["props"]) => {
<Header />
<WithSidebar
sidebar={sidebar}
pageType={{ type: "Grunnleggende", title: "Grunnleggende" }}
pageType={{
type: "grunnleggende",
title: "Grunnleggende",
rootUrl: "/grunnleggende",
rootTitle: "Grunnleggende",
}}
intro={<Ingress className="text-text-on-action">{page?.intro}</Ingress>}
pageProps={page}
>
+1 -1
View File
@@ -97,7 +97,7 @@ export const query = `*[_type == "aksel_forside"][0]{
seo,
${contributorsAll}
},
"komponenter": *[_type in ["komponent_artikkel", "ds_artikkel"] && defined(publishedAt) && !(_id in ^.highlights[]._ref)] | order(publishedAt desc)[0...3]{
"komponenter": *[_type in ["komponent_artikkel", "ds_artikkel", "templates_artikkel"] && defined(publishedAt) && !(_id in ^.highlights[]._ref)] | order(publishedAt desc)[0...3]{
_type,
_id,
heading,
@@ -261,7 +261,12 @@ const Page = ({
<Header />
<WithSidebar
sidebar={sidebar}
pageType={{ type: "Komponenter", title: page?.heading }}
pageType={{
type: "komponenter",
title: page?.heading,
rootUrl: "/komponenter",
rootTitle: "Komponenter",
}}
pageProps={page}
variant="page"
intro={
@@ -74,7 +74,12 @@ const Page = ({ page, sidebar, links }: PageProps["props"]) => {
<Header />
<WithSidebar
sidebar={sidebar}
pageType={{ type: "Komponenter", title: "Komponenter" }}
pageType={{
type: "komponenter",
title: "Komponenter",
rootUrl: "/komponenter",
rootTitle: "Komponenter",
}}
intro={
<Ingress className="text-text-on-action">
{page?.intro}
@@ -0,0 +1,194 @@
import { dateStr } from "@/components";
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity/client.server";
import { getDocumentsTmp } from "@/sanity/interface";
import { destructureBlocks, sidebarQuery } from "@/sanity/queries";
import {
AkselSidebarT,
AkselTemplatesDocT,
ArticleListT,
CodeExampleSchemaT,
NextPageT,
ResolveContributorsT,
ResolveSlugT,
} from "@/types";
import { Detail, Heading } from "@navikt/ds-react";
import { WithSidebar } from "components/layout/WithSidebar";
import Footer from "components/layout/footer/Footer";
import { Header } from "components/layout/header/Header";
import IntroSeksjon from "components/sanity-modules/intro-seksjon/IntroSeksjon";
import { StatusTag } from "components/website-modules/StatusTag";
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
import { SEO } from "components/website-modules/seo/SEO";
import { GetStaticPaths, GetStaticProps } from "next/types";
import { Suspense, lazy } from "react";
import NotFotfund from "../404";
type PageProps = NextPageT<{
page: ResolveContributorsT<ResolveSlugT<AkselTemplatesDocT>>;
sidebar: AkselSidebarT;
seo: any;
refs: ArticleListT;
publishDate: string;
}>;
const query = `{
"page": *[_type == "templates_artikkel" && slug.current == $slug] | order(_updatedAt desc)[0]
{
...,
"slug": slug.current,
content[]{
...,
${destructureBlocks}
},
},
"seo": *[_type == "templates_landingsside"][0].seo.image,
${sidebarQuery}
}`;
export const getStaticPaths: GetStaticPaths = async () => {
return {
paths: await getDocumentsTmp("templates_artikkel").then((paths) =>
paths.map((slug) => ({
params: {
slug: slug.split("/").filter((x) => x !== "monster-maler"),
},
}))
),
fallback: "blocking",
};
};
export const getStaticProps: GetStaticProps = async ({
params: { slug },
preview = false,
}: {
params: { slug: string[] };
preview?: boolean;
}): Promise<PageProps> => {
const { page, sidebar, seo } = await getClient().fetch(query, {
slug: `monster-maler/${slug.slice(0, 2).join("/")}`,
type: "templates_artikkel",
});
return {
props: {
page,
slug: slug.slice(0, 2).join("/"),
seo,
sidebar,
preview,
title: page?.heading ?? "",
id: page?._id ?? "",
refs: [],
publishDate: await dateStr(page?._updatedAt ?? page?._createdAt),
},
notFound: !page && !preview,
revalidate: 60,
};
};
const Page = ({ page, sidebar, seo, publishDate }: PageProps["props"]) => {
if (!page) {
return <NotFotfund />;
}
const metadata: CodeExampleSchemaT["metadata"] = page.content.find(
(x) => x._type === "kode_eksempler"
)?.dir?.metadata;
return (
<>
<SEO
title={page?.heading}
description={page?.seo?.meta}
image={page?.seo?.image ?? seo}
/>
<Header />
<WithSidebar
sidebar={sidebar}
pageType={{
type: "templates",
title: page?.heading,
rootUrl: "/monster-maler",
rootTitle: "Mønster og Maler",
}}
intro={
<Detail as="div">
<div className="mt-2 flex flex-wrap items-center gap-3">
<span>
Oppdatert <time>{publishDate}</time>
</span>
<StatusTag showStable status={page?.status?.tag} />
</div>
</Detail>
}
pageProps={page}
variant="page"
>
<IntroSeksjon node={page?.intro} />
<SanityBlockContent blocks={page["content"]} />
{metadata && metadata.changelog && (
<>
<Heading
tabIndex={-1}
id="changelog"
level="2"
size="large"
className="max-w-text text-deepblue-800 mb-4 mt-12 scroll-mt-20 focus:outline-none"
>
Endringer
</Heading>
<AkselTable
th={[
{ text: "Dato" },
{ text: "Versjon" },
{ text: "Endringer" },
]}
>
{metadata.changelog
.sort((a, b) => a.version - b.version)
.map((log) => (
<AkselTableRow
key={log.version}
tr={[
{ text: log.date },
{ text: log.version },
{ text: log.description },
]}
/>
))}
</AkselTable>
</>
)}
</WithSidebar>
<Footer />
</>
);
};
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<Suspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={query}
params={{
slug: `monster-maler/${props.slug}`,
type: "templates_artikkel",
}}
props={props}
/>
</Suspense>
);
}
return <Page {...props} />;
};
export default Wrapper;
@@ -0,0 +1,138 @@
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity/client.server";
import { landingPageQuery, sidebarQuery } from "@/sanity/queries";
import {
AkselLandingPageDocT,
AkselSidebarT,
ArticleListT,
NextPageT,
} from "@/types";
import { BodyLong, Heading } from "@navikt/ds-react";
import cl from "clsx";
import { WithSidebar } from "components/layout/WithSidebar";
import Footer from "components/layout/footer/Footer";
import { Header } from "components/layout/header/Header";
import ComponentOverview from "components/sanity-modules/component-overview/ComponentOverview";
import { SEO } from "components/website-modules/seo/SEO";
import { GetStaticProps } from "next/types";
import { Suspense, lazy } from "react";
import { templatesKategorier } from "../../sanity/config";
type PageProps = NextPageT<{
page: AkselLandingPageDocT;
sidebar: AkselSidebarT;
links: ArticleListT;
}>;
export const query = `{${sidebarQuery}, ${landingPageQuery(
"templates"
)}, "links": *[_type == "templates_artikkel" && defined(kategori)]{_id,heading,"slug": slug,status,kategori,"sidebarindex": sidebarindex}}`;
export const getStaticProps: GetStaticProps = async ({
preview = false,
}): Promise<PageProps> => {
const { sidebar, page, links } = await getClient().fetch(query, {
type: "templates_artikkel",
});
return {
props: {
page,
sidebar,
links,
slug: "/monster-maler",
preview,
title: "Forside Mønster og Maler",
id: page?._id ?? "",
},
revalidate: 60,
notFound: false,
};
};
const Page = ({ page, sidebar, links }: PageProps["props"]) => {
return (
<>
<SEO
title="Mønster og Maler"
description={page?.seo?.meta}
image={page?.seo?.image}
/>
<Header />
<WithSidebar
sidebar={sidebar}
pageType={{
type: "templates",
title: "Mønster og Maler",
rootUrl: "/monster-maler",
rootTitle: "Mønster og Maler",
}}
intro={
<BodyLong size="large" className="text-text-on-action">
{page?.intro}
</BodyLong>
}
pageProps={page}
>
{templatesKategorier
.filter(
(kat) => links?.filter((x) => x.kategori === kat.value).length > 0
)
.map((kat, i) => (
<div
key={i}
className={cl({ "pb-8": i + 1 < templatesKategorier.length })}
>
<Heading
level="2"
size="large"
spacing
className="text-deepblue-800 scoll-mt-20"
id={kat.value}
>
{kat.title}
</Heading>
<div>
{page?.[`ingress_${kat.value}`] && (
<BodyLong size="large" className="mb-4 only:mb-7">
{page[`ingress_${kat.value}`]}
</BodyLong>
)}
{page?.[`intro_${kat.value}`] && (
<SanityBlockContent blocks={page[`intro_${kat.value}`]} />
)}
</div>
<ComponentOverview
node={links.filter((x) => x.kategori === kat.value)}
/>
</div>
))}
</WithSidebar>
<Footer />
</>
);
};
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<Suspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={query}
props={props}
params={{
type: "templates_artikkel",
}}
/>
</Suspense>
);
}
return <Page {...props} />;
};
export default Wrapper;
@@ -0,0 +1,10 @@
{
"version": 1,
"changelog": [
{
"description": "Oppdaterte X Y og Z",
"date": "31.10.2023",
"version": 1
}
]
}
@@ -0,0 +1,14 @@
import { VStack } from "@navikt/ds-react";
export default function Example() {
const lorem =
"Hvis du ikke bor sammen med begge foreldrene dine, kan du ha rett til barnebidrag fra en eller begge foreldre mens du fullfører videregående skole eller tilsvarende.";
return <VStack gap="4">{lorem}</VStack>;
}
export const args = {
index: 1,
title: "Med søk",
desc: "abc",
};
+22 -16
View File
@@ -12,6 +12,7 @@ export const allArticleDocuments = [
"aksel_blogg",
"aksel_prinsipp",
"aksel_standalone",
"templates_artikkel",
] as const;
export const previews = [
@@ -21,12 +22,14 @@ export const previews = [
"aksel_blogg",
"aksel_prinsipp",
"aksel_standalone",
"templates_artikkel",
];
export const landingsider = [
{ name: "godpraksis_landingsside", url: "god-praksis" },
{ name: "blogg_landingsside", url: "produktbloggen" },
{ name: "grunnleggende_landingsside", url: "grunnleggende" },
{ name: "templates_landingsside", url: "monster-maler" },
{ name: "komponenter_landingsside", url: "komponenter" },
{ name: "prinsipper_landingsside", url: "prinsipper" },
];
@@ -46,7 +49,10 @@ export const grunnleggendeKategorier = [
{ title: "Kode", value: "kode" },
];
export const monsterKategorier = [];
export const templatesKategorier = [
{ title: "Mønster", value: "monster" },
{ title: "Maler", value: "maler" },
];
export const bloggKategorier = [
{ title: "Nytt fra teamene", value: "nytt-fra-teamene" },
@@ -58,19 +64,19 @@ export const prinsippKategorier = [
{ title: "Brukeropplevelse", value: "brukeropplevelse" },
];
const allDocumentTypes = [
"aksel_artikkel",
"aksel_blogg",
"aksel_prinsipp",
"aksel_standalone",
"blogg_landingsside",
"ds_artikkel",
"godpraksis_landingsside",
"grunnleggende_landingsside",
"komponent_artikkel",
"komponenter_landingsside",
"prinsipper_landingsside",
"aksel_forside",
];
export const sanityCategoryLookup = (
category: "komponenter" | "grunnleggende" | "templates"
) => {
const _category = category.toLowerCase();
export const allDocsRef = allDocumentTypes.map((x) => ({ type: x }));
switch (_category) {
case "komponenter":
return komponentKategorier;
case "grunnleggende":
return grunnleggendeKategorier;
case "templates":
return templatesKategorier;
default:
return [];
}
};
@@ -25,6 +25,7 @@ export async function sitemapPages(
"godpraksis": *[_type == "godpraksis_landingsside"][0]._updatedAt,
"grunnleggende": *[_type == "grunnleggende_landingsside"][0]._updatedAt,
"komponenter": *[_type == "komponenter_landingsside"][0]._updatedAt,
"templates": *[_type == "templates_landingsside"][0]._updatedAt,
"blogg": *[_type == "blogg_landingsside"][0]._updatedAt,
}`
);
@@ -35,6 +36,7 @@ export async function sitemapPages(
{ path: "ikoner", lastmod: undefined },
{ path: "grunnleggende", lastmod: pages.grunnleggende },
{ path: "komponenter", lastmod: pages.komponenter },
{ path: "monster-maler", lastmod: pages.templates },
{ path: "produktbloggen", lastmod: pages.blogg },
...temaer.map((x) => ({
path: `god-praksis/${x.path}`,
@@ -61,7 +63,7 @@ export const getAkselDocuments = async (
};
export const getDocumentsTmp = async (
source: "komponent_artikkel" | "ds_artikkel",
source: "komponent_artikkel" | "ds_artikkel" | "templates_artikkel",
token?: string
): Promise<string[]> => {
const docs = await getDocuments(source, token);
@@ -91,6 +93,7 @@ async function getDocuments(
| "aksel_blogg"
| "aksel_prinsipp"
| "aksel_standalone"
| "templates_artikkel"
| "all",
token?: string
): Promise<{ slug: string; lastmod: string }[]> {
@@ -107,6 +110,7 @@ async function getDocuments(
"aksel_blogg",
"aksel_prinsipp",
"aksel_standalone",
"templates_artikkel",
]
: [source],
}
@@ -1,4 +1,4 @@
import { grunnleggendeKategorier, komponentKategorier } from "../config";
import { sanityCategoryLookup } from "../config";
const markDef = `
markDefs[]{
@@ -95,7 +95,6 @@ const defaultBlock = `
_type == "kode_eksempler" =>{
...,
dir->,
filnavn->,
},
_type == "kode_ref" => @->,
${tips},
@@ -185,12 +184,7 @@ export const sidebarQuery = `"sidebar": *[_type == $type && defined(kategori)] {
}`;
export const landingPageQuery = (t) => {
const kat =
t === "komponenter"
? komponentKategorier
: t === "grunnleggende"
? grunnleggendeKategorier
: [];
const kat = sanityCategoryLookup(t);
return `"page": *[_type == "${t}_landingsside"][0]{
...,
@@ -6,6 +6,7 @@ import {
landingsider,
previews,
prinsippKategorier,
templatesKategorier,
} from "../../config";
import { Iframe } from "./IFrame";
@@ -18,6 +19,7 @@ import {
LightBulbIcon,
NewspaperIcon,
PencilBoardIcon,
RectangleSectionsIcon,
TokenIcon,
} from "@navikt/aksel-icons";
import differenceInMonths from "date-fns/differenceInMonths";
@@ -33,6 +35,8 @@ const filtered = [
"ds_artikkel",
"komponent_artikkel",
"grunnleggende_landingsside",
"templates_landingsside",
"templates_artikkel",
"komponenter_landingsside",
"media.tag",
"editor",
@@ -231,6 +235,26 @@ export const structure = async (
)),
])
),
S.listItem()
.title("Mønster og Maler")
.icon(RectangleSectionsIcon)
.child(
S.list()
.title("Mønster og Maler")
.items([
S.documentListItem()
.title(`Landingsside`)
.schemaType(`templates_landingsside`)
.id(`templates_landingsside_id1`),
S.divider(),
...(await PanesWithCount(
"templates_artikkel",
templatesKategorier,
getClient,
S
)),
])
),
S.listItem()
.title("Komponenter")
.icon(ComponentIcon)
@@ -322,7 +346,7 @@ export const structure = async (
]) */
),
S.listItem()
.title("Komponent-eksempler Designsystemet")
.title("Eksempler/Templates")
.child(
S.documentList()
.title("Eksempler")
@@ -19,3 +19,5 @@ export * from "./publiseringsflyt";
export * from "./redirects";
export * from "./skrivehjelp";
export * from "./standalone-artikkel";
export * from "./templates/artikkel";
export * from "./templates/landingsside";
@@ -14,13 +14,26 @@ export const KodeEksempelDoc = defineType({
validation: (Rule) => Rule.required(),
readOnly: true,
}),
defineField({
title: "Toggle om eksemplet er et dir eller filnavn",
name: "dir",
type: "boolean",
title: "Variant",
name: "variant",
type: "string",
validation: (Rule) => Rule.required(),
initialValue: false,
readOnly: true,
options: {
list: [
{
title: "Eksempler",
value: "eksempler",
},
{
title: "Templates",
value: "templates",
},
],
layout: "radio",
},
}),
defineField({
title: "Filer",
@@ -36,21 +49,52 @@ export const KodeEksempelDoc = defineType({
{ title: "Filnavn", name: "navn", type: "string" },
{ title: "Innhold", name: "innhold", type: "string" },
{ title: "Beskrivelse", name: "description", type: "text" },
{ title: "Index", name: "index", type: "number" },
],
},
],
}),
defineField({
title: "Metadata",
name: "metadata",
type: "object",
readOnly: true,
fields: [
defineField({
title: "Version",
name: "version",
type: "number",
}),
defineField({
title: "Changelog",
name: "changelog",
type: "array",
of: [
{
title: "Changelog-entry",
name: "entry",
type: "object",
fields: [
{ title: "Description", name: "description", type: "string" },
{ title: "Version", name: "version", type: "number" },
{ title: "Date", name: "date", type: "string" },
],
},
],
}),
],
}),
],
preview: {
select: {
title: "title",
dir: "dir",
variant: "variant",
},
prepare(selection) {
const { title, dir } = selection;
const { title, variant } = selection;
return {
title,
subtitle: dir ? "Alle kode-eksempler" : "Spesifikt kode-eksempel",
subtitle: variant,
};
},
},
@@ -0,0 +1,89 @@
import { defineField, defineType } from "sanity";
import { templatesKategorier } from "../../../config";
import { artikkelPreview } from "../presets/artikkel-preview";
import { editorField } from "../presets/editors";
import { groups } from "../presets/groups";
import { hiddenFields } from "../presets/hidden-fields";
import { oppdateringsvarsel } from "../presets/oppdateringsvarsel";
import { SEOFields } from "../presets/seo";
import { kategoriSlug } from "../presets/slug";
import { titleField } from "../presets/title-field";
const prefix = "monster-maler/";
export const TemplatesArtikkel = defineType({
title: "Mønster/Maler artikkel",
name: "templates_artikkel",
type: "document",
groups,
...artikkelPreview("Mønster/Maler"),
fields: [
oppdateringsvarsel,
...hiddenFields,
titleField,
editorField,
defineField({
title: "Kategori",
name: "kategori",
type: "string",
validation: (Rule) => Rule.required(),
options: {
list: templatesKategorier.map((x) => ({
title: x.title,
value: x.value,
})),
layout: "radio",
},
}),
kategoriSlug(prefix),
defineField({
title: "Metadata",
name: "status",
group: "innhold",
type: "object",
fields: [
{
title: "Status",
name: "tag",
type: "string",
initialValue: "new",
options: {
list: [
{ title: "Beta", value: "beta" },
{ title: "New", value: "new" },
{ title: "Stable", value: "ready" },
{ title: "Deprecated", value: "deprecated" },
],
layout: "radio",
},
},
{
name: "bilde",
title: "Thumbnail",
type: "image",
},
],
options: {
collapsible: true,
collapsed: false,
},
}),
defineField({
title: "Sidebar index",
description:
"Overstyrer sortering av artikler i sidebar. Hvis feltet er tomt, sorteres den alfabetisk.",
name: "sidebarindex",
type: "number",
group: "settings",
}),
defineField({
title: "Innhold",
description:
"Innholdet i artikkelen er riktekst. Tips: klikk på ikon i høyre hjørne for å skrive i fullskjerm.",
name: "content",
type: "riktekst_templates",
group: "innhold",
}),
SEOFields,
],
});
@@ -0,0 +1,49 @@
import { HouseIcon } from "@navikt/aksel-icons";
import { defineField, defineType } from "sanity";
import { templatesKategorier } from "../../../config";
import { groups } from "../presets/groups";
import { SEOFields } from "../presets/seo";
const views = () => {
const list = [];
templatesKategorier.forEach((kat) => {
list.push(
defineField({
title: `Ingress ${kat.title}`,
name: `ingress_${kat.value}`,
type: "text",
rows: 2,
})
);
list.push(
defineField({
title: `Intro ${kat.title}`,
name: `intro_${kat.value}`,
type: "riktekst_standard",
})
);
});
return list;
};
export const TemplatesLandingSide = defineType({
title: "Landingsside Mønster og Maler",
name: "templates_landingsside",
type: "document",
groups,
fields: [
defineField({
title: "Intro",
name: "intro",
type: "text",
}),
...views(),
SEOFields,
],
preview: {
prepare: () => ({
title: "Landingsside Mønster og Maler",
media: HouseIcon,
}),
},
});
@@ -23,6 +23,10 @@ export const schema: SchemaPluginOptions = {
document.GrunnleggendeLandingSide,
document.GrunnleggendeArtikkel,
/* Møster og Maler */
document.TemplatesLandingSide,
document.TemplatesArtikkel,
/* God-praksis */
document.Tema,
document.GodPraksisArtikkel,
@@ -58,6 +62,7 @@ export const schema: SchemaPluginOptions = {
object.RiktekstKomponent,
object.RiktekstEnkel,
object.RiktekstGrunnleggende,
object.RiktekstTemplates,
object.RiktekstStandard,
object.RiktekstPrinsipp,
object.RiktekstStandalone,
@@ -20,19 +20,17 @@ export const KodeEksempler = defineType({
name: "dir",
type: "reference",
to: [{ type: "kode_eksempler_fil" }],
options: {
filter: "dir == true",
},
}),
],
preview: {
select: {
dir: "dir.title",
variant: "dir.variant",
},
prepare({ dir }) {
prepare({ dir, variant }) {
return {
title: "Komponent-demo",
subtitle: dir ?? "",
subtitle: `${variant} | ${dir}`,
media: ComponentIcon,
};
},
@@ -131,6 +131,7 @@ const Riktekst = (
type:
| "god-praksis"
| "grunnleggende"
| "templates"
| "komponent"
| "prinsipp"
| "standard"
@@ -169,6 +170,8 @@ const Riktekst = (
"token_ref",
];
const templates = ["kode_eksempler"];
const grunnleggende = ["spesial_seksjon"];
fields.push(...standard);
@@ -186,6 +189,9 @@ const Riktekst = (
case "accordion":
fields = [...accordion];
break;
case "templates":
fields.push(...templates);
break;
default:
break;
}
@@ -256,3 +262,11 @@ export const RiktekstStandalone = {
of: Riktekst("standalone"),
icon: FileTextIcon,
};
export const RiktekstTemplates = {
title: "Riktekst",
name: "riktekst_templates",
type: "array",
of: Riktekst("templates"),
icon: FileTextIcon,
};
@@ -1,11 +0,0 @@
import { getExampleFiles } from "../get-example-files";
describe("Reading code-examples files", () => {
test("getExampleFiles", () => {
const files = getExampleFiles();
expect(files.length).toBeTruthy();
});
});
export {};
@@ -1,89 +0,0 @@
import { getExampleFiles } from "../get-example-files";
import {
filterCode,
getDesc,
getIndex,
readExampleFile,
readExampleFiles,
} from "../read-example-files";
const d = `import { Button } from "@navikt/ds-react";
import { withDsExample } from "components/website-modules/examples/withDsExample";
const Example = () => {
return <Button>Primary</Button>;
};`;
const testStr1 = `${d}
export default withDsExample(Example);
export const args = {
index: 0,
desc: "description-text"
};`;
const testStr2 = `${d}
export default withDsExample(Example);
export const args = {
};`;
const testStr3 = `${d}
export default withDsExample(Example);
`;
const testStr4 = `${d}
export default withDsExample(Example, {
variant: "full",
showBreakpoints: true,
});
export const args = {
};`;
const testStr4Res = `import { Button } from "@navikt/ds-react";
const Example = () => {
return <Button>Primary</Button>;
};`;
const codeRes = `import { Button } from "@navikt/ds-react";
const Example = () => {
return <Button>Primary</Button>;
};`;
describe("Reading code-examples", () => {
test("getDesc", () => {
expect(getDesc(testStr1)).toEqual("description-text");
expect(getDesc(testStr2)).toBeNull();
expect(getDesc(testStr3)).toBeNull();
});
test("getIndex", () => {
expect(getIndex(testStr1)).toEqual(0);
expect(getIndex(testStr2)).toEqual(1);
expect(getIndex(testStr3)).toEqual(1);
});
test("filterCode", () => {
expect(filterCode(testStr1)).toEqual(codeRes);
expect(filterCode(testStr4)).toEqual(testStr4Res);
});
test("readExampleFiles", () => {
const files = getExampleFiles();
expect(readExampleFiles(files[0].path.split("/")[0])).toBeTruthy();
});
test("readExampleFile", () => {
const files = getExampleFiles();
expect(readExampleFile(files[0].path)).toBeTruthy();
});
});
export {};
@@ -1,26 +0,0 @@
import path from "path";
import fs from "fs";
/**
* @returns array of all paths and if they are a dir or not
*/
export const getExampleFiles = (): { path: string; dir: boolean }[] => {
const examplePath = path.resolve(process.cwd(), `pages/eksempler`);
const res = [];
if (fs.existsSync(examplePath)) {
const dirs = fs
.readdirSync(examplePath, { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name);
dirs.map((dir) => {
const dirPath = path.resolve(process.cwd(), `pages/eksempler/${dir}`);
const files = fs.readdirSync(dirPath);
files.forEach((file) => res.push({ path: `${dir}/${file}`, dir: false }));
});
dirs.forEach((dir) => res.push({ path: `${dir}`, dir: true }));
}
return res;
};
@@ -1 +0,0 @@
export * from "./read-example-files";
@@ -1,105 +0,0 @@
import path from "path";
import fs from "fs";
import JSON5 from "json5";
export const getDesc = (str: string) => {
const args = str.match(/export const args = {([^}]+)}/)?.[1];
if (args) {
const obj = JSON5.parse(`{${args}}`);
return obj?.desc ?? null;
}
return null;
};
export const filterCode = (code: string) => {
const exampleList = code
.substring(0, code.indexOf("export const args ="))
.split("\n")
.filter((x) => !x.includes("examples/withDsExample"));
const storyIndex = exampleList.findIndex(
(x) => x === "/* Storybook story */"
);
if (storyIndex === -1) {
return exampleList
.join("\n")
.replace(/^\s*export default withDsExample\(Example[\s\S]*?;\s*/gm, "")
.trim();
}
return exampleList
.filter((_, idx) => idx < storyIndex || idx > storyIndex + 3)
.join("\n")
.replace(/^\s*export default withDsExample\(Example[\s\S]*?;\s*/gm, "")
.trim();
};
export const getIndex = (str: string) => {
const args = str.match(/export const args = {([^}]+)}/)?.[1];
if (args) {
const obj = JSON5.parse(`{${args}}`);
return obj?.index ?? 1;
}
return 1;
};
type FileT = { innhold: string; navn: string; description: string | null }[];
const sortResult = (res: FileT) => {
return res.sort((a, b) => {
return getIndex(a.innhold) - getIndex(b.innhold);
});
};
/**
*
* @param dirName Directory name
* @returns File-content for files in dir + filename
*/
export const readExampleFiles = (dirName: string): FileT => {
const examplePath = path.resolve(process.cwd(), `pages/eksempler/${dirName}`);
if (fs.existsSync(examplePath)) {
const files = fs.readdirSync(examplePath);
const res = files.map((file) => {
let code = "";
const filepath = path.resolve(
process.cwd(),
`pages/eksempler/${dirName}/${file}`
);
code = fs.readFileSync(filepath, "utf-8");
return {
innhold: code,
navn: file.replace(".tsx", ""),
description: getDesc(code),
};
});
return sortResult(res).map((x) => ({
...x,
innhold: filterCode(x.innhold),
}));
}
return [];
};
/**
*
* @param fileName example filename including dir: button/primary.tsx
* @returns File-content for file + filename
*/
export const readExampleFile = (
fileName: string
): { innhold: string; navn: string } => {
const examplePath = path.resolve(
process.cwd(),
`pages/eksempler/${fileName}`
);
let code = "";
code = fs.readFileSync(examplePath, "utf-8");
return {
innhold: filterCode(code),
navn: fileName.replace(".tsx", ""),
};
};
@@ -1,48 +0,0 @@
import dotenv from "dotenv";
import { readExampleFile, readExampleFiles } from ".";
import { noCdnClient } from "../../sanity/interface/client.server";
import { getExampleFiles } from "./get-example-files";
dotenv.config();
const createId = (s: string) =>
`kode_eksempelid_${s
.match(/\w/g)
?.join("")
?.match(/\D/g)
?.join("")}`.toLowerCase();
const main = async () => {
const token = process.env.SANITY_WRITE_KEY;
const transactionClient = noCdnClient(token).transaction();
const examples = getExampleFiles();
const docs = await noCdnClient(token).fetch(
`*[_type == "kode_eksempler_fil"]`
);
/* Delete fremoved examples */
for (const doc of docs) {
if (!examples.some((x) => doc._id === createId(x.path))) {
transactionClient.delete(doc._id);
}
}
for (const ex of examples) {
const data = {
_id: createId(ex.path),
_type: "kode_eksempler_fil",
title: ex.path,
dir: ex.dir,
filer: ex.dir ? readExampleFiles(ex.path) : [readExampleFile(ex.path)],
};
transactionClient.createOrReplace(data);
}
await transactionClient
.commit({ autoGenerateArrayKeys: true })
.then(() => console.log(`Oppdaterte kode-eksempler`))
.catch((e) => console.error(e.message));
};
main();
@@ -0,0 +1,31 @@
import { extractArgs } from "../parts/extract-args";
describe("Testing extractArgs function", () => {
test("extractArgs should return null on failed parsing", () => {
const code = `export const args {
title: "Tittel"
desc: "Description",
index 2
}`;
const args = extractArgs(code, "filename", "test");
expect(args).toBeNull();
});
test("extractArgs should parse args from codesnippet", () => {
const code = `export const args = {
title: "Tittel",
desc: "Description",
index: 2
}`;
const args = extractArgs(code, "filename", "test");
expect(args).toEqual({
title: "Tittel",
desc: "Description",
index: 2,
});
});
});
@@ -0,0 +1,36 @@
import fs from "fs";
import { extractMetadata } from "../parts/extract-metadata";
jest.mock("fs");
const sampleObj = {
version: 1,
changelog: [
{
description: "Oppdaterte X Y og Z",
date: "31.10.2023",
version: 1,
},
],
};
const sampleString = JSON.stringify(sampleObj, null, 2);
describe("Testing extractMetadata function", () => {
test("extractMetadata should return undefined if directory does not exist", () => {
(fs.existsSync as jest.Mock).mockReturnValue(false);
const metadata = extractMetadata("nonexistent", "templates");
expect(metadata).toBeUndefined();
});
test("extractMetadata should read meta.json from /pages/templates directory", () => {
(fs.existsSync as jest.Mock).mockReturnValue(true);
(fs.readdirSync as jest.Mock).mockReturnValue(["file1.tsx", "meta.json"]);
(fs.readFileSync as jest.Mock).mockReturnValue(sampleString);
const metadata = extractMetadata("eksempler", "templates");
expect(metadata).toEqual(sampleObj);
});
});
@@ -0,0 +1,8 @@
import { filterCode } from "../parts/filter-code";
import { codeAfter, codeBefore } from "./mockdata";
test("filterCode should remove unwanted code", () => {
const codeResult = filterCode(codeBefore);
expect(codeResult).toEqual(codeAfter);
});
@@ -0,0 +1,15 @@
import { getDirectories } from "../parts/get-directories";
describe("Testing getDirectories function", () => {
test("getDirectories should list directories in /pages/eksempler", () => {
const folders = getDirectories("eksempler");
expect(folders.length).toBeGreaterThan(0);
});
test("getDirectories should list directories in /pages/templates", () => {
const folders = getDirectories("eksempler");
expect(folders.length).toBeGreaterThan(0);
});
});
@@ -0,0 +1,28 @@
export const codeBefore = `import { Alert } from "@navikt/ds-react";
import { withDsExample } from "components/website-modules/examples/withDsExample";
const Example = () => {
return (
<Alert variant="error">Noe gikk galt! Prøv igjen om noen minutter.</Alert>
);
};
export default withDsExample(Example);
/* Storybook story */
export const Demo = {
render: Example,
};
export const args = {
index: 0,
};
`;
export const codeAfter = `import { Alert } from "@navikt/ds-react";
const Example = () => {
return (
<Alert variant="error">Noe gikk galt! Prøv igjen om noen minutter.</Alert>
);
};`;
@@ -0,0 +1,36 @@
import fs from "fs";
import { parseCodeFiles } from "../parts/parse-code-files";
import { codeAfter, codeBefore } from "./mockdata";
jest.mock("fs");
describe("Testing parseCodeFiles function", () => {
test("parseCodeFiles should return an empty array if directory does not exist", () => {
(fs.existsSync as jest.Mock).mockReturnValue(false);
const files = parseCodeFiles("nonexistent", "eksempler");
expect(files).toEqual([]);
});
test("parseCodeFiles should read files from /pages/eksempler directory", () => {
(fs.existsSync as jest.Mock).mockReturnValue(true);
(fs.readdirSync as jest.Mock).mockReturnValue(["file1.tsx", "file2.tsx"]);
(fs.readFileSync as jest.Mock).mockReturnValue(codeBefore);
const files = parseCodeFiles("eksempler", "eksempler");
expect(files.length).toBeGreaterThan(0);
expect(files[0].innhold).toEqual(codeAfter);
});
test("parseCodeFiles should read files from /pages/templates directory", () => {
(fs.existsSync as jest.Mock).mockReturnValue(true);
(fs.readdirSync as jest.Mock).mockReturnValue(["file1.tsx", "file2.tsx"]);
(fs.readFileSync as jest.Mock).mockReturnValue(codeBefore);
const files = parseCodeFiles("templates", "templates");
expect(files.length).toBeGreaterThan(0);
expect(files[0].innhold).toEqual(codeAfter);
});
});
@@ -0,0 +1,20 @@
import JSON5 from "json5";
import { ArgsT } from "../types";
export function extractArgs(
code: string,
fileName: string,
env?: "test"
): ArgsT | null {
const args = code.match(/export const args = {([^}]+)}/)?.[1];
if (!args) {
env !== "test" &&
console.warn(
`Missing args when parsing code for examples/template: ${fileName}`
);
return null;
}
return JSON5.parse(`{${args}}`) ?? null;
}
@@ -0,0 +1,29 @@
import fs from "fs";
import JSON5 from "json5";
import path from "path";
import { CodeExampleSchemaT } from "../../../types";
import { RootDirectoriesT } from "../types";
export function extractMetadata(
dirName: string,
rootDir: RootDirectoriesT
): CodeExampleSchemaT["metadata"] {
const codeDirPath = path.resolve(
process.cwd(),
`pages/${rootDir}/${dirName}`
);
if (
!fs.existsSync(codeDirPath) ||
!fs.readdirSync(codeDirPath).find((x) => x === "meta.json")
) {
return undefined;
}
const metadata = fs.readFileSync(
path.resolve(process.cwd(), `pages/${rootDir}/${dirName}/meta.json`),
"utf-8"
);
return JSON5.parse(metadata);
}
@@ -0,0 +1,21 @@
export function filterCode(code: string) {
const _code = code
.substring(0, code.indexOf("export const args ="))
.split("\n")
.filter((x) => !x.includes("examples/withDsExample"));
const storyIndex = _code.findIndex((x) => x === "/* Storybook story */");
if (storyIndex === -1) {
return _code
.join("\n")
.replace(/^\s*export default withDsExample\(Example[\s\S]*?;\s*/gm, "")
.trim();
}
return _code
.filter((_, idx) => idx < storyIndex || idx > storyIndex + 3)
.join("\n")
.replace(/^\s*export default withDsExample\(Example[\s\S]*?;\s*/gm, "")
.trim();
}
@@ -0,0 +1,23 @@
import fs from "fs";
import path from "path";
import { DirectoryDataT, RootDirectoriesT } from "../types";
/**
* Returns metadata for each 'page' found in directory
* @param directory
* @returns DirectoryDataT
*/
export function getDirectories(directory: RootDirectoriesT): DirectoryDataT {
const rootPath = path.resolve(process.cwd(), `pages/${directory}`);
if (!fs.existsSync(rootPath)) {
return [];
}
const folders = fs
.readdirSync(rootPath, { withFileTypes: true })
.filter((dirent) => dirent.isDirectory())
.map((dirent) => dirent.name);
return folders.map((dir) => ({ path: `${dir}` }));
}
@@ -0,0 +1,47 @@
import fs from "fs";
import path from "path";
import { FileArrayT, RootDirectoriesT } from "../types";
import { extractArgs } from "./extract-args";
import { filterCode } from "./filter-code";
import { sortResult } from "./sort";
export function parseCodeFiles(
dirName: string,
rootDir: RootDirectoriesT
): FileArrayT {
const codeDirPath = path.resolve(
process.cwd(),
`pages/${rootDir}/${dirName}`
);
if (!fs.existsSync(codeDirPath)) {
return [];
}
const codeFiles = fs
.readdirSync(codeDirPath)
.filter((x) => !x.includes(".json"));
const parsedCode: FileArrayT = codeFiles.map((file) => {
let code = "";
code = fs.readFileSync(
path.resolve(process.cwd(), `pages/${rootDir}/${dirName}/${file}`),
"utf-8"
);
const args = extractArgs(code, `pages/${rootDir}/${dirName}/${file}`);
return {
innhold: code,
navn: args?.title ?? file.replace(".tsx", ""),
description: args?.desc,
index: args?.index ?? 1,
};
});
return sortResult(parsedCode).map((x) => ({
...x,
innhold: filterCode(x.innhold),
}));
}
@@ -0,0 +1,7 @@
import { FileArrayT } from "../types";
export function sortResult(res: FileArrayT) {
return res.sort((a, b) => {
return a.index - b.index;
});
}
@@ -0,0 +1,15 @@
export type FileArrayT = {
innhold: string;
navn: string;
index: number;
description?: string;
}[];
export type DirectoryDataT = { path: string }[];
export type ArgsT = {
title?: string;
index?: number;
desc?: string;
};
export type RootDirectoriesT = "eksempler" | "templates";
@@ -0,0 +1,95 @@
import dotenv from "dotenv";
import { noCdnClient } from "../../sanity/interface/client.server";
import { CodeExampleSchemaT } from "../../types";
import { extractMetadata } from "./parts/extract-metadata";
import { getDirectories } from "./parts/get-directories";
import { parseCodeFiles } from "./parts/parse-code-files";
import { RootDirectoriesT } from "./types";
dotenv.config();
const token = process.env.SANITY_WRITE_KEY;
if (!token) {
throw new Error("Missing token 'SANITY_WRITE_KEY' for updating sanity");
}
updateSanity("templates", false);
updateSanity("eksempler", false);
export async function updateSanity(
directory: RootDirectoriesT,
isDryRun: boolean = false
) {
const transactionClient = noCdnClient(token).transaction();
const folders = getDirectories(directory);
/* First we add/update examples */
for (const folder of folders) {
const data: CodeExampleSchemaT = {
_id: createId(folder.path),
_type: "kode_eksempler_fil",
title: folder.path,
variant: directory,
filer: parseCodeFiles(folder.path, directory),
metadata: extractMetadata(folder.path, directory),
};
transactionClient.createOrReplace(data);
}
await transactionClient
.commit({ autoGenerateArrayKeys: true, dryRun: isDryRun })
.then(() => console.log(`Oppdaterte ${directory}-dokumenter i sanity`))
.catch((e) => {
throw new Error(e.message);
});
const oldSanityDocuments = await noCdnClient(token).fetch(
`*[_type == "kode_eksempler_fil" && variant == "${directory}"]`
);
let deletedIds: string[] = [];
/* Delete old examples */
for (const document of oldSanityDocuments) {
if (!folders.some((folder) => document._id === createId(folder.path))) {
transactionClient.delete(document._id);
deletedIds.push(document._id);
}
}
await transactionClient
.commit()
.then(() => console.log(`Successfully deleted unused ${directory}`))
.catch((e) => {
/**
* Errormessage includes all ids that failed.
*/
deletedIds = deletedIds.filter((id) => e.message.includes(id));
console.log("\n");
console.log(
`Found ${deletedIds.length} ${directory} documents longer documented locally, but referenced in sanity.
How to fix:
- Go to links provided under and try to manually delete document.
- You will then be prompted to update referenced document before deleting.
- After updating reference(s) and deleting document(s) there is no need to run the script again.`
);
console.log(
JSON.stringify(
deletedIds.map(
(x) =>
`https://aksel.nav.no/admin/prod/desk/admin;eksemplerTemplates;${x}`
),
null,
2
)
);
throw new Error(
`Failed when deleting old ${directory}-documentation from sanity, see warning above.`
);
});
}
function createId(s: string) {
return `kode_eksempelid_${s.match(/\w/g)?.join("")}`.toLowerCase();
}
+39 -3
View File
@@ -2,6 +2,7 @@ import {
bloggKategorier,
grunnleggendeKategorier,
komponentKategorier,
templatesKategorier,
} from "../sanity/config";
export type ResolveSlugT<T> = Omit<T, "slug"> & {
@@ -138,6 +139,24 @@ export interface AkselGrunnleggendeDocT
};
}
export interface AkselTemplatesDocT extends DocumentT<"ds_artikkel">, ArticleT {
kategori: (typeof templatesKategorier)[number]["value"];
status: {
tag?: "beta" | "new" | "ready" | "deprecated";
unsafe?: boolean;
bilde?: any;
};
intro: {
body?: any[];
brukes_til: string[];
brukes_ikke_til?: string[];
};
content: any[];
updateInfo?: {
lastVerified?: string;
};
}
export type AkselSidebarT = Array<{
heading: string;
slug: string;
@@ -282,13 +301,30 @@ export interface RelatertInnholdT {
>;
}
export type CodeExampleSchemaT = {
_id: string;
_type: string;
title: string;
variant: "eksempler" | "templates";
filer: {
innhold: string;
navn: string;
index: number;
description?: string;
}[];
metadata?: {
version: number;
changelog: { description: string; version: number; date: string }[];
};
};
export interface CodeExamplesT {
title: string;
dir: {
title: string;
filer: Array<
ArrayObjectT<{ navn: string; innhold: string; description?: string }>
>;
filer: Array<ArrayObjectT<CodeExampleSchemaT["filer"][0]>>;
metadata?: CodeExampleSchemaT["metadata"];
variant: CodeExampleSchemaT["variant"];
};
}
+3 -2
View File
@@ -1,5 +1,5 @@
import { allArticleDocuments } from "../sanity/config";
import Fuse from "fuse.js";
import { allArticleDocuments } from "../sanity/config";
export const searchOptions: {
[K in (typeof allArticleDocuments)[number]]: {
@@ -11,7 +11,8 @@ export const searchOptions: {
komponent_artikkel: { display: "Komponenter", index: 0 },
aksel_artikkel: { display: "God praksis", index: 1 },
ds_artikkel: { display: "Grunnleggende", index: 2 },
aksel_blogg: { display: "Blogg", index: 3 },
templates_artikkel: { display: "Mønster og Maler", index: 3 },
aksel_blogg: { display: "Blogg", index: 4 },
aksel_prinsipp: { display: "Prinsipper", index: 5 },
aksel_standalone: { display: "Unike sider", index: 6, hidden: true },
};
+17 -17
View File
@@ -3415,7 +3415,7 @@ __metadata:
languageName: node
linkType: hard
"@navikt/aksel-icons@^5.8.0, @navikt/aksel-icons@workspace:@navikt/aksel-icons":
"@navikt/aksel-icons@^5.9.1, @navikt/aksel-icons@workspace:@navikt/aksel-icons":
version: 0.0.0-use.local
resolution: "@navikt/aksel-icons@workspace:@navikt/aksel-icons"
dependencies:
@@ -3442,8 +3442,8 @@ __metadata:
version: 0.0.0-use.local
resolution: "@navikt/aksel-stylelint@workspace:@navikt/aksel-stylelint"
dependencies:
"@navikt/ds-css": ^5.8.0
"@navikt/ds-tokens": ^5.8.0
"@navikt/ds-css": ^5.9.1
"@navikt/ds-tokens": ^5.9.1
"@types/jest": ^29.0.0
concurrently: 7.2.1
copyfiles: 2.4.1
@@ -3461,7 +3461,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@navikt/aksel@workspace:@navikt/aksel"
dependencies:
"@navikt/ds-css": 5.8.0
"@navikt/ds-css": 5.9.1
"@types/inquirer": ^9.0.3
"@types/jest": ^29.0.0
axios: 1.3.6
@@ -3485,11 +3485,11 @@ __metadata:
languageName: unknown
linkType: soft
"@navikt/ds-css@*, @navikt/ds-css@5.8.0, @navikt/ds-css@^5.8.0, @navikt/ds-css@workspace:@navikt/core/css":
"@navikt/ds-css@*, @navikt/ds-css@5.9.1, @navikt/ds-css@^5.9.1, @navikt/ds-css@workspace:@navikt/core/css":
version: 0.0.0-use.local
resolution: "@navikt/ds-css@workspace:@navikt/core/css"
dependencies:
"@navikt/ds-tokens": ^5.8.0
"@navikt/ds-tokens": ^5.9.1
cssnano: 6.0.0
fast-glob: 3.2.11
lodash: 4.17.21
@@ -3502,13 +3502,13 @@ __metadata:
languageName: unknown
linkType: soft
"@navikt/ds-react@*, @navikt/ds-react@^5.8.0, @navikt/ds-react@workspace:@navikt/core/react":
"@navikt/ds-react@*, @navikt/ds-react@^5.9.1, @navikt/ds-react@workspace:@navikt/core/react":
version: 0.0.0-use.local
resolution: "@navikt/ds-react@workspace:@navikt/core/react"
dependencies:
"@floating-ui/react": 0.25.4
"@navikt/aksel-icons": ^5.8.0
"@navikt/ds-tokens": ^5.8.0
"@navikt/aksel-icons": ^5.9.1
"@navikt/ds-tokens": ^5.9.1
"@radix-ui/react-tabs": 1.0.0
"@radix-ui/react-toggle-group": 1.0.0
"@testing-library/dom": 8.13.0
@@ -3542,11 +3542,11 @@ __metadata:
languageName: unknown
linkType: soft
"@navikt/ds-tailwind@^5.8.0, @navikt/ds-tailwind@workspace:@navikt/core/tailwind":
"@navikt/ds-tailwind@^5.9.1, @navikt/ds-tailwind@workspace:@navikt/core/tailwind":
version: 0.0.0-use.local
resolution: "@navikt/ds-tailwind@workspace:@navikt/core/tailwind"
dependencies:
"@navikt/ds-tokens": ^5.8.0
"@navikt/ds-tokens": ^5.9.1
"@types/jest": ^29.0.0
color: 4.2.3
jest: ^29.0.0
@@ -3557,7 +3557,7 @@ __metadata:
languageName: unknown
linkType: soft
"@navikt/ds-tokens@^5.8.0, @navikt/ds-tokens@workspace:@navikt/core/tokens":
"@navikt/ds-tokens@^5.9.1, @navikt/ds-tokens@workspace:@navikt/core/tokens":
version: 0.0.0-use.local
resolution: "@navikt/ds-tokens@workspace:@navikt/core/tokens"
dependencies:
@@ -8438,11 +8438,11 @@ __metadata:
version: 0.0.0-use.local
resolution: "aksel.nav.no@workspace:aksel.nav.no"
dependencies:
"@navikt/aksel-icons": ^5.8.0
"@navikt/ds-css": ^5.8.0
"@navikt/ds-react": ^5.8.0
"@navikt/ds-tailwind": ^5.8.0
"@navikt/ds-tokens": ^5.8.0
"@navikt/aksel-icons": ^5.9.1
"@navikt/ds-css": ^5.9.1
"@navikt/ds-react": ^5.9.1
"@navikt/ds-tailwind": ^5.9.1
"@navikt/ds-tokens": ^5.9.1
prettier-plugin-tailwindcss: ^0.2.3
languageName: unknown
linkType: soft