feat: 컴포넌트 추가, 스타일 수정

This commit is contained in:
2026-04-10 12:23:48 +09:00
parent a836333512
commit 35f6023f5a
19 changed files with 1263 additions and 56 deletions

View File

@@ -0,0 +1,70 @@
import { DescriptionsItem, DescriptionsItemProps } from './items/DescriptionsItem';
export type DescriotionItemType = {
items: (DescriptionsItemProps & { key?: string })[];
column?: 1 | 2 | 3 | 4;
titleWidth?: number;
className?: string;
titleClassName?: string;
contentClassName?: string;
};
export const Descriptions = (props: DescriotionItemType) => {
const { items, column = 1, titleWidth, className, titleClassName, contentClassName } = props;
const columnClassName =
{
1: 'grid-cols-1',
2: 'grid-cols-2',
3: 'grid-cols-3',
4: 'grid-cols-4',
}[column] || 'grid-cols-1';
const getFirstRowItemIndices = () => {
const firstRowItemIndices: number[] = [];
let availableColumns = column;
for (let index = 0; index < items.length; index += 1) {
if (availableColumns <= 0) {
break;
}
const item = items[index];
const itemSpan = item.span === 'filled' ? column : (item.span ?? 1);
const effectiveSpan = Math.min(typeof itemSpan === 'number' ? itemSpan : column, column);
if (effectiveSpan > availableColumns) {
break;
}
firstRowItemIndices.push(index);
availableColumns -= effectiveSpan;
if (availableColumns === 0) {
break;
}
}
return firstRowItemIndices;
};
const firstRowItemIndices = getFirstRowItemIndices();
return (
<div className={`grid w-full gap-0 ${columnClassName || ''} ${className || ''}`}>
{items.map((item, index) => {
const { key, ...itemProps } = item;
return (
<DescriptionsItem
key={key || index}
{...itemProps}
isFirstRow={firstRowItemIndices.includes(index)}
titleWidth={titleWidth}
titleClassName={titleClassName}
contentClassName={contentClassName}
/>
);
})}
</div>
);
};

View File

@@ -0,0 +1,39 @@
import clsx from 'clsx';
export type DescriptionsItemProps = {
title: React.ReactNode;
content: React.ReactNode;
span?: number | 'filled';
isFirstRow?: boolean;
titleWidth?: number;
titleClassName?: string;
contentClassName?: string;
};
export const DescriptionsItem = (props: DescriptionsItemProps) => {
const { title, content, span, isFirstRow = false, titleWidth, titleClassName, contentClassName } = props;
const gridColumnStyle =
span === 'filled' ? { gridColumn: '1 / -1' } : span && span > 0 ? { gridColumn: `span ${span}` } : {};
return (
<div className="flex" style={gridColumnStyle}>
<div
className={`flex w-25 min-h-10 items-center px-4 bg-primary-tertiary01 text-primary-secondary text-sm font-semibold border-b border-white ${titleClassName || ''}`}
style={{ width: titleWidth }}
>
{title}
</div>
<div
className={clsx(
'relative flex flex-1 items-center pl-4 pr-3 py-2 text-sm font-medium text-kc-black-22 overflow-x-auto after:content-[\'\'] after:absolute after:left-0 after:right-0 after:bottom-0 after:h-px after:bg-primary-tertiary01',
contentClassName,
isFirstRow &&
'before:content-[\'\'] before:absolute before:left-0 before:right-0 before:top-0 before:h-px before:bg-primary-tertiary01'
)}
>
{content}
</div>
</div>
);
};