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:
DDD1542
2026-03-09 14:31:59 +09:00
parent d967cf0a0d
commit 4f10b5e42d
447 changed files with 4520 additions and 4520 deletions

View File

@@ -532,13 +532,13 @@ function FormulaBuilder({
const getTokenBadgeClass = (token: FormulaToken): string => {
switch (token.type) {
case "aggregation":
return "bg-blue-100 text-blue-700 border-blue-200";
return "bg-primary/10 text-primary border-primary/20";
case "column":
return token.isExternal
? "bg-orange-100 text-orange-700 border-orange-200"
: "bg-green-100 text-green-700 border-green-200";
? "bg-amber-100 text-orange-700 border-orange-200"
: "bg-emerald-100 text-emerald-700 border-emerald-200";
case "operator":
return "bg-gray-100 text-gray-700 border-gray-200";
return "bg-muted text-foreground border-border";
case "number":
return "bg-purple-100 text-purple-700 border-purple-200";
default:
@@ -600,8 +600,8 @@ function FormulaBuilder({
{/* 집계 참조 추가 */}
{referenceableAggregations.length > 0 && (
<div className="space-y-2 p-2 bg-blue-50 dark:bg-blue-950 rounded border border-blue-200 dark:border-blue-800 overflow-hidden min-w-0">
<Label className="text-[9px] text-blue-700 dark:text-blue-300"> </Label>
<div className="space-y-2 p-2 bg-primary/10 dark:bg-primary/15 rounded border border-primary/20 dark:border-primary/30 overflow-hidden min-w-0">
<Label className="text-[9px] text-primary dark:text-primary/80"> </Label>
<div className="space-y-1">
<span className="text-[8px] text-muted-foreground"> </span>
<div className="flex gap-1">
@@ -633,8 +633,8 @@ function FormulaBuilder({
)}
{/* 테이블 컬럼 집계 추가 */}
<div className="space-y-2 p-2 bg-green-50 dark:bg-green-950 rounded border border-green-200 dark:border-green-800 overflow-hidden min-w-0">
<Label className="text-[9px] text-green-700 dark:text-green-300"> </Label>
<div className="space-y-2 p-2 bg-emerald-50 dark:bg-emerald-950 rounded border border-emerald-200 dark:border-emerald-800 overflow-hidden min-w-0">
<Label className="text-[9px] text-emerald-700 dark:text-emerald-300"> </Label>
{/* 테이블 선택 */}
<div className="space-y-1">
@@ -704,7 +704,7 @@ function FormulaBuilder({
</div>
{newTokenTable !== sourceTable && newTokenTable && (
<p className="text-[8px] text-orange-600"> 테이블: _EXT </p>
<p className="text-[8px] text-amber-600"> 테이블: _EXT </p>
)}
</div>
@@ -924,7 +924,7 @@ function AggregationConfigItemModal({
return (
<div className={cn(
"border rounded-lg p-4 space-y-4",
isFormula ? "bg-purple-50 dark:bg-purple-950 border-purple-200" : "bg-blue-50 dark:bg-blue-950 border-blue-200"
isFormula ? "bg-purple-50 dark:bg-purple-950 border-purple-200" : "bg-primary/10 dark:bg-primary/15 border-primary/20"
)}>
{/* 헤더 */}
<div className="flex items-center justify-between">
@@ -952,7 +952,7 @@ function AggregationConfigItemModal({
</div>
<Badge className={cn(
"text-xs px-2 py-0.5",
isFormula ? "bg-purple-100 text-purple-700" : "bg-blue-100 text-blue-700"
isFormula ? "bg-purple-100 text-purple-700" : "bg-primary/10 text-primary"
)}>
{isFormula ? "가상" : "집계"} {index + 1}
</Badge>
@@ -1092,8 +1092,8 @@ function AggregationConfigItemModal({
{/* 이전 집계 참조 */}
{referenceableAggregations.length > 0 && (
<div className="space-y-1.5 p-3 bg-blue-100 dark:bg-blue-900 rounded-lg">
<Label className="text-xs text-blue-700 dark:text-blue-300"> </Label>
<div className="space-y-1.5 p-3 bg-primary/10 dark:bg-primary/20 rounded-lg">
<Label className="text-xs text-primary dark:text-primary/80"> </Label>
<div className="flex flex-wrap gap-1">
{referenceableAggregations.map((refAgg) => (
<Button
@@ -1105,7 +1105,7 @@ function AggregationConfigItemModal({
setLocalFormula(newFormula);
onUpdate({ formula: newFormula });
}}
className="h-7 text-xs bg-blue-50 hover:bg-blue-100 border-blue-300"
className="h-7 text-xs bg-primary/10 hover:bg-primary/10 border-primary/40"
>
{refAgg.label || refAgg.resultField}
</Button>
@@ -1115,8 +1115,8 @@ function AggregationConfigItemModal({
)}
{/* 테이블 컬럼 집계 */}
<div className="space-y-2 p-3 bg-green-100 dark:bg-green-900 rounded-lg">
<Label className="text-xs text-green-700 dark:text-green-300"> </Label>
<div className="space-y-2 p-3 bg-emerald-100 dark:bg-emerald-900 rounded-lg">
<Label className="text-xs text-emerald-700 dark:text-emerald-300"> </Label>
<FormulaColumnAggregator
sourceTable={sourceTable}
allTables={allTables}
@@ -1313,7 +1313,7 @@ function ExternalTableRefSelector({
if (tableRowsWithExternalSource.length === 0) {
return (
<div className="p-3 bg-gray-100 dark:bg-gray-800 rounded-lg">
<div className="p-3 bg-muted dark:bg-foreground/90 rounded-lg">
<p className="text-xs text-muted-foreground">
.
</p>
@@ -1371,7 +1371,7 @@ function ExternalTableRefSelector({
"flex items-center gap-2 p-2 rounded border cursor-pointer transition-colors",
isSelected
? "bg-amber-100 border-amber-300"
: "bg-white border-gray-200 hover:bg-gray-50"
: "bg-white border-border hover:bg-muted"
)}
onClick={() => handleToggleTable(row.id)}
>
@@ -1379,7 +1379,7 @@ function ExternalTableRefSelector({
type="checkbox"
checked={isSelected}
onChange={() => {}} // onClick에서 처리
className="h-4 w-4 rounded border-gray-300 text-amber-600 focus:ring-amber-500"
className="h-4 w-4 rounded border-input text-amber-600 focus:ring-amber-500"
/>
<div className="flex-1 min-w-0">
<p className="text-xs font-medium truncate">{tableTitle}</p>
@@ -1473,7 +1473,7 @@ function SyncSaveConfigSection({
};
return (
<div className="space-y-2 p-2 bg-orange-50 dark:bg-orange-950 rounded-lg border border-orange-200">
<div className="space-y-2 p-2 bg-amber-50 dark:bg-orange-950 rounded-lg border border-orange-200">
<div className="flex items-center justify-between">
<Label className="text-[10px] font-semibold text-orange-700 dark:text-orange-300">
( )
@@ -1482,7 +1482,7 @@ function SyncSaveConfigSection({
size="sm"
variant="outline"
onClick={addSyncSave}
className="h-5 text-[9px] px-1 bg-orange-100 hover:bg-orange-200 border-orange-300"
className="h-5 text-[9px] px-1 bg-amber-100 hover:bg-orange-200 border-orange-300"
>
<Plus className="h-2 w-2 mr-0.5" />
@@ -1531,7 +1531,7 @@ function SyncSaveConfigItem({
return (
<div className={cn(
"p-2 rounded border space-y-2",
sync.enabled ? "bg-orange-100 border-orange-300" : "bg-gray-100 border-gray-300 opacity-60"
sync.enabled ? "bg-amber-100 border-orange-300" : "bg-muted border-input opacity-60"
)}>
{/* 헤더 */}
<div className="flex items-center justify-between">
@@ -1998,11 +1998,11 @@ function LayoutSettingsModal({
// 행 타입별 색상
const getRowTypeColor = (type: CardContentRowConfig["type"]) => {
switch (type) {
case "header": return "bg-blue-100 border-blue-300";
case "aggregation": return "bg-orange-100 border-orange-300";
case "table": return "bg-green-100 border-green-300";
case "header": return "bg-primary/10 border-primary/40";
case "aggregation": return "bg-amber-100 border-orange-300";
case "table": return "bg-emerald-100 border-green-300";
case "fields": return "bg-purple-100 border-purple-300";
default: return "bg-gray-100 border-gray-300";
default: return "bg-muted border-input";
}
};
@@ -2031,15 +2031,15 @@ function LayoutSettingsModal({
<div className="space-y-3 py-3 pr-3">
{/* 행 추가 버튼 */}
<div className="flex gap-2 sticky top-0 bg-background z-10 pb-2 border-b">
<Button size="sm" variant="outline" onClick={() => addRow("header")} className="h-8 text-xs flex-1 bg-blue-50 hover:bg-blue-100 border-blue-200">
<Button size="sm" variant="outline" onClick={() => addRow("header")} className="h-8 text-xs flex-1 bg-primary/10 hover:bg-primary/10 border-primary/20">
<Plus className="h-3 w-3 mr-1" />
</Button>
<Button size="sm" variant="outline" onClick={() => addRow("aggregation")} className="h-8 text-xs flex-1 bg-orange-50 hover:bg-orange-100 border-orange-200">
<Button size="sm" variant="outline" onClick={() => addRow("aggregation")} className="h-8 text-xs flex-1 bg-amber-50 hover:bg-amber-100 border-orange-200">
<Plus className="h-3 w-3 mr-1" />
</Button>
<Button size="sm" variant="outline" onClick={() => addRow("table")} className="h-8 text-xs flex-1 bg-green-50 hover:bg-green-100 border-green-200">
<Button size="sm" variant="outline" onClick={() => addRow("table")} className="h-8 text-xs flex-1 bg-emerald-50 hover:bg-emerald-100 border-emerald-200">
<Plus className="h-3 w-3 mr-1" />
</Button>
@@ -2273,7 +2273,7 @@ function LayoutRowConfigModal({
</Button>
</div>
{(row.columns || []).map((col, colIndex) => (
<div key={col.id} className="border rounded p-3 space-y-2 bg-gray-50">
<div key={col.id} className="border rounded p-3 space-y-2 bg-muted">
<div className="flex items-center justify-between">
<span className="text-xs font-medium"> {colIndex + 1}</span>
<Button size="sm" variant="ghost" onClick={() => onRemoveColumn(colIndex)} className="h-6 w-6 p-0">
@@ -2387,7 +2387,7 @@ function LayoutRowConfigModal({
</p>
)}
{(row.aggregationFields || []).map((field, fieldIndex) => (
<div key={fieldIndex} className="border rounded p-3 space-y-2 bg-gray-50">
<div key={fieldIndex} className="border rounded p-3 space-y-2 bg-muted">
<div className="flex items-center justify-between">
<div className="flex items-center gap-1">
<Button
@@ -2519,7 +2519,7 @@ function LayoutRowConfigModal({
</div>
{/* 외부 데이터 소스 설정 */}
<div className="border rounded p-3 bg-blue-50 space-y-3">
<div className="border rounded p-3 bg-primary/10 space-y-3">
<div className="flex items-center justify-between">
<Label className="text-xs font-semibold"> </Label>
<Switch
@@ -2543,7 +2543,7 @@ function LayoutRowConfigModal({
</div>
{/* 조인 조건 설정 */}
<div className="space-y-2 pt-2 border-t border-blue-200">
<div className="space-y-2 pt-2 border-t border-primary/20">
<div className="space-y-1">
<Label className="text-[10px] font-semibold"> </Label>
<p className="text-[9px] text-muted-foreground">
@@ -2610,8 +2610,8 @@ function LayoutRowConfigModal({
</div>
</div>
<div className="mt-1 p-1.5 bg-blue-50 rounded border border-blue-100">
<p className="text-[8px] text-blue-700 font-mono">
<div className="mt-1 p-1.5 bg-primary/10 rounded border border-primary/10">
<p className="text-[8px] text-primary font-mono">
{row.tableDataSource?.sourceTable}.{condition.sourceKey} = {dataSourceTable}.{condition.referenceKey}
</p>
<p className="text-[8px] text-muted-foreground mt-0.5">
@@ -2641,7 +2641,7 @@ function LayoutRowConfigModal({
</div>
{/* 필터 설정 */}
<div className="space-y-2 pt-2 border-t border-blue-200">
<div className="space-y-2 pt-2 border-t border-primary/20">
<div className="flex items-center justify-between">
<div className="space-y-1">
<Label className="text-[10px] font-semibold"> </Label>
@@ -2763,7 +2763,7 @@ function LayoutRowConfigModal({
</div>
{/* CRUD 설정 */}
<div className="space-y-2 p-3 bg-green-100/50 dark:bg-green-900/20 rounded border border-green-200 dark:border-green-800">
<div className="space-y-2 p-3 bg-emerald-100/50 dark:bg-emerald-900/20 rounded border border-emerald-200 dark:border-emerald-800">
<Label className="text-xs font-semibold">CRUD </Label>
<div className="flex flex-wrap gap-4">
<div className="flex items-center gap-2">
@@ -2804,7 +2804,7 @@ function LayoutRowConfigModal({
</div>
</div>
{row.tableCrud?.allowDelete && (
<div className="flex items-center gap-2 pl-2 pt-1 border-t border-green-200">
<div className="flex items-center gap-2 pl-2 pt-1 border-t border-emerald-200">
<Switch
checked={row.tableCrud?.deleteConfirm?.enabled !== false}
onCheckedChange={(checked) =>
@@ -2844,7 +2844,7 @@ function LayoutRowConfigModal({
</Button>
</div>
{(row.tableColumns || []).map((col, colIndex) => (
<div key={col.id} className="border rounded p-3 space-y-2 bg-gray-50">
<div key={col.id} className="border rounded p-3 space-y-2 bg-muted">
<div className="flex items-center justify-between">
<div className="flex items-center gap-1">
<Button
@@ -3181,7 +3181,7 @@ function AggregationSaveConfigSection({
</div>
{saveConfig.enabled && (
<div className="space-y-2 p-2 bg-blue-50/50 dark:bg-blue-900/20 rounded border border-blue-200 dark:border-blue-800">
<div className="space-y-2 p-2 bg-primary/10/50 dark:bg-primary/20/20 rounded border border-primary/20 dark:border-primary/30">
{/* 자동 저장 옵션 */}
<div className="flex items-center justify-between">
<div className="space-y-0.5">
@@ -3277,7 +3277,7 @@ function AggregationSaveConfigSection({
</Badge>
)}
</div>
<div className="font-mono text-blue-600 dark:text-blue-400 break-all">
<div className="font-mono text-primary dark:text-primary/80 break-all">
{saveConfig.targetTable}.{saveConfig.targetColumn}
</div>
{saveConfig.joinKey?.sourceField && saveConfig.joinKey?.targetField && (
@@ -4015,7 +4015,7 @@ export function RepeatScreenModalConfigPanel({ config, onChange }: RepeatScreenM
agg.hidden ? "opacity-50" : "",
agg.sourceType === "formula"
? "bg-purple-50 border border-purple-200"
: "bg-blue-50 border border-blue-200"
: "bg-primary/10 border border-primary/20"
)}
>
<span className="truncate flex-1">
@@ -4061,11 +4061,11 @@ export function RepeatScreenModalConfigPanel({ config, onChange }: RepeatScreenM
{(localConfig.contentRows || []).map((row, index) => {
const getRowTypeColor = (type: CardContentRowConfig["type"]) => {
switch (type) {
case "header": return "bg-blue-50 border-blue-200";
case "aggregation": return "bg-orange-50 border-orange-200";
case "table": return "bg-green-50 border-green-200";
case "header": return "bg-primary/10 border-primary/20";
case "aggregation": return "bg-amber-50 border-orange-200";
case "table": return "bg-emerald-50 border-emerald-200";
case "fields": return "bg-purple-50 border-purple-200";
default: return "bg-gray-50 border-gray-200";
default: return "bg-muted border-border";
}
};
const getRowTypeLabel = (type: CardContentRowConfig["type"]) => {
@@ -4211,9 +4211,9 @@ function ContentRowConfigSection({
// 행 타입별 색상
const typeColors = {
header: "bg-purple-50 dark:bg-purple-950 border-purple-200 dark:border-purple-800",
aggregation: "bg-orange-50 dark:bg-orange-950 border-orange-200 dark:border-orange-800",
table: "bg-blue-50 dark:bg-blue-950 border-blue-200 dark:border-blue-800",
fields: "bg-green-50 dark:bg-green-950 border-green-200 dark:border-green-800",
aggregation: "bg-amber-50 dark:bg-orange-950 border-orange-200 dark:border-orange-800",
table: "bg-primary/10 dark:bg-primary/15 border-primary/20 dark:border-primary/30",
fields: "bg-emerald-50 dark:bg-emerald-950 border-emerald-200 dark:border-emerald-800",
};
const typeLabels = {
@@ -4225,9 +4225,9 @@ function ContentRowConfigSection({
const typeBadgeColors = {
header: "bg-purple-100 text-purple-700",
aggregation: "bg-orange-100 text-orange-700",
table: "bg-blue-100 text-blue-700",
fields: "bg-green-100 text-green-700",
aggregation: "bg-amber-100 text-orange-700",
table: "bg-primary/10 text-primary",
fields: "bg-emerald-100 text-emerald-700",
};
return (
@@ -4407,7 +4407,7 @@ function ContentRowConfigSection({
</div>
{aggregations.length === 0 && (
<p className="text-[9px] text-orange-600 bg-orange-100 dark:bg-orange-900 p-2 rounded">
<p className="text-[9px] text-amber-600 bg-amber-100 dark:bg-orange-900 p-2 rounded">
</p>
)}
@@ -4551,7 +4551,7 @@ function ContentRowConfigSection({
</div>
{/* 외부 테이블 데이터 소스 설정 */}
<div className="space-y-2 p-2 bg-blue-100/50 dark:bg-blue-900/20 rounded border border-blue-200 dark:border-blue-800">
<div className="space-y-2 p-2 bg-primary/10/50 dark:bg-primary/20/20 rounded border border-primary/20 dark:border-primary/30">
<div className="flex items-center gap-2">
<Switch
checked={row.tableDataSource?.enabled || false}
@@ -4990,7 +4990,7 @@ function ContentRowConfigSection({
</div>
{/* CRUD 설정 */}
<div className="space-y-2 p-2 bg-green-100/50 dark:bg-green-900/20 rounded border border-green-200 dark:border-green-800">
<div className="space-y-2 p-2 bg-emerald-100/50 dark:bg-emerald-900/20 rounded border border-emerald-200 dark:border-emerald-800">
<Label className="text-[9px] font-semibold">CRUD </Label>
<div className="flex flex-wrap gap-3">
<div className="flex items-center gap-1">
@@ -5062,7 +5062,7 @@ function ContentRowConfigSection({
)}
{/* 테이블 컬럼 목록 */}
<div className="space-y-2 pl-2 border-l-2 border-blue-300">
<div className="space-y-2 pl-2 border-l-2 border-primary/40">
<div className="flex items-center justify-between">
<Label className="text-[9px] font-semibold"> ({(row.tableColumns || []).length})</Label>
<Button size="sm" variant="outline" onClick={onAddTableColumn} className="h-5 text-[9px] px-1">
@@ -5367,8 +5367,8 @@ function ColumnConfigSection({
{/* 데이터 소스 설정 */}
{col.type !== "aggregation" && (
<div className="space-y-1.5 p-1.5 bg-blue-50 dark:bg-blue-950 rounded border border-blue-200 dark:border-blue-800">
<Label className="text-[9px] font-semibold text-blue-600"></Label>
<div className="space-y-1.5 p-1.5 bg-primary/10 dark:bg-primary/15 rounded border border-primary/20 dark:border-primary/30">
<Label className="text-[9px] font-semibold text-primary"></Label>
<Select
value={col.sourceConfig?.type || "manual"}
onValueChange={(value) =>
@@ -5451,8 +5451,8 @@ function ColumnConfigSection({
)}
{/* 데이터 타겟 설정 */}
<div className="space-y-1.5 p-1.5 bg-green-50 dark:bg-green-950 rounded border border-green-200 dark:border-green-800">
<Label className="text-[9px] font-semibold text-green-600"></Label>
<div className="space-y-1.5 p-1.5 bg-emerald-50 dark:bg-emerald-950 rounded border border-emerald-200 dark:border-emerald-800">
<Label className="text-[9px] font-semibold text-emerald-600"></Label>
<Select
value={col.targetConfig?.targetTable || ""}
@@ -5696,8 +5696,8 @@ function TableColumnConfigSection({
{/* 편집 가능할 때 저장 설정 */}
{col.editable && (
<div className="space-y-1.5 p-1.5 bg-green-50 dark:bg-green-950 rounded border border-green-200 dark:border-green-800">
<Label className="text-[9px] font-semibold text-green-600"></Label>
<div className="space-y-1.5 p-1.5 bg-emerald-50 dark:bg-emerald-950 rounded border border-emerald-200 dark:border-emerald-800">
<Label className="text-[9px] font-semibold text-emerald-600"></Label>
<Select
value={col.targetConfig?.targetTable || ""}