카드 컴포넌트 중간커밋

This commit is contained in:
kjs
2025-12-01 18:39:01 +09:00
parent 617655a42a
commit fb16e224f0
8 changed files with 374 additions and 47 deletions

View File

@@ -43,6 +43,9 @@ export const CardDisplayComponent: React.FC<CardDisplayComponentProps> = ({
const [loadedTableColumns, setLoadedTableColumns] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
// 선택된 카드 상태
const [selectedCardId, setSelectedCardId] = useState<string | number | null>(null);
// 상세보기 모달 상태
const [viewModalOpen, setViewModalOpen] = useState(false);
const [selectedData, setSelectedData] = useState<any>(null);
@@ -261,26 +264,19 @@ export const CardDisplayComponent: React.FC<CardDisplayComponentProps> = ({
borderRadius: "12px", // 컨테이너 자체도 라운드 처리
};
// 카드 스타일 - 통일된 디자인 시스템 적용
// 카드 스타일 - 컴팩트한 디자인
const cardStyle: React.CSSProperties = {
backgroundColor: "white",
border: "2px solid #e5e7eb", // 더 명확한 테두리
borderRadius: "12px", // 통일된 라운드 처리
padding: "24px", // 더 여유로운 패딩
boxShadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)", // 더 깊은 그림자
transition: "all 0.3s cubic-bezier(0.4, 0, 0.2, 1)", // 부드러운 트랜지션
border: "1px solid #e5e7eb",
borderRadius: "8px",
padding: "16px",
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.08)",
transition: "all 0.2s ease",
overflow: "hidden",
display: "flex",
flexDirection: "column",
position: "relative",
minHeight: "240px", // 최소 높이 더 증가
cursor: isDesignMode ? "pointer" : "default",
// 호버 효과를 위한 추가 스타일
"&:hover": {
transform: "translateY(-2px)",
boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)",
borderColor: "#f59e0b", // 호버 시 오렌지 테두리
}
};
// 텍스트 자르기 함수
@@ -328,6 +324,14 @@ export const CardDisplayComponent: React.FC<CardDisplayComponentProps> = ({
};
const handleCardClick = (data: any) => {
const cardId = data.id || data.objid || data.ID;
// 이미 선택된 카드를 다시 클릭하면 선택 해제
if (selectedCardId === cardId) {
setSelectedCardId(null);
} else {
setSelectedCardId(cardId);
}
if (componentConfig.onCardClick) {
componentConfig.onCardClick(data);
}
@@ -421,67 +425,75 @@ export const CardDisplayComponent: React.FC<CardDisplayComponentProps> = ({
? getColumnValue(data, componentConfig.columnMapping.imageColumn)
: data.avatar || data.image || "";
const cardId = data.id || data.objid || data.ID || index;
const isCardSelected = selectedCardId === cardId;
return (
<div
key={data.id || index}
style={cardStyle}
className="card-hover group cursor-pointer"
key={cardId}
style={{
...cardStyle,
borderColor: isCardSelected ? "#000" : "#e5e7eb",
borderWidth: isCardSelected ? "2px" : "1px",
boxShadow: isCardSelected
? "0 4px 6px -1px rgba(0, 0, 0, 0.15)"
: "0 1px 3px rgba(0, 0, 0, 0.08)",
}}
className="card-hover group cursor-pointer transition-all duration-150"
onClick={() => handleCardClick(data)}
>
{/* 카드 이미지 - 통일된 디자인 */}
{/* 카드 이미지 */}
{componentConfig.cardStyle?.showImage && componentConfig.columnMapping?.imageColumn && (
<div className="mb-4 flex justify-center">
<div className="flex h-20 w-20 items-center justify-center rounded-full bg-gradient-to-br from-primary/10 to-primary/20 shadow-sm border-2 border-background">
<span className="text-2xl text-primary">👤</span>
<div className="mb-2 flex justify-center">
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10">
<span className="text-lg text-primary">👤</span>
</div>
</div>
)}
{/* 카드 타이틀 - 통일된 디자인 */}
{componentConfig.cardStyle?.showTitle && (
<div className="mb-3">
<h3 className="text-xl font-bold text-foreground leading-tight">{titleValue}</h3>
{/* 카드 타이틀 + 서브타이틀 (가로 배치) */}
{(componentConfig.cardStyle?.showTitle || componentConfig.cardStyle?.showSubtitle) && (
<div className="mb-2 flex items-center gap-2 flex-wrap">
{componentConfig.cardStyle?.showTitle && (
<h3 className="text-base font-semibold text-foreground leading-tight">{titleValue}</h3>
)}
{componentConfig.cardStyle?.showSubtitle && subtitleValue && (
<span className="text-xs font-medium text-primary bg-primary/10 px-2 py-0.5 rounded-full">{subtitleValue}</span>
)}
</div>
)}
{/* 카드 서브타이틀 - 통일된 디자인 */}
{componentConfig.cardStyle?.showSubtitle && (
<div className="mb-3">
<p className="text-sm font-semibold text-primary bg-primary/10 px-3 py-1 rounded-full inline-block">{subtitleValue}</p>
</div>
)}
{/* 카드 설명 - 통일된 디자인 */}
{/* 카드 설명 */}
{componentConfig.cardStyle?.showDescription && (
<div className="mb-4 flex-1">
<p className="text-sm leading-relaxed text-foreground bg-muted p-3 rounded-lg">
<div className="mb-2 flex-1">
<p className="text-xs text-muted-foreground leading-relaxed">
{truncateText(descriptionValue, componentConfig.cardStyle?.maxDescriptionLength || 100)}
</p>
</div>
)}
{/* 추가 표시 컬럼들 - 통일된 디자인 */}
{/* 추가 표시 컬럼들 - 가로 배치 */}
{componentConfig.columnMapping?.displayColumns &&
componentConfig.columnMapping.displayColumns.length > 0 && (
<div className="space-y-2 border-t border-border pt-4">
<div className="flex flex-wrap items-center gap-x-3 gap-y-0.5 border-t border-border pt-2 text-xs">
{componentConfig.columnMapping.displayColumns.map((columnName, idx) => {
const value = getColumnValue(data, columnName);
if (!value) return null;
return (
<div key={idx} className="flex justify-between items-center text-sm bg-background/50 px-3 py-2 rounded-lg border border-border">
<span className="text-muted-foreground font-medium capitalize">{getColumnLabel(columnName)}:</span>
<span className="font-semibold text-foreground bg-muted px-2 py-1 rounded-md text-xs">{value}</span>
<div key={idx} className="flex items-center gap-1">
<span className="text-muted-foreground">{getColumnLabel(columnName)}:</span>
<span className="font-medium text-foreground">{value}</span>
</div>
);
})}
</div>
)}
{/* 카드 액션 (선택사항) */}
<div className="mt-3 flex justify-end space-x-2">
{/* 카드 액션 */}
<div className="mt-2 flex justify-end space-x-2">
<button
className="text-xs font-medium text-blue-600 hover:text-blue-800 transition-colors"
className="text-xs text-blue-600 hover:text-blue-800 transition-colors"
onClick={(e) => {
e.stopPropagation();
handleCardView(data);
@@ -490,7 +502,7 @@ export const CardDisplayComponent: React.FC<CardDisplayComponentProps> = ({
</button>
<button
className="text-xs font-medium text-muted-foreground hover:text-foreground transition-colors"
className="text-xs text-muted-foreground hover:text-foreground transition-colors"
onClick={(e) => {
e.stopPropagation();
handleCardEdit(data);