77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { ConfigPanelBuilderProps } from "./ConfigPanelTypes";
|
|
import { ConfigSection } from "./ConfigSection";
|
|
import { ConfigField } from "./ConfigField";
|
|
|
|
export function ConfigPanelBuilder<T extends Record<string, any>>({
|
|
config,
|
|
onChange,
|
|
sections,
|
|
presets,
|
|
tableColumns,
|
|
children,
|
|
}: ConfigPanelBuilderProps<T>) {
|
|
return (
|
|
<div className="space-y-3">
|
|
{/* 프리셋 버튼 */}
|
|
{presets && presets.length > 0 && (
|
|
<div className="border-b pb-3">
|
|
<h4 className="mb-2 text-xs font-medium text-muted-foreground">
|
|
빠른 설정
|
|
</h4>
|
|
<div className="flex flex-wrap gap-1">
|
|
{presets.map((preset, idx) => (
|
|
<button
|
|
key={idx}
|
|
onClick={() => {
|
|
Object.entries(preset.values).forEach(([key, value]) => {
|
|
onChange(key, value);
|
|
});
|
|
}}
|
|
className="rounded-full bg-muted px-2.5 py-1 text-[10px] font-medium text-muted-foreground transition-colors hover:bg-primary hover:text-primary-foreground"
|
|
title={preset.description}
|
|
>
|
|
{preset.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* 섹션 렌더링 */}
|
|
{sections.map((section) => {
|
|
if (section.condition && !section.condition(config)) {
|
|
return null;
|
|
}
|
|
|
|
const visibleFields = section.fields.filter(
|
|
(field) => !field.condition || field.condition(config),
|
|
);
|
|
|
|
if (visibleFields.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<ConfigSection key={section.id} section={section}>
|
|
{visibleFields.map((field) => (
|
|
<ConfigField
|
|
key={field.key}
|
|
field={field}
|
|
value={(config as any)[field.key]}
|
|
onChange={onChange}
|
|
tableColumns={tableColumns}
|
|
/>
|
|
))}
|
|
</ConfigSection>
|
|
);
|
|
})}
|
|
|
|
{/* 커스텀 children */}
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|