diff options
| author | Armand Philippot <git@armandphilippot.com> | 2022-04-15 17:38:16 +0200 | 
|---|---|---|
| committer | Armand Philippot <git@armandphilippot.com> | 2022-04-15 17:42:28 +0200 | 
| commit | b3ac82bba9605fa9d9c4b1d29c5a56a52e9de015 (patch) | |
| tree | 1d3d9dcd6993f7b5ebf04218d57670dc751a239d /src/components/organisms | |
| parent | a07729064790df13324dbe7f4d1629892070558b (diff) | |
chore: add a SocialMedia component
Diffstat (limited to 'src/components/organisms')
4 files changed, 140 insertions, 0 deletions
| diff --git a/src/components/organisms/widgets/social-media.module.scss b/src/components/organisms/widgets/social-media.module.scss new file mode 100644 index 0000000..01b6c0e --- /dev/null +++ b/src/components/organisms/widgets/social-media.module.scss @@ -0,0 +1,10 @@ +@use "@styles/abstracts/placeholders"; + +.list { +  @extend %reset-list; + +  display: flex; +  flex-flow: row wrap; +  gap: var(--spacing-xs); +  padding: 0 var(--spacing-2xs); +} diff --git a/src/components/organisms/widgets/social-media.stories.tsx b/src/components/organisms/widgets/social-media.stories.tsx new file mode 100644 index 0000000..2b84012 --- /dev/null +++ b/src/components/organisms/widgets/social-media.stories.tsx @@ -0,0 +1,56 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { IntlProvider } from 'react-intl'; +import SocialMediaWidget, { Media } from './social-media'; + +export default { +  title: 'Organisms/Widgets', +  component: SocialMediaWidget, +  argTypes: { +    level: { +      control: { +        type: 'number', +      }, +      description: 'The heading level.', +      type: { +        name: 'number', +        required: true, +      }, +    }, +    media: { +      description: 'The links data.', +      type: { +        name: 'object', +        required: true, +        value: {}, +      }, +    }, +    title: { +      control: { +        type: 'text', +      }, +      description: 'The widget title.', +      type: { +        name: 'string', +        required: true, +      }, +    }, +  }, +} as ComponentMeta<typeof SocialMediaWidget>; + +const Template: ComponentStory<typeof SocialMediaWidget> = (args) => ( +  <IntlProvider locale="en"> +    <SocialMediaWidget {...args} /> +  </IntlProvider> +); + +const media: Media[] = [ +  { name: 'Github', url: '#' }, +  { name: 'LinkedIn', url: '#' }, +]; + +export const SocialMedia = Template.bind({}); +SocialMedia.args = { +  media, +  title: 'Follow me', +  level: 2, +}; diff --git a/src/components/organisms/widgets/social-media.test.tsx b/src/components/organisms/widgets/social-media.test.tsx new file mode 100644 index 0000000..e40db30 --- /dev/null +++ b/src/components/organisms/widgets/social-media.test.tsx @@ -0,0 +1,33 @@ +import { render, screen } from '@test-utils'; +import SocialMedia, { Media } from './social-media'; + +const media: Media[] = [ +  { name: 'Github', url: '#' }, +  { name: 'LinkedIn', url: '#' }, +]; +const title = 'Dolores ut ut'; +const titleLevel = 2; + +/** + * Next.js mock images with next/image component. So for now, I need to mock + * the svg files manually. + */ +jest.mock('@assets/images/social-media/github.svg', () => 'svg-file'); +jest.mock('@assets/images/social-media/linkedin.svg', () => 'svg-file'); + +describe('SocialMedia', () => { +  it('renders the widget title', () => { +    render(<SocialMedia media={media} title={title} level={titleLevel} />); +    expect( +      screen.getByRole('heading', { +        level: titleLevel, +        name: new RegExp(title, 'i'), +      }) +    ).toBeInTheDocument(); +  }); + +  it('renders the correct number of items', () => { +    render(<SocialMedia media={media} title={title} level={titleLevel} />); +    expect(screen.getAllByRole('listitem')).toHaveLength(media.length); +  }); +}); diff --git a/src/components/organisms/widgets/social-media.tsx b/src/components/organisms/widgets/social-media.tsx new file mode 100644 index 0000000..58b2f73 --- /dev/null +++ b/src/components/organisms/widgets/social-media.tsx @@ -0,0 +1,41 @@ +import SocialLink, { +  type SocialLinkProps, +} from '@components/atoms/links/social-link'; +import Widget, { type WidgetProps } from '@components/molecules/layout/widget'; +import { FC } from 'react'; +import styles from './social-media.module.scss'; + +export type Media = SocialLinkProps; + +export type SocialMediaProps = Pick<WidgetProps, 'level' | 'title'> & { +  media: Media[]; +}; + +/** + * Social Media widget component + * + * Render a social media list with links. + */ +const SocialMedia: FC<SocialMediaProps> = ({ media, ...props }) => { +  /** +   * Retrieve the social media items. +   * +   * @param {SocialMedia[]} links - An array of social media name and url. +   * @returns {JSX.Element[]} The social links. +   */ +  const getItems = (links: Media[]): JSX.Element[] => { +    return links.map((link, index) => ( +      <li key={`media-${index}`}> +        <SocialLink name={link.name} url={link.url} /> +      </li> +    )); +  }; + +  return ( +    <Widget expanded={true} {...props}> +      <ul className={styles.list}>{getItems(media)}</ul> +    </Widget> +  ); +}; + +export default SocialMedia; | 
