diff options
Diffstat (limited to 'src/components')
| -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; | 
