From 58e958829c6571531fbec95363117a1aaf838fa0 Mon Sep 17 00:00:00 2001 From: DDD1542 Date: Tue, 10 Mar 2026 21:16:01 +0900 Subject: [PATCH] feat: update color handling for dark mode compatibility - Updated various components to utilize `getAdaptiveLabelColor` for dynamic label color adjustments based on the current theme. - Enhanced dark mode styles in `globals.css` for better visual consistency across components. Made-with: Cursor --- frontend/app/globals.css | 21 ++++++++++--------- .../screen/InteractiveScreenViewerDynamic.tsx | 6 ++++-- frontend/components/v2/V2Biz.tsx | 4 +++- frontend/components/v2/V2Date.tsx | 6 ++++-- frontend/components/v2/V2Hierarchy.tsx | 4 +++- frontend/components/v2/V2Input.tsx | 6 ++++-- frontend/components/v2/V2Media.tsx | 4 +++- frontend/components/v2/V2Select.tsx | 6 ++++-- .../lib/registry/DynamicComponentRenderer.tsx | 6 ++++-- .../AccordionBasicComponent.tsx | 3 ++- .../CategorySelectComponent.tsx | 3 ++- .../divider-line/DividerLineComponent.tsx | 3 ++- .../image-display/ImageDisplayComponent.tsx | 3 ++- .../slider-basic/SliderBasicComponent.tsx | 3 ++- .../table-list/TableListComponent.tsx | 3 ++- .../test-input/TestInputComponent.tsx | 3 ++- .../text-display/TextDisplayComponent.tsx | 5 +++-- .../textarea-basic/TextareaBasicComponent.tsx | 3 ++- .../toggle-switch/ToggleSwitchComponent.tsx | 3 ++- .../v2-divider-line/DividerLineComponent.tsx | 3 ++- .../v2-table-list/TableListComponent.tsx | 3 ++- .../v2-text-display/TextDisplayComponent.tsx | 3 ++- frontend/lib/utils/darkModeColor.ts | 18 ++++++++++++++++ 23 files changed, 85 insertions(+), 37 deletions(-) create mode 100644 frontend/lib/utils/darkModeColor.ts diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 430810cf..4c289465 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -584,23 +584,24 @@ select { .dark .bg-orange-50 { background-color: hsl(25 40% 12%) !important; } .dark .bg-orange-100 { background-color: hsl(25 40% 15%) !important; } .dark .bg-orange-200 { background-color: hsl(25 40% 20%) !important; } -.dark .text-orange-600 { color: hsl(25 90% 55%) !important; } -.dark .text-orange-700 { color: hsl(25 90% 50%) !important; } +.dark .text-orange-600 { color: hsl(25 90% 65%) !important; } +.dark .text-orange-700 { color: hsl(25 90% 70%) !important; } .dark .border-orange-200 { border-color: hsl(25 40% 25%) !important; } .dark .border-orange-300 { border-color: hsl(25 40% 30%) !important; } /* --- 18. bg/text/border - violet (필터/관계 표시) --- */ .dark .bg-violet-50 { background-color: hsl(263 40% 12%) !important; } -.dark .bg-violet-100 { background-color: hsl(263 40% 15%) !important; } -.dark .bg-violet-200 { background-color: hsl(263 40% 20%) !important; } -.dark .text-violet-500 { color: hsl(263 70% 60%) !important; } -.dark .text-violet-600 { color: hsl(263 70% 55%) !important; } -.dark .text-violet-700 { color: hsl(263 70% 50%) !important; } -.dark .border-violet-200 { border-color: hsl(263 40% 25%) !important; } -.dark .border-violet-300 { border-color: hsl(263 40% 30%) !important; } +.dark .bg-violet-100 { background-color: hsl(263 40% 18%) !important; } +.dark .bg-violet-200 { background-color: hsl(263 40% 22%) !important; } +.dark .text-violet-500 { color: hsl(263 80% 70%) !important; } +.dark .text-violet-600 { color: hsl(263 80% 65%) !important; } +.dark .text-violet-700 { color: hsl(263 80% 72%) !important; } +.dark .border-violet-200 { border-color: hsl(263 40% 30%) !important; } +.dark .border-violet-300 { border-color: hsl(263 40% 35%) !important; } /* --- 19. bg/text/border - amber (조인/경고) --- */ .dark .bg-amber-200 { background-color: hsl(38 40% 20%) !important; } -.dark .text-amber-500 { color: hsl(38 90% 55%) !important; } +.dark .text-amber-500 { color: hsl(38 90% 60%) !important; } +.dark .text-amber-600 { color: hsl(38 90% 65%) !important; } /* ===== End Dark Mode Compatibility Layer ===== */ diff --git a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx index e66ed98a..944fca1d 100644 --- a/frontend/components/screen/InteractiveScreenViewerDynamic.tsx +++ b/frontend/components/screen/InteractiveScreenViewerDynamic.tsx @@ -27,6 +27,8 @@ import { subscribeDom as canvasSplitSubscribeDom, } from "@/lib/registry/components/v2-split-line/canvasSplitStore"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; + // 컴포넌트 렌더러들을 강제로 로드하여 레지스트리에 등록 import "@/lib/registry/components/ButtonRenderer"; import "@/lib/registry/components/CardRenderer"; @@ -1288,7 +1290,7 @@ export const InteractiveScreenViewerDynamic: React.FC( top: `-${estimatedLabelHeight}px`, left: 0, fontSize: style?.labelFontSize || "14px", - color: style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight || "500", }} className="text-sm font-medium whitespace-nowrap" diff --git a/frontend/components/v2/V2Date.tsx b/frontend/components/v2/V2Date.tsx index 86964bf6..d64544ea 100644 --- a/frontend/components/v2/V2Date.tsx +++ b/frontend/components/v2/V2Date.tsx @@ -1,5 +1,7 @@ "use client"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; + /** * V2Date * @@ -719,7 +721,7 @@ export const V2Date = forwardRef((props, ref) => { ...(labelPos === "top" ? { position: "absolute" as const, top: `-${estimatedLabelHeight}px`, left: 0 } : {}), ...(labelPos === "bottom" ? { position: "absolute" as const, bottom: `-${estimatedLabelHeight}px`, left: 0 } : {}), fontSize: style?.labelFontSize || "14px", - color: style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight || "500", }} className="text-sm font-medium whitespace-nowrap" @@ -754,7 +756,7 @@ export const V2Date = forwardRef((props, ref) => { htmlFor={id} style={{ fontSize: style?.labelFontSize || "14px", - color: style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight || "500", }} className="w-full text-sm font-medium whitespace-nowrap sm:w-[120px] sm:shrink-0" diff --git a/frontend/components/v2/V2Hierarchy.tsx b/frontend/components/v2/V2Hierarchy.tsx index 16debe88..ec6e655b 100644 --- a/frontend/components/v2/V2Hierarchy.tsx +++ b/frontend/components/v2/V2Hierarchy.tsx @@ -1,5 +1,7 @@ "use client"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; + /** * V2Hierarchy * @@ -486,7 +488,7 @@ export const V2Hierarchy = forwardRef( top: `-${estimatedLabelHeight}px`, left: 0, fontSize: style?.labelFontSize || "14px", - color: style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight || "500", }} className="text-sm font-medium whitespace-nowrap" diff --git a/frontend/components/v2/V2Input.tsx b/frontend/components/v2/V2Input.tsx index a5675106..5091680e 100644 --- a/frontend/components/v2/V2Input.tsx +++ b/frontend/components/v2/V2Input.tsx @@ -1,5 +1,7 @@ "use client"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; + /** * V2Input * @@ -994,7 +996,7 @@ export const V2Input = forwardRef((props, ref) => ...(labelPos === "top" ? { position: "absolute" as const, top: `-${estimatedLabelHeight}px`, left: 0 } : {}), ...(labelPos === "bottom" ? { position: "absolute" as const, bottom: `-${estimatedLabelHeight}px`, left: 0 } : {}), fontSize: style?.labelFontSize || "14px", - color: style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight || "500", }} className="text-sm font-medium whitespace-nowrap" @@ -1037,7 +1039,7 @@ export const V2Input = forwardRef((props, ref) => htmlFor={id} style={{ fontSize: style?.labelFontSize || "14px", - color: style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight || "500", }} className="w-full text-sm font-medium whitespace-nowrap sm:w-[120px] sm:shrink-0" diff --git a/frontend/components/v2/V2Media.tsx b/frontend/components/v2/V2Media.tsx index 0705aed2..ea2ce425 100644 --- a/frontend/components/v2/V2Media.tsx +++ b/frontend/components/v2/V2Media.tsx @@ -1,5 +1,7 @@ "use client"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; + /** * V2Media * @@ -834,7 +836,7 @@ export const V2Media = forwardRef((props, ref) => htmlFor={id} style={{ fontSize: style?.labelFontSize, - color: style?.labelColor, + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight, marginBottom: style?.labelMarginBottom, }} diff --git a/frontend/components/v2/V2Select.tsx b/frontend/components/v2/V2Select.tsx index eb2762e8..69e1ad6f 100644 --- a/frontend/components/v2/V2Select.tsx +++ b/frontend/components/v2/V2Select.tsx @@ -1,5 +1,7 @@ "use client"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; + /** * V2Select * @@ -1176,7 +1178,7 @@ export const V2Select = forwardRef( ...(labelPos === "top" ? { position: "absolute" as const, top: `-${estimatedLabelHeight}px`, left: 0 } : {}), ...(labelPos === "bottom" ? { position: "absolute" as const, bottom: `-${estimatedLabelHeight}px`, left: 0 } : {}), fontSize: style?.labelFontSize || "14px", - color: style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight || "500", }} className="text-sm font-medium whitespace-nowrap" @@ -1220,7 +1222,7 @@ export const V2Select = forwardRef( htmlFor={id} style={{ fontSize: style?.labelFontSize || "14px", - color: style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight || "500", }} className="w-full text-sm font-medium whitespace-nowrap sm:w-[120px] sm:shrink-0" diff --git a/frontend/lib/registry/DynamicComponentRenderer.tsx b/frontend/lib/registry/DynamicComponentRenderer.tsx index 8a7b6810..6e0b281c 100644 --- a/frontend/lib/registry/DynamicComponentRenderer.tsx +++ b/frontend/lib/registry/DynamicComponentRenderer.tsx @@ -10,6 +10,8 @@ import { filterDOMProps } from "@/lib/utils/domPropsFilter"; import { useV2FormOptional } from "@/components/v2/V2FormContext"; import { apiClient } from "@/lib/api/client"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; + // 컬럼 메타데이터 캐시 (테이블명 → 컬럼 설정 맵) const columnMetaCache: Record> = {}; const columnMetaLoading: Record> = {}; @@ -433,7 +435,7 @@ export const DynamicComponentRenderer: React.FC = if (catNeedsExternalHorizLabel) { const labelGap = component.style?.labelGap || "8px"; const labelFontSize = component.style?.labelFontSize || "14px"; - const labelColor = component.style?.labelColor || "#64748b"; + const labelColor = getAdaptiveLabelColor(component.style?.labelColor); const labelFontWeight = component.style?.labelFontWeight || "500"; const isRequired = component.required || (component as any).required; const isLeft = catLabelPosition === "left"; @@ -850,7 +852,7 @@ export const DynamicComponentRenderer: React.FC = if (needsExternalHorizLabel) { const labelGap = component.style?.labelGap || "8px"; const labelFontSize = component.style?.labelFontSize || "14px"; - const labelColor = component.style?.labelColor || "#64748b"; + const labelColor = getAdaptiveLabelColor(component.style?.labelColor); const labelFontWeight = component.style?.labelFontWeight || "500"; const isRequired = component.required || (component as any).required; const isLeft = labelPosition === "left"; diff --git a/frontend/lib/registry/components/accordion-basic/AccordionBasicComponent.tsx b/frontend/lib/registry/components/accordion-basic/AccordionBasicComponent.tsx index 27d52b81..b60be346 100644 --- a/frontend/lib/registry/components/accordion-basic/AccordionBasicComponent.tsx +++ b/frontend/lib/registry/components/accordion-basic/AccordionBasicComponent.tsx @@ -4,6 +4,7 @@ import React, { useState, useEffect } from "react"; import { ComponentRendererProps } from "../../types"; import { AccordionBasicConfig, AccordionItem, DataSourceConfig, ContentFieldConfig } from "./types"; import { apiClient } from "@/lib/api/client"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; // 커스텀 아코디언 컴포넌트 interface CustomAccordionProps { @@ -692,7 +693,7 @@ export const AccordionBasicComponent: React.FC = ( top: "-25px", left: "0px", fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(component.style?.labelColor), fontWeight: "500", }} > diff --git a/frontend/lib/registry/components/category-select/CategorySelectComponent.tsx b/frontend/lib/registry/components/category-select/CategorySelectComponent.tsx index 6b4ecb70..ea83e6ca 100644 --- a/frontend/lib/registry/components/category-select/CategorySelectComponent.tsx +++ b/frontend/lib/registry/components/category-select/CategorySelectComponent.tsx @@ -12,6 +12,7 @@ import { Label } from "@/components/ui/label"; import { getCategoryValues } from "@/lib/api/tableCategoryValue"; import { TableCategoryValue } from "@/types/tableCategoryValue"; import { Loader2 } from "lucide-react"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; interface CategorySelectComponentProps { component?: any; @@ -137,7 +138,7 @@ export const CategorySelectComponent: React.FC< top: `-${estimatedLabelHeight}px`, left: 0, fontSize: style?.labelFontSize || "14px", - color: style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(style?.labelColor), fontWeight: style?.labelFontWeight || "500", }} className="text-sm font-medium whitespace-nowrap" diff --git a/frontend/lib/registry/components/divider-line/DividerLineComponent.tsx b/frontend/lib/registry/components/divider-line/DividerLineComponent.tsx index ea4428ca..a94e0daf 100644 --- a/frontend/lib/registry/components/divider-line/DividerLineComponent.tsx +++ b/frontend/lib/registry/components/divider-line/DividerLineComponent.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ComponentRendererProps } from "@/types/component"; import { DividerLineConfig } from "./types"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; export interface DividerLineComponentProps extends ComponentRendererProps { config?: DividerLineConfig; @@ -119,7 +120,7 @@ export const DividerLineComponent: React.FC = ({ top: "-25px", left: "0px", fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(component.style?.labelColor), fontWeight: "500", }} > diff --git a/frontend/lib/registry/components/image-display/ImageDisplayComponent.tsx b/frontend/lib/registry/components/image-display/ImageDisplayComponent.tsx index 2f35c799..1f565456 100644 --- a/frontend/lib/registry/components/image-display/ImageDisplayComponent.tsx +++ b/frontend/lib/registry/components/image-display/ImageDisplayComponent.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ComponentRendererProps } from "@/types/component"; import { ImageDisplayConfig } from "./types"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; export interface ImageDisplayComponentProps extends ComponentRendererProps { config?: ImageDisplayConfig; @@ -87,7 +88,7 @@ export const ImageDisplayComponent: React.FC = ({ top: "-25px", left: "0px", fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(component.style?.labelColor), fontWeight: "500", }} > diff --git a/frontend/lib/registry/components/slider-basic/SliderBasicComponent.tsx b/frontend/lib/registry/components/slider-basic/SliderBasicComponent.tsx index d2eadcbf..ec77206d 100644 --- a/frontend/lib/registry/components/slider-basic/SliderBasicComponent.tsx +++ b/frontend/lib/registry/components/slider-basic/SliderBasicComponent.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ComponentRendererProps } from "@/types/component"; import { SliderBasicConfig } from "./types"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; export interface SliderBasicComponentProps extends ComponentRendererProps { config?: SliderBasicConfig; @@ -86,7 +87,7 @@ export const SliderBasicComponent: React.FC = ({ top: "-25px", left: "0px", fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(component.style?.labelColor), fontWeight: "500", // isInteractive 모드에서는 사용자 스타일 우선 적용 ...(isInteractive && component.style ? component.style : {}), diff --git a/frontend/lib/registry/components/table-list/TableListComponent.tsx b/frontend/lib/registry/components/table-list/TableListComponent.tsx index c9dc02d9..53c0f9df 100644 --- a/frontend/lib/registry/components/table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/table-list/TableListComponent.tsx @@ -9,6 +9,7 @@ import { codeCache } from "@/lib/caching/codeCache"; import { useEntityJoinOptimization } from "@/lib/hooks/useEntityJoinOptimization"; import { getFullImageUrl } from "@/lib/api/client"; import { Button } from "@/components/ui/button"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; // 🆕 RelatedDataButtons 전역 레지스트리 타입 선언 declare global { @@ -268,7 +269,7 @@ export const TableListComponent: React.FC = ({ // 디버그 로그 제거 (성능 최적화) - const buttonColor = component.style?.labelColor || "#212121"; + const buttonColor = getAdaptiveLabelColor(component.style?.labelColor); const buttonTextColor = component.config?.buttonTextColor || "#ffffff"; const gridColumns = component.gridColumns || 1; diff --git a/frontend/lib/registry/components/test-input/TestInputComponent.tsx b/frontend/lib/registry/components/test-input/TestInputComponent.tsx index 7042c813..17c033fc 100644 --- a/frontend/lib/registry/components/test-input/TestInputComponent.tsx +++ b/frontend/lib/registry/components/test-input/TestInputComponent.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ComponentRendererProps } from "@/types/component"; import { TestInputConfig } from "./types"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; export interface TestInputComponentProps extends ComponentRendererProps { config?: TestInputConfig; @@ -81,7 +82,7 @@ export const TestInputComponent: React.FC = ({ top: "-25px", left: "0px", fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(component.style?.labelColor), fontWeight: "500", }} > diff --git a/frontend/lib/registry/components/text-display/TextDisplayComponent.tsx b/frontend/lib/registry/components/text-display/TextDisplayComponent.tsx index 289101f1..38a42a75 100644 --- a/frontend/lib/registry/components/text-display/TextDisplayComponent.tsx +++ b/frontend/lib/registry/components/text-display/TextDisplayComponent.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ComponentRendererProps } from "../../types"; import { TextDisplayConfig } from "./types"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; import { filterDOMProps } from "@/lib/utils/domPropsFilter"; export interface TextDisplayComponentProps extends ComponentRendererProps { @@ -60,7 +61,7 @@ export const TextDisplayComponent: React.FC = ({ const textStyle: React.CSSProperties = { fontSize: componentConfig.fontSize || "14px", fontWeight: componentConfig.fontWeight || "normal", - color: componentConfig.color || "hsl(var(--foreground))", + color: getAdaptiveLabelColor(componentConfig.color), textAlign: componentConfig.textAlign || "left", backgroundColor: componentConfig.backgroundColor || "transparent", padding: componentConfig.padding || "0", @@ -92,7 +93,7 @@ export const TextDisplayComponent: React.FC = ({ top: "-25px", left: "0px", fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(component.style?.labelColor), fontWeight: "500", }} > diff --git a/frontend/lib/registry/components/textarea-basic/TextareaBasicComponent.tsx b/frontend/lib/registry/components/textarea-basic/TextareaBasicComponent.tsx index 998e6f52..c1089410 100644 --- a/frontend/lib/registry/components/textarea-basic/TextareaBasicComponent.tsx +++ b/frontend/lib/registry/components/textarea-basic/TextareaBasicComponent.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ComponentRendererProps } from "@/types/component"; import { TextareaBasicConfig } from "./types"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; export interface TextareaBasicComponentProps extends ComponentRendererProps { config?: TextareaBasicConfig; @@ -68,7 +69,7 @@ export const TextareaBasicComponent: React.FC = ({ top: "-25px", left: "0px", fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(component.style?.labelColor), fontWeight: "500", // isInteractive 모드에서는 사용자 스타일 우선 적용 ...(isInteractive && component.style ? component.style : {}), diff --git a/frontend/lib/registry/components/toggle-switch/ToggleSwitchComponent.tsx b/frontend/lib/registry/components/toggle-switch/ToggleSwitchComponent.tsx index 10da0eb7..506e0f85 100644 --- a/frontend/lib/registry/components/toggle-switch/ToggleSwitchComponent.tsx +++ b/frontend/lib/registry/components/toggle-switch/ToggleSwitchComponent.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ComponentRendererProps } from "@/types/component"; import { ToggleSwitchConfig } from "./types"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; export interface ToggleSwitchComponentProps extends ComponentRendererProps { config?: ToggleSwitchConfig; @@ -86,7 +87,7 @@ export const ToggleSwitchComponent: React.FC = ({ top: "-25px", left: "0px", fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(component.style?.labelColor), fontWeight: "500", // isInteractive 모드에서는 사용자 스타일 우선 적용 ...(isInteractive && component.style ? component.style : {}), diff --git a/frontend/lib/registry/components/v2-divider-line/DividerLineComponent.tsx b/frontend/lib/registry/components/v2-divider-line/DividerLineComponent.tsx index ea4428ca..a94e0daf 100644 --- a/frontend/lib/registry/components/v2-divider-line/DividerLineComponent.tsx +++ b/frontend/lib/registry/components/v2-divider-line/DividerLineComponent.tsx @@ -3,6 +3,7 @@ import React from "react"; import { ComponentRendererProps } from "@/types/component"; import { DividerLineConfig } from "./types"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; export interface DividerLineComponentProps extends ComponentRendererProps { config?: DividerLineConfig; @@ -119,7 +120,7 @@ export const DividerLineComponent: React.FC = ({ top: "-25px", left: "0px", fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#64748b", + color: getAdaptiveLabelColor(component.style?.labelColor), fontWeight: "500", }} > diff --git a/frontend/lib/registry/components/v2-table-list/TableListComponent.tsx b/frontend/lib/registry/components/v2-table-list/TableListComponent.tsx index 769d7a91..3b031be2 100644 --- a/frontend/lib/registry/components/v2-table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/v2-table-list/TableListComponent.tsx @@ -11,6 +11,7 @@ import { getFullImageUrl } from "@/lib/api/client"; import { getFilePreviewUrl } from "@/lib/api/file"; import { Button } from "@/components/ui/button"; import { v2EventBus, V2_EVENTS, V2ErrorBoundary } from "@/lib/v2-core"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; // 🖼️ 테이블 셀 이미지 썸네일 컴포넌트 // objid인 경우 인증된 API로 blob URL 생성, 경로인 경우 직접 URL 사용 @@ -404,7 +405,7 @@ export const TableListComponent: React.FC = ({ // 디버그 로그 제거 (성능 최적화) - const buttonColor = component.style?.labelColor || "#212121"; + const buttonColor = getAdaptiveLabelColor(component.style?.labelColor); const buttonTextColor = component.config?.buttonTextColor || "#ffffff"; const gridColumns = component.gridColumns || 1; diff --git a/frontend/lib/registry/components/v2-text-display/TextDisplayComponent.tsx b/frontend/lib/registry/components/v2-text-display/TextDisplayComponent.tsx index acf0d6b5..86b83c19 100644 --- a/frontend/lib/registry/components/v2-text-display/TextDisplayComponent.tsx +++ b/frontend/lib/registry/components/v2-text-display/TextDisplayComponent.tsx @@ -4,6 +4,7 @@ import React from "react"; import { ComponentRendererProps } from "../../types"; import { TextDisplayConfig } from "./types"; import { filterDOMProps } from "@/lib/utils/domPropsFilter"; +import { getAdaptiveLabelColor } from "@/lib/utils/darkModeColor"; export interface TextDisplayComponentProps extends ComponentRendererProps { // 추가 props가 필요한 경우 여기에 정의 @@ -63,7 +64,7 @@ export const TextDisplayComponent: React.FC = ({ const textStyle: React.CSSProperties = { fontSize: customStyle.fontSize || componentConfig.fontSize || "14px", fontWeight: customStyle.fontWeight || componentConfig.fontWeight || "normal", - color: customStyle.color || componentConfig.color || "hsl(var(--foreground))", + color: getAdaptiveLabelColor(customStyle.color || componentConfig.color), textAlign: (customStyle.textAlign || componentConfig.textAlign || "left") as React.CSSProperties["textAlign"], backgroundColor: customStyle.backgroundColor || componentConfig.backgroundColor || "transparent", padding: componentConfig.padding || "0", diff --git a/frontend/lib/utils/darkModeColor.ts b/frontend/lib/utils/darkModeColor.ts new file mode 100644 index 00000000..efbc645f --- /dev/null +++ b/frontend/lib/utils/darkModeColor.ts @@ -0,0 +1,18 @@ +/** + * 다크모드 대응 색상 유틸리티 + * 화면 디자이너에서 기본값으로 저장된 어두운 색상을 감지하여 + * 다크모드에서 자동으로 CSS 변수(foreground)로 대체 + */ + +const DEFAULT_DARK_COLORS = new Set([ + "#212121", "#000000", "#333333", "#333", "#000", + "black", "#111111", "#1a1a1a", "#64748b", +]); + +export const isDefaultDarkLabelColor = (color?: string): boolean => { + if (!color) return true; + return DEFAULT_DARK_COLORS.has(color.toLowerCase().trim()); +}; + +export const getAdaptiveLabelColor = (labelColor?: string): string => + isDefaultDarkLabelColor(labelColor) ? "hsl(var(--foreground))" : labelColor!;