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:
@@ -293,7 +293,7 @@ const ActionConditionBuilder: React.FC<ActionConditionBuilderProps> = ({
|
||||
.map((column) => (
|
||||
<SelectItem key={`to_${column.columnName}`} value={`to.${column.columnName}`}>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-green-600">📥</span>
|
||||
<span className="text-emerald-600">📥</span>
|
||||
<span>{column.displayName || column.columnName}</span>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{column.webType || column.dataType}
|
||||
@@ -419,7 +419,7 @@ const ActionConditionBuilder: React.FC<ActionConditionBuilderProps> = ({
|
||||
|
||||
{/* 선택된 숫자 타입에 대한 설명 */}
|
||||
{mapping.value?.startsWith("#") && mapping.value !== "#custom" && (
|
||||
<div className="text-muted-foreground rounded bg-green-50 p-2 text-xs">
|
||||
<div className="text-muted-foreground rounded bg-emerald-50 p-2 text-xs">
|
||||
{mapping.value === "#AUTO_INCREMENT" && "🔢 데이터베이스에서 자동으로 증가하는 값이 할당됩니다"}
|
||||
{mapping.value === "#RANDOM_INT" && "🎲 1부터 1000 사이의 랜덤한 정수가 생성됩니다"}
|
||||
{mapping.value === "#ZERO" && "0️⃣ 0 값이 저장됩니다"}
|
||||
@@ -514,7 +514,7 @@ const ActionConditionBuilder: React.FC<ActionConditionBuilderProps> = ({
|
||||
.map((column) => (
|
||||
<SelectItem key={`to_${column.columnName}`} value={`to.${column.columnName}`}>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-green-600">📥</span>
|
||||
<span className="text-emerald-600">📥</span>
|
||||
<span>{column.displayName || column.columnName}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
@@ -642,7 +642,7 @@ const ActionConditionBuilder: React.FC<ActionConditionBuilderProps> = ({
|
||||
.map((column) => (
|
||||
<SelectItem key={`to_${column.columnName}`} value={`to.${column.columnName}`}>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-green-600">📥</span>
|
||||
<span className="text-emerald-600">📥</span>
|
||||
<span>{column.displayName || column.columnName}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
@@ -698,9 +698,9 @@ const ActionConditionBuilder: React.FC<ActionConditionBuilderProps> = ({
|
||||
<CardContent className="space-y-3">
|
||||
{/* 매핑되지 않은 필드가 없는 경우 */}
|
||||
{getUnmappedToColumns().length === 0 ? (
|
||||
<div className="rounded-lg border bg-green-50 p-4 text-center">
|
||||
<div className="mb-2 text-green-600">✅ 모든 필드가 매핑되었습니다</div>
|
||||
<p className="text-sm text-green-700">
|
||||
<div className="rounded-lg border bg-emerald-50 p-4 text-center">
|
||||
<div className="mb-2 text-emerald-600">✅ 모든 필드가 매핑되었습니다</div>
|
||||
<p className="text-sm text-emerald-700">
|
||||
컬럼 매핑으로 모든 TO 테이블 필드가 처리되고 있어 별도의 기본값 설정이 필요하지 않습니다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -77,7 +77,7 @@ export const ConnectionStep: React.FC<ConnectionStepProps> = ({
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-2">
|
||||
<h2 className="text-2xl font-bold text-foreground mb-2">
|
||||
연결 선택
|
||||
</h2>
|
||||
<p className="text-muted-foreground">
|
||||
@@ -92,8 +92,8 @@ export const ConnectionStep: React.FC<ConnectionStepProps> = ({
|
||||
<div className="w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center">
|
||||
<span className="text-primary font-bold">1</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-gray-900">FROM 연결</h3>
|
||||
<span className="text-sm text-gray-500">(데이터 소스)</span>
|
||||
<h3 className="text-lg font-semibold text-foreground">FROM 연결</h3>
|
||||
<span className="text-sm text-muted-foreground">(데이터 소스)</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
@@ -103,16 +103,16 @@ export const ConnectionStep: React.FC<ConnectionStepProps> = ({
|
||||
className={`p-4 rounded-lg border-2 cursor-pointer transition-all duration-200 ${
|
||||
selectedFrom === connection.id
|
||||
? "border-primary bg-accent shadow-md"
|
||||
: "border-gray-200 bg-white hover:border-blue-300 hover:bg-blue-25"
|
||||
: "border-border bg-white hover:border-primary/40 hover:bg-blue-25"
|
||||
}`}
|
||||
onClick={() => handleFromSelect(connection.id)}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<Database className="w-6 h-6 text-primary" />
|
||||
<div className="flex-1">
|
||||
<h4 className="font-medium text-gray-900">{connection.name}</h4>
|
||||
<h4 className="font-medium text-foreground">{connection.name}</h4>
|
||||
<p className="text-sm text-muted-foreground">{connection.type}</p>
|
||||
<p className="text-xs text-gray-500">{connection.host}:{connection.port}</p>
|
||||
<p className="text-xs text-muted-foreground">{connection.host}:{connection.port}</p>
|
||||
</div>
|
||||
{selectedFrom === connection.id && (
|
||||
<CheckCircle className="w-5 h-5 text-primary" />
|
||||
@@ -125,19 +125,19 @@ export const ConnectionStep: React.FC<ConnectionStepProps> = ({
|
||||
|
||||
{/* 화살표 */}
|
||||
<div className="hidden lg:flex items-center justify-center">
|
||||
<div className="w-12 h-12 bg-orange-100 rounded-full flex items-center justify-center">
|
||||
<ArrowRight className="w-6 h-6 text-orange-600" />
|
||||
<div className="w-12 h-12 bg-amber-100 rounded-full flex items-center justify-center">
|
||||
<ArrowRight className="w-6 h-6 text-amber-600" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* TO 연결 */}
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
|
||||
<span className="text-green-600 font-bold">2</span>
|
||||
<div className="w-8 h-8 bg-emerald-100 rounded-full flex items-center justify-center">
|
||||
<span className="text-emerald-600 font-bold">2</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-gray-900">TO 연결</h3>
|
||||
<span className="text-sm text-gray-500">(데이터 대상)</span>
|
||||
<h3 className="text-lg font-semibold text-foreground">TO 연결</h3>
|
||||
<span className="text-sm text-muted-foreground">(데이터 대상)</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
@@ -146,20 +146,20 @@ export const ConnectionStep: React.FC<ConnectionStepProps> = ({
|
||||
key={connection.id}
|
||||
className={`p-4 rounded-lg border-2 cursor-pointer transition-all duration-200 ${
|
||||
selectedTo === connection.id
|
||||
? "border-green-500 bg-green-50 shadow-md"
|
||||
: "border-gray-200 bg-white hover:border-green-300 hover:bg-green-25"
|
||||
? "border-emerald-500 bg-emerald-50 shadow-md"
|
||||
: "border-border bg-white hover:border-green-300 hover:bg-green-25"
|
||||
}`}
|
||||
onClick={() => handleToSelect(connection.id)}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<Database className="w-6 h-6 text-green-600" />
|
||||
<Database className="w-6 h-6 text-emerald-600" />
|
||||
<div className="flex-1">
|
||||
<h4 className="font-medium text-gray-900">{connection.name}</h4>
|
||||
<h4 className="font-medium text-foreground">{connection.name}</h4>
|
||||
<p className="text-sm text-muted-foreground">{connection.type}</p>
|
||||
<p className="text-xs text-gray-500">{connection.host}:{connection.port}</p>
|
||||
<p className="text-xs text-muted-foreground">{connection.host}:{connection.port}</p>
|
||||
</div>
|
||||
{selectedTo === connection.id && (
|
||||
<CheckCircle className="w-5 h-5 text-green-600" />
|
||||
<CheckCircle className="w-5 h-5 text-emerald-600" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -175,8 +175,8 @@ export const ConnectionStep: React.FC<ConnectionStepProps> = ({
|
||||
disabled={!canProceed}
|
||||
className={`px-6 py-3 rounded-lg font-medium transition-all duration-200 ${
|
||||
canProceed
|
||||
? "bg-orange-500 text-white hover:bg-orange-600 shadow-md hover:shadow-lg"
|
||||
: "bg-gray-300 text-gray-500 cursor-not-allowed"
|
||||
? "bg-amber-500 text-white hover:bg-orange-600 shadow-md hover:shadow-lg"
|
||||
: "bg-muted/60 text-muted-foreground cursor-not-allowed"
|
||||
}`}
|
||||
>
|
||||
다음 단계: 테이블 선택
|
||||
|
||||
@@ -68,7 +68,7 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-2">
|
||||
<h2 className="text-2xl font-bold text-foreground mb-2">
|
||||
필드 매핑
|
||||
</h2>
|
||||
<p className="text-muted-foreground">
|
||||
@@ -79,22 +79,22 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
{/* 매핑 통계 */}
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="bg-accent p-4 rounded-lg border border-primary/20">
|
||||
<div className="text-2xl font-bold text-blue-900">{fieldMappings.length}</div>
|
||||
<div className="text-sm text-blue-700">총 매핑</div>
|
||||
<div className="text-2xl font-bold text-primary">{fieldMappings.length}</div>
|
||||
<div className="text-sm text-primary">총 매핑</div>
|
||||
</div>
|
||||
<div className="bg-green-50 p-4 rounded-lg border border-green-200">
|
||||
<div className="bg-emerald-50 p-4 rounded-lg border border-emerald-200">
|
||||
<div className="text-2xl font-bold text-green-900">
|
||||
{fieldMappings.filter(m => m.isValid).length}
|
||||
</div>
|
||||
<div className="text-sm text-green-700">유효한 매핑</div>
|
||||
<div className="text-sm text-emerald-700">유효한 매핑</div>
|
||||
</div>
|
||||
<div className="bg-destructive/10 p-4 rounded-lg border border-destructive/20">
|
||||
<div className="text-2xl font-bold text-red-900">
|
||||
{fieldMappings.filter(m => !m.isValid).length}
|
||||
</div>
|
||||
<div className="text-sm text-red-700">오류 매핑</div>
|
||||
<div className="text-sm text-destructive">오류 매핑</div>
|
||||
</div>
|
||||
<div className="bg-yellow-50 p-4 rounded-lg border border-yellow-200">
|
||||
<div className="bg-amber-50 p-4 rounded-lg border border-amber-200">
|
||||
<div className="text-2xl font-bold text-yellow-900">
|
||||
{(toTable?.columns.length || 0) - fieldMappings.length}
|
||||
</div>
|
||||
@@ -106,7 +106,7 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{/* FROM 테이블 필드들 */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
|
||||
<h3 className="text-lg font-semibold text-foreground flex items-center gap-2">
|
||||
<div className="w-6 h-6 bg-primary/20 rounded-full flex items-center justify-center">
|
||||
<span className="text-primary font-bold text-sm">FROM</span>
|
||||
</div>
|
||||
@@ -121,22 +121,22 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
onDragStart={() => handleDragStart(field)}
|
||||
className={`p-3 rounded-lg border-2 cursor-move transition-all duration-200 ${
|
||||
isFieldMapped(field.name)
|
||||
? "border-green-300 bg-green-50 opacity-60"
|
||||
: "border-primary/20 bg-accent hover:border-blue-400 hover:bg-primary/20"
|
||||
? "border-green-300 bg-emerald-50 opacity-60"
|
||||
: "border-primary/20 bg-accent hover:border-primary/60 hover:bg-primary/20"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">{field.name}</div>
|
||||
<div className="font-medium text-foreground">{field.name}</div>
|
||||
<div className="text-sm text-muted-foreground">{field.type}</div>
|
||||
{field.primaryKey && (
|
||||
<span className="text-xs bg-yellow-100 text-yellow-800 px-2 py-1 rounded">
|
||||
<span className="text-xs bg-amber-100 text-yellow-800 px-2 py-1 rounded">
|
||||
PK
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{isFieldMapped(field.name) && (
|
||||
<CheckCircle className="w-5 h-5 text-green-600" />
|
||||
<CheckCircle className="w-5 h-5 text-emerald-600" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -146,9 +146,9 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
|
||||
{/* TO 테이블 필드들 */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-lg font-semibold text-gray-900 flex items-center gap-2">
|
||||
<div className="w-6 h-6 bg-green-100 rounded-full flex items-center justify-center">
|
||||
<span className="text-green-600 font-bold text-sm">TO</span>
|
||||
<h3 className="text-lg font-semibold text-foreground flex items-center gap-2">
|
||||
<div className="w-6 h-6 bg-emerald-100 rounded-full flex items-center justify-center">
|
||||
<span className="text-emerald-600 font-bold text-sm">TO</span>
|
||||
</div>
|
||||
{toTable?.name} 필드들
|
||||
</h3>
|
||||
@@ -163,21 +163,21 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
onDrop={(e) => handleDrop(e, field)}
|
||||
className={`p-3 rounded-lg border-2 transition-all duration-200 ${
|
||||
mappedFromField
|
||||
? "border-green-300 bg-green-50"
|
||||
: "border-gray-200 bg-gray-50 hover:border-green-300 hover:bg-green-25"
|
||||
? "border-green-300 bg-emerald-50"
|
||||
: "border-border bg-muted hover:border-green-300 hover:bg-green-25"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">{field.name}</div>
|
||||
<div className="font-medium text-foreground">{field.name}</div>
|
||||
<div className="text-sm text-muted-foreground">{field.type}</div>
|
||||
{field.primaryKey && (
|
||||
<span className="text-xs bg-yellow-100 text-yellow-800 px-2 py-1 rounded">
|
||||
<span className="text-xs bg-amber-100 text-yellow-800 px-2 py-1 rounded">
|
||||
PK
|
||||
</span>
|
||||
)}
|
||||
{mappedFromField && (
|
||||
<div className="text-xs text-green-700 mt-1">
|
||||
<div className="text-xs text-emerald-700 mt-1">
|
||||
← {mappedFromField.name} ({mappedFromField.type})
|
||||
</div>
|
||||
)}
|
||||
@@ -186,7 +186,7 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
{mappedFromField && (
|
||||
<button
|
||||
onClick={() => removeMapping(`${mappedFromField.name}-${field.name}`)}
|
||||
className="text-red-500 hover:text-red-700"
|
||||
className="text-destructive hover:text-destructive"
|
||||
>
|
||||
<XCircle className="w-4 h-4" />
|
||||
</button>
|
||||
@@ -194,7 +194,7 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
{mappedFromField && (
|
||||
<div>
|
||||
{fieldMappings.find(m => m.toField.name === field.name)?.isValid ? (
|
||||
<CheckCircle className="w-5 h-5 text-green-600" />
|
||||
<CheckCircle className="w-5 h-5 text-emerald-600" />
|
||||
) : (
|
||||
<AlertCircle className="w-5 h-5 text-destructive" />
|
||||
)}
|
||||
@@ -213,7 +213,7 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
<div className="flex justify-between">
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="flex items-center gap-2 px-6 py-3 rounded-lg font-medium text-muted-foreground bg-gray-100 hover:bg-gray-200 transition-all duration-200"
|
||||
className="flex items-center gap-2 px-6 py-3 rounded-lg font-medium text-muted-foreground bg-muted hover:bg-muted/80 transition-all duration-200"
|
||||
>
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
이전 단계
|
||||
@@ -221,7 +221,7 @@ export const FieldMappingStep: React.FC<FieldMappingStepProps> = ({
|
||||
|
||||
<button
|
||||
onClick={onSave}
|
||||
className="flex items-center gap-2 px-6 py-3 rounded-lg font-medium bg-orange-500 text-white hover:bg-orange-600 shadow-md hover:shadow-lg transition-all duration-200"
|
||||
className="flex items-center gap-2 px-6 py-3 rounded-lg font-medium bg-amber-500 text-white hover:bg-orange-600 shadow-md hover:shadow-lg transition-all duration-200"
|
||||
>
|
||||
<Save className="w-4 h-4" />
|
||||
연결 설정 저장
|
||||
|
||||
@@ -89,7 +89,7 @@ const RightPanel: React.FC<RightPanelProps> = ({ state, actions }) => {
|
||||
value={state.relationshipName || ""}
|
||||
onChange={(e) => actions.setRelationshipName(e.target.value)}
|
||||
placeholder="외부호출 관계의 이름을 입력하세요"
|
||||
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-primary focus:ring-1 focus:ring-blue-500 focus:outline-none"
|
||||
className="mt-1 w-full rounded-md border border-input px-3 py-2 text-sm focus:border-primary focus:ring-1 focus:ring-ring focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
@@ -99,7 +99,7 @@ const RightPanel: React.FC<RightPanelProps> = ({ state, actions }) => {
|
||||
onChange={(e) => actions.setDescription(e.target.value)}
|
||||
placeholder="외부호출의 용도나 설명을 입력하세요"
|
||||
rows={2}
|
||||
className="mt-1 w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:border-primary focus:ring-1 focus:ring-blue-500 focus:outline-none"
|
||||
className="mt-1 w-full rounded-md border border-input px-3 py-2 text-sm focus:border-primary focus:ring-1 focus:ring-ring focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -135,7 +135,7 @@ const RightPanel: React.FC<RightPanelProps> = ({ state, actions }) => {
|
||||
<div className="flex gap-3">
|
||||
<Button
|
||||
onClick={actions.saveMappings}
|
||||
className="w-full bg-blue-600 hover:bg-blue-700"
|
||||
className="w-full bg-primary hover:bg-primary/90"
|
||||
disabled={state.isLoading}
|
||||
>
|
||||
{state.isLoading ? "저장 중..." : "저장"}
|
||||
|
||||
@@ -19,7 +19,7 @@ export const StepProgress: React.FC<StepProgressProps> = ({
|
||||
onStepChange,
|
||||
}) => {
|
||||
return (
|
||||
<div className="bg-white border-b border-gray-200 px-6 py-4">
|
||||
<div className="bg-white border-b border-border px-6 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
{steps.map((step, index) => (
|
||||
<React.Fragment key={step.id}>
|
||||
@@ -32,10 +32,10 @@ export const StepProgress: React.FC<StepProgressProps> = ({
|
||||
<div
|
||||
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-medium transition-all duration-200 ${
|
||||
step.id < currentStep
|
||||
? "bg-green-500 text-white"
|
||||
? "bg-emerald-500 text-white"
|
||||
: step.id === currentStep
|
||||
? "bg-orange-500 text-white"
|
||||
: "bg-gray-200 text-muted-foreground"
|
||||
? "bg-amber-500 text-white"
|
||||
: "bg-muted/80 text-muted-foreground"
|
||||
}`}
|
||||
>
|
||||
{step.id < currentStep ? (
|
||||
@@ -47,12 +47,12 @@ export const StepProgress: React.FC<StepProgressProps> = ({
|
||||
|
||||
<div>
|
||||
<h3 className={`text-sm font-medium ${
|
||||
step.id <= currentStep ? "text-gray-900" : "text-gray-500"
|
||||
step.id <= currentStep ? "text-foreground" : "text-muted-foreground"
|
||||
}`}>
|
||||
{step.title}
|
||||
</h3>
|
||||
<p className={`text-xs ${
|
||||
step.id <= currentStep ? "text-muted-foreground" : "text-gray-400"
|
||||
step.id <= currentStep ? "text-muted-foreground" : "text-muted-foreground/70"
|
||||
}`}>
|
||||
{step.description}
|
||||
</p>
|
||||
@@ -60,7 +60,7 @@ export const StepProgress: React.FC<StepProgressProps> = ({
|
||||
</div>
|
||||
|
||||
{index < steps.length - 1 && (
|
||||
<ArrowRight className="w-4 h-4 text-gray-400 mx-4" />
|
||||
<ArrowRight className="w-4 h-4 text-muted-foreground/70 mx-4" />
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
|
||||
@@ -87,7 +87,7 @@ export const TableStep: React.FC<TableStepProps> = ({
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-2">
|
||||
<h2 className="text-2xl font-bold text-foreground mb-2">
|
||||
테이블 선택
|
||||
</h2>
|
||||
<p className="text-muted-foreground">
|
||||
@@ -96,14 +96,14 @@ export const TableStep: React.FC<TableStepProps> = ({
|
||||
</div>
|
||||
|
||||
{/* 연결 정보 표시 */}
|
||||
<div className="bg-gray-50 rounded-lg p-4">
|
||||
<div className="bg-muted rounded-lg p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Database className="w-5 h-5 text-primary" />
|
||||
<span className="font-medium text-gray-900">{fromConnection?.name}</span>
|
||||
<span className="text-sm text-gray-500">→</span>
|
||||
<Database className="w-5 h-5 text-green-600" />
|
||||
<span className="font-medium text-gray-900">{toConnection?.name}</span>
|
||||
<span className="font-medium text-foreground">{fromConnection?.name}</span>
|
||||
<span className="text-sm text-muted-foreground">→</span>
|
||||
<Database className="w-5 h-5 text-emerald-600" />
|
||||
<span className="font-medium text-foreground">{toConnection?.name}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -115,8 +115,8 @@ export const TableStep: React.FC<TableStepProps> = ({
|
||||
<div className="w-8 h-8 bg-primary/20 rounded-full flex items-center justify-center">
|
||||
<span className="text-primary font-bold">1</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-gray-900">소스 테이블</h3>
|
||||
<span className="text-sm text-gray-500">(FROM)</span>
|
||||
<h3 className="text-lg font-semibold text-foreground">소스 테이블</h3>
|
||||
<span className="text-sm text-muted-foreground">(FROM)</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
@@ -126,16 +126,16 @@ export const TableStep: React.FC<TableStepProps> = ({
|
||||
className={`p-4 rounded-lg border-2 cursor-pointer transition-all duration-200 ${
|
||||
selectedFromTable === table.name
|
||||
? "border-primary bg-accent shadow-md"
|
||||
: "border-gray-200 bg-white hover:border-blue-300 hover:bg-blue-25"
|
||||
: "border-border bg-white hover:border-primary/40 hover:bg-blue-25"
|
||||
}`}
|
||||
onClick={() => handleFromTableSelect(table.name)}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<Table className="w-6 h-6 text-primary" />
|
||||
<div className="flex-1">
|
||||
<h4 className="font-medium text-gray-900">{table.name}</h4>
|
||||
<h4 className="font-medium text-foreground">{table.name}</h4>
|
||||
<p className="text-sm text-muted-foreground">{table.columns.length}개 컬럼</p>
|
||||
<p className="text-xs text-gray-500">{table.rowCount?.toLocaleString()}개 행</p>
|
||||
<p className="text-xs text-muted-foreground">{table.rowCount?.toLocaleString()}개 행</p>
|
||||
</div>
|
||||
{selectedFromTable === table.name && (
|
||||
<CheckCircle className="w-5 h-5 text-primary" />
|
||||
@@ -149,11 +149,11 @@ export const TableStep: React.FC<TableStepProps> = ({
|
||||
{/* TO 테이블 */}
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8 bg-green-100 rounded-full flex items-center justify-center">
|
||||
<span className="text-green-600 font-bold">2</span>
|
||||
<div className="w-8 h-8 bg-emerald-100 rounded-full flex items-center justify-center">
|
||||
<span className="text-emerald-600 font-bold">2</span>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-gray-900">대상 테이블</h3>
|
||||
<span className="text-sm text-gray-500">(TO)</span>
|
||||
<h3 className="text-lg font-semibold text-foreground">대상 테이블</h3>
|
||||
<span className="text-sm text-muted-foreground">(TO)</span>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
@@ -162,20 +162,20 @@ export const TableStep: React.FC<TableStepProps> = ({
|
||||
key={table.name}
|
||||
className={`p-4 rounded-lg border-2 cursor-pointer transition-all duration-200 ${
|
||||
selectedToTable === table.name
|
||||
? "border-green-500 bg-green-50 shadow-md"
|
||||
: "border-gray-200 bg-white hover:border-green-300 hover:bg-green-25"
|
||||
? "border-emerald-500 bg-emerald-50 shadow-md"
|
||||
: "border-border bg-white hover:border-green-300 hover:bg-green-25"
|
||||
}`}
|
||||
onClick={() => handleToTableSelect(table.name)}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<Table className="w-6 h-6 text-green-600" />
|
||||
<Table className="w-6 h-6 text-emerald-600" />
|
||||
<div className="flex-1">
|
||||
<h4 className="font-medium text-gray-900">{table.name}</h4>
|
||||
<h4 className="font-medium text-foreground">{table.name}</h4>
|
||||
<p className="text-sm text-muted-foreground">{table.columns.length}개 컬럼</p>
|
||||
<p className="text-xs text-gray-500">{table.rowCount?.toLocaleString()}개 행</p>
|
||||
<p className="text-xs text-muted-foreground">{table.rowCount?.toLocaleString()}개 행</p>
|
||||
</div>
|
||||
{selectedToTable === table.name && (
|
||||
<CheckCircle className="w-5 h-5 text-green-600" />
|
||||
<CheckCircle className="w-5 h-5 text-emerald-600" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -188,7 +188,7 @@ export const TableStep: React.FC<TableStepProps> = ({
|
||||
<div className="flex justify-between">
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="flex items-center gap-2 px-6 py-3 rounded-lg font-medium text-muted-foreground bg-gray-100 hover:bg-gray-200 transition-all duration-200"
|
||||
className="flex items-center gap-2 px-6 py-3 rounded-lg font-medium text-muted-foreground bg-muted hover:bg-muted/80 transition-all duration-200"
|
||||
>
|
||||
<ArrowLeft className="w-4 h-4" />
|
||||
이전 단계
|
||||
@@ -199,8 +199,8 @@ export const TableStep: React.FC<TableStepProps> = ({
|
||||
disabled={!canProceed}
|
||||
className={`flex items-center gap-2 px-6 py-3 rounded-lg font-medium transition-all duration-200 ${
|
||||
canProceed
|
||||
? "bg-orange-500 text-white hover:bg-orange-600 shadow-md hover:shadow-lg"
|
||||
: "bg-gray-300 text-gray-500 cursor-not-allowed"
|
||||
? "bg-amber-500 text-white hover:bg-orange-600 shadow-md hover:shadow-lg"
|
||||
: "bg-muted/60 text-muted-foreground cursor-not-allowed"
|
||||
}`}
|
||||
>
|
||||
다음 단계: 필드 매핑
|
||||
|
||||
@@ -126,11 +126,11 @@ const FieldColumn: React.FC<FieldColumnProps> = ({
|
||||
: isSelected
|
||||
? "border-primary bg-primary/10 shadow-md"
|
||||
: isMapped
|
||||
? "border-green-500 bg-green-50 shadow-sm"
|
||||
? "border-emerald-500 bg-emerald-50 shadow-sm"
|
||||
: isBlockedDropTarget
|
||||
? "border-red-400 bg-destructive/10 shadow-md"
|
||||
? "border-destructive/60 bg-destructive/10 shadow-md"
|
||||
: isDropTarget
|
||||
? "border-blue-400 bg-accent shadow-md"
|
||||
? "border-primary/60 bg-accent shadow-md"
|
||||
: "border-border hover:bg-muted/50 hover:shadow-sm"
|
||||
} `}
|
||||
draggable={type === "from" && !isMapped}
|
||||
@@ -146,8 +146,8 @@ const FieldColumn: React.FC<FieldColumnProps> = ({
|
||||
isSelected
|
||||
? "bg-primary border-primary"
|
||||
: isMapped
|
||||
? "border-green-500 bg-green-500"
|
||||
: "border-gray-300 bg-white"
|
||||
? "border-emerald-500 bg-emerald-500"
|
||||
: "border-input bg-white"
|
||||
} `}
|
||||
style={{
|
||||
[type === "from" ? "right" : "left"]: "-6px",
|
||||
@@ -156,9 +156,9 @@ const FieldColumn: React.FC<FieldColumnProps> = ({
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
{type === "from" && !isMapped && <GripVertical className="h-3 w-3 flex-shrink-0 text-gray-400" />}
|
||||
{type === "from" && !isMapped && <GripVertical className="h-3 w-3 flex-shrink-0 text-muted-foreground/70" />}
|
||||
<span className="truncate text-sm font-medium">{displayName}</span>
|
||||
{isMapped && <Link className="h-3 w-3 flex-shrink-0 text-green-600" />}
|
||||
{isMapped && <Link className="h-3 w-3 flex-shrink-0 text-emerald-600" />}
|
||||
</div>
|
||||
<Badge variant="outline" className="flex-shrink-0 text-xs">
|
||||
{field.webType || field.dataType || "unknown"}
|
||||
|
||||
@@ -91,9 +91,9 @@ const MappingControls: React.FC<MappingControlsProps> = ({
|
||||
</Badge>
|
||||
{/* 타입 호환성 아이콘 */}
|
||||
{selectedFromField.webType === selectedToField.webType ? (
|
||||
<span className="text-xs text-green-600">✅</span>
|
||||
<span className="text-xs text-emerald-600">✅</span>
|
||||
) : (
|
||||
<span className="text-xs text-orange-600">⚠️</span>
|
||||
<span className="text-xs text-amber-600">⚠️</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user