diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 0000000000..e5b6d8d6a6 --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/angry-planes-thank.md b/.changeset/angry-planes-thank.md new file mode 100644 index 0000000000..9cfb7cb3be --- /dev/null +++ b/.changeset/angry-planes-thank.md @@ -0,0 +1,11 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Pagination: +- Remove attributes `currentPage` and `totalPages` on `Pagination` +- Replace `Pagination.Root` with `Paginaton` +- Replace `Pagination.Next`, `Pagination.Previous` and `Pagination.Ellipsis` with `Paginaton.Button` +- Make `usePagination` return spreadable props for subcomponents +- Add support for `showPages` and `onChange` in `usePagination` diff --git a/.changeset/beige-grapes-report.md b/.changeset/beige-grapes-report.md new file mode 100644 index 0000000000..6bf3d4485c --- /dev/null +++ b/.changeset/beige-grapes-report.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Pagination: Use data attrs instead of class names diff --git a/.changeset/blue-rocks-pull.md b/.changeset/blue-rocks-pull.md new file mode 100644 index 0000000000..2e52daaf56 --- /dev/null +++ b/.changeset/blue-rocks-pull.md @@ -0,0 +1,8 @@ +--- +'@digdir/designsystemet-react': patch +'@digdir/designsystemet-theme': patch +'@digdir/designsystemet': patch +'@digdir/designsystemet-css': patch +--- + +Testing snapshot release diff --git a/.changeset/blue-singers-switch.md b/.changeset/blue-singers-switch.md new file mode 100644 index 0000000000..beebbbad3f --- /dev/null +++ b/.changeset/blue-singers-switch.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Chip: Support wrapping in group diff --git a/.changeset/blue-stingrays-heal.md b/.changeset/blue-stingrays-heal.md new file mode 100644 index 0000000000..46e18614cc --- /dev/null +++ b/.changeset/blue-stingrays-heal.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Accordion: Fix chevron abandoning parent in scroll container diff --git a/.changeset/brave-months-shop.md b/.changeset/brave-months-shop.md new file mode 100644 index 0000000000..361671c21c --- /dev/null +++ b/.changeset/brave-months-shop.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet-react': patch +--- + +Correctly mark dependencies as external. This ensures Accordion works when consumers have enabled tree-shaking. diff --git a/.changeset/brave-months-sleep.md b/.changeset/brave-months-sleep.md new file mode 100644 index 0000000000..0616be9a4f --- /dev/null +++ b/.changeset/brave-months-sleep.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Modal: add missing ModalRoot export diff --git a/.changeset/bright-knives-remain.md b/.changeset/bright-knives-remain.md new file mode 100644 index 0000000000..cbdd5a29bc --- /dev/null +++ b/.changeset/bright-knives-remain.md @@ -0,0 +1,8 @@ +--- +"@digdir/designsystemet-react": patch +--- + +RovingFocus: add `orientation` to support for different arrow directions, and add support home/end buttons +- Affects `ToggleGroup`, where up and down arrows can now be used +- Affects `ToggleGroup`, where home and end can now be used +- Affects `Tabs`, where home and end can now be used diff --git a/.changeset/brown-walls-smell.md b/.changeset/brown-walls-smell.md new file mode 100644 index 0000000000..b316665535 --- /dev/null +++ b/.changeset/brown-walls-smell.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-theme": patch +--- + +tokens: Removed validationmessage and label typography styles diff --git a/.changeset/chatty-cheetahs-fetch.md b/.changeset/chatty-cheetahs-fetch.md new file mode 100644 index 0000000000..fe88f41b2d --- /dev/null +++ b/.changeset/chatty-cheetahs-fetch.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": minor +--- + +SkipLink: New style diff --git a/.changeset/chilled-icons-chew.md b/.changeset/chilled-icons-chew.md new file mode 100644 index 0000000000..b87eb3cd88 --- /dev/null +++ b/.changeset/chilled-icons-chew.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Accordion: Fix `defaultOpen` flicker on first render diff --git a/.changeset/chilled-pumas-march.md b/.changeset/chilled-pumas-march.md new file mode 100644 index 0000000000..0fd1539fe0 --- /dev/null +++ b/.changeset/chilled-pumas-march.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Badge: Style using css attributes diff --git a/.changeset/clean-insects-move.md b/.changeset/clean-insects-move.md new file mode 100644 index 0000000000..e2fe625e26 --- /dev/null +++ b/.changeset/clean-insects-move.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +SkipLink: Add css variables diff --git a/.changeset/clean-lizards-chew.md b/.changeset/clean-lizards-chew.md new file mode 100644 index 0000000000..b4a8f5e6bc --- /dev/null +++ b/.changeset/clean-lizards-chew.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +ValidationMessage: Add icon when `error={true}` diff --git a/.changeset/clever-cobras-rescue.md b/.changeset/clever-cobras-rescue.md new file mode 100644 index 0000000000..83fa3a1120 --- /dev/null +++ b/.changeset/clever-cobras-rescue.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Textarea: Use `field-sizing: content` diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 0000000000..0b2b6fdece --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@3.0.2/schema.json", + "changelog": [ + "@svitejs/changesets-changelog-github-compact", + { "repo": "digdir/designsystemet" } + ], + "commit": false, + "fixed": [ + [ + "@digdir/designsystemet", + "@digdir/designsystemet-css", + "@digdir/designsystemet-theme", + "@digdir/designsystemet-react" + ] + ], + "linked": [], + "access": "restricted", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [ + "theme", + "storefront", + "@repo/components", + "@designsystemet/storybook", + "figma-plugin" + ] +} diff --git a/.changeset/cool-lamps-drive.md b/.changeset/cool-lamps-drive.md new file mode 100644 index 0000000000..1d24e1d303 --- /dev/null +++ b/.changeset/cool-lamps-drive.md @@ -0,0 +1,6 @@ +--- +'@digdir/designsystemet': patch +'@digdir/designsystemet-react': patch +--- + +chore: Fix rollup build warnings for react package diff --git a/.changeset/curvy-oranges-notice.md b/.changeset/curvy-oranges-notice.md new file mode 100644 index 0000000000..b9a96e9d71 --- /dev/null +++ b/.changeset/curvy-oranges-notice.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Button: Remove `type` when `asChild={true}` diff --git a/.changeset/cyan-adults-roll.md b/.changeset/cyan-adults-roll.md new file mode 100644 index 0000000000..a302adfd3a --- /dev/null +++ b/.changeset/cyan-adults-roll.md @@ -0,0 +1,8 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Skiplink: +- Simplify DOM +- Add support for `forwardRef` diff --git a/.changeset/eight-dancers-deliver.md b/.changeset/eight-dancers-deliver.md new file mode 100644 index 0000000000..3e3af74b5b --- /dev/null +++ b/.changeset/eight-dancers-deliver.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +ValidationMessage: fix icon abandoning the component when scrolling diff --git a/.changeset/eighty-cougars-think.md b/.changeset/eighty-cougars-think.md new file mode 100644 index 0000000000..9257efbd30 --- /dev/null +++ b/.changeset/eighty-cougars-think.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Tabs: Make arrow keys work in any direction diff --git a/.changeset/eleven-bags-shop.md b/.changeset/eleven-bags-shop.md new file mode 100644 index 0000000000..4fc80ab3f0 --- /dev/null +++ b/.changeset/eleven-bags-shop.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +TableHeaderCell: Remove `sortable` prop, `sort` now handles this diff --git a/.changeset/eleven-experts-raise.md b/.changeset/eleven-experts-raise.md new file mode 100644 index 0000000000..e5fd9700da --- /dev/null +++ b/.changeset/eleven-experts-raise.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Textfield: Removed `htmlSize`, you can now use native `size` diff --git a/.changeset/eleven-peaches-agree.md b/.changeset/eleven-peaches-agree.md new file mode 100644 index 0000000000..b7000e7a40 --- /dev/null +++ b/.changeset/eleven-peaches-agree.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +dropdownmenu: Style using data attributes diff --git a/.changeset/empty-pears-hide.md b/.changeset/empty-pears-hide.md new file mode 100644 index 0000000000..1d836460d0 --- /dev/null +++ b/.changeset/empty-pears-hide.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Accordion: Add css variable for chevron diff --git a/.changeset/empty-singers-yell.md b/.changeset/empty-singers-yell.md new file mode 100644 index 0000000000..1ced134c71 --- /dev/null +++ b/.changeset/empty-singers-yell.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Chip: Text color is now `accent` diff --git a/.changeset/fair-beds-destroy.md b/.changeset/fair-beds-destroy.md new file mode 100644 index 0000000000..68c96596f7 --- /dev/null +++ b/.changeset/fair-beds-destroy.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +CSS: base sizing on font-size so all components can have all sizes, and naturally inherits size from context diff --git a/.changeset/famous-pillows-cheat.md b/.changeset/famous-pillows-cheat.md new file mode 100644 index 0000000000..ab02e3de96 --- /dev/null +++ b/.changeset/famous-pillows-cheat.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet': minor +--- + +Fix design-token warning contrast color reference diff --git a/.changeset/few-brooms-confess.md b/.changeset/few-brooms-confess.md new file mode 100644 index 0000000000..068448099e --- /dev/null +++ b/.changeset/few-brooms-confess.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-react": patch +"@digdir/designsystemet-css": patch +--- + +Table: New hover prop and class for toggling hover on rows diff --git a/.changeset/few-plums-drum.md b/.changeset/few-plums-drum.md new file mode 100644 index 0000000000..a94e6f3baa --- /dev/null +++ b/.changeset/few-plums-drum.md @@ -0,0 +1,7 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Accordion: Animate open/close with CSS +- Replace onFound with onToggle diff --git a/.changeset/few-squids-speak.md b/.changeset/few-squids-speak.md new file mode 100644 index 0000000000..ef1ef07ab5 --- /dev/null +++ b/.changeset/few-squids-speak.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": major +"@digdir/designsystemet-react": major +--- + +Search: New compound API diff --git a/.changeset/fifty-buses-beam.md b/.changeset/fifty-buses-beam.md new file mode 100644 index 0000000000..6c7b4605c0 --- /dev/null +++ b/.changeset/fifty-buses-beam.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Table: Width is now by default `100%` + diff --git a/.changeset/fifty-hornets-hang.md b/.changeset/fifty-hornets-hang.md new file mode 100644 index 0000000000..368ba7a03b --- /dev/null +++ b/.changeset/fifty-hornets-hang.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +CSS: Move default background-color to `` element diff --git a/.changeset/five-apricots-scream.md b/.changeset/five-apricots-scream.md new file mode 100644 index 0000000000..cea113977a --- /dev/null +++ b/.changeset/five-apricots-scream.md @@ -0,0 +1,6 @@ +--- +'@digdir/designsystemet-theme': patch +'@digdir/designsystemet': patch +--- + +refactor: single CSS file for theme diff --git a/.changeset/five-pens-accept.md b/.changeset/five-pens-accept.md new file mode 100644 index 0000000000..b790276873 --- /dev/null +++ b/.changeset/five-pens-accept.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Popover+Dropdown: Fix issue when combining controlled state with changing child elements diff --git a/.changeset/five-turkeys-confess.md b/.changeset/five-turkeys-confess.md new file mode 100644 index 0000000000..ed65071e7e --- /dev/null +++ b/.changeset/five-turkeys-confess.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": major +--- + +Dropdown: Add `Dropdown.Button` for more explicit API diff --git a/.changeset/flat-experts-drop.md b/.changeset/flat-experts-drop.md new file mode 100644 index 0000000000..161fbb25a4 --- /dev/null +++ b/.changeset/flat-experts-drop.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +ErrorSummary: Rename ErrorSummary.Root to ErrorSummary diff --git a/.changeset/four-pears-tie.md b/.changeset/four-pears-tie.md new file mode 100644 index 0000000000..df33346b86 --- /dev/null +++ b/.changeset/four-pears-tie.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Fixes so spacing is the same in checkbox and radio groups diff --git a/.changeset/four-schools-wait.md b/.changeset/four-schools-wait.md new file mode 100644 index 0000000000..59ba30b2e6 --- /dev/null +++ b/.changeset/four-schools-wait.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Breadcrumbs: Add css variable for chevron diff --git a/.changeset/friendly-cups-kiss.md b/.changeset/friendly-cups-kiss.md new file mode 100644 index 0000000000..bccf9dbbbc --- /dev/null +++ b/.changeset/friendly-cups-kiss.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Input: Sufficient color contrast for readonly diff --git a/.changeset/friendly-islands-punch.md b/.changeset/friendly-islands-punch.md new file mode 100644 index 0000000000..bf1d8ba0ca --- /dev/null +++ b/.changeset/friendly-islands-punch.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +fix(Combobox): :bug: Button for toggling open/close should now close when open diff --git a/.changeset/gold-chairs-jog.md b/.changeset/gold-chairs-jog.md new file mode 100644 index 0000000000..9351938447 --- /dev/null +++ b/.changeset/gold-chairs-jog.md @@ -0,0 +1,8 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Tabs: +- Renames `Tabs.Root` to `Tabs` +- Renames `Tabs.Content` to `Tabs.Panel` diff --git a/.changeset/gorgeous-readers-burn.md b/.changeset/gorgeous-readers-burn.md new file mode 100644 index 0000000000..ce075c8ec6 --- /dev/null +++ b/.changeset/gorgeous-readers-burn.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet': minor +--- + +Update init script to new design-tokens format diff --git a/.changeset/gorgeous-shrimps-crash.md b/.changeset/gorgeous-shrimps-crash.md new file mode 100644 index 0000000000..7f5556ba96 --- /dev/null +++ b/.changeset/gorgeous-shrimps-crash.md @@ -0,0 +1,8 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Heading: +- Classes with data attributes +- Move base style to utility classes diff --git a/.changeset/happy-hounds-tie.md b/.changeset/happy-hounds-tie.md new file mode 100644 index 0000000000..1e64a38c85 --- /dev/null +++ b/.changeset/happy-hounds-tie.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +List: Remove `List.Root` and `List.Heading`, which changes API diff --git a/.changeset/happy-worms-applaud.md b/.changeset/happy-worms-applaud.md new file mode 100644 index 0000000000..9e2085886d --- /dev/null +++ b/.changeset/happy-worms-applaud.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Rename classes from `ds-error-message*` to `ds-validation-message*` diff --git a/.changeset/healthy-apples-explode.md b/.changeset/healthy-apples-explode.md new file mode 100644 index 0000000000..4a22ccd0c4 --- /dev/null +++ b/.changeset/healthy-apples-explode.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Alert, Avatar, Button, Divider, Link: Use data-attributes for variant, size and color and move icons to CSS diff --git a/.changeset/heavy-rabbits-boil.md b/.changeset/heavy-rabbits-boil.md new file mode 100644 index 0000000000..1216ccb154 --- /dev/null +++ b/.changeset/heavy-rabbits-boil.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Modal: css changes diff --git a/.changeset/hip-brooms-brush.md b/.changeset/hip-brooms-brush.md new file mode 100644 index 0000000000..477aef6711 --- /dev/null +++ b/.changeset/hip-brooms-brush.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Alert: fix icon abandoning the component when scrolling diff --git a/.changeset/hip-masks-greet.md b/.changeset/hip-masks-greet.md new file mode 100644 index 0000000000..5867ff0485 --- /dev/null +++ b/.changeset/hip-masks-greet.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Button: `text-align: inherit` when not in full width diff --git a/.changeset/hip-schools-greet.md b/.changeset/hip-schools-greet.md new file mode 100644 index 0000000000..80b1ead410 --- /dev/null +++ b/.changeset/hip-schools-greet.md @@ -0,0 +1,14 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Modal: +- Rename `Modal.Dialog` to `Modal` +- Rename `Modal.Root` to `Modal.Context` +- Replace `onInteractOutside` event with `backdropClose` boolean +- Replace `closeButton` and `closeButtonTitle` on `Modal.Header` with `closeButton` on `Modal` +- Add border to `Modal.Header` and `Modal.Footer` +- Remove `Modal.Content` +- Remove `onBeforeClose` +- Remove `subtitle` from `Modal.Header` diff --git a/.changeset/honest-roses-hunt.md b/.changeset/honest-roses-hunt.md new file mode 100644 index 0000000000..dba7cf0f53 --- /dev/null +++ b/.changeset/honest-roses-hunt.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Box: Remove component diff --git a/.changeset/hot-crews-perform.md b/.changeset/hot-crews-perform.md new file mode 100644 index 0000000000..e1d74370e5 --- /dev/null +++ b/.changeset/hot-crews-perform.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Popover: Make sure arrow does not leave the popover diff --git a/.changeset/hot-ligers-rush.md b/.changeset/hot-ligers-rush.md new file mode 100644 index 0000000000..fbb1ef68c4 --- /dev/null +++ b/.changeset/hot-ligers-rush.md @@ -0,0 +1,10 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +"@digdir/designsystemet-theme": patch +--- + +Body/Paragraph +- Add body-xl token +- Add xl paragraph +- Remove ingress tokens diff --git a/.changeset/hot-weeks-tease.md b/.changeset/hot-weeks-tease.md new file mode 100644 index 0000000000..e461e0ff76 --- /dev/null +++ b/.changeset/hot-weeks-tease.md @@ -0,0 +1,7 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Ingress: Remove component +- Use `Paragraph variant='long'` instead diff --git a/.changeset/kind-eyes-cheat.md b/.changeset/kind-eyes-cheat.md new file mode 100644 index 0000000000..303d2c6086 --- /dev/null +++ b/.changeset/kind-eyes-cheat.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Modal: Fix `onClose` not being called diff --git a/.changeset/lemon-countries-smoke.md b/.changeset/lemon-countries-smoke.md new file mode 100644 index 0000000000..6a846957e0 --- /dev/null +++ b/.changeset/lemon-countries-smoke.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Heading: Fix `md` heading size diff --git a/.changeset/long-boxes-sniff.md b/.changeset/long-boxes-sniff.md new file mode 100644 index 0000000000..8da333a73f --- /dev/null +++ b/.changeset/long-boxes-sniff.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Combobox: Make controlled input adhere to `inputValue` and send all change events diff --git a/.changeset/loud-bobcats-look.md b/.changeset/loud-bobcats-look.md new file mode 100644 index 0000000000..889d9ab212 --- /dev/null +++ b/.changeset/loud-bobcats-look.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Textfield: Refactored `characterLimit` to `counter` and now use new `Field.Counter` sub-component diff --git a/.changeset/loud-tips-return.md b/.changeset/loud-tips-return.md new file mode 100644 index 0000000000..274a661674 --- /dev/null +++ b/.changeset/loud-tips-return.md @@ -0,0 +1,9 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Popover: +- Rename `` to `` +- use Popover API, allowing `` to be used without `Popover.Context` +- Remove `portal` prop diff --git a/.changeset/mean-ducks-argue.md b/.changeset/mean-ducks-argue.md new file mode 100644 index 0000000000..fa9ae2bd16 --- /dev/null +++ b/.changeset/mean-ducks-argue.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Tooltip: Only expose background css variable diff --git a/.changeset/mean-snails-visit.md b/.changeset/mean-snails-visit.md new file mode 100644 index 0000000000..839e149211 --- /dev/null +++ b/.changeset/mean-snails-visit.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +chip: Fix wrong font sizes diff --git a/.changeset/metal-bananas-notice.md b/.changeset/metal-bananas-notice.md new file mode 100644 index 0000000000..933209fd0b --- /dev/null +++ b/.changeset/metal-bananas-notice.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Switch: don't show check when not checked in readonly diff --git a/.changeset/metal-tomatoes-compete.md b/.changeset/metal-tomatoes-compete.md new file mode 100644 index 0000000000..6139799c1e --- /dev/null +++ b/.changeset/metal-tomatoes-compete.md @@ -0,0 +1,9 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Card: +- Allow `Card` with content placed directly inside +- Replace `Card.Header`, `Card.Content` and `Card.Footer` with `Card.Block` +- Replace `isLink` with anchor-in-heading + `click` handler for better accessibility diff --git a/.changeset/mighty-buttons-yell.md b/.changeset/mighty-buttons-yell.md new file mode 100644 index 0000000000..2e57921df9 --- /dev/null +++ b/.changeset/mighty-buttons-yell.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Button: Fix SVG and images shrinking in flex containers diff --git a/.changeset/mighty-days-eat.md b/.changeset/mighty-days-eat.md new file mode 100644 index 0000000000..728b66eba2 --- /dev/null +++ b/.changeset/mighty-days-eat.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet': patch +--- + +fix: Export correct types for color diff --git a/.changeset/nasty-turtles-happen.md b/.changeset/nasty-turtles-happen.md new file mode 100644 index 0000000000..6b10a1b02a --- /dev/null +++ b/.changeset/nasty-turtles-happen.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": major +--- + +Fieldset: Move to compound components `Fieldset.Legend` and `Fieldset.Description` diff --git a/.changeset/nine-cameras-peel.md b/.changeset/nine-cameras-peel.md new file mode 100644 index 0000000000..189341970a --- /dev/null +++ b/.changeset/nine-cameras-peel.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Modal: Remove `Modal.Header` and `Modal.Footer`, replace with `Modal.Block` diff --git a/.changeset/nine-countries-invent.md b/.changeset/nine-countries-invent.md new file mode 100644 index 0000000000..022c44e479 --- /dev/null +++ b/.changeset/nine-countries-invent.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +useRadioGroup: Add hook to easily control groups of `` components diff --git a/.changeset/ninety-horses-juggle.md b/.changeset/ninety-horses-juggle.md new file mode 100644 index 0000000000..50619ead29 --- /dev/null +++ b/.changeset/ninety-horses-juggle.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +useCheckboxGroup: Add hook to easily control groups of `` components diff --git a/.changeset/odd-hornets-sleep.md b/.changeset/odd-hornets-sleep.md new file mode 100644 index 0000000000..082f9b9408 --- /dev/null +++ b/.changeset/odd-hornets-sleep.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Select: Rename from `NativeSelect` diff --git a/.changeset/old-melons-stare.md b/.changeset/old-melons-stare.md new file mode 100644 index 0000000000..9266526fd9 --- /dev/null +++ b/.changeset/old-melons-stare.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Table: add `z-index` to stickhy header diff --git a/.changeset/old-sheep-dress.md b/.changeset/old-sheep-dress.md new file mode 100644 index 0000000000..f7b1100b09 --- /dev/null +++ b/.changeset/old-sheep-dress.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Modal: Expose native close event object to onClose callback diff --git a/.changeset/olive-tools-cry.md b/.changeset/olive-tools-cry.md new file mode 100644 index 0000000000..4a5375f48a --- /dev/null +++ b/.changeset/olive-tools-cry.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch + +--- + +Tooltip: Add more variables diff --git a/.changeset/olive-waves-build.md b/.changeset/olive-waves-build.md new file mode 100644 index 0000000000..189df40863 --- /dev/null +++ b/.changeset/olive-waves-build.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Textfield: Now works as expected with `data-size` diff --git a/.changeset/orange-months-listen.md b/.changeset/orange-months-listen.md new file mode 100644 index 0000000000..8813fe7a99 --- /dev/null +++ b/.changeset/orange-months-listen.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Button: Use font-weight `--ds-font-weight-medium` diff --git a/.changeset/plenty-parents-rest.md b/.changeset/plenty-parents-rest.md new file mode 100644 index 0000000000..f35296cae3 --- /dev/null +++ b/.changeset/plenty-parents-rest.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Rename `ErrorMessage` to `ValidationMessage` diff --git a/.changeset/plenty-singers-matter.md b/.changeset/plenty-singers-matter.md new file mode 100644 index 0000000000..68211250fe --- /dev/null +++ b/.changeset/plenty-singers-matter.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Field: Adds `` component wrapping and connecting internal form elements for better accessibility diff --git a/.changeset/plenty-vans-sneeze.md b/.changeset/plenty-vans-sneeze.md new file mode 100644 index 0000000000..09bbee853c --- /dev/null +++ b/.changeset/plenty-vans-sneeze.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +AccordionHeading: Correct name on types diff --git a/.changeset/popular-jeans-happen.md b/.changeset/popular-jeans-happen.md new file mode 100644 index 0000000000..c591e323ee --- /dev/null +++ b/.changeset/popular-jeans-happen.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Textfield: Added `multiline` for switching between `input` and `textarea` diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..5f5938e3ea --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,101 @@ +{ + "mode": "pre", + "tag": "next", + "initialVersions": { + "@repo/components": "0.0.0", + "dev": "0.1.0", + "storefront": "0.1.0", + "theme": "0.1.0", + "@digdir/designsystemet": "0.1.0-alpha.19", + "@digdir/designsystemet-css": "0.11.0-alpha.9", + "@digdir/designsystemet-react": "1.0.0-rc.13", + "@digdir/designsystemet-theme": "1.0.0-rc.13", + "figma-plugin": "0.1.0", + "@designsystemet/storybook": "0.1.0" + }, + "changesets": [ + "angry-planes-thank", + "beige-grapes-report", + "blue-rocks-pull", + "blue-singers-switch", + "brave-months-shop", + "brave-months-sleep", + "bright-knives-remain", + "chatty-cheetahs-fetch", + "chilled-icons-chew", + "chilled-pumas-march", + "clever-cobras-rescue", + "cool-lamps-drive", + "curvy-oranges-notice", + "cyan-adults-roll", + "eighty-cougars-think", + "eleven-bags-shop", + "eleven-peaches-agree", + "empty-singers-yell", + "famous-pillows-cheat", + "few-brooms-confess", + "few-plums-drum", + "fifty-buses-beam", + "five-apricots-scream", + "flat-experts-drop", + "four-pears-tie", + "friendly-islands-punch", + "gold-chairs-jog", + "gorgeous-readers-burn", + "gorgeous-shrimps-crash", + "happy-hounds-tie", + "happy-worms-applaud", + "healthy-apples-explode", + "heavy-rabbits-boil", + "hip-masks-greet", + "hip-schools-greet", + "honest-roses-hunt", + "hot-ligers-rush", + "hot-weeks-tease", + "lemon-countries-smoke", + "long-boxes-sniff", + "loud-tips-return", + "mean-ducks-argue", + "metal-bananas-notice", + "metal-tomatoes-compete", + "mighty-days-eat", + "nine-cameras-peel", + "odd-hornets-sleep", + "plenty-parents-rest", + "plenty-vans-sneeze", + "pretty-dancers-taste", + "proud-walls-flash", + "purple-berries-repeat", + "quiet-mangos-cry", + "red-queens-love", + "rich-carrots-deny", + "serious-frogs-rescue", + "seven-ladybugs-admire", + "shaggy-bears-tan", + "shaggy-rockets-repair", + "shiny-kiwis-switch", + "short-walls-judge", + "six-carrots-guess", + "six-trees-tie", + "slimy-bees-arrive", + "small-queens-breathe", + "spotty-oranges-guess", + "spotty-pumas-cross", + "strong-flowers-ring", + "strong-ghosts-marry", + "stupid-tables-applaud", + "swift-forks-drop", + "tall-guests-arrive", + "tame-rats-mix", + "tender-grapes-refuse", + "tender-ties-swim", + "thin-icons-pay", + "three-carrots-hammer", + "three-dingos-unite", + "three-ducks-chew", + "wise-countries-double", + "witty-clouds-judge", + "witty-moons-sleep", + "yellow-zoos-camp" + ] +} diff --git a/.changeset/pretty-dancers-taste.md b/.changeset/pretty-dancers-taste.md new file mode 100644 index 0000000000..ed2f012c7b --- /dev/null +++ b/.changeset/pretty-dancers-taste.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Table: Set sort button type to prevent form submit diff --git a/.changeset/proud-walls-flash.md b/.changeset/proud-walls-flash.md new file mode 100644 index 0000000000..ab31bf63fe --- /dev/null +++ b/.changeset/proud-walls-flash.md @@ -0,0 +1,10 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +DropdownMenu: +- Rename from `DropdownMenu` to `Dropdown` +- Change API and structure +- Rename `.Root` to `.Context` +- Rename `.Content` to `Dropdown` diff --git a/.changeset/purple-berries-repeat.md b/.changeset/purple-berries-repeat.md new file mode 100644 index 0000000000..d94fb95d02 --- /dev/null +++ b/.changeset/purple-berries-repeat.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Tabs: css changes diff --git a/.changeset/quiet-mangos-cry.md b/.changeset/quiet-mangos-cry.md new file mode 100644 index 0000000000..c4fca8e3e0 --- /dev/null +++ b/.changeset/quiet-mangos-cry.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Divider: hide from screen readers diff --git a/.changeset/real-zoos-fail.md b/.changeset/real-zoos-fail.md new file mode 100644 index 0000000000..d4533224ce --- /dev/null +++ b/.changeset/real-zoos-fail.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Textfield: Removed `hideLabel`, use `aria-label` or `aria-describedby` for "hidden" labels diff --git a/.changeset/red-queens-love.md b/.changeset/red-queens-love.md new file mode 100644 index 0000000000..ec7371d1e1 --- /dev/null +++ b/.changeset/red-queens-love.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +ToggleGroup: Rename ToggleGroup.Root to ToggleGroup diff --git a/.changeset/rich-carrots-deny.md b/.changeset/rich-carrots-deny.md new file mode 100644 index 0000000000..52a5716b18 --- /dev/null +++ b/.changeset/rich-carrots-deny.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Heading: default level is now 2 diff --git a/.changeset/rotten-zoos-live.md b/.changeset/rotten-zoos-live.md new file mode 100644 index 0000000000..46aa063a17 --- /dev/null +++ b/.changeset/rotten-zoos-live.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet": patch +--- + +Removed `init` command. Use `tokens create` instead. diff --git a/.changeset/selfish-meals-pump.md b/.changeset/selfish-meals-pump.md new file mode 100644 index 0000000000..3023c47c75 --- /dev/null +++ b/.changeset/selfish-meals-pump.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": major +--- + +Input+Select: Use native HTML `size` prop instead of `htmlSize` diff --git a/.changeset/serious-frogs-rescue.md b/.changeset/serious-frogs-rescue.md new file mode 100644 index 0000000000..ecd73414df --- /dev/null +++ b/.changeset/serious-frogs-rescue.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet': minor +--- + +New create tokens script with color options support diff --git a/.changeset/seven-ladybugs-admire.md b/.changeset/seven-ladybugs-admire.md new file mode 100644 index 0000000000..a46b621401 --- /dev/null +++ b/.changeset/seven-ladybugs-admire.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Badge: Only use single DOM element for rendering diff --git a/.changeset/seven-tips-rest.md b/.changeset/seven-tips-rest.md new file mode 100644 index 0000000000..7c8a5d9168 --- /dev/null +++ b/.changeset/seven-tips-rest.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Avatar: Fix `aria-hidden` being wrongly added to a fragment diff --git a/.changeset/shaggy-bears-tan.md b/.changeset/shaggy-bears-tan.md new file mode 100644 index 0000000000..96475a3e4a --- /dev/null +++ b/.changeset/shaggy-bears-tan.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Modal: remove `FloatingFocusManager` diff --git a/.changeset/shaggy-rockets-repair.md b/.changeset/shaggy-rockets-repair.md new file mode 100644 index 0000000000..09dcb6f27f --- /dev/null +++ b/.changeset/shaggy-rockets-repair.md @@ -0,0 +1,7 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Select: +- Add Select.Option and Select.Optgroup compond components +- Remove `multiple` prop diff --git a/.changeset/shiny-dryers-count.md b/.changeset/shiny-dryers-count.md new file mode 100644 index 0000000000..727a9af1e1 --- /dev/null +++ b/.changeset/shiny-dryers-count.md @@ -0,0 +1,8 @@ +--- +"@digdir/designsystemet-css": major +"@digdir/designsystemet-react": major +--- + +Radio + Checkbox: +- Use `label` prop instead of `children` as label text +- Remove `Radio.Group` and `Checkbox.Group` and use `Fieldset` instead diff --git a/.changeset/shiny-kiwis-switch.md b/.changeset/shiny-kiwis-switch.md new file mode 100644 index 0000000000..cfeaab5022 --- /dev/null +++ b/.changeset/shiny-kiwis-switch.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet-react': patch +--- + +Badge: Export component diff --git a/.changeset/short-walls-judge.md b/.changeset/short-walls-judge.md new file mode 100644 index 0000000000..5cb3b0ade0 --- /dev/null +++ b/.changeset/short-walls-judge.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +feat(Combobox): :sparkles: Label now supports other elements diff --git a/.changeset/shy-cameras-approve.md b/.changeset/shy-cameras-approve.md new file mode 100644 index 0000000000..2cd77f78aa --- /dev/null +++ b/.changeset/shy-cameras-approve.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Chip: Use correct `32px` height to align nicely with `` diff --git a/.changeset/six-carrots-guess.md b/.changeset/six-carrots-guess.md new file mode 100644 index 0000000000..e6ed28e647 --- /dev/null +++ b/.changeset/six-carrots-guess.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +SkipLink: Remove ds-sr-only class diff --git a/.changeset/six-trees-tie.md b/.changeset/six-trees-tie.md new file mode 100644 index 0000000000..3bc859c0b5 --- /dev/null +++ b/.changeset/six-trees-tie.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Skeleton: Replace Skeleton.Text, Skeleton.Circle and Skeleton.Rectangle with diff --git a/.changeset/slimy-bees-arrive.md b/.changeset/slimy-bees-arrive.md new file mode 100644 index 0000000000..cc1d78e686 --- /dev/null +++ b/.changeset/slimy-bees-arrive.md @@ -0,0 +1,6 @@ +--- +'@digdir/designsystemet-react': patch +'@digdir/designsystemet-css': patch +--- + +Accordion: Now uses details and summary HTML elements diff --git a/.changeset/slimy-buttons-train.md b/.changeset/slimy-buttons-train.md new file mode 100644 index 0000000000..06e0a25d73 --- /dev/null +++ b/.changeset/slimy-buttons-train.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet-css': patch +--- + +Combobox: fix overflow on screens narrower than ~340px diff --git a/.changeset/slow-impalas-vanish.md b/.changeset/slow-impalas-vanish.md new file mode 100644 index 0000000000..b01f7f3776 --- /dev/null +++ b/.changeset/slow-impalas-vanish.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Label: Fix icon abandoning parent in scroll container diff --git a/.changeset/slow-news-act.md b/.changeset/slow-news-act.md new file mode 100644 index 0000000000..360ddb79dd --- /dev/null +++ b/.changeset/slow-news-act.md @@ -0,0 +1,26 @@ +--- +"@digdir/designsystemet-theme": minor +"@digdir/designsystemet": minor +--- + +CSS variables: `--ds-color-*-{1,2,...,13,contrast-1,contrast-2}`, which were generated from the `primitives` layer of design tokens, have been removed since they are always 1-to-1 with the semantic layer. Use the equivalent variables from the semantic layer instead + +Example, for the `neutral` scale: +```css + var(--ds-color-neutral-background-default); /* instead of: var(--ds-color-neutral-1) */ + var(--ds-color-neutral-background-subtle); /* instead of: var(--ds-color-neutral-2) */ + var(--ds-color-neutral-surface-default); /* instead of: var(--ds-color-neutral-3) */ + var(--ds-color-neutral-surface-hover); /* instead of: var(--ds-color-neutral-4) */ + var(--ds-color-neutral-surface-active); /* instead of: var(--ds-color-neutral-5) */ + var(--ds-color-neutral-border-subtle); /* instead of: var(--ds-color-neutral-6) */ + var(--ds-color-neutral-border-default); /* instead of: var(--ds-color-neutral-7) */ + var(--ds-color-neutral-border-strong); /* instead of: var(--ds-color-neutral-8) */ + var(--ds-color-neutral-base-default); /* instead of: var(--ds-color-neutral-9) */ + var(--ds-color-neutral-base-hover); /* instead of: var(--ds-color-neutral-10) */ + var(--ds-color-neutral-base-active); /* instead of: var(--ds-color-neutral-11) */ + var(--ds-color-neutral-text-subtle); /* instead of: var(--ds-color-neutral-12) */ + var(--ds-color-neutral-text-default); /* instead of: var(--ds-color-neutral-13) */ + var(--ds-color-neutral-contrast-default); /* instead of: var(--ds-color-neutral-contrast-1) */ + var(--ds-color-neutral-contrast-subtle); /* instead of: var(--ds-color-neutral-contrast-2) */ +``` +...and similarly for `accent`, `brand1`, `brand2` and `brand3`. diff --git a/.changeset/small-houses-stare.md b/.changeset/small-houses-stare.md new file mode 100644 index 0000000000..903a3f3d8d --- /dev/null +++ b/.changeset/small-houses-stare.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-theme": patch +"@digdir/designsystemet": patch +--- + +Update global colors diff --git a/.changeset/small-queens-breathe.md b/.changeset/small-queens-breathe.md new file mode 100644 index 0000000000..739f242e0d --- /dev/null +++ b/.changeset/small-queens-breathe.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Spinner: Style using data attributes diff --git a/.changeset/smooth-radios-leave.md b/.changeset/smooth-radios-leave.md new file mode 100644 index 0000000000..742c987187 --- /dev/null +++ b/.changeset/smooth-radios-leave.md @@ -0,0 +1,8 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Label: Use data attributes for styling + +ValidationMessage: Use data attributes for styling diff --git a/.changeset/smooth-wombats-grab.md b/.changeset/smooth-wombats-grab.md new file mode 100644 index 0000000000..cfebabb6a0 --- /dev/null +++ b/.changeset/smooth-wombats-grab.md @@ -0,0 +1,7 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Select + Textarea: +- Remove `label`, `hideLabel`, `description`, `characterLimit` and `error` as these will be part of `Field` API diff --git a/.changeset/spotty-oranges-guess.md b/.changeset/spotty-oranges-guess.md new file mode 100644 index 0000000000..1415032986 --- /dev/null +++ b/.changeset/spotty-oranges-guess.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Avatar: new component diff --git a/.changeset/spotty-pumas-cross.md b/.changeset/spotty-pumas-cross.md new file mode 100644 index 0000000000..51c84a51e1 --- /dev/null +++ b/.changeset/spotty-pumas-cross.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": minor +--- + +Breadcrumbs: ✨ new component diff --git a/.changeset/stale-tables-eat.md b/.changeset/stale-tables-eat.md new file mode 100644 index 0000000000..ffca676b55 --- /dev/null +++ b/.changeset/stale-tables-eat.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet": minor +--- + +CLI now supports creating themes with 1 or more "main" colors, a neutral color, and 1 or more "support" colors. The "main" and "support" colors can have arbitrary names. There can not be more than 4 colors of each category unless you're using Figma on the Enterprise plan, due to plan-based restrictions on the number of variable modes per collection. diff --git a/.changeset/strange-jars-compete.md b/.changeset/strange-jars-compete.md new file mode 100644 index 0000000000..e27c13cad3 --- /dev/null +++ b/.changeset/strange-jars-compete.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Pagination: Add css variable for chevron diff --git a/.changeset/strong-flowers-ring.md b/.changeset/strong-flowers-ring.md new file mode 100644 index 0000000000..1683f7d351 --- /dev/null +++ b/.changeset/strong-flowers-ring.md @@ -0,0 +1,10 @@ +--- +'@digdir/designsystemet': minor +--- + +Fix crash when running CLI command `tokens build`: +- add --verbose option to `tokens build` for easier debugging +- `tokens build` crashed when run on result of `tokens create` + +Update tokens template used by CLI command `tokens create` +- removes `ingress`, renames `paragraph` to `body`, and adds `xl` size diff --git a/.changeset/strong-ghosts-marry.md b/.changeset/strong-ghosts-marry.md new file mode 100644 index 0000000000..dcd11341dd --- /dev/null +++ b/.changeset/strong-ghosts-marry.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Paragraph: Add css classes and style with data attributes diff --git a/.changeset/stupid-tables-applaud.md b/.changeset/stupid-tables-applaud.md new file mode 100644 index 0000000000..5f2f34c509 --- /dev/null +++ b/.changeset/stupid-tables-applaud.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Tag: Make neutral default color in CSS diff --git a/.changeset/swift-forks-drop.md b/.changeset/swift-forks-drop.md new file mode 100644 index 0000000000..e429584679 --- /dev/null +++ b/.changeset/swift-forks-drop.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Breadcrumbs: Rename `Breadcrumbs.Root` to `Breadcrumbs` and remove `Breadcrumbs.Nav` diff --git a/.changeset/tall-guests-arrive.md b/.changeset/tall-guests-arrive.md new file mode 100644 index 0000000000..a9b79b95eb --- /dev/null +++ b/.changeset/tall-guests-arrive.md @@ -0,0 +1,9 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Chip: +- Add `Chip.Button` +- Rename `Chip.Toggle` to `Chip.Radio` and `Chip.Checkbox` +- Remove `Chip.Group` diff --git a/.changeset/tame-rats-mix.md b/.changeset/tame-rats-mix.md new file mode 100644 index 0000000000..827c655035 --- /dev/null +++ b/.changeset/tame-rats-mix.md @@ -0,0 +1,9 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +HelpText: +- Use Popover API +- Remove `portal` prop +- Render icon with pseudo element and require aria-label diff --git a/.changeset/tender-grapes-refuse.md b/.changeset/tender-grapes-refuse.md new file mode 100644 index 0000000000..f110e8808d --- /dev/null +++ b/.changeset/tender-grapes-refuse.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": minor +--- + +Badge: ✨ New component diff --git a/.changeset/tender-ties-swim.md b/.changeset/tender-ties-swim.md new file mode 100644 index 0000000000..535771c7b8 --- /dev/null +++ b/.changeset/tender-ties-swim.md @@ -0,0 +1,6 @@ +--- +'@digdir/designsystemet-react': patch +'@digdir/designsystemet': patch +--- + +chore: Replace eslint with biomejs diff --git a/.changeset/thin-icons-pay.md b/.changeset/thin-icons-pay.md new file mode 100644 index 0000000000..ce133e0f7d --- /dev/null +++ b/.changeset/thin-icons-pay.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +ToggleGroup, Tabs: Active item equality check is now strict diff --git a/.changeset/three-carrots-hammer.md b/.changeset/three-carrots-hammer.md new file mode 100644 index 0000000000..49d3b3d967 --- /dev/null +++ b/.changeset/three-carrots-hammer.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet': patch +--- + +fix: Export correct bin files diff --git a/.changeset/three-dingos-unite.md b/.changeset/three-dingos-unite.md new file mode 100644 index 0000000000..d9551b338c --- /dev/null +++ b/.changeset/three-dingos-unite.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet': minor +--- + +feat: Convert to W3C design token format diff --git a/.changeset/three-ducks-chew.md b/.changeset/three-ducks-chew.md new file mode 100644 index 0000000000..b92e847bf2 --- /dev/null +++ b/.changeset/three-ducks-chew.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Fieldset: Style using css attributes diff --git a/.changeset/three-moles-attack.md b/.changeset/three-moles-attack.md new file mode 100644 index 0000000000..75f5014bfd --- /dev/null +++ b/.changeset/three-moles-attack.md @@ -0,0 +1,7 @@ +--- +"@digdir/designsystemet-theme": minor +"@digdir/designsystemet": minor +"@digdir/designsystemet-css": minor +--- + +Implemented a more flexible system of semantic border-radius tokens. diff --git a/.changeset/tidy-cheetahs-cry.md b/.changeset/tidy-cheetahs-cry.md new file mode 100644 index 0000000000..45f8ba1609 --- /dev/null +++ b/.changeset/tidy-cheetahs-cry.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Remove `baseline` layer and fix layerorder for typography diff --git a/.changeset/twelve-onions-laugh.md b/.changeset/twelve-onions-laugh.md new file mode 100644 index 0000000000..4680176c4e --- /dev/null +++ b/.changeset/twelve-onions-laugh.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-css": patch +--- + +Modal backdrop was invisible in some browser versions. See https://caniuse.com/mdn-css_selectors_backdrop_inherit_from_originating_element for affected versions. diff --git a/.changeset/twenty-cheetahs-leave.md b/.changeset/twenty-cheetahs-leave.md new file mode 100644 index 0000000000..ecaf8b0d0e --- /dev/null +++ b/.changeset/twenty-cheetahs-leave.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Table: Add `Table.Foot` and style caption diff --git a/.changeset/wet-scissors-tickle.md b/.changeset/wet-scissors-tickle.md new file mode 100644 index 0000000000..6280a26b3e --- /dev/null +++ b/.changeset/wet-scissors-tickle.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Spinner: `aria-label` required instead of `title` prop diff --git a/.changeset/wise-countries-double.md b/.changeset/wise-countries-double.md new file mode 100644 index 0000000000..060faed18f --- /dev/null +++ b/.changeset/wise-countries-double.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +NativeSelect: add focus in `readOnly` state diff --git a/.changeset/witty-clouds-judge.md b/.changeset/witty-clouds-judge.md new file mode 100644 index 0000000000..34393eb3ff --- /dev/null +++ b/.changeset/witty-clouds-judge.md @@ -0,0 +1,6 @@ +--- +"@digdir/designsystemet-css": patch +"@digdir/designsystemet-react": patch +--- + +Card: Use data attrs diff --git a/.changeset/witty-moons-sleep.md b/.changeset/witty-moons-sleep.md new file mode 100644 index 0000000000..9837ebaa1f --- /dev/null +++ b/.changeset/witty-moons-sleep.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Combobox: fix virtual combobox having large gap between items diff --git a/.changeset/witty-moose-scream.md b/.changeset/witty-moose-scream.md new file mode 100644 index 0000000000..5dff1a2114 --- /dev/null +++ b/.changeset/witty-moose-scream.md @@ -0,0 +1,5 @@ +--- +"@digdir/designsystemet-react": patch +--- + +Textfield: Update to use `Field` internally diff --git a/.changeset/yellow-zoos-camp.md b/.changeset/yellow-zoos-camp.md new file mode 100644 index 0000000000..55cc68f9b2 --- /dev/null +++ b/.changeset/yellow-zoos-camp.md @@ -0,0 +1,5 @@ +--- +'@digdir/designsystemet': patch +--- + +Make sure the internal order of sections in the CSS generated by the CLI is deterministic, to avoid unnecessary git diffs diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index fb79cfb2e0..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,9 +0,0 @@ -node_modules -**/*.d.ts* -dist/ -packages/theme/brand/**/* -packages/react-old/**/* -tsc-build/ -.storybook - -apps/theme/** diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 053b6d88d9..0000000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,96 +0,0 @@ -module.exports = { - root: true, - env: { - node: true, - browser: true, - es6: true, - }, - extends: [ - 'eslint:recommended', - 'plugin:import/recommended', - 'plugin:jsx-a11y/recommended', - 'plugin:react/recommended', - 'plugin:react-hooks/recommended', - 'plugin:react/jsx-runtime', - 'plugin:storybook/recommended', - 'prettier', - ], - plugins: ['import', 'react', 'jsx-a11y'], - overrides: [ - { - // Typescript - files: ['**/*.ts?(x)'], - extends: [ - 'plugin:import/typescript', - 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', - ], - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - tsconfigRootDir: __dirname, - ecmaFeatures: { jsx: true }, - project: [ - './tsconfig.json', - './packages/*/tsconfig.json', - './tsconfig.node.json', - ], - }, - rules: { - '@typescript-eslint/consistent-type-exports': 'warn', - '@typescript-eslint/consistent-type-imports': 'warn', - 'prefer-const': 'warn', - }, - }, - { - files: ['apps/storefront/**/*', 'apps/dev/**/*', 'apps/theme/**/*'], - extends: ['plugin:@next/next/recommended'], - }, - ], - rules: { - 'arrow-body-style': 'off', - 'prefer-arrow-callback': 'off', - // Disabled because we use Typescript types for props - 'react/prop-types': ['off'], - 'react/jsx-no-bind': 'off', - 'react/display-name': 'off', - 'import/no-unresolved': 'error', - 'import/namespace': ['error', { allowComputed: true }], - 'import/no-named-as-default': 'off', - '@next/next/no-html-link-for-pages': ['error', 'apps/storefront/pages/'], - 'jsx-a11y/no-autofocus': 'off', - 'import/order': [ - 'warn', - { - 'newlines-between': 'always', - groups: [ - 'builtin', - 'external', - 'internal', - 'parent', - 'sibling', - 'index', - ], - }, - ], - }, - settings: { - react: { - version: '18', - }, - 'import/parsers': { - '@typescript-eslint/parser': ['.ts', '.tsx'], - }, - 'import/resolver': { - typescript: { - alwaysTryTypes: true, - project: [ - /* all tsconfig files */ - 'tsconfig.json', - './**/tsconfig.json', - ], - }, - }, - }, -}; diff --git a/.github/ISSUE_TEMPLATE/1bug_report.yml b/.github/ISSUE_TEMPLATE/1bug_report.yml index bb93c86fb3..384d2d3a08 100644 --- a/.github/ISSUE_TEMPLATE/1bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1bug_report.yml @@ -8,7 +8,15 @@ body: Thanks for taking the time to fill out this bug report 🤗 Make sure there aren't any open/closed issues for this topic 😃 If possible, please create a [codesandbox](https://codesandbox.io/) with an example of the bug. This will help us a lot to determine the cause of the bug. - + + - type: input + id: bug-version + attributes: + label: Version number + description: If relevant, please provide the version number of the package you are using. + validations: + required: false + - type: textarea id: bug-description attributes: @@ -16,7 +24,7 @@ body: description: Give us a brief description of what happened and what should have happened validations: required: true - + - type: textarea id: steps-to-reproduce attributes: diff --git a/.github/actions/gh-setup/action.yml b/.github/actions/gh-setup/action.yml new file mode 100644 index 0000000000..84ed7b967d --- /dev/null +++ b/.github/actions/gh-setup/action.yml @@ -0,0 +1,13 @@ +name: Setup GH +description: Setup GitHub Actions +runs: + using: composite + steps: + - name: Setup Node & Yarn cache + uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: yarn + - name: Install dependencies + shell: bash + run: yarn install --immutable diff --git a/.github/workflows/add-issue-to-project.yml b/.github/workflows/add-issue-to-project.yml new file mode 100644 index 0000000000..b42ed90fdb --- /dev/null +++ b/.github/workflows/add-issue-to-project.yml @@ -0,0 +1,16 @@ +name: Add new issues to project + +on: + issues: + types: + - opened + +jobs: + add-to-project: + name: Add issue to project + runs-on: ubuntu-latest + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/digdir/projects/3 + github-token: ${{ secrets.GH_ASSIGN_PROJECT_TOKEN }} diff --git a/.github/workflows/build-tokens.yml b/.github/workflows/build-tokens.yml index 4f933dde9b..9d651b5524 100644 --- a/.github/workflows/build-tokens.yml +++ b/.github/workflows/build-tokens.yml @@ -1,11 +1,11 @@ name: Build tokens on: workflow_dispatch: - pull_request: - branches: - - main - paths: - - 'design-tokens/**' + # pull_request: + # branches: + # - main + # paths: + # - 'design-tokens/**' jobs: checks: name: Builds, lints and tests code diff --git a/.github/workflows/check-storefront.yml b/.github/workflows/check-storefront.yml index 6dedb8f088..650214d17a 100644 --- a/.github/workflows/check-storefront.yml +++ b/.github/workflows/check-storefront.yml @@ -1,20 +1,12 @@ -# Runs conventional commit check on PR -name: Checks storefront +name: Build Storefront on: workflow_dispatch: pull_request: - branches: - - main - paths: - - 'apps/storefront/**' - push: - branches: - - main paths: - 'apps/storefront/**' jobs: checks: - name: Builds, lints and tests code + name: Build & test runs-on: ubuntu-latest steps: - name: Checkout repository @@ -32,9 +24,4 @@ jobs: run: yarn build:storefront - name: Types run: yarn types:storefront - - name: Lint Code - run: yarn lint ./apps/storefront - - name: Lint CSS - run: yarn lint-style ./apps/storefront/**/*.css - - name: Test - run: yarn test + diff --git a/.github/workflows/checks-packages.yml b/.github/workflows/checks-packages.yml deleted file mode 100644 index a45d9f6212..0000000000 --- a/.github/workflows/checks-packages.yml +++ /dev/null @@ -1,39 +0,0 @@ -# Runs conventional commit check on PR -name: Checks packages -on: - workflow_dispatch: - pull_request: - branches: - - main - paths: - - 'packages/**' - - '*.*js' - push: - branches: - - main - paths: - - 'packages/**' -jobs: - checks: - name: Builds, lints and tests code - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Use node 20 and yarn cache - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'yarn' - - name: Install dependencies - run: yarn install --immutable - - name: Build - run: yarn build - - name: Types - run: yarn types:react - - name: Lint Code - run: yarn lint:all - - name: Lint CSS - run: yarn lint-style - - name: Test - run: yarn test diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 0000000000..b4c9f56879 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,18 @@ +name: Checks +on: + workflow_dispatch: + pull_request: + paths: + - 'packages/**' + - 'apps/**' + - 'plugins/**' + - 'biome.jsonc' +jobs: + checks: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/gh-setup + - name: Lint code + run: yarn biome ci . diff --git a/.github/workflows/cleanup-preview-deployments.yml b/.github/workflows/cleanup-preview-deployments.yml deleted file mode 100644 index fe15ca2786..0000000000 --- a/.github/workflows/cleanup-preview-deployments.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Cleanup Preview Deployments -on: - pull_request: - types: [closed] - -env: - VERCEL_TEAM: ${{ secrets.VERCEL_TEAM }} - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STOREFRONT }} - STORYBOOK_URL: storybook-pr-${{ github.event.number }}.dev.designsystemet.no - STOREFRONT_URL: storefront-pr-${{ github.event.number }}.dev.designsystemet.no - ALIASES: - -jobs: - Deploy-Preview: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - id: get-aliases - name: Get a list of all Vercel aliases and set it to ENV - run: | - { - echo 'ALIASES<> "$GITHUB_ENV" - - - name: Remove Storybook alias if it exists - if: contains(env.ALIASES, env.STORYBOOK_URL) - run: vercel alias rm --yes --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} ${{ env.STORYBOOK_URL }} - - - name: Remove Storefront alias if it exists - if: contains(env.ALIASES, env.STOREFRONT_URL) - run: vercel alias rm --yes --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} ${{ env.STOREFRONT_URL }} diff --git a/.github/workflows/conventional-pr.yml b/.github/workflows/conventional-pr.yml index 1474642de4..d3d8ef9385 100644 --- a/.github/workflows/conventional-pr.yml +++ b/.github/workflows/conventional-pr.yml @@ -4,6 +4,7 @@ on: pull_request: branches: - main + - next types: - opened - edited @@ -14,7 +15,7 @@ jobs: steps: - uses: actions/checkout@v4 # check for the most recent release: https://github.com/CondeNast/conventional-pull-request-action/releases - - uses: CondeNast/conventional-pull-request-action@v0.2.0 + - uses: zentered/conventional-pull-request-action@v0.3.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/deploy-storefront.yml b/.github/workflows/deploy-storefront.yml new file mode 100644 index 0000000000..876bb5e843 --- /dev/null +++ b/.github/workflows/deploy-storefront.yml @@ -0,0 +1,59 @@ +name: Deploy Storefront +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STOREFRONT }} +on: + workflow_dispatch: + inputs: + environment: + type: choice + default: next + description: Deploy to environment + options: + - production + - next + push: + branches: + - next + paths: + - 'apps/storefront/**' +jobs: + Deploy-Production: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Use node 20 and yarn cache + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Install Vercel CLI + run: yarn add vercel@latest + + - name: Set default environment value if push event is triggered + id: defaultenvironment + run: | + ENVIRONMENT=${{ github.event.inputs.environment }} + echo "value=${ENVIRONMENT:-"next"}" >> "$GITHUB_OUTPUT" + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=${{(steps.defaultenvironment.outputs.value == 'next' && 'preview') || 'production'}} --token=${{ secrets.VERCEL_TOKEN }} + + - name: Build Project Artifacts + run: vercel build ${{(steps.defaultenvironment.outputs.value == 'production' && '--prod') || ''}} --token=${{ secrets.VERCEL_TOKEN }} + + - id: deploy + name: Deploy Project Artifacts to Vercel + run: echo "url=$(vercel deploy --prebuilt ${{(steps.defaultenvironment.outputs.value == 'production' && '--prod') || ''}} --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT + + - name: Set Vercel alias + run: vercel alias --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} set ${{ steps.deploy.outputs.url }} next.designsystemet.no + if: steps.defaultenvironment.outputs.value == 'next' diff --git a/.github/workflows/deploy-storybook.yml b/.github/workflows/deploy-storybook.yml new file mode 100644 index 0000000000..e4af7eaac7 --- /dev/null +++ b/.github/workflows/deploy-storybook.yml @@ -0,0 +1,64 @@ +name: Deploy Storybook +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STORYBOOK }} + +on: + workflow_dispatch: + inputs: + environment: + type: choice + default: next + description: Deploy to environment + options: + - production + - next + push: + branches: + - next + paths: + - 'packages/**' + - 'apps/storybook/**' + - 'assets/**' +jobs: + deploy: + name: Build & deploy to Vercel + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Use node 20 and yarn cache + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Install Vercel CLI + run: yarn add vercel@latest + + - name: Set default environment value if push event is triggered + id: defaultenvironment + run: | + ENVIRONMENT=${{ github.event.inputs.environment }} + echo "value=${ENVIRONMENT:-"next"}" >> "$GITHUB_OUTPUT" + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=${{(steps.defaultenvironment.outputs.value == 'next' && 'preview') || 'production'}} --token=${{ secrets.VERCEL_TOKEN }} + + - name: Build Project Artifacts + run: vercel build ${{(steps.defaultenvironment.outputs.value == 'production' && '--prod') || ''}} --token=${{ secrets.VERCEL_TOKEN }} + + - id: deploy + name: Deploy Project Artifacts to Vercel + run: echo "url=$(vercel deploy --prebuilt ${{(steps.defaultenvironment.outputs.value == 'production' && '--prod') || ''}} --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT + + - name: Set Vercel alias + run: vercel alias --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} set ${{ steps.deploy.outputs.url }} next.storybook.designsystemet.no + if: steps.defaultenvironment.outputs.value == 'next' diff --git a/.github/workflows/deploy-theme.yml b/.github/workflows/deploy-theme.yml new file mode 100644 index 0000000000..bf48feefbc --- /dev/null +++ b/.github/workflows/deploy-theme.yml @@ -0,0 +1,59 @@ +name: Deploy Theme +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_THEME }} +on: + workflow_dispatch: + inputs: + environment: + type: choice + default: next + description: Deploy to environment + options: + - production + - next + push: + branches: + - next + paths: + - 'apps/theme/**' +jobs: + Deploy-Production: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Use node 20 and yarn cache + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Install Vercel CLI + run: yarn add vercel@latest + + - name: Set default environment value if push event is triggered + id: defaultenvironment + run: | + ENVIRONMENT=${{ github.event.inputs.environment }} + echo "value=${ENVIRONMENT:-"next"}" >> "$GITHUB_OUTPUT" + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=${{(steps.defaultenvironment.outputs.value == 'next' && 'preview') || 'production'}} --token=${{ secrets.VERCEL_TOKEN }} + + - name: Build Project Artifacts + run: vercel build ${{(steps.defaultenvironment.outputs.value == 'production' && '--prod') || ''}} --token=${{ secrets.VERCEL_TOKEN }} + + - id: deploy + name: Deploy Project Artifacts to Vercel + run: echo "url=$(vercel deploy --prebuilt ${{(steps.defaultenvironment.outputs.value == 'production' && '--prod') || ''}} --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT + + - name: Set Vercel alias + run: vercel alias --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} set ${{ steps.deploy.outputs.url }} next.theme.designsystemet.no + if: steps.defaultenvironment.outputs.value == 'next' diff --git a/.github/workflows/development-deploy.yml b/.github/workflows/development-deploy.yml deleted file mode 100644 index 68bb23468a..0000000000 --- a/.github/workflows/development-deploy.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: Deploy Development Production -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_DEVELOPMENT }} -on: - workflow_dispatch: - push: - branches: - - main - paths: - - 'apps/dev/**' -jobs: - Deploy-Production: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Use node 20 and yarn cache - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'yarn' - - - name: Install dependencies - run: yarn install --frozen-lockfile - - - name: Build - run: yarn build - - - name: Install Vercel CLI - run: yarn add vercel@latest - - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - - name: Build Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/preview-cleanup.yml b/.github/workflows/preview-cleanup.yml new file mode 100644 index 0000000000..2871f41a0f --- /dev/null +++ b/.github/workflows/preview-cleanup.yml @@ -0,0 +1,38 @@ +name: Cleanup Preview Deployments +on: + pull_request: + types: [closed] + +env: + VERCEL_TEAM: ${{ secrets.VERCEL_TEAM }} + STORYBOOK_URL: pr-${{ github.event.number }}.storybook.designsystemet.no + STOREFRONT_URL: pr-${{ github.event.number }}.designsystemet.no + THEME_URL: pr-${{ github.event.number }}.theme.designsystemet.no + ALIASES: + +jobs: + Deploy-Preview: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - id: get-aliases + name: Get a list of all Vercel aliases and set it to ENV + run: | + { + echo 'ALIASES<> "$GITHUB_ENV" + + - name: Remove Storybook alias if it exists + if: contains(env.ALIASES, env.STORYBOOK_URL) + run: vercel alias rm --yes --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} ${{ env.STORYBOOK_URL }} + + - name: Remove Storefront alias if it exists + if: contains(env.ALIASES, env.STOREFRONT_URL) + run: vercel alias rm --yes --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} ${{ env.STOREFRONT_URL }} + + - name: Remove Theme alias if it exists + if: contains(env.ALIASES, env.THEME_URL) + run: vercel alias rm --yes --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} ${{ env.THEME_URL }} diff --git a/.github/workflows/create-preview-comment.yml b/.github/workflows/preview-comment.yml similarity index 100% rename from .github/workflows/create-preview-comment.yml rename to .github/workflows/preview-comment.yml diff --git a/.github/workflows/preview-storefront.yml b/.github/workflows/preview-storefront.yml new file mode 100644 index 0000000000..7b5c346eb2 --- /dev/null +++ b/.github/workflows/preview-storefront.yml @@ -0,0 +1,92 @@ +name: Deploy Storefront Preview +env: + VERCEL_TEAM: ${{ secrets.VERCEL_TEAM }} + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STOREFRONT }} + PR_NUMBER: ${{ github.event.number }} +on: + workflow_dispatch: + pull_request: + types: [opened, synchronize] + paths: + - 'apps/storefront/**' +jobs: + Deploy-Preview: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Use node 20 and yarn cache + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Install Vercel CLI + run: yarn add vercel@latest + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + + - name: Build Project Artifacts + run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + + - id: deploy + name: Deploy Project Artifacts to Vercel + run: echo "url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT + + - name: Set Vercel alias + run: vercel alias --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} set ${{ steps.deploy.outputs.url }} pr-${{ env.PR_NUMBER }}.designsystemet.no + + - name: Find Preview Comment + uses: peter-evans/find-comment@v2 + id: fc + with: + issue-number: ${{ env.PR_NUMBER }} + body-includes: | + **Preview deployments for this pull request:** + + - run: echo ${{ steps.fc.outputs.comment-id }} + if: success() && env.PR_NUMBER + + - name: Find Storybook deployment + uses: actions-ecosystem/action-regex-match@v2 + id: regex-storybook + with: + text: ${{ steps.fc.outputs.comment-body }} + regex: '\[Storybook\]\((https:\/\/[^)]+)\).*' + + - name: Find Theme deployment + uses: actions-ecosystem/action-regex-match@v2 + id: regex-theme + with: + text: ${{ steps.fc.outputs.comment-body }} + regex: '\[Theme\]\((https:\/\/[^)]+)\).*' + + - name: Get current time in CEST + uses: josStorer/get-current-time@v2 + id: current-time + with: + format: D. MMM YYYY - HH:mm + timezone: Europe/Oslo + + - name: Update comment with deployment + uses: peter-evans/create-or-update-comment@v3 + with: + issue-number: ${{ env.PR_NUMBER }} + comment-id: ${{ steps.fc.outputs.comment-id }} + edit-mode: replace + body: | + **Preview deployments for this pull request:** + + ${{ steps.regex-storybook.outputs.match }} + + [Storefront](https://pr-${{ env.PR_NUMBER }}.designsystemet.no) - `${{ steps.current-time.outputs.formattedTime }}` + + ${{ steps.regex-theme.outputs.match }} diff --git a/.github/workflows/preview-storybook.yml b/.github/workflows/preview-storybook.yml new file mode 100644 index 0000000000..a29c6dbf8a --- /dev/null +++ b/.github/workflows/preview-storybook.yml @@ -0,0 +1,94 @@ +name: Deploy Storybook Preview +env: + VERCEL_TEAM: ${{ secrets.VERCEL_TEAM }} + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STORYBOOK }} + PR_NUMBER: ${{ github.event.number }} +on: + workflow_dispatch: + pull_request: + types: [opened, synchronize] + paths: + - 'packages/**' + - 'apps/storybook/**' + - 'assets/**' +jobs: + Deploy-Preview: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Use node 20 and yarn cache + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Install Vercel CLI + run: yarn add vercel@latest + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + + - name: Build Project Artifacts + run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + + - id: deploy + name: Deploy Project Artifacts to Vercel + run: echo "url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT + + - name: Set Vercel alias + run: vercel alias --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} set ${{ steps.deploy.outputs.url }} pr-${{ env.PR_NUMBER }}.storybook.designsystemet.no + + - name: Find Preview Comment + uses: peter-evans/find-comment@v2 + id: fc + with: + issue-number: ${{ env.PR_NUMBER }} + body-includes: | + **Preview deployments for this pull request:** + + - run: echo ${{ steps.fc.outputs.comment-id }} + if: success() && env.PR_NUMBER + + - name: Find Storefront deployment + uses: actions-ecosystem/action-regex-match@v2 + id: regex-storefront + with: + text: ${{ steps.fc.outputs.comment-body }} + regex: '\[Storefront\]\((https:\/\/[^)]+)\).*' + + - name: Find Theme deployment + uses: actions-ecosystem/action-regex-match@v2 + id: regex-theme + with: + text: ${{ steps.fc.outputs.comment-body }} + regex: '\[Theme\]\((https:\/\/[^)]+)\).*' + + - name: Get current time in CEST + uses: josStorer/get-current-time@v2 + id: current-time + with: + format: D. MMM YYYY - HH:mm + timezone: Europe/Oslo + + - name: Update comment with deployment + uses: peter-evans/create-or-update-comment@v3 + with: + issue-number: ${{ env.PR_NUMBER }} + comment-id: ${{ steps.fc.outputs.comment-id }} + edit-mode: replace + body: | + **Preview deployments for this pull request:** + + [Storybook](https://pr-${{ env.PR_NUMBER }}.storybook.designsystemet.no) - `${{ steps.current-time.outputs.formattedTime }}` + + ${{ steps.regex-storefront.outputs.match }} + + ${{ steps.regex-theme.outputs.match }} diff --git a/.github/workflows/preview-theme.yml b/.github/workflows/preview-theme.yml new file mode 100644 index 0000000000..16473e3315 --- /dev/null +++ b/.github/workflows/preview-theme.yml @@ -0,0 +1,92 @@ +name: Deploy Theme Preview +env: + VERCEL_TEAM: ${{ secrets.VERCEL_TEAM }} + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_THEME }} + PR_NUMBER: ${{ github.event.number }} +on: + workflow_dispatch: + pull_request: + types: [opened, synchronize] + paths: + - 'apps/theme/**' +jobs: + Deploy-Preview: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Use node 20 and yarn cache + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build + + - name: Install Vercel CLI + run: yarn add vercel@latest + + - name: Pull Vercel Environment Information + run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + + - name: Build Project Artifacts + run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + + - id: deploy + name: Deploy Project Artifacts to Vercel + run: echo "url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT + + - name: Set Vercel alias + run: vercel alias --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} set ${{ steps.deploy.outputs.url }} pr-${{ env.PR_NUMBER }}.theme.designsystemet.no + + - name: Find Preview comment + uses: peter-evans/find-comment@v2 + id: fc + with: + issue-number: ${{ env.PR_NUMBER }} + body-includes: | + **Preview deployments for this pull request:** + + - run: echo ${{ steps.fc.outputs.comment-id }} + if: success() && env.PR_NUMBER + + - name: Find Storybook deployment + uses: actions-ecosystem/action-regex-match@v2 + id: regex-storybook + with: + text: ${{ steps.fc.outputs.comment-body }} + regex: '\[Storybook\]\((https:\/\/[^)]+)\).*' + + - name: Find Storefront deployment + uses: actions-ecosystem/action-regex-match@v2 + id: regex-storefront + with: + text: ${{ steps.fc.outputs.comment-body }} + regex: '\[Storefront\]\((https:\/\/[^)]+)\).*' + + - name: Get current time in CEST + uses: josStorer/get-current-time@v2 + id: current-time + with: + format: D. MMM YYYY - HH:mm + timezone: Europe/Oslo + + - name: Update comment with deployment + uses: peter-evans/create-or-update-comment@v3 + with: + issue-number: ${{ env.PR_NUMBER }} + comment-id: ${{ steps.fc.outputs.comment-id }} + edit-mode: replace + body: | + **Preview deployments for this pull request:** + + ${{ steps.regex-storybook.outputs.match }} + + ${{ steps.regex-storefront.outputs.match }} + + [Theme](https://pr-${{ env.PR_NUMBER }}.theme.designsystemet.no) - `${{ steps.current-time.outputs.formattedTime }}` diff --git a/.github/workflows/release-snapshot.yml b/.github/workflows/release-snapshot.yml new file mode 100644 index 0000000000..bd2c05130c --- /dev/null +++ b/.github/workflows/release-snapshot.yml @@ -0,0 +1,36 @@ +# https://github.com/anthonyhastings/turborepo-design-system +name: Release Snapshot + +on: + workflow_dispatch: + inputs: + tag: + description: 'NPM tag' + default: '' + +jobs: + snapshot: + name: Snapshot Release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/gh-setup + - name: Build + run: yarn build + - id: variables + run: echo "tag=${{ github.event.inputs.tag != '' && github.event.inputs.tag || github.ref_name }}" >> $GITHUB_OUTPUT + - name: Creating .npmrc + run: | + cat << EOF > "$HOME/.npmrc" + //registry.npmjs.org/:_authToken=$NPM_TOKEN + EOF + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Create Snapshot Release + run: | + yarn run version-packages --snapshot "${{ steps.variables.outputs.tag }}" + echo '---' + echo 'Detected Changes:' + git diff + echo '---' + yarn run publish --tag "${{ steps.variables.outputs.tag }}" --no-git-tag diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..f8d2eafcc0 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,31 @@ +name: Release + +on: + workflow_dispatch: + push: + branches: + - main + - next + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + release: + name: Release + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/gh-setup + - name: Create Release Pull Request or Publish to npm + # https://github.com/changesets/action + uses: changesets/action@v1 + with: + # this expects you to have a script called release which does a build for your packages and calls changeset publish + publish: yarn publish + version: yarn version-packages + commit: 'chore: new release' + title: 'chore: new release candidate' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/storefront-deploy.yml b/.github/workflows/storefront-deploy.yml deleted file mode 100644 index 83a7d73e50..0000000000 --- a/.github/workflows/storefront-deploy.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Deploy Storefront Production -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STOREFRONT }} -on: - push: - branches: - - main - paths: - - 'apps/storefront/**' -jobs: - Deploy-Production: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Use node 20 and yarn cache - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'yarn' - - - name: Install dependencies - run: yarn install --frozen-lockfile - - - name: Build - run: yarn build - - - name: Install Vercel CLI - run: yarn add vercel@latest - - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - - name: Build Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/storefront-preview.yml b/.github/workflows/storefront-preview.yml deleted file mode 100644 index 8602a8c8df..0000000000 --- a/.github/workflows/storefront-preview.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Deploy Storefront Preview -env: - VERCEL_TEAM: ${{ secrets.VERCEL_TEAM }} - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STOREFRONT }} - PR_NUMBER: ${{ github.event.number }} -on: - workflow_dispatch: - pull_request: - types: [opened, synchronize] - paths: - - 'apps/storefront/**' -jobs: - Deploy-Preview: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Use node 20 and yarn cache - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'yarn' - - - name: Install dependencies - run: yarn install --frozen-lockfile - - - name: Build - run: yarn build - - - name: Install Vercel CLI - run: yarn add vercel@latest - - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} - - - id: deploy - name: Deploy Project Artifacts to Vercel - run: echo "url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT - - - name: Set Vercel alias - run: vercel alias --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} set ${{ steps.deploy.outputs.url }} storefront-pr-${{ env.PR_NUMBER }}.dev.designsystemet.no - - - name: Find Preview Comment - uses: peter-evans/find-comment@v2 - id: fc - with: - issue-number: ${{ env.PR_NUMBER }} - body-includes: | - **Preview deployments for this pull request:** - - - run: echo ${{ steps.fc.outputs.comment-id }} - if: success() && env.PR_NUMBER - - - name: Find Storybook deployment - uses: actions-ecosystem/action-regex-match@v2 - id: regex-storybook - with: - text: ${{ steps.fc.outputs.comment-body }} - regex: '📖 \[Storybook\]\((https:\/\/[^)]+)\) `[^`]+`' - - - name: Get current time in CEST - uses: josStorer/get-current-time@v2 - id: current-time - with: - format: D. MMM YYYY - HH:mm - timezone: Europe/Oslo - - - name: Update comment with deployment - uses: peter-evans/create-or-update-comment@v3 - with: - issue-number: ${{ env.PR_NUMBER }} - comment-id: ${{ steps.fc.outputs.comment-id }} - edit-mode: replace - reactions: rocket, eyes - body: | - **Preview deployments for this pull request:** - - ${{ steps.regex-storybook.outputs.match }} - - 🖥 [Storefront](https://storefront-pr-${{ env.PR_NUMBER }}.dev.designsystemet.no) `${{ steps.current-time.outputs.formattedTime }} (Norwegian time)` - - See all deployments at [https://dev.designsystemet.no](https://dev.designsystemet.no) diff --git a/.github/workflows/storybook-deploy-vercel.yml b/.github/workflows/storybook-deploy-vercel.yml deleted file mode 100644 index 01983ba3dc..0000000000 --- a/.github/workflows/storybook-deploy-vercel.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Deploy Storybook Production -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STORYBOOK }} -on: - workflow_dispatch: - push: - branches: - - main -jobs: - deploy: - name: Build & deploy to Vercel - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Use node 20 and yarn cache - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'yarn' - - - name: Install dependencies - run: yarn install --frozen-lockfile - - - name: Build - run: yarn build - - - name: Install Vercel CLI - run: yarn add vercel@latest - - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - - name: Build Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - - id: deploy - name: Deploy Project Artifacts to Vercel - run: echo "url=$(vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT diff --git a/.github/workflows/storybook-deploy.yml b/.github/workflows/storybook-deploy.yml deleted file mode 100644 index a2e48cb72e..0000000000 --- a/.github/workflows/storybook-deploy.yml +++ /dev/null @@ -1,51 +0,0 @@ -# Builds and deploys Storybook to github pages -# Requires github pages source settings to target the branch and folder in the deploy step from this action -name: Deploy Storybook Production -on: - workflow_dispatch: - push: - branches: - - main -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Use node 20 and yarn cache - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'yarn' - - - name: Install dependencies - run: yarn install --frozen-lockfile - - - name: Build - run: yarn build - - - name: Build Storybook - run: yarn build:storybook - - - name: Upload artifact - uses: actions/upload-pages-artifact@v2 - with: - name: github-pages - path: dist/storybook - # https://github.com/actions/deploy-pages - deploy: - needs: build - permissions: - pages: write - id-token: write - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v2 - with: - artifact_name: github-pages diff --git a/.github/workflows/storybook-preview.yml b/.github/workflows/storybook-preview.yml deleted file mode 100644 index d3d9921f34..0000000000 --- a/.github/workflows/storybook-preview.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Deploy Storybook Preview -env: - VERCEL_TEAM: ${{ secrets.VERCEL_TEAM }} - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STORYBOOK }} - PR_NUMBER: ${{ github.event.number }} -on: - workflow_dispatch: - pull_request: - types: [opened, synchronize] - paths: - - 'packages/**' - - 'apps/storybook/**' - - 'assets/**' -jobs: - Deploy-Preview: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Use node 20 and yarn cache - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'yarn' - - - name: Install dependencies - run: yarn install --frozen-lockfile - - - name: Build - run: yarn build - - - name: Install Vercel CLI - run: yarn add vercel@latest - - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} - - - id: deploy - name: Deploy Project Artifacts to Vercel - run: echo "url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})" >> $GITHUB_OUTPUT - - - name: Set Vercel alias - run: vercel alias --token=${{ secrets.VERCEL_TOKEN }} --scope=${{ secrets.VERCEL_TEAM }} set ${{ steps.deploy.outputs.url }} storybook-pr-${{ env.PR_NUMBER }}.dev.designsystemet.no - - - name: Find Preview Comment - uses: peter-evans/find-comment@v2 - id: fc - with: - issue-number: ${{ env.PR_NUMBER }} - body-includes: | - **Preview deployments for this pull request:** - - - run: echo ${{ steps.fc.outputs.comment-id }} - if: success() && env.PR_NUMBER - - - name: Find Storybook deployment - uses: actions-ecosystem/action-regex-match@v2 - id: regex-storefront - with: - text: ${{ steps.fc.outputs.comment-body }} - regex: '🖥 \[Storefront\]\((https:\/\/[^)]+)\) `[^`]+`' - - - name: Get current time in CEST - uses: josStorer/get-current-time@v2 - id: current-time - with: - format: D. MMM YYYY - HH:mm - timezone: Europe/Oslo - - - name: Update comment with deployment - uses: peter-evans/create-or-update-comment@v3 - with: - issue-number: ${{ env.PR_NUMBER }} - comment-id: ${{ steps.fc.outputs.comment-id }} - edit-mode: replace - reactions: rocket, eyes - body: | - **Preview deployments for this pull request:** - - 📖 [Storybook](https://storybook-pr-${{ env.PR_NUMBER }}.dev.designsystemet.no) `${{ steps.current-time.outputs.formattedTime }} (Norwegian time)` - - ${{ steps.regex-storefront.outputs.match }} - - See all deployments at [https://dev.designsystemet.no](https://dev.designsystemet.no) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..e44e784bfc --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,67 @@ +name: Test +on: + workflow_dispatch: + pull_request: + paths: + - .github/workflows/test.yml + - 'packages/**' + - 'apps/storybook/**' + +permissions: + checks: write + # Required to put a comment into the pull-request + pull-requests: write + +jobs: + checks: + name: Build & test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/gh-setup + - name: Build + run: yarn build + - name: Types + run: yarn types:react + + - name: Test + run: yarn test + - name: 'Report Coverage' + if: success() || failure() + uses: davelosert/vitest-coverage-report-action@v2 + - name: Publish unit test report + uses: mikepenz/action-junit-report@v4 + if: success() || failure() + with: + report_paths: 'test-report.xml' + detailed_summary: true + check_name: Unit Test Report + check_annotations: true + check_title_template: '{{FILE_NAME}} / {{TEST_NAME}}' + + - name: Test CLI (create tokens, then build the theme) + run: yarn test:cli + + - name: Install Playwright + run: npx playwright install --with-deps + - name: Build storybook + run: yarn build:storybook + - name: Run Storybook tests + run: yarn test:storybook + - name: Replace relative paths in test report + uses: jacobtomlinson/gha-find-replace@v3 + if: success() || failure() + with: + include: 'apps/storybook/test-report.xml' + find: '../../' + replace: '' + regex: false + - name: Publish Storybook test report + uses: mikepenz/action-junit-report@v4 + if: success() || failure() + with: + report_paths: 'apps/storybook/test-report.xml' + detailed_summary: true + check_name: Storybook Test Report + check_annotations: true + check_title_template: '{{FILE_NAME}} / {{TEST_NAME}}' diff --git a/.github/workflows/theme-deploy.yml b/.github/workflows/theme-deploy.yml deleted file mode 100644 index 00d6e45bcd..0000000000 --- a/.github/workflows/theme-deploy.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Deploy Theme Production -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_THEME }} -on: - push: - branches: - - main - paths: - - 'apps/theme/**' -jobs: - Deploy-Production: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Use node 20 and yarn cache - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'yarn' - - - name: Install dependencies - run: yarn install --frozen-lockfile - - - name: Build - run: yarn build - - - name: Install Vercel CLI - run: yarn add vercel@latest - - - name: Pull Vercel Environment Information - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - - name: Build Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/visual-tests.yml b/.github/workflows/visual-tests.yml new file mode 100644 index 0000000000..5ab4173fed --- /dev/null +++ b/.github/workflows/visual-tests.yml @@ -0,0 +1,43 @@ +name: Visual tests +on: + workflow_dispatch: + pull_request: + branches: [main, next] + types: + # Ensure workflow is run when PR is ready for review + - ready_for_review + # Also enable the default trigger types, for instances when + # the PR is not opened as a draft first + - opened + - reopened + - synchronize + + paths: + - .github/workflows/visual-tests.yml + - 'packages/**' + - 'apps/storybook/**' + push: + branches: [main, next] + +jobs: + checks: + name: Build & run visual/interaction tests + runs-on: ubuntu-latest + if: ${{ !github.event.pull_request.draft }} + steps: + - uses: actions/checkout@v4 + with: + # Necessary for Chromatic + fetch-depth: 0 + - uses: ./.github/actions/gh-setup + - name: Build + run: yarn build + - name: Build storybook + run: yarn build:storybook + - name: Run Chromatic (visual and interaction tests) + uses: chromaui/action@latest + with: + workingDir: apps/storybook + projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + exitZeroOnChanges: true + autoAcceptChanges: '{main,next}' diff --git a/.gitignore b/.gitignore index ad866af1e4..5d7b73ea83 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ # Built files dist -build ignore tsc-build +*.tsbuildinfo # Yarn stuff; we're not using PnP/Zero installs .pnp.* @@ -36,3 +36,6 @@ coverage/ # Typescript next-env.d.ts + +# jest/vitest test reports +test-report.xml diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index dd887e014c..0000000000 --- a/.prettierignore +++ /dev/null @@ -1,2 +0,0 @@ -packages/theme/brand/**/* -apps/storefront/tokens diff --git a/.stylelintignore b/.stylelintignore deleted file mode 100644 index b6e9c08f6d..0000000000 --- a/.stylelintignore +++ /dev/null @@ -1,4 +0,0 @@ -**/dist/**/*.css -packages/theme/brand/**/*.css -packages/css/dist/**/*.css -apps/theme/** diff --git a/.stylelintrc.mjs b/.stylelintrc.mjs deleted file mode 100644 index ad14852797..0000000000 --- a/.stylelintrc.mjs +++ /dev/null @@ -1,24 +0,0 @@ -export default { - extends: [ - 'stylelint-config-standard', - 'stylelint-config-css-modules', - // 'stylelint-config-prettier', - ], - // plugins: ['stylelint-prettier'], - rules: { - // 'prettier/prettier': true, - 'declaration-block-no-redundant-longhand-properties': null, - 'media-feature-range-notation': 'prefix', - 'custom-property-pattern': null, - // 'custom-property-pattern': 'fds-.+', // this rule needs to replaced the one above once we have new tokens - 'selector-class-pattern': [ - '(^[a-z][a-zA-Z0-9]+)|([a-z]+)$', - { - severity: 'warning', - message: 'Its recommened to use camelCase or kebab-case', - }, - ], - 'alpha-value-notation': 'number', - 'font-family-name-quotes': 'always-unless-keyword', - }, -}; diff --git a/.vscode/css-data.json b/.vscode/css-data.json new file mode 100644 index 0000000000..642ea02fb6 --- /dev/null +++ b/.vscode/css-data.json @@ -0,0 +1,6 @@ +{ + "version": 1.1, + "atDirectives": [ + { "name": "@composes", "description": "Allows `@composes classname from './file.css'` directive" } + ] +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 2a69d57907..e408fa0294 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,12 +1,9 @@ { "recommendations": [ - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode", "unifiedjs.vscode-mdx", "christian-kohler.npm-intellisense", "techer.open-in-browser", "ionutvmi.path-autocomplete", - "stylelint.vscode-stylelint", "jock.svg", "naumovs.color-highlight", "clinyong.vscode-css-modules", @@ -22,6 +19,7 @@ "editorconfig.editorconfig", "zignd.html-css-class-completion", "streetsidesoftware.code-spell-checker", - "streetsidesoftware.code-spell-checker-norwegian-bokmal" + "streetsidesoftware.code-spell-checker-norwegian-bokmal", + "biomejs.biome" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..01b7bb113f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,38 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch build:tokens:debug", + "request": "launch", + "runtimeArgs": ["build:tokens:debug"], + "runtimeExecutable": "yarn", + "skipFiles": ["/**"], + "type": "node", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + }, + { + "name": "Attach to process", + "type": "node", + "request": "attach", + "port": 9229, + "skipFiles": [ + // Node.js internal core modules + "/**", + + // Ignore all dependencies (optional) + "${workspaceFolder}/node_modules/**" + ] + } + ], + "compounds": [ + { + "name": "Debug build:tokens", + "configurations": ["Launch build:tokens:debug", "Attach to process"], + "stopAll": true + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 89e1fb3e85..b71e719a32 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,28 +1,28 @@ { "git.rebaseWhenSync": true, "git.autofetch": true, - "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true, - "prettier.prettierPath": "./node_modules/prettier", + "editor.codeActionsOnSave": { + "quickfix.biome": "explicit", + "source.organizeImports.biome": "explicit" + }, + "editor.defaultFormatter": "biomejs.biome", + "css.customData": ["./.vscode/css-data.json"], + "[css]": { + "editor.defaultFormatter": "biomejs.biome" + }, "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, - "cssvar.files": ["packages/theme/brand/digdir/tokens.css"], - "[ignore]": { - "editor.defaultFormatter": "foxundermoon.shell-format" - }, - "eslint.probe": [ - "javascript", - "javascriptreact", - "typescript", - "typescriptreact", - "html", - "vue", - "markdown", - "mdx" + "cssvar.files": [ + "packages/theme/brand/digdir/color-mode/light.css", + "packages/theme/brand/digdir/typography/primary.css", + "packages/theme/brand/digdir/semantic.css" ], "html-css-class-completion.includeGlobPattern": "packages/css/**/*.{css,html}", - "cSpell.words": ["altinn", "brreg", "designsystemet", "digdir"], - "cSpell.language": "en,nb", - "cSpell.ignorePaths": ["**/node_modules/**", "**/package.json", "yarn.lock"], - "cSpell.enabledLanguageIds": ["markdown", "plaintext"] + "[github-actions-workflow]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[html]": { + "editor.defaultFormatter": "biomejs.biome" + } } diff --git a/.yarn/patches/@storybook-addon-a11y-npm-8.3.4-1c07bc384c.patch b/.yarn/patches/@storybook-addon-a11y-npm-8.3.4-1c07bc384c.patch new file mode 100644 index 0000000000..98cf5abcc4 --- /dev/null +++ b/.yarn/patches/@storybook-addon-a11y-npm-8.3.4-1c07bc384c.patch @@ -0,0 +1,20 @@ +diff --git a/dist/preview.js b/dist/preview.js +index 2ebc8126dbb113e1d43f39f70f0ef9016b96f53f..9392d52eff52f083ced74c93b68680dc718f741a 100644 +--- a/dist/preview.js ++++ b/dist/preview.js +@@ -3,4 +3,4 @@ + var previewApi = require('storybook/internal/preview-api'); + var global = require('@storybook/global'); + +-var ADDON_ID="storybook/a11y";var RESULT=`${ADDON_ID}/result`,REQUEST=`${ADDON_ID}/request`,RUNNING=`${ADDON_ID}/running`,ERROR=`${ADDON_ID}/error`,MANUAL=`${ADDON_ID}/manual`,EVENTS={RESULT,REQUEST,RUNNING,ERROR,MANUAL};var{document}=global.global,channel=previewApi.addons.getChannel(),active=!1,activeStoryId,defaultParameters={config:{},options:{}},handleRequest=async(storyId,input)=>{input?.manual||await run(storyId,input??defaultParameters);},run=async(storyId,input=defaultParameters)=>{activeStoryId=storyId;try{if(!active){active=!0,channel.emit(EVENTS.RUNNING);let{default:axe}=await import('axe-core'),{element="#storybook-root",config,options={}}=input,htmlElement=document.querySelector(element);if(!htmlElement)return;axe.reset(),config&&axe.configure(config);let result=await axe.run(htmlElement,options),resultJson=JSON.parse(JSON.stringify(result));activeStoryId===storyId?channel.emit(EVENTS.RESULT,resultJson):(active=!1,run(activeStoryId));}}catch(error){channel.emit(EVENTS.ERROR,error);}finally{active=!1;}};channel.on(EVENTS.REQUEST,handleRequest);channel.on(EVENTS.MANUAL,run); ++var ADDON_ID="storybook/a11y";var RESULT=`${ADDON_ID}/result`,REQUEST=`${ADDON_ID}/request`,RUNNING=`${ADDON_ID}/running`,ERROR=`${ADDON_ID}/error`,MANUAL=`${ADDON_ID}/manual`,EVENTS={RESULT,REQUEST,RUNNING,ERROR,MANUAL};var{document}=global.global,channel=previewApi.addons.getChannel(),active=!1,activeStoryId,defaultParameters={config:{},options:{}},handleRequest=async(storyId,input)=>{input?.manual||await run(storyId,input??defaultParameters);},run=async(storyId,input=defaultParameters)=>{activeStoryId=storyId;try{if(!active){active=!0,channel.emit(EVENTS.RUNNING);let{default:axe}=await import('axe-core'),{element="#storybook-root",config,options={}}=input,htmlElement=document.querySelectorAll(element);if(!htmlElement)return;axe.reset(),config&&axe.configure(config);let result=await axe.run(htmlElement,options),resultJson=JSON.parse(JSON.stringify(result));activeStoryId===storyId?channel.emit(EVENTS.RESULT,resultJson):(active=!1,run(activeStoryId));}}catch(error){channel.emit(EVENTS.ERROR,error);}finally{active=!1;}};channel.on(EVENTS.REQUEST,handleRequest);channel.on(EVENTS.MANUAL,run); +diff --git a/dist/preview.mjs b/dist/preview.mjs +index 6e52b1b0b1c137af769e84a59ca32a0e8c91bbb7..dee1c98bfde648dd5f63037f16e954ef69913bb8 100644 +--- a/dist/preview.mjs ++++ b/dist/preview.mjs +@@ -1,4 +1,4 @@ + import { addons } from 'storybook/internal/preview-api'; + import { global } from '@storybook/global'; + +-var ADDON_ID="storybook/a11y";var RESULT=`${ADDON_ID}/result`,REQUEST=`${ADDON_ID}/request`,RUNNING=`${ADDON_ID}/running`,ERROR=`${ADDON_ID}/error`,MANUAL=`${ADDON_ID}/manual`,EVENTS={RESULT,REQUEST,RUNNING,ERROR,MANUAL};var{document}=global,channel=addons.getChannel(),active=!1,activeStoryId,defaultParameters={config:{},options:{}},handleRequest=async(storyId,input)=>{input?.manual||await run(storyId,input??defaultParameters);},run=async(storyId,input=defaultParameters)=>{activeStoryId=storyId;try{if(!active){active=!0,channel.emit(EVENTS.RUNNING);let{default:axe}=await import('axe-core'),{element="#storybook-root",config,options={}}=input,htmlElement=document.querySelector(element);if(!htmlElement)return;axe.reset(),config&&axe.configure(config);let result=await axe.run(htmlElement,options),resultJson=JSON.parse(JSON.stringify(result));activeStoryId===storyId?channel.emit(EVENTS.RESULT,resultJson):(active=!1,run(activeStoryId));}}catch(error){channel.emit(EVENTS.ERROR,error);}finally{active=!1;}};channel.on(EVENTS.REQUEST,handleRequest);channel.on(EVENTS.MANUAL,run); ++var ADDON_ID="storybook/a11y";var RESULT=`${ADDON_ID}/result`,REQUEST=`${ADDON_ID}/request`,RUNNING=`${ADDON_ID}/running`,ERROR=`${ADDON_ID}/error`,MANUAL=`${ADDON_ID}/manual`,EVENTS={RESULT,REQUEST,RUNNING,ERROR,MANUAL};var{document}=global,channel=addons.getChannel(),active=!1,activeStoryId,defaultParameters={config:{},options:{}},handleRequest=async(storyId,input)=>{input?.manual||await run(storyId,input??defaultParameters);},run=async(storyId,input=defaultParameters)=>{activeStoryId=storyId;try{if(!active){active=!0,channel.emit(EVENTS.RUNNING);let{default:axe}=await import('axe-core'),{element="#storybook-root",config,options={}}=input,htmlElement=document.querySelectorAll(element);if(!htmlElement)return;axe.reset(),config&&axe.configure(config);let result=await axe.run(htmlElement,options),resultJson=JSON.parse(JSON.stringify(result));activeStoryId===storyId?channel.emit(EVENTS.RESULT,resultJson):(active=!1,run(activeStoryId));}}catch(error){channel.emit(EVENTS.ERROR,error);}finally{active=!1;}};channel.on(EVENTS.REQUEST,handleRequest);channel.on(EVENTS.MANUAL,run); diff --git a/CODEOWNERS b/CODEOWNERS index 6c128322c7..ee8e13fb19 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @mimarz @Barsnes +* @mimarz @Barsnes @eirikbacker @unekinn diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 190822f208..d256f132a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,16 +12,22 @@ All types of contributions are encouraged and valued. See the [Table of Contents ## Table of Contents -- [Code of Conduct](#code-of-conduct) -- [Share your feedback and report issues](#share-your-feedback-and-report-issues) -- [I Want To Contribute](#i-want-to-contribute) - - [Getting involved with development](#getting-involved-with-development) - - [Getting started with development](#getting-started-with-development) - - [Pull requests](#pull-requests) -- [Styleguides](#styleguides) - - [Commit Messages](#commit-messages) - - [How to write and structure your code](#how-to-write-and-structure-your-code) -- [Publishing NPM packages](#publishing-npm-packages) +- [Contributing to Designsystemet](#contributing-to-designsystemet) + - [Table of Contents](#table-of-contents) + - [Code of Conduct](#code-of-conduct) + - [Share your feedback and report issues](#share-your-feedback-and-report-issues) + - [I Want To Contribute](#i-want-to-contribute) + - [Getting involved with development](#getting-involved-with-development) + - [Addressing minor bugs and handling smaller feature requests](#addressing-minor-bugs-and-handling-smaller-feature-requests) + - [Developing new components and handling larger tasks](#developing-new-components-and-handling-larger-tasks) + - [Getting started with development](#getting-started-with-development) + - [4. Start local development servers](#4-start-local-development-servers) + - [Pull requests](#pull-requests) + - [Styleguides](#styleguides) + - [Commit Messages](#commit-messages) + - [Scope](#scope) + - [Examples:](#examples) + - [When to use what keywords](#when-to-use-what-keywords) --- @@ -76,26 +82,13 @@ Developing components for the design system requires that developers are closely ### Getting started with development -Follow these steps to get up and running with storybook and the storefront. +Follow these steps to get up and running with Storybook or Storefront (designsystemet.no). -Run the commands from the root of your project. - -#### 1. Install Node 16+ and Yarn 3 - -Make sure `node` and `yarn` is installed by running: `node --version && yarn --version` - -#### 2. Install dependencies - -`yarn install` - -This will install all the dependancies. - -#### 3. Build packages +Run the commands from the root of your project. Make sure you clone the `next` branch, this is where we do development. +`yarn` `yarn build` -This is required to make sure dependencies between local packages are available. You only need to run this once. - #### 4. Start local development servers `yarn storybook | storefront` @@ -111,6 +104,7 @@ When creating a pull request for the design system, there are a few things to ke - The pull request title must adhere to the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) standard. - We run linting and formatting checks on all the code. - When you are done with development you can mark the pull request as ready for review by clicking on the button at the bottom. A person from the design system team will then review your code and comment if there are things that need to be changed. Once the pull request is approved it will be merged into the main branch. +- Make sure the PR is pointing to the `next` branch. --- @@ -118,7 +112,7 @@ When creating a pull request for the design system, there are a few things to ke ### Commit Messages -This project uses Lerna with the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) +This project uses Changesets with the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification in order to generate changelogs. The [Semantic Versioning 2.0](https://semver.org/) specification is used for versioning. @@ -141,88 +135,6 @@ To make commit messages and the changelog more specific and readable, you have t It is crucial to understand the distinctions between the two sections mentioned below. If you wish for commit messages to be included in the changelog, please use `fix:` or `feat:` as keywords. These keywords indicate changes that impact the users of our NPM packages and are therefore significant to highlight. For any other types of changes that do not directly affect the end user, please utilize a different keyword. If you are uncertain about which keyword to use and the changes are non-user-facing, you can use `chore:` as a default keyword. -##### Added to changelog - -- `fix:` Patches a bug in the codebase. Nothing new is introduced in terms of functionality. -- `feat:` Introduces a new feature to the codebase. A new component is an often use case. - -##### Not added to changelog - -- `build:` Changes that affect the build system or external dependencies (example scopes: rollup, stylelint, npm) -- `chore:` Other changes that don't modify src or test files -- `docs:` Documentation only changes -- `style:` Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) -- `test:` Adding missing tests or correcting existing tests -- `refactor:` A code change that neither fixes a bug nor adds a feature -- `revert:` Reverts a previous commit -- `perf:` A code change that improves performance - -### How to write and structure your code - -To ensure a consistent and enjoyable coding experience for everyone, we have established guidelines for writing our code. - -#### Styling with CSS Modules - -We use CSS modules to style our components. This prevents naming conflicts by adding a unique prefix to all components. -A CSS module file is created by adding `.module.css` to the end of the CSS file. - -#### Use of design tokens - -When styling our components we try to always use semantic tokens from the `@digdir/designsystemet-theme` package when available. -Using hard-coded values is not reusable and we therefore try to avoid this. -To learn more about what tokens are available visit our [documentation page](https://www.designsystemet.no/grunnleggende/designelementer/design-tokens). - -#### Formatting and linting - -In this project, we employ [Prettier](https://prettier.io/) for code formatting. It is advisable to configure your code editor to automatically format files upon saving. This practice will prove beneficial when merging your changes into the main branch. It's worth noting that we enforce rigorous code checks in pull requests, emphasizing the importance of consistent code formatting. - -TypeScript and CSS files have been configured with linting, which means that the project will scan these files for potential problems or issues. Linting helps maintain code quality by detecting errors, enforcing coding conventions, and promoting best practices. You have to fix all errors and warnings before the code can be merged into the main branch. - -We use [Editorconfig](https://editorconfig.org/) for defining rules and formatting for the IDE. - -#### Use of TypeScript files - -In code contributions for this project, we do not permit JavaScript files. The use of TypeScript ensures the safety and testability of our code. - --- -## Publishing NPM packages - -The following documentation outlines the process for releasing new versions of the NPM packages. Please note that in order to release, you must have an NPM account that is connected to the Digdir organization on NPM. Make sure you are in the `main` branch before proceeding further. Publishing from other branches may lead to issues with the changelog. - -### 1. Build distribution files - -`yarn build` - -Build distribution files for all the packages. Make sure they all run successfully before proceeding to next step. - -### 2. Prepare new version - -`yarn lerna:version` - -This step does a few things: - -- Suggests a new version based on the latest commits. Make sure the version is correct before clicking enter. A user error with a commit message might suggest a version that is wrong. -- Creates a new tag with the latest version number. -- Commits the changes. -- Pushes the changes to github. - -### 3. Make sure you are logged in to NPM - -`npm whoami` - -This command will return if you are logged in or not. - -### 4. Publish to NPM - -`yarn lerna:publish` - -Your account also has to be added to the Digdir organisation on NPM. - -### 5. Paste the latest changelog entry into the design system Slack channel - -You can copy markdown from the changelog in storybook to get nice styling and commit links. - -Please ensure that the appearance closely matches the image below. Consistency plays a vital role when interacting with our end users. - ![te](https://i.imgur.com/Uw0qA1O.png) diff --git a/README.md b/README.md index 97013aa131..ec11c3ffcd 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,6 @@
---- -
## 📖 About Designsystemet @@ -19,31 +17,24 @@ Designsystemet is a collection of important design elements, components and patt Our goal is to create consistent and user-friendly experiences in digital solutions for public services, making them more efficient and reliable. ---- - ## 🔗 Links -[Storybook](https://storybook.designsystemet.no/) - For developing and testing our React components. +[Storybook](https://storybook.designsystemet.no/) - Preview for React components. [Storefront](https://designsystemet.no/) - General documentation about the design system. ---- +[Theme](https://theme.designsystemet.no/) - Theme builder. ## 📦 Packages +[`@digdir/designsystemet`](https://www.npmjs.com/package/@digdir/designsystemet) - CLI for Designsystemet. + [`@digdir/designsystemet-theme`](https://www.npmjs.com/package/@digdir/designsystemet-theme) - Themes for Designsystemet. [`@digdir/designsystemet-css`](https://www.npmjs.com/package/@digdir/designsystemet-css) - Styling for components. [`@digdir/designsystemet-react`](https://www.npmjs.com/package/@digdir/designsystemet-react) - React implementation of Designsystemet components. -### Deprecated - -[`@digdir/design-system-react`](https://www.npmjs.com/package/@digdir/design-system-react) – Replaced by [`@digdir/designsystemet-react`](https://www.npmjs.com/package/@digdir/designsystemet-react). Contains legacy components that are no longer maintained - -[`@digdir/design-system-tokens`](https://www.npmjs.com/package/@digdir/design-system-tokens) – Renamed to [`@digdir/designsystemet-theme`](https://www.npmjs.com/package/@digdir/designsystemet-theme) - ---- ## 🚀 Get started @@ -51,17 +42,25 @@ Follow these steps to get started with the React components. ### 1. Install the packages +Depending on your needs and technology stack install the relevant packages + ```sh -npm i @digdir/designsystemet-react @digdir/designsystemet-theme @digdir/designsystemet-css +npm i @digdir/designsystemet +npm i @digdir/designsystemet-css +npm i @digdir/designsystemet-theme +npm i @digdir/designsystemet-react ``` -#### Typescript +#### 1.1 Custom theme -If you use Typescript, make sure you have typescript >= 3.8 as `devDependencies`: -```sh -npm i typescript --save-dev -``` +You can create your own theme to use with the Designsystemet packages by going to our [theme-builder](https://theme.designsystemet.no/). + +Designsystemet theming is defined using [design-tokens](https://www.uxpin.com/studio/blog/what-are-design-tokens). +This is done so that you can use [Token Studio](https://tokens.studio/) to sync your theme in code with [Designsystemet Figma UI kit](https://www.figma.com/community/file/1322138390374166141/designsystemet-core-ui-kit), in addition to provide future flexibility. + +Run `npx @digdir/designsystemet tokens build` to build CSS files for your custom theme (from the design-tokens). +Using your own built CSS theme file you can skip using the `@digdir/designsystemet-theme` package. ### 2. Font @@ -108,21 +107,9 @@ import { Button } from '@digdir/designsystemet-react'; `@digdir/designsystemet-theme` and `@digdir/designsystemet-css` only needs to be imported once. ---- - ## 🫶 Contributing -Learn how you can contribute to this project by reading our Code of Conduct and Contributing Guide. - -### Code of Conduct - -The [Code of Conduct](./CODE_OF_CONDUCT.md) emphasizes the importance of respectful communication and the avoidance of discrimination, harassment, or any harmful behavior, promoting a positive and diverse community. - -### Contributing Guide - -Our [Contributing Guide](./CONTRIBUTING.md) provides clear instructions on how to participate in the project, ensuring that developers can efficiently contribute their skills and ideas to the community. - ---- +Learn how you can contribute to this project by reading our [Code of Conduct](./CODE_OF_CONDUCT.md) and [Contributing Guide](./CONTRIBUTING.md). ## 💪 Contributors @@ -132,8 +119,9 @@ We are lucky to have a great group of people who help with the design system. ---- +
+
-## 📃 License +Chromatic -Designsystemet is [MIT licensed](./LICENSE). +Thanks to [Chromatic](https://www.chromatic.com/) for providing the visual testing platform that helps us review UI changes and catch visual regressions. diff --git a/apps/_components/package.json b/apps/_components/package.json new file mode 100644 index 0000000000..c5ff28ac76 --- /dev/null +++ b/apps/_components/package.json @@ -0,0 +1,33 @@ +{ + "name": "@repo/components", + "version": "0.0.0", + "private": true, + "author": "Designsystemet team", + "main": "src/index.ts", + "sideEffects": false, + "files": [ + "src/**" + ], + "scripts": { + "types": "tsc --noEmit" + }, + "peerDependencies": { + "react": ">=18.3.1", + "react-dom": ">=18.3.1" + }, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@digdir/designsystemet": "workspace:^", + "@digdir/designsystemet-react": "workspace:^", + "@navikt/aksel-icons": "^6.14.0", + "@types/react-syntax-highlighter": "^15.5.13", + "clsx": "^2.1.1", + "prettier": "^3.3.3", + "react-syntax-highlighter": "^15.5.0" + }, + "devDependencies": { + "typescript": "^5.5.4" + } +} diff --git a/apps/storefront/components/ClipboardBtn/ClipboardBtn.module.css b/apps/_components/src/ClipboardButton/ClipboardButton.module.css similarity index 100% rename from apps/storefront/components/ClipboardBtn/ClipboardBtn.module.css rename to apps/_components/src/ClipboardButton/ClipboardButton.module.css diff --git a/apps/_components/src/ClipboardButton/ClipboardButton.tsx b/apps/_components/src/ClipboardButton/ClipboardButton.tsx new file mode 100644 index 0000000000..d21df7faa1 --- /dev/null +++ b/apps/_components/src/ClipboardButton/ClipboardButton.tsx @@ -0,0 +1,46 @@ +'use client'; +import { Button, Tooltip } from '@digdir/designsystemet-react'; +import { ClipboardIcon } from '@navikt/aksel-icons'; +import { useState } from 'react'; + +import classes from './ClipboardButton.module.css'; + +interface ClipboardButtonProps { + title?: string; + value: string; + text?: string; +} + +export const ClipboardButton = ({ + title = 'Kopier', + value, + text, +}: ClipboardButtonProps) => { + const [toolTipText, setToolTipText] = useState('Kopier'); + + const onBtnClick = (text: string) => { + setToolTipText('Kopiert!'); + navigator.clipboard.writeText(text).catch((reason) => { + throw Error(String(reason)); + }); + }; + + return ( + <> + + + + + ); +}; diff --git a/apps/_components/src/CodeSnippet/CodeSnippet.module.css b/apps/_components/src/CodeSnippet/CodeSnippet.module.css new file mode 100644 index 0000000000..40776471c0 --- /dev/null +++ b/apps/_components/src/CodeSnippet/CodeSnippet.module.css @@ -0,0 +1,18 @@ +.codeSnippet { + position: relative; + max-width: 100%; + overflow-x: auto; + width: 100%; + border-radius: var(--ds-border-radius-md); + height: fit-content; +} + +.codeSnippet > pre { + padding-right: var(--ds-spacing-11) !important; +} + +.copyButton { + position: absolute; + top: var(--ds-spacing-2); + right: var(--ds-spacing-2); +} diff --git a/apps/_components/src/CodeSnippet/CodeSnippet.tsx b/apps/_components/src/CodeSnippet/CodeSnippet.tsx new file mode 100644 index 0000000000..790a7d5da2 --- /dev/null +++ b/apps/_components/src/CodeSnippet/CodeSnippet.tsx @@ -0,0 +1,113 @@ +'use client'; + +import { Button, Tooltip } from '@digdir/designsystemet-react'; +import { FilesIcon } from '@navikt/aksel-icons'; +import * as prettierBabel from 'prettier/parser-babel'; +import * as prettierEstree from 'prettier/plugins/estree'; +import * as prettierHtml from 'prettier/plugins/html.js'; +import * as prettierMarkdown from 'prettier/plugins/markdown.js'; +import * as prettierCSS from 'prettier/plugins/postcss.js'; +import * as prettierTypescript from 'prettier/plugins/typescript.js'; +import { format } from 'prettier/standalone.js'; +import { useEffect, useState } from 'react'; +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { nightOwl } from 'react-syntax-highlighter/dist/esm/styles/prism'; + +import classes from './CodeSnippet.module.css'; + +import cl from 'clsx/lite'; + +const plugins = [ + prettierTypescript, + prettierEstree, + prettierCSS, + prettierMarkdown, + prettierHtml, + prettierBabel, +]; + +type CodeSnippetProps = { + language?: 'css' | 'html' | 'ts' | 'markdown' | 'json'; + syntax?: string; + children: string; +} & React.HTMLAttributes; + +const CodeSnippet = ({ + language = 'markdown', + className, + syntax = 'js', + children, + ...rest +}: CodeSnippetProps) => { + const [toolTipText, setToolTipText] = useState('Kopier'); + const [snippet, setSnippet] = useState(''); + + useEffect(() => { + async function formatSnippet( + children: string, + language: CodeSnippetProps['language'], + ) { + try { + const formatted = await format(children, { + parser: language === 'ts' ? 'babel-ts' : language, + plugins, + }); + setSnippet(formatted); + } catch (error) { + console.error('Failed formatting code snippet:', error); + setSnippet(children); + } + } + void formatSnippet(children, language); + + return () => { + setSnippet(children); + }; + }, [children, language]); + + const onButtonClick = () => { + setToolTipText('Kopiert!'); + navigator.clipboard.writeText(children).catch((reason) => { + throw Error(String(reason)); + }); + }; + + return ( +
+ {snippet && ( + <> + + + + + {snippet} + + + )} +
+ ); +}; + +export { CodeSnippet }; diff --git a/apps/_components/src/ColorModal/ColorModal.module.css b/apps/_components/src/ColorModal/ColorModal.module.css new file mode 100644 index 0000000000..566ec35e78 --- /dev/null +++ b/apps/_components/src/ColorModal/ColorModal.module.css @@ -0,0 +1,133 @@ +.modalContent { + margin-bottom: 16px; + overflow: hidden; +} + +.container { + border: 1px solid var(--ds-color-neutral-border-subtle); + border-radius: 8px; + min-height: 255px; + display: flex; + flex-wrap: wrap; +} + +.left { + width: 50%; + padding: 24px; + display: flex; + flex-direction: column; + gap: 20px; + font-size: 16px; +} + +.right { + width: 50%; + border-left: 1px solid var(--ds-color-neutral-border-subtle); + border-radius: 0 7px 7px 0; +} + +.field { + display: flex; + align-items: center; + height: 24px; +} + +.field:last-child { + margin-bottom: 0; +} + +.label { + font-weight: 500; + margin-right: 12px; +} + +.value { + margin-right: 4px; +} + +.description { + margin-bottom: 24px; + margin-top: -6px; + font-size: 16px; + line-height: 1.5em; + width: 80%; +} + +.accordion { + border: none; + margin-top: 24px; + margin-bottom: 4px; +} + +.accordionContent { + padding-left: 4px; + display: flex; + justify-content: space-between; +} + +.accordionHeading { + border: none; + background-color: transparent; +} + +.accordion button { + padding: 0; +} + +.contrastItem { + display: flex; + align-items: center; + gap: 6px; + font-weight: 500; + font-size: 14px; +} + +.contrastBox { + border-right: 1px solid var(--ds-color-neutral-border-subtle); + margin-right: 24px; + flex-grow: 1; + margin-bottom: -14px; +} + +.contrastBox:last-child { + border-right: none; +} + +.contrastItem svg { + color: #169c00; +} + +.contrastItem .contrastError { + color: #dd4b4b; +} + +.contrastSubTitle { + font-weight: 500; + margin-top: 16px; + margin-bottom: 10px; + font-size: 14px; +} + +.contrastContainer { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 12px; +} + +.contrastContainer:last-child { + margin-bottom: 0; +} + +.apcaHelpText { + height: 18px; + width: 18px; +} + +.contrastTitle { + font-size: 16px; +} + +.contrastItemSubText { + font-weight: 400; +} diff --git a/apps/_components/src/ColorModal/ColorModal.tsx b/apps/_components/src/ColorModal/ColorModal.tsx new file mode 100644 index 0000000000..3953845126 --- /dev/null +++ b/apps/_components/src/ColorModal/ColorModal.tsx @@ -0,0 +1,130 @@ +import { Heading, Modal, Paragraph } from '@digdir/designsystemet-react'; +import type { ColorNumber } from '@digdir/designsystemet/color'; +import { + getColorNameFromNumber, + getCssVariable, + hexToHsluv, +} from '@digdir/designsystemet/color'; +import { ClipboardButton } from '@repo/components'; + +import classes from './ColorModal.module.css'; +import { + capitalizeFirstLetter, + getColorCombinations, + getColorDescription, +} from './colorModalUtils'; + +const Field = ({ + label, + value, + copyBtn = false, +}: { + label: string; + value: string; + copyBtn?: boolean; +}) => { + return ( +
+ {label && ( + + {label} + + )} + + {value} + + {copyBtn && } +
+ ); +}; + +type ColorModalProps = { + colorModalRef: React.RefObject; + hex: string; + namespace: string; + weight: ColorNumber; +}; + +export const ColorModal = ({ + colorModalRef, + hex, + namespace, + weight, +}: ColorModalProps) => { + return ( + + + + + {`${capitalizeFirstLetter(namespace)} ${capitalizeFirstLetter(getColorNameFromNumber(weight))}`} + + + +
+ {getColorDescription({ + weight, + namespace, + })} +
+
+
+ + + + + {weight !== 9 && weight !== 10 && weight !== 11 && ( + + )} +
+
+
+ {/* + + + Vis kontrastgrenser mot relevante farger + + + + + + */} +
+
+
+ ); +}; diff --git a/apps/_components/src/ColorModal/colorModalUtils.ts b/apps/_components/src/ColorModal/colorModalUtils.ts new file mode 100644 index 0000000000..b43c2524cc --- /dev/null +++ b/apps/_components/src/ColorModal/colorModalUtils.ts @@ -0,0 +1,74 @@ +import { + type ColorNumber, + getColorNameFromNumber, +} from '@digdir/designsystemet/color'; + +export const capitalizeFirstLetter = (str: string) => { + return str.charAt(0).toUpperCase() + str.slice(1); +}; + +export const getColorDescription = ({ + weight, + namespace, +}: { + weight: ColorNumber; + namespace: string; +}) => { + let description = `${capitalizeFirstLetter(namespace)} ${capitalizeFirstLetter(getColorNameFromNumber(weight))}`; + + if (weight === 1) { + description += ' er den mest nøytrale bakgrunnsfargen.'; + } else if (weight === 2) { + description += ' er en bakgrunnsfarge som har et hint av farge i seg.'; + } else if (weight === 3) { + description += + ' brukes på flater som ligger oppå bakgrunnsfargene. Fargen brukes for eksempel i Card komponenten til Designsystemet.'; + } else if (weight === 4) { + description += + ' brukes på interaktive flater som ligger oppå bakgrunnsfargene i en hover state.'; + } else if (weight === 5) { + description += + ' brukes på interaktive flater som ligger oppå bakgrunnsfargene i en active state.'; + } else if (weight === 6) { + description += + ' er den lyseste border-fargen og brukes for å skille elementer fra hverandre.'; + } else if (weight === 7) { + description += + ' er en border-farge som brukes når man ønsker god kontrast mot bakgrunnsfargene.'; + } else if (weight === 8) { + description += + ' er den mørkeste border-fargen og brukes når man ønsker en veldig tydelig og sterk border.'; + } else if (weight === 9) { + description += ` fargen får den samme hex koden som fargen som er valgt i verktøyet. Brukes ofte som farge på viktige elementer og på flater som skal fange brukerens oppmerksomhet.`; + } else if (weight === 10) { + description += ` kan brukes som hover farge på elementer som bruker Base Default fargen. `; + } else if (weight === 11) { + description += ` kan brukes som active farge på elementer som bruker Base Default fargen`; + } else if (weight === 12) { + description += + ' er den lyseste tekstfargen og brukes på tekst som skal være litt mindre synlig eller for å skape variasjon i typografien.'; + } else if (weight === 13) { + description += + ' er den mørkeste tekstfargen og brukes på tekst som skal være mest synlig. Denne fargen bør brukes på mesteparten av teksten på en side.'; + } + + return description; +}; + +export const getColorCombinations = (colorNumber: number) => { + let text = ''; + if (colorNumber === 1 || colorNumber === 2) { + text += 'Alle fargene.'; + } else if (colorNumber === 3 || colorNumber === 4 || colorNumber === 5) { + text += 'Background subtle- og Default.'; + } else if (colorNumber === 6) { + text += 'Background fargene og Surface Default.'; + } else if (colorNumber === 7 || colorNumber === 8) { + text += 'Background fargene og Surface Default'; + } else if (colorNumber === 12) { + text += 'Background fargene og Surface Default.'; + } else if (colorNumber === 13) { + text += 'Background- og Surface Fargene.'; + } + return text; +}; diff --git a/apps/_components/src/ColorModal/components/ContrastBoxes.tsx b/apps/_components/src/ColorModal/components/ContrastBoxes.tsx new file mode 100644 index 0000000000..e3097d65f3 --- /dev/null +++ b/apps/_components/src/ColorModal/components/ContrastBoxes.tsx @@ -0,0 +1,163 @@ +import type { CssColor } from '@adobe/leonardo-contrast-colors'; +import { Heading } from '@digdir/designsystemet-react'; +import type { ColorNumber } from '@digdir/designsystemet/color'; +import { + areColorsContrasting, + getApcaContrastLc, +} from '@digdir/designsystemet/color'; +import { + CheckmarkCircleFillIcon, + ExclamationmarkTriangleFillIcon, +} from '@navikt/aksel-icons'; + +import classes from '../ColorModal.module.css'; + +const ContrastItem = ({ + error, + text, + subText, +}: { + text: string; + error: boolean; + subText: string; +}) => { + return ( +
+ {error ? ( + + ) : ( + + )} + {text} {subText} +
+ ); +}; + +const ContrastBox = ({ + title, + selectedColor, + contrastColor, + colorNumber, +}: { + title: string; + selectedColor: string; + contrastColor: CssColor; + colorNumber: ColorNumber; +}) => { + return ( +
+ + {title} + +

WCAG 2

+ {colorNumber !== 12 && colorNumber !== 13 && ( +
+ +
+ )} +
+ +
+
+ +
+ + {(colorNumber === 12 || colorNumber === 13) && ( + <> +

APCA

+
+ +
+ + )} +
+ ); +}; + +// TODO: Disabled due to colorTheme not being defined +// export const ContrastBoxes = ({ +// weight, +// hex, +// }: { +// weight: number; +// hex: string; +// }) => { +// let contrastColors: ColorNumber[] = []; + +// if ( +// weight === 1 || +// weight === 2 || +// weight === 3 || +// weight === 4 || +// weight === 5 +// ) { +// contrastColors = [6, 7, 8, 12, 13]; +// } else if ( +// weight === 6 || +// weight === 7 || +// weight === 8 || +// weight === 9 || +// weight === 10 || +// weight === 11 || +// weight === 12 || +// weight === 13 +// ) { +// contrastColors = [1, 2, 3, 4, 5]; +// } +// return ( +// <> +// {contrastColors.map((colorNumber) => ( +// +// ))} +// +// ); +// }; diff --git a/apps/_components/src/Container/Container.module.css b/apps/_components/src/Container/Container.module.css new file mode 100644 index 0000000000..4ef709ae9d --- /dev/null +++ b/apps/_components/src/Container/Container.module.css @@ -0,0 +1,7 @@ +.container { + max-width: var(--grid-max-width, 1620px); + margin: 0 auto; + width: 100%; + padding-left: var(--grid-padding, 16px); + padding-right: var(--grid-padding, 16px); +} diff --git a/apps/_components/src/Container/Container.tsx b/apps/_components/src/Container/Container.tsx new file mode 100644 index 0000000000..10c9a8eb08 --- /dev/null +++ b/apps/_components/src/Container/Container.tsx @@ -0,0 +1,12 @@ +import cl from 'clsx/lite'; + +import classes from './Container.module.css'; + +type ContainerProps = { + children: React.ReactNode; + className?: string; +}; + +export const Container = ({ children, className }: ContainerProps) => { + return
{children}
; +}; diff --git a/apps/_components/src/Footer/Footer.module.css b/apps/_components/src/Footer/Footer.module.css new file mode 100644 index 0000000000..cecb919a45 --- /dev/null +++ b/apps/_components/src/Footer/Footer.module.css @@ -0,0 +1,95 @@ +.footer { + background-color: var(--ds-color-neutral-background-subtle); + border-top: 1px solid var(--ds-color-neutral-border-default); +} + +.container { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); + gap: var(--ds-spacing-10); +} + +.title { + margin-bottom: var(--ds-spacing-4); +} + +.logos { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--ds-spacing-8); + margin-top: var(--ds-spacing-8); +} + +.links { + margin: 0; + padding: 0; +} + +.links li { + list-style: none; + margin-bottom: var(--ds-spacing-5); +} + +.links li:last-child { + margin-bottom: 0; +} + +.link { + --dsc-link-color--visited: var(--ds-color-neutral-text-default); + + & svg { + max-width: 24px; + + & * { + fill: var(--dsc-link-color); + } + } + + &:focus-visible { + & svg * { + fill: var(--dsc-link-color--focus); + } + } + + &:hover { + & svg * { + fill: var(--dsc-link-color--hover); + } + } + + &:active { + & svg * { + fill: var(--dsc-link-color--active); + } + } +} + +.footer .logos svg { + height: 26px; + width: auto; + margin-right: var(--ds-spacing-2); + + &.udir { + height: 32px; + } +} + +.top { + padding: var(--ds-spacing-18) 0; +} + +.bottom { + background-color: var(--ds-color-neutral-background-default); + padding: var(--ds-spacing-7) 0; +} + +.button { + --dsc-button-color: var(--ds-color-neutral-text-default); + --dsc-button-padding-block: var(--ds-spacing-4); + --dsc-button-padding-inline: var(--ds-spacing-5); + + border: 2px dashed var(--ds-color-neutral-border-strong); + width: fit-content; + margin-top: var(--ds-spacing-8); +} diff --git a/apps/_components/src/Footer/Footer.tsx b/apps/_components/src/Footer/Footer.tsx new file mode 100644 index 0000000000..d3068152bb --- /dev/null +++ b/apps/_components/src/Footer/Footer.tsx @@ -0,0 +1,99 @@ +import { Button, Heading, Link, Paragraph } from '@digdir/designsystemet-react'; +import cl from 'clsx/lite'; +import NextLink from 'next/link'; +import { type ReactNode, forwardRef } from 'react'; +import { Container } from '../'; + +import { Bronnoysund } from '../logos/Bronnoysund'; +import { Digdir } from '../logos/Digdir'; +import { Mattilsynet } from '../logos/Mattilsynet'; +import { Udir } from '../logos/Udir'; +import classes from './Footer.module.css'; + +type LinkListItemProps = { + text: string; + url: string; + prefix?: ReactNode; +}; + +const getCurrentYear = () => { + const date = new Date(); + return date.getFullYear(); +}; + +const LinkList = (links: LinkListItemProps[]) => { + return ( +
    + {links.map((item, index) => ( +
  • + + {item.prefix} + {item.text} + +
  • + ))} +
+ ); +}; + +type FooterProps = { + centerLinks: LinkListItemProps[]; + rightLinks: LinkListItemProps[]; +} & React.HTMLAttributes; + +export const Footer = forwardRef(function Footer( + { centerLinks, rightLinks, className, ...rest }, + ref, +) { + return ( +
+
+ +
+ + Lages på tvers av offentlige etater: + +
+ + + + +
+ +
+
+ + Om nettstedet + + {LinkList(centerLinks)} +
+
+ + Kom i kontakt med oss + + {LinkList(rightLinks)} +
+
+
+
+ + + © {getCurrentYear()} Designsystemet + + +
+
+ ); +}); diff --git a/apps/storefront/components/Footer/index.ts b/apps/_components/src/Footer/index.ts similarity index 100% rename from apps/storefront/components/Footer/index.ts rename to apps/_components/src/Footer/index.ts diff --git a/apps/_components/src/Header/Header.module.css b/apps/_components/src/Header/Header.module.css new file mode 100644 index 0000000000..22f4fc7911 --- /dev/null +++ b/apps/_components/src/Header/Header.module.css @@ -0,0 +1,183 @@ +.header { + height: 106px; + display: flex; + align-items: center; + position: relative; + z-index: 5; + background-color: var(--ds-color-neutral-background-default); + + [data-ds-color-mode='dark'] &, + [data-ds-color-mode='auto'] & { + background-color: var(--ds-color-neutral-background-subtle); + } +} + +.container { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + padding: 0 var(--ds-spacing-8); +} + +.container nav { + display: flex; +} + +.container nav button { + height: fit-content; +} + +.logoContainer { + display: flex; + align-items: center; + gap: var(--ds-spacing-4); +} + +.logo { + height: 34px; + width: auto; +} + +.logoLink svg [data-text] { + fill: var(--ds-color-neutral-text-default); +} + +.logoLink { + display: flex; + align-items: center; +} + +.tag { + background-color: var(--ds-global-purple-5); + border-radius: 4px; + padding: 7px 10px; + font-size: 18px; + font-weight: 500; +} + +.toggle { + display: flex; + border: none; + place-self: flex-end; +} + +.menu { + display: flex; + margin: 0; + padding: 0; + max-width: 100%; + align-items: center; +} + +.item { + list-style: none; + margin-left: var(--ds-spacing-7); +} + +.link { + color: inherit; + text-decoration: none; + border-bottom: 3px solid transparent; + padding-bottom: var(--ds-spacing-2); + transition: 0.1s border-color ease-out; +} + +.link:hover, +.link:focus-visible { + border-color: var(--ds-color-neutral-border-subtle); +} + +.itemIcon { + margin-left: var(--ds-spacing-1); +} + +.firstIcon { + margin-left: var(--ds-spacing-8); +} + +.linkIcon { + display: grid; + place-items: center; + padding: 0 var(--ds-spacing-2); +} + +.linkIcon > svg { + height: 26px; + width: 26px; +} + +.linkIcon.figma path { + stroke: var(--ds-color-neutral-border-strong); +} + +.linkIcon.github path { + fill: var(--ds-color-neutral-border-strong); +} + +.linkIcon.figma:hover path { + stroke: var(--ds-color-neutral-border-strong); +} + +.linkIcon.github:hover path { + fill: var(--ds-color-neutral-border-strong); +} + +.item .active { + border-color: var(--ds-color-neutral-border-strong); + font-weight: 500; +} + +.item .active.link:hover { + border-color: var(--ds-color-neutral-border-strong); +} + +.hamburger { + &.header { + height: 72px; + } + + & nav { + gap: var(--ds-spacing-1); + } + + .menu { + border-top: 1px solid var(--ds-color-neutral-border-subtle); + position: absolute; + z-index: 1; + left: 0; + right: 0; + top: 75px; + background-color: var(--ds-color-neutral-background-default); + box-shadow: var(--ds-shadow-lg); + flex-direction: column; + display: none; + padding: 20px 0; + width: 100%; + } + + .item { + padding: 20px 0; + margin-left: 16px; + } + + .active { + display: block; + } + + .item .active { + display: inline-block; + } + + .linkIcon { + place-items: start; + } + + .logo { + height: 26px; + } +} + +.toggleButton svg { + font-size: 1.75em; +} diff --git a/apps/_components/src/Header/Header.tsx b/apps/_components/src/Header/Header.tsx new file mode 100644 index 0000000000..f1c2c1ba5d --- /dev/null +++ b/apps/_components/src/Header/Header.tsx @@ -0,0 +1,231 @@ +'use client'; +import { + Button, + Paragraph, + SkipLink, + Tooltip, +} from '@digdir/designsystemet-react'; +import { + MenuHamburgerIcon, + MoonIcon, + SunIcon, + XMarkIcon, +} from '@navikt/aksel-icons'; +import cl from 'clsx/lite'; +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; +import { useEffect, useRef, useState } from 'react'; + +import classes from './Header.module.css'; +import { DsLogo } from './logos/ds-logo'; +import { FigmaLogo } from './logos/figma-logo'; +import { GithubLogo } from './logos/github-logo'; + +type HeaderProps = { + menu: { name: string; href: string }[]; + betaTag?: boolean; + skipLink?: boolean; + themeSwitcher?: boolean; +}; + +/** + * Detect if any items have wrapped to a new line + */ +const detectWrap = (items: HTMLCollection) => { + const wrappedItems = []; + let prevItem: DOMRect | null = null; + + for (let i = 0; i < items.length; i++) { + const currItem = items[i].getBoundingClientRect(); + + if (prevItem) { + const prevItemTop = prevItem.bottom; + const currItemTop = currItem.bottom; + + // if current's item top position is different from previous + // that means that the item is wrapped + if (prevItemTop < currItemTop) { + wrappedItems.push(items[i]); + } + } + + prevItem = currItem; + } + + return wrappedItems; +}; + +/** + * Only works in next.js projects + */ +const Header = ({ + menu, + betaTag, + skipLink = true, + themeSwitcher = false, +}: HeaderProps) => { + const [open, setOpen] = useState(false); + const [isHamburger, setIsHamburger] = useState(false); + const menuRef = useRef(null); + const headerRef = useRef(null); + const pathname = usePathname(); + + const [theme, setTheme] = useState('light'); + + const handleThemeChange = (newTheme: 'dark' | 'light') => { + setTheme(newTheme); + document.documentElement.setAttribute('data-ds-color-mode', newTheme); + }; + + useEffect(() => { + if (!themeSwitcher) return; + // get user preference + const userPreference = window.matchMedia('(prefers-color-scheme: dark)'); + const userPrefersDark = userPreference.matches; + + // set theme based on user preference + handleThemeChange(userPrefersDark ? 'dark' : 'light'); + }, []); + + useEffect(() => { + const handleResize = () => { + if (isHamburger) return; + if (menuRef.current && headerRef.current) { + const wrappedItems = detectWrap(menuRef.current.children); + setIsHamburger(wrappedItems.length > 0); + } + }; + + handleResize(); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, [menu, isHamburger]); + + return ( + <> + {skipLink ? ( + Hopp til hovedinnhold + ) : null} +
+
+
+ setOpen(false)} + prefetch={false} + > + + + {betaTag &&
Beta
} +
+ +
+
+ + ); +}; + +export { Header }; diff --git a/apps/_components/src/Header/logos/ds-logo.tsx b/apps/_components/src/Header/logos/ds-logo.tsx new file mode 100644 index 0000000000..9904137157 --- /dev/null +++ b/apps/_components/src/Header/logos/ds-logo.tsx @@ -0,0 +1,50 @@ +type DsLogoProps = React.SVGProps; + +export const DsLogo = ({ ...props }: DsLogoProps) => { + return ( + + + + + + + + ); +}; diff --git a/apps/storefront/components/Header/logos/figma-logo.tsx b/apps/_components/src/Header/logos/figma-logo.tsx similarity index 100% rename from apps/storefront/components/Header/logos/figma-logo.tsx rename to apps/_components/src/Header/logos/figma-logo.tsx diff --git a/apps/storefront/components/Header/logos/github-logo.tsx b/apps/_components/src/Header/logos/github-logo.tsx similarity index 100% rename from apps/storefront/components/Header/logos/github-logo.tsx rename to apps/_components/src/Header/logos/github-logo.tsx diff --git a/apps/_components/src/index.ts b/apps/_components/src/index.ts new file mode 100644 index 0000000000..dd59cc55c5 --- /dev/null +++ b/apps/_components/src/index.ts @@ -0,0 +1,9 @@ +export { CodeSnippet } from './CodeSnippet/CodeSnippet'; +export { Container } from './Container/Container'; +export { ClipboardButton } from './ClipboardButton/ClipboardButton'; +export { ColorModal } from './ColorModal/ColorModal'; +export { Header } from './Header/Header'; +export { Figma } from './logos/Figma'; +export { Github } from './logos/Github'; +export { Slack } from './logos/Slack'; +export { Footer } from './Footer/Footer'; diff --git a/apps/_components/src/logos/Bronnoysund.tsx b/apps/_components/src/logos/Bronnoysund.tsx new file mode 100644 index 0000000000..de356d3071 --- /dev/null +++ b/apps/_components/src/logos/Bronnoysund.tsx @@ -0,0 +1,37 @@ +type BronnoysundProps = React.HTMLAttributes; + +export function Bronnoysund(rest: BronnoysundProps) { + return ( + + Brønnøysund logo + + + + + + + + + ); +} diff --git a/apps/_components/src/logos/Digdir.tsx b/apps/_components/src/logos/Digdir.tsx new file mode 100644 index 0000000000..816783f53a --- /dev/null +++ b/apps/_components/src/logos/Digdir.tsx @@ -0,0 +1,44 @@ +type DigdirProps = React.HTMLAttributes; + +export function Digdir(rest: DigdirProps) { + return ( + + Digitaliseringsdirektoratet logo + + + + + + + + + ); +} diff --git a/apps/_components/src/logos/Figma.tsx b/apps/_components/src/logos/Figma.tsx new file mode 100644 index 0000000000..b8cb9f1daf --- /dev/null +++ b/apps/_components/src/logos/Figma.tsx @@ -0,0 +1,30 @@ +type FigmaProps = React.HTMLAttributes; + +export function Figma(rest: FigmaProps) { + return ( + + + + + + + + + + + + ); +} diff --git a/apps/_components/src/logos/Github.tsx b/apps/_components/src/logos/Github.tsx new file mode 100644 index 0000000000..824c8908e3 --- /dev/null +++ b/apps/_components/src/logos/Github.tsx @@ -0,0 +1,33 @@ +type GithubProps = React.HTMLAttributes; + +export function Github(rest: GithubProps) { + return ( + + + + + + + + + + + ); +} diff --git a/apps/_components/src/logos/Mattilsynet.tsx b/apps/_components/src/logos/Mattilsynet.tsx new file mode 100644 index 0000000000..b5d27a7cb3 --- /dev/null +++ b/apps/_components/src/logos/Mattilsynet.tsx @@ -0,0 +1,13 @@ +type MattilsynetProps = React.HTMLAttributes; + +export function Mattilsynet(rest: MattilsynetProps) { + return ( + + Mattilsynet logo + + + ); +} diff --git a/apps/_components/src/logos/Slack.tsx b/apps/_components/src/logos/Slack.tsx new file mode 100644 index 0000000000..0b16c6d928 --- /dev/null +++ b/apps/_components/src/logos/Slack.tsx @@ -0,0 +1,47 @@ +type SlackProps = React.HTMLAttributes; + +export function Slack(rest: SlackProps) { + return ( + + + + + + + + + + + ); +} diff --git a/apps/_components/src/logos/Udir.tsx b/apps/_components/src/logos/Udir.tsx new file mode 100644 index 0000000000..f2bc095722 --- /dev/null +++ b/apps/_components/src/logos/Udir.tsx @@ -0,0 +1,131 @@ +type UdirProps = React.HTMLAttributes; + +export function Udir(rest: UdirProps) { + return ( + + Utdanningsdirektoratet logo + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} diff --git a/apps/_components/tsconfig.json b/apps/_components/tsconfig.json new file mode 100644 index 0000000000..f6a1bad335 --- /dev/null +++ b/apps/_components/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "./tsc-build", + "declarationDir": "./dist/types", + "emitDeclarationOnly": false, + "composite": false, + "allowSyntheticDefaultImports": true, + "noEmit": false, + "incremental": true, + "moduleResolution": "Bundler" + }, + "include": ["./src", "./stories", "declarations.d.ts"], + "rootDir": "./src" +} diff --git a/apps/dev/.env.local.example b/apps/dev/.env.local.example deleted file mode 100644 index 196a992fbe..0000000000 --- a/apps/dev/.env.local.example +++ /dev/null @@ -1,2 +0,0 @@ -VERCEL_TEAM_ID= -VERCEL_TOKEN= diff --git a/apps/dev/README.md b/apps/dev/README.md deleted file mode 100644 index c4033664f8..0000000000 --- a/apps/dev/README.md +++ /dev/null @@ -1,36 +0,0 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/apps/dev/next.config.js b/apps/dev/next.config.js deleted file mode 100644 index 658404ac69..0000000000 --- a/apps/dev/next.config.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = {}; - -module.exports = nextConfig; diff --git a/apps/dev/package.json b/apps/dev/package.json deleted file mode 100644 index 5cba4d05f7..0000000000 --- a/apps/dev/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "dev", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "building": "next build", - "start": "next start", - "lint": "next lint" - }, - "dependencies": { - "next": "^14.0.4", - "react": "^18.3.1", - "react-dom": "^18.3.1" - }, - "devDependencies": { - "@navikt/aksel-icons": "^5.12.2", - "@types/luxon": "^3.3.7", - "@types/react": "^18.2.45", - "@types/react-dom": "^18.2.18", - "luxon": "^3.4.4", - "normalize.css": "^8.0.1", - "react-countdown-circle-timer": "^3.2.1" - } -} diff --git a/apps/dev/public/img/storefront-logo-white.png b/apps/dev/public/img/storefront-logo-white.png deleted file mode 100644 index f40f82bc49..0000000000 Binary files a/apps/dev/public/img/storefront-logo-white.png and /dev/null differ diff --git a/apps/dev/public/img/storefront-logo.png b/apps/dev/public/img/storefront-logo.png deleted file mode 100644 index d611bd3665..0000000000 Binary files a/apps/dev/public/img/storefront-logo.png and /dev/null differ diff --git a/apps/dev/public/img/storybook-logo.png b/apps/dev/public/img/storybook-logo.png deleted file mode 100644 index e98895ccc1..0000000000 Binary files a/apps/dev/public/img/storybook-logo.png and /dev/null differ diff --git a/apps/dev/public/robots.txt b/apps/dev/public/robots.txt deleted file mode 100644 index 1f53798bb4..0000000000 --- a/apps/dev/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/apps/dev/src/app/api/alias/list/route.ts b/apps/dev/src/app/api/alias/list/route.ts deleted file mode 100644 index c56e12b3a6..0000000000 --- a/apps/dev/src/app/api/alias/list/route.ts +++ /dev/null @@ -1,18 +0,0 @@ -export const dynamic = 'force-dynamic'; - -export async function GET() { - const requestHeaders: HeadersInit = new Headers(); - requestHeaders.set('Content-Type', 'application/json'); - requestHeaders.set('Authorization', 'Bearer ' + process.env.VERCEL_TOKEN); - - const res = await fetch( - 'https://api.vercel.com/v4/aliases?teamId=' + process.env.VERCEL_TEAM_ID, - { - headers: requestHeaders, - next: { revalidate: 0 }, - cache: 'no-store', - }, - ); - const data = (await res.json()) as Promise; - return Response.json(data); -} diff --git a/apps/dev/src/app/favicon.ico b/apps/dev/src/app/favicon.ico deleted file mode 100644 index 30e6093372..0000000000 Binary files a/apps/dev/src/app/favicon.ico and /dev/null differ diff --git a/apps/dev/src/app/globals.css b/apps/dev/src/app/globals.css deleted file mode 100644 index 6f2892b2e2..0000000000 --- a/apps/dev/src/app/globals.css +++ /dev/null @@ -1,24 +0,0 @@ -@import url('https://altinncdn.no/fonts/inter/inter.css'); - -:root { - --color-background-darkest: #121212; - --color-background-darker: #1f1f1f; - --color-background-dark: #2c2c2c; - --color-text: #d1d1d1; - --color-text-subtle: #9c9c9c; - --card-padding: 24px; -} - -body { - background-color: var(--color-background-darkest); - max-width: 1000px; - margin: 0 auto !important; - padding: 0 16px; - font-family: 'Inter', sans-serif; -} - -@media (max-width: 500px) { - :root { - --card-padding: 16px; - } -} diff --git a/apps/dev/src/app/layout.tsx b/apps/dev/src/app/layout.tsx deleted file mode 100644 index 2857426473..0000000000 --- a/apps/dev/src/app/layout.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import 'normalize.css/normalize.css'; -import './globals.css'; - -import type { ReactNode } from 'react'; - -export const metadata = { - title: 'Dev - Designsystemet', -}; - -export default function RootLayout({ children }: { children: ReactNode }) { - return ( - - {children} - - ); -} diff --git a/apps/dev/src/app/page.module.css b/apps/dev/src/app/page.module.css deleted file mode 100644 index 5a13fda855..0000000000 --- a/apps/dev/src/app/page.module.css +++ /dev/null @@ -1,36 +0,0 @@ -.main { - color: var(--color-text); - margin-bottom: 70px; - margin-top: 60px; -} - -.empty { - color: var(--color-text-subtle); - margin-top: -8px; -} - -.mainTitle { - font-weight: 500; - margin-top: 0; - margin-bottom: 52px; - font-size: 28px; - display: flex; - align-items: center; -} - -.subTitle { - font-weight: 500; - font-size: 22px; - margin-bottom: 24px; -} - -.logo { - height: 32px; - margin-right: 14px; -} - -.header { - display: flex; - align-items: start; - justify-content: space-between; -} diff --git a/apps/dev/src/app/page.tsx b/apps/dev/src/app/page.tsx deleted file mode 100644 index ee3d9d3ce3..0000000000 --- a/apps/dev/src/app/page.tsx +++ /dev/null @@ -1,159 +0,0 @@ -'use client'; - -import { useState, useEffect } from 'react'; -import { CountdownCircleTimer } from 'react-countdown-circle-timer'; - -import { PullRequestCard } from '../components/PullRequestCard/PullRequestCard'; -import { Alias } from '../components/Alias/Alias'; -import { getActivePullRequests } from '../services/GithubService'; -import { getAliases } from '../services/VercelService'; -import { SkeletonCard } from '../components/SkeletonCard/SkeletonCard'; -import type { PullRequestType } from '../types/PullRequest'; -import type { AliasType } from '../types/Aliases'; - -import classes from './page.module.css'; - -type CombinedItemType = { - title: string; - PRNumber: number; - PRLink: string; - user: string; - userAvatar: string; - storefront: AliasType[]; - storybook: AliasType[]; -}; - -/** - * Combines pullRequests and aliases to create the output itemm - */ -const combineItemsList = ( - pullRequests: PullRequestType[], - aliases: AliasType[], -) => { - const items = []; - - for (let i = 0; i < pullRequests.length; i++) { - const pullRequest = pullRequests[i]; - const item: CombinedItemType = { - title: pullRequest.title, - PRNumber: pullRequest.number, - PRLink: pullRequest.html_url, - user: pullRequest.user ? pullRequest.user.login : '', - userAvatar: pullRequest.user ? pullRequest.user.avatar_url : '', - storefront: aliases.filter((alias: AliasType) => { - return ( - alias.alias.includes(pullRequest.number.toString()) && - alias.alias.includes('storefront') - ); - }), - storybook: aliases.filter((alias: AliasType) => { - return ( - alias.alias.includes(pullRequest.number.toString()) && - alias.alias.includes('storybook') - ); - }), - }; - items.push(item); - } - return items; -}; - -/** - * Returns the items that are going to be rendered in view - */ -const getItems = async () => { - const aliases: AliasType[] = await getAliases(); - const pullRequests: PullRequestType[] = await getActivePullRequests(); - return combineItemsList(pullRequests, aliases); -}; - -export default function Home() { - const [items, setItems] = useState([]); - const [key, setKey] = useState(0); - - useEffect(() => { - void setItemsAsync(); - }, []); - - /** - * Set the items from the async getItems function - */ - const setItemsAsync = async () => { - setItems(await getItems()); - }; - - return ( -
-
-

- - Designsystemet DEV -

-
- { - void setItemsAsync(); - // This is a technique to reset the timer when it completes - setKey((prevKey) => prevKey + 1); - }} - > -
-
-
-

- Active pull requests and deployments -

- {items.length === 0 && ( - <> - {[1, 2, 3, 4, 5].map((item: number, index: number) => ( - - ))} - - )} - {items.length > 0 && ( -
- {items.map((item: CombinedItemType, index: number) => ( - - {!!item.storybook.length && ( - - )} - {!!item.storefront.length && ( - - )} - {!item.storefront.length && !item.storybook.length && ( -
No deployments found.
- )} -
- ))} -
- )} -
-
- ); -} diff --git a/apps/dev/src/components/Alias/Alias.module.css b/apps/dev/src/components/Alias/Alias.module.css deleted file mode 100644 index f2e1aa55a6..0000000000 --- a/apps/dev/src/components/Alias/Alias.module.css +++ /dev/null @@ -1,63 +0,0 @@ -.card { - display: flex; - align-items: center; - transition: 0.1s all; - color: inherit; - text-decoration: none; - padding: 8px 24px 8px 8px; - margin: -8px 24px -8px -8px; -} - -.card:hover { - background-color: var(--color-background-dark); - border-radius: 4px; - color: white; -} - -.type { - background-color: var(--color-background-dark); - height: 48px; - width: 48px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; -} - -.type img { - height: 26px; - width: 26px; -} - -.textContainer { - display: flex; - flex-direction: column; - margin-left: 14px; -} - -.title { - font-size: 16px; - margin-bottom: 6px; - margin-top: 0; - font-weight: 500; - display: flex; - align-items: center; -} - -.title svg { - color: var(--color-text); - margin-left: 5px; - margin-top: -4px; -} - -.date { - font-size: 14px; - color: var(--color-text-subtle); - display: flex; - align-items: center; - margin-left: -1px; -} - -.date svg { - margin-right: 5px; -} diff --git a/apps/dev/src/components/Alias/Alias.tsx b/apps/dev/src/components/Alias/Alias.tsx deleted file mode 100644 index 15a7e30ce5..0000000000 --- a/apps/dev/src/components/Alias/Alias.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { DateTime } from 'luxon'; -import { ExternalLinkIcon, ClockIcon } from '@navikt/aksel-icons'; - -import classes from './Alias.module.css'; - -type CardProps = { - date: number; - type: 'storefront' | 'storybook'; - alias: string; -}; - -export const Alias = ({ date, type, alias }: CardProps) => { - return ( - -
- -
-
-

- {type === 'storefront' ? 'Storefront' : 'Storybook'} - -

-
- - {DateTime.fromMillis(date).toRelative()} -
-
-
- ); -}; diff --git a/apps/dev/src/components/PullRequestCard/PullRequestCard.module.css b/apps/dev/src/components/PullRequestCard/PullRequestCard.module.css deleted file mode 100644 index c7cd71bb9c..0000000000 --- a/apps/dev/src/components/PullRequestCard/PullRequestCard.module.css +++ /dev/null @@ -1,59 +0,0 @@ -.card { - margin-top: 24px; - background-color: var(--color-background-darker); - color: var(--color-text); - padding: var(--card-padding); -} - -.top { - display: flex; - align-items: start; - justify-content: space-between; - margin-bottom: 10px; -} - -.card h2 { - font-size: 18px; - margin-top: 0; - font-weight: 500; -} - -.content { - display: flex; - align-items: center; - flex-wrap: wrap; - gap: 24px; -} - -.content > * { - margin-right: 48px; -} - -.author { - display: flex; - align-items: center; - color: var(--color-text-subtle); -} - -.avatar { - height: 20px; - width: 20px; - border-radius: 50%; - margin-right: 8px; -} - -.number { - color: var(--color-text-subtle); -} - -.link { - color: inherit; - text-decoration: none; - text-underline-offset: 4px; - transition: 0.1s all; -} - -.link:hover { - text-decoration: underline; - color: white; -} diff --git a/apps/dev/src/components/PullRequestCard/PullRequestCard.tsx b/apps/dev/src/components/PullRequestCard/PullRequestCard.tsx deleted file mode 100644 index af03d39b9f..0000000000 --- a/apps/dev/src/components/PullRequestCard/PullRequestCard.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import type { ReactNode } from 'react'; - -import classes from './PullRequestCard.module.css'; - -type PullRequestCardProps = { - children: ReactNode; - title: string; - user: string; - userAvatar: string; - PRNumber: number; - PRLink: string; -}; - -export const PullRequestCard = ({ - children, - title, - user, - userAvatar, - PRNumber, - PRLink, -}: PullRequestCardProps) => { - return ( -
-
-

- - {title} #{PRNumber} - -

-
- User avatar - {user} -
-
-
{children}
-
- ); -}; diff --git a/apps/dev/src/components/SkeletonCard/SkeletonCard.module.css b/apps/dev/src/components/SkeletonCard/SkeletonCard.module.css deleted file mode 100644 index 70b2e86884..0000000000 --- a/apps/dev/src/components/SkeletonCard/SkeletonCard.module.css +++ /dev/null @@ -1,22 +0,0 @@ -.card { - margin-top: 24px; - background-color: var(--color-background-darker); - color: var(--color-text); - height: 100px; - padding: var(--card-padding); - box-sizing: border-box; - display: flex; - flex-direction: column; - gap: 18px; -} - -.element { - background-color: var(--color-background-dark); - height: 28px; - width: 50%; - border-radius: 4px; -} - -.shortElement { - width: 25%; -} diff --git a/apps/dev/src/components/SkeletonCard/SkeletonCard.tsx b/apps/dev/src/components/SkeletonCard/SkeletonCard.tsx deleted file mode 100644 index 00b9b744ba..0000000000 --- a/apps/dev/src/components/SkeletonCard/SkeletonCard.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import cl from 'clsx'; - -import classes from './SkeletonCard.module.css'; - -export const SkeletonCard = () => { - return ( -
-
-
-
- ); -}; diff --git a/apps/dev/src/services/GithubService.ts b/apps/dev/src/services/GithubService.ts deleted file mode 100644 index c2b5880508..0000000000 --- a/apps/dev/src/services/GithubService.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { PullRequestType } from '../types/PullRequest'; - -export const getActivePullRequests = async () => { - const res: Response = await fetch( - 'https://api.github.com/repos/digdir/designsystem/pulls?sort=updated&direction=desc', - ); - return (await res.json()) as Promise; -}; diff --git a/apps/dev/src/services/VercelService.ts b/apps/dev/src/services/VercelService.ts deleted file mode 100644 index b55ee912f6..0000000000 --- a/apps/dev/src/services/VercelService.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { AliasType } from '../types/Aliases'; - -export const getAliases = async () => { - const res = await fetch('/api/alias/list'); - const aliases = (await res.json()) as Promise<{ aliases: AliasType[] }>; - - const filteredAliases: AliasType[] = (await aliases).aliases.filter( - (item: AliasType) => item.alias.includes('pr'), - ); - - return filteredAliases; -}; diff --git a/apps/dev/src/types/Aliases.ts b/apps/dev/src/types/Aliases.ts deleted file mode 100644 index 31b1199a35..0000000000 --- a/apps/dev/src/types/Aliases.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type AliasType = { - updatedAt: number; - alias: string; -}; diff --git a/apps/dev/src/types/PullRequest.ts b/apps/dev/src/types/PullRequest.ts deleted file mode 100644 index 64aad86211..0000000000 --- a/apps/dev/src/types/PullRequest.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type PullRequestType = { - title: string; - number: number; - html_url: string; - user: { - login: string; - avatar_url: string; - }; -}; diff --git a/apps/dev/tsconfig.json b/apps/dev/tsconfig.json deleted file mode 100644 index cd6257aba9..0000000000 --- a/apps/dev/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./src/*"] - }, - "jsx": "preserve" - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] -} diff --git a/apps/storefront/app/(frontpage)/layout.module.css b/apps/storefront/app/(frontpage)/layout.module.css new file mode 100644 index 0000000000..da1c7af384 --- /dev/null +++ b/apps/storefront/app/(frontpage)/layout.module.css @@ -0,0 +1,148 @@ +.header { + height: 600px; + margin-top: -106px; + position: relative; + margin-bottom: 40px; +} + +.content::before { + content: ''; + background-color: var(--ds-color-neutral-background-subtle); + position: absolute; + z-index: 0; + height: 200vh; + width: 300vw; + left: -100vw; + bottom: 120px; + border-radius: 50%; +} + +.content { + position: relative; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + padding-top: 142px; + padding-bottom: 20px; + overflow-x: hidden; +} + +.text { + width: 550px; + text-align: center; + margin-bottom: 38px; +} + +.container { + display: flex; + align-items: center; + flex-direction: column; + width: 100%; + z-index: 1; +} + +.cards { + display: grid; + grid-row-gap: var(--grid-gap); + grid-column-gap: var(--grid-gap); + grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); + width: 100%; +} + +.betaTag { + background-color: var(--ds-global-purple-5); + display: inline-block; + padding: 3px 12px; + border-radius: 4px; + font-size: 21px; + font-weight: 500; + margin-bottom: 15px; +} + +.cluster { + position: absolute; + z-index: 3; +} + +.cluster1, +.cluster2 { + transform: translateY(0); +} + +.clusterRight { + right: 65px; +} + +.clusterLeft { + left: 65px; +} + +.cluster1 { + top: 220px; + width: 150px; + animation-delay: 0.75s; +} + +.cluster2 { + top: 200px; + width: 142px; +} + +.cluster3 { + top: 1050px; + animation-delay: 1s; + width: 200px; +} + +.cluster4 { + top: 1620px; + height: 150px; +} + +.cluster5 { + top: 2290px; + height: 140px; + transform: rotate(45deg); +} + +.cluster6 { + top: 3080px; + height: 160px; + transform: rotate(45deg); +} + +.banners { + margin: 0; + margin-bottom: 130px; +} + +@keyframes floating { + 0% { + transform: translateY(0); + } + + 50% { + transform: translateY(-25px); + } + + 100% { + transform: translateY(0); + } +} + +@media (max-width: 1700px) { + .cluster { + display: none; + } +} + +@media (max-width: 1199.98px) { + .header { + height: auto; + } + + .text { + width: 100%; + } +} diff --git a/apps/storefront/app/(frontpage)/layout.tsx b/apps/storefront/app/(frontpage)/layout.tsx new file mode 100644 index 0000000000..8d052e7d9d --- /dev/null +++ b/apps/storefront/app/(frontpage)/layout.tsx @@ -0,0 +1,118 @@ +import { Heading } from '@digdir/designsystemet-react'; +import { ComponentIcon, PaletteIcon, WrenchIcon } from '@navikt/aksel-icons'; +import { Container } from '@repo/components'; +import cn from 'clsx/lite'; +import type React from 'react'; + +import { NavigationCard } from '@components'; + +import classes from './layout.module.css'; + +const Layout = ({ children }: { children: React.ReactNode }) => { + return ( +
+
+ + + + + + +
+
+ +
+ {children} +
+ ); +}; + +export default Layout; diff --git a/apps/storefront/app/(frontpage)/page.mdx b/apps/storefront/app/(frontpage)/page.mdx new file mode 100644 index 0000000000..276890a671 --- /dev/null +++ b/apps/storefront/app/(frontpage)/page.mdx @@ -0,0 +1,121 @@ +import { + EnvelopeClosedIcon, + BranchingIcon, + PersonChatIcon, +} from '@navikt/aksel-icons'; + +import { Section, ImageBanner } from '@components'; + +import { BlogCard } from '@blog'; + +export default ({ children }) => <>{children}; + +export const metadata = { + title: 'Velkommen', + description: + 'Her finner du UI-komponenter, retningslinjer og god praksis for effektiv produktutvikling og helhetlige brukeropplevelser.', +}; + + + + + + + +
+ + + +
+ +, + variant: 'primary', + }, + { + text: 'Bidra på GitHub', + href: 'https://github.com/digdir/designsystemet', + prefix: , + }, + { + text: 'Send en epost', + href: 'mailto:designsystem@digdir.no', + prefix: , + }, + ]} +/> + + diff --git a/apps/storefront/app/api/tokens/_route.ts b/apps/storefront/app/api/tokens/_route.ts new file mode 100644 index 0000000000..70ef2e60c8 --- /dev/null +++ b/apps/storefront/app/api/tokens/_route.ts @@ -0,0 +1,31 @@ +import { promises as fs } from 'node:fs'; +import path from 'node:path'; + +import { NextResponse } from 'next/server'; + +type outputObjType = { + [key: string]: string; +}; + +export async function GET() { + //Read the json data file data.json + const tokensDirectory = path.join(process.cwd(), 'tokens'); + const fileContents = await fs.readFile( + tokensDirectory + '/tokens.css', + 'utf8', + ); + const fileContentsArr = fileContents.split(';'); + const outputObj: outputObjType = {}; + + for (let i = 0; i < fileContentsArr.length; i++) { + if (i === 0) { + continue; + } + const itemArr = fileContentsArr[i].split(':'); + outputObj[itemArr[0].replace('\n --', '')] = itemArr[1]; + } + return NextResponse.json({ + status: 200, + body: outputObj, + }); +} diff --git a/apps/storefront/app/bloggen/(frontpage)/layout.module.css b/apps/storefront/app/bloggen/(frontpage)/layout.module.css new file mode 100644 index 0000000000..61169be5c0 --- /dev/null +++ b/apps/storefront/app/bloggen/(frontpage)/layout.module.css @@ -0,0 +1,44 @@ +.page { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + gap: var(--ds-spacing-8); + padding-top: var(--ds-spacing-18) !important; + padding-bottom: var(--page-spacing-bottom) !important; + + [data-ds-color-mode='dark'] &, + [data-ds-color-mode='auto'] & { + background-color: var(--ds-color-neutral-background-default); + } +} + +.main { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: var(--ds-spacing-18); + column-gap: var(--ds-spacing-12); +} + +.main [data-featured='true'] { + grid-column: span 3; +} + +@media screen and (max-width: 1024px) { + .main { + grid-template-columns: 1fr 1fr; + } + + .main [data-featured='true'] { + grid-column: span 2; + } +} + +@media screen and (max-width: 768px) { + .main { + grid-template-columns: 1fr; + } + + .main [data-featured='true'] { + grid-column: span 1; + } +} diff --git a/apps/storefront/app/bloggen/(frontpage)/layout.tsx b/apps/storefront/app/bloggen/(frontpage)/layout.tsx new file mode 100644 index 0000000000..47ea2bef1d --- /dev/null +++ b/apps/storefront/app/bloggen/(frontpage)/layout.tsx @@ -0,0 +1,31 @@ +import { PencilIcon } from '@navikt/aksel-icons'; +import { Container } from '@repo/components'; +import type { Metadata } from 'next'; + +import { Banner, BannerHeading, BannerIcon } from 'components/Banner/Banner'; + +import classes from './layout.module.css'; + +export const metadata: Metadata = { + title: 'Bloggen', +}; + +const Layout = ({ children }: { children: React.ReactNode }) => { + return ( +
+ + + + + Bloggen + + +
+ {children} +
+
+
+ ); +}; + +export default Layout; diff --git a/apps/storefront/app/bloggen/(frontpage)/page.mdx b/apps/storefront/app/bloggen/(frontpage)/page.mdx new file mode 100644 index 0000000000..6b6f26b91f --- /dev/null +++ b/apps/storefront/app/bloggen/(frontpage)/page.mdx @@ -0,0 +1,86 @@ +import { PencilIcon } from '@navikt/aksel-icons'; + +import { BlogCard } from '../_components'; + +export default ({ children }) => <>{children}; + +export const metadata = { + title: 'Bloggen', + description: 'Beskrivelse', +}; + + + + + + + + + + + + + + diff --git a/apps/storefront/app/bloggen/2023/derfor-trenger-vi-et-felles-designsystem/page.mdx b/apps/storefront/app/bloggen/2023/derfor-trenger-vi-et-felles-designsystem/page.mdx new file mode 100644 index 0000000000..95fe8c224b --- /dev/null +++ b/apps/storefront/app/bloggen/2023/derfor-trenger-vi-et-felles-designsystem/page.mdx @@ -0,0 +1,79 @@ +import { ResponsiveIframe, Image } from '@components'; +import { Contributors, PostLayout } from '../../_components'; + +export default ({ children }) => ( + +); + +export const metadata = { + title: 'Derfor trenger vi et felles designsystem', + description: + 'Høsten 2023 arrangerte vi en åpen presentasjon og mini-workshop om felles designsystem. Over 200 deltok og vi fikk 440 tilbakemeldinger på gevinster og utfordringer.', + openGraph: { + images: '/img/bloggen/miro.png', + }, +}; + +Ikke alle klarer å bruke offentlige digitale tjenester på egen hånd. Innsikt fra prosjektet [“Digital hele livet med bedre brukeropplevelse”](https://www.digdir.no/sammenhengende-tjenester/digital-hele-livet-med-bedre-brukeropplevelse/4405) har vist at en av grunnene er at brukskvaliteten i de digitale tjenestene ikke er god nok. Prosjektet var et oppdrag fra regjeringen og ble ledet av Digdir. + +## Høyt engasjement + +I presentasjonen snakket vi om hva vi kan gjøre i fellesskap for å få flere til mestre den digitale dialogen med det offentlige. Vi var innom konkrete utfordringer som gjør at mange faller utenfor i dag, og hva et felles designsystem kan løse. Til slutt inviterte vi alle 220 deltakerne inn i et Miro-brett for å få innsikt i hva andre tenker om et felles designsystem i det offentlige. + +Engasjementet har bekreftet hvor viktig det er at vi utforsker et felles designsystem. I tillegg til mer gjenkjennelige tjenester på tvers, påpeker flere at et felles designsystem vil gjøre det mulig for de mindre etatene og kommunene å lage gode løsninger uten å bruke alle ressursene sine på arbeid som kunne blitt gjort felles. Et felles designsystem vil gjøre det lettere for alle å etterleve krav til universell utforming, da dette er ivaretatt i komponentene. + +Noen er bekymret for at merkevarene forsvinner, mens andre påpeker at de offentlige digitale tjenestene fortsatt kan ha ulike avsenderitdenteter selv om de tar utgangspunkt i samme designsystem. + +[Her kan du se sammenstillingen av Miro-brettet](https://miro.com/app/board/uXjVMnk1ZM4=/?) og alle utfordringene og gevinstene som ble nevnt. + +Skjermdump fra Miro som viser at lappene er omskrevet til ren tekst. + +## Felles designsystem er ikke en ny ide + +Fordelene ved å ha et felles designsystem har vært et tema i mange ulike fora i flere år. For i tillegg til å gjøre tjenestene mer brukervennlige, vil det også bidra til en mer effektiv tjenesteutvikling. I dag utvikler og forvalter vi flere designsystem i offentlig sektor. Ved å samarbeide om et felles designsystem, kan vi både spare penger og få bedre kvalitet. + +– Det er store gevinster av å ha et designsystem. Men det blir kostbart hvis vi ser for oss at ti ulike etater skal ha hvert sitt designsystem og egne ansatte som skal ha ganske like oppgaver. Den byrden det er å investere i et designsystem burde vi ta sammen, sier Roy Halvor Frimanslund, brukskvalitetsansvarlig og Design Lead i Brønnøysundregistrene. + +## Veien videre + +I dag samarbeider allerede Digdir og Brønnøysundregistrene om å etablere et felles designsystem. Møtet viste at det er en rekke andre som ønsker å være med på samarbeidet videre. Nøyaktig hvordan det videre samarbeidet skal være, er noe vi må utforske. + +Opptaket fra presentasjonen kan du se her: + + + +I rapporten [“Digital hele livet med bedre brukeropplevelse”](https://www.digdir.no/sammenhengende-tjenester/digital-hele-livet-med-bedre-brukeropplevelse/4405) kan du lese mer om hva det er som gjør at innbyggere opplever at digitale tjenester er vanskelige å bruke. + + diff --git a/apps/storefront/app/bloggen/2024/altinn-studio/page.mdx b/apps/storefront/app/bloggen/2024/altinn-studio/page.mdx new file mode 100644 index 0000000000..03fbcff76a --- /dev/null +++ b/apps/storefront/app/bloggen/2024/altinn-studio/page.mdx @@ -0,0 +1,143 @@ +import { Card, CardContent } from '@digdir/designsystemet-react'; + +import { Image } from '@components'; +import { Contributors, PostLayout } from '../../_components'; + +export default ({ children }) => ( + +); + +export const metadata = { + title: 'Hvordan Altinn Studio bruker Designsystemet', + description: + 'Altinn Studio benytter seg av Designsystemet ved hjelp av fasademønsteret. Lær mer om hvordan!', + openGraph: { + images: '/img/bloggen/altinnstudio-16-9.png', + }, +}; + +[Altinn Studio](https://altinn.studio/) er et verktøy for å lage digitale tjenester. Bruker du Altinn Studio for å bygge tjenester, bruker du automatisk komponenter fra Designsystemet! + +For at Team Altinn Studio skal nå sine mål om å skape et godt verktøy — må et godt designsystem ligge i bunn. Utviklerne i Altinn Studio trenger komponenter som er tilgjengelig for brukerne på en god måte, men samtidig tillater dem å utvide komponentene til det mer komplekse. + +_"Det er viktig at det er mulig å utvide komponentene til det mer komplekse, fordi alle produkter skal løse et unikt behov i markedet, og ofte vil det forekomme situasjoner hvor mer spesialiserte komponenter er nødvendig. Hvis vi kan utvide eksisterende komponenter fra designsystemet, så vil vi kunne ivareta mye av tilgjengelighetskravene og visuell likhet med de grunnleggende komponentene uten å måtte legge inn for mye innsats."_ + + + David Øvrelid, Tech Lead i Altinn Studio, forklarer hvordan Altinn Studio + bruker Designsystemet. Artikkelen ble først publisert på Medium. [Les den + opprinnelige + artikkelen](https://davidovrelid.com/hvordan-vi-kan-ta-i-bruk-designsystemet-no-p%C3%A5-en-forusigbar-m%C3%A5te-3988980884a2) + +
+
+--- +
+ +Når vi skal ta i bruk en tredjepart, uavhengig om det er designsystemt eller noe annet. Så er det viktig å tenke over noen grunnlegende kjøreregler for å sørge for kvalitet og sikkerhet i din løsning. + +Designsystemet tilbyr en hel rekke av grunnleggende komponenter, som kan utformes i mange varianter. Et eksempel er knappkomponenten (se figur 1). + +Illustrasjonen viser flere knapper i ulike varianter og farger. + +Selv om knappkomponenten kommer i mange varianter betyr ikke det at du og ditt team skal ta i bruk alle variantene. Designsystemet tilbyr disse mulighetene for at det skal være fleksibelt, og kunne tilby deg funksjonalitet som både er ofte brukt men også kjente mønstre. + +_Designsystemet har dokumentasjon på mønstre når de forskjellige variantene skal benyttes. [Se eksempelvis for knappen på denne lenken](https://storybook.designsystemet.no/?path=%2Fdocs%2Fkomponenter-button--docs)._ + +Hvordan skal vi klare å sørge for at et helt team har kontroll på hvilke varianter som skal brukes hvor og når i teamets produkt og hvorfor er det så viktig? Det er først og fremst viktig fordi vi skal utvikle en løsning som er gjennomtenkt og formidler et helhetlig produkt som brukeren forstår. Vi må derfor passe på at samme type arbeidsoppgaver for brukeren løses på akkruat den samme måten, både visuelt og funksjonelt på tvers av produktet. Det betyr også at vi må passe på at det ikke blir en tilfeldig implementasjon og brukeropplevelse utfra hvilken utvikler som har implementert funksjonen, men heller ha godt etablerte konsepter i teamet. + +Så, det betyr at vi må sørge for å ivareta tre viktige hovedpunkter når vi tar i bruk designsystemet. + +1. Vi må kunne etablere våre egne mønstre og konsepter som er tilpasset målgruppen til vårt produkt. Slik at vi sørger for god brukeropplevelse for vår målgruppe, men ivaretar helheten på tvers av produkter ved bruk av designsystemet.no. +2. Vi må sørge for at hele teamet har en trygghet når det gjøres oppdatering av npm-pakken fra designsystemet. +3. Vi må sørge for enkel håndering av Breaking Changes, både for tryggheten — men også for å påse at teamet ikke blir hengende heter på major versjoner. + +Hvordan kan vi ivareta egne mønstre, konsepter, trygghet og breaking changes? Nøkkelordet her er å isolere. Ved å isolere tredjepartssystemer øker vi kontrollen på tredjepartssystemet internt i kodebasen og i teamet. + +Hva er egentlig å isolere en trejdepart? Det handler om å sørge for at vi bare har et integrasjonspunkt med tredjepart. I dette tilfellet handler det om at vi bare har avhengigheter til desginsystemet et sted. Hvordan kan vi oppnå det? Vi kan oppnå det ved å ta i bruk fasademønsteret. + +## Fasademønsteret + +_Fasademønsteret i programvareutvikling refererer til en designmønstre som tillater klienter å kommunisere med komplekse systemer gjennom et forenklet grensesnitt. Det brukes til å skjule kompleksiteten til underliggende systemer og fremme en mer modulær og vedlikeholdbar kodebase._ + +**Altinn Studio benytter seg av designsystemet.no ved hjelp av fasademønsteret.** + +Team Altinn Studio benytter seg av monorepo som betyr at de kan opprette egne pakker internt i sin egen kodebase. Dette fremmer muligheten til å bygge modulær og skalerbar kode. + +Altinn Studio har derfor utviklet sin egen pakke internt i monorepo som de kaller for `studio-components`. Hva er forskjellen på desginsystemet og `studio-components`? Forskjellen er at designsystemet tilbyr et helt desginsystem som inkluderer tokens for farger og avstander, samt grunnleggende komponenter. Mens `studio-components` følger fasademønsteret for å bygge videre på komponentene fra designsystemet, samt tar i bruk tokens fra designsystemet. Med andre ord, så oppnår Altinn Studio isolering av designsystemt ved bruk av `studio-components`. Det gir også muligheten for teamet å definere sine egne mønstre og komponenter for sine behov. + +_*Er du nysgjerring på `studio-components`? Altinn Studio har dokumentasjon av komponentene på https://components.altinn.studio. I skrivende stund er dokumentasjonen under utvikling og mer informasjon om mønstere og konsepter kommer.*_ + +Her oppnår Team Altinn Studio isolering av designsystemet, samtidig som det åpner for å utvide designsystemet med mer komplekse komponeter for eget behov. Fordelen med å utvide designsystemet er at man ser helheten og kjenner igjen de sammensatte komponentene, fordi den er bygget opp av en eller flere komponenter fra designsystemet. + +Eksempelvis har Altinn Studio behov for en [ExpressionEditor](https://components.altinn.studio/?path=%2Fdocs%2Fforms-studioexpression--docs). Dette er en komponent som blir for spesifikk for designsystemet, så det er ikke hensiktsmessig å la designsystemet utvikle og vedlikeholde denne komponenten. Team Altinn Studio har derfor laget sin egen komponent i `studio-components` som utvider designsystemet ved å ta i burk grunnkomponentene designsystemet tilbyr. Komponenten tar også i bruk de samme tokene for avstasnder og størrelser som benyttes i designsystemet. I figur 3 under, så kan du kjenne igjen helheten fordi de bruker grunnkomponentene i designsystemet som byggeklosser. Kult, ikke sant! + +Illustrasjonen viser eksempel på en sammensatt komponent av flere komponenter fra designsystemet + +**_Designsystemet er utviklet på en slik måte at det er enkelt å ta i bruk og utvide komponentene til de mer komplekse der det er behov._** + +Her ivaretar Team Altinn Studio det første prinsippet med å kunne definere egne mønstre og konsepter for sitt produkt, for å imøtekomme god brukeropplevelse. Dette forenkler også arbeidshverdagen for designere og utviklere på teamet. Fordi de har skapt en gjenbrukbar komponent for alle steder det er nødvendig å redigere en expression. + +## Hvordan ivareta tryggheten? + +La oss gå videre og finne ut hvordan vi kan ivareta tryggheten ved oppdateringer av ny versjon av designsystemet. + +For å oppnå trygghet og sikkerhet ved oppdateringer av tredjepart er det viktig med isolering av tredjeparten. Hvis man ikke isolerer designsystemet må en ha direkte avhengigheter til designsystemet i alle sider og komponenter i appen. Dette betyr at en må innom alle komponenter og sider som benytter seg av en komponent fra designsystemet som får breaking change. Det betyr at vi potensielt kan få hundrevis av filer som er endret, bare fordi man gjorde en oppdatering av designsystemet. Figur 4 under viser en forenklet illustrasjon. Illustrasjonen viser fire sider som benytter seg av en knapp direkte fra designsystemet, altså ingen isolering. Det betyr at dersom knappen får en breaking change, må det endres kode i 4 side-komponenter. I det virklige liv kan det være snakk om endringer i hundevis av komponenter. Dette gjør at man ikke er helt sikker på om alt fungerer som før oppdateringen. + +Illustrasjon som viser direkte avhengigheter til designsystemet + +Hvrdan kan vi løse denne problemstillingen? Helt riktig — vi kan løse det med isolering av komponentene ved hjelp av fasademønsteret. + +Figur 4 illustrerer hvordan vi kan isolere ved hjelp av fasademønsteret. Ved å isolere eksterne kilder i egne fasadekomponenter. Så kan vi eksportere kun de nødvendige egenskapene til selve applikasjonen vår. Når det kommer en breaking change, så trenger vi bare å implementere endringen i fasadekomponenten og beholde det samme API ut til vår egen applikasjon internt. Det betyr at vi får bare en fil å endre istedenfor 4 side-komponenter som vist i figur 4. + +Når vi implementerer fasade-komponenter så er det viktig å sikre gode unit-tester også for fasade-komponentene. Slik at vi er sikre på at komponenten fungerer på akkurat samme måte både før og etter re-implementienrg av breaking changes. + +Når vi isolerer komponentene våre, eliminerer vi behovet for å endre den eksisterende koden i selve applikasjonen vår. Den eneste delen av koden vi må justere er fasadekomponenten. Dette resulterer i at pull requests som inneholder oppdateringer for breaking changes forblir små, samtidig som testene for fasadekomponenten forsikrer oss om at uendret kode fungerer og oppfører seg som før. + + Illustrasjon som viser isolering av designsystemet. Illustrasjonen viser også hvordan man kan håndtere breaking chnage, uten å mått endre de 4 side-komponentene. + +Nå som Team Altinn Studio har oppnådd isolering av sammensatte komponenter, kan frontend-utivklere og designere jobbe tettere sammen mellom det som er teknisk implementert og skissene i Figma. Det vil si at Figma skissene kan gjenspeile komponentnavnene i `studio-components`. + +Nå kan de dokumentere og benytte de samme komponentene og navnene både i Figma og i kode. Det gjør at det blir lettere for teamet å etablere mønstre og gjenbrukbare komponenter som skal løse de samme problemene på tvres av produktet. Nå kan også fasadekomponentene begrense antall varianter av komponenten fra designsystemet, slik at det blir mindre sannsynlig for at varianter som ikke skal brukes blir benyttet. + +**_Altinn Studio kodebasen er åpen kilekode og derfor åpent tilgjengelig for alle. Er du nysgjerrig på studio-components koden, kan du finne koden på denne lenken https://github.com/Altinn/altinn-studio/tree/main/frontend/libs/studio-components._** + +Det er avgjørende å sikre at komponentene som utgjør fasadepakken er enkle. Dette betyr at de kun bør motta informasjon som input-props, basert på denne inputen, levere et forventet resultat tilbake. Det er essensielt at komponentene i fasadepakken ikke foretar API-kall eller har tette koblinger til eksterne tredjeparter. Dette kan føre til redusert gjenbrukbarhet av komponentene. + +## Oppsummering + +Nå har vi lært at vi burde vurdere å isolere tredjeparter som blir brukt som en sentral del av vår egen løsning. Vi har lært at isolering vil skape trygghet og forutsigbarhet. Det vil bidra til å kunne dokumentere og utivkle interne konsepter og mønstre som bygger videre på designsystemet for produktets behov, samtidig som helheten ivaretas. Det vil være med å knytte et enda tettere og bedre samarbeidet mellom design og utvikling. + + diff --git a/apps/storefront/app/bloggen/2024/bachelor-temavelger/page.mdx b/apps/storefront/app/bloggen/2024/bachelor-temavelger/page.mdx new file mode 100644 index 0000000000..aaec2210b6 --- /dev/null +++ b/apps/storefront/app/bloggen/2024/bachelor-temavelger/page.mdx @@ -0,0 +1,59 @@ +import { ResponsiveIframe } from '@components'; +import { Contributors, PostLayout } from '../../_components'; + +export default ({ children }) => ( + +); + +export const metadata = { + title: 'Temabygger som bacheloroppgave', + description: + 'Hvordan kan vi gjøre det enklere å ta i bruk Designsystemet? Det har blitt utforsket i en bacheloroppgave!', + openGraph: { + images: '/img/bloggen/temavelger-front.png', + }, +}; + +Kristian Birkeli, bachelorstudent i Datateknologi ved UiS, har vårsemesteret 2024 gjennomført en bacheloroppgave i samarbeid med Digdir og Designsystemet. + +I oppgaven har Birkeli utforsket hvordan det kan bli enklere å adoptere og ta i bruk Designsystemet. Han har gjennomført en rekke intervjuer med brukere og potensielle brukere av Designsystemet. Gjennom intervjuene har vi fått innsikt i hva som i dag er utfordrende med å ta Designsystemet i bruk, samt hvilke forventninger potensielle brukere har. + +## Temabygger + +En del av oppgaven har vært å utforske og prototype en «Temabygger» med et grafisk brukergrensesnitt som skal gjøre det enklere å se hvordan komponenter fra Designsystemet kan tilpasses den enkeltes avsenderidentitet. Temabyggeren hadde også mulighet for å eksportere valgte verdier til CSS for å gjøre det enklere å komme i gang med å ta designsystemet i bruk. + + + +Ved bruk av verktøyet kan brukerne med få tastetrykk se komponentene fra designsystemet med sine egne farger. + +## Brukertester og videre arbeid + +Brukertesting av prototypen har også vært en viktig del av bacheloroppgaven. Brukertestene, som har vært gjennomført med seks designere og utviklere, har gitt oss verdifull innsikt i hva som skal til for å gjøre designsystemet enklere å adoptere. + +Digdir har allerede tatt innsikten videre i arbeidet med å forbedre token-strukturen og fargesystemet. Gjennom brukertestene kom det blant annet frem at det eksisterende fargesystemet var vanskelig å forstå. `Action`-fargen påvirket kun `Button`-komponenten, men det var forventet at den skulle fungere som en `accent`-farge som påvirket flere skjema-elementer. Med bakgrunn i innsikten har Digdir videre utforsket et helt nytt fargesystem og token-struktur som skal støtte tematisering ytterligere. + +Innsikten viste også at brukerne forventet at verktøyet automatisk skulle ivareta kontrastkrav. Vi jobbet derfor videre med et fargesystem som tar utgangspunkt i organisasjonens brandfarge, samtidig som farger tiltenkt tekst alltid har god nok kontrast mot farger tiltenkt bakgrunner, både for light- og darkmode. + +## Vi takker for samarbeidet + +Vi takker Birkeli for et veldig godt samarbeid gjennom ukentlige møter. Prototypen Birkeli har utviklet, og innsikten som er samlet, er et svært viktig bidrag som gjør at vi nå er bedre rustet til å lande et fargesystem og en token-struktur som er mer fleksibel, lettere å forstå og samtidig ivaretar kontrastkrav. Designsystem-teamet vil jobbe videre med å lage en temabygger for Designsystemet basert på arbeidet Birkeli har startet. + + diff --git a/apps/storefront/app/bloggen/2024/fluid-typography/page.mdx b/apps/storefront/app/bloggen/2024/fluid-typography/page.mdx new file mode 100644 index 0000000000..2c5326b8d3 --- /dev/null +++ b/apps/storefront/app/bloggen/2024/fluid-typography/page.mdx @@ -0,0 +1,94 @@ +import { ResponsiveIframe, Image } from '@components'; +import { Contributors, PostLayout } from '../../_components'; + +export default ({ children }) => ( + +); + +export const metadata = { + title: 'Dynamiske tekst-størrelser og hvorfor vi gikk bort fra det', + description: + 'Det er mulig å bruke dynamiske tekst-størrelser uten breakpoints', + openGraph: { + images: '/img/bloggen/fluid-front.png', + }, +}; + +Ved hjelp av “Fluid typography” kan vi skalere tekststørrelsen gradvis mellom en min og maks-bredde, i stedet for at det blir en brå oppskalering på et spesifikt brekkpunkt. Den lineære funksjonen tilnærmer seg ønsket størrelse jevnt over skjermens bredde. + +Tekststørrelsene øker gradvis fra viewport-bredde 320px helt til det treffer maksbredden på viewporten som er satt til 1360px. En tekst på 16px vil f.eks øke til 18px på den største viewporten. + +Illustrasjonen viser at en 16px tekststørrelser på små skjermer øker gradvis opp til 18px på store skjermer. + +## Fordeler + +- Du slipper å tenke på breakpoints, størrelsen på skriften blir automatisk tilpasset skjermen. +- Når størrelsene ikke justeres på konkrete breakpoints unngår vi at det blir stykkevis og brå oppskaleringer. + +## Ulemper + +- Halve piksler. Figma runder nedover. Noen nettlesere runder oppover, andre nedover. Det gjør at ting ikke ser likt ut i Figma og i nettleseren. +- Du kan føle du har mindre kontroll. +- I Figma kan denne størrelsesendringen kun skje ved bruk av pluginen "Token Studio", når du har aktivert ønsket viewport for din frame. +- Det er ikke gitt at et produkt vil bygge sitt produkt ved hjelp av dynamisk typografi. Dersom noen legger til moduler fra designsystemet i eget grensesnitt vil det ikke samsvare med skaleringen deres. + +
+ +Basert på [ulempene dette medførte](https://github.com/digdir/designsystemet/issues/1444), valgte vi å gå for en [statisk typografi-skala](/grunnleggende/designelementer/typografi#tekststørrelse) som standard for designsystemet. + +## Har du behov for dynamisk typografi? + +Har du behov for å benytte dynamisk typografi, opprett gjerne en [feature request](https://github.com/digdir/designsystemet/issues/new?assignees=&labels=%F0%9F%92%A1feature+request%2Cneeds+prioritization%E2%9D%97%EF%B8%8F&projects=&template=2feature_request.yml), så kan vi vurdere muligheten for å aktivere "Fluid" som et eget sett. + +Størrelsene som ble brukt i den dynamiske skalaen ble generert ved hjelp av [Fluid Typescale Generator](https://fluid-tokenization.vercel.app/) + +| Step | viewport 320px | viewport 1360px | +| :----- | :-------------------- | :-------------------- | +| f-3 | 12.00px / 0.75rem | 12.00px / 0.75rem | +| f-2 | 13.00px / 0.81rem | 13.00px / 0.81rem | +| f-1 | 15.00px / 0.94rem | 16.00px / 1.00rem | +| **f0** | **16.00px / 1.00rem** | **18.00px / 1.13rem** | +| f1 | 18.00px / 1.13rem | 21.00px / 1.31rem | +| f2 | 19.00px / 1.19rem | 24.00px / 1.50rem | +| f3 | 21.00px / 1.31rem | 28.00px / 1.75rem | +| f4 | 23.00px / 1.44rem | 32.00px / 2.00rem | +| f5 | 26.00px / 1.63rem | 38.00px / 2.38rem | +| f6 | 29.00px / 1.81rem | 44.00px / 2.75rem | + +
+ +For å kunne se riktige tekststørrelser i Figma var vi avhengige av å ha installert pluginen [Tokens Studio for Figma](https://docs.tokens.studio/) og bruke denne til å aktivere riktig viewport. Videoen under viser hvordan pluginen ble brukt for å få riktige tekststørrelser for ulike viewports. + + + + diff --git a/apps/storefront/app/bloggen/2024/v1rc1/page.mdx b/apps/storefront/app/bloggen/2024/v1rc1/page.mdx new file mode 100644 index 0000000000..e8d4a4ad4e --- /dev/null +++ b/apps/storefront/app/bloggen/2024/v1rc1/page.mdx @@ -0,0 +1,159 @@ +import { Link } from '@digdir/designsystemet-react'; + +import { PostLayout, Contributors } from '../../_components'; +import { ResponsiveIframe } from '@components'; +import { CodeSnippet } from '@repo/components'; + +export default ({ children }) => ( + +); + +export const metadata = { + title: 'Dette kommer i V1!', + description: + 'Vi nærmer oss den første versjonen av Designsystemet uten betamerke! Versjon 1 skal være mer stabil, mer fleksibel og støtte flerdimensjonal tematisering.', + openGraph: { + images: '/img/bloggen/v1rc1.png', + }, +}; + +Designsystemet har i lengre tid vært i beta. Betaperioden har gitt oss fleksibilitet og mulighet til å eksperimentere, teste den underliggende strukturen og hvordan komponentene fungerer sammen. Samtidig har det vært litt uforutsigbart for dere som har valgt å bruke designsystemet mens det fortsatt var i beta. Nå nærmer vi oss målstreken og har publisert en release candidate av V1! + +## Hva er nytt? + +Versjon 1 skal være mer stabil, mer fleksibel og støtte flerdimensjonal tematisering. + +Her er en kort oppsummering av hva som er nytt: + +- Fargesystem og token-struktur +- Lett å tilpasse til din virksomhet +- Støtte for darkmode og contrastmode +- Design-tokens templat på Github +- Oppdaterte komponenter i React og Figma med nye tokens + +### Nytt fargesystem og token-struktur + +Flere intervjuer og [brukertester](/bloggen/2024/bachelor-temavelger#brukertester-og-videre-arbeid) avdekket at det første fargesystemet ikke løste alle behov. Fargene hadde heller ikke alltid forventet oppførsel, og strukuren var noe tungtvindt å forholde seg til. + +Vi har de siste månedene utforsket et nytt fargesystem og en token-struktur som er mer fleksibel, lettere å forstå og samtidig ivaretar kontrastkrav. Å definere en solid Token-arkitektur med flerdimensjonale temaer krever overraskende mye tankearbeid - inkludert søvnløse netter og tegninger i dusjen. Ikke bare skal tokens fungere som bro mellom design og kode, det skal støtte multibranding og ulike modes (darkmode og contrastmode), og det skal ivareta kontrastkrav mellom farge-tokens tiltenkt tekst og bakgrunner. + +Vi har latt oss inspirere av [USWDS sine "magic numbers](https://designsystem.digital.gov/design-tokens/color/overview/)" for å sikre tilgjengelige fargekombinasjoner fra hvilken som helst fargepalett. Vi har også blitt inspirert av [Radix sitt lineære fargesystem](https://www.radix-ui.com/colors) med tydelige intensjoner for de ulike fargene. For å sikre at en organisasjonene skal kunne bruke sin faktiske brandfarge, har vi valgt å kombinere to tilnærminger til et helt nytt system. I det nye fargesystemet kan både brand-farger ivaretas og kontrastkrav sikres gjennom de lineære fargene som genereres ut fra brand-fargen. Farger beregnet for tekst vil dermed alltid ha god nok kontrast mot bakgrunnsfarger. + +I forbindelse med det nye fargesystemet har vi utviklet et verktøy der du kan teste dine brand-farger og hvordan det påvirker komponentene. Verktøyet er under arbeid, men er mulig å teste allerede nå. 👀 + + + + + theme.designsystemet.no + + +Selv om vi nå har lagt opp til et fargesystem som støtter darkmode og contrastmode, gjenstår det fremdeles litt utforsking før vi er sikre på at genereringen av farger fungerer optimalt. + +#### Action --> Accent + +Et annet forvirrende element med det forrige fargesystemet var `action`-fargen, som kun endret fargen på `Button`-komponenten. `Action` er nå byttet ut med `neutral` og `accent`-farger som påvirker forventede skjemaelementer. + +## Bli med å teste V1 Release Candidate! + +I arbeidet med å bygge et designsystem som skal fungere for mange ulike virksomheter er vi avhengige av tilbakemeldinger. + +Vi ønsker å være trygge på at det nye systemet er godt testet før vi lanserer det som V1. Derfor håper vi at så mange som mulig vil teste og komme med tilbakemeldinger. + +Vi kommer til å jobbe kontinuerlig med mindre forbedringer basert på tilbakemeldinger vi får frem til lansering av V1. Dato for V1 avhenger av tilbakemeldingene vi får. + +### Hva må du gjøre for å ta i bruk den nye arkitekturen? + +For å lett komme i gang som utvikler med Release Candidate av Designsystemet kan installerer følgende med ditt pakkesystem: + +```bash +npm i @digdir/designsystemet-react@next +npm i @digdir/designsystemet-theme@next +npm i @digdir/designsystemet-css@next +``` + +Denne installerer alle tre pakken, og inneholder tokens, CSS og React komponenter. + +#### Fargemodus + +Ønsker du å teste `dark`, `light` eller `contrast` modus kan du legge på data-atributtet `data-ds-color-mode="MODE"`. +Denne kan legges hvor som helst, og endrer alle barn til modusen du har valgt. + + + {`...`} + + +#### Design-tokens templat + +Du kan sjekke ut templatet vi har laget for Designsystemet design-tokens som du han ta i utgangspunkt for kobling mellom Figma og kode ved hjelp av Token Studio. +Veiledninger på hvordan dette skal tas i bruk kommer! + + + github.com/designsystemet/design-tokens + + +#### Migrere fra beta-versjon + +Dersom du har tidligere brukt beta-versjonen av Designsystemet, så har vi laget et migreringsscript for CSS som prøver å fikse alle endringer vi har gjort på variabelnavn. + +Migreringsscriptet kjører automatisk på alle `.css` filer (inkl. undermapper) der du kjører den. Du kan selv bestemme hvilke filer den kjøres på ved å bruke parmeteret [--glob](), f.eks `--glob "./**/*.css"` + +_Merk at du må dobbelsjekke koden din etter scriptet har kjørt_ + +```sh +npx @digdir/designsystemet migrate beta-to-v1 +``` + +## Takk for samarbeidet så langt! + +I tillegg til teamet som jobber daglig med Designsystemet har vi også en veldig viktig gjeng med bidragsytere som bidrar med både kode, innsikt, design og innspill. Tusen takk! + + + +Fikk du ikke med deg demoen 29. mai, kan du se opptaket i videoen over. + + + +Vi skulle gjerne nevnt alle, men du kan finne en full liste av bidragsytere på [Github](https://github.com/digdir/designsystemet/graphs/contributors). diff --git a/apps/storefront/app/bloggen/2024/v1rc2/page.mdx b/apps/storefront/app/bloggen/2024/v1rc2/page.mdx new file mode 100644 index 0000000000..60902153f4 --- /dev/null +++ b/apps/storefront/app/bloggen/2024/v1rc2/page.mdx @@ -0,0 +1,70 @@ +import { Link } from '@digdir/designsystemet-react'; + +import { PostLayout, Contributors } from '../../_components'; +import { ResponsiveIframe, Image } from '@components'; +import { CodeSnippet } from '@repo/components'; + +export default ({ children }) => ( + +); + +export const metadata = { + title: 'Hvor blir det av V1?', + description: + 'En Release Candidate av V1 ble sluppet før sommeren. Etter det har vi fått flere verdifulle tilbakemeldinger fra våre brukere.', + openGraph: { + images: '/img/bloggen/v1rc2.png', + }, +}; + +Som mange av dere vet, har vi jobbet hardt med å utvikle et designsystem som skal fungere for flere ulike aktører. Målet har alltid vært å skape et robust og helhetlig system som er fleksibelt og fremtidsrettet. Etter lansering av "V1 Release Cancidate" har vi fått verdifulle tilbakemeldinger fra dere som har testet systemet. Basert på denne innsikten har vi nådd et veiskille som krever at vi tar noen viktige beslutninger. + +Et av de mest sentrale spørsmålene vi står overfor, er hvordan vi skal strukturere lanseringen av V1. Vi har nå en fullt funksjonell React-pakke, som mange av dere har begynt å bruke i ulike løsninger. Dette er en stor milepæl for oss, og vi har fått positive tilbakemeldinger på at utvikler-opplevelsen med React-komponentene er god. Samtidig har vi også fått klare signaler om at mange av dere har behov for en rammeverk-uavhengig løsning, i første omgang med en uavhengig CSS-pakke. Et godt CSS-rammeverk vil ikke bare styrke React-pakken, men det vil også sikre en mer helhetlig tilnærming til hvordan vi bygger grensesnitt på tvers av ulike teknologier. + +## Potensielle endringer og "breaking changes" +Vi har identifisert at arbeidet med å utvikle et solid CSS-rammeverk vil påvirke de eksisterende React-komponentene. Dette kan til og med kreve noen endringer i komponent-APIet. Det siste vi ønsker er å påføre dere hyppige og unødvendige "breaking changes" i systemet. Derfor vurderer vi nå om det er bedre å samle opp disse endringene og implementere dem samlet i V1, slik at vi reduserer risikoen for breaking changes etter lansering. Dette krever imidlertid at vi tar oss litt mer tid til å ferdigstille React- og CSS-pakken som en helhet. + +Flyt-illustrasjon av Designsystemets produkter og verktøy. + + +## Hvorfor utsetting kan være det riktige valget +Å utsette en lansering er aldri en enkel beslutning, men i dette tilfellet tror vi at det kan være det riktige valget. Ved å utsette lanseringen, får vi tid til å sørge for at Designsystemet inkluderer både React-komponentene og CSS-rammeverket. Dette gir oss muligheten til å levere et mer komplett produkt, som favner flere etater og brukscenario, unngår potensielt unødvendige omskrivinger for dere, og vil være mer brukervennlig og enklere å vedlikeholde i det lange løp. + +Vi forstår at mange av dere ser frem til V1-lanseringen, og vi setter stor pris på tålmodigheten deres. Vi tror at denne utsettelsen vil resultere i et bedre produkt som vil gagne alle brukerne våre på sikt. Vi ønsker å holde dere oppdatert med jevnlige oppdateringer og åpen kommunikasjon gjennom hele prosessen, og vi ser frem til å dele et enda bedre designsystem med dere snart! + +## Din tilbakemelding er viktig +I arbeidet med å bygge et designsystem som skal fungere for mange ulike aktører, er vi helt avhengige av tilbakemeldinger fra dere som faktisk bruker systemet i praksis. For å sikre at det nye systemet er godt testet og klart for lansering, oppfordrer vi så mange som mulig til å teste de nyeste endringene som legges ut i vår `next`-branch (`@next`). Der vil dere finne de siste oppdateringene og nye funksjoner som vi vurderer å inkludere i den endelige lanseringen av V1. [Se siste gjeldende next-versjoner her](https://github.com/digdir/designsystemet/releases). + +Om du har tilbakemeldinger er det kjempefint om du deler dette i [#Designsystemet-kanalen på Slack](https://join.slack.com/t/designsystemet/shared_invite/zt-2438eotl3-a4266Vd2IeqMWO8TBw5PrQ), oppretter [issues i Github](https://github.com/digdir/designsystemet/issues/new/choose), eller sender oss en [epost](mailto:designsystem@digdir.no). + +Din innsats og dine innspill er helt avgjørende for at vi skal kunne levere et designsystem som fungerer optimalt for alle. + +Takk for at dere er med oss på denne reisen – sammen kan vi skape noe virkelig verdifullt! + + + +
diff --git a/apps/storefront/app/bloggen/_components/Card/BlogCard.module.css b/apps/storefront/app/bloggen/_components/Card/BlogCard.module.css new file mode 100644 index 0000000000..2e139e16a6 --- /dev/null +++ b/apps/storefront/app/bloggen/_components/Card/BlogCard.module.css @@ -0,0 +1,46 @@ +.image { + aspect-ratio: 16 / 9; +} + +@media screen and (min-width: 1024px) { + .card[data-featured='true'] { + display: grid; + grid-template-columns: 1fr 1fr; + } + + .card[data-featured='true'] > :last-child { + display: flex; + flex-direction: column; + justify-content: center; + padding: var(--ds-spacing-8) var(--ds-spacing-10); + } +} + +.card { + [data-ds-color-mode='dark'] &, + [data-ds-color-mode='auto'] & { + --dsc-card-background: var(--ds-color-neutral-surface-default); + } +} + +.tag { + margin-bottom: 11px; + padding: 3px 9px; + font-size: 16px; +} + +.meta { + display: flex; + gap: var(--ds-spacing-3); + color: var(--ds-color-neutral-text-subtle); + font-size: 14px !important; +} + +.metaSquare { + width: 7px; + height: 7px; + transform: rotate(45deg); + border-radius: 1px; + background-color: var(--ds-color-brand1-border-subtle); + margin: auto; +} diff --git a/apps/storefront/app/bloggen/_components/Card/BlogCard.tsx b/apps/storefront/app/bloggen/_components/Card/BlogCard.tsx new file mode 100644 index 0000000000..df9cec33da --- /dev/null +++ b/apps/storefront/app/bloggen/_components/Card/BlogCard.tsx @@ -0,0 +1,78 @@ +import { + Card, + CardBlock, + Heading, + Paragraph, + Tag, +} from '@digdir/designsystemet-react'; +import cl from 'clsx/lite'; +import Link from 'next/link'; + +import classes from './BlogCard.module.css'; + +type BlogCardProps = { + title: string; + desc: string; + author?: string; + date?: string; + image: string; + href: string; + featured?: boolean; + tagText?: string; + tagColor?: 'brand1' | 'brand2' | 'brand3'; + level?: 2 | 3; +} & Omit, 'color'>; + +export const BlogCard = ({ + title, + desc, + author, + image, + href, + date, + featured = false, + className, + tagText, + tagColor, + level = 3, + ...props +}: BlogCardProps) => { + return ( + + + + + + {tagText && ( + + {tagText} + + )} + + {title} + + {desc} + + {author || + (date && ( + <> + {date} + {author && ( + <> + + {author} + + )} + + ))} + + + + ); +}; + +export default BlogCard; diff --git a/apps/storefront/app/bloggen/_components/Contributors/Contributors.module.css b/apps/storefront/app/bloggen/_components/Contributors/Contributors.module.css new file mode 100644 index 0000000000..acfb335aef --- /dev/null +++ b/apps/storefront/app/bloggen/_components/Contributors/Contributors.module.css @@ -0,0 +1,61 @@ +.container { + position: relative; + display: flex; + flex-wrap: wrap; + flex-direction: column; + justify-content: center; + align-items: center; + max-width: 640px; + gap: var(--ds-spacing-4); + margin: 0 auto; + margin-top: var(--ds-spacing-18); + padding: var(--ds-spacing-10); + border-radius: var(--ds-border-radius-lg); + border: 1px solid var(--ds-color-neutral-border-subtle); +} + +.container p, +.container h3 { + margin: 0; +} + +.logo { + --height: 70px; + + position: absolute; + display: grid; + place-items: center; + width: var(--height); + height: var(--height); + top: calc(var(--height) / -2); + left: 50%; + transform: translateX(-50%); + background-color: var(--ds-color-neutral-background-default); +} + +.logo .logoImage { + box-shadow: none !important; + width: 50% !important; + height: 50% !important; + margin: 0 !important; + background-color: transparent !important; +} + +.meta { + display: flex; + flex-wrap: wrap; + text-wrap: nowrap; + justify-content: center; + gap: var(--ds-spacing-3); + color: var(--ds-color-neutral-text-subtle); +} + +.metaSquare { + width: 7px; + height: 7px; + transform: rotate(45deg); + border-radius: 1px; + background-color: var(--ds-color-brand1-border-default); + margin: auto 0; + break-after: avoid; +} diff --git a/apps/storefront/app/bloggen/_components/Contributors/Contributors.tsx b/apps/storefront/app/bloggen/_components/Contributors/Contributors.tsx new file mode 100644 index 0000000000..b0059b204a --- /dev/null +++ b/apps/storefront/app/bloggen/_components/Contributors/Contributors.tsx @@ -0,0 +1,33 @@ +import { Heading, Paragraph } from '@digdir/designsystemet-react'; +import { Fragment } from 'react'; + +import classes from './Contributors.module.css'; + +type ContributorsProps = { + authors: string[]; +}; + +export const Contributors = ({ authors }: ContributorsProps) => { + return ( +
+
+ Designsystemet logo +
+ + Bidragsytere + + + {authors?.map((author, index) => ( + + {index !== 0 && } + {author} + + ))} + +
+ ); +}; diff --git a/apps/storefront/layouts/BlogArticleLayout/components/Figures.tsx b/apps/storefront/app/bloggen/_components/Figures.tsx similarity index 100% rename from apps/storefront/layouts/BlogArticleLayout/components/Figures.tsx rename to apps/storefront/app/bloggen/_components/Figures.tsx diff --git a/apps/storefront/app/bloggen/_components/PostLayout/PostLayout.module.css b/apps/storefront/app/bloggen/_components/PostLayout/PostLayout.module.css new file mode 100644 index 0000000000..48e353efb9 --- /dev/null +++ b/apps/storefront/app/bloggen/_components/PostLayout/PostLayout.module.css @@ -0,0 +1,141 @@ +.wrapper { + --figure-y-offset: 500px; + --figure-rotation: 72deg; + + position: relative; + overflow: hidden; +} + +.page { + margin-top: var(--ds-spacing-18); + margin-bottom: var(--page-spacing-bottom); +} + +.intro { + width: 100%; + max-width: 720px; + display: flex; + flex-wrap: wrap; + flex-direction: column; + gap: var(--ds-spacing-5); + text-align: center; + margin: 0 auto; + margin-top: var(--ds-spacing-12); +} + +.ingress { + margin: 0 auto; +} + +.meta { + display: flex; + justify-content: center; + margin-top: var(--ds-spacing-1); + gap: var(--ds-spacing-3); + color: var(--ds-color-neutral-text-subtle); +} + +.metaSquare { + width: 7px; + height: 7px; + transform: rotate(45deg); + border-radius: 1px; + background-color: var(--ds-color-brand1-border-default); + margin: auto 0; +} + +.main { + display: flex; + flex-direction: column; + gap: var(--ds-spacing-18); +} + +.content { + --text-max-width: 640px; + + max-width: var(--text-max-width); + margin: 0 auto; +} + +.content img { + display: block; + width: 860px; + margin: var(--ds-spacing-12) 0; + margin-left: calc((100% - 860px) / 2) !important; + background-color: var(--ds-color-neutral-background-subtle); +} + +.content video, +.content [data-iframe-video] { + display: block; + width: 860px; + margin-left: calc((100% - 860px) / 2) !important; + background-color: var(--ds-color-neutral-background-subtle); +} + +.main > figure { + margin: auto; + width: 100%; +} + +.main > figure img { + width: 100%; +} + +.content:last-child { + margin-bottom: var(--ds-spacing-12); +} + +.wantToWrite { + margin-top: var(--ds-spacing-12); + border-radius: var(--ds-border-radius-lg); + background: var(--ds-color-brand1-surface-default); + color: var(--ds-color-brand1-text-default); + padding: var(--ds-spacing-8); + display: flex; + flex-wrap: wrap; + flex-direction: column; + gap: var(--ds-spacing-4); +} + +.wantToWrite p a { + display: inline-block; + color: inherit; +} + +.wantToWrite p, +.wantToWrite h3 { + margin: 0; +} + +.wantToWrite p a:hover { + color: var(--ds-color-accent-base-hover); +} + +.figure { + position: absolute; + top: calc(var(--figure-y-offset) * var(--number)); + z-index: -1; + transform: rotate(calc(var(--figure-rotation) * var(--number))); +} + +.figure:nth-of-type(2n - 1) { + left: 100px; +} + +.figure:nth-of-type(2n) { + right: 100px; +} + +@media screen and (max-width: 1350px) { + .figure { + display: none; + } +} + +@media screen and (max-width: 860px) { + .content img { + width: 100%; + margin-left: 0 !important; + } +} diff --git a/apps/storefront/app/bloggen/_components/PostLayout/PostLayout.tsx b/apps/storefront/app/bloggen/_components/PostLayout/PostLayout.tsx new file mode 100644 index 0000000000..07cf0b1618 --- /dev/null +++ b/apps/storefront/app/bloggen/_components/PostLayout/PostLayout.tsx @@ -0,0 +1,103 @@ +import { Heading, Link, Paragraph } from '@digdir/designsystemet-react'; +import { Container } from '@repo/components'; +import type * as React from 'react'; + +import { Image, MdxContent } from '../../../../components'; +import { Figures } from '../Figures'; + +import classes from './PostLayout.module.css'; + +type BlogArticleLayoutProps = { + content: React.ReactNode; + heading: string; + ingress: string; + date?: string; + author?: string; + figureCount?: number; + imageSrc: string; + imageAlt: string; + imageCaption: string; +}; + +const FIGURE_COUNT = 4; + +function PostLayout({ + content, + heading, + ingress, + date, + author, + imageSrc, + imageAlt, + imageCaption, + figureCount = FIGURE_COUNT, +}: BlogArticleLayoutProps) { + return ( +
+ + {Array.from({ length: figureCount }).map((_, index) => ( + + ))} +
+
+ + {heading} + + + {ingress} + + + {date} + + {author} + +
+ {imageAlt} + + {content} +
+ + Ønsker du å skrive for bloggen? + + + Ta kontakt med oss på{' '} + + #designsystemet + {' '} + i Slack kanalen vår. + +
+
+
+
+ +
+ ); +} + +export { PostLayout }; diff --git a/apps/storefront/app/bloggen/_components/index.ts b/apps/storefront/app/bloggen/_components/index.ts new file mode 100644 index 0000000000..ddda5345d0 --- /dev/null +++ b/apps/storefront/app/bloggen/_components/index.ts @@ -0,0 +1,4 @@ +export { BlogCard } from './Card/BlogCard'; +export { Contributors } from './Contributors/Contributors'; +export { PostLayout } from './PostLayout/PostLayout'; +export { Figures } from './Figures'; diff --git a/apps/storefront/app/error.tsx b/apps/storefront/app/error.tsx new file mode 100644 index 0000000000..83a5e9c207 --- /dev/null +++ b/apps/storefront/app/error.tsx @@ -0,0 +1,7 @@ +'use client'; + +import { Paragraph } from '@digdir/designsystemet-react'; + +export default function error() { + return En feil har oppstått; +} diff --git a/apps/storefront/app/god-praksis/brukerinnsikt/brukergrupper-som-er-digitalt-sarbare/page.mdx b/apps/storefront/app/god-praksis/brukerinnsikt/brukergrupper-som-er-digitalt-sarbare/page.mdx new file mode 100644 index 0000000000..8249501d4d --- /dev/null +++ b/apps/storefront/app/god-praksis/brukerinnsikt/brukergrupper-som-er-digitalt-sarbare/page.mdx @@ -0,0 +1,64 @@ +import { PageLayout } from '@layouts'; + +export const metadata = { + title: 'Brukergrupper som er digitalt sårbare', + description: + 'Vi har beskrevet seks brukergrupper som er digitalt sårbare. Disse kan brukes som et verktøy i utviklingen av digitale tjenester.', +}; + +export default ({ children }) => ( + +); + +I rapporten [Digital hele livet med bedre brukeropplevelse](https://www.digdir.no/sammenhengende-tjenester/digital-hele-livet-med-bedre-brukeropplevelse/4405) har vi beskrevet seks brukergrupper som er digitalt sårbare. Hvis vi lager tjenester som imøtekommer behovene til disse gruppene, gjør vi det også lettere for alle andre å bruke digitale tjenester. + +Brukergruppene er beskrevet som personas som kan brukes som et verktøy i utviklingen av digitale tjenester. Personas er fiktive beskrivelser av personer som representerer brukergruppene. De er altså ikke et komplett bilde eller en uttømmende liste over behov og livssituasjoner, men en forenkling av virkeligheten. En innbygger kan befinne seg i flere grupper samtidig eller gå inn og ut av brukergrupper. + +## Brukergruppene møter ulike barrierer for digital deltakelse + +I beskrivelsene av personasene kan du også lese om hvilke barrierer for digital deltakelse de ulike gruppene møter. Det er flere ulike barrierer som gjør at folk faller utenfor, og mange rammes av flere av barrierene. Noen faller utenfor fordi de ikke har nok kunnskap om offentlig forvaltning. Andre har svake språkferdigheter, og klarer derfor ikke å finne, forstå og bruke informasjon om rettigheter og plikter. +Andre blir hindret av helse og livssituasjon, og mangler et nettverk som kan hjelpe dem. I tillegg påvirkes motivasjonen for å løse digitale oppgaver av troen på mestring og selvtillit. Til sist blir noen hindret av at de ikke har tilgang på internett og utstyr som for eksempel PC. + +## 1. Gerda og Kåre - eldre ektepar der en må ta over alt + +Gerda og Kåre representerer de over 65 år. Dette er en veldig stor gruppe, så det er selvsagt store forskjeller innad i gruppen. + +Kåre og Gerda har vært gift i mange år, og er nå pensjonister. Gerda har alltid tatt ansvar for økonomien og digitale oppgaver, men får ikke lenger til det etter et slag. Det betyr at Kåre må overta disse oppgavene. Men hvordan skal han få til det? [Les mer om Kåre og Gerda, gruppen de representerer og hvilke barrierer denne brukergruppen møter.](https://www.digdir.no/klart-sprak/brukergrupper/4658#1_gerda_og_kre__eldre_ektepar_der_en_m_ta_over_alt) + +## 2. Kim - ung som møter forvaltningen for første gang + +Kim representerer unge mellom 16-24 år som har ungdomsskole som høyest fullførte utdanning. + +Kim har vokst opp i et ustabilt hjem og fått lite støtte fra foreldrene. Nå har han flyttet til et nytt sted og blitt arbeidsledig. Derfor trenger han hjelp fra det offentlige, men har lite kunnskap om hvilke rettigheter han har. [Les mer om Kim, gruppen han representerer og hvilke barrierer denne brukergruppen møter.](https://www.digdir.no/klart-sprak/brukergrupper/4658#2_kim__ung_som_mter_forvaltningen_for_frste_gang) + +## 3. Amina - innvandrer og utenfor på alle måter + +Amina representerer ikke-vestlige innvandrerkvinner med svake norskferdigheter. + +Amina har en jobb som krever at hun får mer digital kompetanse, og melder seg derfor på et kurs. Hun trenger blant annet hjelp til å få mannen sin til Norge og til å forstå informasjon fra NAV. [Les mer om Amina, gruppen hun representerer og hvilke barrierer denne brukergruppen møter.](https://www.digdir.no/klart-sprak/brukergrupper/4658#3_amina__innvandrer_og_utenfor_p_alle_mter) + +## 4. Alex - trygdet, alene og skeptisk + +Alex representerer de som står utenfor arbeidslivet. + +Alex ble sykemeldt etter en arbeidsulykke, og skaden gjør at han har svekket konsentrasjon og hukommelse. Han har hatt lite kontakt med offentlig sektor og ikke hatt en jobb som har krevd digital kompetanse. [Les mer om Alex, gruppen han representerer og hvilke barrierer denne brukergruppen møter.](https://www.digdir.no/klart-sprak/brukergrupper/4658#4_alex__trygdet_alene_og_skeptisk) + +## 5. Agne - hjelperen som ikke får hjelpe + +Agne representerer pårørende som vil hjelpe slektninger eller venner som ikke klarer å løse digitale oppgaver på egenhånd. + +Agne må hjelpe moren sin med digitale oppgaver, og har derfor brukt hennes BankID. Da banken får vite det sperrer de BankID. Alternativet er å bli verge, men det trenger ikke moren til Agne. [Les mer om Agne, gruppen han representerer og hvilke barrierer denne brukergruppen møter.](https://www.digdir.no/klart-sprak/brukergrupper/4658#5_agne__hjelperen_som_ikke_fr_hjelpe) + +## 6. Mika - vergen som ikke får gjort jobben sin + +Mika representerer verger. +Mika er verge for 15 personer med ulikt behov for hjelp. Han møter på mange problemer, spesielt med den digitale diaogen han ønsker å ha på vegne av de han er verge for. [Les mer om MIka, gruppen han representerer og hvilke barrierer denne brukergruppen møter.](https://www.digdir.no/klart-sprak/brukergrupper/4658#6_mika__vergen_som_ikke_fr_gjort_jobben_sin) diff --git a/apps/storefront/app/god-praksis/brukerinnsikt/brukerreise-for-din-tjeneste/page.mdx b/apps/storefront/app/god-praksis/brukerinnsikt/brukerreise-for-din-tjeneste/page.mdx new file mode 100644 index 0000000000..8363a62f5a --- /dev/null +++ b/apps/storefront/app/god-praksis/brukerinnsikt/brukerreise-for-din-tjeneste/page.mdx @@ -0,0 +1,35 @@ +import { PageLayout } from '@layouts'; + +export const metadata = { + title: 'Brukerreise for din tjeneste', + description: + 'Tegn opp en brukerreise for de ulike karakterene i møte med virksomheten, før-under-etter.', +}; + +export default ({ children }) => ( + +); + +Å tegne opp opplevelsene og kontaktpunktene gir et overblikk og mulighet til å se relasjonen mellom hvordan tjenestene er bygd opp av hvilke kontaktpunkter og hvordan dette treffer og ikke treffer innbyggeren sin situasjon og behov fra a til å. + +## Øvelse + +Med utgangspunkt i personaen, går denne øvelsen ut å å tegne opp en brukerreise for de ulike karakterene i møte med virksomheten, før-under-etter. Brukerreisen skal gi en oversikt over hva som skjer/hvilken situasjon innbyggeren er i, hvilke kontaktpunkter de møter når og hva er deres opplevelser er av hver t kontaktpunkt og steg i reisen. + +### Personas + +Du kan ta utganspunkt i [de typiske brukergruppene](lenke-brukergrupper) i denne øvelsen, eller i dine egne personas. + +### Mulige produkter + +- Brukerreise-oppsett/mal: Oppsett/mal for å tegne opp opplevelser, kontaktpunkter og vurderinger av det som fungerer bra og ikke. For de som ikke har mulighet til å printe store ark, deles fliser av eks. A4-ark som man kan sette sammen. +- Refleksjonsspørsmål: Eksempelvis vurdere opplevelsene på en skala fra surt fjes til smilefjes, utarbeide forslag til justeringer av brukerreisen for å i større grad imøtekomme behovene. diff --git a/apps/storefront/app/god-praksis/brukerinnsikt/felles-innsiktsbase/page.mdx b/apps/storefront/app/god-praksis/brukerinnsikt/felles-innsiktsbase/page.mdx new file mode 100644 index 0000000000..fc003dbab0 --- /dev/null +++ b/apps/storefront/app/god-praksis/brukerinnsikt/felles-innsiktsbase/page.mdx @@ -0,0 +1,71 @@ +import { PageLayout } from '@layouts'; + +export const metadata = { + title: 'Felles innsiktsbibliotek', + description: 'Åpent innsiktsarbeid på tvers av det offentlige', +}; + +export default ({ children }) => ( + +); + +_"Knowledge is of no value unless you put it into practice"_ - Chekhov + +Hvordan kan vi dele innsikt på tvers i det offentlige? Kan vi gjenbruke hverandres innsiktsarbeid, i stedet for å stadig gjøre de samme undersøkelsene om igjen? + +Seksjon for brukeropplevelse i Digitaliseringsdirektoratet utforsker for tiden en “open-source”-løsning for [innsikt i Github](https://github.com/digdir/innsiktsbibliotek). Visjonen er økt samarbeid på tvers av offentlig sektor, transparens utad og en utviklingsprosess som i større grad bygger på brukerinnsikt, innovasjon og forskning. + +## Utfordringer + +Flere kjenner seg sikkert igjen i disse utfordringene. + +- Kunnskap som forsvinner når rapporter blir lagt i skuffen etter at de er ferdigstilte +- Konsentrasjon av kunnskap hos et fåtall langtidsansatte som må bruke mye tid på å verbalt dele av egen kunnskap om og om igjen +- Begrenset deling og gjenbruk av innsikt på tvers av team, avdelinger og det offentlige +- Høy utviklingstakt i DevOps team der dokumentasjon og deling av funn ikke blir prioritert + +### Modenhet for innsikt + +Forsknings- og innsiktsarbeid heller ofte i en av to retninger: + +1. Generative utforskende studier (generative exploratory research), ofte frikoblet fra dagens løsninger der vi søker dyptgående domeneforståelse for å identifisere mulighetsrom for fremtidige tjenester og løsninger. + +2. Vurderende studier (evaluative research) der vi måler og analyserer, ofte med hensikt å finne riktig løsning på et problem vi allerede er kjent med. Sett i sammenheng hjelper disse ytterpunktene oss å identifisere riktig problem samt å løse problemet på riktig måte. + +Enkelte organisasjoner har allerede oppnådd høy modenhet rundt bruk av innsikt, forskning og innovasjon mens andre har nylig startet på reisen. Det kan ofte kreve store mengder tid og krefter for å bygge kultur og arbeidsmønstre rundt dokumentering, deling og bruk av forskningsdata og innsikt i organisasjonen, noe enkelte er bedre rustet til enn andre. Det vi vet er at det kan være spesielt vanskelig når innsikt blir nedprioritert til fordel for hyppige og korte utviklingsfrister. Eller når gapet mellom innsikt og beslutningstagere blir for stort, der rapporter blir lagt i skuffen uten lovnader om midler og kapasitet til oppfølgning og gjennomføring i etterkant. + +Målet med innsiktsbibiloketet er i første omgang tredelt: + +1. Bidra til økt verdiskaping for organisasjoner med høy modenhet +2. Være et springbrett for aktører som nylig har startet reisen +3. Minske gapet mellom generative langtidsstudier og beslutningstakere på ulike nivå som har ressursene til å handle. Dette gjør vi først og fremst ved å koble innsiktsarbeid på utviklernes arbeidsverktøy og å gjøre arbeidet åpent for alle. + +## Prototype - Innsiksbibliotek + +Innsiktsbibliotektet består av to deler, en samling av github issues og ett tilhørende github prosjekt. + +1. **[Github issues](https://github.com/digdir/innsiktsbibliotek/issues)**\ + Issues muliggjør søk på alt av tekst og tags på tvers av alle issues i tillegg til å filtrere innhold på en mer avansert måte. Denne visningen passer best dersom du leter etter noe helt konkret og har behov for dyptgående søk. +2. **[Github prosjekt](https://github.com/orgs/digdir/projects/19/views/2)**\ + Prosjektet består av en rekke forutbestemte visninger som filtrerer innsikten ut ifra gitte kategorier som STEEPLE + EIF, samt regjeringens digitaliseringsstrategi. Denne visningen passer best til å finne relevant innsikt som er knyttet til forretningsmessige og strategiske gevinster. + +### Registrere egne studier/funn og innsikt + +Dersom du ønsker å dele av egen innsikt i innsiktbiblioteket så har vi satt opp [tre typer skjema som kan fylles ut](https://github.com/digdir/innsiktsbibliotek/issues/new/choose). Vi skiller mellom studier, funn og innsikt der studien beskriver selve datainnhentingen, et funn beskriver en viktig oppdagelse fra studien og innsikt er flere funn sett i sammenheng som forklarer hvorfor noe skjedde. + +Ettersom systemet er på et tidlig prototypstadie og mangler forklarende innholder og guider har vi satt opp [en enkel guide i Miro](https://miro.com/app/board/uXjVM8DHH3o=/?share_link_id=998152182535) som vi håper kan hjelpe deg å komme i gang med å registrere innsikt i innsiktsbiblioteket. + +## Bidra til innsiktsbibilioteket + +Vårt mål er at innsiktsbiblioteket skal eies og modereres i fellesskap på tvers av offentlig sektor. Dersom du ønsker å bidra til å realisere ett felles innsiktsbibliotek på tvers av det offentlige vil vi gjerne høre fra deg. Vi håper også på at alle (kommune, stat, næringsliv, frivillige organisasjoner, innbyggere, mm) gir tilbakemeldinger samt sender inn forslag og ideer til hvordan vi kan gjøre løsningen enda bedre. Opprett gjerne en ny tråd i [Github discussions forumet](https://github.com/digdir/innsiktsbibliotek/discussions) eller kontakt oss på ima@digdir.no og sss@digdir.no. + +Vi har også nylig opprettet en [Github wiki](https://github.com/digdir/innsiktsbibliotek/wiki) der fremtidig dokumentasjon, guider og annet relevant innhold kommer til å ligge og bli oppdatert på veien videre. diff --git a/apps/storefront/app/god-praksis/brukerinnsikt/i-innbyggeren-sine-sko/page.mdx b/apps/storefront/app/god-praksis/brukerinnsikt/i-innbyggeren-sine-sko/page.mdx new file mode 100644 index 0000000000..38960f6fb5 --- /dev/null +++ b/apps/storefront/app/god-praksis/brukerinnsikt/i-innbyggeren-sine-sko/page.mdx @@ -0,0 +1,36 @@ +import { PageLayout } from '@layouts'; + +export const metadata = { + title: 'I innbyggeren sine sko', + description: + 'Sett deg inn i innbyggeren sine opplevelser og situasjon ved å spille ut personaen gjennom et gruppearbeid', +}; + +export default ({ children }) => ( + +); + +Å sette seg inn i innbyggeren sine opplevelser og situasjon er med på å bygge empati og skape en dypere forståelse av situasjonen virksomhetene skal forbedre, som igjen bygger et bedre grunnlag for å utvikle gode løsninger. + +## Øvelse + +Denne øvelsen går ut på å sette seg inn i innbyggeren sine opplevelser og situasjon ved å spille ut personaen gjennom et gruppearbeid. Gruppearbeidet tar for seg oppgaver som er typisk for en designprosess, herunder arbeid med innsikter, idegenerering og testing. Med manuskripter som utgangspunkt, er det opp til hver enkelt å forme og “spille ut ” sin rolle. + +### Personas + +Du kan ta utganspunkt i [de typiske brukergruppene](lenke-brukergrupper) i denne øvelsen, eller i dine egne personas. + +### Mulige produkter + +- Manuskripter: Hver deltaker får hver t sitt manuskript på en persona. Denne inneholder en kor t beskrivelse av personanen (du er ..), videre typiske utsagn (du sier ofte ..), kjepphester (du er opptatt av..) og behov (du trenger..), nok til å forstå hva slags karakter en skal spille ut, men åpen nok til forme den etter eget ønske. +- Designoppgaver: Et sett med oppgaver typisk for en designprosess som går ut på å kartlegge nåsituasjonen, utvikle ideer, teste de og forbedre i omganger, som gruppen arbeider med mens de spiller ut sine karakterer. +- Merch: Navnelapper, figurer eller artefakter som representerer karakteren man er. diff --git a/apps/storefront/app/god-praksis/brukerinnsikt/researchops/page.mdx b/apps/storefront/app/god-praksis/brukerinnsikt/researchops/page.mdx new file mode 100644 index 0000000000..67e9a2940b --- /dev/null +++ b/apps/storefront/app/god-praksis/brukerinnsikt/researchops/page.mdx @@ -0,0 +1,66 @@ +import { PageLayout } from '@layouts'; +import { Contributors } from '@blog'; + +export const metadata = { + title: 'ResearchOps: Nøkkelen til effektiv brukerinnsikt', + description: + 'ResearchOps er en grunnleggende praksis for å strukturere og skalere brukerinnsiktsarbeid. Her får du tre tips for å komme i gang med ResearchOps og prinsipper for beste praksis.', +}; + +export default ({ children }) => ( + +); + +I en stadig mer kompleks digital verden er det avgjørende å forstå brukernes behov og adferd for å utvikle tjenester som møter deres forventninger. Her kommer _ResearchOps_ inn i bildet som en grunnleggende praksis for å strukturere og skalere brukerinnsiktsarbeid. + +I denne artikkelen kommer vi til å presentere tre artikler fra ReOps+ community, samt gi deg tre tips for å komme i gang med ResearchOps og prinsipper for beste praksis. + +## Artikler fra ResearchOps + +- [**De åtte pilarene i brukerinnsikt**](https://uxnorge.no/researchops-de-atte-pilarene-i-brukerinnsikt/) \ +Denne artikkelen gir en grundig forklaring om de åtte pilarene som må være på plass for at brukerinnsikt skal lykkes, uavhengig om det finnes formelle systemer. Den dekker alt fra datainnsamling og analyse til implementering og evaluering, og gir en omfattende forståelse av hva som kreves for å oppnå verdifulle brukerinnsikter. Det er et viktig første skritt før man skalerer og bygger opp innsiktsinfrastrukturen. + +- [**ResearchOps-miljøet i Norge**](https://uxnorge.no/researchops-i-norske-virksomheter/) \ +I denne artikkelen ser vi nærmere på ResearchOps-miljøet i Norge. Vi har snakket med ResearchOps-spesialister og interessenter i virksomheter som NAV, Bekk, Entur, Digdir, Brønnøysundregistrene og Variant. Her deler vi innsikt fra deres erfaringer og diskuterer hvordan ResearchOps har blitt implementert og videreutviklet i disse virksomhetene. + +- [**Hvordan komme i gang med ResearchOps**](https://uxnorge.no/kom-i-gang-med-researchops/) \ +Denne artikkelen gir en praktisk guide til hvordan du kan starte med ResearchOps. Den dekker viktige aspekter som miljø, omfang, rekruttering og administrasjon, data- og organisering av kunnskap, medarbeidere, organisasjonskultur, styring og, ikke minst, verktøy og infrastruktur. Denne artikkelen er en uvurderlig ressurs for alle som ønsker å bygge opp et effektivt ResearchOps-system i sin organisasjon. + +## Tre tips for å komme i gang med ResearchOps +Disse tipsene kommer fra artikkelen [Hvordan komme i gang med ResearchOps](https://uxnorge.no/kom-i-gang-med-researchops/) + +1. **Kartlegg modenhetsnivået i organisasjonen** \ +Det er viktig å forstå hvor moden organisasjonen er når det gjelder innsiktsarbeid. Bruk modeller som "Design Research Maturity Model" for å evaluere nåværende nivå og identifiser hva som må forbedres for å nå neste nivå. Dette gir et realistisk bilde på hva som er oppnåelig og hvilke skritt som bør tas videre. Ta stilling til alle punktene i modellen der grønn representerer det dere allerede gjør, gul er områder dere jobber med, og rød er det dere ikke har. + +2. **Lag en struktur og prosess for Scope** \ +Omfangpilaren er ofte et godt utgangspunkt for å starte med ResearchOps. Vurder hvordan ansatte jobber med innsiktsarbeid, og om det er samsvar mellom prosesser, metoder og implementering av funn fra studier. Lag standardmaler og retningslinjer som kan hjelpe uerfarne innsiktsarbeidere å unngå typiske fallgruver. Sikre at alle dokumenter og ressurser er lett tilgjengelige og enkle å bruke. + +3. **Bygg et solid brukerrekrutteringsteam** \ +Rekruttering og administrasjon av deltakere tar mye tid og ressurser. Et dedikert rekrutteringsteam som forstår innsiktsarbeidets behov kan effektivisere denne prosessen betydelig. Teamet bør håndtere hele prosessen fra utvalg og screening til planlegging og betaling til deltakere, og sikre god kommunikasjon gjennom hele prosessen. + +## Prinsipper for beste praksis +Disse tipsene kommer fra våre deltakere i [ResearchOps i Norge](https://uxnorge.no/researchops-i-norske-virksomheter/) + +- **Tenk utover design:** ResearchOps handler ikke bare om designere, men om alle som arbeider med brukerinnsikt. Det kan være et bindeledd mellom ulike roller i organisasjonen og bidra til å profesjonalisere bruken av kunnskap på tvers av avdelinger og strategiske nivåer. Dette understreker viktigheten av at ResearchOps inkluderer et bredt spekter av fagfolk, ikke bare designere eller innsiktsarbeidere. + +- **Vurder innsiktsnivåer:** Det er viktig å tenke nøye over hvilke typer innsikt som trengs og hvorfor. En god tilnærming til målrettet innsiktsarbeid bør inkludere både taktisk og operativ innsikt, samt utforskende og strategisk innsikt. Å bygge et Research-team som kan lede denne innsatsen og bruke verktøy som "Research Funnel" kan hjelpe med å strukturere innsiktsarbeidet på ulike nivåer. + +- **Del og gjør innsikten nyttig:** Dokumenter all innsikt grundig og del den med relevante interessenter. Sørg for at informasjonen er nyttig og har en konkret innvirkning. Kartlegge effekten av innsikten for å sikre at den blir brukt effektivt på tvers av organisasjonen og bidrar til å nå felles mål. + + + + diff --git a/apps/storefront/app/god-praksis/innholdsarbeid/andre-ressurser/page.mdx b/apps/storefront/app/god-praksis/innholdsarbeid/andre-ressurser/page.mdx new file mode 100644 index 0000000000..07c4b546b0 --- /dev/null +++ b/apps/storefront/app/god-praksis/innholdsarbeid/andre-ressurser/page.mdx @@ -0,0 +1,23 @@ +import { MenuPageLayout } from '@layouts'; + +export const metadata = { + title: 'Andre gode språkressurser', + description: 'Her har vi samlet noen andre gode artikler som angår innhold.', +}; + +export default ({ children }) => ( + +); + +## God praksis - andre ressurser + +- [Innholdsarbeid](https://aksel.nav.no/god-praksis/innholdsarbeid) +- [Brukerinnsikt](https://aksel.nav.no/god-praksis/brukerinnsikt) +- [Universell utforming](https://aksel.nav.no/god-praksis/universell-utforming) +- [Skjemaer](https://aksel.nav.no/god-praksis/skjemaer) diff --git a/apps/storefront/app/god-praksis/innholdsarbeid/begreper/page.mdx b/apps/storefront/app/god-praksis/innholdsarbeid/begreper/page.mdx new file mode 100644 index 0000000000..32ece42e2b --- /dev/null +++ b/apps/storefront/app/god-praksis/innholdsarbeid/begreper/page.mdx @@ -0,0 +1,56 @@ +import { PageLayout } from '@layouts'; +import { Contributors } from '@blog'; + +export const metadata = { + title: 'Begreper', + description: + 'Anbefalinger om felles navn på knapper og navigasjonselementer. ', +}; + +export default ({ children }) => ( + +); + +I Digdir er vi to innholdsdesignere, som skal dekke mange produkter og team. For å bevisstgjøre team på språk, innholdesign og mikrotekster, holder vi kurs om ulike emner knyttet til å lage godt innhold. + +Vi har også startet et arbeid for å standardisere noen språklige ting på tvers. Det gjør vi for at folk som sitter ute i produktteamene skal slippe å lure på hva de skal skrive på en knapp eller i en komponent. + +Denne artikkelen gir anbefalinger om felles navn på knapper og navigasjonselementer. Vi lanserte den i Digdir før sommeren og de ble godt tatt imot. Dette har folk lurt på! Vi håper at anbefalingene kan være nyttig for flere der ute. + +### Hvordan har vi gått frem? + +Vi har søkt og sammenlignet med hva andre virksomheter bruker, der vi har kunnet. Vi har også sjekket definisjoner både på norsk og engelsk. Med disse anbefalingene håper vi at knapper og navigasjonselementer kan bli like på tvers av flere produkter og tjenester. + +Vi tar gjerne imot forslag på andre begreper som det kan være lurt å enes om, slik at de som lager offentlige digitale tjenester kan gi brukerne samstemte innholdselementer fra ett sted til et annet – akkurat som de får samstemte komponenter. + +### Dette er begrepene vi har laget anbefalinger for + + +| Ord | Vi anbefaler | +|---|---| +| Slett/Fjern | Vi anbefaler Slett som knappenavn over alt. Det er for å unngå å ha to begreper for samme handling. Hvis vi trenger å presisere at noe "blir borte permanent" kan vi enten gi en advarsel, eller skrive «Slett permanent» på knappen. Vi har landet på å ikke bruke Fjern. Vi trenger ikke to begreper for samme handling. | +| Neste/Forrige | Vi anbefaler Neste og Forrige på knapper på bokmål, og Neste + Tilbake på nynorsk, hvis man vil unngå Førre. | +| Gå videre/Gå tilbake Gå til (for eksempel innboksen) Til (innboksen) | Kan brukes til brødsmulesti/navlink. På den måten skiller vi mellom neste steg i flyten og handlingen «å bla i mye informasjon». | +| Endre/Rediger | Vi anbefaler Endre. Det er kort og kjent for alle. | +| Lukk | Vi anbefaler Lukk som tekst for å lukke modaler, hvis det trengs noe mer enn x-symbol/ikon. | +| Vis/Skjul | Vi anbefaler Vis og Skjul som tekst i for eksempel i trekkspillister/nedtrekk. Mange bruker kun chevron-symbolet (^) eller pil ned og opp. I lister med mye tekst, der deler av ingressen vises, kan vi vurdere Vis mer og Vis mindre. Mest aktuelt på nettsider. | + +### Tilby kontekst for skjermlesere + +I noen sammenhenger bør vi tilby kontekst for å presisere hva som slettes, lukkes eller endres. For eksempel «Slett søknaden», «Lukk produktoversikt», «Endre profilbilde». De gangene vi ikke viser kontekst, men bare verb, burde kontekst være beskrevet i `aria-label` for skjermlesere. + + \ No newline at end of file diff --git a/apps/storefront/app/god-praksis/innholdsarbeid/skriverad/page.mdx b/apps/storefront/app/god-praksis/innholdsarbeid/skriverad/page.mdx new file mode 100644 index 0000000000..17f00efe9e --- /dev/null +++ b/apps/storefront/app/god-praksis/innholdsarbeid/skriverad/page.mdx @@ -0,0 +1,67 @@ +import { PageLayout } from '@layouts'; + +export const metadata = { + title: 'Slik skriver du kort og tydelig', + description: + 'Retningslinjene skal hjelpe oss til å skrive brukertilpasset, klart og helhetlig.', +}; + +export default ({ children }) => ( + +); + +Komponentene i designsystemet skal fylles med informasjon til brukerne. Når vi gjør det, er det viktig at vi skriver på et klart og korrekt språk som er tilpasset målgruppen. Brukerne skal finne, forstå og gjøre det de kom til tjenesten for å gjøre. + +Her får du noen generelle råd om klarspråk, og lenker videre hvis du vil lese mer om hvordan du kan skrive klart og tydelig. I tillegg er det råd om språk i retningslinjene for de enkelte komponentene i designsystemet. + +## Test på ekte brukere + +Det aller viktigste du kan gjøre for å sikre at brukerne forstår det du skriver, er å brukerteste. Test tidlig og hyppig, og test på ekte brukere. Test ord og begreper. Bruk reell tekst både når du tester tidlige skisser og protyper. [KS har mange gode råd om hvordan du kan teste om brukerne forstår det du skriver](https://www.ks.no/fagomrader/digitalisering/kompetanse-og-verktoy/klarsprak--involver-brukerne-og-mal-effekten/) + +## Slik skriver du kort og tydelig + +Et råd for hvordan du kan skrive tydelig og klart, er ofte også et råd om hvordan du kan skrive kort. La det komme tydelig fram hvem som gjør hva. Tenk at du skriver en samtale. I tillegg er det viktig å skrive konkret, plassere verbene tidlig i setningene og ikke bruke unødvendige substantiver, + +### Hvem som gjør hva må komme tydelig fram + +I digitale tjenester er det viktig at brukerne lett forstår hvem som skal gjøre hva. Regelverk og lover har ofte passivt språk og det har også preget det offentlige språket generelt. Når vi skriver passivt blir det utydelig hvem som gjør hva. + +Derfor skal vi skrive aktivt og som om vi snakker direkte til brukeren. Vi skal bruke ord som “du” og “vi”. + +#### Eksempel + +**Ikke skriv:** Det blir sendt en e-post når søknaden er behandlet. \ +**Skriv heller:** Du får en e-post fra oss når søknaden er behandlet. + +### Unngå substantivsjuken + +Når vi bruker mange substantiver, blir teksten tung å lese og vi bruker flere ord enn nødvendig. Særlig gjelder det når vi gjør et verb om til et substantiv, for eksempel når vi velger å skrive «foreta en utredning» i stedet for å «utrede». Du kan sjekke om teksten er subtantivsjuk ved å se etter ord som slutter på «-ing» og «-else» og har en «av» foran. + +#### Eksempel + +**Ikke skriv:** Vi har foretatt en behandling av søknaden \ +**Skriv heller:** Vi har behandlet søknaden + +### Sett verbet så tidlig som mulig i setningen + +Når språket blir formelt plasserer vi i ofte verbet for langt ut i setningen. Det gjør at du må lese mange ord før du får verbet, og det blir vanskeligere å huske hva som sto tidlig i setningen. + +#### Eksempel + +**Ikke skriv:** Arbeidstaker har en del plikter som må oppfylles \ +**Skriv heller:** Arbeidstaker må oppfylle noen plikter + +### Vil du lese mer om klarspråk? + +[KS har en rekke gode råd om klart språk i digitale løsninger.](https://www.ks.no/fagomrader/digitalisering/klart-sprak-i-digitale-selvbetjeningslosninger/) + +[Les mer om generelle skriveråd fra Språkrådet.](https://www.sprakradet.no/klarsprak/om-skriving/generelle-skriverad-nynorsk/) diff --git a/apps/storefront/app/god-praksis/innholdsarbeid/skumlesing/page.mdx b/apps/storefront/app/god-praksis/innholdsarbeid/skumlesing/page.mdx new file mode 100644 index 0000000000..562138d4ef --- /dev/null +++ b/apps/storefront/app/god-praksis/innholdsarbeid/skumlesing/page.mdx @@ -0,0 +1,60 @@ +import { PageLayout } from '@layouts'; + +export const metadata = { + title: 'Skumlesing', + description: 'Slik skriver du tekster som er lette å skumlese', +}; + +export default ({ children }) => ( + +); + +Når vi er på en nettside eller i en app, skanner vi etter noe som kan fange oppmerksomheten vår, et hint eller tips om hva som er viktig, hva vi skal gjøre eller om vi kan finne svar på det vi lurer på i et avsnitt. + +Denne måten å lese på må vi ta hensyn til når vi lager innhold. I tillegg må vi ta hensyn til brukernes leseferdigheter. Voksne i Norge har generelt gode leseferdigheter, men mange opplever at språket i offentlige digitale tjenester er vanskelig å forstå. Det kan være at de ikke har norsk som morsmål, har kognitive vansker eller svake leseferdigheter av andre grunner. I tillegg er det mange med gode leseferdigheter som synes språket er vanskelig fordi det er ukjente ord, begreper og tematikk. + +Når vi har god struktur på innholdet og bruker klart språk og ord som folk kjenner igjen, blir det lettere å både skanne innholdet og oppfatte innholdet. Det gjelder også dem med svake leseferdigheter + +## Slik skriver du tekster som er lette å skumlese + +1. **Bruk punktlister for å ramse opp** + + - Maks en setning per punkt, helst bare noen få ord. + +2. **Bruk korte ord** + + - Velg enkle og korte ord i stedet for formelle eller lange ord. + - Bruk de ordene brukerne bruker. + - Unngå fagspråk, gammeldagse ord og moteord. + +3. **Unngå lange setninger** + + - Ett poeng i hver setning. + - Unngå mer enn 15 ord i en setning. + +4. **Ett tema i hvert avsnitt** + + - Ha maks 3-4 setninger per avsnitt. + +5. **Lag meningsbærende overskrifter og mellomoverskrifter** + +Overskriftene og mellomoverskriftene skal gjengi innholdet i avsnittet. De skal helst være en hel setning. + +- Overskrifter fungerer som veiskilt i teksten og gjør den enklere å skanne og lettere å lese. +- Mellomtitler bør henge sammen narrativt slik at brukeren forstår det viktigste ved å bare lese dem. +- Sett de viktigste ordene først. + +6. **Ikke bruk store bokstaver, kursiv og fet tekst** + +7. **Skriv klarspråk** + +[Les råd om hvordan du kan skrive kort og tydelig] diff --git a/apps/storefront/app/god-praksis/page.mdx b/apps/storefront/app/god-praksis/page.mdx new file mode 100644 index 0000000000..6d2738a423 --- /dev/null +++ b/apps/storefront/app/god-praksis/page.mdx @@ -0,0 +1,100 @@ +import { HandShakeHeartIcon } from '@navikt/aksel-icons'; + +import { NavPageLayout } from '@layouts'; +import { Grid, TeaserCard } from '@components'; + +export default ({ children }) => ( + , + color: 'yellow', + }} + /> +); + +export const metadata = { + title: 'God Praksis', + description: + 'Råd og veiledning som kan bidra til å lage bedre helhetlige tjenester samles her.', +}; + +## Brukerinnsikt + +Designressurser og kunnskapsdeling rundt brukerinnsikt. + + + + + + + +## Tilgjengelighet + +Tilgjengelighet og universell utforming handler om at det vi lager skal kunne brukes av alle uavhengig av funksjonsevne eller brukskontekst. + + + + + + +## Innholdsarbeid + +Brukerne skal finne, forstå og gjøre det de kom til tjenesten for å gjøre. Derfor er det viktig at vi skriver brukertilpasset, klart og tydelig. + + + + + + diff --git a/apps/storefront/app/god-praksis/tilgjengelighet/forsta-synsnedsettelse/page.mdx b/apps/storefront/app/god-praksis/tilgjengelighet/forsta-synsnedsettelse/page.mdx new file mode 100644 index 0000000000..ae8aa8b730 --- /dev/null +++ b/apps/storefront/app/god-praksis/tilgjengelighet/forsta-synsnedsettelse/page.mdx @@ -0,0 +1,32 @@ +import { PageLayout } from '@layouts'; +import { ResponsiveIframe } from '@components'; + +export const metadata = { + title: 'Forstå synsnedsettelse', + description: + 'Brønnøysundregistrene har undersøkt hvordan mennesker med synsnedsettelser opplever å bruke digitale produkter.', +}; + +export default ({ children }) => ( + +); + +Brønnøysundregistrene har med hjelp fra Blindeforbundet, undersøkt hvordan mennesker med synsnedsettelser opplever å bruke digitale produkter. + + diff --git a/apps/storefront/app/god-praksis/tilgjengelighet/kontrast/page.mdx b/apps/storefront/app/god-praksis/tilgjengelighet/kontrast/page.mdx new file mode 100644 index 0000000000..272ad3101e --- /dev/null +++ b/apps/storefront/app/god-praksis/tilgjengelighet/kontrast/page.mdx @@ -0,0 +1,194 @@ +import { + Card, + CardContent, + Heading, + List, + ListHeading, + ListUnordered, + ListItem, +} from '@digdir/designsystemet-react'; + +import { Image } from '@components'; +import { PageLayout } from '@layouts'; +import { Contributors } from '@blog'; + +export const metadata = { + title: 'Kontrast', + description: 'WCAG 3.0 foreslår ny kontrastmetode', +}; + +export default ({ children }) => ( + +); + +For å sikre god lesbarhet skal all tekst ha tilstrekkelig kontrast mot bakgrunnen. Dette er viktig for alle brukere, særlig under krevende lysforhold. De som trenger dette mest, er svaksynte, dyslektikere og fargeblinde (kilde: [uutilsynet](https://www.uutilsynet.no/veiledning/kontrast/48)). + +## Behov for strengere krav til kontrast + +Alle brukerne, også de med svekket syn, skal kunne se innholdet i digitale tjenester. Web Content Accessibility Guidelines (WCAG) inneholder suksesskriterier og forslag til løsninger for å lykkes. Men det er ikke samsvar mellom dagens kontrastregler og kravet om at alle skal kunne se innholdet. + + + Gjeldende regelverk, WCAG 2.1 + + + **1.4.3 Kontrast (minimum) (Nivå AA)**: Kontrastforholdet mellom + teksten og bakgrunnen er minst 4,5:1. [1.4.3 Kontrast (minimum), WCAG + 2.1 + (w3.org)](https://www.w3.org/Translations/WCAG21-no/#contrast-minimum) + + + **1.4.11 Kontrast for ikke-tekstlig innhold (Nivå AA)**: Den visuelle + presentasjonen av det følgende har et kontrastforhold på minst 3:1 mot + farge(r) som ligger ved siden av. [1.4.11 Kontrast for ikke-tekstlig + innhold, WCAG 2.1 + (w3.org)](https://www.w3.org/Translations/WCAG21-no/#non-text-contrast) + + + + +
+ + + Fremtidig eller strengere: + + + **1.4.6 Kontrast** (forbedret) (Nivå AAA): Den visuelle presentasjonen + av tekst og bilder av tekst har et kontrastforhold på minst 7:1, + unntatt uvesentlig tekst og skriftstørrelser større enn 18px eller + 14px fet. [ 1.4.6 Kontrast (forbedret), WCAG 2.1 + (w3.org)](https://www.w3.org/Translations/WCAG21-no/#contrast-enhanced) + + + **WCAG 2.2: 2.4.13** Focus Appearance (Nivå AAA), om utseende til + fokusmarkering krever at fokusindikator har en kontrastverdi på 3:1 + mellom samme piksler i fokusert og ikke-fokusert tilstand. + [Understanding Success Criterion 2.4.13: Focus Appearance | WAI | + W3C](https://www.w3.org/WAI/WCAG22/Understanding/focus-appearance.html) + + + **WCAG 3** har et krav om farge og kontrast, visuell kontrast i tekst + (sølv): Sørg for tilstrekkelig kontrast mellom tekst i forgrunnen og + bakgrunnen for teksten. Her brukes det en ny metode, med navn APCA, + for å regne ut kontrasten. + + + + +## Mer presis metode + +WCAG 3.0 foreslår nå en mer presis metode enn dagens standard, for å kalkulere kontrast og sette terskelverdier. + + + + Metoden forbedrer hvordan verdien mellom to farger bestemmes, og skiller + også på om fargene er i forgrunnen eller i bakgrunnen. + + + Den setter også tydelige terskelverdier eller målverdier for valg av font, + tekststørrelse og font-vekt. Metoden heter Advanced Perceptual Contrast + Algorithm (APCA). + + + Målet vårt er å ligge over AAA-krav i WCAG 2.1, og vi vil dermed ligge + nærmere terskelverdiene i APCA. Det øker sjansen for at vi klarer å + oppfylle kravet om at alle, også svaksynte, skal kunne se innholdet på + nettstedet. + + + +## I dag bruker vi en høyere standard enn kravene til tilgjengelighet + +For at innholdet i offentlige, digitale tjenester skal være tilgjengelig for alle brukere, følger vi i dag en ønsket standard for kontrast som er høyere enn kravene som stilles til tilgjengelighet. Standarden heter WCAG 2.1, nivå AAA. + +For å øke lesbarheten enda mer, har vi ambisjoner om å oppnå kontrast på nivå 4. Det er toppnivået i APCA-metoden, som nå blir foreslått i WCAG 3.0 + +## Hvorfor duger ikke dagens standard? + +Vi vet at selv om en løsning oppfyller de konkrete kravene fra regelverket om universell utforming, så er den ikke nødvendigvis universelt utformet og tilgjengelig. Siden øyets evne til å oppfatte farger og lys ikke er en del av metoden, er den uegnet til å beregne forskjellen i lysstyrken i fargeparet. + +Hvis vi oppfyller metoden i WCAG 2, etterlever vi teknisk sett kravet til universell utforming, men det betyr ikke at innholdet er tilgjengelig eller universelt utformet. Derfor strekker vi oss langt i å også oppfylle de fremtidige WCAG-3 kravene som bruker APCA-metoden. + + + **Kontrast i WCAG 2 «luminosity contrast algorithm**
+ _«I WCAG 2 er kontrast en måleenhet for forskjellen i den opplevde lysintensiteten + mellom to farger. Denne forskjellen er beskrevet som et forhold fra 1:1 (for + eksempel hvit på hvit) til 21:1 (for eksempel svart på hvit).»_ – WebAIM, vår + oversettelse. Kontrastene regnes ut ved hjelp av fargenes RGB, HEX eller HSL + verdier i tillegg til transparens (alpha), om fargen er tekst, grafikk, forgrunn + eller bakgrunn har ingen betydning. +
+ +
+ + + **Kontrast i WCAG 3 «visual contrast algorithm»**
I WCAG 3 benyttes en + visuell-kontrast algoritme som kalles for APCA, det er fremdeles + fargeverdiene som benyttes for å kalkulere kontrasten, men også om fargen er + tekst, grafikk, forgrunn eller bakgrunn, i tillegg har også valg av font, + font-vekt og størrelse en innvirkning på hvilke kontrastverdier som er + godkjent. Forskjellige farger som i WCAG 2 ville oppnådd like + kontrastverdier vil i APCA kunne få andre verdier fordi en i større grad + kalkulerer ut fra øyets evne til å oppfatte farger enn kun den tekniske + fargeverdien. +
+ +## Verktøy for å teste kontrastverdier + +Fargesystemet for Brønnøysundregistrene finner du i [kontrastverktøyet her](https://contrast.brreg.no/). Du kan teste hvordan kontrastverdier endrer seg etter hvilken tekstfarge, størrelse og vekt du velger. Og du kan se hvilke nivåer av krav som er oppfylt, om det er WCAG AA eller AAA nivåer, eller APCA. + +Tabell som viser tekststørrelser og vekting, og i hviken grad de oppfyller kontrastkravet. + +Terskelverdiene (over) som viser om kontrasten er godkjent eller ikke, er forenklet fra en tidlig «sølv»-nivåtabell fra APCA-arbeidet. Når en ferdig modell er testet og anbefalt fra WCAG 3, endres terskelverdiene. + +Illustrasjonen viser to eksempler (A og B) med 16px stor tekst i normal vekt, begge variantene har 4,6 til 1 i kontrast. + +I eksempelet over ser vi at selv om kontrasten som er utregnet til å være lik med WCAG 2-metoden, er graden av lesbarhet ulik for tekstene i variant A og Variant B. +Begge tekstene har 16px stor tekst i normal vekt, og begge variantene har 4,6 til 1 i kontrast. +I variant A har teksten fargen #6D7879og bakgrunnen er hvit. Teksten er sånn passe lesbar. +I variant B er teksten svart, og bakgrunnen er farge #6D7879. Teksten er noe mindre lesbar enn variant A. + +
+
+ + **Bidra til artikkelen?**
+ Vi vil gjerne ha dine innspill og tilbakemeldinger på artikkelen. Send oss en + e-post på: designsystem@digdir.no eller [kontakt oss i Github](https://github.com/digdir/designsystemet/issues/new). +
+ + +
+
diff --git a/apps/storefront/app/grunnleggende/designelementer/design-tokens/page.mdx b/apps/storefront/app/grunnleggende/designelementer/design-tokens/page.mdx new file mode 100644 index 0000000000..828c079a0f --- /dev/null +++ b/apps/storefront/app/grunnleggende/designelementer/design-tokens/page.mdx @@ -0,0 +1,46 @@ +import { TokenIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; + +export const metadata = { + title: 'Design Tokens', + description: + 'Design tokens er gjenbrukbare verdier som fungerer som et bindeleddet mellom alle flater.', +}; + +export default ({ children }) => ( + , + color: 'yellow', + }} + /> +); + +## Hva er design tokens + +Design Tokens" styrer hvordan komponentene skal se ut i forhold til farger, typografi, størrelser, avstander, former osv. Design tokens sørger vi for at både designere og utviklere arbeider etter de samme reglene og retningslinjene. + +Noen av variablene er lagt opp til å være tema-baserte, det vil si at de tar utgangspunkt i din merkevare med de fargene og preferansene du selv velger. Vi jobber med en tema-bygger som skal gjøre det enklere for deg å tilpasse stilene. + +Design Tokens er fleksible variabler som kan benyttes uavhengig av teknologi eller designverktøy. + +## Design tokens i Figma + +Vi bruker Figma-pluginen "Tokens Studio", da denne lar oss administrere flere stiler og egenskaper enn Figma i seg selv kan. + +Pluginen har som mål å være W3C-kompatibel og retter seg etter standarden som etableres av [W3C Design Tokens Community Group](https://github.com/design-tokens/community-group). Tokens-verdiene er dermed ikke låst til et verktøy - JSON-filen kan flyttes til andre verktøy dersom det skulle bli aktuelt. + +### Flere sett og themes + +Bruk av variabler og tokens gjør det mulig å ha _ett_ designsystem med ulike identiteter. Vi kan lage en komponent i Figma kun èn gang og style den mange ganger - Med et klikk kan vi slå på et annet theme som for eksempel aktiverer en annen fargepalett eller et annet sett med størrelser. Ved å dele tokens inn i både sets og themes, kan vi tilby avanserte former for gjenbruk. + +![Eksempel på fargesystem i Figma](/img/fargerfigma.gif) +Videoen over viser at når settet for «Tilsynet» slås på, overstyres både fargene som er i bruk i filen og stilene som er tilgjengelig i høyremargen byttes ut. + +### Design tokens for utviklere + +Installer NPM-pakken [@digdir/designsystemet-theme](https://www.npmjs.com/package/@digdir/designsystemet-theme) og følg beskrivelsen der på bruk av tokens. Overstyres ved behov. diff --git a/apps/storefront/app/grunnleggende/designelementer/farger/page.mdx b/apps/storefront/app/grunnleggende/designelementer/farger/page.mdx new file mode 100644 index 0000000000..ded833b423 --- /dev/null +++ b/apps/storefront/app/grunnleggende/designelementer/farger/page.mdx @@ -0,0 +1,45 @@ +import { PaletteIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; +import { TokenList } from '../../../../components/Tokens/'; + +export const metadata = { + title: 'Farger', + description: + 'Fargesystemet består av globale farger og et semantisk nivå som beskriver hva fargen skal brukes til.', +}; + +export default ({ children }) => ( + , + color: 'red', + }} + /> +); + +## Et fleksibelt fargesystem + +Fargesystemet består av globale farger som refererer til hva fargen er (eks. red-1) og et semantisk nivå som beskriver hva fargen skal brukes til (eks. Text.Danger). + +### Navnestruktur + +Et semantisk fargenavn er bygget opp av 3 ledd:
+_farge - stryke - vekt_
+ +- Background: Som regel bakgrunnen på hele siden (HTML body). +- Surface: Bakgrunnsfargen til en ting. Eks. et panel, en knapp, en seksjon, etc. +- Border: Fargen til en ramme (stroke). +- Text/Icon: Fargen på tekst og ikoner. + +## Farge-tokens + + diff --git a/apps/storefront/app/grunnleggende/designelementer/ikoner/page.mdx b/apps/storefront/app/grunnleggende/designelementer/ikoner/page.mdx new file mode 100644 index 0000000000..06d22cab79 --- /dev/null +++ b/apps/storefront/app/grunnleggende/designelementer/ikoner/page.mdx @@ -0,0 +1,52 @@ +import { TokenIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; + +export const metadata = { + title: 'Ikoner', + description: 'Hvordan vi bruker ikoner i komponenter', +}; + +export default ({ children }) => ( + , + color: 'red', + }} + /> +); + +## Bli med å samarbeide om ikoner! + +Nav har laget et solid [sett med ikoner](https://aksel.nav.no/ikoner) (800+) som vi anbefaler å bruke og bidra til å videreutvikle. At et ikon har samme betydning i en offentlig sammenheng som en annen tror vi bare har fordeler. + +Ikonene støtter justering i størrelse og fargeendringer, og kommer i både stroke og fill-varianter. + +Her finner du oversikten over ikoner: [aksel.nav.no/ikoner](https://aksel.nav.no/ikoner)
+Her kan du laste ned ikonpakken: [cdn.nav.no/aksel/icons](https://cdn.nav.no/aksel/icons/zip/aksel-icons.zip)
+Her finner du NPM-pakken: [@navikt/aksel-icons](https://www.npmjs.com/package/@navikt/aksel-icons)
+Her finner du ikonene i Figma: [Core Icons 3](https://www.figma.com/community/file/1214869602572392330/Core-Icons-3)
+ +For å holde ikonpakken i Figma i sync med nye oppdateringer og justeringer som kommer trenger du en plugin: [Aksel Icon plugin](https://www.figma.com/community/plugin/1221057403873975172). + +Installer pluginen, trykk "Run" og du henter ned de siste endringene. Tusen takk til designsystem-teamet i NAV som gjorde dette mulig! 🙏🏻👏🏻🏅 + +![Image](https://user-images.githubusercontent.com/1464915/230187062-b17ecf3a-4910-461f-b6c1-7767af26963c.png) + +## Slik bidrar du + +Bli med å [bidra her](https://github.com/navikt/aksel/blob/main/%40navikt/aksel-icons/CONTRIBUTING.md)! Følg disse retningslinjene når du lager nye ikoner: + +- Bruk Keyline-malen som du finner i Figma-filen under "Assets" [Core Icons 3](https://www.figma.com/community/file/1214869602572392330/Core-Icons-3)
+- Alle lag (selv om det kun er ett) må grupperes i en gruppe, enten union, subtract, intersect, eller exclude. +- Den øverste gruppen skal ha fargen icon.default, alle lag og grupper under dette skal kun bruke #262626 +- Alle lag og grupper settes til Constraints: scale, scale +- For ikonvarianten "Stroke": Ikonet må bestå av kun linjer, linjene skal være 1.5 px, center. +- For ikonvarianten "Filled": Ikoner hvor shapes kan fylles, skal fylles. + +### Tilgjengelighet + +Ikonene skal funke for alle brukerene, uansett situasjon. Les mer om [hvordan du sikrer tilgjengeligheten](https://aksel.nav.no/god-praksis/artikler/tilgjengelig-ikonbruk) når du bruker ikoner og hvilke aria-atributter du bør bruke. diff --git a/apps/storefront/app/grunnleggende/designelementer/skygger/page.mdx b/apps/storefront/app/grunnleggende/designelementer/skygger/page.mdx new file mode 100644 index 0000000000..5e02af20cd --- /dev/null +++ b/apps/storefront/app/grunnleggende/designelementer/skygger/page.mdx @@ -0,0 +1,37 @@ +import { MoonIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; +import { TokenList } from '@components'; + +export const metadata = { + title: 'Skygger', + description: 'Hvordan skygger brukes i Designsystemet', +}; + +export default ({ children }) => ( + , + color: 'yellow', + }} + /> +); + +## Bruk av skygger i designet + +Skygger bør brukes bevisst og konsistent da de uttrykker at noe ligger over noe annet i løsningen. + +Skygger kan hjelpe svaksynte til å identifisere komponenter. Bruk av skygger og konturer gjør det enklere og raskere å finne en komponent når du skanner sider. (Research: [Material Design](https://m2.material.io/design/environment/light-shadows.html#research)) + +### Styrker + +Vi har ulike styrker på skyggene, fra xsmall til xlarge. De ulike styrkene brukes for å antyde høyden til overflaten. Overflater i høyere høyder har større skygger, mens de på lavere høyder bør ha mindre skygger. Skygger skal skape et hierarki slik at det som ligger over eller under noe annet kommer tydeligere frem. + + + +### Eksempel + +Popover er en komponent som legger seg over annet innhold. Dette tydeliggjøres ved bruk av en medium skygge. diff --git a/apps/storefront/app/grunnleggende/designelementer/storrelser-og-avstander/page.mdx b/apps/storefront/app/grunnleggende/designelementer/storrelser-og-avstander/page.mdx new file mode 100644 index 0000000000..dea6fb5aa7 --- /dev/null +++ b/apps/storefront/app/grunnleggende/designelementer/storrelser-og-avstander/page.mdx @@ -0,0 +1,58 @@ +import { RulerIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; +import { Image, TokenList } from '@components'; + +export const metadata = { + title: 'Størrelser og avstander', + description: 'Størrelser og avstander', +}; + +export default ({ children }) => ( + , + color: 'blue', + }} + /> +); + +Størrelser (`sizing`) brukes til å definere bredde og høyde på elementer. + +Avstand (`spacing`) brukes til å sette marging og padding. Settet med avstander som er definert i tokens gir oss mulighet til å definere verdier for _"Auto Layout"_ i Figma og sikrer dermed konsistent design på tvers av grensesnitt. + + + + +## Men hvorfor må vi ha både `sizing` og `spacing` når de er helt like? + +Fordi vi ønsker å holde variablene i sync mellom Figma og kode. For å gjøre dette bruker vi foreløpig en plugin som heter "[Token Studio](https://tokens.studio/)". Som du kan se fra [dokumentasjonen til Token Studio](https://docs.tokens.studio/available-tokens/spacing-tokens) er pluginen avhengig av å skille størrelser og avstander. + +### Sizing-variabler i Figma + +Størrelser (sizing) er det du setter under en **_"Section"_**, **_"Frame"_** eller **_"Group"_** i Figma. Der kan du definere bredde (W) og høyde (H). + +Skjermbildet viser hvor du kan bruke Sizing-variabler i Figma + +### Spacing-variabler i Figma + +Avstander er det du setter under _**"Auto Layout"**_ i Figma. Der kan du definere avstand over, under, ved siden av, eller mellom. + +Skjermbildet viser hvor du kan bruke Spacing-variabler i Figma + +
+
diff --git a/apps/storefront/app/grunnleggende/designelementer/typografi/page.mdx b/apps/storefront/app/grunnleggende/designelementer/typografi/page.mdx new file mode 100644 index 0000000000..e2b9bbc087 --- /dev/null +++ b/apps/storefront/app/grunnleggende/designelementer/typografi/page.mdx @@ -0,0 +1,124 @@ +import { TokenIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; +import { CodeSnippet } from '@repo/components'; +import { Image } from '@components'; + +export const metadata = { + title: 'Typografi', + description: + 'For å presentere innholdet korrekt bruker vi stiler og komponenter for typografi.', +}; + +export default ({ children }) => ( + , + color: 'blue', + }} + /> +); + +For å presentere tekst på korrekt måte er det laget stiler som har ulike kombinasjoner av størrelse, fontvekt og linjehøyde. Det er også laget et sett med typografi-komponenter som innkapsler disse stilene, slik at de enkelt kan brukes i ulike sammenhenger. Beskrivelse av hvordan typografi-komponenter brukes finner du i komponentartikkelen [Typography](https://next.storybook.designsystemet.no/?path=/docs/komponenter-typography--docs). + +## Font-family + +Font-family er ikke en del av designsystem-biblioteket, du må selv importere ønsket font i din app. Komponentene har kun blitt testet med fonten "Inter". Velger du en annen font må du selv teste at det ser bra ut. + +Inter er en skrifttype spesielt designet for god lesbarhet på dataskjermer. Den oppfyller følgende kriterier: + +- [Open font license](https://github.com/rsms/inter/blob/master/LICENSE.txt) + har et [aktivt community](https://github.com/rsms/inter) +- Stor skriftfamilie (light, regular, italic, bold, semibold) +- Gjenkjennelige bokstaver, tall og spesialtegn (ikke for kreativ) +- Tydelige overlengder og underlengde på bokstavene. +- Synlig forskjell på lignende tegn (I, l, 1) (må aktiveres) +- Åpne bokstaver gror ikke igjen (f.eks tegn som a, e og c) +- Lik strektykkelse i overgangene. +- Tabular numbers ([monospace](https://fonts.google.com/knowledge/introducing_type/understanding_numerals)) +- [Variabel font](https://rsms.me/inter/#variable) +- God bokstav og ordmellomrom +- Språkstøtte + +Fonten er tilgjengelig i Figma uten at du trenger å laste ned og installere den selv. Trenger du den til andre formål kan du laste den ned fra [github.com/rsms/inter](https://github.com/rsms/inter/releases/tag/v3.19). + +For hosting kan Altinn CDN benyttes: + + + {``} + + +For å aktivere lowercase l with tail, legg til følgende i din CSS: + + + {`font-family: 'Inter', sans-serif; +font-feature-settings: 'cv05' 1; /* Enable lowercase l with tail */`} + + +## Tekststørrelse + +Tekststørrelse-variablene blir angitt i **rem**. Denne verdien er relativ til `html`-elementet sin `font-size`, +og tar utgangspunkt i den vanligste standarden der `1rem = 16px`. Når vi angir tekststørrelse i rem, vil størrelsen være relatert til nettleserens standardstørrelse, og dermed også ta hensyn til om brukeren har valgt å oppskalere tekststørrelsen under innstillingene for tilgjengelighet i sin nettleser. + +Vi har totalt 10 størrelser i designsystemet. 12, 14, 16, 18, 21, 24, 30, 36, 48 og 60px. Default tekststørrelse for `paragraph` er `medium` som tilsvarer 18px. + +| Steg | Størrelse | Body\* | Heading | +| ------ | ------------------ | ----------- | ------- | +| f-2 | 12px / 0.75rem | | | +| f-1 | 14px / 0.875rem | xsmall | | +| **f0** | **16px / 1.00rem** | small | | +| f1 | 18px / 1.125rem | medium | xxsmall | +| f2 | 21px / 1.313rem | large | xsmall | +| f3 | 24px / 1.50rem | xlarge | small | +| f4 | 30px / 1.875rem | | medium | +| f5 | 36px / 2.25rem | | large | +| f6 | 48px / 3.00rem | | xlarge | +| f7 | 60px / 3.75rem | | xxlarge | + +\*`Body`-størrelsene brukes også på `Ingress`, `Label` og `ValidationMessage`. + +### Hva med dynamiske tekststørrelser? + +Dynamisk font-størrelse uten breakpoints var standard i Designsystemet det meste av Beta-perioden. Dynamiske font-størrelser, eller "_Fluid typography"_, medfører noen ulemper som gjorde at vi valgte å gå for en statisk font-skala i stedet. + + **Les mer om [Fluid typography, og hvorfor vi gikk bort fra det](/bloggen/2024/fluid-typography)**. + +## Linjelengde + +For best mulig lesbarhet for alle brukere, bør det ikke være mer enn 65-70 tegn per linje inkludert mellomrom. Da blir teksten mer innbydende og mindre overveldende, og er særlig viktig for blant annet brukere med lesevansker eller konsentrasjonsvansker. _Kilde: [uutilsynet.no](https://www.uutilsynet.no/veiledning/tekst-og-struktur/226)_ + +## Avstand og luft + +Du må selv velge luften du ønsker mellom tekst-elementene. Dette kan du gjøre ved å bruke tokens for `spacing`. + +### Forslag til avstander +Her er et forslag til avstander for å oppnå passelig rytme og luft mellom elementene: + +`spacing-6` under `Heading-xl` \ +`spacing-5` under `Heading-lg` \ +`spacing-4` under `Heading-md` \ +`spacing-3` under `Heading-sm` + +
+ +`spacing-5` mellom `body-md` \ +`spacing-4` mellom `body-sm` + +
+ +`spacing-10` over alle overskrifter/kapitler + + +Eksempel på avstander mellom headinger og avsnitt. + + +
+
diff --git a/apps/storefront/app/grunnleggende/for-designere/bidra-i-figma/page.mdx b/apps/storefront/app/grunnleggende/for-designere/bidra-i-figma/page.mdx new file mode 100644 index 0000000000..9ca2a67cf0 --- /dev/null +++ b/apps/storefront/app/grunnleggende/for-designere/bidra-i-figma/page.mdx @@ -0,0 +1,81 @@ +import { BranchingIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; + +export const metadata = { + title: 'Bidra med design', + description: + 'Vi setter pris på at du hjelper oss å forbedre komponenter og design i Figma.', +}; + +export default ({ children }) => ( + , + color: 'red', + }} + /> +); + +## Foreslå nytt design eller forbedringer + +Vi setter pris på at du hjelper oss å forbedre komponenter og design i Figma. De beste løsningene kommer gjennom samarbeid. + +### Ny komponent + +Ønsker du å foreslå en ny komponent setter vi pris på om den blir [registrert i Github](https://github.com/digdir/designsystemet/discussions/new?category=components). + +Når en ny komponent blir foreslått må vi vurdere om den er verdifull nok til å være en del av designsystemet. Vi ønsker ikke å ende opp med hundrevis av komponenter med små forskjeller, da vi kan risikere uønsket kompleksitet, vedlikehold, samt design- og teknologigjeld. + +For nye komponenter som tas inn må vi: + +- Identifisere og utforske liknende behov hos andre produktteam og offentlige aktører. Hvor mange produkter/etater vil ha bruk for den? +- Vurdere problemet komponenten skal løse og verdien dette gir. +- Tenke på om den kan lages fleksibel og gjenbrukbar nok. +- Tenke på om den er i tråd med [designprinsippene](/grunnleggende/introduksjon/designprinsipper) og om den passer inn i helheten + +### Registrere feil eller mangler på en komponent i Figma + +Har du funnet en svakhet med noen av de eksisterende komponentene i Figma, setter vi pris på om du enten legger igjen en kommentar i Figma sammen med den aktuelle komponenten, eller at du oppretter en [bug-report i Github som forklarer feilen](https://github.com/digdir/designsystemet/issues/new?assignees=&labels=%F0%9F%90%9B+bug&projects=&template=1bug_report.yml), eventuelt en [feature-request som forklarer ønsket tilleggsfunksjonalitet](https://github.com/digdir/designsystemet/issues/new?assignees=&labels=%E2%9C%A8feature+request%2Cneeds+prioritization%E2%9D%97%EF%B8%8F&projects=&template=2feature_request.yml). + +## Lage en komponent i Figma + +Komponenter under arbeid ligger i egne arbeidsfiler. Når designet er ferdig flyttes komponenten til [Designsystemet - Core UI Kit](https://www.figma.com/file/vpM9dqqQPHqU6ogfKp5tlr/Felles-komponenter?type=design&node-id=503%3A3192&mode=design&t=NoWd7lRReSIFNcOx-1). Denne filen blir delt i Figma Community. + +Det er et par ting å tenke på når komponenter lages i Figma: + +- Snakk med en utvikler om spesifikasjon, krav, tilgjengelighet, egenskaper og varianter. Bli enige om scope for komponenten og dokumenter dette i komponentens [Github-sak](https://github.com/orgs/digdir/projects/3/views/14). + +- [Alle styles](https://docs.tokens.studio/available-tokens/available-tokens) (farger, avstander, størrelser, skygger, osv) skal være koblet opp mot korrekt tokens. Bruker du stilene som finnes, er disse allerede automatisk koblet mot tokens. Trenger du nye stiler, må disse også lages som tokens. + +- Bruk typografi-komponentene for all tekst som skal eksistere i komponenten. + +- [Autolayout](https://help.figma.com/hc/en-us/articles/5731482952599-Using-auto-layout): Innholdet skal skalere som forventet ved størrelseendring. Tenk over om innholdet skal wrappe under hverandre dersom det ikke er plass i bredden. Kan det være hensiktsmessig med en min- eller max-width? Og kanskje truncate (...) på teksten dersom den blir for lang? + +- [Varianter](https://help.figma.com/hc/en-us/articles/360056440594-Create-and-use-variants) og "[component properties](https://help.figma.com/hc/en-us/articles/5579474826519-Explore-component-properties)": Bruk varianter for ulike varianter, farger, states, størrelser, og liknende. Bruk Component properties for å vise/skjule lag, instance-swap (F.eks bytte et ikon) og bytte text. Properties navngis på samme måte som props i Storybook. Vi bruker `Variant`, `Size`, `Color`, `State`. + +- Hvilke størrelser skal komponenten eksistere i? Tenk over at komponenten passer med størrelsene på de andre komponentene. For eksempel bør et medium text-field være like høyt som en medium button, da de skal kunne plasseres på siden av hverandre. En medium komponent bør bruke typografi-size medium, og en small komponent bør bruke typografi-size small. + +- Er komponenten interaktiv? I så fall må ulike states eksistere som varianter av komponenten, og disse kobles opp med "[Change to](https://help.figma.com/hc/en-us/articles/360061175334-Create-interactive-components-with-variants#create)". + +- Multibranding. Tenk over i hvilken grad komponenten skal støtte ulik theming og legg til rette for dette ved å bruke brand-farger fra tokens. + +- Navgivning og organisering: Pass på at lagene i komponenten har fornuftige navn og at det ikke finnes unødvendige grupperinger eller lag. + +- Tenk over hvordan en annen designer vil ta i bruk komponenten. Er den intuitiv å bruke? Er den fleksibel nok slik at de ikke trenger å detache den? Kanskje bør den settes opp med [slots](https://www.youtube.com/watch?v=FOGgsPz3UTk) slik at det er mulig å bytte ut innholdet i den og legge inn andre komponenter uten å måtte detache. Bruk gjerne også "[Preferred values](https://help.figma.com/hc/en-us/articles/5579474826519-Explore-component-properties#preferred)" for å femheve komponentene vi tror kommer til å bli mest brukt som innhold. + + - Sjekk at du har gode nok [kontraster](https://www.uutilsynet.no/regelverk/testprosedyrar-nettstader/709#suksesskriterium_143_kontrast) + - At du har tenkt over hvordan tastaturnavigering skal fungere dersom du lager en ny komponent som ikke er standard. (Standard HTML-elementer har tastaturnavigasjon allerede definert). + - Instruksjoner eller informasjon som er essensiell for brukeren skal ikke være kun markert visuelt. Eksempel kan være å bruke ikon eller tekst i tillegg til rødfarge som indikerer at noe feiler. + - Focus: Alle elementer skal ha en visuell markør som blir synlig når elementet får tastaturfokus. Fokusmarkøren skal ha god nok konrast til bakgrunn, for å oppnå dette bruker vi en sort border (2px) og en gul outline (3px) i tillegg. + +- Når komponenten er klar markeres den som "Ready for review". Den blir testet av andre og etter eventuelle justeringer markeres den som "[Ready for development](https://help.figma.com/hc/en-us/articles/15023124644247-Guide-to-Dev-Mode)". Når den er utviklet som en React-komponent lenker vi til komponentsiden i [Storybook](https://storybook.designsystemet.no). + +### Oppdatere tokens + +For å kunne endre eller opprette nye tokens må du lage en ny branch i pluginen [Tokens Studio for Figma](https://tokens.studio/). Du trenger Pro-versjonen av pluginen for å gjøre dette. + +[Se hvordan du kobler pluginen opp mot våre design tokens](/grunnleggende/for-designere/kom-i-gang#bruk-egen-fargepalett-på-komponentene). diff --git a/apps/storefront/app/grunnleggende/for-designere/eget-tema/page.mdx b/apps/storefront/app/grunnleggende/for-designere/eget-tema/page.mdx new file mode 100644 index 0000000000..466ccf91e1 --- /dev/null +++ b/apps/storefront/app/grunnleggende/for-designere/eget-tema/page.mdx @@ -0,0 +1,78 @@ +import { PaletteIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; +import { ResponsiveIframe, Image } from '@components'; + +export const metadata = { + title: 'Bruk designsystemet med eget tema', + description: + 'Lær hvordan du kan bruke designsystemet med dine egne profilfarger og preferanser.', +}; + +export default ({ children }) => ( + , + color: 'blue', + }} + /> +); + +Skal du ta i bruk Designsystemet i din egen organisasjon med dine egne profilfarger og preferanser? Det er flere måter å gjøre det på. Det første du må ta stilling til er om du vil bruke komponentene **_med_** eller **_uten_** kobling mellom Figma og kode. + +Du bør uansett passe på at det er samme Design Tokens som brukes i både Figma og kode, slik at designere og utviklere arbeider etter de samme reglene. Det sikrer at ting ser likt ut i Figma og i de faktiske løsningene. Om du gjør det manuelt eller med en kobling må du vurdere. + +**Alternativ 1:** _Uten_ kobling mellom Figma og kode \ +**Alternativ 2:** _Med_ kobling mellom Figma og kode + +Hvilket alternativ du går for avhenger av dine behov og rammer. Å sette opp en kobling krever en **pro-lisens** av pluginen [Tokens Studio](https://tokens.studio/). Vi håper vi kan gjøre dette enklere med pluginen vår etter hvert. + +Vi guider deg gjennom begge alternativene her. + + +## Alternativ 1: Uten direkte kobling + +Dette alternativet krever **ikke** Token Studio. Med dette alternativet kjører dere samme kodesnutt fra temabyggeren i Designsystemets Figma plugin og i terminalen for å generere Design Tokens til bygg i kode. Det vil ikke være en direkte kobling, men variablene/tokens vil genereres med samme metode, og du vil dermed få like verdier i kode og Figma. + + +### Slik går du frem: + +1. Gå til [Temabyggeren](https://next.theme.designsystemet.no) og generer fargeskalaen ut i fra dine profilfarger. +2. Hent komponentbiblioteket fra [Figma Community](https://www.figma.com/community/file/1322138390374166141/designsystemet-core-ui-kit) (Trykk "Open in Figma"). Merk at dette blir en kopi av komponentbiblioteket uten noen kobling mot hovedfilen. Filen har nå lagt seg i dine "drafts", så du må flytte den til et fornuftig sted i din organisasjon. +3. Installer designsystemets [plugin for Figma](https://www.figma.com/community/plugin/1382044395533039221/designsystemet-beta). +4. Gå tilbake til [Temabyggeren](https://next.theme.designsystemet.no) og klikk "Ta i bruk tema". Kopier kodesnutten og lim den inn i pluginen du installerte i steg 3. (For å generere Design Tokens for kode må utvikler kjøre samme kodesnutt i en terminal.) +5. Velg "Oppdater variabler". Nå skal du se alle komponentene med dine egne profilfarger i Figma. For at andre designere i organisasjonen skal kunne bruke komponentene må du publisere filen. + + +## Alternativ 2: Med kobling + +En kobling gjør at du slipper å legge variablene inn i Figma, du importerer dem i stedet fra pluginen "Tokens Studio". **Du må en pro-lisens av pluginen "Tokens Studio" for å få til denne koblingen.** Du må også ha et sted å lagre filene, f.eks i et Git repo. + + +### Slik går du frem for å få det til: + +1. Gå til [Temabyggeren](https://next.theme.designsystemet.no) og generer fargeskalaen ut i fra dine profilfarger. + +2. Hent komponentbiblioteket fra [Figma Community](https://www.figma.com/community/file/1322138390374166141/designsystemet-core-ui-kit) (Trykk "Open in Figma"). Merk at dette blir en kopi av komponentbiblioteket uten noen kobling mot hovedfilen. Filen har nå lagt seg i dine "drafts", så du må flytte den til et fornuftig sted i din organisasjon. + +3. Installer pluginen [Tokens Studio]() for Figma. Tokens Studio sørger for kobling mellom Figma og kode, ved hjelp av Design Tokens (i json-filer). + +4. Bruk ditt eksisterende Git repo, eller opprett et nytt. F.eks med [Github](https://github.com/new). + +5. Gå tilbake til [Temabyggeren](https://next.theme.designsystemet.no) og klikk "Ta i bruk tema". Kopier kodesnutten og kjør den i en terminal i ditt Git repo. Sjekk inn og push filene. + +6. Nå setter du opp Figma-pluginen "Tokens Studio", som du installerte i steg 3. + + - Følg Tokens Studio sin guide "[Sync your Design Tokens with code](https://docs.tokens.studio/token-storage-and-sync/sync-provider-overview)" for å sette opp ditt Git repo. + - Husk å sette "Token storage location" til `design-tokens` (eller det du har valgt å kalle mappen din med Design Tokens). + +7. Under "Tokens" i Tokens Studio skal du nå se alle fargene du generte med Temabyggeren i steg 1. + +8. I Tokens Studio velg `Styles & variables` og `Export styles & variables to Figma` og følg stegene for å få fargene dine tilgjengelige som variabler i Figma. + +9. Nå skal du se alle komponentene med dine egne profilfarger i Figma. For at andre designere i organisasjonen skal kunne bruke komponentene må du publisere filen. + +9. Ferdig! PS. Dersom du skal gjøre endringer på tokens i Tokens Studio kan du pushe endringene til repoet ditt ved å trykke på "Last-opp"-ikonet (Push) nederst. \ No newline at end of file diff --git a/apps/storefront/app/grunnleggende/for-designere/fargesystem/page.mdx b/apps/storefront/app/grunnleggende/for-designere/fargesystem/page.mdx new file mode 100644 index 0000000000..2198eca51f --- /dev/null +++ b/apps/storefront/app/grunnleggende/for-designere/fargesystem/page.mdx @@ -0,0 +1,73 @@ +import { Table } from '@digdir/designsystemet-react'; + +import { PaletteIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; +import { Image, ResponsiveIframe } from '@components'; + +export const metadata = { + title: 'Sett opp ditt eget fargesystem', + description: 'Her får du hjelp til å sette opp et fargesystem', +}; + +export default ({ children }) => ( + , + color: 'blue', + }} + /> +); + +Med et gjennomtenkt fargesystem kan vi sikre at tekst alltid har god nok kontrast mot våre bakgrunnsfarger og at det finnes nok ulike farger for alle tilstander. + +En profilveileder inneholder ofte kun et sett med primærfarger og sekundærfarger i et par forskjellige fargetoner. Å lage et digitalt produkt kun med disse fargene alene er vanskelig. For å kunne sikre riktig kontrast og korrekte farger for ulike tilstander, er vi avhengig av å definere flere variasjoner av profilfargene. Bare button komponenten består av 6 ulike blåfarger: + +Skjermbildet viser button komponenten og alle de ulike farge-kodene den består av + +Fargesystemet er strukturert for å støtte multibranding og ulike modes (darkmode, contrastmode, etc.), og samtidig ivareta kontrastkrav. Vi har latt oss inspirere av [USWDS sine "magic numbers"](https://designsystem.digital.gov/design-tokens/color/overview/) for å sikre tilgjengelige fargekombinasjoner fra hvilken som helst fargepalett. Vi har også blitt inspirert av [Radix sitt fargesystem](https://www.radix-ui.com/colors) med tydelige intensjoner for de ulike fargene. For å sikre at en organisasjon skal kunne bruke sin faktiske brandfarge, har vi valgt å kombinere to tilnærminger til et helt nytt system. + +## Designsystemets temagenerator + +For å generere en skala som fungerer kan du bruke [Designsystemets temagenerator](https://next.theme.designsystemet.no) Det eneste du trenger å gjøre er å lime inn hex-koden til merkevarens accent-farge og øvrige profil-farger. + +Skjermbildet viser et utsnitt fra fargegeneratoren med 5 fargepaletter. + +Temageneratoren er basert på et fargesystem sørger for at både brand-farger ivaretas og kontrastkrav sikres gjennom de lineære fargene som genereres ut fra brand-fargen. Farger beregnet for tekst vil dermed alltid ha god nok kontrast mot bakgrunnsfarger. + +Eksempler: + +- `Text-default` har alltid god nok kontrast mot alle `background` og `surface` farger. +- `Text-subtle` har alltid god nok kontrast mot alle `background`-farger og `surface-default`. +- Dette vil gjelde uansett hva du har valgt som base-farge. + +`Base-default`-fargen vil alltid være den samme som fargen du har valgt. Dette er for å ivareta brandet ditt best mulig. Du må derfor selv passe på at fargen du velger oppfyller kontrastkravene i forhold til hvor den skal bli brukt. [Designsystemets temagenerator](https://next.theme.designsystemet.no) vil informere deg om eventuelle kontrastbrudd. + +La oss se på et eksempel der vi bytter ut fargene: + + + +## Bruk fargene du har generert + +Når du har generert skalaene, kan du [bruke de nye fargekodene i Designsystemet](/grunnleggende/for-designere/eget-tema), slik at alle komponenter følger din profil. diff --git a/apps/storefront/app/grunnleggende/for-designere/hent-oppdateringer/page.mdx b/apps/storefront/app/grunnleggende/for-designere/hent-oppdateringer/page.mdx new file mode 100644 index 0000000000..b1a4f3dda4 --- /dev/null +++ b/apps/storefront/app/grunnleggende/for-designere/hent-oppdateringer/page.mdx @@ -0,0 +1,29 @@ +import { PaletteIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; + +export const metadata = { + title: 'Hent oppdateringer fra Figma', + description: + 'Hva gjør du når det har kommet en ny versjon av Figma community-filen?', +}; + +export default ({ children }) => ( + , + color: 'blue', + }} + /> +); + +Hva gjør du når det har kommet en ny versjon av Figma community-filen? + +Svaret er dessverre at det ikke finnes en ideell måte å gjøre det på i dag. Figma har foreløpig [ikke støtte for å hente ned endringer fra en Community-fil](https://forum.figma.com/t/need-a-way-to-get-latest-updates-or-subscribe-to-changes-from-a-published-community-file/32571). Vi håper dette vil komme, i mellomtiden kan du vurdere disse alternativene: + +1. Hent ned den siste versjonen av Community-filen og publiser den. De som tar i bruk komponentene fra nå av vil da ha de nyeste komponentene. Det er sannsynligvis lite verdi i å oppdatere gamle skisser og prototyper med nye komponenter. Om du likevel ønsker det kan du bruke "Swap"-funksjonen i Figma. + +2. Lage en [plugin](https://github.com/digdir/designsystemet/issues/289#issuecomment-2037555899) som kan hente ned siste endringer. Dette er noe vi vil vurdere å se på etter hvert. diff --git a/apps/storefront/app/grunnleggende/for-designere/kom-i-gang/page.mdx b/apps/storefront/app/grunnleggende/for-designere/kom-i-gang/page.mdx new file mode 100644 index 0000000000..c4dc9fd112 --- /dev/null +++ b/apps/storefront/app/grunnleggende/for-designere/kom-i-gang/page.mdx @@ -0,0 +1,158 @@ +import { PaletteIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; +import { ResponsiveIframe, Image } from '@components'; + +export const metadata = { + title: 'Kom i gang med designsystemet i Figma', + description: + 'hvordan bruke Designsystemet i Figma og hvordan du kan aktivere bibliotekene.', +}; + +export default ({ children }) => ( + , + color: 'blue', + }} + /> +); + +I Figma finner du komponenter og stiler fra designsystemet som du kan bruke i designet ditt. Designet har også tilhørende design tokens som er i bruk i react-komponentene. Biblioteket er tilgjengeliggjort i [Figma Community](https://www.figma.com/@designsystemet). + +## Kom i gang med komponenter + +Dersom bibliotekene ikke ligger i Figma-organisasjonen din allerede, kan du hente filene fra Figma Community: + +- [Designsystemet - Core UI Kit](https://www.figma.com/@designsystemet) +- [Aksel ikonbibliotek](https://www.figma.com/community/file/1214869602572392330) + +Etter at du har åpnet dem må du + +- Plassere filene der du vil ha dem i din Figma-organisasjon +- Publisere filene +- Aktivere de to fellesbibliotekene i filene du jobber i + +Skjermbilde av Figma. Stegene for å aktivere bibliotekene. + +Skal du bruke designsystemet med egne farger og branding? Se guiden for å [sette opp designsystemet med eget tema](/grunnleggende/for-designere/eget-tema). + +### Ta i bruk komponentene + +For å aktivere bibliotekene: + +1. Trykk på bok-symbolet under "Assets" +2. Aktiver "Core UI Kit" og "Felles ikonbibliotek" + +Når du har slått på bibliotekene skal du kunne se komponentene ved å klikke på "Assets" og søke på det du trenger. Du kan også bruke tastatursnarveien SHIFT + I. + +Nå er det bare å dra komponentene inn i dine egne filer! + +Vil du være med å lage nye komponenter? [Se hvordan du kan bidra](/grunnleggende/for-designere/bidra-i-figma). + +### Varianter + +Alle komponenter kommer med ulike varianter og egenskaper. I Button-komponenten kan du for eksempel aktivere ulike vektinger, states, størrelser og du kan også slå på og av ikoner. + + + +## Bruk designsystemet med egne profilfarger + +Komponentene støtter ulike brand og modes. For å sette opp egne profiler se guiden "[Designsystemet med eget tema](/grunnleggende/for-designere/eget-tema)" + + + +## Kom i gang med stiler og variabler + +Stiler og variabler skal være tilgjengelige i høyremargen når du for eksempel trenger å velge en farge, størrelse, avstand eller skygge. + +### Sizing-variabler + +Størrelser (sizing) er det du setter under en **_"Section"_**, **_"Frame"_** eller **_"Group"_** i Figma. Der kan du definere bredde (W) og høyde (H). + +Skjermbildet viser hvor du kan bruke Sizing-variabler i Figma + +### Spacing-variabler + +Avstander er det du setter under _**"Auto Layout"**_ i Figma. Der kan du definere avstand over, under, ved siden av, eller mellom. + +Skjermbildet viser hvor du kan bruke Spacing-variabler i Figma + +### Fargevariabler + +Fargevariabler er navngitt etter hva de er tiltenkt å brukes til: `background`, `surface`, `border` og `text`. + +- Er du ute etter en `border`-farge kan det være effektiv å søke på "border" for å se alle tilgjengelige farger. +- Er du ute etter en `fill`-farge på et element kan det være effektiv å søke på "surface" for å se alle tilgjengelige farger. +- Er du ute etter en farge for tekst eller ikon kan det være effektiv å søke på "text" for å se alle tilgjengelige farger. + + + +Les mer om [farge-tokens](/grunnleggende/designelementer/farger) og hva de brukes til. + +### Typografi-stiler + +For all tekst bør du bruke de ferdige utformede typografi-komponentene som er tilgjengelig i Figma og kode. Da sikrer vi at vi har et konsistent uttrykk, riktig bruk avstander, størrelser og vekting. + +Du kan også bruke typografi-stilene, men da vil du ikke få mulighet til å slå på avstand under: + + + +Når du bruker Typografi-komponentene, har du mulighet til å aktivere avstand under teksten: + + + +Les mer om [typografi](/grunnleggende/designelementer/typografi). + +
+
diff --git a/apps/storefront/app/grunnleggende/for-designere/terskel.txt b/apps/storefront/app/grunnleggende/for-designere/terskel.txt new file mode 100644 index 0000000000..c530d7d3f8 --- /dev/null +++ b/apps/storefront/app/grunnleggende/for-designere/terskel.txt @@ -0,0 +1,34 @@ + +### Hvordan blir fargene generert? + +Skriv noe om HSL, + +#### Terskel på lightness + +Om du ønsker å lage dine egne farger, kan du bruke tabellen under for å passe på at du holder deg innenfor terkskelverdiene for den gitte fargen. + + + + + Navn + Minimum luminance + Maximum luminance + + + + + Cell 1 + Cell 2 + Cell 3 + + + Cell 4 + Cell 5 + Cell 6 + + +
+ +#### Kontrastfarger + +med eksempler diff --git a/apps/storefront/app/grunnleggende/for-utviklere/endringslogg/page.mdx b/apps/storefront/app/grunnleggende/for-utviklere/endringslogg/page.mdx new file mode 100644 index 0000000000..08c3c47333 --- /dev/null +++ b/apps/storefront/app/grunnleggende/for-utviklere/endringslogg/page.mdx @@ -0,0 +1,26 @@ +import { MenuPageLayout } from '@layouts'; + +export const metadata = { + title: 'Endringslogg', + description: 'Endringslogg for komponenter', +}; + +export default ({ children }) => ( + +); + +## v0.10.1 (2023-03-29) + +**Bug Fixes** + +- Accordion: Fix continous texts word break (#264) (13b3bd6) +- Button: adjust padding to make icon round (#265) (922014d) +- RadioButton: RadioButton looks wrong when zoming in browser (#266) (5f40bc3) +- Select: Display initial value on single select (#268) (7ad5f0f) +- ToggleButtonGroup: Set correct button type (#261) (a706f07) diff --git a/apps/storefront/app/grunnleggende/for-utviklere/kom-i-gang/page.mdx b/apps/storefront/app/grunnleggende/for-utviklere/kom-i-gang/page.mdx new file mode 100644 index 0000000000..752bc46098 --- /dev/null +++ b/apps/storefront/app/grunnleggende/for-utviklere/kom-i-gang/page.mdx @@ -0,0 +1,24 @@ +import { CodeIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; + +export const metadata = { + title: 'Kom i gang som utvikler', + description: 'All informasjonen du trenger for å komme i gang som utvikler.', +}; + +export default ({ children }) => ( + , + color: 'blue', + }} + /> +); + +Besøk vår [readme på GitHub](https://github.com/digdir/designsystemet#table-of-contents) for all informasjonen du trenger for å komme i gang som utvikler. I tillegg kan det være nyttig å lese om [design tokens](/grunnleggende/designelementer/design-tokens). + +Ønsker du å foreslå nytt design eller forbedringer kan [denne informasjonen være nyttig](/grunnleggende/for-designere/bidra-i-figma#ny-komponent). diff --git a/apps/storefront/app/grunnleggende/for-utviklere/komposisjon/page.mdx b/apps/storefront/app/grunnleggende/for-utviklere/komposisjon/page.mdx new file mode 100644 index 0000000000..d7cdbc8135 --- /dev/null +++ b/apps/storefront/app/grunnleggende/for-utviklere/komposisjon/page.mdx @@ -0,0 +1,135 @@ +import { PackageIcon } from '@navikt/aksel-icons'; + +import { MenuPageLayout } from '@layouts'; +import { CodeSnippet } from '@repo/components'; + +export const metadata = { + title: 'Komposisjon', + description: 'Informasjon og bruk av asChild til å løyse komposisjon.', +}; + +export default ({ children }) => ( + , + color: 'blue', + }} + /> +); + +Nokre gonger må du kanskje byte ut ein komponent med ein anna, for eksempel `Button` skulle vore ein `Link`. +Det er her `asChild` kjem inn i biletet. + + + {` + import { Button, Link } from '@digdir/designsystemet-react'; + + +`} + + +I kodesnutten over vert `Button`-komponenten rendra som ein `Link`-komponent. Når dette skal ut i DOMen, er det kun eit element som vert rendra. +Dette skjer ved hjelp av Radix sin `Slot`-komponent. 1 + +`Slot` mergar sine props ned på komponenten som ligg som underordna element. I tilfellet over vert `Button` sine props lagt til på `Link`-komponenten, og ein `a`-tagg vert rendra ut. +Når du brukar `asChild` kan du ikkje ha meir enn eit underordna element, men du kan ha så mange du vil inne i det elementet. + + + {` + <> + /* Dette kaster ein error */ + + + /* Dette går fint */ + + + +`} + + +## Kvifor bruke asChild? + +Vi har tidlegare brukt ein `as` prop for å rendre som andre element. Men når du brukar denne, får du ikkje typesafety eller korrekte typar iht. elementet du har endret til med `as`. +`Slot` ordnar dette ved at du legg til alle props på det underordna elementet av komponenten, og dermed får typesafety. + + + {` + +`} + + +Alt av klassenavn, aria-attributt og andre props som `Button` har, vil bli lagt til på `Link`-komponenten. +Dette betyr at vi kan tilby god tilgjengelegheit, samtidig som du kan bruke andre komponentar som du ynskjer. + +## Event handlers + +Dersom ein prop starter med `on` (td. `onClick`), så vert det sett på som ein event handler. +Når `Slot` mergar props, vil det lage ein ny funksjon som kallar alle event handlers definert på `Button` og `Link`. Funksjonen som ligger på `Link` vil bli kalla først. +Dette betyr at dersom du stoppar eit event på din komponent, vil eventet på `Slot`-komponenten ikkje bli kalla. + +Dersom ein av event handlerane er avhengig av `event.defaultPrevented`, så må du passe på at rekkefølgja er rett. 2 + + + {` + +`} + + +## Bruk dine eigne komponentar + +Fleire komponentar i Designsystemet støttar `asChild` med standard element. Om du endrar dette, må du passe på at tilgjengelegheit vert teke vare på. Det er sjeldent at du treng å endre det underliggjande elementet, men det er meir realistisk at du vil bruke din eigen komponent. + +Ynskjer du å bruke ein eigen komponent må du passe på å spre alle props, og ha støtte for `ref`. 3 + +Komponentane dine vil då sjå slik ut: + + +{`// uten props og ref + const MinKnapp = () =>