From ff3f0a9bebdb1b4e075100d7acd1b6b805ccebeb Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Tue, 30 Jan 2024 12:28:26 +0100 Subject: [PATCH 01/54] Start release 2024.7.0 From 713c239073b3ef25e909c75a1789eb400ef52950 Mon Sep 17 00:00:00 2001 From: Mikkel Jakobsen Date: Wed, 31 Jan 2024 10:42:51 +0100 Subject: [PATCH 02/54] Trigger relase creation... From 7b711577a21fb7b984e4aee70f7730d24a764778 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Wed, 31 Jan 2024 13:51:32 +0100 Subject: [PATCH 03/54] Target skeletons in reservation-list-page class to apply styling Otherwise we can't pull the skeleton apart in React. --- .../Blocks/reservation-page/reservation-page-skeleton.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/Blocks/reservation-page/reservation-page-skeleton.scss b/src/stories/Blocks/reservation-page/reservation-page-skeleton.scss index 4aba799da..8c1069cc9 100644 --- a/src/stories/Blocks/reservation-page/reservation-page-skeleton.scss +++ b/src/stories/Blocks/reservation-page/reservation-page-skeleton.scss @@ -1,6 +1,6 @@ // Since we are using the Skeleton Screen Css classes connected to the existing styling // we deliberately not follow the BEM naming convention here. -.reservation-list-page.ssc { +.reservation-list-page { .ssc-square { height: 72px; From ba907aafa368c2ea0a74846dce815b5b17d61f06 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Wed, 31 Jan 2024 13:52:38 +0100 Subject: [PATCH 04/54] Give .list-reservation__information a minumun width so skeletons look ok This just makes sure that there is a defined width that the skeleton screen classes can use. --- .../reservation-page/reservation-page-skeleton.scss | 8 -------- .../Library/Lists/list-reservation/list-reservation.scss | 5 +++++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/stories/Blocks/reservation-page/reservation-page-skeleton.scss b/src/stories/Blocks/reservation-page/reservation-page-skeleton.scss index 8c1069cc9..d30aaddbf 100644 --- a/src/stories/Blocks/reservation-page/reservation-page-skeleton.scss +++ b/src/stories/Blocks/reservation-page/reservation-page-skeleton.scss @@ -12,12 +12,4 @@ .ssc-circle { height: 90px; } - - & .list-reservation__information { - min-width: 200px; - - @include media-query__x-small("max-width") { - min-width: 100px; - } - } } diff --git a/src/stories/Library/Lists/list-reservation/list-reservation.scss b/src/stories/Library/Lists/list-reservation/list-reservation.scss index c0c331b76..9f9e897c1 100644 --- a/src/stories/Library/Lists/list-reservation/list-reservation.scss +++ b/src/stories/Library/Lists/list-reservation/list-reservation.scss @@ -84,6 +84,11 @@ $list-reservation-space-desktop: 24px; margin-left: $list-reservation-space-mobile; align-items: baseline; justify-content: space-between; + min-width: 200px; + + @include media-query__x-small("max-width") { + min-width: 100px; + } @include media-query__small { margin-left: $list-reservation-space-desktop; From 6e1d5e5d7ea23461776a32262167a6de8e50233b Mon Sep 17 00:00:00 2001 From: Mikkel Jakobsen Date: Wed, 31 Jan 2024 13:13:23 +0100 Subject: [PATCH 05/54] Add .npmrc file in release workflows Apparently it works better to authenticate the npm read/write with a .npmrc file. --- .../workflows/create-release-on-branch-changes.yml | 11 +++++++---- .github/workflows/create-release-on-tag.yml | 9 +++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/create-release-on-branch-changes.yml b/.github/workflows/create-release-on-branch-changes.yml index babbeef71..bfbc560b3 100644 --- a/.github/workflows/create-release-on-branch-changes.yml +++ b/.github/workflows/create-release-on-branch-changes.yml @@ -41,10 +41,13 @@ jobs: - uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' - registry-url: "https://npm.pkg.github.com" - scope: "@${{ github.repository_owner }}" - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Create NPMRC + run: | + echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> ~/.npmrc + echo "[@${{ github.repository_owner }}]:registry=https://npm.pkg.github.com" >> ~/.npmrc + echo "always-auth=true" >> ~/.npmrc + echo 'registry "https://registry.yarnpkg.com"' >> ~/.yarnrc - run: yarn install --frozen-lockfile diff --git a/.github/workflows/create-release-on-tag.yml b/.github/workflows/create-release-on-tag.yml index a3750a09f..10b1a9f64 100644 --- a/.github/workflows/create-release-on-tag.yml +++ b/.github/workflows/create-release-on-tag.yml @@ -30,8 +30,13 @@ jobs: - uses: actions/setup-node@v4 with: node-version-file: '.nvmrc' - registry-url: "https://npm.pkg.github.com" - scope: "@${{ github.repository_owner }}" + + - name: Create NPMRC + run: | + echo "//npm.pkg.github.com/:_authToken=${{ secrets.GITHUB_TOKEN }}" >> ~/.npmrc + echo "@${{ github.repository_owner }}]:registry=https://npm.pkg.github.com" >> ~/.npmrc + echo "always-auth=true" >> ~/.npmrc + echo 'registry "https://registry.yarnpkg.com"' >> ~/.yarnrc - run: yarn install --frozen-lockfile From 77deb4cbbf3cb2ba35f6ed2e109364030cc59620 Mon Sep 17 00:00:00 2001 From: Mikkel Jakobsen Date: Thu, 1 Feb 2024 15:17:51 +0100 Subject: [PATCH 06/54] Rename card list page stories to search result page It is confusing to call search result specific stories/components for card list page --- .../Blocks/advanced-search/AdvancedSearch.tsx | 2 +- ...ories.tsx => SearchResultPage.stories.tsx} | 18 +++--- ...{CardListPage.tsx => SearchResultPage.tsx} | 8 +-- ...istPageData.ts => SearchResultPageData.ts} | 0 ...leton.tsx => SearchResultPageSkeleton.tsx} | 6 +- .../SearchResultPage.stories.tsx | 55 +++++++++++++++++++ 6 files changed, 73 insertions(+), 16 deletions(-) rename src/stories/Library/card-list-page/{CardListPage.stories.tsx => SearchResultPage.stories.tsx} (66%) rename src/stories/Library/card-list-page/{CardListPage.tsx => SearchResultPage.tsx} (91%) rename src/stories/Library/card-list-page/{CardListPageData.ts => SearchResultPageData.ts} (100%) rename src/stories/Library/card-list-page/{CardListPageSkeleton.tsx => SearchResultPageSkeleton.tsx} (90%) create mode 100644 src/stories/Library/search-result-page/SearchResultPage.stories.tsx diff --git a/src/stories/Blocks/advanced-search/AdvancedSearch.tsx b/src/stories/Blocks/advanced-search/AdvancedSearch.tsx index 408760037..f5ebf23f8 100644 --- a/src/stories/Blocks/advanced-search/AdvancedSearch.tsx +++ b/src/stories/Blocks/advanced-search/AdvancedSearch.tsx @@ -3,7 +3,7 @@ import { InputWithDropdown } from "../../Library/input-with-dropdown/InputWithDr import { Multiselect } from "../../Library/multiselect/Multiselect"; import { Button } from "../../Library/Buttons/button/Button"; import InputPreview from "../../Library/input-preview/InputPreview"; -import data from "../../Library/card-list-page/CardListPageData"; +import data from "../../Library/card-list-page/SearchResultPageData"; import { CardListItem } from "../../Library/card-list-item/CardListItem"; import ResultPager from "../../Library/card-list-page/ResultPager"; diff --git a/src/stories/Library/card-list-page/CardListPage.stories.tsx b/src/stories/Library/card-list-page/SearchResultPage.stories.tsx similarity index 66% rename from src/stories/Library/card-list-page/CardListPage.stories.tsx rename to src/stories/Library/card-list-page/SearchResultPage.stories.tsx index 6e9509df9..87b8be959 100644 --- a/src/stories/Library/card-list-page/CardListPage.stories.tsx +++ b/src/stories/Library/card-list-page/SearchResultPage.stories.tsx @@ -1,11 +1,11 @@ import { withDesign } from "storybook-addon-designs"; import { ComponentMeta, ComponentStory } from "@storybook/react"; -import { CardListPage } from "./CardListPage"; -import { CardListPageSkeleton } from "./CardListPageSkeleton"; +import { SearchResultPage } from "./SearchResultPage"; +import { SearchResultPageSkeleton } from "./SearchResultPageSkeleton"; export default { - title: "Blocks / Card list Page", - component: CardListPage, + title: "Blocks / Search Result Page", + component: SearchResultPage, decorators: [withDesign], parameters: { design: { @@ -40,16 +40,16 @@ export default { defaultValue: false, }, }, -} as ComponentMeta; +} as ComponentMeta; -const Template: ComponentStory = (args) => { - return ; +const Template: ComponentStory = (args) => { + return ; }; export const Item = Template.bind({}); -const SkeletonTemplate: ComponentStory = ( +const SkeletonTemplate: ComponentStory = ( args ) => { - return ; + return ; }; export const SkeletonVersion = SkeletonTemplate.bind({}); diff --git a/src/stories/Library/card-list-page/CardListPage.tsx b/src/stories/Library/card-list-page/SearchResultPage.tsx similarity index 91% rename from src/stories/Library/card-list-page/CardListPage.tsx rename to src/stories/Library/card-list-page/SearchResultPage.tsx index 62b86edcc..892e6b171 100644 --- a/src/stories/Library/card-list-page/CardListPage.tsx +++ b/src/stories/Library/card-list-page/SearchResultPage.tsx @@ -5,9 +5,9 @@ import { SearchResultTitle } from "./SearchResultTitle"; import { SearchResultZero } from "./SearchResultZero"; import FacetLine from "./FacetLine"; import FacetLineSelected from "./FacetLineSelectedTerms"; -import data from "./CardListPageData"; +import data from "./SearchResultPageData"; -export type CardListPageProps = { +export type SearchResultPageProps = { title: string; currentResults: number; totalResults: number; @@ -20,14 +20,14 @@ const SearchResultList = data.searchResult.map((item, i) => { return ; }); -export const CardListPage = ({ +export const SearchResultPage = ({ title, linkName, linkTotalResults, currentResults, totalResults, zeroResult, -}: CardListPageProps) => { +}: SearchResultPageProps) => { return (
{ +export const SearchResultPageSkeleton = ({ + title, +}: SearchResultPageSkeletonProps) => { return (
; + +const Template: ComponentStory = (args) => { + return ; +}; +export const Item = Template.bind({}); + +const SkeletonTemplate: ComponentStory = ( + args +) => { + return ; +}; +export const SkeletonVersion = SkeletonTemplate.bind({}); From e23fbfa58e525f91e3f33f243b61e922b35ca7fa Mon Sep 17 00:00:00 2001 From: Mikkel Jakobsen Date: Thu, 1 Feb 2024 16:50:35 +0100 Subject: [PATCH 07/54] Add drop shadow on reservation list items --- .../Library/Lists/list-reservation/list-reservation.scss | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/stories/Library/Lists/list-reservation/list-reservation.scss b/src/stories/Library/Lists/list-reservation/list-reservation.scss index c0c331b76..b46f0c7bc 100644 --- a/src/stories/Library/Lists/list-reservation/list-reservation.scss +++ b/src/stories/Library/Lists/list-reservation/list-reservation.scss @@ -14,7 +14,6 @@ $list-reservation-space-desktop: 24px; width: 100%; display: grid; grid-template-columns: 1fr; - box-shadow: 0 $s-xs 20px rgb(0 0 0 / 10%); position: relative; padding: $list-reservation-space-mobile; cursor: pointer; @@ -26,7 +25,7 @@ $list-reservation-space-desktop: 24px; } &:hover { - filter: drop-shadow(0 $s-xs 20px rgb(72 72 72 / 10%)); + filter: drop-shadow(0 $s-xs 20px rgb(72 72 72 / 20%)); } } @@ -177,6 +176,7 @@ $list-reservation-space-desktop: 24px; @extend %list-stacked; content: " "; + height: 8px; transform: translateY(8px) scale(0.95); z-index: $-z-5; } @@ -185,11 +185,8 @@ $list-reservation-space-desktop: 24px; @extend %list-stacked; content: " "; + height: 9px; transform: translateY($s-md) scale(0.9); z-index: $-z-10; } - - &:hover { - filter: none; - } } From e997574acfe9b8750a8367b6291e657c67094193 Mon Sep 17 00:00:00 2001 From: Mikkel Jakobsen Date: Thu, 1 Feb 2024 16:50:57 +0100 Subject: [PATCH 08/54] Use the same dropshadow color as on reservation list items It is more clear to see selected items. Maybe I am getting old... --- src/stories/Library/card-list-item/card-list-item.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/Library/card-list-item/card-list-item.scss b/src/stories/Library/card-list-item/card-list-item.scss index 6cefeafb9..61a92d428 100644 --- a/src/stories/Library/card-list-item/card-list-item.scss +++ b/src/stories/Library/card-list-item/card-list-item.scss @@ -18,7 +18,7 @@ } &:hover { - filter: drop-shadow(0 $s-xs 20px rgb(72 72 72 / 10%)); + filter: drop-shadow(0 $s-xs 20px rgb(72 72 72 / 20%)); } } From 56a61d57830a0c92e1aa8c4fb072f4b0d7eab136 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Fri, 2 Feb 2024 13:38:55 +0100 Subject: [PATCH 09/54] Make disabled & collapsible optional Button component parameters So that when they're falsey we don't have to define them on every component instance. --- src/stories/Library/Buttons/button/Button.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stories/Library/Buttons/button/Button.tsx b/src/stories/Library/Buttons/button/Button.tsx index d774a5dd0..bd8d38aba 100644 --- a/src/stories/Library/Buttons/button/Button.tsx +++ b/src/stories/Library/Buttons/button/Button.tsx @@ -6,8 +6,8 @@ import { ButtonSize, ButtonType, ButtonVariant } from "./types"; export type ButtonProps = { label: string; buttonType: ButtonType; - disabled: boolean; - collapsible: boolean; + disabled?: boolean; + collapsible?: boolean; size: ButtonSize; variant: ButtonVariant; onClick?: () => void; @@ -17,8 +17,8 @@ export type ButtonProps = { export const Button: React.FC = ({ label, buttonType, - disabled, - collapsible, + disabled = false, + collapsible = false, size, variant, onClick, From 3d151e9b4990a991c616a40d9f3cc7d0dc77ddf4 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Fri, 2 Feb 2024 13:40:53 +0100 Subject: [PATCH 10/54] Make reservation list item be able to show a note at the botton of card --- .../reservation-page/ReservationListItem.tsx | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/stories/Blocks/reservation-page/ReservationListItem.tsx b/src/stories/Blocks/reservation-page/ReservationListItem.tsx index 753b1cc3e..069d6ec62 100644 --- a/src/stories/Blocks/reservation-page/ReservationListItem.tsx +++ b/src/stories/Blocks/reservation-page/ReservationListItem.tsx @@ -3,10 +3,12 @@ import { ReactComponent as ArrowSmallRight } from "../../Library/Arrows/icon-arr export interface ReservationListItemProps { amount: number; + withNote?: boolean; } const ReservationListItem: React.FC = ({ amount, + withNote = false, }) => { const listItems = Array(amount).fill(0); return ( @@ -39,13 +41,20 @@ const ReservationListItem: React.FC = ({ > Jørn Lier Horst (2020)

-

- Detektivbureau Nr. 2 -

+ {!withNote && ( +

+ Detektivbureau Nr. 2 +

+ )}
+ {withNote && ( +
+ You will be charged a fee, when the item is returned +
+ )}
From afae6856211f9649264e21c6ac33116ffd6eb244 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Fri, 2 Feb 2024 13:41:28 +0100 Subject: [PATCH 11/54] Introduce the LoanPage component that shows the loan page --- src/stories/Blocks/loan-page/LoanPage.tsx | 110 ++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/stories/Blocks/loan-page/LoanPage.tsx diff --git a/src/stories/Blocks/loan-page/LoanPage.tsx b/src/stories/Blocks/loan-page/LoanPage.tsx new file mode 100644 index 000000000..4514589d1 --- /dev/null +++ b/src/stories/Blocks/loan-page/LoanPage.tsx @@ -0,0 +1,110 @@ +import { Button } from "../../Library/Buttons/button/Button"; +import ResultPager from "../../Library/card-list-page/ResultPager"; +import ReservationListEmptyState from "../reservation-page/ReservationListEmptyState"; +import ReservationListItem from "../reservation-page/ReservationListItem"; + +export interface LoanPageProps { + headline: string; + physicalLoans: number; + digitalLoans: number; + skeletonVersion?: boolean; +} + +const LoanPage: React.FC = ({ + headline, + physicalLoans, + digitalLoans, + skeletonVersion, +}) => { + if (skeletonVersion) { + return
This will be skeletons
; + } + + if (!physicalLoans && !digitalLoans) { + return ( +
+

{headline}

+ +
+ ); + } + + return ( +
+

{headline}

+ +
+
+

+ Physical loans +
{physicalLoans}
+

+
+ + +
+
+ {!!physicalLoans && ( +
+
    +
  • + +
  • +
+ +
+ )} + {!physicalLoans && ( + + )} +
+ +
+
+

+ Digital reservations +
{digitalLoans}
+

+
+ {!!digitalLoans && ( +
+
    +
  • + +
  • +
+ +
+ )} + {!digitalLoans && ( + + )} +
+
+ ); +}; + +export default LoanPage; From 78f4721243387d1b29e6b4fc5b2be87f9630b799 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Fri, 2 Feb 2024 13:41:52 +0100 Subject: [PATCH 12/54] Introduce the LoanPage story with substories - default - no physical loans - no digital loans - no loans at all --- .../Blocks/loan-page/LoanPage.stories.tsx | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/stories/Blocks/loan-page/LoanPage.stories.tsx diff --git a/src/stories/Blocks/loan-page/LoanPage.stories.tsx b/src/stories/Blocks/loan-page/LoanPage.stories.tsx new file mode 100644 index 000000000..267102307 --- /dev/null +++ b/src/stories/Blocks/loan-page/LoanPage.stories.tsx @@ -0,0 +1,60 @@ +import { ComponentStory } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import LoanPage, { LoanPageProps } from "./LoanPage"; + +export default { + title: "Blocks / Loan Page", + component: LoanPage, + decorators: [withDesign], + argTypes: { + headline: { + name: "Headline", + defaultValue: "Your loans", + control: { type: "text" }, + }, + physicalLoans: { + name: "Physical loans amount", + defaultValue: 2, + control: { type: "number" }, + }, + digitalLoans: { + name: "Digital loans amount", + defaultValue: 2, + control: { type: "number" }, + }, + skeletonVersion: { + name: "Is skeleton version?", + defaultValue: false, + control: { type: "boolean" }, + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=8513%3A85522&mode=design&t=Ms5I0A8fq9bNeuSJ-1", + }, + }, +}; + +const Template: ComponentStory = (args: LoanPageProps) => ( + +); + +export const Default = Template.bind({}); +export const NoPhysicalLoans = Template.bind({}); +NoPhysicalLoans.args = { + physicalLoans: 0, +}; +export const NoDigitalLoans = Template.bind({}); +NoDigitalLoans.args = { + digitalLoans: 0, +}; +export const NoLoansAtAll = Template.bind({}); +NoLoansAtAll.args = { + physicalLoans: 0, + digitalLoans: 0, +}; +export const SkeletonVersion = Template.bind({}); +SkeletonVersion.args = { + skeletonVersion: true, +}; From 7f105a552ee37471e7878b372af397e92ba4f566 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Mon, 5 Feb 2024 10:30:23 +0100 Subject: [PATCH 13/54] Introduce styling for the loan page skeletons --- base.scss | 1 + .../Blocks/loan-page/loan-page-skeleton.scss | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 src/stories/Blocks/loan-page/loan-page-skeleton.scss diff --git a/base.scss b/base.scss index 5ada000ec..cc79df412 100644 --- a/base.scss +++ b/base.scss @@ -129,6 +129,7 @@ @import "./src/stories/Blocks/event-page/event-page"; @import "./src/stories/Blocks/event-list-page/event-list-page"; @import "./src/stories/Blocks/reservation-page/reservation-page-skeleton"; +@import "./src/stories/Blocks/loan-page/loan-page-skeleton"; @import "./src/styles/scss/shared"; @import "./src/styles/scss/internal"; diff --git a/src/stories/Blocks/loan-page/loan-page-skeleton.scss b/src/stories/Blocks/loan-page/loan-page-skeleton.scss new file mode 100644 index 000000000..9400f50f1 --- /dev/null +++ b/src/stories/Blocks/loan-page/loan-page-skeleton.scss @@ -0,0 +1,13 @@ +// Since we are using the Skeleton Screen Css classes connected to the existing styling +// we deliberately not follow the BEM naming convention here. +.loan-list-page { + .ssc-square { + &.cover--size-small { + height: 137px; + width: 95px; + } + } + .ssc-circle { + height: 92px; + } +} From f86955af1604414ed71b71e1c60f67b2f26bf592 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Mon, 5 Feb 2024 10:30:58 +0100 Subject: [PATCH 14/54] Introduce Loan page skeleton and use it in the skeleton story --- src/stories/Blocks/loan-page/LoanPage.tsx | 3 ++- .../Blocks/loan-page/LoanPageSkeleton.tsx | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/stories/Blocks/loan-page/LoanPageSkeleton.tsx diff --git a/src/stories/Blocks/loan-page/LoanPage.tsx b/src/stories/Blocks/loan-page/LoanPage.tsx index 4514589d1..37f46a7e5 100644 --- a/src/stories/Blocks/loan-page/LoanPage.tsx +++ b/src/stories/Blocks/loan-page/LoanPage.tsx @@ -2,6 +2,7 @@ import { Button } from "../../Library/Buttons/button/Button"; import ResultPager from "../../Library/card-list-page/ResultPager"; import ReservationListEmptyState from "../reservation-page/ReservationListEmptyState"; import ReservationListItem from "../reservation-page/ReservationListItem"; +import LoanPageSkeleton from "./LoanPageSkeleton"; export interface LoanPageProps { headline: string; @@ -17,7 +18,7 @@ const LoanPage: React.FC = ({ skeletonVersion, }) => { if (skeletonVersion) { - return
This will be skeletons
; + return ; } if (!physicalLoans && !digitalLoans) { diff --git a/src/stories/Blocks/loan-page/LoanPageSkeleton.tsx b/src/stories/Blocks/loan-page/LoanPageSkeleton.tsx new file mode 100644 index 000000000..2257f8782 --- /dev/null +++ b/src/stories/Blocks/loan-page/LoanPageSkeleton.tsx @@ -0,0 +1,17 @@ +import ReservationListItemSkeleton from "../reservation-page/ReservationListItemSkeleton"; + +const LoanPageSkeleton: React.FC = () => { + return ( +
+
+
+ + +
+ + +
+ ); +}; + +export default LoanPageSkeleton; From f913080bb7b0c7ad579dbf5f40999aafc4ec8827 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Mon, 5 Feb 2024 11:05:02 +0100 Subject: [PATCH 15/54] Make isReady prop on Counter component optional So that it doesn't have to be present when we don't want the counter to be ready. --- src/stories/Library/counter/Counter.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stories/Library/counter/Counter.tsx b/src/stories/Library/counter/Counter.tsx index 09d2b6228..ad7570069 100644 --- a/src/stories/Library/counter/Counter.tsx +++ b/src/stories/Library/counter/Counter.tsx @@ -3,11 +3,11 @@ export type CounterProps = { percentage: number; label: string; status: "danger" | "warning" | "info" | "neutral"; - isReady: boolean; + isReady?: boolean; }; export const Counter = (props: CounterProps) => { - const { value, label, percentage, status, isReady } = props; + const { value, label, percentage, status, isReady = false } = props; function getColor() { if (status === "danger") return "#d22d43"; From a0ee83bfc398574fbe1e1f8c7b75f1094305fb7d Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Mon, 5 Feb 2024 11:05:54 +0100 Subject: [PATCH 16/54] Make Reservation List Item with a note have a red counter with a warning --- .../reservation-page/ReservationListItem.tsx | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/stories/Blocks/reservation-page/ReservationListItem.tsx b/src/stories/Blocks/reservation-page/ReservationListItem.tsx index 069d6ec62..725eca1f5 100644 --- a/src/stories/Blocks/reservation-page/ReservationListItem.tsx +++ b/src/stories/Blocks/reservation-page/ReservationListItem.tsx @@ -1,3 +1,4 @@ +import clsx from "clsx"; import { Counter } from "../../Library/counter/Counter"; import { ReactComponent as ArrowSmallRight } from "../../Library/Arrows/icon-arrow-ui/icon-arrow-ui-small-right.svg"; @@ -60,21 +61,34 @@ const ReservationListItem: React.FC = ({
- + {!withNote && ( + + )} + {withNote && ( + + )}
- Pick up before 02-02-2024 + Pick up before xx-xx-xxxx

Hovedbiblioteket

Reserveringshylde 74

From 453604f384a6d55bd2cbbf1a62eb1fb45df61757 Mon Sep 17 00:00:00 2001 From: Mikkel Jakobsen Date: Sat, 3 Feb 2024 12:24:22 +0100 Subject: [PATCH 17/54] Create symlink to public folder inside of src The reason I do this is to be able to import svg's into stories. If I do not do that I cannot control the svg properties by css. When an svg is used as a src in an image you cannot target the svg propeties. --- src/public | 1 + 1 file changed, 1 insertion(+) create mode 120000 src/public diff --git a/src/public b/src/public new file mode 120000 index 000000000..27f8dec3b --- /dev/null +++ b/src/public @@ -0,0 +1 @@ +../public \ No newline at end of file From b211d1eaf54e7016ab27fc4689ee9fdda0971e06 Mon Sep 17 00:00:00 2001 From: Mikkel Jakobsen Date: Mon, 5 Feb 2024 11:11:09 +0100 Subject: [PATCH 18/54] Ad styling of the list icon button and underline feature --- .../Buttons/icon-button/icon-button.scss | 21 ++++++++++++++++++- .../Library/list-buttons/list-buttons.scss | 2 +- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/stories/Library/Buttons/icon-button/icon-button.scss b/src/stories/Library/Buttons/icon-button/icon-button.scss index af9ccb403..d2adf91de 100644 --- a/src/stories/Library/Buttons/icon-button/icon-button.scss +++ b/src/stories/Library/Buttons/icon-button/icon-button.scss @@ -1,9 +1,28 @@ .dpl-icon-button { all: unset; cursor: pointer; + height: 27px; + path { + fill: $color__global-tertiary-2; + } + // If the icon is not selected and hovered add a vague line at the bottom + // indicating that you can select it. + &:not(&--selected) { + &:hover { + box-shadow: inset 0 -2px 0 0 $color__global-tertiary-2; + } + } + + // If the icon is selected, add a line at the bottom to indicate that it is + // selected. &--selected { - fill: $color__global-tertiary-2; + box-shadow: inset 0 -2px 0 0; + svg { + path { + fill: $color__text-primary-black; + } + } } @extend %default-focus-visible; diff --git a/src/stories/Library/list-buttons/list-buttons.scss b/src/stories/Library/list-buttons/list-buttons.scss index 94d141bd7..d290b6978 100644 --- a/src/stories/Library/list-buttons/list-buttons.scss +++ b/src/stories/Library/list-buttons/list-buttons.scss @@ -28,7 +28,7 @@ } .dpl-list-buttons__buttons__button { - margin-left: $s-xl; + margin-left: $s-md; display: flex; } From 5f16f13825dfda4e0a72d1b72cc7335f8e36e70e Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Mon, 5 Feb 2024 13:01:45 +0100 Subject: [PATCH 19/54] Give dpl-list-buttons__buttons__button class left margin of 32px As it should be. --- src/stories/Library/list-buttons/list-buttons.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/Library/list-buttons/list-buttons.scss b/src/stories/Library/list-buttons/list-buttons.scss index d290b6978..94d141bd7 100644 --- a/src/stories/Library/list-buttons/list-buttons.scss +++ b/src/stories/Library/list-buttons/list-buttons.scss @@ -28,7 +28,7 @@ } .dpl-list-buttons__buttons__button { - margin-left: $s-md; + margin-left: $s-xl; display: flex; } From a81cfdb2b09c4a3ee7316c69d857c812388c0c82 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Mon, 5 Feb 2024 13:02:53 +0100 Subject: [PATCH 20/54] Introcude the loan page - stacked loans substory --- .../Blocks/loan-page/LoanPage.stories.tsx | 9 +++ src/stories/Blocks/loan-page/LoanPage.tsx | 62 ++++++++++++++----- .../reservation-page/ReservationListItem.tsx | 9 ++- 3 files changed, 65 insertions(+), 15 deletions(-) diff --git a/src/stories/Blocks/loan-page/LoanPage.stories.tsx b/src/stories/Blocks/loan-page/LoanPage.stories.tsx index 267102307..99141dd10 100644 --- a/src/stories/Blocks/loan-page/LoanPage.stories.tsx +++ b/src/stories/Blocks/loan-page/LoanPage.stories.tsx @@ -12,6 +12,11 @@ export default { defaultValue: "Your loans", control: { type: "text" }, }, + isStacked: { + name: "Is stacked?", + defaultValue: false, + control: { type: "boolean" }, + }, physicalLoans: { name: "Physical loans amount", defaultValue: 2, @@ -41,6 +46,10 @@ const Template: ComponentStory = (args: LoanPageProps) => ( ); export const Default = Template.bind({}); +export const Stacked = Template.bind({}); +Stacked.args = { + isStacked: true, +}; export const NoPhysicalLoans = Template.bind({}); NoPhysicalLoans.args = { physicalLoans: 0, diff --git a/src/stories/Blocks/loan-page/LoanPage.tsx b/src/stories/Blocks/loan-page/LoanPage.tsx index 37f46a7e5..1498acc98 100644 --- a/src/stories/Blocks/loan-page/LoanPage.tsx +++ b/src/stories/Blocks/loan-page/LoanPage.tsx @@ -3,9 +3,12 @@ import ResultPager from "../../Library/card-list-page/ResultPager"; import ReservationListEmptyState from "../reservation-page/ReservationListEmptyState"; import ReservationListItem from "../reservation-page/ReservationListItem"; import LoanPageSkeleton from "./LoanPageSkeleton"; +import { ReactComponent as ListIcon } from "../../../public/icons/collection/List.svg"; +import { ReactComponent as VariousIcon } from "../../../public/icons/collection/Various.svg"; export interface LoanPageProps { headline: string; + isStacked?: boolean; physicalLoans: number; digitalLoans: number; skeletonVersion?: boolean; @@ -13,6 +16,7 @@ export interface LoanPageProps { const LoanPage: React.FC = ({ headline, + isStacked = false, physicalLoans, digitalLoans, skeletonVersion, @@ -47,26 +51,56 @@ const LoanPage: React.FC = ({
{physicalLoans}
- - - +
+
+ +
+
+
+
+
+
+
{!!physicalLoans && (
  • - +
= ({ amount, withNote = false, + isStacked = false, }) => { const listItems = Array(amount).fill(0); return ( <> {listItems.map(() => ( -
+
From 14f75f0760a93464cb3f6494c405720bcd71bf61 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Mon, 5 Feb 2024 15:13:02 +0100 Subject: [PATCH 21/54] Unify usage of icons - React components over This is how we do it in the React components in dpl-react too. So it's nice to have it unified. --- .../Blocks/advanced-search/AdvancedSearch.tsx | 7 +-- .../autosuggest/Autosuggest.stories.tsx | 14 ++---- src/stories/Blocks/footer/Footer.tsx | 44 +++++-------------- src/stories/Blocks/header/Header.tsx | 37 ++++++---------- .../MaterialMainfestationItem.tsx | 3 +- .../icon-arrow-accent/ArrowAccent.stories.tsx | 6 +-- .../Arrows/icon-arrow-accent/ArrowAccent.tsx | 7 --- .../button/button-expand/ButtonExpand.tsx | 5 +-- .../Library/Forms/date-picker/DatePicker.tsx | 8 +--- .../Library/Icons/icon-watch/IconWatch.tsx | 4 +- .../Modals/modal-infomedia/Infomedia.tsx | 7 +-- src/stories/Library/accordion/Accordion.tsx | 7 +-- .../availability-label/AvailabilityLabel.tsx | 7 +-- src/stories/Library/avatar/Avatar.tsx | 4 +- src/stories/Library/counter/Counter.tsx | 8 ++-- src/stories/Library/disclosure/Disclosure.tsx | 5 +-- src/stories/Library/dropdown/Dropdown.tsx | 22 +++------- .../Library/input-preview/InputPreview.tsx | 7 +-- .../input-with-dropdown/InputWithDropdown.tsx | 7 +-- .../instant-loan/InstantLoanSummary.tsx | 7 +-- .../Library/list-buttons/ListButtons.tsx | 17 ++++--- .../Library/multiselect/Multiselect.tsx | 7 +-- .../pause-reservation/PauseReservation.tsx | 4 +- .../Library/promo-bar/PromoBarIcon.tsx | 4 +- src/stories/Library/review/Review.tsx | 18 ++------ src/stories/Library/tag/Tag.tsx | 9 +--- .../Library/warning-status/WarningStatus.tsx | 7 +-- 27 files changed, 93 insertions(+), 189 deletions(-) delete mode 100644 src/stories/Library/Arrows/icon-arrow-accent/ArrowAccent.tsx diff --git a/src/stories/Blocks/advanced-search/AdvancedSearch.tsx b/src/stories/Blocks/advanced-search/AdvancedSearch.tsx index f5ebf23f8..2245b7b07 100644 --- a/src/stories/Blocks/advanced-search/AdvancedSearch.tsx +++ b/src/stories/Blocks/advanced-search/AdvancedSearch.tsx @@ -6,6 +6,7 @@ import InputPreview from "../../Library/input-preview/InputPreview"; import data from "../../Library/card-list-page/SearchResultPageData"; import { CardListItem } from "../../Library/card-list-item/CardListItem"; import ResultPager from "../../Library/card-list-page/ResultPager"; +import { ReactComponent as PlusButtonIcon } from "../../../public/icons/collection/PlusButton.svg"; export interface AdvancedSearchProps { inputPlaceholder: string; @@ -51,11 +52,7 @@ export const AdvancedSearch: React.FC = ({ ); })}
diff --git a/src/stories/Blocks/autosuggest/Autosuggest.stories.tsx b/src/stories/Blocks/autosuggest/Autosuggest.stories.tsx index 79deea078..e20ec28a6 100644 --- a/src/stories/Blocks/autosuggest/Autosuggest.stories.tsx +++ b/src/stories/Blocks/autosuggest/Autosuggest.stories.tsx @@ -5,6 +5,8 @@ import { Autosuggest, AutosuggestProps } from "./Autosuggest"; import AutosuggestMaterialStories from "../../Library/autosuggest-material/AutosuggestMaterial.stories"; import AutosuggestTextStories from "../../Library/autosuggest-text/AutosuggestText.stories"; import { autosuggestMaterialSuggestions } from "../../Library/autosuggest-material/helper"; +import { ReactComponent as SearchIcon } from "../../../public/icons/basic/icon-search.svg"; +import { ReactComponent as ExpandMoreIcon } from "../../../public/icons/collection/ExpandMore.svg"; export default { title: "Blocks / Autosuggest", @@ -43,16 +45,8 @@ const Template: ComponentStory = ( type="text" placeholder="This field is here just for context." /> - search icon - expand dropdown icon + +
diff --git a/src/stories/Blocks/footer/Footer.tsx b/src/stories/Blocks/footer/Footer.tsx index 39700b1c2..d692bcaf1 100644 --- a/src/stories/Blocks/footer/Footer.tsx +++ b/src/stories/Blocks/footer/Footer.tsx @@ -5,6 +5,10 @@ import { Logo } from "../../Library/logo/Logo"; import { Links } from "../../Library/links/Links"; import { FooterColumn } from "./FooterColumn"; import list from "../../Library/accordion/accordionList"; +import { ReactComponent as FacebookIcon } from "../../../public/icons/social/icon-social-facebook.svg"; +import { ReactComponent as InstagramIcon } from "../../../public/icons/social/icon-social-instagram.svg"; +import { ReactComponent as YoutubeIcon } from "../../../public/icons/social/icon-social-youtube.svg"; +import { ReactComponent as SpotifyIcon } from "../../../public/icons/social/icon-social-spotify.svg"; const dropdownList = [ { @@ -76,28 +80,16 @@ export const Footer = () => {
@@ -202,28 +194,16 @@ export const Footer = () => {
diff --git a/src/stories/Blocks/header/Header.tsx b/src/stories/Blocks/header/Header.tsx index 5d9cef59f..82b4f4554 100644 --- a/src/stories/Blocks/header/Header.tsx +++ b/src/stories/Blocks/header/Header.tsx @@ -1,6 +1,13 @@ import { useEffect, useState } from "react"; import { Logo } from "../../Library/logo/Logo"; import Pagefold from "../../Library/pagefold/Pagefold"; +import { ReactComponent as SearchIcon } from "../../../public/icons/basic/icon-search.svg"; +import { ReactComponent as ExpandMoreIcon } from "../../../public/icons/collection/ExpandMore.svg"; +import { ReactComponent as MenuIcon } from "../../../public/icons/basic/icon-menu.svg"; +import { ReactComponent as ProfileIcon } from "../../../public/icons/basic/icon-profile.svg"; +import { ReactComponent as HeartIcon } from "../../../public/icons/basic/icon-heart.svg"; +import { ReactComponent as WatchStaticIcon } from "../../../public/icons/basic/icon-watch-static.svg"; +import { ReactComponent as CrossIcon } from "../../../public/icons/basic/icon-cross-medium.svg"; export type HeaderProps = { signedIn: boolean; @@ -75,10 +82,7 @@ export const Header = (props: HeaderProps) => { onClick: () => window.eventHeader(), }} > - List of bookmarks +
{ {signedIn && haveNotification && (
)} - Profile + {signedIn && ( {username} )} @@ -114,7 +118,7 @@ export const Header = (props: HeaderProps) => {
@@ -126,17 +130,11 @@ export const Header = (props: HeaderProps) => { type="text" placeholder={inputPlaceholder} /> - search icon + - setIsDropdownOpen(!isDropdownOpen)} - src="icons/collection/ExpandMore.svg" - alt="expand dropdown icon" /> {isDropdownOpen && (
@@ -154,11 +152,7 @@ export const Header = (props: HeaderProps) => {
- clock icon + Fredag 28 Maj
@@ -166,10 +160,7 @@ export const Header = (props: HeaderProps) => {
window.eventHeader()}>
- +
    {list.map((i) => (
  • diff --git a/src/stories/Blocks/material-manifestation-item/MaterialMainfestationItem.tsx b/src/stories/Blocks/material-manifestation-item/MaterialMainfestationItem.tsx index 056b49f4b..7bea22487 100644 --- a/src/stories/Blocks/material-manifestation-item/MaterialMainfestationItem.tsx +++ b/src/stories/Blocks/material-manifestation-item/MaterialMainfestationItem.tsx @@ -5,6 +5,7 @@ import ListDescription, { ListData, } from "../../Library/Lists/list-description/ListDescription"; import Cover from "../../Library/cover/Cover"; +import { ReactComponent as ExpandMoreIcon } from "../../../public/icons/collection/ExpandMore.svg"; export type MaterialMainfestationItemProps = { title: string; @@ -51,7 +52,7 @@ export const MaterialMainfestationItem = ({ }} >

    Detaljer om materialet

    - ExpandMore +
{isOpen && }
diff --git a/src/stories/Library/Arrows/icon-arrow-accent/ArrowAccent.stories.tsx b/src/stories/Library/Arrows/icon-arrow-accent/ArrowAccent.stories.tsx index d13ef734b..9eed64765 100644 --- a/src/stories/Library/Arrows/icon-arrow-accent/ArrowAccent.stories.tsx +++ b/src/stories/Library/Arrows/icon-arrow-accent/ArrowAccent.stories.tsx @@ -1,10 +1,10 @@ import { Meta } from "@storybook/react"; import { withDesign } from "storybook-addon-designs"; -import IconAccentComp from "./ArrowAccent"; +import { ReactComponent as ArrowAccentIcon } from "../../../../public/icons/arrow-accent/icon-arrow-accent.svg"; const StoryBase: Meta = { title: "Library / Arrows / Arrow Accent", - component: IconAccentComp, + component: ArrowAccentIcon, decorators: [withDesign], parameters: { design: { @@ -17,4 +17,4 @@ const StoryBase: Meta = { export default StoryBase; -export const ArrowAccent = () => ; +export const ArrowAccent = () => ; diff --git a/src/stories/Library/Arrows/icon-arrow-accent/ArrowAccent.tsx b/src/stories/Library/Arrows/icon-arrow-accent/ArrowAccent.tsx deleted file mode 100644 index e0d661a13..000000000 --- a/src/stories/Library/Arrows/icon-arrow-accent/ArrowAccent.tsx +++ /dev/null @@ -1,7 +0,0 @@ -const IconAccent = () => { - return ( - arrow accent - ); -}; - -export default IconAccent; diff --git a/src/stories/Library/Buttons/button/button-expand/ButtonExpand.tsx b/src/stories/Library/Buttons/button/button-expand/ButtonExpand.tsx index c0f8a9b34..5005a95ee 100644 --- a/src/stories/Library/Buttons/button/button-expand/ButtonExpand.tsx +++ b/src/stories/Library/Buttons/button/button-expand/ButtonExpand.tsx @@ -1,5 +1,6 @@ import clsx from "clsx"; import { FC } from "react"; +import { ReactComponent as ExpandMoreIcon } from "../../../../../public/icons/collection/ExpandMore.svg"; export type ButtonExpandProps = { showMore: boolean; @@ -14,12 +15,10 @@ const ButtonExpand: FC = ({ showMore, setShowMore }) => { onClick={() => setShowMore(!showMore)} aria-label="Expand More" > - ); diff --git a/src/stories/Library/Forms/date-picker/DatePicker.tsx b/src/stories/Library/Forms/date-picker/DatePicker.tsx index 4dd329baa..edea21638 100644 --- a/src/stories/Library/Forms/date-picker/DatePicker.tsx +++ b/src/stories/Library/Forms/date-picker/DatePicker.tsx @@ -1,13 +1,13 @@ /* eslint-disable import/no-extraneous-dependencies */ // Import default styling import "flatpickr/dist/flatpickr.css"; - import flatpickr from "flatpickr"; import { english } from "flatpickr/dist/l10n/default"; import { Danish } from "flatpickr/dist/l10n/da"; import { Instance } from "flatpickr/dist/types/instance"; import { MutableRefObject, useCallback, useRef } from "react"; import { BaseOptions } from "flatpickr/dist/types/options"; +import { ReactComponent as ExpandMoreIcon } from "../../../../public/icons/collection/ExpandMore.svg"; export type DatePickerProps = { locale?: "en" | "da"; @@ -46,11 +46,7 @@ const DatePicker = (props: DatePickerProps) => { className="datepicker__opener" data-toggle > - Expand more icon +
diff --git a/src/stories/Library/Icons/icon-watch/IconWatch.tsx b/src/stories/Library/Icons/icon-watch/IconWatch.tsx index 126632fe1..afa955dca 100644 --- a/src/stories/Library/Icons/icon-watch/IconWatch.tsx +++ b/src/stories/Library/Icons/icon-watch/IconWatch.tsx @@ -1,8 +1,10 @@ +import { ReactComponent as WatchStaticIcon } from "../../../../public/icons/basic/icon-watch-static.svg"; + export const IconWatch = () => { return (
- klokke + Clock
diff --git a/src/stories/Library/Modals/modal-infomedia/Infomedia.tsx b/src/stories/Library/Modals/modal-infomedia/Infomedia.tsx index f87207575..c916fd20d 100644 --- a/src/stories/Library/Modals/modal-infomedia/Infomedia.tsx +++ b/src/stories/Library/Modals/modal-infomedia/Infomedia.tsx @@ -1,4 +1,5 @@ import Modal from "../Modal"; +import { ReactComponent as InfomediaIcon } from "../../../../public/icons/logo/infomedia-logo.svg"; export type InfomediaProps = { showModal: boolean; @@ -11,11 +12,7 @@ export const Infomedia = (props: InfomediaProps) => { return (
- +

{title}

= ({ list }) => { data-accordion-trigger > {row.header} - + ); diff --git a/src/stories/Library/instant-loan/InstantLoanSummary.tsx b/src/stories/Library/instant-loan/InstantLoanSummary.tsx index 589e7fd1d..034db69b7 100644 --- a/src/stories/Library/instant-loan/InstantLoanSummary.tsx +++ b/src/stories/Library/instant-loan/InstantLoanSummary.tsx @@ -1,4 +1,5 @@ import Cover from "../cover/Cover"; +import { ReactComponent as ExpandMoreIcon } from "../../../public/icons/collection/ExpandMore.svg"; type InstantLoanSummaryProps = { title: string; @@ -24,11 +25,7 @@ const InstantLoanSummary: React.FunctionComponent = ({

{subTitle}

{underlineDescription}

- various-icon +
diff --git a/src/stories/Library/list-buttons/ListButtons.tsx b/src/stories/Library/list-buttons/ListButtons.tsx index 5c78fc355..2e54489e4 100644 --- a/src/stories/Library/list-buttons/ListButtons.tsx +++ b/src/stories/Library/list-buttons/ListButtons.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Button } from "../Buttons/button/Button"; -import IconButton from "../Buttons/icon-button/IconButton"; +import { ReactComponent as MenuIcon } from "../../../public/icons/collection/Menu.svg"; +import { ReactComponent as VariousIcon } from "../../../public/icons/collection/Various.svg"; export type ListButtonProps = { buttonLabel: string; @@ -29,16 +30,14 @@ export const ListButton: React.FC = ({
- +
- +
= ({ Mulighed 1, Mulighed 2, Mulighed 3, Mulighed 4
- +
{isOpen && (
    diff --git a/src/stories/Library/pause-reservation/PauseReservation.tsx b/src/stories/Library/pause-reservation/PauseReservation.tsx index 7b9be8cbc..be9687455 100644 --- a/src/stories/Library/pause-reservation/PauseReservation.tsx +++ b/src/stories/Library/pause-reservation/PauseReservation.tsx @@ -1,3 +1,5 @@ +import { ReactComponent as ReservationsIcon } from "../../../public/icons/collection/Reservations.svg"; + export type PauseReservationProps = { isChecked?: boolean; isPausedtext: string; @@ -18,7 +20,7 @@ export const PauseReservation = ({
    - +
    {isChecked ? isPausedtext : pauseText} diff --git a/src/stories/Library/promo-bar/PromoBarIcon.tsx b/src/stories/Library/promo-bar/PromoBarIcon.tsx index 501027958..ca04b8bc7 100644 --- a/src/stories/Library/promo-bar/PromoBarIcon.tsx +++ b/src/stories/Library/promo-bar/PromoBarIcon.tsx @@ -1,3 +1,5 @@ +import { ReactComponent as InfoIcon } from "../../../public/icons/basic/icon-info.svg"; + export type PromoBarIconType = "none" | "info"; export type PromoBarIconProps = { @@ -8,7 +10,7 @@ export const PromoBarIcon: React.FunctionComponent = ({ type, }) => { if (type === "info") { - return ; + return ; } return null; }; diff --git a/src/stories/Library/review/Review.tsx b/src/stories/Library/review/Review.tsx index 89fca79be..ae5092e30 100644 --- a/src/stories/Library/review/Review.tsx +++ b/src/stories/Library/review/Review.tsx @@ -1,4 +1,6 @@ import React from "react"; +import { ReactComponent as HeartFilledIcon } from "../../../public/icons/basic/icon-heart-filled.svg"; +import { ReactComponent as HeartEmptyIcon } from "../../../public/icons/basic/icon-heart-grey.svg"; export type ReviewProps = { numberOfReviews: number; @@ -35,23 +37,11 @@ export const Review: React.FC = ({ > {filledHeartsArray.map((value) => { return ( - + ); })} {emptyHeartsArray.map((value) => { - return ( - - ); + return ; })}

    {headline}

    diff --git a/src/stories/Library/tag/Tag.tsx b/src/stories/Library/tag/Tag.tsx index a7d86ef86..be1f6cef5 100644 --- a/src/stories/Library/tag/Tag.tsx +++ b/src/stories/Library/tag/Tag.tsx @@ -1,5 +1,6 @@ import { useState } from "react"; import clsx from "clsx"; +import { ReactComponent as CrossIcon } from "../../../public/icons/basic/icon-cross.svg"; type TagProps = { children: React.ReactNode; @@ -35,13 +36,7 @@ export const Tag = ({ )} > {children} - {showCloseIcon && ( - close icon - )} + {showCloseIcon && } ); }; diff --git a/src/stories/Library/warning-status/WarningStatus.tsx b/src/stories/Library/warning-status/WarningStatus.tsx index afd7c72e2..28b95de7d 100644 --- a/src/stories/Library/warning-status/WarningStatus.tsx +++ b/src/stories/Library/warning-status/WarningStatus.tsx @@ -1,5 +1,6 @@ import { Button } from "../Buttons/button/Button"; import { Links } from "../links/Links"; +import { ReactComponent as WarningIcon } from "../../../public/icons/basic/icon-warning.svg"; export type WarningStatusProps = { title?: string; @@ -18,11 +19,7 @@ export const WarningStatus = (props: WarningStatusProps) => { return (
    - warning icon +
    {title &&

    {title}

    } {description && ( From d7248a13c2bc8eff067b7ff4c8182c34744bb912 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Tue, 6 Feb 2024 10:56:42 +0100 Subject: [PATCH 22/54] Fix Pa11y errors- advanced search,footer,header,datepicker & listbuttons These arose after switching from showing icons as img tags to React components. --- .../Blocks/advanced-search/AdvancedSearch.tsx | 25 +++++++++++++++---- src/stories/Blocks/footer/Footer.tsx | 16 ++++++------ src/stories/Blocks/header/Header.tsx | 14 ++++++++--- .../Library/Forms/date-picker/DatePicker.tsx | 1 + .../Library/list-buttons/ListButtons.tsx | 12 +++++++-- 5 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/stories/Blocks/advanced-search/AdvancedSearch.tsx b/src/stories/Blocks/advanced-search/AdvancedSearch.tsx index 2245b7b07..8d24e19f2 100644 --- a/src/stories/Blocks/advanced-search/AdvancedSearch.tsx +++ b/src/stories/Blocks/advanced-search/AdvancedSearch.tsx @@ -37,13 +37,22 @@ export const AdvancedSearch: React.FC = ({ return ( <>
    - - -
    @@ -51,7 +60,10 @@ export const AdvancedSearch: React.FC = ({ ); })} - @@ -89,7 +101,10 @@ export const AdvancedSearch: React.FC = ({ )}
    {isCqlSearch && ( - )} diff --git a/src/stories/Blocks/footer/Footer.tsx b/src/stories/Blocks/footer/Footer.tsx index d692bcaf1..7a12fedf6 100644 --- a/src/stories/Blocks/footer/Footer.tsx +++ b/src/stories/Blocks/footer/Footer.tsx @@ -79,16 +79,16 @@ export const Footer = () => {
    @@ -193,16 +193,16 @@ export const Footer = () => {
    diff --git a/src/stories/Blocks/header/Header.tsx b/src/stories/Blocks/header/Header.tsx index 82b4f4554..19b24641f 100644 --- a/src/stories/Blocks/header/Header.tsx +++ b/src/stories/Blocks/header/Header.tsx @@ -59,7 +59,11 @@ export const Header = (props: HeaderProps) => { <>
- + {signedIn && haveNotification && ( diff --git a/src/stories/Library/Forms/date-picker/DatePicker.tsx b/src/stories/Library/Forms/date-picker/DatePicker.tsx index edea21638..390594733 100644 --- a/src/stories/Library/Forms/date-picker/DatePicker.tsx +++ b/src/stories/Library/Forms/date-picker/DatePicker.tsx @@ -43,6 +43,7 @@ const DatePicker = (props: DatePickerProps) => { />
-
From e3458c90c7dd8fc4d82d2489be66b38a1f118353 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Tue, 6 Feb 2024 11:08:09 +0100 Subject: [PATCH 23/54] Add aria-label to InputWithDropdown button & Button components --- src/stories/Library/Buttons/button/Button.tsx | 1 + src/stories/Library/input-with-dropdown/InputWithDropdown.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stories/Library/Buttons/button/Button.tsx b/src/stories/Library/Buttons/button/Button.tsx index bd8d38aba..818decced 100644 --- a/src/stories/Library/Buttons/button/Button.tsx +++ b/src/stories/Library/Buttons/button/Button.tsx @@ -36,6 +36,7 @@ export const Button: React.FC = ({ )} disabled={disabled} onClick={onClick} + aria-label={label} > {`${label} ${buttonType === "search" ? "(6)" : ""}`} diff --git a/src/stories/Library/input-with-dropdown/InputWithDropdown.tsx b/src/stories/Library/input-with-dropdown/InputWithDropdown.tsx index 94ec28f65..9d3e2930a 100644 --- a/src/stories/Library/input-with-dropdown/InputWithDropdown.tsx +++ b/src/stories/Library/input-with-dropdown/InputWithDropdown.tsx @@ -29,7 +29,7 @@ export const InputWithDropdown: React.FC = ({ arrowWrapper: "dropdown__arrows--inline", }} /> -
From 87e35a599b8aa296fea75d079fde145f5074d8f3 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Tue, 6 Feb 2024 11:38:02 +0100 Subject: [PATCH 24/54] Adjust styling for SVGs to match rendering of the old tags After switching from using img tags to using svgs as React components, some styling needed to be adjusted in order to provide the same visuals. --- src/stories/Library/disclosure/disclosure.scss | 2 ++ src/stories/Library/dropdown/Dropdown.tsx | 4 ++-- src/stories/Library/warning-status/warning-status.scss | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/stories/Library/disclosure/disclosure.scss b/src/stories/Library/disclosure/disclosure.scss index 3e413109a..e5e9612e8 100644 --- a/src/stories/Library/disclosure/disclosure.scss +++ b/src/stories/Library/disclosure/disclosure.scss @@ -80,6 +80,8 @@ &__expand { margin-left: auto; margin-right: $s-md; + height: 40px; + width: 40px; @include media-query__small { margin-right: $s-xl; diff --git a/src/stories/Library/dropdown/Dropdown.tsx b/src/stories/Library/dropdown/Dropdown.tsx index 7b102e3b1..896546138 100644 --- a/src/stories/Library/dropdown/Dropdown.tsx +++ b/src/stories/Library/dropdown/Dropdown.tsx @@ -26,10 +26,10 @@ export const Dropdown: React.FC = ({ const Icon = () => { if (arrowIcon === "triangles") { return ( - + <> - + ); } diff --git a/src/stories/Library/warning-status/warning-status.scss b/src/stories/Library/warning-status/warning-status.scss index 7340f999b..3381e0660 100644 --- a/src/stories/Library/warning-status/warning-status.scss +++ b/src/stories/Library/warning-status/warning-status.scss @@ -11,6 +11,7 @@ .warning-bar__icon { margin-right: $s-md; + min-width: 40px; } .warning-bar__left { From bbac70a142c3be8aafc71979a1c1e7838aff438d Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Tue, 6 Feb 2024 11:46:58 +0100 Subject: [PATCH 25/54] Make disclosure expand icon 24x24px to match how it looked previously I wrongly gave it 40px before --- src/stories/Library/disclosure/disclosure.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stories/Library/disclosure/disclosure.scss b/src/stories/Library/disclosure/disclosure.scss index e5e9612e8..74cad78e6 100644 --- a/src/stories/Library/disclosure/disclosure.scss +++ b/src/stories/Library/disclosure/disclosure.scss @@ -80,8 +80,8 @@ &__expand { margin-left: auto; margin-right: $s-md; - height: 40px; - width: 40px; + height: 24px; + width: 24px; @include media-query__small { margin-right: $s-xl; From fe061697969e5a89015fa9907eaa93df9ae04268 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Tue, 6 Feb 2024 11:48:50 +0100 Subject: [PATCH 26/54] Use min-width insted of width to specify width of disclosure open icon --- src/stories/Library/disclosure/disclosure.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/Library/disclosure/disclosure.scss b/src/stories/Library/disclosure/disclosure.scss index 74cad78e6..b02a849d1 100644 --- a/src/stories/Library/disclosure/disclosure.scss +++ b/src/stories/Library/disclosure/disclosure.scss @@ -81,7 +81,7 @@ margin-left: auto; margin-right: $s-md; height: 24px; - width: 24px; + min-width: 24px; @include media-query__small { margin-right: $s-xl; From 3f502070bec74d8c91f0956b27591e35e33348bf Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Tue, 6 Feb 2024 11:57:14 +0100 Subject: [PATCH 27/54] Adjust width of review hearts to be as it used to be when using Now we use SVG React components, and the styling needs to be adjusted a bit. --- src/stories/Library/review/review.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stories/Library/review/review.scss b/src/stories/Library/review/review.scss index b673b7edb..60b18a565 100644 --- a/src/stories/Library/review/review.scss +++ b/src/stories/Library/review/review.scss @@ -15,6 +15,7 @@ &__heart { // Ensure SVG has same height as font despite top whitespace. height: 14px; + width: 14px; display: inline-block; margin-right: 2px; &:last-of-type { From 4febc7db708176e8dc1eda3680e9bfe1d3376d23 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Wed, 7 Feb 2024 14:00:58 +0100 Subject: [PATCH 28/54] Introduce a group modal item skeleton --- .../Library/Modals/GroupModalItemSkeleton.tsx | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/stories/Library/Modals/GroupModalItemSkeleton.tsx diff --git a/src/stories/Library/Modals/GroupModalItemSkeleton.tsx b/src/stories/Library/Modals/GroupModalItemSkeleton.tsx new file mode 100644 index 000000000..eacd78595 --- /dev/null +++ b/src/stories/Library/Modals/GroupModalItemSkeleton.tsx @@ -0,0 +1,38 @@ +import { FC } from "react"; +import { Checkbox } from "../Forms/checkbox/Checkbox"; + +export type GroupModalItemSkeletonProps = { + withLeftOutset?: boolean; +}; + +const GroupModalItemSkeleton: FC = ({ + withLeftOutset = false, +}) => { + return ( +
  • +
    + {withLeftOutset && ( +
    + +
    + )} +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
  • + ); +}; + +export default GroupModalItemSkeleton; From 5f5995a695471ddc3110b57842ad2418a859137d Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Wed, 7 Feb 2024 14:01:25 +0100 Subject: [PATCH 29/54] Introduce specific stylong for the group modal item skeleton component --- base.scss | 1 + src/stories/Library/Modals/group-modal-item-skeleton.scss | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 src/stories/Library/Modals/group-modal-item-skeleton.scss diff --git a/base.scss b/base.scss index 5ada000ec..80426190d 100644 --- a/base.scss +++ b/base.scss @@ -111,6 +111,7 @@ @import "./src/stories/Library/video-embed/video-embed"; @import "./src/stories/Library/card-grid/card-grid"; @import "./src/stories/Library/promo-title/promo-title"; +@import "./src/stories/Library/Modals/group-modal-item-skeleton"; // Autosuggest block styling needs to be loaded before the rest of the scss for autosuggest @import "./src/stories/Blocks/autosuggest/autosuggest"; diff --git a/src/stories/Library/Modals/group-modal-item-skeleton.scss b/src/stories/Library/Modals/group-modal-item-skeleton.scss new file mode 100644 index 000000000..897c80cd4 --- /dev/null +++ b/src/stories/Library/Modals/group-modal-item-skeleton.scss @@ -0,0 +1,7 @@ +.list-materials { + &__status { + & .ssc-head-line { + min-width: 143px; + } + } +} From 3b7d9cc61064fb202e6bb69d933c75d739d5b39b Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Wed, 7 Feb 2024 14:01:48 +0100 Subject: [PATCH 30/54] Create a story with loading items under Modal - Loans This uses the newly added skeleton items. --- .../Modals/modal-loan/ModalLoan.stories.tsx | 10 ++++++++ .../Library/Modals/modal-loan/ModalLoan.tsx | 25 +++++++++++++------ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/stories/Library/Modals/modal-loan/ModalLoan.stories.tsx b/src/stories/Library/Modals/modal-loan/ModalLoan.stories.tsx index 27cef44d5..ca3c0be1e 100644 --- a/src/stories/Library/Modals/modal-loan/ModalLoan.stories.tsx +++ b/src/stories/Library/Modals/modal-loan/ModalLoan.stories.tsx @@ -19,6 +19,16 @@ const Template: ComponentStory = (args) => ( ); +export const ModalLoanLoading = Template.bind({}); +ModalLoanLoading.args = { + title: "Afleveres 12. oktober 2021", + description: "Kan afleveres på alle Rudersdals biblioteker", + showExpired: true, + showModal: true, + buttonsUpTop: true, + isLoadingItems: true, +}; + export const ModalLoanExpired = Template.bind({}); ModalLoanExpired.args = { title: "Afleveres 12. oktober 2021", diff --git a/src/stories/Library/Modals/modal-loan/ModalLoan.tsx b/src/stories/Library/Modals/modal-loan/ModalLoan.tsx index e272ba121..f3ca826de 100644 --- a/src/stories/Library/Modals/modal-loan/ModalLoan.tsx +++ b/src/stories/Library/Modals/modal-loan/ModalLoan.tsx @@ -9,6 +9,7 @@ import { import { WarningStatus } from "../../warning-status/WarningStatus"; import Modal from "../Modal"; import ResultPager from "../../card-list-page/ResultPager"; +import GroupModalItemSkeleton from "../GroupModalItemSkeleton"; type LoanMaterials = Array<{ materialType?: string; @@ -96,6 +97,7 @@ export type ModalLoanProps = { showModal: boolean; showExpired: boolean; buttonsUpTop: boolean; + isLoadingItems?: boolean; }; export const ModalLoan: React.FC = ({ @@ -104,6 +106,7 @@ export const ModalLoan: React.FC = ({ showExpired, showModal, buttonsUpTop, + isLoadingItems = false, }) => { const [isAllChecked, setChecked] = useState(false); const isExpired = showExpired; @@ -163,17 +166,23 @@ export const ModalLoan: React.FC = ({
    )}
      - {loanList.map(({ list }) => ( + {isLoadingItems && + [0, 1].map(() => )} + {!isLoadingItems && ( <> - {list.map((listItem, index) => ( - + {loanList.map(({ list }) => ( + <> + {list.map((listItem, index) => ( + + ))} + ))} - ))} + )}
    Date: Wed, 7 Feb 2024 15:52:35 +0100 Subject: [PATCH 31/54] DDFLSBP-153 - Removed 100% width on modal-loan to make the modal centered --- src/stories/Library/Modals/modal-loan/modal-loan.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stories/Library/Modals/modal-loan/modal-loan.scss b/src/stories/Library/Modals/modal-loan/modal-loan.scss index 29f74e196..c235af6cb 100644 --- a/src/stories/Library/Modals/modal-loan/modal-loan.scss +++ b/src/stories/Library/Modals/modal-loan/modal-loan.scss @@ -1,7 +1,6 @@ .modal-loan { flex-direction: column; align-items: center; - width: 100%; } .modal-loan__container { From a48e967ebf0dc76d6a2adc7063e9bb2602acdc17 Mon Sep 17 00:00:00 2001 From: Andreas Nielsen Date: Thu, 8 Feb 2024 09:52:56 +0100 Subject: [PATCH 32/54] DDFLSBP-446 - Removed width: 100% on modal-pause__container to prevent horizontal scrollbar --- src/stories/Library/Modals/modal-pause/modal-pause.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stories/Library/Modals/modal-pause/modal-pause.scss b/src/stories/Library/Modals/modal-pause/modal-pause.scss index dcf00d04f..65a2d3bd6 100644 --- a/src/stories/Library/Modals/modal-pause/modal-pause.scss +++ b/src/stories/Library/Modals/modal-pause/modal-pause.scss @@ -21,7 +21,6 @@ margin: 0 $s-lg; padding-top: 96px; max-width: 550px; - width: 100%; @include media-query__small { margin: 0 45px; From c23e245225f882422cbe090dca5604e0e64e1ff4 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Thu, 8 Feb 2024 13:01:38 +0100 Subject: [PATCH 33/54] Introduce the ListDashboardItemSkeleton component and styling --- base.scss | 1 + .../ListDashboardItemSkeleton.tsx | 10 ++++++++++ .../list-dashboard-skeleton.scss | 20 +++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 src/stories/Library/Lists/list-dashboard/ListDashboardItemSkeleton.tsx create mode 100644 src/stories/Library/Lists/list-dashboard/list-dashboard-skeleton.scss diff --git a/base.scss b/base.scss index 80426190d..5e12c5e0a 100644 --- a/base.scss +++ b/base.scss @@ -112,6 +112,7 @@ @import "./src/stories/Library/card-grid/card-grid"; @import "./src/stories/Library/promo-title/promo-title"; @import "./src/stories/Library/Modals/group-modal-item-skeleton"; +@import "./src/stories/Library/Lists/list-dashboard/list-dashboard-skeleton"; // Autosuggest block styling needs to be loaded before the rest of the scss for autosuggest @import "./src/stories/Blocks/autosuggest/autosuggest"; diff --git a/src/stories/Library/Lists/list-dashboard/ListDashboardItemSkeleton.tsx b/src/stories/Library/Lists/list-dashboard/ListDashboardItemSkeleton.tsx new file mode 100644 index 000000000..b03d9c054 --- /dev/null +++ b/src/stories/Library/Lists/list-dashboard/ListDashboardItemSkeleton.tsx @@ -0,0 +1,10 @@ +const ListDashboardItemSkeleton: React.FC = () => { + return ( +
    +
    +
    +
    + ); +}; + +export default ListDashboardItemSkeleton; diff --git a/src/stories/Library/Lists/list-dashboard/list-dashboard-skeleton.scss b/src/stories/Library/Lists/list-dashboard/list-dashboard-skeleton.scss new file mode 100644 index 000000000..86b7ffe76 --- /dev/null +++ b/src/stories/Library/Lists/list-dashboard/list-dashboard-skeleton.scss @@ -0,0 +1,20 @@ +// We don't have any of these dimensions in variables, but we want to preserve +// the skeleton components' dimensions the same as the actual components. +.list-dashboard.ssc { + height: 72px; + + @include media-query__small { + height: 88px; + } + + & .ssc-circle { + width: 40px; + height: 40px; + margin-right: 24px; + + @include media-query__small { + width: 56px; + height: 56px; + } + } +} From df5a891a21d6ea378211b7ec51b740a101a21c1f Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Thu, 8 Feb 2024 13:01:55 +0100 Subject: [PATCH 34/54] Introduce a List Dashboard substory - skeleton screen - for loading --- .../Lists/list-dashboard/ListDashboard.stories.tsx | 9 +++++++++ .../Library/Lists/list-dashboard/ListDashboard.tsx | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/src/stories/Library/Lists/list-dashboard/ListDashboard.stories.tsx b/src/stories/Library/Lists/list-dashboard/ListDashboard.stories.tsx index 5fc33e05e..a83786331 100644 --- a/src/stories/Library/Lists/list-dashboard/ListDashboard.stories.tsx +++ b/src/stories/Library/Lists/list-dashboard/ListDashboard.stories.tsx @@ -34,6 +34,10 @@ export default { control: "string", defaultValue: "/", }, + isSkeleton: { + control: "boolean", + defaultValue: false, + }, }, parameters: { design: { @@ -50,3 +54,8 @@ const Template: ComponentStory = (args) => ( ); export const DashboardList = Template.bind({}); + +export const SkeletonScreen = Template.bind({}); +SkeletonScreen.args = { + isSkeleton: true, +}; diff --git a/src/stories/Library/Lists/list-dashboard/ListDashboard.tsx b/src/stories/Library/Lists/list-dashboard/ListDashboard.tsx index 311d248ab..6df63265e 100644 --- a/src/stories/Library/Lists/list-dashboard/ListDashboard.tsx +++ b/src/stories/Library/Lists/list-dashboard/ListDashboard.tsx @@ -1,6 +1,7 @@ import { StatusLabel, StatusLabelProps } from "../../status-label/StatusLabel"; import { Number, NumberProps } from "../../number/Number"; import { ReactComponent as ArrowSmallRight } from "../../Arrows/icon-arrow-ui/icon-arrow-ui-small-right.svg"; +import ListDashboardItemSkeleton from "./ListDashboardItemSkeleton"; export type ListDashboardProps = { title: string; @@ -8,6 +9,7 @@ export type ListDashboardProps = { number: NumberProps; label: StatusLabelProps; showDot: boolean; + isSkeleton?: boolean; }; export const ListDashboard: React.FC = ({ @@ -16,7 +18,12 @@ export const ListDashboard: React.FC = ({ number, label, showDot, + isSkeleton, }) => { + if (isSkeleton) { + return ; + } + return ( Date: Fri, 9 Feb 2024 11:33:38 +0100 Subject: [PATCH 35/54] Add background color to the modal close button --- src/stories/Library/Modals/modal.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stories/Library/Modals/modal.scss b/src/stories/Library/Modals/modal.scss index 957f7f012..88a7f615b 100644 --- a/src/stories/Library/Modals/modal.scss +++ b/src/stories/Library/Modals/modal.scss @@ -71,6 +71,7 @@ } .modal-btn-close { + background-color: $color__global-primary; position: fixed; top: 0; right: 0; From 71d9035bdaabc270cbaa413d1ed6be43c11acf45 Mon Sep 17 00:00:00 2001 From: clausbruun Date: Fri, 9 Feb 2024 11:37:08 +0100 Subject: [PATCH 36/54] Resolve iOS 15 blue link color override issue in buttons --- src/stories/Blocks/header/header.scss | 1 + .../Library/Lists/list-reservation/list-reservation.scss | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/stories/Blocks/header/header.scss b/src/stories/Blocks/header/header.scss index 62766c649..209d8c98f 100644 --- a/src/stories/Blocks/header/header.scss +++ b/src/stories/Blocks/header/header.scss @@ -238,6 +238,7 @@ display: flex; justify-content: center; align-items: center; + color: $color__text-primary-black; @include media-query__small { height: 70px; diff --git a/src/stories/Library/Lists/list-reservation/list-reservation.scss b/src/stories/Library/Lists/list-reservation/list-reservation.scss index aef0a7e8e..ebf467986 100644 --- a/src/stories/Library/Lists/list-reservation/list-reservation.scss +++ b/src/stories/Library/Lists/list-reservation/list-reservation.scss @@ -18,6 +18,14 @@ $list-reservation-space-desktop: 24px; padding: $list-reservation-space-mobile; cursor: pointer; + h3 { + color: $color__text-primary-black; + } + + p { + color: $color__global-grey; + } + @include media-query__small { grid-template-columns: 1fr 1fr; height: 184px; From 732dff204cebd3626dc0e5132ecfaffd7e937526 Mon Sep 17 00:00:00 2001 From: clausbruun Date: Fri, 9 Feb 2024 11:56:34 +0100 Subject: [PATCH 37/54] Transferring changes made to the user icon in the header from dpl-react to the dpl-design-system --- src/stories/Blocks/header/Header.tsx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/stories/Blocks/header/Header.tsx b/src/stories/Blocks/header/Header.tsx index 5d9cef59f..39d5c67da 100644 --- a/src/stories/Blocks/header/Header.tsx +++ b/src/stories/Blocks/header/Header.tsx @@ -101,17 +101,18 @@ export const Header = (props: HeaderProps) => { ))}
    -
    - - {signedIn && haveNotification && ( - +
    List of bookmarks From 1057eaa75634c5e6b4e18c62026d1c0e88a717f4 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Fri, 9 Feb 2024 12:04:34 +0100 Subject: [PATCH 38/54] Add drop shadown on hover for group modal items --- src/stories/Library/Lists/list-materials/list-materials.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/stories/Library/Lists/list-materials/list-materials.scss b/src/stories/Library/Lists/list-materials/list-materials.scss index 1c5837977..4192e9029 100644 --- a/src/stories/Library/Lists/list-materials/list-materials.scss +++ b/src/stories/Library/Lists/list-materials/list-materials.scss @@ -8,6 +8,11 @@ padding: $s-md; background-color: $color__global-white; justify-content: space-between; + cursor: pointer; + + &:hover { + filter: drop-shadow(0 $s-xs 20px rgb(72 72 72 / 20%)); + } @include media-query__small { padding: $s-md 32px; From 3a24ca8b06632650b7c6c3b4676d8354294b9c19 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Fri, 9 Feb 2024 12:16:34 +0100 Subject: [PATCH 39/54] Introduce list-materials--no-hover modifier class We don't want hover on all the list-materials items - some of them don't have any click functionality. --- .../Library/Lists/list-materials/list-materials.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/stories/Library/Lists/list-materials/list-materials.scss b/src/stories/Library/Lists/list-materials/list-materials.scss index 4192e9029..7f13291da 100644 --- a/src/stories/Library/Lists/list-materials/list-materials.scss +++ b/src/stories/Library/Lists/list-materials/list-materials.scss @@ -23,6 +23,14 @@ &--bottom-buttons-visible { padding-bottom: 90px; } + + &.list-materials--no-hover { + cursor: default; + + &:hover { + filter: none; + } + } } .list-materials__checkbox { From e265442c4ed9d44f61555083792c1fc253f4d915 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Fri, 9 Feb 2024 13:52:57 +0100 Subject: [PATCH 40/54] Don't add className to ListEmpty classes if it's undefined --- src/stories/Library/Lists/list-empty/ListEmpty.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stories/Library/Lists/list-empty/ListEmpty.tsx b/src/stories/Library/Lists/list-empty/ListEmpty.tsx index b429e86c5..cf6c64fa1 100644 --- a/src/stories/Library/Lists/list-empty/ListEmpty.tsx +++ b/src/stories/Library/Lists/list-empty/ListEmpty.tsx @@ -8,8 +8,8 @@ interface ListEmptyProps { const ListEmpty = ({ text, links, className }: ListEmptyProps) => { return ( -
    - {text} +
    +

    {text}

    {links && (
    {links.map((item, index) => ( From 73dc455bb4f72bff8dfd04936208f8c93ebb1a8c Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Fri, 9 Feb 2024 13:53:36 +0100 Subject: [PATCH 41/54] Align empty list box inner text to the center --- src/stories/Library/Lists/list-empty/list-empty.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stories/Library/Lists/list-empty/list-empty.scss b/src/stories/Library/Lists/list-empty/list-empty.scss index 6321991ba..dd10d2e47 100644 --- a/src/stories/Library/Lists/list-empty/list-empty.scss +++ b/src/stories/Library/Lists/list-empty/list-empty.scss @@ -6,7 +6,7 @@ justify-content: center; align-items: center; border: 1px dotted $color__global-grey; - text-align: left; + text-align: center; color: $color__text-secondary-gray; padding: 48px $s-xs; From eef23ebe510469e0e38112dea8615bfc69053fbe Mon Sep 17 00:00:00 2001 From: clausbruun Date: Mon, 12 Feb 2024 09:58:03 +0100 Subject: [PATCH 42/54] Codestyle fix --- .../Library/Lists/list-reservation/list-reservation.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stories/Library/Lists/list-reservation/list-reservation.scss b/src/stories/Library/Lists/list-reservation/list-reservation.scss index ebf467986..9a06c8f89 100644 --- a/src/stories/Library/Lists/list-reservation/list-reservation.scss +++ b/src/stories/Library/Lists/list-reservation/list-reservation.scss @@ -19,13 +19,13 @@ $list-reservation-space-desktop: 24px; cursor: pointer; h3 { - color: $color__text-primary-black; + color: $color__text-primary-black; } p { color: $color__global-grey; } - + @include media-query__small { grid-template-columns: 1fr 1fr; height: 184px; From 64108bc1ebfea865e123604274e100a03902ce91 Mon Sep 17 00:00:00 2001 From: clausbruun Date: Mon, 12 Feb 2024 12:50:47 +0100 Subject: [PATCH 43/54] Add aria-label --- src/stories/Blocks/header/Header.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stories/Blocks/header/Header.tsx b/src/stories/Blocks/header/Header.tsx index 5ccca0709..0142721bc 100644 --- a/src/stories/Blocks/header/Header.tsx +++ b/src/stories/Blocks/header/Header.tsx @@ -112,6 +112,7 @@ export const Header = (props: HeaderProps) => { @@ -164,30 +132,7 @@ export const Header = (props: HeaderProps) => {
    -
    window.eventHeader()}> -
    - - -
    -
    -
    + ); }; - -declare global { - interface Window { - eventHeader: () => void; - } -} diff --git a/src/stories/Blocks/header/header-state.js b/src/stories/Blocks/header/header-state.js new file mode 100644 index 000000000..2c9368d79 --- /dev/null +++ b/src/stories/Blocks/header/header-state.js @@ -0,0 +1,46 @@ +// Function for checking the size of the desktop links container. +function desktopLinksContainerCheckSize() { + const container = document.querySelector(".header__menu-navigation"); + + // By default, assume we are using the burger menu. + document.documentElement.classList.add("has-burger-menu"); + document.documentElement.classList.remove("has-desktop-menu"); + + // The reserved width is for the logo and service buttons. + const reservedWidth = 250 + 70 + 70 + 105; + // Calculate available space subtracting the reserved width from the total inner window width. + const availableSpace = window.innerWidth - reservedWidth; + + // If the width of the menu container is greater than the available space, + // we keep the burger menu. Otherwise, we swap to the desktop menu format. + if (container.scrollWidth > availableSpace) { + document.documentElement.classList.add("has-burger-menu"); + document.documentElement.classList.remove("has-desktop-menu"); + } else { + document.documentElement.classList.remove("has-burger-menu"); + document.documentElement.classList.add("has-desktop-menu"); + } +} + +// Function for initializing the header state based on window size and container width. +function initHeaderState() { + // Finds the node with class 'header__menu-navigation' which is not initialized. + const desktopLinks = document.querySelector( + ".header__menu-navigation:not(.is-header-initialized)" + ); + + // If the desktop links exist, check their size + // and add a resize event listener to check the size whenever the window is resized. + if (desktopLinks) { + desktopLinksContainerCheckSize(desktopLinks); + + window.addEventListener("resize", desktopLinksContainerCheckSize, true); + document.addEventListener("load", desktopLinksContainerCheckSize, true); + + // Mark the links as initialized + desktopLinks.classList.add("is-header-initialized"); + } +} + +// Call the initHeaderState function to execute all the above operations. +initHeaderState(); diff --git a/src/stories/Blocks/header/header-toggle.js b/src/stories/Blocks/header/header-toggle.js deleted file mode 100644 index 00ddf9126..000000000 --- a/src/stories/Blocks/header/header-toggle.js +++ /dev/null @@ -1,13 +0,0 @@ -window.eventHeader = () => { - const elementOverlay = document.getElementById("header__overlay"); - const elementClose = document.getElementById("header__menu--close"); - const elementOpen = document.getElementById("header__menu--open"); - - if (!elementOverlay || !elementClose || !elementOpen) { - // eslint-disable-next-line - console.info("Header - Couldn't find elements"); - return; - } - - elementOverlay.classList.toggle("visible"); -}; diff --git a/src/stories/Blocks/header/header.scss b/src/stories/Blocks/header/header.scss index 209d8c98f..733cd7c8b 100644 --- a/src/stories/Blocks/header/header.scss +++ b/src/stories/Blocks/header/header.scss @@ -2,29 +2,17 @@ border: 1px solid $color__global-tertiary-1; width: 100%; display: grid; - grid-template-columns: 1fr; + grid-template-columns: 250px 1fr 105px; background-color: $color__global-primary; position: sticky; transition-property: all; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); transition-duration: 500ms; z-index: $z-20; - - @include media-query__small { - grid-template-columns: 1fr 105px; - } - - @include media-query__medium { - grid-template-columns: 250px 1fr 105px; - } } .header__logo-desktop { - display: none; border-right: 1px solid $color__global-tertiary-1; - @include media-query__medium { - display: block; - } } .header__logo-desktop-link { @@ -54,27 +42,20 @@ } .header__menu-navigation { - display: none; - - @include media-query__medium { - display: flex; - padding: 0 12px; - height: 100%; - } + display: inline-flex; + padding: 0 12px; + height: 100%; + white-space: nowrap; } .header__menu-navigation-mobile { - display: flex; + display: none; @include media-query__small { .pagefold-triangle-small { display: none; } } - - @include media-query__medium { - display: none; - } } .header__menu-navigation-button { @@ -84,19 +65,6 @@ border-right: 1px solid $color__global-tertiary-1; } -.header__menu-navigation-item:hover { - border-top: 1px solid transparent; // to prevent jumping - border-bottom: 1px solid $color__global-black; -} - -.header__menu-navigation-link { - padding: 0 12px; - height: 100%; - display: flex; - align-items: center; - color: $color__text-primary-black; -} - .header__menu-profile, .header__menu-bookmarked { position: relative; @@ -246,50 +214,35 @@ } } -// The kebab casing conflicts with our naming convention. -#header__overlay.visible { - /* stylelint-disable-line */ - display: grid; -} - -// The kebab casing conflicts with our naming convention. -#header__overlay { - /* stylelint-disable-line */ - display: none; - z-index: $z-20; - position: fixed; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - grid-template-columns: 384px 1fr; +// has-burger-menu is added dynamically using JS, by calculating if there +// is enough space to show the desktop menu, and otherwise enabling the +// burger menu. @see header-state.js +.has-burger-menu { + .header { + grid-template-columns: 1fr; - @include media-query__small { - grid-template-columns: 384px 1fr; + @include media-query__small { + grid-template-columns: 1fr 105px; + } } -} -.header__overlay-main { - background-color: $color__global-primary; -} + .header__menu-navigation { + position: absolute; + top: -999px; -.header__overlay-backdrop { - background-color: $color__global-black; - opacity: 0.6; -} + // This is important, to avoid screen readers seeing double links. + visibility: hidden; + } -.header__overlay-menu { - margin-top: 96px; - margin-left: 56px; -} + .header__logo-desktop { + display: none; + } -.header__overlay-menu-item { - margin-bottom: $s-sm; + .header__menu-navigation-mobile { + display: flex; + } } -// The kebab casing conflicts with our naming convention. -#header__menu--close { - /* stylelint-disable-line */ - position: fixed; - padding: 30px; +#header-sidebar-nav__toggle { + cursor: pointer; } diff --git a/src/stories/Blocks/page/Page.stories.tsx b/src/stories/Blocks/page/Page.stories.tsx new file mode 100644 index 000000000..f23464a3f --- /dev/null +++ b/src/stories/Blocks/page/Page.stories.tsx @@ -0,0 +1,39 @@ +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import Page from "./Page"; + +export default { + title: "Blocks / Pages", + component: Page, + decorators: [withDesign], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=7477-39243&mode=dev", + }, + }, + argTypes: { + hero: { + control: "object", + description: "Object containing hero details", + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ; + +export const frontPage = Template.bind({}); +frontPage.args = { + hero: { + image: + "https://images.unsplash.com/photo-1531058020387-3be344556be6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8ZXZlbnR8fHx8fHwxNzAyOTEwMzE0&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1080", + contentType: "Arrangement", + date: "06 Dec 2022", + title: "Stine Pilgaard vinder De Gyldne Laurbær", + description: + "Boghandlernes store bogpris - De Gyldne går denne gang til Stine Pilgaard for hendes roman 'Meter i sekundet'. Stort tillykke til Stine Pilgaard.", + }, +}; + +export const blankPage = Template.bind({}); +blankPage.args = {}; diff --git a/src/stories/Blocks/page/Page.tsx b/src/stories/Blocks/page/Page.tsx new file mode 100644 index 000000000..58f2c8b55 --- /dev/null +++ b/src/stories/Blocks/page/Page.tsx @@ -0,0 +1,29 @@ +import { FC } from "react"; +import Hero, { HeroProps } from "../../Library/hero/Hero"; +import Paragraph from "../../Library/paragraph/Paragraph"; + +type PageProps = { + hero?: HeroProps; +}; + +const Page: FC = ({ hero }) => { + return ( +
    +
    + {hero && ( + + + + )} +
    +
    + ); +}; + +export default Page; diff --git a/src/stories/Blocks/page/page.scss b/src/stories/Blocks/page/page.scss new file mode 100644 index 000000000..c9f257f2b --- /dev/null +++ b/src/stories/Blocks/page/page.scss @@ -0,0 +1,59 @@ +%hero-2-column { + @include layout-container($layout__max-width--large); + border-bottom: 1px solid $color__global-tertiary-1; + display: grid; + gap: $s-lg; + padding-bottom: $s-2xl; + @include media-query__small { + grid-template-columns: 2fr 1fr; + gap: 0; + padding-bottom: 0; + } + + // if hero-content is a link, remove text-decoration for all children + > a { + text-decoration: none; + } + + .hero-content, + .hero-visual { + @include media-query__small { + padding: $s-2xl; + } + } + + .hero-content { + padding-top: $s-md; + + @include media-query__small { + padding-top: $s-3xl; + } + + // Add margin to all child elements on small screens except .hero-cta + > *:not(.hero-cta) { + margin-left: $s-3xl; + margin-right: $s-3xl; + + @include media-query__small { + margin-left: 0; + margin-right: 0; + } + } + } + + .hero-visual { + @include media-query__small { + grid-column: 1/2; + grid-row: 1/2; + border-right: 1px solid $color__global-tertiary-1; + } + } + + .hero-cta { + width: 100%; + text-decoration: none; + @include media-query__small { + width: auto; + } + } +} diff --git a/src/stories/Library/Arrows/icon-arrow-ui/icon-arrow-ui-nav.svg b/src/stories/Library/Arrows/icon-arrow-ui/icon-arrow-ui-nav.svg new file mode 100644 index 000000000..0fce6f942 --- /dev/null +++ b/src/stories/Library/Arrows/icon-arrow-ui/icon-arrow-ui-nav.svg @@ -0,0 +1,9 @@ + + + diff --git a/src/stories/Library/Icons/icon-close-large/icon-close-large.svg b/src/stories/Library/Icons/icon-close-large/icon-close-large.svg new file mode 100644 index 000000000..fb9f0a84a --- /dev/null +++ b/src/stories/Library/Icons/icon-close-large/icon-close-large.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/stories/Library/Lists/list-description/list-description.scss b/src/stories/Library/Lists/list-description/list-description.scss index 543b3d983..79daf9a9c 100644 --- a/src/stories/Library/Lists/list-description/list-description.scss +++ b/src/stories/Library/Lists/list-description/list-description.scss @@ -40,13 +40,21 @@ dl.list-description.list-description--event { grid-template-columns: repeat(2, 1fr); gap: $s-md; align-items: start; + @include typography($typo__body-placeholder); + line-height: 120%; .list-description__item { grid-template-columns: 1fr; } .list-description__value { - font-weight: bold; + font-weight: $font__weight--semi-bold; + grid-gap: 8px; + gap: 8px; + } + .link-tag { + @include typography($typo__body-placeholder); + line-height: 120%; } @include media-query__small() { diff --git a/src/stories/Library/Modals/modal-facet-browser/FacetBrowser.tsx b/src/stories/Library/Modals/modal-facet-browser/FacetBrowser.tsx index fb8aeca11..36f1cc349 100644 --- a/src/stories/Library/Modals/modal-facet-browser/FacetBrowser.tsx +++ b/src/stories/Library/Modals/modal-facet-browser/FacetBrowser.tsx @@ -2,7 +2,7 @@ import Disclosure from "../../disclosure/Disclosure"; import { Button } from "../../Buttons/button/Button"; import Modal from "../Modal"; import facetBrowserDummyData from "./facet-browser-dummy-data"; -import { Tag } from "../../tag/Tag"; +import { TagButton } from "../../tag/tag-button/TagButton"; export type FacetBrowserProps = { title: string; @@ -44,7 +44,7 @@ const FacetBrowser: React.FC = ({ >
    {facet.tags.map((tag) => ( - {tag} + {tag} ))}
    - - - - ))} - - ); -}; - -declare global { - interface Window { - eventAccordion: ( - event: React.MouseEvent - ) => void; - } -} - -export default {}; diff --git a/src/stories/Library/accordion/accordion.scss b/src/stories/Library/accordion/accordion.scss deleted file mode 100644 index 5e20d97e9..000000000 --- a/src/stories/Library/accordion/accordion.scss +++ /dev/null @@ -1,70 +0,0 @@ -.accordion { - background-color: $color__global-secondary; -} - -.accordion__button-arrow { - transition: transform 0.3s; - transform: rotateZ(180deg); -} - -.accordion__button { - color: $color__text-primary-black; - border-width: 0; - border-color: transparent; - border-radius: 0; - background-color: transparent; - width: 100%; - text-align: left; - height: 100%; - cursor: pointer; - display: flex; - justify-content: space-between; - align-items: center; - border-top: 1px solid $color__global-tertiary-1; - - &[aria-expanded="true"] { - border-bottom: 1px solid $color__global-tertiary-1; - - .accordion__button-arrow { - transform: rotateZ(0deg); - } - } -} - -.accordion__row { - list-style-type: none; -} - -.accordion__header { - height: $s-3xl; - - button { - @extend %default-focus-visible; - } -} - -.accordion__body { - display: grid; - - a { - line-height: $s-xl; - padding-left: $s-2xl; - text-decoration: none; - - @include typography($typo__body-placeholder); - } - - &[hidden] { - display: none; - } -} - -.accordion__row:last-child { - .accordion__button { - border-bottom: 1px solid $color__global-tertiary-1; - } - - .accordion__body { - border-bottom: 1px solid $color__global-tertiary-1; - } -} diff --git a/src/stories/Library/accordion/accordionList.ts b/src/stories/Library/accordion/accordionList.ts deleted file mode 100644 index 02c19d077..000000000 --- a/src/stories/Library/accordion/accordionList.ts +++ /dev/null @@ -1,39 +0,0 @@ -const list = ["Om Bibliotekerne", "Online tilbud", "Kontakt"].map((header) => ({ - header, - content: [ - { - title: "Brug bibliotekerne", - href: "/", - }, - { - title: "Erstatninger og gebyrer", - href: "/", - }, - { - title: "Opret bruger", - href: "/", - }, - { - title: "Biblioteket - A til Å", - href: "/", - }, - { - title: "Internetadgang", - href: "/", - }, - { - title: "Print, scan og kopi", - href: "/", - }, - { - title: "Booking af lokaler", - href: "/", - }, - { - title: "Nyhedsbrev", - href: "/", - }, - ], -})); - -export default list; diff --git a/src/stories/Library/accordion/initaccordion.js b/src/stories/Library/accordion/initaccordion.js deleted file mode 100644 index 7a3363558..000000000 --- a/src/stories/Library/accordion/initaccordion.js +++ /dev/null @@ -1,31 +0,0 @@ -function accordion(event) { - if (!event?.target?.closest) { - // eslint-disable-next-line - console.info("Accordion - No event target"); - return; - } - - const btn = event.target.closest("[data-accordion-trigger]"); - - if (!btn?.getAttribute) { - // eslint-disable-next-line - console.info("Accordion - Can't find accordion row"); - return; - } - - if (!btn.parentNode?.nextElementSibling) { - // eslint-disable-next-line - console.info("Accordion - Can't find next sibling to parentNode"); - return; - } - - const isOpen = btn.getAttribute("aria-expanded") === "true"; - const target = btn.parentNode.nextElementSibling; - - btn.setAttribute("aria-expanded", !isOpen); - target.hidden = isOpen; -} - -window.eventAccordion = (e) => { - accordion(e); -}; diff --git a/src/stories/Library/article-header/ArticleHeader.tsx b/src/stories/Library/article-header/ArticleHeader.tsx index 9604e4095..9f64711d6 100644 --- a/src/stories/Library/article-header/ArticleHeader.tsx +++ b/src/stories/Library/article-header/ArticleHeader.tsx @@ -1,23 +1,43 @@ import { FC } from "react"; -import RowButtons from "../Buttons/row-button/RowButtons"; import ArrowLink from "../links/arrow-link/ArrowLink"; +import Tag from "../tag/Tag"; +import HorizontalTermLine, { + HorizontalTermLineProps, +} from "../horizontal-term-line/HorizontalTermLine"; -type ArticleHeaderProps = { +export type ArticleHeaderProps = { title: string; subtitle: string; + category?: string; author: string; date: string; + tags: string[]; }; const ArticleHeader: FC = ({ title, subtitle, + category, author, date, + tags, }) => { + const tagData: HorizontalTermLineProps = { + title: "Tags", + linkList: tags.map((tag) => { + return { text: tag, url: "#" }; + }), + }; return (
    + {category && ( +
    + + {category} + +
    + )}

    {title}

    {subtitle}

    @@ -27,7 +47,9 @@ const ArticleHeader: FC = ({

    - +
    + +
    ); }; diff --git a/src/stories/Library/article-header/article-header.scss b/src/stories/Library/article-header/article-header.scss index 4cd066de3..3c2f15879 100644 --- a/src/stories/Library/article-header/article-header.scss +++ b/src/stories/Library/article-header/article-header.scss @@ -1,6 +1,6 @@ .article-header { @include layout-container; - @include vertical-spacing; + @include block-spacing(); display: grid; gap: $s-xl; position: relative; diff --git a/src/stories/Library/autosuggest-material/AutosuggestMaterial.tsx b/src/stories/Library/autosuggest-material/AutosuggestMaterial.tsx index 70b8fec52..486f186d4 100644 --- a/src/stories/Library/autosuggest-material/AutosuggestMaterial.tsx +++ b/src/stories/Library/autosuggest-material/AutosuggestMaterial.tsx @@ -20,7 +20,7 @@ export const AutosuggestMaterial: React.FC = ({ return (
  • - +
    {item.title} diff --git a/src/stories/Library/card-grid/CardGrid.stories.tsx b/src/stories/Library/card-grid/CardGrid.stories.tsx index 45bb5e21d..737062ec9 100644 --- a/src/stories/Library/card-grid/CardGrid.stories.tsx +++ b/src/stories/Library/card-grid/CardGrid.stories.tsx @@ -1,30 +1,7 @@ import { ComponentStory, ComponentMeta } from "@storybook/react"; import { withDesign } from "storybook-addon-designs"; import CardGrid from "./CardGrid"; -import Card from "../card/Card"; -import ImageCredited from "../image-credited/ImageCredited"; - -const imageUrl = - "https://images.unsplash.com/photo-1568667256549-094345857637?q=80&w=2815&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"; -const image = ; - -const card = ( - -); - -const cardNoImage = ( - -); +import { card, cardNoImage } from "./card-grid-data"; export default { title: "Library / Card grid ('Nyhedskomponent')", @@ -66,6 +43,7 @@ const Few = Template.bind({}); Few.args = { title: undefined, linkText: undefined, + items: [cardNoImage, card, cardNoImage], }; export { Many, Few }; diff --git a/src/stories/Library/card-grid/card-grid-data.tsx b/src/stories/Library/card-grid/card-grid-data.tsx new file mode 100644 index 000000000..fbcc589b9 --- /dev/null +++ b/src/stories/Library/card-grid/card-grid-data.tsx @@ -0,0 +1,25 @@ +import Card from "../card/Card"; +import ImageCredited from "../image-credited/ImageCredited"; + +const imageUrl = + "https://images.unsplash.com/photo-1568667256549-094345857637?q=80&w=2815&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"; + +const image = ; + +export const card = ( + +); + +export const cardNoImage = ( + +); diff --git a/src/stories/Library/card-grid/card-grid.scss b/src/stories/Library/card-grid/card-grid.scss index d908779c0..e4640e54b 100644 --- a/src/stories/Library/card-grid/card-grid.scss +++ b/src/stories/Library/card-grid/card-grid.scss @@ -4,7 +4,15 @@ $_card-grid-gap: $s-lg; .card-grid { - @include layout-container("none"); + @include layout-container(); + + .card__placeholder-text { + @include typography($typo__card-placeholder--grid); + } +} + +.card-grid--full-width { + @include layout-container(none); } .card-grid__header { @@ -85,6 +93,8 @@ $_card-grid-gap: $s-lg; ); // The card widths on the largest (desktop) screen. + // These sizes are only being used on full-width grids, as the cards will + // become too massive otherwise. $_card-widths--large: ( "x-large": 45%, "small": 15%, @@ -95,6 +105,7 @@ $_card-grid-gap: $s-lg; @each $key, $name in $_card-patterns { // The design is very specific about the masonry design. See the sizes // defined in the arrays above, which we loop through here. + // stylelint-disable max-nesting-depth -- I know it's awful nesting, but i have no choice. &:nth-child(#{$key}) { width: map_get($_card-widths--small, $name); @@ -102,8 +113,10 @@ $_card-grid-gap: $s-lg; width: map_get($_card-widths--medium, $name); } - @include media-query__large { - width: map_get($_card-widths--large, $name); + .card-grid--full-width & { + @include media-query__large { + width: map_get($_card-widths--large, $name); + } } .card { @@ -114,7 +127,6 @@ $_card-grid-gap: $s-lg; // placeholder box, that there is no space for the text, on larger // screens. On smaller screens, it takes up 50% of the page, so // there, there is plenty of space. - // stylelint-disable max-nesting-depth -- I know it's awful nesting, but i have no choice. @if ($name == "small") { @include media-query__small { .card__placeholder-text { @@ -122,8 +134,8 @@ $_card-grid-gap: $s-lg; } } } - // stylelint-enable max-nesting-depth } } + // stylelint-enable max-nesting-depth } } diff --git a/src/stories/Library/card-list-page/FacetLine.tsx b/src/stories/Library/card-list-page/FacetLine.tsx index a465bace6..eaed5b487 100644 --- a/src/stories/Library/card-list-page/FacetLine.tsx +++ b/src/stories/Library/card-list-page/FacetLine.tsx @@ -1,6 +1,6 @@ import { FC } from "react"; import { Dropdown } from "../dropdown/Dropdown"; -import { Tag } from "../tag/Tag"; +import { TagButton } from "../tag/tag-button/TagButton"; export type FacetLineItem = { title: string; @@ -20,9 +20,9 @@ const FacetLine: FC = ({ items }) => { if (type === "term") { return (
  • - + {title} ({score}) - +
  • ); } @@ -46,7 +46,7 @@ const FacetLine: FC = ({ items }) => { return null; })}
  • - + Flere filtre + + Flere filtre
  • ); diff --git a/src/stories/Library/card-list-page/FacetLineSelectedTerms.tsx b/src/stories/Library/card-list-page/FacetLineSelectedTerms.tsx index f411b88ea..d9cd67b35 100644 --- a/src/stories/Library/card-list-page/FacetLineSelectedTerms.tsx +++ b/src/stories/Library/card-list-page/FacetLineSelectedTerms.tsx @@ -1,5 +1,5 @@ import { FC } from "react"; -import { Tag } from "../tag/Tag"; +import { TagButton } from "../tag/tag-button/TagButton"; import { FacetLineItem } from "./FacetLine"; export interface FacetLineSelectedProps { @@ -11,9 +11,9 @@ const FacetLineSelectedTerms: FC = ({ items }) => {
      {items.map(({ title }) => (
    • - + {title} - +
    • ))}
    diff --git a/src/stories/Library/card/card.scss b/src/stories/Library/card/card.scss index fc9c813d8..0b6c2df71 100644 --- a/src/stories/Library/card/card.scss +++ b/src/stories/Library/card/card.scss @@ -11,14 +11,7 @@ } .card__placeholder-text { - @include typography($typo__card-placeholder--small); - @extend %identity-placeholder-inner-padding; - display: flex; - height: 100%; - overflow: hidden; - - align-items: end; - color: $color__text-primary-white; + @extend %identity-placeholder-text; } .card--has-image { @@ -119,16 +112,20 @@ } .card__media { + @extend %identity-placeholder; + aspect-ratio: 1/1; } } %card-variant--small, .card[data-variant="small"] { - @extend %card-variant--x-large; - width: 206px; + .card__media { + aspect-ratio: 1/1; + } + .card__tags, .card__media { margin-bottom: $s-xs; @@ -137,8 +134,6 @@ // On desktop sizes this small, there is no space for placeholder text, and // extra tags, but we can still show it for screenreaders. @include media-query__name($breakpoint__large-card) { - width: 206px; - .card__placeholder-text { font-size: 0; } @@ -155,7 +150,11 @@ %card-variant--medium, .card[data-variant="medium"] { - width: 321px; + width: 200px; + + @include media-query__name($breakpoint__large-card) { + width: 321px; + } .card__media { // Odd aspect ratio, taken from the design. diff --git a/src/stories/Library/cover/Cover.stories.tsx b/src/stories/Library/cover/Cover.stories.tsx index e4f4e218e..6d1be133a 100644 --- a/src/stories/Library/cover/Cover.stories.tsx +++ b/src/stories/Library/cover/Cover.stories.tsx @@ -69,7 +69,7 @@ CoverLinked.args = { size: "small", tint: "80", coverUrl: "/", - description: "Cover of Audrey Hepburn", + alt: "Cover of Audrey Hepburn", }; export const SrcNotWork = Template.bind({}); diff --git a/src/stories/Library/cover/Cover.tsx b/src/stories/Library/cover/Cover.tsx index c20552c68..5f2aee34b 100644 --- a/src/stories/Library/cover/Cover.tsx +++ b/src/stories/Library/cover/Cover.tsx @@ -10,7 +10,7 @@ const Cover: FC = ({ src, tint, coverUrl, - description, + alt, shadow, ariaLabel = "Link to the material", }) => { @@ -25,7 +25,7 @@ const Cover: FC = ({ ), }; - if (coverUrl && description) { + if (coverUrl && alt) { // Images inside links must have an non-empty alt text to meet accessibility requirements. // Only render the cover as a link if we have both an url and a description. return ( @@ -39,7 +39,7 @@ const Cover: FC = ({ setImageLoaded(true)} src={src} - description={description} + alt={alt} size={size} animate={animate} tint={tint} @@ -54,7 +54,7 @@ const Cover: FC = ({ setImageLoaded(true)} src={src} - description={description} + alt={alt} size={size} animate={animate} tint={tint} diff --git a/src/stories/Library/cover/CoverImage.tsx b/src/stories/Library/cover/CoverImage.tsx index 1f451f269..05c250c51 100644 --- a/src/stories/Library/cover/CoverImage.tsx +++ b/src/stories/Library/cover/CoverImage.tsx @@ -8,7 +8,7 @@ type CoverState = { const CoverImage: FC = ({ src, - description, + alt, animate, setImageLoaded, shadow, @@ -27,10 +27,13 @@ const CoverImage: FC = ({ { "cover__img--animate": animate, }, - { "cover__img--shadow": shadow } + { + "cover__img--shadow-small": shadow === "small", + "cover__img--shadow-medium": shadow === "medium", + } )} src={src} - alt={description || ""} + alt={alt || ""} /> ); }; diff --git a/src/stories/Library/cover/cover.scss b/src/stories/Library/cover/cover.scss index b6992c411..e56e3172f 100644 --- a/src/stories/Library/cover/cover.scss +++ b/src/stories/Library/cover/cover.scss @@ -83,7 +83,13 @@ a.cover { } &.cover__img--shadow { - filter: drop-shadow(0 $s-xs 40px rgb(0 0 0 / 15%)); + &-small { + filter: drop-shadow(0 $s-xs 40px rgb(0 0 0 / 15%)); + } + + &-medium { + filter: drop-shadow(0 $s-xs 40px rgb(0 0 0 / 25%)); + } } } // In this case we do not want to use kebab case diff --git a/src/stories/Library/cover/types.ts b/src/stories/Library/cover/types.ts index b5b59b7e6..504f43408 100644 --- a/src/stories/Library/cover/types.ts +++ b/src/stories/Library/cover/types.ts @@ -4,7 +4,7 @@ export type CoverProps = { size: "xsmall" | "small" | "medium" | "large" | "xlarge"; tint?: "20" | "40" | "80" | "100" | "120"; coverUrl?: string; - description?: string; - shadow?: boolean; + alt?: string; + shadow?: "small" | "medium"; ariaLabel?: string; }; diff --git a/src/stories/Library/disclosure/Disclosure.stories.tsx b/src/stories/Library/disclosure/Disclosure.stories.tsx index 937c0fe36..a6f6fbd0a 100644 --- a/src/stories/Library/disclosure/Disclosure.stories.tsx +++ b/src/stories/Library/disclosure/Disclosure.stories.tsx @@ -29,6 +29,11 @@ export default { options: ["Various", "Receipt", "Create", "Profile"], control: { type: "select" }, }, + contentPadding: { + name: "Extra content padding", + defaultValue: false, + control: { type: "boolean" }, + }, withAvailability: { name: "Is with availability label?", defaultValue: false, @@ -52,3 +57,13 @@ export const WithAvailabilityLabel = Template.bind({}); WithAvailabilityLabel.args = { withAvailability: true, }; + +export const WithoutIcon = Template.bind({}); +WithoutIcon.args = { + icon: undefined, +}; + +export const WithExtraContentPadding = Template.bind({}); +WithExtraContentPadding.args = { + contentPadding: true, +}; diff --git a/src/stories/Library/disclosure/Disclosure.tsx b/src/stories/Library/disclosure/Disclosure.tsx index 07e52cb81..884ba0229 100644 --- a/src/stories/Library/disclosure/Disclosure.tsx +++ b/src/stories/Library/disclosure/Disclosure.tsx @@ -12,6 +12,7 @@ export type DisclosureProps = { fullWidth?: boolean; removeHeadlinePadding?: boolean; headingLevel: HeadingLevelType; + contentPadding?: boolean; }; const Disclosure: React.FC = ({ @@ -22,6 +23,7 @@ const Disclosure: React.FC = ({ fullWidth = false, removeHeadlinePadding, headingLevel, + contentPadding = false, }) => { const [isOpen, setIsOpen] = useState(false); return ( @@ -66,7 +68,11 @@ const Disclosure: React.FC = ({ }`} /> - {children} + {contentPadding ? ( +
    {children}
    + ) : ( + children + )} ); }; diff --git a/src/stories/Library/disclosure/disclosure.scss b/src/stories/Library/disclosure/disclosure.scss index b02a849d1..bed11f975 100644 --- a/src/stories/Library/disclosure/disclosure.scss +++ b/src/stories/Library/disclosure/disclosure.scss @@ -95,6 +95,21 @@ } } +.disclosure--paragraph-width .disclosure__expand { + transition: transform 0.3s ease-in-out; +} + +.disclosure--paragraph-width { + @include layout-container($block-max-width__medium); +} + +.disclosure__content-padding { + padding: $s-md; + @include media-query__small { + padding: $s-xl; + } +} + .disclosure[open] .disclosure__expand { transition: transform 0.3s ease-in-out; transform: scaleY(-1); diff --git a/src/stories/Library/dropdown/dropdown.scss b/src/stories/Library/dropdown/dropdown.scss index 3cb52f8be..1b5bf79bd 100644 --- a/src/stories/Library/dropdown/dropdown.scss +++ b/src/stories/Library/dropdown/dropdown.scss @@ -1,3 +1,5 @@ +$_dropdown-icon-size: 50px; + .dropdown { width: 100%; position: relative; @@ -17,18 +19,22 @@ } .dropdown__select { + $_padding: 20px; + appearance: none; -webkit-appearance: none; min-width: 230px; width: 100%; - height: 50px; + height: $_dropdown-icon-size; cursor: pointer; background-color: transparent; color: $color__global-black; border-radius: 0; border: 1px solid; border-color: inherit; - padding: 0 50px 0 20px; + padding: 0; + padding-left: $_padding; + padding-right: $_dropdown-icon-size + $_padding; text-overflow: ellipsis; white-space: nowrap; @@ -51,8 +57,8 @@ position: absolute; right: 0; top: 0; - height: 50px; - width: 50px; + height: $_dropdown-icon-size; + width: $_dropdown-icon-size; display: flex; justify-content: center; align-items: center; diff --git a/src/stories/Library/event-description/EventDescription.tsx b/src/stories/Library/event-description/EventDescription.tsx index 8b71f6b06..3c964dfba 100644 --- a/src/stories/Library/event-description/EventDescription.tsx +++ b/src/stories/Library/event-description/EventDescription.tsx @@ -8,28 +8,29 @@ import ListDescription, { } from "../Lists/list-description/ListDescription"; export type EventDescriptionProps = { - descriptionTitle: string; listDescriptionData: ListData; horizontalTermLineData: HorizontalTermLineProps[]; descriptionDescription: string; }; const EventDescription: FC = ({ - descriptionTitle, descriptionDescription, horizontalTermLineData, listDescriptionData, }) => { return (
    -

    {descriptionTitle}

    {descriptionDescription}

    {horizontalTermLineData.map((item, index) => ( - + ))}
    diff --git a/src/stories/Library/event-description/event-description.scss b/src/stories/Library/event-description/event-description.scss index 25f41f15e..c3c0dd82d 100644 --- a/src/stories/Library/event-description/event-description.scss +++ b/src/stories/Library/event-description/event-description.scss @@ -1,9 +1,8 @@ .event-description { @include layout-container; - @include vertical-spacing; + @include block-spacing(); @include media-query__small { - @include layout-container($layout__max-width--event-description); - @include vertical-spacing; + @include layout-container($block-max-width__medium); display: grid; column-gap: $s-xl; grid-template-columns: 2fr 1fr; @@ -21,6 +20,7 @@ } .event-description__description { + @extend %rich-text; @include typography($typo__body-large); line-height: 24px; diff --git a/src/stories/Library/event-header/EventHeader.tsx b/src/stories/Library/event-header/EventHeader.tsx index 9e1d63e1d..a915528fd 100644 --- a/src/stories/Library/event-header/EventHeader.tsx +++ b/src/stories/Library/event-header/EventHeader.tsx @@ -1,5 +1,5 @@ import { FC } from "react"; -import { Tag } from "../tag/Tag"; +import Tag from "../tag/Tag"; import ImageCredited from "../image-credited/ImageCredited"; type EventHeaderProps = { @@ -11,20 +11,17 @@ type EventHeaderProps = { const EventHeader: FC = ({ title, date, image }) => { return (
    -
    -
    - Udstilling -
    +
    + + design & teknologi +

    {title}

    - + Køb billet
    -
    +
    = ({ {title}
    - - {tagText} - + {tagText && ( + + {tagText} + + )}
    {date}

    {title}

    -

    {description}

    +
    +

    {description}

    +

    {location}

    diff --git a/src/stories/Library/event-list-item/EventListItemStacked.stories.tsx b/src/stories/Library/event-list-item/EventListItemStacked.stories.tsx new file mode 100644 index 000000000..d52607cc2 --- /dev/null +++ b/src/stories/Library/event-list-item/EventListItemStacked.stories.tsx @@ -0,0 +1,36 @@ +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import EventListItemStacked from "./EventListItemStacked"; + +export default { + title: "Library / Event List Item Stacked", + component: EventListItemStacked, + decorators: [withDesign], + argTypes: { + date: { + defaultValue: "01 Feb 2023", + control: { type: "text" }, + }, + time: { + defaultValue: "19:30 - 21:00", + control: { type: "text" }, + }, + href: { + defaultValue: "/", + control: { type: "text" }, + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/0TDev6dKbbWlWQQ7w5yAOw/Gentagende-arrangementer---legeplads?type=design&node-id=0-1&mode=design", // This should be change when the design is in the correct figma + }, + layout: "full", + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const Default = Template.bind({}); diff --git a/src/stories/Library/event-list-item/EventListItemStacked.tsx b/src/stories/Library/event-list-item/EventListItemStacked.tsx new file mode 100644 index 000000000..4b0b51c27 --- /dev/null +++ b/src/stories/Library/event-list-item/EventListItemStacked.tsx @@ -0,0 +1,29 @@ +import { FC } from "react"; +import { ReactComponent as ArrowSmallRight } from "../Arrows/icon-arrow-ui/icon-arrow-ui-small-right.svg"; + +interface EventListItemStackedProps { + href: string; + time: string; + date: string; +} + +const EventListItemStacked: FC = ({ + href = "#", + time, + date, +}) => { + return ( + + + + + ); +}; + +export default EventListItemStacked; diff --git a/src/stories/Library/event-list-item/event-list-item.scss b/src/stories/Library/event-list-item/event-list-item.scss index e755fdd3c..31094f09d 100644 --- a/src/stories/Library/event-list-item/event-list-item.scss +++ b/src/stories/Library/event-list-item/event-list-item.scss @@ -1,17 +1,63 @@ -.event-list-item { +$_desktop-content-rows: 5; +$_event-list-item--image-height: 166px; +$_event-list-item--image-width: 222px; +$_event-list-item--max-width: 1126px; +$_stacked-reduce-width: 20px; + +@mixin event-list-item-stacked-shadow-box { + position: relative; + &::before { + content: ""; + background-color: $color__global-white; + position: absolute; + width: calc(100% - $_stacked-reduce-width); + height: 100%; + left: 50%; + top: 0; + transform: translateX(-50%); + box-shadow: inset 0 10px 10px -10px rgba(0, 0, 0, 0.1); + } +} + +@mixin event-list-item-grid { @include show-svg-on-hover(); + @include layout-container($block-max-width__large); text-decoration: none; display: grid; - padding: $s-lg; + grid-template-columns: 1fr; + + @include media-query__small { + grid-template-columns: $_event-list-item--image-width 1fr; + gap: $s-lg; + } + @include media-query__medium { + grid-template-columns: + $_event-list-item--image-width 1fr + max-content; + gap: $s-2xl; + } +} + +@mixin event-list-item-content-grid { + display: grid; + grid-template-columns: 1fr $s-2xl 120px; +} + +.event-list-item { + @include event-list-item-grid; + padding-top: $s-lg; + padding-bottom: $s-lg; background-color: $color__global-white; margin: 0 auto; grid-template-areas: "image" "content"; grid-template-rows: auto; - row-gap: $s-md; - @include layout-container($padding: $s-lg); + gap: $s-md; +} +.event-list-item, +.event-list-item-stacked { // Extending display none, as mixin show-svg-on-hover // is only working up to __small breakpoint @include media-query__medium("max-width") { @@ -30,52 +76,49 @@ } .event-list-item__image { - position: absolute; - z-index: $z-10; - top: 0; - right: 0; - bottom: 0; - left: 0; width: 100%; height: 100%; object-fit: cover; + position: relative; + z-index: $z-10; } .event-list-item__content { - @include typography($typo__body-medium); display: grid; grid-template-areas: - "tag date" - "title title" - "description description" - "location schedule"; - row-gap: $s-sm; + "tag date date" + "title title title" + "description description description" + "location schedule schedule"; + @include typography($typo__small-caption); } .event-list-item__tag { grid-area: tag; - @include typography($typo__small-caption); width: max-content; + margin-bottom: $s-sm; +} +.event-list-item__pricing { + font-weight: $font__weight--semi-bold; } .event-list-item__date { grid-area: date; - @include typography($typo__small-caption); - text-align: right; + justify-self: end; } .event-list-item__title { grid-area: title; @include typography($typo__h4); @extend %text-truncate; - margin-bottom: $s-sm; } .event-list-item__description { grid-area: description; - @include typography($typo__small-caption); - @include text-ellipsis-truncation(3); - margin-bottom: $s-xl; + margin-bottom: $s-lg; + p { + @include text-ellipsis-truncation(3); + } } .event-list-item__location-wrapper { @@ -96,32 +139,68 @@ display: flex; flex-direction: column; align-items: flex-end; + justify-content: flex-end; + @include typography($typo__body-placeholder); } -.event-list-item__time { - @include typography($typo__body-placeholder); +.event-list-item-stacked { + @include event-list-item-grid; + @include event-list-item-stacked-shadow-box; + padding-top: $s-sm; + padding-bottom: $s-sm; + grid-template-areas: "contentStacked"; + align-items: center; +} + +.event-list-item-stacked__content { + @include typography($typo__small-caption); + @include event-list-item-content-grid; + z-index: $z-10; + grid-area: contentStacked; + grid-template-areas: "dateStacked . timeStacked"; +} + +.event-list-item-stacked__date { + grid-area: dateStacked; +} + +.event-list-item-stacked__time { + grid-area: timeStacked; + justify-self: end; +} + +.event-list-item-stacked > svg { + z-index: $z-10; + grid-area: arrowStacked; } @include media-query__small { .event-list-item { grid-template-areas: "image content"; - grid-template-columns: 222px 1fr; - gap: $s-2xl; } .event-list-item__content { + @include event-list-item-content-grid; grid-area: content; - grid-template-columns: 1fr 1fr $s-2xl max-content; grid-template-areas: - "tag tag . schedule" - "date date . schedule" - "title title . schedule" - "description description . schedule" - "location location . schedule"; + "tag . schedule" + "date . schedule" + "title . schedule" + "description . schedule" + "location . schedule"; + grid-template-rows: repeat( + $_desktop-content-rows, + minmax( + calc($_event-list-item--image-height / $_desktop-content-rows), + auto + ) + ); } + .event-list-item__image-container { - max-width: 222px; grid-area: image; + max-height: $_event-list-item--image-height; + min-height: $_event-list-item--image-height; } .event-list-item__tag { @@ -130,49 +209,65 @@ } .event-list-item__date { - text-align: initial; - align-self: end; + justify-self: start; + align-self: center; } .event-list-item__title { - margin-bottom: unset; grid-area: title; + line-height: 100%; } .event-list-item__description { margin-bottom: unset; - @include text-ellipsis-truncation(2); grid-area: description; + + p { + @include text-ellipsis-truncation(2); + } } .event-list-item__schedule { - align-self: center; - margin-bottom: $s-md; - align-items: flex-start; grid-area: schedule; + grid-row: 3 / span 3; + justify-content: unset; } - .event-list-item__location-wrapper { - margin-top: $s-md; - } - - .event-list-item__time { - grid-column: 4; + .event-list-item-stacked { + grid-template-areas: ". contentStacked"; } - .event-list-item__pricing { - grid-column: 4; + .event-list-item-stacked__content { + grid-template-areas: "dateStacked . timeStacked"; } } @include media-query__medium { .event-list-item { grid-template-areas: "image content arrow"; - grid-template-columns: 222px 1fr max-content; - gap: $s-2xl; + } + + .event-list-item__schedule { + align-items: flex-start; } .event-list-item > svg { grid-area: arrow; } + + .event-list-item-stacked { + grid-template-areas: ". contentStacked arrowStacked"; + } + + .event-list-item-stacked__content { + grid-template-areas: "dateStacked . timeStacked"; + } + + .event-list-item-stacked__time { + justify-self: start; + } + + .event-list-item-stacked > svg { + transform: translateX(-#{calc($_stacked-reduce-width / 2)}); + } } diff --git a/src/stories/Library/event-list/EventList.tsx b/src/stories/Library/event-list/EventList.tsx index d9d87ce9f..5bffd113b 100644 --- a/src/stories/Library/event-list/EventList.tsx +++ b/src/stories/Library/event-list/EventList.tsx @@ -1,7 +1,9 @@ +import clsx from "clsx"; import { EventListItem, EventListItemProps, } from "../event-list-item/EventListItem"; +import EventListItemStacked from "../event-list-item/EventListItemStacked"; type EventListProps = { events: EventListItemProps[]; @@ -10,11 +12,27 @@ type EventListProps = { const EventList: React.FC = ({ events }) => { return (
      - {events.map((event, index) => ( -
    • - -
    • - ))} + {events.map((event, index) => { + // Check if current event should be stacked with the previous one + const isStacked = + index > 0 && + events[index].eventSeriesId === events[index - 1].eventSeriesId; + + return ( +
    • + {isStacked ? ( + + ) : ( + + )} +
    • + ); + })}
    ); }; diff --git a/src/stories/Library/event-list/EventListData.ts b/src/stories/Library/event-list/EventListData.ts index 646febe44..6915540c3 100644 --- a/src/stories/Library/event-list/EventListData.ts +++ b/src/stories/Library/event-list/EventListData.ts @@ -2,54 +2,145 @@ import { EventListItemProps } from "../event-list-item/EventListItem"; const eventListData: EventListItemProps[] = [ { + eventSeriesId: "a", image: - "https://plus.unsplash.com/premium_photo-1696886122527-e4303b76aa8f?q=80&w=5156&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + "https://images.unsplash.com/photo-1549277513-f1b32fe1f8f5?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + tagText: "Foredrag", title: "Kunst og kultur i middelalderen", - description: "En dybdegående analyse af kunst og kultur i middelalderen.", - date: "10 Mar 2023", - time: "15:00 - 17:00", + description: "En dybdegåendenalysef kunst og kultur i middelalderen.", location: "Kulturhuset", price: "50 - 100 KR", href: "/", + date: "2023-01-10", + time: "15:00 - 17:00", }, - { + eventSeriesId: "b", image: - "https://plus.unsplash.com/premium_photo-1696886122527-e4303b76aa8f?q=80&w=5156&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - tagText: "Kunst", - title: "Historien om jazz", - description: "Oplev jazzens rejse gennem tiderne.", - date: "05 May 2023", - time: "20:00 - 22:00", - location: "Jazzklubben", - price: "90 KR", + "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + tagText: "arrangement", + title: "Fars Legestue", + description: "Kom forbi til hygge i Fars Legestue", + location: "Hovedeblibloteket", + price: "60 KR", href: "/", + date: "2023-01-12", + time: "18:00 - 20:00", }, { + eventSeriesId: "b", image: - "https://plus.unsplash.com/premium_photo-1696886122527-e4303b76aa8f?q=80&w=5156&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - tagText: "Liteeratur og poesi", - title: "Moderne litteratur workshop", - description: "Workshop om moderne litteratur og dens indflydelse.", - date: "18 Apr 2023", + "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + tagText: "arrangement", + title: "Fars Legestue", + description: "Kom forbi til hygge i Fars Legestue", + location: "Hovedeblibloteket", + price: "60 KR", + href: "/", + date: "2023-01-13", time: "18:00 - 20:00", - location: "Litteraturhuset", - price: "Gratis - 200 KR", + }, + { + eventSeriesId: "b", + image: + "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + tagText: "arrangement", + title: "Fars Legestue", + description: "Kom forbi til hygge i Fars Legestue", + location: "Hovedeblibloteket", + price: "60 KR", href: "/", + date: "2023-01-14", + time: "18:00 - 20:00", }, { + eventSeriesId: "b", image: - "https://plus.unsplash.com/premium_photo-1696886122527-e4303b76aa8f?q=80&w=5156&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", - tagText: "Filosofi", - title: "Filosofi i det 21. århundrede", - description: "En samtale om moderne filosofiske strømninger.", - date: "23 Jun 2023", - time: "14:00 - 16:00", - location: "Filosofisk Forum", + "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + tagText: "arrangement", + title: "Fars Legestue", + description: "Kom forbi til hygge i Fars Legestue", + location: "Hovedeblibloteket", price: "60 KR", href: "/", + date: "2023-01-15", + time: "18:00 - 20:00", }, -]; + { + eventSeriesId: "a", + image: + "https://images.unsplash.com/photo-1549277513-f1b32fe1f8f5?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + + tagText: "Foredrag", + title: "Kunst og kultur i middelalderen", + description: "En dybdegåendenalysef kunst og kultur i middelalderen.", + location: "Kulturhuset", + price: "50 - 100 KR", + href: "/", + date: "2023-01-20", + time: "15:00 - 17:00", + }, + { + eventSeriesId: "a", + image: + "https://images.unsplash.com/photo-1549277513-f1b32fe1f8f5?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + + tagText: "Foredrag", + title: "Kunst og kultur i middelalderen", + description: "En dybdegåendenalysef kunst og kultur i middelalderen.", + location: "Kulturhuset", + price: "50 - 100 KR", + href: "/", + date: "2023-01-21", + time: "15:00 - 17:00", + }, + { + eventSeriesId: "a", + image: + "https://images.unsplash.com/photo-1549277513-f1b32fe1f8f5?q=80&w=1470&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + + tagText: "Foredrag", + title: "Kunst og kultur i middelalderen", + description: "En dybdegåendenalysef kunst og kultur i middelalderen.", + location: "Kulturhuset", + price: "50 - 100 KR", + href: "/", + date: "2023-01-25", + time: "15:00 - 17:00", + }, + { + eventSeriesId: "b", + image: + "https://images.unsplash.com/photo-1502086223501-7ea6ecd79368?q=80&w=1438&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D", + tagText: "arrangement", + title: "Fars Legestue", + description: "Kom forbi til hygge i Fars Legestue", + location: "Hovedeblibloteket", + price: "60 KR", + href: "/", + date: "2023-01-30", + time: "18:00 - 20:00", + }, +] + .sort((a, b) => { + const dateA = new Date(a.date); + const dateB = new Date(b.date); + return dateA.getTime() - dateB.getTime(); + }) + .map((event) => { + const date = new Date(event.date); + const formattedDate = date.toLocaleDateString("da-DK", { + // weekday: "long", + year: "numeric", + month: "short", + day: "numeric", + }); + + return { + ...event, + date: formattedDate, + }; + }); export default eventListData; diff --git a/src/stories/Library/event-list/event-list.scss b/src/stories/Library/event-list/event-list.scss index 32e640bca..f9b0bac59 100644 --- a/src/stories/Library/event-list/event-list.scss +++ b/src/stories/Library/event-list/event-list.scss @@ -1,8 +1,13 @@ .event-list { - @include layout-container; - @include vertical-spacing(0, $s-xl); + @include layout-container($block-max-width__large); + + margin-top: $s-lg; } .event-list__item { list-style: none; margin-bottom: $s-md; } + +.event-list__item--stacked { + margin-top: -$s-md; +} diff --git a/src/stories/Library/footer-accordions/FooterAccordion.tsx b/src/stories/Library/footer-accordions/FooterAccordion.tsx new file mode 100644 index 000000000..3e74eba21 --- /dev/null +++ b/src/stories/Library/footer-accordions/FooterAccordion.tsx @@ -0,0 +1,45 @@ +import { FC, useState } from "react"; +import { clsx } from "clsx"; +import { FooterColumnType } from "../footer-colums/FooterColumn"; + +type FooterAccordionProps = FooterColumnType & { + open?: boolean; +}; + +const FooterAccordion: FC = ({ + title, + content, + open = false, +}) => { + const [isOpen, setIsOpen] = useState(open); + const toggleAccordion = () => setIsOpen(!isOpen); + + return ( + <> +

    + +

    +
    + + ); +}; + +export default FooterAccordion; diff --git a/src/stories/Library/footer-accordions/FooterAccordions.tsx b/src/stories/Library/footer-accordions/FooterAccordions.tsx new file mode 100644 index 000000000..4c166440f --- /dev/null +++ b/src/stories/Library/footer-accordions/FooterAccordions.tsx @@ -0,0 +1,22 @@ +import { FC } from "react"; +import FooterAccordion from "./FooterAccordion"; +import { FooterColumnType } from "../footer-colums/FooterColumn"; + +export type FooterAccordionsType = { + footerContent: FooterColumnType[]; +}; + +const FooterAccordions: FC = ({ footerContent }) => { + // use the logic in initaccordion.js to initialize the accordion ind drupal + return ( +
      + {footerContent.map(({ title, content }, i) => ( +
    • + +
    • + ))} +
    + ); +}; + +export default FooterAccordions; diff --git a/src/stories/Library/footer-accordions/footer-accordions.js b/src/stories/Library/footer-accordions/footer-accordions.js new file mode 100644 index 000000000..a5ce35055 --- /dev/null +++ b/src/stories/Library/footer-accordions/footer-accordions.js @@ -0,0 +1,21 @@ +document.addEventListener("DOMContentLoaded", () => { + const accordions = document.querySelector("[data-footer-accordions]"); + + accordions.addEventListener("click", (e) => { + const btn = e.target.closest("[data-footer-accordion-trigger]"); + + if (!btn) return; + + const isOpen = btn.getAttribute("aria-expanded") === "true"; + const target = btn.parentNode.nextElementSibling; + + btn.setAttribute("aria-expanded", String(!isOpen)); + + // Toggle the class based on the isOpen value + if (isOpen) { + target.classList.add("footer__content--hidden"); + } else { + target.classList.remove("footer__content--hidden"); + } + }); +}); diff --git a/src/stories/Library/footer-accordions/footer-accordions.scss b/src/stories/Library/footer-accordions/footer-accordions.scss new file mode 100644 index 000000000..146b03162 --- /dev/null +++ b/src/stories/Library/footer-accordions/footer-accordions.scss @@ -0,0 +1,55 @@ +$footer-content-width: $s-2xl; + +// Ensure the footer accordions span the entire width +// by removing the default padding from .internal-pagefold-parent +.footer-accordions { + margin: 0 -50px; +} + +.footer-accordion .footer__content { + padding-top: $s-md; + padding-left: $footer-content-width; + padding-right: $footer-content-width; + padding-bottom: $s-2xl; +} + +.footer-accordion__header { + height: $s-3xl; + + button { + @extend %default-focus-visible; + } +} + +.footer-accordion__header-button { + padding-left: $footer-content-width; + padding-right: $footer-content-width; + width: 100%; + height: 100%; + display: flex; + justify-content: space-between; + align-items: center; + border-top: 1px solid $color__global-tertiary-1; +} + +.footer-accordion__header-button__arrow { + transition: transform 0.3s; + transform: rotateZ(180deg); +} + +.footer-accordion__header-button[aria-expanded="true"] + .footer-accordion__header-button__arrow { + transform: rotateZ(0deg); +} + +.footer-accordion:first-child { + .footer-accordion__header-button { + border-top: 0; + } +} + +.footer-accordion:last-child { + .footer-accordion__header-button { + border-bottom: 1px solid $color__global-tertiary-1; + } +} diff --git a/src/stories/Library/footer-colums/FooterColumn.tsx b/src/stories/Library/footer-colums/FooterColumn.tsx new file mode 100644 index 000000000..6f5155637 --- /dev/null +++ b/src/stories/Library/footer-colums/FooterColumn.tsx @@ -0,0 +1,21 @@ +import { FC } from "react"; + +export type FooterColumnType = { + title: string; + content: string; +}; + +const FooterColumn: FC = ({ title, content }) => { + return ( + <> +

    {title}

    +
    + + ); +}; + +export default FooterColumn; diff --git a/src/stories/Library/footer-colums/FooterColumns.tsx b/src/stories/Library/footer-colums/FooterColumns.tsx new file mode 100644 index 000000000..691bef757 --- /dev/null +++ b/src/stories/Library/footer-colums/FooterColumns.tsx @@ -0,0 +1,20 @@ +import { FC } from "react"; +import FooterColumn, { FooterColumnType } from "./FooterColumn"; + +export type FooterColumnsType = { + footerContent: FooterColumnType[]; +}; + +const FooterColumns: FC = ({ footerContent }) => { + return ( +
      + {footerContent.map(({ title, content }, i) => ( +
    • + +
    • + ))} +
    + ); +}; + +export default FooterColumns; diff --git a/src/stories/Library/footer-colums/footer-colums.scss b/src/stories/Library/footer-colums/footer-colums.scss new file mode 100644 index 000000000..f2fa74bb4 --- /dev/null +++ b/src/stories/Library/footer-colums/footer-colums.scss @@ -0,0 +1,10 @@ +.footer-columns { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(263px, 1fr)); + grid-gap: 82px; +} + +.footer-column { + width: 263px; + height: auto; +} diff --git a/src/stories/Library/footer-info/FooterInfo.tsx b/src/stories/Library/footer-info/FooterInfo.tsx new file mode 100644 index 000000000..545dd2319 --- /dev/null +++ b/src/stories/Library/footer-info/FooterInfo.tsx @@ -0,0 +1,48 @@ +import { FC } from "react"; + +export type FooterSocialMediaType = { + href: string; + alt: string; + icon: string; +}; + +export type FooterInfoLinksType = { + href: string; + label: string; +}; + +type FooterInfoType = { + footerInfoLinks: FooterInfoLinksType[]; + footerSocialMedia: FooterSocialMediaType[]; +}; + +const FooterInfo: FC = ({ + footerInfoLinks, + footerSocialMedia, +}) => { + return ( +
    +
      + {footerInfoLinks.map(({ href, label }, i) => ( +
    • + + {label} + +
    • + ))} +
    + +
      + {footerSocialMedia.map(({ href, alt, icon }, i) => ( +
    • + + {alt} + +
    • + ))} +
    +
    + ); +}; + +export default FooterInfo; diff --git a/src/stories/Library/footer-info/footer-info.scss b/src/stories/Library/footer-info/footer-info.scss new file mode 100644 index 000000000..775135ac9 --- /dev/null +++ b/src/stories/Library/footer-info/footer-info.scss @@ -0,0 +1,34 @@ +.footer-info { + @include media-query__small { + display: flex; + justify-content: space-between; + flex-direction: row-reverse; + } +} + +.footer-info__links { + @include typography($typo__links); + color: $color__text-secondary-gray; + display: flex; + flex-direction: column; + gap: $s-md; + @include media-query__small { + gap: $s-lg; + flex-direction: row; + } +} + +.footer-info__icons { + display: flex; + gap: $s-lg; + margin-top: $s-2xl; + @include media-query__small { + margin-top: 0; + } +} + +.footer-info__link { + text-decoration: none; + @include typography($typo__links); + padding-bottom: $s-md; +} diff --git a/src/stories/Library/footer-separator/FooterSeparator.tsx b/src/stories/Library/footer-separator/FooterSeparator.tsx new file mode 100644 index 000000000..d0d179354 --- /dev/null +++ b/src/stories/Library/footer-separator/FooterSeparator.tsx @@ -0,0 +1,5 @@ +const FooterSeparator = () => { + return
    ; +}; + +export default FooterSeparator; diff --git a/src/stories/Library/footer-separator/footer-separator.scss b/src/stories/Library/footer-separator/footer-separator.scss new file mode 100644 index 000000000..90d3c9d01 --- /dev/null +++ b/src/stories/Library/footer-separator/footer-separator.scss @@ -0,0 +1,9 @@ +.footer-separator { + border-bottom: 1px solid $color__global-tertiary-1; + margin: $s-lg 0; +} + +// Separator mobile tweaks +.footer__mobile .footer-separator { + margin: $s-lg (-50px); +} diff --git a/src/stories/Library/footer-widgets/FooterWidgets.tsx b/src/stories/Library/footer-widgets/FooterWidgets.tsx new file mode 100644 index 000000000..fbcb35d75 --- /dev/null +++ b/src/stories/Library/footer-widgets/FooterWidgets.tsx @@ -0,0 +1,22 @@ +import { FC } from "react"; +import { Dropdown, DropdownItem } from "../dropdown/Dropdown"; +import Logo from "../logo/Logo"; + +type FooterWidgetsType = { + footerLanguages: DropdownItem[]; +}; + +const FooterWidgets: FC = ({ footerLanguages }) => { + return ( +
    + + +
    + ); +}; + +export default FooterWidgets; diff --git a/src/stories/Library/footer-widgets/footer-widgets.scss b/src/stories/Library/footer-widgets/footer-widgets.scss new file mode 100644 index 000000000..42be93968 --- /dev/null +++ b/src/stories/Library/footer-widgets/footer-widgets.scss @@ -0,0 +1,30 @@ +.footer-widgets { + display: flex; + justify-content: space-between; + margin-top: $s-2xl; + @include media-query__small { + margin-top: $s-4xl; + } +} + +// if there are no dropdowns, align the logo to the right +.footer-widgets:not(:has(.dropdown)) { + justify-content: flex-end; +} + +// Dropdown tweaks +.footer-widgets .dropdown { + width: 82px; + + .dropdown__select { + background-color: $color__global-secondary; + height: $s-xl; + padding: 0 12px; + min-width: 82px; + } + + .dropdown__arrows { + height: $s-xl; + width: $s-xl; + } +} diff --git a/src/stories/Library/header-menu-list/HeaderMenuList.tsx b/src/stories/Library/header-menu-list/HeaderMenuList.tsx new file mode 100644 index 000000000..f506adc41 --- /dev/null +++ b/src/stories/Library/header-menu-list/HeaderMenuList.tsx @@ -0,0 +1,24 @@ +import { MenuItemsProps } from "./HeaderMenuListData"; + +interface MenuItemListProps { + menuItems: MenuItemsProps[]; +} + +const MenuItemList: React.FC = ({ menuItems }) => { + return ( + + ); +}; + +export default MenuItemList; diff --git a/src/stories/Library/header-menu-list/HeaderMenuListData.ts b/src/stories/Library/header-menu-list/HeaderMenuListData.ts new file mode 100644 index 000000000..7df342649 --- /dev/null +++ b/src/stories/Library/header-menu-list/HeaderMenuListData.ts @@ -0,0 +1,22 @@ +export interface MenuItemsProps { + title: string; + href: string; +} +export const menuItems: MenuItemsProps[] = [ + { + title: "Det sker", + href: "/", + }, + { + title: "Biblioteker & åbningstider", + href: "/", + }, + { + title: "Digitale tilbud", + href: "/", + }, + { + title: "Litteratur", + href: "/", + }, +]; diff --git a/src/stories/Library/header-menu-list/header-menu-list.scss b/src/stories/Library/header-menu-list/header-menu-list.scss new file mode 100644 index 000000000..cab30f346 --- /dev/null +++ b/src/stories/Library/header-menu-list/header-menu-list.scss @@ -0,0 +1,13 @@ +.header__menu-navigation-item:hover { + border-top: 1px solid transparent; // to prevent jumping + border-bottom: 1px solid $color__global-black; +} +.header__menu-navigation-link { + @include typography($typo__desktop-menu-item); + + padding: 0 12px; + height: 100%; + display: flex; + align-items: center; + color: $color__text-primary-black; +} diff --git a/src/stories/Library/header-sidebar-nav/header-sidebar-nav-js.js b/src/stories/Library/header-sidebar-nav/header-sidebar-nav-js.js new file mode 100644 index 000000000..2c2a2cebd --- /dev/null +++ b/src/stories/Library/header-sidebar-nav/header-sidebar-nav-js.js @@ -0,0 +1,103 @@ +window.addEventListener("load", () => { + const sidebarNavToggle = document.getElementById( + "header-sidebar-nav__toggle" + ); + const backgroundWrapper = document.querySelector( + ".header-sidebar-nav__background-wrapper" + ); + const menu = document.querySelector(".header-sidebar-nav"); + + const closeButton = document.getElementById( + "js-header-sidebar-nav__close-menu-button" + ); + + const lastMenuItem = document.querySelector( + ".header-sidebar-nav .header__menu-navigation li:last-child a" + ); + const menuWrapper = document.querySelector( + ".header-sidebar-nav__menu-wrapper" + ); + + function toggleSidebarNav() { + const isOpen = menu.getAttribute("data-open") === "open"; + + if (menu) { + menu.setAttribute("data-open", isOpen ? "closed" : "open"); + } + + if (sidebarNavToggle) { + sidebarNavToggle.setAttribute("aria-expanded", isOpen ? "false" : "true"); + } + + if (!isOpen && closeButton) { + // When menu opens - move focus to the close button + closeButton.focus(); + } else if (isOpen && sidebarNavToggle) { + // When menu closes - move focus to the menu toggle button + sidebarNavToggle.focus(); + } + } + + if (sidebarNavToggle) { + sidebarNavToggle.addEventListener("click", toggleSidebarNav); + + // Allow menu to be opened with Enter or Space key + sidebarNavToggle.addEventListener("keydown", (event) => { + if (event.key === "Enter" || event.key === " ") { + toggleSidebarNav(); + event.preventDefault(); + } + }); + } + + if (lastMenuItem) { + // When tabbing out of the last menu item, move focus to the close button + lastMenuItem.addEventListener("keydown", (event) => { + if (event.key === "Tab" && !event.shiftKey) { + event.preventDefault(); // Prevent tabbing to an element outside the menu + closeButton.focus(); + } + }); + } + if (closeButton) { + closeButton.addEventListener("click", toggleSidebarNav); + // When tabbing backwards out of the close button, move focus to the last menu item + closeButton.addEventListener("keydown", (event) => { + if (event.key === "Tab" && event.shiftKey) { + event.preventDefault(); // Prevent tabbing to an element outside the menu + lastMenuItem.focus(); + } + // Allow close button to be activated with Enter or Space key + if (event.key === "Enter" || event.key === " ") { + toggleSidebarNav(); + event.preventDefault(); + } + }); + } + + // Close the menu if open when the escape key is pressed + document.addEventListener("keydown", (event) => { + if (event.key === "Escape" && menu.getAttribute("data-open") === "open") { + toggleSidebarNav(); + } + }); + + // Close the menu if a link is clicked + if (menuWrapper) { + menuWrapper.addEventListener("click", (event) => { + // Check if the click is inside a link within a navigation item + if (event.target.closest(".header__menu-navigation-item a")) { + toggleSidebarNav(); + } + }); + } + + if (backgroundWrapper) { + backgroundWrapper.addEventListener("click", (event) => { + // Close the menu if the background wrapper is clicked + if (event.target === backgroundWrapper) { + toggleSidebarNav(); + } + }); + } +}); diff --git a/src/stories/Library/header-sidebar-nav/header-sidebar-nav.scss b/src/stories/Library/header-sidebar-nav/header-sidebar-nav.scss new file mode 100644 index 000000000..8625f65ba --- /dev/null +++ b/src/stories/Library/header-sidebar-nav/header-sidebar-nav.scss @@ -0,0 +1,122 @@ +@use "sass:color"; +:root { + --sidebar-padding: #{$s-md}; +} +$_bezier_transition: cubic-bezier(0.65, 0.1, 0.36, 1); +$_transition_speed: 0.3s; +$_menu_animation_delay: 0.2s; + +.header-sidebar-nav { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: $z-20; + transform: translateX(-100%); + transition: transform $_transition_speed $_bezier_transition; + + ul.header__menu-navigation { + padding: 0; + display: flex; + flex-direction: column; + gap: $s-md; + height: 100%; + padding-top: $s-5xl; + padding-bottom: $s-2xl; + overflow-y: auto; + max-height: calc(100vh - calc(var(--sidebar-padding) * 2)); + position: unset; + visibility: visible; + } + + .header__menu-navigation-item:hover { + border: none; + } + + .header__menu-navigation-link { + @include typography($typo__body-large); + + outline-offset: 0px; + padding: 0; + text-decoration: none; + position: relative; + display: inline-block; + } + + .header__menu-navigation-link::after { + content: ""; + position: absolute; + left: 0; + bottom: -1px; + width: 0; + height: 1px; + background: currentColor; + transition: width $_transition_speed $_bezier_transition; + } + + .header__menu-navigation-link:hover::after, + .header__menu-navigation-link:focus::after { + width: 100%; + } +} + +.header-sidebar-nav__close-menu-button { + height: min-content; + padding: $s-xs; + line-height: 1; + cursor: pointer; +} + +.header-sidebar-nav__menu-wrapper { + background: $color__global-white; + padding: var(--sidebar-padding); + display: grid; + grid-template-columns: max-content 1fr; + grid-gap: $s-md; + height: 100%; + opacity: 0; + transform: translateX(-100%); + transition: opacity $_transition_speed $_bezier_transition + $_menu_animation_delay, + transform $_transition_speed $_bezier_transition $_menu_animation_delay; + cursor: initial; +} + +.header-sidebar-nav[data-open="closed"] { + transform: translateX(-100%); +} + +.header-sidebar-nav[data-open="open"] { + transform: translateX(0%); + + .header-sidebar-nav__menu-wrapper { + opacity: 1; + transform: translateX(0%); + } +} + +.header-sidebar-nav__background-wrapper { + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + background-color: color.adjust($color__global-black, $alpha: -0.5); + cursor: pointer; +} + +@include media-query__small { + :root { + --sidebar-padding: #{$s-lg}; + } + + .header-sidebar-nav__menu-wrapper { + max-width: 375px; + grid-gap: $s-lg; + } + + .header-sidebar-nav__menu-items { + padding-top: 120px; + } +} diff --git a/src/stories/Library/header-sidebar-nav/header-sidebar-nav.stories.tsx b/src/stories/Library/header-sidebar-nav/header-sidebar-nav.stories.tsx new file mode 100644 index 000000000..b2d292f1a --- /dev/null +++ b/src/stories/Library/header-sidebar-nav/header-sidebar-nav.stories.tsx @@ -0,0 +1,37 @@ +import { ComponentMeta, ComponentStory } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import HeaderSidebarNav, { HeaderSidebarNavProps } from "./header-sidebar-nav"; +import { menuItems } from "../header-menu-list/HeaderMenuListData"; + +export default { + title: "Library / Header Sidebar Nav", + component: HeaderSidebarNav, + decorators: [withDesign], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=1354-8717&mode=design&t=FVZ4DJ3kACnnV4jO-4", + }, + }, + argTypes: { + menuLinks: { + table: { + category: "Content", + }, + description: "The links of the menu", + control: { type: "object" }, + defaultValue: menuItems, + }, + menuOpen: { + description: "The state of the menu", + defaultValue: "open", + control: { type: "select", options: ["open", "closed"] }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = ( + args: HeaderSidebarNavProps +) => ; + +export const Default = Template.bind({}); diff --git a/src/stories/Library/header-sidebar-nav/header-sidebar-nav.tsx b/src/stories/Library/header-sidebar-nav/header-sidebar-nav.tsx new file mode 100644 index 000000000..86db7f643 --- /dev/null +++ b/src/stories/Library/header-sidebar-nav/header-sidebar-nav.tsx @@ -0,0 +1,42 @@ +import { useEffect } from "react"; +import { ReactComponent as CloseSidebarIcon } from "../Icons/icon-close-large/icon-close-large.svg"; +import { MenuItemsProps } from "../header-menu-list/HeaderMenuListData"; +import MenuItemList from "../header-menu-list/HeaderMenuList"; + +export type HeaderSidebarNavProps = { + menuLinks: MenuItemsProps[]; + menuOpen?: "open" | "closed"; +}; + +const HeaderSidebarNav: React.FC = ({ + menuLinks, + menuOpen = "closed", +}) => { + useEffect(() => { + /* eslint-disable-next-line global-require */ + require("./header-sidebar-nav-js"); + }, []); + + return ( +
    +
    +
    +
    +
    + +
    +
    +
    + ); +}; + +export default HeaderSidebarNav; diff --git a/src/stories/Library/hero/Hero.stories.tsx b/src/stories/Library/hero/Hero.stories.tsx new file mode 100644 index 000000000..c5ffa9eef --- /dev/null +++ b/src/stories/Library/hero/Hero.stories.tsx @@ -0,0 +1,48 @@ +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import Hero from "./Hero"; + +export default { + title: "Library / Hero", + component: Hero, + decorators: [withDesign], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=7477-39243&mode=dev", + }, + }, + argTypes: { + image: { + name: "Image", + defaultValue: + "https://images.unsplash.com/photo-1531058020387-3be344556be6?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwxfDB8MXxyYW5kb218MHx8ZXZlbnR8fHx8fHwxNzAyOTEwMzE0&ixlib=rb-4.0.3&q=80&utm_campaign=api-credit&utm_medium=referral&utm_source=unsplash_source&w=1080", + control: { type: "text" }, + }, + contentType: { + name: "Type", + defaultValue: "Arrangement", + control: { type: "text" }, + }, + date: { + name: "Date", + defaultValue: "06 Dec 2022", + control: { type: "text" }, + }, + title: { + name: "Title", + defaultValue: "Stine Pilgaard vinder De Gyldne Laurbær", + control: { type: "text" }, + }, + description: { + name: "Description", + defaultValue: + "Boghandlernes store bogpris - De Gyldne går denne gang til Stine Pilgaard for hendes roman 'Meter i sekundet'. Stort tillykke til Stine Pilgaard.", + control: { type: "text" }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ; + +export const Default = Template.bind({}); diff --git a/src/stories/Library/hero/Hero.tsx b/src/stories/Library/hero/Hero.tsx new file mode 100644 index 000000000..ec3505e15 --- /dev/null +++ b/src/stories/Library/hero/Hero.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import ImageCredited from "../image-credited/ImageCredited"; +import Tag from "../tag/Tag"; +import { ReactComponent as ArrowLargeRight } from "../Arrows/icon-arrow-ui/icon-arrow-ui-large-right.svg"; + +export type HeroProps = { + image: string; + contentType?: string; + date: string; + title: string; + description: string; +}; + +const Hero: React.FunctionComponent = ({ + image, + contentType, + date, + title, + description, +}) => { + return ( +
    + + + Arrangement + +
    + {contentType && ( + <> + {contentType}| + + )} + +
    +

    {title}

    +
    +

    {description}

    +
    +
    + +
    +
    + +
    + +
    +
    + ); +}; + +export default Hero; diff --git a/src/stories/Library/hero/hero.scss b/src/stories/Library/hero/hero.scss new file mode 100644 index 000000000..6dc0ec384 --- /dev/null +++ b/src/stories/Library/hero/hero.scss @@ -0,0 +1,42 @@ +.hero { + @extend %hero-2-column; +} + +.hero-tag { + margin-bottom: $s-md; + @include media-query__small { + margin-bottom: $s-lg; + } +} + +.hero__details { + @include typography($typo__h5); + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 10px; + margin-bottom: $s-md; + + &__type { + color: $color__global-tertiary-2; + } + + &__date { + @include media-query__small { + white-space: nowrap; + } + } +} + +.hero-title { + @include typography($typo__h1); + margin-bottom: $s-md; + + @include media-query__small { + margin-bottom: $s-xl; + } +} + +.hero-description { + margin-bottom: $s-md; +} diff --git a/src/stories/Library/horizontal-term-line/HorizontalTermLine.tsx b/src/stories/Library/horizontal-term-line/HorizontalTermLine.tsx index 1db65dd05..b72412320 100644 --- a/src/stories/Library/horizontal-term-line/HorizontalTermLine.tsx +++ b/src/stories/Library/horizontal-term-line/HorizontalTermLine.tsx @@ -1,5 +1,6 @@ import { useState } from "react"; import ButtonExpand from "../Buttons/button/button-expand/ButtonExpand"; +import Heading, { HeadingLevelType } from "../heading/Heading"; export interface HorizontalTermLineList { url: string; @@ -10,6 +11,8 @@ export interface HorizontalTermLineProps { title: string; subTitle?: string; linkList: HorizontalTermLineList[]; + collapsible?: boolean; + headingLevel?: HeadingLevelType; } export function generateId(index: number | string) { @@ -21,8 +24,10 @@ const HorizontalTermLine: React.FC = ({ title, subTitle, linkList, + collapsible = true, + headingLevel = "h2", }) => { - const numberOfItemsToShow = 2; + const numberOfItemsToShow = collapsible ? 2 : linkList.length; const [showMore, setShowMore] = useState(false); const itemsToShow = showMore ? linkList @@ -31,10 +36,10 @@ const HorizontalTermLine: React.FC = ({ return (
    -

    + {`${title}`}{" "} {subTitle && {subTitle} } -

    + {itemsToShow.map((link, index) => ( @@ -44,7 +49,7 @@ const HorizontalTermLine: React.FC = ({ ))} - {showMoreButton && ( + {collapsible && showMoreButton && ( )}
    diff --git a/src/stories/Library/input-label/InputLabel.stories.tsx b/src/stories/Library/input-label/InputLabel.stories.tsx new file mode 100644 index 000000000..6d4fbc30b --- /dev/null +++ b/src/stories/Library/input-label/InputLabel.stories.tsx @@ -0,0 +1,24 @@ +import { ComponentStory } from "@storybook/react"; + +import { InputLabel as InputLabelComp } from "./InputLabel"; + +type DropdownProps = typeof InputLabelComp; + +export default { + title: "Library / Input label", + component: InputLabelComp, + argTypes: { + text: { + defaultValue: "Her er en label", + }, + }, + parameters: { + layout: "padded", + }, +}; + +const Template: ComponentStory = (args) => ( + +); + +export const InputLabel = Template.bind({}); diff --git a/src/stories/Library/input-label/InputLabel.tsx b/src/stories/Library/input-label/InputLabel.tsx new file mode 100644 index 000000000..2b5b28e96 --- /dev/null +++ b/src/stories/Library/input-label/InputLabel.tsx @@ -0,0 +1,7 @@ +export type InputLabelProps = { + text: string; +}; + +export const InputLabel: React.FC = ({ text }) => { + return ; +}; diff --git a/src/stories/Library/input-label/input-label.scss b/src/stories/Library/input-label/input-label.scss new file mode 100644 index 000000000..0f1f8d433 --- /dev/null +++ b/src/stories/Library/input-label/input-label.scss @@ -0,0 +1,7 @@ +.input-label { + @include typography($typo__small-caption); + width: 100%; + height: $s-lg; + margin-bottom: $s-sm; + padding-top: $s-xs; +} diff --git a/src/stories/Library/link-with-icon/link-with-icon.scss b/src/stories/Library/link-with-icon/link-with-icon.scss index 13fba68d7..3beb78f72 100644 --- a/src/stories/Library/link-with-icon/link-with-icon.scss +++ b/src/stories/Library/link-with-icon/link-with-icon.scss @@ -1,19 +1,19 @@ .link-with-icon { @include typography($typo__body-placeholder); @include show-svg-on-hover(); - @include layout-container; background-color: $color__global-primary; - padding-top: $s-md; - padding-bottom: $s-md; + padding: $s-md; display: grid; grid-template-columns: 40px auto max-content; align-items: center; gap: $s-md; text-decoration: none; - border: 1px solid $color__global-tertiary-1; width: 100%; + transform: translateY(-1px); + border: 1px solid $color__global-tertiary-1; + &:first-child { margin-top: 0; } diff --git a/src/stories/Library/logo/Logo.stories.tsx b/src/stories/Library/logo/Logo.stories.tsx index 79b46d54a..f83d4bb18 100644 --- a/src/stories/Library/logo/Logo.stories.tsx +++ b/src/stories/Library/logo/Logo.stories.tsx @@ -1,12 +1,10 @@ import { ComponentStory } from "@storybook/react"; import { withDesign } from "storybook-addon-designs"; -import { Logo as LogoComp } from "./Logo"; - -type LogoProps = typeof LogoComp; +import Logo, { LogoProps } from "./Logo"; export default { title: "Library / Logo", - component: LogoComp, + component: Logo, decorators: [withDesign], argTypes: { libraryName: { @@ -25,10 +23,12 @@ export default { }, }; -const Template: ComponentStory = (args) => ; +const Template: ComponentStory = (args: LogoProps) => ( + +); -export const Logo = Template.bind({}); -Logo.args = { +export const Default = Template.bind({}); +Default.args = { fallback: false, altText: "logo", }; diff --git a/src/stories/Library/logo/Logo.tsx b/src/stories/Library/logo/Logo.tsx index 94fd1f0b2..200180175 100644 --- a/src/stories/Library/logo/Logo.tsx +++ b/src/stories/Library/logo/Logo.tsx @@ -1,13 +1,13 @@ import "../../../styles/css/base.css"; import logo from "./logo.png"; -type LogoProps = { +export type LogoProps = { fallback: boolean; libraryName: string; altText: string; }; -export const Logo = (props: LogoProps) => { +const Logo = (props: LogoProps) => { const { fallback, libraryName, altText } = props; return fallback ? ( diff --git a/src/stories/Library/logo/logo.scss b/src/stories/Library/logo/logo.scss index 6ac760cfd..11a0a3c33 100644 --- a/src/stories/Library/logo/logo.scss +++ b/src/stories/Library/logo/logo.scss @@ -1,6 +1,10 @@ .logo { img { display: none; + + height: 100px; + width: auto; + @include media-query__small { display: block; } diff --git a/src/stories/Library/material-header/MaterialHeader.tsx b/src/stories/Library/material-header/MaterialHeader.tsx index b93ccc372..0427a207e 100644 --- a/src/stories/Library/material-header/MaterialHeader.tsx +++ b/src/stories/Library/material-header/MaterialHeader.tsx @@ -60,7 +60,7 @@ const MaterialHeader: React.FC = ({ size="xlarge" tint="120" animate - shadow + shadow="small" />
    diff --git a/src/stories/Library/medias/medias.scss b/src/stories/Library/medias/medias.scss index 22f48d1eb..c95c37932 100644 --- a/src/stories/Library/medias/medias.scss +++ b/src/stories/Library/medias/medias.scss @@ -1,6 +1,6 @@ $_medias-breakpoint: 550px; -$_max-width-single-media: 896px; -$_max-width-multiple-medias: 1240px; +$_max-width-single-media: $block-max-width__medium; +$_max-width-multiple-medias: $block-max-width__x-large; .medias__item { width: 100%; @@ -15,8 +15,7 @@ $_max-width-multiple-medias: 1240px; } .medias--single { - @include layout-container($_max-width-single-media, 0); - @include vertical-spacing; + @include layout-container($_max-width-single-media); } @include media-query($_medias-breakpoint) { @@ -54,7 +53,6 @@ $_max-width-multiple-medias: 1240px; .medias--multiple { @include layout-container($_max-width-multiple-medias, 0); - @include vertical-spacing; .medias__item--last { img { diff --git a/src/stories/Library/nav-grid/NavGrid.stories.tsx b/src/stories/Library/nav-grid/NavGrid.stories.tsx new file mode 100644 index 000000000..c891d7be5 --- /dev/null +++ b/src/stories/Library/nav-grid/NavGrid.stories.tsx @@ -0,0 +1,70 @@ +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import NavGrid from "./NavGrid"; +import NavTeaser from "../nav-teaser/NavTeaser"; + +const teaser = ( + +); + +export default { + title: "Library / Nav grid ('Navigationskomponent')", + component: NavGrid, + decorators: [withDesign], + argTypes: { + title: { + defaultValue: "Nyheder", + }, + showSubtitles: { + defaultValue: true, + }, + items: { + // Disabling controls, as the different teaser variants are added already. + control: false, + defaultValue: [teaser, teaser, teaser], + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=434-6449&mode=design&t=BnLo07eCsytFa8Ik-4", + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +const Few = Template.bind({}); + +Few.args = { + showSubtitles: false, +}; + +const Many = Template.bind({}); + +Many.args = { + items: [ + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + teaser, + ], +}; + +export { Many, Few }; diff --git a/src/stories/Library/nav-grid/NavGrid.tsx b/src/stories/Library/nav-grid/NavGrid.tsx new file mode 100644 index 000000000..2ddcaba92 --- /dev/null +++ b/src/stories/Library/nav-grid/NavGrid.tsx @@ -0,0 +1,47 @@ +import { FC, ReactNode, useEffect } from "react"; +import clsx from "clsx"; + +type CardProps = { + title?: string; + showSubtitles?: boolean; + items: ReactNode[]; +}; + +const NavGrid: FC = ({ items, title, showSubtitles }) => { + useEffect(() => { + require("./init-nav-grid"); + }, []); + + const hasMany = items.length > 6; + + return ( +
    +
    + {title ?

    {title}

    : ""} +
    +
    + {items.map((item) => { + return
    {item}
    ; + })} +
    + + {hasMany ? ( + + ) : ( + "" + )} +
    + ); +}; + +export default NavGrid; diff --git a/src/stories/Library/nav-grid/init-nav-grid.js b/src/stories/Library/nav-grid/init-nav-grid.js new file mode 100644 index 000000000..769551b5d --- /dev/null +++ b/src/stories/Library/nav-grid/init-nav-grid.js @@ -0,0 +1,18 @@ +window.addEventListener("load", () => { + const grids = document.querySelectorAll( + ".nav-grid--has-many:not(.is-initialized)" + ); + + grids.forEach((grid) => { + grid.classList.add("is-initialized"); + const button = grid.querySelector(".nav-grid__controller"); + + if (!button) { + return; + } + + button.addEventListener("click", () => { + grid.classList.remove("nav-grid--folded"); + }); + }); +}); diff --git a/src/stories/Library/nav-grid/nav-grid.scss b/src/stories/Library/nav-grid/nav-grid.scss new file mode 100644 index 000000000..236e89d67 --- /dev/null +++ b/src/stories/Library/nav-grid/nav-grid.scss @@ -0,0 +1,73 @@ +.nav-grid { + @include layout-container($layout__max-width--large, 0); +} + +.nav-grid--simple { + .nav-teaser__subtitle { + display: none; + } +} + +.nav-grid__controller { + display: none; + margin: auto; + margin-top: $s-md; +} + +.nav-grid__header { + @include layout-container(); + + display: flex; + align-items: center; +} + +.nav-grid__title { + @include typography($typo__h2); + + display: flex; + flex-grow: 1; + margin-bottom: $s-lg; +} + +.nav-grid__items { + display: grid; + grid-gap: 1px; + + grid-template-columns: 1fr; + + @include media-query__small { + grid-template-columns: 1fr 1fr; + } + + @include media-query__medium { + grid-template-columns: 1fr 1fr 1fr; + + .nav-grid--count-1 &, + .nav-grid--count-2 &, + .nav-grid--count-3 &, + .nav-grid--count-4 & { + grid-template-columns: 1fr 1fr; + } + } +} + +.nav-grid__item { + // We use outline, to collapse the border to avoid double 2px borders. + outline: 1px solid $color__global-tertiary-1; + + // We want the borders to collapse, so we'll remove the borders on the + // individual teasers. + .nav-teaser { + border: 0; + } +} + +.nav-grid--folded { + .nav-grid__item:nth-child(n + 7) { + display: none; + } + + .nav-grid__controller { + display: block; + } +} diff --git a/src/stories/Library/nav-spot/NavSpot.stories.tsx b/src/stories/Library/nav-spot/NavSpot.stories.tsx new file mode 100644 index 000000000..782d1e3ab --- /dev/null +++ b/src/stories/Library/nav-spot/NavSpot.stories.tsx @@ -0,0 +1,57 @@ +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import NavSpot from "./NavSpot"; +import ImageCredited from "../image-credited/ImageCredited"; + +export default { + title: "Library / Nav-spot (Navigationsmodul)", + component: NavSpot, + decorators: [withDesign], + argTypes: { + variant: { + // Disabling controls, as the different variations are added already. + control: false, + }, + title: { + defaultValue: "Bøger som har gjort en forskel for romanens udvikling", + type: "string", + }, + subtitle: { + defaultValue: "Stine Pilgaard vinder De Gyldne Laurbær", + type: "string", + }, + media: { + defaultValue: ( + + ), + type: "string", + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=1958-7664&mode=design&t=nK04fkaFk3f9pafj-4", + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +const Large = Template.bind({}); +Large.args = { + variant: "large", +}; + +const Medium = Template.bind({}); +Medium.args = { + variant: "medium", +}; + +const Small = Template.bind({}); +Small.args = { + variant: "small", +}; + +export { Large, Medium, Small }; diff --git a/src/stories/Library/nav-spot/NavSpot.tsx b/src/stories/Library/nav-spot/NavSpot.tsx new file mode 100644 index 000000000..f24094752 --- /dev/null +++ b/src/stories/Library/nav-spot/NavSpot.tsx @@ -0,0 +1,46 @@ +import { FC, ReactNode } from "react"; +import clsx from "clsx"; +import { ReactComponent as Arrow } from "../Arrows/icon-arrow-ui/icon-arrow-ui-large-right.svg"; + +type NavSpotProps = { + variant?: string; + title: string; + subtitle?: string; + media?: ReactNode; + placeholderText?: string; +}; + +const NavSpot: FC = ({ + variant, + title, + subtitle, + media, + placeholderText, +}) => { + const classes = clsx("nav-spot", "arrow__hover--right-large", { + "nav-spot--has-no-media": !media, + "nav-spot--has-media": media, + }); + + return ( + + ); +}; + +export default NavSpot; diff --git a/src/stories/Library/nav-spot/nav-spot.scss b/src/stories/Library/nav-spot/nav-spot.scss new file mode 100644 index 000000000..322f041e7 --- /dev/null +++ b/src/stories/Library/nav-spot/nav-spot.scss @@ -0,0 +1,100 @@ +$_text-padding: $s-xl; + +%nav-spot--default { + @include typography($typo__body-large); + + .nav-spot__text { + padding-top: $_text-padding; + } + + .nav-spot__title { + @include typography($typo__h2); + + margin-bottom: $s-md; + } + + .nav-spot__subtitle { + margin-bottom: $s-md; + } + + .nav-spot__content { + text-decoration: none; + } + + .nav-spot__media { + aspect-ratio: 16/9; + + * { + height: 100%; + } + + img { + height: 100%; + width: 100%; + object-fit: cover; + object-position: center; + } + } + + @include media-query__medium("max-width") { + .nav-spot__text { + padding-left: $_text-padding; + padding-right: $_text-padding; + } + } +} + +.nav-spot { + @extend %nav-spot--default; +} + +.nav-spot--has-no-media { + .nav-spot__media { + @extend %identity-placeholder; + } +} + +.nav-spot__placeholder-text { + @extend %identity-placeholder-text; +} + +%nav-spot--large, +.nav-spot[data-variant="large"] { + background-color: white; + + .nav-spot__media { + margin-bottom: 0; + } + + .nav-spot__text { + padding: $_text-padding; + flex-grow: 1; + align-self: center; + } + + @include media-query__medium { + .nav-spot__content { + display: flex; + } + + .nav-spot__media { + width: 60%; + } + } +} + +%nav-spot--small, +.nav-spot[data-variant="small"] { + .nav-spot__title { + @include typography($typo__h3); + } + .nav-spot__media { + aspect-ratio: 1/1; + } + + @include media-query__medium("max-width") { + .nav-spot__text { + padding-left: 0; + } + } +} diff --git a/src/stories/Library/nav-spots/NavSpots.stories.tsx b/src/stories/Library/nav-spots/NavSpots.stories.tsx new file mode 100644 index 000000000..3a9950952 --- /dev/null +++ b/src/stories/Library/nav-spots/NavSpots.stories.tsx @@ -0,0 +1,73 @@ +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import NavSpots from "./NavSpots"; +import NavSpot from "../nav-spot/NavSpot"; +import ImageCredited from "../image-credited/ImageCredited"; + +const media = ( + +); +const teaser = ( + +); + +const teaserNoImage = ( + +); + +export default { + title: "Library / Nav spots (Navigationsmodul)", + component: NavSpots, + decorators: [withDesign], + argTypes: { + items: { + // Disabling controls, as the different card variants are added already. + control: false, + defaultValue: [teaser, teaser], + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=1958-7664&mode=design&t=nK04fkaFk3f9pafj-4", + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +const Many = Template.bind({}); + +Many.args = { + items: [teaser, teaser], +}; + +const ManyNoImage = Template.bind({}); + +ManyNoImage.args = { + items: [teaserNoImage, teaserNoImage], +}; + +const Single = Template.bind({}); + +Single.args = { + items: [teaser], +}; + +const SingleNoImage = Template.bind({}); + +SingleNoImage.args = { + items: [teaserNoImage], +}; + +export { Many, ManyNoImage, Single, SingleNoImage }; diff --git a/src/stories/Library/nav-spots/NavSpots.tsx b/src/stories/Library/nav-spots/NavSpots.tsx new file mode 100644 index 000000000..9ec0c0ef3 --- /dev/null +++ b/src/stories/Library/nav-spots/NavSpots.tsx @@ -0,0 +1,20 @@ +import { FC, ReactNode } from "react"; +import clsx from "clsx"; + +type NavSpotsProps = { + items: ReactNode[]; +}; + +const NavSpots: FC = ({ items }) => { + return ( +
    +
    + {items.map((item) => { + return
    {item}
    ; + })} +
    +
    + ); +}; + +export default NavSpots; diff --git a/src/stories/Library/nav-spots/nav-spots.scss b/src/stories/Library/nav-spots/nav-spots.scss new file mode 100644 index 000000000..3e9699f4a --- /dev/null +++ b/src/stories/Library/nav-spots/nav-spots.scss @@ -0,0 +1,37 @@ +.nav-spots { + @include layout-container($block-max-width__large, 0); +} + +.nav-spots--count-1 { + .nav-spot { + @extend %nav-spot--large; + } +} + +.nav-spots--count-2 { + $_gap: $s-4xl; + + .nav-spots__item + .nav-spots__item { + padding-top: $_gap; + padding-left: $_gap; + box-sizing: border-box; + + .nav-spot { + @extend %nav-spot--small; + } + } + + @include media-query__medium { + .nav-spots__items { + display: flex; + } + + .nav-spots__item { + width: 60%; + } + + .nav-spots__item + .nav-spots__item { + width: 40%; + } + } +} diff --git a/src/stories/Library/nav-teaser/NavTeaser.stories.tsx b/src/stories/Library/nav-teaser/NavTeaser.stories.tsx new file mode 100644 index 000000000..12e80d97c --- /dev/null +++ b/src/stories/Library/nav-teaser/NavTeaser.stories.tsx @@ -0,0 +1,32 @@ +import { ComponentStory, ComponentMeta } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import NavTeaser from "./NavTeaser"; + +export default { + title: "Library / Nav teaser", + component: NavTeaser, + decorators: [withDesign], + argTypes: { + title: { + defaultValue: "Læseklub for børn", + }, + subtitle: { + defaultValue: + "Børn har en tendens til at droppe fritidslæsningen omkring de 10 år. Med læsefamilieposerne får du inspiration til at få hele familien samlet omkring læsning.", + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=434-6449&mode=design&t=BnLo07eCsytFa8Ik-4", + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +const Teaser = Template.bind({}); + +export { Teaser }; diff --git a/src/stories/Library/nav-teaser/NavTeaser.tsx b/src/stories/Library/nav-teaser/NavTeaser.tsx new file mode 100644 index 000000000..a2c9defeb --- /dev/null +++ b/src/stories/Library/nav-teaser/NavTeaser.tsx @@ -0,0 +1,23 @@ +import { FC } from "react"; +import { ReactComponent as Arrow } from "../Arrows/icon-arrow-ui/icon-arrow-ui-nav.svg"; + +type NavTeaserProps = { + title: string; + subtitle?: string; +}; + +const NavTeaser: FC = ({ title, subtitle }) => { + return ( + + ); +}; + +export default NavTeaser; diff --git a/src/stories/Library/nav-teaser/nav-teaser.scss b/src/stories/Library/nav-teaser/nav-teaser.scss new file mode 100644 index 000000000..a3c7236ea --- /dev/null +++ b/src/stories/Library/nav-teaser/nav-teaser.scss @@ -0,0 +1,36 @@ +.nav-teaser { + @include typography($typo__body-placeholder); + color: $color__global-black; + + display: block; + width: 100%; + box-sizing: border-box; + border: 1px solid $color__global-tertiary-1; + cursor: pointer; + + > a { + display: block; + width: 100%; + height: 100%; + padding: $s-md; + text-decoration: none; + + @include media-query__medium { + padding: $s-xl $s-2xl; + } + + @include media-query__large { + padding: $s-2xl $s-3xl; + } + } +} + +.nav-teaser__title { + @include typography($typo__h3); + + margin-bottom: $s-md; +} + +.nav-teaser__subtitle { + margin-bottom: $s-lg; +} diff --git a/src/stories/Library/paragraph/Paragraph.tsx b/src/stories/Library/paragraph/Paragraph.tsx new file mode 100644 index 000000000..4772565bf --- /dev/null +++ b/src/stories/Library/paragraph/Paragraph.tsx @@ -0,0 +1,16 @@ +import { FC } from "react"; + +type ParagraphProps = { + modifier: string; + children: React.ReactNode; +}; + +const Paragraph: FC = ({ modifier, children }) => { + return ( +
    + {children} +
    + ); +}; + +export default Paragraph; diff --git a/src/stories/Library/paragraphs/Paragraphs.tsx b/src/stories/Library/paragraphs/Paragraphs.tsx index 6d5800afc..9684e7587 100644 --- a/src/stories/Library/paragraphs/Paragraphs.tsx +++ b/src/stories/Library/paragraphs/Paragraphs.tsx @@ -1,23 +1,25 @@ +import CardGrid from "../card-grid/CardGrid"; +import { card, cardNoImage } from "../card-grid/card-grid-data"; import { LinkWithIcon } from "../link-with-icon/LinkWithIcon"; +import Paragraph from "../paragraph/Paragraph"; +import { Recommendation } from "../recommendation/Recommendation"; import { RichText, RichTextEvent } from "../rich-text/RichText"; import VideoEmbed from "../video-embed/VideoEmbed"; export const EventParagraphs = () => { return (
    -
    + -
    -
    - -
    -
    + + + + + + + -
    +
    ); }; @@ -25,19 +27,54 @@ export const EventParagraphs = () => { export const ArticleParagraphs = () => { return (
    -
    + -
    -
    + + + -
    -
    - + + + + + + + + + + + -
    + + + + +
    ); }; diff --git a/src/stories/Library/paragraphs/paragraphs.scss b/src/stories/Library/paragraphs/paragraphs.scss index af2a7638f..53950851d 100644 --- a/src/stories/Library/paragraphs/paragraphs.scss +++ b/src/stories/Library/paragraphs/paragraphs.scss @@ -1,13 +1,24 @@ -.paragraphs__item { - @include vertical-spacing; +.paragraphs { + @include block-spacing(); } -// 'Links' + 'Files' paragraphs should go flush against each-other. +.paragraphs__item + .paragraphs__item { + @include block-spacing(); +} + +// Some paragraphs should go flush against each-other. .paragraphs__item--links, -.paragraphs__item--files { +.paragraphs__item--files, +.paragraphs__item--accordion { + @include layout-container($block-max-width__medium); + + + .paragraphs__item--accordion, + .paragraphs__item--files, + .paragraphs__item--links { - // -1px to also collapse the border. - margin-top: -($_vertical-spacing--large + 1px); + @include block-spacing("sibling"); } } + +.paragraphs__item--hero { + @include block-spacing("negative"); +} diff --git a/src/stories/Library/recommendation/Recommendation.stories.tsx b/src/stories/Library/recommendation/Recommendation.stories.tsx new file mode 100644 index 000000000..939daef0f --- /dev/null +++ b/src/stories/Library/recommendation/Recommendation.stories.tsx @@ -0,0 +1,62 @@ +// Recommendation.stories.tsx +import { ComponentMeta, ComponentStory } from "@storybook/react"; +import { Recommendation } from "./Recommendation"; +import recommendedMaterialArgs from "../recommended-material/RecommendedMaterialArgs"; + +export default { + title: "Library/Recommendation", + component: Recommendation, + argTypes: { + title: { + control: "text", + description: "Title of the recommendation", + }, + description: { + control: "text", + description: "Description of the recommendation", + }, + href: { + control: "text", + description: "Link to the recommended material", + }, + positionImageRight: { + control: "boolean", + description: "Toggle image position", + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=434-6424&mode=design&t=ADgZ8H4KNumis8iG-4", + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const RecommendationImageLeft = Template.bind({}); + +RecommendationImageLeft.args = { + positionImageRight: false, + title: "Børnenes Naturhobbybog", + description: + "Naturen er fyldt med alle mulige ting fx blade, blomster, sten osv., der kan bruges til at lave en forskellige kreative ting af. Her er inspiration at hente til små og store hobbyprojekter.", + href: "#", + recommendedMaterialProps: { + ...recommendedMaterialArgs, + }, +}; +export const RecommendationImageRight = Template.bind({}); + +RecommendationImageRight.args = { + positionImageRight: true, + title: "Børnenes Naturhobbybog", + description: + "Naturen er fyldt med alle mulige ting fx blade, blomster, sten osv., der kan bruges til at lave en forskellige kreative ting af. Her er inspiration at hente til små og store hobbyprojekter.", + href: "#", + recommendedMaterialProps: { + ...recommendedMaterialArgs, + }, +}; diff --git a/src/stories/Library/recommendation/Recommendation.tsx b/src/stories/Library/recommendation/Recommendation.tsx new file mode 100644 index 000000000..a0fd8756f --- /dev/null +++ b/src/stories/Library/recommendation/Recommendation.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import clsx from "clsx"; +import { + RecommendedMaterial, + RecommendedMaterialProps, +} from "../recommended-material/RecommendedMaterial"; +import { ReactComponent as ArrowSmallRight } from "../Arrows/icon-arrow-ui/icon-arrow-ui-small-right.svg"; + +export type RecommendationProps = { + title: string; + description: string; + href: string; + recommendedMaterialProps: RecommendedMaterialProps; + positionImageRight?: boolean; +}; + +export const Recommendation: React.FC = ({ + title, + description, + href, + recommendedMaterialProps, + positionImageRight = false, +}) => { + return ( + + ); +}; diff --git a/src/stories/Library/recommendation/recommendation-skeleton.scss b/src/stories/Library/recommendation/recommendation-skeleton.scss new file mode 100644 index 000000000..4804a5b19 --- /dev/null +++ b/src/stories/Library/recommendation/recommendation-skeleton.scss @@ -0,0 +1,9 @@ +.recommendation { + .ssc-line { + margin-bottom: 8px; + } + .ssc-header { + height: 20px; + width: 70%; + } +} diff --git a/src/stories/Library/recommendation/recommendation.scss b/src/stories/Library/recommendation/recommendation.scss new file mode 100644 index 000000000..1bc0dd602 --- /dev/null +++ b/src/stories/Library/recommendation/recommendation.scss @@ -0,0 +1,69 @@ +// Some variables used here are defined in recommended-material.scss +$_recommendation-max-width: 896px; + +.recommendation { + @include layout-container($padding: $s-2xl); + + background-color: $color__global-primary; + display: flex; + flex-direction: column; + gap: $s-xl; + padding-top: $s-xl; + padding-bottom: $s-xl; +} + +.recommendation__texts { + text-decoration: none; +} +.recommendation__title { + @include typography($typo__h2); + word-wrap: break-word; + margin-bottom: $s-md; +} +.recommendation__description { + @include typography($typo__body-medium); + margin-bottom: $s-md; + word-wrap: break-word; +} + +@include media-query__small { + .recommendation { + @include layout-container( + $padding: 0, + $max-width: $_recommendation-max-width + ); + display: grid; + grid-template-columns: + $_recommended-material-max-width + minmax($_recommended-material-max-width, 1fr); + grid-template-areas: "material text-content"; + padding-top: unset; + padding-bottom: unset; + gap: 0; + max-height: $_recommended-material-max-height; + overflow: hidden; + } + .recommendation_title { + @include typography($typo__h3); + } + .recommendation--reversed { + grid-template-columns: + minmax($_recommended-material-max-width, 1fr) + $_recommended-material-max-width; + grid-template-areas: "text-content material"; + } + .recommendation__material { + grid-area: material; + } + .recommendation__texts { + grid-area: text-content; + padding-left: $s-4xl; + padding-right: $s-4xl; + display: flex; + justify-content: center; + flex-direction: column; + } + .recommendation__description { + margin-bottom: $s-lg; + } +} diff --git a/src/stories/Library/recommended-material/RecommendedMaterial.stories.tsx b/src/stories/Library/recommended-material/RecommendedMaterial.stories.tsx new file mode 100644 index 000000000..9c6e5fa1f --- /dev/null +++ b/src/stories/Library/recommended-material/RecommendedMaterial.stories.tsx @@ -0,0 +1,31 @@ +import { ComponentMeta, ComponentStory } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import { RecommendedMaterial } from "./RecommendedMaterial"; +import recommendedMaterialArgs from "./RecommendedMaterialArgs"; + +export default { + title: "Library / Recommended Material", + component: RecommendedMaterial, + decorators: [withDesign], + argTypes: { + favoriteFill: { + control: "boolean", + defaultValue: true, + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?type=design&node-id=434-6005&mode=design&t=ADgZ8H4KNumis8iG-4", + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const MediumCoverRecommendation = Template.bind({}); +MediumCoverRecommendation.args = { + ...recommendedMaterialArgs, +}; diff --git a/src/stories/Library/recommended-material/RecommendedMaterial.tsx b/src/stories/Library/recommended-material/RecommendedMaterial.tsx new file mode 100644 index 000000000..a5ab8ef11 --- /dev/null +++ b/src/stories/Library/recommended-material/RecommendedMaterial.tsx @@ -0,0 +1,41 @@ +import { ButtonFavourite } from "../Buttons/button-favourite/ButtonFavourite"; +import Cover from "../cover/Cover"; + +export type RecommendedMaterialProps = { + author: string; + description: string; + src: string; + alt: string; + favoriteFill?: boolean; + coverUrl?: string; +}; + +export const RecommendedMaterial: React.FC = ({ + author, + description, + src, + alt, + favoriteFill = true, + coverUrl, +}) => { + return ( +
    +
    + +
    + +
    +

    {description}

    +

    {author}

    +
    +
    + ); +}; diff --git a/src/stories/Library/recommended-material/RecommendedMaterialArgs.ts b/src/stories/Library/recommended-material/RecommendedMaterialArgs.ts new file mode 100644 index 000000000..c26639e71 --- /dev/null +++ b/src/stories/Library/recommended-material/RecommendedMaterialArgs.ts @@ -0,0 +1,12 @@ +import { RecommendedMaterialProps } from "./RecommendedMaterial"; + +const recommendedMaterialArgs: RecommendedMaterialProps = { + author: "Pia Deges (2019)", + description: "Børnenes Naturhobbybog", + favoriteFill: false, + coverUrl: "#", + src: "images/book_cover_6.jpg", + alt: "book cover", +}; + +export default recommendedMaterialArgs; diff --git a/src/stories/Library/recommended-material/recommended-material-skeleton.scss b/src/stories/Library/recommended-material/recommended-material-skeleton.scss new file mode 100644 index 000000000..c1c508903 --- /dev/null +++ b/src/stories/Library/recommended-material/recommended-material-skeleton.scss @@ -0,0 +1,23 @@ +.recommended-material { + .ssc-square { + width: 30px; + height: 30px; + justify-self: end; + } + + .ssc-square.image-square { + height: 216px; + aspect-ratio: 0.79; + width: auto; + justify-self: center; + } + .ssc-text-wrapper { + width: 100%; + display: flex; + flex-direction: column; + gap: 5px; + } + .ssc-line { + width: 60%; + } +} diff --git a/src/stories/Library/recommended-material/recommended-material.scss b/src/stories/Library/recommended-material/recommended-material.scss new file mode 100644 index 000000000..af49e8e71 --- /dev/null +++ b/src/stories/Library/recommended-material/recommended-material.scss @@ -0,0 +1,45 @@ +$_recommended-material-max-height: 432px; +$_recommended-material-max-width: 378px; +$_aspect-ratio-mobile: 285 / 320; +// stylelint-disable-next-line +$_aspect-ratio-desktop: $_recommended-material-max-width / + $_recommended-material-max-height; +$_material-image-box-shadow: 0 4px 40px rgba(0, 0, 0, 0.45); + +.recommended-material { + background-color: $color__global-secondary; + max-height: $_recommended-material-max-height; + width: 100%; + padding: $s-md; + display: grid; + grid-template-columns: 1fr; + grid-template-rows: auto 1fr auto; + row-gap: $s-lg; + justify-items: center; + align-items: center; + aspect-ratio: $_aspect-ratio-mobile; + + @include media-query__small { + padding: $s-lg; + aspect-ratio: $_aspect-ratio-desktop; + max-width: $_recommended-material-max-width; + } +} + +.recommended-material__icon { + justify-self: end; + line-height: 1; +} + +.recommended-material__texts { + justify-self: start; +} +.recommended-material__description, +.recommended-material__author { + @include typography($typo__body-small); + @include text-ellipsis-truncation(1); +} +.recommended-material__description { + font-weight: $font__weight--bold; + line-height: 2; +} diff --git a/src/stories/Library/rich-text/rich-text.scss b/src/stories/Library/rich-text/rich-text.scss index 3a6b47f4d..efd4ceb68 100644 --- a/src/stories/Library/rich-text/rich-text.scss +++ b/src/stories/Library/rich-text/rich-text.scss @@ -1,12 +1,10 @@ // This component is used for WYSIWYG content. // E.g. we cannot control classes of the underlying elements, so in this case // we will target HTML tags instead. -$_max-width-rich-text: 780px; +$_max-width-rich-text: $block-max-width__small; -.rich-text { +%rich-text { @include typography($typo__rich-text-body); - @include layout-container($_max-width-rich-text); - @include vertical-spacing; a { @extend %text-inline-link; @@ -126,3 +124,9 @@ $_max-width-rich-text: 780px; font-weight: bold; } } + +.rich-text { + @include layout-container($_max-width-rich-text); + + @extend %rich-text; +} diff --git a/src/stories/Library/slider/init-slider.js b/src/stories/Library/slider/init-slider.js index 6c62fbcb2..ca9536f5f 100644 --- a/src/stories/Library/slider/init-slider.js +++ b/src/stories/Library/slider/init-slider.js @@ -1,11 +1,85 @@ +// SwiperJS has a hard time understanding how to deal with keyboard focus and +// setting the slider positioning. +// Because we have items with very different widths, and we use "auto" for +// the actual movement, the focus goes out of sync with the visual visibility. +// This function is called when the swiper is initialized. +// We listen on focus within the item wrapper, and when we detect it, we +// calculate our own transform value, overwriting SwiperJS. +function swiperWrapperEventInit(swiperWrapper) { + swiperWrapper.addEventListener("focusin", () => { + // SwiperJS really wants to remove the tranisition duraton when not in use, + // but we still want it active when using keyboard tabbing. + // eslint-disable-next-line no-param-reassign + swiperWrapper.style.transitionDuration = "300ms"; + + const activeSlide = swiperWrapper.querySelector(".swiper-slide-active"); + + if (!activeSlide) { + return; + } + + let currentSibling = activeSlide; + let translateWidth = 0; + let sideMargins = 0; + + // Finding all previous siblings. + while (currentSibling.previousElementSibling) { + currentSibling = currentSibling.previousElementSibling; + + // Offset width only gives us the 'inner' width. We also need to get + // the side margins. + const style = getComputedStyle(currentSibling); + sideMargins = + parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10); + + // Set a new translate width, used in transform. + translateWidth -= currentSibling.offsetWidth + sideMargins; + } + + if (translateWidth === 0) { + return; + } + + // Calculate a new translate value, for pulling the slider. + // We add half of the latest known sidemargin, so the active slide doesn't + // go flush against the screen. + // eslint-disable-next-line no-param-reassign + swiperWrapper.style.transform = `translate3d(${Math.floor( + translateWidth + sideMargins / 2 + )}px, 0, 0)`; + }); +} + +// We want to make the controls not controllable by keyboard, as it quickly +// becomes a confusing experience, when the active-slide is not what you get to +// when you tab along. +function disableKeyboardNavigation(swiper) { + const controls = swiper.el.querySelectorAll(".swiper-next, .swiper-prev"); + + controls.forEach((control) => { + // eslint-disable-next-line no-param-reassign + control.tabIndex = -1; + }); +} + // Initialize the Swiper library, when the page is ready. window.addEventListener("load", () => { // eslint-disable-next-line no-undef, @typescript-eslint/no-unused-vars - const swiper = new Swiper(".swiper", { + const swiperInit = new Swiper(".swiper", { slidesPerView: "auto", spaceBetween: "5%", freeMode: true, centeredSlidesBounds: false, + on: { + afterInit: (swiper) => { + const swiperWrapper = swiper.el.querySelector(".swiper-wrapper"); + swiperWrapperEventInit(swiperWrapper); + disableKeyboardNavigation(swiper); + }, + transitionEnd: (swiper) => { + disableKeyboardNavigation(swiper); + }, + }, a11y: { slideRole: "listitem", }, diff --git a/src/stories/Library/slider/slider.scss b/src/stories/Library/slider/slider.scss index 077ab774b..4933ba451 100644 --- a/src/stories/Library/slider/slider.scss +++ b/src/stories/Library/slider/slider.scss @@ -1,7 +1,3 @@ -.slider { - @include vertical-spacing; -} - .slider__header { @include layout-container; @@ -50,21 +46,19 @@ max-width: calc(100vw - #{$_card-mobile-peek}); } - // For some reason, all no-image cards in the slider should be pulled - // up higher than the image ones. - .card--has-image { - margin-top: $s-xl; - } - // The slider follows a very specific card pattern: // 1: large, 2: x-large, 3: medium, 4: small - repeating. @for $i from 1 through 4 { &:nth-child(4n + #{$i}) .card { @if $i == 1 { + margin-top: $s-xl; + @extend %card-variant--large; } @else if $i == 2 { @extend %card-variant--x-large; } @else if $i == 3 { + margin-top: $s-xl; + @extend %card-variant--medium; } @else if $i == 4 { @extend %card-variant--small; diff --git a/src/stories/Library/tag/Tag.stories.tsx b/src/stories/Library/tag/Tag.stories.tsx index 542e61a4f..e30c602a6 100644 --- a/src/stories/Library/tag/Tag.stories.tsx +++ b/src/stories/Library/tag/Tag.stories.tsx @@ -1,13 +1,11 @@ import { ComponentStory } from "@storybook/react"; import { withDesign } from "storybook-addon-designs"; -import { Tag as TagComp } from "./Tag"; - -type TagProps = typeof TagComp; +import Tag, { TagProps } from "./Tag"; export default { - title: "Library / Tag", - component: TagComp, + title: "Library / Tag / Tag", + component: Tag, decorators: [withDesign], parameters: { design: { @@ -17,40 +15,35 @@ export default { layout: "centered", }, argTypes: { - hasBackground: { - control: { type: "boolean" }, - defaultValue: false, + children: { + control: { type: "text" }, + defaultValue: "Litteratur", }, - showCloseIcon: { + hasBackground: { control: { type: "boolean" }, defaultValue: false, }, - isClickable: { - control: { type: "boolean" }, - defaultValue: true, - }, }, }; -export const Tag: ComponentStory = (args) => ( - Vi anbefaler +const Template: ComponentStory = (args: TagProps) => ( + ); -Tag.args = { +export const Default = Template.bind({}); +Default.args = {}; + +export const Large = Template.bind({}); +Large.args = { size: "large", - hasBackground: true, }; -export const TagRemovable: ComponentStory = (args) => ( - Litteratur -); -TagRemovable.args = { - showCloseIcon: true, +export const WithBackground = Template.bind({}); +WithBackground.args = { hasBackground: true, }; -export const facet: ComponentStory = (args) => ( - Skønlitteratur (96) -); -facet.args = { - hasBackground: false, +export const LargeWithBackground = Template.bind({}); +LargeWithBackground.args = { + size: "large", + hasBackground: true, }; diff --git a/src/stories/Library/tag/Tag.tsx b/src/stories/Library/tag/Tag.tsx index be1f6cef5..78da44c1c 100644 --- a/src/stories/Library/tag/Tag.tsx +++ b/src/stories/Library/tag/Tag.tsx @@ -1,43 +1,33 @@ -import { useState } from "react"; import clsx from "clsx"; import { ReactComponent as CrossIcon } from "../../../public/icons/basic/icon-cross.svg"; -type TagProps = { +export type TagProps = { children: React.ReactNode; size?: "small" | "large"; - usesCursor?: boolean; hasBackground?: boolean; showCloseIcon?: boolean; - isClickable?: boolean; className?: string; }; -export const Tag = ({ +const Tag = ({ children, - hasBackground = false, size = "small", - usesCursor = true, + hasBackground = false, showCloseIcon = false, - isClickable = true, className, }: TagProps) => { - const [selected, setSelected] = useState(false); - return ( - + ); }; diff --git a/src/stories/Library/tag/tag-button/TagButton.stories.tsx b/src/stories/Library/tag/tag-button/TagButton.stories.tsx new file mode 100644 index 000000000..d3cfe2c3b --- /dev/null +++ b/src/stories/Library/tag/tag-button/TagButton.stories.tsx @@ -0,0 +1,56 @@ +import { ComponentStory } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; + +import { TagButton as TagComp } from "./TagButton"; + +type TagProps = typeof TagComp; + +export default { + title: "Library / Tag / Tag button", + component: TagComp, + decorators: [withDesign], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?node-id=836%3A5757", + }, + layout: "centered", + }, + argTypes: { + hasBackground: { + control: { type: "boolean" }, + defaultValue: false, + }, + showCloseIcon: { + control: { type: "boolean" }, + defaultValue: false, + }, + isClickable: { + control: { type: "boolean" }, + defaultValue: true, + }, + }, +}; + +export const Tag: ComponentStory = (args) => ( + Vi anbefaler +); +Tag.args = { + size: "large", + hasBackground: true, +}; + +export const TagRemovable: ComponentStory = (args) => ( + Litteratur +); +TagRemovable.args = { + showCloseIcon: true, + hasBackground: true, +}; + +export const facet: ComponentStory = (args) => ( + Skønlitteratur (96) +); +facet.args = { + hasBackground: false, +}; diff --git a/src/stories/Library/tag/tag-button/TagButton.tsx b/src/stories/Library/tag/tag-button/TagButton.tsx new file mode 100644 index 000000000..7a668f194 --- /dev/null +++ b/src/stories/Library/tag/tag-button/TagButton.tsx @@ -0,0 +1,49 @@ +import { useState } from "react"; +import clsx from "clsx"; + +type TagProps = { + children: React.ReactNode; + size?: "small" | "large"; + usesCursor?: boolean; + hasBackground?: boolean; + showCloseIcon?: boolean; + isClickable?: boolean; + className?: string; +}; + +export const TagButton = ({ + children, + hasBackground = false, + size = "small", + usesCursor = true, + showCloseIcon = false, + isClickable = true, + className, +}: TagProps) => { + const [selected, setSelected] = useState(false); + + return ( + + ); +}; + +export default TagButton; diff --git a/src/stories/Library/tag/tag-link/TagLink.stories.tsx b/src/stories/Library/tag/tag-link/TagLink.stories.tsx new file mode 100644 index 000000000..e80fe803a --- /dev/null +++ b/src/stories/Library/tag/tag-link/TagLink.stories.tsx @@ -0,0 +1,55 @@ +import { ComponentStory } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; + +import { TagLink as TagComp } from "./TagLink"; + +type TagProps = typeof TagComp; + +export default { + title: "Library / Tag / Tag link", + component: TagComp, + decorators: [withDesign], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?node-id=836%3A5757", + }, + layout: "centered", + }, + argTypes: { + children: { + name: "text", + control: { type: "text" }, + defaultValue: "Litteratur", + }, + hasBackground: { + control: { type: "boolean" }, + defaultValue: false, + }, + showCloseIcon: { + control: { type: "boolean" }, + defaultValue: false, + }, + }, +}; + +export const Default: ComponentStory = ({ children, ...args }) => ( + {children} +); + +export const LargeWithBackground: ComponentStory = ({ + children, + ...args +}) => {children}; +LargeWithBackground.args = { + size: "large", + hasBackground: true, +}; + +export const Removable: ComponentStory = ({ children, ...args }) => ( + {children} +); +Removable.args = { + showCloseIcon: true, + hasBackground: true, +}; diff --git a/src/stories/Library/tag/tag-link/TagLink.tsx b/src/stories/Library/tag/tag-link/TagLink.tsx new file mode 100644 index 000000000..14f5b2665 --- /dev/null +++ b/src/stories/Library/tag/tag-link/TagLink.tsx @@ -0,0 +1,40 @@ +import clsx from "clsx"; + +type TagProps = { + children: React.ReactNode; + size?: "small" | "large"; + hasBackground?: boolean; + showCloseIcon?: boolean; + className?: string; +}; + +export const TagLink = ({ + children, + size = "small", + hasBackground = false, + showCloseIcon = false, + className, +}: TagProps) => { + return ( + + {children} + {showCloseIcon && ( + close icon + )} + + ); +}; + +export default TagLink; diff --git a/src/stories/Library/tag/tag-list/TagList.stories.tsx b/src/stories/Library/tag/tag-list/TagList.stories.tsx new file mode 100644 index 000000000..6820b05f5 --- /dev/null +++ b/src/stories/Library/tag/tag-list/TagList.stories.tsx @@ -0,0 +1,36 @@ +import { ComponentMeta, ComponentStory } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import TagList from "./TagList"; + +export default { + title: "Library / Tag List", + component: TagList, + decorators: [withDesign], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?node-id=836%3A5757", + }, + layout: "centered", + argTypes: { + tags: { + defaultValue: [], + type: "array", + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const Default = Template.bind({}); +Default.args = { + tags: ["litteratur"], +}; + +export const WithTags = Template.bind({}); +WithTags.args = { + tags: ["litteratur", "skønlitteratur", "børn", "fantasy"], +}; diff --git a/src/stories/Library/tag/tag-list/TagList.tsx b/src/stories/Library/tag/tag-list/TagList.tsx new file mode 100644 index 000000000..d87243714 --- /dev/null +++ b/src/stories/Library/tag/tag-list/TagList.tsx @@ -0,0 +1,50 @@ +import { FC, useEffect } from "react"; +import Tag from "../Tag"; + +type TagListProps = { + tags: string[]; +}; + +const TagList: FC = ({ tags }) => { + useEffect(() => { + require("../../../utils/show-more"); + }, []); + + if (!tags) { + return null; + } + + return ( + <> + {tags.length > 1 && ( +
    +
      + {tags.map((tag, index) => ( +
    • + + {tag} + +
    • + ))} +
    + +
    + )} + {tags.length === 1 && ( +
    + + {tags[0]} + +
    + )} + + ); +}; + +export default TagList; diff --git a/src/stories/Library/tag/tag-list/tag-list.scss b/src/stories/Library/tag/tag-list/tag-list.scss new file mode 100644 index 000000000..747086d40 --- /dev/null +++ b/src/stories/Library/tag/tag-list/tag-list.scss @@ -0,0 +1,12 @@ +.tag-list { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; + + ul, + ol { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + } +} diff --git a/src/stories/Library/tag/tag.scss b/src/stories/Library/tag/tag.scss index 717c3f1b8..7c896e491 100644 --- a/src/stories/Library/tag/tag.scss +++ b/src/stories/Library/tag/tag.scss @@ -5,6 +5,7 @@ border: 1px solid $color__global-tertiary-1; padding: $s-sm $s-md; @include typography($typo__tags); + text-decoration: none; &.tag--fill { background-color: $color__global-secondary; diff --git a/src/stories/utils/show-more.md b/src/stories/utils/show-more.md index 25c6a2d9b..4d0ae3d4c 100644 --- a/src/stories/utils/show-more.md +++ b/src/stories/utils/show-more.md @@ -10,7 +10,7 @@ Structure your HTML elements as follows for implementing the "Show More/Less" feature: - **List Element**: -Use an `
      ` or `
        ` element with the `data-show-more-list` attribute +Use an wrapper element with the `data-show-more-list` attribute This element will contain both the list items and the toggle button. - **List Items**: Assign the `data-show-more-item` attribute to each list item that you want @@ -34,11 +34,13 @@ Set the initial number of visible items with the ### Example HTML Markup ```html -
          -
        • Item 1
        • -
        • Item 2
        • - -
        • Item 3
        • +
          +
            +
          • Item 1
          • +
          • Item 2
          • + +
          • Item 3
          • +
          -
        +
    `````` diff --git a/src/styles/scss/tools/placeholder.scss b/src/styles/scss/tools/placeholder.scss index 0bd06719f..24e848957 100644 --- a/src/styles/scss/tools/placeholder.scss +++ b/src/styles/scss/tools/placeholder.scss @@ -46,7 +46,7 @@ } } -%link-tag { +@mixin link-tag { @include typography($typo__body-placeholder); text-decoration: none; @@ -72,6 +72,10 @@ } } +%link-tag { + @include link-tag; +} + %button-link { @extend %link-tag; @@ -89,6 +93,17 @@ } } +%identity-placeholder-text { + @include typography($typo__card-placeholder--medium); + @extend %identity-placeholder-inner-padding; + display: flex; + height: 100%; + overflow: hidden; + + align-items: end; + color: $color__text-primary-white; +} + %default-focus-visible { &:focus-visible { outline: 2px solid $color__text-primary-black; diff --git a/src/styles/scss/tools/variables.layout.scss b/src/styles/scss/tools/variables.layout.scss index e9ee294b7..f14f77c43 100644 --- a/src/styles/scss/tools/variables.layout.scss +++ b/src/styles/scss/tools/variables.layout.scss @@ -13,13 +13,16 @@ $layout__max-width--medium: 1024px; $layout__max-width--large: 1440px; $layout__max-width--x-large: 1920px; $layout__max-width--xx-large: 2200px; -$layout__max-width--event-description: 886px; + +$block-max-width__small: 780px; +$block-max-width__medium: 896px; +$block-max-width__large: 1124px; +$block-max-width__x-large: 1240px; +$block-max-width__2x-large: $layout__max-width--large; // Variables specifically for managing the vertical space between elements -$_vertical-spacing--small: $s-sm; -$_vertical-spacing--medium: $s-md; -$_vertical-spacing--large: $s-lg; -$_vertical-spacing--x-large: $s-xl; +$_block-vertical-spacing: 48px; +$_block-vertical-spacing--large: 64px; // Edge spacing for containers, ensures edge spacing for mobile or tablet. $layout__edge-spacing: $s-md; @@ -29,118 +32,34 @@ $layout__edge-spacing: $s-md; $max-width: $layout__max-width--medium, $padding: $layout__edge-spacing ) { - max-width: $max-width; - margin: auto; + max-width: $max-width + ($padding * 2); + margin-left: auto; + margin-right: auto; padding-left: $padding; padding-right: $padding; box-sizing: border-box; } -// Mixin for controlling vertical spacing(margin) of an element -@mixin vertical-spacing( - $top: $_vertical-spacing--large, - $bottom: $_vertical-spacing--large -) { - margin-top: $top; - margin-bottom: $bottom; -} - -// ########## Avoid using utilities as described in documentation ############ - -// Utility classes for vertical spacing adjustments -.layout__vertical-spacing { - @include vertical-spacing; - - &--small { - @include vertical-spacing( - $_vertical-spacing--small, - $_vertical-spacing--small - ); - } - &--medium { - @include vertical-spacing( - $_vertical-spacing--medium, - $_vertical-spacing--medium - ); - } - &--large { - @include vertical-spacing( - $_vertical-spacing--large, - $_vertical-spacing--large - ); - } - &--x-large { - @include vertical-spacing( - $_vertical-spacing--x-large, - $_vertical-spacing--x-large - ); - } -} - -// Utility classes for max-width adjustments -.layout__max-width { - @include layout-container($padding: 0); +// Mixin for controlling vertical spacing (margin) of an element +@mixin block-spacing($modifier: "standard") { + $_spacing: $_block-vertical-spacing; + $_spacing--large: $_block-vertical-spacing--large; - &--x-small { - @include layout-container( - $max-width: $layout__max-width--x-small, - $padding: 0 - ); - } - &--small { - @include layout-container( - $max-width: $layout__max-width--small, - $padding: 0 - ); - } - &--medium { - @include layout-container( - $max-width: $layout__max-width--medium, - $padding: 0 - ); - } - &--large { - @include layout-container( - $max-width: $layout__max-width--large, - $padding: 0 - ); - } - &--x-large { - @include layout-container( - $max-width: $layout__max-width--x-large, - $padding: 0 - ); - } - &--xx-large { - @include layout-container( - $max-width: $layout__max-width--xx-large, - $padding: 0 - ); + // If we want sibling spacing, we'll move the element up by 1px, to avoid + // double borders. + @if ($modifier == "sibling") { + $_spacing: -1px; + $_spacing--large: -1px; } -} - -// Utility classes for edge-spacing (padding) adjustments -.layout__edge-spacing { - padding-left: $s-md; - padding-right: $s-md; - &--small { - padding-left: $s-sm; - padding-right: $s-sm; + @if ($modifier == "negative") { + $_spacing: $_spacing * -1; + $_spacing--large: $_spacing--large * -1; } - &--medium { - padding-left: $s-md; - padding-right: $s-md; - } - - &--large { - padding-left: $s-lg; - padding-right: $s-lg; - } + margin-top: $_spacing; - &--x-large { - padding-left: $s-xl; - padding-right: $s-xl; + @include media-query__medium { + margin-top: $_spacing--large; } } diff --git a/src/styles/scss/tools/variables.spacings.scss b/src/styles/scss/tools/variables.spacings.scss index b370166cd..98445bf8a 100644 --- a/src/styles/scss/tools/variables.spacings.scss +++ b/src/styles/scss/tools/variables.spacings.scss @@ -27,5 +27,5 @@ $spacings: ( $placeholder-paddings: ( mobile: $s-lg, small: $s-xl, - medium: $s-3xl, + medium: $s-2xl, ); diff --git a/src/styles/scss/tools/variables.typography.scss b/src/styles/scss/tools/variables.typography.scss index 12657aa42..93b80906d 100644 --- a/src/styles/scss/tools/variables.typography.scss +++ b/src/styles/scss/tools/variables.typography.scss @@ -130,9 +130,6 @@ $typo__body-large: ( font-style: normal, font-weight: $font__weight--normal, font-size: 16px, - line-height: 42px, - ), - small: ( line-height: 160%, ), medium: ( @@ -164,6 +161,17 @@ $typo__body-placeholder: ( ), ); +$typo__desktop-menu-item: ( + mobile: ( + font-family: $font__body, + font-style: normal, + font-weight: $font__weight--normal, + line-height: 32px, + color: $color__text-secondary-gray, + font-size: 18px, + ), +); + // "Body Copy - M - medium" $typo__body-medium: ( mobile: ( @@ -325,7 +333,7 @@ $typo__card-placeholder: ( ), ); -$typo__card-placeholder--small: ( +$typo__card-placeholder--medium: ( mobile: ( font-family: $font__title, font-style: normal, @@ -338,3 +346,17 @@ $typo__card-placeholder--small: ( line-height: 32px, ), ); + +$typo__card-placeholder--grid: ( + mobile: ( + font-family: $font__title, + font-style: normal, + font-weight: $font__weight--normal, + font-size: 16px, + line-height: 20px, + ), + #{$breakpoint__large-card}: ( + font-size: 20px, + line-height: 24px, + ), +); diff --git a/wysiwyg.scss b/wysiwyg.scss new file mode 100644 index 000000000..c24e28f9a --- /dev/null +++ b/wysiwyg.scss @@ -0,0 +1,14 @@ +@import "./src/styles/scss/tools"; +@import "./src/styles/scss/reset"; +@import "./src/stories/Library/rich-text/rich-text"; + +// Making CKEditor reflect the frontend display. +// This file will be loaded into CMS using ckeditor5-stylesheets. +.ck.ck-content { + @extend %rich-text; + + ul, + ol { + list-style: none; + } +} diff --git a/yarn.lock b/yarn.lock index 4a1564b56..b1d8c9122 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2873,10 +2873,10 @@ lz-string "^1.5.0" pretty-format "^27.0.2" -"@testing-library/jest-dom@^6.2.0": - version "6.2.0" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.2.0.tgz#b572bd5cd6b29314487bac7ba393188e4987b4f7" - integrity sha512-+BVQlJ9cmEn5RDMUS8c2+TU6giLvzaHZ8sU/x0Jj7fk+6/46wPdwlgOPcpxS17CjcanBi/3VmGMqVr2rmbUmNw== +"@testing-library/jest-dom@^6.4.2": + version "6.4.2" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.2.tgz#38949f6b63722900e2d75ba3c6d9bf8cffb3300e" + integrity sha512-CzqH0AFymEMG48CpzXFriYYkOjk6ZGPCLMhW9e9jg3KMCn5OfJecF8GtGW7yGfR/IgCe3SX8BSwjdzI6BBbZLw== dependencies: "@adobe/css-tools" "^4.3.2" "@babel/runtime" "^7.9.2" @@ -3034,10 +3034,10 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^29.5.11": - version "29.5.11" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.11.tgz#0c13aa0da7d0929f078ab080ae5d4ced80fa2f2c" - integrity sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ== +"@types/jest@^29.5.12": + version "29.5.12" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" + integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== dependencies: expect "^29.0.0" pretty-format "^29.0.0" @@ -12748,10 +12748,10 @@ postcss@^7, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, po picocolors "^0.2.1" source-map "^0.6.1" -postcss@^8.1.0, postcss@^8.4.19, postcss@^8.4.33: - version "8.4.33" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742" - integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg== +postcss@^8.1.0, postcss@^8.4.19, postcss@^8.4.35: + version "8.4.35" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.35.tgz#60997775689ce09011edf083a549cea44aabe2f7" + integrity sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA== dependencies: nanoid "^3.3.7" picocolors "^1.0.0" @@ -13977,10 +13977,10 @@ sass-loader@^10.0.5: schema-utils "^3.0.0" semver "^7.3.2" -sass@^1.70.0: - version "1.70.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.70.0.tgz#761197419d97b5358cb25f9dd38c176a8a270a75" - integrity sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ== +sass@^1.71.0: + version "1.71.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.71.0.tgz#b3085759b9b2ab503a977aecb7e91153bf941117" + integrity sha512-HKKIKf49Vkxlrav3F/w6qRuPcmImGVbIXJ2I3Kg0VMA+3Bav+8yE9G5XmP5lMj6nl4OlqbPftGAscNaNu28b8w== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -15968,10 +15968,10 @@ web-namespaces@^1.0.0: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== -web-vitals@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-3.5.1.tgz#af7a9dc60708b81007922ab55a23d963676ba30a" - integrity sha512-xQ9lvIpfLxUj0eSmT79ZjRoU5wIRfIr7pNukL7ZE4EcWZSmfZQqOlhuAGfkVa3EFmzPHZhWhXfm2i5ys+THVPg== +web-vitals@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-3.5.2.tgz#5bb58461bbc173c3f00c2ddff8bfe6e680999ca9" + integrity sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg== webidl-conversions@^3.0.0: version "3.0.1" From 783f68fa6241ffe263142d55c06e60330978bcd7 Mon Sep 17 00:00:00 2001 From: Adam Antal Date: Thu, 22 Feb 2024 13:35:29 +0100 Subject: [PATCH 54/54] Add aria labels to header links that don't have text inside --- src/stories/Blocks/header/Header.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stories/Blocks/header/Header.tsx b/src/stories/Blocks/header/Header.tsx index 58ab130a7..d50a0828f 100644 --- a/src/stories/Blocks/header/Header.tsx +++ b/src/stories/Blocks/header/Header.tsx @@ -84,7 +84,7 @@ export const Header = (props: HeaderProps) => { {signedIn && haveNotification && (
    )} - + {signedIn && ( {username} )} @@ -92,7 +92,7 @@ export const Header = (props: HeaderProps) => {