157 lines
5.8 KiB
TypeScript
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>
|
|
);
|
|
};
|