diff --git a/base.scss b/base.scss index 1c94a6f29..5e584d9d1 100644 --- a/base.scss +++ b/base.scss @@ -144,6 +144,7 @@ @import "./src/stories/Library/filtered-event-list/filtered-event-list"; @import "./src/stories/Library/event-list-stacked/event-list-stacked"; @import "./src/stories/Library/material-search/material-search"; +@import "./src/stories/Library/banner/banner"; // Autosuggest block styling needs to be loaded before the rest of the scss for autosuggest @import "./src/stories/Blocks/autosuggest/autosuggest"; diff --git a/public/icons/basic/icon-underlined.svg b/public/icons/basic/icon-underlined.svg new file mode 100644 index 000000000..8352ab299 --- /dev/null +++ b/public/icons/basic/icon-underlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/stories/Library/banner/Banner.stories.tsx b/src/stories/Library/banner/Banner.stories.tsx new file mode 100644 index 000000000..4f5ac8a6b --- /dev/null +++ b/src/stories/Library/banner/Banner.stories.tsx @@ -0,0 +1,72 @@ +import { ComponentMeta, ComponentStory } from "@storybook/react"; +import { withDesign } from "storybook-addon-designs"; +import Banner from "./Banner"; + +export default { + title: "Library / Banner", + component: Banner, + decorators: [withDesign], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/design/Zx9GrkFA3l4ISvyZD2q0Qi/Designsystem?node-id=446-6957&t=IWAOniAbcjV2y2Hf-4", + }, + }, + argTypes: { + imageSrc: { + defaultValue: "images/campaign_cover.jpg", + control: { type: "text" }, + }, + title: { + name: "Title", + defaultValue: "Hvad skal jeg høre?", + control: { type: "text" }, + }, + description: { + name: "Description", + defaultValue: + "Om du er dedikeret musiknørd eller moderat musikinteresseret, så er dette siden til dig. Her kan du finde anbefalinger, digitale musikmagasiner, nyheder, musiklitteratur og meget mere.", + control: { type: "text" }, + }, + link: { + name: "Link", + defaultValue: "#", + control: { type: "text" }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ; + +export const Default = Template.bind({}); + +export const NoImage = Template.bind({}); +NoImage.args = { + imageSrc: undefined, +}; + +export const NoImageOnlyTitle = Template.bind({}); +NoImageOnlyTitle.args = { + title: "Title uden billede", + imageSrc: undefined, + description: undefined, +}; + +export const NoImageOnlyDescription = Template.bind({}); +NoImageOnlyDescription.args = { + title: undefined, + imageSrc: undefined, + description: + "Om du er dedikeret musiknørd eller moderat musikinteresseret, så er dette siden til dig. Her kan du finde anbefalinger, digitale musikmagasiner, nyheder, musiklitteratur og meget mere.", +}; + +export const WithImageOnlyTitle = Template.bind({}); +WithImageOnlyTitle.args = { + title: "Banner uden beskrivelse", + description: undefined, +}; +export const WithImageOnlyDescription = Template.bind({}); +WithImageOnlyDescription.args = { + description: + "Om du er dedikeret musiknørd eller moderat musikinteresseret, så er dette siden til dig. Her kan du finde anbefalinger, digitale musikmagasiner, nyheder, musiklitteratur og meget mere.", +}; diff --git a/src/stories/Library/banner/Banner.tsx b/src/stories/Library/banner/Banner.tsx new file mode 100644 index 000000000..9bdb2787e --- /dev/null +++ b/src/stories/Library/banner/Banner.tsx @@ -0,0 +1,46 @@ +import clsx from "clsx"; +import { FC, ReactNode } from "react"; +import { ReactComponent as ArrowLargeRight } from "../Arrows/icon-arrow-ui/icon-arrow-ui-large-right.svg"; + +type BannerType = { + link: string; + title: string; + imageSrc?: ReactNode; + description?: string; +}; + +const Banner: FC = ({ link, imageSrc, title, description }) => { + const backgroundImageStyle = imageSrc + ? { backgroundImage: `url(${imageSrc})` } + : {}; + return ( + +
+
+ {title && ( +

) words. + // eslint-disable-next-line react/no-danger + dangerouslySetInnerHTML={{ __html: title }} + /> + )} + {description &&

{description}

} + +

+
+
+ ); +}; + +export default Banner; diff --git a/src/stories/Library/banner/banner.scss b/src/stories/Library/banner/banner.scss new file mode 100644 index 000000000..7a6bd4e47 --- /dev/null +++ b/src/stories/Library/banner/banner.scss @@ -0,0 +1,79 @@ +$_banner-content-wrapper-width: 944px; +$_banner-content-max-width-small: 330px; +$_banner-content-max-width-medium: 569px; +$_banner-content-no-image-max-width-small: $layout__max-width--small; +$_banner-height-small: 500px; +$_banner-height-medium: 810px; + +.banner { + @include layout-container($layout__max-width--large, 0); + + display: grid; + align-items: center; + text-decoration: none; + box-sizing: border-box; + background-color: $color__global-secondary; + min-height: $_banner-height-small; + + &--has-image { + background-repeat: no-repeat; + background-position: center; + background-size: cover; + height: 100%; + width: 100%; + } + + @include media-query__small { + min-height: $_banner-height-medium; + } +} + +.banner__content-wrapper { + @include layout-container($_banner-content-wrapper-width, 0); + width: 100%; + padding: $s-2xl 0; + + &--has-image { + padding-right: $s-2xl; + } + + @include media-query__small { + padding-right: unset; + } +} + +.banner__content { + display: flex; + flex-direction: column; + align-items: center; + gap: $s-md; + text-align: center; + padding: $s-xl; + margin: 0 auto; + max-width: $_banner-content-max-width-medium; + + &--has-image { + padding: $s-xl; + margin: unset; + text-align: unset; + align-items: unset; + background-color: $color__global-white; + max-width: $_banner-content-max-width-small; + } + + @include media-query__small { + gap: $s-lg; + padding: calc($s-2xl + 6px); + max-width: $_banner-content-max-width-medium; + } +} + +.banner__title { + @include typography($typo__h2); + @include u-extending-underline-style; +} + +.banner__description { + @include typography($typo__body-placeholder); + line-height: 160%; +} diff --git a/src/styles/scss/tools/mixins.tools.scss b/src/styles/scss/tools/mixins.tools.scss index a78af14f2..62a722ab6 100644 --- a/src/styles/scss/tools/mixins.tools.scss +++ b/src/styles/scss/tools/mixins.tools.scss @@ -70,3 +70,29 @@ text-overflow: ellipsis; text-align: left; } + +/** + * Mixin `u-extending-underline-style` applies a custom underline effect to `` elements. + * - Uses a pseudo-element (::after) with a positioned SVG image as the underline. + * - Removes default text underline. + */ +@mixin u-extending-underline-style { + u { + position: relative; + text-decoration: none; + + &::after { + content: ""; + position: absolute; + bottom: -5px; + left: 0; + width: 100%; + height: 12px; + background-repeat: no-repeat; + background-position: left; + background-size: cover; + // Underlined icon from public/icons/basic/icon-underlined.svg + background-image: url("data:image/svg+xml,%3Csvg width='205' height='8' viewBox='0 0 205 8' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1.11133 6.87425C73.7223 0.129386 128.695 1.4981 203.889 1.8943' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A"); + } + } +}