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
This commit is contained in:
DDD1542
2026-03-10 21:16:01 +09:00
parent fa6f76bff1
commit 58e958829c
23 changed files with 85 additions and 37 deletions

View File

@@ -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<string, Record<string, any>> = {};
const columnMetaLoading: Record<string, Promise<void>> = {};
@@ -433,7 +435,7 @@ export const DynamicComponentRenderer: React.FC<DynamicComponentRendererProps> =
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<DynamicComponentRendererProps> =
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";

View File

@@ -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<AccordionBasicComponentProps> = (
top: "-25px",
left: "0px",
fontSize: component.style?.labelFontSize || "14px",
color: component.style?.labelColor || "#64748b",
color: getAdaptiveLabelColor(component.style?.labelColor),
fontWeight: "500",
}}
>

View File

@@ -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"

View File

@@ -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<DividerLineComponentProps> = ({
top: "-25px",
left: "0px",
fontSize: component.style?.labelFontSize || "14px",
color: component.style?.labelColor || "#64748b",
color: getAdaptiveLabelColor(component.style?.labelColor),
fontWeight: "500",
}}
>

View File

@@ -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<ImageDisplayComponentProps> = ({
top: "-25px",
left: "0px",
fontSize: component.style?.labelFontSize || "14px",
color: component.style?.labelColor || "#64748b",
color: getAdaptiveLabelColor(component.style?.labelColor),
fontWeight: "500",
}}
>

View File

@@ -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<SliderBasicComponentProps> = ({
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 : {}),

View File

@@ -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<TableListComponentProps> = ({
// 디버그 로그 제거 (성능 최적화)
const buttonColor = component.style?.labelColor || "#212121";
const buttonColor = getAdaptiveLabelColor(component.style?.labelColor);
const buttonTextColor = component.config?.buttonTextColor || "#ffffff";
const gridColumns = component.gridColumns || 1;

View File

@@ -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<TestInputComponentProps> = ({
top: "-25px",
left: "0px",
fontSize: component.style?.labelFontSize || "14px",
color: component.style?.labelColor || "#64748b",
color: getAdaptiveLabelColor(component.style?.labelColor),
fontWeight: "500",
}}
>

View File

@@ -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<TextDisplayComponentProps> = ({
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<TextDisplayComponentProps> = ({
top: "-25px",
left: "0px",
fontSize: component.style?.labelFontSize || "14px",
color: component.style?.labelColor || "#64748b",
color: getAdaptiveLabelColor(component.style?.labelColor),
fontWeight: "500",
}}
>

View File

@@ -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<TextareaBasicComponentProps> = ({
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 : {}),

View File

@@ -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<ToggleSwitchComponentProps> = ({
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 : {}),

View File

@@ -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<DividerLineComponentProps> = ({
top: "-25px",
left: "0px",
fontSize: component.style?.labelFontSize || "14px",
color: component.style?.labelColor || "#64748b",
color: getAdaptiveLabelColor(component.style?.labelColor),
fontWeight: "500",
}}
>

View File

@@ -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<TableListComponentProps> = ({
// 디버그 로그 제거 (성능 최적화)
const buttonColor = component.style?.labelColor || "#212121";
const buttonColor = getAdaptiveLabelColor(component.style?.labelColor);
const buttonTextColor = component.config?.buttonTextColor || "#ffffff";
const gridColumns = component.gridColumns || 1;

View File

@@ -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<TextDisplayComponentProps> = ({
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",

View File

@@ -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!;