From 4a79f0d5511d6a6732428687740f8190e000f1b9 Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Thu, 31 Mar 2022 22:34:23 +0200 Subject: chore: add a Link component --- src/components/atoms/links/link.module.scss | 37 ++++++++++++++++ src/components/atoms/links/link.stories.tsx | 66 +++++++++++++++++++++++++++++ src/components/atoms/links/link.test.tsx | 9 ++++ src/components/atoms/links/link.tsx | 41 ++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 src/components/atoms/links/link.module.scss create mode 100644 src/components/atoms/links/link.stories.tsx create mode 100644 src/components/atoms/links/link.test.tsx create mode 100644 src/components/atoms/links/link.tsx (limited to 'src/components/atoms/links') diff --git a/src/components/atoms/links/link.module.scss b/src/components/atoms/links/link.module.scss new file mode 100644 index 0000000..e7ead86 --- /dev/null +++ b/src/components/atoms/links/link.module.scss @@ -0,0 +1,37 @@ +@use "@styles/abstracts/functions" as fun; +@use "@styles/abstracts/variables" as var; + +.link { + &[hreflang] { + &::after { + display: inline-block; + content: "\0000a0["attr(hreflang) "]"; + font-size: var(--font-size-sm); + } + } + + &--external { + &::after { + display: inline-block; + content: "\0000a0"url(fun.encode-svg('')); + } + + &:focus:not(:active)::after { + content: "\0000a0"url(fun.encode-svg('')); + } + + &[hreflang] { + &::after { + content: "\0000a0["attr(hreflang) "]\0000a0"url(fun.encode-svg( + '' + )); + } + + &:focus:not(:active)::after { + content: "\0000a0["attr(hreflang) "]\0000a0"url(fun.encode-svg( + '' + )); + } + } + } +} diff --git a/src/components/atoms/links/link.stories.tsx b/src/components/atoms/links/link.stories.tsx new file mode 100644 index 0000000..e5a8b0a --- /dev/null +++ b/src/components/atoms/links/link.stories.tsx @@ -0,0 +1,66 @@ +import { ComponentMeta, ComponentStory } from '@storybook/react'; +import LinkComponent from './link'; + +export default { + title: 'Atoms/Links', + component: LinkComponent, + argTypes: { + children: { + control: { + type: 'text', + }, + description: 'The link body.', + type: { + name: 'string', + required: true, + }, + }, + external: { + control: { + type: 'boolean', + }, + table: { + category: 'Options', + }, + description: 'Determine if the link is external of the current website.', + type: { + name: 'boolean', + required: false, + }, + }, + href: { + control: { + type: 'text', + }, + description: 'The link target.', + type: { + name: 'string', + required: true, + }, + }, + lang: { + control: { + type: 'text', + }, + table: { + category: 'Options', + }, + description: 'The target language as code language.', + type: { + name: 'string', + required: false, + }, + }, + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => ( + +); + +export const Link = Template.bind({}); +Link.args = { + children: 'A link', + href: '#', + external: false, +}; diff --git a/src/components/atoms/links/link.test.tsx b/src/components/atoms/links/link.test.tsx new file mode 100644 index 0000000..54e2414 --- /dev/null +++ b/src/components/atoms/links/link.test.tsx @@ -0,0 +1,9 @@ +import { render, screen } from '@test-utils'; +import Link from './link'; + +describe('Link', () => { + it('render a link', () => { + render(A link); + expect(screen.getByRole('link')).toHaveTextContent('A link'); + }); +}); diff --git a/src/components/atoms/links/link.tsx b/src/components/atoms/links/link.tsx new file mode 100644 index 0000000..0a69c33 --- /dev/null +++ b/src/components/atoms/links/link.tsx @@ -0,0 +1,41 @@ +import NextLink from 'next/link'; +import { FC } from 'react'; +import styles from './link.module.scss'; + +type LinkProps = { + /** + * True if it is an external link. Default: false. + */ + external?: boolean; + /** + * The link target. + */ + href: string; + /** + * The link target code language. + */ + lang?: string; +}; + +/** + * Link Component + * + * Render a link. + */ +const Link: FC = ({ children, href, lang, external = false }) => { + return external ? ( + + {children} + + ) : ( + + {children} + + ); +}; + +export default Link; -- cgit v1.2.3 From 163f9dc0fe436b708de4e59999e87005c6685a0f Mon Sep 17 00:00:00 2001 From: Armand Philippot Date: Fri, 1 Apr 2022 17:11:25 +0200 Subject: chore: add a social link component --- src/components/atoms/links/social-link.module.scss | 43 ++++++++++++++++++ src/components/atoms/links/social-link.stories.tsx | 40 +++++++++++++++++ src/components/atoms/links/social-link.test.tsx | 15 +++++++ src/components/atoms/links/social-link.tsx | 51 ++++++++++++++++++++++ 4 files changed, 149 insertions(+) create mode 100644 src/components/atoms/links/social-link.module.scss create mode 100644 src/components/atoms/links/social-link.stories.tsx create mode 100644 src/components/atoms/links/social-link.test.tsx create mode 100644 src/components/atoms/links/social-link.tsx (limited to 'src/components/atoms/links') 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; + +const Template: ComponentStory = (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(); + 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 = ({ 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