refactor: 전체 프론트엔드 하드코딩 색상 → CSS 변수 일괄 치환
447+ 파일, 4500+ 줄 변경: - gray-* → border/bg-muted/text-foreground/text-muted-foreground - blue-* → primary/ring - red-* → destructive - green-* → emerald (일관성) - indigo-* → primary - yellow/orange → amber (통일) - dark mode 변형도 시맨틱 토큰으로 변환 Made-with: Cursor
This commit is contained in:
@@ -3150,38 +3150,38 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
{/* 드래그 핸들 - 컴포넌트 외부 상단 */}
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-4 cursor-move items-center justify-between rounded-t border border-b-0 bg-gray-100 px-1",
|
||||
isSelectedComp ? "border-primary" : "border-gray-200"
|
||||
"flex h-4 cursor-move items-center justify-between rounded-t border border-b-0 bg-muted px-1",
|
||||
isSelectedComp ? "border-primary" : "border-border"
|
||||
)}
|
||||
style={{ width: displayWidth }}
|
||||
onMouseDown={(e) => handlePanelDragStart(e, "left", comp)}
|
||||
>
|
||||
<div className="flex items-center gap-0.5">
|
||||
<Move className="h-2.5 w-2.5 text-gray-400" />
|
||||
<span className="max-w-[100px] truncate text-[9px] text-gray-500">
|
||||
<Move className="h-2.5 w-2.5 text-muted-foreground/70" />
|
||||
<span className="max-w-[100px] truncate text-[9px] text-muted-foreground">
|
||||
{comp.label || comp.componentType}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
className="rounded p-0.5 hover:bg-gray-200"
|
||||
className="rounded p-0.5 hover:bg-muted/80"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onSelectPanelComponent?.("left", comp.id, comp);
|
||||
}}
|
||||
title="설정"
|
||||
>
|
||||
<Settings className="h-2.5 w-2.5 text-gray-500" />
|
||||
<Settings className="h-2.5 w-2.5 text-muted-foreground" />
|
||||
</button>
|
||||
<button
|
||||
className="rounded p-0.5 hover:bg-red-100"
|
||||
className="rounded p-0.5 hover:bg-destructive/10"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemovePanelComponent("left", comp.id);
|
||||
}}
|
||||
title="삭제"
|
||||
>
|
||||
<Trash2 className="h-2.5 w-2.5 text-red-500" />
|
||||
<Trash2 className="h-2.5 w-2.5 text-destructive" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -3192,7 +3192,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
"relative overflow-hidden rounded-b border bg-white shadow-sm",
|
||||
isSelectedComp
|
||||
? "border-primary ring-2 ring-primary/30"
|
||||
: "border-gray-200",
|
||||
: "border-border",
|
||||
(isDraggingComp || isResizingComp) && "opacity-80 shadow-lg",
|
||||
!(isDraggingComp || isResizingComp) && "transition-all"
|
||||
)}
|
||||
@@ -3270,12 +3270,12 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
)
|
||||
) : (
|
||||
// 컴포넌트가 없을 때 드롭 영역 표시
|
||||
<div className="flex h-full w-full flex-col items-center justify-center rounded border-2 border-dashed border-gray-300 bg-gray-50/50">
|
||||
<Plus className="mb-2 h-8 w-8 text-gray-400" />
|
||||
<p className="text-sm font-medium text-gray-500">
|
||||
<div className="flex h-full w-full flex-col items-center justify-center rounded border-2 border-dashed border-input bg-muted/50">
|
||||
<Plus className="mb-2 h-8 w-8 text-muted-foreground/70" />
|
||||
<p className="text-sm font-medium text-muted-foreground">
|
||||
커스텀 모드
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-gray-400">
|
||||
<p className="mt-1 text-xs text-muted-foreground/70">
|
||||
{isDesignMode ? "컴포넌트를 드래그하여 배치하세요" : "배치된 컴포넌트가 없습니다"}
|
||||
</p>
|
||||
</div>
|
||||
@@ -3287,21 +3287,21 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
{isDesignMode ? (
|
||||
// 디자인 모드: 샘플 테이블
|
||||
<div className="overflow-auto">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="bg-gray-50">
|
||||
<table className="min-w-full divide-y divide-border">
|
||||
<thead className="bg-muted">
|
||||
<tr>
|
||||
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">컬럼 1</th>
|
||||
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">컬럼 2</th>
|
||||
<th className="px-3 py-2 text-left text-xs font-medium text-gray-500 uppercase">컬럼 3</th>
|
||||
<th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase">컬럼 1</th>
|
||||
<th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase">컬럼 2</th>
|
||||
<th className="px-3 py-2 text-left text-xs font-medium text-muted-foreground uppercase">컬럼 3</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200 bg-white">
|
||||
<tr className="cursor-pointer hover:bg-gray-50">
|
||||
<tbody className="divide-y divide-border bg-white">
|
||||
<tr className="cursor-pointer hover:bg-muted">
|
||||
<td className="px-3 py-2 text-sm whitespace-nowrap">데이터 1-1</td>
|
||||
<td className="px-3 py-2 text-sm whitespace-nowrap">데이터 1-2</td>
|
||||
<td className="px-3 py-2 text-sm whitespace-nowrap">데이터 1-3</td>
|
||||
</tr>
|
||||
<tr className="cursor-pointer hover:bg-gray-50">
|
||||
<tr className="cursor-pointer hover:bg-muted">
|
||||
<td className="px-3 py-2 text-sm whitespace-nowrap">데이터 2-1</td>
|
||||
<td className="px-3 py-2 text-sm whitespace-nowrap">데이터 2-2</td>
|
||||
<td className="px-3 py-2 text-sm whitespace-nowrap">데이터 2-3</td>
|
||||
@@ -3371,16 +3371,16 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
<div className="overflow-auto">
|
||||
{groupedLeftData.map((group, groupIdx) => (
|
||||
<div key={groupIdx} className="mb-4">
|
||||
<div className="bg-gray-100 px-3 py-2 text-sm font-semibold">
|
||||
<div className="bg-muted px-3 py-2 text-sm font-semibold">
|
||||
{group.groupKey} ({group.count}개)
|
||||
</div>
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="bg-gray-50">
|
||||
<table className="min-w-full divide-y divide-border">
|
||||
<thead className="bg-muted">
|
||||
<tr>
|
||||
{columnsToShow.map((col, idx) => (
|
||||
<th
|
||||
key={idx}
|
||||
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-gray-500 uppercase whitespace-nowrap"
|
||||
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase whitespace-nowrap"
|
||||
style={{
|
||||
width: col.width ? `${col.width}px` : "auto",
|
||||
minWidth: "80px",
|
||||
@@ -3391,12 +3391,12 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
</th>
|
||||
))}
|
||||
{hasGroupedLeftActions && (
|
||||
<th className="px-3 py-2 text-right text-xs font-medium tracking-wider text-gray-500 uppercase whitespace-nowrap" style={{ width: "80px" }}>
|
||||
<th className="px-3 py-2 text-right text-xs font-medium tracking-wider text-muted-foreground uppercase whitespace-nowrap" style={{ width: "80px" }}>
|
||||
</th>
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200 bg-white">
|
||||
<tbody className="divide-y divide-border bg-white">
|
||||
{group.items.map((item, idx) => {
|
||||
const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
|
||||
const itemId = item[sourceColumn] || item.id || item.ID || idx;
|
||||
@@ -3415,7 +3415,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
{columnsToShow.map((col, colIdx) => (
|
||||
<td
|
||||
key={colIdx}
|
||||
className="px-3 py-2 text-sm whitespace-nowrap text-gray-900"
|
||||
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
|
||||
style={{ textAlign: col.align || "left" }}
|
||||
>
|
||||
{formatCellValue(
|
||||
@@ -3435,9 +3435,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
e.stopPropagation();
|
||||
handleEditClick("left", item);
|
||||
}}
|
||||
className="rounded p-1 transition-colors hover:bg-gray-200"
|
||||
className="rounded p-1 transition-colors hover:bg-muted/80"
|
||||
>
|
||||
<Pencil className="h-3.5 w-3.5 text-gray-500" />
|
||||
<Pencil className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
</button>
|
||||
)}
|
||||
{(componentConfig.leftPanel?.showDelete !== false) && (
|
||||
@@ -3446,9 +3446,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
e.stopPropagation();
|
||||
handleDeleteClick("left", item);
|
||||
}}
|
||||
className="rounded p-1 transition-colors hover:bg-red-100"
|
||||
className="rounded p-1 transition-colors hover:bg-destructive/10"
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5 text-red-500" />
|
||||
<Trash2 className="h-3.5 w-3.5 text-destructive" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -3472,13 +3472,13 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
);
|
||||
return (
|
||||
<div className="overflow-auto">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<thead className="sticky top-0 z-10 bg-gray-50">
|
||||
<table className="min-w-full divide-y divide-border">
|
||||
<thead className="sticky top-0 z-10 bg-muted">
|
||||
<tr>
|
||||
{columnsToShow.map((col, idx) => (
|
||||
<th
|
||||
key={idx}
|
||||
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-gray-500 uppercase whitespace-nowrap"
|
||||
className="px-3 py-2 text-left text-xs font-medium tracking-wider text-muted-foreground uppercase whitespace-nowrap"
|
||||
style={{
|
||||
width: col.width ? `${col.width}px` : "auto",
|
||||
minWidth: "80px",
|
||||
@@ -3489,12 +3489,12 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
</th>
|
||||
))}
|
||||
{hasLeftTableActions && (
|
||||
<th className="px-3 py-2 text-right text-xs font-medium tracking-wider text-gray-500 uppercase whitespace-nowrap" style={{ width: "80px" }}>
|
||||
<th className="px-3 py-2 text-right text-xs font-medium tracking-wider text-muted-foreground uppercase whitespace-nowrap" style={{ width: "80px" }}>
|
||||
</th>
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-gray-200 bg-white">
|
||||
<tbody className="divide-y divide-border bg-white">
|
||||
{filteredData.map((item, idx) => {
|
||||
const sourceColumn = componentConfig.leftPanel?.itemAddConfig?.sourceColumn || "id";
|
||||
const itemId = item[sourceColumn] || item.id || item.ID || idx;
|
||||
@@ -3513,7 +3513,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
{columnsToShow.map((col, colIdx) => (
|
||||
<td
|
||||
key={colIdx}
|
||||
className="px-3 py-2 text-sm whitespace-nowrap text-gray-900"
|
||||
className="px-3 py-2 text-sm whitespace-nowrap text-foreground"
|
||||
style={{ textAlign: col.align || "left" }}
|
||||
>
|
||||
{formatCellValue(
|
||||
@@ -3533,9 +3533,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
e.stopPropagation();
|
||||
handleEditClick("left", item);
|
||||
}}
|
||||
className="rounded p-1 transition-colors hover:bg-gray-200"
|
||||
className="rounded p-1 transition-colors hover:bg-muted/80"
|
||||
>
|
||||
<Pencil className="h-3.5 w-3.5 text-gray-500" />
|
||||
<Pencil className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
</button>
|
||||
)}
|
||||
{(componentConfig.leftPanel?.showDelete !== false) && (
|
||||
@@ -3544,9 +3544,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
e.stopPropagation();
|
||||
handleDeleteClick("left", item);
|
||||
}}
|
||||
className="rounded p-1 transition-colors hover:bg-red-100"
|
||||
className="rounded p-1 transition-colors hover:bg-destructive/10"
|
||||
>
|
||||
<Trash2 className="h-3.5 w-3.5 text-red-500" />
|
||||
<Trash2 className="h-3.5 w-3.5 text-destructive" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -3699,9 +3699,9 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
{hasChildren ? (
|
||||
<div className="flex-shrink-0">
|
||||
{isExpanded ? (
|
||||
<ChevronDown className="h-4 w-4 text-gray-500" />
|
||||
<ChevronDown className="h-4 w-4 text-muted-foreground" />
|
||||
) : (
|
||||
<ChevronRight className="h-4 w-4 text-gray-500" />
|
||||
<ChevronRight className="h-4 w-4 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
@@ -3726,10 +3726,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
e.stopPropagation();
|
||||
handleEditClick("left", item);
|
||||
}}
|
||||
className="rounded p-1 transition-colors hover:bg-gray-200"
|
||||
className="rounded p-1 transition-colors hover:bg-muted/80"
|
||||
title="수정"
|
||||
>
|
||||
<Pencil className="h-4 w-4 text-gray-600" />
|
||||
<Pencil className="h-4 w-4 text-muted-foreground" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -3740,10 +3740,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
e.stopPropagation();
|
||||
handleDeleteClick("left", item);
|
||||
}}
|
||||
className="rounded p-1 transition-colors hover:bg-red-100"
|
||||
className="rounded p-1 transition-colors hover:bg-destructive/10"
|
||||
title="삭제"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 text-red-600" />
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -3754,10 +3754,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
e.stopPropagation();
|
||||
handleItemAddClick(item);
|
||||
}}
|
||||
className="rounded p-1 transition-colors hover:bg-gray-200"
|
||||
className="rounded p-1 transition-colors hover:bg-muted/80"
|
||||
title="하위 항목 추가"
|
||||
>
|
||||
<Plus className="h-4 w-4 text-gray-600" />
|
||||
<Plus className="h-4 w-4 text-muted-foreground" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -4272,38 +4272,38 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-4 cursor-move items-center justify-between rounded-t border border-b-0 bg-gray-100 px-1",
|
||||
isSelectedComp ? "border-primary" : "border-gray-200"
|
||||
"flex h-4 cursor-move items-center justify-between rounded-t border border-b-0 bg-muted px-1",
|
||||
isSelectedComp ? "border-primary" : "border-border"
|
||||
)}
|
||||
style={{ width: displayWidth }}
|
||||
onMouseDown={(e) => handlePanelDragStart(e, "right", comp)}
|
||||
>
|
||||
<div className="flex items-center gap-0.5">
|
||||
<Move className="h-2.5 w-2.5 text-gray-400" />
|
||||
<span className="max-w-[100px] truncate text-[9px] text-gray-500">
|
||||
<Move className="h-2.5 w-2.5 text-muted-foreground/70" />
|
||||
<span className="max-w-[100px] truncate text-[9px] text-muted-foreground">
|
||||
{comp.label || comp.componentType}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
className="rounded p-0.5 hover:bg-gray-200"
|
||||
className="rounded p-0.5 hover:bg-muted/80"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onSelectPanelComponent?.("right", comp.id, comp);
|
||||
}}
|
||||
title="설정"
|
||||
>
|
||||
<Settings className="h-2.5 w-2.5 text-gray-500" />
|
||||
<Settings className="h-2.5 w-2.5 text-muted-foreground" />
|
||||
</button>
|
||||
<button
|
||||
className="rounded p-0.5 hover:bg-red-100"
|
||||
className="rounded p-0.5 hover:bg-destructive/10"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemovePanelComponent("right", comp.id);
|
||||
}}
|
||||
title="삭제"
|
||||
>
|
||||
<Trash2 className="h-2.5 w-2.5 text-red-500" />
|
||||
<Trash2 className="h-2.5 w-2.5 text-destructive" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -4313,7 +4313,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
"relative overflow-hidden rounded-b border bg-white shadow-sm",
|
||||
isSelectedComp
|
||||
? "border-primary ring-2 ring-primary/30"
|
||||
: "border-gray-200",
|
||||
: "border-border",
|
||||
(isDraggingComp || isResizingComp) && "opacity-80 shadow-lg",
|
||||
!(isDraggingComp || isResizingComp) && "transition-all"
|
||||
)}
|
||||
@@ -4380,12 +4380,12 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
)
|
||||
) : (
|
||||
// 컴포넌트가 없을 때 드롭 영역 표시
|
||||
<div className="flex h-full w-full flex-col items-center justify-center rounded border-2 border-dashed border-gray-300 bg-gray-50/50">
|
||||
<Plus className="mb-2 h-8 w-8 text-gray-400" />
|
||||
<p className="text-sm font-medium text-gray-500">
|
||||
<div className="flex h-full w-full flex-col items-center justify-center rounded border-2 border-dashed border-input bg-muted/50">
|
||||
<Plus className="mb-2 h-8 w-8 text-muted-foreground/70" />
|
||||
<p className="text-sm font-medium text-muted-foreground">
|
||||
커스텀 모드
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-gray-400">
|
||||
<p className="mt-1 text-xs text-muted-foreground/70">
|
||||
{isDesignMode ? "컴포넌트를 드래그하여 배치하세요" : "배치된 컴포넌트가 없습니다"}
|
||||
</p>
|
||||
</div>
|
||||
@@ -4550,10 +4550,10 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
e.stopPropagation();
|
||||
handleDeleteClick("right", item);
|
||||
}}
|
||||
className="rounded p-1 transition-colors hover:bg-red-100"
|
||||
className="rounded p-1 transition-colors hover:bg-destructive/10"
|
||||
title={componentConfig.rightPanel?.deleteButton?.buttonLabel || "삭제"}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 text-red-600" />
|
||||
<Trash2 className="h-4 w-4 text-destructive" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
@@ -4883,7 +4883,7 @@ export const SplitPanelLayoutComponent: React.FC<SplitPanelLayoutComponentProps>
|
||||
<div key={index}>
|
||||
<Label htmlFor={col.name} className="text-xs sm:text-sm">
|
||||
{col.label} {col.required && <span className="text-destructive">*</span>}
|
||||
{isPreFilled && <span className="ml-2 text-[10px] text-blue-600">(자동 설정됨)</span>}
|
||||
{isPreFilled && <span className="ml-2 text-[10px] text-primary">(자동 설정됨)</span>}
|
||||
</Label>
|
||||
<Input
|
||||
id={col.name}
|
||||
|
||||
Reference in New Issue
Block a user