feat: add next-themes package and update styles
- Added `next-themes` package for theme management. - Updated various components to use `hsl(var(--foreground))` for color consistency. - Changed background colors from `bg-white` to `bg-card` in multiple components for better theming support. Made-with: Cursor
This commit is contained in:
@@ -1474,7 +1474,7 @@ export const EditModal: React.FC<EditModalProps> = ({ className }) => {
|
||||
>
|
||||
<div
|
||||
data-screen-runtime="true"
|
||||
className="relative m-auto bg-white"
|
||||
className="relative m-auto bg-card"
|
||||
style={{
|
||||
width: screenDimensions?.width || 800,
|
||||
// 조건부 레이어가 활성화되면 높이 자동 확장
|
||||
|
||||
@@ -2217,7 +2217,7 @@ export const InteractiveScreenViewer: React.FC<InteractiveScreenViewerProps> = (
|
||||
|
||||
const labelStyle: React.CSSProperties = {
|
||||
fontSize: component.style?.labelFontSize || "14px",
|
||||
color: component.style?.labelColor || "#212121",
|
||||
color: component.style?.labelColor || "hsl(var(--foreground))",
|
||||
fontWeight: component.style?.labelFontWeight || "500",
|
||||
backgroundColor: component.style?.labelBackgroundColor || "transparent",
|
||||
padding: component.style?.labelPadding || "0",
|
||||
|
||||
@@ -1288,7 +1288,7 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
|
||||
className="text-sm font-medium leading-none"
|
||||
style={{
|
||||
fontSize: style?.labelFontSize || "14px",
|
||||
color: style?.labelColor || "#212121",
|
||||
color: style?.labelColor || "hsl(var(--foreground))",
|
||||
fontWeight: style?.labelFontWeight || "500",
|
||||
...(isHorizLabel ? { whiteSpace: "nowrap" as const, display: "flex", alignItems: "center" } : {}),
|
||||
...(labelPos === "bottom" ? { marginTop: style?.labelMarginBottom || "4px" } : {}),
|
||||
@@ -1344,7 +1344,7 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
|
||||
? { right: "100%", marginRight: labelGapValue }
|
||||
: { left: "100%", marginLeft: labelGapValue }),
|
||||
fontSize: style?.labelFontSize || "14px",
|
||||
color: style?.labelColor || "#212121",
|
||||
color: style?.labelColor || "hsl(var(--foreground))",
|
||||
fontWeight: style?.labelFontWeight || "500",
|
||||
whiteSpace: "nowrap",
|
||||
}}
|
||||
|
||||
@@ -221,7 +221,7 @@ export const ScreenNode: React.FC<{ data: ScreenNodeData }> = ({ data }) => {
|
||||
</div>
|
||||
|
||||
{/* 화면 미리보기 영역 (컴팩트) */}
|
||||
<div className="h-[140px] overflow-hidden bg-slate-50 p-2">
|
||||
<div className="h-[140px] overflow-hidden bg-muted/50 p-2">
|
||||
{layoutSummary ? (
|
||||
<ScreenPreview layoutSummary={layoutSummary} screenType={screenType} />
|
||||
) : (
|
||||
@@ -233,11 +233,11 @@ export const ScreenNode: React.FC<{ data: ScreenNodeData }> = ({ data }) => {
|
||||
</div>
|
||||
|
||||
{/* 필드 매핑 영역 */}
|
||||
<div className="flex-1 overflow-hidden border-t border-slate-200 bg-white px-2 py-1.5">
|
||||
<div className="mb-1 flex items-center gap-1 text-[9px] font-medium text-slate-500">
|
||||
<div className="flex-1 overflow-hidden border-t border-border bg-card px-2 py-1.5">
|
||||
<div className="mb-1 flex items-center gap-1 text-[9px] font-medium text-muted-foreground">
|
||||
<Columns3 className="h-3 w-3" />
|
||||
<span>필드 매핑</span>
|
||||
<span className="ml-auto text-[8px] text-slate-400">
|
||||
<span className="ml-auto text-[8px] text-muted-foreground/70">
|
||||
{layoutSummary?.layoutItems?.filter(i => i.label && !i.componentKind?.includes('button')).length || 0}개
|
||||
</span>
|
||||
</div>
|
||||
@@ -319,7 +319,7 @@ const ScreenPreview: React.FC<{ layoutSummary: ScreenLayoutSummary; screenType:
|
||||
// 그리드 화면 일러스트
|
||||
if (screenType === "grid") {
|
||||
return (
|
||||
<div className="flex h-full flex-col gap-2 rounded-lg border border-slate-200 bg-muted/30 p-3">
|
||||
<div className="flex h-full flex-col gap-2 rounded-lg border border-border bg-muted/30 p-3">
|
||||
{/* 상단 툴바 */}
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="h-4 w-16 rounded bg-pink-400/80 shadow-sm" />
|
||||
@@ -337,19 +337,19 @@ const ScreenPreview: React.FC<{ layoutSummary: ScreenLayoutSummary; screenType:
|
||||
{/* 테이블 행들 */}
|
||||
<div className="flex flex-1 flex-col gap-1 overflow-hidden">
|
||||
{[...Array(7)].map((_, i) => (
|
||||
<div key={i} className={`flex gap-1 rounded px-2 py-1.5 ${i % 2 === 0 ? "bg-slate-100" : "bg-white"}`}>
|
||||
<div key={i} className={`flex gap-1 rounded px-2 py-1.5 ${i % 2 === 0 ? "bg-muted" : "bg-card"}`}>
|
||||
{[...Array(5)].map((_, j) => (
|
||||
<div key={j} className="h-2 flex-1 rounded bg-slate-300/70" />
|
||||
<div key={j} className="h-2 flex-1 rounded bg-muted-foreground/30" />
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{/* 페이지네이션 */}
|
||||
<div className="flex items-center justify-center gap-2 pt-1">
|
||||
<div className="h-2.5 w-4 rounded bg-slate-300" />
|
||||
<div className="h-2.5 w-4 rounded bg-muted-foreground/40" />
|
||||
<div className="h-2.5 w-4 rounded bg-primary" />
|
||||
<div className="h-2.5 w-4 rounded bg-slate-300" />
|
||||
<div className="h-2.5 w-4 rounded bg-slate-300" />
|
||||
<div className="h-2.5 w-4 rounded bg-muted-foreground/40" />
|
||||
<div className="h-2.5 w-4 rounded bg-muted-foreground/40" />
|
||||
</div>
|
||||
{/* 컴포넌트 수 */}
|
||||
<div className="absolute bottom-2 right-2 rounded-md bg-slate-800/80 px-2 py-1 text-[10px] font-medium text-white shadow-sm">
|
||||
@@ -362,17 +362,17 @@ const ScreenPreview: React.FC<{ layoutSummary: ScreenLayoutSummary; screenType:
|
||||
// 폼 화면 일러스트
|
||||
if (screenType === "form") {
|
||||
return (
|
||||
<div className="flex h-full flex-col gap-3 rounded-lg border border-slate-200 bg-muted/30 p-3">
|
||||
<div className="flex h-full flex-col gap-3 rounded-lg border border-border bg-muted/30 p-3">
|
||||
{/* 폼 필드들 */}
|
||||
{[...Array(6)].map((_, i) => (
|
||||
<div key={i} className="flex items-center gap-3">
|
||||
<div className="h-2.5 w-14 rounded bg-slate-400" />
|
||||
<div className="h-5 flex-1 rounded-md border border-slate-300 bg-white shadow-sm" />
|
||||
<div className="h-2.5 w-14 rounded bg-muted-foreground/50" />
|
||||
<div className="h-5 flex-1 rounded-md border border-border bg-card shadow-sm" />
|
||||
</div>
|
||||
))}
|
||||
{/* 버튼 영역 */}
|
||||
<div className="mt-auto flex justify-end gap-2 border-t border-slate-100 pt-3">
|
||||
<div className="h-5 w-14 rounded-md bg-slate-300 shadow-sm" />
|
||||
<div className="mt-auto flex justify-end gap-2 border-t border-border pt-3">
|
||||
<div className="h-5 w-14 rounded-md bg-muted-foreground/40 shadow-sm" />
|
||||
<div className="h-5 w-14 rounded-md bg-primary shadow-sm" />
|
||||
</div>
|
||||
{/* 컴포넌트 수 */}
|
||||
@@ -386,7 +386,7 @@ const ScreenPreview: React.FC<{ layoutSummary: ScreenLayoutSummary; screenType:
|
||||
// 대시보드 화면 일러스트
|
||||
if (screenType === "dashboard") {
|
||||
return (
|
||||
<div className="grid h-full grid-cols-2 gap-2 rounded-lg border border-slate-200 bg-muted/30 p-3">
|
||||
<div className="grid h-full grid-cols-2 gap-2 rounded-lg border border-border bg-muted/30 p-3">
|
||||
{/* 카드/차트들 */}
|
||||
<div className="rounded-lg bg-emerald-100 p-2 shadow-sm">
|
||||
<div className="mb-2 h-2.5 w-10 rounded bg-emerald-400" />
|
||||
@@ -419,15 +419,15 @@ const ScreenPreview: React.FC<{ layoutSummary: ScreenLayoutSummary; screenType:
|
||||
// 액션 화면 일러스트 (버튼 중심)
|
||||
if (screenType === "action") {
|
||||
return (
|
||||
<div className="flex h-full flex-col items-center justify-center gap-4 rounded-lg border border-slate-200 bg-muted/30 p-3">
|
||||
<div className="rounded-full bg-slate-100 p-4 text-slate-400">
|
||||
<div className="flex h-full flex-col items-center justify-center gap-4 rounded-lg border border-border bg-muted/30 p-3">
|
||||
<div className="rounded-full bg-muted p-4 text-muted-foreground">
|
||||
<MousePointer2 className="h-10 w-10" />
|
||||
</div>
|
||||
<div className="flex gap-3">
|
||||
<div className="h-7 w-16 rounded-md bg-primary shadow-sm" />
|
||||
<div className="h-7 w-16 rounded-md bg-slate-300 shadow-sm" />
|
||||
<div className="h-7 w-16 rounded-md bg-muted-foreground/40 shadow-sm" />
|
||||
</div>
|
||||
<div className="text-xs font-medium text-slate-400">액션 화면</div>
|
||||
<div className="text-xs font-medium text-muted-foreground">액션 화면</div>
|
||||
{/* 컴포넌트 수 */}
|
||||
<div className="absolute bottom-2 right-2 rounded-md bg-slate-800/80 px-2 py-1 text-[10px] font-medium text-white shadow-sm">
|
||||
{totalComponents}개
|
||||
@@ -695,7 +695,7 @@ export const TableNode: React.FC<{ data: TableNodeData }> = ({ data }) => {
|
||||
if (filterRefs.length === 0 && lookupRefs.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 mb-1.5 rounded border border-slate-300 bg-slate-50 text-[9px]">
|
||||
<div className="flex items-center gap-1.5 px-2 py-1 mb-1.5 rounded border border-border bg-muted text-[9px]">
|
||||
{/* 필터 뱃지 */}
|
||||
{filterRefs.length > 0 && (
|
||||
<span
|
||||
@@ -861,7 +861,7 @@ export const TableNode: React.FC<{ data: TableNodeData }> = ({ data }) => {
|
||||
export const LegacyScreenNode = ScreenNode;
|
||||
export const AggregateNode: React.FC<{ data: any }> = ({ data }) => {
|
||||
return (
|
||||
<div className="rounded-lg border-2 border-purple-300 bg-white p-3 shadow-lg">
|
||||
<div className="rounded-lg border-2 border-purple-300 bg-card p-3 shadow-lg">
|
||||
<Handle type="target" position={Position.Left} id="left" className="!h-3 !w-3 !bg-purple-500" />
|
||||
<Handle type="source" position={Position.Right} id="right" className="!h-3 !w-3 !bg-purple-500" />
|
||||
<div className="flex items-center gap-2 text-purple-600">
|
||||
|
||||
@@ -690,7 +690,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId
|
||||
type: "smoothstep",
|
||||
label: `${i + 1}`,
|
||||
labelStyle: { fontSize: 11, fill: "#0ea5e9", fontWeight: 600 },
|
||||
labelBgStyle: { fill: "white", stroke: "#e2e8f0", strokeWidth: 1 },
|
||||
labelBgStyle: { fill: "hsl(var(--card))", stroke: "hsl(var(--border))", strokeWidth: 1 },
|
||||
labelBgPadding: [4, 2] as [number, number],
|
||||
markerEnd: { type: MarkerType.ArrowClosed, color: "#0ea5e9" },
|
||||
animated: true,
|
||||
@@ -1007,7 +1007,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId
|
||||
type: "smoothstep",
|
||||
label: rel.relation_type === "join" ? "조인" : rel.crud_operations || "",
|
||||
labelStyle: { fontSize: 9, fill: "#10b981" },
|
||||
labelBgStyle: { fill: "white", stroke: "#e2e8f0", strokeWidth: 1 },
|
||||
labelBgStyle: { fill: "hsl(var(--card))", stroke: "hsl(var(--border))", strokeWidth: 1 },
|
||||
labelBgPadding: [3, 2] as [number, number],
|
||||
style: { stroke: "#10b981", strokeWidth: 1.5 },
|
||||
});
|
||||
@@ -1030,7 +1030,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId
|
||||
animated: true,
|
||||
label: flow.flow_label || flow.flow_type || "이동",
|
||||
labelStyle: { fontSize: 10, fill: "#8b5cf6", fontWeight: 500 },
|
||||
labelBgStyle: { fill: "white", stroke: "#e2e8f0", strokeWidth: 1 },
|
||||
labelBgStyle: { fill: "hsl(var(--card))", stroke: "hsl(var(--border))", strokeWidth: 1 },
|
||||
labelBgPadding: [4, 2] as [number, number],
|
||||
markerEnd: { type: MarkerType.ArrowClosed, color: "#8b5cf6" },
|
||||
style: { stroke: "#8b5cf6", strokeWidth: 2 },
|
||||
@@ -2333,7 +2333,7 @@ function ScreenRelationFlowInner({ screen, selectedGroup, initialFocusedScreenId
|
||||
maxZoom={1.5}
|
||||
proOptions={{ hideAttribution: true }}
|
||||
>
|
||||
<Background variant={BackgroundVariant.Dots} gap={20} size={1} color="#e2e8f0" />
|
||||
<Background variant={BackgroundVariant.Dots} gap={20} size={1} color="hsl(var(--border))" />
|
||||
<Controls position="bottom-right" />
|
||||
</ReactFlow>
|
||||
</div>
|
||||
|
||||
@@ -404,7 +404,7 @@ export function ScreenSettingModal({
|
||||
{/* 2컬럼 레이아웃: 왼쪽 탭(좁게) + 오른쪽 프리뷰(넓게) */}
|
||||
<div className="flex min-h-0 flex-1 gap-3">
|
||||
{/* 왼쪽: 탭 컨텐츠 (40%) */}
|
||||
<div className="flex min-h-0 w-[40%] flex-col rounded-lg border bg-white">
|
||||
<div className="flex min-h-0 w-[40%] flex-col rounded-lg border bg-card">
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onValueChange={setActiveTab}
|
||||
@@ -511,7 +511,7 @@ export function ScreenSettingModal({
|
||||
</div>
|
||||
|
||||
{/* 오른쪽: 화면 프리뷰 (60%, 항상 표시) */}
|
||||
<div className="flex min-h-0 w-[60%] flex-col overflow-hidden rounded-lg border bg-white">
|
||||
<div className="flex min-h-0 w-[60%] flex-col overflow-hidden rounded-lg border bg-card">
|
||||
<PreviewTab
|
||||
screenId={currentScreenId}
|
||||
screenName={currentScreenName}
|
||||
@@ -926,7 +926,7 @@ function TableColumnAccordion({
|
||||
|
||||
{/* 펼쳐진 내용 */}
|
||||
{isOpen && (
|
||||
<div className={`border-t border-${themeColor}-100 p-3 space-y-3 bg-white/50`}>
|
||||
<div className={`border-t border-${themeColor}-100 p-3 space-y-3 bg-card/50`}>
|
||||
{/* 필터 연결 정보 (필터 테이블만) */}
|
||||
{!isMain && filterKeyMapping && (
|
||||
<div className="flex items-center gap-1 text-xs">
|
||||
@@ -2529,7 +2529,7 @@ function FieldMappingTab({
|
||||
{componentColumns.map((comp, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className="rounded-lg border bg-white overflow-hidden"
|
||||
className="rounded-lg border bg-card overflow-hidden"
|
||||
>
|
||||
{/* 컴포넌트 헤더 */}
|
||||
<div className="flex items-center justify-between px-3 py-2 bg-muted border-b">
|
||||
@@ -4282,7 +4282,7 @@ function ControlManagementTab({
|
||||
);
|
||||
const tableName = (flow as any).tableType || (flow as any).tableName;
|
||||
return (
|
||||
<div key={`flow-list-${flow.flowId}`} className="flex items-center gap-2 px-2 py-1.5 rounded bg-white/50 hover:bg-white">
|
||||
<div key={`flow-list-${flow.flowId}`} className="flex items-center gap-2 px-2 py-1.5 rounded bg-card/50 hover:bg-card">
|
||||
{/* 플로우 이름 - 일반 텍스트 */}
|
||||
<Workflow className="h-3.5 w-3.5 text-purple-500 shrink-0" />
|
||||
<span className="text-xs font-medium text-foreground shrink-0">
|
||||
@@ -4744,7 +4744,7 @@ function PreviewTab({ screenId, screenName, companyCode, iframeKey = 0, canvasWi
|
||||
className="relative min-h-0 flex-1 overflow-hidden flex items-center justify-center bg-muted"
|
||||
>
|
||||
{loading && (
|
||||
<div className="absolute inset-0 z-10 flex items-center justify-center bg-white/80">
|
||||
<div className="absolute inset-0 z-10 flex items-center justify-center bg-background/80">
|
||||
<div className="text-center">
|
||||
<Loader2 className="mx-auto h-8 w-8 animate-spin text-primary" />
|
||||
<p className="mt-2 text-sm text-muted-foreground">화면 로딩 중...</p>
|
||||
@@ -4797,7 +4797,7 @@ function PreviewTab({ screenId, screenName, companyCode, iframeKey = 0, canvasWi
|
||||
key={iframeKey}
|
||||
id="screen-preview-iframe"
|
||||
src={previewUrl}
|
||||
className="border-0 shadow-lg rounded bg-white pointer-events-none"
|
||||
className="border-0 shadow-lg rounded bg-card pointer-events-none"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
|
||||
Reference in New Issue
Block a user