Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui-kit): List, ListItem, ListItemImage 컴포넌트 추가 #45

Merged
merged 4 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ui-kit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
],
"author": "Lubycon",
"dependencies": {
"@types/classnames": "^2.2.11",
"classnames": "^2.2.6",
"ionicons": "^5.2.3",
"react-spring": "^8.0.27"
Expand Down
57 changes: 57 additions & 0 deletions ui-kit/src/components/List/ListItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { HTMLAttributes, forwardRef, ReactNode } from 'react';
import classnames from 'classnames';
import { Combine } from 'src/types/utils';
import Text from '../Text';

type Props = Combine<
{
left?: ReactNode;
right?: ReactNode;
title?: string;
content: string;
caption?: string;
},
Omit<HTMLAttributes<HTMLLIElement>, 'children' | 'role'>
>;
const ListItem = forwardRef<HTMLLIElement, Props>(function ListItem(
{ className, left, right, title, content, caption, onClick, ...props },
ref
) {
const isClickable = onClick != null;

return (
<li
ref={ref}
className={classnames(
'lubycon-list__item',
{
'lubycon-list__item--clickable': isClickable,
},
className
)}
onClick={onClick}
role="listitem"
{...props}
>
{left ? <div className="lubycon-list__item__left">{left}</div> : null}
<div className="lubycon-list__item__center">
{title ? (
<Text className="lubycon-list__item__center__title" fontWeight="bold">
{title}
</Text>
) : null}
<Text className="lubycon-list__item__center__content" typography="p2">
{content}
</Text>
{caption ? (
<Text className="lubycon-list__item__center__caption" typography="caption">
{caption}
</Text>
) : null}
</div>
{right ? <div className="lubycon-list__item__right">{right}</div> : null}
</li>
);
});

export default ListItem;
22 changes: 22 additions & 0 deletions ui-kit/src/components/List/ListItemImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { ImgHTMLAttributes } from 'react';
import classnames from 'classnames';

const ListItemImage = ({
className,
src,
alt,
tabIndex,
...props
}: ImgHTMLAttributes<HTMLImageElement>) => (
<div
className={classnames('lubycon-list__item__image', className)}
style={{ backgroundImage: `url(${src})` }}
role="img"
aria-label={alt}
tabIndex={tabIndex}
>
<img src={src} alt={alt} tabIndex={-1} {...props} />
</div>
);

export default ListItemImage;
18 changes: 18 additions & 0 deletions ui-kit/src/components/List/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { HTMLAttributes, forwardRef } from 'react';
import classnames from 'classnames';

type Props = Omit<HTMLAttributes<HTMLUListElement>, 'role'>;
const List = forwardRef<HTMLUListElement, Props>(function List(
{ children, className, ...props },
ref
) {
return (
<ul ref={ref} className={classnames('lubycon-list', className)} role="list" {...props}>
{children}
</ul>
);
});

export default List;
export { default as ListItem } from './ListItem';
export { default as ListItemImage } from './ListItemImage';
1 change: 1 addition & 0 deletions ui-kit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export {
CardFooter,
} from './components/Card';
export { default as Snackbar } from './components/Snackbar';
export { default as List, ListItem } from './components/List';
export { Portal } from './contexts/Portal';
export { useToast } from './contexts/Toast';
export { useSnackbar } from './contexts/Snackbar';
Expand Down
69 changes: 69 additions & 0 deletions ui-kit/src/sass/components/_List.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
.lubycon-list {
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
}

.lubycon-list__item {
display: flex;
align-items: center;
list-style: none;
margin: 0;
padding: 13px 0;
& + & {
border-top: 1px solid get-color('gray20');
}
&--clickable {
transition: background-color 0.1s ease-in-out;
cursor: pointer;
&:hover {
background-color: get-color('gray10');
}
&:active {
background-color: get-color('gray20');
}
}

&__left {
padding-left: 12px;
width: auto;
flex: 0 0 auto;
}
&__center {
padding: 0 16px;
display: flex;
flex-direction: column;
flex-grow: 1;
&__title {
color: get-color('gray90');
}
&__content {
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
display: -webkit-box;
overflow: hidden;
}
&__caption {
margin-top: 4px;
color: get-color('gray60');
}
}
&__right {
padding-right: 8px;
}

&__image {
position: relative;
width: 48px;
height: 48px;
border-radius: 4px;
overflow: hidden;
background-repeat: no-repeat;
background-size: cover;
background-position: 50% 50%;
> img {
display: none;
}
}
}
1 change: 1 addition & 0 deletions ui-kit/src/sass/components/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@
@import './Card';
@import './Snackbar';
@import './Container';
@import './List';
2 changes: 1 addition & 1 deletion ui-kit/src/sass/utils/_typography.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,6 @@
@include _typography('h5', 24px, 36px);
@include _typography('h6', 20px, 30px);
@include _typography('subtitle', 18px, 30px);
@include _typography('p1', 16px, 28px);
@include _typography('p1', 16px, 32px);
@include _typography('p2', 14px, 24px);
@include _typography('caption', 12px, 20px);
138 changes: 138 additions & 0 deletions ui-kit/src/stories/List.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import React from 'react';
import { Button, List, ListItem } from 'src';
import { Meta } from '@storybook/react/types-6-0';
import { ListItemImage } from 'src/components/List';
import Icon from 'src/components/Icon';
import { chevronForward } from 'ionicons/icons';
import { colors } from 'src/constants/colors';

export default {
title: 'Lubycon UI Kit/List',
} as Meta;

const DummyItem = ({ onClick }: { onClick?: () => void }) => (
<ListItem
title="리스트 제목"
content="여기에 내용이 들어갑니다"
caption="캡션입니다"
onClick={onClick}
/>
);
const DummyItemWithoutCaption = () => (
<ListItem title="리스트 제목" content="여기에 내용이 들어갑니다" />
);
const DummyItemWithoutTitle = () => (
<ListItem content="여기에 내용이 들어갑니다" caption="캡션입니다" />
);
const noop = () => {};

export const Default = () => {
return (
<List>
<ListItem title="루비콘 UI Kit" content="리스트 컴포넌트" caption="5일전" />
<DummyItem />
<DummyItem />
<DummyItem />
<DummyItem />
</List>
);
};

export const WithoutCaption = () => {
return (
<List>
<ListItem title="루비콘 UI Kit" content="리스트 컴포넌트" />
<DummyItemWithoutCaption />
<DummyItemWithoutCaption />
<DummyItemWithoutCaption />
<DummyItemWithoutCaption />
</List>
);
};

export const WithoutTitle = () => {
return (
<List>
<ListItem content="리스트 컴포넌트" caption="5일전" />
<DummyItemWithoutTitle />
<DummyItemWithoutTitle />
<DummyItemWithoutTitle />
<DummyItemWithoutTitle />
</List>
);
};

export const LeftRight = () => {
return (
<List>
<ListItem
left={<ListItemImage src="http://cogulmars.cafe24.com/img/04about_img01.png" />}
title="썸네일 조합형"
content="UI Kit에서 제공되는 이미지 컴포넌트를 사용한 예시입니다"
/>
<ListItem
left={<ListItemImage src="http://cogulmars.cafe24.com/img/04about_img01.png" />}
title="썸네일 조합형"
content="UI Kit에서 제공되는 이미지 컴포넌트를 사용한 예시입니다"
caption="5일전"
/>
<ListItem
left={
<img
src="http://cogulmars.cafe24.com/img/04about_img01.png"
style={{ width: 48, borderRadius: 4 }}
/>
}
title="썸네일 조합형"
content="일반 img 태그를 사용한 예시입니다"
caption="5일전"
/>
<ListItem
title="버튼 조합형"
content="자세히 보려면 클릭하세요"
right={<Icon icon={chevronForward} type="outline" size={24} color={colors.gray60} />}
onClick={noop}
/>
<ListItem
title="버튼 조합형 자유"
content="자세히 보려면 클릭하세요"
right={<Button size="small">보러가기</Button>}
/>
<ListItem
left={<ListItemImage src="http://cogulmars.cafe24.com/img/04about_img01.png" />}
title="썸네일 + 버튼 조합형"
content="자세히 보려면 클릭하세요"
right={<Icon icon={chevronForward} type="outline" size={24} color={colors.gray60} />}
onClick={noop}
/>
</List>
);
};

export const Clickable = () => {
return (
<List>
<ListItem title="루비콘 UI Kit" content="리스트 컴포넌트" caption="5일전" onClick={noop} />
<DummyItem onClick={noop} />
<DummyItem onClick={noop} />
<DummyItem onClick={noop} />
<DummyItem onClick={noop} />
</List>
);
};

export const Multiline = () => {
return (
<List style={{ maxWidth: 375 }}>
<ListItem
title="루비콘 UI Kit"
content="리스트 컴포넌트의 내용이 두 줄이 넘어가면 말줄임으로 처리됩니다. 루비콘 UI kit 은 오픈소스로 배포되는 한국형 라이브러리입니다"
caption="5일전"
/>
<DummyItem />
<DummyItem />
<DummyItem />
<DummyItem />
</List>
);
};