카드 컴포넌트 중간커밋
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user