From 865623d3a7cc17bff64944ef3e8b1b3d50b8f6b5 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 30 Oct 2024 10:41:42 +0100 Subject: [PATCH 01/47] refactor(sbb-image): extract 'caption' and 'copyright' feature --- src/elements/core/styles/image.scss | 35 +++++ src/elements/core/styles/standard-theme.scss | 1 + src/elements/image/image.scss | 12 -- src/elements/image/image.stories.ts | 76 +++++----- src/elements/image/image.ts | 138 ++++++------------- src/elements/image/readme.md | 57 +++++--- 6 files changed, 151 insertions(+), 168 deletions(-) create mode 100644 src/elements/core/styles/image.scss diff --git a/src/elements/core/styles/image.scss b/src/elements/core/styles/image.scss new file mode 100644 index 0000000000..35b3e6f226 --- /dev/null +++ b/src/elements/core/styles/image.scss @@ -0,0 +1,35 @@ +@use './mixins/typo'; + +.sbb-figure { + display: grid; + grid-row-gap: var(--sbb-spacing-fixed-4x); + margin: 0; + height: 100%; + + img, + sbb-image, + .sbb-image { + grid-row: 1; + grid-column: 1; + } + + figcaption, + .sbb-caption { + grid-row: 2; + grid-column: 1; + @include typo.text-xs--regular; + } + + $alignments: start, center, end; + @each $row-alignment in $alignments { + @each $column-alignment in $alignments { + .sbb-figure-overlap-#{$row-alignment}-#{$column-alignment} { + z-index: 1; + grid-row: 1; + grid-column: 1; + place-self: #{$row-alignment} #{$column-alignment}; + margin: 0.75rem; + } + } + } +} diff --git a/src/elements/core/styles/standard-theme.scss b/src/elements/core/styles/standard-theme.scss index 984efe558b..3540ec02f0 100644 --- a/src/elements/core/styles/standard-theme.scss +++ b/src/elements/core/styles/standard-theme.scss @@ -5,6 +5,7 @@ @use './typography'; @use './a11y'; @use './animation'; +@use './image'; @use './layout'; @use './lists'; @use './table'; diff --git a/src/elements/image/image.scss b/src/elements/image/image.scss index ba9db1741d..fd95ab7e25 100644 --- a/src/elements/image/image.scss +++ b/src/elements/image/image.scss @@ -76,14 +76,6 @@ --sbb-image-border-radius: var(--sbb-border-radius-infinity); } -.sbb-image__figure { - display: flex; - flex-direction: column; - gap: var(--sbb-spacing-fixed-4x); - margin: 0; - height: 100%; -} - .sbb-image__img { opacity: 0.000001; @@ -128,7 +120,3 @@ picture { aspect-ratio: var(--sbb-image-aspect-ratio); border-radius: var(--sbb-image-border-radius); } - -.sbb-image__caption { - @include sbb.text-xs--regular; -} diff --git a/src/elements/image/image.stories.ts b/src/elements/image/image.stories.ts index 55618550bc..baf84fd271 100644 --- a/src/elements/image/image.stories.ts +++ b/src/elements/image/image.stories.ts @@ -9,8 +9,35 @@ import images from '../core/images.js'; import { SbbImageElement } from './image.js'; import readme from './readme.md?raw'; - -const Template = (args: Args): TemplateResult => html``; +import '../chip.js'; + +const WithCaptionTemplate = (args: Args): TemplateResult => html` +
+ +
+ With the + Half Fare Travelcard + , you can travel for half price on all SBB routes and most other railways as well as on boats + and Postbuses. You also benefit from discounts on urban transport as well as other additional + attractive services and discounts. +
+
+`; + +const Template = (args: Args): TemplateResult => html` +
+ +
+`; + +const WithChipTemplate = (args: Args): TemplateResult => html` +
+ + AI generated +
+`; const imageSrc: InputType = { control: { @@ -37,31 +64,6 @@ const alt: InputType = { }, }; -const caption: InputType = { - control: { - type: 'text', - }, -}; - -const copyright: InputType = { - control: { - type: 'text', - }, - table: { - category: 'Legal', - }, -}; - -const copyrightHolder: InputType = { - control: { - type: 'inline-radio', - }, - options: ['Organization', 'Person'], - table: { - category: 'Legal', - }, -}; - const customFocalPoint: InputType = { control: { type: 'boolean', @@ -128,11 +130,8 @@ const performanceMark: InputType = { const defaultArgTypes: ArgTypes = { alt, - caption, 'border-radius': borderRadius, 'aspect-ratio': aspectRatio, - copyright, - 'copyright-holder': copyrightHolder, 'custom-focal-point': customFocalPoint, 'focal-point-debug': focalPointDebug, 'focal-point-x': focalPointX, @@ -145,12 +144,9 @@ const defaultArgTypes: ArgTypes = { const defaultArgs: Args = { alt: '', - caption: undefined, // we need a string and not boolean, otherwise storybook add/remove the attribute but don't write the value 'border-radius': 'default', 'aspect-ratio': aspectRatio.options![0], - copyright: '', - 'copyright-holder': copyrightHolder.options![0], 'custom-focal-point': false, 'focal-point-debug': false, 'focal-point-x': '', @@ -162,13 +158,9 @@ const defaultArgs: Args = { }; export const Default: StoryObj = { - render: Template, + render: WithCaptionTemplate, argTypes: defaultArgTypes, - args: { - ...defaultArgs, - caption: - 'Mit Ihrem Halbtax profitieren Sie zudem von attraktiven Zusatzleistungen und Rabatten. Wenn Sie unter 25 Jahre jung sind, können Sie zu Ihrem Halbtax das beliebte Gleis 7 dazu kaufen.', - }, + args: defaultArgs, }; export const TransparentImage: StoryObj = { @@ -208,6 +200,12 @@ export const SkipLqip: StoryObj = { }, }; +export const WithChip: StoryObj = { + render: WithChipTemplate, + argTypes: defaultArgTypes, + args: defaultArgs, +}; + const meta: Meta = { decorators: [ (story) => html`
${story()}
`, diff --git a/src/elements/image/image.ts b/src/elements/image/image.ts index dce9297bfc..d544d75999 100644 --- a/src/elements/image/image.ts +++ b/src/elements/image/image.ts @@ -24,7 +24,6 @@ import { type TemplateResult, } from 'lit'; import { customElement, eventOptions, property } from 'lit/decorators.js'; -import { ref } from 'lit/directives/ref.js'; import { forceType } from '../core/decorators.js'; import { hostContext } from '../core/dom.js'; @@ -199,31 +198,6 @@ class SbbImageElement extends LitElement { @property({ attribute: 'skip-lqip', type: Boolean, reflect: true }) public accessor skipLqip: boolean = false; - /** - * A caption can provide additional context to the image (e.g. - * descriptions and the like). - * Links will automatically receive tabindex=-1 if hideFromScreenreader - * is set to true. That way they will no longer become focusable. - */ - @forceType() - @property() - public accessor caption: string = ''; - - /** - * If a copyright text is provided, we will add it to the caption - * and create a structured data json-ld block with the copyright - * information. - */ - @forceType() - @property() - public accessor copyright: string = ''; - - /** - * Copyright holder can either be an Organization or a Person - */ - @property({ attribute: 'copyright-holder' }) - public accessor copyrightHolder: 'Organization' | 'Person' = 'Organization'; - /** * Set this to true, if you want to pass a custom focal point * for the image. See full documentation here: @@ -613,9 +587,6 @@ class SbbImageElement extends LitElement { } protected override render(): TemplateResult { - let { caption } = this; - let schemaData = ''; - const imageUrlLQIP = this._prepareImageUrl(this.imageSrc, true); const imageUrlWithParams = this._prepareImageUrl(this.imageSrc, false); @@ -624,19 +595,6 @@ class SbbImageElement extends LitElement { this.importance = 'low'; } - if (this.copyright) { - caption = `${this.caption} ©${this.copyright}`; - schemaData = `{ - "@context": "https://schema.org", - "@type": "Photograph", - "image": "${this.imageSrc}", - "copyrightHolder": { - "@type": "${this.copyrightHolder}", - "name": "${this.copyright}" - } - }`; - } - const pictureSizeConfigs = this._preparePictureSizeConfigs(); /** @@ -646,66 +604,52 @@ class SbbImageElement extends LitElement { * they might try to interpret the img element. */ return html` -
-
- ${!this.skipLqip - ? html`` - : nothing} - - - - ${pictureSizeConfigs.map((config) => { - const imageHeight = config.image.height; - const imageWidth = config.image.width; - const mediaQuery = this._createMediaQueryString(config.mediaQueries); - return [ - html` `, - ]; - })} - ${this.alt this.dispatchEvent(new Event('error'))} - class="sbb-image__img" - src=${this.imageSrc!} +
+ ${!this.skipLqip + ? html` - -
- ${caption - ? html`
{ - this._captionElement = el as HTMLElement; - })} - >
` + />` : nothing} - ${schemaData - ? html`` - : nothing} -
+ + + + ${pictureSizeConfigs.map((config) => { + const imageHeight = config.image.height; + const imageWidth = config.image.width; + const mediaQuery = this._createMediaQueryString(config.mediaQueries); + return [ + html` `, + ]; + })} + ${this.alt this.dispatchEvent(new Event('error'))} + class="sbb-image__img" + src=${this.imageSrc!} + width="1000" + height="562" + loading=${this.loading ?? nothing} + decoding=${this.decoding ?? nothing} + .fetchPriority=${this.importance ?? nothing} + /> + + `; } } diff --git a/src/elements/image/readme.md b/src/elements/image/readme.md index 2d53ca42f9..1f54c56c66 100644 --- a/src/elements/image/readme.md +++ b/src/elements/image/readme.md @@ -3,30 +3,47 @@ The `sbb-image` component is used to render an image. Mainly from cdn.img.sbb.ch (with `imageSrc`), but we can set an external image too. The size can be set with `pictureSizesConfig`. +## Usage + +It is possible to add a caption and/or the copyright by wrapping everything in a `figure` tag. + +```html +
+ or or <... class="sbb-image" /> +
Caption / Copyright
+
+``` + +Also, you can place overlapping content by using the `sbb-figure-overlap-${horizontal-alignment}-${vertical-alignment}` utility classes. + +```html +
+ + +
+``` + ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| -------------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `alt` | `alt` | public | `string` | `''` | An alt text is not always necessary (e.g. in teaser cards when additional link text is provided). In this case we can leave the value of the alt attribute blank, but the attribute itself still needs to be present. That way we can signal assistive technology, that they can skip the image. | -| `aspectRatio` | `aspect-ratio` | public | `'free' \| '1-1' \| '1-2' \| '2-1' \| '2-3' \| '3-2' \| '3-4' \| '4-3' \| '4-5' \| '5-4' \| '9-16' \| '16-9'` | `'16-9'` | Set an aspect ratio default is '16-9' (16/9) other values: 'free', '1-1', '1-2', '2-1', '2-3', '3-2', '3-4', '4-3', '4-5', '5-4', '9-16' | -| `borderRadius` | `border-radius` | public | `'default' \| 'none' \| 'round'` | `'default'` | Border radius of the image. Choose between a default radius, no radius and a completely round image. | -| `caption` | `caption` | public | `string` | `''` | A caption can provide additional context to the image (e.g. descriptions and the like). Links will automatically receive tabindex=-1 if hideFromScreenreader is set to true. That way they will no longer become focusable. | -| `complete` | - | public | `boolean` | | Whether the image is finished loading or failed to load. | -| `copyright` | `copyright` | public | `string` | `''` | If a copyright text is provided, we will add it to the caption and create a structured data json-ld block with the copyright information. | -| `copyrightHolder` | `copyright-holder` | public | `'Organization' \| 'Person'` | `'Organization'` | Copyright holder can either be an Organization or a Person | -| `customFocalPoint` | `custom-focal-point` | public | `boolean` | `false` | Set this to true, if you want to pass a custom focal point for the image. See full documentation here: https://docs.imgix.com/apis/rendering/focalpoint-crop | -| `decoding` | `decoding` | public | `'sync' \| 'async' \| 'auto'` | `'auto'` | If the lazy property is set to true, the module will automatically change the decoding to async, otherwise the decoding is set to auto which leaves the handling up to the browser. Read more about the decoding attribute here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decoding | -| `focalPointDebug` | `focal-point-debug` | public | `boolean` | `false` | Set this to true, to receive visual guidance where the custom focal point is currently set. | -| `focalPointX` | `focal-point-x` | public | `number` | `1` | Pass in a floating number between 0 (left) and 1 (right). | -| `focalPointY` | `focal-point-y` | public | `number` | `1` | Pass in a floating number between 0 (top) and 1 (bottom). | -| `imageSrc` | `image-src` | public | `string` | `''` | Right now the module is heavily coupled with the image delivery service imgix and depends on the original files being stored inside AEM. You can pass in any https://cdn.img.sbb.ch img src address you find on sbb.ch to play around with it. Just strip the url parameters and paste in the plain file address. If you want to know how to best work with this module with images coming from a different source, please contact the LYNE Core Team. | -| `importance` | `importance` | public | `'auto' \| 'high' \| 'low'` | `'high'` | The importance attribute is fairly new attribute which should help the browser decide which resources it should prioritise during page load. We will set the attribute value based on the value, we receive in the loading attribute. 'eager', which we use for the largest image within the initial viewport, will set the attribute value to 'high'. 'lazy', which we use for images below the fold, will set the attribute value to 'low'. | -| `loading` | `loading` | public | `'eager' \| 'lazy'` | `'eager'` | With the support of native image lazy loading, we can now decide whether we want to load the image immediately or only once it is close to the visible viewport. The value eager is best used for images within the initial viewport. We want to load these images as fast as possible to improve the Core Web Vitals values. lazy on the other hand works best for images which are further down the page or invisible during the loading of the initial viewport. | -| `performanceMark` | `performance-mark` | public | `string` | `''` | With performance.mark you can log a timestamp associated with the name you define in performanceMark when a certain event is happening. In our case we will log the performance.mark into the PerformanceEntry API once the image is fully loaded. Performance monitoring tools like SpeedCurve or Lighthouse are then able to grab these entries from the PerformanceEntry API and give us additional information and insights about our page loading behaviour. We are then also able to monitor these values over a long period to see if our performance increases or decreases over time. Best to use lowercase strings here, separate words with underscores or dashes. | -| `pictureSizesConfig` | `picture-sizes-config` | public | `string` | `''` | With the pictureSizesConfig object, you can pass in information into image about what kind of source elements should get rendered. mediaQueries accepts multiple Media Query entries which can get combined by defining a conditionOperator. Type is: stringified InterfaceImageAttributesSizesConfig-Object An example could look like this: { "breakpoints": \[ { "image": { "height": "675", "width": "1200" }, "mediaQueries": \[ { "conditionFeature": "min-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-large-min" }, "conditionOperator": false } ] }, { "image": { "height": "549", "width": "976" }, "mediaQueries": \[ { "conditionFeature": "min-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-small-min" }, "conditionOperator": false } ] }, { "image": { "height": "180", "width": "320" }, "mediaQueries": \[ { "conditionFeature": "max-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-micro-max" }, "conditionOperator": "and" }, { "conditionFeature": "orientation", "conditionFeatureValue": { "lyneDesignToken": false, "value": "landscape" }, "conditionOperator": false } ] } ] } | -| `skipLqip` | `skip-lqip` | public | `boolean` | `false` | If set to false, we show a blurred version of the image as placeholder before the actual image shows up. This will help to improve the perceived loading performance. Read more about the idea of lqip here: https://medium.com/@imgix/lqip-your-images-for-fast-loading-2523d9ee4a62 | +| Name | Attribute | Privacy | Type | Default | Description | +| -------------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `alt` | `alt` | public | `string` | `''` | An alt text is not always necessary (e.g. in teaser cards when additional link text is provided). In this case we can leave the value of the alt attribute blank, but the attribute itself still needs to be present. That way we can signal assistive technology, that they can skip the image. | +| `aspectRatio` | `aspect-ratio` | public | `'free' \| '1-1' \| '1-2' \| '2-1' \| '2-3' \| '3-2' \| '3-4' \| '4-3' \| '4-5' \| '5-4' \| '9-16' \| '16-9'` | `'16-9'` | Set an aspect ratio default is '16-9' (16/9) other values: 'free', '1-1', '1-2', '2-1', '2-3', '3-2', '3-4', '4-3', '4-5', '5-4', '9-16' | +| `borderRadius` | `border-radius` | public | `'default' \| 'none' \| 'round'` | `'default'` | Border radius of the image. Choose between a default radius, no radius and a completely round image. | +| `complete` | - | public | `boolean` | | Whether the image is finished loading or failed to load. | +| `customFocalPoint` | `custom-focal-point` | public | `boolean` | `false` | Set this to true, if you want to pass a custom focal point for the image. See full documentation here: https://docs.imgix.com/apis/rendering/focalpoint-crop | +| `decoding` | `decoding` | public | `'sync' \| 'async' \| 'auto'` | `'auto'` | If the lazy property is set to true, the module will automatically change the decoding to async, otherwise the decoding is set to auto which leaves the handling up to the browser. Read more about the decoding attribute here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decoding | +| `focalPointDebug` | `focal-point-debug` | public | `boolean` | `false` | Set this to true, to receive visual guidance where the custom focal point is currently set. | +| `focalPointX` | `focal-point-x` | public | `number` | `1` | Pass in a floating number between 0 (left) and 1 (right). | +| `focalPointY` | `focal-point-y` | public | `number` | `1` | Pass in a floating number between 0 (top) and 1 (bottom). | +| `imageSrc` | `image-src` | public | `string` | `''` | Right now the module is heavily coupled with the image delivery service imgix and depends on the original files being stored inside AEM. You can pass in any https://cdn.img.sbb.ch img src address you find on sbb.ch to play around with it. Just strip the url parameters and paste in the plain file address. If you want to know how to best work with this module with images coming from a different source, please contact the LYNE Core Team. | +| `importance` | `importance` | public | `'auto' \| 'high' \| 'low'` | `'high'` | The importance attribute is fairly new attribute which should help the browser decide which resources it should prioritise during page load. We will set the attribute value based on the value, we receive in the loading attribute. 'eager', which we use for the largest image within the initial viewport, will set the attribute value to 'high'. 'lazy', which we use for images below the fold, will set the attribute value to 'low'. | +| `loading` | `loading` | public | `'eager' \| 'lazy'` | `'eager'` | With the support of native image lazy loading, we can now decide whether we want to load the image immediately or only once it is close to the visible viewport. The value eager is best used for images within the initial viewport. We want to load these images as fast as possible to improve the Core Web Vitals values. lazy on the other hand works best for images which are further down the page or invisible during the loading of the initial viewport. | +| `performanceMark` | `performance-mark` | public | `string` | `''` | With performance.mark you can log a timestamp associated with the name you define in performanceMark when a certain event is happening. In our case we will log the performance.mark into the PerformanceEntry API once the image is fully loaded. Performance monitoring tools like SpeedCurve or Lighthouse are then able to grab these entries from the PerformanceEntry API and give us additional information and insights about our page loading behaviour. We are then also able to monitor these values over a long period to see if our performance increases or decreases over time. Best to use lowercase strings here, separate words with underscores or dashes. | +| `pictureSizesConfig` | `picture-sizes-config` | public | `string` | `''` | With the pictureSizesConfig object, you can pass in information into image about what kind of source elements should get rendered. mediaQueries accepts multiple Media Query entries which can get combined by defining a conditionOperator. Type is: stringified InterfaceImageAttributesSizesConfig-Object An example could look like this: { "breakpoints": \[ { "image": { "height": "675", "width": "1200" }, "mediaQueries": \[ { "conditionFeature": "min-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-large-min" }, "conditionOperator": false } ] }, { "image": { "height": "549", "width": "976" }, "mediaQueries": \[ { "conditionFeature": "min-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-small-min" }, "conditionOperator": false } ] }, { "image": { "height": "180", "width": "320" }, "mediaQueries": \[ { "conditionFeature": "max-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-micro-max" }, "conditionOperator": "and" }, { "conditionFeature": "orientation", "conditionFeatureValue": { "lyneDesignToken": false, "value": "landscape" }, "conditionOperator": false } ] } ] } | +| `skipLqip` | `skip-lqip` | public | `boolean` | `false` | If set to false, we show a blurred version of the image as placeholder before the actual image shows up. This will help to improve the perceived loading performance. Read more about the idea of lqip here: https://medium.com/@imgix/lqip-your-images-for-fast-loading-2523d9ee4a62 | ## Events From d8835a1492b63cd2d4d7dfcb37fb2ffe9c65808f Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Mon, 4 Nov 2024 14:08:44 +0100 Subject: [PATCH 02/47] style(image): extract mixin --- src/elements/core/styles/_index.scss | 1 + src/elements/core/styles/image.scss | 19 ++++----------- src/elements/core/styles/mixins/image.scss | 27 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 src/elements/core/styles/mixins/image.scss diff --git a/src/elements/core/styles/_index.scss b/src/elements/core/styles/_index.scss index db8fac890e..568231e357 100644 --- a/src/elements/core/styles/_index.scss +++ b/src/elements/core/styles/_index.scss @@ -9,6 +9,7 @@ @forward './mixins/chip'; @forward './mixins/font-face'; @forward './mixins/helpers'; +@forward './mixins/image'; @forward './mixins/inputs'; @forward './mixins/layout'; @forward './mixins/link'; diff --git a/src/elements/core/styles/image.scss b/src/elements/core/styles/image.scss index 35b3e6f226..bd0a8d650e 100644 --- a/src/elements/core/styles/image.scss +++ b/src/elements/core/styles/image.scss @@ -1,34 +1,25 @@ @use './mixins/typo'; +@use './mixins/image'; .sbb-figure { - display: grid; - grid-row-gap: var(--sbb-spacing-fixed-4x); - margin: 0; - height: 100%; + @include image.figure; img, sbb-image, .sbb-image { - grid-row: 1; - grid-column: 1; + @include image.figure-image; } figcaption, .sbb-caption { - grid-row: 2; - grid-column: 1; - @include typo.text-xs--regular; + @include image.figure-caption; } $alignments: start, center, end; @each $row-alignment in $alignments { @each $column-alignment in $alignments { .sbb-figure-overlap-#{$row-alignment}-#{$column-alignment} { - z-index: 1; - grid-row: 1; - grid-column: 1; - place-self: #{$row-alignment} #{$column-alignment}; - margin: 0.75rem; + @include image.figure-overlap($row-alignment, $column-alignment); } } } diff --git a/src/elements/core/styles/mixins/image.scss b/src/elements/core/styles/mixins/image.scss new file mode 100644 index 0000000000..5f050d328f --- /dev/null +++ b/src/elements/core/styles/mixins/image.scss @@ -0,0 +1,27 @@ +@use './typo'; + +@mixin figure { + display: grid; + grid-row-gap: var(--sbb-spacing-fixed-4x); + margin: 0; + height: 100%; +} + +@mixin figure-image { + grid-row: 1; + grid-column: 1; +} + +@mixin figure-caption { + grid-row: 2; + grid-column: 1; + @include typo.text-xs--regular; +} + +@mixin figure-overlap($row-alignment, $column-alignment) { + z-index: 1; + grid-row: 1; + grid-column: 1; + place-self: #{$row-alignment} #{$column-alignment}; + margin: 0.75rem; +} From 8b2f2bec8515f91501e2a4c010811f77db23b390 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 6 Nov 2024 10:19:12 +0100 Subject: [PATCH 03/47] refactor(sbb-teaser-hero, sbb-teaser-product): adapt sbb-image usages --- src/elements/core/styles/core.scss | 27 +++ src/elements/core/styles/mixins/image.scss | 1 + .../teaser-hero.snapshot.spec.snap.js | 168 +++++++++--------- src/elements/teaser-hero/readme.md | 19 +- src/elements/teaser-hero/teaser-hero.scss | 25 +-- .../teaser-hero/teaser-hero.snapshot.spec.ts | 48 ++--- src/elements/teaser-hero/teaser-hero.spec.ts | 15 +- .../teaser-hero/teaser-hero.ssr.spec.ts | 11 +- .../teaser-hero/teaser-hero.stories.ts | 36 ++-- src/elements/teaser-hero/teaser-hero.ts | 11 +- .../teaser-hero/teaser-hero.visual.spec.ts | 22 ++- .../common/teaser-product-common.scss | 15 -- ...easer-product-static.snapshot.spec.snap.js | 12 +- .../teaser-product-static/readme.md | 20 ++- .../teaser-product-static.snapshot.spec.ts | 4 +- .../teaser-product-static.spec.ts | 4 +- .../teaser-product-static.ssr.spec.ts | 4 +- .../teaser-product-static.stories.ts | 28 ++- .../teaser-product-static.visual.spec.ts | 29 ++- .../teaser-product.snapshot.spec.snap.js | 12 +- .../teaser-product/teaser-product/readme.md | 20 ++- .../teaser-product/teaser-product.scss | 16 +- .../teaser-product.snapshot.spec.ts | 4 +- .../teaser-product/teaser-product.spec.ts | 4 +- .../teaser-product/teaser-product.ssr.spec.ts | 4 +- .../teaser-product/teaser-product.stories.ts | 28 ++- .../teaser-product.visual.spec.ts | 29 ++- 27 files changed, 371 insertions(+), 245 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index 38ddec81fe..5107ddbec6 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -153,3 +153,30 @@ input[data-sbb-time-input] { max-width: var(--sbb-time-input-s-max-width); } } + +// Target the slotted `sbb-image` which are generally wrapped by a
(therefore are not reachable with the :slotted) +// Apply the brightness effect on mouse hover +// TODO Move back to the teaser components when the global css refactoring happens +:is(sbb-teaser, sbb-teaser-hero, sbb-teaser-product) { + & [slot='image']:is(sbb-image, img), + & [slot='image'] :is(sbb-image, img) { + will-change: filter; + filter: brightness(var(--sbb-teaser-image-brightness, 1)); + transition: filter var(--sbb-teaser-image-animation-duration) + var(--sbb-teaser-image-animation-easing); + } +} + +:is(sbb-teaser-product, sbb-teaser-product-static) { + // Reset sbb-image border radius in order to control it from teaser product. + sbb-image { + --sbb-image-border-radius: 0; + } + + // TODO create and use utility classes + img { + place-self: stretch; + object-fit: cover; + aspect-ratio: 16 / 9; + } +} diff --git a/src/elements/core/styles/mixins/image.scss b/src/elements/core/styles/mixins/image.scss index 5f050d328f..5a1c3e1c85 100644 --- a/src/elements/core/styles/mixins/image.scss +++ b/src/elements/core/styles/mixins/image.scss @@ -10,6 +10,7 @@ @mixin figure-image { grid-row: 1; grid-column: 1; + width: 100%; } @mixin figure-caption { diff --git a/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js b/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js index 6e383f3db1..bc7741d298 100644 --- a/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js +++ b/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js @@ -6,21 +6,32 @@ snapshots["sbb-teaser-hero renders DOM"] = accessibility-label="label" data-action="" data-link="" - data-slot-names="chip unnamed" + data-slot-names="image link-content unnamed" href="https://www.sbb.ch" - image-alt="SBB CFF FFS Employee" - link-content="Find out more" - rel="external" - target="_blank" > Break out and explore castles and palaces. - + Find out more + +
- Label - + + + + Label + +
`; /* end snapshot sbb-teaser-hero renders DOM */ @@ -30,11 +41,7 @@ snapshots["sbb-teaser-hero renders Shadow DOM"] = aria-label="label" class="sbb-action-base sbb-teaser-hero" href="https://www.sbb.ch" - rel="external" - target="_blank" > - -

@@ -44,74 +51,92 @@ snapshots["sbb-teaser-hero renders Shadow DOM"] = class="sbb-teaser-hero__panel-link" data-action="" data-sbb-link="" - data-slot-names="unnamed" + data-slot-names="link-content unnamed" icon-name="chevron-small-right-small" icon-placement="end" negative="" size="m" > - Find out more - - - - . Link target opens in a new window. - `; /* end snapshot sbb-teaser-hero renders Shadow DOM */ -snapshots["sbb-teaser-hero renders with slots DOM"] = +snapshots["sbb-teaser-hero renders A11y tree Firefox"] = +`

+ { + "role": "document", + "name": "", + "children": [ + { + "role": "link", + "name": "label", + "value": "https://www.sbb.ch/" + } + ] +} +

+`; +/* end snapshot sbb-teaser-hero renders A11y tree Firefox */ + +snapshots["sbb-teaser-hero renders A11y tree Chrome"] = +`

+ { + "role": "WebArea", + "name": "", + "children": [ + { + "role": "link", + "name": "label" + } + ] +} +

+`; +/* end snapshot sbb-teaser-hero renders A11y tree Chrome */ + +snapshots["sbb-teaser-hero renders with img DOM"] = ` Break out and explore castles and palaces. - - Find out more - - - - - Label - + alt + + Label + +
`; -/* end snapshot sbb-teaser-hero renders with slots DOM */ +/* end snapshot sbb-teaser-hero renders with img DOM */ -snapshots["sbb-teaser-hero renders with slots Shadow DOM"] = +snapshots["sbb-teaser-hero renders with img Shadow DOM"] = ` - -

@@ -121,52 +146,23 @@ snapshots["sbb-teaser-hero renders with slots Shadow DOM"] = class="sbb-teaser-hero__panel-link" data-action="" data-sbb-link="" - data-slot-names="link-content unnamed" + data-slot-names="unnamed" icon-name="chevron-small-right-small" icon-placement="end" negative="" size="m" > + Find out more + + . Link target opens in a new window. + `; -/* end snapshot sbb-teaser-hero renders with slots Shadow DOM */ - -snapshots["sbb-teaser-hero renders A11y tree Chrome"] = -`

- { - "role": "WebArea", - "name": "", - "children": [ - { - "role": "link", - "name": "label" - } - ] -} -

-`; -/* end snapshot sbb-teaser-hero renders A11y tree Chrome */ - -snapshots["sbb-teaser-hero renders A11y tree Firefox"] = -`

- { - "role": "document", - "name": "", - "children": [ - { - "role": "link", - "name": "label", - "value": "https://www.sbb.ch/" - } - ] -} -

-`; -/* end snapshot sbb-teaser-hero renders A11y tree Firefox */ +/* end snapshot sbb-teaser-hero renders with img Shadow DOM */ diff --git a/src/elements/teaser-hero/readme.md b/src/elements/teaser-hero/readme.md index eb9bc5152f..1394b7f0f0 100644 --- a/src/elements/teaser-hero/readme.md +++ b/src/elements/teaser-hero/readme.md @@ -5,23 +5,18 @@ it should be an eye-catcher and should have an emotional effect on the user with It is possible to provide the panel label via an unnamed slot, while the link text can be provided using the `link-content` slot or the `linkContent` property; -similarly, the background image can be provided using the `image` slot or the `imageSrc` property. -Optionally a `sbb-chip` can be slotted in the `chip` slot, either together with the other slottable elements or alone. -```html - - Break out and explore castles and palaces. - +Use the `image` slot to pass a `figure` containing an `sbb-image | img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure`. +```html Break out and explore castles and palaces. - Find out more +
+ + Chip label +
``` diff --git a/src/elements/teaser-hero/teaser-hero.scss b/src/elements/teaser-hero/teaser-hero.scss index dad3d5fa01..1a7c6ea2ec 100644 --- a/src/elements/teaser-hero/teaser-hero.scss +++ b/src/elements/teaser-hero/teaser-hero.scss @@ -10,9 +10,12 @@ // which appears in normalize css of several frameworks. outline: none !important; - --sbb-teaser-hero-brightness-hover: var(--sbb-hover-image-brightness); - --sbb-teaser-hero-chip-inset: var(--sbb-spacing-responsive-xxxs) auto auto - var(--sbb-spacing-responsive-xxxs); + --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); + --sbb-teaser-image-animation-duration: var( + --sbb-disable-animation-zero-time, + var(--sbb-animation-duration-4x) + ); + --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); @include sbb.panel-variables; } @@ -20,7 +23,7 @@ @include sbb.hover-mq($hover: true) { :host(:hover) { --sbb-panel-background-color: var(--sbb-panel-background-color-hover); - --sbb-teaser-hero-brightness: var(--sbb-teaser-hero-brightness-hover); + --sbb-teaser-image-brightness: var(--sbb-teaser-image-brightness-hover); } } @@ -28,6 +31,7 @@ position: relative; display: block; min-height: var(--sbb-panel-height); + text-decoration: none; // Hide focus outline when focus origin is mouse or touch. This is being used as a workaround in various components. :host(:not([data-focus-origin='mouse'], [data-focus-origin='touch'])) &:focus-visible { @@ -60,16 +64,3 @@ margin: 0; padding: 0; } - -::slotted([slot='image']), -sbb-image { - will-change: filter; - filter: brightness(var(--sbb-teaser-hero-brightness, 1)); - transition: filter var(--sbb-panel-animation-duration) var(--sbb-panel-animation-easing); -} - -::slotted([slot='chip']) { - position: absolute; - inset: var(--sbb-teaser-hero-chip-inset); - z-index: 2; -} diff --git a/src/elements/teaser-hero/teaser-hero.snapshot.spec.ts b/src/elements/teaser-hero/teaser-hero.snapshot.spec.ts index 9ff8fa75fa..bf19c00a84 100644 --- a/src/elements/teaser-hero/teaser-hero.snapshot.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.snapshot.spec.ts @@ -14,23 +14,20 @@ const imageUrl = import.meta.resolve('../core/testing/assets/lucerne.png'); describe(`sbb-teaser-hero`, () => { let element: SbbTeaserHeroElement; - describe('renders', () => { + describe('renders', async () => { beforeEach(async () => { element = await fixture( - html` + html` Break out and explore castles and palaces. - Label + Find out more + +
+ + Label +
`, ); - await waitForImageReady(element.shadowRoot!.querySelector('sbb-image')!); + await waitForImageReady(element.querySelector('sbb-image')!); }); it('DOM', async () => { @@ -38,32 +35,39 @@ describe(`sbb-teaser-hero`, () => { }); it('Shadow DOM', async () => { - await expect(element).shadowDom.to.be.equalSnapshot({ ignoreAttributes: ['image-src'] }); + await expect(element).shadowDom.to.be.equalSnapshot(); }); testA11yTreeSnapshot(); }); - describe('renders with slots', async () => { + describe('renders with img', () => { beforeEach(async () => { element = await fixture( - html` + html` Break out and explore castles and palaces. - Find out more - - - Label + +
+ alt + Label +
`, ); - await waitForImageReady(element.querySelector('sbb-image')!); + await waitForImageReady(element.querySelector('img')!); }); it('DOM', async () => { - await expect(element).dom.to.be.equalSnapshot({ ignoreAttributes: ['image-src'] }); + await expect(element).dom.to.be.equalSnapshot({ ignoreAttributes: ['src'] }); }); it('Shadow DOM', async () => { - await expect(element).shadowDom.to.be.equalSnapshot(); + await expect(element).shadowDom.to.be.equalSnapshot({ ignoreAttributes: ['src'] }); }); }); }); diff --git a/src/elements/teaser-hero/teaser-hero.spec.ts b/src/elements/teaser-hero/teaser-hero.spec.ts index ed3c2328f5..f911c97b62 100644 --- a/src/elements/teaser-hero/teaser-hero.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.spec.ts @@ -8,6 +8,7 @@ import type { SbbImageElement } from '../image.js'; import { SbbTeaserHeroElement } from './teaser-hero.js'; import '../chip.js'; +import '../image.js'; const imageUrl = import.meta.resolve('../core/testing/assets/lucerne.png'); @@ -15,9 +16,7 @@ describe(`sbb-teaser-hero`, () => { let element: SbbTeaserHeroElement; it('renders', async () => { - element = await fixture( - html``, - ); + element = await fixture(html``); assert.instanceOf(element, SbbTeaserHeroElement); }); @@ -35,13 +34,17 @@ describe(`sbb-teaser-hero`, () => { it('styles slotted components', async () => { element = await fixture( - html` - Label + html` +
+ + Label +
`, ); + await waitForLitRender(element); const chip = element.querySelector('sbb-chip')!; - const image = element.shadowRoot!.querySelector('sbb-image')!; + const image = element.querySelector('sbb-image')!; expect(chip).to.have.attribute('color', 'charcoal'); expect(image).to.have.attribute('data-teaser'); diff --git a/src/elements/teaser-hero/teaser-hero.ssr.spec.ts b/src/elements/teaser-hero/teaser-hero.ssr.spec.ts index 2b1c9c1106..e021afb5da 100644 --- a/src/elements/teaser-hero/teaser-hero.ssr.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.ssr.spec.ts @@ -5,14 +5,21 @@ import images from '../core/images.js'; import { ssrHydratedFixture } from '../core/testing/private.js'; import { SbbTeaserHeroElement } from './teaser-hero.js'; +import '../chip.js'; +import '../image.js'; describe(`sbb-teaser-hero ssr`, () => { let root: SbbTeaserHeroElement; beforeEach(async () => { root = await ssrHydratedFixture( - html``, - { modules: ['./teaser-hero.js'] }, + html` +
+ + Label +
+
`, + { modules: ['./teaser-hero.js', '../image.js', '../chip.js'] }, ); }); diff --git a/src/elements/teaser-hero/teaser-hero.stories.ts b/src/elements/teaser-hero/teaser-hero.stories.ts index fef914a8b1..cec4ce5ba8 100644 --- a/src/elements/teaser-hero/teaser-hero.stories.ts +++ b/src/elements/teaser-hero/teaser-hero.stories.ts @@ -111,36 +111,30 @@ const defaultArgs: Args = { 'chip-label': undefined, }; -const chip = (content: string): TemplateResult => html` - ${content} -`; - -const TemplateSbbTeaserHeroDefault = ({ - content, - 'chip-label': chipLabel, - ...args -}: Args): TemplateResult => html` - ${content} ${chipLabel ? chip(chipLabel) : nothing} - -`; - const TemplateSbbTeaserWithSlots = ({ content, + 'chip-label': chipLabel, 'link-content': linkContent, 'image-src': imageSrc, 'image-alt': imageAlt, ...args }: Args): TemplateResult => html` - ${content} - ${linkContent} - + ${content ? content : nothing} + ${linkContent ? html`${linkContent}` : nothing} + +
+ + + ${chipLabel + ? html`${chipLabel}` + : nothing} +
`; export const defaultTeaser: StoryObj = { - render: TemplateSbbTeaserHeroDefault, + render: TemplateSbbTeaserWithSlots, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -148,7 +142,7 @@ export const defaultTeaser: StoryObj = { }; export const openInNewWindow: StoryObj = { - render: TemplateSbbTeaserHeroDefault, + render: TemplateSbbTeaserWithSlots, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -157,7 +151,7 @@ export const openInNewWindow: StoryObj = { }; export const withChip: StoryObj = { - render: TemplateSbbTeaserHeroDefault, + render: TemplateSbbTeaserWithSlots, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -166,7 +160,7 @@ export const withChip: StoryObj = { }; export const chipOnly: StoryObj = { - render: TemplateSbbTeaserHeroDefault, + render: TemplateSbbTeaserWithSlots, argTypes: defaultArgTypes, args: { ...defaultArgs, diff --git a/src/elements/teaser-hero/teaser-hero.ts b/src/elements/teaser-hero/teaser-hero.ts index 8b7da8037c..7a76220f88 100644 --- a/src/elements/teaser-hero/teaser-hero.ts +++ b/src/elements/teaser-hero/teaser-hero.ts @@ -39,13 +39,12 @@ class SbbTeaserHeroElement extends SbbLinkBaseElement { @property({ attribute: 'image-alt' }) public accessor imageAlt: string = ''; - private _chipSlotChanged(): void { - this.querySelector('sbb-chip')?.setAttribute('color', 'charcoal'); + private _imageSlotChanged(): void { + Array.from(this.querySelectorAll('sbb-chip')).forEach((c) => (c.color = 'charcoal')); } protected override renderTemplate(): TemplateResult { return html` - this._chipSlotChanged()}>

@@ -62,11 +61,7 @@ class SbbTeaserHeroElement extends SbbLinkBaseElement { ` : nothing} - - ${this.imageSrc - ? html`` - : nothing} - + `; } } diff --git a/src/elements/teaser-hero/teaser-hero.visual.spec.ts b/src/elements/teaser-hero/teaser-hero.visual.spec.ts index 492233405e..8ec358ae2f 100644 --- a/src/elements/teaser-hero/teaser-hero.visual.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.visual.spec.ts @@ -20,9 +20,13 @@ describe(`sbb-teaser-hero`, () => { state.name, state.with(async (setup) => { await setup.withFixture(html` - + Break out and explore castles and palaces. - Label + +

+ + Label +
`); @@ -41,8 +45,11 @@ describe(`sbb-teaser-hero`, () => { Break out and explore castles and palaces. Find out more - - Label + +
+ + Label +
`); @@ -54,8 +61,11 @@ describe(`sbb-teaser-hero`, () => { `without content ${state.name}`, state.with(async (setup) => { await setup.withFixture(html` - - Label + +
+ + Label +
`); diff --git a/src/elements/teaser-product/common/teaser-product-common.scss b/src/elements/teaser-product/common/teaser-product-common.scss index b303f1fc15..32c5fc0991 100644 --- a/src/elements/teaser-product/common/teaser-product-common.scss +++ b/src/elements/teaser-product/common/teaser-product-common.scss @@ -52,21 +52,6 @@ } } -::slotted(img) { - display: flex; - width: 100%; - height: 100%; - object-fit: cover; - aspect-ratio: 16 / 9; -} - -// Reset sbb-image border radius in order to control it from teaser product. -::slotted(sbb-image) { - --sbb-image-border-radius: 0; - - height: 100%; -} - ::slotted(p.sbb-teaser-product--spacing) { margin: 0; } diff --git a/src/elements/teaser-product/teaser-product-static/__snapshots__/teaser-product-static.snapshot.spec.snap.js b/src/elements/teaser-product/teaser-product-static/__snapshots__/teaser-product-static.snapshot.spec.snap.js index 21154bd051..45bf228bd4 100644 --- a/src/elements/teaser-product/teaser-product-static/__snapshots__/teaser-product-static.snapshot.spec.snap.js +++ b/src/elements/teaser-product/teaser-product-static/__snapshots__/teaser-product-static.snapshot.spec.snap.js @@ -7,12 +7,16 @@ snapshots["sbb-teaser-product-static renders DOM"] = data-slot-names="footnote image unnamed" image-alignment="after" > - - + + +

Content

diff --git a/src/elements/teaser-product/teaser-product-static/readme.md b/src/elements/teaser-product/teaser-product-static/readme.md index 554f896ea4..64707b6ee4 100644 --- a/src/elements/teaser-product/teaser-product-static/readme.md +++ b/src/elements/teaser-product/teaser-product-static/readme.md @@ -5,7 +5,9 @@ otherwise, see [sbb-teaser-product](/docs/elements-sbb-teaser-sbb-teaser-product ```html - +
+ +

Content ...

@@ -15,15 +17,21 @@ otherwise, see [sbb-teaser-product](/docs/elements-sbb-teaser-sbb-teaser-product ## Slots -Use the `image` slot to pass a `sbb-image` or an `img` that will be used as a background, -and use the optional `footnote` slot to add a text anchored to the bottom-end of the component. +Use the `image` slot to pass a `figure` containing an `sbb-image | img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure`. + +Use the optional `footnote` slot to add a text anchored to the bottom-end of the component. The default slot is reserved for the main content: it could be a simple text or a text combined with more elements, like a `sbb-title` or some interactive elements, like buttons or links within the `sbb-action-group` component. ```html - +
+ + Chip label +
+

Content ...

``` @@ -33,7 +41,9 @@ to display the components with the correct spacings. ```html - +
+ +
Benefit from up to 70% discount diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.snapshot.spec.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.snapshot.spec.ts index 546242e430..92b50b86ea 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.snapshot.spec.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.snapshot.spec.ts @@ -16,7 +16,9 @@ describe(`sbb-teaser-product-static`, () => { beforeEach(async () => { element = await fixture(html` - +
+ +

Content

Footnote

diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.spec.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.spec.ts index 95fc01af24..5438de529f 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.spec.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.spec.ts @@ -15,7 +15,9 @@ describe('sbb-teaser-product-static', () => { beforeEach(async () => { element = await fixture(html` - +
+ +

Content

Footnote

diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.ssr.spec.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.ssr.spec.ts index 9e943fdd5b..2299d4cf19 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.ssr.spec.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.ssr.spec.ts @@ -16,7 +16,9 @@ describe(`sbb-teaser-product-static ssr`, () => { root = await ssrHydratedFixture( html` - +
+ +

Content

Footnote

diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts index d16eb4b64f..8e0796d1be 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts @@ -19,6 +19,7 @@ import './teaser-product-static.js'; import '../../action-group.js'; import '../../button/button.js'; import '../../button/secondary-button.js'; +import '../../chip.js'; import '../../image.js'; import '../../title.js'; @@ -41,6 +42,12 @@ const withFooter: InputType = { }, }; +const withChip: InputType = { + control: { + type: 'boolean', + }, +}; + const slottedImg: InputType = { control: { type: 'boolean', @@ -51,6 +58,7 @@ const defaultArgTypes: ArgTypes = { 'image-alignment': imageAlignment, negative, withFooter, + withChip, slottedImg, }; @@ -58,6 +66,7 @@ const defaultArgs: Args = { 'image-alignment': imageAlignment.options![0], negative: false, withFooter: true, + withChip: false, slottedImg: false, }; @@ -85,11 +94,16 @@ const footer = (): TemplateResult => html`

`; -const Template = ({ withFooter, slottedImg, ...args }: Args): TemplateResult => html` +const Template = ({ withChip, withFooter, slottedImg, ...args }: Args): TemplateResult => html` - ${slottedImg - ? html`` - : html``} +
+ ${slottedImg + ? html`` + : html``} + ${withChip + ? html`AI generated` + : nothing} +
${content()} ${withFooter ? footer() : nothing}
`; @@ -124,6 +138,12 @@ export const SlottedImg: StoryObj = { args: { ...defaultArgs, slottedImg: true }, }; +export const WithChip: StoryObj = { + render: Template, + argTypes: defaultArgTypes, + args: { ...defaultArgs, withChip: true }, +}; + const meta: Meta = { decorators: [withActions as Decorator], parameters: { diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts index 3172c79db7..8b823d116f 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts @@ -12,6 +12,7 @@ import './teaser-product-static.js'; import '../../action-group.js'; import '../../button/button.js'; import '../../button/secondary-button.js'; +import '../../chip.js'; import '../../image.js'; import '../../title.js'; @@ -50,17 +51,24 @@ const template = ({ showFooter, slottedImg, longContent, + withChip, }: { negative?: boolean; imageAlignment?: string; showFooter?: boolean; slottedImg?: boolean; longContent?: boolean; + withChip?: boolean; } = {}): TemplateResult => html` - ${slottedImg - ? html`` - : html``} +
+ ${slottedImg + ? html`` + : html``} + ${withChip + ? html`Label` + : nothing} +
${content(longContent)} ${showFooter ? footer() : nothing}
`; @@ -83,6 +91,21 @@ describe('sbb-teaser-product-static', () => { ); }), ); + + it( + `withChip_${visualState.name}`, + visualState.with(async (setup) => { + await setup.withFixture( + template({ negative, showFooter: true, slottedImg, withChip: true }), + { + backgroundColor: negative ? 'var(--sbb-color-black)' : undefined, + }, + ); + await waitForImageReady( + setup.snapshotElement.querySelector(slottedImg ? 'img' : 'sbb-image')!, + ); + }), + ); } }); } diff --git a/src/elements/teaser-product/teaser-product/__snapshots__/teaser-product.snapshot.spec.snap.js b/src/elements/teaser-product/teaser-product/__snapshots__/teaser-product.snapshot.spec.snap.js index b850117190..4623e58988 100644 --- a/src/elements/teaser-product/teaser-product/__snapshots__/teaser-product.snapshot.spec.snap.js +++ b/src/elements/teaser-product/teaser-product/__snapshots__/teaser-product.snapshot.spec.snap.js @@ -9,12 +9,16 @@ snapshots["sbb-teaser-product renders DOM"] = href="https://www.sbb.ch" image-alignment="after" > - - + + +

Content

diff --git a/src/elements/teaser-product/teaser-product/readme.md b/src/elements/teaser-product/teaser-product/readme.md index 6166250124..194a0c85ca 100644 --- a/src/elements/teaser-product/teaser-product/readme.md +++ b/src/elements/teaser-product/teaser-product/readme.md @@ -6,7 +6,9 @@ If it has to include more than one interactive element, use the [sbb-teaser-prod ```html - +
+ +

Content ...

@@ -16,15 +18,21 @@ If it has to include more than one interactive element, use the [sbb-teaser-prod ## Slots -Use the `image` slot to pass a `sbb-image` or an `img` that will be used as a background, -and use the optional `footnote` slot to add a text anchored to the bottom-end of the component. +Use the `image` slot to pass a `figure` containing an `sbb-image | img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure`. + +Use the optional `footnote` slot to add a text anchored to the bottom-end of the component. The default slot is reserved for the main content: it could be a simple text or a text combined with more elements, like the `sbb-title` or an interactive element, like a button or a link (needs to be in static variant!). ```html - +
+ + Chip label +
+

Content ...

``` @@ -34,7 +42,9 @@ to display the components with the correct spacings. ```html - +
+ +
Benefit from up to 70% discount diff --git a/src/elements/teaser-product/teaser-product/teaser-product.scss b/src/elements/teaser-product/teaser-product/teaser-product.scss index 13e52cc285..bbc7c1b716 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.scss +++ b/src/elements/teaser-product/teaser-product/teaser-product.scss @@ -1,18 +1,18 @@ @use '../../core/styles' as sbb; :host { - --sbb-teaser-product-brightness-hover: var(--sbb-hover-image-brightness); - --sbb-teaser-product-animation-duration: var( + --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); + --sbb-teaser-image-animation-duration: var( --sbb-disable-animation-zero-time, var(--sbb-animation-duration-4x) ); - --sbb-teaser-product-animation-easing: var(--sbb-animation-easing); + --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); --sbb-teaser-product-border-radius: var(--sbb-border-radius-4x); } :host(:hover) { @include sbb.hover-mq($hover: true) { - --sbb-teaser-product-brightness: var(--sbb-teaser-product-brightness-hover); + --sbb-teaser-image-brightness: var(--sbb-teaser-image-brightness-hover); } } @@ -33,11 +33,3 @@ } } } - -::slotted(:is(img, sbb-image)) { - will-change: filter; - transition-property: filter; - transition-duration: var(--sbb-teaser-product-animation-duration); - transition-timing-function: var(--sbb-animation-easing); - filter: brightness(var(--sbb-teaser-product-brightness, 1)); -} diff --git a/src/elements/teaser-product/teaser-product/teaser-product.snapshot.spec.ts b/src/elements/teaser-product/teaser-product/teaser-product.snapshot.spec.ts index 4e75eccf7c..5eea0dc29a 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.snapshot.spec.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.snapshot.spec.ts @@ -16,7 +16,9 @@ describe(`sbb-teaser-product`, () => { beforeEach(async () => { element = await fixture(html` - +
+ +

Content

Footnote

diff --git a/src/elements/teaser-product/teaser-product/teaser-product.spec.ts b/src/elements/teaser-product/teaser-product/teaser-product.spec.ts index d2504d5d82..9dbba53e38 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.spec.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.spec.ts @@ -14,7 +14,9 @@ describe('sbb-teaser-product', () => { beforeEach(async () => { element = await fixture(html` - +
+ +

Content

Footnote

diff --git a/src/elements/teaser-product/teaser-product/teaser-product.ssr.spec.ts b/src/elements/teaser-product/teaser-product/teaser-product.ssr.spec.ts index ff856d0b06..ac2db8687b 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.ssr.spec.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.ssr.spec.ts @@ -16,7 +16,9 @@ describe(`sbb-teaser-product ssr`, () => { root = await ssrHydratedFixture( html` - +
+ +

Content

Footnote

diff --git a/src/elements/teaser-product/teaser-product/teaser-product.stories.ts b/src/elements/teaser-product/teaser-product/teaser-product.stories.ts index b17659f9c1..caa4070992 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.stories.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.stories.ts @@ -17,6 +17,7 @@ import sampleImages from '../../core/images.js'; import readme from './readme.md?raw'; import './teaser-product.js'; import '../../button/button-static.js'; +import '../../chip.js'; import '../../image.js'; import '../../title.js'; @@ -39,6 +40,12 @@ const withFooter: InputType = { }, }; +const withChip: InputType = { + control: { + type: 'boolean', + }, +}; + const slottedImg: InputType = { control: { type: 'boolean', @@ -67,6 +74,7 @@ const defaultArgTypes: ArgTypes = { 'image-alignment': imageAlignment, negative, withFooter, + withChip, slottedImg, href, 'accessibility-label': accessibilityLabel, @@ -76,6 +84,7 @@ const defaultArgs: Args = { 'image-alignment': imageAlignment.options![0], negative: false, withFooter: true, + withChip: false, slottedImg: false, href: 'https://www.sbb.ch', 'accessibility-label': undefined, @@ -102,11 +111,16 @@ const footer = (): TemplateResult => html`

`; -const Template = ({ withFooter, slottedImg, ...args }: Args): TemplateResult => html` +const Template = ({ withChip, withFooter, slottedImg, ...args }: Args): TemplateResult => html` - ${slottedImg - ? html`` - : html``} +
+ ${slottedImg + ? html`` + : html``} + ${withChip + ? html`AI generated` + : nothing} +
${content()} ${withFooter ? footer() : nothing}
`; @@ -141,6 +155,12 @@ export const SlottedImg: StoryObj = { args: { ...defaultArgs, slottedImg: true }, }; +export const WithChip: StoryObj = { + render: Template, + argTypes: defaultArgTypes, + args: { ...defaultArgs, withChip: true }, +}; + const meta: Meta = { decorators: [withActions as Decorator], parameters: { diff --git a/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts b/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts index 5484b3501e..66e1966381 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts @@ -11,6 +11,7 @@ import { waitForImageReady } from '../../core/testing/wait-for-image-ready.js'; import './teaser-product.js'; import '../../button/button-static.js'; +import '../../chip.js'; import '../../image.js'; import '../../title.js'; @@ -46,17 +47,24 @@ const template = ({ showFooter, slottedImg, longContent, + withChip, }: { negative?: boolean; imageAlignment?: string; showFooter?: boolean; slottedImg?: boolean; longContent?: boolean; + withChip?: boolean; } = {}): TemplateResult => html` - ${slottedImg - ? html`` - : html``} +
+ ${slottedImg + ? html`` + : html``} + ${withChip + ? html`Label` + : nothing} +
${content(longContent)} ${showFooter ? footer() : nothing}
`; @@ -79,6 +87,21 @@ describe('sbb-teaser-product', () => { ); }), ); + + it( + `withChip_${visualState.name}`, + visualState.with(async (setup) => { + await setup.withFixture( + template({ negative, showFooter: true, slottedImg, withChip: true }), + { + backgroundColor: negative ? 'var(--sbb-color-black)' : undefined, + }, + ); + await waitForImageReady( + setup.snapshotElement.querySelector(slottedImg ? 'img' : 'sbb-image')!, + ); + }), + ); } }); } From a4ba48185f90068d17760d3f94803c92a684f404 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 6 Nov 2024 14:41:22 +0100 Subject: [PATCH 04/47] refactor(sbb-teaser): adapt sbb-image usages --- src/elements/core/styles/core.scss | 22 ++++++++++++ .../teaser.snapshot.spec.snap.js | 10 ++++-- src/elements/teaser/readme.md | 12 +++++-- src/elements/teaser/teaser.scss | 35 ++++++------------- src/elements/teaser/teaser.snapshot.spec.ts | 4 ++- src/elements/teaser/teaser.stories.ts | 32 +++++++++-------- src/elements/teaser/teaser.visual.spec.ts | 28 ++++++++++++--- 7 files changed, 93 insertions(+), 50 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index 5107ddbec6..bc7ecc0016 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -167,6 +167,7 @@ input[data-sbb-time-input] { } } +// TODO Move back to the teaser components when the global css refactoring happens :is(sbb-teaser-product, sbb-teaser-product-static) { // Reset sbb-image border radius in order to control it from teaser product. sbb-image { @@ -180,3 +181,24 @@ input[data-sbb-time-input] { aspect-ratio: 16 / 9; } } + +// TODO Move back to the teaser components when the global css refactoring happens +:is(sbb-teaser) { + & [slot='image']:is(sbb-image, img), + & [slot='image'] :is(sbb-image, img) { + transition-property: filter, transform; + will-change: filter, transform; + transform: scale(var(--sbb-teaser-scale, 1)); + } + + // TODO create and use utility classes + sbb-image { + --sbb-image-aspect-ratio: 4 / 3; + } + + // TODO create and use utility classes + img { + object-fit: cover; + aspect-ratio: 4/3; + } +} diff --git a/src/elements/teaser/__snapshots__/teaser.snapshot.spec.snap.js b/src/elements/teaser/__snapshots__/teaser.snapshot.spec.snap.js index 7afc024946..eacc5aa08f 100644 --- a/src/elements/teaser/__snapshots__/teaser.snapshot.spec.snap.js +++ b/src/elements/teaser/__snapshots__/teaser.snapshot.spec.snap.js @@ -115,11 +115,15 @@ snapshots["sbb-teaser renders below with projected content DOM"] = data-slot-names="chip image title unnamed" href="https://github.com/sbb-design-systems/lyne-components" > - 400x300 + 400x300 + Chip diff --git a/src/elements/teaser/readme.md b/src/elements/teaser/readme.md index 77e213e210..c18ffed67b 100644 --- a/src/elements/teaser/readme.md +++ b/src/elements/teaser/readme.md @@ -9,7 +9,9 @@ Simple teaser example: title-content="Title" chip-content="Chip label" > - 400x300 +
+ 400x300 +
A brief description. ``` @@ -19,9 +21,15 @@ Simple teaser example: The default slot is reserved for the description. The component displays the `image` and the `title` with the self-named slots. It's also possible to display a [sbb-chip-label](/docs/elements-sbb-chip-label--docs) using the `chip` slot. +Use the `image` slot to pass a `figure` containing an `sbb-image | img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure`. + ```html - 400x300 +
+ 400x300 + AI Generated +
Chip label Title A brief description. diff --git a/src/elements/teaser/teaser.scss b/src/elements/teaser/teaser.scss index 1af507f64b..274e33e9c7 100644 --- a/src/elements/teaser/teaser.scss +++ b/src/elements/teaser/teaser.scss @@ -17,11 +17,12 @@ --sbb-teaser-gap: var(--sbb-spacing-fixed-4x); --sbb-teaser-width: fit-content; --sbb-teaser-border-radius: var(--sbb-border-radius-4x); - --sbb-teaser-brightness-hover: var(--sbb-hover-image-brightness); - --sbb-teaser-animation-duration: var( - --sbb-disable-animation-zero-duration, + --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); + --sbb-teaser-image-animation-duration: var( + --sbb-disable-animation-zero-time, var(--sbb-animation-duration-4x) ); + --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); } :host([alignment='after']) { @@ -35,6 +36,13 @@ --sbb-teaser-width: 100%; } +@include sbb.hover-mq($hover: true) { + :host(:hover) { + --sbb-teaser-image-brightness: var(--sbb-teaser-image-brightness-hover); + --sbb-teaser-scale: var(--sbb-teaser-scale-hover); + } +} + .sbb-teaser { display: flex; text-decoration: none; @@ -75,27 +83,6 @@ ::slotted([slot='image']) { width: #{sbb.px-to-rem-build(300)}; - will-change: transform; - display: block; - filter: brightness(var(--sbb-teaser-brightness, 1)); - transition: var(--sbb-teaser-animation-duration) var(--sbb-animation-easing); - - @include sbb.hover-mq($hover: true) { - .sbb-teaser:hover & { - transform: scale(var(--sbb-teaser-scale-hover)); - - --sbb-teaser-brightness: var(--sbb-teaser-brightness-hover); - } - } -} - -::slotted(sbb-image[slot='image']) { - --sbb-image-aspect-ratio: 4 / 3; -} - -::slotted(img[slot='image']) { - aspect-ratio: 4/3; - object-fit: cover; } .sbb-teaser__image-wrapper { diff --git a/src/elements/teaser/teaser.snapshot.spec.ts b/src/elements/teaser/teaser.snapshot.spec.ts index 9ed4f1c472..696efb458b 100644 --- a/src/elements/teaser/teaser.snapshot.spec.ts +++ b/src/elements/teaser/teaser.snapshot.spec.ts @@ -62,7 +62,9 @@ describe(`sbb-teaser`, () => { accessibility-label="SBB teaser" alignment="below" > - 400x300 +
+ 400x300 +
Chip TITLE description diff --git a/src/elements/teaser/teaser.stories.ts b/src/elements/teaser/teaser.stories.ts index fec1a00ad2..107e77dd28 100644 --- a/src/elements/teaser/teaser.stories.ts +++ b/src/elements/teaser/teaser.stories.ts @@ -10,6 +10,7 @@ import images from '../core/images.js'; import placeholderImage from './assets/placeholder.png'; import readme from './readme.md?raw'; +import '../chip-label.js'; import '../image.js'; import './teaser.js'; @@ -89,7 +90,10 @@ const defaultArgs: Args = { const TemplateDefault = ({ description, ...remainingArgs }: Args): TemplateResult => { return html` - 400x300 +
+ 400x300 + AI Generated +
${description}
`; @@ -98,7 +102,9 @@ const TemplateDefault = ({ description, ...remainingArgs }: Args): TemplateResul const TemplateDefaultFixedWidth = ({ description, ...remainingArgs }: Args): TemplateResult => { return html` - 400x300 +
+ 400x300 +
${description}
`; @@ -107,12 +113,9 @@ const TemplateDefaultFixedWidth = ({ description, ...remainingArgs }: Args): Tem const TemplateCustom = ({ description, ...remainingArgs }: Args): TemplateResult => { return html` - 200x100 +
+ 200x100 +
${description}
`; @@ -126,7 +129,9 @@ const TemplateSlots = ({ }: Args): TemplateResult => { return html` - 400x300 +
+ 400x300 +
${chipContent} ${titleContent} ${description} @@ -149,12 +154,9 @@ const TemplateGrid = ({ description, ...remainingArgs }: Args): TemplateResult = new Array(4), () => html` - +
+ +
${description}
`, diff --git a/src/elements/teaser/teaser.visual.spec.ts b/src/elements/teaser/teaser.visual.spec.ts index 34101c0059..fa4747506e 100644 --- a/src/elements/teaser/teaser.visual.spec.ts +++ b/src/elements/teaser/teaser.visual.spec.ts @@ -52,7 +52,9 @@ describe(`sbb-teaser`, () => { await setup.withFixture( html` - +
+ +
This is a paragraph
`, @@ -75,7 +77,14 @@ describe(`sbb-teaser`, () => { alignment=${alignment} chip-content=${hasChip ? 'This is a chip.' : nothing} > - +
+ + ${hasChip + ? html`AI chip` + : nothing} +
${withLongContent ? loremIpsum : 'This is a paragraph'}
`, @@ -98,7 +107,9 @@ describe(`sbb-teaser`, () => { alignment=${alignment} chip-content=${longChip} > - +
+ +
This is a paragraph
`, @@ -123,7 +134,9 @@ describe(`sbb-teaser`, () => { href="#" alignment=${alignment} > - +
+ +
This is the paragraph n.${i + 1} @@ -155,7 +168,12 @@ describe(`sbb-teaser`, () => { alignment="below" style="--sbb-teaser-align-items: stretch;" > - +
+ + AI chip +
This is a paragraph `, From 4f1fcba3f5e1740ca9c986cc088fa19c2ef47f57 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 6 Nov 2024 17:36:02 +0100 Subject: [PATCH 05/47] refactor(sbb-image): convert 'aspect-ratio' and 'border-radius' to classes --- src/elements/core/styles/image.scss | 50 +++++++++++++++ src/elements/image/image.scss | 54 +--------------- src/elements/image/image.stories.ts | 55 ++++++++++++----- src/elements/image/image.ts | 35 +---------- src/elements/image/image.visual.spec.ts | 82 +++++++++++++++---------- src/elements/image/readme.md | 62 +++++++++++++------ 6 files changed, 184 insertions(+), 154 deletions(-) diff --git a/src/elements/core/styles/image.scss b/src/elements/core/styles/image.scss index bd0a8d650e..41d14c82e5 100644 --- a/src/elements/core/styles/image.scss +++ b/src/elements/core/styles/image.scss @@ -15,6 +15,7 @@ @include image.figure-caption; } + // Utility classes for placing elements over an image (eg. 'sbb-figure-overlap-start-start') $alignments: start, center, end; @each $row-alignment in $alignments { @each $column-alignment in $alignments { @@ -24,3 +25,52 @@ } } } + +// Utility classes for the aspect ratio (eg. 'sbb-image-16-9') +$aspects-ratio: ( + 'free': 'auto', + '1-1': '1 / 1', + '1-2': '1 / 2', + '2-1': '2 / 1', + '2-3': '2 / 3', + '3-2': '3 / 2', + '3-4': '3 / 4', + '4-3': '4 / 3', + '4-5': '4 / 5', + '5-4': '5 / 4', + '9-16': '9 / 16', + '16-9': '16 / 9', +); +@each $name, $ratio in $aspects-ratio { + sbb-image { + &.sbb-image-#{$name} { + --sbb-image-aspect-ratio: #{$ratio}; + } + } + + img { + &.sbb-image-#{$name} { + aspect-ratio: #{$ratio}; + } + } +} + +// Utility classes for the border radius (eg. 'sbb-image-border-radius-none') +$border-radius: ( + 'default': 'var(--sbb-border-radius-4x)', + 'none': '0', + 'round': 'var(--sbb-border-radius-infinity)', +); +@each $name, $radius in $border-radius { + sbb-image { + &.sbb-image-border-radius-#{$name} { + --sbb-image-border-radius: #{$radius}; + } + } + + img { + &.sbb-image-border-radius-#{$name} { + border-radius: #{$radius}; + } + } +} diff --git a/src/elements/image/image.scss b/src/elements/image/image.scss index b517431e21..c85948e4e3 100644 --- a/src/elements/image/image.scss +++ b/src/elements/image/image.scss @@ -5,7 +5,7 @@ :host { --sbb-image-border-radius: var(--sbb-border-radius-4x); - --sbb-image-aspect-ratio: auto; + --sbb-image-aspect-ratio: 16 / 9; --sbb-image-animation-duration: var( --sbb-disable-animation-zero-duration, var(--sbb-animation-duration-4x) @@ -15,50 +15,6 @@ display: block; } -:host([aspect-ratio='1-1']) { - --sbb-image-aspect-ratio: 1 / 1; -} - -:host([aspect-ratio='1-2']) { - --sbb-image-aspect-ratio: 1 / 2; -} - -:host([aspect-ratio='2-1']) { - --sbb-image-aspect-ratio: 2 / 1; -} - -:host([aspect-ratio='2-3']) { - --sbb-image-aspect-ratio: 2 / 3; -} - -:host([aspect-ratio='3-2']) { - --sbb-image-aspect-ratio: 3 / 2; -} - -:host([aspect-ratio='3-4']) { - --sbb-image-aspect-ratio: 3 / 4; -} - -:host([aspect-ratio='4-3']) { - --sbb-image-aspect-ratio: 4 / 3; -} - -:host([aspect-ratio='4-5']) { - --sbb-image-aspect-ratio: 4 / 5; -} - -:host([aspect-ratio='5-4']) { - --sbb-image-aspect-ratio: 5 / 4; -} - -:host([aspect-ratio='16-9']) { - --sbb-image-aspect-ratio: 16 / 9; -} - -:host([aspect-ratio='9-16']) { - --sbb-image-aspect-ratio: 9 / 16; -} - // Variant: Hero Teaser and Paid Teaser :host([data-teaser]) { --sbb-image-aspect-ratio: 1 / 1; @@ -68,14 +24,6 @@ } } -:host(:is([border-radius='none'], [data-teaser])) { - --sbb-image-border-radius: 0; -} - -:host([border-radius='round']:not([data-teaser])) { - --sbb-image-border-radius: var(--sbb-border-radius-infinity); -} - .sbb-image__img { opacity: 0.000001; diff --git a/src/elements/image/image.stories.ts b/src/elements/image/image.stories.ts index 709ceddc07..c3621d7576 100644 --- a/src/elements/image/image.stories.ts +++ b/src/elements/image/image.stories.ts @@ -3,6 +3,7 @@ import type { InputType } from '@storybook/types'; import type { Args, ArgTypes, Decorator, Meta, StoryObj } from '@storybook/web-components'; import type { TemplateResult } from 'lit'; import { html } from 'lit'; +import { classMap } from 'lit/directives/class-map.js'; import { sbbSpread } from '../../storybook/helpers/spread.js'; import images from '../core/images.js'; @@ -11,9 +12,20 @@ import { SbbImageElement } from './image.js'; import readme from './readme.md?raw'; import '../chip-label.js'; +const imageTemplate = ({ aspectRatio, borderRadius, ...args }: Args): TemplateResult => html` + + +`; + const WithCaptionTemplate = (args: Args): TemplateResult => html`
- + ${imageTemplate(args)}
With the html` `; const Template = (args: Args): TemplateResult => html` -
- -
+
${imageTemplate(args)}
`; -const WithChipTemplate = (args: Args): TemplateResult => html` +const WithChipTemplate = ({ chipPosition, ...args }: Args): TemplateResult => html`
- - AI generated + ${imageTemplate(args)} + AI generated
`; @@ -51,11 +61,25 @@ const borderRadius: InputType = { type: 'select', }, options: ['default', 'none', 'round'], + table: { + category: 'Utility classes', + }, }; const aspectRatio: InputType = { control: { type: 'select' }, options: ['free', '1-1', '1-2', '2-1', '2-3', '3-2', '3-4', '4-3', '4-5', '5-4', '9-16', '16-9'], + table: { + category: 'Utility classes', + }, +}; + +const chipPosition: InputType = { + control: { type: 'select' }, + options: ['start-start', 'start-end', 'end-start', 'end-end'], + table: { + category: 'Utility classes', + }, }; const alt: InputType = { @@ -130,8 +154,9 @@ const performanceMark: InputType = { const defaultArgTypes: ArgTypes = { alt, - 'border-radius': borderRadius, - 'aspect-ratio': aspectRatio, + borderRadius, + aspectRatio, + chipPosition, 'custom-focal-point': customFocalPoint, 'focal-point-debug': focalPointDebug, 'focal-point-x': focalPointX, @@ -144,9 +169,9 @@ const defaultArgTypes: ArgTypes = { const defaultArgs: Args = { alt: '', - // we need a string and not boolean, otherwise storybook add/remove the attribute but don't write the value - 'border-radius': 'default', - 'aspect-ratio': aspectRatio.options![0], + borderRadius: borderRadius.options![0], + aspectRatio: aspectRatio.options![0], + chipPosition: chipPosition.options![0], 'custom-focal-point': false, 'focal-point-debug': false, 'focal-point-x': '', @@ -177,7 +202,7 @@ export const NoCaptionNoRadius: StoryObj = { argTypes: defaultArgTypes, args: { ...defaultArgs, - 'border-radius': 'none', + borderRadius: 'none', }, }; @@ -186,8 +211,8 @@ export const RoundBorderRadius: StoryObj = { argTypes: defaultArgTypes, args: { ...defaultArgs, - 'border-radius': 'round', - 'aspect-ratio': '1-1', + borderRadius: 'round', + aspectRatio: '1-1', }, }; diff --git a/src/elements/image/image.ts b/src/elements/image/image.ts index d544d75999..229f0209c6 100644 --- a/src/elements/image/image.ts +++ b/src/elements/image/image.ts @@ -364,34 +364,6 @@ class SbbImageElement extends LitElement { @property({ attribute: 'picture-sizes-config' }) public accessor pictureSizesConfig: string = ''; - /** - * Border radius of the image. Choose between a default radius, no radius and a completely round image. - */ - @property({ attribute: 'border-radius', reflect: true }) public accessor borderRadius: - | 'default' - | 'none' - | 'round' = 'default'; - - /** - * Set an aspect ratio - * default is '16-9' (16/9) - * other values: 'free', '1-1', '1-2', '2-1', '2-3', '3-2', '3-4', '4-3', '4-5', '5-4', '9-16' - */ - @property({ attribute: 'aspect-ratio', reflect: true }) - public accessor aspectRatio: - | 'free' - | '1-1' - | '1-2' - | '2-1' - | '2-3' - | '3-2' - | '3-4' - | '4-3' - | '4-5' - | '5-4' - | '9-16' - | '16-9' = '16-9'; - /** Whether the image is finished loading or failed to load. */ public get complete(): boolean { return this.shadowRoot?.querySelector?.('.sbb-image__img')?.complete ?? false; @@ -399,11 +371,8 @@ class SbbImageElement extends LitElement { public override connectedCallback(): void { super.connectedCallback(); - // Check if the current element is nested in an `` element on in an `` element. - this.toggleAttribute( - 'data-teaser', - !!hostContext('sbb-teaser-hero', this) || !!this.closest('sbb-teaser-paid'), - ); + // Check if the current element is nested in an `` element. + this.toggleAttribute('data-teaser', !!hostContext('sbb-teaser-hero', this)); } protected override updated(changedProperties: PropertyValues): void { diff --git a/src/elements/image/image.visual.spec.ts b/src/elements/image/image.visual.spec.ts index b69f110c20..50652e0d47 100644 --- a/src/elements/image/image.visual.spec.ts +++ b/src/elements/image/image.visual.spec.ts @@ -9,6 +9,7 @@ import './image.js'; const imageUrl = import.meta.resolve('../core/testing/assets/placeholder-image.png'); const aspectRatios = [ + 'free', '1-1', '1-2', '2-1', @@ -29,7 +30,9 @@ describe(`sbb-image`, () => { `aspect-ratio=${aspectRatio}`, visualDiffDefault.with(async (setup) => { await setup.withFixture( - html``, + html`
+ +
`, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -41,27 +44,30 @@ describe(`sbb-image`, () => { `aspect-ratio=free`, visualDiffDefault.with(async (setup) => { await setup.withFixture( - html``, + html`
+ +
`, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); }), ); - for (const borderRadius of ['none', 'round']) { + for (const borderRadius of ['none', 'round', 'default']) { it( `border-radius=${borderRadius}`, visualDiffDefault.with(async (setup) => { await setup.withFixture( - html``, + html`
+ +
`, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -73,11 +79,16 @@ describe(`sbb-image`, () => { 'with caption', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`Gleis 7
. After the link there is more text.`} - >`, + html`
+ +
+ A long text which takes several lines and contains a link + Gleis 7. After the link there is more text. +
+
`, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -87,7 +98,11 @@ describe(`sbb-image`, () => { it( 'transparent image from img cdn', visualDiffDefault.with(async (setup) => { - await setup.withFixture(html``); + await setup.withFixture( + html`
+ +
`, + ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); }), @@ -97,7 +112,9 @@ describe(`sbb-image`, () => { 'cropped', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html``, + html`
+ +
`, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -108,11 +125,10 @@ describe(`sbb-image`, () => { 'cropped with caption', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html``, + html`
+ +
I am a caption below
+
`, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -123,10 +139,9 @@ describe(`sbb-image`, () => { 'cropped with object-position', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html``, + html`
+ +
`, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -137,10 +152,9 @@ describe(`sbb-image`, () => { 'cropped with object-fit', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html``, + html`
+ +
`, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -151,7 +165,9 @@ describe(`sbb-image`, () => { 'skipLqip=true', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html``, + html`
+ +
`, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); diff --git a/src/elements/image/readme.md b/src/elements/image/readme.md index 984d2bc8d6..42eb103ad8 100644 --- a/src/elements/image/readme.md +++ b/src/elements/image/readme.md @@ -5,16 +5,20 @@ The size can be set with `pictureSizesConfig`. ## Usage -It is possible to add a caption and/or the copyright by wrapping everything in a `figure` tag. +In general, it is strongly recommended to wrap an `sbb-image` and all its related elements in a `figure` tag. + +It is possible to add a caption and/or the copyright using the `figcaption`. ```html
- or or <... class="sbb-image" /> + or
Caption / Copyright
``` -Also, you can place overlapping content by using the `sbb-figure-overlap-${horizontal-alignment}-${vertical-alignment}` utility classes. +### Utility classes + +You can place overlapping content by using the `sbb-figure-overlap-${horizontal-alignment}-${vertical-alignment}` utility classes. ```html
@@ -23,27 +27,45 @@ Also, you can place overlapping content by using the `sbb-figure-overlap-${horiz
``` +Use the `sbb-image-border-radius-${value}` utility classes to set the image border radius. Available values: `default`, `none` and `round` + +```html +
+ + + +
+``` + +Use the `sbb-image-${value}` utility classes to set the image aspect ratio. Available values: `free`, `1-1`, `2-3`, `3-2` ... `9-16`, `16-9` + +```html +
+ + + +
+``` + ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| -------------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `alt` | `alt` | public | `string` | `''` | An alt text is not always necessary (e.g. in teaser cards when additional link text is provided). In this case we can leave the value of the alt attribute blank, but the attribute itself still needs to be present. That way we can signal assistive technology, that they can skip the image. | -| `aspectRatio` | `aspect-ratio` | public | `'free' \| '1-1' \| '1-2' \| '2-1' \| '2-3' \| '3-2' \| '3-4' \| '4-3' \| '4-5' \| '5-4' \| '9-16' \| '16-9'` | `'16-9'` | Set an aspect ratio default is '16-9' (16/9) other values: 'free', '1-1', '1-2', '2-1', '2-3', '3-2', '3-4', '4-3', '4-5', '5-4', '9-16' | -| `borderRadius` | `border-radius` | public | `'default' \| 'none' \| 'round'` | `'default'` | Border radius of the image. Choose between a default radius, no radius and a completely round image. | -| `complete` | - | public | `boolean` | | Whether the image is finished loading or failed to load. | -| `customFocalPoint` | `custom-focal-point` | public | `boolean` | `false` | Set this to true, if you want to pass a custom focal point for the image. See full documentation here: https://docs.imgix.com/apis/rendering/focalpoint-crop | -| `decoding` | `decoding` | public | `'sync' \| 'async' \| 'auto'` | `'auto'` | If the lazy property is set to true, the module will automatically change the decoding to async, otherwise the decoding is set to auto which leaves the handling up to the browser. Read more about the decoding attribute here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decoding | -| `focalPointDebug` | `focal-point-debug` | public | `boolean` | `false` | Set this to true, to receive visual guidance where the custom focal point is currently set. | -| `focalPointX` | `focal-point-x` | public | `number` | `1` | Pass in a floating number between 0 (left) and 1 (right). | -| `focalPointY` | `focal-point-y` | public | `number` | `1` | Pass in a floating number between 0 (top) and 1 (bottom). | -| `imageSrc` | `image-src` | public | `string` | `''` | Right now the module is heavily coupled with the image delivery service imgix and depends on the original files being stored inside AEM. You can pass in any https://cdn.img.sbb.ch img src address you find on sbb.ch to play around with it. Just strip the url parameters and paste in the plain file address. If you want to know how to best work with this module with images coming from a different source, please contact the LYNE Core Team. | -| `importance` | `importance` | public | `'auto' \| 'high' \| 'low'` | `'high'` | The importance attribute is fairly new attribute which should help the browser decide which resources it should prioritise during page load. We will set the attribute value based on the value, we receive in the loading attribute. 'eager', which we use for the largest image within the initial viewport, will set the attribute value to 'high'. 'lazy', which we use for images below the fold, will set the attribute value to 'low'. | -| `loading` | `loading` | public | `'eager' \| 'lazy'` | `'eager'` | With the support of native image lazy loading, we can now decide whether we want to load the image immediately or only once it is close to the visible viewport. The value eager is best used for images within the initial viewport. We want to load these images as fast as possible to improve the Core Web Vitals values. lazy on the other hand works best for images which are further down the page or invisible during the loading of the initial viewport. | -| `performanceMark` | `performance-mark` | public | `string` | `''` | With performance.mark you can log a timestamp associated with the name you define in performanceMark when a certain event is happening. In our case we will log the performance.mark into the PerformanceEntry API once the image is fully loaded. Performance monitoring tools like SpeedCurve or Lighthouse are then able to grab these entries from the PerformanceEntry API and give us additional information and insights about our page loading behaviour. We are then also able to monitor these values over a long period to see if our performance increases or decreases over time. Best to use lowercase strings here, separate words with underscores or dashes. | -| `pictureSizesConfig` | `picture-sizes-config` | public | `string` | `''` | With the pictureSizesConfig object, you can pass in information into image about what kind of source elements should get rendered. mediaQueries accepts multiple Media Query entries which can get combined by defining a conditionOperator. Type is: stringified InterfaceImageAttributesSizesConfig-Object An example could look like this: { "breakpoints": \[ { "image": { "height": "675", "width": "1200" }, "mediaQueries": \[ { "conditionFeature": "min-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-large-min" }, "conditionOperator": false } ] }, { "image": { "height": "549", "width": "976" }, "mediaQueries": \[ { "conditionFeature": "min-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-small-min" }, "conditionOperator": false } ] }, { "image": { "height": "180", "width": "320" }, "mediaQueries": \[ { "conditionFeature": "max-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-micro-max" }, "conditionOperator": "and" }, { "conditionFeature": "orientation", "conditionFeatureValue": { "lyneDesignToken": false, "value": "landscape" }, "conditionOperator": false } ] } ] } | -| `skipLqip` | `skip-lqip` | public | `boolean` | `false` | If set to false, we show a blurred version of the image as placeholder before the actual image shows up. This will help to improve the perceived loading performance. Read more about the idea of lqip here: https://medium.com/@imgix/lqip-your-images-for-fast-loading-2523d9ee4a62 | +| Name | Attribute | Privacy | Type | Default | Description | +| -------------------- | ---------------------- | ------- | ----------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `alt` | `alt` | public | `string` | `''` | An alt text is not always necessary (e.g. in teaser cards when additional link text is provided). In this case we can leave the value of the alt attribute blank, but the attribute itself still needs to be present. That way we can signal assistive technology, that they can skip the image. | +| `complete` | - | public | `boolean` | | Whether the image is finished loading or failed to load. | +| `customFocalPoint` | `custom-focal-point` | public | `boolean` | `false` | Set this to true, if you want to pass a custom focal point for the image. See full documentation here: https://docs.imgix.com/apis/rendering/focalpoint-crop | +| `decoding` | `decoding` | public | `'sync' \| 'async' \| 'auto'` | `'auto'` | If the lazy property is set to true, the module will automatically change the decoding to async, otherwise the decoding is set to auto which leaves the handling up to the browser. Read more about the decoding attribute here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decoding | +| `focalPointDebug` | `focal-point-debug` | public | `boolean` | `false` | Set this to true, to receive visual guidance where the custom focal point is currently set. | +| `focalPointX` | `focal-point-x` | public | `number` | `1` | Pass in a floating number between 0 (left) and 1 (right). | +| `focalPointY` | `focal-point-y` | public | `number` | `1` | Pass in a floating number between 0 (top) and 1 (bottom). | +| `imageSrc` | `image-src` | public | `string` | `''` | Right now the module is heavily coupled with the image delivery service imgix and depends on the original files being stored inside AEM. You can pass in any https://cdn.img.sbb.ch img src address you find on sbb.ch to play around with it. Just strip the url parameters and paste in the plain file address. If you want to know how to best work with this module with images coming from a different source, please contact the LYNE Core Team. | +| `importance` | `importance` | public | `'auto' \| 'high' \| 'low'` | `'high'` | The importance attribute is fairly new attribute which should help the browser decide which resources it should prioritise during page load. We will set the attribute value based on the value, we receive in the loading attribute. 'eager', which we use for the largest image within the initial viewport, will set the attribute value to 'high'. 'lazy', which we use for images below the fold, will set the attribute value to 'low'. | +| `loading` | `loading` | public | `'eager' \| 'lazy'` | `'eager'` | With the support of native image lazy loading, we can now decide whether we want to load the image immediately or only once it is close to the visible viewport. The value eager is best used for images within the initial viewport. We want to load these images as fast as possible to improve the Core Web Vitals values. lazy on the other hand works best for images which are further down the page or invisible during the loading of the initial viewport. | +| `performanceMark` | `performance-mark` | public | `string` | `''` | With performance.mark you can log a timestamp associated with the name you define in performanceMark when a certain event is happening. In our case we will log the performance.mark into the PerformanceEntry API once the image is fully loaded. Performance monitoring tools like SpeedCurve or Lighthouse are then able to grab these entries from the PerformanceEntry API and give us additional information and insights about our page loading behaviour. We are then also able to monitor these values over a long period to see if our performance increases or decreases over time. Best to use lowercase strings here, separate words with underscores or dashes. | +| `pictureSizesConfig` | `picture-sizes-config` | public | `string` | `''` | With the pictureSizesConfig object, you can pass in information into image about what kind of source elements should get rendered. mediaQueries accepts multiple Media Query entries which can get combined by defining a conditionOperator. Type is: stringified InterfaceImageAttributesSizesConfig-Object An example could look like this: { "breakpoints": \[ { "image": { "height": "675", "width": "1200" }, "mediaQueries": \[ { "conditionFeature": "min-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-large-min" }, "conditionOperator": false } ] }, { "image": { "height": "549", "width": "976" }, "mediaQueries": \[ { "conditionFeature": "min-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-small-min" }, "conditionOperator": false } ] }, { "image": { "height": "180", "width": "320" }, "mediaQueries": \[ { "conditionFeature": "max-width", "conditionFeatureValue": { "lyneDesignToken": true, "value": "sbb-breakpoint-micro-max" }, "conditionOperator": "and" }, { "conditionFeature": "orientation", "conditionFeatureValue": { "lyneDesignToken": false, "value": "landscape" }, "conditionOperator": false } ] } ] } | +| `skipLqip` | `skip-lqip` | public | `boolean` | `false` | If set to false, we show a blurred version of the image as placeholder before the actual image shows up. This will help to improve the perceived loading performance. Read more about the idea of lqip here: https://medium.com/@imgix/lqip-your-images-for-fast-loading-2523d9ee4a62 | ## Events From 838819aa3a2806d5574ea28288011f7239a02a30 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Thu, 7 Nov 2024 10:09:22 +0100 Subject: [PATCH 06/47] refactor(sbb-image): update tests --- .../__snapshots__/image.snapshot.spec.snap.js | 58 +++++++++---------- .../lead-container.snapshot.spec.snap.js | 2 - .../message.snapshot.spec.snap.js | 2 - .../teaser-hero.snapshot.spec.snap.js | 2 - src/elements/teaser-hero/teaser-hero.spec.ts | 2 +- ...easer-product-static.snapshot.spec.snap.js | 5 +- .../teaser-product.snapshot.spec.snap.js | 5 +- src/elements/teaser/teaser.stories.ts | 4 +- 8 files changed, 31 insertions(+), 49 deletions(-) diff --git a/src/elements/image/__snapshots__/image.snapshot.spec.snap.js b/src/elements/image/__snapshots__/image.snapshot.spec.snap.js index b4bb7b14df..a2ed420dcf 100644 --- a/src/elements/image/__snapshots__/image.snapshot.spec.snap.js +++ b/src/elements/image/__snapshots__/image.snapshot.spec.snap.js @@ -2,50 +2,44 @@ export const snapshots = {}; snapshots["sbb-image should render DOM"] = -` +` `; /* end snapshot sbb-image should render DOM */ snapshots["sbb-image should render Shadow DOM"] = -`
-
+`
+ + + + + - - - - - - -
-
+ + `; /* end snapshot sbb-image should render Shadow DOM */ diff --git a/src/elements/lead-container/__snapshots__/lead-container.snapshot.spec.snap.js b/src/elements/lead-container/__snapshots__/lead-container.snapshot.spec.snap.js index 3a88024149..737465bddf 100644 --- a/src/elements/lead-container/__snapshots__/lead-container.snapshot.spec.snap.js +++ b/src/elements/lead-container/__snapshots__/lead-container.snapshot.spec.snap.js @@ -4,8 +4,6 @@ export const snapshots = {}; snapshots["sbb-lead-container DOM"] = ` diff --git a/src/elements/message/__snapshots__/message.snapshot.spec.snap.js b/src/elements/message/__snapshots__/message.snapshot.spec.snap.js index bd5bb84d96..bcf94c327d 100644 --- a/src/elements/message/__snapshots__/message.snapshot.spec.snap.js +++ b/src/elements/message/__snapshots__/message.snapshot.spec.snap.js @@ -4,8 +4,6 @@ export const snapshots = {}; snapshots["sbb-message renders DOM"] = ` diff --git a/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js b/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js index 596fe3da66..0615e65c0e 100644 --- a/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js +++ b/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js @@ -18,8 +18,6 @@ snapshots["sbb-teaser-hero renders DOM"] = slot="image" > diff --git a/src/elements/teaser-hero/teaser-hero.spec.ts b/src/elements/teaser-hero/teaser-hero.spec.ts index 17c55ebe25..cc13598778 100644 --- a/src/elements/teaser-hero/teaser-hero.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.spec.ts @@ -43,7 +43,7 @@ describe(`sbb-teaser-hero`, () => { ); await waitForLitRender(element); - const chip = element.querySelector('sbb-chip')!; + const chip = element.querySelector('sbb-chip-label')!; const image = element.querySelector('sbb-image')!; expect(chip).to.have.attribute('color', 'charcoal'); diff --git a/src/elements/teaser-product/teaser-product-static/__snapshots__/teaser-product-static.snapshot.spec.snap.js b/src/elements/teaser-product/teaser-product-static/__snapshots__/teaser-product-static.snapshot.spec.snap.js index 45bf228bd4..da246ea977 100644 --- a/src/elements/teaser-product/teaser-product-static/__snapshots__/teaser-product-static.snapshot.spec.snap.js +++ b/src/elements/teaser-product/teaser-product-static/__snapshots__/teaser-product-static.snapshot.spec.snap.js @@ -11,10 +11,7 @@ snapshots["sbb-teaser-product-static renders DOM"] = class="sbb-figure" slot="image" > - +

diff --git a/src/elements/teaser-product/teaser-product/__snapshots__/teaser-product.snapshot.spec.snap.js b/src/elements/teaser-product/teaser-product/__snapshots__/teaser-product.snapshot.spec.snap.js index 4623e58988..9a7aa1d84f 100644 --- a/src/elements/teaser-product/teaser-product/__snapshots__/teaser-product.snapshot.spec.snap.js +++ b/src/elements/teaser-product/teaser-product/__snapshots__/teaser-product.snapshot.spec.snap.js @@ -13,10 +13,7 @@ snapshots["sbb-teaser-product renders DOM"] = class="sbb-figure" slot="image" > - +

diff --git a/src/elements/teaser/teaser.stories.ts b/src/elements/teaser/teaser.stories.ts index 107e77dd28..e8a9895468 100644 --- a/src/elements/teaser/teaser.stories.ts +++ b/src/elements/teaser/teaser.stories.ts @@ -113,8 +113,8 @@ const TemplateDefaultFixedWidth = ({ description, ...remainingArgs }: Args): Tem const TemplateCustom = ({ description, ...remainingArgs }: Args): TemplateResult => { return html` -

- 200x100 +
+ 200x100
${description} From 826fdaa8398746855c100f05504e9820c5cf8be9 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Thu, 7 Nov 2024 10:37:42 +0100 Subject: [PATCH 07/47] refactor(sbb-image): update snapshots --- .../__snapshots__/flip-card-summary.snapshot.spec.snap.js | 6 +----- .../flip-card/__snapshots__/flip-card.snapshot.spec.snap.js | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/elements/flip-card/flip-card-summary/__snapshots__/flip-card-summary.snapshot.spec.snap.js b/src/elements/flip-card/flip-card-summary/__snapshots__/flip-card-summary.snapshot.spec.snap.js index ff68aacd62..f1ab816c5f 100644 --- a/src/elements/flip-card/flip-card-summary/__snapshots__/flip-card-summary.snapshot.spec.snap.js +++ b/src/elements/flip-card/flip-card-summary/__snapshots__/flip-card-summary.snapshot.spec.snap.js @@ -30,11 +30,7 @@ snapshots["sbb-flip-card-summary DOM"] = > Summary - + `; diff --git a/src/elements/flip-card/flip-card/__snapshots__/flip-card.snapshot.spec.snap.js b/src/elements/flip-card/flip-card/__snapshots__/flip-card.snapshot.spec.snap.js index c2b823d882..1b3a1a62f6 100644 --- a/src/elements/flip-card/flip-card/__snapshots__/flip-card.snapshot.spec.snap.js +++ b/src/elements/flip-card/flip-card/__snapshots__/flip-card.snapshot.spec.snap.js @@ -39,11 +39,7 @@ snapshots["sbb-flip-card DOM"] = > Summary - + Date: Mon, 11 Nov 2024 09:38:44 +0100 Subject: [PATCH 08/47] test(sbb-image): fix visual spec --- src/elements/image/image.scss | 1 + src/elements/image/image.visual.spec.ts | 2 +- src/elements/teaser/teaser.visual.spec.ts | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/elements/image/image.scss b/src/elements/image/image.scss index c85948e4e3..4cf0152751 100644 --- a/src/elements/image/image.scss +++ b/src/elements/image/image.scss @@ -18,6 +18,7 @@ // Variant: Hero Teaser and Paid Teaser :host([data-teaser]) { --sbb-image-aspect-ratio: 1 / 1; + --sbb-image-border-radius: 0; @include sbb.mq($from: small) { --sbb-image-aspect-ratio: 16 / 9; diff --git a/src/elements/image/image.visual.spec.ts b/src/elements/image/image.visual.spec.ts index 50652e0d47..aed3a7cfa5 100644 --- a/src/elements/image/image.visual.spec.ts +++ b/src/elements/image/image.visual.spec.ts @@ -31,7 +31,7 @@ describe(`sbb-image`, () => { visualDiffDefault.with(async (setup) => { await setup.withFixture( html`
- +
`, ); diff --git a/src/elements/teaser/teaser.visual.spec.ts b/src/elements/teaser/teaser.visual.spec.ts index fa4747506e..e5cf3cd4d8 100644 --- a/src/elements/teaser/teaser.visual.spec.ts +++ b/src/elements/teaser/teaser.visual.spec.ts @@ -168,8 +168,8 @@ describe(`sbb-teaser`, () => { alignment="below" style="--sbb-teaser-align-items: stretch;" > -
- +
+ AI chip From d398703cfea41a4b0e02285e0c760b8ee46f4daf Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Mon, 11 Nov 2024 12:28:35 +0100 Subject: [PATCH 09/47] test(sbb-image): fix visual spec --- src/elements/core/styles/mixins/image.scss | 2 +- src/elements/image/image.stories.ts | 7 ++++++- src/elements/image/image.visual.spec.ts | 22 ++++++++++++++-------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/elements/core/styles/mixins/image.scss b/src/elements/core/styles/mixins/image.scss index 5a1c3e1c85..d1dd63e2ec 100644 --- a/src/elements/core/styles/mixins/image.scss +++ b/src/elements/core/styles/mixins/image.scss @@ -24,5 +24,5 @@ grid-row: 1; grid-column: 1; place-self: #{$row-alignment} #{$column-alignment}; - margin: 0.75rem; + margin: var(--sbb-spacing-responsive-xxxs); } diff --git a/src/elements/image/image.stories.ts b/src/elements/image/image.stories.ts index c3621d7576..72e42e01f6 100644 --- a/src/elements/image/image.stories.ts +++ b/src/elements/image/image.stories.ts @@ -12,7 +12,12 @@ import { SbbImageElement } from './image.js'; import readme from './readme.md?raw'; import '../chip-label.js'; -const imageTemplate = ({ aspectRatio, borderRadius, ...args }: Args): TemplateResult => html` +const imageTemplate = ({ + aspectRatio, + borderRadius, + _chipPosition, + ...args +}: Args): TemplateResult => html` { 'cropped', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- + html`
+
`, ); @@ -125,8 +125,8 @@ describe(`sbb-image`, () => { 'cropped with caption', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- + html`
+
I am a caption below
`, ); @@ -139,8 +139,11 @@ describe(`sbb-image`, () => { 'cropped with object-position', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- + html`
+
`, ); @@ -152,8 +155,11 @@ describe(`sbb-image`, () => { 'cropped with object-fit', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- + html`
+
`, ); From c3512d4e18597237e7f9c8ec2f69ba89285b713a Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 12 Nov 2024 14:31:10 +0100 Subject: [PATCH 10/47] style(sbb-image): cleanup --- src/elements/core/styles/core.scss | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index bc7ecc0016..e1a0667d43 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -174,7 +174,6 @@ input[data-sbb-time-input] { --sbb-image-border-radius: 0; } - // TODO create and use utility classes img { place-self: stretch; object-fit: cover; @@ -191,12 +190,10 @@ input[data-sbb-time-input] { transform: scale(var(--sbb-teaser-scale, 1)); } - // TODO create and use utility classes sbb-image { --sbb-image-aspect-ratio: 4 / 3; } - // TODO create and use utility classes img { object-fit: cover; aspect-ratio: 4/3; From 97114359d2864e15f3d837d06cb4fc32db87cd97 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 13 Nov 2024 14:22:36 +0100 Subject: [PATCH 11/47] style(image-mixin): fix figure layout --- src/elements/core/styles/mixins/image.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/elements/core/styles/mixins/image.scss b/src/elements/core/styles/mixins/image.scss index d1dd63e2ec..ae884ea0a7 100644 --- a/src/elements/core/styles/mixins/image.scss +++ b/src/elements/core/styles/mixins/image.scss @@ -2,7 +2,9 @@ @mixin figure { display: grid; - grid-row-gap: var(--sbb-spacing-fixed-4x); + grid-template-rows: auto; + grid-template-columns: 100%; + grid-auto-rows: auto; margin: 0; height: 100%; } @@ -16,6 +18,7 @@ @mixin figure-caption { grid-row: 2; grid-column: 1; + padding-block-start: var(--sbb-spacing-fixed-4x); @include typo.text-xs--regular; } From eb2663164aefb27d170f44ca3b6fae884bb5dd33 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 13 Nov 2024 15:43:42 +0100 Subject: [PATCH 12/47] test(sbb-image): fix visual spec --- src/elements/image/image.visual.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/elements/image/image.visual.spec.ts b/src/elements/image/image.visual.spec.ts index 21f72598b2..b39b9063df 100644 --- a/src/elements/image/image.visual.spec.ts +++ b/src/elements/image/image.visual.spec.ts @@ -9,7 +9,6 @@ import './image.js'; const imageUrl = import.meta.resolve('../core/testing/assets/placeholder-image.png'); const aspectRatios = [ - 'free', '1-1', '1-2', '2-1', From 94152d70aa407b89dbe668c2b0ea941d69282de3 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 20 Nov 2024 10:22:14 +0100 Subject: [PATCH 13/47] fix: review feedbacks --- src/elements/teaser-hero/readme.md | 4 ++-- src/elements/teaser-hero/teaser-hero.stories.ts | 2 +- src/elements/teaser-product/teaser-product-static/readme.md | 4 ++-- .../teaser-product-static/teaser-product-static.stories.ts | 2 +- src/elements/teaser-product/teaser-product/readme.md | 4 ++-- .../teaser-product/teaser-product/teaser-product.stories.ts | 2 +- src/elements/teaser/readme.md | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/elements/teaser-hero/readme.md b/src/elements/teaser-hero/readme.md index f16719de1b..3bc40cc467 100644 --- a/src/elements/teaser-hero/readme.md +++ b/src/elements/teaser-hero/readme.md @@ -6,8 +6,8 @@ it should be an eye-catcher and should have an emotional effect on the user with It is possible to provide the panel label via an unnamed slot, while the link text can be provided using the `link-content` slot or the `linkContent` property; -Use the `image` slot to pass a `figure` containing an `sbb-image | img` that will be used as background. -Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure`. +Use the `image` slot to pass a `figure` containing an `sbb-image` or an `img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure` (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). ```html diff --git a/src/elements/teaser-hero/teaser-hero.stories.ts b/src/elements/teaser-hero/teaser-hero.stories.ts index bd3f205808..ab3f21030b 100644 --- a/src/elements/teaser-hero/teaser-hero.stories.ts +++ b/src/elements/teaser-hero/teaser-hero.stories.ts @@ -120,7 +120,7 @@ const TemplateSbbTeaserWithSlots = ({ ...args }: Args): TemplateResult => html` - ${content ? content : nothing} + ${content ?? nothing} ${linkContent ? html`${linkContent}` : nothing}
diff --git a/src/elements/teaser-product/teaser-product-static/readme.md b/src/elements/teaser-product/teaser-product-static/readme.md index 64707b6ee4..ca7550cb59 100644 --- a/src/elements/teaser-product/teaser-product-static/readme.md +++ b/src/elements/teaser-product/teaser-product-static/readme.md @@ -17,8 +17,8 @@ otherwise, see [sbb-teaser-product](/docs/elements-sbb-teaser-sbb-teaser-product ## Slots -Use the `image` slot to pass a `figure` containing an `sbb-image | img` that will be used as background. -Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure`. +Use the `image` slot to pass a `figure` containing an `sbb-image` or an `img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure` (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). Use the optional `footnote` slot to add a text anchored to the bottom-end of the component. diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts index bf8e3afae7..5ee37c4892 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts @@ -98,7 +98,7 @@ const Template = ({ withChip, withFooter, slottedImg, ...args }: Args): Template
${slottedImg - ? html`` + ? html`` : html``} ${withChip ? html`AI generated` diff --git a/src/elements/teaser-product/teaser-product/readme.md b/src/elements/teaser-product/teaser-product/readme.md index 194a0c85ca..d1168e1a94 100644 --- a/src/elements/teaser-product/teaser-product/readme.md +++ b/src/elements/teaser-product/teaser-product/readme.md @@ -18,8 +18,8 @@ If it has to include more than one interactive element, use the [sbb-teaser-prod ## Slots -Use the `image` slot to pass a `figure` containing an `sbb-image | img` that will be used as background. -Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure`. +Use the `image` slot to pass a `figure` containing an `sbb-image` or an `img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure` (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). Use the optional `footnote` slot to add a text anchored to the bottom-end of the component. diff --git a/src/elements/teaser-product/teaser-product/teaser-product.stories.ts b/src/elements/teaser-product/teaser-product/teaser-product.stories.ts index 9e561b4981..8acf87ab55 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.stories.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.stories.ts @@ -115,7 +115,7 @@ const Template = ({ withChip, withFooter, slottedImg, ...args }: Args): Template
${slottedImg - ? html`` + ? html`` : html``} ${withChip ? html`AI generated` diff --git a/src/elements/teaser/readme.md b/src/elements/teaser/readme.md index c18ffed67b..733ee2686c 100644 --- a/src/elements/teaser/readme.md +++ b/src/elements/teaser/readme.md @@ -21,8 +21,8 @@ Simple teaser example: The default slot is reserved for the description. The component displays the `image` and the `title` with the self-named slots. It's also possible to display a [sbb-chip-label](/docs/elements-sbb-chip-label--docs) using the `chip` slot. -Use the `image` slot to pass a `figure` containing an `sbb-image | img` that will be used as background. -Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure`. +Use the `image` slot to pass a `figure` containing an `sbb-image` or an `img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure` (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). ```html From d6debce396577c9f9cadfd85143377165e2b6936 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 20 Nov 2024 10:25:22 +0100 Subject: [PATCH 14/47] fix: review feedbacks --- src/elements/teaser-hero/teaser-hero.scss | 2 +- src/elements/teaser/teaser.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elements/teaser-hero/teaser-hero.scss b/src/elements/teaser-hero/teaser-hero.scss index 1a7c6ea2ec..1f627c5045 100644 --- a/src/elements/teaser-hero/teaser-hero.scss +++ b/src/elements/teaser-hero/teaser-hero.scss @@ -12,7 +12,7 @@ --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); --sbb-teaser-image-animation-duration: var( - --sbb-disable-animation-zero-time, + --sbb-disable-animation-zero-duration, var(--sbb-animation-duration-4x) ); --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); diff --git a/src/elements/teaser/teaser.scss b/src/elements/teaser/teaser.scss index 274e33e9c7..0bf970df73 100644 --- a/src/elements/teaser/teaser.scss +++ b/src/elements/teaser/teaser.scss @@ -19,7 +19,7 @@ --sbb-teaser-border-radius: var(--sbb-border-radius-4x); --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); --sbb-teaser-image-animation-duration: var( - --sbb-disable-animation-zero-time, + --sbb-disable-animation-zero-duration, var(--sbb-animation-duration-4x) ); --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); From 64e88ed5d849f1ee67508aa0f112df300202a139 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Fri, 29 Nov 2024 11:30:27 +0100 Subject: [PATCH 15/47] fix: pr feedbacks --- src/elements/core/styles/image.scss | 22 +++++++++++++++++----- src/elements/core/styles/mixins/image.scss | 7 +++++-- src/elements/image/image.ts | 7 +++---- src/elements/teaser-hero/readme.md | 2 -- src/elements/teaser-hero/teaser-hero.ts | 11 ----------- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/elements/core/styles/image.scss b/src/elements/core/styles/image.scss index 41d14c82e5..42d3a50ee4 100644 --- a/src/elements/core/styles/image.scss +++ b/src/elements/core/styles/image.scss @@ -4,18 +4,30 @@ .sbb-figure { @include image.figure; - img, - sbb-image, - .sbb-image { + :is(img, sbb-image, .sbb-image) { @include image.figure-image; } - figcaption, - .sbb-caption { + :is(figcaption, .sbb-caption) { @include image.figure-caption; } // Utility classes for placing elements over an image (eg. 'sbb-figure-overlap-start-start') + :is( + .sbb-figure-overlap-start-start, + .sbb-figure-overlap-start-center, + .sbb-figure-overlap-start-end, + .sbb-figure-overlap-center-start, + .sbb-figure-overlap-center-center, + .sbb-figure-overlap-center-end, + .sbb-figure-overlap-end-start, + .sbb-figure-overlap-end-center, + .sbb-figure-overlap-end-end, + + ) { + @include image.figure-overlap-base; + } + $alignments: start, center, end; @each $row-alignment in $alignments { @each $column-alignment in $alignments { diff --git a/src/elements/core/styles/mixins/image.scss b/src/elements/core/styles/mixins/image.scss index ae884ea0a7..a606c26d11 100644 --- a/src/elements/core/styles/mixins/image.scss +++ b/src/elements/core/styles/mixins/image.scss @@ -22,10 +22,13 @@ @include typo.text-xs--regular; } -@mixin figure-overlap($row-alignment, $column-alignment) { +@mixin figure-overlap-base { z-index: 1; grid-row: 1; grid-column: 1; - place-self: #{$row-alignment} #{$column-alignment}; margin: var(--sbb-spacing-responsive-xxxs); } + +@mixin figure-overlap($row-alignment, $column-alignment) { + place-self: #{$row-alignment} #{$column-alignment}; +} diff --git a/src/elements/image/image.ts b/src/elements/image/image.ts index 3e17c0af3f..2462be41f5 100644 --- a/src/elements/image/image.ts +++ b/src/elements/image/image.ts @@ -590,8 +590,8 @@ class SbbImageElement extends LitElement { const imageHeight = config.image.height; const imageWidth = config.image.width; const mediaQuery = this._createMediaQueryString(config.mediaQueries); - return [ - html` `, - ]; + >`; })} ${this.alt (c.color = 'charcoal')); } From 39c14699e6b8c361aea5109a5cfeb1963e79758c Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Fri, 29 Nov 2024 11:48:54 +0100 Subject: [PATCH 16/47] fix: pr feedbacks pt.2 --- src/elements/core/styles/image.scss | 21 +++++++++---------- .../teaser-hero/teaser-hero.stories.ts | 9 +------- src/storybook/pages/home/home.common.ts | 13 ++++++------ 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/src/elements/core/styles/image.scss b/src/elements/core/styles/image.scss index 42d3a50ee4..89ee607402 100644 --- a/src/elements/core/styles/image.scss +++ b/src/elements/core/styles/image.scss @@ -14,17 +14,16 @@ // Utility classes for placing elements over an image (eg. 'sbb-figure-overlap-start-start') :is( - .sbb-figure-overlap-start-start, - .sbb-figure-overlap-start-center, - .sbb-figure-overlap-start-end, - .sbb-figure-overlap-center-start, - .sbb-figure-overlap-center-center, - .sbb-figure-overlap-center-end, - .sbb-figure-overlap-end-start, - .sbb-figure-overlap-end-center, - .sbb-figure-overlap-end-end, - - ) { + .sbb-figure-overlap-start-start, + .sbb-figure-overlap-start-center, + .sbb-figure-overlap-start-end, + .sbb-figure-overlap-center-start, + .sbb-figure-overlap-center-center, + .sbb-figure-overlap-center-end, + .sbb-figure-overlap-end-start, + .sbb-figure-overlap-end-center, + .sbb-figure-overlap-end-end + ) { @include image.figure-overlap-base; } diff --git a/src/elements/teaser-hero/teaser-hero.stories.ts b/src/elements/teaser-hero/teaser-hero.stories.ts index ab3f21030b..9a48615c77 100644 --- a/src/elements/teaser-hero/teaser-hero.stories.ts +++ b/src/elements/teaser-hero/teaser-hero.stories.ts @@ -10,6 +10,7 @@ import sampleImages from '../core/images.js'; import readme from './readme.md?raw'; import './teaser-hero.js'; import '../chip-label.js'; +import '../image.js'; const accessibilityLabel: InputType = { control: { @@ -75,12 +76,6 @@ const imageSrc: InputType = { }, }; -const imageAlt: InputType = { - control: { - type: 'text', - }, -}; - const chipLabel: InputType = { control: { type: 'text', @@ -95,7 +90,6 @@ const defaultArgTypes: ArgTypes = { content, 'link-content': linkContent, 'image-src': imageSrc, - 'image-alt': imageAlt, 'chip-label': chipLabel, }; @@ -107,7 +101,6 @@ const defaultArgs: Args = { content: 'Break out and explore castles and palaces.', 'link-content': 'Find out more', 'image-src': sampleImages[1], - 'image-alt': 'SBB CFF FFS Employee', 'chip-label': undefined, }; diff --git a/src/storybook/pages/home/home.common.ts b/src/storybook/pages/home/home.common.ts index 5a72f68418..a173c99343 100644 --- a/src/storybook/pages/home/home.common.ts +++ b/src/storybook/pages/home/home.common.ts @@ -8,6 +8,7 @@ import '../../../elements/clock.js'; import '../../../elements/divider.js'; import '../../../elements/footer.js'; import '../../../elements/icon.js'; +import '../../../elements/image.js'; import '../../../elements/header.js'; import '../../../elements/logo.js'; import '../../../elements/link.js'; @@ -206,13 +207,13 @@ export const liberoProduct = (): TemplateResult => html` export const teaserHero = (): TemplateResult => html`
- + Considerate with SBB Green Class. +
+ +
`; From 56fc8aee6d81829aae07965f82fcfa8d4fdc0803 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Fri, 29 Nov 2024 14:54:11 +0100 Subject: [PATCH 17/47] test(sbb-flip-card): fix visual spec --- src/elements/flip-card/flip-card/flip-card.visual.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elements/flip-card/flip-card/flip-card.visual.spec.ts b/src/elements/flip-card/flip-card/flip-card.visual.spec.ts index 4b4cc92a4c..cf74cdfac0 100644 --- a/src/elements/flip-card/flip-card/flip-card.visual.spec.ts +++ b/src/elements/flip-card/flip-card/flip-card.visual.spec.ts @@ -111,7 +111,7 @@ describe(`sbb-flip-card`, () => { for (const imageAlignment of ['after', 'below']) { it( - `grid`, + `image-alignment=${imageAlignment}_grid`, visualDiffDefault.with(async (setup) => { await setup.withFixture( html`
Date: Tue, 3 Dec 2024 10:47:58 +0100 Subject: [PATCH 18/47] fix: pr feedbacks pt.1 --- src/elements/core/styles/core.scss | 12 ++++++------ src/elements/core/styles/image.scss | 7 +------ src/elements/image/image.stories.ts | 6 ++---- src/elements/teaser-hero/teaser-hero.spec.ts | 1 - src/elements/teaser-hero/teaser-hero.stories.ts | 12 ++++++------ 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index 5f0b7717c9..082212b6ce 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -156,7 +156,7 @@ input[data-sbb-time-input] { // Target the slotted `sbb-image` which are generally wrapped by a
(therefore are not reachable with the :slotted) // Apply the brightness effect on mouse hover -// TODO Move back to the teaser components when the global css refactoring happens +// TODO: Move back to the teaser components when the global css refactoring happens :is(sbb-teaser, sbb-teaser-hero, sbb-teaser-product) { & [slot='image']:is(sbb-image, img), & [slot='image'] :is(sbb-image, img) { @@ -167,7 +167,7 @@ input[data-sbb-time-input] { } } -// TODO Move back to the teaser components when the global css refactoring happens +// TODO: Move back to the teaser components when the global css refactoring happens :is(sbb-teaser-product, sbb-teaser-product-static) { // Reset sbb-image border radius in order to control it from teaser product. sbb-image { @@ -181,13 +181,13 @@ input[data-sbb-time-input] { } } -// TODO Move back to the teaser components when the global css refactoring happens +// TODO: Move back to the teaser components when the global css refactoring happens :is(sbb-teaser) { & [slot='image']:is(sbb-image, img), & [slot='image'] :is(sbb-image, img) { - transition-property: filter, transform; - will-change: filter, transform; - transform: scale(var(--sbb-teaser-scale, 1)); + transition-property: filter, scale; + will-change: filter, scale; + scale: var(--sbb-teaser-scale, 1); } sbb-image { diff --git a/src/elements/core/styles/image.scss b/src/elements/core/styles/image.scss index 89ee607402..3ce756cd47 100644 --- a/src/elements/core/styles/image.scss +++ b/src/elements/core/styles/image.scss @@ -15,19 +15,14 @@ // Utility classes for placing elements over an image (eg. 'sbb-figure-overlap-start-start') :is( .sbb-figure-overlap-start-start, - .sbb-figure-overlap-start-center, .sbb-figure-overlap-start-end, - .sbb-figure-overlap-center-start, - .sbb-figure-overlap-center-center, - .sbb-figure-overlap-center-end, .sbb-figure-overlap-end-start, - .sbb-figure-overlap-end-center, .sbb-figure-overlap-end-end ) { @include image.figure-overlap-base; } - $alignments: start, center, end; + $alignments: start, end; @each $row-alignment in $alignments { @each $column-alignment in $alignments { .sbb-figure-overlap-#{$row-alignment}-#{$column-alignment} { diff --git a/src/elements/image/image.stories.ts b/src/elements/image/image.stories.ts index 72e42e01f6..1b476fce6f 100644 --- a/src/elements/image/image.stories.ts +++ b/src/elements/image/image.stories.ts @@ -161,7 +161,6 @@ const defaultArgTypes: ArgTypes = { alt, borderRadius, aspectRatio, - chipPosition, 'custom-focal-point': customFocalPoint, 'focal-point-debug': focalPointDebug, 'focal-point-x': focalPointX, @@ -176,7 +175,6 @@ const defaultArgs: Args = { alt: '', borderRadius: borderRadius.options![0], aspectRatio: aspectRatio.options![0], - chipPosition: chipPosition.options![0], 'custom-focal-point': false, 'focal-point-debug': false, 'focal-point-x': '', @@ -232,8 +230,8 @@ export const SkipLqip: StoryObj = { export const WithChip: StoryObj = { render: WithChipTemplate, - argTypes: defaultArgTypes, - args: defaultArgs, + argTypes: { ...defaultArgTypes, chipPosition }, + args: { ...defaultArgs, chipPosition: chipPosition.options![0] }, }; const meta: Meta = { diff --git a/src/elements/teaser-hero/teaser-hero.spec.ts b/src/elements/teaser-hero/teaser-hero.spec.ts index cc13598778..bbbd890150 100644 --- a/src/elements/teaser-hero/teaser-hero.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.spec.ts @@ -41,7 +41,6 @@ describe(`sbb-teaser-hero`, () => {
`, ); - await waitForLitRender(element); const chip = element.querySelector('sbb-chip-label')!; const image = element.querySelector('sbb-image')!; diff --git a/src/elements/teaser-hero/teaser-hero.stories.ts b/src/elements/teaser-hero/teaser-hero.stories.ts index 9a48615c77..3a4edf1bcf 100644 --- a/src/elements/teaser-hero/teaser-hero.stories.ts +++ b/src/elements/teaser-hero/teaser-hero.stories.ts @@ -104,7 +104,7 @@ const defaultArgs: Args = { 'chip-label': undefined, }; -const TemplateSbbTeaserWithSlots = ({ +const Template = ({ content, 'chip-label': chipLabel, 'link-content': linkContent, @@ -127,7 +127,7 @@ const TemplateSbbTeaserWithSlots = ({ `; export const defaultTeaser: StoryObj = { - render: TemplateSbbTeaserWithSlots, + render: Template, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -135,7 +135,7 @@ export const defaultTeaser: StoryObj = { }; export const openInNewWindow: StoryObj = { - render: TemplateSbbTeaserWithSlots, + render: Template, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -144,7 +144,7 @@ export const openInNewWindow: StoryObj = { }; export const withChip: StoryObj = { - render: TemplateSbbTeaserWithSlots, + render: Template, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -153,7 +153,7 @@ export const withChip: StoryObj = { }; export const chipOnly: StoryObj = { - render: TemplateSbbTeaserWithSlots, + render: Template, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -165,7 +165,7 @@ export const chipOnly: StoryObj = { }; export const withSlots: StoryObj = { - render: TemplateSbbTeaserWithSlots, + render: Template, argTypes: defaultArgTypes, args: { ...defaultArgs, From a55826a3f1c6be6ae96960fd6f7e6aa3568e64f4 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 3 Dec 2024 10:58:13 +0100 Subject: [PATCH 19/47] refactor(sbb-image): removed dependency from teaser-hero --- src/elements/core/styles/core.scss | 12 ++++++++++++ src/elements/image/image.scss | 10 ---------- src/elements/image/image.ts | 7 ------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index 082212b6ce..af7d75c5b0 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -200,6 +200,18 @@ input[data-sbb-time-input] { } } +// TODO: Move back to the teaser-hero components when the global css refactoring happens +:is(sbb-teaser-hero) { + sbb-image { + --sbb-image-aspect-ratio: 1 / 1; + --sbb-image-border-radius: 0; + + @include mediaqueries.mq($from: small) { + --sbb-image-aspect-ratio: 16 / 9; + } + } +} + // TODO: move to train formation after css refactoring sbb-train-formation:has(sbb-train[direction-label]) { --sbb-train-formation-reserve-spacing-display: block; diff --git a/src/elements/image/image.scss b/src/elements/image/image.scss index 4cf0152751..8f86fa3fcf 100644 --- a/src/elements/image/image.scss +++ b/src/elements/image/image.scss @@ -15,16 +15,6 @@ display: block; } -// Variant: Hero Teaser and Paid Teaser -:host([data-teaser]) { - --sbb-image-aspect-ratio: 1 / 1; - --sbb-image-border-radius: 0; - - @include sbb.mq($from: small) { - --sbb-image-aspect-ratio: 16 / 9; - } -} - .sbb-image__img { opacity: 0.000001; diff --git a/src/elements/image/image.ts b/src/elements/image/image.ts index 2462be41f5..34a479bbcc 100644 --- a/src/elements/image/image.ts +++ b/src/elements/image/image.ts @@ -26,7 +26,6 @@ import { import { customElement, eventOptions, property } from 'lit/decorators.js'; import { forceType } from '../core/decorators.js'; -import { hostContext } from '../core/dom.js'; import style from './image.scss?lit&inline'; @@ -367,12 +366,6 @@ class SbbImageElement extends LitElement { return this.shadowRoot?.querySelector?.('.sbb-image__img')?.complete ?? false; } - public override connectedCallback(): void { - super.connectedCallback(); - // Check if the current element is nested in an `` element. - this.toggleAttribute('data-teaser', !!hostContext('sbb-teaser-hero', this)); - } - protected override updated(changedProperties: PropertyValues): void { super.updated(changedProperties); From 55a12dc1c525787f0789fb9fb4971d770baa8e66 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 3 Dec 2024 11:37:17 +0100 Subject: [PATCH 20/47] docs(sbb-image): only suggest to use 'figure' when needed --- src/elements/image/image.stories.ts | 23 +++------- src/elements/image/image.visual.spec.ts | 60 +++++++++---------------- src/elements/image/readme.md | 29 ++++++------ 3 files changed, 42 insertions(+), 70 deletions(-) diff --git a/src/elements/image/image.stories.ts b/src/elements/image/image.stories.ts index 1b476fce6f..27dd0a745d 100644 --- a/src/elements/image/image.stories.ts +++ b/src/elements/image/image.stories.ts @@ -12,12 +12,7 @@ import { SbbImageElement } from './image.js'; import readme from './readme.md?raw'; import '../chip-label.js'; -const imageTemplate = ({ - aspectRatio, - borderRadius, - _chipPosition, - ...args -}: Args): TemplateResult => html` +const ImageTemplate = ({ aspectRatio, borderRadius, ...args }: Args): TemplateResult => html` html`
- ${imageTemplate(args)} + ${ImageTemplate(args)}
With the html`
`; -const Template = (args: Args): TemplateResult => html` -
${imageTemplate(args)}
-`; - const WithChipTemplate = ({ chipPosition, ...args }: Args): TemplateResult => html`
- ${imageTemplate(args)} + ${ImageTemplate(args)} AI generated
`; @@ -192,7 +183,7 @@ export const Default: StoryObj = { }; export const TransparentImage: StoryObj = { - render: Template, + render: ImageTemplate, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -201,7 +192,7 @@ export const TransparentImage: StoryObj = { }; export const NoCaptionNoRadius: StoryObj = { - render: Template, + render: ImageTemplate, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -210,7 +201,7 @@ export const NoCaptionNoRadius: StoryObj = { }; export const RoundBorderRadius: StoryObj = { - render: Template, + render: ImageTemplate, argTypes: defaultArgTypes, args: { ...defaultArgs, @@ -220,7 +211,7 @@ export const RoundBorderRadius: StoryObj = { }; export const SkipLqip: StoryObj = { - render: Template, + render: ImageTemplate, argTypes: defaultArgTypes, args: { ...defaultArgs, diff --git a/src/elements/image/image.visual.spec.ts b/src/elements/image/image.visual.spec.ts index b39b9063df..99b4d208bf 100644 --- a/src/elements/image/image.visual.spec.ts +++ b/src/elements/image/image.visual.spec.ts @@ -29,9 +29,7 @@ describe(`sbb-image`, () => { `aspect-ratio=${aspectRatio}`, visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- -
`, + html``, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -43,13 +41,11 @@ describe(`sbb-image`, () => { `aspect-ratio=free`, visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- -
`, + html``, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -61,12 +57,10 @@ describe(`sbb-image`, () => { `border-radius=${borderRadius}`, visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- -
`, + html``, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -97,11 +91,7 @@ describe(`sbb-image`, () => { it( 'transparent image from img cdn', visualDiffDefault.with(async (setup) => { - await setup.withFixture( - html`
- -
`, - ); + await setup.withFixture(html``); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); }), @@ -111,9 +101,7 @@ describe(`sbb-image`, () => { 'cropped', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- -
`, + html``, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -138,12 +126,10 @@ describe(`sbb-image`, () => { 'cropped with object-position', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- -
`, + html``, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -154,12 +140,10 @@ describe(`sbb-image`, () => { 'cropped with object-fit', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- -
`, + html``, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); @@ -170,9 +154,7 @@ describe(`sbb-image`, () => { 'skipLqip=true', visualDiffDefault.with(async (setup) => { await setup.withFixture( - html`
- -
`, + html``, ); await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); diff --git a/src/elements/image/readme.md b/src/elements/image/readme.md index 42eb103ad8..455be69359 100644 --- a/src/elements/image/readme.md +++ b/src/elements/image/readme.md @@ -3,11 +3,14 @@ The `sbb-image` component is used to render an image. Mainly from cdn.img.sbb.ch (with `imageSrc`), but we can set an external image too. The size can be set with `pictureSizesConfig`. -## Usage +```html + +``` -In general, it is strongly recommended to wrap an `sbb-image` and all its related elements in a `figure` tag. +## Usage -It is possible to add a caption and/or the copyright using the `figcaption`. +For image related elements, it is strongly recommended to wrap an `sbb-image` and all its related elements in a `figure` tag. +E.g. `
` or ``. ```html
@@ -16,8 +19,6 @@ It is possible to add a caption and/or the copyright using the `figcaption`.
``` -### Utility classes - You can place overlapping content by using the `sbb-figure-overlap-${horizontal-alignment}-${vertical-alignment}` utility classes. ```html @@ -27,24 +28,22 @@ You can place overlapping content by using the `sbb-figure-overlap-${horizontal-
``` +### Utility classes + Use the `sbb-image-border-radius-${value}` utility classes to set the image border radius. Available values: `default`, `none` and `round` ```html -
- - - -
+ + + ``` Use the `sbb-image-${value}` utility classes to set the image aspect ratio. Available values: `free`, `1-1`, `2-3`, `3-2` ... `9-16`, `16-9` ```html -
- - - -
+ + + ``` From 09a5bb02083ca421d24a0b21c01900130e491669 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 3 Dec 2024 12:10:43 +0100 Subject: [PATCH 21/47] docs(sbb-teaser-hero): only suggest to use 'figure' when needed --- src/elements/teaser-hero/readme.md | 13 +++++++++++-- src/elements/teaser-hero/teaser-hero.stories.ts | 16 ++++++++-------- .../teaser-hero/teaser-hero.visual.spec.ts | 11 ++--------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/elements/teaser-hero/readme.md b/src/elements/teaser-hero/readme.md index e2f4151f09..56cee4aff1 100644 --- a/src/elements/teaser-hero/readme.md +++ b/src/elements/teaser-hero/readme.md @@ -6,8 +6,17 @@ it should be an eye-catcher and should have an emotional effect on the user with It is possible to provide the panel label via an unnamed slot, while the link text can be provided using the `link-content` slot or the `linkContent` property; -Use the `image` slot to pass a `figure` containing an `sbb-image` or an `img` that will be used as background. -Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure` (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). +Use the `image` slot to pass an `sbb-image` or an `img` that will be used as background. + +```html + + Break out and explore castles and palaces. + Find out more + + +``` + +Optionally, you can add an overlapping `sbb-chip-label` by wrapping the `sbb-image` in a `figure` tag (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). ```html diff --git a/src/elements/teaser-hero/teaser-hero.stories.ts b/src/elements/teaser-hero/teaser-hero.stories.ts index 3a4edf1bcf..08b574d245 100644 --- a/src/elements/teaser-hero/teaser-hero.stories.ts +++ b/src/elements/teaser-hero/teaser-hero.stories.ts @@ -115,14 +115,14 @@ const Template = ({ ${content ?? nothing} ${linkContent ? html`${linkContent}` : nothing} - -
- - - ${chipLabel - ? html`${chipLabel}` - : nothing} -
+ ${!chipLabel + ? html`` + : html` +
+ + ${chipLabel} +
+ `}
`; diff --git a/src/elements/teaser-hero/teaser-hero.visual.spec.ts b/src/elements/teaser-hero/teaser-hero.visual.spec.ts index dde96f9cd2..33d4625e62 100644 --- a/src/elements/teaser-hero/teaser-hero.visual.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.visual.spec.ts @@ -45,11 +45,7 @@ describe(`sbb-teaser-hero`, () => { Break out and explore castles and palaces. Find out more - -
- - Label -
+
`); @@ -62,10 +58,7 @@ describe(`sbb-teaser-hero`, () => { state.with(async (setup) => { await setup.withFixture(html` -
- - Label -
+
`); From eadd6754d963e4aa4a1d093c2b01c36fde6f5325 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 3 Dec 2024 12:34:03 +0100 Subject: [PATCH 22/47] docs(sbb-teaser-product, sbb-teaser-product-static): only use 'figure' when needed --- .../teaser-product-static/readme.md | 12 +++----- .../teaser-product-static.stories.ts | 28 +++++++++--------- .../teaser-product-static.visual.spec.ts | 29 +++++++++++++++---- .../teaser-product/teaser-product/readme.md | 12 +++----- .../teaser-product/teaser-product.stories.ts | 27 +++++++++-------- .../teaser-product.visual.spec.ts | 29 +++++++++++++++---- 6 files changed, 81 insertions(+), 56 deletions(-) diff --git a/src/elements/teaser-product/teaser-product-static/readme.md b/src/elements/teaser-product/teaser-product-static/readme.md index ca7550cb59..ff73fa8ea5 100644 --- a/src/elements/teaser-product/teaser-product-static/readme.md +++ b/src/elements/teaser-product/teaser-product-static/readme.md @@ -5,9 +5,7 @@ otherwise, see [sbb-teaser-product](/docs/elements-sbb-teaser-sbb-teaser-product ```html -
- -
+

Content ...

@@ -17,8 +15,8 @@ otherwise, see [sbb-teaser-product](/docs/elements-sbb-teaser-sbb-teaser-product ## Slots -Use the `image` slot to pass a `figure` containing an `sbb-image` or an `img` that will be used as background. -Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure` (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). +Use the `image` slot to pass an `sbb-image` or an `img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` by wrapping the `sbb-image` in a `figure` tag (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). Use the optional `footnote` slot to add a text anchored to the bottom-end of the component. @@ -41,9 +39,7 @@ to display the components with the correct spacings. ```html -
- -
+ Benefit from up to 70% discount diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts index 5ee37c4892..58d1894bdb 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts @@ -42,12 +42,6 @@ const withFooter: InputType = { }, }; -const withChip: InputType = { - control: { - type: 'boolean', - }, -}; - const slottedImg: InputType = { control: { type: 'boolean', @@ -58,7 +52,6 @@ const defaultArgTypes: ArgTypes = { 'image-alignment': imageAlignment, negative, withFooter, - withChip, slottedImg, }; @@ -66,7 +59,6 @@ const defaultArgs: Args = { 'image-alignment': imageAlignment.options![0], negative: false, withFooter: true, - withChip: false, slottedImg: false, }; @@ -94,15 +86,23 @@ const footer = (): TemplateResult => html`

`; -const Template = ({ withChip, withFooter, slottedImg, ...args }: Args): TemplateResult => html` +const Template = ({ withFooter, slottedImg, ...args }: Args): TemplateResult => html` + + ${slottedImg + ? html`` + : html``} + ${content()} ${withFooter ? footer() : nothing} + +`; + +const WithChipTemplate = ({ withFooter, slottedImg, ...args }: Args): TemplateResult => html`
${slottedImg ? html`` : html``} - ${withChip - ? html`AI generated` - : nothing} + + AI generated
${content()} ${withFooter ? footer() : nothing}
@@ -139,9 +139,9 @@ export const SlottedImg: StoryObj = { }; export const WithChip: StoryObj = { - render: Template, + render: WithChipTemplate, argTypes: defaultArgTypes, - args: { ...defaultArgs, withChip: true }, + args: { ...defaultArgs }, }; const meta: Meta = { diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts index 5ab59845e8..2a287f5a24 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts @@ -51,23 +51,40 @@ const template = ({ showFooter, slottedImg, longContent, - withChip, }: { negative?: boolean; imageAlignment?: string; showFooter?: boolean; slottedImg?: boolean; longContent?: boolean; - withChip?: boolean; +} = {}): TemplateResult => html` + + ${slottedImg + ? html`` + : html``} + ${content(longContent)} ${showFooter ? footer() : nothing} + +`; + +const withChipTemplate = ({ + negative, + imageAlignment, + showFooter, + slottedImg, + longContent, +}: { + negative?: boolean; + imageAlignment?: string; + showFooter?: boolean; + slottedImg?: boolean; + longContent?: boolean; } = {}): TemplateResult => html`
${slottedImg ? html`` : html``} - ${withChip - ? html`Label` - : nothing} + Label
${content(longContent)} ${showFooter ? footer() : nothing}
@@ -96,7 +113,7 @@ describe('sbb-teaser-product-static', () => { `withChip_${visualState.name}`, visualState.with(async (setup) => { await setup.withFixture( - template({ negative, showFooter: true, slottedImg, withChip: true }), + withChipTemplate({ negative, showFooter: true, slottedImg }), { backgroundColor: negative ? 'var(--sbb-color-black)' : undefined, }, diff --git a/src/elements/teaser-product/teaser-product/readme.md b/src/elements/teaser-product/teaser-product/readme.md index d1168e1a94..6d170b7953 100644 --- a/src/elements/teaser-product/teaser-product/readme.md +++ b/src/elements/teaser-product/teaser-product/readme.md @@ -6,9 +6,7 @@ If it has to include more than one interactive element, use the [sbb-teaser-prod ```html -
- -
+

Content ...

@@ -18,8 +16,8 @@ If it has to include more than one interactive element, use the [sbb-teaser-prod ## Slots -Use the `image` slot to pass a `figure` containing an `sbb-image` or an `img` that will be used as background. -Optionally, you can add an overlapping `sbb-chip-label` to the slotted `figure` (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). +Use the `image` slot to pass an `sbb-image` or an `img` that will be used as background. +Optionally, you can add an overlapping `sbb-chip-label` by wrapping the `sbb-image` in a `figure` tag (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). Use the optional `footnote` slot to add a text anchored to the bottom-end of the component. @@ -42,9 +40,7 @@ to display the components with the correct spacings. ```html -
- -
+ Benefit from up to 70% discount diff --git a/src/elements/teaser-product/teaser-product/teaser-product.stories.ts b/src/elements/teaser-product/teaser-product/teaser-product.stories.ts index 5c523270fc..b0a1fac33f 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.stories.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.stories.ts @@ -40,12 +40,6 @@ const withFooter: InputType = { }, }; -const withChip: InputType = { - control: { - type: 'boolean', - }, -}; - const slottedImg: InputType = { control: { type: 'boolean', @@ -74,7 +68,6 @@ const defaultArgTypes: ArgTypes = { 'image-alignment': imageAlignment, negative, withFooter, - withChip, slottedImg, href, 'accessibility-label': accessibilityLabel, @@ -84,7 +77,6 @@ const defaultArgs: Args = { 'image-alignment': imageAlignment.options![0], negative: false, withFooter: true, - withChip: false, slottedImg: false, href: 'https://www.sbb.ch', 'accessibility-label': 'Benefit from up to 70% discount, Follow the link to benefit.', @@ -111,15 +103,22 @@ const footer = (): TemplateResult => html`

`; -const Template = ({ withChip, withFooter, slottedImg, ...args }: Args): TemplateResult => html` +const Template = ({ withFooter, slottedImg, ...args }: Args): TemplateResult => html` + + ${slottedImg + ? html`` + : html``} + ${content()} ${withFooter ? footer() : nothing} + +`; + +const WithChipTemplate = ({ withFooter, slottedImg, ...args }: Args): TemplateResult => html`
${slottedImg ? html`` : html``} - ${withChip - ? html`AI generated` - : nothing} + AI generated
${content()} ${withFooter ? footer() : nothing}
@@ -156,9 +155,9 @@ export const SlottedImg: StoryObj = { }; export const WithChip: StoryObj = { - render: Template, + render: WithChipTemplate, argTypes: defaultArgTypes, - args: { ...defaultArgs, withChip: true }, + args: { ...defaultArgs }, }; const meta: Meta = { diff --git a/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts b/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts index 314e780473..c233478b93 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts @@ -47,23 +47,40 @@ const template = ({ showFooter, slottedImg, longContent, - withChip, }: { negative?: boolean; imageAlignment?: string; showFooter?: boolean; slottedImg?: boolean; longContent?: boolean; - withChip?: boolean; +} = {}): TemplateResult => html` + + ${slottedImg + ? html`` + : html``} + ${content(longContent)} ${showFooter ? footer() : nothing} + +`; + +const withChipTemplate = ({ + negative, + imageAlignment, + showFooter, + slottedImg, + longContent, +}: { + negative?: boolean; + imageAlignment?: string; + showFooter?: boolean; + slottedImg?: boolean; + longContent?: boolean; } = {}): TemplateResult => html`
${slottedImg ? html`` : html``} - ${withChip - ? html`Label` - : nothing} + Label
${content(longContent)} ${showFooter ? footer() : nothing}
@@ -92,7 +109,7 @@ describe('sbb-teaser-product', () => { `withChip_${visualState.name}`, visualState.with(async (setup) => { await setup.withFixture( - template({ negative, showFooter: true, slottedImg, withChip: true }), + withChipTemplate({ negative, showFooter: true, slottedImg }), { backgroundColor: negative ? 'var(--sbb-color-black)' : undefined, }, From 714be9c0adfaf016bccf82d629f7207e24c2cc0a Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 3 Dec 2024 12:35:50 +0100 Subject: [PATCH 23/47] fix: pr feedbacks pt.2 --- .../__snapshots__/teaser-hero.snapshot.spec.snap.js | 5 +---- src/storybook/pages/home/home.common.ts | 9 ++++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js b/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js index 0615e65c0e..368976b45f 100644 --- a/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js +++ b/src/elements/teaser-hero/__snapshots__/teaser-hero.snapshot.spec.snap.js @@ -17,10 +17,7 @@ snapshots["sbb-teaser-hero renders DOM"] = class="sbb-figure" slot="image" > - + html`
Considerate with SBB Green Class. -
- -
+
`; From b7ed26c6cfdae23ca20ae2b550d3a232a3b5ac52 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 3 Dec 2024 13:00:47 +0100 Subject: [PATCH 24/47] fix: pr feedbacks pt.3 --- src/elements/core/styles/core.scss | 7 +++++++ src/elements/teaser-hero/teaser-hero.scss | 7 ------- .../teaser-product/teaser-product/teaser-product.scss | 6 ------ src/elements/teaser/teaser.scss | 6 ------ 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index af7d75c5b0..e649fa7f96 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -158,6 +158,13 @@ input[data-sbb-time-input] { // Apply the brightness effect on mouse hover // TODO: Move back to the teaser components when the global css refactoring happens :is(sbb-teaser, sbb-teaser-hero, sbb-teaser-product) { + --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); + --sbb-teaser-image-animation-duration: var( + --sbb-disable-animation-zero-duration, + var(--sbb-animation-duration-4x) + ); + --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); + & [slot='image']:is(sbb-image, img), & [slot='image'] :is(sbb-image, img) { will-change: filter; diff --git a/src/elements/teaser-hero/teaser-hero.scss b/src/elements/teaser-hero/teaser-hero.scss index 1f627c5045..182283b055 100644 --- a/src/elements/teaser-hero/teaser-hero.scss +++ b/src/elements/teaser-hero/teaser-hero.scss @@ -10,13 +10,6 @@ // which appears in normalize css of several frameworks. outline: none !important; - --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); - --sbb-teaser-image-animation-duration: var( - --sbb-disable-animation-zero-duration, - var(--sbb-animation-duration-4x) - ); - --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); - @include sbb.panel-variables; } diff --git a/src/elements/teaser-product/teaser-product/teaser-product.scss b/src/elements/teaser-product/teaser-product/teaser-product.scss index 680fd08905..b47cb2dde0 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.scss +++ b/src/elements/teaser-product/teaser-product/teaser-product.scss @@ -1,12 +1,6 @@ @use '../../core/styles' as sbb; :host { - --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); - --sbb-teaser-image-animation-duration: var( - --sbb-disable-animation-zero-duration, - var(--sbb-animation-duration-4x) - ); - --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); --sbb-teaser-product-border-radius: var(--sbb-border-radius-4x); // Simulate link color optically diff --git a/src/elements/teaser/teaser.scss b/src/elements/teaser/teaser.scss index 4001370ad4..c793df135d 100644 --- a/src/elements/teaser/teaser.scss +++ b/src/elements/teaser/teaser.scss @@ -17,12 +17,6 @@ --sbb-teaser-gap: var(--sbb-spacing-fixed-4x); --sbb-teaser-width: fit-content; --sbb-teaser-border-radius: var(--sbb-border-radius-4x); - --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); - --sbb-teaser-image-animation-duration: var( - --sbb-disable-animation-zero-duration, - var(--sbb-animation-duration-4x) - ); - --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); @include sbb.if-forced-colors { --sbb-teaser-description-color: LinkText; From ba3bee8dc4291437aa24ddb87afdfec3b9a5190a Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 3 Dec 2024 14:19:16 +0100 Subject: [PATCH 25/47] fix: pr feedbacks pt.4 --- src/elements/teaser-hero/teaser-hero.spec.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/elements/teaser-hero/teaser-hero.spec.ts b/src/elements/teaser-hero/teaser-hero.spec.ts index bbbd890150..ce02d210af 100644 --- a/src/elements/teaser-hero/teaser-hero.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.spec.ts @@ -4,7 +4,6 @@ import { html } from 'lit/static-html.js'; import type { SbbChipLabelElement } from '../chip-label.js'; import { fixture } from '../core/testing/private.js'; import { waitForLitRender } from '../core/testing.js'; -import type { SbbImageElement } from '../image.js'; import { SbbTeaserHeroElement } from './teaser-hero.js'; import '../chip-label.js'; @@ -43,9 +42,7 @@ describe(`sbb-teaser-hero`, () => { ); const chip = element.querySelector('sbb-chip-label')!; - const image = element.querySelector('sbb-image')!; expect(chip).to.have.attribute('color', 'charcoal'); - expect(image).to.have.attribute('data-teaser'); }); }); From 68b0175eff48c38eef89d04b7c28e60204453487 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 3 Dec 2024 15:55:41 +0100 Subject: [PATCH 26/47] fix: pr feedbacks pt.5 --- src/elements/core/styles/mixins/image.scss | 3 ++- .../teaser-product/common/teaser-product-common.scss | 4 ++++ .../teaser-product-static.stories.ts | 8 +++++++- .../teaser-product-static.visual.spec.ts | 4 ++-- .../teaser-product/teaser-product.stories.ts | 8 +++++++- 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/elements/core/styles/mixins/image.scss b/src/elements/core/styles/mixins/image.scss index a606c26d11..b3ccd25b3e 100644 --- a/src/elements/core/styles/mixins/image.scss +++ b/src/elements/core/styles/mixins/image.scss @@ -23,7 +23,8 @@ } @mixin figure-overlap-base { - z-index: 1; + position: relative; + order: 1; // Alternative to z-index grid-row: 1; grid-column: 1; margin: var(--sbb-spacing-responsive-xxxs); diff --git a/src/elements/teaser-product/common/teaser-product-common.scss b/src/elements/teaser-product/common/teaser-product-common.scss index 262a59d129..c65182595b 100644 --- a/src/elements/teaser-product/common/teaser-product-common.scss +++ b/src/elements/teaser-product/common/teaser-product-common.scss @@ -63,6 +63,10 @@ margin-block-start: var(--sbb-spacing-responsive-xxs); } +::slotted([slot='image']) { + height: 100%; +} + .sbb-teaser-product__root { @include sbb.if-forced-colors { // Apply a visual border for forced color mode diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts index 58d1894bdb..8deccd21b1 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.stories.ts @@ -102,7 +102,13 @@ const WithChipTemplate = ({ withFooter, slottedImg, ...args }: Args): TemplateRe ? html`` : html``} - AI generated + + AI generated +
${content()} ${withFooter ? footer() : nothing}
diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts index 2a287f5a24..07c838a9b9 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts @@ -60,8 +60,8 @@ const template = ({ } = {}): TemplateResult => html` ${slottedImg - ? html`` - : html``} + ? html`` + : html``} ${content(longContent)} ${showFooter ? footer() : nothing} `; diff --git a/src/elements/teaser-product/teaser-product/teaser-product.stories.ts b/src/elements/teaser-product/teaser-product/teaser-product.stories.ts index b0a1fac33f..ac5f7c8317 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.stories.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.stories.ts @@ -118,7 +118,13 @@ const WithChipTemplate = ({ withFooter, slottedImg, ...args }: Args): TemplateRe ${slottedImg ? html`` : html``} - AI generated + + AI generated +
${content()} ${withFooter ? footer() : nothing} From d74e7a0bb525b88c06263034d5b7ab203237ad56 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 4 Dec 2024 09:40:09 +0100 Subject: [PATCH 27/47] fix(sbb-teaser-product): fix visual spec --- .../teaser-product/common/teaser-product-common.scss | 1 + .../teaser-product-static.visual.spec.ts | 7 ++++++- .../teaser-product/teaser-product.visual.spec.ts | 7 ++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/elements/teaser-product/common/teaser-product-common.scss b/src/elements/teaser-product/common/teaser-product-common.scss index c65182595b..a2955bb60d 100644 --- a/src/elements/teaser-product/common/teaser-product-common.scss +++ b/src/elements/teaser-product/common/teaser-product-common.scss @@ -64,6 +64,7 @@ } ::slotted([slot='image']) { + display: block; height: 100%; } diff --git a/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts b/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts index 07c838a9b9..dd5c87255c 100644 --- a/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts +++ b/src/elements/teaser-product/teaser-product-static/teaser-product-static.visual.spec.ts @@ -84,7 +84,12 @@ const withChipTemplate = ({ ${slottedImg ? html`` : html``} - Label + Label
${content(longContent)} ${showFooter ? footer() : nothing} diff --git a/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts b/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts index c233478b93..cedb15c592 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts +++ b/src/elements/teaser-product/teaser-product/teaser-product.visual.spec.ts @@ -80,7 +80,12 @@ const withChipTemplate = ({ ${slottedImg ? html`` : html``} - Label + Label
${content(longContent)} ${showFooter ? footer() : nothing} From b321a86d33a2fb4f075442e1876d32484dda21b5 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 4 Dec 2024 10:17:39 +0100 Subject: [PATCH 28/47] fix(sbb-teaser-hero): fix support of img slotting --- src/elements/core/styles/core.scss | 12 ++++++++++++ .../teaser-hero/teaser-hero.visual.spec.ts | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index e649fa7f96..ac67931b33 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -217,6 +217,18 @@ input[data-sbb-time-input] { --sbb-image-aspect-ratio: 16 / 9; } } + + img { + --sbb-image-aspect-ratio: 1 / 1; + + width: 100%; + display: block; + aspect-ratio: var(--sbb-image-aspect-ratio); + + @include mediaqueries.mq($from: small) { + --sbb-image-aspect-ratio: 16 / 9; + } + } } // TODO: move to train formation after css refactoring diff --git a/src/elements/teaser-hero/teaser-hero.visual.spec.ts b/src/elements/teaser-hero/teaser-hero.visual.spec.ts index 33d4625e62..5cc7cb0a31 100644 --- a/src/elements/teaser-hero/teaser-hero.visual.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.visual.spec.ts @@ -2,6 +2,7 @@ import { html } from 'lit'; import { describeViewports, + loadAssetAsBase64, visualDiffDefault, visualDiffFocus, visualDiffHover, @@ -12,6 +13,7 @@ import '../image.js'; import '../chip-label.js'; const imageUrl = import.meta.resolve('../core/testing/assets/placeholder-image.png'); +const imageBase64 = await loadAssetAsBase64(imageUrl); describe(`sbb-teaser-hero`, () => { describeViewports({ viewports: ['zero', 'micro', 'small', 'medium', 'wide'] }, () => { @@ -53,6 +55,21 @@ describe(`sbb-teaser-hero`, () => { }), ); + it( + `slotted-image ${state.name}`, + state.with(async (setup) => { + await setup.withFixture(html` + + Break out and explore castles and palaces. + Find out more + + + `); + + await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); + }), + ); + it( `without content ${state.name}`, state.with(async (setup) => { From fecce08893c3d3c318a3996c2841622500d461ee Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 4 Dec 2024 10:24:56 +0100 Subject: [PATCH 29/47] fix: pr feedbacks pt.6 --- src/elements/core/styles/core.scss | 6 ++++++ src/elements/teaser-hero/teaser-hero.scss | 1 - .../teaser-product/teaser-product/teaser-product.scss | 6 ------ src/elements/teaser/teaser.scss | 1 - 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index ac67931b33..a5e2a65eb9 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -165,6 +165,12 @@ input[data-sbb-time-input] { ); --sbb-teaser-image-animation-easing: var(--sbb-animation-easing); + &:hover { + @include mediaqueries.hover-mq($hover: true) { + --sbb-teaser-image-brightness: var(--sbb-teaser-image-brightness-hover); + } + } + & [slot='image']:is(sbb-image, img), & [slot='image'] :is(sbb-image, img) { will-change: filter; diff --git a/src/elements/teaser-hero/teaser-hero.scss b/src/elements/teaser-hero/teaser-hero.scss index 182283b055..8f7c96b17f 100644 --- a/src/elements/teaser-hero/teaser-hero.scss +++ b/src/elements/teaser-hero/teaser-hero.scss @@ -16,7 +16,6 @@ @include sbb.hover-mq($hover: true) { :host(:hover) { --sbb-panel-background-color: var(--sbb-panel-background-color-hover); - --sbb-teaser-image-brightness: var(--sbb-teaser-image-brightness-hover); } } diff --git a/src/elements/teaser-product/teaser-product/teaser-product.scss b/src/elements/teaser-product/teaser-product/teaser-product.scss index b47cb2dde0..3f48795931 100644 --- a/src/elements/teaser-product/teaser-product/teaser-product.scss +++ b/src/elements/teaser-product/teaser-product/teaser-product.scss @@ -11,12 +11,6 @@ } } -:host(:hover) { - @include sbb.hover-mq($hover: true) { - --sbb-teaser-image-brightness: var(--sbb-teaser-image-brightness-hover); - } -} - .sbb-teaser-product__wrapper { position: relative; } diff --git a/src/elements/teaser/teaser.scss b/src/elements/teaser/teaser.scss index c793df135d..8cc5dceaaf 100644 --- a/src/elements/teaser/teaser.scss +++ b/src/elements/teaser/teaser.scss @@ -37,7 +37,6 @@ @include sbb.hover-mq($hover: true) { :host(:hover) { - --sbb-teaser-image-brightness: var(--sbb-teaser-image-brightness-hover); --sbb-teaser-scale: var(--sbb-teaser-scale-hover); } } From 761055892c8e52721833a1dd8a96162e0e0ffbfe Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 4 Dec 2024 11:19:06 +0100 Subject: [PATCH 30/47] chore: empty commit From 448f856fee4e44d465ff040bf075805fc270323a Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 4 Dec 2024 11:50:52 +0100 Subject: [PATCH 31/47] fix(sbb-teaser-hero): fix visual spec --- .../teaser-hero/teaser-hero.visual.spec.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/elements/teaser-hero/teaser-hero.visual.spec.ts b/src/elements/teaser-hero/teaser-hero.visual.spec.ts index 5cc7cb0a31..75995fe282 100644 --- a/src/elements/teaser-hero/teaser-hero.visual.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.visual.spec.ts @@ -32,11 +32,7 @@ describe(`sbb-teaser-hero`, () => { `); - await waitForImageReady( - setup.snapshotElement - .querySelector('sbb-teaser-hero')! - .shadowRoot!.querySelector('sbb-image')!, - ); + await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); }), ); @@ -66,7 +62,7 @@ describe(`sbb-teaser-hero`, () => { `); - await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); + await waitForImageReady(setup.snapshotElement.querySelector('img')!); }), ); @@ -79,11 +75,7 @@ describe(`sbb-teaser-hero`, () => { `); - await waitForImageReady( - setup.snapshotElement - .querySelector('sbb-teaser-hero')! - .shadowRoot!.querySelector('sbb-image')!, - ); + await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); }), ); } From 38f8dd1a859ea19e5daa45943615f4929f563e49 Mon Sep 17 00:00:00 2001 From: Jeremias Peier Date: Wed, 4 Dec 2024 15:29:13 +0100 Subject: [PATCH 32/47] fix: move border radius to host --- src/elements/container/container/container.scss | 5 +---- src/elements/core/styles/core.scss | 5 +++-- src/elements/core/styles/image.scss | 12 ++---------- .../flip-card-summary/flip-card-summary.scss | 12 ++++++------ .../image/__snapshots__/image.snapshot.spec.snap.js | 4 ---- src/elements/image/image.scss | 5 ++--- src/elements/image/image.ts | 2 -- src/elements/image/readme.md | 11 +++++------ src/elements/lead-container/lead-container.scss | 3 ++- 9 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/elements/container/container/container.scss b/src/elements/container/container/container.scss index 27b441d9eb..3b2a499f35 100644 --- a/src/elements/container/container/container.scss +++ b/src/elements/container/container/container.scss @@ -62,15 +62,12 @@ } ::slotted([slot='image']) { - --sbb-image-border-radius: 0; - + border-radius: 0; position: absolute; inset: 0; :host(:not([expanded], [background-expanded])) & { @include sbb.mq($from: ultra) { - --sbb-image-border-radius: var(--sbb-border-radius-4x); - border-radius: var(--sbb-border-radius-4x); } } diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index a5e2a65eb9..9be4442122 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -184,7 +184,7 @@ input[data-sbb-time-input] { :is(sbb-teaser-product, sbb-teaser-product-static) { // Reset sbb-image border radius in order to control it from teaser product. sbb-image { - --sbb-image-border-radius: 0; + border-radius: 0; } img { @@ -217,7 +217,8 @@ input[data-sbb-time-input] { :is(sbb-teaser-hero) { sbb-image { --sbb-image-aspect-ratio: 1 / 1; - --sbb-image-border-radius: 0; + + border-radius: 0; @include mediaqueries.mq($from: small) { --sbb-image-aspect-ratio: 16 / 9; diff --git a/src/elements/core/styles/image.scss b/src/elements/core/styles/image.scss index 3ce756cd47..6e241fa2db 100644 --- a/src/elements/core/styles/image.scss +++ b/src/elements/core/styles/image.scss @@ -68,15 +68,7 @@ $border-radius: ( 'round': 'var(--sbb-border-radius-infinity)', ); @each $name, $radius in $border-radius { - sbb-image { - &.sbb-image-border-radius-#{$name} { - --sbb-image-border-radius: #{$radius}; - } - } - - img { - &.sbb-image-border-radius-#{$name} { - border-radius: #{$radius}; - } + :is(img, sbb-image).sbb-image-border-radius-#{$name} { + border-radius: #{$radius}; } } diff --git a/src/elements/flip-card/flip-card-summary/flip-card-summary.scss b/src/elements/flip-card/flip-card-summary/flip-card-summary.scss index 64699826c4..8c44281a11 100644 --- a/src/elements/flip-card/flip-card-summary/flip-card-summary.scss +++ b/src/elements/flip-card/flip-card-summary/flip-card-summary.scss @@ -74,16 +74,16 @@ } } -::slotted(img) { - object-fit: cover; +::slotted(:is(img, sbb-image)) { + border-radius: 0; width: 100%; height: 100%; } +::slotted(img) { + object-fit: cover; +} + ::slotted(sbb-image) { - --sbb-image-border-radius: 0; --sbb-image-aspect-ratio: auto; - - width: 100%; - height: 100%; } diff --git a/src/elements/image/__snapshots__/image.snapshot.spec.snap.js b/src/elements/image/__snapshots__/image.snapshot.spec.snap.js index a2ed420dcf..e5e10acbaf 100644 --- a/src/elements/image/__snapshots__/image.snapshot.spec.snap.js +++ b/src/elements/image/__snapshots__/image.snapshot.spec.snap.js @@ -13,9 +13,7 @@ snapshots["sbb-image should render Shadow DOM"] = alt="" class="sbb-image__blurred" decoding="auto" - height="562" loading="eager" - width="1000" > diff --git a/src/elements/image/image.scss b/src/elements/image/image.scss index 8f86fa3fcf..47c6f8825c 100644 --- a/src/elements/image/image.scss +++ b/src/elements/image/image.scss @@ -4,7 +4,6 @@ @include sbb.box-sizing; :host { - --sbb-image-border-radius: var(--sbb-border-radius-4x); --sbb-image-aspect-ratio: 16 / 9; --sbb-image-animation-duration: var( --sbb-disable-animation-zero-duration, @@ -13,6 +12,8 @@ --sbb-image-object-fit: cover; display: block; + border-radius: var(--sbb-border-radius-4x); + overflow: hidden; } .sbb-image__img { @@ -53,9 +54,7 @@ picture { .sbb-image__wrapper { display: flex; position: relative; - overflow: hidden; width: 100%; height: 100%; aspect-ratio: var(--sbb-image-aspect-ratio); - border-radius: var(--sbb-image-border-radius); } diff --git a/src/elements/image/image.ts b/src/elements/image/image.ts index 34a479bbcc..6f764f9b61 100644 --- a/src/elements/image/image.ts +++ b/src/elements/image/image.ts @@ -152,8 +152,6 @@ const breakpointMap: Record = { * @cssprop [--sbb-image-aspect-ratio=auto] - Can be used to override `aspectRatio` property. * This way we can have, for example, an image component with an aspect * ratio of 4/3 in smaller viewports and 16/9 in larger viewports. - * @cssprop [--sbb-image-border-radius=var(--sbb-border-radius-4x)] - Can be used to override the - * `borderRadius` property in case of different values for different viewports. * @cssprop [--sbb-image-object-position] - Can be used to set the object-position css property of the image itself if the image itself is cropped. * @cssprop [--sbb-image-object-fit=cover] - Can be used to set the object-fit css property of the image itself if the image itself is cropped. */ diff --git a/src/elements/image/readme.md b/src/elements/image/readme.md index 455be69359..c84d324f5e 100644 --- a/src/elements/image/readme.md +++ b/src/elements/image/readme.md @@ -75,9 +75,8 @@ Use the `sbb-image-${value}` utility classes to set the image aspect ratio. Avai ## CSS Properties -| Name | Default | Description | -| ----------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `--sbb-image-aspect-ratio` | `auto` | Can be used to override `aspectRatio` property. This way we can have, for example, an image component with an aspect ratio of 4/3 in smaller viewports and 16/9 in larger viewports. | -| `--sbb-image-border-radius` | `var(--sbb-border-radius-4x)` | Can be used to override the `borderRadius` property in case of different values for different viewports. | -| `--sbb-image-object-fit` | `cover` | Can be used to set the object-fit css property of the image itself if the image itself is cropped. | -| `--sbb-image-object-position` | | Can be used to set the object-position css property of the image itself if the image itself is cropped. | +| Name | Default | Description | +| ----------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `--sbb-image-aspect-ratio` | `auto` | Can be used to override `aspectRatio` property. This way we can have, for example, an image component with an aspect ratio of 4/3 in smaller viewports and 16/9 in larger viewports. | +| `--sbb-image-object-fit` | `cover` | Can be used to set the object-fit css property of the image itself if the image itself is cropped. | +| `--sbb-image-object-position` | | Can be used to set the object-position css property of the image itself if the image itself is cropped. | diff --git a/src/elements/lead-container/lead-container.scss b/src/elements/lead-container/lead-container.scss index b08d33c3e0..91d99393d4 100644 --- a/src/elements/lead-container/lead-container.scss +++ b/src/elements/lead-container/lead-container.scss @@ -29,7 +29,8 @@ ::slotted(sbb-image[slot='image']) { --sbb-image-aspect-ratio: var(--sbb-lead-container-image-ratio); - --sbb-image-border-radius: var(--sbb-lead-container-image-border-radius); + + border-radius: var(--sbb-lead-container-image-border-radius); } ::slotted(:is(img[slot='image'], picture[slot='image'])) { From bdc88bbedd5625c167fbe9acaa4db71a83fbf597 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 4 Dec 2024 15:56:10 +0100 Subject: [PATCH 33/47] docs(sbb-image): update readme --- src/elements/image/readme.md | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/elements/image/readme.md b/src/elements/image/readme.md index c84d324f5e..264f2a7d4f 100644 --- a/src/elements/image/readme.md +++ b/src/elements/image/readme.md @@ -21,6 +21,13 @@ E.g. `
` or ``. You can place overlapping content by using the `sbb-figure-overlap-${horizontal-alignment}-${vertical-alignment}` utility classes. +| Position | CSS class | +| -------------- | -------------------------------- | +| `top-left` | `sbb-figure-overlap-start-start` | +| `top-right` | `sbb-figure-overlap-start-end` | +| `bottom-left` | `sbb-figure-overlap-end-start` | +| `bottom-right` | `sbb-figure-overlap-end-end` | + ```html
@@ -30,7 +37,13 @@ You can place overlapping content by using the `sbb-figure-overlap-${horizontal- ### Utility classes -Use the `sbb-image-border-radius-${value}` utility classes to set the image border radius. Available values: `default`, `none` and `round` +Use the `sbb-image-border-radius-${value}` utility classes to set the image border radius. + +| Border Radius | CSS class | +| ------------- | ------------------- | +| `default` | `sbb-image-default` | +| `none` | `sbb-image-none` | +| `round` | `sbb-image-round` | ```html @@ -38,7 +51,22 @@ Use the `sbb-image-border-radius-${value}` utility classes to set the image bord ``` -Use the `sbb-image-${value}` utility classes to set the image aspect ratio. Available values: `free`, `1-1`, `2-3`, `3-2` ... `9-16`, `16-9` +Use the `sbb-image-${ratio}` utility classes to set the image aspect ratio. + +| Aspect Ratio | CSS class | +| ------------ | ---------------- | +| `free` | `sbb-image-free` | +| `1-1` | `sbb-image-1-1` | +| `1-2` | `sbb-image-1-2` | +| `2-1` | `sbb-image-2-1` | +| `2-3` | `sbb-image-2-3` | +| `3-2` | `sbb-image-3-2` | +| `3-4` | `sbb-image-3-4` | +| `4-3` | `sbb-image-4-3` | +| `4-5` | `sbb-image-4-5` | +| `5-4` | `sbb-image-5-4` | +| `9-16` | `sbb-image-9-16` | +| `16-9` | `sbb-image-16-9` | ```html From 2c92877c6d359353f16c4abbd3604c97bc45ba4c Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 4 Dec 2024 16:10:06 +0100 Subject: [PATCH 34/47] fix: pr feedbacks pt.8 --- src/elements/core/styles/core.scss | 14 +++++--------- src/elements/teaser-hero/teaser-hero.stories.ts | 8 -------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index 9be4442122..5e61509db8 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -215,26 +215,22 @@ input[data-sbb-time-input] { // TODO: Move back to the teaser-hero components when the global css refactoring happens :is(sbb-teaser-hero) { - sbb-image { + :is(sbb-image, img) { --sbb-image-aspect-ratio: 1 / 1; - border-radius: 0; - @include mediaqueries.mq($from: small) { --sbb-image-aspect-ratio: 16 / 9; } } - img { - --sbb-image-aspect-ratio: 1 / 1; + sbb-image { + border-radius: 0; + } + img { width: 100%; display: block; aspect-ratio: var(--sbb-image-aspect-ratio); - - @include mediaqueries.mq($from: small) { - --sbb-image-aspect-ratio: 16 / 9; - } } } diff --git a/src/elements/teaser-hero/teaser-hero.stories.ts b/src/elements/teaser-hero/teaser-hero.stories.ts index 08b574d245..25d6d64fa9 100644 --- a/src/elements/teaser-hero/teaser-hero.stories.ts +++ b/src/elements/teaser-hero/teaser-hero.stories.ts @@ -164,14 +164,6 @@ export const chipOnly: StoryObj = { }, }; -export const withSlots: StoryObj = { - render: Template, - argTypes: defaultArgTypes, - args: { - ...defaultArgs, - }, -}; - const meta: Meta = { decorators: [withActions as Decorator], parameters: { From 2b6341db799dd52de76a20a84d57ee2eb6dfa8f5 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 4 Dec 2024 16:46:14 +0100 Subject: [PATCH 35/47] fix: pr feedbacks pt.8 --- src/elements/image/__snapshots__/image.snapshot.spec.snap.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/elements/image/__snapshots__/image.snapshot.spec.snap.js b/src/elements/image/__snapshots__/image.snapshot.spec.snap.js index e5e10acbaf..a2ed420dcf 100644 --- a/src/elements/image/__snapshots__/image.snapshot.spec.snap.js +++ b/src/elements/image/__snapshots__/image.snapshot.spec.snap.js @@ -13,7 +13,9 @@ snapshots["sbb-image should render Shadow DOM"] = alt="" class="sbb-image__blurred" decoding="auto" + height="562" loading="eager" + width="1000" > From 7e651a8b7aedd311313fb360045a5724a96865d9 Mon Sep 17 00:00:00 2001 From: Jeremias Peier Date: Thu, 5 Dec 2024 08:12:53 +0100 Subject: [PATCH 36/47] docs: improve teaser-hero docs --- src/elements/teaser-hero/readme.md | 6 +++++- src/elements/teaser-hero/teaser-hero.stories.ts | 4 +++- src/elements/teaser-hero/teaser-hero.visual.spec.ts | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/elements/teaser-hero/readme.md b/src/elements/teaser-hero/readme.md index 56cee4aff1..278fd46827 100644 --- a/src/elements/teaser-hero/readme.md +++ b/src/elements/teaser-hero/readme.md @@ -17,6 +17,8 @@ Use the `image` slot to pass an `sbb-image` or an `img` that will be used as bac ``` Optionally, you can add an overlapping `sbb-chip-label` by wrapping the `sbb-image` in a `figure` tag (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). +If the `sbb-chip-label` should appear on top of the red panel (e.g. on small screens), you need to set a `z-index` on the `sbb-chip-label`. +Otherwise, it stays behind the red panel. ```html @@ -24,7 +26,9 @@ Optionally, you can add an overlapping `sbb-chip-label` by wrapping the `sbb-ima Find out more
- Chip label + + Chip label +
``` diff --git a/src/elements/teaser-hero/teaser-hero.stories.ts b/src/elements/teaser-hero/teaser-hero.stories.ts index 25d6d64fa9..3e7c23dc37 100644 --- a/src/elements/teaser-hero/teaser-hero.stories.ts +++ b/src/elements/teaser-hero/teaser-hero.stories.ts @@ -120,7 +120,9 @@ const Template = ({ : html`
- ${chipLabel} + + ${chipLabel} +
`} diff --git a/src/elements/teaser-hero/teaser-hero.visual.spec.ts b/src/elements/teaser-hero/teaser-hero.visual.spec.ts index 75995fe282..5423b4eeee 100644 --- a/src/elements/teaser-hero/teaser-hero.visual.spec.ts +++ b/src/elements/teaser-hero/teaser-hero.visual.spec.ts @@ -27,7 +27,9 @@ describe(`sbb-teaser-hero`, () => {
- Label + + Label +
`); From 3ec88276840714f57309d0e78cce19bfcfc3efd1 Mon Sep 17 00:00:00 2001 From: Jeremias Peier Date: Thu, 5 Dec 2024 09:00:45 +0100 Subject: [PATCH 37/47] fix: fix teaser product height styling --- src/elements/core/styles/mixins/image.scss | 1 - src/elements/teaser-product/common/teaser-product-common.scss | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elements/core/styles/mixins/image.scss b/src/elements/core/styles/mixins/image.scss index b3ccd25b3e..8124911314 100644 --- a/src/elements/core/styles/mixins/image.scss +++ b/src/elements/core/styles/mixins/image.scss @@ -6,7 +6,6 @@ grid-template-columns: 100%; grid-auto-rows: auto; margin: 0; - height: 100%; } @mixin figure-image { diff --git a/src/elements/teaser-product/common/teaser-product-common.scss b/src/elements/teaser-product/common/teaser-product-common.scss index a2955bb60d..cb9c0caec8 100644 --- a/src/elements/teaser-product/common/teaser-product-common.scss +++ b/src/elements/teaser-product/common/teaser-product-common.scss @@ -64,7 +64,8 @@ } ::slotted([slot='image']) { - display: block; + display: flex; + width: 100%; height: 100%; } From 61a3a7f24577033ee0de3511d33d9eb55016c4e3 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Thu, 5 Dec 2024 11:47:26 +0100 Subject: [PATCH 38/47] style(img): use generic variables for ratio, fit and position --- .../container/container/container.scss | 3 +- src/elements/core/styles/core.scss | 31 +++++++++---------- src/elements/core/styles/image.scss | 12 ++----- .../flip-card-summary/flip-card-summary.scss | 2 +- 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/elements/container/container/container.scss b/src/elements/container/container/container.scss index 3b2a499f35..1b3a25217d 100644 --- a/src/elements/container/container/container.scss +++ b/src/elements/container/container/container.scss @@ -74,7 +74,8 @@ } ::slotted(img[slot='image']) { - object-fit: cover; + --sbb-image-object-fit: cover; + height: 100%; width: 100%; } diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index 5e61509db8..8b05b843c0 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -154,6 +154,12 @@ input[data-sbb-time-input] { } } +img { + aspect-ratio: var(--sbb-image-aspect-ratio); + object-fit: var(--sbb-image-object-fit); + object-position: var(--sbb-image-object-position); +} + // Target the slotted `sbb-image` which are generally wrapped by a
(therefore are not reachable with the :slotted) // Apply the brightness effect on mouse hover // TODO: Move back to the teaser components when the global css refactoring happens @@ -182,15 +188,15 @@ input[data-sbb-time-input] { // TODO: Move back to the teaser components when the global css refactoring happens :is(sbb-teaser-product, sbb-teaser-product-static) { - // Reset sbb-image border radius in order to control it from teaser product. - sbb-image { - border-radius: 0; + :is(sbb-image, img) { + border-radius: 0; // Reset sbb-image border radius in order to control it from teaser product. + + --sbb-image-object-fit: cover; + --sbb-image-aspect-ratio: 16 / 9; } img { place-self: stretch; - object-fit: cover; - aspect-ratio: 16 / 9; } } @@ -203,14 +209,10 @@ input[data-sbb-time-input] { scale: var(--sbb-teaser-scale, 1); } - sbb-image { + :is(sbb-image, img) { + --sbb-image-object-fit: cover; --sbb-image-aspect-ratio: 4 / 3; } - - img { - object-fit: cover; - aspect-ratio: 4/3; - } } // TODO: Move back to the teaser-hero components when the global css refactoring happens @@ -218,19 +220,16 @@ input[data-sbb-time-input] { :is(sbb-image, img) { --sbb-image-aspect-ratio: 1 / 1; + border-radius: 0; + @include mediaqueries.mq($from: small) { --sbb-image-aspect-ratio: 16 / 9; } } - sbb-image { - border-radius: 0; - } - img { width: 100%; display: block; - aspect-ratio: var(--sbb-image-aspect-ratio); } } diff --git a/src/elements/core/styles/image.scss b/src/elements/core/styles/image.scss index 6e241fa2db..2d4f29b98b 100644 --- a/src/elements/core/styles/image.scss +++ b/src/elements/core/styles/image.scss @@ -48,16 +48,8 @@ $aspects-ratio: ( '16-9': '16 / 9', ); @each $name, $ratio in $aspects-ratio { - sbb-image { - &.sbb-image-#{$name} { - --sbb-image-aspect-ratio: #{$ratio}; - } - } - - img { - &.sbb-image-#{$name} { - aspect-ratio: #{$ratio}; - } + :is(sbb-image, img).sbb-image-#{$name} { + --sbb-image-aspect-ratio: #{$ratio}; } } diff --git a/src/elements/flip-card/flip-card-summary/flip-card-summary.scss b/src/elements/flip-card/flip-card-summary/flip-card-summary.scss index 8c44281a11..911a5f89ce 100644 --- a/src/elements/flip-card/flip-card-summary/flip-card-summary.scss +++ b/src/elements/flip-card/flip-card-summary/flip-card-summary.scss @@ -81,7 +81,7 @@ } ::slotted(img) { - object-fit: cover; + --sbb-image-object-fit: cover; } ::slotted(sbb-image) { From 31fb1473ac1e0bb181e0414f5f4fb743630bf6af Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Thu, 5 Dec 2024 14:56:38 +0100 Subject: [PATCH 39/47] feat(sbb-container): support the use of `figure` as bg image --- .../container/container/container.scss | 20 +++----- .../container/container.visual.spec.ts | 51 ++++++++++++------- src/elements/core/styles/core.scss | 20 ++++++-- 3 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/elements/container/container/container.scss b/src/elements/container/container/container.scss index 1b3a25217d..0950dc6905 100644 --- a/src/elements/container/container/container.scss +++ b/src/elements/container/container/container.scss @@ -4,6 +4,8 @@ @include sbb.box-sizing; :host { + --sbb-container-background-border-radius: 0; + display: block; } @@ -28,6 +30,12 @@ position: relative; } +:host(:not([expanded], [background-expanded])) { + @include sbb.mq($from: ultra) { + --sbb-container-background-border-radius: var(--sbb-border-radius-4x); + } +} + .sbb-container { background-color: var(--sbb-container-background-color); padding: var(--sbb-container-padding); @@ -62,20 +70,8 @@ } ::slotted([slot='image']) { - border-radius: 0; position: absolute; inset: 0; - - :host(:not([expanded], [background-expanded])) & { - @include sbb.mq($from: ultra) { - border-radius: var(--sbb-border-radius-4x); - } - } -} - -::slotted(img[slot='image']) { - --sbb-image-object-fit: cover; - height: 100%; width: 100%; } diff --git a/src/elements/container/container/container.visual.spec.ts b/src/elements/container/container/container.visual.spec.ts index d95e6344d7..a94864a87b 100644 --- a/src/elements/container/container/container.visual.spec.ts +++ b/src/elements/container/container/container.visual.spec.ts @@ -25,10 +25,19 @@ describe(`sbb-container`, () => { const images = [ { + name: 'sbb-image', selector: 'sbb-image', image: html``, }, { + name: 'figure-sbb-image', + selector: 'sbb-image', + image: html`
+ +
`, + }, + { + name: 'img', selector: 'img', image: html` { alt='' >`, }, + { + name: 'figure-img', + selector: 'img', + image: html`
+ +
`, + }, ]; const containerContent = (): TemplateResult => html` @@ -88,7 +104,7 @@ describe(`sbb-container`, () => { describe(`expanded=${expanded}`, () => { for (const image of images) { it( - `slotted=${image.selector}`, + `slotted=${image.name}`, visualDiffDefault.with(async (setup) => { await setup.withFixture( html` @@ -146,23 +162,24 @@ describe(`sbb-container`, () => { }), ); - it( - `background-image`, - visualDiffDefault.with(async (setup) => { - await setup.withFixture( - html` - - ${backgroundImageContent} - - - `, - wrapperStyles, - ); + for (const image of images) { + it( + `background-image slotted=${image.name}`, + visualDiffDefault.with(async (setup) => { + await setup.withFixture( + html` + + ${backgroundImageContent} ${image.image} + + `, + wrapperStyles, + ); - await setViewport(viewport); - await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); - }), - ); + await setViewport(viewport); + await waitForImageReady(setup.snapshotElement.querySelector(image.selector)!); + }), + ); + } }); } }); diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index 8b05b843c0..f7c15dd3b4 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -160,6 +160,18 @@ img { object-position: var(--sbb-image-object-position); } +// TODO: Move back to the sbb-container components when the global css refactoring happens +sbb-container { + [slot='image']:is(sbb-image, img), + [slot='image'] :is(sbb-image, img) { + --sbb-image-object-fit: cover; + + border-radius: var(--sbb-container-background-border-radius); + height: 100%; + position: absolute; + } +} + // Target the slotted `sbb-image` which are generally wrapped by a
(therefore are not reachable with the :slotted) // Apply the brightness effect on mouse hover // TODO: Move back to the teaser components when the global css refactoring happens @@ -177,8 +189,8 @@ img { } } - & [slot='image']:is(sbb-image, img), - & [slot='image'] :is(sbb-image, img) { + [slot='image']:is(sbb-image, img), + [slot='image'] :is(sbb-image, img) { will-change: filter; filter: brightness(var(--sbb-teaser-image-brightness, 1)); transition: filter var(--sbb-teaser-image-animation-duration) @@ -202,8 +214,8 @@ img { // TODO: Move back to the teaser components when the global css refactoring happens :is(sbb-teaser) { - & [slot='image']:is(sbb-image, img), - & [slot='image'] :is(sbb-image, img) { + [slot='image']:is(sbb-image, img), + [slot='image'] :is(sbb-image, img) { transition-property: filter, scale; will-change: filter, scale; scale: var(--sbb-teaser-scale, 1); From 385cfcdfb8b4a1d1b2581ccc1f26bc3f660ebe7e Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Mon, 9 Dec 2024 09:36:00 +0100 Subject: [PATCH 40/47] feat(sbb-lead-container): support the use of `figure` as lead image --- src/elements/core/styles/core.scss | 14 ++- .../lead-container/lead-container.scss | 11 +- .../lead-container/lead-container.stories.ts | 114 +++++++++++------- .../lead-container.visual.spec.ts | 93 +++++++++----- 4 files changed, 143 insertions(+), 89 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index f7c15dd3b4..c4a6564a1c 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -154,7 +154,8 @@ input[data-sbb-time-input] { } } -img { +img, +picture { aspect-ratio: var(--sbb-image-aspect-ratio); object-fit: var(--sbb-image-object-fit); object-position: var(--sbb-image-object-position); @@ -172,6 +173,17 @@ sbb-container { } } +// TODO: Move back to the sbb-lead-container components when the global css refactoring happens +sbb-lead-container { + [slot='image']:is(sbb-image, img, picture), + [slot='image'] :is(sbb-image, img, picture) { + --sbb-image-aspect-ratio: var(--sbb-lead-container-image-ratio); + --sbb-image-object-fit: cover; + + border-radius: var(--sbb-lead-container-image-border-radius); + } +} + // Target the slotted `sbb-image` which are generally wrapped by a
(therefore are not reachable with the :slotted) // Apply the brightness effect on mouse hover // TODO: Move back to the teaser components when the global css refactoring happens diff --git a/src/elements/lead-container/lead-container.scss b/src/elements/lead-container/lead-container.scss index 91d99393d4..69f997a787 100644 --- a/src/elements/lead-container/lead-container.scss +++ b/src/elements/lead-container/lead-container.scss @@ -27,18 +27,9 @@ padding-block-end: var(--sbb-spacing-responsive-l); } -::slotted(sbb-image[slot='image']) { - --sbb-image-aspect-ratio: var(--sbb-lead-container-image-ratio); - - border-radius: var(--sbb-lead-container-image-border-radius); -} - -::slotted(:is(img[slot='image'], picture[slot='image'])) { +::slotted([slot='image']) { display: block; width: 100%; - object-fit: cover; - aspect-ratio: var(--sbb-lead-container-image-ratio); - border-radius: var(--sbb-lead-container-image-border-radius); } ::slotted(:is(sbb-breadcrumb-group, sbb-block-link).sbb-lead-container-spacing) { diff --git a/src/elements/lead-container/lead-container.stories.ts b/src/elements/lead-container/lead-container.stories.ts index 15fc4a0f52..e99960e47c 100644 --- a/src/elements/lead-container/lead-container.stories.ts +++ b/src/elements/lead-container/lead-container.stories.ts @@ -3,6 +3,7 @@ import { html, type TemplateResult } from 'lit'; import '../alert.js'; import '../breadcrumb.js'; +import '../chip-label.js'; import '../image.js'; import '../link/block-link/block-link.js'; import '../notification.js'; @@ -13,60 +14,77 @@ import images from '../core/images.js'; import readme from './readme.md?raw'; +const content = (): TemplateResult => html` + + + + The rail traffic between Allaman and Morges is interrupted. All trains are cancelled. + + + + + Level 1 + Level 2 + Level 3 + Level 4 + + + Link + + Title +

+ Lead text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer enim elit, ultricies + in tincidunt quis, mattis eu quam. Nulla sit amet lorem fermentum, molestie nunc ut, hendrerit + risus. +

+ + Vestibulum rutrum elit et lacus sollicitudin, quis malesuada lorem vehicula. Suspendisse at + augue quis tellus vulputate tempor. Vivamus urna velit, varius nec est ac, mollis efficitur + lorem. Quisque non nisl eget massa interdum tempus. Praesent vel feugiat metus. + +

+ Other content. Vestibulum rutrum elit et lacus sollicitudin, quis malesuada lorem vehicula. + Suspendisse at augue quis tellus vulputate tempor. Vivamus urna velit, varius nec est ac, mollis + efficitur lorem. Quisque non nisl eget massa interdum tempus. Praesent vel feugiat metus. +

+`; + const DefaultTemplate = (): TemplateResult => html` - + ${content()}; - - +`; + +const WithChipTemplate = (): TemplateResult => html` + + ${content()}; + + + + + AI generated - The rail traffic between Allaman and Morges is interrupted. All trains are cancelled. - - - - - Level 1 - Level 2 - Level 3 - Level 4 - - - Link - - Title -

- Lead text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer enim elit, - ultricies in tincidunt quis, mattis eu quam. Nulla sit amet lorem fermentum, molestie nunc ut, - hendrerit risus. -

- - Vestibulum rutrum elit et lacus sollicitudin, quis malesuada lorem vehicula. Suspendisse at - augue quis tellus vulputate tempor. Vivamus urna velit, varius nec est ac, mollis efficitur - lorem. Quisque non nisl eget massa interdum tempus. Praesent vel feugiat metus. - -

- Other content. Vestibulum rutrum elit et lacus sollicitudin, quis malesuada lorem vehicula. - Suspendisse at augue quis tellus vulputate tempor. Vivamus urna velit, varius nec est ac, - mollis efficitur lorem. Quisque non nisl eget massa interdum tempus. Praesent vel feugiat - metus. -

+
`; @@ -74,6 +92,10 @@ export const Default: StoryObj = { render: DefaultTemplate, }; +export const WithChip: StoryObj = { + render: WithChipTemplate, +}; + const meta: Meta = { parameters: { docs: { diff --git a/src/elements/lead-container/lead-container.visual.spec.ts b/src/elements/lead-container/lead-container.visual.spec.ts index 638ce85452..07128a9d96 100644 --- a/src/elements/lead-container/lead-container.visual.spec.ts +++ b/src/elements/lead-container/lead-container.visual.spec.ts @@ -10,6 +10,7 @@ import { waitForImageReady } from '../core/testing.js'; import '../alert.js'; import '../breadcrumb.js'; +import '../chip-label.js'; import '../image.js'; import '../link/block-link/block-link.js'; import '../notification.js'; @@ -22,14 +23,63 @@ const leadImageBase64 = await loadAssetAsBase64(leadImageUrl); describe(`sbb-lead-container`, () => { const wrapperStyles = { backgroundColor: `var(--sbb-color-milk)`, padding: '0' }; - const leadContainerTemplate = (image: TemplateResult): TemplateResult => html` + const testCases = [ + { + title: 'with sbb-image', + imgSelector: 'sbb-image', + imgTemplate: () => html``, + }, + { + title: 'with img tag', + imgSelector: 'img', + imgTemplate: () => html``, + }, + { + title: 'with figure_sbb-image', + imgSelector: 'sbb-image', + imgTemplate: () => + html`
+ + AI generated +
`, + }, + { + title: 'with figure_img', + imgSelector: 'img', + imgTemplate: () => + html`
+ + AI generated +
`, + }, + { + title: 'with picture_sbb-image', + imgSelector: 'sbb-image', + imgTemplate: () => + html` + + AI generated + `, + }, + { + title: 'with picture_img', + imgSelector: 'img', + imgTemplate: () => + html` + + AI generated + `, + }, + ]; + + const leadContainerTemplate = (image: () => TemplateResult): TemplateResult => html` - ${image} + ${image()} { `; describeViewports(() => { - it( - 'with sbb-image', - visualDiffDefault.with(async (setup) => { - await setup.withFixture( - leadContainerTemplate( - html``, - ), - wrapperStyles, - ); - - await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); - }), - ); - - it( - 'with img tag', - visualDiffDefault.with(async (setup) => { - await setup.withFixture( - leadContainerTemplate( - html`Station of Lucerne from outside`, - ), - wrapperStyles, - ); + for (const testCase of testCases) { + it( + testCase.title, + visualDiffDefault.with(async (setup) => { + await setup.withFixture(leadContainerTemplate(testCase.imgTemplate), wrapperStyles); - await waitForImageReady(setup.snapshotElement.querySelector('img')!); - }), - ); + await waitForImageReady(setup.snapshotElement.querySelector(testCase.imgSelector)!); + }), + ); + } }); }); From 1f875efa821d5e4bbed85a5b2648897d71c89fe6 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Mon, 9 Dec 2024 10:20:39 +0100 Subject: [PATCH 41/47] feat(sbb-flip-card): support the use of `figure` as image --- src/elements/core/styles/core.scss | 12 +++ .../flip-card-summary/flip-card-summary.scss | 11 +-- .../flip-card/flip-card/flip-card.stories.ts | 42 ++++++--- .../flip-card/flip-card.visual.spec.ts | 86 +++++++++++++++---- 4 files changed, 114 insertions(+), 37 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index c4a6564a1c..f17a517503 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -173,6 +173,18 @@ sbb-container { } } +// TODO: Move back to the sbb-flip-card-summary components when the global css refactoring happens +sbb-flip-card-summary { + [slot='image']:is(sbb-image, img), + [slot='image'] :is(sbb-image, img) { + --sbb-image-aspect-ratio: auto; + --sbb-image-object-fit: cover; + + border-radius: 0; + height: 100%; + } +} + // TODO: Move back to the sbb-lead-container components when the global css refactoring happens sbb-lead-container { [slot='image']:is(sbb-image, img, picture), diff --git a/src/elements/flip-card/flip-card-summary/flip-card-summary.scss b/src/elements/flip-card/flip-card-summary/flip-card-summary.scss index 911a5f89ce..8c4e74c294 100644 --- a/src/elements/flip-card/flip-card-summary/flip-card-summary.scss +++ b/src/elements/flip-card/flip-card-summary/flip-card-summary.scss @@ -74,16 +74,7 @@ } } -::slotted(:is(img, sbb-image)) { - border-radius: 0; +::slotted([slot='image']) { width: 100%; height: 100%; } - -::slotted(img) { - --sbb-image-object-fit: cover; -} - -::slotted(sbb-image) { - --sbb-image-aspect-ratio: auto; -} diff --git a/src/elements/flip-card/flip-card/flip-card.stories.ts b/src/elements/flip-card/flip-card/flip-card.stories.ts index 101635a45f..6e97581f49 100644 --- a/src/elements/flip-card/flip-card/flip-card.stories.ts +++ b/src/elements/flip-card/flip-card/flip-card.stories.ts @@ -10,9 +10,10 @@ import sampleImages from '../../core/images.js'; import { SbbFlipCardElement } from './flip-card.js'; import readme from './readme.md?raw'; -import '../../image/image.js'; -import '../../link/link/link.js'; -import '../../title/title.js'; +import '../../chip-label.js'; +import '../../image.js'; +import '../../link/link.js'; +import '../../title.js'; import '../flip-card-details.js'; import '../flip-card-summary.js'; @@ -53,20 +54,30 @@ const defaultArgs: Args = { 'accessibility-label': undefined, }; +const imgTemplate = (): TemplateResult => html` + +`; + +const imgWithChipTemplate = (): TemplateResult => html` +
+ + AI generated +
+`; + const cardSummary = ( label: string, imageAlignment: any, showImage: boolean, + showChip?: boolean, ): TemplateResult => html` ${label} - ${showImage - ? html`` - : nothing} + ${showImage ? (showChip ? imgWithChipTemplate() : imgTemplate()) : nothing} `; @@ -84,6 +95,11 @@ const DefaultTemplate = (args: Args): TemplateResult => ${cardSummary(args.label, args.imageAlignment, true)} ${cardDetails()} `; +const WithChipTemplate = (args: Args): TemplateResult => + html` + ${cardSummary(args.label, args.imageAlignment, true, true)} ${cardDetails()} + `; + const NoImageTemplate = (args: Args): TemplateResult => html` ${cardSummary(args.label, args.imageAlignment, false)} ${cardDetails()} @@ -153,6 +169,12 @@ export const ImageBelow: StoryObj = { args: { ...defaultArgs, imageAlignment: imageAlignment.options![1] }, }; +export const WithChipOnImage: StoryObj = { + render: WithChipTemplate, + argTypes: defaultArgTypes, + args: { ...defaultArgs }, +}; + export const NoImage: StoryObj = { render: NoImageTemplate, argTypes: defaultArgTypes, diff --git a/src/elements/flip-card/flip-card/flip-card.visual.spec.ts b/src/elements/flip-card/flip-card/flip-card.visual.spec.ts index 7ed3c32148..f7a619267b 100644 --- a/src/elements/flip-card/flip-card/flip-card.visual.spec.ts +++ b/src/elements/flip-card/flip-card/flip-card.visual.spec.ts @@ -15,9 +15,10 @@ import type { SbbFlipCardElement } from './flip-card.js'; import './flip-card.js'; import '../flip-card-summary.js'; import '../flip-card-details.js'; -import '../../title.js'; -import '../../link.js'; +import '../../chip-label.js'; import '../../image.js'; +import '../../link.js'; +import '../../title.js'; const imageUrl = import.meta.resolve('../../core/testing/assets/placeholder-image.png'); @@ -25,10 +26,13 @@ const content = ( title: string = 'Summary', imageAlignment: SbbFlipCardImageAlignment = 'after', longContent: boolean = false, + imgTemplate?: () => TemplateResult, ): TemplateResult => html` ${title} - + ${imgTemplate + ? imgTemplate() + : html``} Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam luctus ornare condimentum. @@ -45,6 +49,37 @@ const content = ( Link `; +const imgTestCases = [ + { + title: 'with sbb-image', + imgSelector: 'sbb-image', + imgTemplate: () => html``, + }, + { + title: 'with img tag', + imgSelector: 'img', + imgTemplate: () => html``, + }, + { + title: 'with figure_sbb-image', + imgSelector: 'sbb-image', + imgTemplate: () => + html`
+ + AI generated +
`, + }, + { + title: 'with figure_img', + imgSelector: 'img', + imgTemplate: () => + html`
+ + AI generated +
`, + }, +]; + describe(`sbb-flip-card`, () => { describeViewports({ viewports: ['zero', 'medium'] }, () => { for (const imageAlignment of ['after', 'below']) { @@ -95,20 +130,6 @@ describe(`sbb-flip-card`, () => { }), ); - for (const imageAlignment of ['after', 'below']) { - it( - `long content image-alignment=${imageAlignment}`, - visualDiffDefault.with(async (setup) => { - await setup.withFixture( - html` - ${content('Summary', imageAlignment as SbbFlipCardImageAlignment, true)} - `, - ); - await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); - }), - ); - } - for (const imageAlignment of ['after', 'below']) { describe(`imageAlignment=${imageAlignment}`, () => { it( @@ -146,6 +167,37 @@ describe(`sbb-flip-card`, () => { await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); }), ); + + it( + `long content`, + visualDiffDefault.with(async (setup) => { + await setup.withFixture( + html` + ${content('Summary', imageAlignment as SbbFlipCardImageAlignment, true)} + `, + ); + await waitForImageReady(setup.snapshotElement.querySelector('sbb-image')!); + }), + ); + + for (const testCase of imgTestCases) { + it( + testCase.title, + visualDiffDefault.with(async (setup) => { + await setup.withFixture( + html` + ${content( + 'Summary', + imageAlignment as SbbFlipCardImageAlignment, + false, + testCase.imgTemplate, + )} + `, + ); + await waitForImageReady(setup.snapshotElement.querySelector(testCase.imgSelector)!); + }), + ); + } }); } From ab9cb93659b1637a534419b81bd45dcd436c852d Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Mon, 9 Dec 2024 10:24:18 +0100 Subject: [PATCH 42/47] feat(sbb-container): support the use of `figure` as bg image pt.2 --- src/elements/container/container/container.visual.spec.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/elements/container/container/container.visual.spec.ts b/src/elements/container/container/container.visual.spec.ts index a94864a87b..da75e666c8 100644 --- a/src/elements/container/container/container.visual.spec.ts +++ b/src/elements/container/container/container.visual.spec.ts @@ -11,6 +11,7 @@ import { waitForImageReady } from '../../core/testing.js'; import '../../button.js'; import '../../card.js'; +import '../../chip-label.js'; import '../../image.js'; import '../../title.js'; import './container.js'; @@ -34,6 +35,7 @@ describe(`sbb-container`, () => { selector: 'sbb-image', image: html`
+ AI generated
`, }, { @@ -50,6 +52,7 @@ describe(`sbb-container`, () => { selector: 'img', image: html`
+ AI generated
`, }, ]; From 1696197ec31778366f1021bd4555b51964814f87 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Mon, 9 Dec 2024 10:29:50 +0100 Subject: [PATCH 43/47] feat(sbb-lead-container): support the use of `figure` as bg image pt.2 --- src/elements/lead-container/lead-container.stories.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/elements/lead-container/lead-container.stories.ts b/src/elements/lead-container/lead-container.stories.ts index 9ffeb925f8..10da1282f1 100644 --- a/src/elements/lead-container/lead-container.stories.ts +++ b/src/elements/lead-container/lead-container.stories.ts @@ -76,13 +76,13 @@ const WithChipTemplate = (): TemplateResult => html` ${content()}; - +
AI generated - +
`; From 87aacf7f6f78a4ec77eb82a5b17d96866a8bc6b8 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Mon, 9 Dec 2024 12:19:42 +0100 Subject: [PATCH 44/47] feat: support the use of `figure` as image pt.2 --- src/elements/core/styles/core.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index f17a517503..f751792787 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -154,8 +154,7 @@ input[data-sbb-time-input] { } } -img, -picture { +img { aspect-ratio: var(--sbb-image-aspect-ratio); object-fit: var(--sbb-image-object-fit); object-position: var(--sbb-image-object-position); From 9feca0dff2b8d2000e86d8b18935334c72f79e63 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Tue, 10 Dec 2024 12:52:13 +0100 Subject: [PATCH 45/47] feat(sbb-flip-card): support the use of `figure` as image pt.2 --- src/elements/core/styles/core.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index f751792787..1da26d7abc 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -180,6 +180,7 @@ sbb-flip-card-summary { --sbb-image-object-fit: cover; border-radius: 0; + display: block; height: 100%; } } From 155767d7ac26690b86ec554746f714cfdfb22143 Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 11 Dec 2024 08:54:56 +0100 Subject: [PATCH 46/47] docs: add overlap chip doc --- src/elements/container/container/readme.md | 15 +++++++++++++++ .../flip-card/flip-card-summary/readme.md | 19 ++++++++++++++++++- src/elements/lead-container/readme.md | 15 +++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/elements/container/container/readme.md b/src/elements/container/container/readme.md index e5a7cc9f83..3bb1543a81 100644 --- a/src/elements/container/container/readme.md +++ b/src/elements/container/container/readme.md @@ -19,6 +19,21 @@ use CSS object-position for slotted `img`, or `--sbb-image-object-position` vari If an image is present, the container receives a pre-defined padding. It's possible to override the padding by using the CSS variable `--sbb-container-padding`. +Optionally, you can add an overlapping `sbb-chip-label` by wrapping the `sbb-image` in a `figure` tag (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). + +```html + +
+ + ... +
+ ... +
+``` + ## Style By default `sbb-container` uses the `page spacing` defined in the [layout documentation](/docs/styles-layout--docs). Optionally the user can use the `expanded` property (default: `false`) to switch to the `page spacing expanded` layout. diff --git a/src/elements/flip-card/flip-card-summary/readme.md b/src/elements/flip-card/flip-card-summary/readme.md index 9063e233e4..c2cb95dd87 100644 --- a/src/elements/flip-card/flip-card-summary/readme.md +++ b/src/elements/flip-card/flip-card-summary/readme.md @@ -12,7 +12,24 @@ The component's slot is implicitly set to `"summary"`. ## Slots -Use the unnamed slot of `sbb-flip-card-summary` to provide a title and, optionally, the `image` slot to provide an image (via either `sbb-image` or `img`). +Use the unnamed slot to provide a title and the `image` slot to provide an image (via either `sbb-image` or `img`). + +Optionally, you can add an overlapping `sbb-chip-label` by wrapping the `sbb-image` in a `figure` tag (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). + +```html + + + ... +
+ + ... +
+
+
+``` diff --git a/src/elements/lead-container/readme.md b/src/elements/lead-container/readme.md index 22291b3951..c675c422fc 100644 --- a/src/elements/lead-container/readme.md +++ b/src/elements/lead-container/readme.md @@ -67,6 +67,21 @@ Full example with applied spacings (CSS classes) in content:
``` +Optionally, you can add an overlapping `sbb-chip-label` by wrapping the `sbb-image` in a `figure` tag (see [sbb-image doc](/docs/elements-sbb-image--docs#utility%classes)). + +```html + +
+ + ... +
+ ... +
+``` + ## Accessibility Please either define the `alt` attribute of your image or set `aria-hidden="true"` to the image From fcd0dc171bc84dc317960c8ef26db4a8e4c016df Mon Sep 17 00:00:00 2001 From: Tommmaso Menga Date: Wed, 11 Dec 2024 08:57:36 +0100 Subject: [PATCH 47/47] fix: post-merge fix --- src/elements/core/styles/core.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/elements/core/styles/core.scss b/src/elements/core/styles/core.scss index 1da26d7abc..220a7f68e3 100644 --- a/src/elements/core/styles/core.scss +++ b/src/elements/core/styles/core.scss @@ -202,7 +202,7 @@ sbb-lead-container { :is(sbb-teaser, sbb-teaser-hero, sbb-teaser-product) { --sbb-teaser-image-brightness-hover: var(--sbb-hover-image-brightness); --sbb-teaser-image-animation-duration: var( - --sbb-disable-animation-zero-duration, + --sbb-disable-animation-duration, var(--sbb-animation-duration-4x) ); --sbb-teaser-image-animation-easing: var(--sbb-animation-easing);