diff options
Diffstat (limited to 'src/components/organisms/widgets/social-media-widget')
4 files changed, 114 insertions, 0 deletions
diff --git a/src/components/organisms/widgets/social-media-widget/index.ts b/src/components/organisms/widgets/social-media-widget/index.ts new file mode 100644 index 0000000..33a6f3f --- /dev/null +++ b/src/components/organisms/widgets/social-media-widget/index.ts @@ -0,0 +1 @@ +export * from './social-media-widget'; diff --git a/src/components/organisms/widgets/social-media-widget/social-media-widget.stories.tsx b/src/components/organisms/widgets/social-media-widget/social-media-widget.stories.tsx new file mode 100644 index 0000000..5c6efb0 --- /dev/null +++ b/src/components/organisms/widgets/social-media-widget/social-media-widget.stories.tsx @@ -0,0 +1,43 @@ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Heading } from '../../../atoms'; +import { SocialMediaWidget, type SocialMediaData } from './social-media-widget'; + +/** + * SocialMedia - Storybook Meta + */ +export default { + title: 'Organisms/Widgets/SocialMedia', + component: SocialMediaWidget, + argTypes: { + media: { + description: 'The social media data.', + type: { + name: 'object', + required: true, + value: {}, + }, + }, + }, +} as ComponentMeta<typeof SocialMediaWidget>; + +const Template: ComponentStory<typeof SocialMediaWidget> = (args) => ( + <SocialMediaWidget {...args} /> +); + +const media: SocialMediaData[] = [ + { icon: 'Github', id: 'github', label: 'Github', url: '#' }, + { icon: 'LinkedIn', id: 'gitlab', label: 'Gitlab', url: '#' }, +]; + +/** + * Widgets Stories - Social media + */ +export const SocialMedia = Template.bind({}); +SocialMedia.args = { + heading: ( + <Heading isFake level={3}> + Follow me + </Heading> + ), + media, +}; diff --git a/src/components/organisms/widgets/social-media-widget/social-media-widget.test.tsx b/src/components/organisms/widgets/social-media-widget/social-media-widget.test.tsx new file mode 100644 index 0000000..197b9ac --- /dev/null +++ b/src/components/organisms/widgets/social-media-widget/social-media-widget.test.tsx @@ -0,0 +1,27 @@ +import { describe, expect, it } from '@jest/globals'; +import { render, screen as rtlScreen } from '@testing-library/react'; +import { Heading } from '../../../atoms'; +import { type SocialMediaData, SocialMediaWidget } from './social-media-widget'; + +describe('SocialMediaWidget', () => { + it('render the widget heading and a list of social media', () => { + const heading = 'aut dolorem molestiae'; + const headingLvl = 3; + const media = [ + { icon: 'Github', id: 'github', label: 'Github', url: '#github' }, + { icon: 'LinkedIn', id: 'linkedin', label: 'LinkedIn', url: '#linkedin' }, + ] satisfies SocialMediaData[]; + + render( + <SocialMediaWidget + heading={<Heading level={headingLvl}>{heading}</Heading>} + media={media} + /> + ); + + expect( + rtlScreen.getByRole('heading', { level: headingLvl }) + ).toHaveTextContent(heading); + expect(rtlScreen.getAllByRole('link')).toHaveLength(media.length); + }); +}); diff --git a/src/components/organisms/widgets/social-media-widget/social-media-widget.tsx b/src/components/organisms/widgets/social-media-widget/social-media-widget.tsx new file mode 100644 index 0000000..d75f48f --- /dev/null +++ b/src/components/organisms/widgets/social-media-widget/social-media-widget.tsx @@ -0,0 +1,43 @@ +import { forwardRef, type ForwardRefRenderFunction } from 'react'; +import { + List, + ListItem, + SocialLink, + type SocialLinkProps, +} from '../../../atoms'; +import { Collapsible, type CollapsibleProps } from '../../../molecules'; + +export type SocialMediaData = Required< + Pick<SocialLinkProps, 'icon' | 'id' | 'label' | 'url'> +>; + +export type SocialMediaProps = Omit<CollapsibleProps, 'children'> & { + media: SocialMediaData[]; +}; + +const SocialMediaWidgetWithRef: ForwardRefRenderFunction< + HTMLDivElement, + SocialMediaProps +> = ({ media, ...props }, ref) => ( + <Collapsible {...props} ref={ref}> + <List + hideMarker + isInline + // eslint-disable-next-line react/jsx-no-literals + spacing="xs" + > + {media.map(({ id, ...link }) => ( + <ListItem key={id}> + <SocialLink {...link} /> + </ListItem> + ))} + </List> + </Collapsible> +); + +/** + * Social Media widget component + * + * Render a social media list with links. + */ +export const SocialMediaWidget = forwardRef(SocialMediaWidgetWithRef); |
