diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/atoms/links/social-link.module.scss | 43 | ||||
| -rw-r--r-- | src/components/atoms/links/social-link.stories.tsx | 40 | ||||
| -rw-r--r-- | src/components/atoms/links/social-link.test.tsx | 15 | ||||
| -rw-r--r-- | src/components/atoms/links/social-link.tsx | 51 | 
4 files changed, 149 insertions, 0 deletions
| diff --git a/src/components/atoms/links/social-link.module.scss b/src/components/atoms/links/social-link.module.scss new file mode 100644 index 0000000..02fc61c --- /dev/null +++ b/src/components/atoms/links/social-link.module.scss @@ -0,0 +1,43 @@ +@use "@styles/abstracts/functions" as fun; + +.link { +  display: flex; +  width: var(--link-size, #{fun.convert-px(60)}); +  height: var(--link-size, #{fun.convert-px(60)}); +  box-shadow: fun.convert-px(1) fun.convert-px(1) fun.convert-px(1) +      var(--color-shadow), +    fun.convert-px(1) fun.convert-px(2) fun.convert-px(2) fun.convert-px(-1) +      var(--color-shadow), +    fun.convert-px(3) fun.convert-px(4) fun.convert-px(4) fun.convert-px(-3) +      var(--color-shadow), +    0 0 0 0 var(--color-shadow); +  transition: all 0.25s linear 0s; + +  &:hover, +  &:focus { +    box-shadow: fun.convert-px(1) fun.convert-px(1) fun.convert-px(1) +        var(--color-shadow), +      fun.convert-px(1) fun.convert-px(1) fun.convert-px(2) fun.convert-px(-1) +        var(--color-shadow-light), +      fun.convert-px(3) fun.convert-px(3) fun.convert-px(4) fun.convert-px(-4) +        var(--color-shadow-light), +      fun.convert-px(6) fun.convert-px(6) fun.convert-px(10) fun.convert-px(-3) +        var(--color-shadow); +    transform: scale(1.15); +  } + +  &:focus { +    outline: var(--color-primary) dashed fun.convert-px(2); +  } + +  &:active { +    box-shadow: 0 0 0 0 var(--color-shadow); +    outline: none; +    transform: scale(0.9); +  } +} + +.icon { +  max-width: 100%; +  max-height: 100%; +} diff --git a/src/components/atoms/links/social-link.stories.tsx b/src/components/atoms/links/social-link.stories.tsx new file mode 100644 index 0000000..bd9a364 --- /dev/null +++ b/src/components/atoms/links/social-link.stories.tsx @@ -0,0 +1,40 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import SocialLinkComponent from './social-link'; + +export default { +  title: 'Atoms/Links', +  component: SocialLinkComponent, +  argTypes: { +    name: { +      control: { +        type: 'select', +      }, +      description: 'Social website name.', +      options: ['Github', 'Gitlab', 'LinkedIn', 'Twitter'], +      type: { +        name: 'string', +        required: true, +      }, +    }, +    url: { +      control: { +        type: null, +      }, +      description: 'Social profile url.', +      type: { +        name: 'string', +        required: true, +      }, +    }, +  }, +} as ComponentMeta<typeof SocialLinkComponent>; + +const Template: ComponentStory<typeof SocialLinkComponent> = (args) => ( +  <SocialLinkComponent {...args} /> +); + +export const SocialLink = Template.bind({}); +SocialLink.args = { +  name: 'Github', +  url: '#', +}; diff --git a/src/components/atoms/links/social-link.test.tsx b/src/components/atoms/links/social-link.test.tsx new file mode 100644 index 0000000..f49fb5a --- /dev/null +++ b/src/components/atoms/links/social-link.test.tsx @@ -0,0 +1,15 @@ +import { render, screen } from '@test-utils'; +import SocialLink from './social-link'; + +/** + * Next.js mock images to use next/image component. So for now, I need to mock + * the svg files manually. + */ +jest.mock('@assets/images/social-media/github.svg', () => 'svg-file'); + +describe('SocialLink', () => { +  it('render a social link', () => { +    render(<SocialLink name="Github" url="#" />); +    expect(screen.getByRole('link')).toHaveAccessibleName('Github'); +  }); +}); diff --git a/src/components/atoms/links/social-link.tsx b/src/components/atoms/links/social-link.tsx new file mode 100644 index 0000000..489c8b4 --- /dev/null +++ b/src/components/atoms/links/social-link.tsx @@ -0,0 +1,51 @@ +import GithubIcon from '@assets/images/social-media/github.svg'; +import GitlabIcon from '@assets/images/social-media/gitlab.svg'; +import LinkedInIcon from '@assets/images/social-media/linkedin.svg'; +import TwitterIcon from '@assets/images/social-media/twitter.svg'; +import { FC } from 'react'; +import styles from './social-link.module.scss'; + +type SocialLinkProps = { +  /** +   * The social website name. +   */ +  name: 'Github' | 'Gitlab' | 'LinkedIn' | 'Twitter'; +  /** +   * The social profile url. +   */ +  url: string; +}; + +/** + * SocialLink component + * + * Render a social icon link. + */ +const SocialLink: FC<SocialLinkProps> = ({ name, url }) => { +  /** +   * Retrieve a social link icon by id. +   * @param {string} id - The social website id. +   */ +  const getIcon = (id: string) => { +    switch (id) { +      case 'Github': +        return <GithubIcon className={styles.icon} aria-hidden="true" />; +      case 'Gitlab': +        return <GitlabIcon className={styles.icon} aria-hidden="true" />; +      case 'LinkedIn': +        return <LinkedInIcon className={styles.icon} aria-hidden="true" />; +      case 'Twitter': +        return <TwitterIcon className={styles.icon} aria-hidden="true" />; +      default: +        break; +    } +  }; + +  return ( +    <a href={url} className={styles.link} aria-label={name}> +      {getIcon(name)} +    </a> +  ); +}; + +export default SocialLink; | 
