From 355625b5dd1b4e2e52e6e5d0eee1a13d76c09fda Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Sat, 9 Apr 2022 19:40:14 +0200 Subject: chore: add a Section component --- src/components/atoms/layout/section.module.scss | 25 ++++++++ src/components/atoms/layout/section.stories.tsx | 85 +++++++++++++++++++++++++ src/components/atoms/layout/section.test.tsx | 17 +++++ src/components/atoms/layout/section.tsx | 57 +++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 src/components/atoms/layout/section.module.scss create mode 100644 src/components/atoms/layout/section.stories.tsx create mode 100644 src/components/atoms/layout/section.test.tsx create mode 100644 src/components/atoms/layout/section.tsx (limited to 'src') diff --git a/src/components/atoms/layout/section.module.scss b/src/components/atoms/layout/section.module.scss new file mode 100644 index 0000000..012493a --- /dev/null +++ b/src/components/atoms/layout/section.module.scss @@ -0,0 +1,25 @@ +@use "@styles/abstracts/functions" as fun; +@use "@styles/abstracts/placeholders"; + +.wrapper { + @extend %grid; + + padding: var(--spacing-md) 0; + + &--borders { + border-bottom: fun.convert-px(1) solid var(--color-border); + } + + &--dark { + background: var(--color-bg-secondary); + } + + &--light { + background: var(--color-bg); + } +} + +.body, +.title { + grid-column: 2; +} diff --git a/src/components/atoms/layout/section.stories.tsx b/src/components/atoms/layout/section.stories.tsx new file mode 100644 index 0000000..abbbeed --- /dev/null +++ b/src/components/atoms/layout/section.stories.tsx @@ -0,0 +1,85 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import SectionComponent from './section'; + +export default { + title: 'Atoms/Layout', + component: SectionComponent, + args: { + variant: 'dark', + withBorder: true, + }, + argTypes: { + className: { + control: { + type: 'text', + }, + description: 'Set additional classnames to the section element.', + table: { + category: 'Styles', + }, + type: { + name: 'string', + required: false, + }, + }, + content: { + control: { + type: 'text', + }, + description: 'The section content.', + type: { + name: 'string', + required: true, + }, + }, + title: { + control: { + type: 'text', + }, + description: 'The section title.', + type: { + name: 'string', + required: true, + }, + }, + variant: { + control: { + type: 'select', + }, + description: 'The section variant.', + options: ['light', 'dark'], + table: { + category: 'Styles', + defaultValue: { summary: 'dark' }, + }, + type: { + name: 'string', + required: false, + }, + }, + withBorder: { + control: { + type: 'boolean', + }, + description: 'Add a border at the bottom of the section.', + table: { + category: 'Styles', + defaultValue: { summary: true }, + }, + type: { + name: 'boolean', + required: false, + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const Section = Template.bind({}); +Section.args = { + title: 'A title', + content: 'The content.', +}; diff --git a/src/components/atoms/layout/section.test.tsx b/src/components/atoms/layout/section.test.tsx new file mode 100644 index 0000000..ca5f03a --- /dev/null +++ b/src/components/atoms/layout/section.test.tsx @@ -0,0 +1,17 @@ +import { render, screen } from '@test-utils'; +import Section from './section'; + +const title = 'Section title'; +const content = 'Section content.'; + +describe('Section', () => { + it('renders a title (h2)', () => { + render(
); + expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent(title); + }); + + it('renders a content', () => { + render(
); + expect(screen.getByText(content)).toBeInTheDocument(); + }); +}); diff --git a/src/components/atoms/layout/section.tsx b/src/components/atoms/layout/section.tsx new file mode 100644 index 0000000..f1bbb34 --- /dev/null +++ b/src/components/atoms/layout/section.tsx @@ -0,0 +1,57 @@ +import { ReactNode, VFC } from 'react'; +import Heading from '../headings/heading'; +import styles from './section.module.scss'; + +export type SectionVariant = 'dark' | 'light'; + +export type SectionProps = { + /** + * Set additional classnames to the section element. + */ + className?: string; + /** + * The section content. + */ + content: ReactNode; + /** + * The section title. + */ + title: string; + /** + * The section variant. + */ + variant?: SectionVariant; + /** + * Add a border at the bottom of the section. Default: true. + */ + withBorder?: boolean; +}; + +/** + * Section component + * + * Render a section element. + */ +const Section: VFC = ({ + className = '', + content, + title, + variant = 'dark', + withBorder = true, +}) => { + const borderClass = withBorder ? styles[`wrapper--borders`] : ''; + const variantClass = styles[`wrapper--${variant}`]; + + return ( +
+ + {title} + +
{content}
+
+ ); +}; + +export default Section; -- cgit v1.2.3