import { CheckOutlined, DeleteOutlined, LeftOutlined, PlayCircleOutlined, PlusOutlined, RightOutlined, UnorderedListOutlined, } from '@ant-design/icons'; import { Button, Empty, Input, Tag, Typography } from 'antd'; import type { SyntheticEvent } from 'react'; import { InputUI } from '../../components/inputs/primitives/input'; import { SelectUI, type SelectOptionItem } from '../../components/inputs/select'; import type { LayoutPreviewBaseInputState, LayoutPreviewEmptyPaneState, LayoutPreviewMemoState, LayoutPreviewSelectState, } from './layoutPreviewRuntime'; const { Text } = Typography; function stopPreviewEvent(event: SyntheticEvent) { event.stopPropagation(); } function formatMemoTimestamp(value: string) { return new Intl.DateTimeFormat('ko-KR', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', }).format(new Date(value)); } function getMemoPreview(body: string) { return body.replace(/\s+/g, ' ').trim() || '새 메모'; } function formatEmptyPaneTimestamp(value: string | null) { if (!value) { return '아직 메모가 없습니다.'; } return new Intl.DateTimeFormat('ko-KR', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', }).format(new Date(value)); } const EMPTY_PANE_READINESS_META: Record< LayoutPreviewEmptyPaneState['readiness'], { label: string; tone: 'default' | 'processing' | 'success' } > = { unassigned: { label: '컴포넌트 대기', tone: 'default' }, drafting: { label: '요구 정리 중', tone: 'processing' }, ready: { label: '준비 완료', tone: 'success' }, }; export function LayoutPreviewTextMemoPane({ state, skin = 'note', title = '메모 본문', onStartDraft, onToggleList, onDeleteSelection, onSaveDraft, onSelectNote, onMoveSelection, onDraftChange, }: { state: LayoutPreviewMemoState; skin?: 'flat' | 'note'; title?: string; onStartDraft: () => void; onToggleList: () => void; onDeleteSelection: () => void; onSaveDraft: () => void; onSelectNote: (noteId: string) => void; onMoveSelection: (direction: -1 | 1) => void; onDraftChange: (nextValue: string) => void; }) { const selectedIndex = state.selectedId ? state.notes.findIndex((note) => note.id === state.selectedId) : -1; const selectedNote = selectedIndex >= 0 ? state.notes[selectedIndex] : null; const hasDraft = state.draftBody.trim().length > 0; const isFlat = skin === 'flat'; return (
{isFlat ? (
{title} {selectedNote ? '선택 항목 편집 중' : '새 항목 작성 가능'}
) : null}
{state.isLoading ? (
) : state.isListOpen ? (
{state.notes.length ? (
{state.notes.map((note) => ( ))}
) : (
)}
) : (
{selectedNote ? formatMemoTimestamp(selectedNote.updatedAt) : '새 메모'} {state.draftBody.length}/1200
{ onDraftChange(event.target.value); }} />
)}
); } export function LayoutPreviewBaseInputPane({ state, fillPane = false, placeholder = '입력 후 Enter 또는 blur', }: { state: LayoutPreviewBaseInputState; fillPane?: boolean; placeholder?: string; }) { return (
); } export function LayoutPreviewActionPane({ label = 'Codex 실행', description = '선택한 레이아웃과 기능설명 조합 기준으로 실행합니다.', onClick, }: { label?: string; description?: string; onClick?: () => void; }) { return (
전역 실행 {label} {description}
); } export function LayoutPreviewSelectPane({ state, data, onChange, }: { state: LayoutPreviewSelectState; data: SelectOptionItem[]; onChange: (nextCode?: string, item?: SelectOptionItem) => void; }) { const resolvedSelectedCode = state.selectedCode && data.some((item) => item.code === state.selectedCode) ? state.selectedCode : data[0]?.code; const formatComboLabel = (item: SelectOptionItem) => item.value; return (
); } export function LayoutPreviewEmptyPane({ paneLabel, paneDescription, sizeSummary, state, onReadinessChange, onNoteChange, }: { paneLabel: string; paneDescription: string; sizeSummary: string; state: LayoutPreviewEmptyPaneState; onReadinessChange: (nextValue: LayoutPreviewEmptyPaneState['readiness']) => void; onNoteChange: (nextValue: string) => void; }) { const readinessMeta = EMPTY_PANE_READINESS_META[state.readiness]; return (
{paneLabel} {paneDescription}
{readinessMeta.label}
배치 규칙 {sizeSummary}
최근 변경 {formatEmptyPaneTimestamp(state.updatedAt)}
{ onNoteChange(event.target.value); }} />
); }