Skip to content

Commit

Permalink
feat(styles, documentation): teaser card component (#4460)
Browse files Browse the repository at this point in the history
Co-authored-by: Philipp Gfeller <[email protected]>
  • Loading branch information
leagrdv and gfellerph authored Jan 20, 2025
1 parent 006f442 commit 39fd2ae
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .changeset/silent-ears-drive.md
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.
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] });
});
});
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} />
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 packages/documentation/src/stories/components/teaser/teaser.stories.ts
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>
`,
};
1 change: 1 addition & 0 deletions packages/styles/src/components/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
@use 'subnavigation';
@use 'tables';
@use 'tabs';
@use 'teaser';
@use 'text-highlight';
@use 'timepicker';
@use 'toast';
Expand Down
114 changes: 114 additions & 0 deletions packages/styles/src/components/teaser.scss
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');
}
}
}
}

0 comments on commit 39fd2ae

Please sign in to comment.