"use client"; /** * ImageProperties.tsx — 이미지 컴포넌트 설정 * * - section="data": 모달 내 ImageLayoutTabs (업로드 / 자르기 / 맞춤 / 캡션 / 표시 조건) * - section="style": 우측 패널 — 투명도, 모서리, 회전/반전, 캡션 스타일 */ import { useState } from "react"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button"; import { Slider } from "@/components/ui/slider"; import { ChevronRight, FlipHorizontal, FlipVertical } from "lucide-react"; import { useReportDesigner } from "@/contexts/ReportDesignerContext"; import type { ComponentConfig } from "@/types/report"; import { ImageLayoutTabs } from "../modals/ImageLayoutTabs"; interface Props { component: ComponentConfig; section?: "style" | "data"; } function StyleAccordion({ label, isOpen, onToggle, children, }: { label: string; isOpen: boolean; onToggle: () => void; children: React.ReactNode; }) { return (
{isOpen && (
{children}
)}
); } export function ImageProperties({ component, section }: Props) { const { updateComponent } = useReportDesigner(); const showStyle = !section || section === "style"; const showData = !section || section === "data"; const [openSections, setOpenSections] = useState>(new Set(["opacity"])); const toggleSection = (id: string) => { setOpenSections((prev) => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); }; const update = (updates: Partial) => { updateComponent(component.id, updates); }; return ( <> {showData && } {showStyle && (
{/* 투명도 & 모서리 */} toggleSection("opacity")}>
update({ imageOpacity: v })} min={0} max={1} step={0.01} />
update({ imageBorderRadius: v })} min={0} max={100} step={1} />
{[0, 4, 8, 16, 50, 100].map((v) => ( ))}
{/* 회전 & 반전 */} toggleSection("transform")}>
update({ imageRotation: v })} min={0} max={360} step={1} className="flex-1" /> update({ imageRotation: parseInt(e.target.value) || 0 })} className="h-7 w-14 text-center text-[10px]" min={0} max={360} />
{/* 캡션 스타일 (캡션 텍스트가 있을 때만) */} {component.imageCaption && ( toggleSection("caption")}>
update({ imageCaptionFontSize: parseInt(e.target.value) || 12 })} className="h-9 text-xs" min={8} max={32} />
update({ imageCaptionColor: e.target.value })} className="h-7 w-7 shrink-0 cursor-pointer rounded border-0 p-0" /> update({ imageCaptionColor: e.target.value })} className="h-7 border-0 bg-transparent px-1 font-mono text-xs shadow-none focus-visible:ring-0" />
)}
)} ); }