-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sbb-teaser-product): initial implementation (#2976)
--------- Co-authored-by: Davide Mininni <[email protected]> Co-authored-by: Jeremias Peier <[email protected]>
- Loading branch information
1 parent
25dbd78
commit 79601d2
Showing
24 changed files
with
1,427 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './teaser-product/teaser-product.js'; | ||
export * from './teaser-product/teaser-product-static.js'; | ||
export * from './teaser-product/common.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './common/teaser-product-common.js'; | ||
|
||
export { default as teaserProductCommonStyle } from './common/teaser-product-common.scss?lit&inline'; |
157 changes: 157 additions & 0 deletions
157
src/elements/teaser-product/common/teaser-product-common.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
@use '../../core/styles/index' as sbb; | ||
|
||
// Box-sizing rules contained in typography are not traversing Shadow DOM boundaries. We need to include box-sizing mixin in every component. | ||
@include sbb.box-sizing; | ||
|
||
:host { | ||
display: block; | ||
|
||
--sbb-teaser-product-background-color: var(--sbb-color-cloud); | ||
--sbb-teaser-product-background-gradient-direction: to right; | ||
--sbb-teaser-product-background: var(--sbb-teaser-product-background-color); | ||
--sbb-teaser-product-border-radius: var(--sbb-border-radius-4x); | ||
--sbb-teaser-product-content-color: var(--sbb-color-iron); | ||
--sbb-teaser-product-footer-color: var(--sbb-color-anthracite); | ||
--sbb-teaser-product-container-padding-block: var(--sbb-spacing-responsive-l); | ||
--sbb-teaser-product-min-height: #{sbb.px-to-rem-build(600)}; | ||
--sbb-teaser-product-background-gradient-start: 25%; | ||
--sbb-teaser-product-background-gradient-end: 75%; | ||
|
||
@include sbb.mq($from: large) { | ||
--sbb-teaser-product-background: linear-gradient( | ||
var(--sbb-teaser-product-background-gradient-direction), | ||
var(--sbb-teaser-product-background-color) var(--sbb-teaser-product-background-gradient-start), | ||
transparent var(--sbb-teaser-product-background-gradient-end) | ||
); | ||
} | ||
} | ||
|
||
:host([negative]) { | ||
--sbb-teaser-product-background-color: var(--sbb-color-midnight); | ||
--sbb-teaser-product-content-color: var(--sbb-color-cloud); | ||
--sbb-teaser-product-footer-color: var(--sbb-color-cloud); | ||
--sbb-focus-outline-color: var(--sbb-focus-outline-color-dark); | ||
--sbb-title-text-color-normal-override: var(--sbb-color-milk); | ||
} | ||
|
||
:host([image-alignment='before']) { | ||
--sbb-teaser-product-background-gradient-direction: to left; | ||
} | ||
|
||
.sbb-teaser-product__image-container { | ||
display: block; | ||
overflow: hidden; | ||
|
||
// We have to remove the image bottom border-radius when stacked | ||
border-radius: var(--sbb-teaser-product-border-radius) var(--sbb-teaser-product-border-radius) 0 0; | ||
|
||
@include sbb.mq($from: large) { | ||
position: absolute; | ||
inset: 0; | ||
border-radius: var(--sbb-teaser-product-border-radius); | ||
} | ||
} | ||
|
||
::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; | ||
} | ||
|
||
::slotted(sbb-title.sbb-teaser-product--spacing) { | ||
--sbb-title-margin-block-start: 0; | ||
} | ||
|
||
::slotted(:is(sbb-action-group, [data-action]).sbb-teaser-product--spacing) { | ||
margin-block-start: var(--sbb-spacing-responsive-xxs); | ||
} | ||
|
||
.sbb-action-base { | ||
display: block; | ||
position: relative; | ||
text-decoration: none; | ||
|
||
@include sbb.if-forced-colors { | ||
// Apply a visual border for forced color mode | ||
&::after { | ||
content: ''; | ||
position: absolute; | ||
display: block; | ||
inset: 0; | ||
pointer-events: none; | ||
border: var(--sbb-border-width-2x) solid CanvasText; | ||
border-radius: var(--sbb-teaser-product-border-radius); | ||
} | ||
} | ||
} | ||
|
||
.sbb-teaser-product__container { | ||
display: block; | ||
background: var(--sbb-teaser-product-background); | ||
border-radius: 0 0 var(--sbb-teaser-product-border-radius) var(--sbb-teaser-product-border-radius); | ||
padding: var(--sbb-spacing-responsive-s); | ||
|
||
@include sbb.mq($from: large) { | ||
display: grid; | ||
grid: | ||
'content .' 1fr | ||
'footnote .' auto / 1fr 1fr; | ||
column-gap: var(--sbb-spacing-responsive-xxl); | ||
background: var(--sbb-teaser-product-background); | ||
border-radius: var(--sbb-teaser-product-border-radius); | ||
padding-block: var(--sbb-teaser-product-container-padding-block) 0; | ||
padding-inline: var(--sbb-spacing-responsive-xl); | ||
position: relative; | ||
|
||
:host([image-alignment='before']) & { | ||
grid-template-areas: | ||
'. content' | ||
'. footnote'; | ||
} | ||
} | ||
} | ||
|
||
.sbb-teaser-product__content { | ||
grid-area: content; | ||
align-self: center; | ||
margin: 0; | ||
color: var(--sbb-teaser-product-content-color); | ||
|
||
@include sbb.mq($from: large) { | ||
align-content: center; | ||
min-height: calc( | ||
var(--sbb-teaser-product-min-height) - 2 * var(--sbb-teaser-product-container-padding-block) | ||
); | ||
} | ||
} | ||
|
||
.sbb-teaser-product__footnote { | ||
grid-area: footnote; | ||
display: block; | ||
padding-block-start: var(--sbb-spacing-responsive-s); | ||
color: var(--sbb-teaser-product-footer-color); | ||
|
||
@include sbb.text-xxs--regular; | ||
|
||
:host(:not([data-slot-names~='footnote'])) & { | ||
padding-block-start: 0; | ||
} | ||
|
||
@include sbb.mq($from: large) { | ||
min-height: var(--sbb-teaser-product-container-padding-block); | ||
padding-block: var(--sbb-spacing-responsive-xs); | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
src/elements/teaser-product/common/teaser-product-common.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { html, type TemplateResult } from 'lit'; | ||
import { property } from 'lit/decorators.js'; | ||
|
||
import type { SbbActionBaseElement } from '../../core/base-elements.js'; | ||
import { slotState } from '../../core/decorators.js'; | ||
import { | ||
SbbNegativeMixin, | ||
type SbbNegativeMixinType, | ||
type AbstractConstructor, | ||
} from '../../core/mixins.js'; | ||
|
||
export declare class SbbTeaserProductCommonElementMixinType extends SbbNegativeMixinType { | ||
public imageAlignment?: 'after' | 'before'; | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
export const SbbTeaserProductCommonElementMixin = < | ||
T extends AbstractConstructor<SbbActionBaseElement>, | ||
>( | ||
superClass: T, | ||
): AbstractConstructor<SbbTeaserProductCommonElementMixinType> & T => { | ||
@slotState() | ||
abstract class SbbTeaserProductCommonElement | ||
extends SbbNegativeMixin(superClass) | ||
implements SbbTeaserProductCommonElementMixinType | ||
{ | ||
/** | ||
* Whether the fully visible part of the image is aligned 'before' or 'after' the content. | ||
* Only relevant starting from large breakpoint. | ||
*/ | ||
@property({ attribute: 'image-alignment', reflect: true }) | ||
public imageAlignment: 'after' | 'before' = 'after'; | ||
|
||
protected override renderTemplate(): TemplateResult { | ||
return html` | ||
<span class="sbb-teaser-product__image-container"><slot name="image"></slot></span> | ||
<span class="sbb-teaser-product__container"> | ||
<span class="sbb-teaser-product__content"> | ||
<slot></slot> | ||
</span> | ||
<span class="sbb-teaser-product__footnote"> | ||
<slot name="footnote"></slot> | ||
</span> | ||
</span> | ||
`; | ||
} | ||
} | ||
return SbbTeaserProductCommonElement as AbstractConstructor<SbbTeaserProductCommonElementMixinType> & | ||
T; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './teaser-product-static/teaser-product-static.js'; |
90 changes: 90 additions & 0 deletions
90
...r-product/teaser-product-static/__snapshots__/teaser-product-static.snapshot.spec.snap.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* @web/test-runner snapshot v1 */ | ||
export const snapshots = {}; | ||
|
||
snapshots["sbb-teaser-product-static renders DOM"] = | ||
`<sbb-teaser-product-static | ||
data-action="" | ||
data-slot-names="footnote image unnamed" | ||
dir="ltr" | ||
image-alignment="after" | ||
> | ||
<sbb-image | ||
aspect-ratio="16-9" | ||
border-radius="default" | ||
image-src="http://localhost:8000/src/elements/core/testing/assets/placeholder-image.png" | ||
slot="image" | ||
> | ||
</sbb-image> | ||
<p class="sbb-teaser-product--spacing"> | ||
Content | ||
</p> | ||
<p | ||
class="sbb-teaser-product--spacing" | ||
slot="footnote" | ||
> | ||
Footnote | ||
</p> | ||
</sbb-teaser-product-static> | ||
`; | ||
/* end snapshot sbb-teaser-product-static renders DOM */ | ||
|
||
snapshots["sbb-teaser-product-static renders Shadow DOM"] = | ||
`<span class="sbb-action-base sbb-teaser-product-static"> | ||
<span class="sbb-teaser-product__image-container"> | ||
<slot name="image"> | ||
</slot> | ||
</span> | ||
<span class="sbb-teaser-product__container"> | ||
<span class="sbb-teaser-product__content"> | ||
<slot> | ||
</slot> | ||
</span> | ||
<span class="sbb-teaser-product__footnote"> | ||
<slot name="footnote"> | ||
</slot> | ||
</span> | ||
</span> | ||
</span> | ||
`; | ||
/* end snapshot sbb-teaser-product-static renders Shadow DOM */ | ||
|
||
snapshots["sbb-teaser-product-static renders A11y tree Chrome"] = | ||
`<p> | ||
{ | ||
"role": "WebArea", | ||
"name": "", | ||
"children": [ | ||
{ | ||
"role": "text", | ||
"name": "Content" | ||
}, | ||
{ | ||
"role": "text", | ||
"name": "Footnote" | ||
} | ||
] | ||
} | ||
</p> | ||
`; | ||
/* end snapshot sbb-teaser-product-static renders A11y tree Chrome */ | ||
|
||
snapshots["sbb-teaser-product-static renders A11y tree Firefox"] = | ||
`<p> | ||
{ | ||
"role": "document", | ||
"name": "", | ||
"children": [ | ||
{ | ||
"role": "text leaf", | ||
"name": "Content" | ||
}, | ||
{ | ||
"role": "text leaf", | ||
"name": "Footnote" | ||
} | ||
] | ||
} | ||
</p> | ||
`; | ||
/* end snapshot sbb-teaser-product-static renders A11y tree Firefox */ | ||
|
87 changes: 87 additions & 0 deletions
87
src/elements/teaser-product/teaser-product-static/readme.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
The `sbb-teaser-product-static` is a component that can display a text and a footnote, | ||
combined with an image as background, to tease a product. | ||
It should be used if there is more than one interactive action, | ||
otherwise, see [sbb-teaser-product](/docs/elements-sbb-teaser-sbb-teaser-product--docs). | ||
|
||
```html | ||
<sbb-teaser-product-static> | ||
<sbb-image slot="image" image-src="..."></sbb-image> | ||
|
||
<p class="sbb-teaser-product--spacing">Content ...</p> | ||
|
||
<p slot="footnote" class="sbb-teaser-product--spacing">...</p> | ||
</sbb-teaser-product-static> | ||
``` | ||
|
||
## 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. | ||
|
||
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 | ||
<sbb-teaser-product-static> | ||
<sbb-image slot="image" image-src="..."></sbb-image> | ||
<p class="sbb-teaser-product--spacing">Content ...</p> | ||
</sbb-teaser-product-static> | ||
``` | ||
|
||
If paragraphs, title and/or button are used, consumers can apply the helper class `sbb-teaser-product--spacing` | ||
to display the components with the correct spacings. | ||
|
||
```html | ||
<sbb-teaser-product-static> | ||
<sbb-image slot="image" image-src="..."></sbb-image> | ||
<sbb-title level="3" class="sbb-teaser-product--spacing"> | ||
Benefit from up to 70% discount | ||
</sbb-title> | ||
<p class="sbb-teaser-product--spacing"> | ||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent pretium felis sit amet felis | ||
viverra lacinia. Donec et enim mi. Aliquam erat volutpat. Proin ut odio tellus. | ||
</p> | ||
<sbb-action-group class="sbb-teaser-product--spacing"> | ||
<sbb-button>Label</sbb-button> | ||
<sbb-secondary-button>Label</sbb-secondary-button> | ||
</sbb-action-group> | ||
</sbb-teaser-product-static> | ||
``` | ||
|
||
## Style | ||
|
||
Use the `image-alignment` attribute to anchor the content `after` (on the left) or `before` (on the right). | ||
|
||
```html | ||
<sbb-teaser-product-static image-alignment="before"> ... </sbb-teaser-product-static> | ||
``` | ||
|
||
Add the `negative` attribute to enable the negative variant. | ||
|
||
```html | ||
<sbb-teaser-product-static negative> ... </sbb-teaser-product-static> | ||
``` | ||
|
||
<!-- Auto Generated Below --> | ||
|
||
## Properties | ||
|
||
| Name | Attribute | Privacy | Type | Default | Description | | ||
| ---------------- | ----------------- | ------- | --------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `imageAlignment` | `image-alignment` | public | `'after' \| 'before'` | `'after'` | Whether the fully visible part of the image is aligned 'before' or 'after' the content. Only relevant starting from large breakpoint. | | ||
| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | | ||
|
||
## CSS Properties | ||
|
||
| Name | Default | Description | | ||
| ------------------------------------------------ | ------- | -------------------------------------------------------------------- | | ||
| `--sbb-teaser-product-background-gradient-end` | `75%` | At which percentage the background should be fully transparent. | | ||
| `--sbb-teaser-product-background-gradient-start` | `25%` | At which percentage the background should start getting transparent. | | ||
|
||
## Slots | ||
|
||
| Name | Description | | ||
| ---------- | ------------------------------------------------------------------- | | ||
| | Use this slot to provide the main content. | | ||
| `footnote` | Use this slot to provide a footnote. | | ||
| `image` | Use this slot to provide an image or a `sbb-image` as a background. | |
Oops, something went wrong.