diff --git a/.eslintrc.js b/.eslintrc.js index 8112dc1..6c121be 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -53,6 +53,7 @@ module.exports = { 'react/react-in-jsx-scope': 'off', 'react/require-default-props': 'off', 'react/jsx-no-constructed-context-values': 'off', + 'react/no-array-index-key': 'off', 'import/order': [ 'error', { diff --git a/src/components/common/Table/index.tsx b/src/components/common/Table/index.tsx new file mode 100644 index 0000000..42a12f2 --- /dev/null +++ b/src/components/common/Table/index.tsx @@ -0,0 +1,104 @@ +import { ReactNode, ReactElement, ComponentProps } from 'react'; +import { css } from 'styled-components'; + +import FlexBox from '@components/common/FlexBox'; +import Text from '@components/common/Text'; +import { offscreen } from '@styles/commonStyles'; + +type TableDefaultProps = { + children: ReactElement | ReactElement[]; +}; + +export interface TableProps extends TableDefaultProps { + caption: string; + columnsWidth?: string[]; +} + +const Table = ({ caption, columnsWidth, children }: TableProps) => ( + `0.1rem solid ${theme.palette.borderLine}`}; + table-layout: fixed; + `} + > + + {columnsWidth && ( + + {columnsWidth.map((width, index) => ( + + ))} + + )} + {children} +
{caption}
+); + +const Thead = ({ children }: TableDefaultProps) => {children}; + +const Tbody = ({ children }: TableDefaultProps) => ( + theme.palette.hoverColor}; + } + `} + > + {children} + +); + +const Tr = ({ children }: TableDefaultProps) => ( + + `0.1rem solid ${theme.palette.borderLine}`}; + `} + > + {children} + +); + +type CellSX = { + width?: string; + justifyContent?: 'center' | 'flex-start'; +}; + +const flexCss = { + justifyContent: 'center', + alignItems: 'center', + gap: '1rem', +} as Pick, 'sx'>; + +type ThProps = { + colSpan?: number; + sx?: CellSX; + children: ReactNode; +}; + +const Th = ({ sx = {}, children, ...restProps }: ThProps) => ( + + + {children} + + +); + +export interface TdProps extends ThProps { + rowSpan?: number; +} + +const Td = ({ sx = {}, children, ...restProps }: TdProps) => ( + + {children} + +); + +Table.Head = Thead; +Table.Body = Tbody; +Table.Row = Tr; +Table.HeadCell = Th; +Table.BodyCell = Td; + +export default Table; diff --git a/src/components/common/Table/table.stories.tsx b/src/components/common/Table/table.stories.tsx new file mode 100644 index 0000000..5532ae4 --- /dev/null +++ b/src/components/common/Table/table.stories.tsx @@ -0,0 +1,197 @@ +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import Icon from '@components/common/Icon'; +import Table from '@components/common/Table'; +import Text from '@components/common/Text'; + +export default { + title: 'common/Table', + component: Table, +} as ComponentMeta; + +const noticeList = [ + { + id: 1, + title: '스터디 가입전 해당 공지사항을 숙지해주세요.', + writer: '파크', + date: '2022.10.22', + view: 101, + isFixed: true, + isNew: false, + commentCount: 14, + }, + { + id: 2, + title: '스터디 전체 공지 드립니다.', + writer: '파크크크크크크크크', + date: '1시간 전', + view: 11, + isFixed: true, + isNew: true, + commentCount: 0, + }, +]; + +export const NoticeList: ComponentStory = () => ( + + + + 번호 + 제목 + 작성자 + 날짜 + 조회수 + + + + {noticeList + .reverse() + .map(({ id, title, writer, date, view, commentCount }) => ( + + + {id} + + + {title} + {commentCount > 0 && ( + + {commentCount} + + )} + + + {writer} + + + {date} + + + {view} + + + ))} + +
+); + +const memberManagementList = [ + { + id: 1, + nickName: 'Hemdi', + status: 'waiting', + dateOfSubscription: '2022.10.22', + periodOfActivity: 0, + uncheckin: 0, + uncheckout: 0, + penaltyPoint: 0, + }, + { + id: 2, + nickName: 'Jamie', + status: 'warning', + dateOfSubscription: '2022.10.22', + periodOfActivity: 0, + uncheckin: 0, + uncheckout: 10, + penaltyPoint: 990, + }, + { + id: 3, + nickName: 'Park', + status: 'member', + dateOfSubscription: '2022.10.22', + periodOfActivity: 0, + uncheckin: 0, + uncheckout: 0, + penaltyPoint: 0, + }, +]; + +const STATUS = { + member: { + text: '활동 중', + color: 'primary', + }, + waiting: { + text: '가입 승인 대기 중', + color: 'fontColor', + }, + warning: { + text: '벌점 초과', + color: 'warning', + }, + danger: { + text: '경고 대상', + color: 'danger', + }, +}; + +export const MemberManagementList: ComponentStory = () => ( + + + + 닉네임 + 상태 + 가입일 + 활동일 + + 미 체크인 + + + + 미 체크아웃 + + + 벌점 + + + + {memberManagementList.map((props) => ( + + + + {props.nickName} + + + + + {STATUS[props.status].text} + + + + + {props.dateOfSubscription} + + + {props.periodOfActivity}일 + + + {props.uncheckin}회 + + + {props.uncheckout}회 + + + {props.penaltyPoint}점 + + + ))} + +
+); diff --git a/src/styles/commonStyles.ts b/src/styles/commonStyles.ts new file mode 100644 index 0000000..2132695 --- /dev/null +++ b/src/styles/commonStyles.ts @@ -0,0 +1,10 @@ +import { CSSObject } from 'styled-components'; + +export const offscreen: CSSObject = { + position: 'absolute', + width: '1px', + height: '1px', + margin: '-1px', + overflow: 'hidden', + clipPath: 'polygon(0 0, 0 0, 0 0)', +};