120 lines
5.0 KiB
TypeScript
120 lines
5.0 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { useBuilderState } from "../hooks/useBuilderState";
|
|
import type { Component, ButtonConfig, ButtonBarConfig } from "@/types/invyone-component";
|
|
|
|
const ACTION_OPTIONS: { value: string; label: string }[] = [
|
|
{ value: "save", label: "저장" },
|
|
{ value: "edit", label: "수정" },
|
|
{ value: "delete", label: "삭제" },
|
|
{ value: "add", label: "신규" },
|
|
{ value: "cancel", label: "취소" },
|
|
{ value: "close", label: "닫기" },
|
|
{ value: "navigate", label: "화면 이동" },
|
|
{ value: "popup", label: "팝업 열기" },
|
|
{ value: "search", label: "검색" },
|
|
{ value: "reset", label: "초기화" },
|
|
{ value: "submit", label: "제출" },
|
|
{ value: "approval", label: "승인" },
|
|
];
|
|
|
|
const VARIANT_OPTIONS: { value: string; label: string }[] = [
|
|
{ value: "primary", label: "강조 (파란색)" },
|
|
{ value: "default", label: "기본 (테두리)" },
|
|
{ value: "destructive", label: "위험 (빨간색)" },
|
|
{ value: "outline", label: "아웃라인" },
|
|
{ value: "ghost", label: "투명" },
|
|
];
|
|
|
|
export function SingleButtonProps({ block }: { block: Component }) {
|
|
const updateBlockConfig = useBuilderState((s) => s.updateBlockConfig);
|
|
const config = block.config as ButtonConfig;
|
|
|
|
const update = (key: string, val: any) => updateBlockConfig(block.id, { [key]: val });
|
|
|
|
return (
|
|
<>
|
|
<div className="dev-prop-sec">버튼 설정</div>
|
|
<div className="dev-prop-row">
|
|
<span className="dev-prop-label">텍스트</span>
|
|
<input className="dev-input" value={config.text}
|
|
onChange={(e) => update("text", e.target.value)} />
|
|
</div>
|
|
<div className="dev-prop-row inline">
|
|
<span className="dev-prop-label">액션</span>
|
|
<select className="dev-select" value={config.actionType}
|
|
onChange={(e) => update("actionType", e.target.value)}>
|
|
{ACTION_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
|
|
</select>
|
|
</div>
|
|
<div className="dev-prop-row inline">
|
|
<span className="dev-prop-label">스타일</span>
|
|
<select className="dev-select" value={config.variant}
|
|
onChange={(e) => update("variant", e.target.value)}>
|
|
{VARIANT_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
|
|
</select>
|
|
</div>
|
|
<div className="dev-prop-row">
|
|
<span className="dev-prop-label">확인 메시지</span>
|
|
<input className="dev-input" value={config.confirm || ""}
|
|
placeholder="비워두면 확인 없이 실행"
|
|
onChange={(e) => update("confirm", e.target.value || undefined)} />
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function ButtonBarProps({ block }: { block: Component }) {
|
|
const updateBlockConfig = useBuilderState((s) => s.updateBlockConfig);
|
|
const config = block.config as ButtonBarConfig;
|
|
|
|
const updateButton = (idx: number, key: string, val: any) => {
|
|
const buttons = [...config.buttons];
|
|
buttons[idx] = { ...buttons[idx], [key]: val };
|
|
updateBlockConfig(block.id, { buttons } as any);
|
|
};
|
|
|
|
const addButton = () => {
|
|
const buttons = [...config.buttons, { text: "버튼", actionType: "save" as const, variant: "default" as const }];
|
|
updateBlockConfig(block.id, { buttons } as any);
|
|
};
|
|
|
|
const removeButton = (idx: number) => {
|
|
const buttons = config.buttons.filter((_, i) => i !== idx);
|
|
updateBlockConfig(block.id, { buttons } as any);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<div className="dev-prop-sec">버튼 목록</div>
|
|
{config.buttons.map((btn, i) => (
|
|
<div key={i} style={{ padding: "0.15rem 0.6rem", borderBottom: "1px dashed var(--d-border)" }}>
|
|
<div style={{ display: "flex", alignItems: "center", gap: "0.2rem", marginBottom: "0.1rem" }}>
|
|
<input className="dev-input" style={{ flex: 1 }} value={btn.text}
|
|
onChange={(e) => updateButton(i, "text", e.target.value)} />
|
|
<button className="dev-delete-btn" style={{ width: "auto", padding: "0.15rem 0.3rem", fontSize: "0.4rem" }}
|
|
onClick={() => removeButton(i)}>✕</button>
|
|
</div>
|
|
<div style={{ display: "flex", gap: "0.2rem" }}>
|
|
<select className="dev-select" style={{ flex: 1, fontSize: "0.42rem" }} value={btn.actionType}
|
|
onChange={(e) => updateButton(i, "actionType", e.target.value)}>
|
|
{ACTION_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
|
|
</select>
|
|
<select className="dev-select" style={{ flex: 1, fontSize: "0.42rem" }} value={btn.variant}
|
|
onChange={(e) => updateButton(i, "variant", e.target.value)}>
|
|
{VARIANT_OPTIONS.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
))}
|
|
<div style={{ padding: "0.2rem 0.6rem" }}>
|
|
<button className="dev-btn" style={{ width: "100%", justifyContent: "center" }}
|
|
onClick={addButton}>
|
|
+ 버튼 추가
|
|
</button>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|