From 0c1d12c7f951db56e501145bd73071480273340a Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Tue, 5 Apr 2022 17:51:12 +0200 Subject: chore: add a SharingLink component --- .../atoms/links/sharing-link.module.scss | 157 +++++++++++++++++++++ .../atoms/links/sharing-link.stories.tsx | 50 +++++++ src/components/atoms/links/sharing-link.test.tsx | 46 ++++++ src/components/atoms/links/sharing-link.tsx | 48 +++++++ 4 files changed, 301 insertions(+) create mode 100644 src/components/atoms/links/sharing-link.module.scss create mode 100644 src/components/atoms/links/sharing-link.stories.tsx create mode 100644 src/components/atoms/links/sharing-link.test.tsx create mode 100644 src/components/atoms/links/sharing-link.tsx (limited to 'src') diff --git a/src/components/atoms/links/sharing-link.module.scss b/src/components/atoms/links/sharing-link.module.scss new file mode 100644 index 0000000..26ca737 --- /dev/null +++ b/src/components/atoms/links/sharing-link.module.scss @@ -0,0 +1,157 @@ +@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 new file mode 100644 index 0000000..335fa50 --- /dev/null +++ b/src/components/atoms/links/sharing-link.stories.tsx @@ -0,0 +1,50 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { IntlProvider } from 'react-intl'; +import SharingLinkComponent from './sharing-link'; + +export default { + title: 'Atoms/Links', + component: SharingLinkComponent, + 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) => ( + + + +); + +export const SharingLink = Template.bind({}); +SharingLink.args = { + medium: 'diaspora', + url: '#', +}; diff --git a/src/components/atoms/links/sharing-link.test.tsx b/src/components/atoms/links/sharing-link.test.tsx new file mode 100644 index 0000000..e4c849c --- /dev/null +++ b/src/components/atoms/links/sharing-link.test.tsx @@ -0,0 +1,46 @@ +import { render, screen } from '@test-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 new file mode 100644 index 0000000..ca53ef9 --- /dev/null +++ b/src/components/atoms/links/sharing-link.tsx @@ -0,0 +1,48 @@ +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. + */ +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}`; + + return ( + + {text} + + ); +}; + +export default SharingLink; -- cgit v1.2.3