mirror of
https://github.com/navikt/aksel.git
synced 2026-10-15 02:02:02 +00:00
Compare commits
32
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da0fbc3299 | ||
|
|
9f59e67e2a | ||
|
|
ed7aafcac8 | ||
|
|
dfbbe92a63 | ||
|
|
42b5af64ab | ||
|
|
329119fa04 | ||
|
|
0fc80f45cb | ||
|
|
337b9fda13 | ||
|
|
659e835da9 | ||
|
|
e10f4375b1 | ||
|
|
9a8bb26c36 | ||
|
|
69aea38784 | ||
|
|
8f16d1571e | ||
|
|
e2265c9a78 | ||
|
|
925aa7a140 | ||
|
|
7c17e40cac | ||
|
|
3c8889ea88 | ||
|
|
e060961050 | ||
|
|
18aa4ee7fb | ||
|
|
f44edd76a2 | ||
|
|
1fa636bdd5 | ||
|
|
44a75acb6b | ||
|
|
550faee900 | ||
|
|
88b6174b0b | ||
|
|
fbf016b3bd | ||
|
|
09fa503b98 | ||
|
|
f5688485f5 | ||
|
|
6385c4686e | ||
|
|
30068dca3f | ||
|
|
3aa04d2375 | ||
|
|
91343563c9 | ||
|
|
d5c8112339 |
No files matched your search
@@ -0,0 +1,17 @@
|
||||
### :memo: PR Checklist
|
||||
|
||||
<!-- Remove non-relevant fields -->
|
||||
|
||||
- [ ] :sparkles: New component? Add CSS-mappings to `@navikt/core/css/config/_mappings.js`.
|
||||
|
||||
- [ ] :wastebasket: Are you deprecating a CSS class? (are you removing the last known reference to a CSS class?). Add it to `@navikt/aksel-stylelint/src/deprecations.ts` with a suitable description.
|
||||
|
||||
- [ ] :balance_scale: Is the feature/component/code sufficiently complex to warrant tests? Add some unit-tests :test_tube:
|
||||
|
||||
- [ ] :balance_scale: Does the feature/component add some complex user-interactions? Consider adding some [interaction-tests with storybook](https://storybook.js.org/docs/react/writing-tests/interaction-testing) :test_tube:
|
||||
|
||||
- [ ] :boom: Are there breaking changes? Consider adding a codemod for easier migration.
|
||||
|
||||
- [ ] :test_tube: Are all variations and cases shown in the storybook stories? Stories are used for [visual regression testing](https://www.chromatic.com/docs/), so make sure they are complete.
|
||||
|
||||
- [ ] Run `yarn changeset` for version and changelog generation
|
||||
@@ -1,5 +1,26 @@
|
||||
# @navikt/aksel-icons
|
||||
|
||||
## 4.1.7
|
||||
|
||||
## 4.1.6
|
||||
|
||||
## 4.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2054](https://github.com/navikt/aksel/pull/2054) [`8f16d1571`](https://github.com/navikt/aksel/commit/8f16d1571ec7cf452c09618a9a918ee2a634c75a) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :tada: Nye ikoner
|
||||
|
||||
- ChevronRightLast
|
||||
- ChevronLeftLast
|
||||
|
||||
## 4.1.4
|
||||
|
||||
## 4.1.3
|
||||
|
||||
## 4.1.2
|
||||
|
||||
## 4.1.1
|
||||
|
||||
## 4.1.0
|
||||
|
||||
## 4.0.0
|
||||
|
||||
@@ -15,5 +15,5 @@ keywords:
|
||||
- Sammenføye
|
||||
- Kildekontroll
|
||||
variant: Stroke
|
||||
updated_at: 08.03.2023
|
||||
updated_at: 24.05.2023
|
||||
created_at: 07.03.2023
|
||||
@@ -5,5 +5,5 @@ keywords:
|
||||
- left
|
||||
- venstre
|
||||
variant: Stroke
|
||||
updated_at: 08.03.2023
|
||||
updated_at: 14.06.2023
|
||||
created_at: 07.03.2023
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.5 6.25C7.5 5.83579 7.16421 5.5 6.75 5.5C6.33579 5.5 6 5.83579 6 6.25V17.75C6 18.1642 6.33579 18.5 6.75 18.5C7.16421 18.5 7.5 18.1642 7.5 17.75V6.25ZM17.7803 7.03033C18.0732 6.73744 18.0732 6.26256 17.7803 5.96967C17.4874 5.67678 17.0126 5.67678 16.7197 5.96967L11.2197 11.4697C11.079 11.6103 11 11.8011 11 12C11 12.1989 11.079 12.3897 11.2197 12.5303L16.7197 18.0303C17.0126 18.3232 17.4874 18.3232 17.7803 18.0303C18.0732 17.7374 18.0732 17.2626 17.7803 16.9697L12.8107 12L17.7803 7.03033Z" fill="#262626"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 664 B |
@@ -0,0 +1,12 @@
|
||||
name: ChevronLeftFirst
|
||||
category: Arrows
|
||||
sub_category: Chevron
|
||||
keywords:
|
||||
- left
|
||||
- venstre
|
||||
- side
|
||||
- first
|
||||
- først
|
||||
variant: Stroke
|
||||
updated_at: 15.06.2023
|
||||
created_at: 15.06.2023
|
||||
@@ -6,5 +6,5 @@ keywords:
|
||||
- høyre
|
||||
- side
|
||||
variant: Stroke
|
||||
updated_at: 08.03.2023
|
||||
updated_at: 09.06.2023
|
||||
created_at: 07.03.2023
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18 6.25C18 5.83579 17.6642 5.5 17.25 5.5C16.8358 5.5 16.5 5.83579 16.5 6.25V17.75C16.5 18.1642 16.8358 18.5 17.25 18.5C17.6642 18.5 18 18.1642 18 17.75V6.25ZM7.28033 6.21967C6.98744 5.92678 6.51256 5.92678 6.21967 6.21967C5.92678 6.51256 5.92678 6.98744 6.21967 7.28033L11.1893 12.25L6.21967 17.2197C5.92678 17.5126 5.92678 17.9874 6.21967 18.2803C6.51256 18.5732 6.98744 18.5732 7.28033 18.2803L12.7803 12.7803C13.0732 12.4874 13.0732 12.0126 12.7803 11.7197L7.28033 6.21967Z" fill="#262626"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 648 B |
@@ -0,0 +1,10 @@
|
||||
name: ChevronRightLast
|
||||
category: Arrows
|
||||
sub_category: Chevron
|
||||
keywords:
|
||||
- right
|
||||
- høyre
|
||||
- side
|
||||
variant: Stroke
|
||||
updated_at: 15.06.2023
|
||||
created_at: 15.06.2023
|
||||
@@ -15,5 +15,5 @@ keywords:
|
||||
- markup-språk
|
||||
- kildekode
|
||||
variant: Stroke
|
||||
updated_at: 08.03.2023
|
||||
updated_at: 24.05.2023
|
||||
created_at: 07.03.2023
|
||||
@@ -13,5 +13,5 @@ keywords:
|
||||
- dra og slippe
|
||||
- skifte
|
||||
variant: Stroke
|
||||
updated_at: 08.03.2023
|
||||
updated_at: 26.05.2023
|
||||
created_at: 07.03.2023
|
||||
@@ -23,5 +23,5 @@ keywords:
|
||||
- milepæler
|
||||
- hendelser
|
||||
variant: Stroke
|
||||
updated_at: 08.03.2023
|
||||
updated_at: 31.05.2023
|
||||
created_at: 07.03.2023
|
||||
@@ -7,5 +7,5 @@ keywords:
|
||||
- delete
|
||||
- slett
|
||||
variant: Stroke
|
||||
updated_at: 08.03.2023
|
||||
updated_at: 24.05.2023
|
||||
created_at: 07.03.2023
|
||||
@@ -6,5 +6,5 @@ keywords:
|
||||
- uploading
|
||||
- send
|
||||
variant: Stroke
|
||||
updated_at: 08.03.2023
|
||||
updated_at: 08.06.2023
|
||||
created_at: 07.03.2023
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-icons",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.7",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/ikoner",
|
||||
"repository": {
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @navikt/aksel-stylelint
|
||||
|
||||
## 4.1.7
|
||||
|
||||
## 4.1.6
|
||||
|
||||
## 4.1.5
|
||||
|
||||
## 4.1.4
|
||||
|
||||
## 4.1.3
|
||||
|
||||
## 4.1.2
|
||||
|
||||
## 4.1.1
|
||||
|
||||
## 4.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel-stylelint",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.7",
|
||||
"author": "Aksel | NAV",
|
||||
"homepage": "https://aksel.nav.no/grunnleggende/kode/stylelint",
|
||||
"repository": {
|
||||
@@ -35,8 +35,8 @@
|
||||
"dev": "yarn watch:lint"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-css": "^4.1.0",
|
||||
"@navikt/ds-tokens": "^4.1.0",
|
||||
"@navikt/ds-css": "^4.1.7",
|
||||
"@navikt/ds-tokens": "^4.1.7",
|
||||
"@types/jest": "^29.0.0",
|
||||
"concurrently": "7.2.1",
|
||||
"copyfiles": "2.4.1",
|
||||
|
||||
@@ -1,5 +1,54 @@
|
||||
# @navikt/aksel
|
||||
|
||||
## 4.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`42b5af64a`](https://github.com/navikt/aksel/commit/42b5af64ab35d0f2d126d41f8fc3e61fe2834b36)]:
|
||||
- @navikt/ds-css@4.1.7
|
||||
|
||||
## 4.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@4.1.6
|
||||
|
||||
## 4.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@4.1.5
|
||||
|
||||
## 4.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e06096105`](https://github.com/navikt/aksel/commit/e060961050c75ec815e5c125001f1ff99106e298)]:
|
||||
- @navikt/ds-css@4.1.4
|
||||
|
||||
## 4.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@4.1.3
|
||||
|
||||
## 4.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/ds-css@4.1.2
|
||||
|
||||
## 4.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`91343563c`](https://github.com/navikt/aksel/commit/91343563c916a554d8ade5401c28ab4c3b3e26af)]:
|
||||
- @navikt/ds-css@4.1.1
|
||||
|
||||
## 4.1.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/aksel",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.7",
|
||||
"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": "4.1.0",
|
||||
"@navikt/ds-css": "4.1.7",
|
||||
"axios": "1.3.6",
|
||||
"chalk": "4.1.0",
|
||||
"clipboardy": "^2.3.0",
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# @navikt/ds-css
|
||||
|
||||
## 4.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [`42b5af64a`](https://github.com/navikt/aksel/commit/42b5af64ab35d0f2d126d41f8fc3e61fe2834b36) Thanks [@KenAJoh](https://github.com/KenAJoh)! - Fikset jsdom-problemer ved rendring av Timeline
|
||||
|
||||
## 4.1.6
|
||||
|
||||
## 4.1.5
|
||||
|
||||
## 4.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2049](https://github.com/navikt/aksel/pull/2049) [`e06096105`](https://github.com/navikt/aksel/commit/e060961050c75ec815e5c125001f1ff99106e298) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :bug: Subtle-description på form-elementer brakk bruk av Readmore
|
||||
|
||||
## 4.1.3
|
||||
|
||||
## 4.1.2
|
||||
|
||||
## 4.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [`91343563c`](https://github.com/navikt/aksel/commit/91343563c916a554d8ade5401c28ab4c3b3e26af) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :bug: Fikset markering av tekst i skeleton.
|
||||
|
||||
## 4.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
.navds-help-text__popover.navds-popover {
|
||||
background-color: var(--ac-help-text-popover-bg, var(--a-surface-info-subtle));
|
||||
max-width: 65ch;
|
||||
max-width: min(65ch, 90vw);
|
||||
|
||||
--ac-popover-border: var(--a-border-info);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-css",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.7",
|
||||
"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": "^4.1.0",
|
||||
"@navikt/ds-tokens": "^4.1.7",
|
||||
"cssnano": "6.0.0",
|
||||
"fast-glob": "3.2.11",
|
||||
"lodash": "4.17.21",
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
border-left: 2px solid var(--ac-read-more-line, var(--a-border-divider));
|
||||
margin-left: 13px;
|
||||
padding-left: 13px;
|
||||
color: var(--a-text-default);
|
||||
}
|
||||
|
||||
.navds-read-more--small .navds-read-more__content {
|
||||
|
||||
Vendored
+1
@@ -3,6 +3,7 @@
|
||||
background-color: var(--ac-skeleton-bg, var(--a-surface-neutral-moderate));
|
||||
height: 1.3em;
|
||||
animation: akselSkeletonAnimation 0.8s linear infinite alternate;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.navds-skeleton--has-children {
|
||||
|
||||
@@ -61,6 +61,10 @@
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.navds-timeline__row-periods:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.navds-timeline__period {
|
||||
height: 100%;
|
||||
border-radius: var(--a-border-radius-full);
|
||||
|
||||
@@ -1,5 +1,68 @@
|
||||
# @navikt/ds-react
|
||||
|
||||
## 4.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [`42b5af64a`](https://github.com/navikt/aksel/commit/42b5af64ab35d0f2d126d41f8fc3e61fe2834b36) Thanks [@KenAJoh](https://github.com/KenAJoh)! - Fikset jsdom-problemer ved rendring av Timeline
|
||||
|
||||
- [#2056](https://github.com/navikt/aksel/pull/2056) [`dfbbe92a6`](https://github.com/navikt/aksel/commit/dfbbe92a63210278d9dd4d154c01f116ad921fc1) Thanks [@KenAJoh](https://github.com/KenAJoh)! - La til `wrapperClassname`-prop for HelpText
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/aksel-icons@4.1.7
|
||||
|
||||
## 4.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [`9a8bb26c3`](https://github.com/navikt/aksel/commit/9a8bb26c36cfbb1a95cf28a043d2df3dbfe7185d) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :bug: Timeline-period brakk ved bruk av jsdom-tester
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/aksel-icons@4.1.6
|
||||
|
||||
## 4.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2051](https://github.com/navikt/aksel/pull/2051) [`925aa7a14`](https://github.com/navikt/aksel/commit/925aa7a140bc0cd63e8884bea0bd478838c1aa17) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :bug: OverridableComponent fungerer nå med komponenter som allerede bruker 'as'-prop
|
||||
|
||||
- [#2052](https://github.com/navikt/aksel/pull/2052) [`7c17e40ca`](https://github.com/navikt/aksel/commit/7c17e40cac6703f00ce756276e9616deb73f6098) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :bug: floating-ui sendte ikke escape-events opp gjennom dom-treet
|
||||
|
||||
- Updated dependencies [[`8f16d1571`](https://github.com/navikt/aksel/commit/8f16d1571ec7cf452c09618a9a918ee2a634c75a)]:
|
||||
- @navikt/aksel-icons@4.1.5
|
||||
|
||||
## 4.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/aksel-icons@4.1.4
|
||||
|
||||
## 4.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [`44a75acb6`](https://github.com/navikt/aksel/commit/44a75acb6b904d614a01344f42111761a48cb7e2) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :bug: Classname ble ikke riktig forwardet til ikke-klikkbar Period i Timeline
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/aksel-icons@4.1.3
|
||||
|
||||
## 4.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [`30068dca3`](https://github.com/navikt/aksel/commit/30068dca3fcdf4bf7bbfbfb3d09baa9fee003962) Thanks [@KenAJoh](https://github.com/KenAJoh)! - Jsdoc for Skeleton-komponent
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/aksel-icons@4.1.2
|
||||
|
||||
## 4.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @navikt/aksel-icons@4.1.1
|
||||
|
||||
## 4.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-react",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.7",
|
||||
"description": "Aksel react-components for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"license": "MIT",
|
||||
@@ -38,7 +38,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "0.24.1",
|
||||
"@navikt/aksel-icons": "^4.1.0",
|
||||
"@navikt/aksel-icons": "^4.1.7",
|
||||
"@radix-ui/react-tabs": "1.0.0",
|
||||
"@radix-ui/react-toggle-group": "1.0.0",
|
||||
"clsx": "^1.2.1",
|
||||
|
||||
@@ -114,6 +114,11 @@ export interface DatePickerDefaultProps
|
||||
* @default "absolute"
|
||||
*/
|
||||
strategy?: "absolute" | "fixed";
|
||||
/**
|
||||
* Bubbles Escape keydown-event up trough DOM-tree. This is set to false by default to prevent closing components like Modal on Escape
|
||||
* @default false
|
||||
*/
|
||||
bubbleEscape?: boolean;
|
||||
}
|
||||
|
||||
export type DatePickerProps = DatePickerDefaultProps & ConditionalModeProps;
|
||||
@@ -180,6 +185,7 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
|
||||
onClose,
|
||||
onOpenToggle,
|
||||
strategy = "absolute",
|
||||
bubbleEscape = false,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
@@ -251,6 +257,7 @@ export const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(
|
||||
role="dialog"
|
||||
ref={ref}
|
||||
strategy={strategy}
|
||||
bubbleEscape={bubbleEscape}
|
||||
>
|
||||
<DayPicker
|
||||
locale={getLocaleFromString(locale)}
|
||||
|
||||
@@ -319,6 +319,7 @@ export const useDatepicker = (
|
||||
onOpenToggle: () => handleOpen(!open),
|
||||
disabled,
|
||||
disableWeekends,
|
||||
bubbleEscape: true,
|
||||
ref: setDaypickerRef,
|
||||
};
|
||||
|
||||
|
||||
@@ -312,6 +312,7 @@ export const useMonthpicker = (
|
||||
open,
|
||||
onOpenToggle: () => handleOpen(!open),
|
||||
disabled,
|
||||
bubbleEscape: true,
|
||||
ref: setMonthpickerRef,
|
||||
};
|
||||
|
||||
|
||||
@@ -544,6 +544,7 @@ export const useRangeDatepicker = (
|
||||
onOpenToggle: () => setOpen((x) => !x),
|
||||
disabled,
|
||||
disableWeekends,
|
||||
bubbleEscape: true,
|
||||
ref: setDaypickerRef,
|
||||
};
|
||||
|
||||
|
||||
@@ -86,6 +86,11 @@ export interface MonthPickerProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
* @default "absolute"
|
||||
*/
|
||||
strategy?: "absolute" | "fixed";
|
||||
/**
|
||||
* Bubbles Escape keydown-event up trough DOM-tree. This is set to false by default to prevent closing components like Modal on Escape
|
||||
* @default false
|
||||
*/
|
||||
bubbleEscape?: boolean;
|
||||
}
|
||||
|
||||
interface MonthPickerComponent
|
||||
@@ -153,6 +158,7 @@ export const MonthPicker = forwardRef<HTMLDivElement, MonthPickerProps>(
|
||||
year,
|
||||
onYearChange,
|
||||
strategy = "absolute",
|
||||
bubbleEscape = false,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
@@ -204,6 +210,7 @@ export const MonthPicker = forwardRef<HTMLDivElement, MonthPickerProps>(
|
||||
id={ariaId}
|
||||
className="navds-date"
|
||||
strategy={strategy}
|
||||
bubbleEscape={bubbleEscape}
|
||||
>
|
||||
<RootProvider
|
||||
locale={getLocaleFromString(locale)}
|
||||
|
||||
@@ -29,6 +29,10 @@ export interface HelpTextProps
|
||||
| "right-end"
|
||||
| "left-start"
|
||||
| "left-end";
|
||||
/**
|
||||
* Classname for wrapper
|
||||
*/
|
||||
wrapperClassName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,6 +57,7 @@ export const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
|
||||
strategy = "absolute",
|
||||
title = "hjelp",
|
||||
onClick,
|
||||
wrapperClassName,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
@@ -62,7 +67,7 @@ export const HelpText = forwardRef<HTMLButtonElement, HelpTextProps>(
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="navds-help-text">
|
||||
<div className={cl("navds-help-text", wrapperClassName)}>
|
||||
<button
|
||||
{...rest}
|
||||
ref={mergedRef}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { HelpText } from "..";
|
||||
import { BodyLong, Heading, HelpText } from "..";
|
||||
|
||||
export default {
|
||||
title: "ds-react/HelpText",
|
||||
@@ -65,3 +65,36 @@ export const Open = () => {
|
||||
</HelpText>
|
||||
);
|
||||
};
|
||||
|
||||
export const WrapperClassName = {
|
||||
render: () => {
|
||||
return (
|
||||
<div>
|
||||
<BodyLong spacing>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta
|
||||
perspiciatis vero voluptatum, asperiores cumque, deserunt accusantium
|
||||
ullam ipsa accusamus officia cupiditate quae unde esse culpa, ratione
|
||||
ab quam ea quas?
|
||||
</BodyLong>
|
||||
|
||||
<Heading level="2" size="medium">
|
||||
67 år og 1 måneder øklasdjkl askdak døkasøk daøkdkølasøkld asølkdøka
|
||||
<HelpText wrapperClassName="testClass">
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta
|
||||
perspiciatis vero voluptatum, asperiores cumque, deserunt
|
||||
accusantium ullam ipsa accusamus officia cupiditate quae unde esse
|
||||
culpa, ratione ab quam ea quas?
|
||||
</HelpText>
|
||||
<style>{`.testClass {display: inline-block; margin-left: 0.5rem; vertical-align: middle;}`}</style>
|
||||
</Heading>
|
||||
|
||||
<BodyLong spacing>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Soluta
|
||||
perspiciatis vero voluptatum, asperiores cumque, deserunt accusantium
|
||||
ullam ipsa accusamus officia cupiditate quae unde esse culpa, ratione
|
||||
ab quam ea quas?
|
||||
</BodyLong>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
};
|
||||
@@ -72,6 +72,11 @@ export interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
|
||||
* @default "absolute"
|
||||
*/
|
||||
strategy?: "absolute" | "fixed";
|
||||
/**
|
||||
* Bubbles Escape keydown-event up trough DOM-tree. This is set to false by default to prevent closing components like Modal on Escape
|
||||
* @default false
|
||||
*/
|
||||
bubbleEscape?: boolean;
|
||||
}
|
||||
|
||||
interface PopoverComponent
|
||||
@@ -113,6 +118,7 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
placement = "top",
|
||||
offset,
|
||||
strategy: userStrategy = "absolute",
|
||||
bubbleEscape = false,
|
||||
...rest
|
||||
},
|
||||
ref
|
||||
@@ -143,7 +149,11 @@ export const Popover = forwardRef<HTMLDivElement, PopoverProps>(
|
||||
|
||||
const { getFloatingProps } = useInteractions([
|
||||
useClick(context),
|
||||
useDismiss(context),
|
||||
useDismiss(context, {
|
||||
bubbles: {
|
||||
escapeKey: bubbleEscape,
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
useClientLayoutEffect(() => {
|
||||
|
||||
@@ -12,11 +12,20 @@ export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
*/
|
||||
height?: number | string;
|
||||
/**
|
||||
* When not infering width from children, you must specify width
|
||||
* When not inferring width from children, you must specify width
|
||||
*/
|
||||
width?: number | string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple skeleton loader
|
||||
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/skeleton)
|
||||
* @see 🏷️ {@link SkeletonProps}
|
||||
* @example
|
||||
* ```jsx
|
||||
* <Skeleton variant="circle" height="5rem" width="5rem" />
|
||||
* ```
|
||||
*/
|
||||
export const Skeleton = forwardRef<HTMLDivElement, SkeletonProps>(
|
||||
(
|
||||
{ className, children, height, width, style, variant = "text", ...rest },
|
||||
|
||||
@@ -11,15 +11,9 @@ import {
|
||||
useHover,
|
||||
useInteractions,
|
||||
} from "@floating-ui/react";
|
||||
import { useEventListener, mergeRefs } from "../util";
|
||||
import { format } from "date-fns";
|
||||
import React, {
|
||||
forwardRef,
|
||||
useCallback,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import React, { forwardRef, useMemo, useRef, useState } from "react";
|
||||
import { mergeRefs } from "../util";
|
||||
import { useTimelineContext } from "./hooks/useTimelineContext";
|
||||
import { position } from "./utils/calc";
|
||||
import { TimelineComponentTypes } from "./utils/types.internal";
|
||||
@@ -83,22 +77,6 @@ export const Pin = forwardRef<HTMLButtonElement, TimelinePinProps>(
|
||||
[ref, refs.setReference]
|
||||
);
|
||||
|
||||
useEventListener(
|
||||
"focusin",
|
||||
useCallback(
|
||||
(e: FocusEvent) => {
|
||||
if (
|
||||
![refs.domReference.current, refs?.floating?.current].some(
|
||||
(element) => element?.contains(e.target as Node)
|
||||
)
|
||||
) {
|
||||
open && setOpen(false);
|
||||
}
|
||||
},
|
||||
[open, refs.domReference, refs?.floating]
|
||||
)
|
||||
);
|
||||
|
||||
const staticSide = {
|
||||
top: "bottom",
|
||||
right: "left",
|
||||
@@ -139,6 +117,10 @@ export const Pin = forwardRef<HTMLButtonElement, TimelinePinProps>(
|
||||
ref={refs.setFloating}
|
||||
{...getFloatingProps({
|
||||
tabIndex: -1,
|
||||
onBlur: (e) =>
|
||||
e.target.previousSibling !== document.activeElement &&
|
||||
open &&
|
||||
setOpen(false),
|
||||
})}
|
||||
style={{
|
||||
...floatingStyles,
|
||||
|
||||
@@ -72,6 +72,7 @@ export const TimelineRow = forwardRef<HTMLOListElement, TimelineRowProps>(
|
||||
>
|
||||
<ol
|
||||
{...rest}
|
||||
tabIndex={-1}
|
||||
ref={ref}
|
||||
aria-label={
|
||||
periods.length === 0
|
||||
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
useHover,
|
||||
useInteractions,
|
||||
} from "@floating-ui/react";
|
||||
import { useEventListener, mergeRefs } from "../../util";
|
||||
import cl from "clsx";
|
||||
import React, { useCallback, useMemo, useRef, useState } from "react";
|
||||
import React, { useMemo, useRef, useState } from "react";
|
||||
import { mergeRefs } from "../../util";
|
||||
import { usePeriodContext } from "../hooks/usePeriodContext";
|
||||
import { useRowContext } from "../hooks/useRowContext";
|
||||
import { useTimelineContext } from "../hooks/useTimelineContext";
|
||||
@@ -85,22 +85,6 @@ const ClickablePeriod = React.memo(
|
||||
[periodRef, refs.setReference]
|
||||
);
|
||||
|
||||
useEventListener(
|
||||
"focusin",
|
||||
useCallback(
|
||||
(e: FocusEvent) => {
|
||||
if (
|
||||
![refs.domReference.current, refs?.floating?.current].some(
|
||||
(element) => element?.contains(e.target as Node)
|
||||
)
|
||||
) {
|
||||
open && setOpen(false);
|
||||
}
|
||||
},
|
||||
[open, refs.domReference, refs?.floating]
|
||||
)
|
||||
);
|
||||
|
||||
const staticSide = {
|
||||
top: "bottom",
|
||||
right: "left",
|
||||
@@ -165,6 +149,10 @@ const ClickablePeriod = React.memo(
|
||||
ref={refs.setFloating}
|
||||
{...getFloatingProps({
|
||||
tabIndex: -1,
|
||||
onBlur: (e) =>
|
||||
e.target.previousSibling !== document.activeElement &&
|
||||
open &&
|
||||
setOpen(false),
|
||||
})}
|
||||
style={{
|
||||
...floatingStyles,
|
||||
|
||||
@@ -26,7 +26,7 @@ const NonClickablePeriod = ({
|
||||
{...restProps}
|
||||
className={cl(
|
||||
getConditionalClasses(cropped, direction, status),
|
||||
restProps?.classname
|
||||
restProps?.className
|
||||
)}
|
||||
style={{
|
||||
width: `${width}%`,
|
||||
|
||||
@@ -7,6 +7,6 @@ export interface OverridableComponent<Component, Element extends HTMLElement> {
|
||||
props: {
|
||||
as: As;
|
||||
} & Component &
|
||||
Omit<React.ComponentPropsWithRef<As>, keyof Component>
|
||||
Omit<React.ComponentPropsWithRef<As>, keyof Component | "as">
|
||||
): ReturnType<React.FC>;
|
||||
}
|
||||
@@ -1,5 +1,19 @@
|
||||
# @navikt/ds-tailwind
|
||||
|
||||
## 4.1.7
|
||||
|
||||
## 4.1.6
|
||||
|
||||
## 4.1.5
|
||||
|
||||
## 4.1.4
|
||||
|
||||
## 4.1.3
|
||||
|
||||
## 4.1.2
|
||||
|
||||
## 4.1.1
|
||||
|
||||
## 4.1.0
|
||||
|
||||
## 4.0.0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tailwind",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.7",
|
||||
"description": "Tailwind config based on @navikt/ds-tokens",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
@@ -22,7 +22,7 @@
|
||||
"directory": "@navikt/core/tailwind"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@navikt/ds-tokens": "^4.1.0",
|
||||
"@navikt/ds-tokens": "^4.1.7",
|
||||
"@types/jest": "^29.0.0",
|
||||
"color": "4.2.3",
|
||||
"jest": "^29.0.0",
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @navikt/ds-tokens
|
||||
|
||||
## 4.1.7
|
||||
|
||||
## 4.1.6
|
||||
|
||||
## 4.1.5
|
||||
|
||||
## 4.1.4
|
||||
|
||||
## 4.1.3
|
||||
|
||||
## 4.1.2
|
||||
|
||||
## 4.1.1
|
||||
|
||||
## 4.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -47,27 +47,27 @@
|
||||
"name": "--a-font-family",
|
||||
"value": "\"Source Sans Pro\", Arial, sans-serif"
|
||||
},
|
||||
{ "name": "--a-font-weight-bold", "value": "600" },
|
||||
{ "name": "--a-font-weight-regular", "value": "400" },
|
||||
{ "name": "--a-font-line-height-heading-2xlarge", "value": "3.25rem" },
|
||||
{ "name": "--a-font-line-height-heading-xlarge", "value": "2.5rem" },
|
||||
{ "name": "--a-font-line-height-heading-large", "value": "2.25rem" },
|
||||
{ "name": "--a-font-line-height-heading-medium", "value": "2rem" },
|
||||
{ "name": "--a-font-line-height-heading-small", "value": "1.75rem" },
|
||||
{ "name": "--a-font-line-height-heading-xsmall", "value": "1.5rem" },
|
||||
{ "name": "--a-font-line-height-xlarge", "value": "1.75rem" },
|
||||
{ "name": "--a-font-line-height-large", "value": "1.5rem" },
|
||||
{ "name": "--a-font-line-height-medium", "value": "1.25rem" },
|
||||
{ "name": "--a-font-size-heading-2xlarge", "value": "2.5rem" },
|
||||
{ "name": "--a-font-size-heading-xlarge", "value": "2rem" },
|
||||
{ "name": "--a-font-size-heading-large", "value": "1.75rem" },
|
||||
{ "name": "--a-font-size-heading-medium", "value": "1.5rem" },
|
||||
{ "name": "--a-font-size-heading-small", "value": "1.25rem" },
|
||||
{ "name": "--a-font-size-heading-xsmall", "value": "1.125rem" },
|
||||
{ "name": "--a-font-size-xlarge", "value": "1.25rem" },
|
||||
{ "name": "--a-font-size-large", "value": "1.125rem" },
|
||||
{ "name": "--a-font-weight-bold", "value": "600" },
|
||||
{ "name": "--a-font-size-small", "value": "0.875rem" },
|
||||
{ "name": "--a-font-size-medium", "value": "1rem" },
|
||||
{ "name": "--a-font-size-small", "value": "0.875rem" }
|
||||
{ "name": "--a-font-size-large", "value": "1.125rem" },
|
||||
{ "name": "--a-font-size-xlarge", "value": "1.25rem" },
|
||||
{ "name": "--a-font-size-heading-xsmall", "value": "1.125rem" },
|
||||
{ "name": "--a-font-size-heading-small", "value": "1.25rem" },
|
||||
{ "name": "--a-font-size-heading-medium", "value": "1.5rem" },
|
||||
{ "name": "--a-font-size-heading-large", "value": "1.75rem" },
|
||||
{ "name": "--a-font-size-heading-xlarge", "value": "2rem" },
|
||||
{ "name": "--a-font-size-heading-2xlarge", "value": "2.5rem" },
|
||||
{ "name": "--a-font-line-height-medium", "value": "1.25rem" },
|
||||
{ "name": "--a-font-line-height-large", "value": "1.5rem" },
|
||||
{ "name": "--a-font-line-height-xlarge", "value": "1.75rem" },
|
||||
{ "name": "--a-font-line-height-heading-xsmall", "value": "1.5rem" },
|
||||
{ "name": "--a-font-line-height-heading-small", "value": "1.75rem" },
|
||||
{ "name": "--a-font-line-height-heading-medium", "value": "2rem" },
|
||||
{ "name": "--a-font-line-height-heading-large", "value": "2.25rem" },
|
||||
{ "name": "--a-font-line-height-heading-xlarge", "value": "2.5rem" },
|
||||
{ "name": "--a-font-line-height-heading-2xlarge", "value": "3.25rem" }
|
||||
],
|
||||
"global-base": [
|
||||
{ "name": "--a-transparent", "value": "rgba(255, 255, 255, 0)" },
|
||||
@@ -195,26 +195,34 @@
|
||||
{ "name": "--a-purple-900", "value": "rgba(31, 20, 47, 1)" }
|
||||
],
|
||||
|
||||
"semantic-border": [
|
||||
"semantic-border-default": [
|
||||
{ "name": "--a-border-default", "value": "rgba(0, 0, 0, 0.44)" },
|
||||
{ "name": "--a-border-strong", "value": "rgba(0, 0, 0, 0.65)" },
|
||||
{ "name": "--a-border-divider", "value": "rgba(0, 0, 0, 0.19)" },
|
||||
{ "name": "--a-border-subtle", "value": "rgba(0, 0, 0, 0.1)" },
|
||||
{ "name": "--a-border-subtle-hover", "value": "rgba(0, 0, 0, 0.19)" },
|
||||
{ "name": "--a-border-on-inverted", "value": "rgba(229, 229, 229, 1)" },
|
||||
{ "name": "--a-border-on-inverted-subtle", "value": "rgba(89, 89, 89, 1)" }
|
||||
],
|
||||
"semantic-border-action": [
|
||||
{ "name": "--a-border-action", "value": "rgba(0, 103, 197, 1)" },
|
||||
{ "name": "--a-border-action-selected", "value": "rgba(0, 91, 130, 1)" },
|
||||
{ "name": "--a-border-selected", "value": "rgba(0, 103, 197, 1)" },
|
||||
{ "name": "--a-border-selected", "value": "rgba(0, 103, 197, 1)" }
|
||||
],
|
||||
"semantic-border-status": [
|
||||
{ "name": "--a-border-success", "value": "rgba(6, 137, 58, 1)" },
|
||||
{ "name": "--a-border-danger", "value": "rgba(195, 0, 0, 1)" },
|
||||
{ "name": "--a-border-warning", "value": "rgba(199, 115, 0, 1)" },
|
||||
{ "name": "--a-border-info", "value": "rgba(54, 141, 168, 1)" },
|
||||
{ "name": "--a-border-on-inverted", "value": "rgba(229, 229, 229, 1)" },
|
||||
{ "name": "--a-border-on-inverted-subtle", "value": "rgba(89, 89, 89, 1)" },
|
||||
{ "name": "--a-border-info", "value": "rgba(54, 141, 168, 1)" }
|
||||
],
|
||||
"semantic-border-focus": [
|
||||
{ "name": "--a-border-focus", "value": "rgba(0, 52, 125, 1)" },
|
||||
{
|
||||
"name": "--a-border-focus-on-inverted",
|
||||
"value": "rgba(153, 195, 255, 1)"
|
||||
},
|
||||
}
|
||||
],
|
||||
"semantic-border-alt": [
|
||||
{ "name": "--a-border-alt-1", "value": "rgba(130, 105, 162, 1)" },
|
||||
{ "name": "--a-border-alt-2", "value": "rgba(127, 137, 0, 1)" },
|
||||
{ "name": "--a-border-alt-3", "value": "rgba(0, 91, 130, 1)" }
|
||||
@@ -241,7 +249,7 @@
|
||||
{ "name": "--a-text-on-alt-2", "value": "rgba(38, 38, 38, 1)" },
|
||||
{ "name": "--a-text-on-alt-3", "value": "rgba(255, 255, 255, 1)" }
|
||||
],
|
||||
"semantic-surface": [
|
||||
"semantic-surface-default": [
|
||||
{ "name": "--a-surface-default", "value": "rgba(255, 255, 255, 1)" },
|
||||
{ "name": "--a-surface-hover", "value": "rgba(0, 0, 0, 0.05)" },
|
||||
{ "name": "--a-surface-active", "value": "rgba(0, 0, 0, 0.1)" },
|
||||
@@ -251,7 +259,9 @@
|
||||
{ "name": "--a-surface-backdrop", "value": "rgba(0, 0, 0, 0.65)" },
|
||||
{ "name": "--a-surface-inverted-hover", "value": "rgba(64, 64, 64, 1)" },
|
||||
{ "name": "--a-surface-inverted-active", "value": "rgba(89, 89, 89, 1)" },
|
||||
{ "name": "--a-surface-inverted", "value": "rgba(38, 38, 38, 1)" },
|
||||
{ "name": "--a-surface-inverted", "value": "rgba(38, 38, 38, 1)" }
|
||||
],
|
||||
"semantic-surface-action": [
|
||||
{ "name": "--a-surface-action-subtle", "value": "rgba(230, 240, 255, 1)" },
|
||||
{
|
||||
"name": "--a-surface-action-subtle-hover",
|
||||
@@ -264,7 +274,9 @@
|
||||
{
|
||||
"name": "--a-surface-action-selected-hover",
|
||||
"value": "rgba(0, 80, 119, 1)"
|
||||
},
|
||||
}
|
||||
],
|
||||
"semantic-surface-neutral": [
|
||||
{ "name": "--a-surface-neutral-subtle", "value": "rgba(0, 0, 0, 0.05)" },
|
||||
{
|
||||
"name": "--a-surface-neutral-subtle-hover",
|
||||
@@ -274,7 +286,9 @@
|
||||
{ "name": "--a-surface-neutral", "value": "rgba(89, 89, 89, 1)" },
|
||||
{ "name": "--a-surface-neutral-hover", "value": "rgba(64, 64, 64, 1)" },
|
||||
{ "name": "--a-surface-neutral-selected", "value": "rgba(38, 38, 38, 1)" },
|
||||
{ "name": "--a-surface-neutral-active", "value": "rgba(38, 38, 38, 1)" },
|
||||
{ "name": "--a-surface-neutral-active", "value": "rgba(38, 38, 38, 1)" }
|
||||
],
|
||||
"semantic-surface-success": [
|
||||
{ "name": "--a-surface-success-subtle", "value": "rgba(204, 241, 214, 1)" },
|
||||
{
|
||||
"name": "--a-surface-success-subtle-hover",
|
||||
@@ -285,7 +299,9 @@
|
||||
"value": "rgba(153, 222, 173, 1)"
|
||||
},
|
||||
{ "name": "--a-surface-success", "value": "rgba(6, 137, 58, 1)" },
|
||||
{ "name": "--a-surface-success-hover", "value": "rgba(0, 124, 46, 1)" },
|
||||
{ "name": "--a-surface-success-hover", "value": "rgba(0, 124, 46, 1)" }
|
||||
],
|
||||
"semantic-surface-danger": [
|
||||
{ "name": "--a-surface-danger-subtle", "value": "rgba(255, 194, 194, 1)" },
|
||||
{
|
||||
"name": "--a-surface-danger-subtle-hover",
|
||||
@@ -297,7 +313,9 @@
|
||||
},
|
||||
{ "name": "--a-surface-danger", "value": "rgba(195, 0, 0, 1)" },
|
||||
{ "name": "--a-surface-danger-hover", "value": "rgba(173, 0, 0, 1)" },
|
||||
{ "name": "--a-surface-danger-active", "value": "rgba(140, 0, 0, 1)" },
|
||||
{ "name": "--a-surface-danger-active", "value": "rgba(140, 0, 0, 1)" }
|
||||
],
|
||||
"semantic-surface-warning": [
|
||||
{ "name": "--a-surface-warning-subtle", "value": "rgba(255, 236, 204, 1)" },
|
||||
{
|
||||
"name": "--a-surface-warning-moderate",
|
||||
@@ -307,14 +325,18 @@
|
||||
{
|
||||
"name": "--a-surface-warning-subtle-hover",
|
||||
"value": "rgba(255, 215, 153, 1)"
|
||||
},
|
||||
}
|
||||
],
|
||||
"semantic-surface-info": [
|
||||
{ "name": "--a-surface-info-subtle", "value": "rgba(216, 249, 255, 1)" },
|
||||
{
|
||||
"name": "--a-surface-info-subtle-hover",
|
||||
"value": "rgba(181, 241, 255, 1)"
|
||||
},
|
||||
{ "name": "--a-surface-info-moderate", "value": "rgba(181, 241, 255, 1)" },
|
||||
{ "name": "--a-surface-info", "value": "rgba(102, 203, 236, 1)" },
|
||||
{ "name": "--a-surface-info", "value": "rgba(102, 203, 236, 1)" }
|
||||
],
|
||||
"semantic-surface-alt": [
|
||||
{ "name": "--a-surface-alt-1", "value": "rgba(130, 105, 162, 1)" },
|
||||
{ "name": "--a-surface-alt-1-subtle", "value": "rgba(224, 216, 233, 1)" },
|
||||
{ "name": "--a-surface-alt-1-moderate", "value": "rgba(192, 178, 210, 1)" },
|
||||
@@ -337,18 +359,22 @@
|
||||
"value": "rgba(241, 241, 241, 1)"
|
||||
}
|
||||
],
|
||||
"semantic-icon": [
|
||||
"semantic-icon-defaults": [
|
||||
{ "name": "--a-icon-default", "value": "rgba(38, 38, 38, 1)" },
|
||||
{ "name": "--a-icon-subtle", "value": "rgba(0, 0, 0, 0.65)" },
|
||||
{ "name": "--a-icon-on-neutral", "value": "rgba(255, 255, 255, 1)" },
|
||||
{ "name": "--a-icon-on-inverted", "value": "rgba(255, 255, 255, 1)" },
|
||||
{ "name": "--a-icon-on-inverted", "value": "rgba(255, 255, 255, 1)" }
|
||||
],
|
||||
"semantic-icon-action": [
|
||||
{ "name": "--a-icon-action", "value": "rgba(0, 103, 197, 1)" },
|
||||
{ "name": "--a-icon-action-selected", "value": "rgba(0, 91, 130, 1)" },
|
||||
{
|
||||
"name": "--a-icon-action-on-action-subtle",
|
||||
"value": "rgba(0, 86, 180, 1)"
|
||||
},
|
||||
{ "name": "--a-icon-on-action", "value": "rgba(255, 255, 255, 1)" },
|
||||
{ "name": "--a-icon-on-action", "value": "rgba(255, 255, 255, 1)" }
|
||||
],
|
||||
"semantic-icon-status": [
|
||||
{ "name": "--a-icon-success", "value": "rgba(6, 137, 58, 1)" },
|
||||
{ "name": "--a-icon-on-success", "value": "rgba(255, 255, 255, 1)" },
|
||||
{ "name": "--a-icon-danger", "value": "rgba(195, 0, 0, 1)" },
|
||||
@@ -356,11 +382,14 @@
|
||||
{ "name": "--a-icon-warning", "value": "rgba(199, 115, 0, 1)" },
|
||||
{ "name": "--a-icon-on-warning", "value": "rgba(38, 38, 38, 1)" },
|
||||
{ "name": "--a-icon-info", "value": "rgba(35, 107, 125, 1)" },
|
||||
{ "name": "--a-icon-on-info", "value": "rgba(38, 38, 38, 1)" },
|
||||
{ "name": "--a-icon-on-info", "value": "rgba(38, 38, 38, 1)" }
|
||||
],
|
||||
"semantic-icon-alt": [
|
||||
{ "name": "--a-icon-alt-1", "value": "rgba(99, 70, 137, 1)" },
|
||||
{ "name": "--a-icon-alt-2", "value": "rgba(127, 137, 0, 1)" },
|
||||
{ "name": "--a-icon-alt-3", "value": "rgba(51, 128, 165, 1)" }
|
||||
],
|
||||
|
||||
"semantic-data-surface": [
|
||||
{
|
||||
"name": "--a-data-surface-1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@navikt/ds-tokens",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.7",
|
||||
"description": "Design-tokens for NAV designsystem",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"keywords": [
|
||||
|
||||
+5
-12
@@ -1,19 +1,12 @@
|
||||
FROM node:18.1-alpine3.14
|
||||
RUN apk add --no-cache libc6-compat
|
||||
FROM gcr.io/distroless/nodejs:18 as runtime
|
||||
|
||||
ENV NODE_ENV production
|
||||
|
||||
WORKDIR /app
|
||||
COPY aksel.nav.no/website/.next/standalone ./
|
||||
# COPY aksel.nav.no/website/package.json .
|
||||
# COPY aksel.nav.no/website/.next/ .next/
|
||||
# COPY aksel.nav.no/website/public/ public
|
||||
# COPY aksel.nav.no/website/.env .
|
||||
# COPY aksel.nav.no/website/next.config.js .
|
||||
# COPY node_modules/ node_modules/
|
||||
# COPY @navikt/ @navikt/
|
||||
# CMD yarn start
|
||||
COPY aksel.nav.no/website/next-logger.config.js ./
|
||||
|
||||
ENV NODE_OPTIONS '-r next-logger'
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["node", "aksel.nav.no/website/server.js"]
|
||||
|
||||
CMD ["aksel.nav.no/website/server.js"]
|
||||
@@ -35,3 +35,7 @@ spec:
|
||||
- host: cdn.sanity.io
|
||||
rules: []
|
||||
env:
|
||||
filesFrom:
|
||||
- emptyDir:
|
||||
medium: Memory
|
||||
mountPath: /app/aksel.nav.no/website/.next/cache
|
||||
@@ -46,3 +46,7 @@ spec:
|
||||
age: 7
|
||||
numNewerVersions: 3
|
||||
withState: ANY
|
||||
filesFrom:
|
||||
- emptyDir:
|
||||
medium: Memory
|
||||
mountPath: /app/aksel.nav.no/website/.next/cache
|
||||
@@ -15,11 +15,11 @@
|
||||
"website"
|
||||
],
|
||||
"dependencies": {
|
||||
"@navikt/aksel-icons": "^4.1.0",
|
||||
"@navikt/ds-css": "^4.1.0",
|
||||
"@navikt/ds-react": "^4.1.0",
|
||||
"@navikt/ds-tailwind": "^4.1.0",
|
||||
"@navikt/ds-tokens": "^4.1.0"
|
||||
"@navikt/aksel-icons": "^4.1.7",
|
||||
"@navikt/ds-css": "^4.1.7",
|
||||
"@navikt/ds-react": "^4.1.7",
|
||||
"@navikt/ds-tailwind": "^4.1.7",
|
||||
"@navikt/ds-tokens": "^4.1.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier-plugin-tailwindcss": "^0.2.3"
|
||||
|
||||
@@ -25,20 +25,8 @@ import {
|
||||
UuFeedback,
|
||||
Video,
|
||||
} from ".";
|
||||
|
||||
export const InlineCode = (props: React.HTMLAttributes<HTMLElement>) => (
|
||||
<code
|
||||
className="bg-surface-alt-3-subtle/50 py-05 rounded px-1 leading-normal [font-size:_calc(16em_/_18)]"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const KBD = (props: React.HTMLAttributes<HTMLElement>) => (
|
||||
<kbd
|
||||
className="text-text-default bg-surface-default py-05 text-medium whitespace-nowrap rounded px-1 leading-normal shadow-[0_0_0_1px_var(--a-border-strong)]"
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
import { KBD } from "components/website-modules/KBD";
|
||||
import { InlineCode } from "components/website-modules/InlineCode";
|
||||
|
||||
const serializers = {
|
||||
types: {
|
||||
@@ -169,7 +157,7 @@ const serializers = {
|
||||
return (
|
||||
<BodyLong
|
||||
as="li"
|
||||
className="ml-5 mb-3 max-w-[calc(theme(spacing.text)_-_1em)]"
|
||||
className="mb-3 ml-5 max-w-[calc(theme(spacing.text)_-_1em)]"
|
||||
>
|
||||
{props.children}
|
||||
</BodyLong>
|
||||
|
||||
@@ -75,7 +75,7 @@ export const WithSidebar = ({
|
||||
<>
|
||||
<Header />
|
||||
<div className="bg-bg-default">
|
||||
<div className="mx-auto mt-6 mb-24 flex w-full max-w-screen-2xl gap-6">
|
||||
<div className="mx-auto mb-24 mt-6 flex w-full max-w-screen-2xl gap-6">
|
||||
<Sidebar kategori={pageType.type} links={sidebar} />
|
||||
<div className="relative w-full">
|
||||
<main
|
||||
@@ -83,76 +83,80 @@ export const WithSidebar = ({
|
||||
id="hovedinnhold"
|
||||
className="min-h-screen-header md:max-w-screen-sidebar relative w-full px-4 focus:outline-none sm:pl-6 sm:pr-6 md:pl-0"
|
||||
>
|
||||
<div
|
||||
className={cl(
|
||||
"relative mb-10 min-h-[12.5rem] overflow-hidden rounded-xl pl-6 pr-4 md:pl-10 lg:pr-10",
|
||||
{
|
||||
"bg-surface-subtle flex items-center justify-between":
|
||||
variant === "page",
|
||||
"bg-deepblue-700 grid py-[4.25rem] pb-6":
|
||||
variant !== "page",
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div className="z-[1]">
|
||||
{variant === "page" && pageProps?.kategori && (
|
||||
<Detail as="div" className="mb-2">
|
||||
<NextLink
|
||||
href={`/${pageType.type.toLowerCase()}`}
|
||||
passHref
|
||||
legacyBehavior
|
||||
>
|
||||
<Link className="text-text-default">
|
||||
{capitalize(pageType.type)}
|
||||
</Link>
|
||||
</NextLink>{" "}
|
||||
/ {capitalize(pageProps.kategori)}
|
||||
</Detail>
|
||||
)}
|
||||
|
||||
<Heading
|
||||
level="1"
|
||||
size="xlarge"
|
||||
className={cl({
|
||||
"text-deepblue-800": variant === "page",
|
||||
"text-text-on-action bg-deepblue-700/80 w-fit":
|
||||
<div className="from-deepblue-700 rounded-xl bg-gradient-to-br via-blue-500 to-violet-700">
|
||||
<div
|
||||
className={cl(
|
||||
"relative mb-10 min-h-[12.5rem] overflow-hidden rounded-xl pl-6 pr-4 md:pl-10 lg:pr-10",
|
||||
{
|
||||
"bg-surface-subtle flex items-center justify-between":
|
||||
variant === "page",
|
||||
"bg-deepblue-700/80 grid py-[4.25rem] pb-6":
|
||||
variant !== "page",
|
||||
})}
|
||||
>
|
||||
{pageType.title}
|
||||
</Heading>
|
||||
<div
|
||||
className={cl({
|
||||
"bg-deepblue-700/80 w-fit": variant !== "page",
|
||||
})}
|
||||
>
|
||||
{intro && intro}
|
||||
</div>
|
||||
</div>
|
||||
{variant === "page" && pageProps.status?.bilde && (
|
||||
<div
|
||||
className={cl(
|
||||
"relative hidden aspect-square h-[12.5rem] lg:block xl:mr-40",
|
||||
{
|
||||
"hue-rotate-[65deg]": pageProps?.status?.tag === "beta",
|
||||
}
|
||||
}
|
||||
)}
|
||||
>
|
||||
<div className="z-[1]">
|
||||
{variant === "page" && pageProps?.kategori && (
|
||||
<Detail as="div" className="mb-2">
|
||||
<NextLink
|
||||
href={`/${pageType.type.toLowerCase()}`}
|
||||
passHref
|
||||
legacyBehavior
|
||||
>
|
||||
<Link className="text-text-default">
|
||||
{capitalize(pageType.type)}
|
||||
</Link>
|
||||
</NextLink>{" "}
|
||||
/ {capitalize(pageProps.kategori)}
|
||||
</Detail>
|
||||
)}
|
||||
>
|
||||
<Image
|
||||
src={urlFor(pageProps.status?.bilde).auto("format").url()}
|
||||
decoding="async"
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
aria-hidden
|
||||
priority
|
||||
/>
|
||||
|
||||
<Heading
|
||||
level="1"
|
||||
size="xlarge"
|
||||
className={cl({
|
||||
"text-deepblue-800": variant === "page",
|
||||
"text-text-on-action w-fit": variant !== "page",
|
||||
})}
|
||||
>
|
||||
{pageType.title}
|
||||
</Heading>
|
||||
<div
|
||||
className={cl({
|
||||
" w-fit": variant !== "page",
|
||||
})}
|
||||
>
|
||||
{intro && intro}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{variant === "landingPage" && (
|
||||
<div className="pointer-events-none absolute top-0 right-0 hidden sm:block">
|
||||
<HeaderCube className="text-deepblue-300 z-0 max-h-full" />
|
||||
</div>
|
||||
)}
|
||||
{variant === "page" && pageProps.status?.bilde && (
|
||||
<div
|
||||
className={cl(
|
||||
"relative hidden aspect-square h-[12.5rem] lg:block xl:mr-40",
|
||||
{
|
||||
"hue-rotate-[65deg]":
|
||||
pageProps?.status?.tag === "beta",
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Image
|
||||
src={urlFor(pageProps.status?.bilde)
|
||||
.auto("format")
|
||||
.url()}
|
||||
decoding="async"
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
aria-hidden
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{variant === "landingPage" && (
|
||||
<div className="pointer-events-none absolute right-0 top-0 hidden sm:block">
|
||||
<HeaderCube className="text-deepblue-300 z-[-1] max-h-full" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={cl("sm:px-6 md:px-10", { flex: withToc })}>
|
||||
{withToc && (
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import Footer from "./Footer";
|
||||
import { Meta } from "@storybook/react";
|
||||
import { NextDecorator } from "../../StoryDecorator";
|
||||
|
||||
const MetaData: Meta = {
|
||||
component: Footer,
|
||||
tags: ["autodocs"],
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<NextDecorator>
|
||||
<Story />
|
||||
</NextDecorator>
|
||||
),
|
||||
],
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
},
|
||||
};
|
||||
|
||||
export default MetaData;
|
||||
|
||||
export const FooterDemo = {
|
||||
render: () => <Footer />,
|
||||
};
|
||||
@@ -50,7 +50,7 @@ export function Hit({
|
||||
<span className="mt-4 flex gap-2 empty:mt-0">
|
||||
{hit.item?.tema &&
|
||||
hit.item?.tema.map((x) => (
|
||||
<Tag variant="alt3" size="xsmall" key={x}>
|
||||
<Tag variant="neutral-moderate" size="xsmall" key={x}>
|
||||
{x}
|
||||
</Tag>
|
||||
))}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { useDebounce, logSearch } from "@/utils";
|
||||
import { SearchLogT, SearchResultsT, searchOptions } from "@/types";
|
||||
import { logSearch, useDebounce } from "@/utils";
|
||||
import { MagnifyingGlassIcon } from "@navikt/aksel-icons";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
CheckboxGroup,
|
||||
Detail,
|
||||
Loader,
|
||||
Search,
|
||||
} from "@navikt/ds-react";
|
||||
import { ChangeLogIconOutline } from "components/assets";
|
||||
import { SearchLogT, searchOptions, SearchResultsT } from "@/types";
|
||||
import { KBD } from "components/website-modules/KBD";
|
||||
import { useRouter } from "next/router";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import ReactModal from "react-modal";
|
||||
import { Group, GroupComponent } from "./Group";
|
||||
import styles from "../header.module.css";
|
||||
import { MagnifyingGlassIcon } from "@navikt/aksel-icons";
|
||||
import { Group, GroupComponent } from "./Group";
|
||||
|
||||
/**
|
||||
* https://www.figma.com/file/71Sm1h6VV23lbBbQ3CJJ9t/Aksel-v2?node-id=1861%3A186079&t=ARKgZcA6B7ysmG3V-0
|
||||
@@ -189,7 +189,7 @@ export const GlobalSearch = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="z-[1050] mr-4 ml-auto flex justify-center lg:mr-0 lg:ml-0">
|
||||
<div className="z-[1050] ml-auto mr-4 flex justify-center lg:ml-0 lg:mr-0">
|
||||
<Button
|
||||
variant="primary"
|
||||
className="hover:bg-deepblue-700 bg-deepblue-600 focus-visible:shadow-focus-gap h-11 focus:shadow-none"
|
||||
@@ -215,12 +215,21 @@ export const GlobalSearch = () => {
|
||||
overlayClassName={styles.modalOverlaySearch}
|
||||
>
|
||||
<div className="search-grid-wrapper relative mx-auto max-w-4xl gap-4 gap-x-8 py-24">
|
||||
<button
|
||||
className="focus-visible:shadow-focus hover:bg-surface-neutral-subtle-hover absolute top-8 right-4 flex items-center justify-center rounded py-3 px-2 text-lg focus:outline-none"
|
||||
onClick={() => handleClose()}
|
||||
{/* <button
|
||||
className="focus-visible:shadow-focus hover:bg-surface-neutral-subtle-hover absolute right-4 top-8 flex items-center justify-center gap-2 rounded px-2 py-3 text-lg focus:outline-none"
|
||||
|
||||
>
|
||||
Lukk søk <KBD>ESC</KBD>
|
||||
</button>
|
||||
<span>Lukk søk</span>
|
||||
</button> */}
|
||||
<Button
|
||||
className="absolute right-4 top-8"
|
||||
variant="tertiary-neutral"
|
||||
icon={<KBD>ESC</KBD>}
|
||||
onClick={() => handleClose()}
|
||||
iconPosition="right"
|
||||
>
|
||||
Lukk søk
|
||||
</Button>
|
||||
<div className="search-grid-filter mt-8">
|
||||
<CheckboxGroup legend="Filter" onChange={setTags}>
|
||||
{Object.entries(searchOptions)
|
||||
@@ -247,8 +256,8 @@ export const GlobalSearch = () => {
|
||||
<form role="search" onSubmit={(e) => e.preventDefault()}>
|
||||
<Search
|
||||
label={
|
||||
<span className="flex items-center">
|
||||
Søk i hele Aksel{" "}
|
||||
<span className="flex items-center gap-2">
|
||||
<span>Søk i hele Aksel</span>
|
||||
{os === "mac" ? <KBD>CMD + B</KBD> : <KBD>CTRL + B</KBD>}
|
||||
</span>
|
||||
}
|
||||
@@ -359,14 +368,3 @@ export const GlobalSearch = () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function KBD({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<Detail
|
||||
as="kbd"
|
||||
className="bg-surface-neutral-subtle-hover ml-2 hidden rounded px-2 font-sans font-semibold uppercase md:inline-block"
|
||||
>
|
||||
{children}
|
||||
</Detail>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { AkselSidebarT } from "@/types";
|
||||
import { logNav } from "@/utils";
|
||||
import { ChevronDownIcon } from "@navikt/aksel-icons";
|
||||
import { BodyShort, Detail, Tag } from "@navikt/ds-react";
|
||||
import { Detail, Tag } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
@@ -17,61 +17,52 @@ const NavItem = ({
|
||||
}) => {
|
||||
const isActive = asPath === `/${link.slug}`;
|
||||
return (
|
||||
<li
|
||||
className={cl(
|
||||
"focus-within:shadow-focus peer relative rounded-sm pl-2 before:absolute before:left-0 before:z-[-1]",
|
||||
{
|
||||
"before:border-l-border-action-selected before:top-1/2 before:h-6 before:-translate-y-1/2 before:rounded-full before:border-l-[4px]":
|
||||
isActive,
|
||||
"before:h-full before:rounded-full before:border-l before:border-l-gray-200 hover:before:top-1/2 hover:before:h-6 hover:before:-translate-y-1/2 hover:before:border-l-2 hover:before:border-l-gray-400":
|
||||
!isActive,
|
||||
}
|
||||
)}
|
||||
>
|
||||
<Link href={`/${link.slug}`} passHref legacyBehavior>
|
||||
<BodyShort
|
||||
as="a"
|
||||
size="small"
|
||||
onClick={(e) => {
|
||||
logNav(
|
||||
"meny",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
);
|
||||
}}
|
||||
className={cl(
|
||||
"hover:text-deepblue-800 relative flex overflow-hidden px-2 py-[6px] no-underline focus:outline-none",
|
||||
{
|
||||
"text-deepblue-800 font-semibold": isActive,
|
||||
"text-text-subtle": !isActive,
|
||||
}
|
||||
)}
|
||||
>
|
||||
{link.heading}
|
||||
<span className="ml-auto capitalize">
|
||||
{link.tag && ["deprecated", "beta", "new"].includes(link.tag) && (
|
||||
<Tag
|
||||
size="xsmall"
|
||||
variant={
|
||||
link.tag === "beta"
|
||||
? "alt1"
|
||||
: link.tag === "deprecated"
|
||||
? "neutral"
|
||||
: "info"
|
||||
}
|
||||
className={cl({
|
||||
"border-violet-300 bg-violet-50": link.tag === "beta",
|
||||
})}
|
||||
>
|
||||
{link.tag === "new"
|
||||
? "ny"
|
||||
<li>
|
||||
<Link
|
||||
href={`/${link.slug}`}
|
||||
onClick={(e) => {
|
||||
logNav(
|
||||
"meny",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
);
|
||||
}}
|
||||
className={cl(
|
||||
"hover:text-deepblue-800 focus-visible:shadow-focus text-medium relative flex overflow-hidden rounded-sm py-1 pl-4 pr-2 leading-snug before:rounded-full hover:before:transition-colors focus:outline-none",
|
||||
{
|
||||
"before:border-l-border-action-selected before:absolute before:left-0 before:top-1/2 before:h-6 before:-translate-y-1/2 before:border-l-[4px]":
|
||||
isActive,
|
||||
"text-deepblue-800 font-semibold": isActive,
|
||||
"text-text-subtle": !isActive,
|
||||
"before:absolute before:left-0 before:h-full before:border-l before:border-l-gray-200 hover:before:top-1/2 hover:before:h-6 hover:before:-translate-y-1/2 hover:before:border-l-2 hover:before:border-l-gray-400":
|
||||
!isActive,
|
||||
}
|
||||
)}
|
||||
>
|
||||
{link.heading}
|
||||
<span className="ml-auto capitalize">
|
||||
{link.tag && ["deprecated", "beta", "new"].includes(link.tag) && (
|
||||
<Tag
|
||||
size="xsmall"
|
||||
variant={
|
||||
link.tag === "beta"
|
||||
? "alt1"
|
||||
: link.tag === "deprecated"
|
||||
? "Avviklet"
|
||||
: link.tag}
|
||||
</Tag>
|
||||
)}
|
||||
</span>
|
||||
</BodyShort>
|
||||
? "neutral"
|
||||
: "info"
|
||||
}
|
||||
className={cl({
|
||||
"border-violet-300 bg-violet-50": link.tag === "beta",
|
||||
})}
|
||||
>
|
||||
{link.tag === "new"
|
||||
? "ny"
|
||||
: link.tag === "deprecated"
|
||||
? "Avviklet"
|
||||
: link.tag}
|
||||
</Tag>
|
||||
)}
|
||||
</span>
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
@@ -88,10 +79,10 @@ const Dropdown = ({
|
||||
const { asPath } = useRouter();
|
||||
|
||||
return (
|
||||
<li className="sidebar-dropdown w-full" data-open={open}>
|
||||
<li className="peer w-full peer-data-[open=true]:mt-6" data-open={open}>
|
||||
<button
|
||||
onClick={() => setOpen((x) => !x)}
|
||||
className="min-h-8 text-text-subtle hover:text-deepblue-800 group z-10 flex w-full cursor-pointer items-center justify-between pr-2 focus:outline-none"
|
||||
className="min-h-8 text-text-subtle hover:text-deepblue-800 group z-10 flex w-full cursor-pointer items-center justify-between focus:outline-none"
|
||||
aria-expanded={open}
|
||||
>
|
||||
<Detail
|
||||
@@ -109,16 +100,11 @@ const Dropdown = ({
|
||||
</Detail>
|
||||
</button>
|
||||
|
||||
<ul hidden={!open} className="px-2">
|
||||
<ul hidden={!open} className="pl-2">
|
||||
{links.map((z) => (
|
||||
<NavItem link={z} key={z?.heading} asPath={asPath} />
|
||||
))}
|
||||
</ul>
|
||||
<style jsx>{`
|
||||
.sidebar-dropdown[data-open="true"] + .sidebar-dropdown {
|
||||
margin-top: var(--a-spacing-6);
|
||||
}
|
||||
`}</style>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
@@ -135,10 +121,10 @@ export const Sidebar = ({
|
||||
return (
|
||||
<div
|
||||
data-testid="ds-sidebar"
|
||||
className="toc-ignore w-sidebar bg-surface-default z-[1002] hidden shrink-0 self-start pb-4 md:block"
|
||||
className="toc-ignore w-sidebar bg-surface-default z-[1002] hidden shrink-0 self-start overflow-x-auto pb-8 pl-6 pr-2 md:block"
|
||||
>
|
||||
<nav aria-label={kategori} className={cl("overflow-x-auto")}>
|
||||
<ul className="pb-4 pl-6">
|
||||
<nav aria-label={kategori}>
|
||||
<ul>
|
||||
{sections.map((kat) => (
|
||||
<Dropdown links={kat.pages} title={kat.title} key={kat.title} />
|
||||
))}
|
||||
|
||||
@@ -3,37 +3,36 @@ import { withErrorBoundary } from "@/error-boundary";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { DoDontT } from "@/types";
|
||||
import {
|
||||
CheckmarkCircleFillIcon,
|
||||
ExclamationmarkTriangleFillIcon,
|
||||
XMarkOctagonFillIcon,
|
||||
CheckmarkIcon,
|
||||
ExclamationmarkIcon,
|
||||
XMarkIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import { BodyShort } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import React from "react";
|
||||
|
||||
const GetIcon = (s: string) => {
|
||||
switch (s) {
|
||||
case "do":
|
||||
return (
|
||||
<CheckmarkCircleFillIcon
|
||||
<CheckmarkIcon
|
||||
aria-hidden
|
||||
fontSize="1.5rem"
|
||||
fontSize="2rem"
|
||||
className="flex-shrink-0 text-green-500"
|
||||
/>
|
||||
);
|
||||
case "dont":
|
||||
return (
|
||||
<XMarkOctagonFillIcon
|
||||
<XMarkIcon
|
||||
aria-hidden
|
||||
fontSize="1.5rem"
|
||||
fontSize="2rem"
|
||||
className="flex-shrink-0 text-red-500"
|
||||
/>
|
||||
);
|
||||
case "warning":
|
||||
return (
|
||||
<ExclamationmarkTriangleFillIcon
|
||||
<ExclamationmarkIcon
|
||||
aria-hidden
|
||||
fontSize="1.5rem"
|
||||
fontSize="2rem"
|
||||
className="flex-shrink-0 text-orange-500"
|
||||
/>
|
||||
);
|
||||
@@ -42,42 +41,56 @@ const GetIcon = (s: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getText = (s: string) => {
|
||||
switch (s) {
|
||||
case "do":
|
||||
return "Do: ";
|
||||
case "dont":
|
||||
return "Don't: ";
|
||||
case "warning":
|
||||
return "Fare på ferde: ";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const Element = ({ block }: { block: DoDontT["blokker"][number] }) => {
|
||||
if (!block.picture) return null;
|
||||
return (
|
||||
<figure
|
||||
className={cl("sm:min-w-80 flex min-w-full flex-1 flex-col rounded-t", {
|
||||
className={cl("sm:min-w-80 flex min-w-full flex-1 flex-col", {
|
||||
"basis-full": block?.fullwidth,
|
||||
"max-w-sm": !block?.fullwidth,
|
||||
})}
|
||||
>
|
||||
<img
|
||||
className="ring-border-subtle rounded-t bg-gray-50 ring-1"
|
||||
alt={block.alt}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
src={urlFor(block.picture).auto("format").url()}
|
||||
/>
|
||||
<div
|
||||
className={cl(
|
||||
"z-10 -ml-[1px] w-[calc(100%_+_2px)] rounded-b border-t-8",
|
||||
"relative z-10 -ml-[1px] w-[calc(100%_+_2px)] border-t-4",
|
||||
{
|
||||
"border-t-border-success": block.variant === "do",
|
||||
"border-t-border-danger": block.variant === "dont",
|
||||
"border-t-surface-warning": block.variant === "warning",
|
||||
}
|
||||
)}
|
||||
aria-hidden
|
||||
>
|
||||
<span className="absolute right-[10px] z-10 translate-y-2">
|
||||
{GetIcon(block.variant)}
|
||||
</span>
|
||||
</div>
|
||||
<img
|
||||
className="ring-border-subtle bg-gray-50 ring-1"
|
||||
alt={block.alt}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
src={urlFor(block.picture).auto("format").url()}
|
||||
/>
|
||||
<figcaption data-variant={block.variant}>
|
||||
<div className="mt-3">
|
||||
{block.description && (
|
||||
<BodyShort
|
||||
size="small"
|
||||
as="span"
|
||||
className="inline-flex items-center gap-2"
|
||||
>
|
||||
{GetIcon(block.variant)}
|
||||
{block.description}
|
||||
<BodyShort size="small" as="span">
|
||||
<span className="font-semibold">{getText(block.variant)}</span>
|
||||
<span>{block.description}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,9 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { UUTableT } from "@/types";
|
||||
import cl from "clsx";
|
||||
import React from "react";
|
||||
import { KBD } from "components/website-modules/KBD";
|
||||
|
||||
const KBD = (props: React.HTMLAttributes<HTMLElement>) => (
|
||||
<kbd
|
||||
className={cl(
|
||||
"mx-05 my-0 inline-block min-w-[2rem] rounded-md border border-gray-300 bg-gray-100 py-[1px] px-2 text-center font-mono text-sm text-gray-900"
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
import React from "react";
|
||||
|
||||
const UuSeksjon = ({ node }: { node: UUTableT }) => {
|
||||
if (!node || !node?.tastatur) {
|
||||
@@ -18,7 +11,7 @@ const UuSeksjon = ({ node }: { node: UUTableT }) => {
|
||||
}
|
||||
|
||||
const getKey = (s: string) => (
|
||||
<span className="flex w-full flex-wrap gap-x-1 gap-y-2">
|
||||
<span className="my-1 flex w-full flex-wrap gap-x-1 gap-y-2">
|
||||
{s
|
||||
.trim()
|
||||
.split(" ")
|
||||
@@ -32,27 +25,14 @@ const UuSeksjon = ({ node }: { node: UUTableT }) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<table className="mb-7 w-full border-separate border-spacing-0 rounded border border-gray-300">
|
||||
<thead>
|
||||
<tr className="rounded-t">
|
||||
<td className="rounded-tl bg-gray-50 p-2 ">Kommando</td>
|
||||
<td className="rounded-tr bg-gray-50 p-2 ">Interaksjon</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="">
|
||||
{node.tastatur.map((x) => (
|
||||
<tr
|
||||
key={x._key}
|
||||
className="peer border-b border-t border-gray-300 text-base last-of-type:rounded-b"
|
||||
>
|
||||
<td className="border-t border-r border-gray-300 p-2">
|
||||
{getKey(x.key)}
|
||||
</td>
|
||||
<td className="border-t border-gray-300 p-2">{x.action}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<AkselTable th={[{ text: "Kommando" }, { text: "Interaksjon" }]}>
|
||||
{node.tastatur.map((x) => (
|
||||
<AkselTableRow
|
||||
key={x._key}
|
||||
tr={[{ text: getKey(x.key) }, { text: x.action }]}
|
||||
/>
|
||||
))}
|
||||
</AkselTable>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ChevronDownCircleIcon } from "@navikt/aksel-icons";
|
||||
import core from "@navikt/ds-css/tokens.json";
|
||||
import { BodyLong, CopyButton, Label, Link } from "@navikt/ds-react";
|
||||
import cl from "classnames";
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
import NextLink from "next/link";
|
||||
import { useState } from "react";
|
||||
|
||||
@@ -27,27 +28,13 @@ const TokenTable = ({ node }: { node: TokenTableT }) => {
|
||||
!open && showMore,
|
||||
})}
|
||||
>
|
||||
<table className="border-border-divider w-full border-separate border-spacing-0 rounded-t border">
|
||||
<thead>
|
||||
<tr className="rounded-t">
|
||||
<td className="rounded-tl bg-gray-50 p-2 ">Token</td>
|
||||
<td className="rounded-tr bg-gray-50 p-2 ">Fallback</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.entries(tokens).map(([key, val]) => (
|
||||
<tr
|
||||
key={key}
|
||||
className="peer border-b border-t border-gray-300 font-mono text-sm last-of-type:rounded-b"
|
||||
>
|
||||
<td className="border-r border-t border-gray-300 p-2">{key}</td>
|
||||
<td className="border-t border-gray-300 p-2">{val}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<AkselTable th={[{ text: "Token" }, { text: "Fallback" }]}>
|
||||
{Object.entries(tokens).map(([key, val]) => (
|
||||
<AkselTableRow key={key} tr={[{ text: key }, { text: val }]} />
|
||||
))}
|
||||
</AkselTable>
|
||||
{(open || !showMore) && (
|
||||
<div className="border-border-divider bg-surface-neutral-subtle relative w-full rounded-b border border-t-0 p-2 pr-14">
|
||||
<div className="border-border-subtle bg-surface-default relative -mt-8 w-full rounded-b border border-t-0 p-2 pr-14">
|
||||
<CopyButton
|
||||
copyText={Object.entries(tokens).reduce(
|
||||
(prev, cur) =>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
|
||||
import {
|
||||
ResolveContributorsSingleT,
|
||||
ResolveTemaT,
|
||||
ResolveSlugT,
|
||||
AkselGodPraksisDocT,
|
||||
ResolveContributorsSingleT,
|
||||
ResolveSlugT,
|
||||
ResolveTemaT,
|
||||
} from "@/types";
|
||||
import { BodyShort, Detail, Heading } from "@navikt/ds-react";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import NextLink from "next/link";
|
||||
import { abbrName, dateStr, logNav } from "../..";
|
||||
import { abbrName, logNav } from "../..";
|
||||
|
||||
const ArtikkelCard = ({
|
||||
slug,
|
||||
@@ -25,11 +26,9 @@ const ArtikkelCard = ({
|
||||
}: ResolveContributorsSingleT<
|
||||
ResolveTemaT<ResolveSlugT<AkselGodPraksisDocT>>
|
||||
> & { source: string; variant: string; level?: "2" | "3" }) => {
|
||||
const date = (rest as any)?.updateInfo?.lastVerified
|
||||
? (rest as any)?.updateInfo?.lastVerified
|
||||
: publishedAt
|
||||
? publishedAt
|
||||
: _updatedAt;
|
||||
const date = useFormatedDate(
|
||||
(rest as any)?.updateInfo?.lastVerified ?? publishedAt ?? _updatedAt
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="hover:shadow-small focus-within:ring-border-focus bg-surface-default ring-border-subtle group relative rounded-lg p-3 pb-16 ring-1 focus-within:ring-[3px] sm:p-5 sm:pb-16">
|
||||
@@ -70,7 +69,7 @@ const ArtikkelCard = ({
|
||||
</Detail>
|
||||
)}
|
||||
<Detail as="span" className="text-text-subtle">
|
||||
{dateStr(date)}
|
||||
{date}
|
||||
</Detail>
|
||||
</span>
|
||||
) : (
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import { getAuthors } from "components/website-modules/LatestBloggs";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import NextLink from "next/link";
|
||||
import { dateStr, logNav } from "../..";
|
||||
import { getAuthors, logNav } from "@/utils";
|
||||
|
||||
const BloggCard = ({
|
||||
blog,
|
||||
}: {
|
||||
blog: ResolveContributorsT<ResolveSlugT<AkselBloggDocT>>;
|
||||
}) => {
|
||||
const date = useFormatedDate(blog?.publishedAt ?? blog._createdAt);
|
||||
return (
|
||||
<li
|
||||
key={blog._id}
|
||||
@@ -38,7 +39,7 @@ const BloggCard = ({
|
||||
className="text-text-subtle mt-auto flex gap-2 justify-self-end"
|
||||
>
|
||||
<span className="font-semibold">{getAuthors(blog)[0]}</span>
|
||||
<span>{dateStr(blog?.publishedAt ?? blog._createdAt)}</span>
|
||||
<span>{date}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</li>
|
||||
|
||||
@@ -82,6 +82,7 @@ const ComponentExamples = ({ node }: { node: CodeExapmplesT }) => {
|
||||
{node.dir.filer.map((fil) => {
|
||||
return (
|
||||
<Chips.Toggle
|
||||
checkmark={false}
|
||||
key={fil._key}
|
||||
value={fil.navn}
|
||||
selected={active === fil.navn}
|
||||
|
||||
@@ -46,8 +46,9 @@ const CodeSnippet = ({
|
||||
>
|
||||
<CopyButton
|
||||
data-theme="dark"
|
||||
size="small"
|
||||
copyText={code.code}
|
||||
className={cl(style.copybutton, "absolute top-2 right-2 z-10")}
|
||||
className={cl(style.copybutton, "absolute right-2 top-2 z-10")}
|
||||
/>
|
||||
<Highlight
|
||||
code={code.code}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { abbrName, dateStr } from "@/utils";
|
||||
import { BodyShort, Detail, Heading } from "@navikt/ds-react";
|
||||
import { logNav } from "components/website-modules/utils/amplitude";
|
||||
import NextLink from "next/link";
|
||||
import NextImage from "next/legacy/image";
|
||||
import { Tag } from "./Tag";
|
||||
import cl from "clsx";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { abbrName } from "@/utils";
|
||||
import { BodyShort, Detail, Heading } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { logNav } from "components/website-modules/utils/amplitude";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import NextImage from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
import { Tag } from "./Tag";
|
||||
|
||||
export type ArticleT = {
|
||||
_key: string;
|
||||
@@ -37,7 +38,7 @@ const Card = ({
|
||||
visible: boolean;
|
||||
index: number;
|
||||
}) => {
|
||||
const date = article.publishedAt ? article.publishedAt : article._updatedAt;
|
||||
const date = useFormatedDate(article.publishedAt ?? article._updatedAt);
|
||||
|
||||
const showFooter = ["aksel_artikkel", "aksel_blogg"].includes(article._type);
|
||||
const showImage = [
|
||||
@@ -142,7 +143,7 @@ const Card = ({
|
||||
{abbrName(article?.contributors[0]?.title)}
|
||||
</Detail>
|
||||
)}
|
||||
<Detail as="span">{dateStr(date)}</Detail>
|
||||
<Detail as="span">{date}</Detail>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { getAuthors, logNav } from "@/utils";
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import Image from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
import { ArticleT } from "./Card";
|
||||
import { Tag } from "./Tag";
|
||||
|
||||
export const Highlight = ({
|
||||
article,
|
||||
compact,
|
||||
}: {
|
||||
article: ArticleT;
|
||||
compact: boolean;
|
||||
}) => {
|
||||
const showFooter = ["aksel_artikkel", "aksel_blogg"].includes(article._type);
|
||||
const useStatusImage =
|
||||
["ds_artikkel", "komponent_artikkel"].includes(article._type) &&
|
||||
article.status?.bilde;
|
||||
|
||||
const date = useFormatedDate(article?.publishedAt ?? article._createdAt);
|
||||
|
||||
return (
|
||||
<section
|
||||
aria-label={`Fremhevet artikkel: ${article?.heading}`}
|
||||
className={cl({
|
||||
"grid content-start gap-8 md:grid-cols-2": compact,
|
||||
"grid content-start gap-6": !compact,
|
||||
})}
|
||||
>
|
||||
<div className="relative block aspect-video">
|
||||
{useStatusImage ? (
|
||||
<Image
|
||||
src={urlFor(article.status.bilde).quality(100).auto("format").url()}
|
||||
quality={100}
|
||||
layout="fill"
|
||||
aria-hidden
|
||||
priority
|
||||
className={cl(
|
||||
"bg-deepblue-200 rounded-lg object-cover sm:object-contain",
|
||||
{
|
||||
"hue-rotate-[65deg]": article?.status?.tag === "beta",
|
||||
}
|
||||
)}
|
||||
decoding="sync"
|
||||
/>
|
||||
) : article?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(article.seo.image).quality(100).auto("format").url()}
|
||||
quality={100}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className={cl("rounded-lg", {
|
||||
"hue-rotate-[65deg]": article?.status?.tag === "beta",
|
||||
})}
|
||||
decoding="sync"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(article?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
decoding="sync"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<Tag
|
||||
type={article._type}
|
||||
text={article.tema ? article.tema[0] : undefined}
|
||||
beta={article?.status?.tag === "beta"}
|
||||
/>
|
||||
<NextLink href={`/${article.slug.current}`} passHref legacyBehavior>
|
||||
<Link
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"artikkel-kort",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
className="text-text-default mb-5 mt-2 no-underline hover:underline"
|
||||
>
|
||||
<Heading size="large" level="3">
|
||||
{article?.heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mb-4" size="small">
|
||||
{article?.ingress ?? article.seo?.meta}
|
||||
</BodyLong>
|
||||
{showFooter && getAuthors(article as any).length > 0 && (
|
||||
<BodyShort size="small" className="text-text-subtle flex gap-2">
|
||||
<span className="font-semibold">
|
||||
{getAuthors(article as any)[0]}
|
||||
</span>
|
||||
<span>{date}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
@@ -1,16 +1,10 @@
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import Masonry, { ResponsiveMasonry } from "react-responsive-masonry";
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import Image from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import { getAuthors } from "components/website-modules/LatestBloggs";
|
||||
import { dateStr, logNav } from "@/utils";
|
||||
import { Tag } from "./Tag";
|
||||
import Card, { ArticleT } from "./Card";
|
||||
import { Heading } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import Masonry, { ResponsiveMasonry } from "react-responsive-masonry";
|
||||
import Card, { ArticleT } from "./Card";
|
||||
import { Highlight } from "./Highlight";
|
||||
|
||||
export type LatestT = {
|
||||
_type: "nytt_fra_aksel";
|
||||
@@ -29,9 +23,12 @@ const Latest = ({ block }: { block: LatestT }) => {
|
||||
const section = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(([entry]) => {
|
||||
entry.isIntersecting && setIntersected(entry.isIntersecting);
|
||||
});
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => {
|
||||
entry.isIntersecting && setIntersected(entry.isIntersecting);
|
||||
},
|
||||
{ rootMargin: "0px 0px 100px 0px" }
|
||||
);
|
||||
observer.observe(section.current);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
@@ -74,99 +71,9 @@ function Highlights({ highlights }: { highlights: ArticleT[] }) {
|
||||
<div
|
||||
className={cl({ "grid gap-8 md:grid-cols-2": highlights?.length === 2 })}
|
||||
>
|
||||
{highlights.map((x, idx) => {
|
||||
const showFooter = ["aksel_artikkel", "aksel_blogg"].includes(x._type);
|
||||
const useStatusImage =
|
||||
["ds_artikkel", "komponent_artikkel"].includes(x._type) &&
|
||||
x.status?.bilde;
|
||||
return (
|
||||
<section
|
||||
aria-label={`Fremhevet artikkel: ${x?.heading}`}
|
||||
key={idx}
|
||||
className={cl({
|
||||
"grid content-start gap-8 md:grid-cols-2":
|
||||
highlights?.length === 1,
|
||||
"grid content-start gap-6": highlights?.length === 2,
|
||||
})}
|
||||
>
|
||||
<div className="relative block aspect-video">
|
||||
{useStatusImage ? (
|
||||
<Image
|
||||
src={urlFor(x.status.bilde).quality(100).auto("format").url()}
|
||||
quality={100}
|
||||
layout="fill"
|
||||
aria-hidden
|
||||
priority
|
||||
className={cl(
|
||||
"bg-deepblue-200 rounded-lg object-cover sm:object-contain",
|
||||
{
|
||||
"hue-rotate-[65deg]": x?.status?.tag === "beta",
|
||||
}
|
||||
)}
|
||||
decoding="sync"
|
||||
/>
|
||||
) : x?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(x.seo.image).quality(100).auto("format").url()}
|
||||
quality={100}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className={cl("rounded-lg", {
|
||||
"hue-rotate-[65deg]": x?.status?.tag === "beta",
|
||||
})}
|
||||
decoding="sync"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(x?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
decoding="sync"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<Tag
|
||||
type={x._type}
|
||||
text={x.tema ? x.tema[0] : undefined}
|
||||
beta={x?.status?.tag === "beta"}
|
||||
/>
|
||||
<NextLink href={`/${x.slug.current}`} passHref legacyBehavior>
|
||||
<Link
|
||||
onClick={(e) =>
|
||||
logNav(
|
||||
"artikkel-kort",
|
||||
window.location.pathname,
|
||||
e.currentTarget.getAttribute("href")
|
||||
)
|
||||
}
|
||||
className="text-text-default mb-5 mt-2 no-underline hover:underline"
|
||||
>
|
||||
<Heading size="large" level="3">
|
||||
{x?.heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mb-4" size="small">
|
||||
{x?.ingress ?? x.seo?.meta}
|
||||
</BodyLong>
|
||||
{showFooter && getAuthors(x as any).length > 0 && (
|
||||
<BodyShort size="small" className="text-text-subtle flex gap-2">
|
||||
<span className="font-semibold">
|
||||
{getAuthors(x as any)[0]}
|
||||
</span>
|
||||
<span>{dateStr(x?.publishedAt ?? x._createdAt)}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
})}
|
||||
{highlights.map((x, idx) => (
|
||||
<Highlight article={x} key={idx} compact={highlights.length === 1} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
import { TipsT } from "@/types";
|
||||
import Tips from "./index";
|
||||
|
||||
export default {
|
||||
title: "Components/Tips",
|
||||
component: Tips,
|
||||
};
|
||||
|
||||
const mockData: TipsT = {
|
||||
_key: "eb522d23896b",
|
||||
body: [
|
||||
{
|
||||
_key: "86a3e733e9bb",
|
||||
_type: "block",
|
||||
children: [
|
||||
{
|
||||
_key: "5d65a8d0f1760",
|
||||
_type: "span",
|
||||
marks: [],
|
||||
text: "Cupidatat nostrud occaecat incididunt elit adipisicing consequat eu ex anim qui officia mollit.",
|
||||
},
|
||||
{
|
||||
_key: "5d65a8d0f1760",
|
||||
_type: "span",
|
||||
marks: [],
|
||||
text: "Sint incididunt non incididunt ipsum ad esse officia.",
|
||||
},
|
||||
],
|
||||
markDefs: [],
|
||||
style: "normal",
|
||||
},
|
||||
],
|
||||
eksperiment: false,
|
||||
};
|
||||
|
||||
export const TipsDemo = () => <Tips node={mockData as any} />;
|
||||
export const TipsDemoAksel = () => (
|
||||
<div className="aksel-artikkel bg-surface-subtle">
|
||||
<Tips node={mockData as any} />
|
||||
</div>
|
||||
);
|
||||
|
||||
export const TipsDemoExperiment = () => (
|
||||
<Tips node={{ ...mockData, eksperiment: true } as any} />
|
||||
);
|
||||
@@ -0,0 +1,49 @@
|
||||
import { CheckmarkIcon, ClipboardIcon } from "@navikt/aksel-icons";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import cl from "clsx";
|
||||
|
||||
export const Copy = ({ text, copyText }) => {
|
||||
const [active, setActive] = useState(false);
|
||||
const [canfade, setCanfade] = useState(false);
|
||||
const timeoutRef = useRef<number>();
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
timeoutRef.current && clearTimeout(timeoutRef.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleClick = () => {
|
||||
timeoutRef.current && clearTimeout(timeoutRef.current);
|
||||
setCanfade(true);
|
||||
navigator.clipboard.writeText(copyText);
|
||||
setActive(true);
|
||||
|
||||
timeoutRef.current = window.setTimeout(() => {
|
||||
setActive(false);
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
aria-live="polite"
|
||||
className="py-05 focus-visible:shadow-focus min-h-8 text-medium hover:bg-surface-neutral-subtle-hover group rounded px-1 leading-none focus:outline-none"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<span className="inline-flex flex-row-reverse items-center gap-1">
|
||||
<span>
|
||||
{active ? (
|
||||
<CheckmarkIcon title="Kopiert" className="animate-textbounce" />
|
||||
) : (
|
||||
<ClipboardIcon
|
||||
title="Kopier css-variabel"
|
||||
className={cl(canfade && "animate-fadeIn")}
|
||||
/>
|
||||
)}
|
||||
</span>
|
||||
<span aria-live="polite">{text}</span>
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -1,70 +0,0 @@
|
||||
import { CheckmarkIcon, FilesIcon } from "@navikt/aksel-icons";
|
||||
import cl from "clsx";
|
||||
import copystring from "copy-to-clipboard";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
export const CopyToken = ({ val }: { val: string }) => {
|
||||
const timerRef = useRef(null);
|
||||
|
||||
const [copyTimer, setCopyTimer] = useState(false);
|
||||
const [done, setDone] = useState(true);
|
||||
|
||||
const copyToken = () => {
|
||||
copystring(`var(${val})`);
|
||||
|
||||
if (done) {
|
||||
clearTimeout(timerRef.current);
|
||||
setCopyTimer(true);
|
||||
setDone(false);
|
||||
timerRef.current = setTimeout(() => {
|
||||
setCopyTimer(false);
|
||||
setDone(true);
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
return () => clearTimeout(timerRef.current);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={() => copyToken()}
|
||||
className="bg-surface-subtle z-1000 hover:text-text-subtle focus-visible:border-border-focus border-surface-default group relative h-8 w-full overflow-x-hidden overflow-y-hidden whitespace-nowrap rounded border-2 font-mono text-sm focus-visible:outline-none"
|
||||
aria-label={
|
||||
copyTimer ? "kopierte token" : `kopier ${val.replace("--a-", "")}`
|
||||
}
|
||||
>
|
||||
<span
|
||||
className={cl("flex h-7 w-full items-center justify-between px-2", {
|
||||
"animate-popout -translate-y-full": copyTimer,
|
||||
})}
|
||||
>
|
||||
<span aria-hidden>{val}</span>
|
||||
|
||||
<span className="text-text-subtle bg-surface-subtle group-hover:text-text-default text-md absolute right-2 flex h-7 translate-x-3/4 items-center gap-1 px-1 shadow-[-7px_0_8px_0px_var(--a-surface-subbg-surface-subtle)] transition-transform duration-200 group-hover:translate-x-0">
|
||||
<FilesIcon aria-hidden className="h-4 w-4 flex-shrink-0" />
|
||||
<span className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">
|
||||
Kopier
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className={cl(
|
||||
"bg-surface-action-selected text-md text-text-on-action flex h-7 w-full px-2 font-sans text-sm",
|
||||
{ "animate-popup translate-y-[-100%]": copyTimer }
|
||||
)}
|
||||
aria-hidden
|
||||
>
|
||||
<span
|
||||
className={cl("flex w-full items-center justify-center gap-1", {
|
||||
"animate-textbounce": copyTimer,
|
||||
})}
|
||||
>
|
||||
<CheckmarkIcon aria-hidden className="h-5 w-5 flex-shrink-0" />
|
||||
Kopiert
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
@@ -1,77 +0,0 @@
|
||||
import { Detail } from "@navikt/ds-react";
|
||||
import { CopyToken } from "./CopyToken";
|
||||
|
||||
export const Frame = ({
|
||||
tokens,
|
||||
styles,
|
||||
element: Element,
|
||||
showHex,
|
||||
}: {
|
||||
tokens: { name: string; value: string; description?: string }[];
|
||||
styles?: string;
|
||||
element?: ({ token, name }: { token: string; name?: string }) => JSX.Element;
|
||||
showHex?: boolean;
|
||||
}) => {
|
||||
const hasDescription = !!tokens.find((x) => x?.description);
|
||||
return (
|
||||
<table className="w-full">
|
||||
<thead className="sr-only">
|
||||
<tr>
|
||||
<td />
|
||||
<th>Token navn</th>
|
||||
<th>Verdi</th>
|
||||
{hasDescription && <th>Beskrivelse</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="component-token-grid grid grid-cols-[repeat(auto-fill,_minmax(min(20rem,_100%),_1fr))] gap-4">
|
||||
{tokens.map((c) => (
|
||||
<tr
|
||||
key={c.name}
|
||||
className="ring-border-subtle flex flex-col justify-start rounded-md p-3 align-top ring-1"
|
||||
>
|
||||
<td className="component-checkered-bg rounded-md p-0">
|
||||
{Element ? (
|
||||
<Element token={c.value} name={c.name} />
|
||||
) : (
|
||||
<div
|
||||
style={{ [styles]: c.value }}
|
||||
className="min-h-16 shadow-small h-full w-full rounded-md"
|
||||
aria-hidden
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
<td className="mt-3 w-full overflow-x-hidden">
|
||||
<CopyToken val={c.name} />
|
||||
</td>
|
||||
<td className="mt-2 font-mono text-sm tracking-tighter">
|
||||
{c.value}
|
||||
</td>
|
||||
<Detail as="td" className="mt-1">
|
||||
{showHex ? getHex(c.value) : c.description}
|
||||
</Detail>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
function getHex(value: string) {
|
||||
return RGBAToHexA(value.replace(", 1)", ""));
|
||||
}
|
||||
|
||||
/* https://stackoverflow.com/a/73401564 */
|
||||
function RGBAToHexA(rgba, forceRemoveAlpha = false) {
|
||||
return (
|
||||
"#" +
|
||||
rgba
|
||||
.replace(/^rgba?\(|\s+|\)$/g, "") // Get's rgba / rgb string values
|
||||
.split(",") // splits them at ","
|
||||
.filter((string, index) => !forceRemoveAlpha || index !== 3)
|
||||
.map((string) => parseFloat(string)) // Converts them to numbers
|
||||
.map((number, index) => (index === 3 ? Math.round(number * 255) : number)) // Converts alpha to 255 number
|
||||
.map((number) => number.toString(16)) // Converts numbers to hex
|
||||
.map((string) => (string.length === 1 ? "0" + string : string)) // Adds 0 when length of one number is 1
|
||||
.join("")
|
||||
); // Puts the array to togehter to a string
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
import cl from "clsx";
|
||||
|
||||
export const Grid = ({
|
||||
children,
|
||||
stacked = false,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
stacked?: boolean;
|
||||
}) => (
|
||||
<div
|
||||
className={cl("mt-8 grid", {
|
||||
"grid-cols-[repeat(auto-fit,_minmax(16rem,_1fr))] gap-6 xl:grid-cols-3":
|
||||
!stacked,
|
||||
"gap-8": stacked,
|
||||
})}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
+41
-105
@@ -1,126 +1,62 @@
|
||||
import {
|
||||
LaptopIcon,
|
||||
MobileIcon,
|
||||
MobileSmallIcon,
|
||||
MonitorIcon,
|
||||
TabletIcon,
|
||||
} from "@navikt/aksel-icons";
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { Frame } from "../Frame";
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
|
||||
export const BreakpointsView = ({ cat }: { cat: string }) => {
|
||||
const breakpoints = docs[cat];
|
||||
|
||||
return (
|
||||
<Frame
|
||||
tokens={breakpoints}
|
||||
element={({ name }: { token: string; name?: string }) => {
|
||||
const Svg = getSvg(name);
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 bg-surface-default flex h-full w-full items-center justify-start rounded-md px-4 text-5xl font-semibold"
|
||||
aria-hidden
|
||||
>
|
||||
{Svg}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<AkselTable
|
||||
withCopy
|
||||
th={[
|
||||
{ text: "Enhet" },
|
||||
{ text: "Verdi" },
|
||||
{ text: "Media queries", hideOnSm: true },
|
||||
{ text: "Bruk" },
|
||||
]}
|
||||
>
|
||||
{breakpoints.map((x) => (
|
||||
<AkselTableRow
|
||||
key={x.name}
|
||||
tr={[
|
||||
{ text: getSvg(x.name) },
|
||||
{ text: x.value },
|
||||
{ text: x.description, hideOnSm: true },
|
||||
{
|
||||
text:
|
||||
Number(x.value.replace("px", "")) % 2 === 0
|
||||
? "Mobile first"
|
||||
: "Desktop first",
|
||||
},
|
||||
]}
|
||||
copyText={x.name}
|
||||
/>
|
||||
))}
|
||||
</AkselTable>
|
||||
);
|
||||
};
|
||||
|
||||
function getSvg(token: string) {
|
||||
switch (true) {
|
||||
case token.includes("xs"):
|
||||
return (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
focusable={false}
|
||||
aria-hidden
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M7.75 5.77778C7.75 5.16382 8.20527 4.75 8.66667 4.75H15.3333C15.7947 4.75 16.25 5.16382 16.25 5.77778V18.2222C16.25 18.8362 15.7947 19.25 15.3333 19.25H8.66667C8.20527 19.25 7.75 18.8362 7.75 18.2222V5.77778ZM8.66667 3.25C7.28712 3.25 6.25 4.42806 6.25 5.77778V18.2222C6.25 19.5719 7.28712 20.75 8.66667 20.75H15.3333C16.7129 20.75 17.75 19.5719 17.75 18.2222V5.77778C17.75 4.42806 16.7129 3.25 15.3333 3.25H8.66667ZM12 16.75C11.5858 16.75 11.25 17.0858 11.25 17.5C11.25 17.9142 11.5858 18.25 12 18.25H12.01C12.4242 18.25 12.76 17.9142 12.76 17.5C12.76 17.0858 12.4242 16.75 12.01 16.75H12Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
return <MobileSmallIcon title="Mobile small" fontSize="2.5rem" />;
|
||||
|
||||
case token.includes("sm"):
|
||||
return (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
focusable={false}
|
||||
aria-hidden
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M6.75 5C6.75 4.30964 7.30964 3.75 8 3.75H16C16.6904 3.75 17.25 4.30964 17.25 5V19C17.25 19.6904 16.6904 20.25 16 20.25H8C7.30964 20.25 6.75 19.6904 6.75 19V5ZM8 2.25C6.48122 2.25 5.25 3.48122 5.25 5V19C5.25 20.5188 6.48122 21.75 8 21.75H16C17.5188 21.75 18.75 20.5188 18.75 19V5C18.75 3.48122 17.5188 2.25 16 2.25H8ZM11.5 4.75C11.0858 4.75 10.75 5.08579 10.75 5.5C10.75 5.91421 11.0858 6.25 11.5 6.25H12.5C12.9142 6.25 13.25 5.91421 13.25 5.5C13.25 5.08579 12.9142 4.75 12.5 4.75H11.5Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
return <MobileIcon title="Mobile regular" fontSize="2.5rem" />;
|
||||
|
||||
case token.includes("md"):
|
||||
return (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
focusable={false}
|
||||
aria-hidden
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M3.75 6C3.75 5.30964 4.30964 4.75 5 4.75H19C19.6904 4.75 20.25 5.30964 20.25 6V18C20.25 18.6904 19.6904 19.25 19 19.25H5C4.30964 19.25 3.75 18.6904 3.75 18V6ZM5 3.25C3.48122 3.25 2.25 4.48122 2.25 6V18C2.25 19.5188 3.48122 20.75 5 20.75H19C20.5188 20.75 21.75 19.5188 21.75 18V6C21.75 4.48122 20.5188 3.25 19 3.25H5ZM10.5 5.75C10.0858 5.75 9.75 6.08579 9.75 6.5C9.75 6.91421 10.0858 7.25 10.5 7.25H13.5C13.9142 7.25 14.25 6.91421 14.25 6.5C14.25 6.08579 13.9142 5.75 13.5 5.75H10.5Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
return <TabletIcon title="Tablet" fontSize="2.5rem" />;
|
||||
|
||||
case token.includes("lg"):
|
||||
return (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
focusable={false}
|
||||
aria-hidden
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M5.5 4.25C4.5335 4.25 3.75 5.0335 3.75 6V15C3.75 15.9665 4.5335 16.75 5.5 16.75H18.5C19.4665 16.75 20.25 15.9665 20.25 15V6C20.25 5.0335 19.4665 4.25 18.5 4.25H5.5ZM5.25 6C5.25 5.86193 5.36193 5.75 5.5 5.75H18.5C18.6381 5.75 18.75 5.86193 18.75 6V15C18.75 15.1381 18.6381 15.25 18.5 15.25H5.5C5.36193 15.25 5.25 15.1381 5.25 15V6ZM3 18.25C2.58579 18.25 2.25 18.5858 2.25 19C2.25 19.4142 2.58579 19.75 3 19.75H21C21.4142 19.75 21.75 19.4142 21.75 19C21.75 18.5858 21.4142 18.25 21 18.25H3Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
return <LaptopIcon title="Laptop" fontSize="2.5rem" />;
|
||||
case token.includes("xl"):
|
||||
return (
|
||||
<svg
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
focusable={false}
|
||||
aria-hidden
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M2.25 4.5C2.25 3.80964 2.80964 3.25 3.5 3.25H20.5C21.1904 3.25 21.75 3.80964 21.75 4.5V15.5C21.75 16.1904 21.1904 16.75 20.5 16.75H12.75V19.25H19C19.4142 19.25 19.75 19.5858 19.75 20C19.75 20.4142 19.4142 20.75 19 20.75H6C5.58579 20.75 5.25 20.4142 5.25 20C5.25 19.5858 5.58579 19.25 6 19.25H11.25V16.75H3.5C2.80964 16.75 2.25 16.1904 2.25 15.5V4.5ZM3.75 4.75V15.25H20.25V4.75H3.75Z"
|
||||
fill="#262626"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
return <MonitorIcon title="Dekstop" fontSize="2.5rem" />;
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
||||
@@ -1,71 +1,59 @@
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { Frame } from "../Frame";
|
||||
|
||||
const text = "The quick brown fox jumps over the lazy dog";
|
||||
import { sanitizeName } from "../utilities";
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
|
||||
export const FontView = ({ cat }: { cat: string }) => {
|
||||
const shapes = docs[cat];
|
||||
const fonts = docs[cat];
|
||||
|
||||
return (
|
||||
<Frame
|
||||
tokens={shapes}
|
||||
styles="borderRadius"
|
||||
element={({ token, name }: { token: string; name?: string }) => {
|
||||
if (name.includes("font-family")) {
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 bg-surface-default flex h-full w-full items-end rounded-md px-4 text-xl"
|
||||
aria-hidden
|
||||
>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (name.includes("font-weight")) {
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 bg-surface-default flex h-full w-full items-end rounded-md px-4 text-xl"
|
||||
aria-hidden
|
||||
style={{
|
||||
fontWeight: token,
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (name.includes("font-line-height")) {
|
||||
return (
|
||||
<div className="bg-surface-default">
|
||||
<div
|
||||
className="min-h-16 flex h-full max-w-xs items-end rounded-md px-4 text-xl"
|
||||
aria-hidden
|
||||
style={{
|
||||
lineHeight: token,
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (name.includes("font-size")) {
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 bg-surface-default flex h-full w-full items-end rounded-md px-4 text-xl"
|
||||
aria-hidden
|
||||
style={{
|
||||
fontSize: token,
|
||||
fontWeight: name.includes("size-heading") ? "600" : "400",
|
||||
lineHeight: 1.33,
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
/>
|
||||
<AkselTable
|
||||
withCopy
|
||||
th={[
|
||||
{ text: "Token" },
|
||||
{ text: "Verdi" },
|
||||
{ text: "Demo", sronly: true },
|
||||
]}
|
||||
>
|
||||
{fonts.map((x) => (
|
||||
<AkselTableRow
|
||||
key={x.name}
|
||||
tr={[
|
||||
{ text: sanitizeName(x.name.replace("--a-font-", "")) },
|
||||
{ text: x.value },
|
||||
{ text: getDemoCell(x) },
|
||||
]}
|
||||
copyText={x.name}
|
||||
/>
|
||||
))}
|
||||
</AkselTable>
|
||||
);
|
||||
};
|
||||
|
||||
function getDemoCell({ value, name }: { value: string; name: string }) {
|
||||
switch (true) {
|
||||
case name.includes("weight"):
|
||||
return <span style={{ fontWeight: value }}>Foreldrepenger</span>;
|
||||
case name.includes("line-height"):
|
||||
return (
|
||||
<span style={{ lineHeight: value }}>
|
||||
Hello <br />
|
||||
World
|
||||
</span>
|
||||
);
|
||||
case name.includes("size-heading"):
|
||||
return (
|
||||
<span
|
||||
className="leading-none"
|
||||
style={{ fontSize: value, fontWeight: value }}
|
||||
>
|
||||
Aa
|
||||
</span>
|
||||
);
|
||||
|
||||
case name.includes("size"):
|
||||
return <span style={{ fontSize: value }}>Aa</span>;
|
||||
|
||||
default:
|
||||
return <span style={{ fontSize: value }}>Foreldrepenger</span>;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,35 @@
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
|
||||
import { Frame } from "../Frame";
|
||||
import { Grid } from "../Grid";
|
||||
import { getColorString, sanitizeName } from "../utilities";
|
||||
import { Copy } from "../Copy";
|
||||
|
||||
export const GlobalView = ({ cat }: { cat: string }) => {
|
||||
const colors = docs[cat];
|
||||
|
||||
return <Frame tokens={colors} styles="background" showHex />;
|
||||
const colors: { name: string; value: string }[] = docs[cat];
|
||||
return (
|
||||
<Grid>
|
||||
{colors.map((x) => {
|
||||
return (
|
||||
<div key={x.name} id={x.name} className="z-0 flex w-fit items-center">
|
||||
<div
|
||||
style={{
|
||||
background: `var(${x.name})`,
|
||||
boxShadow: `inset 0 2px 4px 0 rgba(0,0,0,0.06)`,
|
||||
}}
|
||||
className="mr-3 grid h-16 w-16 place-content-center rounded-lg"
|
||||
>
|
||||
<div className="component-checkered-bg z-[-1] h-16 w-16" />
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy text={sanitizeName(x.name)} copyText={x.name} />
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{getColorString(x.value)}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
+293
-81
@@ -1,99 +1,311 @@
|
||||
import { PersonCircleIcon } from "@navikt/aksel-icons";
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import Link from "next/link";
|
||||
import color from "tinycolor2";
|
||||
import { Frame } from "../Frame";
|
||||
import { Copy } from "../Copy";
|
||||
import { Grid } from "../Grid";
|
||||
import { getColorString, getGlobalReference, sanitizeName } from "../utilities";
|
||||
|
||||
export const SemanticView = ({ cat }: { cat: string }) => {
|
||||
const colors = docs[cat];
|
||||
|
||||
if (cat === "semantic-text") {
|
||||
if (cat.startsWith("semantic-text")) {
|
||||
return (
|
||||
<Frame
|
||||
tokens={colors}
|
||||
styles="color"
|
||||
showHex
|
||||
element={({ token }: { token: string }) => {
|
||||
const c = color(token);
|
||||
const isLigth = c.getLuminance() > 0.9;
|
||||
<Grid>
|
||||
{colors.map((x) => {
|
||||
const ref = getGlobalReference(x.value);
|
||||
const c = color(x.value);
|
||||
const isLight = c.getLuminance() > 0.9;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 flex h-full w-full items-end rounded-md px-4 text-5xl font-semibold"
|
||||
aria-hidden
|
||||
style={{
|
||||
color: token,
|
||||
background: isLigth
|
||||
? `var(--a-surface-inverted)`
|
||||
: `var(--a-surface-default)`,
|
||||
}}
|
||||
>
|
||||
Aa
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (cat === "semantic-icon") {
|
||||
return (
|
||||
<Frame
|
||||
tokens={colors}
|
||||
styles="color"
|
||||
showHex
|
||||
element={({ token }: { token: string }) => {
|
||||
const c = color(token);
|
||||
const isLigth = c.getLuminance() > 0.9;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 flex h-full w-full items-center justify-center rounded-md px-4 text-4xl font-semibold"
|
||||
aria-hidden
|
||||
style={{
|
||||
color: token,
|
||||
background: isLigth
|
||||
? `var(--a-surface-inverted)`
|
||||
: `var(--a-surface-default)`,
|
||||
}}
|
||||
>
|
||||
<PersonCircleIcon aria-hidden />
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (cat === "semantic-border" || cat === "semantic-data-border") {
|
||||
return (
|
||||
<Frame
|
||||
tokens={colors}
|
||||
styles="color"
|
||||
showHex
|
||||
element={({ token }: { token: string }) => {
|
||||
const c = color(token);
|
||||
const isLigth = c.getLuminance() > 0.7;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 flex h-full w-full items-center justify-center rounded-md px-4 text-5xl font-semibold"
|
||||
aria-hidden
|
||||
style={{
|
||||
background: isLigth
|
||||
? `var(--a-surface-inverted)`
|
||||
: `var(--a-surface-default)`,
|
||||
}}
|
||||
>
|
||||
<div key={x.name} id={x.name} className="flex w-fit items-center">
|
||||
<div
|
||||
className="h-12 w-full rounded-md"
|
||||
style={{
|
||||
border: `2px solid ${token}`,
|
||||
background: isLight ? `var(--a-surface-inverted)` : undefined,
|
||||
color: x.value,
|
||||
boxShadow: `inset 0 2px 4px 0 rgba(0,0,0,0.06)`,
|
||||
}}
|
||||
/>
|
||||
className="mr-3 grid h-16 w-16 place-content-center rounded-lg text-2xl leading-none"
|
||||
>
|
||||
Aa
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("text-", ""))}
|
||||
copyText={x.name}
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{ref ? (
|
||||
<Link
|
||||
href={`#${ref.name}`}
|
||||
className="focus-visible:bg-border-focus focus-visible:text-text-on-action hover:underline focus:outline-none"
|
||||
>
|
||||
{sanitizeName(ref.name)}
|
||||
</Link>
|
||||
) : (
|
||||
getColorString(x.value)
|
||||
)}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
return <Frame tokens={colors} styles="background" showHex />;
|
||||
if (cat.startsWith("semantic-icon")) {
|
||||
return (
|
||||
<Grid>
|
||||
{colors.map((x) => {
|
||||
const ref = getGlobalReference(x.value);
|
||||
const c = color(x.value);
|
||||
const isLight = c.getLuminance() > 0.9;
|
||||
return (
|
||||
<div key={x.name} id={x.name} className="flex w-fit items-center">
|
||||
<div
|
||||
style={{
|
||||
background: isLight ? `var(--a-surface-inverted)` : undefined,
|
||||
boxShadow: `inset 0 2px 4px 0 rgba(0,0,0,0.06)`,
|
||||
}}
|
||||
className="mr-3 grid h-16 w-16 place-content-center rounded-lg text-4xl leading-none"
|
||||
>
|
||||
<PersonCircleIcon
|
||||
aria-hidden
|
||||
style={{
|
||||
color: x.value,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("icon-", ""))}
|
||||
copyText={x.name}
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{ref ? (
|
||||
<Link
|
||||
href={`#${ref.name}`}
|
||||
className="focus-visible:bg-border-focus focus-visible:text-text-on-action hover:underline focus:outline-none"
|
||||
>
|
||||
{sanitizeName(ref.name)}
|
||||
</Link>
|
||||
) : (
|
||||
getColorString(x.value)
|
||||
)}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
if (cat.startsWith("semantic-border")) {
|
||||
return (
|
||||
<Grid>
|
||||
{colors.map((x) => {
|
||||
const ref = getGlobalReference(x.value);
|
||||
|
||||
return (
|
||||
<div key={x.name} id={x.name} className="flex w-fit items-center">
|
||||
<div
|
||||
style={{
|
||||
boxShadow: `inset 0 0 0 3px var(${x.name})`,
|
||||
}}
|
||||
className="mr-3 grid h-16 w-16 place-content-center rounded-lg text-4xl leading-none"
|
||||
/>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("border-", ""))}
|
||||
copyText={x.name}
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{ref ? (
|
||||
<Link
|
||||
href={`#${ref.name}`}
|
||||
className="focus-visible:bg-border-focus focus-visible:text-text-on-action hover:underline focus:outline-none"
|
||||
>
|
||||
{sanitizeName(ref.name)}
|
||||
</Link>
|
||||
) : (
|
||||
getColorString(x.value)
|
||||
)}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
if (cat.startsWith("semantic-data-border")) {
|
||||
return (
|
||||
<Grid>
|
||||
{colors.map((x) => {
|
||||
const ref = getGlobalReference(x.value);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={x.name}
|
||||
id={x.name}
|
||||
className="z-0 flex w-fit items-center"
|
||||
>
|
||||
<div className="mr-3 flex h-16 w-16 items-end justify-evenly rounded-lg text-4xl leading-none">
|
||||
<span
|
||||
className="rounded-t-small h-full w-3"
|
||||
style={{
|
||||
border: `1px solid var(${x.name})`,
|
||||
backgroundColor: `var(${x.name.replace(
|
||||
"border",
|
||||
"surface"
|
||||
)}-subtle)`,
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className="rounded-t-small h-2/3 w-3"
|
||||
style={{
|
||||
border: `1px solid var(${x.name})`,
|
||||
backgroundColor: `var(${x.name.replace(
|
||||
"border",
|
||||
"surface"
|
||||
)}-subtle)`,
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
className="rounded-t-small h-1/3 w-3"
|
||||
style={{
|
||||
border: `1px solid var(${x.name})`,
|
||||
backgroundColor: `var(${x.name.replace(
|
||||
"border",
|
||||
"surface"
|
||||
)}-subtle)`,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("surface-", ""))}
|
||||
copyText={x.name}
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{ref ? (
|
||||
<Link
|
||||
href={`#${ref.name}`}
|
||||
className="focus-visible:bg-border-focus focus-visible:text-text-on-action hover:underline focus:outline-none"
|
||||
>
|
||||
{sanitizeName(ref.name)}
|
||||
</Link>
|
||||
) : (
|
||||
getColorString(x.value)
|
||||
)}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
if (cat.startsWith("semantic-data-surface")) {
|
||||
return (
|
||||
<Grid>
|
||||
{colors.map((x) => {
|
||||
const ref = getGlobalReference(x.value);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={x.name}
|
||||
id={x.name}
|
||||
className="z-0 flex w-fit items-center"
|
||||
>
|
||||
<div className="mr-3 flex h-16 w-16 items-end justify-evenly rounded-lg text-4xl leading-none">
|
||||
<span
|
||||
className="rounded-t-small h-full w-3"
|
||||
style={{ backgroundColor: `var(${x.name})` }}
|
||||
/>
|
||||
<span
|
||||
className="rounded-t-small h-2/3 w-3"
|
||||
style={{ backgroundColor: `var(${x.name})` }}
|
||||
/>
|
||||
<span
|
||||
className="rounded-t-small h-1/3 w-3"
|
||||
style={{ backgroundColor: `var(${x.name})` }}
|
||||
/>
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("surface-", ""))}
|
||||
copyText={x.name}
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{ref ? (
|
||||
<Link
|
||||
href={`#${ref.name}`}
|
||||
className="focus-visible:bg-border-focus focus-visible:text-text-on-action hover:underline focus:outline-none"
|
||||
>
|
||||
{sanitizeName(ref.name)}
|
||||
</Link>
|
||||
) : (
|
||||
getColorString(x.value)
|
||||
)}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Grid>
|
||||
{colors.map((x) => {
|
||||
const ref = getGlobalReference(x.value);
|
||||
|
||||
return (
|
||||
<div key={x.name} id={x.name} className="z-0 flex w-fit items-center">
|
||||
<div
|
||||
style={{
|
||||
background: `var(${x.name})`,
|
||||
boxShadow: `inset 0 2px 4px 0 rgba(0,0,0,0.06)`,
|
||||
}}
|
||||
className="mr-3 grid h-16 w-16 place-content-center rounded-lg text-4xl leading-none"
|
||||
>
|
||||
<div className="component-checkered-bg z-[-1] h-16 w-16" />
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("surface-", ""))}
|
||||
copyText={x.name}
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{ref ? (
|
||||
<Link
|
||||
href={`#${ref.name}`}
|
||||
className="focus-visible:bg-border-focus focus-visible:text-text-on-action hover:underline focus:outline-none"
|
||||
>
|
||||
{sanitizeName(ref.name)}
|
||||
</Link>
|
||||
) : (
|
||||
getColorString(x.value)
|
||||
)}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -1,38 +1,36 @@
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { Frame } from "../Frame";
|
||||
import { Copy } from "../Copy";
|
||||
import { Grid } from "../Grid";
|
||||
import { sanitizeName } from "../utilities";
|
||||
|
||||
export const ShadowView = ({ cat }: { cat: string }) => {
|
||||
const shadows = docs[cat];
|
||||
|
||||
return (
|
||||
<Frame
|
||||
tokens={shadows}
|
||||
styles="boxShadow"
|
||||
element={({ token, name }: { token: string; name?: string }) => {
|
||||
const isLigth = name && name.includes("focus-inverted");
|
||||
|
||||
<Grid stacked>
|
||||
{shadows.map((x) => {
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 flex h-full w-full items-center justify-center rounded-md px-4 text-5xl font-semibold"
|
||||
aria-hidden
|
||||
style={{
|
||||
background: isLigth
|
||||
? `var(--a-surface-inverted)`
|
||||
: `var(--a-surface-default)`,
|
||||
}}
|
||||
>
|
||||
<div key={x.name} id={x.name} className="flex w-fit items-center">
|
||||
<div
|
||||
className="h-8 w-full rounded-md"
|
||||
style={{
|
||||
boxShadow: `${token}`,
|
||||
background: isLigth
|
||||
? "var(--a-surface-inverted)"
|
||||
: "var(--a-bg-subtle)",
|
||||
boxShadow: `var(${x.name})`,
|
||||
}}
|
||||
className="mr-3 grid h-16 w-16 place-content-center rounded-lg text-4xl leading-none"
|
||||
/>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("shadow-", ""))}
|
||||
copyText={x.name}
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{x.value}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -1,37 +1,34 @@
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { Frame } from "../Frame";
|
||||
import { Copy } from "../Copy";
|
||||
import { Grid } from "../Grid";
|
||||
import { sanitizeName } from "../utilities";
|
||||
|
||||
export const ShapesView = ({ cat }: { cat: string }) => {
|
||||
const shapes = docs[cat];
|
||||
|
||||
return (
|
||||
<Frame
|
||||
tokens={shapes}
|
||||
styles="borderRadius"
|
||||
element={({ token }: { token: string; name?: string }) => {
|
||||
<Grid>
|
||||
{shapes.map((x) => {
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 flex h-full w-full items-center justify-center gap-4 rounded-md px-4 text-5xl font-semibold"
|
||||
aria-hidden
|
||||
style={{
|
||||
background: `var(--a-surface-default)`,
|
||||
}}
|
||||
>
|
||||
<div key={x.name} id={x.name} className="flex w-fit items-center">
|
||||
<div
|
||||
className="bg-surface-alt-3-strong h-8 w-8 rounded-md"
|
||||
style={{
|
||||
borderRadius: `${token}`,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className="bg-surface-alt-3-strong h-8 w-20 rounded-md"
|
||||
style={{
|
||||
borderRadius: `${token}`,
|
||||
}}
|
||||
style={{ borderRadius: x.value }}
|
||||
className="bg-surface-alt-3-strong mr-3 grid h-16 w-16 place-content-center rounded-lg text-4xl leading-none"
|
||||
/>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("border-radius-", ""))}
|
||||
copyText={x.name}
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{x.value}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -1,31 +1,41 @@
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { Frame } from "../Frame";
|
||||
import { AkselTable, AkselTableRow } from "components/website-modules/Table";
|
||||
|
||||
export const SpacingView = ({ cat }: { cat: string }) => {
|
||||
const spacings = docs[cat];
|
||||
|
||||
return (
|
||||
<Frame
|
||||
tokens={spacings}
|
||||
styles="boxShadow"
|
||||
element={({ token }: { token: string; name?: string }) => {
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 flex h-full w-full items-center justify-start rounded-md px-4 text-5xl font-semibold"
|
||||
aria-hidden
|
||||
style={{
|
||||
background: `var(--a-surface-default)`,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="bg-surface-alt-3-strong h-8 rounded-md"
|
||||
style={{
|
||||
width: token,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<AkselTable
|
||||
withCopy
|
||||
th={[
|
||||
{ text: "Token" },
|
||||
{ text: "rem" },
|
||||
{ text: "px" },
|
||||
{ text: "demo", sronly: true, hideOnSm: true },
|
||||
]}
|
||||
>
|
||||
{spacings.map((x) => (
|
||||
<AkselTableRow
|
||||
key={x.name}
|
||||
tr={[
|
||||
{ text: x.name.replace("--a-spacing-", "") },
|
||||
{ text: x.value.replace("rem", "") },
|
||||
{ text: Number(x.value.replace("rem", "") * 16) },
|
||||
{
|
||||
hideOnSm: true,
|
||||
text: (
|
||||
<div
|
||||
className="bg-surface-alt-3-strong mr-auto h-8 rounded-md"
|
||||
style={{
|
||||
width: x.value,
|
||||
}}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]}
|
||||
copyText={x.name}
|
||||
/>
|
||||
))}
|
||||
</AkselTable>
|
||||
);
|
||||
};
|
||||
@@ -1,26 +1,49 @@
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
import { Frame } from "../Frame";
|
||||
import cl from "clsx";
|
||||
import { Copy } from "../Copy";
|
||||
import { Grid } from "../Grid";
|
||||
import { sanitizeName } from "../utilities";
|
||||
|
||||
export const ZindexView = ({ cat }: { cat: string }) => {
|
||||
const shapes = docs[cat];
|
||||
const zindex = docs[cat];
|
||||
|
||||
return (
|
||||
<Frame
|
||||
tokens={shapes}
|
||||
styles="borderRadius"
|
||||
element={({ token }: { token: string; name?: string }) => {
|
||||
<Grid>
|
||||
{zindex.map((x, y) => {
|
||||
return (
|
||||
<div
|
||||
className="min-h-16 flex h-full w-full items-end rounded-md px-4 text-5xl font-semibold"
|
||||
aria-hidden
|
||||
style={{
|
||||
background: `var(--a-surface-default)`,
|
||||
}}
|
||||
>
|
||||
{token}
|
||||
<div key={x.name} id={x.name} className="flex w-fit items-center">
|
||||
<div
|
||||
style={{ boxShadow: `inset 0 2px 4px 0 rgba(0,0,0,0.06)` }}
|
||||
className="bg-surface-subtle mr-3 flex h-16 w-16 flex-col-reverse justify-between overflow-hidden rounded-lg text-4xl leading-none"
|
||||
>
|
||||
{zindex.map((x, xi) => (
|
||||
<div
|
||||
aria-hidden
|
||||
key={x.value}
|
||||
className={cl(
|
||||
"h-3 w-16 group-hover:opacity-10 peer-focus-visible:opacity-10",
|
||||
{
|
||||
"bg-surface-alt-3-strong": y === xi,
|
||||
"bg-surface-neutral-subtle": y !== xi,
|
||||
}
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<dl className="grid h-full">
|
||||
<dt className="inline-flex items-center gap-2">
|
||||
<Copy
|
||||
text={sanitizeName(x.name.replace("z-index-", ""))}
|
||||
copyText={x.name}
|
||||
/>
|
||||
</dt>
|
||||
<dd className="text-text-subtle text-medium mt-auto">
|
||||
{x.value}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
})}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import { withErrorBoundary } from "@/error-boundary";
|
||||
import { BreakpointsView } from "components/sanity-modules/token-view/categories/Breakpoints";
|
||||
import { BreakpointsView } from "./categories/Breakpoints";
|
||||
import { FontView } from "./categories/Font";
|
||||
import { GlobalView } from "./categories/Global";
|
||||
import { SemanticView } from "./categories/Semantic";
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { FontView } from "./categories/Font";
|
||||
import { GlobalView } from "./categories/Global";
|
||||
import { SemanticView } from "./categories/Semantic";
|
||||
import { ShadowView } from "./categories/Shadow";
|
||||
import { SpacingView } from "./categories/Spacing";
|
||||
import { ZindexView } from "./categories/Zindex";
|
||||
import { BreakpointsView } from "./categories/Breakpoints";
|
||||
import { ShapesView } from "./categories/Shapes";
|
||||
import "../../../dist/tw.css";
|
||||
export default {
|
||||
title: "sanity-modules/tokenview",
|
||||
parameters: {
|
||||
layout: "fullscreen",
|
||||
},
|
||||
};
|
||||
|
||||
export const FontViewDemo = () => <FontView cat="font" />;
|
||||
|
||||
export const GlobalViewDemo = () => <GlobalView cat="global-blue" />;
|
||||
|
||||
export const SemanticViewDemo = () => <SemanticView cat="semantic-surface" />;
|
||||
|
||||
export const SemanticBorderView = () => <SemanticView cat="semantic-border" />;
|
||||
|
||||
export const SemanticIconView = () => <SemanticView cat="semantic-icon" />;
|
||||
|
||||
export const SemanticTextView = () => <SemanticView cat="semantic-text" />;
|
||||
|
||||
export const RadiusViewDemo = () => <ShapesView cat="radius" />;
|
||||
|
||||
export const ShadowViewDemo = () => <ShadowView cat="shadow" />;
|
||||
|
||||
export const SpacingViewDemo = () => <SpacingView cat="spacing" />;
|
||||
|
||||
export const IndexView = () => <ZindexView cat="z-index" />;
|
||||
|
||||
export const BreakpointView = () => <BreakpointsView cat="breakpoints" />;
|
||||
@@ -0,0 +1,24 @@
|
||||
import color from "tinycolor2";
|
||||
import docs from "@navikt/ds-tokens/docs.json";
|
||||
|
||||
const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
|
||||
|
||||
export const sanitizeName = (x: string) =>
|
||||
capitalize(x.replace("--a-", "").replaceAll("-", " "));
|
||||
|
||||
export const getColorString = (s: string) => {
|
||||
const c = color(s);
|
||||
|
||||
const alpha = c.getAlpha() !== 1;
|
||||
return alpha ? c.toRgbString() : c.toHexString().toUpperCase();
|
||||
};
|
||||
|
||||
export const getGlobalReference = (
|
||||
semanticValue: string
|
||||
): { name: string; value: string } => {
|
||||
const globalRefs = Object.entries(docs)
|
||||
.filter(([key]) => key.startsWith("global-"))
|
||||
.reduce((acc, [_, value]) => [...acc, ...value], []);
|
||||
|
||||
return globalRefs.find(({ value }) => semanticValue === value) ?? null;
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
export const InlineCode = (props: React.HTMLAttributes<HTMLElement>) => (
|
||||
<code className="text-deepblue-800 font-mono text-sm font-semibold leading-normal before:contents">
|
||||
<span aria-hidden className="inline-code-amp">
|
||||
`
|
||||
</span>
|
||||
<span>{props.children}</span>
|
||||
<span aria-hidden className="inline-code-amp">
|
||||
`
|
||||
</span>
|
||||
</code>
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
import cl from "clsx";
|
||||
|
||||
export const KBD = (props: React.HTMLAttributes<HTMLElement>) => (
|
||||
<kbd
|
||||
className={cl(
|
||||
"mx-05 ring-border-subtle my-0 inline-block min-w-[2rem] rounded-md px-2 py-[1px] text-center font-mono text-sm text-gray-900 ring-1 ring-inset",
|
||||
"from-surface-default via-surface-default to-surface-neutral-subtle bg-gradient-to-b"
|
||||
)}
|
||||
>
|
||||
<span className="kbd">{props.children}</span>
|
||||
<style jsx>{`
|
||||
.kbd {
|
||||
text-shadow: 0 1px 0px var(--a-grayalpha-200);
|
||||
}
|
||||
`}</style>
|
||||
</kbd>
|
||||
);
|
||||
@@ -1,270 +0,0 @@
|
||||
import { SanityBlockContent } from "@/sanity-block";
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
|
||||
import { dateStr } from "@/utils";
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import Image from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
|
||||
export const getAuthors = (
|
||||
blog: ResolveContributorsT<ResolveSlugT<AkselBloggDocT>>
|
||||
) => (blog?.contributors as any)?.map((x) => x?.title) ?? [];
|
||||
|
||||
export const LatestBloggposts = ({
|
||||
bloggs,
|
||||
title,
|
||||
level = "1",
|
||||
intro,
|
||||
}: {
|
||||
bloggs: ResolveContributorsT<ResolveSlugT<AkselBloggDocT>>[];
|
||||
title: string;
|
||||
level?: "1" | "2";
|
||||
intro?: any[];
|
||||
}) => {
|
||||
if (!bloggs || bloggs.length < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-20">
|
||||
<Heading
|
||||
level={level}
|
||||
size="xlarge"
|
||||
className="text-deepblue-700 mx-auto w-full text-5xl md:mx-0 md:max-w-none"
|
||||
>
|
||||
{title}
|
||||
</Heading>
|
||||
{intro && (
|
||||
<SanityBlockContent
|
||||
blocks={intro}
|
||||
isIngress
|
||||
noLastMargin
|
||||
className="mt-4"
|
||||
/>
|
||||
)}
|
||||
{/* Desktop-view */}
|
||||
<div className="my-12 hidden grid-cols-2 gap-12 md:grid">
|
||||
<div className="col-span-1">
|
||||
<div className="relative mb-10 block aspect-video">
|
||||
{bloggs[0]?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(bloggs[0].seo.image)
|
||||
.quality(100)
|
||||
.auto("format")
|
||||
.url()}
|
||||
quality={100}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
decoding="sync"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(bloggs[0]?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
decoding="sync"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<NextLink href={`/${bloggs[0].slug}`} passHref legacyBehavior>
|
||||
<Link className="text-deepblue-500 no-underline hover:underline">
|
||||
<Heading
|
||||
size="large"
|
||||
level={(Number(level) + 1).toString() as any}
|
||||
>
|
||||
{bloggs[0].heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mt-4" size="small">
|
||||
{bloggs[0]?.ingress}
|
||||
</BodyLong>
|
||||
{getAuthors(bloggs[0]).length > 0 && (
|
||||
<BodyShort
|
||||
size="small"
|
||||
className="text-text-subtle mt-4 flex gap-2"
|
||||
>
|
||||
<span className="font-semibold">{getAuthors(bloggs[0])[0]}</span>
|
||||
<span>
|
||||
{dateStr(bloggs[0]?.publishedAt ?? bloggs[0]._createdAt)}
|
||||
</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
<div className="col-span-1 grid place-content-start gap-12">
|
||||
{bloggs.slice(1, 3).map((blog) => (
|
||||
<div key={blog._id} className="flex gap-6">
|
||||
<div className="relative hidden aspect-square h-[11.75rem] lg:block">
|
||||
{blog?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(blog.seo.image).auto("format").url()}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(blog?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<NextLink href={`/${blog.slug}`} passHref legacyBehavior>
|
||||
<Link className="text-deepblue-500 no-underline hover:underline">
|
||||
<Heading
|
||||
size="small"
|
||||
level={(Number(level) + 1).toString() as any}
|
||||
>
|
||||
{blog.heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mt-4" size="small">
|
||||
{blog?.ingress}
|
||||
</BodyLong>
|
||||
{getAuthors(blog).length > 0 ? (
|
||||
<BodyShort
|
||||
size="small"
|
||||
className="text-text-subtle mt-4 flex gap-2"
|
||||
>
|
||||
<span className="font-semibold">{getAuthors(blog)[0]}</span>
|
||||
<span>{dateStr(blog?.publishedAt ?? blog._createdAt)}</span>
|
||||
</BodyShort>
|
||||
) : (
|
||||
<BodyShort size="small" className="text-text-subtle mt-4">
|
||||
<span>{dateStr(blog?.publishedAt ?? blog._createdAt)}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mobile view */}
|
||||
<div className="my-10 mx-auto grid gap-12 md:hidden">
|
||||
<div className="w-full">
|
||||
<div className="relative mb-10 block aspect-video">
|
||||
{bloggs[0]?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(bloggs[0].seo.image)
|
||||
.quality(100)
|
||||
.auto("format")
|
||||
.url()}
|
||||
quality={100}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(bloggs[0]?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<NextLink href={`/${bloggs[0].slug}`} passHref legacyBehavior>
|
||||
<Link className="text-deepblue-500 no-underline hover:underline">
|
||||
<Heading
|
||||
size="large"
|
||||
level={(Number(level) + 1).toString() as any}
|
||||
>
|
||||
{bloggs[0].heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mt-4" size="small">
|
||||
{bloggs[0]?.ingress}
|
||||
</BodyLong>
|
||||
{getAuthors(bloggs[0]).length > 0 && (
|
||||
<BodyShort
|
||||
size="small"
|
||||
className="text-text-subtle mt-4 flex gap-2"
|
||||
>
|
||||
<span className="font-semibold">{getAuthors(bloggs[0])[0]}</span>
|
||||
<span>
|
||||
{dateStr(bloggs[0]?.publishedAt ?? bloggs[0]._createdAt)}
|
||||
</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
<div className="grid w-full gap-12">
|
||||
{bloggs.slice(1, 3).map((blog) => (
|
||||
<div key={blog._id}>
|
||||
<div className="relative mb-6 block aspect-video">
|
||||
{blog?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(blog.seo.image).auto("format").url()}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(blog?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<NextLink href={`/${blog.slug}`} passHref legacyBehavior>
|
||||
<Link className="text-deepblue-500 no-underline hover:underline">
|
||||
<Heading
|
||||
size="small"
|
||||
level={(Number(level) + 1).toString() as any}
|
||||
>
|
||||
{blog.heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mt-4" size="small">
|
||||
{blog?.ingress}
|
||||
</BodyLong>
|
||||
{getAuthors(blog).length > 0 ? (
|
||||
<BodyShort
|
||||
size="small"
|
||||
className="text-text-subtle mt-4 flex gap-2"
|
||||
>
|
||||
<span className="font-semibold">{getAuthors(blog)[0]}</span>
|
||||
<span>{dateStr(blog?.publishedAt ?? blog._createdAt)}</span>
|
||||
</BodyShort>
|
||||
) : (
|
||||
<BodyShort size="small" className="text-text-subtle mt-4">
|
||||
<span>{dateStr(blog?.publishedAt ?? blog._createdAt)}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
import { CopyButton } from "@navikt/ds-react";
|
||||
import cl from "clsx";
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
const TableContext = createContext<boolean>(false);
|
||||
|
||||
export function AkselTable({
|
||||
children,
|
||||
th,
|
||||
withCopy,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
th: { text: string; hideOnSm?: boolean; sronly?: boolean }[];
|
||||
withCopy?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<table className="border-border-subtle mb-7 w-full border-separate border-spacing-0 rounded border">
|
||||
<thead>
|
||||
<tr className="rounded-t text-left">
|
||||
{th.map((x) => (
|
||||
<th
|
||||
key={x.text}
|
||||
className={cl("font-regular bg-surface-subtle rounded-tl p-2", {
|
||||
"hidden sm:table-cell": !!x.hideOnSm,
|
||||
})}
|
||||
>
|
||||
{x?.sronly ? <span className="sr-only">{x.text}</span> : x.text}
|
||||
</th>
|
||||
))}
|
||||
{withCopy && (
|
||||
<th className="font-regular bg-surface-subtle hidden rounded-tl p-2 sm:table-cell">
|
||||
<span className="sr-only">Kopi</span>
|
||||
</th>
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<TableContext.Provider value={withCopy ?? false}>
|
||||
{children}
|
||||
</TableContext.Provider>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
}
|
||||
|
||||
export function AkselTableRow({
|
||||
tr,
|
||||
copyText = "",
|
||||
}: {
|
||||
tr: { text: string | React.ReactNode; hideOnSm?: boolean }[];
|
||||
copyText?: string;
|
||||
}) {
|
||||
const useCopy = useContext(TableContext);
|
||||
|
||||
return (
|
||||
<tr className="peer border-b border-t border-gray-200 text-base last-of-type:rounded-b">
|
||||
{tr.map((x, xi) => (
|
||||
<td
|
||||
key={xi}
|
||||
className={cl("border-t border-gray-200 px-2 py-1", {
|
||||
"hidden sm:table-cell": !!x.hideOnSm,
|
||||
})}
|
||||
>
|
||||
{x.text}
|
||||
</td>
|
||||
))}
|
||||
{useCopy && (
|
||||
<td className="hidden border-t border-gray-200 px-2 py-1 sm:table-cell">
|
||||
<CopyButton copyText={copyText} size="small" className="ml-auto" />
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
|
||||
import { getAuthors } from "@/utils";
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import Image from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
|
||||
export const BloggList = ({
|
||||
blogg,
|
||||
}: {
|
||||
blogg: ResolveContributorsT<ResolveSlugT<AkselBloggDocT>>;
|
||||
}) => {
|
||||
const date = useFormatedDate(blogg?.publishedAt ?? blogg._createdAt);
|
||||
return (
|
||||
<div>
|
||||
<div className="hidden gap-6 md:flex">
|
||||
<div className="relative hidden aspect-square h-[11.75rem] lg:block">
|
||||
{blogg?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(blogg.seo.image).auto("format").url()}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(blogg?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<NextLink href={`/${blogg.slug}`} passHref legacyBehavior>
|
||||
<Link className="text-deepblue-500 no-underline hover:underline">
|
||||
<Heading size="small" level="2">
|
||||
{blogg.heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mt-4" size="small">
|
||||
{blogg?.ingress}
|
||||
</BodyLong>
|
||||
{getAuthors(blogg).length > 0 ? (
|
||||
<BodyShort
|
||||
size="small"
|
||||
className="text-text-subtle mt-4 flex gap-2"
|
||||
>
|
||||
<span className="font-semibold">{getAuthors(blogg)[0]}</span>
|
||||
<span className="animate-fadeIn">{date}</span>
|
||||
</BodyShort>
|
||||
) : (
|
||||
<BodyShort size="small" className="text-text-subtle mt-4">
|
||||
<span className="animate-fadeIn">{date}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:hidden">
|
||||
<div className="relative mb-6 block aspect-video">
|
||||
{blogg?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(blogg.seo.image).auto("format").url()}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(blogg?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="md:hidden">
|
||||
<NextLink href={`/${blogg.slug}`} passHref legacyBehavior>
|
||||
<Link className="text-deepblue-500 no-underline hover:underline">
|
||||
<Heading size="small" level="2">
|
||||
{blogg.heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mt-4" size="small">
|
||||
{blogg?.ingress}
|
||||
</BodyLong>
|
||||
{getAuthors(blogg).length > 0 ? (
|
||||
<BodyShort
|
||||
size="small"
|
||||
className="text-text-subtle mt-4 flex gap-2"
|
||||
>
|
||||
<span className="font-semibold">{getAuthors(blogg)[0]}</span>
|
||||
<span>{date}</span>
|
||||
</BodyShort>
|
||||
) : (
|
||||
<BodyShort size="small" className="text-text-subtle mt-4">
|
||||
<span>{date}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
import { urlFor } from "@/sanity/interface";
|
||||
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
|
||||
import { getAuthors } from "@/utils";
|
||||
import { BodyLong, BodyShort, Heading, Link } from "@navikt/ds-react";
|
||||
import { getImage } from "components/website-modules/utils/get-image";
|
||||
import { useFormatedDate } from "components/website-modules/utils/getDate";
|
||||
import Image from "next/legacy/image";
|
||||
import NextLink from "next/link";
|
||||
|
||||
export const HighlightedBlogg = ({
|
||||
blogg,
|
||||
}: {
|
||||
blogg: ResolveContributorsT<ResolveSlugT<AkselBloggDocT>>;
|
||||
}) => {
|
||||
const date = useFormatedDate(blogg?.publishedAt ?? blogg._createdAt);
|
||||
return (
|
||||
<div>
|
||||
<div className="col-span-1 hidden md:block">
|
||||
<div className="relative mb-10 block aspect-video">
|
||||
{blogg?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(blogg.seo.image).quality(100).auto("format").url()}
|
||||
quality={100}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
decoding="sync"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(blogg?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
decoding="sync"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<NextLink href={`/${blogg.slug}`} passHref legacyBehavior>
|
||||
<Link className="text-deepblue-500 no-underline hover:underline">
|
||||
<Heading size="large" level="2">
|
||||
{blogg.heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mt-4" size="small">
|
||||
{blogg?.ingress}
|
||||
</BodyLong>
|
||||
{getAuthors(blogg).length > 0 && (
|
||||
<BodyShort size="small" className="text-text-subtle mt-4 flex gap-2">
|
||||
<span className="font-semibold">{getAuthors(blogg)[0]}</span>
|
||||
<span>{date}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
{/* Mobile view */}
|
||||
<div className="w-full md:hidden">
|
||||
<div className="relative mb-10 block aspect-video">
|
||||
{blogg?.seo?.image ? (
|
||||
<Image
|
||||
src={urlFor(blogg.seo.image).quality(100).auto("format").url()}
|
||||
quality={100}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src={getImage(blogg?.heading ?? "", "thumbnail")}
|
||||
layout="fill"
|
||||
objectFit="contain"
|
||||
aria-hidden
|
||||
priority
|
||||
className="rounded-lg"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<NextLink href={`/${blogg.slug}`} passHref legacyBehavior>
|
||||
<Link className="text-deepblue-500 no-underline hover:underline">
|
||||
<Heading size="large" level="2">
|
||||
{blogg.heading}
|
||||
</Heading>
|
||||
</Link>
|
||||
</NextLink>
|
||||
<BodyLong className="mt-4" size="small">
|
||||
{blogg?.ingress}
|
||||
</BodyLong>
|
||||
{getAuthors(blogg).length > 0 && (
|
||||
<BodyShort size="small" className="text-text-subtle mt-4 flex gap-2">
|
||||
<span className="font-semibold">{getAuthors(blogg)[0]}</span>
|
||||
<span>{date}</span>
|
||||
</BodyShort>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
import { SanityBlockContent } from "@/sanity-block";
|
||||
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
|
||||
import { Heading } from "@navikt/ds-react";
|
||||
import { BloggList } from "./BloggList";
|
||||
import { HighlightedBlogg } from "./HighlightedBlogg";
|
||||
|
||||
export const LatestBloggposts = ({
|
||||
bloggs,
|
||||
title,
|
||||
intro,
|
||||
}: {
|
||||
bloggs: ResolveContributorsT<ResolveSlugT<AkselBloggDocT>>[];
|
||||
title: string;
|
||||
intro?: any[];
|
||||
}) => {
|
||||
if (!bloggs || bloggs.length < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-20">
|
||||
<Heading
|
||||
level="1"
|
||||
size="xlarge"
|
||||
className="text-deepblue-700 mx-auto w-full text-5xl md:mx-0 md:max-w-none"
|
||||
>
|
||||
{title}
|
||||
</Heading>
|
||||
{intro && (
|
||||
<SanityBlockContent
|
||||
blocks={intro}
|
||||
isIngress
|
||||
noLastMargin
|
||||
className="mt-4"
|
||||
/>
|
||||
)}
|
||||
{/* Desktop-view */}
|
||||
<div className="mx-auto my-10 grid gap-12 md:my-12 md:grid-cols-2">
|
||||
<HighlightedBlogg blogg={bloggs[0]} />
|
||||
<div className="col-span-1 grid place-content-start gap-12">
|
||||
{bloggs.slice(1, 3).map((blogg) => (
|
||||
<BloggList blogg={blogg} key={blogg._id} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -126,7 +126,7 @@ export const IconPage = ({ name }: { name: string }) => {
|
||||
onSubmit={(e) => e.preventDefault()}
|
||||
className="flex h-fit w-full flex-wrap-reverse items-center gap-4 px-4 py-2"
|
||||
>
|
||||
<div className="min-w-40">
|
||||
<div className="min-w-[10.25rem]">
|
||||
<ToggleGroup
|
||||
value={toggle}
|
||||
onChange={(v) => setToggle(v as any)}
|
||||
@@ -137,7 +137,7 @@ export const IconPage = ({ name }: { name: string }) => {
|
||||
<ToggleGroup.Item value="fill">Fill</ToggleGroup.Item>
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
<div className=" min-w-48 flex w-full items-center gap-2 md:w-fit">
|
||||
<div className="min-w-48 md:min-w-96 flex w-full items-center gap-2 md:w-fit">
|
||||
<Search
|
||||
variant="simple"
|
||||
label="Ikonsøk"
|
||||
@@ -209,9 +209,9 @@ export const IconPage = ({ name }: { name: string }) => {
|
||||
}
|
||||
}}
|
||||
className={cl(
|
||||
"hover:bg-surface-hover bg-surface-default active:bg-surface-neutral-subtle-hover group relative grid aspect-square w-11 shrink-0 place-items-center rounded focus:outline-none focus:ring-2 focus:ring-blue-800",
|
||||
"hover:bg-surface-hover bg-surface-default active:bg-surface-neutral-subtle-hover group relative grid aspect-square w-11 shrink-0 place-items-center rounded focus:outline-none focus:ring-blue-800 focus-visible:ring-2",
|
||||
{
|
||||
"bg-surface-selected ring-border-alt-3 z-10 ring-1":
|
||||
"from-surface-selected bg-surface-selected ring-border-alt-3 z-10 bg-gradient-to-br to-teal-50 ring-1":
|
||||
i.id === name,
|
||||
}
|
||||
)}
|
||||
|
||||
@@ -184,7 +184,7 @@ export const IconSidebar = ({
|
||||
theme={undefined}
|
||||
>
|
||||
{({ tokens, getLineProps, getTokenProps }) => (
|
||||
<pre className="relative m-0 max-w-[80vw] overflow-x-auto overflow-y-auto rounded-b-lg p-3 font-mono lg:max-w-[20rem]">
|
||||
<pre className="relative m-0 max-w-[80vw] overflow-x-auto overflow-y-auto rounded-b-lg p-3 font-mono lg:max-w-sm">
|
||||
{tokens.map((line, i) => (
|
||||
<div
|
||||
key={i}
|
||||
@@ -217,7 +217,7 @@ export const IconSidebar = ({
|
||||
theme={undefined}
|
||||
>
|
||||
{({ tokens, getLineProps, getTokenProps }) => (
|
||||
<pre className="w-text relative m-0 max-w-[80vw] overflow-x-auto overflow-y-auto rounded-b-lg p-3 font-mono lg:w-auto lg:max-w-[20rem]">
|
||||
<pre className="w-text relative m-0 max-w-[80vw] overflow-x-auto overflow-y-auto rounded-b-lg p-3 font-mono lg:w-auto lg:max-w-sm">
|
||||
{tokens.map((line, i) => (
|
||||
<div
|
||||
key={i}
|
||||
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
import { SuggestionBlock } from "./index";
|
||||
import { Meta } from "@storybook/react";
|
||||
import { NextDecorator } from "../../StoryDecorator";
|
||||
|
||||
const MetaData: Meta = {
|
||||
component: SuggestionBlock,
|
||||
tags: ["autodocs"],
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<NextDecorator>
|
||||
<Story />
|
||||
</NextDecorator>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
export default MetaData;
|
||||
|
||||
export const Ikoner = {
|
||||
render: () => <SuggestionBlock variant="ikoner" />,
|
||||
};
|
||||
|
||||
export const Ikon = {
|
||||
render: () => <SuggestionBlock variant="ikon" />,
|
||||
};
|
||||
|
||||
export const Komponent = {
|
||||
render: () => <SuggestionBlock variant="komponent" />,
|
||||
};
|
||||
|
||||
export const KomponentBeta = {
|
||||
render: () => <SuggestionBlock variant="komponent-beta" />,
|
||||
};
|
||||
|
||||
export const KomponentNy = {
|
||||
render: () => <SuggestionBlock variant="komponent-ny" />,
|
||||
};
|
||||
|
||||
export const Komponenter = {
|
||||
render: () => <SuggestionBlock variant="komponenter" />,
|
||||
};
|
||||
@@ -21,12 +21,12 @@ describe("Utils test", () => {
|
||||
expect(capitalize(str4)).toEqual("Teststr");
|
||||
});
|
||||
|
||||
test("dateStr", () => {
|
||||
test("dateStr", async () => {
|
||||
const date = "2022-06-09T11:05:48Z";
|
||||
const date2 = "2021-03-02T12:05:48Z";
|
||||
|
||||
expect(dateStr(date)).toEqual("9. juni 2022");
|
||||
expect(dateStr(date2)).toEqual("2. mars 2021");
|
||||
expect(await dateStr(date)).toEqual("9. juni 2022");
|
||||
expect(await dateStr(date2)).toEqual("2. mars 2021");
|
||||
});
|
||||
|
||||
test("abbrName", () => {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export const dateStr = async (date: string) => {
|
||||
const format = (await import("date-fns/format")).default;
|
||||
const locale = (await import("date-fns/locale/nb")).default;
|
||||
return format(new Date(date), "d. MMMM YYY", { locale: locale });
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { dateStr } from "components/website-modules/utils/date-string";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export const useFormatedDate = (date: string) => {
|
||||
const [_date, setDate] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleDate = async () => setDate(await dateStr(date));
|
||||
handleDate();
|
||||
}, [date]);
|
||||
return _date;
|
||||
};
|
||||
@@ -1,16 +1,10 @@
|
||||
import nbLocale from "date-fns/locale/nb";
|
||||
import { format } from "date-fns";
|
||||
import { AkselBloggDocT, ResolveContributorsT, ResolveSlugT } from "@/types";
|
||||
|
||||
export * from "./util";
|
||||
export * from "./amplitude";
|
||||
export * from "./hooks";
|
||||
export * from "./contexts";
|
||||
|
||||
export const dateStr = (date: string) =>
|
||||
format(new Date(date), "d. MMMM YYY", { locale: nbLocale });
|
||||
|
||||
export const dateTimeStr = (date: string) =>
|
||||
format(new Date(date), "d-MM-YYY", { locale: nbLocale });
|
||||
export * from "./date-string";
|
||||
|
||||
export const isNew = (date: string) => {
|
||||
const date1 = new Date(date);
|
||||
@@ -32,3 +26,7 @@ export const abbrName = (name: string): string => {
|
||||
)
|
||||
.join(" ");
|
||||
};
|
||||
|
||||
export const getAuthors = (
|
||||
blog: ResolveContributorsT<ResolveSlugT<AkselBloggDocT>>
|
||||
) => (blog?.contributors as any)?.map((x) => x?.title) ?? [];
|
||||
@@ -0,0 +1,7 @@
|
||||
import pino from "pino";
|
||||
import { logger as sharedPinoConfig } from "./next-logger.config";
|
||||
|
||||
/**
|
||||
* This logger is not isomorphic, and should only be used on the server
|
||||
*/
|
||||
export const logger: pino.Logger = sharedPinoConfig();
|
||||
@@ -0,0 +1,32 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
const pino = require("pino");
|
||||
|
||||
const logger = (defaultConfig = {}) =>
|
||||
pino({
|
||||
...defaultConfig,
|
||||
timestamp: false,
|
||||
formatters: {
|
||||
level: (label) => {
|
||||
return { level: label };
|
||||
},
|
||||
log: (object) => {
|
||||
if (object.err) {
|
||||
// massage the error object so logs.adeo.no shows stack traces
|
||||
const err =
|
||||
object.err instanceof Error
|
||||
? pino.stdSerializers.err(object.err)
|
||||
: object.err;
|
||||
object.stack_trace = err.stack;
|
||||
object.type = err.type;
|
||||
object.message = err.message;
|
||||
delete object.err;
|
||||
}
|
||||
|
||||
return object;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
logger,
|
||||
};
|
||||
@@ -5,7 +5,7 @@
|
||||
"description": "Aksel.nav.no website",
|
||||
"author": "Aksel | NAV designsystem team",
|
||||
"scripts": {
|
||||
"dev": "next",
|
||||
"dev": "next | pino-pretty",
|
||||
"build:old": "next build",
|
||||
"build": "next build && yarn cp:assets",
|
||||
"start": "cd .next/standalone/aksel.nav.no/website && node server.js",
|
||||
@@ -27,26 +27,27 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@sanity/block-content-to-react": "^3.0.0",
|
||||
"@sanity/client": "^6.1.2",
|
||||
"@sanity/client": "^6.1.3",
|
||||
"@sanity/code-input": "4.1.1",
|
||||
"@sanity/color-input": "^3.1.0",
|
||||
"@sanity/icons": "2.3.1",
|
||||
"@sanity/image-url": "1.0.2",
|
||||
"@sanity/preview-kit": "^1.5.4",
|
||||
"@sanity/table": "1.0.1",
|
||||
"@sanity/ui": "^1.3.3",
|
||||
"@sanity/vision": "3.11.5",
|
||||
"@sanity/ui": "^1.3.0",
|
||||
"@sanity/vision": "3.12.1",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"amplitude-js": "^8.21.5",
|
||||
"boring-avatars": "1.7.0",
|
||||
"clsx": "^1.2.1",
|
||||
"codesandbox": "^2.2.3",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
"date-fns": "2.29.3",
|
||||
"fuse.js": "^6.6.2",
|
||||
"lodash": "^4.17.21",
|
||||
"next": "^13.2.1",
|
||||
"next-logger": "^3.0.2",
|
||||
"next-sanity": "^4.3.3",
|
||||
"pino": "^8.14.1",
|
||||
"prism-react-renderer": "^1.3.0",
|
||||
"prismjs": "^1.27.0",
|
||||
"react": "^18.0.0",
|
||||
@@ -54,7 +55,7 @@
|
||||
"react-modal": "3.15.1",
|
||||
"react-responsive-masonry": "^2.1.7",
|
||||
"recharts": "^2.2.0",
|
||||
"sanity": "3.11.5",
|
||||
"sanity": "3.9.1",
|
||||
"sanity-plugin-asset-source-unsplash": "^1.1.0",
|
||||
"sanity-plugin-media": "^2.0.5",
|
||||
"sharp": "0.31.3",
|
||||
@@ -82,6 +83,7 @@
|
||||
"jest": "^29.0.0",
|
||||
"jest-environment-jsdom": "^29.0.0",
|
||||
"json5": "2.2.1",
|
||||
"pino-pretty": "^10.0.0",
|
||||
"postcss": "^8.4.0",
|
||||
"postcss-import": "^14.1.0",
|
||||
"postcss-loader": "7.0.0",
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// This is imported to allow the Output File Tracing feature of Next.js to work correctly with the log patcher
|
||||
import "next-logger";
|
||||
|
||||
import { Html, Head, Main, NextScript } from "next/document";
|
||||
|
||||
export default function Document() {
|
||||
|
||||
Loaded 100 of 115 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user