From a3fb0aa94717aafae897ac293488c43a099c0b2b Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Tue, 3 Oct 2023 18:52:57 +0200 Subject: refactor(components): rewrite SharingLink component * replace default label with label prop * simplify CSS rules --- .../atoms/links/sharing-link.module.scss | 157 --------------------- .../atoms/links/sharing-link.stories.tsx | 98 ------------- src/components/atoms/links/sharing-link.test.tsx | 47 ------ src/components/atoms/links/sharing-link.tsx | 47 ------ src/components/atoms/links/sharing-link/index.ts | 1 + .../links/sharing-link/sharing-link.module.scss | 88 ++++++++++++ .../links/sharing-link/sharing-link.stories.tsx | 114 +++++++++++++++ .../atoms/links/sharing-link/sharing-link.test.tsx | 83 +++++++++++ .../atoms/links/sharing-link/sharing-link.tsx | 51 +++++++ 9 files changed, 337 insertions(+), 349 deletions(-) delete mode 100644 src/components/atoms/links/sharing-link.module.scss delete mode 100644 src/components/atoms/links/sharing-link.stories.tsx delete mode 100644 src/components/atoms/links/sharing-link.test.tsx delete mode 100644 src/components/atoms/links/sharing-link.tsx create mode 100644 src/components/atoms/links/sharing-link/index.ts create mode 100644 src/components/atoms/links/sharing-link/sharing-link.module.scss create mode 100644 src/components/atoms/links/sharing-link/sharing-link.stories.tsx create mode 100644 src/components/atoms/links/sharing-link/sharing-link.test.tsx create mode 100644 src/components/atoms/links/sharing-link/sharing-link.tsx (limited to 'src/components/atoms') diff --git a/src/components/atoms/links/sharing-link.module.scss b/src/components/atoms/links/sharing-link.module.scss deleted file mode 100644 index 089fd13..0000000 --- a/src/components/atoms/links/sharing-link.module.scss +++ /dev/null @@ -1,157 +0,0 @@ -@use "../../../styles/abstracts/functions" as fun; - -.link { - display: inline-flex; - align-items: center; - padding: var(--spacing-2xs) var(--spacing-xs); - border-radius: fun.convert-px(3); - - &:hover, - &:focus { - transform: translateX(#{fun.convert-px(-3)}) - translateY(#{fun.convert-px(-3)}); - } - - &:active { - transform: translateX(#{fun.convert-px(2)}) translateY(#{fun.convert-px(2)}); - } - - &::before { - content: ""; - display: block; - width: fun.convert-px(30); - height: fun.convert-px(30); - background-repeat: no-repeat; - filter: drop-shadow( - #{fun.convert-px(1)} #{fun.convert-px(1)} #{fun.convert-px(1)} hsl(0, 0%, 0%) - ); - } - - &--diaspora { - background: hsl(0, 0%, 13%); - box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(0, 0%, 3%); - - &:hover, - &:focus { - box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 hsl(0, 0%, 3%); - } - - &:active { - box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 hsl(0, 0%, 3%); - } - - &::before { - background-image: url(fun.encode-svg( - '' - )); - } - } - - &--email { - background: hsl(0, 0%, 44%); - box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(0, 0%, 34%); - - &:hover, - &:focus { - box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 hsl(0, 0%, 34%); - } - - &:active { - box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 hsl(0, 0%, 34%); - } - - &::before { - background-image: url(fun.encode-svg( - '' - )); - } - } - - &--facebook { - background: hsl(214, 89%, 52%); - box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(214, 89%, 42%); - - &:hover, - &:focus { - box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 - hsl(214, 89%, 42%); - } - - &:active { - box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 - hsl(214, 89%, 42%); - } - - &::before { - background-image: url(fun.encode-svg( - '' - )); - } - } - - &--journal-du-hacker { - background: hsl(210, 24%, 51%); - box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(210, 24%, 41%); - - &:hover, - &:focus { - box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 - hsl(210, 24%, 41%); - } - - &:active { - box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 - hsl(210, 24%, 41%); - } - - &::before { - background-image: url(fun.encode-svg( - '' - )); - } - } - - &--linkedin { - background: hsl(210, 90%, 40%); - box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(210, 90%, 30%); - - &:hover, - &:focus { - box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 - hsl(210, 90%, 30%); - } - - &:active { - box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 - hsl(210, 90%, 30%); - } - - &::before { - background-image: url(fun.encode-svg( - '' - )); - } - } - - &--twitter { - background: hsl(203, 89%, 53%); - box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 hsl(203, 89%, 43%); - - &:hover, - &:focus { - box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 - hsl(203, 89%, 43%); - } - - &:active { - box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 - hsl(203, 89%, 43%); - } - - &::before { - background-image: url(fun.encode-svg( - '' - )); - } - } -} diff --git a/src/components/atoms/links/sharing-link.stories.tsx b/src/components/atoms/links/sharing-link.stories.tsx deleted file mode 100644 index 7ab5caf..0000000 --- a/src/components/atoms/links/sharing-link.stories.tsx +++ /dev/null @@ -1,98 +0,0 @@ -import { ComponentMeta, ComponentStory } from '@storybook/react'; -import { SharingLink } from './sharing-link'; - -/** - * SharingLink - Storybook Meta - */ -export default { - title: 'Atoms/Buttons/Sharing', - component: SharingLink, - argTypes: { - medium: { - control: { - type: 'select', - }, - description: 'The sharing medium.', - options: [ - 'diaspora', - 'email', - 'facebook', - 'journal-du-hacker', - 'linkedin', - 'twitter', - ], - type: { - name: 'string', - required: true, - }, - }, - url: { - control: { - type: 'text', - }, - description: 'The sharing url.', - type: { - name: 'string', - required: true, - }, - }, - }, -} as ComponentMeta; - -const Template: ComponentStory = (args) => ( - -); - -/** - * Sharing Link Stories - Diaspora - */ -export const Diaspora = Template.bind({}); -Diaspora.args = { - medium: 'diaspora', - url: '#', -}; - -/** - * Sharing Link Stories - Email - */ -export const Email = Template.bind({}); -Email.args = { - medium: 'email', - url: '#', -}; - -/** - * Sharing Link Stories - Facebook - */ -export const Facebook = Template.bind({}); -Facebook.args = { - medium: 'facebook', - url: '#', -}; - -/** - * Sharing Link Stories - Journal du Hacker - */ -export const JournalDuHacker = Template.bind({}); -JournalDuHacker.args = { - medium: 'journal-du-hacker', - url: '#', -}; - -/** - * Sharing Link Stories - LinkedIn - */ -export const LinkedIn = Template.bind({}); -LinkedIn.args = { - medium: 'linkedin', - url: '#', -}; - -/** - * Sharing Link Stories - Twitter - */ -export const Twitter = Template.bind({}); -Twitter.args = { - medium: 'twitter', - url: '#', -}; diff --git a/src/components/atoms/links/sharing-link.test.tsx b/src/components/atoms/links/sharing-link.test.tsx deleted file mode 100644 index 87375a9..0000000 --- a/src/components/atoms/links/sharing-link.test.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { describe, expect, it } from '@jest/globals'; -import { render, screen } from '../../../../tests/utils'; -import { SharingLink } from './sharing-link'; - -describe('SharingLink', () => { - it('render a Diaspora sharing link', () => { - render(); - expect(screen.getByRole('link', { name: 'Share on diaspora' })).toHaveClass( - 'link--diaspora' - ); - }); - - it('render an Email sharing link', () => { - render(); - expect(screen.getByRole('link', { name: 'Share on email' })).toHaveClass( - 'link--email' - ); - }); - - it('render a Facebook sharing link', () => { - render(); - expect(screen.getByRole('link', { name: 'Share on facebook' })).toHaveClass( - 'link--facebook' - ); - }); - - it('render a Journal du Hacker sharing link', () => { - render(); - expect( - screen.getByRole('link', { name: 'Share on journal-du-hacker' }) - ).toHaveClass('link--journal-du-hacker'); - }); - - it('render a LinkedIn sharing link', () => { - render(); - expect(screen.getByRole('link', { name: 'Share on linkedin' })).toHaveClass( - 'link--linkedin' - ); - }); - - it('render a Twitter sharing link', () => { - render(); - expect(screen.getByRole('link', { name: 'Share on twitter' })).toHaveClass( - 'link--twitter' - ); - }); -}); diff --git a/src/components/atoms/links/sharing-link.tsx b/src/components/atoms/links/sharing-link.tsx deleted file mode 100644 index 0b9d5fb..0000000 --- a/src/components/atoms/links/sharing-link.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { FC } from 'react'; -import { useIntl } from 'react-intl'; -import styles from './sharing-link.module.scss'; - -export type SharingMedium = - | 'diaspora' - | 'email' - | 'facebook' - | 'journal-du-hacker' - | 'linkedin' - | 'twitter'; - -export type SharingLinkProps = { - /** - * The sharing medium id. - */ - medium: SharingMedium; - /** - * The sharing url. - */ - url: string; -}; - -/** - * SharingLink component - * - * Render a sharing link. - */ -export const SharingLink: FC = ({ medium, url }) => { - const intl = useIntl(); - const text = intl.formatMessage( - { - defaultMessage: 'Share on {name}', - description: 'Sharing: share on social network text', - id: 'ureXFw', - }, - { name: medium } - ); - const mediumClass = `link--${medium}`; - const linkClass = `${styles.link} ${styles[mediumClass]}`; - - return ( - - {text} - - ); -}; diff --git a/src/components/atoms/links/sharing-link/index.ts b/src/components/atoms/links/sharing-link/index.ts new file mode 100644 index 0000000..20201eb --- /dev/null +++ b/src/components/atoms/links/sharing-link/index.ts @@ -0,0 +1 @@ +export * from './sharing-link'; diff --git a/src/components/atoms/links/sharing-link/sharing-link.module.scss b/src/components/atoms/links/sharing-link/sharing-link.module.scss new file mode 100644 index 0000000..e1c9c3c --- /dev/null +++ b/src/components/atoms/links/sharing-link/sharing-link.module.scss @@ -0,0 +1,88 @@ +@use "../../../../styles/abstracts/functions" as fun; + +.link { + display: inline-flex; + align-items: center; + padding: var(--spacing-2xs) var(--spacing-xs); + border-radius: fun.convert-px(3); + box-shadow: #{fun.convert-px(3)} #{fun.convert-px(3)} 0 0 var(--shadowColor); + transition: all 0.3s linear 0s; + + &:hover, + &:focus { + box-shadow: #{fun.convert-px(6)} #{fun.convert-px(6)} 0 0 var(--shadowColor); + transform: translateX(#{fun.convert-px(-3)}) + translateY(#{fun.convert-px(-3)}); + } + + &:active { + box-shadow: #{fun.convert-px(1)} #{fun.convert-px(1)} 0 0 var(--shadowColor); + transform: translateX(#{fun.convert-px(2)}) translateY(#{fun.convert-px(2)}); + } + + &::before { + content: ""; + display: block; + width: fun.convert-px(30); + height: fun.convert-px(30); + background-image: var(--logo); + background-repeat: no-repeat; + filter: drop-shadow( + #{fun.convert-px(1)} #{fun.convert-px(1)} #{fun.convert-px(1)} hsl(0, 0%, 0%) + ); + } + + &--diaspora { + // Prettier is removing spacing between attributes. + // prettier-ignore + --logo: url('#{fun.encode-svg('')}'); + --shadowColor: hsl(0, 0%, 3%); + + background: hsl(0, 0%, 13%); + } + + &--email { + // Prettier is removing spacing between attributes. + // prettier-ignore + --logo: url('#{fun.encode-svg('')}'); + --shadowColor: hsl(0, 0%, 34%); + + background: hsl(0, 0%, 44%); + } + + &--facebook { + // Prettier is removing spacing between attributes. + // prettier-ignore + --logo: url('#{fun.encode-svg('')}'); + --shadowColor: hsl(214, 89%, 42%); + + background: hsl(214, 89%, 52%); + } + + &--journal-du-hacker { + // Prettier is removing spacing between attributes. + // prettier-ignore + --logo: url('#{fun.encode-svg('')}'); + --shadowColor: hsl(210, 24%, 41%); + + background: hsl(210, 24%, 51%); + } + + &--linkedin { + // Prettier is removing spacing between attributes. + // prettier-ignore + --logo: url('#{fun.encode-svg('')}'); + --shadowColor: hsl(210, 90%, 30%); + + background: hsl(210, 90%, 40%); + } + + &--twitter { + // Prettier is removing spacing between attributes. + // prettier-ignore + --logo: url('#{fun.encode-svg('')}'); + --shadowColor: hsl(203, 89%, 43%); + + background: hsl(203, 89%, 53%); + } +} diff --git a/src/components/atoms/links/sharing-link/sharing-link.stories.tsx b/src/components/atoms/links/sharing-link/sharing-link.stories.tsx new file mode 100644 index 0000000..932d468 --- /dev/null +++ b/src/components/atoms/links/sharing-link/sharing-link.stories.tsx @@ -0,0 +1,114 @@ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import { SharingLink } from './sharing-link'; + +/** + * SharingLink - Storybook Meta + */ +export default { + title: 'Atoms/Links/Sharing', + component: SharingLink, + argTypes: { + medium: { + control: { + type: 'select', + }, + description: 'The sharing medium.', + options: [ + 'diaspora', + 'email', + 'facebook', + 'journal-du-hacker', + 'linkedin', + 'twitter', + ], + type: { + name: 'string', + required: true, + }, + }, + label: { + control: { + type: 'text', + }, + description: 'An accessible label that describe the link..', + type: { + name: 'string', + required: true, + }, + }, + url: { + control: { + type: 'text', + }, + description: 'The sharing url.', + type: { + name: 'string', + required: true, + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +/** + * Sharing Link Stories - Diaspora + */ +export const Diaspora = Template.bind({}); +Diaspora.args = { + label: 'Share on Diaspora', + medium: 'diaspora', + url: '#', +}; + +/** + * Sharing Link Stories - Email + */ +export const Email = Template.bind({}); +Email.args = { + label: 'Share by Email', + medium: 'email', + url: '#', +}; + +/** + * Sharing Link Stories - Facebook + */ +export const Facebook = Template.bind({}); +Facebook.args = { + label: 'Share on Facebook', + medium: 'facebook', + url: '#', +}; + +/** + * Sharing Link Stories - Journal du Hacker + */ +export const JournalDuHacker = Template.bind({}); +JournalDuHacker.args = { + label: 'Share on Journal du Hacker', + medium: 'journal-du-hacker', + url: '#', +}; + +/** + * Sharing Link Stories - LinkedIn + */ +export const LinkedIn = Template.bind({}); +LinkedIn.args = { + label: 'Share on LinkedIn', + medium: 'linkedin', + url: '#', +}; + +/** + * Sharing Link Stories - Twitter + */ +export const Twitter = Template.bind({}); +Twitter.args = { + label: 'Share on Twitter', + medium: 'twitter', + url: '#', +}; diff --git a/src/components/atoms/links/sharing-link/sharing-link.test.tsx b/src/components/atoms/links/sharing-link/sharing-link.test.tsx new file mode 100644 index 0000000..06cfb22 --- /dev/null +++ b/src/components/atoms/links/sharing-link/sharing-link.test.tsx @@ -0,0 +1,83 @@ +import { describe, expect, it } from '@jest/globals'; +import { render, screen as rtlScreen } from '@testing-library/react'; +import { SharingLink, type SharingMedium } from './sharing-link'; + +describe('SharingLink', () => { + it('render a Diaspora sharing link', () => { + const label = 'ab'; + const medium: SharingMedium = 'diaspora'; + const target = '/totam'; + + render(); + + const link = rtlScreen.getByRole('link', { name: label }); + + expect(link).toHaveAttribute('href', target); + expect(link).toHaveClass('link--diaspora'); + }); + + it('render an Email sharing link', () => { + const label = 'ut'; + const medium: SharingMedium = 'email'; + const target = '/nostrum'; + + render(); + + const link = rtlScreen.getByRole('link', { name: label }); + + expect(link).toHaveAttribute('href', target); + expect(link).toHaveClass('link--email'); + }); + + it('render a Facebook sharing link', () => { + const label = 'autem'; + const medium: SharingMedium = 'facebook'; + const target = '/perspiciatis'; + + render(); + + const link = rtlScreen.getByRole('link', { name: label }); + + expect(link).toHaveAttribute('href', target); + expect(link).toHaveClass('link--facebook'); + }); + + it('render a Journal du Hacker sharing link', () => { + const label = 'in'; + const medium: SharingMedium = 'journal-du-hacker'; + const target = '/labore'; + + render(); + + const link = rtlScreen.getByRole('link', { name: label }); + + expect(link).toHaveAttribute('href', target); + expect(link).toHaveClass('link--journal-du-hacker'); + }); + + it('render a LinkedIn sharing link', () => { + const label = 'id'; + const medium: SharingMedium = 'linkedin'; + const target = '/nesciunt'; + + render(); + + const link = rtlScreen.getByRole('link', { name: label }); + + expect(link).toHaveAttribute('href', target); + expect(link).toHaveClass('link--linkedin'); + }); + + it('render a Twitter sharing link', () => { + const label = 'illum'; + const medium: SharingMedium = 'twitter'; + const target = '/consectetur'; + + render(); + + const link = rtlScreen.getByRole('link', { name: label }); + + expect(link).toHaveAttribute('href', target); + expect(link).toHaveClass('link--twitter'); + }); +}); diff --git a/src/components/atoms/links/sharing-link/sharing-link.tsx b/src/components/atoms/links/sharing-link/sharing-link.tsx new file mode 100644 index 0000000..186000e --- /dev/null +++ b/src/components/atoms/links/sharing-link/sharing-link.tsx @@ -0,0 +1,51 @@ +import type { AnchorHTMLAttributes, FC } from 'react'; +import styles from './sharing-link.module.scss'; + +export type SharingMedium = + | 'diaspora' + | 'email' + | 'facebook' + | 'journal-du-hacker' + | 'linkedin' + | 'twitter'; + +export type SharingLinkProps = Omit< + AnchorHTMLAttributes, + 'children' | 'href' +> & { + /** + * An accessible label (visually hidden). + */ + label: string; + /** + * The sharing medium id. + */ + medium: SharingMedium; + /** + * The sharing url. + */ + url: string; +}; + +/** + * SharingLink component + * + * Render a sharing link. + */ +export const SharingLink: FC = ({ + className = '', + label, + medium, + url, + ...props +}) => { + const mediumClass = `link--${medium}`; + const linkClass = `${styles.link} ${styles[mediumClass]} ${className}`; + + return ( + + {/* eslint-disable-next-line -- SR class allowed */} + {label} + + ); +}; -- cgit v1.2.3