Compare commits

...
Author SHA1 Message Date
github-actions[bot]andgithub-actions[bot] 44671abb5f Version Packages (#1885)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-03-29 13:27:04 +02:00
Ken 2eb358ad88 ✨ Alert, Chips og ErrorSummary har nå bedre utvalg av tokens
📝 Token for Toggle-chips text

🎨 Alert bruker nye ikoner, token for ikonfarger

🎨 Alert bruker gamle ikoner, men nå med tokens

🎨 Error-summary bruker nå riktig token for listemarkering
2023-03-29 13:15:29 +02:00
Ken 6bdc02761b Merge branch 'codeblock' 2023-03-29 12:48:34 +02:00
Ken f52ef19be2 ♻️ Refactor copy-button
💄 Copybutton animasjon

💄 dropdown bakgrunn-animert

💄 bakgrunnsfarge på snippet

💄 Toc-animasjon

♻️ bruker en samlet copybutton-implementasjon
2023-03-29 12:48:23 +02:00
github-actions[bot]andgithub-actions[bot] 989a97a8bc Version Packages (#1880)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-03-29 10:53:19 +02:00
Ken 8de6ba22c3 🎨 Bedre tokens for accordion 2023-03-29 10:49:39 +02:00
Ken f664370826 🎨 Accordion tokens for header-bakgrunn 2023-03-29 10:38:19 +02:00
Ken 55b5856183 🐛 Select text-color (#1879) 2023-03-29 10:21:44 +02:00
Ken 5a72a62190 🐛 Fikset preview for komponentsider
🔥 Fjernet JSX.Element type fra gammel nextjs config
2023-03-28 10:46:37 +02:00
Ken d89eaccd44 ♻️ Refactor query-struktur og typer for /pages
♻️ refaktorert forside-setup

🏷️ Flyttet ts-typer

🚚 Inlinet Template-sider

🚚 Inlinet prinsipp-template

♻️ Refactor god-praksis sider

♻️ Refakorert typer for blogg, komponenter og grunnleggende
2023-03-27 16:56:10 +02:00
Ken 7cffc0bf12 ♿ Bruker native ol-liste da skjermleser nå feilet 2023-03-24 16:12:09 +01:00
Ken 8d4966c83f 💄 Erstattet li-element med css 2023-03-24 16:06:50 +01:00
100 changed files with 1651 additions and 1506 deletions

No files matched your search

+4
View File
@@ -1,5 +1,9 @@
# @navikt/aksel-icons
## 2.8.6
## 2.8.5
## 2.8.4
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-icons",
"version": "2.8.4",
"version": "2.8.6",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/ikoner",
"repository": {
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-codemod
## 2.8.6
## 2.8.5
## 2.8.4
## 2.8.3
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-codemod",
"version": "2.8.4",
"version": "2.8.6",
"description": "Aksel codemods for NAVs designsystem",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
+2 -2
View File
@@ -39,8 +39,8 @@
"build-pict": "svgr --silent --index-template index-template.js --out-dir src/pictograms pictograms"
},
"dependencies": {
"@navikt/ds-icons": "^2.8.4",
"@navikt/ds-react": "^2.8.4",
"@navikt/ds-icons": "^2.8.6",
"@navikt/ds-react": "^2.8.6",
"clsx": "^1.1.1"
},
"devDependencies": {
+14
View File
@@ -1,5 +1,19 @@
# @navikt/ds-css
## 2.8.6
### Patch Changes
- [`2eb358ad8`](https://github.com/navikt/aksel/commit/2eb358ad888979d21c385b3900973946f3f466be) Thanks [@KenAJoh](https://github.com/KenAJoh)! - Alert, Chips og ErrorSummary har nå bedre utvalg av tokens
## 2.8.5
### Patch Changes
- [`f66437082`](https://github.com/navikt/aksel/commit/f664370826ed51bda7ad681e1f1799c26d2c1f0a) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :art: Accordion-tokens for header bakgrunn
- [#1879](https://github.com/navikt/aksel/pull/1879) [`55b585618`](https://github.com/navikt/aksel/commit/55b585618341a4d8bf26ed9b9e129d897b1600dc) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :bug: Fikset tekstfarge i select på iphone
## 2.8.4
## 2.8.3
+7 -2
View File
@@ -11,7 +11,7 @@
padding: 14px var(--a-spacing-3) var(--a-spacing-3);
margin: 0;
text-align: left;
background: transparent;
background: var(--ac-accordion-header-bg, var(--a-surface-transparent));
cursor: pointer;
border: none;
border-bottom: 2px solid var(--ac-accordion-header-border, var(--a-border-divider));
@@ -25,6 +25,7 @@
.navds-accordion__header:hover {
color: var(--ac-accordion-header-text-hover, var(--a-text-action-on-action-subtle));
border-color: var(--ac-accordion-header-border-hover, var(--a-border-default));
background: var(--ac-accordion-header-bg-hover, var(--a-surface-transparent));
}
.navds-accordion__header-content {
@@ -33,10 +34,14 @@
}
.navds-accordion__item--open > .navds-accordion__header {
background-color: var(--ac-accordion-item-bg-open, var(--a-surface-action-subtle));
background-color: var(--ac-accordion-header-bg-open, var(--ac-accordion-item-bg-open, var(--a-surface-action-subtle)));
border-color: var(--ac-accordion-item-border-open, var(--a-surface-action-subtle));
}
.navds-accordion__item--open > :where(.navds-accordion__header:hover) {
background-color: var(--ac-accordion-header-bg-open-hover, var(--a-surface-action-subtle));
}
.navds-accordion__content {
padding: var(--a-spacing-3) var(--a-spacing-3) 18px;
border-bottom: 2px solid var(--ac-accordion-content-border, var(--a-border-divider));
+13
View File
@@ -37,6 +37,10 @@
background-color: var(--ac-alert-error-bg, var(--a-surface-danger-subtle));
}
.navds-alert--error > .navds-alert__icon {
color: var(--ac-alert-icon-error-color, var(--a-icon-danger));
}
.navds-alert--warning {
border-color: var(--ac-alert-warning-border, var(--a-border-warning));
background-color: var(--ac-alert-warning-bg, var(--a-surface-warning-subtle));
@@ -44,6 +48,7 @@
.navds-alert--warning > .navds-alert__icon {
background: radial-gradient(circle at 50% 57%, var(--a-surface-default) 32%, 0, transparent);
color: var(--ac-alert-icon-warning-color, var(--a-icon-warning));
}
.navds-alert--info {
@@ -51,11 +56,19 @@
background-color: var(--ac-alert-info-bg, var(--a-surface-info-subtle));
}
.navds-alert--info > .navds-alert__icon {
color: var(--ac-alert-icon-info-color, var(--a-icon-info));
}
.navds-alert--success {
border-color: var(--ac-alert-success-border, var(--a-border-success));
background-color: var(--ac-alert-success-bg, var(--a-surface-success-subtle));
}
.navds-alert--success > .navds-alert__icon {
color: var(--ac-alert-icon-success-color, var(--a-icon-success));
}
.navds-alert--inline {
background-color: transparent;
border: none;
+1
View File
@@ -36,6 +36,7 @@
.navds-chips__toggle {
box-shadow: inset 0 0 0 1px var(--ac-chip-toggle-border, var(--a-border-default));
background-color: var(--ac-chip-toggle-bg, var(--a-surface-neutral-subtle));
color: var(--ac-chip-toggle-text, var(--a-text-default));
}
.navds-chips__toggle:hover {
+1 -1
View File
@@ -23,7 +23,7 @@
}
.navds-error-summary__list > * {
color: var(--a-blue-500);
color: var(--ac-error-summary-list-dot, var(--a-text-action));
}
.navds-error-summary--small > .navds-error-summary__list {
+1
View File
@@ -3,6 +3,7 @@
background-color: var(--ac-select-bg, var(--a-surface-default));
border-radius: var(--a-border-radius-medium);
border: 1px solid var(--ac-select-border, var(--a-border-default));
color: var(--ac-select-text, var(--a-text-default));
width: 100%;
box-sizing: border-box;
min-height: 48px;
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "2.8.4",
"version": "2.8.6",
"description": "CSS for NAV Designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -20,7 +20,7 @@
"watch": "postcss --watch --use postcss-import -o dist/index.css index.css"
},
"devDependencies": {
"@navikt/ds-tokens": "^2.8.4",
"@navikt/ds-tokens": "^2.8.6",
"normalize.css": "^8.0.1",
"postcss": "^8.4.0",
"postcss-cli": "^9.0.0",
+13 -2
View File
@@ -2,18 +2,26 @@
"alert": {
"--ac-alert-error-border": "--a-border-danger",
"--ac-alert-error-bg": "--a-surface-danger-subtle",
"--ac-alert-icon-error-color": "--a-icon-danger",
"--ac-alert-warning-border": "--a-border-warning",
"--ac-alert-warning-bg": "--a-surface-warning-subtle",
"--ac-alert-icon-warning-color": "--a-icon-warning",
"--ac-alert-info-border": "--a-border-info",
"--ac-alert-info-bg": "--a-surface-info-subtle",
"--ac-alert-icon-info-color": "--a-icon-info",
"--ac-alert-success-border": "--a-border-success",
"--ac-alert-success-bg": "--a-surface-success-subtle"
"--ac-alert-success-bg": "--a-surface-success-subtle",
"--ac-alert-icon-success-color": "--a-icon-success"
},
"accordion": {
"--ac-accordion-header-bg": "--ac-surface-transparent",
"--ac-accordion-header-bg-hover": "--ac-surface-transparent",
"--ac-accordion-header-border": "--a-border-divider",
"--ac-accordion-header-text-hover": "--a-text-action-on-action-subtle",
"--ac-accordion-header-border-hover": "--a-border-default",
"--ac-accordion-item-bg-open": "--a-surface-action-subtle",
"--ac-accordion-header-bg-open": "--ac-accordion-item-bg-open",
"--ac-accordion-header-bg-open-hover": "--a-surface-action-subtle",
"--ac-accordion-item-border-open": "--a-surface-action-subtle",
"--ac-accordion-content-border": "--a-border-divider",
"--ac-accordion-content-border-open": "--a-border-default"
@@ -76,6 +84,7 @@
"chips": {
"--ac-chip-toggle-border": "--a-border-default",
"--ac-chip-toggle-bg": "--a-surface-neutral-subtle",
"--ac-chip-toggle-text": "--a-text-default",
"--ac-chip-toggle-hover-border": "--a-border-strong",
"--ac-chip-toggle-hover-bg": "--a-surface-neutral-subtle-hover",
"--ac-chip-toggle-pressed-bg": "--a-surface-action-selected",
@@ -292,7 +301,8 @@
},
"errorsummary": {
"--ac-error-summary-bg": "--a-surface-default",
"--ac-error-summary-border": "--a-border-danger"
"--ac-error-summary-border": "--a-border-danger",
"--ac-error-summary-list-dot": "--a-text-action"
},
"checkbox-radio": {
"--ac-radio-checkbox-bg": "--a-surface-default",
@@ -312,6 +322,7 @@
},
"select": {
"--ac-select-bg": "--a-surface-default",
"--ac-select-text": "--a-text-default",
"--ac-select-border": "--a-border-default",
"--ac-select-hover-bg": "--a-border-action",
"--ac-select-error-border": "--a-surface-danger"
+18
View File
@@ -1,5 +1,23 @@
# @navikt/ds-react
## 2.8.6
### Patch Changes
- [`2eb358ad8`](https://github.com/navikt/aksel/commit/2eb358ad888979d21c385b3900973946f3f466be) Thanks [@KenAJoh](https://github.com/KenAJoh)! - Alert, Chips og ErrorSummary har nå bedre utvalg av tokens
- Updated dependencies []:
- @navikt/aksel-icons@2.8.6
- @navikt/ds-icons@2.8.6
## 2.8.5
### Patch Changes
- Updated dependencies []:
- @navikt/aksel-icons@2.8.5
- @navikt/ds-icons@2.8.5
## 2.8.4
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "2.8.4",
"version": "2.8.6",
"description": "Aksel react-components for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -37,8 +37,8 @@
},
"dependencies": {
"@floating-ui/react": "0.17.0",
"@navikt/aksel-icons": "^2.8.4",
"@navikt/ds-icons": "^2.8.4",
"@navikt/aksel-icons": "^2.8.6",
"@navikt/ds-icons": "^2.8.6",
"@radix-ui/react-tabs": "1.0.0",
"@radix-ui/react-toggle-group": "1.0.0",
"clsx": "^1.2.1",
+8 -8
View File
@@ -1,8 +1,8 @@
import {
ErrorColored,
InformationColored,
SuccessColored,
WarningColored,
ErrorFilled,
InformationFilled,
SuccessFilled,
WarningFilled,
} from "@navikt/ds-icons";
import cl from "clsx";
import React, { forwardRef } from "react";
@@ -37,13 +37,13 @@ export interface AlertProps extends React.HTMLAttributes<HTMLDivElement> {
const Icon = ({ variant, ...props }) => {
switch (variant) {
case "error":
return <ErrorColored title="Feil" {...props} />;
return <ErrorFilled title="Feil" {...props} />;
case "warning":
return <WarningColored title="Advarsel" {...props} />;
return <WarningFilled title="Advarsel" {...props} />;
case "info":
return <InformationColored title="Informasjon" {...props} />;
return <InformationFilled title="Informasjon" {...props} />;
case "success":
return <SuccessColored title="Suksess" {...props} />;
return <SuccessFilled title="Suksess" {...props} />;
default:
return null;
}
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-tailwind
## 2.8.6
## 2.8.5
## 2.8.4
## 2.8.3
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tailwind",
"version": "2.8.4",
"version": "2.8.6",
"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": "^2.8.4",
"@navikt/ds-tokens": "^2.8.6",
"@types/jest": "^29.0.0",
"color": "4.2.3",
"jest": "^29.0.0",
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-tokens
## 2.8.6
## 2.8.5
## 2.8.4
## 2.8.3
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tokens",
"version": "2.8.4",
"version": "2.8.6",
"description": "Design-tokens for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-icons
## 2.8.6
## 2.8.5
## 2.8.4
## 2.8.3
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-icons",
"version": "2.8.4",
"version": "2.8.6",
"description": "Aksel icons for NAV",
"author": "Aksel | NAV designsystem team",
"repository": {
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-css-internal
## 2.8.6
## 2.8.5
## 2.8.4
## 2.8.3
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css-internal",
"version": "2.8.4",
"version": "2.8.6",
"description": "CSS for NAV internal Designsystem-components",
"author": "Aksel | NAV designsystem team",
"keywords": [
+16
View File
@@ -1,5 +1,21 @@
# @navikt/ds-react-internal
## 2.8.6
### Patch Changes
- Updated dependencies [[`2eb358ad8`](https://github.com/navikt/aksel/commit/2eb358ad888979d21c385b3900973946f3f466be)]:
- @navikt/ds-react@2.8.6
- @navikt/ds-icons@2.8.6
## 2.8.5
### Patch Changes
- Updated dependencies []:
- @navikt/ds-react@2.8.5
- @navikt/ds-icons@2.8.5
## 2.8.4
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react-internal",
"version": "2.8.4",
"version": "2.8.6",
"description": "Aksel react components for internal UIs in NAV",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -35,8 +35,8 @@
"watch": "tsc --watch -p tsconfig.esm.json"
},
"dependencies": {
"@navikt/ds-icons": "^2.8.4",
"@navikt/ds-react": "^2.8.4",
"@navikt/ds-icons": "^2.8.6",
"@navikt/ds-react": "^2.8.6",
"clsx": "^1.1.1",
"copy-to-clipboard": "^3.3.1"
},
+9 -9
View File
@@ -15,15 +15,15 @@
"website"
],
"dependencies": {
"@navikt/aksel-icons": "^2.8.4",
"@navikt/ds-codemod": "^2.8.4",
"@navikt/ds-css": "^2.8.4",
"@navikt/ds-css-internal": "^2.8.4",
"@navikt/ds-icons": "^2.8.4",
"@navikt/ds-react": "^2.8.4",
"@navikt/ds-react-internal": "^2.8.4",
"@navikt/ds-tailwind": "^2.8.4",
"@navikt/ds-tokens": "^2.8.4"
"@navikt/aksel-icons": "^2.8.6",
"@navikt/ds-codemod": "^2.8.6",
"@navikt/ds-css": "^2.8.6",
"@navikt/ds-css-internal": "^2.8.6",
"@navikt/ds-icons": "^2.8.6",
"@navikt/ds-react": "^2.8.6",
"@navikt/ds-react-internal": "^2.8.6",
"@navikt/ds-tailwind": "^2.8.6",
"@navikt/ds-tokens": "^2.8.6"
},
"devDependencies": {
"prettier-plugin-tailwindcss": "^0.2.3"
@@ -1,7 +1,7 @@
import React from "react";
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
const Logo = (props): JSX.Element => (
const Logo = (props) => (
<svg
width="119"
height="26"
@@ -1,5 +1,5 @@
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
const NAVLogoDark = (props): JSX.Element => (
const NAVLogoDark = (props) => (
<svg
width="3.25em"
height="3.25em"
@@ -1,5 +1,5 @@
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
const NAVLogoWhite = (props): JSX.Element => (
const NAVLogoWhite = (props) => (
<svg
width="3.25em"
height="3.25em"
-1
View File
@@ -1,5 +1,4 @@
export * from "./assets";
export { default as LayoutPicker } from "./layout/TemplatePicker";
export { default as Accordion } from "./sanity-modules/Accordion";
export { default as Alert } from "./sanity-modules/Alert";
export { default as Bilde } from "./sanity-modules/bilde/Bilde";
@@ -1,53 +0,0 @@
import Error from "next/error";
import React from "react";
import { SanityT } from "@/lib";
import AkselArtikkelTemplate from "./page-templates/AkselArtikkel";
import AkselPrinsippTemplate from "./page-templates/AkselPrinsipp";
type aksel_artikkel = {
aksel_artikkel: (props: {
data: SanityT.Schema.aksel_artikkel;
title: string;
}) => JSX.Element;
};
type aksel_prinsipp = {
aksel_prinsipp: (props: {
data: SanityT.Schema.aksel_prinsipp;
title: string;
}) => JSX.Element;
};
type templateT = aksel_artikkel | aksel_prinsipp;
const templates: templateT = {
aksel_artikkel: (props) => <AkselArtikkelTemplate {...props} />,
aksel_prinsipp: (props) => <AkselPrinsippTemplate {...props} />,
};
const TemplatePicker = ({
data,
title,
}: {
data: SanityT.Schema.aksel_artikkel | SanityT.Schema.aksel_prinsipp;
title: string;
}): JSX.Element => {
if (!Object.keys(templates).includes(data?._type)) {
console.warn(
`${data?._type} does not have a valid template to use, please create one.`
);
return (
<Error
statusCode={404}
title="Sanity-side mangler template, kontakt utvikler"
/>
);
}
const Template = templates[data?._type];
return <Template data={data} title={title} />;
};
export default TemplatePicker;
@@ -1,4 +1,4 @@
import { PageTypeT, SidebarT, urlFor } from "@/lib";
import { urlFor } from "@/lib";
import { Detail, Heading, Link } from "@navikt/ds-react";
import Footer from "components/layout/footer/Footer";
import { Header } from "components/layout/header/Header";
@@ -10,6 +10,7 @@ import NextLink from "next/link";
import { capitalize } from "@/utils";
import Image from "next/legacy/image";
import { TableOfContentsv2 } from "components/website-modules/TOCv2";
import { AkselSidebarT } from "@/types";
const HeaderCube = ({ ...props }) => (
<svg
@@ -59,8 +60,11 @@ export const WithSidebar = ({
footer,
}: {
children: ReactNode;
sidebar: SidebarT;
pageType: PageTypeT;
sidebar: AkselSidebarT;
pageType: {
type: "Komponenter" | "Grunnleggende";
title: string;
};
pageProps: any;
intro?: ReactNode;
footer?: ReactNode;
@@ -1,6 +1,6 @@
import { Button, Label, Textarea } from "@navikt/ds-react";
import { IdContext } from "components/website-modules/utils/contexts/id-context";
import { FeedbackT } from "lib/types/types";
import { FeedbackT } from "@/types";
import { useRouter } from "next/router";
import { useContext, useEffect, useState } from "react";
@@ -1,5 +1,5 @@
import { Label } from "@navikt/ds-react";
import { GroupedHits, SearchHit, options } from "lib/types/search";
import { GroupedHitsT, SearchHitT, searchOptions } from "@/types";
import { Hit, IconHit, IconPageHit } from "./Hit";
import React from "react";
@@ -9,7 +9,7 @@ export function Group({
startIndex,
logSuccess,
}: {
groups: GroupedHits;
groups: GroupedHitsT;
query: string;
startIndex: number;
logSuccess: (index: number, url: string) => void;
@@ -21,7 +21,7 @@ export function Group({
return (
<>
{Object.entries(groups)
.sort((a, b) => options[a[0]].index - options[b[0]].index)
.sort((a, b) => searchOptions[a[0]].index - searchOptions[b[0]].index)
.map(([key, val], index, arr) => {
const prev = arr.slice(0, index);
const total =
@@ -32,7 +32,7 @@ export function Group({
logSuccess={logSuccess}
startIndex={total}
key={key}
heading={`${options[key].display} (${val.length})`}
heading={`${searchOptions[key].display} (${val.length})`}
hits={val}
query={query}
/>
@@ -50,7 +50,7 @@ export function GroupComponent({
logSuccess,
}: {
heading: React.ReactNode;
hits: SearchHit[];
hits: SearchHitT[];
query: string;
startIndex: number;
logSuccess: (index: number, url: string) => void;
@@ -4,7 +4,7 @@ import { Tag } from "@navikt/ds-react";
import cl from "classnames";
import Image from "next/legacy/image";
import { StatusTag } from "components/website-modules/StatusTag";
import { SearchHit } from "lib/types/search";
import { SearchHitT } from "@/types";
import NextLink from "next/link";
export function Hit({
@@ -13,7 +13,7 @@ export function Hit({
index,
logSuccess,
}: {
hit: SearchHit;
hit: SearchHitT;
query: string;
index: number;
logSuccess: (index: number, url: string) => void;
@@ -81,7 +81,7 @@ export function IconHit({
index,
logSuccess,
}: {
hit: SearchHit;
hit: SearchHitT;
query: string;
index: number;
logSuccess: (index: number, url: string) => void;
@@ -139,7 +139,7 @@ export function IconPageHit({
index,
logSuccess,
}: {
hit: SearchHit;
hit: SearchHitT;
query: string;
index: number;
logSuccess: (index: number, url: string) => void;
@@ -9,7 +9,7 @@ import {
Search,
} from "@navikt/ds-react";
import { ChangeLogIconOutline } from "components/assets";
import { options, SearchResults } from "lib/types/search";
import { searchOptions, SearchResultsT } from "@/types";
import { useRouter } from "next/router";
import React, { useCallback, useEffect, useRef, useState } from "react";
import ReactModal from "react-modal";
@@ -24,10 +24,10 @@ import styles from "../header.module.css";
*/
export const GlobalSearch = () => {
const [results, setResults] = useState<SearchResults>(null);
const [results, setResults] = useState<SearchResultsT>(null);
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
const [activeTags, setTags] = useState<Array<keyof typeof options>>([]);
const [activeTags, setTags] = useState<Array<keyof typeof searchOptions>>([]);
const [os, setOs] = useState<"mac" | "windows">("windows");
const inputRef = useRef(null);
@@ -223,7 +223,7 @@ export const GlobalSearch = () => {
</button>
<div className="search-grid-filter mt-8">
<CheckboxGroup legend="Filter" onChange={setTags}>
{Object.entries(options)
{Object.entries(searchOptions)
.filter((x) => !x[1].hidden)
.map(([key, val]) => (
<Checkbox
@@ -284,7 +284,7 @@ export const GlobalSearch = () => {
{`${results?.totalHits} treff på "${query}"${
activeTags.length > 0
? ` i ${activeTags
.map((x) => options[x].display.toLowerCase())
.map((x) => searchOptions[x].display.toLowerCase())
.join(", ")}`
: ""
}`}
@@ -1,214 +0,0 @@
import { SanityT, urlFor } from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { Next } from "@navikt/ds-icons";
import { BodyShort, Detail, Heading, Ingress, Label } from "@navikt/ds-react";
import ArtikkelCard from "components/sanity-modules/cards/ArtikkelCard";
import Head from "next/head";
import NextLink from "next/link";
import {
abbrName,
BreadCrumbs,
dateStr,
Feedback,
TableOfContents,
} from "../..";
import { NoSidebarLayout } from "./wrappers/NoSidebar";
const AkselArtikkelTemplate = ({
data,
title,
}: {
data: SanityT.Schema.aksel_artikkel;
title: string;
}): JSX.Element => {
if (!data.content || !data.heading) {
console.warn(
`Artikkelen har ikke ${
!data.content ? "innhold" : "overskrift"
}, så den kan ikke vises.`
);
return null;
}
const date = data?.updateInfo?.lastVerified
? data?.updateInfo?.lastVerified
: data?.publishedAt
? data.publishedAt
: data._updatedAt;
const authors = (data?.contributors as any)?.map((x) => x?.title) ?? [];
const hasTema = "tema" in data && data.tema && data?.tema.length > 0;
const aside = data?.relevante_artikler?.length > 0 && (
<aside
className="overflow-x-clip py-8"
aria-labelledby="relevante-artikler-aside"
>
<div className="relativept-12 pb-16">
<div className="dynamic-wrapper">
<Heading
level="2"
size="medium"
className="text-deepblue-700 px-4"
id="relevante-artikler-aside"
>
{data?.relevante_artikler?.length === 1
? `Les også`
: `Relevante artikler`}
</Heading>
<div className="card-grid-3-1 mt-6 px-4">
{data.relevante_artikler.map((x: any) =>
x && x?._id ? <ArtikkelCard level="3" {...x} key={x._id} /> : null
)}
</div>
</div>
</div>
</aside>
);
const filteredTema =
hasTema && data?.tema?.filter((x: any) => x?.title && x?.slug);
return (
<>
<Head>
<title>{`${data?.heading} - ${title}`}</title>
<meta
property="og:title"
content={`${data?.heading} - ${title}`}
key="ogtitle"
/>
<meta
name="description"
content={data?.seo?.meta ?? data?.ingress}
key="desc"
/>
<meta
property="og:description"
content={data?.seo?.meta ?? data?.ingress}
key="ogdesc"
/>
<meta property="og:type" content="article" />
<meta
property="og:image"
content={
data?.seo?.image
? urlFor(data?.seo?.image)
.width(1200)
.height(630)
.fit("crop")
.quality(100)
.url()
: hasTema && (data.tema[0] as any)?.seo?.image
? urlFor((data.tema[0] as any)?.seo?.image)
.width(1200)
.height(630)
.fit("crop")
.quality(100)
.url()
: ""
}
key="ogimage"
/>
</Head>
<NoSidebarLayout aside={aside}>
<div className="mx-auto mb-16 max-w-prose lg:ml-0">
<BreadCrumbs auto />
<Heading
level="1"
size="large"
className="text-deepblue-800 mt-4 md:text-5xl"
>
{data.heading}
</Heading>
{data?.ingress && (
<Ingress className="override-text-700 mt-4 text-2xl">
{data?.ingress}
</Ingress>
)}
<div className="mt-6 inline-flex flex-wrap items-center gap-2 text-base">
<Detail uppercase as="span">
{dateStr(date)}
</Detail>
{authors?.length > 0 && (
<>
<span className="bg-deepblue-700 h-2 w-2 rotate-45 rounded-[1px] opacity-25" />
<BodyShort
size="small"
as="div"
className="flex flex-wrap gap-1"
>
<address className="not-italic">{authors?.[0]}</address>
</BodyShort>
</>
)}
</div>
{hasTema && (
<div className="mt-8 flex flex-wrap gap-2">
{filteredTema.map(({ title, slug }: any) => (
<span key={title}>
<NextLink
key={title}
href={`/god-praksis/${slug.current}`}
passHref
legacyBehavior
>
<BodyShort
size="small"
as="a"
className="min-h-8 text-deepblue-800 focus-visible:shadow-focus flex items-center justify-center gap-[2px] rounded-full bg-gray-200 pl-4 pr-1 capitalize no-underline hover:underline focus:outline-none"
>
{title}
<Next aria-hidden />
</BodyShort>
</NextLink>
</span>
))}
</div>
)}
</div>
<div className="relative mx-auto mt-4 max-w-prose lg:ml-0 lg:grid lg:max-w-none lg:grid-flow-row-dense lg:grid-cols-3 lg:items-start lg:gap-x-12">
<TableOfContents
changedState={data?.content ?? []}
hideToc={false}
aksel
/>
<div className="max-w-prose lg:col-span-2 lg:col-start-1">
<SanityBlockContent blocks={data?.content ?? []} variant="aksel" />
<div className="mt-12">
{authors?.length > 0 && (
<Label className="text-deepblue-700 mb-2" as="p">
Bidragsytere
</Label>
)}
{authors?.length > 0 && (
<BodyShort
as="div"
className="text-text-subtle mb-1 flex flex-wrap gap-1"
>
{authors.map(abbrName).map((x, y) => (
<address className="not-italic" key={x}>
{x}
{y !== authors.length - 1 && ", "}
</address>
))}
</BodyShort>
)}
<BodyShort as="span" className="text-text-subtle">
Publisert: {dateStr(data?.publishedAt ?? data?._updatedAt)}
</BodyShort>
</div>
<div className="mt-12 md:mt-16">
<Feedback akselFeedback docId={data?._id} docType={data?._type} />
</div>
</div>
</div>
</NoSidebarLayout>
</>
);
};
export default AkselArtikkelTemplate;
@@ -1,189 +0,0 @@
import { SanityT, urlFor } from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { BodyShort, Heading, Ingress, Label } from "@navikt/ds-react";
import cl from "clsx";
import { Header } from "components/layout/header/Header";
import Head from "next/head";
import { Footer } from "..";
import {
abbrName,
Bilde,
BreadCrumbs,
dateStr,
Feedback,
TableOfContents,
} from "../..";
const AkselPrinsippTemplate = ({
data,
title,
}: {
data: SanityT.Schema.aksel_prinsipp;
title: string;
}): JSX.Element => {
if (!data.content || !data.heading) {
console.warn(
`Artikkelen har ikke ${
!data.content ? "innhold" : "overskrift"
}, så den kan ikke vises.`
);
return null;
}
const authors = (data?.contributors as any)?.map((x) => x?.title) ?? [];
const mainPage = data?.prinsipp?.hovedside;
return (
<>
<Head>
<title>{`${data?.heading} - Prinsipp - ${title}`}</title>
<meta
property="og:title"
content={`${data?.heading} - ${title}`}
key="ogtitle"
/>
<meta
property="og:description"
content={data?.seo?.meta ?? data?.ingress}
key="ogdesc"
/>
<meta property="og:type" content="article" />
<meta
property="og:image"
content={
data?.seo?.image
? urlFor(data?.seo?.image)
.width(1200)
.height(630)
.fit("crop")
.quality(100)
.url()
: ""
}
key="ogimage"
/>
</Head>
<Header variant={mainPage ? "default" : "subtle"} />
<main
tabIndex={-1}
id="hovedinnhold"
className={cl("aksel-artikkel pt-4 focus:outline-none", {
"bg-white": mainPage,
"bg-surface-subtle": !mainPage,
})}
>
<article className="overflow-x-clip">
<div
className={cl("max-w-aksel mx-auto px-4 sm:w-[90%]", {
"pb-32": mainPage,
})}
>
<div className="pt-12">
<div className="mx-auto mb-16 max-w-prose lg:ml-0 ">
{!mainPage && (
<BreadCrumbs
text={`Prinsipper for ${data?.prinsipp?.prinsippvalg}`}
href={`/prinsipper/${data?.prinsipp?.prinsippvalg}`}
/>
)}
<Heading
level="1"
size="large"
className="text-deepblue-700 mt-4 md:text-5xl"
>
{data.heading}
</Heading>
{data?.ingress && (
<Ingress className="override-text-700 mt-5 text-2xl">
{data?.ingress}
</Ingress>
)}
<div className="mt-6 flex gap-3 text-base">
<BodyShort
size="small"
as="span"
className="text-text-subtle "
>
{dateStr(data?._updatedAt)}
</BodyShort>
{authors?.length > 0 && (
<BodyShort
size="small"
as="div"
className="flex flex-wrap gap-1"
>
<address className="not-italic">{authors[0]}</address>
</BodyShort>
)}
</div>
</div>
</div>
</div>
<div
className={cl("pt-32", {
"bg-gray-100": mainPage,
})}
>
<div className="max-w-aksel mx-auto px-4 sm:w-[90%]">
<div className="pb-16 md:pb-32">
<div className="relative mx-auto mt-4 max-w-prose lg:ml-0 lg:grid lg:max-w-none lg:grid-flow-row-dense lg:grid-cols-3 lg:items-start lg:gap-x-12">
<TableOfContents
changedState={data?.content ?? []}
hideToc={false}
aksel
/>
<div className="max-w-prose lg:col-span-2 lg:col-start-1">
{data?.hero_bilde && (
<Bilde
node={data.hero_bilde as any}
className="-mt-36 mb-10 sm:-mt-72"
/>
)}
<SanityBlockContent
blocks={data?.content ?? []}
variant="aksel"
/>
<div className="mt-12">
{authors?.length > 0 && (
<Label className="text-deepblue-700 mb-2" as="p">
Bidragsytere
</Label>
)}
{authors?.length > 0 && (
<BodyShort
as="div"
className="text-text-subtle mb-1 flex flex-wrap gap-1"
>
{authors.map(abbrName).map((x, y) => (
<address className="not-italic" key={x}>
{x}
{y !== authors.length - 1 && ", "}
</address>
))}
</BodyShort>
)}
<BodyShort as="span" className="text-text-subtle ">
Publisert:{" "}
{dateStr(data?.publishedAt ?? data?._updatedAt)}
</BodyShort>
</div>
<div className="mt-12 md:mt-16">
<Feedback
akselFeedback
docId={data?._id}
docType={data?._type}
/>
</div>
</div>
</div>
</div>
</div>
</div>
</article>
</main>
<Footer />
</>
);
};
export default AkselPrinsippTemplate;
@@ -1,28 +0,0 @@
import { Footer } from "@/layout";
import { Header } from "components/layout/header/Header";
import React from "react";
export const NoSidebarLayout = ({
children,
aside = null,
}: {
children: React.ReactNode;
aside?: React.ReactNode;
}) => {
return (
<>
<Header variant="subtle" />
<main
tabIndex={-1}
id="hovedinnhold"
className="aksel-artikkel bg-surface-subtle pt-4 focus:outline-none"
>
<div className="max-w-aksel mx-auto px-4 sm:w-[90%]">
<article className="pt-12 pb-16 md:pb-32">{children}</article>
</div>
{aside}
</main>
<Footer />
</>
);
};
@@ -1,6 +1,6 @@
import { SidebarT } from "@/lib";
import { AkselSidebarT } from "@/types";
import { logNav } from "@/utils";
import { Expand } from "@navikt/ds-icons";
import { ChevronDownIcon } from "@navikt/aksel-icons";
import { BodyShort, Detail, Tag } from "@navikt/ds-react";
import cl from "clsx";
import Link from "next/link";
@@ -26,7 +26,7 @@ const NavItem = ({
{
"before:border-l-border-action-selected before:top-1/2 before:h-6 before:-translate-y-1/2 before:rounded-full before:border-l-[4px]":
isActive,
"before:h-full before:rounded-full before:border-l before:border-l-gray-200 hover:before:top-1/2 hover:before:h-6 hover:before:-translate-y-1/2 hover:before:border-l-2 hover:before:border-l-gray-400":
"before:h-full before:rounded-full before:border-l before:border-l-gray-200 hover:before:top-1/2 hover:before:h-6 hover:before:-translate-y-1/2 hover:before:border-l-2 hover:before:border-l-gray-400":
!isActive,
}
)}
@@ -80,7 +80,13 @@ const NavItem = ({
);
};
const Dropdown = ({ title, links }: { title: string; links: SidebarT }) => {
const Dropdown = ({
title,
links,
}: {
title: string;
links: AkselSidebarT;
}) => {
const [open, setOpen] = useState(true);
const { asPath } = useRouter();
@@ -93,11 +99,11 @@ const Dropdown = ({ title, links }: { title: string; links: SidebarT }) => {
>
<Detail
as="span"
className="group-focus-visible:shadow-focus group-hover:bg-surface-neutral-subtle group-active:bg-bg-surface-neutral-subtle-hover mt-6 flex w-full items-center justify-between rounded-sm pl-2 font-semibold first:mt-0"
className="group-focus-visible:shadow-focus group-hover:bg-surface-neutral-subtle group-active:bg-bg-surface-neutral-subtle-hover mt-6 flex w-full items-center justify-between rounded-sm pl-2 font-semibold transition first:mt-0"
>
{title}
<span className="flex h-6 w-6 items-center justify-center rounded">
<Expand
<span className="flex h-6 w-6 items-center justify-center rounded">
<ChevronDownIcon
className={cl("text-base", { "rotate-180": open })}
aria-hidden
title={!open ? `åpne ${title}` : `lukk ${title}`}
@@ -125,7 +131,7 @@ export const Sidebar = ({
links,
}: {
kategori: "Komponenter" | "Grunnleggende";
links: SidebarT;
links: AkselSidebarT;
}) => {
const sections = useMemo(
() =>
@@ -4,11 +4,7 @@ import { SanityT } from "@/lib";
import { withErrorBoundary } from "@/error-boundary";
import { SanityBlockContent } from "@/sanity-block";
const Accordion = ({
node,
}: {
node: SanityT.Schema.accordion;
}): JSX.Element => {
const Accordion = ({ node }: { node: SanityT.Schema.accordion }) => {
if (!node || node.list.length === 0) {
return null;
}
@@ -3,11 +3,7 @@ import React from "react";
import { SanityT } from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
const Alert = ({
node,
}: {
node: SanityT.Schema.alert & { _key: string };
}): JSX.Element => {
const Alert = ({ node }: { node: SanityT.Schema.alert & { _key: string } }) => {
return (
<div className="mb-7 max-w-2xl">
<DsAlert variant={node.variant}>
@@ -1,21 +1,13 @@
/* eslint-disable @next/next/no-img-element */
import { SanityT, urlFor } from "@/lib";
import { urlFor } from "@/lib";
import { Heading } from "@navikt/ds-react";
import Nextlink from "next/link";
import cl from "clsx";
import Image from "next/legacy/image";
import { StatusTag } from "components/website-modules/StatusTag";
import { ArticleListT } from "@/types";
const ComponentOverview = ({
node,
}: {
node: {
_id: string;
heading: string;
slug: { current: string };
status?: SanityT.Schema.komponent_artikkel["status"];
}[];
}): JSX.Element => {
const ComponentOverview = ({ node }: { node: ArticleListT }) => {
if (!node || node.length === 0) {
return null;
}
@@ -38,7 +38,7 @@ const Element = ({
block,
}: {
block: Sanity.Keyed<SanityT.Schema.do_dont_block>;
}): JSX.Element => {
}) => {
if (!block.picture) return null;
return (
<figure
@@ -11,7 +11,7 @@ const ExpansionCard = ({
description?: string;
body: any[];
};
}): JSX.Element => {
}) => {
if (!node.heading || !node.body || !node.heading_level) {
return null;
}
@@ -1,15 +1,15 @@
import { LevelTwoHeading } from "@/components";
import { withErrorBoundary } from "@/error-boundary";
import { SanityT } from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { AkselGrunnleggendeDocT, AkselKomponentDocT } from "@/types";
import { Label } from "@navikt/ds-react";
import React from "react";
const Intro = ({
node,
}: {
node: SanityT.Schema.intro_komponent;
}): JSX.Element => {
node: AkselKomponentDocT["intro"] | AkselGrunnleggendeDocT["intro"];
}) => {
if (!node || !node.body || !node.brukes_til) {
return null;
}
@@ -2,7 +2,7 @@ import { Snippet } from "@/components";
import { withErrorBoundary } from "@/error-boundary";
import { SanityT } from "@/lib";
const Kode = ({ node }: { node: SanityT.Schema.kode }): JSX.Element => {
const Kode = ({ node }: { node: SanityT.Schema.kode }) => {
if (!node || !node.code) {
return null;
}
@@ -12,7 +12,7 @@ type SpesialT = {
token?: { title: string; kategori: string };
};
const SideModul = ({ node }: { node: SpesialT }): JSX.Element => {
const SideModul = ({ node }: { node: SpesialT }) => {
if (!node || !node.modul) {
return null;
}
@@ -2,11 +2,7 @@ import { withErrorBoundary } from "@/error-boundary";
import { SanityT } from "@/lib";
import { Table } from "@navikt/ds-react";
const TableComponent = ({
node,
}: {
node: SanityT.Schema.tabell_v2;
}): JSX.Element => {
const TableComponent = ({ node }: { node: SanityT.Schema.tabell_v2 }) => {
if (!node || !node.rows || node.rows.length < 2) {
return null;
}
@@ -12,11 +12,7 @@ const KBD = (props: React.HTMLAttributes<HTMLElement>) => (
/>
);
const UuSeksjon = ({
node,
}: {
node: SanityT.Schema.tastatur_modul;
}): JSX.Element => {
const UuSeksjon = ({ node }: { node: SanityT.Schema.tastatur_modul }) => {
if (!node || !node?.tastatur) {
return null;
}
@@ -1,39 +1,16 @@
import { withErrorBoundary } from "@/error-boundary";
import { SanityT } from "@/lib";
import { ClipboardIcon } from "@navikt/aksel-icons";
import internal from "@navikt/ds-css-internal/tokens.json";
import core from "@navikt/ds-css/tokens.json";
import { Expand, SuccessStroke } from "@navikt/ds-icons";
import { Expand } from "@navikt/ds-icons";
import { BodyLong, Label, Link } from "@navikt/ds-react";
import cl from "classnames";
import copy from "copy-to-clipboard";
import CopyButton from "components/sanity-modules/code/CopyButton";
import NextLink from "next/link";
import { useEffect, useRef, useState } from "react";
import { useState } from "react";
const TokenTable = ({ node }: { node: SanityT.Schema.token_kategori }) => {
const [open, setOpen] = useState(false);
const [active, setActive] = useState(false);
const timeoutRef = useRef<NodeJS.Timeout>();
const handleCopy = () => {
setActive(true);
timeoutRef.current && clearTimeout(timeoutRef.current);
timeoutRef.current = setTimeout(() => setActive(false), 2000);
const str = Object.entries(tokens).reduce(
(prev, cur) =>
prev +
`${cur[0]}: ${
cur[1].startsWith("--") ? `var(${cur[1]})` : `${cur[1]}`
};\n`,
""
);
copy(str);
};
useEffect(() => {
return () => timeoutRef.current && clearTimeout(timeoutRef.current);
}, []);
const tokens: { [key: string]: string } | null =
node.title in core
@@ -77,22 +54,17 @@ const TokenTable = ({ node }: { node: SanityT.Schema.token_kategori }) => {
</table>
{(open || !showMore) && (
<div className="border-border-divider bg-surface-neutral-subtle relative w-full rounded-b border border-t-0 p-2">
<button
onClick={handleCopy}
className="text-text-default hover:bg-surface-neutral-subtle-hover focus-visible:shadow-focus absolute top-2 right-2 rounded px-1 py-1 text-2xl focus:outline-none"
>
{active ? (
<>
<SuccessStroke className="text-[1.5rem]" aria-hidden />
<span className="sr-only">Kopier formarterte tokens</span>
</>
) : (
<>
<ClipboardIcon aria-hidden />
<span className="sr-only">Kopier formarterte tokens</span>
</>
<CopyButton
variant="tokentable"
content={Object.entries(tokens).reduce(
(prev, cur) =>
prev +
`${cur[0]}: ${
cur[1].startsWith("--") ? `var(${cur[1]})` : `${cur[1]}`
};\n`,
""
)}
</button>
/>
<Label size="small" as="span" spacing>
Hva er dette?
</Label>
@@ -1,4 +1,4 @@
import { FeedbackT } from "@/lib";
import { FeedbackT } from "@/types";
import { IdContext } from "@/utils";
import { Button, Heading, Textarea } from "@navikt/ds-react";
import cl from "classnames";
@@ -16,7 +16,7 @@ const Video = ({
transkripsjon?: string;
caption?: string;
};
}): JSX.Element => {
}) => {
const [open, setOpen] = useState(false);
if (
@@ -19,7 +19,7 @@ const Bilde = ({
dekorativt?: boolean;
};
className?: string;
}): JSX.Element => {
}) => {
if (!node || !node.asset) {
return null;
}
@@ -1,5 +1,11 @@
import { withErrorBoundary } from "@/error-boundary";
import { SanityT } from "@/lib";
import {
ResolveContributorsSingleT,
ResolveTemaT,
ResolveSlugT,
AkselGodPraksisDocT,
} from "@/types";
import { BodyShort, Detail, Heading } from "@navikt/ds-react";
import NextLink from "next/link";
import { abbrName, dateStr, logNav } from "../..";
@@ -16,16 +22,9 @@ const ArtikkelCard = ({
tema,
level = "2",
...rest
}: Partial<
(SanityT.Schema.aksel_artikkel | SanityT.Schema.aksel_blogg) & {
slug: string;
tema: string[];
source?: string;
contributor: { title: string } | null;
variant?: "god-praksis" | "tema";
level?: "2" | "3" | "4";
}
>) => {
}: ResolveContributorsSingleT<
ResolveTemaT<ResolveSlugT<AkselGodPraksisDocT>>
> & { source: string; variant: string; level?: "2" | "3" }) => {
const date = (rest as any)?.updateInfo?.lastVerified
? (rest as any)?.updateInfo?.lastVerified
: publishedAt
@@ -1,14 +1,11 @@
import { withErrorBoundary } from "@/error-boundary";
import { urlFor } from "@/lib";
import { AkselTemaT } from "@/types";
import { logNav } from "@/utils";
import { BodyShort } from "@navikt/ds-react";
import cl from "clsx";
import NextLink from "next/link";
import Image from "next/legacy/image";
import { logNav } from "@/utils";
import { SanityT, urlFor } from "@/lib";
interface AkselTemaT extends SanityT.Schema.aksel_tema {
refCount: number;
}
import NextLink from "next/link";
const GodPraksisCard = ({ node }: { node: AkselTemaT }) => {
if (
@@ -1,12 +1,9 @@
import { withErrorBoundary } from "@/error-boundary";
import NextLink from "next/link";
import Image from "next/legacy/image";
import { urlFor } from "@/lib";
import { AkselTemaT } from "@/types";
import { logNav } from "@/utils";
import { SanityT, urlFor } from "@/lib";
interface AkselTemaT extends SanityT.Schema.aksel_tema {
refCount: number;
}
import Image from "next/legacy/image";
import NextLink from "next/link";
const GodPraksisCardSimple = ({ node }: { node: Partial<AkselTemaT> }) => {
if (!node?.pictogram || !node?.slug?.current || !node?.title) {
@@ -10,7 +10,7 @@ const RelatertInnhold = ({
node,
}: {
node: SanityT.Schema.relatert_innhold;
}): JSX.Element => {
}) => {
if (!node || node?.lenker?.length === 0) {
return null;
}
@@ -16,7 +16,7 @@ const ComponentExamples = ({
dir?: SanityT.Schema.kode_eksempler_fil;
filnavn?: SanityT.Schema.kode_eksempler_fil;
};
}): JSX.Element => {
}) => {
const [activeExample, setActiveExample] = useState(null);
const [frameState, setFrameState] = useState(300);
const [unloaded, setUnloaded] = useState(true);
@@ -1,10 +1,9 @@
import { SuccessStroke } from "@navikt/ds-icons";
import { useRef, useState, useEffect } from "react";
import copy from "copy-to-clipboard";
import React from "react";
import cl from "clsx";
import style from "./index.module.css";
import { ClipboardIcon } from "@navikt/aksel-icons";
import { CheckmarkIcon, ClipboardIcon } from "@navikt/aksel-icons";
const copyCode = (content: string) =>
copy(content, {
@@ -13,12 +12,11 @@ const copyCode = (content: string) =>
interface CopyButtonProps {
content: string;
inTabs?: boolean;
inverted?: boolean;
variant?: "tokentable" | "codeblock";
}
const CopyButton = React.forwardRef<HTMLButtonElement, CopyButtonProps>(
({ content, inTabs, inverted = false }, ref) => {
({ content, variant = "codeblock" }, ref) => {
const [active, setActive] = useState(false);
const timeoutRef = useRef<NodeJS.Timeout>();
@@ -31,7 +29,7 @@ const CopyButton = React.forwardRef<HTMLButtonElement, CopyButtonProps>(
copyCode(content);
setActive(true);
timeoutRef.current && clearTimeout(timeoutRef.current);
timeoutRef.current = setTimeout(() => setActive(false), 3000);
timeoutRef.current = setTimeout(() => setActive(false), 1000);
};
return (
@@ -39,25 +37,39 @@ const CopyButton = React.forwardRef<HTMLButtonElement, CopyButtonProps>(
ref={ref}
aria-live={active ? "polite" : "off"}
role={active ? "alert" : undefined}
className={cl(style.copybutton, "navds-body-short group z-10", {
"flex w-16 items-center justify-center hover:bg-blue-50 focus:outline-none focus-visible:shadow-[inset_0_0_0_2px_var(--a-border-focus)]":
inTabs,
"text-text-default focus-visible:outline-focus absolute top-2 right-2 rounded bg-gray-100 px-2 py-1 hover:bg-gray-900/10 hover:underline focus-visible:outline-2":
!inTabs && inverted,
"text-text-on-inverted focus-visible:shadow-focus-inverted absolute top-2 right-2 flex h-10 w-10 items-center justify-center rounded bg-gray-900 hover:bg-gray-800 focus:outline-none":
!inTabs && !inverted,
})}
className={cl(
style.copybutton,
"navds-body-short group/button absolute top-2 right-2 z-10 flex h-10 w-10 items-center justify-center overflow-hidden rounded backdrop-blur transition duration-75 focus:outline-none",
{
"hover:text-text-on-inverted focus-visible:shadow-focus-inverted text-3xl text-gray-100 hover:bg-white/20 ":
variant === "codeblock",
"hover:text-deepblue-800 focus-visible:shadow-focus text-text-subtle hover:bg-surface-hover text-2xl":
variant === "tokentable",
}
)}
onClick={handleCopy}
>
{active ? (
<SuccessStroke className="text-[1.5rem]" title="Kopierte kodesnutt" />
) : (
<ClipboardIcon
fontSize="2rem"
className="opacity-90 group-hover:opacity-100"
title="Kopier kodesnutt"
/>
)}
<span
aria-hidden={!active}
className={cl(
"absolute inset-0 grid place-content-center transition duration-300",
{
"pointer-events-none translate-y-1.5 opacity-0": !active,
}
)}
>
<CheckmarkIcon title="Kopierte kodesnutt" />
</span>
<span
aria-hidden={active}
className={cl("flex items-center transition duration-300", {
"pointer-events-none -translate-y-1.5 opacity-0": active,
"group-hover/button:opacity-100": !active,
})}
>
<ClipboardIcon title="Kopier kodesnutt" />
</span>
</button>
);
}
@@ -13,7 +13,7 @@ const CodeSnippet = ({
node: SanityT.Schema.kode;
className?: string;
style?: any;
}): JSX.Element => {
}) => {
if (!code || !code.code) {
return null;
}
@@ -27,7 +27,7 @@ const CodeSnippet = ({
<div
className={cl(
className,
"relative mb-8 grid max-h-96 overflow-x-auto rounded bg-gray-900"
"relative mb-8 grid max-h-96 overflow-x-auto rounded bg-[#0f172a]"
)}
{...props}
>
@@ -39,7 +39,7 @@ const CodeSnippet = ({
theme={undefined}
>
{({ tokens, getLineProps, getTokenProps }) => (
<pre className="text-text-on-inverted relative m-0 overflow-x-auto overflow-y-auto rounded-lg bg-gray-900 p-4 pr-16 font-mono">
<pre className="text-text-on-inverted relative m-0 overflow-x-auto overflow-y-auto rounded-lg bg-[#0f172a] p-4 pr-16 font-mono">
{tokens.map((line, i) => (
<div
key={i}
@@ -6,7 +6,7 @@ import NextLink from "next/link";
import { urlFor } from "lib/sanity/santiy";
import { getImage } from "components/website-modules/utils/get-image";
import { getAuthors } from "components/website-modules/LatestBloggs";
import { dateStr } from "@/utils";
import { dateStr, logNav } from "@/utils";
import { Tag } from "./Tag";
import { Card, ArticleT } from "./Card";
import cl from "clsx";
@@ -117,7 +117,16 @@ function Highlights({ highlights }: { highlights: ArticleT[] }) {
beta={x?.status?.tag === "beta"}
/>
<NextLink href={`/${x.slug.current}`} passHref legacyBehavior>
<Link className="text-text-default mb-5 mt-2 no-underline hover:underline">
<Link
onClick={(e) =>
logNav(
"artikkel-kort",
window.location.pathname,
e.currentTarget.getAttribute("href")
)
}
className="text-text-default mb-5 mt-2 no-underline hover:underline"
>
<Heading size="large" level="3">
{x?.heading}
</Heading>
@@ -4,7 +4,7 @@ export const Highlighter = ({
}: {
type: string;
prev?: string;
}): JSX.Element => {
}) => {
const isString = type === "string" || type.match(/^["][^"]+"$/) !== null;
const isType =
@@ -27,7 +27,11 @@ const List = ({ prop, parent }: { prop: any; parent: string }) => {
prop?.required ? "" : "?"
} `}</span>
) : (
<Tooltip content={`${prop.defaultValue}`} arrow={false} delay={0}>
<Tooltip
content={`default: ${prop.defaultValue}`}
arrow={false}
delay={0}
>
<span className="mr-2 cursor-pointer border-b border-dashed border-gray-600 font-semibold">{`${
prop.name
}${prop?.required ? "" : "?"}`}</span>
@@ -51,7 +55,7 @@ const List = ({ prop, parent }: { prop: any; parent: string }) => {
);
};
const PropTable = ({ komponent }: { komponent: PropT }): JSX.Element => {
const PropTable = ({ komponent }: { komponent: PropT }) => {
return (
<div>
<Heading
@@ -2,7 +2,7 @@ import React from "react";
import { withErrorBoundary } from "@/error-boundary";
import PropTableV2, { PropT } from "./PropTabell";
const PropsSeksjon = ({ node }: { node: any }): JSX.Element => {
const PropsSeksjon = ({ node }: { node: any }) => {
if (
!node ||
(node?.elementer?.length === 0 && node?.komponenter?.length === 0)
@@ -7,7 +7,7 @@ import cl from "clsx";
import React from "react";
import style from "./tips.module.css";
const Tips = ({ node }: { node: SanityT.Schema.tips }): JSX.Element => {
const Tips = ({ node }: { node: SanityT.Schema.tips }) => {
if (!node || !node.body) {
return null;
}
@@ -3,7 +3,7 @@ import { Tooltip } from "@navikt/ds-react";
import { useContext } from "react";
import { IdContext, useCheckAuth } from "./utils";
function EditButton(): JSX.Element {
function EditButton() {
const idCtx = useContext(IdContext);
const validUser = useCheckAuth();
@@ -10,7 +10,7 @@ export const LevelTwoHeading = ({
children: [React.ReactNode | string];
hidden?: boolean;
id: string;
}): JSX.Element => {
}) => {
return (
<>
{hidden && <div id={id} className="scroll-m-18" />}
@@ -6,7 +6,7 @@ import { BodyShort, Button } from "@navikt/ds-react";
import Link from "next/link";
import { useRouter } from "next/router";
function PreviewBanner(): JSX.Element {
function PreviewBanner() {
const { asPath } = useRouter();
const validUser = useCheckAuth();
@@ -13,7 +13,7 @@ export function TableOfContents({
changedState: any;
hideToc?: boolean;
aksel?: boolean;
}): JSX.Element {
}) {
const [toc, setToc] = useState<
{ heading: string; id: string; lvl3: { heading: string; id: string }[] }[]
>([]);
@@ -13,7 +13,7 @@ export function TableOfContentsv2({
changedState: any;
hideToc?: boolean;
aksel?: boolean;
}): JSX.Element {
}) {
const [toc, setToc] = useState<
{ heading: string; id: string; lvl3: { heading: string; id: string }[] }[]
>([]);
@@ -157,7 +157,7 @@ export function TableOfContentsv2({
<BodyShort
as="li"
size="small"
className={cl("py-1", {
className={cl("relative py-1", {
"font-semibold": link.id === activeId,
"": link.id !== activeId,
})}
@@ -166,7 +166,7 @@ export function TableOfContentsv2({
href={`#${link.id}`}
onClick={() => handleFocus(`${link.id}`)}
className={cl(
"block max-w-full no-underline hover:underline",
"z-10 block max-w-full no-underline hover:underline",
{
"text-deepblue-800":
link.id === activeId &&
@@ -179,7 +179,7 @@ export function TableOfContentsv2({
</Link>
{link?.lvl3?.length > 0 && (
<ul
className={cl("animate-fadeIn pt-1", {
className={cl("animate-toc z-10 pt-1 ", {
hidden: link.id !== activeId,
})}
>
@@ -1,4 +1,4 @@
import { FeedbackT, HelpfulArticleEnum } from "@/lib";
import { FeedbackT, HelpfulArticleEnum } from "@/types";
import { Button, Heading, Label, Textarea } from "@navikt/ds-react";
import cl from "clsx";
import { useRouter } from "next/router";
@@ -18,7 +18,7 @@ const Feedback = ({
center?: boolean;
akselFeedback?: boolean;
text?: string;
}): JSX.Element => {
}) => {
const idCtx = useContext(IdContext);
const { asPath, basePath } = useRouter();
const [textValue, setTextValue] = useState("");
-2
View File
@@ -1,7 +1,5 @@
export * from "./sanity/queries";
export * from "./sanity/santiy";
export * from "./types/types";
export * from "./types/search";
export type { default as SanityT } from "./types/schema";
export function isDevelopment(): boolean {
+3 -248
View File
@@ -168,239 +168,24 @@ ${expansionCardBlock},
${defaultBlock},
`;
export const allDocuments = `*[]{...,'slug': slug.current }`;
export const akselTema = `*[_type == "godpraksis_landingsside"][0]{
"page": {
...,
intro[]{
...,
${destructureBlocks}
}
},
"temaer": *[_type == "aksel_tema" && defined(seksjoner[].sider[])]{
...,
"refCount": count(*[_type == "aksel_artikkel" && !(_id in path("drafts.**")) && references(^._id)])
},
"resent": *[_type == "aksel_artikkel" && defined(publishedAt)] | order(publishedAt desc)[0...9]{
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
"slug": slug.current,
"tema": tema[]->title,
ingress,
}
}`;
export const contributorsAll = `contributors[]->{
anonym == true => {"title":@.anon_navn.current},
anonym != true => {"title":@.title}
}`;
const contributorsSingle = `contributors[0]->{
export const contributorsSingle = `contributors[0]->{
anonym == true => {"title":@.anon_navn.current},
anonym != true => {"title":@.title}
}`;
export const akselForsideQuery = `*[_type == "aksel_forside"][0]{
"page": {
...,
},
"tema": *[_type == "aksel_tema" && defined(seksjoner[].sider[])],
blocks[]{
...,
_type == "nytt_fra_aksel"=>{
highlights[]->{
...,
"content": null,
${contributorsAll},
"tema": tema[]->title,
},
"curatedResent": {
"bloggposts": *[_type == "aksel_blogg" && !(_id in ^.highlights[]._ref)] | order(_createdAt desc)[0...2]{
_type,
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
"slug": slug.current,
ingress,
seo,
${contributorsAll}
},
"artikler": *[_type == "aksel_artikkel" && defined(publishedAt) && !(_id in ^.highlights[]._ref)] | order(publishedAt desc)[0...3]{
_type,
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
"slug": slug.current,
"tema": tema[]->title,
ingress,
seo,
${contributorsAll}
},
"komponenter": *[_type in ["komponent_artikkel", "ds_artikkel"] && defined(publishedAt) && !(_id in ^.highlights[]._ref)] | order(publishedAt desc)[0...3]{
_type,
_id,
heading,
"slug": slug.current,
status,
kategori,
_createdAt,
_updatedAt,
publishedAt,
seo,
${contributorsAll}
},
},
}
}
}`;
export const akselPrinsippBySlug = `{
"prinsipp": *[slug.current == $slug] | order(_updatedAt desc)[0]
{
...,
"slug": slug.current,
"content": select(
$valid == "true" => content[]{
...,
${destructureBlocks}
},
$valid != "true" => []
),
${contributorsAll}
}
}`;
export const akselDocumentBySlug = `{
"page": *[slug.current == $slug] | order(_updatedAt desc)[0]
{
...,
"slug": slug.current,
content[]{
...,
${destructureBlocks}
},
tema[]->{title, slug, seo},
${contributorsAll},
relevante_artikler[]->{
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
updateInfo,
"slug": slug.current,
"tema": tema[]->tag,
ingress,
"contributor": ${contributorsSingle},
}
}
}`;
export const akselEditorById = `*[_id == $id][0]
{
${contributorsAll}
}`;
const sidebarQuery = `"sidebar": *[_type == $type && defined(kategori)] {
export const sidebarQuery = `"sidebar": *[_type == $type && defined(kategori)] {
heading,
"slug": slug.current,
kategori,
"tag": status.tag,
}`;
/**
* "refs" må disables i preview da next-sanity sin
* preview-funksjonalitet fører til en infinite loop som låser applikasjonen.
* Dette er på grunn av av hele datasettet blir lastet inn i preview flere ganger som til slutt låser vinduet.
*/
export const komponentQuery = `{
"page": *[_type == "komponent_artikkel" && slug.current == $slug] | order(_updatedAt desc)[0]
{
...,
"slug": slug.current,
linked_package {
"title": @->title,
"github_link": @->github_link,
"status": @->status
},
intro{
...,
body[]{
...,
${destructureBlocks}
}
},
content[]{
...,
${destructureBlocks}
},
},
"refs": select(
$preview == "true" => [],
$preview != "true" => *[_type == "komponent_artikkel" && count(*[references(^._id)][slug.current == $slug]) > 0][0...3]{
_id,
heading,
"slug": slug,
status
}
),
"seo": *[_type == "komponenter_landingsside"][0].seo.image,
${sidebarQuery}
}`;
export const grunnleggendeQuery = `{
"page": *[_type == "ds_artikkel" && slug.current == $slug] | order(_updatedAt desc)[0]
{
...,
"slug": slug.current,
content[]{
...,
${destructureBlocks}
},
},
"seo": *[_type == "komponenter_landingsside"][0].seo.image,
${sidebarQuery}
}`;
export const akselTemaDocs = `{
"tema": *[_type == "aksel_tema" && slug.current == $slug] | order(_updatedAt desc)[0]{
...,
"ansvarlig": ansvarlig->{title, roller},
seksjoner[]{
...,
beskrivelse[]{
...,
${destructureBlocks}
},
sider[]->{
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
updateInfo,
"slug": slug.current,
"tema": tema[]->title,
ingress,
"contributor": ${contributorsSingle}
}
},
"pictogram": pictogram.asset-> {
url,
altText,
},
}
}`;
const landingsSideQuery = (t) => {
export const landingPageQuery = (t) => {
const kat =
t === "komponenter"
? komponentKategorier
@@ -413,33 +198,3 @@ const landingsSideQuery = (t) => {
${kat.map((x) => `intro_${x.value}[]{...,${destructureBlocks}}`).join(",")}
}`;
};
export const komponentLandingQuery = `{${sidebarQuery}, ${landingsSideQuery(
"komponenter"
)}, "links": *[_type == "komponent_artikkel" && defined(kategori)]{_id,heading,"slug": slug,status,kategori}}`;
export const grunnleggendeLandingQuery = `{${sidebarQuery}, ${landingsSideQuery(
"grunnleggende"
)}, "links": *[_type == "ds_artikkel" && defined(kategori)]{_id,heading,"slug": slug,status,kategori}}`;
export const akselArticleFields = `
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
updateInfo,
"slug": slug.current,
"tema": tema[]->title,
ingress,
status,
_type,
`;
export const akselArticleAll = (boundry = "") => {
return `{
"articles": *[_type == "aksel_artikkel" && defined(publishedAt)] | order(publishedAt desc)${boundry} {
${akselArticleFields}
}
}`;
};
@@ -1,15 +1,3 @@
export type SidebarT = {
heading: string;
slug: string;
kategori: string;
tag?: string;
}[];
export type PageTypeT = {
type: "Komponenter" | "Grunnleggende";
title: string;
};
export enum HelpfulArticleEnum {
"JA" = "ja",
"DELVIS" = "delvis",
+2
View File
@@ -1,2 +1,4 @@
export * from "./schema-types";
export * from "./next";
export * from "./feedback";
export * from "./search";
+147 -1
View File
@@ -1,4 +1,8 @@
import { bloggKategorier } from "../../sanity/config";
import {
bloggKategorier,
grunnleggendeKategorier,
komponentKategorier,
} from "../../sanity/config";
export type ResolveSlugT<T> = Omit<T, "slug"> & {
slug: string;
@@ -8,6 +12,29 @@ export type ResolveContributorsT<T> = Omit<T, "contributors"> & {
contributors: { title: string }[];
};
export type ResolveContributorsSingleT<T> = Omit<T, "contributors"> & {
contributor: { title: string };
};
export type ResolveTemaT<T> = Omit<T, "tema"> & {
tema: string[];
};
export type ResolveRelatedArticlesT<T> = Omit<T, "relevante_artikler"> & {
relevante_artikler?: Array<
ResolveContributorsSingleT<
ResolveSlugT<
ResolveTemaT<
| AkselBloggDocT
| AkselGodPraksisDocT
| AkselKomponentDocT
| AkselGrunnleggendeDocT
>
>
>
>;
};
type DocumentT<T> = {
_createdAt: string;
_updatedAt: string;
@@ -16,6 +43,10 @@ type DocumentT<T> = {
_type: T;
};
type ObjectT<T> = T & {
_key: string;
};
type ArticleT = {
publishedAt?: string;
heading: string;
@@ -45,3 +76,118 @@ export interface AkselBloggFrontpageT extends DocumentT<"blogg_landingsside"> {
export interface AkselBloggDocT extends DocumentT<"aksel_blogg">, ArticleT {
kategori: typeof bloggKategorier[number]["value"];
}
export interface AkselGodPraksisDocT
extends DocumentT<"aksel_artikkel">,
ArticleT {
tema: { _ref: string }[];
updateInfo?: {
lastVerified?: string;
};
relevante_artikler?: { _ref: string }[];
}
export interface AkselPrinsippDocT
extends DocumentT<"aksel_prinsipp">,
ArticleT {
hero_bilde: any;
prinsipp: { prinsippvalg: string; hovedside: boolean };
}
export interface AkselKomponentDocT
extends DocumentT<"komponent_artikkel">,
ArticleT {
kategori: typeof komponentKategorier[number]["value"];
status: {
tag?: "beta" | "new" | "ready" | "deprecated";
unsafe?: boolean;
bilde?: any;
};
intro: {
body?: any[];
brukes_til: string[];
brukes_ikke_til?: string[];
};
content: any[];
kodepakker?: string[];
figma_link?: string;
updateInfo?: {
lastVerified?: string;
};
}
export interface AkselGrunnleggendeDocT
extends DocumentT<"ds_artikkel">,
ArticleT {
kategori: typeof grunnleggendeKategorier[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;
kategori: typeof komponentKategorier[number]["value"];
tag: "beta" | "new" | "ready" | "deprecated";
}>;
export type ArticleListT = Array<{
_id: string;
heading: string;
slug: { current: string };
kategori: typeof komponentKategorier[number]["value"];
status: {
tag?: "beta" | "new" | "ready" | "deprecated";
unsafe?: boolean;
bilde?: any;
};
}>;
export type LandingPageTypeT<T extends string> = `${T}_landingsside`;
export type IngressT<T extends string> = `${T}_ingress`;
export interface AkselLandingPageDocT
extends DocumentT<LandingPageTypeT<"komponenter">> {
intro: any[];
seo?: ArticleT["seo"];
}
export interface AkselGodPraksisLandingPageDocT
extends DocumentT<"godpraksis_landingsside"> {
intro: any[];
seo?: ArticleT["seo"];
}
export interface AkselTemaT extends DocumentT<"aksel_tema"> {
title: string;
oppsummering?: string;
beskrivelse?: any;
refCount?: number;
slug: { current: string };
ansvarlig?: { _ref: string };
seksjoner: Array<
ObjectT<{
title: string;
beskrivelse: any;
sider: Array<
ResolveContributorsSingleT<
ResolveTemaT<ResolveSlugT<AkselGodPraksisDocT>>
>
>;
}>
>;
pictogram: any;
seo?: ArticleT["seo"];
}
@@ -1,6 +1,6 @@
import { allArticleDocuments } from "../../sanity/config";
export const options: {
export const searchOptions: {
[K in typeof allArticleDocuments[number] | "icon" | "icon_page"]: {
display: string;
index: number;
@@ -17,15 +17,15 @@ export const options: {
icon_page: { display: "Ikonsøk", index: 7, hidden: true },
};
export type SearchResults = {
groupedHits: GroupedHits;
topResults: SearchHit[];
hits: Record<keyof typeof options, number>;
export type SearchResultsT = {
groupedHits: GroupedHitsT;
topResults: SearchHitT[];
hits: Record<keyof typeof searchOptions, number>;
totalHits: number;
};
interface PageItemT {
_type: keyof Omit<keyof typeof options, "icon">;
_type: keyof Omit<keyof typeof searchOptions, "icon">;
content: string;
heading: string;
ingress?: string;
@@ -58,7 +58,7 @@ export interface IconPageItemT {
export type FuseItemT = PageItemT | IconItemT | IconPageItemT;
export type FuseHits = {
export type FuseHitsT = {
item: FuseItemT;
score: number;
@@ -71,7 +71,7 @@ export type FuseHits = {
}[];
};
export type SearchHit = {
export type SearchHitT = {
item: FuseItemT;
score: number;
@@ -81,4 +81,6 @@ export type SearchHit = {
};
};
export type GroupedHits = Partial<Record<keyof typeof options, SearchHit[]>>;
export type GroupedHitsT = Partial<
Record<keyof typeof searchOptions, SearchHitT[]>
>;
+1 -1
View File
@@ -21,7 +21,7 @@ function App({
Component: any;
pageProps: any;
router: Router;
}): JSX.Element {
}) {
useScrollToHashOnPageLoad();
usePageView(router, pageProps);
@@ -1,4 +1,3 @@
import { akselArticleFields } from "@/lib";
import { getClient } from "@/sanity-client";
import { format } from "date-fns";
import { NextApiRequest, NextApiResponse } from "next";
@@ -21,10 +20,17 @@ export default async function akselAarticles(
const query = `{
"publishDateArticles": *[_type == "aksel_artikkel" && defined(publishedAt) && publishedAt <= "${lastPublishedAt}"] | order(publishedAt desc) {
${akselArticleFields}
},
"noPublishDateArticles": *[_type == "aksel_artikkel" && !defined(publishedAt)] | order(_updatedAt desc){
${akselArticleFields}
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
updateInfo,
"slug": slug.current,
"tema": tema[]->title,
ingress,
status,
_type,
}
}`;
@@ -33,7 +39,7 @@ export default async function akselAarticles(
await getClient()
.fetch(query)
.then((data) => {
payload = [...data.publishDateArticles, ...data.noPublishDateArticles];
payload = [...data.publishDateArticles];
return data;
})
.catch((err) => {
+1 -1
View File
@@ -1,6 +1,6 @@
import { FeedbackT } from "@/types";
import dotenv from "dotenv";
import type { NextApiRequest, NextApiResponse } from "next";
import { FeedbackT } from "@/lib";
import { noCdnClient } from "../../lib/sanity/sanity.server";
dotenv.config();
@@ -1,15 +1,14 @@
import {
FuseHits,
FuseHitsT,
FuseItemT,
GroupedHits,
GroupedHitsT,
IconPageItemT,
SearchHit,
SearchResults,
} from "@/lib";
SearchHitT,
SearchResultsT,
} from "@/types";
import { omit } from "@navikt/ds-react";
import Fuse from "fuse.js";
import { NextApiRequest, NextApiResponse } from "next";
import { akselArticleFields } from "../../../../lib/sanity/queries";
import { allArticleDocuments } from "../../../../sanity/config";
import IconMetadata from "@navikt/aksel-icons/metadata";
@@ -58,15 +57,15 @@ export default async function initialSearch(
iconPageData,
];
const result: FuseHits[] = getSearchResults(
const result: FuseHitsT[] = getSearchResults(
hits.map((x) => ({
...x,
...(x?.content ? { content: x.content.replace(/\n|\r/g, " ") } : {}),
})),
query
) as unknown as FuseHits[];
) as unknown as FuseHitsT[];
const filteredResult: FuseHits[] = getSearchResults(
const filteredResult: FuseHitsT[] = getSearchResults(
hits
.filter((x) => doc.includes(x._type))
.map((x) => ({
@@ -74,12 +73,12 @@ export default async function initialSearch(
...(x?.content ? { content: x.content.replace(/\n|\r/g, " ") } : {}),
})),
query
) as unknown as FuseHits[];
) as unknown as FuseHitsT[];
const formatedResults = formatResults(filteredResult, query);
const groupedHits: GroupedHits = formatedResults?.reduce(
(prev, cur: SearchHit) => {
const groupedHits: GroupedHitsT = formatedResults?.reduce(
(prev, cur: SearchHitT) => {
if (cur.item._type in prev) {
return { ...prev, [cur.item._type]: [...prev[cur.item._type], cur] };
} else {
@@ -94,7 +93,7 @@ export default async function initialSearch(
query
);
const response: SearchResults = {
const response: SearchResultsT = {
groupedHits,
topResults: filteredResult?.length > 8 ? topResults : [],
totalHits: filteredResult?.length ?? 0,
@@ -127,7 +126,7 @@ function findRelevantQuery(q: string) {
return q.split(" ")[0].toLowerCase();
}
function formatResults(res: FuseHits[], query: string): SearchHit[] {
function formatResults(res: FuseHitsT[], query: string): SearchHitT[] {
return res.map((x) => {
let hightlightDesc = !!x.matches[0].indices
.map((y) => x.matches[0].value.slice(y[0], y[1] + 1))
@@ -175,7 +174,7 @@ function formatResults(res: FuseHits[], query: string): SearchHit[] {
highlight: { shouldHightlight: hightlightDesc, description },
},
["matches"]
) as SearchHit;
) as SearchHitT;
});
}
@@ -185,7 +184,17 @@ async function searchSanity() {
const sanityQueryHttp = `*[_type in [${allArticleDocuments.map(
(x) => `"${x}"`
)}] ]{
${akselArticleFields}
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
updateInfo,
"slug": slug.current,
"tema": tema[]->title,
ingress,
status,
_type,
"intro": pt::text(intro.body),
"content": content[]{...,
_type == "kode_eksempler" => {
@@ -224,7 +233,7 @@ async function searchSanity() {
function getSearchResults(results, query) {
/* https://fusejs.io/api/options.html */
const fuse = new Fuse<SearchHit>(results, {
const fuse = new Fuse<SearchHitT>(results, {
keys: [
{ name: "heading", weight: 100 },
{ name: "ingress", weight: 50 },
@@ -1,8 +1,14 @@
import { abbrName } from "@/components";
import { Footer } from "@/layout";
import { akselTemaDocs, getAkselTema, SanityT, urlFor } from "@/lib";
import {
contributorsSingle,
destructureBlocks,
getAkselTema,
urlFor,
} from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity-client";
import { AkselTemaT, NextPageT } from "@/types";
import { Detail, Heading, Label } from "@navikt/ds-react";
import cl from "clsx";
import { Header } from "components/layout/header/Header";
@@ -14,29 +20,80 @@ import Image from "next/legacy/image";
import { lazy } from "react";
import NotFotfund from "../404";
export type ArtiklerT = Partial<
SanityT.Schema.aksel_artikkel & {
slug: string;
tema: string[];
contributors?: { title?: string }[];
type PageProps = NextPageT<{
tema: Omit<AkselTemaT, "ansvarlig"> & {
ansvarlig: { title: string; roller: string[] };
};
}>;
export const query = `{
"tema": *[_type == "aksel_tema" && slug.current == $slug] | order(_updatedAt desc)[0]{
...,
"ansvarlig": ansvarlig->{title, roller},
seksjoner[]{
...,
beskrivelse[]{
...,
${destructureBlocks}
},
sider[]->{
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
updateInfo,
"slug": slug.current,
"tema": tema[]->title,
ingress,
"contributor": ${contributorsSingle}
}
},
"pictogram": pictogram.asset-> {
url,
altText,
},
}
>;
}`;
export interface AkselTemaPage
extends Omit<SanityT.Schema.aksel_tema, "ansvarlig" | "pictogram"> {
artikler: ArtiklerT[];
ansvarlig?: { title?: string; roller: string[] };
pictogram: { url: string; altText?: string };
seo: any;
}
export const getStaticPaths = async () => {
return {
paths: await getAkselTema().then((paths) =>
paths.map(({ path }) => ({
params: {
slug: path,
},
}))
),
fallback: "blocking",
};
};
interface PageProps {
tema: AkselTemaPage;
slug: string;
preview: boolean;
}
export const getStaticProps = async ({
params: { slug },
preview = false,
}: {
params: { slug: string };
preview?: boolean;
}): Promise<PageProps> => {
const { tema } = await getClient().fetch(query, {
slug,
});
const Page = ({ tema: page }: PageProps): JSX.Element => {
return {
props: {
tema,
slug,
preview,
id: tema?._id ?? null,
title: tema?.title ?? "",
},
notFound: !tema && !preview,
revalidate: 60,
};
};
const Page = ({ tema: page }: PageProps["props"]) => {
if (!page || !page.seksjoner || page.seksjoner.length === 0) {
return <NotFotfund />;
}
@@ -158,17 +215,15 @@ const Page = ({ tema: page }: PageProps): JSX.Element => {
</div>
)}
<div className="card-grid-3-1 mt-6">
{(seksjon?.sider as unknown as ArtiklerT[])?.map(
(x: ArtiklerT) => (
<ArtikkelCard
{...x}
level="3"
source={page?.slug?.current}
key={x._id}
variant="god-praksis"
/>
)
)}
{seksjon?.sider?.map((x) => (
<ArtikkelCard
{...x}
level="3"
source={page?.slug?.current}
key={x._id}
variant="god-praksis"
/>
))}
</div>
</div>
) : null
@@ -191,13 +246,13 @@ const Page = ({ tema: page }: PageProps): JSX.Element => {
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={akselTemaDocs}
query={query}
props={props}
params={{
slug: props?.slug,
@@ -211,40 +266,3 @@ const Wrapper = (props: any): JSX.Element => {
};
export default Wrapper;
export const getStaticPaths = async () => {
return {
paths: await getAkselTema().then((paths) =>
paths.map(({ path }) => ({
params: {
slug: path,
},
}))
),
fallback: "blocking",
};
};
export const getStaticProps = async ({
params: { slug },
preview = false,
}: {
params: { slug: string };
preview?: boolean;
}) => {
const { tema } = await getClient().fetch(akselTemaDocs, {
slug,
});
return {
props: {
tema,
slug,
preview,
id: tema?._id ?? null,
title: tema?.title ?? "",
},
notFound: !tema && !preview,
revalidate: 60,
};
};
@@ -1,44 +1,70 @@
import { LayoutPicker } from "@/components";
import { SanityT, akselDocumentBySlug, getAkselDocuments } from "@/lib";
import {
contributorsAll,
contributorsSingle,
destructureBlocks,
getAkselDocuments,
urlFor,
} from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity-client";
import {
AkselGodPraksisDocT,
NextPageT,
ResolveContributorsT,
ResolveRelatedArticlesT,
ResolveSlugT,
ResolveTemaT,
} from "@/types";
import { Next } from "@navikt/ds-icons";
import { BodyShort, Detail, Heading, Ingress, Label } from "@navikt/ds-react";
import ArtikkelCard from "components/sanity-modules/cards/ArtikkelCard";
import { PreviewSuspense } from "next-sanity/preview";
import React, { lazy } from "react";
import Head from "next/head";
import NextLink from "next/link";
import { lazy } from "react";
import NotFotfund from "../../404";
const Page = (props: {
slug?: string;
page: SanityT.Schema.aksel_artikkel;
preview: boolean;
}): JSX.Element => {
if (!props?.page) {
return <NotFotfund />;
import {
abbrName,
BreadCrumbs,
dateStr,
Feedback,
TableOfContents,
} from "@/components";
import { Footer } from "@/layout";
import { Header } from "components/layout/header/Header";
type PageProps = NextPageT<{
page: ResolveContributorsT<
ResolveTemaT<ResolveSlugT<ResolveRelatedArticlesT<AkselGodPraksisDocT>>>
>;
}>;
export const query = `{
"page": *[slug.current == $slug] | order(_updatedAt desc)[0]
{
...,
"slug": slug.current,
content[]{
...,
${destructureBlocks}
},
tema[]->{title, slug, seo},
${contributorsAll},
relevante_artikler[]->{
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
updateInfo,
"slug": slug.current,
"tema": tema[]->tag,
ingress,
"contributor": ${contributorsSingle},
}
}
return <LayoutPicker title="Aksel" data={props.page} />;
};
const WithPreview = lazy(() => import("../../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={akselDocumentBySlug}
props={props}
params={{
slug: `god-praksis/artikler/${props?.slug}`,
}}
/>
</PreviewSuspense>
);
}
return <Page {...props} />;
};
export default Wrapper;
}`;
export const getStaticPaths = async (): Promise<{
fallback: string;
@@ -56,26 +82,14 @@ export const getStaticPaths = async (): Promise<{
};
};
interface StaticProps {
props: {
page: SanityT.Schema.aksel_artikkel;
slug: string;
preview: boolean;
id?: string;
title: string;
};
notFound: boolean;
revalidate: number;
}
export const getStaticProps = async ({
params: { slug },
preview = false,
}: {
params: { slug: string };
preview?: boolean;
}): Promise<StaticProps | { notFound: true }> => {
const { page } = await getClient().fetch(akselDocumentBySlug, {
}): Promise<PageProps> => {
const { page } = await getClient().fetch(query, {
slug: `god-praksis/artikler/${slug}`,
});
@@ -91,3 +105,239 @@ export const getStaticProps = async ({
revalidate: 60,
};
};
const Page = ({ page: data }: PageProps["props"]) => {
if (!data) {
return <NotFotfund />;
}
if (!data.content || !data.heading) {
console.warn(
`Artikkelen har ikke ${
!data.content ? "innhold" : "overskrift"
}, så den kan ikke vises.`
);
return null;
}
const date = data?.updateInfo?.lastVerified
? data?.updateInfo?.lastVerified
: data?.publishedAt
? data.publishedAt
: data._updatedAt;
const authors = (data?.contributors as any)?.map((x) => x?.title) ?? [];
const hasTema = "tema" in data && data.tema && data?.tema.length > 0;
const aside = data?.relevante_artikler?.length > 0 && (
<aside
className="overflow-x-clip py-8"
aria-labelledby="relevante-artikler-aside"
>
<div className="relativept-12 pb-16">
<div className="dynamic-wrapper">
<Heading
level="2"
size="medium"
className="text-deepblue-700 px-4"
id="relevante-artikler-aside"
>
{data?.relevante_artikler?.length === 1
? `Les også`
: `Relevante artikler`}
</Heading>
<div className="card-grid-3-1 mt-6 px-4">
{data.relevante_artikler.map((x: any) =>
x && x?._id ? <ArtikkelCard level="3" {...x} key={x._id} /> : null
)}
</div>
</div>
</div>
</aside>
);
const filteredTema =
hasTema && data?.tema?.filter((x: any) => x?.title && x?.slug);
return (
<>
<Head>
<title>{`${data?.heading} - Aksel`}</title>
<meta
property="og:title"
content={`${data?.heading} - Aksel`}
key="ogtitle"
/>
<meta
name="description"
content={data?.seo?.meta ?? data?.ingress}
key="desc"
/>
<meta
property="og:description"
content={data?.seo?.meta ?? data?.ingress}
key="ogdesc"
/>
<meta property="og:type" content="article" />
<meta
property="og:image"
content={
data?.seo?.image
? urlFor(data?.seo?.image)
.width(1200)
.height(630)
.fit("crop")
.quality(100)
.url()
: hasTema && (data.tema[0] as any)?.seo?.image
? urlFor((data.tema[0] as any)?.seo?.image)
.width(1200)
.height(630)
.fit("crop")
.quality(100)
.url()
: ""
}
key="ogimage"
/>
</Head>
<Header variant="subtle" />
<main
tabIndex={-1}
id="hovedinnhold"
className="aksel-artikkel bg-surface-subtle pt-4 focus:outline-none"
>
<div className="max-w-aksel mx-auto px-4 sm:w-[90%]">
<article className="pt-12 pb-16 md:pb-32">
<div className="mx-auto mb-16 max-w-prose lg:ml-0">
<BreadCrumbs auto />
<Heading
level="1"
size="large"
className="text-deepblue-800 mt-4 md:text-5xl"
>
{data.heading}
</Heading>
{data?.ingress && (
<Ingress className="override-text-700 mt-4 text-2xl">
{data?.ingress}
</Ingress>
)}
<div className="mt-6 inline-flex flex-wrap items-center gap-2 text-base">
<Detail uppercase as="span">
{dateStr(date)}
</Detail>
{authors?.length > 0 && (
<>
<span className="bg-deepblue-700 h-2 w-2 rotate-45 rounded-[1px] opacity-25" />
<BodyShort
size="small"
as="div"
className="flex flex-wrap gap-1"
>
<address className="not-italic">{authors?.[0]}</address>
</BodyShort>
</>
)}
</div>
{hasTema && (
<div className="mt-8 flex flex-wrap gap-2">
{filteredTema.map(({ title, slug }: any) => (
<span key={title}>
<NextLink
key={title}
href={`/god-praksis/${slug.current}`}
passHref
legacyBehavior
>
<BodyShort
size="small"
as="a"
className="min-h-8 text-deepblue-800 focus-visible:shadow-focus flex items-center justify-center gap-[2px] rounded-full bg-gray-200 pl-4 pr-1 capitalize no-underline hover:underline focus:outline-none"
>
{title}
<Next aria-hidden />
</BodyShort>
</NextLink>
</span>
))}
</div>
)}
</div>
<div className="relative mx-auto mt-4 max-w-prose lg:ml-0 lg:grid lg:max-w-none lg:grid-flow-row-dense lg:grid-cols-3 lg:items-start lg:gap-x-12">
<TableOfContents
changedState={data?.content ?? []}
hideToc={false}
aksel
/>
<div className="max-w-prose lg:col-span-2 lg:col-start-1">
<SanityBlockContent
blocks={data?.content ?? []}
variant="aksel"
/>
<div className="mt-12">
{authors?.length > 0 && (
<Label className="text-deepblue-700 mb-2" as="p">
Bidragsytere
</Label>
)}
{authors?.length > 0 && (
<BodyShort
as="div"
className="text-text-subtle mb-1 flex flex-wrap gap-1"
>
{authors.map(abbrName).map((x, y) => (
<address className="not-italic" key={x}>
{x}
{y !== authors.length - 1 && ", "}
</address>
))}
</BodyShort>
)}
<BodyShort as="span" className="text-text-subtle">
Publisert: {dateStr(data?.publishedAt ?? data?._updatedAt)}
</BodyShort>
</div>
<div className="mt-12 md:mt-16">
<Feedback
akselFeedback
docId={data?._id}
docType={data?._type}
/>
</div>
</div>
</div>
</article>
</div>
{aside}
</main>
<Footer />
</>
);
};
const WithPreview = lazy(() => import("../../../components/WithPreview"));
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={query}
props={props}
params={{
slug: `god-praksis/artikler/${props?.slug}`,
}}
/>
</PreviewSuspense>
);
}
return <Page {...props} />;
};
export default Wrapper;
@@ -1,22 +1,70 @@
import { contributorsSingle } from "@/lib";
import { getClient } from "@/sanity-client";
import {
NextPageT,
ResolveTemaT,
ResolveSlugT,
AkselGodPraksisDocT,
ResolveContributorsSingleT,
} from "@/types";
import { Button, ErrorMessage, Heading } from "@navikt/ds-react";
import Footer from "components/layout/footer/Footer";
import { Header } from "components/layout/header/Header";
import ArtikkelCard from "components/sanity-modules/cards/ArtikkelCard";
import { AkselCubeStatic } from "components/website-modules/cube";
import { akselArticleAll } from "lib/sanity/queries";
import Head from "next/head";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import useSWR from "swr";
import { ArtiklerT } from "../[slug]";
interface ArtiklerProps {
articles: ArtiklerT[];
}
type ArticleT = ResolveContributorsSingleT<
ResolveTemaT<ResolveSlugT<AkselGodPraksisDocT>>
>;
const Artikler = ({ articles }: ArtiklerProps) => {
const [allArticles, setAllArticles] = useState<ArtiklerT[]>(articles);
type PageProps = NextPageT<{
articles: Array<ArticleT>;
}>;
export const query = (boundry = "") => {
return `{
"articles": *[_type == "aksel_artikkel" && defined(publishedAt)] | order(publishedAt desc)${boundry} {
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
updateInfo,
"slug": slug.current,
"tema": tema[]->title,
ingress,
status,
_type,
"contributor": ${contributorsSingle}
}
}`;
};
export const getStaticProps = async ({
preview = false,
}: {
preview?: boolean;
}): Promise<PageProps> => {
const { articles } = await getClient().fetch(query("[0..21]"));
return {
props: {
articles,
id: "godpraksis_landingsside_id1",
title: "Alle God praksis artikler",
preview,
},
revalidate: 60,
notFound: false,
};
};
const Artikler = ({ articles }: PageProps["props"]) => {
const [allArticles, setAllArticles] = useState<Array<ArticleT>>(articles);
const [hasFetched, setHasFetched] = useState<boolean>(false);
const { alleArtikler } = useRouter().query;
@@ -67,12 +115,12 @@ const Artikler = ({ articles }: ArtiklerProps) => {
</Heading>
<div className="card-grid-3-1 mt-6">
{allArticles
.filter((a: ArtiklerT) => a.tema)
.filter((a) => a.tema)
.map((x) => {
return (
<ArtikkelCard
{...x}
source={x?.slug?.current}
source={x?.slug}
key={x._id}
variant="tema"
/>
@@ -103,17 +151,4 @@ const Artikler = ({ articles }: ArtiklerProps) => {
);
};
export const getStaticProps = async () => {
const { articles } = await getClient().fetch(akselArticleAll("[0..21]"));
return {
props: {
articles,
id: "godpraksis_landingsside_id1",
title: "Alle God praksis artikler",
},
revalidate: 60,
};
};
export default Artikler;
@@ -1,7 +1,16 @@
import { Footer } from "@/layout";
import { akselTema, urlFor, SanityT } from "@/lib";
import { urlFor, destructureBlocks } from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity-client";
import {
AkselGodPraksisDocT,
AkselGodPraksisLandingPageDocT,
AkselTemaT,
NextPageT,
ResolveContributorsT,
ResolveSlugT,
ResolveTemaT,
} from "@/types";
import { Clock } from "@navikt/ds-icons";
import { Heading } from "@navikt/ds-react";
import { Header } from "components/layout/header/Header";
@@ -12,24 +21,61 @@ import { PreviewSuspense } from "next-sanity/preview";
import Head from "next/head";
import React, { lazy } from "react";
interface AkselTemaT extends SanityT.Schema.aksel_tema {
refCount: number;
}
type PageProps = NextPageT<{
page: AkselGodPraksisLandingPageDocT;
temaer: Array<AkselTemaT>;
resent: Array<
ResolveTemaT<ResolveContributorsT<ResolveSlugT<AkselGodPraksisDocT>>>
>;
}>;
interface PageProps {
temaer: AkselTemaT[];
resent: SanityT.Schema.aksel_artikkel &
{
slug: string;
tema: string[];
contributors?: { title?: string }[];
}[];
page: any;
slug: string;
preview: boolean;
}
export const query = `*[_type == "godpraksis_landingsside"][0]{
"page": {
...,
intro[]{
...,
${destructureBlocks}
}
},
"temaer": *[_type == "aksel_tema" && defined(seksjoner[].sider[])]{
...,
"refCount": count(*[_type == "aksel_artikkel" && !(_id in path("drafts.**")) && references(^._id)])
},
"resent": *[_type == "aksel_artikkel" && defined(publishedAt)] | order(publishedAt desc)[0...9]{
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
"slug": slug.current,
"tema": tema[]->title,
ingress,
}
}`;
const Page = ({ temaer, page, resent }: PageProps): JSX.Element => {
export const getStaticProps = async ({
preview = false,
}: {
preview?: boolean;
}): Promise<PageProps> => {
const { temaer, page, resent } = await getClient().fetch(query);
return {
props: {
page,
temaer,
resent,
slug: "/god-praksis",
preview,
title: "Forside God praksis",
id: page?._id ?? "",
},
notFound: !temaer,
revalidate: 60,
};
};
const Page = ({ temaer, page, resent }: PageProps["props"]) => {
const filteredTemas = temaer.filter((x) => x.refCount > 0);
return (
<>
@@ -118,11 +164,11 @@ const Page = ({ temaer, page, resent }: PageProps): JSX.Element => {
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
<WithPreview comp={Page} query={akselTema} props={props} />
<WithPreview comp={Page} query={query} props={props} />
</PreviewSuspense>
);
}
@@ -131,24 +177,3 @@ const Wrapper = (props: any): JSX.Element => {
};
export default Wrapper;
export const getStaticProps = async ({
preview = false,
}: {
preview?: boolean;
}) => {
const { temaer, page, resent } = await getClient().fetch(akselTema);
return {
props: {
page,
temaer,
resent,
slug: "/god-praksis",
preview,
title: "Forside God praksis",
},
notFound: !temaer,
revalidate: 60,
};
};
@@ -1,9 +1,22 @@
import { dateStr } from "@/components";
import { getDocumentsTmp, grunnleggendeQuery, urlFor } from "@/lib";
import {
destructureBlocks,
getDocumentsTmp,
sidebarQuery,
urlFor,
} from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity-client";
import {
AkselGrunnleggendeDocT,
AkselSidebarT,
ArticleListT,
NextPageT,
ResolveContributorsT,
ResolveSlugT,
} from "@/types";
import { Detail } from "@navikt/ds-react";
import { WithSidebar } from "components/layout/page-templates/WithSidebar";
import { WithSidebar } from "components/layout/WithSidebar";
import IntroSeksjon from "components/sanity-modules/IntroSeksjon";
import { StatusTag } from "components/website-modules/StatusTag";
import { PreviewSuspense } from "next-sanity/preview";
@@ -11,17 +24,72 @@ import Head from "next/head";
import { lazy } from "react";
import NotFotfund from "../404";
const Page = ({
page,
sidebar,
seo,
}: {
slug?: string[];
page: any;
sidebar: any;
type PageProps = NextPageT<{
page: ResolveContributorsT<ResolveSlugT<AkselGrunnleggendeDocT>>;
sidebar: AkselSidebarT;
seo: any;
preview: boolean;
}): JSX.Element => {
refs: ArticleListT;
}>;
export const query = `{
"page": *[_type == "ds_artikkel" && slug.current == $slug] | order(_updatedAt desc)[0]
{
...,
"slug": slug.current,
content[]{
...,
${destructureBlocks}
},
},
"seo": *[_type == "komponenter_landingsside"][0].seo.image,
${sidebarQuery}
}`;
export const getStaticPaths = async (): Promise<{
fallback: string;
paths: { params: { slug: string[] } }[];
}> => {
return {
paths: await getDocumentsTmp("ds_artikkel").then((paths) =>
paths.map((slug) => ({
params: {
slug: slug.split("/").filter((x) => x !== "grunnleggende"),
},
}))
),
fallback: "blocking",
};
};
export const getStaticProps = async ({
params: { slug },
preview = false,
}: {
params: { slug: string[] };
preview?: boolean;
}): Promise<PageProps> => {
const { page, sidebar, seo } = await getClient().fetch(query, {
slug: `grunnleggende/${slug.slice(0, 2).join("/")}`,
type: "ds_artikkel",
});
return {
props: {
page: page,
slug: slug.slice(0, 2).join("/"),
seo,
sidebar,
preview,
title: page?.heading ?? "",
id: page?._id ?? "",
refs: [],
},
notFound: !page && !preview,
revalidate: 60,
};
};
const Page = ({ page, sidebar, seo }: PageProps["props"]) => {
if (!page) {
return <NotFotfund />;
}
@@ -82,15 +150,15 @@ const Page = ({
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={grunnleggendeQuery}
query={query}
params={{
slug: `grunnleggende/${props.slug.slice(0, 2).join("/")}`,
slug: `grunnleggende/${props.slug}`,
type: "ds_artikkel",
}}
props={props}
@@ -103,45 +171,3 @@ const Wrapper = (props: any): JSX.Element => {
};
export default Wrapper;
export const getStaticPaths = async (): Promise<{
fallback: string;
paths: { params: { slug: string[] } }[];
}> => {
return {
paths: await getDocumentsTmp("ds_artikkel").then((paths) =>
paths.map((slug) => ({
params: {
slug: slug.split("/").filter((x) => x !== "grunnleggende"),
},
}))
),
fallback: "blocking",
};
};
export const getStaticProps = async ({
params: { slug },
preview = false,
}: {
params: { slug: string[] };
preview?: boolean;
}) => {
const { page, sidebar, seo } = await getClient().fetch(grunnleggendeQuery, {
slug: `grunnleggende/${slug.slice(0, 2).join("/")}`,
type: "ds_artikkel",
});
return {
props: {
page: page,
slug,
seo,
sidebar,
preview,
title: page?.heading ?? "",
},
notFound: !page && !preview,
revalidate: 60,
};
};
@@ -1,29 +1,56 @@
import { grunnleggendeLandingQuery, SidebarT, urlFor } from "@/lib";
import { landingPageQuery, sidebarQuery, urlFor } from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity-client";
import {
AkselLandingPageDocT,
AkselSidebarT,
ArticleListT,
NextPageT,
} from "@/types";
import { Heading, Ingress } from "@navikt/ds-react";
import cl from "clsx";
import { WithSidebar } from "components/layout/page-templates/WithSidebar";
import { WithSidebar } from "components/layout/WithSidebar";
import ComponentOverview from "components/sanity-modules/ComponentOverview";
import { PreviewSuspense } from "next-sanity/preview";
import Head from "next/head";
import { lazy } from "react";
import { grunnleggendeKategorier } from "../../sanity/config";
const Page = ({
page,
sidebar,
links,
type PageProps = NextPageT<{
page: AkselLandingPageDocT;
sidebar: AkselSidebarT;
links: ArticleListT;
}>;
export const query = `{${sidebarQuery}, ${landingPageQuery(
"grunnleggende"
)}, "links": *[_type == "ds_artikkel" && defined(kategori)]{_id,heading,"slug": slug,status,kategori}}`;
export const getStaticProps = async ({
preview = false,
}: {
page: any;
links: {
_id: string;
heading: string;
slug: { current: string };
kategori: string;
}[];
sidebar: SidebarT;
}): JSX.Element => {
preview?: boolean;
}): Promise<PageProps> => {
const { sidebar, page, links } = await getClient().fetch(query, {
type: "ds_artikkel",
});
return {
props: {
page,
sidebar,
links,
slug: "/grunnleggende",
preview,
title: "Forside Grunnleggende",
id: page?._id ?? "",
},
revalidate: 60,
notFound: false,
};
};
const Page = ({ page, sidebar, links }: PageProps["props"]) => {
return (
<>
<Head>
@@ -99,13 +126,13 @@ const Page = ({
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={grunnleggendeLandingQuery}
query={query}
props={props}
params={{
type: "ds_artikkel",
@@ -119,28 +146,3 @@ const Wrapper = (props: any): JSX.Element => {
};
export default Wrapper;
export const getStaticProps = async ({
preview = false,
}: {
preview?: boolean;
}) => {
const { sidebar, page, links } = await getClient().fetch(
grunnleggendeLandingQuery,
{
type: "ds_artikkel",
}
);
return {
props: {
page,
sidebar,
links,
slug: "/grunnleggende",
preview,
title: "Forside Grunnleggende",
},
revalidate: 60,
};
};
+102 -55
View File
@@ -1,9 +1,9 @@
/* eslint-disable @next/next/no-img-element */
import { Footer } from "@/layout";
import { akselForsideQuery, SanityT, urlFor } from "@/lib";
import { contributorsAll, urlFor } from "@/lib";
import { getClient } from "@/sanity-client";
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
import { AkselTemaT, NextPageT } from "@/types";
import {
CompassIcon,
ComponentIcon,
@@ -15,19 +15,109 @@ import { Heading, Ingress } from "@navikt/ds-react";
import cl from "clsx";
import { Header } from "components/layout/header/Header";
import GodPraksisCardSimple from "components/sanity-modules/cards/GodPraksisCardSimple";
import FrontpageBlock, {
BlocksT,
} from "components/sanity-modules/frontpage-blocks/FrontpageBlocks";
import { AkselCube } from "components/website-modules/cube";
import { IntroCards } from "components/website-modules/IntroCards";
import { PrefersReducedMotion } from "components/website-modules/utils/prefers-reduced-motion";
import { PreviewSuspense } from "next-sanity/preview";
import Head from "next/head";
import { lazy, useEffect, useState } from "react";
import FrontpageBlock, {
BlocksT,
} from "components/sanity-modules/frontpage-blocks/FrontpageBlocks";
const WithPreview = lazy(() => import("../components/WithPreview"));
type PageProps = NextPageT<{
tema: Array<AkselTemaT>;
page: {
title: string;
god_praksis_intro: string;
seo: { meta: string; image: string };
};
blocks?: BlocksT[];
}>;
const Forside = ({ page, tema, blocks }: PageProps): JSX.Element => {
export const getStaticProps = async ({
preview = false,
}: {
preview?: boolean;
}): Promise<PageProps> => {
const client = getClient();
const { page = null, tema = null, blocks = null } = await client.fetch(query);
return {
props: {
tema,
page,
blocks,
slug: "/",
preview,
id: page?._id ?? "",
title: "Forsiden",
},
revalidate: 600,
notFound: false,
};
};
export const query = `*[_type == "aksel_forside"][0]{
"page": {
...,
},
"tema": *[_type == "aksel_tema" && defined(seksjoner[].sider[])],
blocks[]{
...,
_type == "nytt_fra_aksel"=>{
highlights[]->{
...,
"content": null,
${contributorsAll},
"tema": tema[]->title,
},
"curatedResent": {
"bloggposts": *[_type == "aksel_blogg" && !(_id in ^.highlights[]._ref)] | order(_createdAt desc)[0...2]{
_type,
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
"slug": slug.current,
ingress,
seo,
${contributorsAll}
},
"artikler": *[_type == "aksel_artikkel" && defined(publishedAt) && !(_id in ^.highlights[]._ref)] | order(publishedAt desc)[0...3]{
_type,
_id,
heading,
_createdAt,
_updatedAt,
publishedAt,
"slug": slug.current,
"tema": tema[]->title,
ingress,
seo,
${contributorsAll}
},
"komponenter": *[_type in ["komponent_artikkel", "ds_artikkel"] && defined(publishedAt) && !(_id in ^.highlights[]._ref)] | order(publishedAt desc)[0...3]{
_type,
_id,
heading,
"slug": slug.current,
status,
kategori,
_createdAt,
_updatedAt,
publishedAt,
seo,
${contributorsAll}
},
},
}
}
}`;
const Forside = ({ page, tema, blocks }: PageProps["props"]) => {
const [pause, setPause] = useState(false);
const [reducedMotion, setReducedMotion] = useState(false);
@@ -52,7 +142,7 @@ const Forside = ({ page, tema, blocks }: PageProps): JSX.Element => {
t?.title &&
t?.slug &&
t?.pictogram &&
t?.seksjoner.find((s) => !!s?.sider.find((s) => s?._ref))
t?.seksjoner.find((s) => !!s?.sider.find((s: any) => s?._ref))
);
})
.sort((a, b) => a.title.localeCompare(b.title));
@@ -202,11 +292,13 @@ const Forside = ({ page, tema, blocks }: PageProps): JSX.Element => {
);
};
const Page = (props: PageProps): JSX.Element => {
const WithPreview = lazy(() => import("../components/WithPreview"));
const Page = (props: PageProps["props"]) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Forside {...props} />}>
<WithPreview comp={Forside} query={akselForsideQuery} props={props} />
<WithPreview comp={Forside} query={query} props={props} />
</PreviewSuspense>
);
}
@@ -214,49 +306,4 @@ const Page = (props: PageProps): JSX.Element => {
return <Forside {...props} />;
};
interface PageProps {
tema: SanityT.Schema.aksel_tema[];
bloggs: ResolveContributorsT<ResolveSlugT<AkselBloggDocT>>[];
page: {
title: string;
god_praksis_intro: string;
seo: { meta: string; image: string };
};
resent: SanityT.Schema.aksel_artikkel &
{
slug: string;
tema: string[];
contributors?: { title?: string }[];
}[];
blocks?: BlocksT[];
slug: string;
preview: boolean;
}
export const getStaticProps = async ({
preview = false,
}: {
preview?: boolean;
}) => {
const client = getClient();
const {
page = null,
tema = null,
blocks = null,
} = await client.fetch(akselForsideQuery);
return {
props: {
tema,
page,
blocks,
slug: "/",
preview,
id: page?._id ?? "",
},
revalidate: 60,
};
};
export default Page;
@@ -6,11 +6,24 @@ import {
logAmplitudeEvent,
YarnIcon,
} from "@/components";
import { getDocumentsTmp, komponentQuery, urlFor } from "@/lib";
import {
destructureBlocks,
getDocumentsTmp,
sidebarQuery,
urlFor,
} from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity-client";
import {
AkselKomponentDocT,
AkselSidebarT,
ArticleListT,
NextPageT,
ResolveContributorsT,
ResolveSlugT,
} from "@/types";
import { BodyShort, Detail, Heading } from "@navikt/ds-react";
import { WithSidebar } from "components/layout/page-templates/WithSidebar";
import { WithSidebar } from "components/layout/WithSidebar";
import ComponentOverview from "components/sanity-modules/ComponentOverview";
import IntroSeksjon from "components/sanity-modules/IntroSeksjon";
import { StatusTag } from "components/website-modules/StatusTag";
@@ -65,19 +78,99 @@ const kodepakker = {
},
};
const Page = ({
page,
sidebar,
refs,
seo,
}: {
slug?: string[];
page: any;
refs: any[];
sidebar: any;
type PageProps = NextPageT<{
page: ResolveContributorsT<ResolveSlugT<AkselKomponentDocT>>;
sidebar: AkselSidebarT;
seo: any;
preview: boolean;
}): JSX.Element => {
refs: ArticleListT;
}>;
/**
* "refs" må disables i preview da next-sanity sin
* preview-funksjonalitet fører til en infinite loop som låser applikasjonen.
* Dette er på grunn av av hele datasettet blir lastet inn i preview flere ganger som til slutt låser vinduet.
*/
export const query = `{
"page": *[_type == "komponent_artikkel" && slug.current == $slug] | order(_updatedAt desc)[0]
{
...,
"slug": slug.current,
linked_package {
"title": @->title,
"github_link": @->github_link,
"status": @->status
},
intro{
...,
body[]{
...,
${destructureBlocks}
}
},
content[]{
...,
${destructureBlocks}
},
},
"refs": select(
$preview == "true" => [],
$preview != "true" => *[_type == "komponent_artikkel" && count(*[references(^._id)][slug.current == $slug]) > 0][0...3]{
_id,
heading,
"slug": slug,
status
}
),
"seo": *[_type == "komponenter_landingsside"][0].seo.image,
${sidebarQuery}
}`;
export const getStaticPaths = async (): Promise<{
fallback: string;
paths: { params: { slug: string[] } }[];
}> => {
return {
paths: await getDocumentsTmp("komponent_artikkel").then((paths) =>
paths.map((slug) => ({
params: {
slug: slug.split("/").filter((x) => x !== "komponenter"),
},
}))
),
fallback: "blocking",
};
};
export const getStaticProps = async ({
params: { slug },
preview = false,
}: {
params: { slug: string[] };
preview?: boolean;
}): Promise<PageProps> => {
const { page, sidebar, refs, seo } = await getClient().fetch(query, {
slug: `komponenter/${slug.slice(0, 2).join("/")}`,
type: "komponent_artikkel",
preview: "false",
});
return {
props: {
page: page,
refs,
slug: slug.slice(0, 2).join("/"),
seo,
sidebar,
preview,
title: page?.heading ?? "",
id: page?._id ?? "",
},
notFound: !page && !preview,
revalidate: 60,
};
};
const Page = ({ page, sidebar, refs, seo }: PageProps["props"]) => {
if (!page) {
return <NotFotfund />;
}
@@ -258,15 +351,15 @@ const Page = ({
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={komponentQuery}
query={query}
params={{
slug: `komponenter/${props.slug.slice(0, 2).join("/")}`,
slug: `komponenter/${props.slug}`,
type: "komponent_artikkel",
preview: "true",
}}
@@ -280,47 +373,3 @@ const Wrapper = (props: any): JSX.Element => {
};
export default Wrapper;
export const getStaticPaths = async (): Promise<{
fallback: string;
paths: { params: { slug: string[] } }[];
}> => {
return {
paths: await getDocumentsTmp("komponent_artikkel").then((paths) =>
paths.map((slug) => ({
params: {
slug: slug.split("/").filter((x) => x !== "komponenter"),
},
}))
),
fallback: "blocking",
};
};
export const getStaticProps = async ({
params: { slug },
preview = false,
}: {
params: { slug: string[] };
preview?: boolean;
}) => {
const { page, sidebar, refs, seo } = await getClient().fetch(komponentQuery, {
slug: `komponenter/${slug.slice(0, 2).join("/")}`,
type: "komponent_artikkel",
preview: "false",
});
return {
props: {
page: page,
refs,
slug,
seo,
sidebar,
preview,
title: page?.heading ?? "",
},
notFound: !page && !preview,
revalidate: 60,
};
};
@@ -1,6 +1,12 @@
import { komponentLandingQuery, SanityT, SidebarT, urlFor } from "@/lib";
import { landingPageQuery, sidebarQuery, urlFor } from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity-client";
import {
AkselLandingPageDocT,
AkselSidebarT,
ArticleListT,
NextPageT,
} from "@/types";
import { logAmplitudeEvent } from "@/utils";
import { CodeIcon } from "@navikt/aksel-icons";
import { BodyShort, Heading, Ingress } from "@navikt/ds-react";
@@ -12,7 +18,7 @@ import {
StorybookIcon,
YarnIcon,
} from "components/assets";
import { WithSidebar } from "components/layout/page-templates/WithSidebar";
import { WithSidebar } from "components/layout/WithSidebar";
import ComponentOverview from "components/sanity-modules/ComponentOverview";
import { IntroCards } from "components/website-modules/IntroCards";
import { PreviewSuspense } from "next-sanity/preview";
@@ -104,21 +110,41 @@ function Links() {
);
}
const Page = ({
page,
sidebar,
links,
type PageProps = NextPageT<{
page: AkselLandingPageDocT;
sidebar: AkselSidebarT;
links: ArticleListT;
}>;
export const query = `{${sidebarQuery}, ${landingPageQuery(
"komponenter"
)}, "links": *[_type == "komponent_artikkel" && defined(kategori)]{_id,heading,"slug": slug,status,kategori}}`;
export const getStaticProps = async ({
preview = false,
}: {
page: any;
links: {
_id: string;
heading: string;
slug: { current: string };
kategori: string;
status?: SanityT.Schema.komponent_artikkel["status"];
}[];
sidebar: SidebarT;
}): JSX.Element => {
preview?: boolean;
}): Promise<PageProps> => {
const { sidebar, page, links } = await getClient().fetch(query, {
type: "komponent_artikkel",
});
return {
props: {
page,
sidebar,
links,
slug: "/komponenter",
preview,
title: "",
id: page?._id ?? "",
},
revalidate: 60,
notFound: false,
};
};
const Page = ({ page, sidebar, links }: PageProps["props"]) => {
return (
<>
<Head>
@@ -221,13 +247,13 @@ const Page = ({
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={komponentLandingQuery}
query={query}
props={props}
params={{
type: "komponent_artikkel",
@@ -241,28 +267,3 @@ const Wrapper = (props: any): JSX.Element => {
};
export default Wrapper;
export const getStaticProps = async ({
preview = false,
}: {
preview?: boolean;
}) => {
const { sidebar, page, links } = await getClient().fetch(
komponentLandingQuery,
{
type: "komponent_artikkel",
}
);
return {
props: {
page,
sidebar,
links,
slug: "/komponenter",
preview,
title: "",
},
revalidate: 60,
};
};
@@ -1,37 +1,253 @@
import { LayoutPicker } from "@/components";
import { akselPrinsippBySlug, SanityT } from "@/lib";
import {
abbrName,
Bilde,
BreadCrumbs,
dateStr,
Feedback,
TableOfContents,
} from "@/components";
import { Footer } from "@/layout";
import { contributorsAll, destructureBlocks, urlFor } from "@/lib";
import { SanityBlockContent } from "@/sanity-block";
import { getClient } from "@/sanity-client";
import {
AkselPrinsippDocT,
NextPageT,
ResolveContributorsT,
ResolveSlugT,
} from "@/types";
import { BodyShort, Heading, Ingress, Label } from "@navikt/ds-react";
import cl from "clsx";
import { Header } from "components/layout/header/Header";
import { PreviewSuspense } from "next-sanity/preview";
import Head from "next/head";
import { GetServerSideProps } from "next/types";
import React, { lazy } from "react";
import { lazy } from "react";
import NotFotfund from "../404";
interface PageProps {
prinsipp: SanityT.Schema.aksel_prinsipp;
slug: string[];
preview: boolean;
}
type PageProps = NextPageT<{
prinsipp: ResolveContributorsT<ResolveSlugT<AkselPrinsippDocT>>;
}>;
const Page = (props: PageProps): JSX.Element => {
if (!props?.prinsipp) {
export const query = `{
"prinsipp": *[slug.current == $slug] | order(_updatedAt desc)[0]
{
...,
"slug": slug.current,
"content": select(
$valid == "true" => content[]{
...,
${destructureBlocks}
},
$valid != "true" => []
),
${contributorsAll}
}
}`;
export const getServerSideProps: GetServerSideProps = async (
context
): Promise<PageProps> => {
const { prinsipp } = await getClient().fetch(query, {
slug: `prinsipper/${(context.params?.prinsipp as string[]).join("/")}`,
valid: "true",
});
return {
props: {
prinsipp,
slug: (context.params?.prinsipp as string[]).join("/"),
preview: context.preview ?? false,
id: prinsipp?._id,
title: prinsipp?.heading ?? "",
},
notFound:
(!prinsipp && !context.preview) || context.params.prinsipp.length > 2,
};
};
const Page = ({ prinsipp: data }: PageProps["props"]) => {
if (!data) {
return <NotFotfund />;
}
return <LayoutPicker title="Aksel" data={props.prinsipp} />;
if (!data.content || !data.heading) {
console.warn(
`Artikkelen har ikke ${
!data.content ? "innhold" : "overskrift"
}, så den kan ikke vises.`
);
return null;
}
const authors = (data?.contributors as any)?.map((x) => x?.title) ?? [];
const mainPage = data?.prinsipp?.hovedside;
return (
<>
<Head>
<title>{`${data?.heading} - Prinsipp - Aksel`}</title>
<meta
property="og:title"
content={`${data?.heading} - Aksel`}
key="ogtitle"
/>
<meta
property="og:description"
content={data?.seo?.meta ?? data?.ingress}
key="ogdesc"
/>
<meta property="og:type" content="article" />
<meta
property="og:image"
content={
data?.seo?.image
? urlFor(data?.seo?.image)
.width(1200)
.height(630)
.fit("crop")
.quality(100)
.url()
: ""
}
key="ogimage"
/>
</Head>
<Header variant={mainPage ? "default" : "subtle"} />
<main
tabIndex={-1}
id="hovedinnhold"
className={cl("aksel-artikkel pt-4 focus:outline-none", {
"bg-white": mainPage,
"bg-surface-subtle": !mainPage,
})}
>
<article className="overflow-x-clip">
<div
className={cl("max-w-aksel mx-auto px-4 sm:w-[90%]", {
"pb-32": mainPage,
})}
>
<div className="pt-12">
<div className="mx-auto mb-16 max-w-prose lg:ml-0 ">
{!mainPage && (
<BreadCrumbs
text={`Prinsipper for ${data?.prinsipp?.prinsippvalg}`}
href={`/prinsipper/${data?.prinsipp?.prinsippvalg}`}
/>
)}
<Heading
level="1"
size="large"
className="text-deepblue-700 mt-4 md:text-5xl"
>
{data.heading}
</Heading>
{data?.ingress && (
<Ingress className="override-text-700 mt-5 text-2xl">
{data?.ingress}
</Ingress>
)}
<div className="mt-6 flex gap-3 text-base">
<BodyShort
size="small"
as="span"
className="text-text-subtle "
>
{dateStr(data?._updatedAt)}
</BodyShort>
{authors?.length > 0 && (
<BodyShort
size="small"
as="div"
className="flex flex-wrap gap-1"
>
<address className="not-italic">{authors[0]}</address>
</BodyShort>
)}
</div>
</div>
</div>
</div>
<div
className={cl("pt-32", {
"bg-gray-100": mainPage,
})}
>
<div className="max-w-aksel mx-auto px-4 sm:w-[90%]">
<div className="pb-16 md:pb-32">
<div className="relative mx-auto mt-4 max-w-prose lg:ml-0 lg:grid lg:max-w-none lg:grid-flow-row-dense lg:grid-cols-3 lg:items-start lg:gap-x-12">
<TableOfContents
changedState={data?.content ?? []}
hideToc={false}
aksel
/>
<div className="max-w-prose lg:col-span-2 lg:col-start-1">
{data?.hero_bilde && (
<Bilde
node={data.hero_bilde as any}
className="-mt-36 mb-10 sm:-mt-72"
/>
)}
<SanityBlockContent
blocks={data?.content ?? []}
variant="aksel"
/>
<div className="mt-12">
{authors?.length > 0 && (
<Label className="text-deepblue-700 mb-2" as="p">
Bidragsytere
</Label>
)}
{authors?.length > 0 && (
<BodyShort
as="div"
className="text-text-subtle mb-1 flex flex-wrap gap-1"
>
{authors.map(abbrName).map((x, y) => (
<address className="not-italic" key={x}>
{x}
{y !== authors.length - 1 && ", "}
</address>
))}
</BodyShort>
)}
<BodyShort as="span" className="text-text-subtle ">
Publisert:{" "}
{dateStr(data?.publishedAt ?? data?._updatedAt)}
</BodyShort>
</div>
<div className="mt-12 md:mt-16">
<Feedback
akselFeedback
docId={data?._id}
docType={data?._type}
/>
</div>
</div>
</div>
</div>
</div>
</div>
</article>
</main>
<Footer />
</>
);
};
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
<WithPreview
comp={Page}
query={akselPrinsippBySlug}
query={query}
props={props}
params={{
slug: `prinsipper/${props.slug.join("/")}`,
slug: `prinsipper/${props.slug}`,
valid: "true",
}}
/>
@@ -43,25 +259,3 @@ const Wrapper = (props: any): JSX.Element => {
};
export default Wrapper;
export const getServerSideProps: GetServerSideProps = async (
context
): Promise<any | { notFound: true }> => {
if (context.params.prinsipp.length > 2) return { notFound: true };
const { prinsipp } = await getClient().fetch(akselPrinsippBySlug, {
slug: `prinsipper/${(context.params.prinsipp as string[]).join("/")}`,
valid: "true",
});
return {
props: {
prinsipp,
slug: context.params.prinsipp,
preview: context.preview ?? false,
id: prinsipp?._id,
title: prinsipp?.heading ?? "",
},
notFound: !prinsipp && !context.preview,
};
};
@@ -255,7 +255,7 @@ const Page = ({ blogg, morePosts }: PageProps["props"]) => {
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
@@ -53,12 +53,12 @@ export const getStaticProps = async ({
title: "Forside Blogg",
id: page?._id ?? "",
},
notFound: !bloggposts && !preview,
notFound: false,
revalidate: 60,
};
};
const Page = (props: PageProps["props"]): JSX.Element => {
const Page = (props: PageProps["props"]) => {
if (!props.bloggposts) {
return <NotFotfund />;
}
@@ -135,7 +135,7 @@ const Page = (props: PageProps["props"]): JSX.Element => {
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
+1 -1
View File
@@ -97,7 +97,7 @@ const Page = ({ page }: PageProps["props"]) => {
const WithPreview = lazy(() => import("../../components/WithPreview"));
const Wrapper = (props: any): JSX.Element => {
const Wrapper = (props: any) => {
if (props?.preview) {
return (
<PreviewSuspense fallback={<Page {...props} />}>
@@ -3,7 +3,6 @@ import {
AccessDeniedIcon,
BookIcon,
BulbOutlineIcon,
ChartUpwardIcon,
CommentIcon,
JoystickIcon,
OkHandIcon,
@@ -23,7 +22,7 @@ import {
import { FeedbackPanes } from "./feedback";
import { FeedbackView } from "./FeedbackPreview";
import { GodPraksisPanes } from "./god-praksis";
import Metrics from "./Metrics";
/* import Metrics from "./Metrics"; */
import { PanesWithCount } from "./with-count";
/* import { WebPreview, JsonView } from './previews' */
@@ -415,18 +414,18 @@ export const defaultDocumentNode = (S, { schemaType }) => {
revision: true,
},
})
.title("Preview"),
.title("Forhåndsvinsing"),
S.view
.component(FeedbackView)
.icon(CommentIcon)
.title("Tilbakemeldinger"),
S.view.component(Metrics).icon(ChartUpwardIcon).title("Metrikker"),
/* S.view.component(Metrics).icon(ChartUpwardIcon).title("Metrikker"), */
]);
}
if (schemaType === "aksel_forside") {
return S.document().views([
S.view.form(),
S.view.component(Metrics).icon(ChartUpwardIcon).title("Metrikker"),
/* S.view.component(Metrics).icon(ChartUpwardIcon).title("Metrikker"), */
]);
}
return S.document().views([S.view.form()]);
+10 -16
View File
@@ -27,37 +27,31 @@ p.override-text-no-max {
}
.aksel-artikkel .aksel-list-ul li::before {
content: url("data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIxMSIKICBoZWlnaHQ9IjEwIgogIHZpZXdCb3g9IjAgMCAxMSAxMCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxyZWN0CiAgICB5PSI1IgogICAgd2lkdGg9IjgiCiAgICBoZWlnaHQ9IjgiCiAgICByeD0iMiIKICAgIHRyYW5zZm9ybT0icm90YXRlKC00NSAwIDUpIgogICAgZmlsbD0iIzAwNUI4MiIKICAvPgo8L3N2Zz4K");
position: absolute;
width: 8px;
height: 8px;
border-radius: 2px;
background-color: var(--a-deepblue-500);
transform: translateY(10px) translateX(2px) rotate(45deg);
left: 0;
content: "";
}
.aksel-artikkel .aksel-list-ul li::marker,
.aksel-artikkel .aksel-list-ol li::marker {
.aksel-artikkel .aksel-list-ul li::marker
/* .aksel-artikkel .aksel-list-ol li::marker */ {
content: none;
}
/*
.aksel-artikkel .aksel-list-ol {
counter-reset: li;
list-style: none;
}
} */
.aksel-artikkel .aksel-list-ul {
list-style: none;
}
.aksel-artikkel .aksel-list-ol li::before {
counter-increment: li;
content: " ." counter(li);
color: var(--a-deepblue-800);
display: inline-block;
width: 1em;
margin-left: -1em;
margin-right: 0.5em;
text-align: right;
direction: rtl;
}
.component-checkered-bg {
background-color: var(--a-white);
background-image: repeating-linear-gradient(
+5
View File
@@ -115,6 +115,10 @@ module.exports = {
"0%": { opacity: 0 },
"100%": { opacity: 1 },
},
toc: {
"0%": { opacity: 0.2 },
"100%": { opacity: 1 },
},
expand: {
"0%": {
opacity: 0.2,
@@ -191,6 +195,7 @@ module.exports = {
shimmerBg: "shimmerBg 15s ease infinite",
fadeInRight: "fadeInRight 0.30s ease-in-out forwards",
fadeIn: "fadeIn 0.15s cubic-bezier(0.65, 0, 0.35, 1)",
toc: "toc 0.15s cubic-bezier(0.65, 0, 0.35, 1)",
expand: "expand 0.15s cubic-bezier(0.215, 0.61, 0.355, 1)",
expandLg: "expandLg 0.15s cubic-bezier(0.215, 0.61, 0.355, 1)",
popup: "popup 2s cubic-bezier(0.215, 0.61, 0.355, 1)",
+2 -2
View File
@@ -10,8 +10,8 @@
"preview": "vite preview"
},
"dependencies": {
"@navikt/ds-css": "2.8.4",
"@navikt/ds-react": "2.8.4",
"@navikt/ds-css": "2.8.6",
"@navikt/ds-react": "2.8.6",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},