ERP-node/frontend/components/screen/panels/ResponsiveConfigPanel.tsx

157 lines
5.8 KiB
TypeScript

/**
* 반응형 설정 패널
*
* 컴포넌트별로 브레이크포인트마다 다른 레이아웃 설정 가능
*/
import React, { useState } from "react";
import { ComponentData } from "@/types/screen-management";
import { Breakpoint, BREAKPOINTS, ResponsiveComponentConfig } from "@/types/responsive";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Checkbox } from "@/components/ui/checkbox";
interface ResponsiveConfigPanelProps {
component: ComponentData;
onUpdate: (config: ResponsiveComponentConfig) => void;
}
export const ResponsiveConfigPanel: React.FC<ResponsiveConfigPanelProps> = ({ component, onUpdate }) => {
const [activeTab, setActiveTab] = useState<Breakpoint>("desktop");
const config = component.responsiveConfig || {
designerPosition: {
x: component.position.x,
y: component.position.y,
width: component.size.width,
height: component.size.height,
},
useSmartDefaults: true,
};
return (
<Card>
<CardHeader>
<CardTitle> </CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{/* 스마트 기본값 토글 */}
<div className="flex items-center space-x-2">
<Checkbox
id="smartDefaults"
checked={config.useSmartDefaults}
onCheckedChange={(checked) => {
onUpdate({
...config,
useSmartDefaults: checked as boolean,
});
}}
/>
<Label htmlFor="smartDefaults"> ()</Label>
</div>
<div className="text-xs text-gray-500">
.
</div>
{/* 수동 설정 */}
{!config.useSmartDefaults && (
<Tabs value={activeTab} onValueChange={(v) => setActiveTab(v as Breakpoint)}>
<TabsList className="grid w-full grid-cols-3">
<TabsTrigger value="desktop"></TabsTrigger>
<TabsTrigger value="tablet">릿</TabsTrigger>
<TabsTrigger value="mobile"></TabsTrigger>
</TabsList>
<TabsContent value={activeTab} className="space-y-4">
{/* 그리드 컬럼 수 */}
<div className="space-y-2">
<Label> ( )</Label>
<Select
value={config.responsive?.[activeTab]?.gridColumns?.toString()}
onValueChange={(v) => {
onUpdate({
...config,
responsive: {
...config.responsive,
[activeTab]: {
...config.responsive?.[activeTab],
gridColumns: parseInt(v),
},
},
});
}}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="컬럼 수 선택" />
</SelectTrigger>
<SelectContent>
{[...Array(BREAKPOINTS[activeTab].columns)].map((_, i) => {
const cols = i + 1;
const percent = ((cols / BREAKPOINTS[activeTab].columns) * 100).toFixed(0);
return (
<SelectItem key={cols} value={cols.toString()}>
{cols} / {BREAKPOINTS[activeTab].columns} ({percent}%)
</SelectItem>
);
})}
</SelectContent>
</Select>
</div>
{/* 표시 순서 */}
<div className="space-y-2">
<Label> </Label>
<Input
type="number"
min="1"
value={config.responsive?.[activeTab]?.order || 1}
onChange={(e) => {
onUpdate({
...config,
responsive: {
...config.responsive,
[activeTab]: {
...config.responsive?.[activeTab],
order: parseInt(e.target.value),
},
},
});
}}
/>
<div className="text-xs text-gray-500"> .</div>
</div>
{/* 숨김 */}
<div className="flex items-center space-x-2">
<Checkbox
id={`hide-${activeTab}`}
checked={config.responsive?.[activeTab]?.hide || false}
onCheckedChange={(checked) => {
onUpdate({
...config,
responsive: {
...config.responsive,
[activeTab]: {
...config.responsive?.[activeTab],
hide: checked as boolean,
},
},
});
}}
/>
<Label htmlFor={`hide-${activeTab}`}>
{activeTab === "desktop" ? "데스크톱" : activeTab === "tablet" ? "태블릿" : "모바일"}
</Label>
</div>
</TabsContent>
</Tabs>
)}
</CardContent>
</Card>
);
};