Compare commits

..
Author SHA1 Message Date
github-actions[bot]andgithub-actions[bot] 21d5ddd433 Version Packages (#2515)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-11-24 19:40:44 +01:00
Ken 1b7bc53294 🐛 Synket date-fns versioner i Repo 2023-11-24 18:56:08 +01:00
Lars Eirik Korsgaard Hansen 4dc5a90c72 ⬆️ upgrade date-fns version & make it minor-version agnostic (#2514)
* yarn lock

* ⬆️ upgrade date-fns version & make it minor-version agnostic
2023-11-24 11:04:24 +01:00
github-actions[bot]andgithub-actions[bot] c7694f8ddd Version Packages (#2513)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-11-23 14:16:48 +01:00
Ken 10bbdb730b Switch color (#2511)
* 💄 Switch er nå action

* 📝 changeset

* 🐛 Byttet fra action til action-selected
2023-11-23 13:57:06 +01:00
github-actions[bot]andgithub-actions[bot] f4458f3bb8 Version Packages (#2505)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-11-23 12:58:08 +01:00
Halvor Haugan 9dafbeb4eb ♿ Textarea: Forsinkelse ved live-opplesning av gjenstående tegn (#2502) 2023-11-23 12:51:57 +01:00
Halvor Haugan 4b4e190c20 Endre navn på ikon DrawingPin -> PushPin 2023-11-23 11:25:54 +01:00
Halvor Haugan b7d03bfc89 Textarea: Mulighet for å sette resize-retning (#2494) 2023-11-22 15:26:34 +01:00
Halvor Haugan bc259f5b30 Nytt ikon DrawingPin (#2503) 2023-11-22 15:21:18 +01:00
Halvor Haugan 16cad26378 ✨ Textarea: Støtte for automatisk scrollbar (#2457) 2023-11-22 15:15:32 +01:00
Ken 6ee4aa3e82 [Sanity/Aksel.nav.no] Sanity cleanup (#2499)
* ♻️ Sanity-id ut i const

* ⚡ Flyttet sanity apiVersion ut i const

* ⚡ Flyttet sanity dataset ut i const

* 🏷️ Bedre typer structure

* ⚡ La til blur på highlight-bilder

* 💄 Cube ligger nå bak innhold på bloggen

* 🔥 Fjernet gammel SEO fra sanity

* ♻️ SEO og groups import sanity

* ♻️ Ryddet opp i metadata

* 🎉 Annotering av lenker i sanity

* 🎨 Preview av kodemodul

* 🎨 Preview for dodont

* 🎨 Tips-preview

* 🎨 Relatert innhold preview

* 🔥 Fjernet console.log

* 🐛 Fikset småfeil

* 💄 Fikset darkmode-visning for preview
2023-11-22 11:47:31 +01:00
Ken bb5466178a 📝 Oppdatert typo-eksempler (#2493) 2023-11-22 10:14:05 +01:00
Ken efb92be344 🐛 Headings med space førte til wrapping av tekst (#2490) 2023-11-22 09:46:32 +01:00
KenandHalvor Haugan e3f75f542f 📝 Alert eksempler (#2492)
* 📝 Inline description i eksempler

* Update aksel.nav.no/website/pages/eksempler/alert/error.tsx

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>

* Update aksel.nav.no/website/pages/eksempler/alert/info.tsx

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>

---------

Co-authored-by: Halvor Haugan <83693529+HalvorHaugan@users.noreply.github.com>
2023-11-22 09:39:53 +01:00
Halvor Haugan 96610bb543 Fiks storybook:aksel 2023-11-21 13:51:43 +01:00
Ken eee7143cf6 [Aksel.nav.no] Fjernet Scrollbar gutters på eksempler (#2491)
* 🐛 Fjerner scroll-gutters fra eksempler

* 🎨 Bedre visning av breakpoints i eksempler

* ⬆️ Yarn.lock
2023-11-20 11:58:24 +01:00
Ken a1b8cc0364 📝 Oppdatert page gutters eksempel (#2496) 2023-11-20 09:15:07 +01:00
github-actions[bot]andgithub-actions[bot] e5d2f7eb8c Version Packages (#2498)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-11-20 09:11:39 +01:00
Håvard Stigen Andersen 67b8b6626e Gjør lukknapp i alert til type button (#2497) 2023-11-20 09:08:04 +01:00
Ken 8783f1821d [Sanity] Oppdatert til v3.20, slått på kommentarer (#2487)
* 🎨 Updated sanity and enabled comments

* ♻️ Oppdatert structure

* 🎨 Bruker native input for bedre perspective og comment støtte

* 🎨 Added presentation-mode

* ⚡ Raskere load av sider

* 🔥 Fjernet experimental features
2023-11-17 21:44:46 +01:00
Julian Nymark d52085f256 ✨ add 1440px width to playroom default widths (#2476)
* ✨ add 1440px width to playroom default widths

* 🐛 fix for routing wrt /sandbox + future fix for default widths

* 🚚 shuffle redirect check to earlier in middleware
2023-11-17 17:18:18 +01:00
Halvor Haugan 67e8565da3 Link: Oppdatert eksempler (#2479) 2023-11-17 14:51:21 +01:00
Halvor Haugan bb4ff1afc3 Justering av eksempler på ConfirmationPanel (#2489) 2023-11-17 13:37:53 +01:00
dependabot[bot] 16c0c15c67 ⬆️ Bump sharp from 0.32.5 to 0.32.6 in /aksel.nav.no/website (#2488)
Bumps [sharp](https://github.com/lovell/sharp) from 0.32.5 to 0.32.6.
- [Release notes](https://github.com/lovell/sharp/releases)
- [Changelog](https://github.com/lovell/sharp/blob/main/docs/changelog.md)
- [Commits](https://github.com/lovell/sharp/compare/v0.32.5...v0.32.6)

---
updated-dependencies:
- dependency-name: sharp
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-17 12:54:27 +01:00
124 changed files with 1392 additions and 1375 deletions

No files matched your search

+12
View File
@@ -1,5 +1,17 @@
# @navikt/aksel-icons
## 5.11.2
## 5.11.1
## 5.11.0
### Minor Changes
- Ikoner: Nytt ikon `PushPin` ([#2503](https://github.com/navikt/aksel/pull/2503))
## 5.10.4
## 5.10.3
## 5.10.2
+3
View File
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.3117 3.25101C15.5796 2.51892 14.3754 2.57898 13.7198 3.38029L10.1358 7.76072C10.1008 7.80356 10.0525 7.83356 9.99854 7.84601L5.5894 8.8635C4.25008 9.17258 3.77354 10.8342 4.74547 11.8061L7.93934 15L3.46967 19.4697C3.17678 19.7626 3.17678 20.2374 3.46967 20.5303C3.76256 20.8232 4.23744 20.8232 4.53033 20.5303L9 16.0607L12.1939 19.2545C13.1658 20.2265 14.8274 19.7499 15.1365 18.4106L16.154 14.0015C16.1664 13.9475 16.1964 13.8992 16.2393 13.8642L20.6197 10.2802C21.421 9.62457 21.4811 8.42042 20.749 7.68833L16.3117 3.25101ZM9.53033 14.4697L13.2545 18.1939C13.3934 18.3327 13.6308 18.2646 13.6749 18.0733L14.6924 13.6642C14.7795 13.2866 14.9895 12.9486 15.2894 12.7032L19.6699 9.11925C19.7843 9.02559 19.7929 8.85357 19.6883 8.74899L15.251 4.31167C15.1464 4.20709 14.9744 4.21567 14.8807 4.33014L11.2968 8.71058C11.0514 9.01048 10.7134 9.22046 10.3358 9.3076L5.92669 10.3251C5.73536 10.3692 5.66728 10.6066 5.80613 10.7455L9.53033 14.4697Z" fill="#23262A"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+9
View File
@@ -0,0 +1,9 @@
name: PushPin
category: Home
sub_category: Hosehold items
keywords:
- pinn
- tegnestift
variant: Stroke
updated_at: 23.11.2023
created_at: 23.11.2023
@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.3117 3.25101C15.5796 2.51892 14.3754 2.57898 13.7198 3.38029L10.1358 7.76072C10.1008 7.80356 10.0525 7.83356 9.99856 7.84601L5.58942 8.8635C4.2501 9.17258 3.77356 10.8342 4.74548 11.8061L12.1939 19.2545C13.1658 20.2265 14.8274 19.7499 15.1365 18.4106L16.154 14.0015C16.1665 13.9475 16.1965 13.8992 16.2393 13.8642L20.6197 10.2802C21.421 9.62457 21.4811 8.42042 20.749 7.68833L16.3117 3.25101ZM4.53033 20.5303L8.06066 17L7 15.9393L3.46967 19.4697C3.17678 19.7626 3.17678 20.2374 3.46967 20.5303C3.76256 20.8232 4.23744 20.8232 4.53033 20.5303Z" fill="#23262A"/>
</svg>

After

Width:  |  Height:  |  Size: 718 B

@@ -0,0 +1,9 @@
name: PushPinFill
category: Home
sub_category: Hosehold items
keywords:
- pinn
- tegnestift
variant: Fill
updated_at: 23.11.2023
created_at: 23.11.2023
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-icons",
"version": "5.10.3",
"version": "5.11.2",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/ikoner",
"repository": {
+8
View File
@@ -1,5 +1,13 @@
# @navikt/aksel-stylelint
## 5.11.2
## 5.11.1
## 5.11.0
## 5.10.4
## 5.10.3
## 5.10.2
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel-stylelint",
"version": "5.10.3",
"version": "5.11.2",
"author": "Aksel | NAV",
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
"repository": {
@@ -35,8 +35,8 @@
"dev": "yarn watch:lint"
},
"devDependencies": {
"@navikt/ds-css": "^5.10.3",
"@navikt/ds-tokens": "^5.10.3",
"@navikt/ds-css": "^5.11.2",
"@navikt/ds-tokens": "^5.11.2",
"@types/jest": "^29.0.0",
"concurrently": "7.2.1",
"copyfiles": "2.4.1",
+28
View File
@@ -1,5 +1,33 @@
# @navikt/aksel
## 5.11.2
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@5.11.2
## 5.11.1
### Patch Changes
- Updated dependencies [[`10bbdb730`](https://github.com/navikt/aksel/commit/10bbdb730ba79544fa65e1aacebd865be8672a05)]:
- @navikt/ds-css@5.11.1
## 5.11.0
### Patch Changes
- Updated dependencies [[`b7d03bfc8`](https://github.com/navikt/aksel/commit/b7d03bfc89dddb679c49a075bd45d675aacc7a71), [`9dafbeb4e`](https://github.com/navikt/aksel/commit/9dafbeb4eb802532cb9c6ad50ab5bf502e1bd5b4), [`16cad2637`](https://github.com/navikt/aksel/commit/16cad263787ad12978c191e2fb45816d2015ef0c)]:
- @navikt/ds-css@5.11.0
## 5.10.4
### Patch Changes
- Updated dependencies []:
- @navikt/ds-css@5.10.4
## 5.10.3
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/aksel",
"version": "5.10.3",
"version": "5.11.2",
"description": "Aksel command line interface. Handles css-imports, codemods and more",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -29,7 +29,7 @@
},
"homepage": "https://aksel.nav.no/grunnleggende/kode/kommandolinje",
"dependencies": {
"@navikt/ds-css": "5.10.3",
"@navikt/ds-css": "5.11.2",
"axios": "1.6.0",
"chalk": "4.1.0",
"clipboardy": "^2.3.0",
+22
View File
@@ -1,5 +1,27 @@
# @navikt/ds-css
## 5.11.2
## 5.11.1
### Patch Changes
- Switch: Byttet success-farger med action npr checked ([#2511](https://github.com/navikt/aksel/pull/2511))
## 5.11.0
### Minor Changes
- :sparkles: Textarea: Mulighet for å sette resize-retning ([#2494](https://github.com/navikt/aksel/pull/2494))
- :sparkles: Textarea: Eksperimentell støtte for automatisk scrollbar ([#2457](https://github.com/navikt/aksel/pull/2457))
### Patch Changes
- :wheelchair: Textarea: Forsinkelse ved live-opplesning av gjenstående tegn ([#2502](https://github.com/navikt/aksel/pull/2502))
## 5.10.4
## 5.10.3
### Patch Changes
+5 -10
View File
@@ -61,7 +61,7 @@
.navds-switch__input:hover ~ .navds-switch__label-wrapper,
.navds-switch__label-wrapper:hover {
color: var(--ac-switch-action, var(--a-surface-action));
color: var(--ac-switch-action, var(--a-surface-action-selected));
}
.navds-switch__input:disabled:hover ~ .navds-switch__label-wrapper {
@@ -91,7 +91,7 @@
}
.navds-switch__input:checked ~ .navds-switch__track {
background-color: var(--ac-switch-checked-bg, var(--a-surface-success));
background-color: var(--ac-switch-checked-bg, var(--a-surface-action-selected));
}
.navds-switch__input:hover ~ .navds-switch__track {
@@ -99,7 +99,7 @@
}
.navds-switch__input:hover:checked ~ .navds-switch__track {
background-color: var(--ac-switch-checked-hover-bg, var(--a-surface-success-hover));
background-color: var(--ac-switch-checked-hover-bg, var(--a-surface-action-selected-hover));
}
.navds-switch__input:disabled ~ .navds-switch__track {
@@ -107,7 +107,7 @@
}
.navds-switch__input:checked:disabled ~ .navds-switch__track {
background-color: var(--ac-switch-checked-bg, var(--a-border-success));
background-color: var(--ac-switch-checked-bg, var(--a-border-action-selected));
}
.navds-switch__input:focus-visible ~ .navds-switch__track {
@@ -139,7 +139,7 @@
.navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb {
transform: translateX(1.25rem);
color: var(--ac-switch-thumb-icon-checked, var(--a-icon-success));
color: var(--ac-switch-thumb-icon-checked, var(--a-icon-action-selected));
}
@media (hover: hover) and (pointer: fine) {
@@ -160,11 +160,6 @@
transform: translateX(1.25rem);
}
/* Loader */
.navds-switch__input:checked ~ .navds-switch__track > .navds-switch__thumb .navds-loader__foreground {
stroke: var(--ac-switch-thumb-icon-checked, var(--a-icon-success));
}
/* Disabled */
.navds-switch__input:disabled {
appearance: none;
+36 -2
View File
@@ -22,7 +22,7 @@
.navds-textarea__wrapper {
position: relative;
width: 100%;
min-width: 100%;
}
.navds-textarea__input {
@@ -70,8 +70,42 @@
color: var(--ac-textarea-counter-error-text, var(--__ac-textarea-counter-error-text, var(--a-text-danger)));
}
.navds-textarea--resize .navds-textarea__input {
.navds-textarea__sr-counter {
display: none;
}
.navds-textarea__wrapper:focus-within .navds-textarea__sr-counter {
display: initial;
}
.navds-textarea--resize-both .navds-textarea__input {
resize: both;
border-end-end-radius: 0;
}
.navds-textarea--resize-horizontal .navds-textarea__input {
resize: horizontal;
border-end-end-radius: 0;
}
.navds-textarea--resize-vertical .navds-textarea__input {
resize: vertical;
border-end-end-radius: 0;
}
.navds-textarea--autoscrollbar,
.navds-textarea--autoscrollbar .navds-textarea__wrapper {
display: flex;
flex-direction: column;
overflow: hidden;
/* Makes the box-shadow visible even though overflow is hidden: */
padding: 3px;
margin: -3px;
}
.navds-textarea--autoscrollbar .navds-textarea__input {
scrollbar-gutter: stable; /* Needed to prevent scrollbar from appearing too early */
}
/**
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "5.10.3",
"version": "5.11.2",
"description": "CSS for NAV Designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -27,7 +27,7 @@
"css:get-version": "node config/get-version.js"
},
"devDependencies": {
"@navikt/ds-tokens": "^5.10.3",
"@navikt/ds-tokens": "^5.11.2",
"cssnano": "6.0.0",
"fast-glob": "3.2.11",
"lodash": "4.17.21",
+4 -4
View File
@@ -401,14 +401,14 @@
"--ac-select-error-border": "--a-surface-danger"
},
"switch": {
"--ac-switch-action": "--a-surface-action",
"--ac-switch-action": "--a-surface-action-selected",
"--ac-switch-bg": "--a-surface-neutral",
"--ac-switch-checked-bg": "--a-surface-success",
"--ac-switch-checked-bg": "--a-surface-action-selected",
"--ac-switch-hover-bg": "--a-surface-neutral-hover",
"--ac-switch-checked-hover-bg": "--a-surface-success-hover",
"--ac-switch-checked-hover-bg": "--a-surface-action-selected-hover",
"--ac-switch-thumb-bg": "--a-surface-default",
"--ac-switch-thumb-icon": "--a-icon-subtle",
"--ac-switch-thumb-icon-checked": "--a-icon-success"
"--ac-switch-thumb-icon-checked": "--a-icon-action-selected"
},
"textfield": {
"--ac-textfield-bg": "--a-surface-default",
+46
View File
@@ -1,5 +1,51 @@
# @navikt/ds-react
## 5.11.2
### Patch Changes
- ⬆️ upgrade date-fns version & make it minor-version agnostic ([#2514](https://github.com/navikt/aksel/pull/2514))
- Updated dependencies []:
- @navikt/ds-tokens@5.11.2
- @navikt/aksel-icons@5.11.2
## 5.11.1
### Patch Changes
- Switch: Byttet success-farger med action npr checked ([#2511](https://github.com/navikt/aksel/pull/2511))
- Updated dependencies []:
- @navikt/ds-tokens@5.11.1
- @navikt/aksel-icons@5.11.1
## 5.11.0
### Minor Changes
- :sparkles: Textarea: Mulighet for å sette resize-retning ([#2494](https://github.com/navikt/aksel/pull/2494))
- :sparkles: Textarea: Eksperimentell støtte for automatisk scrollbar ([#2457](https://github.com/navikt/aksel/pull/2457))
### Patch Changes
- :wheelchair: Textarea: Forsinkelse ved live-opplesning av gjenstående tegn ([#2502](https://github.com/navikt/aksel/pull/2502))
- Updated dependencies [[`bc259f5b3`](https://github.com/navikt/aksel/commit/bc259f5b306319c0e08397d5300596fc1d43353e)]:
- @navikt/aksel-icons@5.11.0
- @navikt/ds-tokens@5.11.0
## 5.10.4
### Patch Changes
- Gjør lukknapp i Alert til type button ([#2497](https://github.com/navikt/aksel/pull/2497))
- Updated dependencies []:
- @navikt/ds-tokens@5.10.4
- @navikt/aksel-icons@5.10.4
## 5.10.3
### Patch Changes
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "5.10.3",
"version": "5.11.2",
"description": "Aksel react-components for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -38,12 +38,12 @@
},
"dependencies": {
"@floating-ui/react": "0.25.4",
"@navikt/aksel-icons": "^5.10.3",
"@navikt/ds-tokens": "^5.10.3",
"@navikt/aksel-icons": "^5.11.2",
"@navikt/ds-tokens": "^5.11.2",
"@radix-ui/react-tabs": "1.0.0",
"@radix-ui/react-toggle-group": "1.0.0",
"clsx": "^1.2.1",
"date-fns": "2.29.3",
"date-fns": "^2.30.0",
"react-day-picker": "8.3.4"
},
"devDependencies": {
+1
View File
@@ -117,6 +117,7 @@ export const Alert = forwardRef<HTMLDivElement, AlertProps>(
size="small"
variant="tertiary-neutral"
onClick={onClose}
type="button"
icon={<XMarkIcon title="Lukk Alert" />}
/>
</div>
+7 -3
View File
@@ -5,11 +5,11 @@ import React, {
useEffect,
useState,
} from "react";
import { FormFieldProps, useFormField } from "./useFormField";
import { ReadOnlyIcon } from "./ReadOnlyIcon";
import { Loader } from "../loader";
import { BodyShort } from "../typography";
import { omit } from "../util";
import { ReadOnlyIcon } from "./ReadOnlyIcon";
import { FormFieldProps, useFormField } from "./useFormField";
const SelectedIcon = () => (
<svg
@@ -134,7 +134,11 @@ export const Switch = forwardRef<HTMLInputElement, SwitchProps>(
<span className="navds-switch__track">
<span className="navds-switch__thumb">
{loading ? (
<Loader size="xsmall" aria-live="polite" />
<Loader
size="xsmall"
aria-live="polite"
variant={checked ? "interaction" : "neutral"}
/>
) : checked ? (
<SelectedIcon />
) : null}
+12 -2
View File
@@ -45,7 +45,13 @@ export interface TextareaProps
/**
* Enables resizing of field
*/
resize?: boolean;
resize?: boolean | "vertical" | "horizontal";
/**
* Textarea will stop growing and get a scrollbar when there's no more room to grow.
* Requires `display:flex` on the parent.
* Experimental feature that may be removed or get breaking changes in a minor version.
*/
UNSAFE_autoScrollbar?: boolean;
/**
* i18n-translations for counter-text
*/
@@ -86,6 +92,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
maxLength,
hideLabel = false,
resize,
UNSAFE_autoScrollbar,
i18n,
readOnly,
...rest
@@ -121,7 +128,9 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
"navds-form-field--readonly": readOnly,
"navds-textarea--readonly": readOnly,
"navds-textarea--error": hasError,
"navds-textarea--resize": resize,
"navds-textarea--autoscrollbar": UNSAFE_autoScrollbar,
[`navds-textarea--resize-${resize === true ? "both" : resize}`]:
resize,
}
)}
>
@@ -157,6 +166,7 @@ export const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(
: setControlledValue(e.target.value)
}
minRows={getMinRows()}
autoScrollbar={UNSAFE_autoScrollbar}
ref={ref}
readOnly={readOnly}
className={cl(
+39 -12
View File
@@ -1,6 +1,7 @@
import cl from "clsx";
import React from "react";
import React, { useEffect, useState } from "react";
import { BodyShort } from "../typography";
import debounce from "../util/debounce";
import type { TextareaProps } from "./Textarea";
interface Props {
@@ -13,19 +14,45 @@ interface Props {
const TextareaCounter = ({ maxLength, currentLength, size, i18n }: Props) => {
const difference = maxLength - currentLength;
const [debouncedDiff, setDebouncedDiff] = useState(difference);
useEffect(() => {
const debounceFunc = debounce(() => {
setDebouncedDiff(difference);
}, 2000);
debounceFunc();
return () => {
debounceFunc.clear();
};
}, [difference]);
return (
<BodyShort
className={cl("navds-textarea__counter", {
"navds-textarea__counter--error": difference < 0,
})}
role={difference < 20 ? "status" : undefined}
size={size}
>
{difference < 0
? `${Math.abs(difference)} ${i18n?.counterTooMuch ?? "tegn for mye"}`
: `${difference} ${i18n?.counterLeft ?? "tegn igjen"}`}
</BodyShort>
<>
{difference < 20 && (
<span
role="status"
className="navds-textarea__sr-counter navds-sr-only"
>
{getCounterText(debouncedDiff, i18n)}
</span>
)}
<BodyShort
className={cl("navds-textarea__counter", {
"navds-textarea__counter--error": difference < 0,
})}
size={size}
>
{getCounterText(difference, i18n)}
</BodyShort>
</>
);
};
const getCounterText = (difference: number, i18n: TextareaProps["i18n"]) =>
difference < 0
? `${Math.abs(difference)} ${i18n?.counterTooMuch ?? "tegn for mye"}`
: `${difference} ${i18n?.counterLeft ?? "tegn igjen"}`;
export default TextareaCounter;
@@ -1,5 +1,6 @@
import { Meta, StoryObj } from "@storybook/react";
import React from "react";
import { Button } from "../../button";
import { Textarea } from "../index";
const meta: Meta<typeof Textarea> = {
@@ -16,10 +17,13 @@ export const Default: StoryObj<typeof Textarea> = {
args: {
maxLength: 0,
label: "Ipsum enim quis culpa",
resize: false,
},
argTypes: {
resize: {
control: { type: "radio" },
options: [true, "vertical", "horizontal"],
},
size: {
control: { type: "radio" },
options: ["medium", "small"],
@@ -99,7 +103,7 @@ export const HideLabel = () => {
};
export const MaxLength = () => {
return <Textarea maxLength={200} label="Ipsum enim quis culpa" />;
return <Textarea maxLength={50} label="Ipsum enim quis culpa" />;
};
export const MinRows = () => {
@@ -138,3 +142,35 @@ export const Readonly = () => {
</div>
);
};
export const AutoScrollbar = (props) => (
<div
style={{
border: "1px solid lightGreen",
height: "90vh",
display: "flex",
flexDirection: "column",
}}
>
<div style={{ border: "1px dashed gray" }}>
<h1>Header</h1>
</div>
<Textarea
resize
label="Textarea with autoScrollbar"
description="Description"
maxLength={30}
UNSAFE_autoScrollbar
{...props}
/>
<div style={{ border: "1px dashed gray" }}>
<Button>Send</Button>
</div>
</div>
);
AutoScrollbar.argTypes = {
error: { type: "string" },
hideLabel: { type: "boolean" },
maxRows: { type: "number" },
minRows: { type: "number" },
};
+4 -3
View File
@@ -1,13 +1,14 @@
import React, { forwardRef } from "react";
import cl from "clsx";
import React, { forwardRef } from "react";
import { OverridableComponent } from "../util/OverridableComponent";
export interface LinkProps
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
/**
* Inverts when the underline appears. If this is false,
* the underline does not appear by default, but does appear when the link is hovered.
* This makes it more suitable for use when inlined in text.
* the underline only appears on hover.
*
* **NB: Underline can only be removed in menus etc. where it's obvious that it's a link.**
* @default true
*/
underline?: boolean;
@@ -1,19 +1,57 @@
/* https://github.com/mui/material-ui/blob/master/packages/mui-base/src/TextareaAutosize/TextareaAutosize.js */
/* https://github.com/mui/material-ui/blob/master/packages/mui-base/src/TextareaAutosize/TextareaAutosize.tsx */
import React, { forwardRef, useEffect, useMemo, useRef, useState } from "react";
import ReactDOM from "react-dom";
import { debounce, mergeRefs, useClientLayoutEffect } from "../util";
type State = {
outerHeightStyle: number;
overflow?: boolean | undefined;
};
const updateState = (
prevState: State,
newState: State,
renders: React.MutableRefObject<number>
) => {
const { outerHeightStyle, overflow } = newState;
// Need a large enough difference to update the height.
// This prevents infinite rendering loop.
if (
renders.current < 20 &&
((outerHeightStyle > 0 &&
Math.abs((prevState.outerHeightStyle || 0) - outerHeightStyle) > 1) ||
prevState.overflow !== overflow)
) {
renders.current += 1;
return {
overflow,
outerHeightStyle,
};
}
if (process.env.NODE_ENV !== "production") {
if (renders.current === 20) {
console.error(
[
"Textarea: Too many re-renders. The layout is unstable.",
"TextareaAutosize limits the number of renders to prevent an infinite loop.",
].join("\n")
);
}
}
return prevState;
};
/**
* https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/ownerDocument.ts
* https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/ownerWindow.ts
* https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/ownerDocument/ownerDocument.ts
* https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/ownerWindow/ownerWindow.ts
*/
const ownerWindow = (node: Node | null): Window => {
const ownerWindow = (node: Node | undefined): Window => {
const doc = (node && node.ownerDocument) || document;
return doc.defaultView || window;
};
function getStyleValue(computedStyle, property) {
return parseInt(computedStyle[property], 10) || 0;
function getStyleValue(value: string) {
return parseInt(value, 10) || 0;
}
interface TextareaAutosizeProps
@@ -30,34 +68,46 @@ interface TextareaAutosizeProps
* @default 1
*/
minRows?: number;
/**
* If true, textarea will never get `overflow:hidden`
*/
autoScrollbar?: boolean;
}
const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
(
{ className, onChange, maxRows, minRows = 1, style, value, ...other },
{
className,
onChange,
maxRows,
minRows = 1,
autoScrollbar,
style,
value,
...other
}: TextareaAutosizeProps,
ref
) => {
const { current: isControlled } = useRef(value != null);
const inputRef = useRef<HTMLTextAreaElement | null>(null);
const inputRef = useRef<HTMLTextAreaElement>(null);
const handleRef = useMemo(() => mergeRefs([inputRef, ref]), [ref]);
const shadowRef = useRef<HTMLTextAreaElement | null>(null);
const shadowRef = useRef<HTMLTextAreaElement>(null);
const renders = useRef(0);
const [state, setState] = useState<any>({});
const [state, setState] = useState<State>({ outerHeightStyle: 0 });
const getUpdatedState = React.useCallback(() => {
if (!inputRef.current || !shadowRef.current) return;
const input = inputRef.current;
const input = inputRef.current!;
const containerWindow = ownerWindow(input);
const computedStyle = containerWindow.getComputedStyle(input);
// If input's width is shrunk and it's not visible, don't sync height.
if (computedStyle.width === "0px") {
return;
return { outerHeightStyle: 0 };
}
const inputShallow = shadowRef.current;
const inputShallow = shadowRef.current!;
inputShallow.style.width = computedStyle.width;
inputShallow.value = input.value || other?.placeholder || "x";
inputShallow.value = input.value || other.placeholder || "x";
if (inputShallow.value.slice(-1) === "\n") {
// Certain fonts which overflow the line height will cause the textarea
// to report a different scrollHeight depending on whether the last line
@@ -65,13 +115,13 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
inputShallow.value += " ";
}
const boxSizing = computedStyle["box-sizing"];
const boxSizing = computedStyle.boxSizing;
const padding =
getStyleValue(computedStyle, "padding-bottom") +
getStyleValue(computedStyle, "padding-top");
getStyleValue(computedStyle.paddingBottom) +
getStyleValue(computedStyle.paddingTop);
const border =
getStyleValue(computedStyle, "border-bottom-width") +
getStyleValue(computedStyle, "border-top-width");
getStyleValue(computedStyle.borderBottomWidth) +
getStyleValue(computedStyle.borderTopWidth);
// The height of the inner content
const innerHeight = inputShallow.scrollHeight - padding;
@@ -97,7 +147,7 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
const overflow = Math.abs(outerHeight - innerHeight) <= 1;
return { outerHeightStyle, overflow };
}, [maxRows, minRows, other?.placeholder]);
}, [maxRows, minRows, other.placeholder]);
const syncHeight = React.useCallback(() => {
const newState = getUpdatedState();
@@ -106,85 +156,52 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
return;
}
setState((prevState) => {
return updateState(prevState, newState);
});
setState((prevState) => updateState(prevState, newState, renders));
}, [getUpdatedState]);
const updateState = (prevState, newState) => {
const { outerHeightStyle, overflow } = newState;
// Need a large enough difference to update the height.
// This prevents infinite rendering loop.
if (
renders.current < 20 &&
((outerHeightStyle > 0 &&
Math.abs((prevState.outerHeightStyle || 0) - outerHeightStyle) > 1) ||
prevState.overflow !== overflow)
) {
renders.current += 1;
return {
overflow,
outerHeightStyle,
};
}
if (process.env.NODE_ENV !== "production") {
if (renders.current === 20) {
console.error(
[
"Textarea: Too many re-renders. The layout is unstable.",
"TextareaAutosize limits the number of renders to prevent an infinite loop.",
].join("\n")
);
useClientLayoutEffect(() => {
const syncHeightWithFlushSync = () => {
const newState = getUpdatedState();
if (isEmpty(newState)) {
return;
}
}
return prevState;
};
const withFlushSync = () => {
const newState = getUpdatedState();
if (isEmpty(newState)) {
return;
}
// In React 18, state updates in a ResizeObserver's callback are happening after the paint which causes flickering
// when doing some visual updates in it. Using flushSync ensures that the dom will be painted after the states updates happen
// Related issue - https://github.com/facebook/react/issues/24331
ReactDOM.flushSync(() => {
setState((prevState) => {
return updateState(prevState, newState);
// In React 18, state updates in a ResizeObserver's callback are happening after
// the paint, this leads to an infinite rendering.
//
// Using flushSync ensures that the states is updated before the next pain.
// Related issue - https://github.com/facebook/react/issues/24331
ReactDOM.flushSync(() => {
setState((prevState) => updateState(prevState, newState, renders));
});
});
};
};
React.useEffect(() => {
const handleResize = debounce(() => {
const handleResize = () => {
renders.current = 0;
syncHeightWithFlushSync();
};
if (inputRef.current) {
withFlushSync();
}
});
let resizeObserver: ResizeObserver;
const debounceHandleResize = debounce(handleResize);
const input = inputRef.current!;
const containerWindow = ownerWindow(input);
containerWindow.addEventListener("resize", handleResize);
containerWindow.addEventListener("resize", debounceHandleResize);
let resizeObserver: ResizeObserver;
if (typeof ResizeObserver !== "undefined") {
resizeObserver = new ResizeObserver(handleResize);
resizeObserver.observe(input);
}
return () => {
handleResize.clear();
containerWindow.removeEventListener("resize", handleResize);
debounceHandleResize.clear();
containerWindow.removeEventListener("resize", debounceHandleResize);
if (resizeObserver) {
resizeObserver.disconnect();
}
};
});
}, [getUpdatedState]);
useClientLayoutEffect(() => {
syncHeight();
@@ -194,7 +211,7 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
renders.current = 0;
}, [value]);
const handleChange = (event) => {
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
renders.current = 0;
if (!isControlled) {
@@ -218,7 +235,7 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
height: state.outerHeightStyle,
// Need a large enough difference to allow scrolling.
// This prevents infinite rendering loop.
...(state.overflow ? { overflow: "hidden" } : {}),
overflow: state.overflow && !autoScrollbar ? "hidden" : undefined,
...style,
}}
{...other}
@@ -250,12 +267,12 @@ const TextareaAutosize = forwardRef<HTMLTextAreaElement, TextareaAutosizeProps>(
}
);
function isEmpty(obj: any) {
function isEmpty(obj: State) {
return (
obj === undefined ||
obj === null ||
Object.keys(obj).length === 0 ||
(obj?.outerHeightStyle === 0 && !obj?.overflow)
(obj.outerHeightStyle === 0 && !obj.overflow)
);
}
+8
View File
@@ -1,5 +1,13 @@
# @navikt/ds-tailwind
## 5.11.2
## 5.11.1
## 5.11.0
## 5.10.4
## 5.10.3
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tailwind",
"version": "5.10.3",
"version": "5.11.2",
"description": "Tailwind config based on @navikt/ds-tokens",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -24,7 +24,7 @@
"directory": "@navikt/core/tailwind"
},
"devDependencies": {
"@navikt/ds-tokens": "^5.10.3",
"@navikt/ds-tokens": "^5.11.2",
"@types/jest": "^29.0.0",
"color": "4.2.3",
"jest": "^29.0.0",
+8
View File
@@ -1,5 +1,13 @@
# @navikt/ds-tokens
## 5.11.2
## 5.11.1
## 5.11.0
## 5.10.4
## 5.10.3
## 5.10.2
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tokens",
"version": "5.10.3",
"version": "5.11.2",
"description": "Design-tokens for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
+101 -71
View File
@@ -1,24 +1,50 @@
# Changelog
## 5.11
### @navikt/ds-react
- ⬆️ upgrade date-fns version & make it minor-version agnostic ([#2514](https://github.com/navikt/aksel/pull/2514))
* Switch: Byttet success-farger med action npr checked ([#2511](https://github.com/navikt/aksel/pull/2511))
- :sparkles: Textarea: Mulighet for å sette resize-retning ([#2494](https://github.com/navikt/aksel/pull/2494))
- :sparkles: Textarea: Eksperimentell støtte for automatisk scrollbar ([#2457](https://github.com/navikt/aksel/pull/2457))
* :wheelchair: Textarea: Forsinkelse ved live-opplesning av gjenstående tegn ([#2502](https://github.com/navikt/aksel/pull/2502))
### @navikt/ds-css
- Switch: Byttet success-farger med action npr checked ([#2511](https://github.com/navikt/aksel/pull/2511))
* :sparkles: Textarea: Mulighet for å sette resize-retning ([#2494](https://github.com/navikt/aksel/pull/2494))
* :sparkles: Textarea: Eksperimentell støtte for automatisk scrollbar ([#2457](https://github.com/navikt/aksel/pull/2457))
- :wheelchair: Textarea: Forsinkelse ved live-opplesning av gjenstående tegn ([#2502](https://github.com/navikt/aksel/pull/2502))
### @navikt/aksel-icons
- Ikoner: Nytt ikon `PushPin` ([#2503](https://github.com/navikt/aksel/pull/2503))
## 5.10
### @navikt/ds-react
- :wheelchair: Textarea: Byttet fra `aria-live` til `role=status` på telleren for bedre semantikk ([#2483](https://github.com/navikt/aksel/pull/2483))
- Gjør lukknapp i Alert til type button ([#2497](https://github.com/navikt/aksel/pull/2497))
- :bug: Textarea: Teller flyttet ut av tekstfeltet for å unngå overlapp og misforståelser ([#2483](https://github.com/navikt/aksel/pull/2483))
* :wheelchair: Textarea: Byttet fra `aria-live` til `role=status` på telleren for bedre semantikk ([#2483](https://github.com/navikt/aksel/pull/2483))
- ErrorSummary: Gjør det mulig å rendre ErrorSummary.Item conditionally ([#2484](https://github.com/navikt/aksel/pull/2484))
* :bug: Textarea: Teller flyttet ut av tekstfeltet for å unngå overlapp og misforståelser ([#2483](https://github.com/navikt/aksel/pull/2483))
* OverridableComponent: Fungerer nå bedre ved bruk av typeof <komponent> ([#2474](https://github.com/navikt/aksel/pull/2474))
* ErrorSummary: Gjør det mulig å rendre ErrorSummary.Item conditionally ([#2484](https://github.com/navikt/aksel/pull/2484))
- Table: Håndterer nå sjekk for interaktive elementer i ExpandableRow bedre ([#2461](https://github.com/navikt/aksel/pull/2461))
- OverridableComponent: Fungerer nå bedre ved bruk av typeof <komponent> ([#2474](https://github.com/navikt/aksel/pull/2474))
* Primitives: Ny komponent `Page` og `Page.Block` ([#2456](https://github.com/navikt/aksel/pull/2456))
* Table: Håndterer nå sjekk for interaktive elementer i ExpandableRow bedre ([#2461](https://github.com/navikt/aksel/pull/2461))
### @navikt/ds-tailwind
- typescript types for tailwind preset ([#2486](https://github.com/navikt/aksel/pull/2486))
- Primitives: Ny komponent `Page` og `Page.Block` ([#2456](https://github.com/navikt/aksel/pull/2456))
### @navikt/ds-css
@@ -28,6 +54,10 @@
- Primitives: Ny komponent `Page` og `Page.Block` ([#2456](https://github.com/navikt/aksel/pull/2456))
### @navikt/ds-tailwind
- typescript types for tailwind preset ([#2486](https://github.com/navikt/aksel/pull/2486))
## 5.9
### @navikt/ds-react
@@ -74,10 +104,6 @@
## 5.7
### @navikt/aksel-icons
- Ikoner: Nye ikoner `ChevronLeftFirstCircle` og `ChevronRightLastCircle` ([#2365](https://github.com/navikt/aksel/pull/2365))
### @navikt/ds-react
- :lipstick: Chips.Toggle: Ikon i uvalgt tilstand ([#2395](https://github.com/navikt/aksel/pull/2395))
@@ -118,15 +144,11 @@
- Ny spacing token på 0.375rem ([#2370](https://github.com/navikt/aksel/pull/2370))
## 5.6
### @navikt/aksel-icons
- Ikoner: SVG export setter nå `height="1em"`, `width="1em"` og `fill="currentColor"`. ([#2300](https://github.com/navikt/aksel/pull/2300))
- Ikoner: Nye ikoner `ChevronLeftFirstCircle` og `ChevronRightLastCircle` ([#2365](https://github.com/navikt/aksel/pull/2365))
- Ikoner: Nye ikoner `book` og `books` ([#2313](https://github.com/navikt/aksel/pull/2313))
* Ikoner: Nye ikoner `ClipboardCheckmark` og `ClipboardLink` ([#2307](https://github.com/navikt/aksel/pull/2307))
## 5.6
### @navikt/ds-react
@@ -178,6 +200,14 @@
- Tokens: Tilbyr nå token literals for typer, tidligere string literals ([#2342](https://github.com/navikt/aksel/pull/2342))
### @navikt/aksel-icons
- Ikoner: SVG export setter nå `height="1em"`, `width="1em"` og `fill="currentColor"`. ([#2300](https://github.com/navikt/aksel/pull/2300))
- Ikoner: Nye ikoner `book` og `books` ([#2313](https://github.com/navikt/aksel/pull/2313))
* Ikoner: Nye ikoner `ClipboardCheckmark` og `ClipboardLink` ([#2307](https://github.com/navikt/aksel/pull/2307))
## 5.5
### @navikt/ds-react
@@ -218,10 +248,6 @@
## 5.3
### @navikt/aksel-icons
- :bug: SVG import map er nå riktig path ([#2250](https://github.com/navikt/aksel/pull/2250))
### @navikt/ds-react
- :bug: Popover: sjekk at det er et HTML-element som får fokus ([#2258](https://github.com/navikt/aksel/pull/2258))
@@ -258,11 +284,11 @@
- Typography: Oppdatert med typo-klasser for `textColor`, `weight`, `align`, `visuallyHidden` og `truncated`. ([#2211](https://github.com/navikt/aksel/pull/2211))
## 5.2
### @navikt/aksel-icons
- Ikoner: Oppdatert ikonpakke ([#2197](https://github.com/navikt/aksel/pull/2197))
- :bug: SVG import map er nå riktig path ([#2250](https://github.com/navikt/aksel/pull/2250))
## 5.2
### @navikt/ds-react
@@ -280,6 +306,10 @@
* Hovering over combobox dropdown will move selection/focus in the list, so we don't end up with a split focus, and reversely when moving focus while hovering ([#2193](https://github.com/navikt/aksel/pull/2193))
### @navikt/aksel-icons
- Ikoner: Oppdatert ikonpakke ([#2197](https://github.com/navikt/aksel/pull/2197))
## 5.1
### @navikt/ds-react
@@ -495,18 +525,18 @@
* Fikset klassenavn brukt for popover i Datepicker og Monthpicker ([PR](https://github.com/navikt/aksel/pull/2041))
### @navikt/ds-tailwind
- Shadow-tokens er oppdatert ([PR](https://github.com/navikt/aksel/pull/2041))
- Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600). ([PR](https://github.com/navikt/aksel/pull/2036))
### @navikt/ds-css
- :lipstick: Chat: fjernet border, satt avatar svg til 24x24px, byttet om "subtle" og "neutral" ([#2077](https://github.com/navikt/aksel/pull/2077))
* Shadow-tokens er oppdatert: Datepicker har nå ikke border, Modal bruker shadow-xlarge, LinkCard bruker shadow-xsmall ([PR](https://github.com/navikt/aksel/pull/2041))
### @navikt/ds-tailwind
- Shadow-tokens er oppdatert ([PR](https://github.com/navikt/aksel/pull/2041))
- Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600). ([PR](https://github.com/navikt/aksel/pull/2036))
### @navikt/ds-tokens
- Shadow-tokens er oppdatert til mer tydeligere varianter ([PR](https://github.com/navikt/aksel/pull/2041))
@@ -539,10 +569,6 @@
- Deprecated klassenavn `navds-chips--icon-left` ([PR](https://github.com/navikt/aksel/pull/2035))
### @navikt/aksel-icons
- Nye ikoner `ChevronRightLast` og `ChevronLeftLast` ([PR](https://github.com/navikt/aksel/pull/2054))
### @navikt/ds-react
- Fikset JSDom-problemer ved testing av Timeline
@@ -567,10 +593,6 @@
- Accordion: La til `indent`-prop ([PR](https://github.com/navikt/aksel/pull/2027))
### @navikt/ds-tailwind
- :tada: Fargetokens for datavisualisering. ([PR](https://github.com/navikt/aksel/pull/2032))
### @navikt/ds-css
- Readmore: setter nå eksplisitt color for å ikke arve text-subtle fra parent. ([PR](https://github.com/navikt/aksel/pull/2049))
@@ -581,12 +603,20 @@
- Alle description-felter på fieldsets har nå `text-subtle` som farge. ([PR](https://github.com/navikt/aksel/pull/2036))
### @navikt/ds-tailwind
- :tada: Fargetokens for datavisualisering. ([PR](https://github.com/navikt/aksel/pull/2032))
### @navikt/ds-tokens
- :tada: Fargetokens for datavisualisering. ([PR](https://github.com/navikt/aksel/pull/2032))
- Oppdatert text-subtle og icon-subtle tokens til 700-skala (tidligere 600). ([PR](https://github.com/navikt/aksel/pull/2036))
### @navikt/aksel-icons
- Nye ikoner `ChevronRightLast` og `ChevronLeftLast` ([PR](https://github.com/navikt/aksel/pull/2054))
## 4.0
### @navikt/aksel
@@ -639,10 +669,6 @@
## 3.2
### @navikt/aksel-icons
- Nye ikoner `FileParagraph` og `FilePlus` ([PR](https://github.com/navikt/aksel/pull/1998))
### @navikt/ds-react
- Search: Støtter nå htmlSize-prop ([PR](https://github.com/navikt/aksel/pull/2000))
@@ -661,6 +687,10 @@
- CopyButton: `xsmall`-size for bruk i tabeller ([PR](https://github.com/navikt/aksel/pull/1994))
### @navikt/aksel-icons
- Nye ikoner `FileParagraph` og `FilePlus` ([PR](https://github.com/navikt/aksel/pull/1998))
## 3.1
### @navikt/ds-react
@@ -693,16 +723,6 @@
## 2.9
### @navikt/aksel-icons
- Oppdatert Statusikoner til å være tydeligere og mer konsistente. ([PR](https://github.com/navikt/aksel/pull/1959))
* Fikset `CheckmarkIcon`-bug
- Fikset `CheckmarkCircleIcon`-bug ([PR](https://github.com/navikt/aksel/pull/1956))
* Nye ikoner `BulletList` og `NumberList` ([PR](https://github.com/navikt/aksel/pull/1950))
### @navikt/aksel
- :truck: Flyttet Codemods fra `@navikt/ds-codemods` -> `@navikt/aksel`. `@navikt/ds-codemods` regnes nå som deprecated ([PR](https://github.com/navikt/aksel/pull/1952))
@@ -715,19 +735,17 @@
- CSS nå tilgjengelig som separate filer: Kan lastest fra CDN, minified-versjoner tilgjengelig ([PR](https://github.com/navikt/aksel/pull/1941))
## 2.8
### @navikt/aksel-icons
- :tada: Nye ikoner `HandKnot` og `HandKnotFilled` ([PR](https://github.com/navikt/aksel/pull/1928))
- Oppdatert Statusikoner til å være tydeligere og mer konsistente. ([PR](https://github.com/navikt/aksel/pull/1959))
* Oppdatert `InformationSquare`-ikon ([PR](https://github.com/navikt/aksel/pull/1921))
* Fikset `CheckmarkIcon`-bug
- Oppdatert `VideoSlack`, `Questionmark` og `Information`-ikoner ([PR](https://github.com/navikt/aksel/pull/1909))
- Fikset `CheckmarkCircleIcon`-bug ([PR](https://github.com/navikt/aksel/pull/1956))
* Nye ikoner `VideoSlash` og `VideoSlashFill`
* Nye ikoner `BulletList` og `NumberList` ([PR](https://github.com/navikt/aksel/pull/1950))
- Fikset Sourcemap-bug
## 2.8
### @navikt/ds-react
@@ -763,8 +781,26 @@
- ExpansioCard: Oppdatert typografi ([PR](https://github.com/navikt/aksel/pull/1870))
### @navikt/aksel-icons
- :tada: Nye ikoner `HandKnot` og `HandKnotFilled` ([PR](https://github.com/navikt/aksel/pull/1928))
* Oppdatert `InformationSquare`-ikon ([PR](https://github.com/navikt/aksel/pull/1921))
- Oppdatert `VideoSlack`, `Questionmark` og `Information`-ikoner ([PR](https://github.com/navikt/aksel/pull/1909))
* Nye ikoner `VideoSlash` og `VideoSlashFill`
- Fikset Sourcemap-bug
## 2.7
### @navikt/ds-css
- Tabs: La til focus-markering for Tabs.Panel ([PR](https://github.com/navikt/aksel/pull/1863))
* ToggleGroup: Fikset token-bug
### @navikt/aksel-icons
- Nye ikoner `CaretUpDownFilledDown`, `CaretUpDownFilledUp`, `CloudDown`, `CloudDownFill`, `CloudUp`, `CloudUpFill`, `HddDown`, `HddDownFill`, `HddUp`, `HddUpFill`, `Inbox`, `InboxDown`, `InboxDownFill`, `InboxFill`, `InboxUp`, `InboxUpFill`, `ShoppingBasket`, `ShoppingBasketFill`
@@ -773,12 +809,6 @@
- Ny ikonpakke med for core icons 3! `@navikt/aksel-icons` ([PR](https://github.com/navikt/aksel/pull/1847))
### @navikt/ds-css
- Tabs: La til focus-markering for Tabs.Panel ([PR](https://github.com/navikt/aksel/pull/1863))
* ToggleGroup: Fikset token-bug
## 2.6
### @navikt/ds-react
@@ -893,10 +923,6 @@
* Fonter blir bruk i all typografi blir nå lastet fra CDN
### @navikt/ds-tailwind
- Alle token er oppdatert til nytt format. ([Guide](https://aksel.nav.no/grunnleggende/kode/migrering#h76f47744d112))
### @navikt/ds-css
- Radio: Fikset default visuell error-state ([PR](https://github.com/navikt/aksel/pull/1737))
@@ -909,6 +935,10 @@
* Tokens: Alle komponenter bruker nå semantiske tokens for som standard, med innebygd støtte for komponent-spesifikke tokens.
### @navikt/ds-tailwind
- Alle token er oppdatert til nytt format. ([Guide](https://aksel.nav.no/grunnleggende/kode/migrering#h76f47744d112))
### @navikt/ds-tokens
- Alle token er oppdatert til nytt format. ([Guide](https://aksel.nav.no/grunnleggende/kode/migrering#h76f47744d112))
+5 -5
View File
@@ -16,11 +16,11 @@
"playroom"
],
"dependencies": {
"@navikt/aksel-icons": "^5.10.3",
"@navikt/ds-css": "^5.10.3",
"@navikt/ds-react": "^5.10.3",
"@navikt/ds-tailwind": "^5.10.3",
"@navikt/ds-tokens": "^5.10.3"
"@navikt/aksel-icons": "^5.11.2",
"@navikt/ds-css": "^5.11.2",
"@navikt/ds-react": "^5.11.2",
"@navikt/ds-tailwind": "^5.11.2",
"@navikt/ds-tokens": "^5.11.2"
},
"devDependencies": {
"prettier-plugin-tailwindcss": "^0.2.3"
+2 -1
View File
@@ -12,7 +12,8 @@ module.exports = {
// Optional:
title: "Aksel Sandbox",
snippets: path.resolve("./src/snippets.ts"),
widths: [480, 768, 1024, 1280],
widths: [320, 480, 768, 1024, 1280, 1440],
defaultWidths: [320, 1280], // will be supported if this PR is merged: https://github.com/seek-oss/playroom/pull/302
port: 9000,
frameComponent: path.resolve("./src/FrameComponent.tsx"),
useScope: path.resolve("./src/useScope.tsx"),
@@ -40,7 +40,7 @@ const Header = ({
return (
<header
className={cl("z-20", {
"bg-[#FEFCE9]": variant === "blogg",
"bg-amber-50": variant === "blogg",
"bg-surface-default": variant === "default",
"bg-surface-subtle": variant === "subtle",
"bg-surface-transparent": variant === "transparent",
@@ -27,7 +27,7 @@ const Element = ({ block }: { block: DoDontT["blokker"][number] }) => {
<BodyShort
as="span"
className={cl(
"relative z-[-1] flex items-center gap-1 rounded-t-lg px-4 py-2",
"text-text-default relative z-[-1] flex items-center gap-1 rounded-t-lg px-4 py-2",
{
"bg-surface-success-moderate": block.variant === "do",
"bg-surface-danger-moderate": block.variant === "dont",
@@ -1,4 +1,5 @@
import ErrorBoundary from "@/error-boundary";
import { useFormatedDate } from "@/hooks/useFormatedDate";
import { amplitudeLogNavigation } from "@/logging";
import { urlFor } from "@/sanity/interface";
import { abbrName, getImage } from "@/utils";
@@ -7,7 +8,6 @@ import cl from "clsx";
import NextImage from "next/legacy/image";
import NextLink from "next/link";
import { Tag } from "./Tag";
import { useFormatedDate } from "@/hooks/useFormatedDate";
export type ArticleT = {
_key: string;
@@ -71,7 +71,13 @@ const Card = ({ article, visible, index }: CardProps) => {
{article.status?.bilde ?? article.seo?.image ? (
article.status?.bilde ? (
<NextImage
src={urlFor(article.status?.bilde).auto("format").url()}
src={urlFor(article.status.bilde).auto("format").url()}
blurDataURL={urlFor(article.status.bilde)
.width(24)
.height(24)
.blur(10)
.url()}
placeholder="blur"
width="200"
height="200"
alt={article.heading + " thumbnail"}
@@ -81,6 +87,12 @@ const Card = ({ article, visible, index }: CardProps) => {
<div className="relative h-[200px] w-full">
<NextImage
src={urlFor(article.seo?.image).auto("format").url()}
blurDataURL={urlFor(article.seo?.image)
.width(24)
.height(24)
.blur(10)
.url()}
placeholder="blur"
layout="fill"
objectFit="cover"
alt={article.heading + " thumbnail"}
@@ -1,3 +1,4 @@
import { useFormatedDate } from "@/hooks/useFormatedDate";
import { amplitudeLogNavigation } from "@/logging";
import { urlFor } from "@/sanity/interface";
import { getAuthors, getImage } from "@/utils";
@@ -7,7 +8,6 @@ import Image from "next/legacy/image";
import NextLink from "next/link";
import { ArticleT } from "./Card";
import { Tag } from "./Tag";
import { useFormatedDate } from "@/hooks/useFormatedDate";
export const Highlight = ({
article,
@@ -35,6 +35,12 @@ export const Highlight = ({
{useStatusImage ? (
<Image
src={urlFor(article.status.bilde).quality(100).auto("format").url()}
blurDataURL={urlFor(article.status.bilde)
.width(24)
.height(24)
.blur(10)
.url()}
placeholder="blur"
quality={100}
layout="fill"
aria-hidden
@@ -49,6 +55,12 @@ export const Highlight = ({
) : article?.seo?.image ? (
<Image
src={urlFor(article.seo.image).quality(100).auto("format").url()}
blurDataURL={urlFor(article.seo.image)
.width(24)
.height(24)
.blur(10)
.url()}
placeholder="blur"
quality={100}
layout="fill"
objectFit="cover"
@@ -18,9 +18,9 @@ const RelatertInnhold = ({ node }: RelatertInnholdProps) => {
x?.intern ? `/${x.intern_lenke}` : x.ekstern_link;
return (
<div className="ring-border-subtle toc-ignore bg-surface-neutral-subtle my-7 max-w-2xl rounded-lg p-4 ring-1 ring-inset sm:p-6">
<div className="ring-border-subtle toc-ignore bg-surface-neutral-subtle my-7 max-w-2xl rounded-lg p-4 ring-1 ring-inset dark:bg-gray-800 sm:p-6">
<Heading
className="override-text-no-max text-text-subtle flex items-center gap-2"
className="override-text-no-max text-text-subtle dark:text-text-on-inverted flex items-center gap-2"
size="small"
as="p"
spacing
@@ -40,7 +40,7 @@ const RelatertInnhold = ({ node }: RelatertInnholdProps) => {
e.currentTarget.getAttribute("href")
)
}
className="text-xl font-semibold text-gray-800"
className="dark:text-text-on-inverted text-xl font-semibold text-gray-800"
>
{x.title}
</Link>
@@ -1,5 +1,6 @@
import { SANITY_PROJECT_ID } from "@/sanity/config";
import { AkselTheme, getKey } from "@/sb-util";
import type { Meta, StoryObj } from "@storybook/react";
import { getKey, AkselTheme } from "@/sb-util";
import Video from "./Video";
const meta = {
@@ -18,7 +19,7 @@ const args = {
caption: "caption-tekst",
transkripsjon: "Transkripsjonstekst",
webm: {
url: "https://cdn.sanity.io/files/hnbe3yhs/production/274a2ceb69b056e1a7048ad1a5a2f8deff53a2f4.webm",
url: `https://cdn.sanity.io/files/${SANITY_PROJECT_ID}/production/274a2ceb69b056e1a7048ad1a5a2f8deff53a2f4.webm`,
extension: "WEBM",
},
},
@@ -1,7 +1,7 @@
const InlineCode = (
props: React.HTMLAttributes<HTMLElement> & { noAmps?: boolean }
) => (
<code className="text-deepblue-800 font-mono text-sm font-semibold leading-normal before:contents">
<code className="text-deepblue-800 dark:text-deepblue-300 font-mono text-sm font-semibold leading-normal before:contents">
{!props?.noAmps && (
<span aria-hidden className="inline-code-amp">
`
@@ -19,6 +19,12 @@ export const HighlightedBlogg = ({
{blogg?.seo?.image ? (
<Image
src={urlFor(blogg.seo.image).quality(100).auto("format").url()}
blurDataURL={urlFor(blogg.seo.image)
.width(24)
.height(24)
.blur(10)
.url()}
placeholder="blur"
quality={100}
layout="fill"
objectFit="cover"
@@ -62,6 +68,12 @@ export const HighlightedBlogg = ({
{blogg?.seo?.image ? (
<Image
src={urlFor(blogg.seo.image).quality(100).auto("format").url()}
blurDataURL={urlFor(blogg.seo.image)
.width(24)
.height(24)
.blur(10)
.url()}
placeholder="blur"
quality={100}
layout="fill"
objectFit="cover"
@@ -10,18 +10,17 @@ import cl from "clsx";
import { ComponentType, useEffect, useState } from "react";
import styles from "./examples.module.css";
type withDsT = {
variant?: "full" | "inverted" | "static" | "subtle";
showBreakpoints?: boolean;
};
export const withDsExample = (
Component: ComponentType,
/**
* Static: Used for dynamic-height examples like ExpansionCard
*/
{
variant,
showBreakpoints,
}: {
variant?: "full" | "inverted" | "static" | "subtle";
showBreakpoints?: boolean;
} = {}
{ variant, showBreakpoints }: withDsT = {}
) => {
const DsHOC = (props: any) => {
const [width, setWidth] = useState<number>();
@@ -57,7 +56,12 @@ export const withDsExample = (
breakpoint = "xl";
}
return (
<HStack gap="1" className="absolute left-2 top-1" align="center">
<HStack
gap="05"
className="rounded-br-medium absolute left-0 top-0 p-1"
align="center"
style={{ background: getBg(variant) }}
>
<Icon aria-hidden fontSize="1.5rem" /> {`${breakpoint}`}
</HStack>
);
@@ -66,12 +70,12 @@ export const withDsExample = (
return (
<div
className={cl(styles.examples, {
"bg-gray-900": variant === "inverted",
"bg-bg-subtle": variant === "subtle",
[styles.containerStatic]: variant === "static",
[styles.container]: variant !== "static",
})}
style={{ background: getBg(variant) }}
>
<style global>{`html {scrollbar-gutter: unset;}`}</style>
{showBreakpoints && <BreakpointText />}
<div
id="ds-example"
@@ -91,3 +95,15 @@ export const withDsExample = (
return DsHOC;
};
function getBg(variant: withDsT["variant"]): string {
switch (variant) {
case "inverted":
return "var(--a-surface-inverted)";
case "subtle":
return "var(--a-bg-subtle)";
default:
return "var(--a-bg-default)";
}
}
@@ -52,7 +52,7 @@ function UlList({
className="whitespace-break-spaces"
weight={isActive(node.id) ? "semibold" : "regular"}
>
{removeEmojies(node.title)}
{removeEmojies(node.title).trim()}
</BodyShort>
</a>
{!nested && node.children.length > 0 && (
+10
View File
@@ -19,6 +19,16 @@ export async function middleware(req: NextRequest) {
return NextResponse.next();
}
const url = req.nextUrl.clone();
if (
url.pathname.startsWith("/sandbox") &&
!url.pathname.includes("index.html") &&
!url.pathname.match(/(\..*)$/)
) {
url.pathname = url.pathname + "/index.html";
return NextResponse.redirect(url);
}
try {
const redirect = await sanityClient.fetch(
`
+9 -9
View File
@@ -34,16 +34,16 @@
"dependencies": {
"@amplitude/analytics-browser": "^2.2.3",
"@portabletext/react": "^3.0.11",
"@sanity/client": "^6.6.0",
"@sanity/client": "^6.8.6",
"@sanity/code-input": "4.1.1",
"@sanity/color-input": "^3.1.0",
"@sanity/image-url": "1.0.2",
"@sanity/table": "1.0.1",
"@sanity/vision": "3.18.0",
"@sanity/vision": "3.20.0",
"boring-avatars": "1.10.1",
"clsx": "^1.2.1",
"codesandbox": "^2.2.3",
"date-fns": "2.29.3",
"date-fns": "^2.30.0",
"fuse.js": "^6.6.2",
"jscodeshift": "^0.15.1",
"lodash": "^4.17.21",
@@ -57,10 +57,10 @@
"react-dom": "^18.0.0",
"react-hotjar": "^6.1.0",
"react-responsive-masonry": "^2.1.7",
"sanity": "3.18.0",
"sanity-plugin-asset-source-unsplash": "^1.1.1",
"sanity-plugin-media": "^2.2.2",
"sharp": "0.32.5",
"sanity": "3.20.0",
"sanity-plugin-asset-source-unsplash": "^1.1.2",
"sanity-plugin-media": "^2.2.4",
"sharp": "0.32.6",
"styled-components": "^6.0.0",
"swr": "^1.1.2",
"tailwindcss": "^3.3.3",
@@ -72,8 +72,8 @@
"@next/bundle-analyzer": "13.2.1",
"@next/eslint-plugin-next": "13.2.1",
"@playwright/test": "1.35.1",
"@sanity/block-tools": "^3.18.0",
"@sanity/schema": "^3.18.0",
"@sanity/block-tools": "^3.20.0",
"@sanity/schema": "^3.20.0",
"@testing-library/jest-dom": "^5.16.0",
"@testing-library/react": "^13.3.0",
"@types/jest": "^29.0.0",
@@ -1,3 +1,4 @@
import cl from "clsx";
import { NextStudio } from "next-sanity/studio";
import { useEffect, useState } from "react";
import { workspaceConfig } from "../../sanity/sanity.config";
@@ -20,7 +21,9 @@ const StudioPage = () => {
return (
<div
data-theme={scheme}
className="aksel-admin h-full min-h-screen"
className={cl("aksel-admin h-full min-h-screen", {
dark: scheme === "dark",
})}
id="sanity-wrapper"
>
<NextStudio
@@ -15,5 +15,6 @@ export const Demo = {
};
export const args = {
index: 0,
index: 4,
desc: "Brukes til å informere brukere om at noe kritisk har skjedd og vil kreve umiddelbar oppmerksomhet.",
};
@@ -30,5 +30,5 @@ export const Demo = {
};
export const args = {
index: 2,
index: 8,
};
@@ -19,5 +19,6 @@ export const Demo = {
};
export const args = {
index: 0,
index: 2,
desc: "Skal formidle ren informasjon",
};
@@ -30,5 +30,6 @@ export const Demo = {
};
export const args = {
index: 3,
index: 9,
desc: "Bruk inline om varselet er en del av annet innhold eller når panelet og bakgrunnsfarge blir støy for brukeren.",
};
@@ -32,5 +32,5 @@ export const Demo = {
};
export const args = {
index: 0,
index: 10,
};
@@ -22,5 +22,6 @@ export const Demo = {
};
export const args = {
index: 4,
index: 7,
desc: "Husk riktig h-tag ved bruk av heading i Alert",
};
@@ -49,5 +49,5 @@ export const Demo = {
};
export const args = {
index: 1,
index: 6,
};
@@ -1,24 +1,16 @@
import { withDsExample } from "@/web/examples/withDsExample";
import { Alert } from "@navikt/ds-react";
import { Alert, VStack } from "@navikt/ds-react";
const Example = () => {
return (
<div className="grid gap-4">
<Alert size="small" variant="info">
Hvis du er mellom 62 og 67 år når du søker, må du som hovedregel ha hatt
en pensjonsgivende inntekt som tilsvarer x G, året før du fikk nedsatt
arbeidsevnen.
</Alert>
<VStack gap="4" align="center">
<Alert size="small" variant="success">
Søknad er sendt inn!
</Alert>
<Alert size="small" variant="warning">
Du må være registrert hos NAV for å bruke aktivitetsplanen.
<Alert size="small" variant="success" inline>
Søknad er sendt inn!
</Alert>
<Alert size="small" variant="error">
Noe gikk galt! Prøv igjen om noen minutter.
</Alert>
</div>
</VStack>
);
};
@@ -30,5 +22,5 @@ export const Demo = {
};
export const args = {
index: 1,
index: 5,
};
@@ -13,5 +13,6 @@ export const Demo = {
};
export const args = {
index: 0,
index: 1,
desc: "Bekrefter at en oppgave er fullført som forventet.",
};
@@ -17,5 +17,6 @@ export const Demo = {
};
export const args = {
index: 0,
index: 3,
desc: "Bruk denne når du vil at brukeren skal foreta en bestemt handling eller for å advare dem om noe viktig.",
};
@@ -1,5 +1,5 @@
import { withDsExample } from "@/web/examples/withDsExample";
import { ConfirmationPanel } from "@navikt/ds-react";
import { ConfirmationPanel, Heading } from "@navikt/ds-react";
import { useState } from "react";
const Example = () => {
@@ -7,11 +7,12 @@ const Example = () => {
return (
<ConfirmationPanel
checked={state}
label="Ja, jeg samtykker."
label="Jeg bekrefter at jeg vil svare så godt jeg kan på spørsmålene i søknaden."
onChange={() => setState((x) => !x)}
>
For å komme videre må du gi oss lov til å hente inn og bruke opplysninger
om deg.
<Heading level="2" size="xsmall">
Vi stoler på deg
</Heading>
</ConfirmationPanel>
);
};
@@ -1,5 +1,5 @@
import { withDsExample } from "@/web/examples/withDsExample";
import { ConfirmationPanel } from "@navikt/ds-react";
import { ConfirmationPanel, Heading } from "@navikt/ds-react";
import { useState } from "react";
const Example = () => {
@@ -7,12 +7,13 @@ const Example = () => {
return (
<ConfirmationPanel
checked={state}
label="Ja, jeg samtykker."
label="Jeg bekrefter at jeg vil svare så godt jeg kan på spørsmålene i søknaden."
onChange={() => setState((x) => !x)}
error={!state && "Du må samtykke før du kan fortsette."}
error={!state && "Du må bekrefte før du kan fortsette."}
>
For å komme videre må du gi oss lov til å hente inn og bruke opplysninger
om deg.
<Heading level="2" size="xsmall">
Vi stoler på deg
</Heading>
</ConfirmationPanel>
);
};
@@ -1,5 +1,5 @@
import { withDsExample } from "@/web/examples/withDsExample";
import { ConfirmationPanel } from "@navikt/ds-react";
import { ConfirmationPanel, Heading } from "@navikt/ds-react";
import { useState } from "react";
const Example = () => {
@@ -7,12 +7,13 @@ const Example = () => {
return (
<ConfirmationPanel
checked={state}
label="Ja, jeg samtykker."
label="Jeg bekrefter at jeg vil svare så godt jeg kan på spørsmålene i søknaden."
onChange={() => setState((x) => !x)}
size="small"
>
For å komme videre må du gi oss lov til å hente inn og bruke opplysninger
om deg.
<Heading level="2" size="xsmall">
Vi stoler på deg
</Heading>
</ConfirmationPanel>
);
};
@@ -26,4 +27,5 @@ export const Demo = {
export const args = {
index: 1,
desc: "Small brukes på interne flater der det er behov for et mer komprimert grensesnitt.",
};
@@ -10,7 +10,9 @@ const Example = () => {
<Divider />
<div>
<Descriptor>Spacing </Descriptor>
<Heading size="large">{lorem}</Heading>
<Heading size="large" spacing>
{lorem}
</Heading>
</div>
</VStack>
);
@@ -10,7 +10,9 @@ const Example = () => {
<Divider />
<div>
<Descriptor>Spacing </Descriptor>
<Heading size="medium">{lorem}</Heading>
<Heading size="medium" spacing>
{lorem}
</Heading>
</div>
</VStack>
);
@@ -10,7 +10,9 @@ const Example = () => {
<Divider />
<div>
<Descriptor>Spacing </Descriptor>
<Heading size="small">{lorem}</Heading>
<Heading size="small" spacing>
{lorem}
</Heading>
</div>
</VStack>
);
@@ -10,7 +10,9 @@ const Example = () => {
<Divider />
<div>
<Descriptor>Spacing</Descriptor>
<Heading size="xlarge">{lorem}</Heading>
<Heading size="xlarge" spacing>
{lorem}
</Heading>
</div>
</VStack>
);
@@ -10,7 +10,9 @@ const Example = () => {
<Divider />
<div>
<Descriptor>Spacing </Descriptor>
<Heading size="xsmall">{lorem}</Heading>
<Heading size="xsmall" spacing>
{lorem}
</Heading>
</div>
</VStack>
);
@@ -7,8 +7,12 @@ const Example = () => {
return (
<div>
<Label spacing>{lorem}</Label>
<Label spacing>{lorem}</Label>
<Label spacing as="p">
{lorem}
</Label>
<Label spacing as="p">
{lorem}
</Label>
</div>
);
};
@@ -7,10 +7,10 @@ const Example = () => {
return (
<div>
<Label size="small" spacing>
<Label size="small" spacing as="p">
{lorem}
</Label>
<Label size="small" spacing>
<Label size="small" spacing as="p">
{lorem}
</Label>
</div>
@@ -0,0 +1,40 @@
import { withDsExample } from "@/web/examples/withDsExample";
import { Link } from "@navikt/ds-react";
import NextLink from "next/link";
const Example = () => (
<Link as={NextLink} href="#">
Lenke til ny side
</Link>
);
/*
import { Link as ReactRouterLink } from "react-router-dom";
const ReactRouterExample = () => (
<Link as={ReactRouterLink} to="#">
Lenke til ny side
</Link>
);
import { Link as RemixLink } from "@remix-run/react";
const RemixExample = () => (
<Link as={RemixLink} to="#">
Lenke til ny side
</Link>
);
*/
export default withDsExample(Example);
/* Storybook story */
export const Demo = {
render: Example,
};
export const args = {
index: 5,
desc: "Bruk 'as'-propen hvis du bruker et rammeverk som har sin egen link-komponent.",
sandbox: false,
};
@@ -27,4 +27,5 @@ export const Demo = {
export const args = {
index: 1,
desc: "Prop-en 'inlineText' gjør at teksten wrapper.",
};
@@ -1,23 +0,0 @@
import { withDsExample } from "@/web/examples/withDsExample";
import { Link } from "@navikt/ds-react";
import NextLink from "next/link";
const Example = () => {
return (
<Link href="#" as={NextLink}>
Lenke til ny side
</Link>
);
};
export default withDsExample(Example);
/* Storybook story */
export const Demo = {
render: Example,
};
export const args = {
index: 5,
sandbox: false,
};
@@ -1,25 +0,0 @@
import { withDsExample } from "@/web/examples/withDsExample";
import { BodyLong, Link } from "@navikt/ds-react";
const Example = () => {
return (
<BodyLong>
Officia incididunt{" "}
<Link href="#" underline={false}>
lenke til ny side
</Link>{" "}
occaecat commodo id ad aliquip.
</BodyLong>
);
};
export default withDsExample(Example);
/* Storybook story */
export const Demo = {
render: Example,
};
export const args = {
index: 4,
};
@@ -1,19 +1,19 @@
import { withDsExample } from "@/web/examples/withDsExample";
import { Link } from "@navikt/ds-react";
import { Link, VStack } from "@navikt/ds-react";
const Example = () => {
return (
<div className="colgap">
{["action", "neutral", "subtle"].map((variant) => (
<>
<div>
<Link variant={variant as "action" | "neutral" | "subtle"}>
Ex aliqua incididunt
</Link>
</div>
</>
))}
</div>
<VStack gap="3">
<Link href="#" variant="action">
Action variant
</Link>
<Link href="#" variant="neutral">
Neutral variant
</Link>
<Link href="#" variant="subtle">
Subtle variant
</Link>
</VStack>
);
};
@@ -26,4 +26,5 @@ export const Demo = {
export const args = {
index: 2,
desc: "Ikke bruk action-varianten på farget bakgrunn.",
};
@@ -5,22 +5,28 @@ const Example = () => {
return (
<Page
footer={
<Box as="footer" background="surface-neutral-moderate" padding="8">
<Page.Block gutters>Footer</Page.Block>
</Box>
<Page.Block gutters as="footer">
<Box background="surface-neutral-moderate" padding="8">
Footer
</Box>
</Page.Block>
}
>
<Box as="header" background="surface-neutral-moderate" padding="8">
<Page.Block gutters>Header</Page.Block>
</Box>
<Box
as="main"
background="surface-alt-3-moderate"
padding="8"
paddingBlock="16"
>
<Page.Block gutters>Content</Page.Block>
</Box>
<Page.Block gutters as="header">
<Box background="surface-neutral-moderate" padding="8">
Header
</Box>
</Page.Block>
<Page.Block gutters as="main">
<Box background="surface-alt-3-moderate" paddingBlock="16" padding="8">
Med gutter
</Box>
</Page.Block>
<Page.Block as="main">
<Box background="surface-alt-3-subtle" paddingBlock="16" padding="8">
Uten gutter
</Box>
</Page.Block>
</Page>
);
};
@@ -94,7 +94,7 @@ const Page = ({ blogg, morePosts, publishDate }: PageProps["props"]) => {
<main
tabIndex={-1}
id="hovedinnhold"
className="aksel-artikkel group/aksel overflow-hidden bg-[#FEFCE9] pb-16 pt-[8vw] focus:outline-none sm:pb-32"
className="aksel-artikkel group/aksel overflow-hidden bg-amber-50 pb-16 pt-[8vw] focus:outline-none sm:pb-32"
>
<div className="px-4">
<div className="dynamic-wrapper-prose text-center">
@@ -134,6 +134,12 @@ const Page = ({ blogg, morePosts, publishDate }: PageProps["props"]) => {
.auto("format")
.quality(100)
.url()}
blurDataURL={urlFor(blogg?.seo?.image)
.width(24)
.height(24)
.blur(10)
.url()}
placeholder="blur"
decoding="sync"
layout="fill"
objectFit="cover"
@@ -158,15 +164,15 @@ const Page = ({ blogg, morePosts, publishDate }: PageProps["props"]) => {
</div>
</div>
<div className="relative mt-16">
<AkselCubeStatic className="text-[#FFE78A] opacity-20" />
<div className="mt-8 px-4">
<AkselCubeStatic className="z-0 text-amber-300 opacity-20" />
<div className="relative z-10 mt-8 px-4">
<SanityBlockContent
className="dynamic-wrapper-prose"
blocks={blogg?.content ?? []}
/>
</div>
</div>
<div className="mt-16 px-4">
<div className="relative z-10 mt-16 px-4">
<div className="dynamic-wrapper-prose">
<div className="bg-deepblue-800 mx-auto mb-10 h-2 w-2 rotate-45 rounded-[1px]" />
{authors?.length > 0 && (
@@ -73,7 +73,7 @@ const Page = (props: PageProps["props"]) => {
image={props?.page?.seo?.image}
/>
<div className="bg-[#FEFCE9]">
<div className="bg-amber-50">
<Header variant="blogg" />
<main
tabIndex={-1}
@@ -1,3 +1,4 @@
import { SANITY_DATASET, SANITY_PROJECT_ID } from "@/sanity/config";
import { defineCliConfig } from "sanity/cli";
/**
@@ -11,7 +12,7 @@ import { defineCliConfig } from "sanity/cli";
*/
export default defineCliConfig({
api: {
projectId: "hnbe3yhs",
dataset: "production",
projectId: SANITY_PROJECT_ID,
dataset: SANITY_DATASET,
},
});
+7 -3
View File
@@ -1,8 +1,12 @@
export const SANITY_PROJECT_ID = "hnbe3yhs";
export const SANITY_API_VERSION = "2021-10-21";
export const SANITY_DATASET = "production";
export const clientConfig = {
projectId: "hnbe3yhs",
dataset: "production",
projectId: SANITY_PROJECT_ID,
dataset: SANITY_DATASET,
useCdn: false,
apiVersion: "2021-05-31",
apiVersion: SANITY_API_VERSION,
};
export const allArticleDocuments = [
@@ -1,3 +1,5 @@
import { SanityBlockContent } from "@/sanity-block";
import { SANITY_API_VERSION } from "@/sanity/config";
import { Button } from "@navikt/ds-react";
import { differenceInMonths, format } from "date-fns";
import { useState } from "react";
@@ -9,7 +11,6 @@ import {
useDocumentOperation,
} from "sanity";
import useSWR from "swr";
import { SanityBlockContent } from "@/sanity-block";
export const createWrappedFocusAction = (action: DocumentActionComponent) => {
const WrappedFocus = (
@@ -157,7 +158,7 @@ interface QualityCheckContentProps {
}
export const QualityCheckContent = ({ type }: QualityCheckContentProps) => {
const client = useClient({ apiVersion: "2021-06-07" });
const client = useClient({ apiVersion: SANITY_API_VERSION });
const { data, error } = useSWR(`*[_id == "publication_flow"][0]`, (query) =>
client.fetch(query)
);
@@ -1,126 +0,0 @@
import { Alert, BodyLong, Heading, Loader } from "@navikt/ds-react";
import {
IntentButton,
Preview,
getPublishedId,
useClient,
useSchema,
} from "sanity";
import useSWR from "swr";
export function FeedbackView(props) {
const { documentId } = props;
const schema = useSchema();
const schemaType = schema.get("aksel_feedback");
const client = useClient({ apiVersion: "2021-06-07" });
const { data, error, isValidating } = useSWR(
`*[_type == "aksel_feedback" && references($id)]`,
(query) =>
client.fetch(query, {
id: documentId,
})
);
if (isValidating) {
return (
<div className="grid place-items-center px-6">
<div className="mx-auto mt-24">
<Loader size="xlarge" variant="neutral" />
</div>
</div>
);
}
if (error) {
return (
<div className="grid place-items-center">
<div className="mx-auto mt-24 px-6">
En feil oppstod, prøv å laste side på nytt eller kontakt utvikler.
</div>
</div>
);
}
if (data.length === 0) {
return (
<div className="grid place-items-center">
<div className="mx-auto mt-24 px-6">
Siden har ingen tilbakemeldinger enda.
</div>
</div>
);
}
const done = data.filter((x) => x?.behandlet === true);
const notDone = data.filter((x) => x?.behandlet === false);
return (
<div className="grid place-items-center">
<div className="mx-auto mt-4 w-full px-6">
<Alert variant="info" data-theme="light">
Løsning for tilbakemeldinger på Aksel er midlertidig slått av.
</Alert>
<div className="mt-7">
<Heading level="2" size="small" spacing>
Tilbakemeldinger
</Heading>
{notDone.length === 0 && (
<BodyLong textColor="subtle">Ingen nye tilbakemeldinger</BodyLong>
)}
<ul>
{notDone.map((x) => (
<li key={x._id}>
<IntentButton
key={x._id}
intent="edit"
mode="ghost"
padding={1}
radius={0}
params={{
type: "aksel_feedback",
id: getPublishedId(x._id),
}}
style={{ width: "100%" }}
>
<Preview
schemaType={schemaType}
value={x}
key={x._id}
layout="default"
/>
</IntentButton>
</li>
))}
</ul>
</div>
{done.length > 0 && (
<div className="mt-7">
<Heading level="2" size="small" spacing>
Ferdig behandet
</Heading>
<ul>
{done.map((x) => (
<li key={x._id}>
<IntentButton
intent="edit"
mode="bleed"
radius={2}
params={{
type: "aksel_feedback",
id: getPublishedId(x._id),
}}
>
<Preview schemaType={schemaType} value={x} key={x._id} />
</IntentButton>
</li>
))}
</ul>
</div>
)}
</div>
</div>
);
}
@@ -1,211 +0,0 @@
import {
EyeClosedIcon,
EyeWithPupilIcon,
MinusIcon,
PresentationIcon,
} from "@navikt/aksel-icons";
import { StructureBuilder } from "sanity/desk";
export const FeedbackPanes = async (getClient, S: StructureBuilder) => {
const fb = await getClient({ apiVersion: "2021-06-07" }).fetch(
`{
"behandlet": count(*[_type == "aksel_feedback" && behandlet == true]),
"ubehandlet": count(*[_type == "aksel_feedback" && behandlet == false]),
"totalt-gp": count(*[_type == "aksel_feedback" && doc_ref->_type == "aksel_artikkel"]),
"totalt-comp": count(*[_type == "aksel_feedback" && doc_ref->_type == "komponent_artikkel"]),
"totalt-grunnleggende": count(*[_type == "aksel_feedback" && doc_ref->_type == "ds_artikkel"]),
"totalt-rest": count(*[_type == "aksel_feedback" && !(doc_ref->_type in ["ds_artikkel", "komponent_artikkel", "aksel_artikkel"])]),
"totalt-footer": count(*[_type == "aksel_feedback" && feedback_type == "footer"]),
"totalt-uu": count(*[_type == "aksel_feedback" && feedback_type == "uu_feedback"]),
"totalt-ja": count(*[_type == "aksel_feedback" && artikkel_feedback == "ja"]),
"totalt-nei": count(*[_type == "aksel_feedback" && artikkel_feedback == "nei"]),
"totalt-forslag": count(*[_type == "aksel_feedback" && artikkel_feedback == "forslag"]),
}`
);
/* const types = [...fb.ubehandlet, ...fb.behandlet]?.reduce((acc, curr) => {
return {
...acc,
[curr._type]: acc[curr?._type] ? acc[curr._type] + 1 : 1,
};
}, {});
console.log(types); */
return [
S.listItem()
.title(`Ubehandlet (${fb.ubehandlet})`)
.icon(EyeWithPupilIcon)
.child(
S.documentList()
.title(`Ubehandlet`)
.filter(`_type == "aksel_feedback" && behandlet == false`)
/* .menuItems([...S.documentTypeList("aksel_artikkel").getMenuItems()]) */
),
S.listItem()
.title(`God praksis`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && behandlet == false && doc_ref->_type == "aksel_artikkel"`
)
),
S.listItem()
.title(`Komponentsider`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && behandlet == false && doc_ref->_type == "komponent_artikkel"`
)
),
S.listItem()
.title(`Grunnleggende`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && behandlet == false && doc_ref->_type == "ds_artikkel"`
)
),
S.listItem()
.title(`Andre sider`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && behandlet == false && !(doc_ref->_type in ["ds_artikkel", "komponent_artikkel", "aksel_artikkel"])`
)
),
S.listItem()
.title(`Fant ikke det de lette etter`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && behandlet == false && artikkel_feedback == "nei"`
)
),
S.listItem()
.title(`Footer`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && behandlet == false && feedback_type == "footer"`
)
),
S.listItem()
.title(`UU-feedback`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && behandlet == false && feedback_type == "uu_feedback"`
)
),
S.divider(),
S.listItem()
.title(`Behandlet (${fb.behandlet})`)
.icon(EyeClosedIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(`_type == "aksel_feedback" && behandlet == true`)
),
S.divider(),
S.listItem()
.title(`Alle tilbakemeldinger (${fb.ubehandlet + fb.behandlet})`)
.icon(PresentationIcon)
.child(
S.documentList().title(`Ubehandlet`).filter(`_type == "aksel_feedback"`)
),
S.listItem()
.title(`God praksis totalt (${fb["totalt-gp"]})`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && doc_ref->_type == "aksel_artikkel"`
)
),
S.listItem()
.title(`Komponentsider totalt (${fb["totalt-comp"]})`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && doc_ref->_type == "komponent_artikkel"`
)
),
S.listItem()
.title(`Grunnleggende totalt (${fb["totalt-grunnleggende"]})`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && doc_ref->_type == "ds_artikkel"`
)
),
S.listItem()
.title(`Andre sider totalt (${fb["totalt-rest"]})`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(
`_type == "aksel_feedback" && !(doc_ref->_type in ["ds_artikkel", "komponent_artikkel", "aksel_artikkel"])`
)
),
S.listItem()
.title(`Nei totalt (${fb["totalt-nei"]})`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(`_type == "aksel_feedback" && artikkel_feedback == "nei"`)
),
S.listItem()
.title(`Forslag totalt (${fb["totalt-forslag"]})`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(`_type == "aksel_feedback" && artikkel_feedback == "forslag"`)
),
S.listItem()
.title(`Ja totalt (${fb["totalt-ja"]})`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(`_type == "aksel_feedback" && artikkel_feedback == "ja"`)
),
S.listItem()
.title(`Footer totalt (${fb["totalt-footer"]})`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(`_type == "aksel_feedback" && feedback_type == "footer"`)
),
S.listItem()
.title(`UU-feedback totalt (${fb["totalt-uu"]})`)
.icon(MinusIcon)
.child(
S.documentList()
.title(`Behandlet`)
.filter(`_type == "aksel_feedback" && feedback_type == "uu_feedback"`)
),
];
};
@@ -1,9 +1,10 @@
import { SANITY_API_VERSION } from "@/sanity/config";
import { FileXMarkIcon, TagIcon } from "@navikt/aksel-icons";
import { StructureBuilder } from "sanity/desk";
/* documentStore is in Alpha, so avoid using for now */
export const GodPraksisPanes = async (getClient, S: StructureBuilder) => {
let tema = await getClient({ apiVersion: "2021-06-07" }).fetch(
let tema = await getClient({ apiVersion: SANITY_API_VERSION }).fetch(
`*[_type == "aksel_tema"]{title,seksjoner, _id}`
);
tema = tema
@@ -21,7 +22,7 @@ export const GodPraksisPanes = async (getClient, S: StructureBuilder) => {
)
);
const ids = await getClient({ apiVersion: "2021-06-07" }).fetch(
const ids = await getClient({ apiVersion: SANITY_API_VERSION }).fetch(
`*[_type == "aksel_artikkel"]{_id, tema}`
);
@@ -1,5 +1,5 @@
import { StructureBuilder } from "sanity/desk";
import {
SANITY_API_VERSION,
bloggKategorier,
grunnleggendeKategorier,
komponentKategorier,
@@ -11,7 +11,6 @@ import {
import { Iframe } from "./IFrame";
import {
ChatIcon,
CircleSlashIcon,
ComponentIcon,
FileTextIcon,
@@ -23,14 +22,16 @@ import {
TokenIcon,
} from "@navikt/aksel-icons";
import differenceInMonths from "date-fns/differenceInMonths";
import { FeedbackView } from "./FeedbackPreview";
import { FeedbackPanes } from "./feedback";
import { StructureResolver } from "sanity/desk";
import { GodPraksisPanes } from "./god-praksis";
import { PanesWithCount } from "./with-count";
import { Panes } from "./panes";
const isAfter = (date) => differenceInMonths(new Date(), new Date(date)) >= 6;
/* import { WebPreview, JsonView } from './previews' */
/**
* List of document-types added to structure.
* If not added to `filtered`, they will be shown as an entry on main studio view
*/
const filtered = [
"ds_artikkel",
"komponent_artikkel",
@@ -58,11 +59,11 @@ const filtered = [
"aksel_feedback",
];
export const structure = async (
S: StructureBuilder,
export const structure: StructureResolver = async (
S,
{ currentUser, getClient }
) => {
const ids = await getClient({ apiVersion: "2021-06-07" })
const ids = await getClient({ apiVersion: SANITY_API_VERSION })
.fetch(`*[_type == "editor"]{
_id,
user_id
@@ -76,17 +77,12 @@ export const structure = async (
["developer"].includes(x.name)
);
const feedback = await getClient({ apiVersion: "2021-06-07" }).fetch(
`*[_type == "aksel_feedback" && $id in doc_ref->contributors[]->user_id.current]{_id, behandlet}`,
{ id: currentUser?.id }
);
let outdated = await getClient({ apiVersion: "2021-06-07" }).fetch(
`*[$id in contributors[]->user_id.current]{_id, updateInfo}`,
{ id: currentUser?.id }
);
outdated = outdated.filter((x) => isAfter(x.updateInfo?.lastVerified));
const outdated = (
await getClient({ apiVersion: SANITY_API_VERSION }).fetch(
`*[$id in contributors[]->user_id.current]{_id, updateInfo}`,
{ id: currentUser?.id }
)
).filter((x) => isAfter(x.updateInfo?.lastVerified));
return S.list()
.title("Innholdstyper")
@@ -112,64 +108,7 @@ export const structure = async (
),
]
: []),
...(feedback.length > 0
? [
S.listItem()
.title(
`Tilbakemeldinger (${
feedback.filter(
(x) => !x._id.includes("draft") && x.behandlet === false
).length
})`
)
.icon(ChatIcon)
.child(
S.list()
.title("Tilbakemeldinger.")
.items([
S.listItem()
.title(
`Nye tilbakemeldinger (${
feedback.filter(
(x) =>
!x._id.includes("draft") && x.behandlet === false
).length
})`
)
.child(
S.documentList()
.title(`Nye tilbakemeldinger`)
.filter(
`_type == 'aksel_feedback' && behandlet == false && _id in $ids`
)
.params({
ids: feedback.map((x) => x?._id),
})
),
S.listItem()
.title(
`Ferdig behandlet (${
feedback.filter(
(x) =>
!x._id.includes("draft") && x.behandlet === true
).length
})`
)
.child(
S.documentList()
.title("Ferdig")
.filter(
`_type == 'aksel_feedback' && behandlet == true && _id in $ids`
)
.params({
ids: feedback.map((x) => x?._id),
})
),
])
),
S.divider(),
]
: [S.divider()]),
...(outdated.length > 0 || !!editor ? [S.divider()] : []),
S.listItem()
.title("God Praksis")
.icon(PencilBoardIcon)
@@ -227,12 +166,7 @@ export const structure = async (
.schemaType(`grunnleggende_landingsside`)
.id(`grunnleggende_landingsside_id1`),
S.divider(),
...(await PanesWithCount(
"ds_artikkel",
grunnleggendeKategorier,
getClient,
S
)),
...Panes("ds_artikkel", grunnleggendeKategorier, S),
])
),
S.listItem()
@@ -247,12 +181,7 @@ export const structure = async (
.schemaType(`templates_landingsside`)
.id(`templates_landingsside_id1`),
S.divider(),
...(await PanesWithCount(
"templates_artikkel",
templatesKategorier,
getClient,
S
)),
...Panes("templates_artikkel", templatesKategorier, S),
])
),
S.listItem()
@@ -267,12 +196,7 @@ export const structure = async (
.schemaType(`komponenter_landingsside`)
.id(`komponenter_landingsside_id1`),
S.divider(),
...(await PanesWithCount(
"komponent_artikkel",
komponentKategorier,
getClient,
S
)),
...Panes("komponent_artikkel", komponentKategorier, S),
])
),
S.listItem()
@@ -287,12 +211,7 @@ export const structure = async (
.schemaType(`blogg_landingsside`)
.id(`blogg_landingsside_id1`),
S.divider(),
...(await PanesWithCount(
"aksel_blogg",
[...bloggKategorier],
getClient,
S
)),
...Panes("aksel_blogg", [...bloggKategorier], S),
])
),
...(adminOrDev
@@ -310,14 +229,6 @@ export const structure = async (
.schemaType(`aksel_forside`)
.icon(ImageIcon)
.id(`aksel_forside_dokument`),
S.listItem()
.title("Feedback")
.icon(ChatIcon)
.child(
S.list()
.title("Feedback")
.items([...(await FeedbackPanes(getClient, S))])
),
S.listItem().title("Standalone-sider").child(
S.documentList()
@@ -442,7 +353,6 @@ export const defaultDocumentNode = (S, { schemaType }) => {
url: (doc) => resolveProductionUrl(doc),
})
.title("Forhåndsvisning"),
S.view.component(FeedbackView).icon(ChatIcon).title("Tilbakemeldinger"),
]);
}
if (schemaType === "aksel_forside") {
@@ -1,34 +1,24 @@
import { FileXMarkIcon } from "@navikt/aksel-icons";
/* documentStore is in Alpha, so avoid using for now */
export const PanesWithCount = async (
export const Panes = (
docType,
categories: { title: string; value: string }[],
getClient,
S
) => {
const ids = await getClient({ apiVersion: "2021-06-07" }).fetch(
`*[_type == $docType]{_id, kategori}`,
{ docType }
);
return [
...categories.map(({ value, title }) =>
S.listItem()
.title(
`${title} (${ids.filter((x) => x?.kategori === value).length ?? 0})`
)
.title(title)
.child(
S.documentList()
.title(title)
.schemaType(docType)
.filter(`_type == $docType && $kat == kategori`)
.params({ kat: value, docType })
/* .menuItems([...S.documentTypeList(docType).getMenuItems()]) */
)
),
S.listItem()
.title(`Uten kategori (${ids.filter((x) => !x?.kategori).length ?? 0})`)
.title(`Uten kategori`)
.icon(FileXMarkIcon)
.child(
S.documentList()
@@ -36,7 +26,6 @@ export const PanesWithCount = async (
.schemaType(docType)
.filter(`_type == $docType && !defined(kategori)`)
.params({ docType })
/* .menuItems([...S.documentTypeList(docType).getMenuItems()]) */
),
];
};
+16 -19
View File
@@ -1,4 +1,4 @@
import { InputWithCounter } from "./schema/custom-components";
import { DatabaseIcon, TestFlaskIcon } from "@navikt/aksel-icons";
import { codeInput } from "@sanity/code-input";
import { colorInput } from "@sanity/color-input";
import { table } from "@sanity/table";
@@ -7,15 +7,15 @@ import { defineConfig } from "sanity";
import { unsplashImageAsset } from "sanity-plugin-asset-source-unsplash";
import { media } from "sanity-plugin-media";
import { deskTool } from "sanity/desk";
import {
SANITY_API_VERSION,
SANITY_PROJECT_ID,
allArticleDocuments,
} from "./config";
import { defaultDocumentNode, publicationFlow, structure } from "./plugins";
import { getTemplates } from "./util";
import { allArticleDocuments } from "./config";
import { schema } from "./schema";
import { DatabaseIcon, TestFlaskIcon } from "@navikt/aksel-icons";
const projectId = "hnbe3yhs";
import { InputWithCounter } from "./schema/custom-components";
import { getTemplates } from "./util";
export const workspaceConfig = defineConfig([
{
@@ -40,8 +40,8 @@ export const workspaceConfig = defineConfig([
function defaultConfig() {
return {
projectId,
apiVersion: "2021-10-21",
projectId: SANITY_PROJECT_ID,
apiVersion: SANITY_API_VERSION,
schema,
form: {
components: {
@@ -49,23 +49,20 @@ function defaultConfig() {
const name = props.schemaType?.name;
if (name === "string" && props.schemaType?.options?.maxLength) {
return <InputWithCounter {...props.inputProps} />;
return <InputWithCounter {...props} />;
}
if (name === "text" && props.schemaType?.options?.maxLength) {
return <InputWithCounter {...props.inputProps} size="large" />;
return <InputWithCounter {...props} size="large" />;
}
return props.renderDefault(props);
},
},
},
document: {
newDocumentOptions: (prev, { currentUser }) => {
return currentUser.roles.find((x) =>
["developer", "administrator"].includes(x.name)
)
? [...getTemplates(prev), ...prev]
: getTemplates();
newDocumentOptions: getTemplates,
unstable_comments: {
enabled: true,
},
},
plugins: [
@@ -98,7 +95,7 @@ function authStore(dataset: string) {
return {
redirectOnSingle: false,
mode: "replace" as const,
projectId,
projectId: SANITY_PROJECT_ID,
dataset,
providers: [
{
@@ -1,3 +1,4 @@
import { SANITY_API_VERSION } from "@/sanity/config";
import {
Accordion,
BodyShort,
@@ -9,9 +10,9 @@ import {
import { differenceInMonths } from "date-fns";
import React, { useMemo } from "react";
import {
getPublishedId,
IntentButton,
Preview,
getPublishedId,
useClient,
useCurrentUser,
useFormValue,
@@ -158,73 +159,16 @@ const DraftList = ({ data }: { data: any[] }) => {
);
};
const FeedbackList = ({ data, title }: { data: any[]; title: string }) => {
const schema = useSchema();
const list = useMemo(
() =>
data.filter((x) =>
title.startsWith("Ferdig") ? x.behandlet : !x.behandlet
),
[data, title]
);
if (list.length === 0) {
return null;
}
return (
<Accordion.Item>
<Accordion.Header>{`${title} (${list.length ?? 0})`}</Accordion.Header>
<Accordion.Content>
<ul className="mt-4">
{list.map((x) => (
<li key={x._id}>
<IntentButton
intent="edit"
mode="ghost"
padding={1}
radius={0}
params={{
type: "aksel_feedback",
id: getPublishedId(x._id),
}}
style={{ width: "100%" }}
>
<Preview
layout="default"
schemaType={schema.get("aksel_feedback")}
value={x}
key={x._id}
/>
</IntentButton>
</li>
))}
</ul>
</Accordion.Content>
</Accordion.Item>
);
};
export const EditorPage = () => {
const user = useCurrentUser();
const userId = useFormValue([`user_id`]) as { current?: string };
const client = useClient({ apiVersion: "2021-06-07" });
const client = useClient({ apiVersion: SANITY_API_VERSION });
const { data, error } = useSWR(
`*[count((contributors[]->user_id.current)[@ == "${userId?.current}"]) > 0]`,
(query) => client.fetch(query)
);
const {
data: fbData,
error: fbError,
isValidating: fbValidating,
} = useSWR(
`*[_type == "aksel_feedback" && $id in doc_ref->contributors[]->user_id.current]{_id, behandlet}`,
(query) => client.fetch(query, { id: userId.current })
);
if (error || !user) {
return <div>Feilet lasting av bruker...</div>;
}
@@ -259,20 +203,7 @@ export const EditorPage = () => {
</Link>
</p>
</div>
{!fbError && !fbValidating && (
<div className="mt-7">
<Heading level="2" size="small" spacing>
Tilbakemeldinger på artikler du er bidragsyter i (
{fbData?.length ?? 0})
</Heading>
{fbData?.length > 0 && (
<Accordion>
<FeedbackList data={fbData} title="Ubehandlet" />
<FeedbackList data={fbData} title="Ferdig behandlet" />
</Accordion>
)}
</div>
)}
<div className="mt-7">
<Heading level="2" size="small" spacing>
Under arbeid / må re-valideres
@@ -1,3 +1,4 @@
import { SANITY_API_VERSION } from "@/sanity/config";
import { Tag } from "@navikt/ds-react";
import { useEffect, useState } from "react";
import {
@@ -10,7 +11,7 @@ import {
export function EditorPreview(props) {
const editors = useFormValue(["contributors"]) as any[];
const user = useCurrentUser();
const client = useClient({ apiVersion: "2021-06-07" });
const client = useClient({ apiVersion: SANITY_API_VERSION });
const [editor, setEditor] = useState<any[]>([]);
@@ -1,42 +1,45 @@
import { Textarea } from "@navikt/ds-react";
import React, { useCallback } from "react";
import { set, StringInputProps, TextInputProps, unset } from "sanity";
import { Box, Detail, VStack } from "@navikt/ds-react";
import cl from "clsx";
import { StringInputProps, TextInputProps } from "sanity";
export function InputWithCounter(
props: (StringInputProps | TextInputProps) & {
size?: "medium" | "large";
}
) {
const { onChange, value = "", elementProps, schemaType } = props;
//@ts-ignore
const maxLength = schemaType?.options?.maxLength
? //@ts-ignore
schemaType?.options?.maxLength
: 60;
const handleChange = useCallback(
(event: React.ChangeEvent<any>) =>
onChange(
event.currentTarget.value ? set(event.currentTarget.value) : unset()
),
[onChange]
);
const hasError =
props.validationError && props.validation.find((x) => x.level === "error");
const { value, schemaType } = props;
return (
<Textarea
{...elementProps}
size="small"
label={schemaType.title}
description={schemaType?.description}
maxLength={maxLength}
onChange={handleChange}
value={value}
error={hasError && props.validationError}
rows={!props.size || props.size === "medium" ? 2 : 1}
/>
<VStack gap="1">
{props.renderDefault(props)}
<Counter
// @ts-ignore
maxLength={schemaType?.options?.maxLength}
currentLength={value?.length ?? 0}
/>
</VStack>
);
}
function Counter({
maxLength,
currentLength,
}: {
maxLength: number;
currentLength: number;
}) {
const difference = maxLength - currentLength;
return (
<Box paddingInline="3">
<Detail
role={difference < 20 ? "status" : undefined}
className={cl({ "text-text-danger dark:text-red-300": difference < 0 })}
>
{difference < 0
? `${Math.abs(difference)} tegn for mye`
: `${difference} tegn igjen`}
</Detail>
</Box>
);
}
@@ -0,0 +1,58 @@
/**
* https://www.sanity.io/guides/ultimate-guide-for-customising-portable-text-from-schema-to-react-component
*/
import { SANITY_API_VERSION } from "@/sanity/config";
import { Tooltip } from "@navikt/ds-react";
import { useClient } from "sanity";
import useSWR from "swr";
export const ExternalLinkRenderer = (props) => {
if (props.validation.length > 0) {
return props.renderDefault(props);
}
return (
<Tooltip
content={props.value?.href || "Ingen lenke definert"}
placement="bottom"
maxChar={999}
>
{props.renderDefault(props)}
</Tooltip>
);
};
export const InternalLinkRenderer = (props) => {
const client = useClient({
apiVersion: SANITY_API_VERSION,
});
const { data, error, isValidating } = useSWR(
`*[_id == "${props.value?.reference?._ref}"]{heading, 'slug': slug.current}[0]`,
(query) => client.fetch(query)
);
if (
error ||
props.validation.length > 0 ||
!data ||
data.heading === null ||
data.slug === null
) {
return props.renderDefault(props);
}
return (
<Tooltip
content={
isValidating ? "Henter lenke" : `${data?.heading}: /${data?.slug}`
}
/* Unknown how long title + slug will be */
maxChar={999}
placement="right"
>
{props.renderDefault(props)}
</Tooltip>
);
};
@@ -1,3 +1,4 @@
import { SANITY_API_VERSION } from "@/sanity/config";
import { Heading, VStack } from "@navikt/ds-react";
import { useEffect, useState } from "react";
import {
@@ -10,7 +11,7 @@ import {
} from "sanity";
export function TemaView() {
const client = useClient({ apiVersion: "2021-06-07" });
const client = useClient({ apiVersion: SANITY_API_VERSION });
const title = useFormValue([`title`]);
const schema = useSchema();
@@ -1,9 +1,10 @@
import { SanityBlockContent } from "@/sanity-block";
import { SANITY_API_VERSION } from "@/sanity/config";
import { useClient } from "sanity";
import useSWR from "swr";
import { SanityBlockContent } from "@/sanity-block";
export const WriteHelp = () => {
const client = useClient({ apiVersion: "2021-06-07" });
const client = useClient({ apiVersion: SANITY_API_VERSION });
const { data, error } = useSWR(`*[_id == "skrivehjelp"][0]`, (query) =>
client.fetch(query)
);
@@ -1,13 +1,13 @@
import { defineField, defineType } from "sanity";
import { groups } from "../presets/groups";
import { artikkelPreview } from "../presets/artikkel-preview";
import { hiddenFields } from "../presets/hidden-fields";
import { editorField } from "../presets/editors";
import { titleField } from "../presets/title-field";
import { ingressField } from "../presets/ingress";
import { SEOFields } from "../presets/seo";
import { sanitySlug } from "../presets/slug";
import { bloggKategorier } from "../../../config";
import { artikkelPreview } from "../presets/artikkel-preview";
import { editorField } from "../presets/editors";
import SanityTabGroups from "../presets/groups";
import { hiddenFields } from "../presets/hidden-fields";
import { ingressField } from "../presets/ingress";
import BaseSEOPreset from "../presets/seo";
import { sanitySlug } from "../presets/slug";
import { titleField } from "../presets/title-field";
const prefix = "produktbloggen/";
@@ -15,7 +15,7 @@ export const Blogg = defineType({
title: "Bloggpost",
name: "aksel_blogg",
type: "document",
groups,
groups: SanityTabGroups,
...artikkelPreview("Produktbloggen"),
fields: [
...hiddenFields,
@@ -41,6 +41,6 @@ export const Blogg = defineType({
type: "riktekst_standard",
group: "innhold",
}),
SEOFields,
BaseSEOPreset,
],
});
@@ -1,21 +1,20 @@
import { defineField, defineType } from "sanity";
/* import { bloggKategorier } from "../../../config"; */
import { SEOFields } from "../presets/seo";
import { groups } from "../presets/groups";
import { HouseIcon } from "@navikt/aksel-icons";
import { defineField, defineType } from "sanity";
import SanityTabGroups from "../presets/groups";
import BaseSEOPreset from "../presets/seo";
export const BloggLandingSide = defineType({
title: "Landingsside Blogg",
name: "blogg_landingsside",
type: "document",
groups,
groups: SanityTabGroups,
fields: [
defineField({
title: "Intro",
name: "intro",
type: "riktekst_standard",
}),
SEOFields,
BaseSEOPreset,
],
preview: {
prepare: () => ({
@@ -1,13 +1,14 @@
import { SANITY_API_VERSION } from "@/sanity/config";
import Avatar from "boring-avatars";
import React from "react";
import {
defineType,
defineField,
SlugSourceContext,
InitialValueResolverContext,
SlugSourceContext,
defineField,
defineType,
} from "sanity";
import Avatar from "boring-avatars";
import { EditorPreview } from "../custom-components/EditorPreview";
import { EditorPage } from "../custom-components/EditorPage";
import { EditorPreview } from "../custom-components/EditorPreview";
const navn = [
"Alpesteinbukk",
@@ -116,7 +117,7 @@ const generateName = async (
ctx: SlugSourceContext | InitialValueResolverContext
) => {
const names = await ctx
.getClient({ apiVersion: "2021-06-07" })
.getClient({ apiVersion: SANITY_API_VERSION })
.fetch(`*[_type == "editor"].anon_navn.current`);
let c = 0;
@@ -1,13 +1,13 @@
import { defineField, defineType } from "sanity";
import { allArticleDocsRef } from "../../config";
import { groups } from "./presets";
import { SEOFields } from "./presets/seo";
import SanityTabGroups from "./presets/groups";
import BaseSEOPreset from "./presets/seo";
export const Forside = defineType({
title: "Forside Aksel",
name: "aksel_forside",
type: "document",
groups,
groups: SanityTabGroups,
fields: [
defineField({
title: "God praksis intro",
@@ -37,7 +37,7 @@ export const Forside = defineType({
name: "highlight",
type: "reference",
hidden: ({ value }) => !value,
to: [...allArticleDocsRef],
to: allArticleDocsRef,
validation: (Rule) => Rule.required(),
}),
],
@@ -51,7 +51,7 @@ export const Forside = defineType({
}),
],
}),
SEOFields,
BaseSEOPreset,
],
preview: {
prepare() {
@@ -1,15 +1,15 @@
import { defineField, defineType } from "sanity";
import { artikkelPreview } from "../presets/artikkel-preview";
import { editorField } from "../presets/editors";
import { groups } from "../presets/groups";
import SanityTabGroups from "../presets/groups";
import { hiddenFields } from "../presets/hidden-fields";
import { ingressField } from "../presets/ingress";
import { oppdateringsvarsel } from "../presets/oppdateringsvarsel";
import { relevanteArtiklerField } from "../presets/relevante-artikler";
import { SEOFields } from "../presets/seo";
import BaseSEOPreset from "../presets/seo";
import { skrivehjelp } from "../presets/skrivehjelp";
import { sanitySlug } from "../presets/slug";
import { titleField } from "../presets/title-field";
import { oppdateringsvarsel } from "../presets/oppdateringsvarsel";
const prefix = "god-praksis/artikler/";
@@ -17,7 +17,7 @@ export const GodPraksisArtikkel = defineType({
title: "God praksis artikkel",
name: "aksel_artikkel",
type: "document",
groups,
groups: SanityTabGroups,
...artikkelPreview("God praksis"),
fields: [
oppdateringsvarsel,
@@ -44,7 +44,7 @@ export const GodPraksisArtikkel = defineType({
group: "innhold",
}),
relevanteArtiklerField,
SEOFields,
BaseSEOPreset,
skrivehjelp,
],
});
@@ -1,20 +1,20 @@
import { defineField, defineType } from "sanity";
import { SEOFields } from "../presets/seo";
import { groups } from "../presets/groups";
import { HouseIcon } from "@navikt/aksel-icons";
import { defineField, defineType } from "sanity";
import SanityTabGroups from "../presets/groups";
import BaseSEOPreset from "../presets/seo";
export const GodPraksisLandingSide = defineType({
title: "Landingsside Grunnleggende",
name: "godpraksis_landingsside",
type: "document",
groups,
groups: SanityTabGroups,
fields: [
defineField({
title: "Intro",
name: "intro",
type: "riktekst_standard",
}),
SEOFields,
BaseSEOPreset,
],
preview: {
prepare: () => ({
@@ -1,14 +1,14 @@
import { groups } from "../presets/groups";
import { defineField, defineType } from "sanity";
import { TemaView } from "../../custom-components/TemaView";
import { TemaPreview } from "../../custom-components/TemaPreview";
import { SEOFields } from "../presets/seo";
import { TemaView } from "../../custom-components/TemaView";
import SanityTabGroups from "../presets/groups";
import BaseSEOPreset from "../presets/seo";
export const Tema = defineType({
title: "Aksel Tema",
name: "aksel_tema",
type: "document",
groups,
groups: SanityTabGroups,
components: {
preview: TemaPreview,
item: TemaPreview,
@@ -29,7 +29,7 @@ export const Tema = defineType({
group: "innhold",
options: {
//@ts-ignore
// @ts-expect-error
maxLength: 130,
},
validation: (Rule) =>
@@ -156,6 +156,6 @@ export const Tema = defineType({
],
validation: (Rule) => Rule.required().error("Tema må ha pictogram"),
}),
SEOFields,
BaseSEOPreset,
],
});
@@ -1,13 +1,13 @@
import { defineField, defineType } from "sanity";
import { groups } from "../presets/groups";
import { artikkelPreview } from "../presets/artikkel-preview";
import { hiddenFields } from "../presets/hidden-fields";
import { editorField } from "../presets/editors";
import { titleField } from "../presets/title-field";
import { SEOFields } from "../presets/seo";
import { kategoriSlug } from "../presets/slug";
import { grunnleggendeKategorier } from "../../../config";
import { artikkelPreview } from "../presets/artikkel-preview";
import { editorField } from "../presets/editors";
import SanityTabGroups from "../presets/groups";
import { hiddenFields } from "../presets/hidden-fields";
import { oppdateringsvarsel } from "../presets/oppdateringsvarsel";
import BaseSEOPreset from "../presets/seo";
import { kategoriSlug } from "../presets/slug";
import { titleField } from "../presets/title-field";
const prefix = "grunnleggende/";
@@ -15,7 +15,7 @@ export const GrunnleggendeArtikkel = defineType({
title: "Grunnleggende artikkel",
name: "ds_artikkel",
type: "document",
groups,
groups: SanityTabGroups,
...artikkelPreview("Grunnleggende"),
fields: [
oppdateringsvarsel,
@@ -63,10 +63,6 @@ export const GrunnleggendeArtikkel = defineType({
type: "image",
},
],
options: {
collapsible: true,
collapsed: false,
},
}),
defineField({
title: "Sidebar index",
@@ -84,6 +80,6 @@ export const GrunnleggendeArtikkel = defineType({
type: "riktekst_grunnleggende",
group: "innhold",
}),
SEOFields,
BaseSEOPreset,
],
});
@@ -1,8 +1,8 @@
import { HouseIcon } from "@navikt/aksel-icons";
import { defineField, defineType } from "sanity";
import { grunnleggendeKategorier } from "../../../config";
import { SEOFields } from "../presets/seo";
import { groups } from "../presets/groups";
import { HouseIcon } from "@navikt/aksel-icons";
import SanityTabGroups from "../presets/groups";
import BaseSEOPreset from "../presets/seo";
const views = () => {
const list = [];
@@ -30,7 +30,7 @@ export const GrunnleggendeLandingSide = defineType({
title: "Landingsside Grunnleggende",
name: "grunnleggende_landingsside",
type: "document",
groups,
groups: SanityTabGroups,
fields: [
defineField({
title: "Intro",
@@ -38,7 +38,7 @@ export const GrunnleggendeLandingSide = defineType({
type: "text",
}),
...views(),
SEOFields,
BaseSEOPreset,
],
preview: {
prepare: () => ({
@@ -3,10 +3,10 @@ import { komponentKategorier } from "../../../config";
import { devsOnly } from "../../../util";
import { artikkelPreview } from "../presets/artikkel-preview";
import { editorField } from "../presets/editors";
import { groups } from "../presets/groups";
import SanityTabGroups from "../presets/groups";
import { hiddenFields } from "../presets/hidden-fields";
import { oppdateringsvarsel } from "../presets/oppdateringsvarsel";
import { SEOFields } from "../presets/seo";
import BaseSEOPreset from "../presets/seo";
import { kategoriSlug } from "../presets/slug";
import { titleField } from "../presets/title-field";
@@ -16,7 +16,7 @@ export const KomponentArtikkel = defineType({
title: "Komponentartikkel",
name: "komponent_artikkel",
type: "document",
groups,
groups: SanityTabGroups,
...artikkelPreview("Komponenter"),
fields: [
oppdateringsvarsel,
@@ -80,10 +80,6 @@ export const KomponentArtikkel = defineType({
type: "image",
}),
],
options: {
collapsible: true,
collapsed: false,
},
}),
defineField({
title: "Sidebar index",
@@ -134,6 +130,6 @@ export const KomponentArtikkel = defineType({
type: "url",
group: "lenker",
}),
SEOFields,
BaseSEOPreset,
],
});
@@ -1,5 +1,3 @@
/* import { ExampleKeys } from "website/component-examples"; */
import { defineField, defineType } from "sanity";
export const KodeEksempelDoc = defineType({
@@ -1,8 +1,8 @@
import { HouseIcon } from "@navikt/aksel-icons";
import { defineField, defineType } from "sanity";
import { komponentKategorier } from "../../../config";
import { SEOFields } from "../presets/seo";
import { groups } from "../presets/groups";
import { HouseIcon } from "@navikt/aksel-icons";
import SanityTabGroups from "../presets/groups";
import BaseSEOPreset from "../presets/seo";
const views = () => {
const list = [];
@@ -30,7 +30,7 @@ export const KomponentLandingSide = defineType({
title: "Landingsside Komponenter",
name: "komponenter_landingsside",
type: "document",
groups,
groups: SanityTabGroups,
fields: [
defineField({
title: "Intro",
@@ -38,7 +38,7 @@ export const KomponentLandingSide = defineType({
type: "text",
}),
...views(),
SEOFields,
BaseSEOPreset,
],
preview: {
prepare: () => ({
@@ -1,5 +1,3 @@
/* import { ExampleKeys } from "website/component-examples"; */
import { defineField, defineType } from "sanity";
export const Props = defineType({
Loaded 100 of 124 files, more files were not shown because too many files have changed in this diff. Show more