mirror of
https://github.com/navikt/aksel.git
synced 2026-10-16 02:32:02 +00:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37165e9f38 | ||
|
|
d19920ca78 | ||
|
|
60d3481300 | ||
|
|
f486937439 | ||
|
|
c62058abc1 | ||
|
|
84d9b8260f | ||
|
|
c108063dcb | ||
|
|
2a8533ad56 | ||
|
|
9b990a2178 | ||
|
|
5fec1f24f4 | ||
|
|
c27c1cfe26 | ||
|
|
5a649d2282 | ||
|
|
baac9cc251 | ||
|
|
d924d523e4 | ||
|
|
fc5a77081d |
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
-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,9 @@
|
||||
# @navikt/aksel-icons
|
||||
|
||||
## 5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-icons",
|
||||
"version": "5.9.1",
|
||||
"version": "5.10.0",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/ikoner",
|
||||
"repository": {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# @navikt/aksel-stylelint
|
||||
|
||||
## 5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-stylelint",
|
||||
"version": "5.9.1",
|
||||
"version": "5.10.0",
|
||||
"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.1",
|
||||
"@navikt/ds-tokens": "^5.9.1",
|
||||
"@navikt/ds-css": "^5.10.0",
|
||||
"@navikt/ds-tokens": "^5.10.0",
|
||||
"@types/jest": "^29.0.0",
|
||||
"concurrently": "7.2.1",
|
||||
"copyfiles": "2.4.1",
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @navikt/aksel
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel",
|
||||
"version": "5.9.1",
|
||||
"version": "5.10.0",
|
||||
"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.1",
|
||||
"@navikt/ds-css": "5.10.0",
|
||||
"axios": "1.3.6",
|
||||
"chalk": "4.1.0",
|
||||
"clipboardy": "^2.3.0",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @navikt/ds-css
|
||||
|
||||
## 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
|
||||
|
||||
@@ -35,6 +35,10 @@ const StyleMappings = {
|
||||
component: "Box",
|
||||
main: primitivesCss,
|
||||
},
|
||||
{
|
||||
component: "Page",
|
||||
main: primitivesCss,
|
||||
},
|
||||
{
|
||||
component: "HGrid",
|
||||
main: primitivesCss,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "5.9.1",
|
||||
"version": "5.10.0",
|
||||
"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.1",
|
||||
"@navikt/ds-tokens": "^5.10.0",
|
||||
"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,27 @@
|
||||
# @navikt/ds-react
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "5.9.1",
|
||||
"version": "5.10.0",
|
||||
"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.1",
|
||||
"@navikt/ds-tokens": "^5.9.1",
|
||||
"@navikt/aksel-icons": "^5.10.0",
|
||||
"@navikt/ds-tokens": "^5.10.0",
|
||||
"@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";
|
||||
@@ -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,5 +1,9 @@
|
||||
# @navikt/ds-tailwind
|
||||
|
||||
## 5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tailwind",
|
||||
"version": "5.9.1",
|
||||
"version": "5.10.0",
|
||||
"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.1",
|
||||
"@navikt/ds-tokens": "^5.10.0",
|
||||
"@types/jest": "^29.0.0",
|
||||
"color": "4.2.3",
|
||||
"jest": "^29.0.0",
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# @navikt/ds-tokens
|
||||
|
||||
## 5.10.0
|
||||
|
||||
## 5.9.2
|
||||
|
||||
## 5.9.1
|
||||
|
||||
## 5.9.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tokens",
|
||||
"version": "5.9.1",
|
||||
"version": "5.10.0",
|
||||
"description": "Design-tokens for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
|
||||
+275
-259
File diff suppressed because it is too large.
Load diff
@@ -15,11 +15,11 @@
|
||||
"website"
|
||||
],
|
||||
"dependencies": {
|
||||
"@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"
|
||||
"@navikt/aksel-icons": "^5.10.0",
|
||||
"@navikt/ds-css": "^5.10.0",
|
||||
"@navikt/ds-react": "^5.10.0",
|
||||
"@navikt/ds-tailwind": "^5.10.0",
|
||||
"@navikt/ds-tokens": "^5.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier-plugin-tailwindcss": "^0.2.3"
|
||||
|
||||
@@ -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,8 @@ 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,
|
||||
},
|
||||
{
|
||||
_key: getKey(),
|
||||
@@ -31,6 +35,8 @@ 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,
|
||||
},
|
||||
{
|
||||
_key: getKey(),
|
||||
@@ -38,6 +44,8 @@ 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,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -34,7 +34,15 @@ 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);
|
||||
@@ -75,7 +83,7 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
const fixName = (str: string) =>
|
||||
capitalize(
|
||||
str
|
||||
.replace(/[^\w]|_/g, " ")
|
||||
.replace(/[^\wæøå]|_/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim()
|
||||
) ?? str;
|
||||
@@ -85,6 +93,7 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
}
|
||||
|
||||
const active = activeExample ?? node?.dir?.filer?.[0]?.navn;
|
||||
const demoVariant = node.dir?.variant;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -107,7 +116,7 @@ const ComponentExamples = ({ node }: CodeExamplesProps) => {
|
||||
);
|
||||
}}
|
||||
>
|
||||
{fixName(fil.navn)}
|
||||
{fixName(fil.title)}
|
||||
</Chips.Toggle>
|
||||
);
|
||||
})}
|
||||
@@ -138,7 +147,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 +157,10 @@ 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,
|
||||
"p-6": demoVariant === "templates",
|
||||
}
|
||||
)}
|
||||
title="Kode-eksempler"
|
||||
ref={iframeRef}
|
||||
@@ -199,10 +211,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
@@ -43,6 +43,7 @@ const Card = ({ article, visible, index }: CardProps) => {
|
||||
"ds_artikkel",
|
||||
"komponent_artikkel",
|
||||
"aksel_blogg",
|
||||
"templates_artikkel",
|
||||
].includes(article._type);
|
||||
|
||||
return (
|
||||
|
||||
+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>
|
||||
)}
|
||||
|
||||
@@ -56,6 +56,12 @@ export function SEO({
|
||||
</>
|
||||
)}
|
||||
{canonical && <link rel="canonical" href={canonical} />}
|
||||
<link
|
||||
rel="alternate"
|
||||
type="application/rss+xml"
|
||||
title="Produktbloggen - aksel.nav.no"
|
||||
href="https://aksel.nav.no/rss/produktbloggen-rss.xml"
|
||||
/>
|
||||
</Head>
|
||||
);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -6,14 +6,15 @@ const withBundleAnalyzer = require("@next/bundle-analyzer")({
|
||||
|
||||
const cdnUrl = "https://cdn.nav.no";
|
||||
const hotjarUrl = "https://*.hotjar.com";
|
||||
const dekoratorUrl = "https://www.nav.no";
|
||||
|
||||
const ContentSecurityPolicy = `
|
||||
default-src 'self' 'unsafe-inline' ${cdnUrl};
|
||||
font-src 'self' ${cdnUrl} ${hotjarUrl} data:;
|
||||
img-src 'self' cdn.sanity.io https://avatars.githubusercontent.com data: ${cdnUrl} ${hotjarUrl};
|
||||
script-src 'self' ${cdnUrl} ${hotjarUrl} https://in2.taskanalytics.com/tm.js 'nonce-4e1aa203a32e' 'unsafe-eval';
|
||||
style-src 'self' ${cdnUrl} ${hotjarUrl} 'unsafe-inline';
|
||||
connect-src 'self' ${cdnUrl} ${hotjarUrl} https://*.hotjar.io wss://*.hotjar.com https://raw.githubusercontent.com/navikt/ https://hnbe3yhs.apicdn.sanity.io wss://hnbe3yhs.api.sanity.io cdn.sanity.io *.api.sanity.io https://amplitude.nav.no https://in2.taskanalytics.com/03346;
|
||||
img-src 'self' cdn.sanity.io ${dekoratorUrl} https://avatars.githubusercontent.com data: ${cdnUrl} ${hotjarUrl};
|
||||
script-src 'self' ${dekoratorUrl} ${cdnUrl} ${hotjarUrl} https://in2.taskanalytics.com/tm.js 'nonce-4e1aa203a32e' 'unsafe-eval';
|
||||
style-src 'self' ${dekoratorUrl} ${cdnUrl} ${hotjarUrl} 'unsafe-inline';
|
||||
connect-src 'self' ${dekoratorUrl} ${cdnUrl} ${hotjarUrl} https://*.hotjar.io wss://*.hotjar.com https://raw.githubusercontent.com/navikt/ https://hnbe3yhs.apicdn.sanity.io wss://hnbe3yhs.api.sanity.io cdn.sanity.io *.api.sanity.io https://amplitude.nav.no https://in2.taskanalytics.com/03346;
|
||||
frame-ancestors 'self' localhost:3000;
|
||||
media-src 'self' ${cdnUrl} cdn.sanity.io;
|
||||
frame-src 'self' https://web.microsoftstream.com localhost:3000 https://aksel.ekstern.dev.nav.no;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"scripts": {
|
||||
"dev": "next | pino-pretty",
|
||||
"build:old": "next build",
|
||||
"build": "next build && yarn update:searchindex && yarn cp:assets",
|
||||
"build": "next build && yarn update:searchindex && yarn update:rss && yarn cp:assets",
|
||||
"start": "cd .next/standalone/aksel.nav.no/website && PORT=3000 HOSTNAME=0.0.0.0 node server.js",
|
||||
"cp:assets": "cross-env cp -R public .next/standalone/aksel.nav.no/website/ && cross-env cp -R .next/static .next/standalone/aksel.nav.no/website/.next/static",
|
||||
"update:searchindex": "ts-node --project tsconfig.json ./scripts/create-index",
|
||||
@@ -15,9 +15,10 @@
|
||||
"e2e:full": "yarn build && ts-node ./e2e/genUrls.ts && FULL_TEST=true yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"e2e:ci": " yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"e2e:ci-full": "ts-node ./e2e/genUrls.ts && FULL_TEST=true yarn start-server-and-test start http://localhost:3000 playwright",
|
||||
"update:rss": "ts-node --project tsconfig.tsnode.json ./scripts/generate-rss-feed",
|
||||
"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",
|
||||
@@ -85,6 +86,7 @@
|
||||
"postcss": "^8.4.31",
|
||||
"postcss-import": "^14.1.0",
|
||||
"postcss-loader": "7.0.0",
|
||||
"rss": "^1.2.2",
|
||||
"showdown": "^2.1.0",
|
||||
"start-server-and-test": "^1.14.0",
|
||||
"ts-jest": "^29.0.0",
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import { AmplitudeEvents, amplitude } from "@/logging";
|
||||
import { BodyLong, Heading, Link } from "@navikt/ds-react";
|
||||
import { AkselCubeStatic } from "components/website-modules/aksel-cube/AkselCube";
|
||||
import NextLink from "next/link";
|
||||
import { BugIcon } from "@navikt/aksel-icons";
|
||||
import {
|
||||
BodyShort,
|
||||
Box,
|
||||
HGrid,
|
||||
Heading,
|
||||
Link,
|
||||
List,
|
||||
Page,
|
||||
VStack,
|
||||
} from "@navikt/ds-react";
|
||||
import Footer from "components/layout/footer/Footer";
|
||||
import { Header } from "components/layout/header/Header";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function Page() {
|
||||
export default function NotFound() {
|
||||
useEffect(() => {
|
||||
amplitude.track(AmplitudeEvents.notfound, {
|
||||
side: window.location.pathname,
|
||||
@@ -12,24 +22,89 @@ function Page() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
id="vk-notFoundId"
|
||||
className="relative flex h-screen w-screen items-center justify-center gap-8 overflow-hidden"
|
||||
>
|
||||
<AkselCubeStatic className="text-deepblue-300 opacity-10" />
|
||||
<div>
|
||||
<Heading spacing level="1" size="large">
|
||||
404 - Fant ikke siden
|
||||
</Heading>
|
||||
<BodyLong className="mb-2">
|
||||
Vi fant ikke siden du var ute etter{" "}
|
||||
</BodyLong>
|
||||
<NextLink href="/" passHref legacyBehavior>
|
||||
<Link>Tilbake til forsiden</Link>
|
||||
</NextLink>
|
||||
</div>
|
||||
</div>
|
||||
<Page data-aksel-template="404-v1" footer={<Footer />} id="vk-notFoundId">
|
||||
<Header />
|
||||
<Page.Block as="main" width="xl" gutters>
|
||||
<Box paddingBlock="20 16">
|
||||
<HGrid gap="12" columns={{ sm: 1, md: 2 }}>
|
||||
<VStack gap="16">
|
||||
<VStack gap="12" align="start">
|
||||
<div>
|
||||
<Heading level="1" size="large" spacing>
|
||||
Beklager, vi fant ikke siden
|
||||
</Heading>
|
||||
<BodyShort>
|
||||
Denne siden kan være slettet eller flyttet, eller det er en
|
||||
feil i lenken.
|
||||
</BodyShort>
|
||||
<List>
|
||||
<List.Item>Bruk gjerne søket eller menyen</List.Item>
|
||||
<List.Item>
|
||||
<Link href="/">Gå til forsiden</Link>
|
||||
</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
<Link href="https://github.com/navikt/aksel/issues/new?assignees=&labels=bug+%F0%9F%90%9B&projects=&template=bug-report.md&title=[Aksel.nav.no%20-%20404]">
|
||||
<BugIcon aria-hidden />
|
||||
Meld gjerne fra om at lenken ikke virker
|
||||
</Link>
|
||||
</VStack>
|
||||
|
||||
<div>
|
||||
<Heading level="2" size="large" spacing>
|
||||
Page not found
|
||||
</Heading>
|
||||
<BodyShort spacing>
|
||||
The page you requested cannot be found.
|
||||
</BodyShort>
|
||||
<BodyShort>
|
||||
Go to the <Link href="/">front page</Link>, or use one of the
|
||||
links in the menu.
|
||||
</BodyShort>
|
||||
</div>
|
||||
</VStack>
|
||||
<StatusSvg />
|
||||
</HGrid>
|
||||
</Box>
|
||||
</Page.Block>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page;
|
||||
function StatusSvg() {
|
||||
return (
|
||||
<svg
|
||||
width="min(100%, 500px)"
|
||||
viewBox="0 0 550 340"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-labelledby="404-illustration"
|
||||
>
|
||||
<title id="404-illustration">404 - fant ikke siden</title>
|
||||
<path
|
||||
d="M60.0927 243.567L95.542 245.427L96.7806 221.769C97.1476 214.76 97.7964 206.556 98.7272 197.16C99.8768 187.775 100.745 179.584 101.33 172.585L100.017 172.516C97.0704 178.512 94.0083 184.612 90.831 190.815C87.6652 196.799 84.3842 202.887 80.9881 209.079L60.0927 243.567ZM90.8631 334.801L93.3058 288.143L4.68237 283.493L6.74662 244.063L84.0445 125.551L154.287 129.236L148.06 248.182L170.38 249.353L168.143 292.069L145.823 290.898L143.381 337.556L90.8631 334.801Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M265.703 258.53C242.695 258.53 223.96 249.317 209.498 230.891C195.255 212.246 188.133 185.046 188.133 149.291C188.133 113.536 195.255 86.7747 209.498 69.0069C223.96 51.0198 242.695 42.0263 265.703 42.0263C288.711 42.0263 307.337 51.0198 321.58 69.0069C336.042 86.994 343.273 113.755 343.273 149.291C343.273 185.046 336.042 212.246 321.58 230.891C307.337 249.317 288.711 258.53 265.703 258.53ZM265.703 215.097C270.085 215.097 274.139 213.452 277.864 210.162C281.589 206.871 284.548 200.51 286.739 191.078C288.93 181.646 290.026 167.717 290.026 149.291C290.026 130.865 288.93 117.155 286.739 108.162C284.548 98.9489 281.589 92.9166 277.864 90.065C274.139 86.994 270.085 85.4585 265.703 85.4585C261.321 85.4585 257.267 86.994 253.542 90.065C249.817 92.9166 246.858 98.9489 244.667 108.162C242.476 117.155 241.38 130.865 241.38 149.291C241.38 167.717 242.476 181.646 244.667 191.078C246.858 200.51 249.817 206.871 253.542 210.162C257.267 213.452 261.321 215.097 265.703 215.097Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M429.98 129.301L465.429 127.441L464.191 103.783C463.824 96.7733 463.613 88.5473 463.557 79.105C463.721 69.6512 463.728 61.4137 463.58 54.3925L462.267 54.4614C459.962 60.7326 457.554 67.1192 455.042 73.621C452.518 79.9038 449.891 86.3018 447.16 92.8151L429.98 129.301ZM470.108 216.815L467.666 170.156L379.042 174.806L376.978 135.376L441.478 9.42432L511.72 5.7392L517.947 124.686L540.267 123.515L542.503 166.23L520.183 167.401L522.626 214.06L470.108 216.815Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -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(
|
||||
|
||||
@@ -1,72 +1,70 @@
|
||||
import {
|
||||
VirusIcon,
|
||||
PencilIcon,
|
||||
HospitalIcon,
|
||||
PiggybankIcon,
|
||||
PersonIcon,
|
||||
ParasolBeachIcon,
|
||||
PencilIcon,
|
||||
PersonIcon,
|
||||
PiggybankIcon,
|
||||
VirusIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import { Timeline } from "@navikt/ds-react";
|
||||
import { Timeline, TimelinePeriodProps } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
import { useState } from "react";
|
||||
|
||||
const Example = () => {
|
||||
const [activePeriod, setActivePeriod] = useState<any>();
|
||||
const [activePeriod, setActivePeriod] = useState("");
|
||||
|
||||
return (
|
||||
<div className="min-w-[800px] overflow-x-auto">
|
||||
<div className="min-w-[800px]">
|
||||
<Timeline>
|
||||
<Timeline.Row label="Person" icon={<PersonIcon aria-hidden />}>
|
||||
{person.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
onSelectPeriod={() => setActivePeriod(p.id)}
|
||||
isActive={activePeriod && activePeriod === p.id}
|
||||
aria-controls="timeline-panel"
|
||||
id={p.id}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{person.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
onSelectPeriod={() => setActivePeriod(p.id)}
|
||||
isActive={activePeriod === p.id}
|
||||
aria-controls="timeline-panel"
|
||||
id={p.id}
|
||||
/>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
<Timeline.Row label="Sykehus A" icon={<HospitalIcon aria-hidden />}>
|
||||
{jobb.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
onSelectPeriod={() => setActivePeriod(p.id)}
|
||||
isActive={activePeriod && activePeriod === p.id}
|
||||
aria-controls="timeline-panel"
|
||||
id={p.id}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{jobb.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
onSelectPeriod={() => setActivePeriod(p.id)}
|
||||
isActive={activePeriod === p.id}
|
||||
aria-controls="timeline-panel"
|
||||
id={p.id}
|
||||
/>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
</Timeline>
|
||||
{activePeriod && (
|
||||
<div
|
||||
aria-controls={activePeriod.id}
|
||||
aria-controls={activePeriod}
|
||||
id="timeline-panel"
|
||||
className="mt-8"
|
||||
>{`${activePeriod}: ${
|
||||
[...person, ...jobb].find((x) => x.id === activePeriod).start
|
||||
[...person, ...jobb].find((p) => p.id === activePeriod).start
|
||||
}`}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const person = [
|
||||
const person: TimelinePeriodProps[] = [
|
||||
{
|
||||
id: 1,
|
||||
id: "1",
|
||||
start: new Date("Jan 1 2022"),
|
||||
end: new Date("Jan 31 2022"),
|
||||
status: "warning",
|
||||
@@ -74,16 +72,15 @@ const person = [
|
||||
statusLabel: "Sykemeldt",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
id: "2",
|
||||
start: new Date("Apr 1 2022"),
|
||||
end: new Date("Apr 30 2022"),
|
||||
status: "neutral",
|
||||
icon: <ParasolBeachIcon aria-hidden />,
|
||||
label: "test",
|
||||
statusLabel: "Ferie",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
id: "3",
|
||||
start: new Date("Jul 1 2022"),
|
||||
end: new Date("Jul 31 2022"),
|
||||
status: "warning",
|
||||
@@ -91,7 +88,7 @@ const person = [
|
||||
statusLabel: "Sykemeldt",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
id: "4",
|
||||
start: new Date("Aug 1 2022"),
|
||||
end: new Date("Aug 30 2022"),
|
||||
status: "warning",
|
||||
@@ -100,9 +97,9 @@ const person = [
|
||||
},
|
||||
];
|
||||
|
||||
const jobb = [
|
||||
const jobb: TimelinePeriodProps[] = [
|
||||
{
|
||||
id: 5,
|
||||
id: "5",
|
||||
start: new Date("Feb 2 2022"),
|
||||
end: new Date("Mar 1 2022"),
|
||||
status: "success",
|
||||
@@ -110,7 +107,7 @@ const jobb = [
|
||||
icon: <PiggybankIcon aria-hidden />,
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
id: "6",
|
||||
start: new Date("Mar 2 2022"),
|
||||
end: new Date("Apr 1 2022"),
|
||||
status: "success",
|
||||
@@ -118,7 +115,7 @@ const jobb = [
|
||||
icon: <PiggybankIcon aria-hidden />,
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
id: "7",
|
||||
start: new Date("May 2 2022"),
|
||||
end: new Date("June 1 2022"),
|
||||
status: "success",
|
||||
@@ -126,7 +123,7 @@ const jobb = [
|
||||
icon: <PiggybankIcon aria-hidden />,
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
id: "8",
|
||||
start: new Date("June 2 2022"),
|
||||
end: new Date("July 1 2022"),
|
||||
status: "success",
|
||||
|
||||
@@ -1,77 +1,75 @@
|
||||
import {
|
||||
VirusIcon,
|
||||
PencilIcon,
|
||||
HospitalIcon,
|
||||
PiggybankIcon,
|
||||
PersonGroupIcon,
|
||||
ParasolBeachIcon,
|
||||
PencilIcon,
|
||||
PersonGroupIcon,
|
||||
PiggybankIcon,
|
||||
VirusIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import { Timeline } from "@navikt/ds-react";
|
||||
import { Timeline, TimelinePeriodProps } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
import { useState } from "react";
|
||||
|
||||
const Example = () => {
|
||||
const [activePeriod, setActivePeriod] = useState<any>();
|
||||
const [activePeriod, setActivePeriod] = useState("");
|
||||
|
||||
return (
|
||||
<div className="min-w-[800px] overflow-x-auto">
|
||||
<div className="min-w-[800px]">
|
||||
<Timeline>
|
||||
<Timeline.Pin date={new Date("Mar 15 2022")}>
|
||||
<p>Utbetalt: 12 345 kr</p>
|
||||
</Timeline.Pin>
|
||||
<Timeline.Row label="Person" icon={<PersonGroupIcon aria-hidden />}>
|
||||
{person.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
onSelectPeriod={() => setActivePeriod(p.id)}
|
||||
isActive={activePeriod && activePeriod === p.id}
|
||||
aria-controls="timeline-panel"
|
||||
id={p.id}
|
||||
>
|
||||
{p?.children ?? null}
|
||||
</Timeline.Period>
|
||||
);
|
||||
})}
|
||||
{person.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
onSelectPeriod={() => setActivePeriod(p.id)}
|
||||
isActive={activePeriod && activePeriod === p.id}
|
||||
aria-controls="timeline-panel"
|
||||
id={p.id}
|
||||
>
|
||||
{p.children ?? null}
|
||||
</Timeline.Period>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
<Timeline.Row label="Sykehus A" icon={<HospitalIcon aria-hidden />}>
|
||||
{jobb.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
onSelectPeriod={() => setActivePeriod(p.id)}
|
||||
isActive={activePeriod && activePeriod === p.id}
|
||||
aria-controls="timeline-panel"
|
||||
id={p.id}
|
||||
>
|
||||
{p?.children ?? null}
|
||||
</Timeline.Period>
|
||||
);
|
||||
})}
|
||||
{jobb.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
onSelectPeriod={() => setActivePeriod(p.id)}
|
||||
isActive={activePeriod && activePeriod === p.id}
|
||||
aria-controls="timeline-panel"
|
||||
id={p.id}
|
||||
>
|
||||
{p.children ?? null}
|
||||
</Timeline.Period>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
</Timeline>
|
||||
{activePeriod && (
|
||||
<div
|
||||
aria-controls={activePeriod.id}
|
||||
aria-controls={activePeriod}
|
||||
id="timeline-panel"
|
||||
className="mt-8"
|
||||
>{`${activePeriod}: ${
|
||||
[...person, ...jobb].find((x) => x.id === activePeriod).start
|
||||
[...person, ...jobb].find((p) => p.id === activePeriod).start
|
||||
}`}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const person = [
|
||||
const person: TimelinePeriodProps[] = [
|
||||
{
|
||||
start: new Date("Jan 1 2022"),
|
||||
end: new Date("Jan 31 2022"),
|
||||
@@ -79,16 +77,15 @@ const person = [
|
||||
icon: <PencilIcon aria-hidden />,
|
||||
statusLabel: "Sykemeldt",
|
||||
children: <div>50% sykemeldt</div>,
|
||||
id: 1,
|
||||
id: "1",
|
||||
},
|
||||
{
|
||||
start: new Date("Apr 1 2022"),
|
||||
end: new Date("Apr 30 2022"),
|
||||
status: "neutral",
|
||||
icon: <ParasolBeachIcon aria-hidden />,
|
||||
label: "test",
|
||||
statusLabel: "Ferie",
|
||||
id: 2,
|
||||
id: "2",
|
||||
},
|
||||
{
|
||||
start: new Date("Jul 1 2022"),
|
||||
@@ -96,7 +93,7 @@ const person = [
|
||||
status: "warning",
|
||||
icon: <PencilIcon aria-hidden />,
|
||||
statusLabel: "Sykemeldt",
|
||||
id: 3,
|
||||
id: "3",
|
||||
},
|
||||
{
|
||||
start: new Date("Aug 1 2022"),
|
||||
@@ -104,11 +101,11 @@ const person = [
|
||||
status: "warning",
|
||||
icon: <VirusIcon aria-hidden />,
|
||||
statusLabel: "Stønad korona",
|
||||
id: 4,
|
||||
id: "4",
|
||||
},
|
||||
];
|
||||
|
||||
const jobb = [
|
||||
const jobb: TimelinePeriodProps[] = [
|
||||
{
|
||||
start: new Date("Feb 2 2022"),
|
||||
end: new Date("Mar 1 2022"),
|
||||
@@ -116,7 +113,7 @@ const jobb = [
|
||||
statusLabel: "Utbetaling",
|
||||
icon: <PiggybankIcon aria-hidden />,
|
||||
children: <div>100% utbetaling</div>,
|
||||
id: 11,
|
||||
id: "11",
|
||||
},
|
||||
{
|
||||
start: new Date("Mar 2 2022"),
|
||||
@@ -125,7 +122,7 @@ const jobb = [
|
||||
statusLabel: "Utbetaling",
|
||||
icon: <PiggybankIcon aria-hidden />,
|
||||
children: <div>100% utbetaling</div>,
|
||||
id: 22,
|
||||
id: "22",
|
||||
},
|
||||
{
|
||||
start: new Date("May 2 2022"),
|
||||
@@ -134,7 +131,7 @@ const jobb = [
|
||||
statusLabel: "Utbetaling",
|
||||
icon: <PiggybankIcon aria-hidden />,
|
||||
children: <div>100% utbetaling</div>,
|
||||
id: 33,
|
||||
id: "33",
|
||||
},
|
||||
{
|
||||
start: new Date("June 2 2022"),
|
||||
@@ -142,7 +139,7 @@ const jobb = [
|
||||
status: "success",
|
||||
statusLabel: "Utbetaling",
|
||||
icon: <PiggybankIcon aria-hidden />,
|
||||
id: 44,
|
||||
id: "44",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -155,5 +152,5 @@ export const Demo = {
|
||||
|
||||
export const args = {
|
||||
index: 4,
|
||||
desc: "Vi anbefaler å bruke 'aria-controls' begge veier mellom aktive perioder og panelet det refererer til. Dette gir brukere av enkelte skjermlesere keyboard-shortcuts for å hoppe mellom perioder og panelet.",
|
||||
desc: "Vi anbefaler å bruke 'aria-controls' begge veier mellom aktive perioder og panelet det refererer til. Dette gir brukere av enkelte skjermlesere hurtigtaster for å hoppe mellom perioder og panelet.",
|
||||
};
|
||||
@@ -1,17 +1,17 @@
|
||||
import {
|
||||
VirusIcon,
|
||||
PencilIcon,
|
||||
HospitalIcon,
|
||||
PiggybankIcon,
|
||||
PersonIcon,
|
||||
ParasolBeachIcon,
|
||||
PencilIcon,
|
||||
PersonIcon,
|
||||
PiggybankIcon,
|
||||
VirusIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import { Timeline } from "@navikt/ds-react";
|
||||
import { Timeline, TimelinePeriodProps } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
|
||||
const Example = () => {
|
||||
return (
|
||||
<div className="min-w-[800px] overflow-x-auto">
|
||||
<div className="min-w-[800px]">
|
||||
<Timeline>
|
||||
<Timeline.Pin date={new Date("Mar 15 2022")}>
|
||||
<p>Periode: 01.03.2022 - 01.04.2022</p>
|
||||
@@ -29,50 +29,47 @@ const Example = () => {
|
||||
<p style={{ color: "red" }}>Dager igjen: 1</p>
|
||||
</Timeline.Pin>
|
||||
<Timeline.Row label="Person" icon={<PersonIcon aria-hidden />}>
|
||||
{person.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{person.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
/>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
<Timeline.Row label="Sykehus A" icon={<HospitalIcon aria-hidden />}>
|
||||
{jobb.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{jobb.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
/>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
<Timeline.Row label="Sykehus B" icon={<HospitalIcon aria-hidden />}>
|
||||
{jobb.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{jobb.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
/>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
</Timeline>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const person = [
|
||||
const person: TimelinePeriodProps[] = [
|
||||
{
|
||||
start: new Date("Jan 1 2022"),
|
||||
end: new Date("Jan 31 2022"),
|
||||
@@ -85,7 +82,6 @@ const person = [
|
||||
end: new Date("Apr 30 2022"),
|
||||
status: "neutral",
|
||||
icon: <ParasolBeachIcon aria-hidden />,
|
||||
label: "test",
|
||||
statusLabel: "Ferie",
|
||||
},
|
||||
{
|
||||
@@ -104,7 +100,7 @@ const person = [
|
||||
},
|
||||
];
|
||||
|
||||
const jobb = [
|
||||
const jobb: TimelinePeriodProps[] = [
|
||||
{
|
||||
start: new Date("Feb 2 2022"),
|
||||
end: new Date("Mar 1 2022"),
|
||||
|
||||
@@ -1,67 +1,64 @@
|
||||
import {
|
||||
VirusIcon,
|
||||
PencilIcon,
|
||||
HospitalIcon,
|
||||
PiggybankIcon,
|
||||
PersonIcon,
|
||||
ParasolBeachIcon,
|
||||
PencilIcon,
|
||||
PersonIcon,
|
||||
PiggybankIcon,
|
||||
VirusIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import { Timeline } from "@navikt/ds-react";
|
||||
import { Timeline, TimelinePeriodProps } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
|
||||
const Example = () => {
|
||||
return (
|
||||
<div className="min-w-[800px] overflow-x-auto">
|
||||
<div className="min-w-[800px]">
|
||||
<Timeline>
|
||||
<Timeline.Row label="Person" icon={<PersonIcon aria-hidden />}>
|
||||
{person.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
>
|
||||
{p?.children ?? null}
|
||||
</Timeline.Period>
|
||||
);
|
||||
})}
|
||||
{person.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
>
|
||||
{p.children ?? null}
|
||||
</Timeline.Period>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
<Timeline.Row label="Sykehus A" icon={<HospitalIcon aria-hidden />}>
|
||||
{jobb.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
>
|
||||
{p?.children ?? null}
|
||||
</Timeline.Period>
|
||||
);
|
||||
})}
|
||||
{jobb.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
>
|
||||
{p.children ?? null}
|
||||
</Timeline.Period>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
<Timeline.Row label="Sykehus B" icon={<HospitalIcon aria-hidden />}>
|
||||
{jobb.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{jobb.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
/>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
</Timeline>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const person = [
|
||||
const person: TimelinePeriodProps[] = [
|
||||
{
|
||||
start: new Date("Jan 1 2022"),
|
||||
end: new Date("Jan 31 2022"),
|
||||
@@ -75,7 +72,6 @@ const person = [
|
||||
end: new Date("Apr 30 2022"),
|
||||
status: "neutral",
|
||||
icon: <ParasolBeachIcon aria-hidden />,
|
||||
label: "test",
|
||||
statusLabel: "Ferie",
|
||||
},
|
||||
{
|
||||
@@ -94,7 +90,7 @@ const person = [
|
||||
},
|
||||
];
|
||||
|
||||
const jobb = [
|
||||
const jobb: TimelinePeriodProps[] = [
|
||||
{
|
||||
start: new Date("Feb 2 2022"),
|
||||
end: new Date("Mar 1 2022"),
|
||||
|
||||
@@ -1,56 +1,53 @@
|
||||
import {
|
||||
VirusIcon,
|
||||
PencilIcon,
|
||||
HospitalIcon,
|
||||
PiggybankIcon,
|
||||
PersonIcon,
|
||||
ParasolBeachIcon,
|
||||
PencilIcon,
|
||||
PersonIcon,
|
||||
PiggybankIcon,
|
||||
VirusIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import { Timeline } from "@navikt/ds-react";
|
||||
import { Timeline, TimelinePeriodProps } from "@navikt/ds-react";
|
||||
import { withDsExample } from "components/website-modules/examples/withDsExample";
|
||||
|
||||
const Example = () => {
|
||||
return (
|
||||
<div className="min-w-[800px] overflow-x-auto">
|
||||
<div className="min-w-[800px]">
|
||||
<Timeline>
|
||||
<Timeline.Row label="Person" icon={<PersonIcon aria-hidden />}>
|
||||
{person.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{person.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
/>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
<Timeline.Row label="Sykehus A" icon={<HospitalIcon aria-hidden />}>
|
||||
{jobb.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{jobb.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
/>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
<Timeline.Row label="Sykehus B" icon={<HospitalIcon aria-hidden />}>
|
||||
{jobb.map((p: any, i) => {
|
||||
return (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{jobb.map((p, i) => (
|
||||
<Timeline.Period
|
||||
key={i}
|
||||
start={p.start}
|
||||
end={p.end}
|
||||
status={p.status}
|
||||
icon={p.icon}
|
||||
statusLabel={p.statusLabel}
|
||||
/>
|
||||
))}
|
||||
</Timeline.Row>
|
||||
<Timeline.Zoom>
|
||||
<Timeline.Zoom.Button label="3 mnd" interval="month" count={3} />
|
||||
@@ -63,7 +60,7 @@ const Example = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const person = [
|
||||
const person: TimelinePeriodProps[] = [
|
||||
{
|
||||
start: new Date("Jan 1 2022"),
|
||||
end: new Date("Jan 31 2022"),
|
||||
@@ -76,7 +73,6 @@ const person = [
|
||||
end: new Date("Apr 30 2022"),
|
||||
status: "neutral",
|
||||
icon: <ParasolBeachIcon aria-hidden />,
|
||||
label: "test",
|
||||
statusLabel: "Ferie",
|
||||
},
|
||||
{
|
||||
@@ -95,7 +91,7 @@ const person = [
|
||||
},
|
||||
];
|
||||
|
||||
const jobb = [
|
||||
const jobb: TimelinePeriodProps[] = [
|
||||
{
|
||||
start: new Date("Feb 2 2022"),
|
||||
end: new Date("Mar 1 2022"),
|
||||
@@ -135,5 +131,5 @@ export const Demo = {
|
||||
|
||||
export const args = {
|
||||
index: 3,
|
||||
desc: "Lar deg 'zoome' til predefinerte tidsperioder. Bruk 'startDate/endDate'-prop i Timeline for å justere hvilken tidsperiode som blir vist.",
|
||||
desc: "Lar deg \"zoome\" til predefinerte tidsperioder. Bruk 'startDate/endDate'-prop i Timeline for å justere hvilken tidsperiode som blir vist.",
|
||||
};
|
||||
@@ -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}
|
||||
>
|
||||
|
||||
@@ -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,131 @@
|
||||
import {
|
||||
BodyShort,
|
||||
Box,
|
||||
HGrid,
|
||||
Heading,
|
||||
Link,
|
||||
List,
|
||||
Page,
|
||||
} from "@navikt/ds-react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function Example() {
|
||||
useDekorator();
|
||||
|
||||
return (
|
||||
<Page footer={<Footer />}>
|
||||
<Header />
|
||||
<Page.Block as="main" width="xl" gutters>
|
||||
<Box paddingBlock="20 16">
|
||||
<HGrid gap="12" columns={{ sm: 1, md: 2 }}>
|
||||
<div>
|
||||
<Heading level="1" size="large" spacing>
|
||||
Beklager, vi fant ikke siden
|
||||
</Heading>
|
||||
<BodyShort>
|
||||
Denne siden kan være slettet eller flyttet, eller det er en feil
|
||||
i lenken.
|
||||
</BodyShort>
|
||||
<List>
|
||||
<List.Item>Bruk gjerne søket eller menyen</List.Item>
|
||||
<List.Item>
|
||||
<Link href="#">Gå til forsiden</Link>
|
||||
</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
<StatusSvg />
|
||||
</HGrid>
|
||||
</Box>
|
||||
</Page.Block>
|
||||
<Env />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
function Header() {
|
||||
return <div id="decorator-header" />;
|
||||
}
|
||||
|
||||
function Footer() {
|
||||
return <div id="decorator-footer" />;
|
||||
}
|
||||
|
||||
const MILJO_URL = "https://www.nav.no/dekoratoren";
|
||||
|
||||
function Env() {
|
||||
return (
|
||||
<div
|
||||
id="decorator-env"
|
||||
data-src={`${MILJO_URL}/env?context=privatperson`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* OBS: Dette er ikke anbefalt metode for å laste dekoratør!
|
||||
* Se `nav-dekoratoren`-dokumentasjon for riktig implementasjon
|
||||
* @see https://github.com/navikt/nav-dekoratoren
|
||||
*/
|
||||
function useDekorator() {
|
||||
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);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
function StatusSvg() {
|
||||
return (
|
||||
<svg
|
||||
data-aksel-template="404-v1"
|
||||
width="min(100%, 500px)"
|
||||
viewBox="0 0 550 340"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-labelledby="404-illustration"
|
||||
>
|
||||
<title id="404-illustration">404 - fant ikke siden</title>
|
||||
<path
|
||||
d="M60.0927 243.567L95.542 245.427L96.7806 221.769C97.1476 214.76 97.7964 206.556 98.7272 197.16C99.8768 187.775 100.745 179.584 101.33 172.585L100.017 172.516C97.0704 178.512 94.0083 184.612 90.831 190.815C87.6652 196.799 84.3842 202.887 80.9881 209.079L60.0927 243.567ZM90.8631 334.801L93.3058 288.143L4.68237 283.493L6.74662 244.063L84.0445 125.551L154.287 129.236L148.06 248.182L170.38 249.353L168.143 292.069L145.823 290.898L143.381 337.556L90.8631 334.801Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M265.703 258.53C242.695 258.53 223.96 249.317 209.498 230.891C195.255 212.246 188.133 185.046 188.133 149.291C188.133 113.536 195.255 86.7747 209.498 69.0069C223.96 51.0198 242.695 42.0263 265.703 42.0263C288.711 42.0263 307.337 51.0198 321.58 69.0069C336.042 86.994 343.273 113.755 343.273 149.291C343.273 185.046 336.042 212.246 321.58 230.891C307.337 249.317 288.711 258.53 265.703 258.53ZM265.703 215.097C270.085 215.097 274.139 213.452 277.864 210.162C281.589 206.871 284.548 200.51 286.739 191.078C288.93 181.646 290.026 167.717 290.026 149.291C290.026 130.865 288.93 117.155 286.739 108.162C284.548 98.9489 281.589 92.9166 277.864 90.065C274.139 86.994 270.085 85.4585 265.703 85.4585C261.321 85.4585 257.267 86.994 253.542 90.065C249.817 92.9166 246.858 98.9489 244.667 108.162C242.476 117.155 241.38 130.865 241.38 149.291C241.38 167.717 242.476 181.646 244.667 191.078C246.858 200.51 249.817 206.871 253.542 210.162C257.267 213.452 261.321 215.097 265.703 215.097Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M429.98 129.301L465.429 127.441L464.191 103.783C463.824 96.7733 463.613 88.5473 463.557 79.105C463.721 69.6512 463.728 61.4137 463.58 54.3925L462.267 54.4614C459.962 60.7326 457.554 67.1192 455.042 73.621C452.518 79.9038 449.891 86.3018 447.16 92.8151L429.98 129.301ZM470.108 216.815L467.666 170.156L379.042 174.806L376.978 135.376L441.478 9.42432L511.72 5.7392L517.947 124.686L540.267 123.515L542.503 166.23L520.183 167.401L522.626 214.06L470.108 216.815Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const args = {
|
||||
index: 1,
|
||||
title: "Enkel",
|
||||
desc: "I sin enkleste form skal 404-side inneholde en tittel, feilmelding, løsningsforslag og illustrasjon.",
|
||||
};
|
||||
@@ -0,0 +1,158 @@
|
||||
import { BugIcon } from "@navikt/aksel-icons";
|
||||
import {
|
||||
BodyShort,
|
||||
Box,
|
||||
Button,
|
||||
HGrid,
|
||||
Heading,
|
||||
Link,
|
||||
List,
|
||||
VStack,
|
||||
Page,
|
||||
} from "@navikt/ds-react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function Example() {
|
||||
useDekorator();
|
||||
|
||||
return (
|
||||
<Page footer={<Footer />}>
|
||||
<Header />
|
||||
<Page.Block as="main" width="xl" gutters>
|
||||
<Box paddingBlock="20 16">
|
||||
<HGrid gap="12" columns={{ sm: 1, md: 2 }}>
|
||||
<VStack gap="16">
|
||||
<VStack gap="12" align="start">
|
||||
<div>
|
||||
<Heading level="1" size="large" spacing>
|
||||
Beklager, vi fant ikke siden
|
||||
</Heading>
|
||||
<BodyShort>
|
||||
Denne siden kan være slettet eller flyttet, eller det er en
|
||||
feil i lenken.
|
||||
</BodyShort>
|
||||
<List>
|
||||
<List.Item>Bruk gjerne søket eller menyen</List.Item>
|
||||
<List.Item>
|
||||
<Link href="#">Gå til forsiden</Link>
|
||||
</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
<Button as="a" href="#">
|
||||
Gå til Min side
|
||||
</Button>
|
||||
<Link href="#">
|
||||
<BugIcon aria-hidden />
|
||||
Meld gjerne fra om at lenken ikke virker
|
||||
</Link>
|
||||
</VStack>
|
||||
|
||||
<div>
|
||||
<Heading level="2" size="large" spacing>
|
||||
Page not found
|
||||
</Heading>
|
||||
<BodyShort spacing>
|
||||
The page you requested cannot be found.
|
||||
</BodyShort>
|
||||
<BodyShort>
|
||||
Go to the <Link href="#">front page</Link>, or use one of the
|
||||
links in the menu.
|
||||
</BodyShort>
|
||||
</div>
|
||||
</VStack>
|
||||
<StatusSvg />
|
||||
</HGrid>
|
||||
</Box>
|
||||
</Page.Block>
|
||||
<Env />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
function Header() {
|
||||
return <div id="decorator-header" />;
|
||||
}
|
||||
|
||||
function Footer() {
|
||||
return <div id="decorator-footer" />;
|
||||
}
|
||||
|
||||
const MILJO_URL = "https://www.nav.no/dekoratoren";
|
||||
|
||||
function Env() {
|
||||
return (
|
||||
<div
|
||||
id="decorator-env"
|
||||
data-src={`${MILJO_URL}/env?context=privatperson`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* OBS: Dette er ikke anbefalt metode for å laste dekoratør!
|
||||
* Se `nav-dekoratoren`-dokumentasjon for riktig implementasjon
|
||||
* @see https://github.com/navikt/nav-dekoratoren
|
||||
*/
|
||||
function useDekorator() {
|
||||
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);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
function StatusSvg() {
|
||||
return (
|
||||
<svg
|
||||
data-aksel-template="404-v1"
|
||||
width="min(100%, 500px)"
|
||||
viewBox="0 0 550 340"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-labelledby="404-illustration"
|
||||
>
|
||||
<title id="404-illustration">404 - fant ikke siden</title>
|
||||
<path
|
||||
d="M60.0927 243.567L95.542 245.427L96.7806 221.769C97.1476 214.76 97.7964 206.556 98.7272 197.16C99.8768 187.775 100.745 179.584 101.33 172.585L100.017 172.516C97.0704 178.512 94.0083 184.612 90.831 190.815C87.6652 196.799 84.3842 202.887 80.9881 209.079L60.0927 243.567ZM90.8631 334.801L93.3058 288.143L4.68237 283.493L6.74662 244.063L84.0445 125.551L154.287 129.236L148.06 248.182L170.38 249.353L168.143 292.069L145.823 290.898L143.381 337.556L90.8631 334.801Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M265.703 258.53C242.695 258.53 223.96 249.317 209.498 230.891C195.255 212.246 188.133 185.046 188.133 149.291C188.133 113.536 195.255 86.7747 209.498 69.0069C223.96 51.0198 242.695 42.0263 265.703 42.0263C288.711 42.0263 307.337 51.0198 321.58 69.0069C336.042 86.994 343.273 113.755 343.273 149.291C343.273 185.046 336.042 212.246 321.58 230.891C307.337 249.317 288.711 258.53 265.703 258.53ZM265.703 215.097C270.085 215.097 274.139 213.452 277.864 210.162C281.589 206.871 284.548 200.51 286.739 191.078C288.93 181.646 290.026 167.717 290.026 149.291C290.026 130.865 288.93 117.155 286.739 108.162C284.548 98.9489 281.589 92.9166 277.864 90.065C274.139 86.994 270.085 85.4585 265.703 85.4585C261.321 85.4585 257.267 86.994 253.542 90.065C249.817 92.9166 246.858 98.9489 244.667 108.162C242.476 117.155 241.38 130.865 241.38 149.291C241.38 167.717 242.476 181.646 244.667 191.078C246.858 200.51 249.817 206.871 253.542 210.162C257.267 213.452 261.321 215.097 265.703 215.097Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M429.98 129.301L465.429 127.441L464.191 103.783C463.824 96.7733 463.613 88.5473 463.557 79.105C463.721 69.6512 463.728 61.4137 463.58 54.3925L462.267 54.4614C459.962 60.7326 457.554 67.1192 455.042 73.621C452.518 79.9038 449.891 86.3018 447.16 92.8151L429.98 129.301ZM470.108 216.815L467.666 170.156L379.042 174.806L376.978 135.376L441.478 9.42432L511.72 5.7392L517.947 124.686L540.267 123.515L542.503 166.23L520.183 167.401L522.626 214.06L470.108 216.815Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const args = {
|
||||
index: 0,
|
||||
title: "Komplett",
|
||||
desc: "I sin fullstendige form kan en 404-side inneholde tittel, feilmelding, løsningsforslag, CTA, tilbakemeldingsfunksjon, flere språk og illustrasjon.",
|
||||
};
|
||||
@@ -0,0 +1,138 @@
|
||||
import {
|
||||
BodyShort,
|
||||
Box,
|
||||
Button,
|
||||
HGrid,
|
||||
Heading,
|
||||
Link,
|
||||
List,
|
||||
Page,
|
||||
VStack,
|
||||
} from "@navikt/ds-react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function Example() {
|
||||
useDekorator();
|
||||
|
||||
return (
|
||||
<Page footer={<Footer />}>
|
||||
<Header />
|
||||
<Page.Block as="main" width="xl" gutters>
|
||||
<Box paddingBlock="20 16">
|
||||
<HGrid gap="12" columns={{ sm: 1, md: 2 }}>
|
||||
<VStack gap="12" align="start">
|
||||
<div>
|
||||
<Heading level="1" size="large" spacing>
|
||||
Beklager, vi fant ikke siden
|
||||
</Heading>
|
||||
<BodyShort>
|
||||
Denne siden kan være slettet eller flyttet, eller det er en
|
||||
feil i lenken.
|
||||
</BodyShort>
|
||||
<List>
|
||||
<List.Item>Bruk gjerne søket eller menyen</List.Item>
|
||||
<List.Item>
|
||||
<Link href="#">Gå til forsiden</Link>
|
||||
</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
<Button as="a" href="#">
|
||||
Gå til Min side
|
||||
</Button>
|
||||
</VStack>
|
||||
<StatusSvg />
|
||||
</HGrid>
|
||||
</Box>
|
||||
</Page.Block>
|
||||
<Env />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
function Header() {
|
||||
return <div id="decorator-header" />;
|
||||
}
|
||||
|
||||
function Footer() {
|
||||
return <div id="decorator-footer" />;
|
||||
}
|
||||
|
||||
const MILJO_URL = "https://www.nav.no/dekoratoren";
|
||||
|
||||
function Env() {
|
||||
return (
|
||||
<div
|
||||
id="decorator-env"
|
||||
data-src={`${MILJO_URL}/env?context=privatperson`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* OBS: Dette er ikke anbefalt metode for å laste dekoratør!
|
||||
* Se `nav-dekoratoren`-dokumentasjon for riktig implementasjon
|
||||
* @see https://github.com/navikt/nav-dekoratoren
|
||||
*/
|
||||
function useDekorator() {
|
||||
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);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
function StatusSvg() {
|
||||
return (
|
||||
<svg
|
||||
data-aksel-template="404-v1"
|
||||
width="min(100%, 500px)"
|
||||
viewBox="0 0 550 340"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-labelledby="404-illustration"
|
||||
>
|
||||
<title id="404-illustration">404 - fant ikke siden</title>
|
||||
<path
|
||||
d="M60.0927 243.567L95.542 245.427L96.7806 221.769C97.1476 214.76 97.7964 206.556 98.7272 197.16C99.8768 187.775 100.745 179.584 101.33 172.585L100.017 172.516C97.0704 178.512 94.0083 184.612 90.831 190.815C87.6652 196.799 84.3842 202.887 80.9881 209.079L60.0927 243.567ZM90.8631 334.801L93.3058 288.143L4.68237 283.493L6.74662 244.063L84.0445 125.551L154.287 129.236L148.06 248.182L170.38 249.353L168.143 292.069L145.823 290.898L143.381 337.556L90.8631 334.801Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M265.703 258.53C242.695 258.53 223.96 249.317 209.498 230.891C195.255 212.246 188.133 185.046 188.133 149.291C188.133 113.536 195.255 86.7747 209.498 69.0069C223.96 51.0198 242.695 42.0263 265.703 42.0263C288.711 42.0263 307.337 51.0198 321.58 69.0069C336.042 86.994 343.273 113.755 343.273 149.291C343.273 185.046 336.042 212.246 321.58 230.891C307.337 249.317 288.711 258.53 265.703 258.53ZM265.703 215.097C270.085 215.097 274.139 213.452 277.864 210.162C281.589 206.871 284.548 200.51 286.739 191.078C288.93 181.646 290.026 167.717 290.026 149.291C290.026 130.865 288.93 117.155 286.739 108.162C284.548 98.9489 281.589 92.9166 277.864 90.065C274.139 86.994 270.085 85.4585 265.703 85.4585C261.321 85.4585 257.267 86.994 253.542 90.065C249.817 92.9166 246.858 98.9489 244.667 108.162C242.476 117.155 241.38 130.865 241.38 149.291C241.38 167.717 242.476 181.646 244.667 191.078C246.858 200.51 249.817 206.871 253.542 210.162C257.267 213.452 261.321 215.097 265.703 215.097Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M429.98 129.301L465.429 127.441L464.191 103.783C463.824 96.7733 463.613 88.5473 463.557 79.105C463.721 69.6512 463.728 61.4137 463.58 54.3925L462.267 54.4614C459.962 60.7326 457.554 67.1192 455.042 73.621C452.518 79.9038 449.891 86.3018 447.16 92.8151L429.98 129.301ZM470.108 216.815L467.666 170.156L379.042 174.806L376.978 135.376L441.478 9.42432L511.72 5.7392L517.947 124.686L540.267 123.515L542.503 166.23L520.183 167.401L522.626 214.06L470.108 216.815Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const args = {
|
||||
index: 2,
|
||||
title: "Med CTA til side",
|
||||
desc: "En 404-side kan inneholde en CTA som leder til et relevant område eller side, avhengig av konteksten.",
|
||||
};
|
||||
@@ -0,0 +1,139 @@
|
||||
import { BugIcon } from "@navikt/aksel-icons";
|
||||
import {
|
||||
BodyShort,
|
||||
Box,
|
||||
HGrid,
|
||||
Heading,
|
||||
Link,
|
||||
List,
|
||||
Page,
|
||||
VStack,
|
||||
} from "@navikt/ds-react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function Example() {
|
||||
useDekorator();
|
||||
|
||||
return (
|
||||
<Page footer={<Footer />}>
|
||||
<Header />
|
||||
<Page.Block as="main" width="xl" gutters>
|
||||
<Box paddingBlock="20 16">
|
||||
<HGrid gap="12" columns={{ sm: 1, md: 2 }}>
|
||||
<VStack gap="12" align="start">
|
||||
<div>
|
||||
<Heading level="1" size="large" spacing>
|
||||
Beklager, vi fant ikke siden
|
||||
</Heading>
|
||||
<BodyShort>
|
||||
Denne siden kan være slettet eller flyttet, eller det er en
|
||||
feil i lenken.
|
||||
</BodyShort>
|
||||
<List>
|
||||
<List.Item>Bruk gjerne søket eller menyen</List.Item>
|
||||
<List.Item>
|
||||
<Link href="#">Gå til forsiden</Link>
|
||||
</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
<Link href="#">
|
||||
<BugIcon aria-hidden />
|
||||
Meld gjerne fra om at lenken ikke virker
|
||||
</Link>
|
||||
</VStack>
|
||||
<StatusSvg />
|
||||
</HGrid>
|
||||
</Box>
|
||||
</Page.Block>
|
||||
<Env />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
function Header() {
|
||||
return <div id="decorator-header" />;
|
||||
}
|
||||
|
||||
function Footer() {
|
||||
return <div id="decorator-footer" />;
|
||||
}
|
||||
|
||||
const MILJO_URL = "https://www.nav.no/dekoratoren";
|
||||
|
||||
function Env() {
|
||||
return (
|
||||
<div
|
||||
id="decorator-env"
|
||||
data-src={`${MILJO_URL}/env?context=privatperson`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* OBS: Dette er ikke anbefalt metode for å laste dekoratør!
|
||||
* Se `nav-dekoratoren`-dokumentasjon for riktig implementasjon
|
||||
* @see https://github.com/navikt/nav-dekoratoren
|
||||
*/
|
||||
function useDekorator() {
|
||||
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);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
function StatusSvg() {
|
||||
return (
|
||||
<svg
|
||||
data-aksel-template="404-v1"
|
||||
width="min(100%, 500px)"
|
||||
viewBox="0 0 550 340"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-labelledby="404-illustration"
|
||||
>
|
||||
<title id="404-illustration">404 - fant ikke siden</title>
|
||||
<path
|
||||
d="M60.0927 243.567L95.542 245.427L96.7806 221.769C97.1476 214.76 97.7964 206.556 98.7272 197.16C99.8768 187.775 100.745 179.584 101.33 172.585L100.017 172.516C97.0704 178.512 94.0083 184.612 90.831 190.815C87.6652 196.799 84.3842 202.887 80.9881 209.079L60.0927 243.567ZM90.8631 334.801L93.3058 288.143L4.68237 283.493L6.74662 244.063L84.0445 125.551L154.287 129.236L148.06 248.182L170.38 249.353L168.143 292.069L145.823 290.898L143.381 337.556L90.8631 334.801Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M265.703 258.53C242.695 258.53 223.96 249.317 209.498 230.891C195.255 212.246 188.133 185.046 188.133 149.291C188.133 113.536 195.255 86.7747 209.498 69.0069C223.96 51.0198 242.695 42.0263 265.703 42.0263C288.711 42.0263 307.337 51.0198 321.58 69.0069C336.042 86.994 343.273 113.755 343.273 149.291C343.273 185.046 336.042 212.246 321.58 230.891C307.337 249.317 288.711 258.53 265.703 258.53ZM265.703 215.097C270.085 215.097 274.139 213.452 277.864 210.162C281.589 206.871 284.548 200.51 286.739 191.078C288.93 181.646 290.026 167.717 290.026 149.291C290.026 130.865 288.93 117.155 286.739 108.162C284.548 98.9489 281.589 92.9166 277.864 90.065C274.139 86.994 270.085 85.4585 265.703 85.4585C261.321 85.4585 257.267 86.994 253.542 90.065C249.817 92.9166 246.858 98.9489 244.667 108.162C242.476 117.155 241.38 130.865 241.38 149.291C241.38 167.717 242.476 181.646 244.667 191.078C246.858 200.51 249.817 206.871 253.542 210.162C257.267 213.452 261.321 215.097 265.703 215.097Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M429.98 129.301L465.429 127.441L464.191 103.783C463.824 96.7733 463.613 88.5473 463.557 79.105C463.721 69.6512 463.728 61.4137 463.58 54.3925L462.267 54.4614C459.962 60.7326 457.554 67.1192 455.042 73.621C452.518 79.9038 449.891 86.3018 447.16 92.8151L429.98 129.301ZM470.108 216.815L467.666 170.156L379.042 174.806L376.978 135.376L441.478 9.42432L511.72 5.7392L517.947 124.686L540.267 123.515L542.503 166.23L520.183 167.401L522.626 214.06L470.108 216.815Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const args = {
|
||||
index: 3,
|
||||
title: "Med tilbakemeldingsfunksjon",
|
||||
desc: "Hvis løsningen din støtter det, kan du vurdere å gi brukerne muligheten til å rapportere avvik.",
|
||||
};
|
||||
@@ -0,0 +1,147 @@
|
||||
import {
|
||||
BodyShort,
|
||||
Box,
|
||||
HGrid,
|
||||
Heading,
|
||||
Link,
|
||||
List,
|
||||
Page,
|
||||
VStack,
|
||||
} from "@navikt/ds-react";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function Example() {
|
||||
useDekorator();
|
||||
|
||||
return (
|
||||
<Page footer={<Footer />}>
|
||||
<Header />
|
||||
<Page.Block as="main" width="xl" gutters>
|
||||
<Box paddingBlock="20 16">
|
||||
<HGrid gap="12" columns={{ sm: 1, md: 2 }}>
|
||||
<VStack gap="16">
|
||||
<div>
|
||||
<Heading level="1" size="large" spacing>
|
||||
Beklager, vi fant ikke siden
|
||||
</Heading>
|
||||
<BodyShort>
|
||||
Denne siden kan være slettet eller flyttet, eller det er en
|
||||
feil i lenken.
|
||||
</BodyShort>
|
||||
<List>
|
||||
<List.Item>Bruk gjerne søket eller menyen</List.Item>
|
||||
<List.Item>
|
||||
<Link href="#">Gå til forsiden</Link>
|
||||
</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Heading level="2" size="large" spacing>
|
||||
Page not found
|
||||
</Heading>
|
||||
<BodyShort spacing>
|
||||
The page you requested cannot be found.
|
||||
</BodyShort>
|
||||
<BodyShort>
|
||||
Go to the <Link href="#">front page</Link>, or use one of the
|
||||
links in the menu.
|
||||
</BodyShort>
|
||||
</div>
|
||||
</VStack>
|
||||
<StatusSvg />
|
||||
</HGrid>
|
||||
</Box>
|
||||
</Page.Block>
|
||||
<Env />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
function Header() {
|
||||
return <div id="decorator-header" />;
|
||||
}
|
||||
|
||||
function Footer() {
|
||||
return <div id="decorator-footer" />;
|
||||
}
|
||||
|
||||
const MILJO_URL = "https://www.nav.no/dekoratoren";
|
||||
|
||||
function Env() {
|
||||
return (
|
||||
<div
|
||||
id="decorator-env"
|
||||
data-src={`${MILJO_URL}/env?context=privatperson`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* OBS: Dette er ikke anbefalt metode for å laste dekoratør!
|
||||
* Se `nav-dekoratoren`-dokumentasjon for riktig implementasjon
|
||||
* @see https://github.com/navikt/nav-dekoratoren
|
||||
*/
|
||||
function useDekorator() {
|
||||
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);
|
||||
};
|
||||
}, []);
|
||||
}
|
||||
|
||||
function StatusSvg() {
|
||||
return (
|
||||
<svg
|
||||
data-aksel-template="404-v1"
|
||||
width="min(100%, 500px)"
|
||||
viewBox="0 0 550 340"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-labelledby="404-illustration"
|
||||
>
|
||||
<title id="404-illustration">404 - fant ikke siden</title>
|
||||
<path
|
||||
d="M60.0927 243.567L95.542 245.427L96.7806 221.769C97.1476 214.76 97.7964 206.556 98.7272 197.16C99.8768 187.775 100.745 179.584 101.33 172.585L100.017 172.516C97.0704 178.512 94.0083 184.612 90.831 190.815C87.6652 196.799 84.3842 202.887 80.9881 209.079L60.0927 243.567ZM90.8631 334.801L93.3058 288.143L4.68237 283.493L6.74662 244.063L84.0445 125.551L154.287 129.236L148.06 248.182L170.38 249.353L168.143 292.069L145.823 290.898L143.381 337.556L90.8631 334.801Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M265.703 258.53C242.695 258.53 223.96 249.317 209.498 230.891C195.255 212.246 188.133 185.046 188.133 149.291C188.133 113.536 195.255 86.7747 209.498 69.0069C223.96 51.0198 242.695 42.0263 265.703 42.0263C288.711 42.0263 307.337 51.0198 321.58 69.0069C336.042 86.994 343.273 113.755 343.273 149.291C343.273 185.046 336.042 212.246 321.58 230.891C307.337 249.317 288.711 258.53 265.703 258.53ZM265.703 215.097C270.085 215.097 274.139 213.452 277.864 210.162C281.589 206.871 284.548 200.51 286.739 191.078C288.93 181.646 290.026 167.717 290.026 149.291C290.026 130.865 288.93 117.155 286.739 108.162C284.548 98.9489 281.589 92.9166 277.864 90.065C274.139 86.994 270.085 85.4585 265.703 85.4585C261.321 85.4585 257.267 86.994 253.542 90.065C249.817 92.9166 246.858 98.9489 244.667 108.162C242.476 117.155 241.38 130.865 241.38 149.291C241.38 167.717 242.476 181.646 244.667 191.078C246.858 200.51 249.817 206.871 253.542 210.162C257.267 213.452 261.321 215.097 265.703 215.097Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M429.98 129.301L465.429 127.441L464.191 103.783C463.824 96.7733 463.613 88.5473 463.557 79.105C463.721 69.6512 463.728 61.4137 463.58 54.3925L462.267 54.4614C459.962 60.7326 457.554 67.1192 455.042 73.621C452.518 79.9038 449.891 86.3018 447.16 92.8151L429.98 129.301ZM470.108 216.815L467.666 170.156L379.042 174.806L376.978 135.376L441.478 9.42432L511.72 5.7392L517.947 124.686L540.267 123.515L542.503 166.23L520.183 167.401L522.626 214.06L470.108 216.815Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const args = {
|
||||
index: 4,
|
||||
title: "Flerspråk",
|
||||
desc: "En 404-feil kan være frustrerende, spesielt hvis den er på et ukjent språk. En melding på engelsk kan gjøre det lettere å forstå problemet og hva du skal gjøre videre",
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": 1,
|
||||
"changelog": [
|
||||
{
|
||||
"description": "Publiserte varianter med CTA, tilbakemelding og språkvalg",
|
||||
"date": "03.11.2023",
|
||||
"version": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import {
|
||||
BodyShort,
|
||||
Box,
|
||||
HGrid,
|
||||
Heading,
|
||||
Link,
|
||||
List,
|
||||
Page,
|
||||
} from "@navikt/ds-react";
|
||||
import Footer from "components/layout/footer/Footer";
|
||||
import { Header } from "components/layout/header/Header";
|
||||
|
||||
export default function Example() {
|
||||
return (
|
||||
<Page footer={<Footer />}>
|
||||
<Header />
|
||||
<Page.Block as="main" width="xl" gutters>
|
||||
<Box paddingBlock="20 16">
|
||||
<HGrid gap="12" columns={{ sm: 1, md: 2 }}>
|
||||
<div>
|
||||
<Heading level="1" size="large" spacing>
|
||||
Beklager, vi fant ikke siden
|
||||
</Heading>
|
||||
<BodyShort>
|
||||
Denne siden kan være slettet eller flyttet, eller det er en feil
|
||||
i lenken.
|
||||
</BodyShort>
|
||||
<List>
|
||||
<List.Item>Bruk gjerne søket eller menyen</List.Item>
|
||||
<List.Item>
|
||||
<Link href="#">Gå til forsiden</Link>
|
||||
</List.Item>
|
||||
</List>
|
||||
</div>
|
||||
<StatusSvg />
|
||||
</HGrid>
|
||||
</Box>
|
||||
</Page.Block>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
function StatusSvg() {
|
||||
return (
|
||||
<svg
|
||||
data-aksel-template="404-v1"
|
||||
width="min(100%, 500px)"
|
||||
viewBox="0 0 550 340"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-labelledby="404-illustration"
|
||||
>
|
||||
<title id="404-illustration">404 - fant ikke siden</title>
|
||||
<path
|
||||
d="M60.0927 243.567L95.542 245.427L96.7806 221.769C97.1476 214.76 97.7964 206.556 98.7272 197.16C99.8768 187.775 100.745 179.584 101.33 172.585L100.017 172.516C97.0704 178.512 94.0083 184.612 90.831 190.815C87.6652 196.799 84.3842 202.887 80.9881 209.079L60.0927 243.567ZM90.8631 334.801L93.3058 288.143L4.68237 283.493L6.74662 244.063L84.0445 125.551L154.287 129.236L148.06 248.182L170.38 249.353L168.143 292.069L145.823 290.898L143.381 337.556L90.8631 334.801Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M265.703 258.53C242.695 258.53 223.96 249.317 209.498 230.891C195.255 212.246 188.133 185.046 188.133 149.291C188.133 113.536 195.255 86.7747 209.498 69.0069C223.96 51.0198 242.695 42.0263 265.703 42.0263C288.711 42.0263 307.337 51.0198 321.58 69.0069C336.042 86.994 343.273 113.755 343.273 149.291C343.273 185.046 336.042 212.246 321.58 230.891C307.337 249.317 288.711 258.53 265.703 258.53ZM265.703 215.097C270.085 215.097 274.139 213.452 277.864 210.162C281.589 206.871 284.548 200.51 286.739 191.078C288.93 181.646 290.026 167.717 290.026 149.291C290.026 130.865 288.93 117.155 286.739 108.162C284.548 98.9489 281.589 92.9166 277.864 90.065C274.139 86.994 270.085 85.4585 265.703 85.4585C261.321 85.4585 257.267 86.994 253.542 90.065C249.817 92.9166 246.858 98.9489 244.667 108.162C242.476 117.155 241.38 130.865 241.38 149.291C241.38 167.717 242.476 181.646 244.667 191.078C246.858 200.51 249.817 206.871 253.542 210.162C257.267 213.452 261.321 215.097 265.703 215.097Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
<path
|
||||
d="M429.98 129.301L465.429 127.441L464.191 103.783C463.824 96.7733 463.613 88.5473 463.557 79.105C463.721 69.6512 463.728 61.4137 463.58 54.3925L462.267 54.4614C459.962 60.7326 457.554 67.1192 455.042 73.621C452.518 79.9038 449.891 86.3018 447.16 92.8151L429.98 129.301ZM470.108 216.815L467.666 170.156L379.042 174.806L376.978 135.376L441.478 9.42432L511.72 5.7392L517.947 124.686L540.267 123.515L542.503 166.23L520.183 167.401L522.626 214.06L470.108 216.815Z"
|
||||
stroke="var(--a-border-default)"
|
||||
strokeWidth="2.19124"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeDasharray="6.57 8.76"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const args = {
|
||||
index: 5,
|
||||
title: "Uten dekoratøren",
|
||||
desc: "404-malen kan også enkelt brukes på sider uten nav-dekoratøren.",
|
||||
sandbox: false,
|
||||
};
|
||||
@@ -17,6 +17,7 @@ Disallow: /*_ssgManifest.js$
|
||||
Disallow: /*.js$
|
||||
|
||||
Disallow: /eksempler
|
||||
Disallow: /templates
|
||||
Disallow: /admin
|
||||
|
||||
Sitemap: https://aksel.nav.no/sitemap.xml
|
||||
@@ -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",
|
||||
@@ -33,24 +46,56 @@ export const KodeEksempelDoc = defineType({
|
||||
name: "fil",
|
||||
type: "object",
|
||||
fields: [
|
||||
{ title: "Title", name: "title", type: "string" },
|
||||
{ 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,60 @@
|
||||
import dotenv from "dotenv";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import RSS from "rss";
|
||||
import { noCdnClient } from "../sanity/interface/client.server";
|
||||
|
||||
dotenv.config();
|
||||
dotenv.config({ path: `.env.local` });
|
||||
|
||||
const token = process.env.SANITY_PRIVATE_NO_DRAFTS;
|
||||
|
||||
if (!token) {
|
||||
throw new Error(
|
||||
"Missing token 'SANITY_PRIVATE_NO_DRAFTS' when updating RSS-feed"
|
||||
);
|
||||
}
|
||||
|
||||
generateRssFeed();
|
||||
|
||||
async function generateRssFeed() {
|
||||
const site_url = "https://aksel.nav.no";
|
||||
const rss_path = "produktbloggen-rss.xml";
|
||||
const rss_dir = "public/rss";
|
||||
|
||||
const query = `*[_type == "aksel_blogg"] | order(publishedAt desc) {
|
||||
heading,
|
||||
ingress,
|
||||
publishedAt,
|
||||
_id,
|
||||
"slug": slug.current,
|
||||
}`;
|
||||
|
||||
const bloggposts = await noCdnClient(token).fetch(query);
|
||||
|
||||
const feedOptions = {
|
||||
title: "Produktbloggen - aksel.nav.no",
|
||||
site_url,
|
||||
feed_url: `${site_url}/rss/${rss_path}`,
|
||||
pubDate: new Date(),
|
||||
};
|
||||
|
||||
const feed = new RSS(feedOptions);
|
||||
|
||||
bloggposts.forEach((post) => {
|
||||
feed.item({
|
||||
title: post.heading,
|
||||
description: post.ingress,
|
||||
url: `${site_url}/${post.slug}`,
|
||||
date: post.publishedAt,
|
||||
});
|
||||
});
|
||||
|
||||
const rssPath = path.resolve(process.cwd(), rss_dir);
|
||||
|
||||
if (!fs.existsSync(rssPath)) {
|
||||
fs.mkdirSync(rssPath);
|
||||
}
|
||||
|
||||
fs.writeFileSync(`${rssPath}/${rss_path}`, feed.xml({ indent: true }));
|
||||
}
|
||||
@@ -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("templates");
|
||||
|
||||
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,48 @@
|
||||
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,
|
||||
title: args?.title ?? file.replace(".tsx", ""),
|
||||
navn: 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,16 @@
|
||||
export type FileArrayT = {
|
||||
innhold: string;
|
||||
title: 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,98 @@
|
||||
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).map((x) => ({
|
||||
...x,
|
||||
_key: x.navn.split(".")[0],
|
||||
})),
|
||||
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();
|
||||
}
|
||||
@@ -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,31 @@ export interface RelatertInnholdT {
|
||||
>;
|
||||
}
|
||||
|
||||
export type CodeExampleSchemaT = {
|
||||
_id: string;
|
||||
_type: string;
|
||||
title: string;
|
||||
variant: "eksempler" | "templates";
|
||||
filer: {
|
||||
title: string;
|
||||
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"];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 },
|
||||
};
|
||||
|
||||
+16
-16
@@ -15,7 +15,7 @@
|
||||
"chromatic": "npx chromatic --project-token x3xqdfgkujg --build-script-name build:storybook",
|
||||
"build:storybook": "storybook build",
|
||||
"test": "yarn workspaces foreach -p run test",
|
||||
"lint": "yarn eslint . && yarn stylelint @navikt/**/*.css",
|
||||
"lint": "yarn eslint --rule \"import/no-cycle:error\" . && yarn stylelint @navikt/**/*.css",
|
||||
"lint:css": "yarn stylelint @navikt/**/*.css",
|
||||
"changeset": "changeset",
|
||||
"version": "changeset version && yarn changelog",
|
||||
@@ -120,19 +120,19 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "2.26.2",
|
||||
"@storybook/addon-a11y": "^7.4.1",
|
||||
"@storybook/addon-essentials": "^7.4.1",
|
||||
"@storybook/addon-interactions": "^7.4.1",
|
||||
"@storybook/addon-storysource": "^7.4.1",
|
||||
"@storybook/blocks": "^7.4.1",
|
||||
"@storybook/csf-tools": "^7.4.1",
|
||||
"@storybook/jest": "^0.2.2",
|
||||
"@storybook/manager-api": "^7.4.1",
|
||||
"@storybook/nextjs": "^7.4.1",
|
||||
"@storybook/react": "^7.4.1",
|
||||
"@storybook/react-vite": "^7.4.1",
|
||||
"@storybook/testing-library": "^0.2.0",
|
||||
"@storybook/theming": "^7.4.1",
|
||||
"@storybook/addon-a11y": "^7.5.3",
|
||||
"@storybook/addon-essentials": "^7.5.3",
|
||||
"@storybook/addon-interactions": "^7.5.3",
|
||||
"@storybook/addon-storysource": "^7.5.3",
|
||||
"@storybook/blocks": "^7.5.3",
|
||||
"@storybook/csf-tools": "^7.5.3",
|
||||
"@storybook/jest": "^0.2.3",
|
||||
"@storybook/manager-api": "^7.5.3",
|
||||
"@storybook/nextjs": "^7.5.3",
|
||||
"@storybook/react": "^7.5.3",
|
||||
"@storybook/react-vite": "^7.5.3",
|
||||
"@storybook/testing-library": "^0.2.2",
|
||||
"@storybook/theming": "^7.5.3",
|
||||
"@svitejs/changesets-changelog-github-compact": "^1.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.7.3",
|
||||
"@typescript-eslint/parser": "^6.7.3",
|
||||
@@ -146,7 +146,7 @@
|
||||
"eslint-plugin-jsx-a11y": "^6.7.1",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-storybook": "^0.6.14",
|
||||
"eslint-plugin-storybook": "^0.6.15",
|
||||
"eslint-plugin-testing-library": "^6.0.2",
|
||||
"fast-glob": "3.2.11",
|
||||
"fs-extra": "^10.0.1",
|
||||
@@ -158,7 +158,7 @@
|
||||
"react": "^18.0.0",
|
||||
"react-docgen-typescript": "2.2.2",
|
||||
"react-dom": "^18.0.0",
|
||||
"storybook": "^7.4.1",
|
||||
"storybook": "^7.5.3",
|
||||
"stylelint": "^14.8.5",
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-standard": "^25.0.0",
|
||||
|
||||
Loaded 100 of 101 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user