Skip to content

Commit

Permalink
Added TagItem and TagList components
Browse files Browse the repository at this point in the history
  • Loading branch information
winkerVSbecks committed Oct 15, 2020
1 parent 5bbe65d commit bb2f7c4
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,5 @@ export * from './CodeSnippets';
export * from './header/Header';
export * from './header/NavLink';
export { NavItem } from './header/NavItem';
export * from './tag/TagItem';
export * from './tag/TagList';
12 changes: 12 additions & 0 deletions src/components/tag/TagItem.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import { TagItem } from './TagItem';
import { StoryLinkWrapper } from '../StoryLinkWrapper';

export default {
component: TagItem,
title: 'Design System/Tag/TagItem',
};

export const Default = () => <TagItem>⚛️ React</TagItem>;

export const WithLinkWrapper = () => <TagItem LinkWrapper={StoryLinkWrapper}>⚛️ React</TagItem>;
52 changes: 52 additions & 0 deletions src/components/tag/TagItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React from 'react';
import styled from 'styled-components';
import { rgba } from 'polished';
import { color, typography, background, spacing } from '../shared/styles';
// @ts-ignore
import { Link } from '../Link';

type TagItemProps = {
containsIcon?: boolean;
inverse?: boolean;
isButton?: boolean;
LinkWrapper?: React.ComponentType | (() => React.ReactNode);
nochrome?: boolean;
secondary?: boolean;
tertiary?: boolean;
withArrow?: boolean;
};

export const TagItem = styled(Link)<TagItemProps>`
background: ${background.app};
border-radius: ${spacing.borderRadius.small}px;
padding: 5px 10px;
font-size: ${typography.size.s2}px;
line-height: ${typography.size.m2}px;
position: relative;
color: ${color.darkest};
border-width: 1px;
border-style: solid;
border-color: transparent;
white-space: nowrap;
&:after {
content: '';
position: absolute;
z-index: -1;
top: 0;
left: 0;
width: 100%;
height: 100%;
box-shadow: rgba(0, 0, 0, 0.08) 0 3px 10px 0;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
&:hover {
border-color: ${rgba(color.secondary, 0.5)};
&:after {
opacity: 1;
}
}
`;
127 changes: 127 additions & 0 deletions src/components/tag/TagList.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import React from 'react';
import { TagList } from './TagList';
import { TagItem } from './TagItem';

export default {
component: TagList,
excludeStories: /.*Data$/,
title: 'Design System/Tag/TagList',
};

export const Default = () => (
<TagList
tags={mockTagsData.slice(0, 4).map((tag) => (
<TagItem key={tag.link} href={tag.link}>
{tag.name}
</TagItem>
))}
/>
);

export const WithMoreTags = () => (
<TagList
tags={mockTagsData.map((tag) => (
<TagItem key={tag.link} href={tag.link}>
{tag.name}
</TagItem>
))}
/>
);

export const WithCustomLimit = () => (
<TagList
tags={mockTagsData.map((tag) => (
<TagItem key={tag.link} href={tag.link}>
{tag.name}
</TagItem>
))}
limit={6}
/>
);

export const mockTagsData = [
{
link: '/ui',
name: '📲 UI',
},
{
link: '/react',
name: '⚛️ React',
},
{
link: '/components',
name: '🧩 Components',
},
{
link: '/front-end-development',
name: '👩🏽‍💻 Front-end development',
},
{
link: '/graphql',
name: '🕸 GraphQL',
},
{
link: '/storybook',
name: '📕 Storybook',
},
{
link: '/component-libraries',
name: '🏗 Component libraries',
},
{
link: '/design',
name: '🎨 Design',
},
{
link: '/open-source',
name: 'Open-source',
},
{
link: '/startup',
name: 'Startup',
},
{
link: '/ux',
name: 'UX',
},
{
link: '/design-system',
name: '🗃 Design systems',
},
{
link: '/api',
name: 'API',
},
{
link: '/entrepreneurship',
name: 'Entrepreneurship',
},
{
link: '/testing',
name: '✅ Testing',
},
{
link: '/remote-work',
name: 'Remote work',
},
{
link: '/venture-capital',
name: 'Venture capital',
},
{
link: '/company-culture',
name: 'Company culture',
},
{
link: '/dev-tools',
name: 'Dev tools',
},
{
link: '/mongodb',
name: 'MongoDB',
},
{
link: '/animation',
name: '📽 Animation',
},
];
57 changes: 57 additions & 0 deletions src/components/tag/TagList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useState, forwardRef } from 'react';
import styled from 'styled-components';
import { typography } from '../shared/styles';
// @ts-ignore
import { Link } from '../Link';
import { TagItem } from './TagItem';

const TagListWrapper = styled.div`
display: flex;
flex-wrap: wrap;
> * {
margin-right: 10px;
margin-bottom: 10px;
}
margin-bottom: -10px;
`;

const MoreTagsButton = styled(Link)`
font-size: ${typography.size.s2}px;
padding-left: 5px;
padding-right: 5px;
&:focus {
outline: auto;
}
`;

type TagListTypes = {
tags: typeof TagItem[];
limit: number;
};

export const TagList = forwardRef<HTMLDivElement, TagListTypes>(
({ tags, limit, ...props }: TagListTypes, ref) => {
const primaryTags = tags.slice(0, limit);
const moreTags = tags.slice(limit);
const [moreTagsVisible, setMoreTagsVisible] = useState(false);

return (
<TagListWrapper {...props} ref={ref}>
{primaryTags}
{moreTagsVisible && moreTags}
{moreTags.length > 0 && !moreTagsVisible && (
<MoreTagsButton isButton appearance="primary" onClick={() => setMoreTagsVisible(true)}>
{`+ ${moreTags.length} more`}
</MoreTagsButton>
)}
</TagListWrapper>
);
}
);

TagList.defaultProps = {
limit: 4,
};

0 comments on commit bb2f7c4

Please sign in to comment.