-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(styles, documentation): teaser card component (#4460)
Co-authored-by: Philipp Gfeller <[email protected]>
- Loading branch information
Showing
7 changed files
with
323 additions
and
0 deletions.
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,6 @@ | ||
--- | ||
'@swisspost/design-system-documentation': minor | ||
'@swisspost/design-system-styles': minor | ||
--- | ||
|
||
Added Teaser Card component. |
7 changes: 7 additions & 0 deletions
7
packages/documentation/cypress/snapshots/components/teaser.snapshot.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,7 @@ | ||
describe('Teaser', () => { | ||
it('default', () => { | ||
cy.visit('/iframe.html?id=snapshots--teaser'); | ||
cy.get('.teaser-container', { timeout: 30000 }).should('be.visible'); | ||
cy.percySnapshot('Teaser', { widths: [1440] }); | ||
}); | ||
}); |
29 changes: 29 additions & 0 deletions
29
packages/documentation/src/stories/components/teaser/teaser.docs.mdx
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,29 @@ | ||
import { Canvas, Controls, Meta } from '@storybook/blocks'; | ||
import * as TeaserStories from './teaser.stories'; | ||
|
||
<Meta of={TeaserStories} /> | ||
|
||
<div className="docs-title"> | ||
# Teaser Card | ||
|
||
<nav> | ||
<link-design of={JSON.stringify(TeaserStories)}></link-design> | ||
</nav> | ||
</div> | ||
|
||
<p className="lead"> | ||
A teaser card is a clickable preview that leads to detailed content, providing a convenient entry | ||
point for users to access more information. It contains maximum one interactive element (button) | ||
which links to the same location as the card.{' '} | ||
</p> | ||
|
||
<Canvas sourceState="shown" of={TeaserStories.Default} /> | ||
<div className="hide-col-default"> | ||
<Controls of={TeaserStories.Default} /> | ||
</div> | ||
|
||
## Teaser section | ||
|
||
The teaser card component will take the full width of its container and should be implemented within a grid system. Here is an example of what a teaser section would look like. | ||
|
||
<Canvas sourceState="shown" of={TeaserStories.Section} /> |
42 changes: 42 additions & 0 deletions
42
packages/documentation/src/stories/components/teaser/teaser.snapshot.stories.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,42 @@ | ||
import { Args, StoryContext, StoryObj } from '@storybook/web-components'; | ||
import { html } from 'lit'; | ||
import { schemes } from '@/shared/snapshots/schemes'; | ||
|
||
import meta, { renderTeaserCard, renderTeaserSectionHeader } from './teaser.stories'; | ||
|
||
const { id, ...metaWithoutId } = meta; | ||
|
||
export default { | ||
...metaWithoutId, | ||
title: 'Snapshots', | ||
}; | ||
|
||
type Story = StoryObj; | ||
|
||
export const Teaser: Story = { | ||
render: (_args: Args, context: StoryContext) => { | ||
return schemes( | ||
() => html` | ||
<div class="d-flex flex-column gap-16"> | ||
${['sm', 'lg'].map((size: string) => { | ||
const args = { | ||
...context.args, | ||
size, | ||
}; | ||
return html` | ||
<div class="teaser-container container py-56 d-flex flex-column gap-32"> | ||
${renderTeaserSectionHeader(args.size)} | ||
<div class="row gy-16 gy-lg-24"> | ||
${Array.from( | ||
{ length: 4 }, | ||
() => html` <div class="col-md-6 col-lg-3">${renderTeaserCard(args)}</div> `, | ||
)} | ||
</div> | ||
</div> | ||
`; | ||
})} | ||
</div> | ||
`, | ||
); | ||
}, | ||
}; |
124 changes: 124 additions & 0 deletions
124
packages/documentation/src/stories/components/teaser/teaser.stories.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,124 @@ | ||
import { Args, StoryObj } from '@storybook/web-components'; | ||
import { html } from 'lit'; | ||
import { MetaComponent } from '@root/types'; | ||
|
||
const meta: MetaComponent = { | ||
id: '68699b2c-ec1f-467d-81ae-8b3f48d7c595', | ||
title: 'Components/Teaser Card', | ||
tags: ['package:HTML'], | ||
parameters: { | ||
design: { | ||
type: 'figma', | ||
url: 'https://www.figma.com/design/JIT5AdGYqv6bDRpfBPV8XR/Foundations-%26-Components-Next-Level?node-id=3850-8203', | ||
}, | ||
}, | ||
args: { | ||
size: 'sm', | ||
title: 'Title', | ||
buttonLabel: 'Button label', | ||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', | ||
}, | ||
argTypes: { | ||
title: { | ||
name: 'Title', | ||
description: 'Title of the teaser card', | ||
control: { | ||
type: 'text', | ||
}, | ||
table: { | ||
category: 'Content', | ||
}, | ||
}, | ||
content: { | ||
name: 'Content', | ||
description: 'Content of the teaser card', | ||
control: { | ||
type: 'text', | ||
}, | ||
table: { | ||
category: 'Content', | ||
}, | ||
}, | ||
buttonLabel: { | ||
name: 'Button label', | ||
description: 'Button label of the teaser card', | ||
control: { | ||
type: 'text', | ||
}, | ||
table: { | ||
category: 'Content', | ||
}, | ||
}, | ||
size: { | ||
name: 'Size', | ||
description: 'Size of the teaser card', | ||
control: { | ||
type: 'radio', | ||
labels: { | ||
sm: 'Small (default)', | ||
lg: 'Large', | ||
}, | ||
}, | ||
options: ['sm', 'lg'], | ||
table: { | ||
category: 'General', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj; | ||
|
||
export function renderTeaserCard(args: Args) { | ||
return html`<div class="teaser-card${args.size === 'lg' ? ' teaser-card-lg' : ''}"> | ||
<img src="https://picsum.photos/id/38/500/400" alt="My placeholder image"> | ||
<div> | ||
<div> | ||
<h3>${args.title}</h3> | ||
<p>${args.content}</p> | ||
</div> | ||
<a href="#" class="btn btn-tertiary px-0">${ | ||
args.buttonLabel | ||
} <post-icon name="arrowright"></post-icon></post-icon></a> | ||
</div> | ||
</div> | ||
`; | ||
} | ||
|
||
export function renderTeaserSectionHeader(size?: string) { | ||
return html` <div class="d-flex align-items-end justify-content-between gap-24"> | ||
<div class="d-flex flex-column gap-8"> | ||
<h2 class="m-0">Teaser section ${size}</h2> | ||
<p class="m-0"> | ||
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempo. | ||
</p> | ||
</div> | ||
<a href="#" class="flex-shrink-0 btn btn-primary" | ||
>Let's go <post-icon name="arrowright"></post-icon | ||
></a> | ||
</div>`; | ||
} | ||
|
||
export const Default: Story = { | ||
render: renderTeaserCard, | ||
decorators: [story => html`<div style="max-width: 400px;">${story()}</div>`], | ||
}; | ||
|
||
export const Section: Story = { | ||
parameters: { | ||
layout: 'fullscreen', | ||
}, | ||
render: args => html` | ||
<div class="container py-56 d-flex flex-column gap-32"> | ||
${renderTeaserSectionHeader()} | ||
<div class="row gy-16 gy-lg-24"> | ||
${Array.from( | ||
{ length: 4 }, | ||
() => html` <div class="col-md-6 col-lg-3">${renderTeaserCard(args)}</div> `, | ||
)} | ||
</div> | ||
</div> | ||
`, | ||
}; |
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
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,114 @@ | ||
@use '../tokens/components'; | ||
@use '../functions/tokens'; | ||
@use '../mixins/utilities'; | ||
|
||
tokens.$default-map: components.$post-teaser; | ||
|
||
.teaser-card { | ||
height: 100%; | ||
box-shadow: tokens.get('card-interactive-elevation', components.$post-cards); | ||
border-radius: tokens.get('card-border-radius', components.$post-cards); | ||
position: relative; | ||
background-color: tokens.get('teaser-card-enabled-bg'); | ||
color: tokens.get('teaser-card-content-enabled-fg'); | ||
display: flex; | ||
flex-direction: column; | ||
transition: | ||
background-color 150ms, | ||
color 150ms; | ||
|
||
&:hover { | ||
background-color: tokens.get('teaser-card-hover-bg'); | ||
color: tokens.get('teaser-card-content-hover-fg'); | ||
} | ||
|
||
a.btn { | ||
position: unset; | ||
outline-style: none !important; | ||
|
||
&::before { | ||
content: ''; | ||
position: absolute; | ||
top: 0; | ||
left: 0; | ||
width: 100%; | ||
height: 100%; | ||
cursor: pointer; | ||
border-radius: tokens.get('card-border-radius', components.$post-cards); | ||
} | ||
|
||
@include utilities.focus-style('::before'); | ||
} | ||
|
||
img { | ||
height: tokens.get('teaser-card-sm-image-height'); | ||
min-height: tokens.get('teaser-card-sm-image-height'); | ||
width: 100%; | ||
object-fit: cover; | ||
border-top-left-radius: tokens.get('card-border-radius', components.$post-cards); | ||
border-top-right-radius: tokens.get('card-border-radius', components.$post-cards); | ||
} | ||
|
||
h1, | ||
h2, | ||
h3, | ||
h4, | ||
h5, | ||
h6, | ||
p { | ||
margin: 0; | ||
word-break: break-word; | ||
} | ||
|
||
h1, | ||
h2, | ||
h3, | ||
h4, | ||
h5, | ||
h6 { | ||
font-size: tokens.get('teaser-card-sm-heading-font-size'); | ||
} | ||
|
||
// Card content (text + button) | ||
> div { | ||
display: flex; | ||
flex-direction: column; | ||
align-items: flex-start; | ||
padding: tokens.get('teaser-card-sm-section-content-padding'); | ||
gap: tokens.get('teaser-card-sm-section-content-gap'); | ||
height: 100%; | ||
justify-content: space-between; | ||
|
||
// Card text button | ||
> div { | ||
display: flex; | ||
flex-direction: column; | ||
gap: tokens.get('teaser-card-sm-content-gap'); | ||
} | ||
} | ||
|
||
&.teaser-card-lg { | ||
img { | ||
height: tokens.get('teaser-card-lg-image-height'); | ||
min-height: tokens.get('teaser-card-lg-image-height'); | ||
} | ||
|
||
h1, | ||
h2, | ||
h3, | ||
h4, | ||
h5, | ||
h6 { | ||
font-size: tokens.get('teaser-card-lg-heading-font-size'); | ||
} | ||
|
||
> div { | ||
padding: tokens.get('teaser-card-lg-section-content-padding'); | ||
gap: tokens.get('teaser-card-lg-section-content-gap'); | ||
|
||
> div { | ||
gap: tokens.get('teaser-card-lg-content-gap'); | ||
} | ||
} | ||
} | ||
} |