diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-04-09 19:40:14 +0200 |
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-04-09 19:40:14 +0200 |
| commit | 355625b5dd1b4e2e52e6e5d0eee1a13d76c09fda (patch) | |
| tree | c1a4d04e386a04f37d46e912c1547a656fcd03e0 /src/components/atoms/layout | |
| parent | 7b9b5c2368ecff5b083b171cf38ce914746284ac (diff) | |
chore: add a Section component
Diffstat (limited to 'src/components/atoms/layout')
| -rw-r--r-- | src/components/atoms/layout/section.module.scss | 25 | ||||
| -rw-r--r-- | src/components/atoms/layout/section.stories.tsx | 85 | ||||
| -rw-r--r-- | src/components/atoms/layout/section.test.tsx | 17 | ||||
| -rw-r--r-- | src/components/atoms/layout/section.tsx | 57 |
4 files changed, 184 insertions, 0 deletions
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<typeof SectionComponent>; + +const Template: ComponentStory<typeof SectionComponent> = (args) => ( + <SectionComponent {...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(<Section title={title} content={content} />); + expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent(title); + }); + + it('renders a content', () => { + render(<Section title={title} content={content} />); + 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<SectionProps> = ({ + className = '', + content, + title, + variant = 'dark', + withBorder = true, +}) => { + const borderClass = withBorder ? styles[`wrapper--borders`] : ''; + const variantClass = styles[`wrapper--${variant}`]; + + return ( + <section + className={`${styles.wrapper} ${borderClass} ${variantClass} ${className}`} + > + <Heading level={2} className={styles.title}> + {title} + </Heading> + <div className={styles.body}>{content}</div> + </section> + ); +}; + +export default Section; |
