summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorArmand Philippot <git@armandphilippot.com>2022-04-01 17:11:25 +0200
committerArmand Philippot <git@armandphilippot.com>2022-04-01 17:22:39 +0200
commit163f9dc0fe436b708de4e59999e87005c6685a0f (patch)
tree34f25b014b606f88976710e622cda7eb38e2dd49 /src
parent2385ec8ca0963306f6b87564467301cb5a2a1834 (diff)
chore: add a social link component
Diffstat (limited to 'src')
-rw-r--r--src/components/atoms/links/social-link.module.scss43
-rw-r--r--src/components/atoms/links/social-link.stories.tsx40
-rw-r--r--src/components/atoms/links/social-link.test.tsx15
-rw-r--r--src/components/atoms/links/social-link.tsx51
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;