2025-09-02 11:16:40 +09:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import { useState } from "react";
|
|
|
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { Input } from "@/components/ui/input";
|
|
|
|
|
import { Label } from "@/components/ui/label";
|
|
|
|
|
import { Slider } from "@/components/ui/slider";
|
|
|
|
|
import { Grid, Settings, RotateCcw } from "lucide-react";
|
|
|
|
|
|
|
|
|
|
interface GridSettings {
|
|
|
|
|
columns: number;
|
|
|
|
|
gap: number;
|
|
|
|
|
padding: number;
|
|
|
|
|
snapToGrid: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface GridControlsProps {
|
|
|
|
|
gridSettings: GridSettings;
|
|
|
|
|
onGridSettingsChange: (settings: GridSettings) => void;
|
|
|
|
|
className?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function GridControls({ gridSettings, onGridSettingsChange, className }: GridControlsProps) {
|
|
|
|
|
const [localSettings, setLocalSettings] = useState<GridSettings>(gridSettings);
|
|
|
|
|
|
|
|
|
|
const handleSettingChange = (key: keyof GridSettings, value: number | boolean) => {
|
|
|
|
|
const newSettings = { ...localSettings, [key]: value };
|
|
|
|
|
setLocalSettings(newSettings);
|
|
|
|
|
onGridSettingsChange(newSettings);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const resetToDefault = () => {
|
|
|
|
|
const defaultSettings: GridSettings = {
|
|
|
|
|
columns: 12,
|
|
|
|
|
gap: 16,
|
|
|
|
|
padding: 16,
|
|
|
|
|
snapToGrid: true,
|
|
|
|
|
};
|
|
|
|
|
setLocalSettings(defaultSettings);
|
|
|
|
|
onGridSettingsChange(defaultSettings);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Card className={className}>
|
|
|
|
|
<CardHeader className="pb-3">
|
|
|
|
|
<CardTitle className="flex items-center space-x-2 text-sm">
|
|
|
|
|
<Grid className="h-4 w-4" />
|
|
|
|
|
<span>격자 설정</span>
|
|
|
|
|
</CardTitle>
|
|
|
|
|
</CardHeader>
|
|
|
|
|
<CardContent className="space-y-4">
|
|
|
|
|
{/* 격자 열 개수 */}
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="columns" className="text-xs font-medium">
|
|
|
|
|
격자 열 개수
|
|
|
|
|
</Label>
|
|
|
|
|
<div className="flex items-center space-x-2">
|
|
|
|
|
<Slider
|
|
|
|
|
id="columns"
|
|
|
|
|
min={1}
|
|
|
|
|
max={24}
|
|
|
|
|
step={1}
|
|
|
|
|
value={[localSettings.columns]}
|
|
|
|
|
onValueChange={(value) => handleSettingChange("columns", value[0])}
|
|
|
|
|
className="flex-1"
|
|
|
|
|
/>
|
|
|
|
|
<Input
|
|
|
|
|
type="number"
|
|
|
|
|
min={1}
|
|
|
|
|
max={24}
|
|
|
|
|
value={localSettings.columns}
|
|
|
|
|
onChange={(e) => handleSettingChange("columns", parseInt(e.target.value) || 12)}
|
|
|
|
|
className="w-16 text-xs"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-xs text-gray-500">현재: {localSettings.columns}열</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 격자 간격 */}
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="gap" className="text-xs font-medium">
|
|
|
|
|
격자 간격 (px)
|
|
|
|
|
</Label>
|
|
|
|
|
<div className="flex items-center space-x-2">
|
|
|
|
|
<Slider
|
|
|
|
|
id="gap"
|
|
|
|
|
min={0}
|
|
|
|
|
max={32}
|
|
|
|
|
step={2}
|
|
|
|
|
value={[localSettings.gap]}
|
|
|
|
|
onValueChange={(value) => handleSettingChange("gap", value[0])}
|
|
|
|
|
className="flex-1"
|
|
|
|
|
/>
|
|
|
|
|
<Input
|
|
|
|
|
type="number"
|
|
|
|
|
min={0}
|
|
|
|
|
max={32}
|
|
|
|
|
value={localSettings.gap}
|
|
|
|
|
onChange={(e) => handleSettingChange("gap", parseInt(e.target.value) || 16)}
|
|
|
|
|
className="w-16 text-xs"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 여백 */}
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="padding" className="text-xs font-medium">
|
|
|
|
|
캔버스 여백 (px)
|
|
|
|
|
</Label>
|
|
|
|
|
<div className="flex items-center space-x-2">
|
|
|
|
|
<Slider
|
|
|
|
|
id="padding"
|
|
|
|
|
min={0}
|
|
|
|
|
max={48}
|
|
|
|
|
step={4}
|
|
|
|
|
value={[localSettings.padding]}
|
|
|
|
|
onValueChange={(value) => handleSettingChange("padding", value[0])}
|
|
|
|
|
className="flex-1"
|
|
|
|
|
/>
|
|
|
|
|
<Input
|
|
|
|
|
type="number"
|
|
|
|
|
min={0}
|
|
|
|
|
max={48}
|
|
|
|
|
value={localSettings.padding}
|
|
|
|
|
onChange={(e) => handleSettingChange("padding", parseInt(e.target.value) || 16)}
|
|
|
|
|
className="w-16 text-xs"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 격자 스냅 */}
|
|
|
|
|
<div className="flex items-center justify-between">
|
|
|
|
|
<Label htmlFor="snapToGrid" className="text-xs font-medium">
|
|
|
|
|
격자에 맞춤
|
|
|
|
|
</Label>
|
|
|
|
|
<Button
|
|
|
|
|
variant={localSettings.snapToGrid ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => handleSettingChange("snapToGrid", !localSettings.snapToGrid)}
|
|
|
|
|
className="h-6 px-2 text-xs"
|
|
|
|
|
>
|
|
|
|
|
{localSettings.snapToGrid ? "ON" : "OFF"}
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 격자 변경 안내 */}
|
2025-10-02 14:34:15 +09:00
|
|
|
<div className="rounded-md bg-accent p-2 text-xs text-blue-700">
|
2025-09-02 11:16:40 +09:00
|
|
|
<div className="font-medium">💡 격자 변경 시 자동 조정</div>
|
2025-10-02 14:34:15 +09:00
|
|
|
<div className="mt-1 text-primary">
|
2025-09-02 11:16:40 +09:00
|
|
|
격자 설정을 변경하면 기존 컴포넌트들이 새 격자에 맞춰 자동으로 위치와 크기가 조정됩니다.
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 격자 미리보기 */}
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label className="text-xs font-medium">격자 미리보기</Label>
|
|
|
|
|
<div className="rounded border bg-gray-50 p-2">
|
|
|
|
|
<div
|
|
|
|
|
className="grid h-16 gap-px"
|
|
|
|
|
style={{
|
|
|
|
|
gridTemplateColumns: `repeat(${localSettings.columns}, 1fr)`,
|
|
|
|
|
gap: `${Math.max(1, localSettings.gap / 4)}px`,
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{Array.from({ length: localSettings.columns }).map((_, i) => (
|
|
|
|
|
<div key={i} className="rounded-sm bg-blue-200" />
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 초기화 버튼 */}
|
|
|
|
|
<Button variant="outline" size="sm" onClick={resetToDefault} className="w-full text-xs">
|
|
|
|
|
<RotateCcw className="mr-1 h-3 w-3" />
|
|
|
|
|
기본값으로 초기화
|
|
|
|
|
</Button>
|
|
|
|
|
</CardContent>
|
|
|
|
|
</Card>
|
|
|
|
|
);
|
|
|
|
|
}
|