Skip to content

Commit

Permalink
Merge pull request #27 from Myongji-Graduate/list-molecule-component/#18
Browse files Browse the repository at this point in the history


implement List molecule component/#18
  • Loading branch information
gahyuun authored Feb 22, 2024
2 parents 249d1af + 4ab6c6c commit a97f6e6
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 7 deletions.
6 changes: 3 additions & 3 deletions app/ui/view/atom/button/button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './button';
import Button from './button';

const meta = {
title: 'ui/view/atom/Button',
Expand Down Expand Up @@ -71,10 +71,10 @@ export const SecondaryButton: StoryObj<typeof Button> = {
render: (args) => <Button {...args} />,
};

export const DeleteButton: StoryObj<typeof Button> = {
export const ListActionButton: StoryObj<typeof Button> = {
args: {
size: 'default',
variant: 'delete',
variant: 'list',
label: '삭제',
},
render: (args) => <Button {...args} />,
Expand Down
10 changes: 6 additions & 4 deletions app/ui/view/atom/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import React from 'react';

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
label: string;
variant?: 'primary' | 'secondary' | 'text' | 'delete';
variant?: 'primary' | 'secondary' | 'text' | 'list';
size?: 'xs' | 'sm' | 'md' | 'lg' | 'default';
}

export const ButtonVariants = cva(`flex justify-center items-center`, {
variants: {
variant: {
primary: 'bg-primary rounded-[100px] text-white border-0 hover:bg-primary-hover',
secondary: 'bg-white rounded-[100px] border-solid border-[1px] border-gray hover:bg-white-hover',
secondary: 'bg-white rounded-[100px] border-solid border-[1px] border-gray-6 hover:bg-white-hover',
text: 'font-medium text-slate-400 text-sm hover:text-slate-600',
delete: 'py-2 px-3.5 bg-[#35353559] rounded-[7px] text-white leading-5 font-medium text-[18px]',
list: 'py-2 px-3.5 bg-neutral-400 rounded-[7px] text-white leading-5 font-medium text-[18px] hover:bg-neutral-500',
},
size: {
default: '',
Expand All @@ -25,7 +25,7 @@ export const ButtonVariants = cva(`flex justify-center items-center`, {
},
});

export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(function Button(
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(function Button(
{ label, variant = 'primary', size = 'default', ...props },
ref,
) {
Expand All @@ -35,3 +35,5 @@ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(function
</button>
);
});

export default Button;
9 changes: 9 additions & 0 deletions app/ui/view/molecule/grid/grid-column.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ReactNode } from 'react';

type GridColumnProps = {
children: ReactNode;
};

export function GridColumn({ children }: GridColumnProps) {
return <div className={'place-self-center text-center'}>{children}</div>;
}
23 changes: 23 additions & 0 deletions app/ui/view/molecule/grid/grid-root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { cva } from 'class-variance-authority';
import { ReactNode } from 'react';

export type ColType = 3 | 4 | 5 | 6;

type GridRootProps = {
children: ReactNode;
cols: ColType;
};

export const GridVariants = cva('grid', {
variants: {
cols: {
3: 'grid-cols-3',
4: 'grid-cols-4',
5: 'grid-cols-5',
6: 'grid-cols-6',
},
},
});
export function GridRoot({ children, cols = 3 }: GridRootProps) {
return <div className={GridVariants({ cols })}>{children}</div>;
}
8 changes: 8 additions & 0 deletions app/ui/view/molecule/grid/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { GridColumn } from './grid-column';
import { GridRoot } from './grid-root';

const Grid = Object.assign(GridRoot, {
Column: GridColumn,
});

export default Grid;
8 changes: 8 additions & 0 deletions app/ui/view/molecule/list/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ListRoot } from './list-root';
import { ListRow } from './list-row';

const List = Object.assign(ListRoot, {
Row: ListRow,
});

export default List;
10 changes: 10 additions & 0 deletions app/ui/view/molecule/list/list-root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ReactNode } from 'react';

type ListRootProps<T> = {
data: T[];
render: (item: T) => ReactNode;
};

export function ListRoot<T>({ data, render }: ListRootProps<T>) {
return <div className="rounded-2xl border-[1px] border-black-2 w-full">{data.map((item) => render(item))}</div>;
}
19 changes: 19 additions & 0 deletions app/ui/view/molecule/list/list-row.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ReactNode } from 'react';
import { twMerge } from 'tailwind-merge';

type ListRowProps = {
children: ReactNode;
textColor?: 'red' | 'black';
};
export function ListRow({ children, textColor = 'black' }: ListRowProps) {
return (
<div
className={twMerge(
'border-solid border-gray-300 border-b-[1px] last:border-b-0 py-4 font-medium text-lg',
textColor === 'red' ? 'text-red-500' : 'text-black-2',
)}
>
{children}
</div>
);
}
8 changes: 8 additions & 0 deletions app/ui/view/molecule/table/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { TableHeader } from './table-header';
import { TableRoot } from './table-root';

const Table = Object.assign(TableRoot, {
Header: TableHeader,
});

export default Table;
19 changes: 19 additions & 0 deletions app/ui/view/molecule/table/table-header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Grid from '../grid';
import { ColType } from '../grid/grid-root';

type TableHeaderProps = {
headerInfo: string[];
cols: ColType;
};

export function TableHeader({ cols, headerInfo }: TableHeaderProps) {
return (
<div className="text-light-blue-6 leading-4 text-lg font-bold bg-light-blue-1 py-5 rounded-[100px]">
<Grid cols={cols}>
{headerInfo.map((info) => (
<Grid.Column key={info}>{info}</Grid.Column>
))}
</Grid>
</div>
);
}
41 changes: 41 additions & 0 deletions app/ui/view/molecule/table/table-root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { TableHeader } from './table-header';
import { ColType } from '../grid/grid-root';
import List from '../list';
import Grid from '../grid';

type TableRootProps = {
headerInfo: string[];
data: string[][];
actionButton?: JSX.Element;
};

function isCol(cols: number): cols is ColType {
if (cols === 3 || cols === 4 || cols === 5 || cols === 6) {
return true;
}
return false;
}

export function TableRoot({ data, headerInfo, actionButton }: TableRootProps) {
const cols = actionButton ? headerInfo.length + 1 : headerInfo.length;

const render = (item: string[]) => {
return (
<List.Row>
<Grid cols={isCol(cols) ? cols : 6}>
{item.map((info) => (
<Grid.Column key={info}>{info}</Grid.Column>
))}
{actionButton ? <Grid.Column>{actionButton}</Grid.Column> : null}
</Grid>
</List.Row>
);
};

return (
<div className="flex flex-col gap-2.5 w-[800px]">
<TableHeader headerInfo={headerInfo} cols={isCol(cols) ? cols : 6} />
<List data={data} render={render}></List>
</div>
);
}
44 changes: 44 additions & 0 deletions app/ui/view/molecule/table/table.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Meta, StoryObj } from '@storybook/react';
import Table from '.';
import Button from '../../atom/button/button';

const meta = {
title: 'ui/view/molecule/Table',
component: Table,
} satisfies Meta<typeof Table>;

export default meta;

export const TakenLectureTable: StoryObj = {
render: () => {
const headerInfo = ['과목코드', '과목명', '학점'];
const lectures = [
['HEC01208', '데이터구조와알고리즘1', '3'],
['HEC01208', '데이터구조와알고리즘1', '3'],
['HEC01208', '데이터구조와알고리즘1', '3'],
];

return (
<main>
<Table data={lectures} headerInfo={headerInfo} />
</main>
);
},
};

export const ButtonLectureTable: StoryObj = {
render: () => {
const headerInfo = ['수강년도', '수강학기', '과목코드', '과목명', '학점'];
const lectures = [
['2022', '2학기', 'HEC01208', '데이터구조와알고리즘1', '3'],
['2022', '2학기', 'HEC01208', '데이터구조와알고리즘1', '3'],
['2022', '2학기', 'HEC01208', '데이터구조와알고리즘1', '3'],
];
const actionButton = <Button variant="list" label="삭제" />;
return (
<main>
<Table headerInfo={headerInfo} data={lectures} actionButton={actionButton} />
</main>
);
},
};

0 comments on commit a97f6e6

Please sign in to comment.