diff --git a/frontend/lib/registry/components/table-list/CardModeRenderer.tsx b/frontend/lib/registry/components/table-list/CardModeRenderer.tsx new file mode 100644 index 00000000..2988f864 --- /dev/null +++ b/frontend/lib/registry/components/table-list/CardModeRenderer.tsx @@ -0,0 +1,224 @@ +"use client"; + +import React from "react"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Eye, Edit, Trash2, MoreHorizontal } from "lucide-react"; +import { CardDisplayConfig, ColumnConfig } from "./types"; + +interface CardModeRendererProps { + data: Record[]; + cardConfig: CardDisplayConfig; + visibleColumns: ColumnConfig[]; + onRowClick?: (row: Record) => void; + onRowSelect?: (row: Record, selected: boolean) => void; + selectedRows?: string[]; + showActions?: boolean; +} + +/** + * 카드 모드 렌더러 + * 테이블 데이터를 카드 형태로 표시 + */ +export const CardModeRenderer: React.FC = ({ + data, + cardConfig, + visibleColumns, + onRowClick, + onRowSelect, + selectedRows = [], + showActions = true, +}) => { + // 기본값 설정 + const config = { + cardsPerRow: 3, + cardSpacing: 16, + showActions: true, + cardHeight: "auto", + ...cardConfig, + }; + + // 카드 그리드 스타일 계산 + const gridStyle: React.CSSProperties = { + display: "grid", + gridTemplateColumns: `repeat(${config.cardsPerRow}, 1fr)`, + gap: `${config.cardSpacing}px`, + padding: `${config.cardSpacing}px`, + }; + + // 카드 높이 스타일 + const cardStyle: React.CSSProperties = { + height: config.cardHeight === "auto" ? "auto" : `${config.cardHeight}px`, + cursor: onRowClick ? "pointer" : "default", + }; + + // 컬럼 값 가져오기 함수 + const getColumnValue = (row: Record, columnName?: string): string => { + if (!columnName || !row) return ""; + return String(row[columnName] || ""); + }; + + // 액션 버튼 렌더링 + const renderActions = (row: Record) => { + if (!showActions || !config.showActions) return null; + + return ( +
+ + + + +
+ ); + }; + + // 데이터가 없는 경우 + if (!data || data.length === 0) { + return ( +
+
+
+
+
표시할 데이터가 없습니다
+
조건을 변경하거나 새로운 데이터를 추가해보세요
+
+ ); + } + + return ( +
+ {data.map((row, index) => { + const idValue = getColumnValue(row, config.idColumn); + const titleValue = getColumnValue(row, config.titleColumn); + const subtitleValue = getColumnValue(row, config.subtitleColumn); + const descriptionValue = getColumnValue(row, config.descriptionColumn); + const imageValue = getColumnValue(row, config.imageColumn); + + const isSelected = selectedRows.includes(idValue); + + return ( + onRowClick?.(row)} + > + +
+
+ + {titleValue || "제목 없음"} + + {subtitleValue && ( +
+ {subtitleValue} +
+ )} +
+ + {/* ID 뱃지 */} + {idValue && ( + + {idValue} + + )} +
+
+ + + {/* 이미지 표시 */} + {imageValue && ( +
+ {titleValue} { + const target = e.target as HTMLImageElement; + target.style.display = "none"; + }} + /> +
+ )} + + {/* 설명 표시 */} + {descriptionValue && ( +
+ {descriptionValue} +
+ )} + + {/* 추가 필드들 표시 (선택적) */} +
+ {visibleColumns + .filter(col => + col.columnName !== config.idColumn && + col.columnName !== config.titleColumn && + col.columnName !== config.subtitleColumn && + col.columnName !== config.descriptionColumn && + col.columnName !== config.imageColumn && + col.columnName !== "__checkbox__" && + col.visible + ) + .slice(0, 3) // 최대 3개 추가 필드만 표시 + .map((col) => { + const value = getColumnValue(row, col.columnName); + if (!value) return null; + + return ( +
+ {col.displayName}: + {value} +
+ ); + })} +
+ + {/* 액션 버튼들 */} + {renderActions(row)} +
+
+ ); + })} +
+ ); +};