Skip to content

Commit

Permalink
OPHJOD-281: Add color card component
Browse files Browse the repository at this point in the history
  • Loading branch information
sauanto committed Mar 27, 2024
1 parent d296a84 commit 1bc13fd
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 0 deletions.
140 changes: 140 additions & 0 deletions lib/components/ColorCard/ColorCard.stories.tsx
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>
),
],
};
56 changes: 56 additions & 0 deletions lib/components/ColorCard/ColorCard.test.tsx
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();
});
});
51 changes: 51 additions & 0 deletions lib/components/ColorCard/ColorCard.tsx
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>
);
};

0 comments on commit 1bc13fd

Please sign in to comment.