Skip to content

Commit

Permalink
feat(ui-kit): List, ListItem, ListItemImage 컴포넌트 추가 (#45)
Browse files Browse the repository at this point in the history
* feat(ui-kit): 리스트 기본 모양 잡음

* feat(ui-kit): 리스트에 left, right area 추가

* feat(ui-kit): 리스트 스토리북 수정
  • Loading branch information
evan-moon authored Feb 16, 2021
1 parent 2894397 commit 3bda7ed
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 2 deletions.
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 { default as Input } from './components/Input';
export { Portal } from './contexts/Portal';
export { useToast } from './contexts/Toast';
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,4 +14,5 @@
@import './Card';
@import './Snackbar';
@import './Container';
@import './List';
@import './Input';
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>
);
};

0 comments on commit 3bda7ed

Please sign in to comment.