138 lines
5.1 KiB
TypeScript
138 lines
5.1 KiB
TypeScript
"use client";
|
|
|
|
import type { DividerBlockProps } from "@/features/editor/state/editorStore";
|
|
import { NumericPropertyControl } from "@/features/editor/components/NumericPropertyControl";
|
|
import { ColorPickerField, TEXT_COLOR_PALETTE } from "@/features/editor/components/ColorPickerField";
|
|
|
|
export type DividerPropertiesPanelProps = {
|
|
dividerProps: DividerBlockProps;
|
|
selectedBlockId: string;
|
|
updateBlock: (id: string, partial: Partial<DividerBlockProps>) => void;
|
|
};
|
|
|
|
export function DividerPropertiesPanel({ dividerProps, selectedBlockId, updateBlock }: DividerPropertiesPanelProps) {
|
|
return (
|
|
<>
|
|
<div className="space-y-1">
|
|
<label className="flex flex-col gap-1 text-xs text-slate-400">
|
|
<span>정렬</span>
|
|
<select
|
|
className="rounded border border-slate-700 bg-slate-900 px-2 py-1 text-xs outline-none focus:border-sky-500"
|
|
aria-label="구분선 정렬"
|
|
value={dividerProps.align}
|
|
onChange={(e) => {
|
|
const value = e.target.value as DividerBlockProps["align"];
|
|
updateBlock(selectedBlockId, { align: value } as any);
|
|
}}
|
|
>
|
|
<option value="left">왼쪽</option>
|
|
<option value="center">가운데</option>
|
|
<option value="right">오른쪽</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<div className="space-y-1">
|
|
<label className="flex flex-col gap-1 text-xs text-slate-400">
|
|
<span>두께</span>
|
|
<select
|
|
className="rounded border border-slate-700 bg-slate-900 px-2 py-1 text-xs outline-none focus:border-sky-500"
|
|
aria-label="구분선 두께"
|
|
value={dividerProps.thickness}
|
|
onChange={(e) => {
|
|
const value = e.target.value as DividerBlockProps["thickness"];
|
|
updateBlock(selectedBlockId, { thickness: value } as any);
|
|
}}
|
|
>
|
|
<option value="thin">얇게</option>
|
|
<option value="medium">보통</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
|
|
<div className="mt-3 space-y-2 border-t border-slate-800 pt-3 text-xs text-slate-400">
|
|
<h4 className="text-[11px] font-semibold text-slate-200">구분선 스타일</h4>
|
|
|
|
{/* 길이/너비 모드 */}
|
|
<label className="flex flex-col gap-1">
|
|
<span>길이 모드</span>
|
|
<select
|
|
className="rounded border border-slate-700 bg-slate-900 px-2 py-1 text-xs outline-none focus:border-sky-500"
|
|
aria-label="구분선 길이 모드"
|
|
value={dividerProps.widthMode ?? "full"}
|
|
onChange={(e) => {
|
|
const value = e.target.value as NonNullable<DividerBlockProps["widthMode"]>;
|
|
updateBlock(selectedBlockId, { widthMode: value } as any);
|
|
}}
|
|
>
|
|
<option value="auto">내용에 맞춤</option>
|
|
<option value="full">전체 폭</option>
|
|
<option value="fixed">고정 길이 (px)</option>
|
|
</select>
|
|
</label>
|
|
|
|
{(dividerProps.widthMode ?? "full") === "fixed" && (
|
|
<NumericPropertyControl
|
|
label="고정 길이 (px)"
|
|
unitLabel="(px)"
|
|
value={dividerProps.widthPx ?? 320}
|
|
min={40}
|
|
max={1200}
|
|
step={10}
|
|
presets={[
|
|
{ id: "sm", label: "짧게", value: 240 },
|
|
{ id: "md", label: "보통", value: 320 },
|
|
{ id: "lg", label: "길게", value: 480 },
|
|
]}
|
|
onChangeValue={(v) => {
|
|
updateBlock(selectedBlockId, { widthPx: v } as any);
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{/* 색상 */}
|
|
<ColorPickerField
|
|
label="선 색상"
|
|
ariaLabelColorInput="구분선 색상 피커"
|
|
ariaLabelHexInput="구분선 색상 HEX"
|
|
value={
|
|
dividerProps.colorHex && dividerProps.colorHex.trim() !== ""
|
|
? dividerProps.colorHex
|
|
: TEXT_COLOR_PALETTE[0]?.color ?? "#64748b"
|
|
}
|
|
onChange={(hex) => {
|
|
updateBlock(selectedBlockId, { colorHex: hex } as any);
|
|
}}
|
|
palette={TEXT_COLOR_PALETTE}
|
|
onPaletteSelect={(item) => {
|
|
updateBlock(selectedBlockId, { colorHex: item.color } as any);
|
|
}}
|
|
/>
|
|
|
|
{/* 상하 여백 (슬라이더) */}
|
|
<NumericPropertyControl
|
|
label="위/아래 여백"
|
|
unitLabel="(px)"
|
|
value={(() => {
|
|
if (typeof dividerProps.marginYPx === "number") {
|
|
return dividerProps.marginYPx;
|
|
}
|
|
const y = dividerProps.marginY ?? "md";
|
|
return y === "sm" ? 8 : y === "lg" ? 24 : 16;
|
|
})()}
|
|
min={0}
|
|
max={50}
|
|
step={2}
|
|
presets={[
|
|
{ id: "sm", label: "작게", value: 8 },
|
|
{ id: "md", label: "보통", value: 16 },
|
|
{ id: "lg", label: "크게", value: 24 },
|
|
]}
|
|
onChangeValue={(v) => {
|
|
updateBlock(selectedBlockId, { marginYPx: v } as any);
|
|
}}
|
|
/>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|