From 8eea6ad1c5f306122d1850116f24aea9435d43ef Mon Sep 17 00:00:00 2001 From: Chloekkk Date: Sun, 24 Apr 2022 22:12:18 +0900 Subject: [PATCH] =?UTF-8?q?feat(blog):=20tagMenu=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84=20#37?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/TagMenu/TagMenu.stories.tsx | 43 +++++++++++++ .../components/TagMenu/TagMenu.styled.tsx | 63 +++++++++++++++++++ packages/blog/components/TagMenu/TagMenu.tsx | 60 ++++++++++++++++++ packages/blog/components/TagMenu/index.tsx | 2 + 4 files changed, 168 insertions(+) create mode 100644 packages/blog/components/TagMenu/TagMenu.stories.tsx create mode 100644 packages/blog/components/TagMenu/TagMenu.styled.tsx create mode 100644 packages/blog/components/TagMenu/TagMenu.tsx create mode 100644 packages/blog/components/TagMenu/index.tsx diff --git a/packages/blog/components/TagMenu/TagMenu.stories.tsx b/packages/blog/components/TagMenu/TagMenu.stories.tsx new file mode 100644 index 0000000..b4edca2 --- /dev/null +++ b/packages/blog/components/TagMenu/TagMenu.stories.tsx @@ -0,0 +1,43 @@ +import React from 'react' +import { ComponentMeta, ComponentStory } from '@storybook/react' +import TagMenu from './TagMenu' + +export default { + title: 'Components/TagMenu', + component: TagMenu, + parameters: { + layout: 'fullscreen', + }, +} as ComponentMeta + +const Template: ComponentStory = (args) => ( +
+ +
+) + +export const Default = Template.bind({}) +Default.args = { + tags: [ + 'ALL', + 'javascript', + 'typescript', + 'react', + 'vue', + 'Angular', + 'Node', + 'Express', + 'MongoDB', + 'MySQL', + 'PostgreSQL', + 'SQL', + 'NoSQL', + 'GraphQL', + 'Apollo', + 'Gatsby', + 'Next', + 'Git', + 'GitHub', + 'GitLab', + ], +} diff --git a/packages/blog/components/TagMenu/TagMenu.styled.tsx b/packages/blog/components/TagMenu/TagMenu.styled.tsx new file mode 100644 index 0000000..e49990a --- /dev/null +++ b/packages/blog/components/TagMenu/TagMenu.styled.tsx @@ -0,0 +1,63 @@ +import styled from 'styled-components' + +const Styled = { + container: styled.div` + position: relative; + + width: 100%; + height: 65px; + + background-color: ${({ theme }) => theme.color.grey200}; + border-radius: 7px; + `, + scrollbar: styled.div` + position: relative; + z-index: 1; + + display: flex; + width: 100%; + height: 100%; + padding: 16px 20px; + + overflow-x: scroll; + + column-gap: 9px; + + scroll-behavior: smooth; + -ms-overflow-style: none; + scrollbar-width: none; + &::-webkit-scrollbar { + display: none; + } + `, + leftShadow: styled.div` + position: absolute; + top: 0; + left: 0; + z-index: 2; + + width: 100%; + height: 100%; + + border-radius: 7px 0 0 7px; + box-shadow: inset 7px 0 9px -7px rgba(0, 0, 0, 0.4); + + pointer-events: none; + `, + rightShadow: styled.div` + position: absolute; + top: 0; + right: 0; + z-index: 2; + + width: 100%; + height: 100%; + + border-radius: 0px 7px 7px 0; + box-shadow: inset -7px 0 9px -7px rgba(0, 0, 0, 0.4); + + pointer-events: none; + `, +} + +export default Styled diff --git a/packages/blog/components/TagMenu/TagMenu.tsx b/packages/blog/components/TagMenu/TagMenu.tsx new file mode 100644 index 0000000..b44136a --- /dev/null +++ b/packages/blog/components/TagMenu/TagMenu.tsx @@ -0,0 +1,60 @@ +import React, { useEffect, useState, useRef, useCallback } from 'react' +import { theme } from '../../styles/theme' +import Tag from '../Tag/Tag' +import Styled from './TagMenu.styled' + +export interface TagMenuProps { + tags: string[] +} + +type edgeType = 'left' | 'right' | 'both' | 'none' + +const TagMenu: React.FC = ({ tags }) => { + const scrollRef = useRef() + const [edge, setEdge] = useState('none') + const [selectedTag, setSelectedTag] = useState(0) + const activeStyle = { + color: theme.color.white, + backgroundColor: theme.color.main, + } + + const handleEdge = useCallback( + ({ scrollLeft, scrollWidth, clientWidth }: { scrollLeft: number; scrollWidth: number; clientWidth: number }) => { + const scrollRange = scrollWidth - clientWidth + if (scrollRange === 0) setEdge('none') + else if (scrollLeft === 0) setEdge('right') + else if (scrollLeft === scrollRange) setEdge('left') + else setEdge('both') + }, + [] + ) + + useEffect(() => { + handleEdge(scrollRef.current) + }, [handleEdge, scrollRef]) + + const onTagMenuScroll = (e: React.UIEvent) => { + handleEdge(e.currentTarget) + e.stopPropagation() + } + + return ( + + {edge === 'left' || edge === 'both' ? : <>} + {edge === 'right' || edge === 'both' ? : <>} + + {tags.map((tag, idx) => ( + setSelectedTag(idx)} + view={'menu'} + style={selectedTag === idx ? activeStyle : {}} + /> + ))} + + + ) +} + +export default TagMenu diff --git a/packages/blog/components/TagMenu/index.tsx b/packages/blog/components/TagMenu/index.tsx new file mode 100644 index 0000000..1fbe3d3 --- /dev/null +++ b/packages/blog/components/TagMenu/index.tsx @@ -0,0 +1,2 @@ +export { default } from './TagMenu' +export type { TagMenuProps } from './TagMenu'