Table
데이터를 표 형태로 표시하는 테이블 컴포넌트입니다.
개요
Table은 구조화된 데이터를 표 형태로 표시하는 컴포넌트입니다. Cals Table은 Cals 브랜드 스타일과 예약 상태 컬러가 적용되어 있으며, 예약 목록과 고객 관리 데이터를 효과적으로 표시합니다. Foundation Table의 모든 기능을 상속합니다.
주요 특징:
- 정렬 가능한 컬럼
- 예약 상태별 Row 색상
- Cals 브랜드 컬러 적용 (Pink, Blue, Purple)
- 예약 상태 컬러 완벽 지원 (Available, Pending, Confirmed, Cancelled, Completed)
- 필터링 및 검색
- 페이지네이션
사용 사례:
- Cals 예약 목록 테이블 (상태별 row 색상)
- 고객 예약 히스토리
- 서비스 예약 현황
- 고객 관리 목록
설치
npx @vortex/cli add table --package cals기본 사용법
import "@vortex/ui-cals/theme"; // Cals 테마 적용
import {
Table,
TableHeader,
TableBody,
TableRow,
TableHead,
TableCell,
} from "@vortex/ui-cals";
export default function Example() {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>예약번호</TableHead>
<TableHead>고객명</TableHead>
<TableHead>상태</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>#12345</TableCell>
<TableCell>홍길동</TableCell>
<TableCell>예약 확정</TableCell>
</TableRow>
</TableBody>
</Table>
);
}Variants (변형)
Default
기본 테이블 스타일입니다.
<Table>
<TableHeader>
<TableRow>
<TableHead>컬럼 1</TableHead>
<TableHead>컬럼 2</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>데이터 1</TableCell>
<TableCell>데이터 2</TableCell>
</TableRow>
</TableBody>
</Table>With Status Colors (예약 상태별 Row 색상)
예약 상태에 따라 Row 배경색이 변경됩니다.
import { Badge } from "@vortex/ui-cals";
<Table>
<TableHeader>
<TableRow>
<TableHead>예약번호</TableHead>
<TableHead>상태</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow className="bg-available/10">
<TableCell>#001</TableCell>
<TableCell>
<Badge variant="available">예약 가능</Badge>
</TableCell>
</TableRow>
<TableRow className="bg-pending/10">
<TableCell>#002</TableCell>
<TableCell>
<Badge variant="pending">승인 대기</Badge>
</TableCell>
</TableRow>
<TableRow className="bg-confirmed/10">
<TableCell>#003</TableCell>
<TableCell>
<Badge variant="confirmed">예약 확정</Badge>
</TableCell>
</TableRow>
<TableRow className="bg-cancelled/10">
<TableCell>#004</TableCell>
<TableCell>
<Badge variant="cancelled">예약 취소</Badge>
</TableCell>
</TableRow>
<TableRow className="bg-completed/10">
<TableCell>#005</TableCell>
<TableCell>
<Badge variant="completed">서비스 완료</Badge>
</TableCell>
</TableRow>
</TableBody>
</Table>;With Actions
액션 버튼이 포함된 테이블입니다.
import { Button } from "@vortex/ui-cals";
import { Eye, Edit, Trash } from "lucide-react";
<Table>
<TableHeader>
<TableRow>
<TableHead>예약번호</TableHead>
<TableHead>고객명</TableHead>
<TableHead className="text-right">액션</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>#12345</TableCell>
<TableCell>홍길동</TableCell>
<TableCell className="text-right">
<div className="flex gap-xs justify-end">
<Button variant="ghost" size="sm">
<Eye size={14} />
</Button>
<Button variant="ghost" size="sm">
<Edit size={14} />
</Button>
<Button variant="ghost" size="sm">
<Trash size={14} />
</Button>
</div>
</TableCell>
</TableRow>
</TableBody>
</Table>;Cals 브랜딩
브랜드 컬러
Cals Table은 다음 브랜드 컬러를 사용합니다:
- Primary (Pink):
#e91e63- 헤더 강조, CTA 버튼 - Secondary (Blue):
#03a9f4- 링크, 보조 액션 - Accent (Purple):
#9c27b0- 특별 상태 표시
예약 상태 컬러 ⭐
Cals는 예약 시스템에 특화된 5가지 상태 컬러를 제공합니다:
- Available (Green):
#4caf50- 예약 가능 - Pending (Orange):
#ff9800- 승인 대기 - Confirmed (Blue):
#03a9f4- 예약 확정 - Cancelled (Red):
#f44336- 예약 취소 - Completed (Purple):
#9c27b0- 서비스 완료
Cals 특화 사용 가이드
예약 상태별 Row 색상:
// bg-{status}/10 클래스로 상태별 배경색 적용
<TableRow className="bg-available/10"> // 연한 Green
<TableRow className="bg-pending/10"> // 연한 Orange
<TableRow className="bg-confirmed/10"> // 연한 Blue
<TableRow className="bg-cancelled/10"> // 연한 Red
<TableRow className="bg-completed/10"> // 연한 Purple예약 목록 테이블:
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from '@vortex/ui-cals'
import { Badge, Button } from '@vortex/ui-cals'
import { Calendar, Clock, Check, X } from 'lucide-react'
const reservations = [
{ id: '#001', customer: '홍길동', date: '2024-01-20 14:00', service: '프리미엄', status: 'confirmed' },
{ id: '#002', customer: '김영희', date: '2024-01-21 10:00', service: '스탠다드', status: 'pending' },
{ id: '#003', customer: '이철수', date: '2024-01-22 15:30', service: 'VIP', status: 'available' }
]
<Table>
<TableHeader>
<TableRow>
<TableHead>예약번호</TableHead>
<TableHead>고객명</TableHead>
<TableHead>예약일시</TableHead>
<TableHead>서비스</TableHead>
<TableHead>상태</TableHead>
<TableHead className="text-right">액션</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{reservations.map((reservation) => (
<TableRow key={reservation.id} className={`bg-${reservation.status}/10`}>
<TableCell className="font-medium">{reservation.id}</TableCell>
<TableCell>{reservation.customer}</TableCell>
<TableCell>
<div className="flex items-center gap-xs">
<Calendar size={14} />
{reservation.date}
</div>
</TableCell>
<TableCell>{reservation.service}</TableCell>
<TableCell>
<Badge variant={reservation.status}>
{reservation.status === 'confirmed' && '예약 확정'}
{reservation.status === 'pending' && '승인 대기'}
{reservation.status === 'available' && '예약 가능'}
</Badge>
</TableCell>
<TableCell className="text-right">
<div className="flex gap-xs justify-end">
<Button variant="ghost" size="sm">
<Check size={14} />
</Button>
<Button variant="ghost" size="sm">
<X size={14} />
</Button>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>Foundation/iCignal/Cals 비교
| 속성 | Foundation | iCignal | Cals |
|---|---|---|---|
| 브랜드 컬러 | 중립 회색 | iCignal Blue | Cals Pink/Blue/Purple |
| 특화 기능 | 없음 | Analytics 데이터 | 예약 상태 Row 색상 |
| 사용 맥락 | 범용 | 데이터 분석 | 예약 관리 |
| 상태 컬러 | ❌ | ❌ | ✅ 5가지 예약 상태 |
| Row 색상 | ❌ | ❌ | ✅ 상태별 배경색 |
| 테마 | 중립적 테마 | iCignal 테마 | Cals 테마 (@vortex/ui-cals/theme) |
import 경로 차이:
// Foundation
import { Table } from "@vortex/ui-foundation";
// iCignal
import "@vortex/ui-icignal/theme";
import { Table } from "@vortex/ui-icignal";
// Cals
import "@vortex/ui-cals/theme"; // 테마 import 필수
import { Table } from "@vortex/ui-cals";Props API
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | 추가 CSS 클래스 |
| children | ReactNode | - | 테이블 내용 |
접근성
Table 컴포넌트는 WCAG 2.1 AA 기준을 준수합니다.
시맨틱 HTML:
<table>,<thead>,<tbody>,<tr>,<th>,<td>사용scope속성으로 헤더-데이터 관계 명시
키보드 네비게이션:
Tab: 테이블 내 포커스 가능한 요소로 이동Arrow Keys: 셀 간 네비게이션 (고급 기능)
스크린 리더 지원:
- 테이블 캡션 제공 (선택사항)
- 헤더가 명확하게 읽힘
- 상태 정보가 정확하게 전달됨
색상 대비:
- 텍스트와 배경 4.5:1 이상
- 예약 상태 Row 색상 대비 충족
예제
예제 1: 예약 목록 테이블 ⭐
import "@vortex/ui-cals/theme";
import {
Table,
TableHeader,
TableBody,
TableRow,
TableHead,
TableCell,
} from "@vortex/ui-cals";
import { Badge, Button } from "@vortex/ui-cals";
import { Card, CardHeader, CardContent } from "@vortex/ui-cals";
import { Calendar, Clock, User, Phone, Check, X, Eye } from "lucide-react";
export default function ReservationListTable() {
const reservations = [
{
id: "#12345",
customer: "홍길동",
phone: "010-1234-5678",
date: "2024-01-20",
time: "14:00",
service: "프리미엄 패키지",
price: "150,000원",
status: "confirmed",
},
{
id: "#12346",
customer: "김영희",
phone: "010-2345-6789",
date: "2024-01-21",
time: "10:00",
service: "스탠다드 패키지",
price: "100,000원",
status: "pending",
},
{
id: "#12347",
customer: "이철수",
phone: "010-3456-7890",
date: "2024-01-22",
time: "15:30",
service: "VIP 패키지",
price: "200,000원",
status: "available",
},
{
id: "#12348",
customer: "박민수",
phone: "010-4567-8901",
date: "2024-01-19",
time: "11:00",
service: "베이직 패키지",
price: "80,000원",
status: "cancelled",
},
{
id: "#12349",
customer: "정수진",
phone: "010-5678-9012",
date: "2024-01-18",
time: "16:00",
service: "프리미엄 패키지",
price: "150,000원",
status: "completed",
},
];
const getStatusBadge = (status) => {
const statusMap = {
available: { label: "예약 가능", icon: Calendar },
pending: { label: "승인 대기", icon: Clock },
confirmed: { label: "예약 확정", icon: Check },
cancelled: { label: "예약 취소", icon: X },
completed: { label: "서비스 완료", icon: Check },
};
const { label, icon: Icon } = statusMap[status];
return (
<Badge variant={status}>
<Icon size={14} className="mr-xs" />
{label}
</Badge>
);
};
return (
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<h2 className="text-xl font-bold">예약 목록</h2>
<Button variant="primary">
<Calendar size={16} className="mr-xs" />
신규 예약 등록
</Button>
</div>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>예약번호</TableHead>
<TableHead>고객 정보</TableHead>
<TableHead>예약 일시</TableHead>
<TableHead>서비스</TableHead>
<TableHead className="text-right">금액</TableHead>
<TableHead>상태</TableHead>
<TableHead className="text-right">액션</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{reservations.map((reservation) => (
<TableRow
key={reservation.id}
className={`bg-${reservation.status}/10 hover:bg-${reservation.status}/20 transition-colors`}
>
<TableCell className="font-medium">{reservation.id}</TableCell>
<TableCell>
<div className="space-y-xs">
<div className="flex items-center gap-xs">
<User size={14} className="text-muted-foreground" />
<span className="font-medium">
{reservation.customer}
</span>
</div>
<div className="flex items-center gap-xs text-sm text-muted-foreground">
<Phone size={12} />
{reservation.phone}
</div>
</div>
</TableCell>
<TableCell>
<div className="space-y-xs">
<div className="flex items-center gap-xs">
<Calendar size={14} className="text-muted-foreground" />
{reservation.date}
</div>
<div className="flex items-center gap-xs text-sm text-muted-foreground">
<Clock size={12} />
{reservation.time}
</div>
</div>
</TableCell>
<TableCell>{reservation.service}</TableCell>
<TableCell className="text-right font-medium">
{reservation.price}
</TableCell>
<TableCell>{getStatusBadge(reservation.status)}</TableCell>
<TableCell className="text-right">
<div className="flex gap-xs justify-end">
<Button variant="ghost" size="sm" aria-label="상세보기">
<Eye size={14} />
</Button>
{reservation.status === "pending" && (
<>
<Button variant="ghost" size="sm" aria-label="승인">
<Check size={14} className="text-green-600" />
</Button>
<Button variant="ghost" size="sm" aria-label="거절">
<X size={14} className="text-red-600" />
</Button>
</>
)}
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
);
}예제 2: 고객 예약 히스토리 ⭐
import "@vortex/ui-cals/theme";
import {
Table,
TableHeader,
TableBody,
TableRow,
TableHead,
TableCell,
} from "@vortex/ui-cals";
import { Badge } from "@vortex/ui-cals";
import { Star, Calendar } from "lucide-react";
export default function CustomerReservationHistory() {
const history = [
{
date: "2024-01-18",
service: "프리미엄 패키지",
status: "completed",
rating: 5,
},
{
date: "2024-01-15",
service: "스탠다드 패키지",
status: "completed",
rating: 4,
},
{
date: "2024-01-20",
service: "VIP 패키지",
status: "confirmed",
rating: null,
},
{
date: "2024-01-10",
service: "베이직 패키지",
status: "cancelled",
rating: null,
},
];
return (
<div className="space-y-md">
<h3 className="text-lg font-semibold">예약 이력</h3>
<Table>
<TableHeader>
<TableRow>
<TableHead>예약일</TableHead>
<TableHead>서비스</TableHead>
<TableHead>상태</TableHead>
<TableHead>평점</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{history.map((item, index) => (
<TableRow key={index} className={`bg-${item.status}/10`}>
<TableCell>
<div className="flex items-center gap-xs">
<Calendar size={14} />
{item.date}
</div>
</TableCell>
<TableCell>{item.service}</TableCell>
<TableCell>
<Badge variant={item.status}>
{item.status === "completed" && "완료"}
{item.status === "confirmed" && "확정"}
{item.status === "cancelled" && "취소"}
</Badge>
</TableCell>
<TableCell>
{item.rating ? (
<div className="flex items-center gap-xs">
{[...Array(item.rating)].map((_, i) => (
<Star
key={i}
size={14}
className="fill-yellow-400 text-yellow-400"
/>
))}
</div>
) : (
<span className="text-muted-foreground text-sm">-</span>
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}관련 컴포넌트
- Foundation Table - 기본 버전 참조
- iCignal Table - iCignal 버전 참조
- Badge - 예약 상태 표시
- Button - 액션 버튼
- Card - 테이블 컨테이너
- Pagination - 페이지 네비게이션
Last updated on