diff options
Diffstat (limited to 'src/components/molecules/layout')
| -rw-r--r-- | src/components/molecules/layout/modal.module.scss | 21 | ||||
| -rw-r--r-- | src/components/molecules/layout/modal.stories.tsx | 57 | ||||
| -rw-r--r-- | src/components/molecules/layout/modal.test.tsx | 9 | ||||
| -rw-r--r-- | src/components/molecules/layout/modal.tsx | 48 | 
4 files changed, 135 insertions, 0 deletions
| diff --git a/src/components/molecules/layout/modal.module.scss b/src/components/molecules/layout/modal.module.scss new file mode 100644 index 0000000..2fff562 --- /dev/null +++ b/src/components/molecules/layout/modal.module.scss @@ -0,0 +1,21 @@ +@use "@styles/abstracts/functions" as fun; + +.wrapper { +  padding: var(--spacing-md); +  background: var(--color-bg-secondary); +  border: fun.convert-px(4) solid; +  border-image: radial-gradient( +      ellipse at top, +      var(--color-primary-lighter) 20%, +      var(--color-primary) 100% +    ) +    1; +  box-shadow: fun.convert-px(2) fun.convert-px(-2) fun.convert-px(3) +    fun.convert-px(-1) var(--color-shadow-dark); +} + +.icon { +  --icon-size: #{fun.convert-px(30)}; + +  margin-right: var(--spacing-2xs); +} diff --git a/src/components/molecules/layout/modal.stories.tsx b/src/components/molecules/layout/modal.stories.tsx new file mode 100644 index 0000000..396e89e --- /dev/null +++ b/src/components/molecules/layout/modal.stories.tsx @@ -0,0 +1,57 @@ +import Cog from '@components/atoms/icons/cog'; +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import ModalComponent from './modal'; + +export default { +  title: 'Molecules/Layout', +  component: ModalComponent, +  argTypes: { +    children: { +      control: { +        type: 'text', +      }, +      description: 'The modal body.', +      type: { +        name: 'string', +        required: true, +      }, +    }, +    icon: { +      control: { +        type: 'select', +      }, +      description: 'The title icon.', +      options: ['', 'cogs', 'search'], +      table: { +        category: 'Options', +      }, +      type: { +        name: 'string', +        required: false, +      }, +    }, +    title: { +      control: { +        type: 'text', +      }, +      description: 'The modal title.', +      table: { +        category: 'Options', +      }, +      type: { +        name: 'string', +        required: false, +      }, +    }, +  }, +} as ComponentMeta<typeof ModalComponent>; + +const Template: ComponentStory<typeof ModalComponent> = (args) => ( +  <ModalComponent {...args} /> +); + +export const Modal = Template.bind({}); +Modal.args = { +  children: +    'Inventore natus dignissimos aut illum modi asperiores. Et voluptatibus delectus.', +}; diff --git a/src/components/molecules/layout/modal.test.tsx b/src/components/molecules/layout/modal.test.tsx new file mode 100644 index 0000000..14fb224 --- /dev/null +++ b/src/components/molecules/layout/modal.test.tsx @@ -0,0 +1,9 @@ +import { render, screen } from '@test-utils'; +import Modal from './modal'; + +describe('Modal', () => { +  it('renders a title', () => { +    render(<Modal title="A custom title" />); +    expect(screen.getByText('A custom title')).toBeInTheDocument(); +  }); +}); diff --git a/src/components/molecules/layout/modal.tsx b/src/components/molecules/layout/modal.tsx new file mode 100644 index 0000000..4dc3b0a --- /dev/null +++ b/src/components/molecules/layout/modal.tsx @@ -0,0 +1,48 @@ +import Heading from '@components/atoms/headings/heading'; +import dynamic from 'next/dynamic'; +import { FC, ReactNode } from 'react'; +import styles from './modal.module.scss'; + +export type Icons = 'cogs' | 'search'; + +export type ModalProps = { +  icon?: Icons; +  title?: string; +}; + +const CogIcon = dynamic<ReactNode>(() => import('@components/atoms/icons/cog')); +const SearchIcon = dynamic<ReactNode>( +  () => import('@components/atoms/icons/magnifying-glass') +); + +/** + * Modal component + * + * Render a modal component with an optional title and icon. + */ +const Modal: FC<ModalProps> = ({ children, icon, title }) => { +  const getIcon = (id: Icons) => { +    switch (id) { +      case 'cogs': +        return <CogIcon />; +      case 'search': +        return <SearchIcon />; +      default: +        return <></>; +    } +  }; + +  return ( +    <div className={styles.wrapper}> +      {title && ( +        <Heading isFake={true} level={3}> +          {icon && <span className={styles.icon}>{getIcon(icon)}</span>} +          {title} +        </Heading> +      )} +      {children} +    </div> +  ); +}; + +export default Modal; | 
