Compare commits

..
Author SHA1 Message Date
Hans Kristian Flaattenandsnyk-bot 51bbeb00b0 [Snyk] Security upgrade node from 16.4-alpine3.14 to 16.13.1-alpine3.14 (#1817)
Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2023-02-22 13:55:55 +01:00
Ken 79773ff44b Merge branch 'next' 2023-02-07 15:45:39 +01:00
Ken 1e7633e692 Merge branch 'master' into next 2023-02-07 15:13:39 +01:00
Martin Berglund ba22ba7b70 Source Sans 3 Latin Extended (#1791) 2023-02-07 15:12:37 +01:00
Ken ccedba0132 🐛 Fikset e2e-tester for uu 2023-02-07 14:00:12 +01:00
Vegard Haugstvedt 2dbc5125d6 Unpublished articles crash in preview mode, because the page does not exist (#1788) 2023-02-07 11:59:46 +01:00
Ken bdf83d447f ♿ Disable animasjon for safari-brukere (voiceover-problem) 2023-02-07 09:43:09 +01:00
Ken da9445389e 📝 Readmes 2023-02-06 16:37:36 +01:00
Ken c0601bb510 🐛 prod-deploy workflow har å riktige .env nøkler 2023-02-06 16:35:39 +01:00
Ken e20df992ec 🎨 Bruker defaults readiness og readiness i dev 2023-02-06 16:26:23 +01:00
Ken d42200b61f 👷 Flyttet sanity-synk ut i egen GHA-job 2023-02-06 16:24:44 +01:00
Ken 4e5f422693 👷 Oppdatert docker/login action for node 16 support 2023-02-06 16:01:32 +01:00
Ken 2c77e103f9 ⚡ Bruker default nais resouces 2023-02-06 15:47:56 +01:00
Ken 45e9e5f564 👷 Prod-workflow venter nå på smoketest før deploy 2023-02-06 15:44:52 +01:00
Kai Erik Schieren 6b1f9f1560 👷 add snyk to prod workflow 2023-02-06 15:40:28 +01:00
Ken eb50604788 👷 Tester alle sider med playwright 2023-02-06 15:25:08 +01:00
Ken 5ca140d4f7 Oppdatert isProduction-testing (#1786) 2023-02-06 15:21:18 +01:00
Kai Erik Schieren 7943489380 👷 test root only 2023-02-06 14:16:33 +01:00
Kai Erik Schieren 82cdd68d00 👷 snyk continue-on-error 2023-02-06 14:08:52 +01:00
Kai Erik Schieren 76af311b63 👷 snyk ignore out of sync 2023-02-06 14:02:56 +01:00
Kai Erik Schieren b624bff400 🎨 --all-projects > --yarn-workspaces 2023-02-06 13:58:34 +01:00
Kai Erik Schieren d5ab822973 👷 change snyk org name 2023-02-06 13:40:35 +01:00
Kai Erik Schieren c8b230fc1c Snyk workflow (#1785)
* ✨ add snyk workflow  to dev

* 🎨 add all-projects arg
2023-02-06 13:36:49 +01:00
Ken d35f7326d7 ⬆️ Yarn.lock sync 2023-02-06 12:58:14 +01:00
Ken eb07f63d12 ⬆️ Yarn.lock sync 2023-02-06 09:45:35 +01:00
Ken df42875d41 ♿ Bedre aria for search-shortcut, shortcut fungerer nå ikke ved shift 2023-02-06 09:29:30 +01:00
Ken 404274003c 👷 Ignore scripts-dir ved nextjs build 2023-02-05 18:53:50 +01:00
Ken fc9c5170b9 👷 Fjernet docgen og ubrukt fil i dockerfile 2023-02-05 18:42:12 +01:00
Ken dc2f1958ff 👷 Dev-miljø støtter flere branches 2023-02-05 18:23:53 +01:00
Ken fc9196ad6f 📝 Oppdatert nextjs-config 2023-02-04 21:17:53 +01:00
Ken 9cfc03fe6b 🔥 Fjernet ubrukte scripts og imports for slettet sanity-løsning 2023-02-04 21:08:46 +01:00
Ken 9b8ed2d985 📝 readmes 2023-02-04 21:02:45 +01:00
Ken 728dd2ead3 ⚰️ Fjernet gammel sanity-v2 løsning 2023-02-04 21:02:18 +01:00
Ken 71fbe7d7f2 ✨ Sanity cli fungerer nå i /website 2023-02-04 15:06:30 +01:00
Ken 2a4447b6e7 Merge branch 'master' of https://github.com/navikt/Designsystemet 2023-02-04 15:02:55 +01:00
Vegard Haugstvedt aaad005455 Publish accessibility statement for Aksel.nav.no (#1782) 2023-02-03 16:30:48 +01:00
Ken 3bb4a2e36f 🎨 visning av standalone-sider 2023-02-03 16:14:16 +01:00
Ken f346a4694c 🎨 Cacher resultater fra sanity 2023-02-03 16:09:20 +01:00
Ken 51c0883255 Merge branch 'next' 2023-02-03 14:00:31 +01:00
Ken 45e67d5b50 🎨 Logging av success søk 2023-02-03 13:58:20 +01:00
Ken 6739d29074 🔥 Fjernet console.log 2023-02-03 13:19:44 +01:00
Ken 189858a9d7 🎨 Logging av standard og feilet søk 2023-02-03 13:19:18 +01:00
Kai Erik Schieren f1731730fa Usage metrics (#1740) 2023-02-03 12:09:08 +01:00
Ken 1b37aad4dc 🐛 Fikset onClick på lenker i sanityblockcontent 2023-02-03 12:05:36 +01:00
Ken 323018a935 🐛 Opacity-endring brakk alle token visninger 2023-02-03 12:03:18 +01:00
Ken 7b6e5f2e60 🎨 uu-feedback for standalone sider 2023-02-03 12:00:43 +01:00
Ken 5557fc2ef0 🎨 uu-feedback modul sanity 2023-02-03 10:46:11 +01:00
Ken 6c07afe963 🎨 Oppdatert hotkey for søk 2023-02-03 10:39:10 +01:00
Ken ac217adaa6 🎨 Fikset aria-status opplesing 2023-02-03 10:32:29 +01:00
Ken 5c50658036 🎨 Søk støtter visning og søk på kode-eksempler 2023-02-02 16:10:09 +01:00
Ken 8ab100dfb3 Merge branch 'next' of https://github.com/navikt/Designsystemet into next 2023-02-02 13:42:31 +01:00
Ken 3ac20c695c 🎨 Tagger basert på status på søketreff 2023-02-02 13:40:35 +01:00
github-actions[bot]andgithub-actions[bot] 218707905e Version Packages (#1778)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-02-02 13:28:59 +01:00
Kai Erik Schieren 72f1ab0c85 🎨 fix frontpage tema preview (#1779) 2023-02-02 13:28:20 +01:00
Ken 2c57117098 📱 Tilpasset header for mobil 2023-02-02 13:25:22 +01:00
Ken f6ba5e1219 🎨 Justert header for riktig høyde 2023-02-02 13:12:16 +01:00
Ken 1c53160a2a ♿ Aria-hidden på åpne-søk knapp 2023-02-02 13:05:56 +01:00
Ken 22527c073f 🎨 Fikset href for søk 2023-02-02 12:54:29 +01:00
Ken 5b41ecac4c 💄 Fikset margin-top ved tom beskrivelse 2023-02-02 12:53:07 +01:00
Ken 14e07e4ca6 🔥 Fjernet ubrukt funksjonsvariabel 2023-02-02 12:49:57 +01:00
Ken cd1c93f9d4 openOnFocus-prop for useDatepicker/useMonthpicker (#1777) 2023-02-02 12:42:17 +01:00
Ken 545864553f 🎨 Bedre lasting og visning av ikoner 2023-02-02 12:40:13 +01:00
Ken 3b2f10fb91 🎨 Ikonsøk i søket 2023-02-02 11:43:32 +01:00
Ken bec7d5945f 🎨 Visning for ikoner 2023-02-02 11:17:54 +01:00
Ken f32bd408a2 🎨 Bedre highlighting basert på multiword string 2023-02-02 02:02:06 +01:00
Ken 7ba8c466f4 🎨 Lagt til github for image-providing 2023-02-02 00:07:42 +01:00
Ken bede18133c 🎨 Clamping på komponent-description 2023-02-01 23:46:23 +01:00
Ken 81e65cc0ab 🎨 Fikset z-level stacking ved bruk av flere modaler 2023-02-01 23:24:35 +01:00
Ken 5acdbe33c1 🎨 Loading-state funker nå ved søk med samme query 2023-02-01 23:19:15 +01:00
Ken 727999ba72 🎨 Redusert api-fetch reponse size 20x 2023-02-01 19:40:40 +01:00
Ken 7ad82450b4 🎨 Refaktorert API-respons for søk 2023-02-01 19:06:51 +01:00
Ken a72e965785 🏷️ Flyttet typer ut til lib 2023-02-01 18:43:24 +01:00
Ken e3fd48728b 🚚 Flyttet Hit og Group ut i egen fil 2023-02-01 18:30:37 +01:00
Ken 89c3603765 🎨 Bedre staehandling for lukking av search 2023-02-01 16:27:18 +01:00
Ken 03f7034fca 📝 Skrivefeil options 2023-02-01 16:11:37 +01:00
Ken 527ba00287 Update GlobalSearch.tsx 2023-02-01 16:11:00 +01:00
Ken b3831f0b1c 🎨 Fikset build 2023-02-01 16:08:57 +01:00
Ken 0549ad19b6 🎨 Oppdaterert og åpner søk basert på url-queries 2023-02-01 14:12:00 +01:00
Ken 7d1095fd96 📝 Todos 2023-02-01 13:18:35 +01:00
Ken acb1d0b955 ♿ Oppdatert semantikk for skjermleser i søk 2023-02-01 13:11:22 +01:00
Ken 4fc51e00b5 Merge branch 'master' into sanity-search 2023-02-01 12:04:00 +01:00
Ken 796bb5225f 🔊 Oppdatert logging av lenker 2023-02-01 10:06:44 +01:00
Ken 9ff2830297 ⬆️ Oppdatert Sanity 2023-02-01 09:36:29 +01:00
Ken d40939458a 🐛 Disable dev-workspace in sanity 2023-01-31 16:11:14 +01:00
Kai Erik Schieren 310974b3c3 🎨 filter states & filter hit count 2023-01-31 15:43:49 +01:00
Ken 73b30a8ea7 🐛 Fikset onClick button 2023-01-31 13:46:29 +01:00
Ken 790e70a90d 💄 Redesign header og søkeknapp 2023-01-31 13:29:43 +01:00
Ken 4114cecd93 💄 Oppdatert markering av treff 2023-01-31 12:12:04 +01:00
Ken 797f48a9fb 🎨 Tags på god-praksis i søk 2023-01-31 12:04:03 +01:00
Ken 13d3007293 Merge branch 'master' into sanity-search 2023-01-31 11:18:00 +01:00
Ken bcfd6747d9 📝 Changeset versions 2023-01-31 11:09:43 +01:00
Ken 122bbf0090 🐛 Date-fns import feilet fra ESM 2023-01-31 11:08:45 +01:00
Ken c0cb5a02b3 Merge master 2023-01-31 10:59:10 +01:00
Ken b60d047b95 Merge branch 'next' 2023-01-31 10:57:00 +01:00
Ken 66badd5df5 🎨 Filter 2023-01-30 18:06:47 +01:00
Ken 7360426aef 🎨 Modal funker nå på desktop 2023-01-30 16:15:19 +01:00
Ken b71d407396 🎨 scroll active element into view 2023-01-30 15:11:50 +01:00
Ken ca7c4964a2 🎨 Z-stacking for header-menyer 2023-01-30 13:50:41 +01:00
Ken 5e078db3fd 🎨 Struktur hamburgermeny og søk i header 2023-01-30 13:33:13 +01:00
Ken eb32b0a80b 🎨 Rename search-navn 2023-01-30 13:18:25 +01:00
Ken b56f83bf50 Merge branch 'master' into sanity-search 2023-01-30 13:15:05 +01:00
Ken 1399f6f084 Merge branch 'next' of https://github.com/navikt/Designsystemet into next 2023-01-30 13:10:56 +01:00
Kai Erik SchierenandKen 1cf90c1753 Feature/suggestion box (#1773)
* 🎨 SuggestionBlock

* ✨ SuggestionBlock for grunnleggende/komponentsider

* 🎨 Flyttet options ut til eget object

* 🎨 optional chain suggestion block

* 🎨 add issue url to new icon

* 🎨 add urls for updates requests

* 🎨 add labels to links

* 🎨 add cml label to href

* 🎨 url to new and beta

* 🎨 add fitting labels to hrefs

* fix reference 🐛

* 💄 Oppdatert ikoner/heading for beta og Ny

---------

Co-authored-by: Ken <ken.aleksander@gmail.com>
2023-01-30 13:02:20 +01:00
Ken b55bfac1c3 🎨 Eventlisteners ved keyboard-navigering 2023-01-30 11:19:51 +01:00
Ken de2dcdcc15 🎨 Søk i modal og header 2023-01-27 19:59:32 +01:00
Ken 12e95d063a 💄 Loader size 2023-01-27 19:25:08 +01:00
Ken 643ae3bc15 🎨 Temp-lagring av sanity-data 2023-01-27 19:24:02 +01:00
Ken 73f5f9fbfd 🎨 Loader ved empty-state 2023-01-27 14:04:58 +01:00
Ken 527fe4f0c1 🎨 Justert søketreff-config 2023-01-27 13:56:32 +01:00
Ken 1a9214e328 ⬆️ yarn lock 2023-01-27 13:24:50 +01:00
Ken 8c0b2363e0 Merge branch 'master' into sanity-search 2023-01-27 13:23:15 +01:00
Ken 6d38b7bbdd ♿ ul > li for søketreff 2023-01-26 11:42:05 +01:00
Ken 936e794e2f 🎨 Juster søk-config for bedre komponent-treff 2023-01-26 10:37:27 +01:00
Ken 500eecc43d 📝 todos 2023-01-26 09:24:20 +01:00
Ken 2ac73a7812 📝 todos 2023-01-26 09:17:32 +01:00
Ken 451dacb14a 📝 todos 2023-01-26 09:15:00 +01:00
Ken e6228c103d 🎨 Thumbnail-bilde preview 2023-01-25 22:32:00 +01:00
Ken 572d913718 🎨 La til hr-element som divider 2023-01-25 22:19:57 +01:00
Ken c0cd0dd66f 🎨 Bedre comparisons med lowercase i highlighting 2023-01-25 18:39:02 +01:00
Ken 613e20eb12 📝 Lagt til todos 2023-01-25 15:53:43 +01:00
Ken 4bf0506362 💄 Stylet search-hit 2023-01-25 15:50:37 +01:00
Ken 5997db2b38 🎨 Oppdatert tailwind config med nye farger 2023-01-25 15:03:58 +01:00
Ken 9f18063fe5 🎨 La data fra søkeresultat inn i 'item'-key 2023-01-25 14:52:11 +01:00
Vegard Haugstvedt b037114863 🎨 Convert const arrow functions to regular functions 2023-01-25 14:12:44 +01:00
Vegard Haugstvedt e47521d6e5 🎨 Refaktorert kode for å håndtere docQuery verdier for Søk 2023-01-25 14:03:26 +01:00
Vegard Haugstvedt 61357fb40a 🎨 Endre options-format til objekt, og legg inn støtte for flere tags i fetch-kall 2023-01-25 13:36:02 +01:00
Ken 5678d4cf10 🎨 Fikset highlighting 2023-01-25 13:02:57 +01:00
Ken d403c09b1a 🎨 Prototype med highlighting 2023-01-25 13:02:37 +01:00
Ken deff5b25b2 🔥 Fjernet console.log 2023-01-24 13:58:18 +01:00
Ken 31e60deea8 🎨 Selektiv visning av grupper basert på tags 2023-01-24 13:55:23 +01:00
Ken 847142dc72 🎨 Search-gruppering og visning 2023-01-24 13:19:19 +01:00
Ken a5b3ad81a7 🎨 Throttled-search 2023-01-24 12:36:07 +01:00
Ken fe1ac779bf 🎨 Bedre initial-search 2023-01-24 11:47:12 +01:00
Ken 064b2fc612 Merge branch 'master' into sanity-search 2023-01-24 11:39:35 +01:00
Ken 5d57586dc1 🎨 Chips oppdaterer nyeste artikler visning 2022-12-29 19:49:19 +01:00
Ken e8d012b82d 🎨 Fuse-search 2022-12-28 15:12:24 +01:00
Ken 4e90102efd 🎨 Bedre fine-grained query 2022-12-27 16:01:21 +01:00
Ken 02c55aaa0f 🎨 query 2022-12-27 14:22:06 +01:00
Ken 8d4ee29d78 🎉 Nytt søk 2022-12-27 14:08:45 +01:00
195 changed files with 4062 additions and 21682 deletions

No files matched your search

+29 -4
View File
@@ -9,6 +9,34 @@ env:
IMAGE: ghcr.io/navikt/designsystemet
jobs:
snyk-monitor:
name: monitor dependencies
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run Snyk to check for vulnerabilities
continue-on-error: true
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: monitor
args: --org=designsystemet --severity-threshold=high
snyk-test:
name: analyze dependencies
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: test
args: --org=designsystemet --severity-threshold=high
build_and_deploy:
name: Build and deploy to dev-gcp
runs-on: ubuntu-20.04
@@ -17,8 +45,6 @@ jobs:
with:
node-version: "14"
- uses: actions/checkout@v2
with:
ref: "next"
- name: add tokens to .env
run: |
echo "SANITY_WRITE_KEY=${{ secrets.SANITY_FEEDBACK_WRITE_KEY }}" >> aksel.nav.no/website/.env
@@ -40,11 +66,10 @@ jobs:
- name: Build application
run: |
yarn boot
yarn docgen
yarn workspace aksel.nav.no build:next
- name: Login to GitHub Container Registry
uses: docker/login-action@ab80d026d4753220c4243394c07c7d80f9638d06 # Use commit-sha1 instead of tag for security concerns
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # Use commit-sha1 instead of tag for security concerns
with:
registry: ghcr.io
username: ${{ github.actor }}
+70 -12
View File
@@ -10,9 +10,68 @@ env:
IMAGE: ghcr.io/navikt/designsystemet
jobs:
snyk-monitor:
name: monitor dependencies
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run Snyk to check for vulnerabilities
continue-on-error: true
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: monitor
args: --org=designsystemet --severity-threshold=high
snyk-test:
name: analyze dependencies
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
continue-on-error: true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
command: test
args: --org=designsystemet --severity-threshold=high
sync_data_with_sanity:
name: Update component data
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v1
with:
node-version: "14"
- uses: actions/checkout@v2
- name: add tokens to .env
run: |
echo "SANITY_WRITE_KEY=${{ secrets.SANITY_FEEDBACK_WRITE_KEY }}" >> aksel.nav.no/website/.env
- name: Restore cache
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-prod-${{ github.sha }}
restore-keys: |
${{ runner.os }}-prod-
- name: Install dependencies
run: yarn
- name: Run docgen
run: |
yarn boot
yarn docgen
- name: Update sanity sync
run: yarn workspace aksel.nav.no sanity:update
build_and_deploy:
name: Build and deploy to prod-gcp
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- uses: actions/setup-node@v1
with:
@@ -36,25 +95,17 @@ jobs:
- name: Install dependencies
run: yarn
- name: build packages
run: |
yarn boot
yarn docgen
- name: Build packages
run: yarn boot
- name: Tests
run: yarn workspace aksel.nav.no test
- name: E2E
run: NEXT_PUBLIC_TEST=true yarn workspace website e2e
- name: Update sanity sync
run: yarn workspace aksel.nav.no sanity:update
- name: Build application
run: yarn workspace aksel.nav.no build:next
- name: Login to GitHub Container Registry
uses: docker/login-action@ab80d026d4753220c4243394c07c7d80f9638d06 # Use commit-sha1 instead of tag for security concerns
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # Use commit-sha1 instead of tag for security concerns
with:
registry: ghcr.io
username: ${{ github.actor }}
@@ -65,6 +116,13 @@ jobs:
run: echo "DOCKER_TAG=${{ env.IMAGE }}:${{ env.TAG }}" >> $GITHUB_ENV
- name: Build docker image
run: docker build -t ${{ env.DOCKER_TAG }} . -f aksel.nav.no/Dockerfile
- name: Wait for e2e-tests to succeed
uses: lewagon/wait-on-check-action@v1.2.0
with:
ref: ${{ github.ref }}
check-name: "Smoketest Aksel"
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
- name: Push docker image
run: |
docker push ${{ env.DOCKER_TAG }}
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
node-version: "14"
- uses: actions/checkout@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@ab80d026d4753220c4243394c07c7d80f9638d06 # Use commit-sha1 instead of tag for security concerns
uses: docker/login-action@f4ef78c080cd8ba55a85445d5b36e214a81df20a # Use commit-sha1 instead of tag for security concerns
with:
registry: ghcr.io
username: ${{ github.actor }}
+7 -5
View File
@@ -12,6 +12,8 @@ on:
jobs:
playwright:
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.30.0-focal
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
@@ -36,15 +38,15 @@ jobs:
- name: Install dependencies
run: yarn
- name: build packages
- name: Build packages
run: |
yarn boot
yarn docgen
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Build application
run: yarn workspace aksel.nav.no build:next
- name: Run Playwright tests
run: yarn workspace website e2e:full
run: yarn workspace website e2e:ci-full
- uses: actions/upload-artifact@v3
if: always()
with:
+49
View File
@@ -0,0 +1,49 @@
name: Smoketest aksel.nav.no
on:
push:
branches:
- master
paths:
- "aksel.nav.no/**"
env:
IMAGE: ghcr.io/navikt/designsystemet
jobs:
smoketest:
name: Smoketest Aksel
runs-on: ubuntu-latest
container:
image: mcr.microsoft.com/playwright:v1.30.0-focal
steps:
- uses: actions/setup-node@v1
with:
node-version: "14"
- uses: actions/checkout@v2
- name: add tokens to .env
run: |
echo "SANITY_WRITE_KEY=${{ secrets.SANITY_FEEDBACK_WRITE_KEY }}" >> aksel.nav.no/website/.env
echo "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" >> aksel.nav.no/website/.env
echo "SANITY_PREVIEW_TOKEN=${{ secrets.SANITY_PREVIEW_TOKEN }}" >> aksel.nav.no/website/.env
echo "SANITY_PRIVATE_NO_DRAFTS=${{ secrets.SANITY_PRIVATE_NO_DRAFTS }}" >> aksel.nav.no/website/.env
- name: Restore cache
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-prod-${{ github.sha }}
restore-keys: |
${{ runner.os }}-prod-
- name: Install dependencies
run: yarn
- name: build packages
run: |
yarn boot
- name: Build application
run: yarn workspace aksel.nav.no build:next
- name: E2E smoketest
run: yarn workspace website e2e:ci
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-codemod
## 2.1.6
## 2.1.5
## 2.1.4
## 2.1.3
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-codemod",
"version": "2.1.4",
"version": "2.1.6",
"description": "Aksel codemods for NAVs designsystem",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
+2 -2
View File
@@ -39,8 +39,8 @@
"build-pict": "svgr --silent --index-template index-template.js --out-dir src/pictograms pictograms"
},
"dependencies": {
"@navikt/ds-icons": "^2.1.4",
"@navikt/ds-react": "^2.1.4",
"@navikt/ds-icons": "^2.1.6",
"@navikt/ds-react": "^2.1.6",
"clsx": "^1.1.1"
},
"devDependencies": {
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-css
## 2.1.6
## 2.1.5
## 2.1.4
## 2.1.3
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css",
"version": "2.1.4",
"version": "2.1.6",
"description": "CSS for NAV Designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -20,7 +20,7 @@
"watch": "postcss --watch --use postcss-import -o dist/index.css index.css"
},
"devDependencies": {
"@navikt/ds-tokens": "^2.1.4",
"@navikt/ds-tokens": "^2.1.6",
"normalize.css": "^8.0.1",
"postcss": "^8.4.0",
"postcss-cli": "^9.0.0",
+18
View File
@@ -1,5 +1,23 @@
# @navikt/ds-react
## 2.1.6
### Patch Changes
- [#1777](https://github.com/navikt/Designsystemet/pull/1777) [`cd1c93f9d`](https://github.com/navikt/Designsystemet/commit/cd1c93f9d471fbbc38215d788a73f21b5b216c5b) Thanks [@KenAJoh](https://github.com/KenAJoh)! - :sparkles: Datepicker og monthpicker kan nå bestemme om popover skal dukke opp ved fokus
- Updated dependencies []:
- @navikt/ds-icons@2.1.6
## 2.1.5
### Patch Changes
- Hotfix: ESM import fra date-fns feilet
- Updated dependencies []:
- @navikt/ds-icons@2.1.5
## 2.1.4
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react",
"version": "2.1.4",
"version": "2.1.6",
"description": "Aksel react-components for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -37,7 +37,7 @@
},
"dependencies": {
"@floating-ui/react": "0.17.0",
"@navikt/ds-icons": "^2.1.4",
"@navikt/ds-icons": "^2.1.6",
"@radix-ui/react-tabs": "1.0.0",
"@radix-ui/react-toggle-group": "1.0.0",
"clsx": "^1.2.1",
@@ -148,6 +148,7 @@ export const UseDatepicker = () => {
fromDate: new Date("Aug 23 2019"),
onDateChange: console.log,
locale: "en",
openOnFocus: false,
});
return (
@@ -179,6 +180,21 @@ export const UseRangedDatepicker = () => {
);
};
export const OpenOnFocus = () => {
const { datepickerProps, inputProps } = UNSAFE_useDatepicker({
onDateChange: console.log,
openOnFocus: false,
});
return (
<div style={{ display: "flex", gap: "1rem" }}>
<DatePicker {...datepickerProps}>
<DatePicker.Input {...inputProps} label="Velg dato" />
</DatePicker>
</div>
);
};
export const NB = () => (
<DatePicker.Standalone locale="nb" today={new Date("2006-07-01")} />
);
@@ -56,6 +56,11 @@ export interface UseDatepickerOptions
* In 2023 this equals to 1943 - 2042
*/
allowTwoDigitYear?: boolean;
/**
* Opens datepicker on input-focus
* @default true
*/
openOnFocus?: boolean;
}
interface UseDatepickerValue {
@@ -123,6 +128,7 @@ export const useDatepicker = (
onValidate,
defaultMonth,
allowTwoDigitYear = true,
openOnFocus = true,
} = opt;
const locale = getLocaleFromString(_locale);
@@ -198,7 +204,7 @@ export const useDatepicker = (
};
const handleFocus: React.FocusEventHandler<HTMLInputElement> = (e) => {
!open && setOpen(true);
!open && openOnFocus && setOpen(true);
let day = parseDate(
e.target.value,
today,
@@ -42,6 +42,11 @@ export interface UseMonthPickerOptions
* In 2023 this equals to 1943 - 2042
*/
allowTwoDigitYear?: boolean;
/**
* Opens datepicker on input-focus
* @default true
*/
openOnFocus?: boolean;
}
interface UseMonthPickerValue {
@@ -104,6 +109,7 @@ export const useMonthpicker = (
onValidate,
defaultYear,
allowTwoDigitYear = true,
openOnFocus = true,
} = opt;
const [defaultSelected, setDefaultSelected] = useState(_defaultSelected);
@@ -180,7 +186,7 @@ export const useMonthpicker = (
};
const handleFocus: React.FocusEventHandler<HTMLInputElement> = (e) => {
!open && setOpen(true);
!open && openOnFocus && setOpen(true);
let day = parseDate(
e.target.value,
today,
@@ -1,5 +1,5 @@
import differenceInCalendarDays from "date-fns/differenceInCalendarDays";
import { isBefore } from "date-fns/esm";
import isBefore from "date-fns/isBefore";
import isWeekend from "date-fns/isWeekend";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { DateRange, isMatch } from "react-day-picker";
@@ -204,6 +204,7 @@ export const useRangeDatepicker = (
onValidate,
defaultMonth,
allowTwoDigitYear = true,
openOnFocus = true,
} = opt;
const locale = getLocaleFromString(_locale);
@@ -323,7 +324,7 @@ export const useRangeDatepicker = (
};
const handleFocus = (e, src: RangeT) => {
!open && setOpen(true);
!open && openOnFocus && setOpen(true);
let day = parseDate(
e.target.value,
today,
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-tailwind
## 2.1.6
## 2.1.5
## 2.1.4
## 2.1.3
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tailwind",
"version": "2.1.4",
"version": "2.1.6",
"description": "Tailwind config based on @navikt/ds-tokens",
"author": "Aksel | NAV designsystem team",
"keywords": [
@@ -22,7 +22,7 @@
"directory": "@navikt/core/tailwind"
},
"devDependencies": {
"@navikt/ds-tokens": "^2.1.4",
"@navikt/ds-tokens": "^2.1.6",
"@types/jest": "^29.0.0",
"color": "4.2.3",
"jest": "^29.0.0",
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-tokens
## 2.1.6
## 2.1.5
## 2.1.4
## 2.1.3
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-tokens",
"version": "2.1.4",
"version": "2.1.6",
"description": "Design-tokens for NAV designsystem",
"author": "Aksel | NAV designsystem team",
"keywords": [
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-icons
## 2.1.6
## 2.1.5
## 2.1.4
## 2.1.3
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-icons",
"version": "2.1.4",
"version": "2.1.6",
"description": "Aksel icons for NAV",
"author": "Aksel | NAV designsystem team",
"repository": {
+4
View File
@@ -1,5 +1,9 @@
# @navikt/ds-css-internal
## 2.1.6
## 2.1.5
## 2.1.4
## 2.1.3
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-css-internal",
"version": "2.1.4",
"version": "2.1.6",
"description": "CSS for NAV internal Designsystem-components",
"author": "Aksel | NAV designsystem team",
"keywords": [
+16
View File
@@ -1,5 +1,21 @@
# @navikt/ds-react-internal
## 2.1.6
### Patch Changes
- Updated dependencies [[`cd1c93f9d`](https://github.com/navikt/Designsystemet/commit/cd1c93f9d471fbbc38215d788a73f21b5b216c5b)]:
- @navikt/ds-react@2.1.6
- @navikt/ds-icons@2.1.6
## 2.1.5
### Patch Changes
- Updated dependencies []:
- @navikt/ds-react@2.1.5
- @navikt/ds-icons@2.1.5
## 2.1.4
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@navikt/ds-react-internal",
"version": "2.1.4",
"version": "2.1.6",
"description": "Aksel react components for internal UIs in NAV",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
@@ -35,8 +35,8 @@
"watch": "tsc --watch -p tsconfig.esm.json"
},
"dependencies": {
"@navikt/ds-icons": "^2.1.4",
"@navikt/ds-react": "^2.1.4",
"@navikt/ds-icons": "^2.1.6",
"@navikt/ds-react": "^2.1.6",
"clsx": "^1.1.1",
"copy-to-clipboard": "^3.3.1"
},
+1 -2
View File
@@ -39,8 +39,7 @@
aksel.nav.no/
├── website # NEXT.JS app (v12)
├── website/sanity # Sanity CMS-app (v3)
└── sanity # Sanity CMS-app (deprecated v2)
└── website/sanity # Sanity CMS-app (v3)
```
## Commands
+1 -2
View File
@@ -1,4 +1,4 @@
FROM node:16.4-alpine3.14
FROM node:16.13.1-alpine3.14
RUN apk add --no-cache libc6-compat
ENV NODE_ENV production
@@ -8,7 +8,6 @@ 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/redirects.json .
COPY aksel.nav.no/website/next.config.js .
COPY node_modules/ node_modules/
COPY @navikt/ @navikt/
+1 -1
View File
@@ -19,7 +19,7 @@ Det publiserte studioet finner man på [aksel.nav.no/admin](https://aksel.nav.no
### Bidrag
Branch `master` blir pusher rett til prod -> aksel.nav.no. For å utvikle nye features brukes branch `next` som ved push publiseres til devmiljø aksel.dev.nav.no (krever naisdevice).
Branch `master` blir pusher rett til prod -> aksel.nav.no. For å utvikle nye features brukes branch `next` som ved push publiseres til devmiljø aksel.dev.nav.no (krever naisdevice). Kan også publisere andre branches til dev ved bruk av workflow-dispatch.
### Nettside (localhost:3000)
-13
View File
@@ -12,24 +12,11 @@ spec:
- "https://aksel.dev.nav.no"
liveness:
path: /api/isAlive
initialDelay: 20
timeout: 1
periodSeconds: 5
failureThreshold: 10
readiness:
path: /api/isAlive
initialDelay: 20
timeout: 1
replicas:
min: 1
max: 1
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 200m
memory: 256Mi
accessPolicy:
outbound:
external:
+8 -8
View File
@@ -15,14 +15,14 @@
"website"
],
"dependencies": {
"@navikt/ds-codemod": "^2.1.4",
"@navikt/ds-css": "^2.1.4",
"@navikt/ds-css-internal": "^2.1.4",
"@navikt/ds-icons": "^2.1.4",
"@navikt/ds-react": "^2.1.4",
"@navikt/ds-react-internal": "^2.1.4",
"@navikt/ds-tailwind": "^2.1.4",
"@navikt/ds-tokens": "^2.1.4"
"@navikt/ds-codemod": "^2.1.6",
"@navikt/ds-css": "^2.1.6",
"@navikt/ds-css-internal": "^2.1.6",
"@navikt/ds-icons": "^2.1.6",
"@navikt/ds-react": "^2.1.6",
"@navikt/ds-react-internal": "^2.1.6",
"@navikt/ds-tailwind": "^2.1.6",
"@navikt/ds-tokens": "^2.1.6"
},
"devDependencies": {
"prettier-plugin-tailwindcss": "^0.1.13"
-2
View File
@@ -1,2 +0,0 @@
.yarn/cache
*.tar.gz
@@ -1,46 +0,0 @@
// https://www.sanity.io/schemas/make-a-field-read-only-after-publishing-once-d87bf5f6
import { useState, useEffect } from "react";
import { useDocumentOperation, useValidationStatus } from "@sanity/react-hooks";
import PublishIcon from "part:@sanity/base/publish-icon";
export default function SetAndPublishAction(props) {
const { patch, publish }: any = useDocumentOperation(props.id, props.type);
const { isValidating, markers }: any = useValidationStatus(
props.id,
props.type
);
const [isPublishing, setIsPublishing] = useState(false);
useEffect(() => {
// if the isPublishing state was set to true and the draft has changed
// to become `null` the document has been published
if (isPublishing && !props.draft) {
setIsPublishing(false);
}
}, [props.draft]);
return {
disabled:
publish.disabled ||
isValidating ||
markers.some((x) => x?.level === "error"),
label: isPublishing ? "Publishing…" : "Publish",
color: "success",
icon: PublishIcon,
onHandle: () => {
// This will update the button text
setIsPublishing(true);
// Set publishedAt to current date and time
!props.published &&
patch.execute([{ set: { publishedAt: new Date().toISOString() } }]);
// Perform the publish
publish.execute();
// Signal that the action is completed
props.onComplete();
},
};
}
@@ -1,139 +0,0 @@
import { EyeScreened } from "@navikt/ds-icons";
import { BodyLong, Button } from "@navikt/ds-react";
import React from "react";
const sanityClient = require("@sanity/client");
const SanityConfig = require("../../sanity.json");
const client = sanityClient({
projectId: SanityConfig.api.projectId,
dataset: SanityConfig.api.dataset,
apiVersion: "2021-08-21",
withCredentials: true,
});
export default function SetPrivateAction(props) {
const [isDialogOpen, setDialogOpen] = React.useState(false);
const isPrivate =
props?.published?.tilgang?.privat ?? props?.draft?.tilgang?.privat;
const handlePatch = async (dir: boolean) => {
props?.published &&
(await client
.patch(props.id)
.set({ tilgang: { privat: dir } })
.commit()
.catch((err) => {
console.error(err.message);
}));
props?.draft &&
(await client
.patch(props.draft._id)
.set({ tilgang: { privat: dir } })
.commit()
.catch((err) => {
console.error(err.message);
}));
props.onComplete();
};
return {
label: isPrivate ? "Åpne side for alle" : "Skjul side bak innlogging",
/* color: "success",
icon: PublishIcon, */
icon: EyeScreened,
onHandle: async () => {
setDialogOpen(true);
},
dialog: isDialogOpen && {
type: "modal",
onClose: props.onComplete,
header: isPrivate
? "Åpne innhold for alle"
: "Gjemme innhold bak innlogging",
content: (
<div>
{isPrivate ? (
<BodyLong spacing>
Innholdet gjøres nå tilgjengelig for alle utenfor NAV! Dette kan
medføre konsekvenser siden innholdet i artikkelen blir
tilgjengelig for alle. Innhold som NAV potensielt ikke ønsker å
dele offentlig kan medføre eks omdømmetap og uønsket oppmerksomhet
utenfra. Dobbelsjekk med temaansvarlig og andre som har skrevet
artikkelen før du velger å åpne innholdet for alle. Er du usikker
er det bare å sende en melding på #Aksel-designsystemet eller
#aksel-redaktører på Slack.
</BodyLong>
) : (
<>
<BodyLong spacing>
Innholdet gjøres nå bare tilgjengelig for NAV-ansatte. Alt
utenom "innhold" vil fortsatt være tilgjengelig for alle. Dette
inkluderer alle bilder som er lastet opp til sanity også! Husk
at ingen "sikker" data skal skrives i Aksel, og at
innloggings-barrieren er ment for å kunne dele innhold som vi
ikke er helt trygg på å dele med alle.
</BodyLong>
Dette vil fortsatt være åpent for alle
<ul>
<li>Sidetittel</li>
<li>Ingress</li>
<li>Redaktører</li>
<li>Bilder/filer</li>
<li>SEO</li>
</ul>
Dette vil bare være tilgjengelig for NAV-ansatte
<ul>
<li>"Innhold"-blokken</li>
</ul>
</>
)}
<div style={{ display: "flex", gap: "6px", marginTop: 8 }}>
{isPrivate ? (
<>
<Button
onClick={() => {
setDialogOpen(false);
handlePatch(false);
}}
>
Åpne innholdet for alle
</Button>
<Button
variant="secondary"
onClick={() => {
setDialogOpen(false);
props.onComplete();
}}
>
Avbryt
</Button>
</>
) : (
<>
<Button
onClick={() => {
setDialogOpen(false);
handlePatch(true);
}}
>
Skjul innholdet bak innlogging
</Button>
<Button
variant="secondary"
onClick={() => {
setDialogOpen(false);
props.onComplete();
}}
>
Avbryt
</Button>
</>
)}
</div>
</div>
),
},
};
}
@@ -1,3 +0,0 @@
import MediaAssetSource from "part:sanity-plugin-media/asset-source";
import Unsplash from "part:sanity-plugin-asset-source-unsplash/image-asset-source";
export default [MediaAssetSource, Unsplash];
@@ -1,53 +0,0 @@
import { Send } from "@navikt/ds-icons";
import { BodyLong, Button, Heading, Modal } from "@navikt/ds-react";
import React, { useRef, useState } from "react";
const BundleChecker = () => {
const [inc, setInc] = useState(0);
const interval = useRef(null);
const start = () => {
interval.current = setInterval(() => {
setInc((x) => x + 0.4);
}, 10);
};
if (inc > 99) {
clearInterval(interval.current);
window.location.replace("https://aksel.nav.no/admin");
}
document.body.style.opacity = `${100 - inc}%`;
document.body.style.scale = `${1 - inc / 150}`;
document.body.style.rotate = `${inc ** 1.3}deg`;
return (
<Modal
aria-labelledby="modal-heading"
closeButton={false}
open
onClose={() => null}
>
<Modal.Content style={{ minWidth: "20rem", maxWidth: "40rem" }}>
<Heading spacing id="modal-heading" size="medium" level="1">
Studioet er flyttet!
</Heading>
<BodyLong spacing>
Vi har oppdatert studioet og flyttet det til ny url:
aksel.nav.no/admin. Hvis noe ikke fungerer, ta kontakt på slack
#aksel-redaksjonen! Husk å logge inn med samme login-provider. For de
fleste vil dette være NAV SSO.
</BodyLong>
<Button
onClick={() => start()}
icon={<Send aria-hidden />}
iconPosition="right"
>
Gå til nytt studio
</Button>
</Modal.Content>
</Modal>
);
};
export default BundleChecker;
@@ -1,44 +0,0 @@
import { allDocumentTypes } from "../config";
export default {
widgets: [
{
name: "document-list",
options: {
title: "Drafts for God Praksis",
query: '*[_type in $types && (_id in path("drafts.**"))]',
queryParams: {
types: allDocumentTypes.filter((x) => x.startsWith("gp")),
},
},
},
{
name: "document-list",
options: {
title: "Drafts for Designsystemet",
query: '*[_type in $types && (_id in path("drafts.**"))]',
queryParams: {
types: allDocumentTypes.filter((x) => x.startsWith("ds")),
},
},
},
{
name: "outdated-documents-widget",
options: {
type: "warning",
},
},
{
name: "outdated-documents-widget",
options: {
type: "error",
},
},
{
name: "project-info",
},
{
name: "project-users",
},
],
};
@@ -1,19 +0,0 @@
import { Picture } from "@navikt/ds-icons";
import S from "@sanity/desk-tool/structure-builder";
import React from "react";
export const adminPanel = async (roles) =>
roles.find((x) => x.name === "administrator") &&
S.listItem()
.title("Admin")
.child(
S.list()
.title("Admin")
.items([
S.listItem()
.title("Standalone-sider")
.child(S.documentTypeList("aksel_standalone")),
S.listItem().title("Redirects").child(S.documentTypeList("redirect")),
])
);
@@ -1,104 +0,0 @@
import { prinsipper } from "@/lib";
import { Facilitet } from "@navikt/ds-icons";
import S from "@sanity/desk-tool/structure-builder";
import documentStore from "part:@sanity/base/datastore/document";
import React from "react";
import { map } from "rxjs/operators";
const temaQuery = `*[_type == "aksel_tema" && count(*[references(^._id)]) > 0]`;
const AkselLogo = () => (
<svg
width="192px"
height="192px"
viewBox="0 0 192 192"
fill="none"
xmlns="http://www.w3.org/2000/svg"
focusable="false"
aria-hidden="true"
strokeLinecap="round"
strokeWidth="10"
stroke="currentColor"
>
<path d="m41.63 150.3 47.39-47.38" />
<path d="M40.92 80.3 77.7 43.53c4.25-4.24 9.9-4.24 14.15 0l56.56 56.57c4.25 4.25 4.25 9.9 0 14.14l-36.77 36.77" />
<path d="m40.92 80.3 38.19-38.18c3.53-3.54 6.72-3.18 13.79-3.18h48.79s0 0 0 0c6.36 0 11.31 4.95 11.31 11.31 0 0 0 0 0 0v48.8c0 7.06.35 10.24-3.18 13.78l-38.19 38.18" />
</svg>
);
export const akselInnhold = async () => {
return S.listItem()
.title("Aksel")
.icon(() => <AkselLogo />)
.child(
S.list()
.title("Innhold")
.items([
S.listItem()
.title("Artikler")
.child(() =>
documentStore.listenQuery(temaQuery).pipe(
map((tema: any) => {
return S.list()
.title("Artikler")
.items([
S.listItem()
.title("Alle artikler")
.child(S.documentTypeList("aksel_artikkel")),
S.listItem()
.title("Uten tema")
.child(
S.documentTypeList("aksel_artikkel").filter(
`_type == "aksel_artikkel" && !defined(tema)`
)
),
...tema.map((tag) => {
return S.listItem()
.title(tag.title)
.child(
S.documentList()
.title(tag.title)
.filter(
`_type == 'aksel_artikkel' && $tag in tema[]->title`
)
.params({ tag: tag.title })
);
}),
]);
})
)
),
S.listItem()
.title("Produktbloggen")
.child(S.documentTypeList("aksel_blogg")),
S.listItem()
.title("Prinsipper")
.child(
S.list()
.title("Prinsipper")
.items([
S.listItem()
.title("Alle artikler")
.child(S.documentTypeList("aksel_prinsipp")),
...prinsipper.map(({ value, title }) =>
S.listItem()
.title(title)
.child(
S.documentList()
.title(title)
.filter(
`_type == 'aksel_prinsipp' && $value == prinsipp.prinsippvalg`
)
.params({ value })
)
),
])
),
S.divider(),
S.listItem()
.title("Temasider")
.icon(() => <Facilitet />)
.child(S.documentTypeList("aksel_tema")),
])
);
};
@@ -1,92 +0,0 @@
import { CoApplicant, Facilitet, Information, People } from "@navikt/ds-icons";
import S from "@sanity/desk-tool/structure-builder";
import userStore from "part:@sanity/base/user";
import React from "react";
import { createSuperPane } from "sanity-super-pane";
import { ComponentPageWebPreview } from "../../web-previews/ComponentWebPreview";
import { KomponentPreview } from "../../web-previews/KomponentPreview";
import { PageWebPreview } from "../../web-previews/PageWebPreview";
import { adminPanel } from "./admin";
import { akselInnhold } from "./aksel";
import { dsPanel } from "./ds";
import { profilePanel } from "./profile";
export const getDefaultDocumentNode = ({ schemaType }) => {
switch (schemaType) {
case "komponent_artikkel":
return S.document().views([
S.view.form(),
S.view.component(ComponentPageWebPreview).title("Preview"),
S.view.component(KomponentPreview).title("Preview-dev"),
]);
case "ds_artikkel":
return S.document().views([
S.view.form(),
S.view.component(PageWebPreview).title("Preview"),
S.view.component(KomponentPreview).title("Preview-dev"),
]);
case "aksel_artikkel":
return S.document().views([
S.view.form(),
S.view.component(PageWebPreview).title("Preview"),
S.view.component(KomponentPreview).title("Preview-dev"),
]);
case "aksel_blogg":
return S.document().views([
S.view.form(),
S.view.component(PageWebPreview).title("Preview"),
S.view.component(KomponentPreview).title("Preview-dev"),
]);
case "aksel_prinsipp":
return S.document().views([
S.view.form(),
S.view.component(PageWebPreview).title("Preview"),
S.view.component(KomponentPreview).title("Preview-dev"),
]);
case "aksel_standalone":
return S.document().views([
S.view.form(),
S.view.component(PageWebPreview).title("Preview"),
S.view.component(KomponentPreview).title("Preview-dev"),
]);
}
};
const items = [
S.divider(),
S.listItem()
.title("Redaktører")
.icon(() => <People />)
.child(createSuperPane("editor")),
S.divider(),
];
export default () => {
return userStore.getCurrentUser().then(async ({ roles, id }) => {
const panels = [];
const admin = await adminPanel(roles);
const profile = await profilePanel(id);
const ds = await dsPanel(roles);
const aksel = await akselInnhold();
const intro = [];
profile && intro.push(profile);
profile && intro.push(S.divider());
let struct = items;
if (ds) {
struct = [ds, ...struct];
}
struct = [aksel, ...struct];
if (admin) {
struct = [...struct, admin];
}
return S.list()
.title("Aksel")
.items([...intro, ...struct, ...panels]);
});
};
@@ -1,115 +0,0 @@
import {
Facilitet,
FileContent,
Findout,
Folder,
Picture,
Place,
Ruler,
Task,
} from "@navikt/ds-icons";
import S from "@sanity/desk-tool/structure-builder";
import client from "part:@sanity/base/client";
import React from "react";
import { createSuperPane } from "sanity-super-pane";
export const dsPanel = async (roles) => {
const role = roles.some(({ name }) => "aksel-editor" === name);
if (role) {
return null;
} else {
return S.listItem()
.title("Designsystemet")
.icon(() => <Facilitet />)
.child(
S.list()
.title("Designsystem")
.items([
S.listItem()
.title("Komponentsider")
.icon(() => <Facilitet />)
.child(createSuperPane("komponent_artikkel")),
S.listItem()
.title("Artikler")
.icon(() => <FileContent />)
.child(createSuperPane("ds_artikkel")),
S.divider(),
S.documentListItem()
.title(`Navigasjon`)
.schemaType(`ds_navigation`)
.icon(() => <Place />)
.id(`ds_navigationid`),
S.listItem()
.title("Publiserte sider ikke i navigasjon")
.child(async (): Promise<any> => {
const doc = await client.fetch(
`*[_id == 'ds_navigationid'][0]{
headings[]{
title,
menu
}
}`
);
if (!doc.headings) {
return [];
}
let allIds = "";
try {
allIds = doc.headings
.map((heading) =>
heading.menu
.filter((item) => item._type === "item")
.map((item) => item.link._ref)
.map((x) => `"${x}"`)
.join(",")
)
.join(",");
} catch (e) {
console.log(e);
}
return S.documentList()
.title("Sider ikke i navigasjon")
.filter(
`!(_id in [${allIds}]) && !(_id in path('drafts.**')) && _type in ["komponent_artikkel", "ds_artikkel"]`
);
}),
S.documentListItem()
.title(`Forside`)
.schemaType(`ds_frontpage`)
.icon(() => <Picture />)
.id(`frontpage_designsystem`),
S.divider(),
S.listItem()
.title("Autogenerert data")
.child(
S.list()
.title("Autogenerert data")
.items([
S.listItem()
.title("Eksempler")
.icon(() => <span>{`EX`}</span>)
.child(S.documentTypeList("kode_eksempler_fil")),
S.listItem()
.title("Props")
.icon(() => <Folder />)
.child(S.documentTypeList("ds_props")),
S.listItem()
.title("Token-kategorier")
.icon(() => <Folder />)
.child(S.documentTypeList("token_kategori")),
])
),
S.divider(),
S.documentListItem()
.title(`Komponent-template`)
.schemaType(`ds_component_template`)
.icon(() => <Task />)
.id(`ds_component_templateid`),
])
);
}
};
@@ -1,26 +0,0 @@
import { Picture } from "@navikt/ds-icons";
import S from "@sanity/desk-tool/structure-builder";
import userStore from "part:@sanity/base/user";
import client from "part:@sanity/base/client";
import React from "react";
export const profilePanel = async (id) => {
const ids = await client.withConfig({ apiVersion: "2021-05-31" })
.fetch(`*[_type == "editor"]{
_id,
user_id
}`);
const editor = ids.find(({ user_id }) => user_id?.current === id);
if (editor) {
return S.documentListItem()
.title(`Profil`)
.schemaType(`editor`)
.icon(() => <Picture />)
.id(editor._id);
} else {
return null;
}
};
@@ -1,53 +0,0 @@
import React from "react";
import { People } from "@navikt/ds-icons";
import T from "@sanity/base/initial-value-template-builder";
import userStore from "part:@sanity/base/user";
const sanityClient = require("@sanity/client");
const sanityToken = process.env.SANITY_TOKEN;
const SanityConfig = require("../sanity.json");
const client = sanityClient({
projectId: SanityConfig.api.projectId,
dataset: SanityConfig.api.dataset,
apiVersion: "2020-06-19",
/* Token er safe og har bare tillatelse til å lese template doc */
token:
"skt6kqEcXmRxUTGDzdEcw11g7HJi9DaHX2fyn8Z0Dearr1k67ykW2N64KTP9GxAPNN6P8TlzPjUdkfGsvbJkfmwfq0UNudKfMYOfyz9OeA666y15pPLRr6D7xnrJGEEBYwSvG6baLLiJI478YowWpjqp1Mz2U1PbAPnIMW4W5btTpdQbwPSD",
useCdn: false,
});
export default [
...T.defaults().filter((x) => !["komponent_artikkel"].includes(x.spec.id)),
T.template({
id: "komponent_artikkel_template",
title: "Mal for Komponentsider",
schemaType: "komponent_artikkel",
value: async () => {
const doc = await client.fetch(`*[_type == "ds_component_template"][0]`);
return doc
? Object.entries(doc).reduce((old, [key, val]) => {
return key.startsWith("_") ? { ...old } : { ...old, [key]: val };
}, {})
: {};
},
}),
T.template({
id: "newEditor",
title: "Editor",
schemaType: "editor",
icon: () => <People />,
value: async () => {
const { id, displayName } = await userStore.getUser("me");
return {
title: displayName,
user_id: {
current: id,
},
_type: "editor",
};
},
}),
];
@@ -1,38 +0,0 @@
import S from "@sanity/base/structure-builder";
const docTypes = [
{
name: "aksel_artikkel",
title: "Aksel Artikkel",
},
{
name: "newEditor",
title: "Bruker/redaktør",
desc: "Lager en psuedo-bruker for deg som kan koble artikler til brukeren",
},
{
name: "aksel_blogg",
title: "Bloggpost",
},
{
name: "ds_artikkel",
title: "Designsystem Artikkel",
desc: "Atikkel som legges under designsystemet",
},
{
name: "komponent_artikkel_template",
title: "Designsystem Komponentside",
desc: "Atikkel som legges under designsystemet",
},
];
export default [
...docTypes.map((doct) =>
S.initialValueTemplateItem(doct.name)
.id(`doc-${doct.name}`)
.title(doct.title)
.templateId(doct.name)
.description(doct?.desc ?? "")
),
/* ...S.defaultInitialValueTemplateItems() */
];
@@ -1,15 +0,0 @@
import defaultResolve, {
PublishAction,
} from "part:@sanity/base/document-actions";
import SetAndPublishAction from "./actions/publishedAt";
/* import SetPrivateAction from "./actions/set-private"; */
import { allDocumentTypes } from "../config";
export default function resolveDocumentActions(props) {
const [publish, ...rest] = defaultResolve(props).map((Action) => {
return allDocumentTypes.includes(props.type) && Action === PublishAction
? SetAndPublishAction
: Action;
});
return [publish /* SetPrivateAction */, ...rest];
}
@@ -1,53 +0,0 @@
import { Button, Card, Inline, Stack, Text } from "@sanity/ui";
import moment from "moment";
import PatchEvent, { set } from "part:@sanity/form-builder/patch-event";
import React from "react";
const CustomDisplay = React.forwardRef((props, ref) => {
const click = () => {
props.onChange &&
props.onChange(
PatchEvent.from(set(new Date().toISOString().split("T")[0]))
);
};
const lastUpdate = moment(props.value);
const daysSince = moment().diff(lastUpdate, "days");
return (
<Stack tabIndex={0} space={4} ref={ref}>
{daysSince > 90 && (
<Card
padding={[3, 3, 4]}
radius={2}
shadow={1}
tone={daysSince > 180 ? "critical" : "caution"}
>
<Text align="center" size={[2, 2, 3]}>
{daysSince > 180
? "Innholdet er utdatert!"
: "Innholdet er stagnert!"}
</Text>
</Card>
)}
<Stack space={4}>
<Text size={1} weight="semibold">
Sist oppdatert
</Text>
<Text size={2}>{props.value?.split("-").reverse().join("/")}</Text>
</Stack>
<Inline space={[3, 3, 4]}>
<Button
onClick={() => click()}
fontSize={[2]}
mode="ghost"
padding={[2, 2]}
text="Oppdater"
/>
</Inline>
</Stack>
);
});
export default CustomDisplay;
@@ -1,30 +0,0 @@
import React, { useState, useEffect, useRef } from "react";
import { withDocument } from "part:@sanity/form-builder";
import {
TextInput,
Stack,
Label,
Checkbox,
Radio,
Flex,
Text,
Box,
Card,
} from "@sanity/ui";
import styled from "styled-components";
/* TODO: Implement this. Issue now is that document returns null in props */
const CustomDisplay = React.forwardRef((props, ref) => {
const [doc, setDoc] = useState(null);
useEffect(() => {
doc && setDoc(props.document);
}, [props]);
return (
<Stack space={0} ref={ref}>
<Card padding={0}>T</Card>
</Stack>
);
});
export default withDocument(CustomDisplay);
@@ -1,49 +0,0 @@
import React from "react";
import Preview from "part:@sanity/base/preview";
import { IntentLink } from "part:@sanity/base/router";
import schema from "part:@sanity/base/schema";
import {
Item as DefaultItem,
List as DefaultList,
} from "part:@sanity/components/lists/default";
import styles from "./profile.css";
const ReferringDocumentsList = (props) => {
const { documents } = props;
return (
<DefaultList className={styles.root}>
{documents
.sort(
(a, b) =>
new Date(b._updatedAt).getTime() - new Date(a._updatedAt).getTime()
)
.map((document) => {
const schemaType = schema.get(document._type);
return (
<DefaultItem key={document._id} className={styles.item}>
{schemaType ? (
<IntentLink
className={styles.link}
intent="edit"
params={{ id: document._id, type: document._type }}
>
<Preview value={document} type={schemaType} />
{document._updatedAt
.split("T")[0]
.split("-")
.reverse()
.join("-")}
</IntentLink>
) : (
<div>
A document of the unknown type <em>{document._type}</em>
</div>
)}
</DefaultItem>
);
})}
</DefaultList>
);
};
export default ReferringDocumentsList;
@@ -1,18 +0,0 @@
export const getUnpublished = (docs: Record<string, any>[]) =>
docs.filter(
(doc, i, arr) =>
doc._id.startsWith("drafts.") &&
!arr.find((x, y) => i !== y && doc._id.includes(x._id))
);
export const getDrafts = (docs: Record<string, any>[]) =>
docs.filter((doc, i, arr) =>
arr.find((x, y) => i !== y && x._id.includes(doc._id))
);
export const getPublished = (docs: Record<string, any>[]) =>
docs
.filter(
(doc, i, arr) => !arr.find((x, y) => i !== y && x._id.includes(doc._id))
)
.filter((doc) => !doc._id.includes("drafts"));
@@ -1,147 +0,0 @@
import { Caseworker, Sandglass, Upload, Wrench } from "@navikt/ds-icons";
import {
BodyShort,
Detail,
Heading,
HelpText,
Label,
Link,
ReadMore,
} from "@navikt/ds-react";
import { SanityDocument } from "@sanity/client";
import { Stack } from "@sanity/ui";
import userStore from "part:@sanity/base/user";
import { WithReferringDocuments } from "part:@sanity/base/with-referring-documents";
import Spinner from "part:@sanity/components/loading/spinner";
import { withDocument } from "part:@sanity/form-builder";
import React, { useEffect, useState } from "react";
import ReferringDocumentsList from "./document-list";
import styles from "../styles.css";
import { getDrafts, getPublished, getUnpublished } from "./filter-docs";
type Props = {
referringDocuments: Record<string, any>[];
isLoading: boolean;
published?: SanityDocument | null;
type: any;
document: any;
};
const IntroPage = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
const { document } = props;
const [user, setUser] = useState<any>({});
useEffect(() => {
userStore.getCurrentUser().then((user) => setUser(user));
}, []);
const EmptyState = () => (
<Detail className={styles.detailsContent} size="small">
Ingen sider her...
</Detail>
);
if (
!document._id ||
(document?.user_id?.current !== user.id &&
!user?.roles?.find((x) => x.name === "administrator"))
)
return null;
return (
<Stack ref={ref} space={[3, 1, 2, 4]}>
<Heading level="2" size="medium" spacing style={{ display: "flex" }}>
Profil <Caseworker style={{ marginLeft: "0.5rem", fontSize: "2rem" }} />
</Heading>
{user?.roles && (
<div>
<Heading level="3" size="small" spacing>
Roller/tilganger:
</Heading>
{user?.roles.map((x, i) => (
<div key={i}>
<Label size="small" spacing as="p">
{x?.title}
</Label>
<BodyShort size="small">{x?.description}</BodyShort>
</div>
))}
</div>
)}
<BodyShort
size="small"
spacing
as="span"
style={{ display: "flex", gap: "0.5rem" }}
>
<ReadMore header="Har du ikke de rollene du trenger?">
Send en melding til oss på{" "}
<Link href="https://nav-it.slack.com/archives/C7NE7A8UF">
#Aksel-designsystemet
</Link>{" "}
slack så fikser vi det.
</ReadMore>
</BodyShort>
<div style={{ borderTop: "1px solid #bbb" }} />
<WithReferringDocuments id={document._id?.replace("drafts.", "")}>
{({ referringDocuments, isLoading }) => {
if (isLoading) {
return <Spinner message="Looking for referring documents…" />;
}
if (!referringDocuments.length) return null;
const drafts = getDrafts(referringDocuments);
const published = getPublished(referringDocuments);
const unpublished = getUnpublished(referringDocuments);
return (
<Stack space={2}>
<Heading level="3" size="xsmall" style={{ display: "flex" }}>
<Upload />
Publiserte sider
</Heading>
<ReadMore header={`Oppdaterte: ${published.length}`}>
{published ? (
<ReferringDocumentsList documents={published} />
) : (
<EmptyState />
)}
</ReadMore>
<ReadMore header={`Med upubliserte endringer: ${drafts.length}`}>
{drafts ? (
<ReferringDocumentsList documents={drafts} />
) : (
<EmptyState />
)}
</ReadMore>
<Heading level="3" size="xsmall" className={styles.headings}>
<Wrench />
Under arbeid
</Heading>
<ReadMore header={`Sider: ${unpublished.length}`}>
{unpublished ? (
<ReferringDocumentsList documents={unpublished} />
) : (
<EmptyState />
)}
</ReadMore>
<Heading level="3" size="xsmall" className={styles.headings}>
<Sandglass />
Utdaterte sider
</Heading>
<ReadMore header={`Ikke oppdatert på over 90 dager: 0`}>
<EmptyState />
</ReadMore>
<ReadMore header={`Ikke oppdatert på over 180 dager: 0`}>
<EmptyState />
</ReadMore>
</Stack>
);
}}
</WithReferringDocuments>
</Stack>
);
});
export default withDocument(IntroPage);
@@ -1,35 +0,0 @@
/* ./cms/styles/ReferringDocumentsList.css */
@import "part:@sanity/base/theme/variables-style";
.root {
composes: root from "part:@sanity/components/lists/default-style";
}
.item {
composes: lineBetween from "part:@sanity/components/lists/default-item-style";
background: var(--white);
border-radius: var(--border-radius-base);
color: inherit;
margin-bottom: var(--small-padding);
border: 1px solid var(--list-border-color);
}
.item:hover {
background-color: var(--a-surface-action-subtle-hover, rgba(230, 240, 255, 1));
}
.link {
padding: var(--small-padding);
color: inherit;
text-decoration: none;
display: flex;
align-items: center;
justify-content: space-between;
}
.link:focus {
border-radius: 2px;
outline: none;
box-shadow: var(--a-shadow-focus, var(--a-shadow-focus, 0 0 0 3px rgba(0, 52, 125, 1)));
}
-21
View File
@@ -1,21 +0,0 @@
@import "part:@sanity/base/theme/variables-style";
.link {
composes: item from "part:@sanity/base/theme/layout/selectable-style";
display: block;
color: inherit;
text-decoration: inherit;
outline: none;
padding: 0.5rem 0;
height: 100%;
}
.headings {
margin-top: 1rem !important;
display: flex;
}
p.detailsContent {
margin-left: 2rem;
margin-bottom: 1.5rem;
}
@@ -1,130 +0,0 @@
import { Heading, Stack, Text } from "@sanity/ui";
import { withDocument } from "part:@sanity/form-builder";
import { getPublishedId } from "part:@sanity/base/util/draft-utils";
import schema from "part:@sanity/base/schema";
import React, { useEffect, useCallback, useState } from "react";
import moment from "moment";
import { IntentLink } from "part:@sanity/base/router";
import { Item, List } from "part:@sanity/components/lists/default";
import SanityPreview from "part:@sanity/base/preview";
import styles from "./styles.css";
const sanityClient = require("@sanity/client");
const SanityConfig = require("../sanity.json");
const client = sanityClient({
projectId: SanityConfig.api.projectId,
dataset: SanityConfig.api.dataset,
apiVersion: "2020-06-19",
useCdn: false,
});
const RelatedArticles = React.forwardRef((props, ref) => {
const [userDocuments, setUserDocuments] = useState([]);
const getUserDocs = useCallback(async () => {
const userDocs = await client
.fetch(`*["${props.document._id}" == contact._ref]`)
.catch((e) => console.error(e.message));
userDocs && setUserDocuments(userDocs);
}, [props.document]);
useEffect(() => {
if (!props.document) {
return;
}
getUserDocs();
}, [getUserDocs]);
const outdated = userDocuments.filter((doc) => {
if (!doc?.metadata?.last_update) return false;
const lastUpdate = moment(doc._updatedAt);
const daysSince = moment().diff(lastUpdate, "days");
return daysSince > 180;
});
const stagnated = userDocuments.filter((doc) => {
if (!doc?.metadata?.last_update) return false;
const lastUpdate = moment(doc._updatedAt);
const daysSince = moment().diff(lastUpdate, "days");
return daysSince > 90 && daysSince <= 180;
});
return (
<Stack space={0} ref={ref} space={[3, 1, 2, 4]}>
<details>
<summary>Utdaterte sider: {outdated.length}</summary>
<List>
{outdated.map((doc) => (
<Item key={doc._id}>
<IntentLink
intent="edit"
params={{
type: doc._type,
id: getPublishedId(doc._id),
}}
className={styles.link}
>
<SanityPreview
layout="default"
type={schema.get(doc._type)}
value={doc}
key={doc._id}
/>
</IntentLink>
</Item>
))}
</List>
</details>
<details>
<summary>Stagnerte sider: {stagnated.length}</summary>
<List>
{stagnated.map((doc) => (
<Item key={doc._id}>
<IntentLink
intent="edit"
params={{
type: doc._type,
id: getPublishedId(doc._id),
}}
className={styles.link}
>
<SanityPreview
layout="default"
type={schema.get(doc._type)}
value={doc}
key={doc._id}
/>
</IntentLink>
</Item>
))}
</List>
</details>
<details>
<summary>Alle sider: {userDocuments.length}</summary>
<List>
{userDocuments.map((doc) => (
<Item key={doc._id}>
<IntentLink
intent="edit"
params={{
type: doc._type,
id: getPublishedId(doc._id),
}}
className={styles.link}
>
<SanityPreview
layout="default"
type={schema.get(doc._type)}
value={doc}
key={doc._id}
/>
</IntentLink>
</Item>
))}
</List>
</details>
</Stack>
);
});
export default withDocument(RelatedArticles);
-41
View File
@@ -1,41 +0,0 @@
const teams = [
{
name: "designsystem",
prefix: "ds",
documents: ["komponent_artikkel", "ds_artikkel"],
navigation: `navigation_designsystem`,
},
{
name: "god_praksis",
prefix: "gp",
documents: ["aksel_artikkel", "aksel_blogg", "aksel_prinsipp"],
},
];
/* Collection of all document-pages to account for */
const allDocumentTypes = teams.reduce(
(docs, team) => [...docs, ...team.documents],
[]
);
/* Collection of all navigation-documents */
const allNavDocumentIds = teams.map((x) => x?.navigation).filter((x) => x);
/**
* Defines when a document of a spesific type is set to stagnant or expired
* @returns [stagnant Date, expired Date]
*/
function getExpireDates() {
const stagnantDate = new Date();
const expiredDate = new Date();
stagnantDate.setDate(stagnantDate.getDate() + 120);
expiredDate.setDate(expiredDate.getDate() + 180);
return [stagnantDate, expiredDate];
}
module.exports = {
teams,
allDocumentTypes,
allNavDocumentIds,
getExpireDates,
};
-10
View File
@@ -1,10 +0,0 @@
{
"#": "Used by Sanity to keep track of configuration file checksums, do not delete or modify!",
"@sanity/default-layout": "bb034f391ba508a6ca8cd971967cbedeb131c4d19b17b28a0895f32db5d568ea",
"@sanity/default-login": "6fb6d3800aa71346e1b84d95bbcaa287879456f2922372bb0294e30b968cd37f",
"@sanity/form-builder": "b38478227ba5e22c91981da4b53436df22e48ff25238a55a973ed620be5068aa",
"@sanity/data-aspects": "d199e2c199b3e26cd28b68dc84d7fc01c9186bf5089580f2e2446994d36b3cb6",
"@sanity/vision": "da5b6ed712703ecd04bf4df560570c668aa95252c6bc1c41d6df1bda9b8b8f60",
"power-table": "922902575995e62af8f628e6abe652ecc5f3b1e1d2dec5859392e79e47707088",
"table": "e56785cc6cecbacf8ebe6bb99ffae32b973e233503c0714497ac7df3042863f1"
}
@@ -1,3 +0,0 @@
{
"listOptions": {}
}
@@ -1,6 +0,0 @@
{
"toolSwitcher": {
"order": [],
"hidden": []
}
}
@@ -1,14 +0,0 @@
{
"providers": {
"mode": "append",
"redirectOnSingle": false,
"entries": [
{
"name": "saml",
"title": "NAV SSO",
"url": "https://api.sanity.io/v2021-10-01/auth/saml/login/f3270b37",
"logo": "/static/navlogo.svg"
}
]
}
}
@@ -1,5 +0,0 @@
{
"images": {
"directUploads": true
}
}
@@ -1,3 +0,0 @@
{
"defaultApiVersion": "2021-10-21"
}
-105
View File
@@ -1,105 +0,0 @@
import { allDocumentTypes } from "../config";
export const editorField = {
title: "Redaktører",
description: "Legg til alle som har bidratt med denne siden!",
name: "contributors",
type: "array",
of: [{ type: "reference", to: [{ type: "editor" }] }],
group: "settings",
validation: (Rule) => Rule.required(),
};
export const privateField = {
title: "Sidetilganger",
name: "tilgang",
type: "object",
description: "Styrer tilgang for side-innhold",
hidden: true,
fields: [
{
title: "Privat",
name: "privat",
type: "boolean",
},
],
initialValue: {
privat: true,
},
};
export const publishedAtField = {
title: "Publiseringsdato",
name: "publishedAt",
type: "datetime",
group: "settings",
description: "Synlig bare for admins. Setter publiseringsdato for dokument",
hidden: ({ currentUser }) =>
!currentUser.roles.find((x) => x.name === "administrator"),
};
export const titleField = {
title: "Sidetittel",
name: "heading",
type: "string",
group: "innhold",
description:
"Bruk en kort og konsis tittel om mulig. Blir satt som `<H1 />` på toppen av siden i URL.",
validation: (Rule) =>
Rule.required()
.max(60)
.error("Siden bør ha en kort og konsis heading (<h1>)"),
};
export const ingressField = {
title: "Ingress",
name: "ingress",
description: "Side, innganger og seo description-tag",
type: "text",
group: "innhold",
rows: 3,
validation: (Rule) =>
Rule.required().max(210).error("Ingress kan ikke være på over 210 tegn"),
};
export const innholdFieldNew = {
title: "Innhold",
name: "content",
type: "riktekst_aksel",
group: "innhold",
};
export const innholdFieldPrinsipp = {
title: "Innhold",
name: "content",
type: "riktekst_prinsipp",
group: "innhold",
};
export const relevanteArtiklerField = {
title: "Relevante artikler",
description:
"Legg til relaterte artikler som du tenker er relevant å lese (maks 3)",
name: "relevante_artikler",
type: "array",
group: "innhold",
validation: (Rule) =>
Rule.max(3).error("Kan ikke ha mer enn 3 relevante artikler lagt til"),
of: [
{
type: "reference",
weak: true,
to: [...allDocumentTypes.map((x) => ({ type: x }))],
},
],
};
export const innholdFieldNewNested = (name?: string, type?: string) => {
const fields = {
...innholdFieldNew,
type: type ?? "riktekst_ds_artikkel",
name: name ?? "content",
};
delete fields.group;
return fields;
};
-154
View File
@@ -1,154 +0,0 @@
export * from "./fields";
export * from "./preview";
export * from "./seo";
import { Settings } from "@navikt/ds-icons";
import sanityClient from "part:@sanity/base/client";
const client = sanityClient.withConfig({ apiVersion: "2020-06-19" });
export const prinsipper = [
{ title: "Brukeropplevelse", value: "brukeropplevelse" },
];
export function toPlainText(blocks = []) {
return blocks
.filter((block) => !(block._type !== "block" || !block.children))
.map((block) => {
return block.children.map((child) => child.text).join("");
})
.join("\n");
}
export const sanitySlug = (prefix: string, depth: number, source?: string) => ({
title: "url",
name: "slug",
type: "slug",
validation: (Rule) => validateSlug(Rule, prefix, depth ?? 3),
group: "settings",
options: {
isUnique: isSlugUnique,
source: source ?? "heading",
slugify: (input) =>
`${prefix}${input}`
.toLowerCase()
.trim()
.slice(0, 80)
.trim()
.replace(/\s+/g, "-")
.replace("--", "-")
.replace("(", "")
.replace(")", "")
.replace("æ", "a")
.replace("ø", "o")
.replace("å", "a")
.replace(".", "-"),
},
});
/* Checks that slug starts with prefix and is nested to x depth */
export const validateSlug = (Rule, prefix, nesting) =>
Rule.required().custom((slug) => {
if (!slug.current.startsWith(prefix)) {
return `Slug må starte med prefiks: ${prefix}`;
}
if ((slug.current.match(/\//g) || []).length > nesting - 1) {
return `Siden kan bare være på ${nesting} nivå`;
}
return true;
});
/* Checks every document for matching slug */
export const isSlugUnique = (slug, options) => {
const { document } = options;
const id = document._id.replace(/^drafts\./, "");
const params = {
draft: `drafts.${id}`,
published: id,
slug,
};
const query = `!defined(*[!(_id in [$draft, $published]) && slug.current == $slug][0]._id)`;
return client.fetch(query, params);
};
export const isEditorUnique = (slug, options) => {
const { document } = options;
const id = document._id.replace(/^drafts\./, "");
const params = {
draft: `drafts.${id}`,
published: id,
slug,
};
const query = `!defined(*[!(_id in [$draft, $published]) && _type == "editor" && user_id.current == $slug][0]._id)`;
return client.fetch(query, params);
};
export const groups = [
{
name: "innhold",
title: "Innhold",
default: true,
},
{
name: "metadata",
title: "Metadata",
},
{
name: "settings",
title: "Innstillinger",
icon: Settings,
},
{
name: "lenker",
title: "Linking",
},
{
name: "beta",
title: "Beta",
},
{
name: "seo",
title: "SEO",
},
];
export const validateKategoriSlug = (Rule, prefix) =>
Rule.required().custom((slug, { document }) => {
if (!slug.current.startsWith(`${prefix}${document?.kategori}/`)) {
return `Slug må starte med prefiks: ${prefix}${document?.kategori}`;
}
if ((slug.current.match(/\//g) || []).length > 3 - 1) {
return `Siden kan bare være på ${3} nivå`;
}
return true;
});
export const kategoriSlug = (prefix: string) => ({
title: "url (v2)",
name: "slug_v2",
type: "slug",
validation: (Rule) => validateKategoriSlug(Rule, prefix),
group: "settings",
options: {
source: (s) => `${s?.kategori}/${s?.heading}`,
slugify: (input) => {
return (
`${prefix}${input}`
.toLowerCase()
.trim()
.slice(0, 200)
.trim()
.replace(/\s+/g, "-")
.replace(/-+/gm, "-")
.replace(/æ/g, "a")
.replace(/å/g, "a")
.replace(/ø/g, "o")
// eslint-disable-next-line no-useless-escape
.replace(/[&\\#!,+()$~%.'"¨:*?<>{}]/g, "")
);
},
},
});
-38
View File
@@ -1,38 +0,0 @@
import { Edit, Task } from "@navikt/ds-icons";
import React from "react";
export const defaultDocPreview = {
preview: {
select: {
heading: "heading",
status: "status",
metadata: "metadata",
id: "_id",
type: "_type",
tema: "tema.0.title",
prinsipp: "prinsipp",
},
prepare(selection) {
const { id, heading, type, tema, prinsipp } = selection;
return {
title: heading,
subtitle: !!prinsipp
? !!prinsipp?.hovedside
? "Hovedside"
: "Artikkel"
: !!tema
? `${tema}`
: type.includes("_component_")
? "Komponentside"
: type.includes("_tabbed_")
? "Artikkel m/tabs"
: "Artikkel",
media: id.includes("drafts.") ? (
<Edit aria-hidden />
) : (
<Task aria-hidden />
),
};
},
},
};
-48
View File
@@ -1,48 +0,0 @@
const pattern = /^image-([a-f\d]+)-(\d+x\d+)-(\w+)$/;
const decodeAssetId = (id) => {
const [, assetId, dimensions, format] = pattern.exec(id);
const [width, height] = dimensions.split("x").map((v) => parseInt(v, 10));
return {
assetId,
dimensions: { width, height },
format,
};
};
export const SEOFields = {
name: "seo",
type: "object",
title: "SEO",
group: "seo",
fields: [
{
name: "meta",
type: "text",
title: "Meta/:og description",
description:
"Anbefalt maks 150-160 bokstaver. Erstatter ingress som <meta /> description",
rows: 3,
},
{
title: "og:Image",
name: "image",
type: "image",
description: "Anbefalt størrelse er 1200:630px",
options: {
accept: "image/*",
},
validation: (Rule) =>
Rule.custom((image) => {
if (!image) return true;
const { dimensions } = decodeAssetId(image.asset._ref);
const aspectR = dimensions.width / dimensions.height;
if (aspectR < 1.5 || aspectR > 2.4) {
return `Forventet aspect-ration rundt 1.91:1. Er nå: ${aspectR}:1.`;
}
return true;
}),
},
],
};
-57
View File
@@ -1,57 +0,0 @@
{
"name": "sanity",
"private": true,
"version": "0.1.0",
"description": "Sanity setup (v2) for Aksel.nav.no",
"author": "Aksel | NAV designsystem team",
"license": "MIT",
"scripts": {
"start": "sanity start",
"build": "sanity build",
"deploy": "yarn typegen && sanity deploy",
"backup": "node scripts/backup.js",
"typegen": "sanity exec typegen.ts",
"sanity:dev": "sanity start",
"sanity:deploy": "yarn typegen && sanity deploy",
"sanity:backup": "node scripts/backup.js"
},
"main": "package.json",
"keywords": [
"sanity"
],
"dependencies": {
"@sanity/base": "^2.35.0",
"@sanity/cli": "^2.35.0",
"@sanity/code-input": "^2.35.0",
"@sanity/components": "^2.14.0",
"@sanity/core": "^2.35.0",
"@sanity/dashboard": "^2.35.0",
"@sanity/default-layout": "^2.35.0",
"@sanity/default-login": "^2.35.0",
"@sanity/desk-tool": "^2.35.0",
"@sanity/export": "^2.30.3",
"@sanity/production-preview": "^2.29.3",
"@sanity/react-hooks": "^2.35.0",
"@sanity/ui": "^0.37.22",
"@sanity/vision": "^2.35.0",
"moment": "2.29.4",
"sanity-codegen": "0.9.8",
"sanity-plugin-asset-source-unsplash": "^0.1.5",
"sanity-plugin-dashboard-widget-document-list": "^0.0.13",
"sanity-plugin-media": "^1.4.4",
"sanity-super-pane": "^1.0.0-alpha.11",
"styled-components": "^5.3.1"
},
"devDependencies": {
"@babel/core": "^7.19.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@babel/preset-typescript": "^7.0.0",
"@sanity-codegen/schema-codegen": "1.0.0-alpha.13",
"babel-plugin-mock-imports": "1.2.0"
},
"repository": {
"type": "git",
"url": "https://github.com/navikt/aksel-website.git"
}
}
-1
View File
@@ -1 +0,0 @@
User-specific packages can be placed here
@@ -1,137 +0,0 @@
/* https://github.com/sanity-io/dashboard-widget-document-list/blob/master/src/DocumentList.js */
import client from "@sanity/client";
import { Button, Flex } from "@sanity/ui";
import { DashboardWidget } from "@sanity/dashboard";
import React, { useEffect, useState, useRef, useCallback } from "react";
import config from "../../config";
import SanityConfig from "../../sanity.json";
import moment from "moment";
import styles from "./widget.css";
import { Item, List } from "part:@sanity/components/lists/default";
import { IntentLink } from "part:@sanity/base/router";
import { getPublishedId } from "part:@sanity/base/util/draft-utils";
import { Tag } from "@navikt/ds-react";
const sanityClient = client({
projectId: SanityConfig.api.projectId,
dataset: SanityConfig.api.dataset,
apiVersion: "2020-06-19",
useCdn: false,
});
const OutDatedComponents = ({ type }) => {
const query = `*[_type in [${config.allDocumentTypes.map((x) => `"${x}"`)}]]`;
const [docs, setDocs] = useState([]);
const [loading, setloading] = useState(true);
const [timer, setTimer] = useState(new Date());
const [fromTime, setFromTime] = useState(moment(new Date()).fromNow());
const success = (v) => {
setDocs(
v
.filter((x) => {
if (!x?._updatedAt) return false;
const lastUpdate = moment(x._updatedAt);
const daysSince = moment().diff(lastUpdate, "days");
return type === "error"
? daysSince > 180
: daysSince >= 90 && daysSince < 180;
})
.sort((a, b) => {
const lastUpdateA = moment(a._updatedAt);
const lastUpdateB = moment(b._updatedAt);
return lastUpdateA.diff(lastUpdateB, "days");
})
);
setloading(false);
setTimer(new Date());
};
const load = useCallback(() => {
setloading(true);
sanityClient.fetch(query).then(success, (e) => console.error(e));
}, []);
useEffect(() => {
load();
}, []);
/* Refreshes every 5 minutes */
useEffect(() => {
const interval = setInterval(() => {
load();
}, 300000);
return () => clearInterval(interval);
}, []);
useEffect(() => {
const interval = setInterval(() => {
setFromTime(moment(timer).fromNow());
}, 10000);
return () => clearInterval(interval);
}, []);
const refresh = () => {
load();
};
const footer = (
<Flex direction="column" align="stretch">
<Button
fontSize={[2]}
tone="primary"
paddingX={2}
paddingY={4}
text={`Updated ${fromTime}`}
onClick={() => refresh()}
mode="bleed"
loading={loading}
disabled={loading}
/>
</Flex>
);
return (
<DashboardWidget
header={type === "error" ? "Utdaterte sider" : "Stagnerte sider"}
footer={footer}
>
<List>
{docs &&
docs.map((doc) => {
const lastUpdate = moment(doc._updatedAt);
const daysSince = moment().diff(lastUpdate, "days");
return (
<Item key={doc._id}>
<IntentLink
intent="edit"
params={{
type: doc._type,
id: getPublishedId(doc._id),
}}
className={styles.link}
>
<span className={styles.spacing}>
<Tag size="small" variant={type}>
{daysSince}d
</Tag>
{doc?.heading}
</span>
</IntentLink>
</Item>
);
})}
</List>
</DashboardWidget>
);
};
export default {
name: "outdated-documents-widget",
component: OutDatedComponents,
};
@@ -1,9 +0,0 @@
{
"parts": [
{
"name": "part:@sanity/dashboard/widget/outdated-documents-widget",
"implements": "part:@sanity/dashboard/widget",
"path": "index.js"
}
]
}
@@ -1,47 +0,0 @@
@import "part:@sanity/base/theme/variables-style";
.container {
composes: container from "part:@sanity/dashboard/widget-styles";
}
.header {
composes: header from "part:@sanity/dashboard/widget-styles";
}
.title {
composes: title from "part:@sanity/dashboard/widget-styles";
}
.content {
composes: content from "part:@sanity/dashboard/widget-styles";
border-top: 1px solid var(--hairline-color);
padding: var(--small-padding) 0;
display: flex;
justify-content: center;
}
.link {
composes: item from "part:@sanity/base/theme/layout/selectable-style";
display: block;
color: inherit;
text-decoration: inherit;
outline: none;
padding: var(--small-padding) var(--medium-padding);
height: 100%;
}
.footer {
composes: footer from "part:@sanity/dashboard/widget-styles";
border-top: 1px solid var(--hairline-color);
}
.img {
display: block;
width: 100%;
}
.spacing {
display: inline-flex;
gap: 1rem;
align-items: center;
}
-69
View File
@@ -1,69 +0,0 @@
{
"root": true,
"project": {
"name": "Aksel"
},
"api": {
"projectId": "hnbe3yhs",
"dataset": "production"
},
"env": {
"development": {
"api": {
"dataset": "production"
},
"plugins": ["@sanity/vision"]
}
},
"plugins": [
"@sanity/base",
"@sanity/components",
"@sanity/default-layout",
"@sanity/default-login",
"@sanity/desk-tool",
"@sanity/code-input",
"@sanity/dashboard",
"dashboard-widget-document-list",
"outdated-documents-widget",
"media",
"asset-source-unsplash"
],
"parts": [
{
"name": "part:@sanity/base/schema",
"path": "./schemas/schema"
},
{
"name": "part:@sanity/desk-tool/structure",
"path": "./client/desk-structure/deskStructure.tsx"
},
{
"implements": "part:@sanity/dashboard/config",
"path": "./client/dashboardConfig.tsx"
},
{
"name": "part:@sanity/base/initial-value-templates",
"path": "./client/initialValueTemplates.tsx"
},
{
"name": "part:@sanity/base/new-document-structure",
"path": "./client/newDocumentStructure.tsx"
},
{
"implements": "part:@sanity/base/absolutes",
"path": "./client/bundleCheck.tsx"
},
{
"implements": "part:@sanity/form-builder/input/image/asset-sources",
"path": "./client/assetSources.ts"
},
{
"implements": "part:@sanity/form-builder/input/file/asset-sources",
"path": "./client/assetSources.ts"
},
{
"implements": "part:@sanity/base/document-actions/resolver",
"path": "./client/resolveDocumentActions.tsx"
}
]
}
-1
View File
@@ -1 +0,0 @@
export default null;
@@ -1,57 +0,0 @@
import {
defaultDocPreview,
editorField,
groups,
ingressField,
innholdFieldNew,
publishedAtField,
relevanteArtiklerField,
sanitySlug,
SEOFields,
titleField,
} from "@/lib";
const prefix = "god-praksis/artikler/";
export default {
title: "Aksel Artikkel",
name: "aksel_artikkel",
type: "document",
groups,
...defaultDocPreview,
fields: [
publishedAtField,
{
title: "Sist godkjent",
name: "updateInfo",
type: "object",
hidden: true,
fields: [
{
type: "date",
name: "lastVerified",
title: "Sist oppdatert",
description: "Kun synlig for utviklere",
readOnly: true,
},
],
},
editorField,
titleField,
sanitySlug(prefix, 3),
{
title: "Tema",
description: "Legg til de viktigeste temaene",
name: "tema",
type: "array",
of: [{ type: "reference", to: [{ type: "aksel_tema" }] }],
group: "innhold",
},
ingressField,
innholdFieldNew,
relevanteArtiklerField,
SEOFields,
],
};
@@ -1,31 +0,0 @@
import {
defaultDocPreview,
editorField,
groups,
ingressField,
innholdFieldNew,
publishedAtField,
sanitySlug,
SEOFields,
titleField,
} from "@/lib";
const prefix = "produktbloggen/";
export default {
title: "Blogg",
name: "aksel_blogg",
type: "document",
groups,
...defaultDocPreview,
fields: [
publishedAtField,
editorField,
titleField,
sanitySlug(prefix, 2),
ingressField,
innholdFieldNew,
SEOFields,
],
};
@@ -1,7 +0,0 @@
import KomponentArtikkel from "./komponent";
export default {
...KomponentArtikkel,
title: "Komponentartikkel-template",
name: "ds_component_template",
};
@@ -1,65 +0,0 @@
import {
defaultDocPreview,
editorField,
groups,
innholdFieldNew,
kategoriSlug,
publishedAtField,
titleField,
} from "@/lib";
const prefix = "grunnleggende/";
export default {
title: "Artikkel",
name: "ds_artikkel",
type: "document",
groups,
...defaultDocPreview,
fields: [
{
title: "Sist godkjent",
name: "updateInfo",
type: "object",
hidden: true,
fields: [
{
type: "date",
name: "lastVerified",
title: "Sist oppdatert",
description: "Kun synlig for utviklere",
readOnly: true,
},
],
},
publishedAtField,
editorField,
titleField,
kategoriSlug(prefix),
{ title: "url", name: "slug", type: "slug", hidden: true },
{
title: "Kategori",
name: "kategori",
type: "string",
validation: (Rule) => Rule.required(),
options: {
list: [
{ title: "Styling", value: "styling" },
{ title: "Tokens", value: "tokens" },
{ title: "Stæsj", value: "staesj" },
{ title: "Guider", value: "guider" },
].map((x) => ({
title: x.title,
value: x.value,
})),
layout: "radio",
},
hidden: ({ currentUser }) =>
!currentUser.roles.find((x) => x.name === "developer"),
},
{
...innholdFieldNew,
type: "riktekst_ds_artikkel",
},
],
};
@@ -1,77 +0,0 @@
export default {
title: "Forside",
name: "ds_frontpage",
type: "document",
fields: [
{
name: "body",
type: "riktekst_enkel",
title: "Innhold",
validation: (Rule) => Rule.required(),
},
{
name: "cards",
type: "array",
title: "Cards",
of: [
{
title: "Card",
name: "card",
type: "object",
fields: [
{
title: "Lenke",
name: "link_ref",
type: "reference",
to: [{ type: "komponent_artikkel" }, { type: "ds_artikkel" }],
validation: (Rule) => Rule.required(),
},
{
title: "Tittel",
name: "title",
type: "string",
},
{
title: "Innhold",
name: "content",
type: "string",
},
{
title: "Pictogram",
name: "picture",
type: "image",
options: {
hotspot: true,
},
fields: [
{
name: "title",
title: "Alt-tekst",
type: "string",
validation: (Rule) =>
Rule.required().error("Bilde må ha en alt-tekst"),
description: "Beskriv bildet for skjermlesere",
options: {
isHighlighted: true,
},
},
],
validation: (Rule) =>
Rule.required().error("Må legge til et pictogram"),
},
],
options: {
modal: {
type: "dialog",
width: "medium", // 'small' | 'medium' | 'large' | 'full'
},
},
},
],
validation: (Rule) => Rule.required(),
},
],
preview: {
prepare: () => ({ title: "Forside designsystemet" }),
},
};
@@ -1,218 +0,0 @@
// MIGRERT
import { People } from "@navikt/ds-icons";
import React from "react";
import profilePage from "../../components/profile/profile-page";
import { isEditorUnique } from "@/lib";
import userStore from "part:@sanity/base/user";
import sanityClient from "part:@sanity/base/client";
const navn = [
"Alpesteinbukk",
"Amurtiger",
"Kamel",
"Blissbukk",
"Borneoorangutang",
"Damfrosk",
"Dvergsilkeape",
"Dåhjort",
"Edderkoppape",
"Elandantilope",
"Elg",
"Esel",
"Oter",
"Fjellrev",
"Flodsvin",
"Fugler",
"Gaupe",
"Gepard",
"Gulkinngibbon",
"Javalangur",
"Jerv",
"Krokodille",
"Labrador",
"Puddel",
"Skogskatt",
"Maine Coon",
"Lavlandstapir",
"Beagle",
"Hysky",
"Løve",
"Løvetamarin",
"Nubisk geit",
"Papegøye",
"Ringhalelemur",
"Rødpanda",
"Sau",
"Sjimpanse",
"Sjiraff",
"Stråleskilpadde",
"Slanger",
"Steppesebra",
"Flamingo",
"Struts",
"Shetlandsponni",
"Surikat",
"Tiger",
"Ulv",
"Fjordfe",
"Ekorn",
"Bever",
"Lemen",
"Klatremus",
"Fjellmarkmus",
"Dvergmus",
"Småskogmus",
"Steinkobbe",
"Røyskatt",
"Moskusfe",
];
const adjektiv = [
"aktuell",
"alvorlig",
"ansvarlig",
"berømt",
"bevisst",
"klein",
"eksisterende",
"fjern",
"forsiktig",
"heldig",
"hjelpsom",
"hyppig",
"imponerende",
"kul",
"sjarmerende",
"lykkelig",
"lys",
"merkelig",
"mistenkelig",
"modig",
"morsom",
"nysgjerrig",
"rå",
"rask",
"blå",
"fersk",
"grønn",
"rettferdig",
"rimelig",
"ryddig",
"selvsikker",
"skarp",
"skikkelig",
"skyldig",
"smal",
"sprudlende",
"søt",
"stolt",
"streng",
"sulten",
"tilgjengelig",
"vennlig",
"voksen",
"ærlig",
"flittig",
];
const client = sanityClient.withConfig({ apiVersion: "2020-06-19" });
const generateName = async () => {
const names = await client.fetch(`*[_type == "editor"].anon_navn.current`);
let c = 0;
let res = "";
while ((res === "" || names.includes(res)) && c < 1000) {
const adj = adjektiv[Math.floor(Math.random() * adjektiv.length)];
const animal = navn[Math.floor(Math.random() * navn.length)];
res = `${adj.charAt(0).toUpperCase() + adj.slice(1)} ${animal}`;
c += 1;
}
return res;
};
const generateInitialName = async () => ({
current: await generateName(),
});
export default {
title: "Redaktører",
name: "editor",
type: "document",
fields: [
{
title: "Navn",
name: "title",
type: "string",
validation: (Rule) => Rule.required().error("Må legge til navn"),
},
{
title: "Sanity bruker-id",
name: "user_id",
type: "slug",
validation: (Rule) => Rule.required().error("Må ha Id"),
options: {
isUnique: isEditorUnique,
source: async () => {
const { id } = await userStore.getUser("me");
return id;
},
slugify: (input) => input,
},
},
{
title: "Gjør meg anonym",
description:
"På artikler bytter vi ut navnet ditt med et tullenavn. Eks. Sprudlende Tiger",
name: "anonym",
type: "boolean",
initialValue: true,
hidden: true,
},
{
hidden: true,
title: "Anonymt navn",
name: "anon_navn",
type: "slug",
initialValue: () => generateInitialName(),
readOnly: true,
},
{
title: "Roller",
description: "eks: Utvikler, Webanalytiker, uu-spesialist",
name: "roller",
type: "array",
of: [{ type: "string" }],
options: {
layout: "tags",
},
},
{
name: "profile_page",
type: "string",
title: "Profil",
inputComponent: profilePage,
hidden: ({ currentUser, parent }) => {
const { id, roles } = currentUser;
return (
!roles.find(({ name }) => name === "administrator") &&
parent?.user_id?.current !== id
);
},
},
],
preview: {
select: {
title: "title",
},
prepare(selection) {
const { title } = selection;
return {
title,
media: () => <People />,
};
},
},
};
@@ -1,58 +0,0 @@
import { groups, SEOFields } from "@/lib";
export default {
title: "Forside",
name: "vk_frontpage",
type: "document",
groups,
fields: [
{
title: "Tittel",
name: "title",
type: "string",
validation: (Rule) => Rule.required(),
},
{
title: "Beskrivelse",
name: "beskrivelse",
type: "riktekst_enkel",
validation: (Rule) => Rule.required(),
},
{
title: "Brukeropplevelse",
name: "prinsipp_1",
type: "object",
fields: [
{
title: "Vis på forside",
name: "vis",
type: "boolean",
validation: (Rule) => Rule.required(),
},
{
title: "Beskrivelse",
name: "beskrivelse",
type: "riktekst_enkel",
validation: (Rule) => Rule.required(),
},
{
title: "Hovedside",
name: "hovedside",
type: "reference",
weak: true,
to: [{ type: "aksel_prinsipp" }],
},
{
title: "Undersider",
description: "Rekkefølge bestemmer rekkefølgen på forsiden!",
name: "undersider",
type: "array",
of: [
{ type: "reference", weak: true, to: [{ type: "aksel_prinsipp" }] },
],
},
],
},
SEOFields,
],
};
@@ -1,57 +0,0 @@
/* import { ExampleKeys } from "website/component-examples"; */
export default {
title: "Dir/filnavn for kode eksempler",
name: "kode_eksempler_fil",
type: "document",
fields: [
{
title: "Tittel",
name: "title",
type: "string",
validation: (Rule) => Rule.required(),
readOnly: true,
},
{
title: "Toggle om eksemplet er et dir eller filnavn",
name: "dir",
type: "boolean",
validation: (Rule) => Rule.required(),
initialValue: false,
readOnly: true,
},
{
title: "Filer",
name: "filer",
type: "array",
readOnly: true,
of: [
{
title: "Data i filer",
name: "fil",
type: "object",
fields: [
{ title: "Filnavn", name: "navn", type: "string" },
{ title: "Innhold", name: "innhold", type: "string" },
{ title: "Beskrivelse", name: "description", type: "text" },
],
},
],
},
],
preview: {
select: {
title: "title",
dir: "dir",
},
prepare(selection) {
const { title, dir } = selection;
return {
title: title,
subtitle: dir ? "Alle kode-eksempler" : "Spesifikt kode-eksempel",
media: () => "</>",
};
},
},
__experimental_omnisearch_visibility: false,
};
@@ -1,126 +0,0 @@
import {
defaultDocPreview,
editorField,
groups,
innholdFieldNew,
kategoriSlug,
publishedAtField,
titleField,
} from "@/lib";
const prefix = "komponenter/";
export default {
title: "Komponentartikkel",
name: "komponent_artikkel",
type: "document",
groups,
...defaultDocPreview,
fields: [
publishedAtField,
editorField,
titleField,
kategoriSlug(prefix),
{ title: "url", name: "slug", type: "slug", hidden: true },
{
title: "Sist godkjent",
name: "updateInfo",
type: "object",
hidden: true,
fields: [
{
type: "date",
name: "lastVerified",
title: "Sist oppdatert",
description: "Kun synlig for utviklere",
readOnly: true,
},
],
},
{
title: "Kategori",
name: "kategori",
type: "string",
validation: (Rule) => Rule.required(),
options: {
list: [
{ title: "Core", value: "core" },
{ title: "Internal", value: "internal" },
].map((x) => ({
title: x.title,
value: x.value,
})),
layout: "radio",
},
hidden: ({ currentUser }) =>
!currentUser.roles.find((x) => x.name === "developer"),
},
{
title: "Metadata",
name: "status",
group: "innhold",
type: "object",
fields: [
{
title: "Status",
name: "tag",
type: "string",
initialValue: "new",
options: {
list: [
{ title: "Beta", value: "beta" },
{ title: "New", value: "new" },
{ title: "Ready", value: "ready" },
{ title: "Deprecated", value: "deprecated" },
],
layout: "radio",
},
validation: (Rule) => Rule.required(),
},
{
name: "bilde",
title: "Thumbnail",
type: "image",
},
],
options: {
collapsible: true,
collapsed: true,
},
},
{
name: "intro",
type: "intro_komponent",
group: "innhold",
},
{
...innholdFieldNew,
type: "riktekst_komponent",
name: "content",
title: "Innhold",
},
{
title: "Kodepakker",
name: "kodepakker",
type: "array",
of: [{ type: "string" }],
options: {
list: [
{ title: "ds-react", value: "ds-react" },
{ title: "ds-css", value: "ds-css" },
{ title: "ds-react-internal", value: "ds-react-internal" },
{ title: "ds-css-internal", value: "ds-css-internal" },
{ title: "ds-icons", value: "ds-icons" },
{ title: "ds-tokens", value: "ds-tokens" },
{ title: "ds-tailwind", value: "ds-tailwind" },
],
},
},
{
title: "Figma lenke (optional)",
name: "figma_link",
type: "url",
group: "lenker",
},
],
};
@@ -1,129 +0,0 @@
export default {
name: "ds_navigation",
title: "Navigation",
type: "document",
fields: [
{
title: "Designsystem navigajsons-struktur",
name: "title",
type: "string",
readOnly: true,
hidden: true,
initialValue: "Designsystem navigajsons-struktur",
},
{
name: "headings",
title: "Header linker",
type: "array",
of: [
{
type: "ds_navigation_heading",
name: "heading",
title: "Header link",
},
],
validation: (Rule) =>
Rule.required()
.min(1)
.error("Headingmenyen må ha minst en koblet lenke i sidemenyen"),
},
],
};
export const ds_header_heading = {
name: "ds_navigation_heading",
title: "Header link",
type: "object",
fields: [
{
name: "title",
title: "Heading tittel",
type: "string",
validation: (Rule) =>
Rule.required().error("Header lenken må ha en tittel"),
},
{
title: "Side selve headingen linker til",
description:
"Husk å legge denne til i menyen også, hvis ikke blir den bare tilgjengelig via headern",
name: "link_ref",
type: "reference",
to: [{ type: "komponent_artikkel" }, { type: "ds_artikkel" }],
validation: (Rule) =>
Rule.required().error("Header lenken må linke til en startside"),
},
{
title: "Meny for denne headingen",
name: "menu",
type: "array",
validation: (Rule) =>
Rule.required().error("Sidemeny må ha misnt en lenke"),
of: [
{
title: "Menypunkt",
name: "item",
type: "object",
fields: [
{
title: "Menypunkt tittel",
name: "title",
type: "string",
validation: (Rule) =>
Rule.required().error("Sidemeny-lenken må ha en tittel"),
},
{
title: "Link til side",
name: "link",
type: "reference",
to: [{ type: "komponent_artikkel" }, { type: "ds_artikkel" }],
options: {
modal: {
type: "dialog",
width: "medium", // 'small' | 'medium' | 'large' | 'full'
},
},
validation: (Rule) =>
Rule.required().error("Sidemeny-lenken må lenke til en side"),
},
],
},
{
title: "Subheading",
name: "subheading",
type: "object",
fields: [
{
title: "Subheading",
name: "title",
type: "string",
validation: (Rule) =>
Rule.required().error("Subheading må være fylt ut"),
},
],
preview: {
select: {
title: "title",
},
prepare(selection) {
const { title } = selection;
return {
title: title,
subtitle: "Subheading",
};
},
},
},
],
},
],
preview: {
select: {
title: "title",
},
prepare({ title }) {
return {
title: `${title}`,
};
},
},
};
@@ -1,141 +0,0 @@
import {
defaultDocPreview,
editorField,
groups,
ingressField,
innholdFieldPrinsipp,
isSlugUnique,
prinsipper,
publishedAtField,
SEOFields,
titleField,
} from "@/lib";
import sanityClient from "part:@sanity/base/client";
const client = sanityClient.withConfig({ apiVersion: "2020-06-19" });
const prefix = "prinsipper/";
export default {
title: "Aksel Prinsipp",
name: "aksel_prinsipp",
type: "document",
groups,
...defaultDocPreview,
fields: [
publishedAtField,
editorField,
titleField,
{
title: "url",
name: "slug",
type: "slug",
validation: (Rule) =>
Rule.required().custom((slug, { document }) => {
if (!slug || !slug.current)
return `Må ha noe innhold. Har du husket å velget et prinsipp først?`;
const maxLength = document?.prinsipp?.hovedside ? 2 : 3;
const newPrefix = `${prefix}${document?.prinsipp?.prinsippvalg}`;
if (!document?.prinsipp?.prinsippvalg)
return `Siden må ha valgt prinsipp for å sette opp url`;
if (document?.prinsipp?.hovedside && slug.current !== newPrefix) {
return `Siden er en hovedside for prinsippet og må derfor være på url ${newPrefix}`;
}
if (
!document?.prinsipp?.hovedside &&
!slug.current.startsWith(newPrefix)
) {
return `Slug må starte med: ${newPrefix}`;
}
if (
(slug.current.split("/") || []).filter((x) => !!x).length !==
maxLength
) {
return `Siden må være på ${maxLength} nivå`;
}
return true;
}),
group: "settings",
options: {
isUnique: isSlugUnique,
source: ({ prinsipp = null, heading = null }) => ({
prinsipp,
heading,
}),
slugify: ({ prinsipp, heading }) => {
if (!prinsipp || !heading) return "";
const rest = prinsipp.hovedside ? "" : `/${heading}`;
return `${prefix}${prinsipp.prinsippvalg}${rest}`
.toLowerCase()
.trim()
.slice(0, 80)
.trim()
.replace(/\s+/g, "-")
.replace("æ", "a")
.replace("ø", "o")
.replace("å", "a");
},
},
},
{
title: "Prinsipp",
description: "Velg prinsippet siden omhandler",
name: "prinsipp",
group: "innhold",
type: "object",
fields: [
{
title: "Velg prinsipp",
name: "prinsippvalg",
type: "string",
options: {
list: prinsipper,
layout: "radio",
},
validation: (Rule) =>
Rule.required().error("Prinsippsider må ha valgt et prinsipp"),
},
{
title: "Er denne siden hovedsiden til Prinsippet?",
name: "hovedside",
type: "boolean",
initialValue: false,
validation: (Rule) =>
Rule.required().custom(async (_, { document, parent }) => {
const id = document._id.replace(/^drafts\./, "");
const params = {
draft: `drafts.${id}`,
published: id,
hoved: parent?.hovedside,
prinsipp: parent?.prinsippvalg,
};
const query = `*[!(_id in [$draft, $published]) && _type == "aksel_prinsipp" && prinsipp.prinsippvalg == $prinsipp && prinsipp.hovedside == true][0]{heading,_id}`;
const res = await client.fetch(query, params);
if (parent?.hovedside && !!res?._id) {
return `Kan bare ha en hovedside for hvert prinsipp. Hovedsiden er nå: ${
res?.heading ?? "Siden har ikke en heading"
}`;
} else if (!parent?.hovedside && !res?._id) {
return `Hvert prinsipp må ha minst en hovedside. Velg en hovedside før du fortsetter`;
}
return true;
}),
},
],
},
{
title: "Hero bilde",
name: "hero_bilde",
type: "herobilde",
group: "innhold",
hidden: ({ parent }) => !parent.prinsipp.hovedside,
},
ingressField,
innholdFieldPrinsipp,
SEOFields,
],
};
@@ -1,88 +0,0 @@
/* import { ExampleKeys } from "website/component-examples"; */
export default {
title: "Autogenerert Propdata",
name: "ds_props",
type: "document",
fields: [
{
title: "Tittel",
name: "title",
type: "string",
readOnly: true,
},
{
title: "Displayname",
name: "displayname",
type: "string",
readOnly: true,
},
{
title: "Filepath",
name: "filepath",
type: "string",
readOnly: true,
},
{
title: "props",
name: "proplist",
type: "array",
readOnly: true,
of: [
{
title: "Prop",
name: "prop",
type: "object",
fields: [
{
title: "Name",
name: "name",
type: "string",
},
{
title: "DefaultValue",
name: "defaultValue",
type: "string",
},
{
title: "Description",
name: "description",
type: "string",
},
{
title: "Required",
name: "required",
type: "boolean",
},
{
title: "Type",
name: "type",
type: "string",
},
{
title: "isRef",
name: "ref",
type: "boolean",
},
],
},
],
},
],
preview: {
select: {
title: "title",
filepath: "filepath",
id: "_id",
},
prepare(selection) {
const { title, filepath, id } = selection;
const str = id.includes("core") ? "ds-react" : "ds-internal";
return {
title,
subtitle: `${str}: ${filepath}`,
};
},
},
__experimental_omnisearch_visibility: false,
};
@@ -1,49 +0,0 @@
const limits = [
"/blogg/",
"/artikkel/",
"/prinsipper/",
"/designsystem/side/",
"/designsystem/komponenter/",
];
export default {
name: "redirect",
title: "Redirect",
type: "document",
fields: [
{
name: "source",
title: "Fra",
type: "string",
validation: (Rule) =>
Rule.required().custom((_, { parent }) => {
if (!parent?.source?.startsWith?.("/")) {
return "Kan bare redirecte fra relativ-url, eks /min/gamle/sideurl";
}
const valid = limits.find(
(x) => parent?.source?.startsWith?.(x) && parent.source > x
);
if (!valid) {
return `Kan bare redirecte fra sider som starter med en av disse url-ene ${limits.join(
", "
)}`;
}
return true;
}),
},
{
name: "destination",
title: "Til",
type: "string",
validation: (Rule) => Rule.required(),
},
{
name: "permanent",
title: "Permanent",
type: "boolean",
initialValue: () => true,
},
],
__experimental_omnisearch_visibility: false,
};
@@ -1,24 +0,0 @@
import {
defaultDocPreview,
groups,
innholdFieldNew,
publishedAtField,
sanitySlug,
titleField,
} from "@/lib";
const prefix = "side/";
export default {
title: "Standalone-sider",
name: "aksel_standalone",
type: "document",
groups,
...defaultDocPreview,
fields: [
publishedAtField,
titleField,
sanitySlug(prefix, 2),
innholdFieldNew,
],
};
@@ -1,148 +0,0 @@
import { groups } from "@/lib";
export default {
title: "Aksel Tema",
name: "aksel_tema",
type: "document",
groups,
fields: [
{
title: "Navn",
name: "title",
type: "string",
group: "innhold",
validation: (Rule) =>
Rule.required()
.warning("Denne endringe påvirker URL")
.error("Temaet må ha et navn"),
},
{
title: "Kort Intro/Oppsummering",
description: "Brukes i kort og innganger",
name: "oppsummering",
type: "string",
group: "innhold",
validation: (Rule) =>
Rule.required()
.max(65)
.error("Temaet burde ha en kort oppsummering/intro på max 65tegn"),
},
{
title: "Beskrivelse",
name: "beskrivelse",
type: "riktekst_enkel",
group: "innhold",
},
{
title: "Hidden",
name: "bruk_seksjoner",
type: "boolean",
hidden: true,
},
{
title: "Shortname",
description: "En mer sanitert visning av tema-navnet i url ene",
name: "slug",
type: "slug",
group: "innhold",
validation: (Rule) => Rule.required().error("Tema må ha en URL"),
options: {
source: "title",
slugify: (s: string) =>
s
? s
.toLowerCase()
.trim()
.replace(/\s+/g, "-")
.replace(/-+/gm, "-")
.replace(/æ/g, "a")
.replace(/å/g, "a")
.replace(/ø/g, "o")
// eslint-disable-next-line no-useless-escape
.replace(/[&\\#!,+()$~%.'"¨:*?<>{}]/g, "")
: "",
},
},
{
title: "Ansvarlig for tema",
description: "Legg til redaktør som har forvaltningsansvaret for temaet",
name: "ansvarlig",
type: "reference",
to: [{ type: "editor" }],
validation: (Rule) => Rule.required(),
group: "innhold",
},
{
title: "Seksjonering",
description:
"Del inn artiklene i flere seksjoner (vises ikke i preview før publisering desverre)",
name: "seksjoner",
type: "array",
group: "innhold",
of: [
{
type: "object",
title: "Seksjon",
name: "seksjon",
fields: [
{
type: "string",
name: "title",
title: "Tittel",
validation: (Rule) =>
Rule.required().error("Seksjonen må ha et navn"),
},
{
title: "Beskrivelse",
name: "beskrivelse",
type: "riktekst_enkel",
},
{
name: "sider",
type: "array",
title: "Sider",
of: [
{
type: "reference",
name: "ref",
title: "Side",
validation: (Rule) =>
Rule.required().error("Seksjonen må ha minst en referanse"),
to: [{ type: "aksel_artikkel" }],
options: {
filter: ({ document, parent }) => {
const selected = parent
.filter((x) => !!x._ref)
.map((x) => x._ref);
return {
filter: "references($refId) && !(_id in $docIds)",
params: {
refId: document._id.replace("drafts.", ""),
docIds: selected,
},
};
},
},
},
],
},
],
},
],
},
{
title: "Pictogram",
name: "pictogram",
type: "image",
fields: [
{
name: "alt",
type: "string",
title: "Attribution",
hidden: true,
},
],
validation: (Rule) => Rule.required().error("Tema må ha pictogram"),
},
],
};
@@ -1,22 +0,0 @@
export default {
title: "Tokens",
name: "token_kategori",
type: "document",
fields: [
{
title: "Navn",
name: "title",
type: "string",
validation: (Rule) => Rule.required(),
readOnly: true,
},
{
title: "Kategori",
name: "kategori",
type: "string",
validation: (Rule) => Rule.required(),
readOnly: true,
},
],
__experimental_omnisearch_visibility: false,
};
@@ -1,75 +0,0 @@
import { Expand } from "@navikt/ds-icons";
import { innholdFieldNewNested } from "@/lib";
import React from "react";
import { BodyLong, Label } from "@navikt/ds-react";
export default {
name: "accordion",
title: "Accordion",
type: "object",
fields: [
{ title: "Tittel (optional)", type: "string", name: "title" },
{
title: "Liste",
description: "Legg til en eller flere elementer",
name: "list",
type: "array",
of: [
{
title: "Accordion",
name: "element",
type: "object",
fields: [
{
title: "Tittel ",
name: "title",
type: "string",
validation: (Rule) =>
Rule.required().error("Accordion må ha en tittel"),
},
innholdFieldNewNested("content", "riktekst_aksel"),
],
preview: {
select: {
title: "title",
},
prepare(selection) {
return {
title: selection.title ?? "",
media: () => <Expand />,
};
},
},
},
],
validation: (Rule) =>
Rule.required().min(1).error("Accordion modul må ha minst 1 element"),
},
],
preview: {
select: {
title: "title",
list: "list",
},
prepare(s) {
return {
title: s?.title ? s.title : "Accordion",
list: s?.list,
};
},
component: ({ value }) => {
return value?.list ? (
<BodyLong as="div">
<Label as="p">{`Accordion (${value.list.length})`}</Label>
<ul>
{value.list.map((x, y) => (
<li key={x._key}>{x.title}</li>
))}
</ul>
</BodyLong>
) : (
<Label as="p">Accordion</Label>
);
},
},
};
@@ -1,68 +0,0 @@
import { toPlainText } from "@/lib";
import { Warning } from "@navikt/ds-icons";
import React from "react";
export default {
name: "alert",
title: "Alert",
type: "object",
icon: Warning,
fields: [
{
title: "Variant",
name: "variant",
type: "string",
validation: (Rule) => Rule.required().error("Alert må ha en variant"),
options: {
list: [
{ value: "success", title: "Suksess" },
{ value: "info", title: "Info" },
{ value: "warning", title: "Fare" },
{ value: "error", title: "Error" },
],
layout: "radio",
},
initialValue: "info",
},
{
title: "Heading (optional)",
name: "heading",
type: "string",
},
{
title: "Heading nivå",
name: "heading_level",
type: "string",
validation: (Rule) =>
Rule.required().error("Alert må ha et heading-nivå"),
options: {
list: [
{ value: "h3", title: "H3" },
{ value: "h4", title: "H4" },
],
layout: "radio",
},
hidden: ({ parent }) => !parent.heading,
initialValue: "h3",
},
{
title: "Innhold",
name: "body",
type: "riktekst_enkel",
validation: (Rule) => Rule.required().error("Alert må ha noe innhold"),
},
],
preview: {
select: {
variant: "variant",
body: "body",
},
prepare(selection) {
return {
title: toPlainText(selection?.body),
subtitle: `Alert - ${selection.variant}`,
media: () => <Warning />,
};
},
},
};
@@ -1,105 +0,0 @@
import { Picture } from "@navikt/ds-icons";
import React from "react";
export default {
title: "Bilde",
name: "bilde",
type: "image",
icon: Picture,
options: {
hotspot: true,
},
fields: [
{
name: "alt",
title: "Alt-tekst",
type: "string",
validation: (Rule) => Rule.required().error("Bilde må ha en alt-tekst"),
description: "Beskriv bildet for skjermlesere",
options: {
isHighlighted: true,
},
},
{
name: "caption",
title: "Bilde-tekst (optional)",
description: "Dette vil stå under bildet",
type: "string",
hidden: ({ parent }) => parent?.floating,
options: {
isHighlighted: true,
},
},
{
name: "small",
title: "Bildet tar bare ~halve bredden",
type: "boolean",
initialValue: false,
hidden: ({ parent }) => parent?.floating || parent?.hide_floating,
options: {
isHighlighted: true,
},
},
{
title: "Kilde",
type: "object",
name: "kilde",
options: {
isHighlighted: true,
collapsible: true,
},
fields: [
{
title: "Legg til kilde",
name: "har_kilde",
type: "boolean",
initialValue: false,
},
{
title: "Kilde-prefix",
name: "prefix",
type: "string",
options: {
list: [
{ title: "FOTO:", value: "FOTO" },
{ title: "Kilde:", value: "Kilde" },
],
layout: "radio",
direction: "horizontal",
},
hidden: ({ parent }) => !parent?.har_kilde,
},
{
title: "Tekst",
name: "tekst",
type: "string",
hidden: ({ parent }) => !parent?.har_kilde,
},
{
title: "Lenke-kilde",
description: "Kilde-teksten blir satt som lenke",
name: "link",
type: "url",
hidden: ({ parent }) => !parent?.har_kilde,
},
],
},
],
validation: (Rule) =>
Rule.custom((v) => {
return v?.asset ? true : "Må legge til et bilde";
}).error(),
preview: {
select: {
alt: "alt",
floating: "floating",
},
prepare(selection) {
return {
title: selection?.alt,
subtitle: `Bilde`,
media: () => <Picture />,
};
},
},
};
@@ -1,89 +0,0 @@
import { Success } from "@navikt/ds-icons";
import React from "react";
export default {
title: "Do / Dont",
name: "do_dont",
type: "object",
icon: Success,
fields: [
{
type: "array",
name: "blokker",
title: "Do / donts",
of: [{ type: "do_dont_block" }],
validation: (Rule) => Rule.required().max(4),
},
],
preview: {
prepare() {
return {
title: "Do / Dont",
media: () => <Success />,
};
},
},
};
export const doDontBlock = {
title: "DoDont",
name: "do_dont_block",
type: "object",
fields: [
{
title: "Fullwidth",
description: "Tar opp ~ 40% eller 100% av tilgjengelig bredde",
name: "fullwidth",
type: "boolean",
validation: (Rule) => Rule.required(),
initialValue: false,
},
{
title: "Bilde",
name: "picture",
type: "image",
validation: (Rule) =>
Rule.required().error("Do/dont må ha et bilde lagt til"),
options: {
hotspot: true,
},
},
{
title: "alt tekst for bilde",
name: "alt",
type: "string",
validation: (Rule) => Rule.required().error("Do/dont må ha en alt-tekst"),
options: {
isHighlighted: true,
},
},
{
name: "description",
title: "Fritekst",
description:
"Korte konsise beskrivelser. Bruk fullbredde bilde i dodont med egen tekst for lengre forklaringer",
type: "text",
},
{
name: "variant",
title: "Variant",
type: "string",
options: {
list: [
{ title: "Do", value: "do" },
{ title: "Dont", value: "dont" },
{ title: "Warning", value: "warning" },
],
layout: "radio",
},
initialValue: "do",
validation: (Rule) => Rule.required(),
},
],
};
/*
*/
@@ -1,36 +0,0 @@
import { Picture } from "@navikt/ds-icons";
import React from "react";
export default {
title: "Hero bilde",
name: "herobilde",
type: "image",
icon: Picture,
options: {
hotspot: true,
},
fields: [
{
name: "alt",
title: "Alt-tekst",
type: "string",
validation: (Rule) => Rule.required().error("Bilde må ha en alt-tekst"),
description: "Beskriv bildet for skjermlesere",
options: {
isHighlighted: true,
},
},
],
preview: {
select: {
alt: "alt",
},
prepare(selection) {
return {
title: selection?.alt,
subtitle: `Bilde`,
media: () => <Picture />,
};
},
},
};
@@ -1,59 +0,0 @@
import Accordion from "./accordion";
import Alert from "./alert";
import Innholdskort from "./innholdskort";
import Bilde from "./bilde";
import DoDont, { doDontBlock } from "./do-dont";
import HeroBilde from "./hero-bilde";
import introKomponent from "./intro-komponent";
import Kode from "./kode";
import KodeEksempler from "./kode-eksempler";
import Props from "./props";
import RelatertInnhold from "./relatert-innhold";
import { tmpTabell, tmpTabellRow } from "./tabellv2";
import {
RiktekstAksel,
RiktekstDsArtikkel,
RiktekstEnkel,
RiktekstKomponent,
RiktekstPrinsipp,
RiktekstTabell,
} from "./riktekst";
import SpesialSeksjon from "./spesial-seksjon";
import Tastatur from "./tastatur";
import Tips from "./tips";
import TokenRef from "./token-tabell";
import Video from "./video";
const v2Blocks = [
tmpTabell,
tmpTabellRow,
/* Blocks */
RiktekstEnkel,
RiktekstAksel,
RiktekstDsArtikkel,
RiktekstKomponent,
RiktekstTabell,
RiktekstPrinsipp,
/* Moduler */
/* Tabellv2, */
DoDont,
doDontBlock,
Bilde,
HeroBilde,
Alert,
Kode,
RelatertInnhold,
Innholdskort,
introKomponent,
Props,
Accordion,
SpesialSeksjon,
Video,
Tips,
Tastatur,
KodeEksempler,
TokenRef,
];
export default v2Blocks;
@@ -1,55 +0,0 @@
// Usikker på om skal være med videre
import { FileContent } from "@navikt/ds-icons";
import React from "react";
export default {
title: "Innholdskort",
name: "innholdskort",
type: "object",
fields: [
{
title: "Tittel",
name: "title",
type: "string",
validation: (Rule) =>
Rule.required().error("Innholdskort må ha en beskrivende tittel"),
},
{
title: "Lenke til prinsipp",
name: "lenke",
type: "reference",
to: [{ type: "aksel_prinsipp" }],
validation: (Rule) =>
Rule.required().error("Innholdskort må ha en lenke"),
},
{
title: "Innhold",
description: "Ikke bruk lenker inne i selve kortet",
name: "body",
type: "riktekst_enkel",
validation: (Rule) =>
Rule.required().error("Innholdskort må ha noe beskrivende innhold"),
},
],
validation: (Rule) =>
Rule.custom((_, { document }) => {
if (!document?.prinsipp?.hovedside) {
return "Innholdskort kan bare brukes på 'hovedsiden' til prinsippet";
}
return true;
}),
preview: {
select: {
title: "title",
},
prepare(selection) {
return {
title: selection?.title,
subtitle: `Innholdskort`,
media: () => <FileContent />,
};
},
},
};
@@ -1,45 +0,0 @@
import { Home } from "@navikt/ds-icons";
import React from "react";
export default {
title: "Intro",
name: "intro_komponent",
type: "object",
fields: [
{
title: "Intro-tekst",
name: "body",
type: "riktekst_enkel",
validation: (Rule) =>
Rule.required().error("Komponentintro må ha en intro"),
},
{
type: "array",
name: "brukes_til",
title: "Egnet til å:",
of: [{ type: "string" }],
validation: (Rule) => Rule.required().min(1),
},
{
type: "array",
name: "brukes_ikke_til",
title: "Vurder noe annet: (optional)",
of: [{ type: "string" }],
},
],
options: {
collapsible: true,
collapsed: true,
},
preview: {
select: {
title: "title",
},
prepare() {
return {
title: "Komponent-intro",
media: () => <Home />,
};
},
},
};
@@ -1,60 +0,0 @@
import { Ruler } from "@navikt/ds-icons";
import React from "react";
export default {
title: "Kode-eksempler",
name: "kode_eksempler",
type: "object",
fields: [
{
title: "tittel",
name: "title",
type: "string",
initialValue: "Kode-eksempler",
readOnly: true,
hidden: true,
},
{
title: "Standalone-eksempel",
description: "Vis bare et spesfikt eksempel",
name: "standalone",
type: "boolean",
initialValue: false,
},
{
title: "Eksempel-navn",
name: "dir",
type: "reference",
to: [{ type: "kode_eksempler_fil" }],
options: {
filter: "dir == true",
},
hidden: ({ parent }) => parent.standalone,
},
{
title: "Installasjon-snippet",
name: "filnavn",
type: "reference",
to: [{ type: "kode_eksempler_fil" }],
options: {
filter: "dir != true",
},
hidden: ({ parent }) => !parent.standalone,
},
],
icon: () => <Ruler />,
preview: {
select: {
standalone: "standalone",
filnavn: "filnavn.title",
dir: "dir.title",
},
prepare({ standalone, filnavn, dir }) {
return {
title: "Komponent-demo",
subtitle: standalone ? filnavn?.replace(".tsx", "") ?? "" : dir ?? "",
media: () => <Ruler />,
};
},
},
};
@@ -1,41 +0,0 @@
// MIGRERT
import React from "react";
export default {
title: "Kode",
name: "kode",
type: "object",
icon: () => <div>{`<>`}</div>,
fields: [
{
name: "code",
title: "Kode",
type: "code",
hidden: ({ parent }) => parent?.variant,
validation: (Rule) => Rule.required(),
options: {
languageAlternatives: [
{ value: "js", title: "Javascript" },
{ value: "jsx", title: "JSX" },
{ value: "html", title: "HTML" },
{ value: "css", title: "CSS" },
{ value: "less", title: "Less" },
{ value: "terminal", title: "Terminal/Bash" },
{ value: "terminal", title: "Standard" },
],
},
},
],
preview: {
select: {
code: "code",
ref: "ref.title",
},
prepare: ({ code, ref }) => ({
title: code ? `${code?.code?.slice(0, 50)}...` : ref ? ref : "Kode",
subtitle: "kode",
media: () => <div>{`</>`}</div>,
}),
},
};
@@ -1,60 +0,0 @@
// MIGRERT
import { List } from "@navikt/ds-icons";
import React from "react";
export default {
title: "Props",
name: "props_seksjon",
type: "object",
icon: List,
fields: [
{
title: "Tittel (h2)",
name: "title",
type: "string",
initialValue: "Props",
readOnly: true,
},
{
title: "Props",
type: "array",
name: "komponenter",
of: [
{
title: "Komponent",
type: "object",
name: "komponent",
fields: [
{
title: "Komponent navn",
description: "Slik man ville brukt den, eks Accordion.Item",
type: "string",
name: "title",
},
{
title: "Bruker komponenten OverridableComponent API-et",
type: "boolean",
name: "overridable",
initialValue: false,
},
{
name: "propref",
title: "Komponent referanse",
type: "reference",
to: [{ type: "ds_props" }],
},
],
},
],
},
],
preview: {
prepare() {
return {
title: "Props",
media: () => <List />,
};
},
},
};
@@ -1,79 +0,0 @@
// MIGRERT
import { allDocumentTypes } from "../../config";
import { Link } from "@navikt/ds-icons";
import React from "react";
export default {
name: "relatert_innhold",
title: "Relatert Innhold",
type: "object",
icon: Link,
fields: [
{
title: "Lenker til innhold",
name: "lenker",
type: "array",
validation: (Rule) =>
Rule.required().max(4).error("Kan ha maks 4 relaterte lenker"),
of: [
{
title: "Lenke",
name: "lenke",
type: "object",
fields: [
{
title: "Tittel",
name: "title",
type: "string",
validation: (Rule) =>
Rule.required()
.max(40)
.error("Tittelen kan være på maks 35 tegn"),
},
{
title: "Intern side i Sanity",
name: "intern",
type: "boolean",
option: {
layout: "checkbox",
},
validation: (Rule) => Rule.required(),
initialValue: false,
},
{
title: "Lenke til Intern sanity-side",
name: "intern_lenke",
type: "reference",
to: [...allDocumentTypes.map((x) => ({ type: x }))],
hidden: ({ parent }) => !parent?.intern,
},
{
title: "Lenke til ekstern side",
name: "ekstern_link",
type: "url",
hidden: ({ parent }) => parent?.intern,
},
{
title: "Linker til et eksternt domene",
description:
"Sett denne hvis lenken går til en side utenfor aksel.nav.no",
name: "ekstern_domene",
type: "boolean",
initialValue: false,
hidden: ({ parent }) => parent?.intern,
},
],
},
],
},
],
preview: {
select: {
links: "links",
},
prepare(s) {
return { title: "Relatert innhold kort", media: () => <Link /> };
},
},
};
@@ -1,269 +0,0 @@
import "@navikt/ds-css?raw";
import "@navikt/ds-css-internal?raw";
import { ExternalLink, FileContent, Link } from "@navikt/ds-icons";
import { BodyLong, Heading } from "@navikt/ds-react/cjs";
import { KBD } from "@sanity/ui";
import React from "react";
import styled from "styled-components";
import { allDocumentTypes } from "../../config";
export const TitleRenderer = (props, size, level) => (
<Heading size={size} level={level}>
{props.children}
</Heading>
);
export const ScCode = styled.code`
color: var(--a-deepblue-500);
background-color: var(--a-deepblue-50);
border-radius: 6px;
font-size: 1rem;
padding: 2px 0.5rem;
`;
export const styles = [
{
title: "Avsnitt",
value: "normal",
blockEditor: {
render: (props) => <BodyLong>{props.children}</BodyLong>,
},
},
];
export const block = {
title: "Block",
type: "block",
styles: [...styles],
lists: [
{ title: "Bullet", value: "bullet" },
{ title: "Numbered", value: "number" },
],
// Marks let you mark up inline text in the block editor.
marks: {
// Decorators usually describe a single property – e.g. a typographic
// preference or highlighting by editors.
decorators: [
{ title: "Strong", value: "strong" },
{ title: "Emphasis", value: "em" },
{
title: "Code",
value: "code",
blockEditor: {
render: (props) => <ScCode>{props.children}</ScCode>,
},
},
{
title: "KBD",
value: "kbd",
blockEditor: {
icon: () => <div>KBD</div>,
render: (props) => (
<KBD padding={[1, 1, 2]} style={{ verticalAlign: "super" }}>
{props.children}
</KBD>
),
},
},
],
// Annotations can be any object structure – e.g. a link or a footnote.
annotations: [
{
title: "Link til side i sanity",
name: "internalLink",
type: "object",
blockEditor: {
icon: () => <Link />,
},
options: {
modal: {
type: "dialog",
width: "medium", // 'small' | 'medium' | 'large' | 'full'
},
},
fields: [
{
title: "Reference",
name: "reference",
type: "reference",
to: [
...allDocumentTypes.map((doc) => ({
type: doc,
})),
],
},
],
},
{
title: "Lenke",
name: "link",
type: "object",
blockEditor: {
icon: () => <ExternalLink />,
},
fields: [
{
title: "URL",
name: "href",
type: "url",
validation: (Rule) =>
Rule.uri({
scheme: ["https", "mailto", "tel"],
}),
},
{
title: "Åpne siden i ny tab",
description:
"Vi anbefaler å ikke åpne lenker i ny fane slik at brukeren selv kan styre det om ønsket.",
name: "blank",
type: "boolean",
initialValue: false,
},
],
},
],
},
};
export const headingStyles = [
...block.styles,
{
title: "H2",
value: "h2",
blockEditor: {
render: (props) => (
<Heading as="span" size="medium">
{props.children}
</Heading>
),
},
},
{
title: "H3",
value: "h3",
blockEditor: {
render: (props) => (
<Heading as="span" size="small">
{props.children}
</Heading>
),
},
},
{
title: "H4",
value: "h4",
blockEditor: {
render: (props) => (
<Heading as="span" size="xsmall">
{props.children}
</Heading>
),
},
},
];
const Riktekst = (type: "aksel" | "ds" | "komponent" | "prinsipp") => {
const fields: string[] = [];
const standard = [
"relatert_innhold",
"bilde",
"kode",
"tips",
"do_dont",
"accordion",
"alert",
"tabell_v2",
"video",
];
const comp = [
"props_seksjon",
"tastatur_modul",
"kode_eksempler",
"token_ref",
];
const ds_artikkel = ["spesial_seksjon"];
fields.push(...standard);
switch (type) {
case "komponent":
fields.push(...comp);
break;
case "ds":
fields.push(...ds_artikkel);
break;
case "prinsipp":
fields.push("innholdskort");
break;
default:
break;
}
const uniq = fields.filter((item, pos, self) => self.indexOf(item) === pos);
return [
{
...block,
styles: [...headingStyles],
},
...uniq.map((x) => ({ type: x })),
];
};
export const RiktekstAksel = {
title: "Riktekst Aksel",
name: "riktekst_aksel",
type: "array",
of: Riktekst("aksel"),
icon: () => <FileContent />,
};
export const RiktekstPrinsipp = {
title: "Riktekst Aksel",
name: "riktekst_prinsipp",
type: "array",
of: Riktekst("prinsipp"),
icon: () => <FileContent />,
};
export const RiktekstDsArtikkel = {
title: "Riktekst Aksel",
name: "riktekst_ds_artikkel",
type: "array",
of: Riktekst("ds"),
icon: () => <FileContent />,
};
export const RiktekstKomponent = {
title: "Riktekst Aksel",
name: "riktekst_komponent",
type: "array",
of: Riktekst("komponent"),
icon: () => <FileContent />,
};
export const RiktekstTabell = {
title: "Riktekst",
name: "riktekst_tabell",
type: "array",
of: [
{
...block,
marks: {
...block.marks,
annotations: block.marks.annotations.filter(
(x) => x.name !== "internalLink"
),
},
},
],
};
export const RiktekstEnkel = {
title: "Riktekst",
name: "riktekst_enkel",
type: "array",
of: [block],
};
Loaded 100 of 195 files, more files were not shown because too many files have changed in this diff. Show more