-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OPHJOD-281: Add color card component
- Loading branch information
Showing
3 changed files
with
247 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,140 @@ | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { ColorCard } from './ColorCard'; | ||
|
||
const meta = { | ||
title: 'Primitives/Cards/ColorCard', | ||
component: ColorCard, | ||
tags: ['autodocs'], | ||
} satisfies Meta<typeof ColorCard>; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof meta>; | ||
|
||
const secondaryCardArgs = { | ||
title: 'Tunnista osaamistasi ja tutki mahdollisuuksia', | ||
backgroundColor: '#00A8B3F2', | ||
}; | ||
|
||
export const Primary: Story = { | ||
parameters: { | ||
design: { | ||
type: 'figma', | ||
url: 'https://www.figma.com/file/LP7Acqn5dNNHS0R1YUWM1n/cx_jod_sb?node-id=98%3A43037', | ||
}, | ||
docs: { | ||
description: { | ||
story: 'This is a primary color card component.', | ||
}, | ||
}, | ||
backgrounds: { | ||
default: 'light', | ||
}, | ||
}, | ||
args: { | ||
title: 'Astu rohkeasti muutokseen! Tutki mahdollisuuksiasi, suunnittele polkusi ja luo tulevaisuutesi.', | ||
content: | ||
'Elämä on jatkuvaa muutosta ja uudistumista. Olipa kyse uran vaihdosta, uuden osaamisen oppimisesta tai henkilökohtaisen elämäntilanteen parantamisesta, me tarjoamme sinulle tiedon ja inspiraation joita tarvitset.', | ||
backgroundColor: '#006DB3F2', | ||
actionContent: 'Kokeile palvelua', | ||
}, | ||
decorators: [ | ||
(Story) => ( | ||
<div className="mb-[30px] max-w-2xl"> | ||
<Story /> | ||
</div> | ||
), | ||
], | ||
}; | ||
|
||
export const Secondary: Story = { | ||
parameters: { | ||
design: { | ||
type: 'figma', | ||
url: 'https://www.figma.com/file/LP7Acqn5dNNHS0R1YUWM1n/cx_jod_sb?node-id=98%3A43040', | ||
}, | ||
docs: { | ||
description: { | ||
story: 'This is a secondary color card component.', | ||
}, | ||
}, | ||
}, | ||
args: { | ||
title: secondaryCardArgs.title, | ||
}, | ||
decorators: [ | ||
(Story) => ( | ||
<div className="max-w-xs"> | ||
<Story /> | ||
</div> | ||
), | ||
], | ||
}; | ||
|
||
export const MultipleSecondary: Story = { | ||
parameters: { | ||
design: { | ||
type: 'figma', | ||
url: 'https://www.figma.com/file/LP7Acqn5dNNHS0R1YUWM1n/cx_jod_sb?node-id=98%3A42967', | ||
}, | ||
docs: { | ||
description: { | ||
story: 'Multiple color card components.', | ||
}, | ||
}, | ||
}, | ||
args: secondaryCardArgs, | ||
decorators: [ | ||
(Story) => ( | ||
<div className="grid grid-flow-row auto-rows-max grid-cols-3 gap-[32px] lg:container"> | ||
<Story /> | ||
<Story | ||
args={{ title: 'Tutustu miten käytät palvelua ja luot oman tulevaisuutesi', backgroundColor: '#EE7C45F2' }} | ||
/> | ||
<Story args={{ title: 'Luo oma profiili ja suunnittele polkusi', backgroundColor: '#CD4EB3F2' }} /> | ||
</div> | ||
), | ||
], | ||
}; | ||
|
||
export const Hero: Story = { | ||
parameters: { | ||
design: { | ||
type: 'figma', | ||
url: 'https://www.figma.com/file/LP7Acqn5dNNHS0R1YUWM1n/cx_jod_sb?node-id=98%3A43037', | ||
}, | ||
docs: { | ||
description: { | ||
story: 'This is a hero component with multiple color card components.', | ||
}, | ||
}, | ||
backgrounds: { | ||
default: 'light', | ||
}, | ||
layout: 'fullscreen', | ||
}, | ||
args: { | ||
title: 'Astu rohkeasti muutokseen! Tutki mahdollisuuksiasi, suunnittele polkusi ja luo tulevaisuutesi.', | ||
content: | ||
'Elämä on jatkuvaa muutosta ja uudistumista. Olipa kyse uran vaihdosta, uuden osaamisen oppimisesta tai henkilökohtaisen elämäntilanteen parantamisesta, me tarjoamme sinulle tiedon ja inspiraation joita tarvitset.', | ||
backgroundColor: '#006DB3F2', | ||
actionContent: 'Kokeile palvelua', | ||
}, | ||
decorators: [ | ||
(Story) => ( | ||
<div className="mx-auto flex flex-col gap-[104px] bg-[url('https://images.unsplash.com/photo-1523464862212-d6631d073194?q=80&w=2070')] bg-[length:2000px_cover] bg-[top_-6rem_left_-10rem] p-8 lg:container"> | ||
<div className="mb-[30px] max-w-2xl"> | ||
<Story /> | ||
</div> | ||
<div className="grid grid-flow-row auto-rows-max grid-cols-3 gap-[32px] lg:container"> | ||
<Story args={secondaryCardArgs} /> | ||
<Story | ||
args={{ title: 'Tutustu miten käytät palvelua ja luot oman tulevaisuutesi', backgroundColor: '#EE7C45F2' }} | ||
/> | ||
<Story args={{ title: 'Luo oma profiili ja suunnittele polkusi', backgroundColor: '#CD4EB3F2' }} /> | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { afterEach, describe, it, expect } from 'vitest'; | ||
import { render, screen, cleanup } from '@testing-library/react'; | ||
import '@testing-library/jest-dom'; | ||
|
||
import { ColorCard } from './ColorCard'; | ||
|
||
afterEach(() => { | ||
cleanup(); | ||
}); | ||
|
||
describe('ColorCard', () => { | ||
const title = 'Test Title'; | ||
const content = 'Test Content'; | ||
const actionContent = 'Test Action Content'; | ||
const backgroundColor = '#444BACF2'; | ||
|
||
it('renders ColorCard with actionContent', () => { | ||
render( | ||
<ColorCard title={title} content={content} actionContent={actionContent} backgroundColor={backgroundColor} />, | ||
); | ||
|
||
// Assert title, content, and actionContent are rendered | ||
expect(screen.getByText(title)).toBeInTheDocument(); | ||
expect(screen.getByText(content)).toBeInTheDocument(); | ||
expect(screen.getByText(actionContent)).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders ColorCard with a link when actionContent is provided', () => { | ||
render( | ||
<ColorCard title={title} content={content} actionContent={actionContent} backgroundColor={backgroundColor} />, | ||
); | ||
|
||
// Assert ColorCard is wrapped in a link | ||
const linkElement = screen.getByRole('link'); | ||
expect(linkElement).toBeInTheDocument(); | ||
}); | ||
|
||
it('renders ColorCard without actionContent', () => { | ||
render(<ColorCard title={title} content={content} backgroundColor={backgroundColor} />); | ||
|
||
// Assert title and content are rendered | ||
expect(screen.getByText(title)).toBeInTheDocument(); | ||
expect(screen.getByText(content)).toBeInTheDocument(); | ||
|
||
// Assert actionContent is not rendered | ||
expect(screen.queryByText(actionContent)).toBeNull(); | ||
}); | ||
|
||
it('renders ColorCard with a link when actionContent is not provided', () => { | ||
render(<ColorCard title={title} content={content} backgroundColor={backgroundColor} />); | ||
|
||
// Assert ColorCard is wrapped in a link | ||
const linkElement = screen.getByRole('link'); | ||
expect(linkElement).toBeInTheDocument(); | ||
}); | ||
}); |
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,51 @@ | ||
export interface ColorCardProps { | ||
/** Title text shown on the card */ | ||
title: string; | ||
/** Content text shown on the card */ | ||
content?: string; | ||
/** Action content shown on the card */ | ||
actionContent?: string; | ||
/** Background color of the card */ | ||
backgroundColor?: string; | ||
} | ||
|
||
export const ColorCard = ({ title, content, actionContent, backgroundColor = '#444BACF2' }: ColorCardProps) => ( | ||
<> | ||
{actionContent ? ( | ||
<BaseCard title={title} content={content} actionContent={actionContent} backgroundColor={backgroundColor} /> | ||
) : ( | ||
<a href="/" className="flex rounded-[28px] outline-none transition-transform hover:scale-105 focus:scale-105"> | ||
<BaseCard title={title} content={content} actionContent={actionContent} backgroundColor={backgroundColor} /> | ||
</a> | ||
)} | ||
</> | ||
); | ||
|
||
const BaseCard = ({ title, content, actionContent, backgroundColor }: ColorCardProps) => { | ||
const Heading = actionContent ? 'h1' : 'h2'; | ||
return ( | ||
<div | ||
className={`relative flex flex-col gap-[24px] rounded-[28px] px-[32px] pb-[64px] pt-[32px] text-white`} | ||
style={{ backgroundColor }} | ||
> | ||
<Heading className="overflow hyphens-auto text-pretty text-[28px] font-bold leading-[34px]">{title}</Heading> | ||
{content && <p>{content}</p>} | ||
{actionContent ? ( | ||
<a | ||
href="/" | ||
className="absolute bottom-0 right-[32px] translate-y-2/4 rounded-[40px] outline-none transition-transform hover:scale-105 focus:scale-105" | ||
> | ||
<div | ||
className="flex select-none gap-4 rounded-[40px] bg-white px-[40px] py-[20px] text-[28px] font-bold leading-[38px]" | ||
style={{ color: backgroundColor }} | ||
> | ||
{actionContent} | ||
<i>→</i> | ||
</div> | ||
</a> | ||
) : ( | ||
<i className="absolute bottom-[14px] right-[32px] select-none text-[28px] font-bold leading-[32px]">→</i> | ||
)} | ||
</div> | ||
); | ||
}; |