415 lines
26 KiB
PHP
415 lines
26 KiB
PHP
{{-- Block Properties Panel (우측 사이드바) --}}
|
|
<div class="block-properties bg-white border-l border-gray-200 overflow-y-auto shrink-0">
|
|
|
|
{{-- 미선택 상태 --}}
|
|
<div x-show="!getSelectedBlock()" class="flex flex-col items-center justify-center h-full text-gray-400 p-6">
|
|
<svg class="w-10 h-10 mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
|
|
</svg>
|
|
<p class="text-sm">블록을 선택하면</p>
|
|
<p class="text-sm">속성을 편집할 수 있습니다</p>
|
|
</div>
|
|
|
|
{{-- 선택된 블록 속성 편집 --}}
|
|
<div x-show="getSelectedBlock()" class="p-3">
|
|
<div class="flex items-center justify-between mb-3">
|
|
<h3 class="text-sm font-semibold text-gray-700">
|
|
<span x-text="blockTypes[getSelectedBlock()?.type]?.label || ''"></span> 속성
|
|
</h3>
|
|
<button @click="selectedBlockId = null" class="text-gray-400 hover:text-gray-600">
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
{{-- ===== Heading 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'heading'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">텍스트</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.text"
|
|
@input="updateBlockProp('text', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">레벨</label>
|
|
<select :value="getSelectedBlock()?.props.level"
|
|
@change="updateBlockProp('level', parseInt($event.target.value)); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
<option value="1">H1 — 가장 큰 제목</option>
|
|
<option value="2">H2 — 큰 제목</option>
|
|
<option value="3">H3 — 중간 제목</option>
|
|
<option value="4">H4 — 작은 제목</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">정렬</label>
|
|
<div class="flex border border-gray-200 rounded-md overflow-hidden">
|
|
<button @click="updateBlockProp('align', 'left'); pushHistory()"
|
|
:class="getSelectedBlock()?.props.align === 'left' ? 'bg-blue-50 text-blue-700' : 'text-gray-500 hover:bg-gray-50'"
|
|
class="flex-1 py-1.5 text-xs font-medium">왼쪽</button>
|
|
<button @click="updateBlockProp('align', 'center'); pushHistory()"
|
|
:class="getSelectedBlock()?.props.align === 'center' ? 'bg-blue-50 text-blue-700' : 'text-gray-500 hover:bg-gray-50'"
|
|
class="flex-1 py-1.5 text-xs font-medium border-l border-gray-200">가운데</button>
|
|
<button @click="updateBlockProp('align', 'right'); pushHistory()"
|
|
:class="getSelectedBlock()?.props.align === 'right' ? 'bg-blue-50 text-blue-700' : 'text-gray-500 hover:bg-gray-50'"
|
|
class="flex-1 py-1.5 text-xs font-medium border-l border-gray-200">오른쪽</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Paragraph 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'paragraph'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">텍스트</label>
|
|
<textarea :value="getSelectedBlock()?.props.text"
|
|
@input="updateBlockProp('text', $event.target.value); pushHistory()"
|
|
rows="4"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500 focus:border-blue-500"></textarea>
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">정렬</label>
|
|
<div class="flex border border-gray-200 rounded-md overflow-hidden">
|
|
<button @click="updateBlockProp('align', 'left'); pushHistory()"
|
|
:class="getSelectedBlock()?.props.align === 'left' ? 'bg-blue-50 text-blue-700' : 'text-gray-500 hover:bg-gray-50'"
|
|
class="flex-1 py-1.5 text-xs font-medium">왼쪽</button>
|
|
<button @click="updateBlockProp('align', 'center'); pushHistory()"
|
|
:class="getSelectedBlock()?.props.align === 'center' ? 'bg-blue-50 text-blue-700' : 'text-gray-500 hover:bg-gray-50'"
|
|
class="flex-1 py-1.5 text-xs font-medium border-l border-gray-200">가운데</button>
|
|
<button @click="updateBlockProp('align', 'right'); pushHistory()"
|
|
:class="getSelectedBlock()?.props.align === 'right' ? 'bg-blue-50 text-blue-700' : 'text-gray-500 hover:bg-gray-50'"
|
|
class="flex-1 py-1.5 text-xs font-medium border-l border-gray-200">오른쪽</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Table 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'table'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="flex items-center gap-2 text-xs font-medium text-gray-500">
|
|
<input type="checkbox" :checked="getSelectedBlock()?.props.showHeader !== false"
|
|
@change="updateBlockProp('showHeader', $event.target.checked); pushHistory()"
|
|
class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
|
|
헤더 표시
|
|
</label>
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">헤더</label>
|
|
<template x-for="(header, hIdx) in getSelectedBlock()?.props.headers" :key="'ph_' + hIdx">
|
|
<div class="flex items-center gap-1 mb-1">
|
|
<input type="text" :value="header"
|
|
@input="let b = getSelectedBlock(); b.props.headers[hIdx] = $event.target.value; markDirty()"
|
|
@change="pushHistory()"
|
|
class="prop-input flex-1 border border-gray-200 rounded px-2 py-1 focus:ring-1 focus:ring-blue-500">
|
|
<button @click="removeTableColumn(getSelectedBlock(), hIdx)"
|
|
class="text-gray-400 hover:text-red-500 shrink-0" title="열 삭제">
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
<button @click="addTableColumn(getSelectedBlock())"
|
|
class="text-xs text-blue-600 hover:text-blue-800 mt-1">+ 열 추가</button>
|
|
</div>
|
|
<div>
|
|
<div class="flex items-center justify-between mb-1">
|
|
<label class="text-xs font-medium text-gray-500">데이터 행</label>
|
|
<span class="text-xs text-gray-400" x-text="getSelectedBlock()?.props.rows?.length + '행'"></span>
|
|
</div>
|
|
<template x-for="(row, rIdx) in getSelectedBlock()?.props.rows" :key="'pr_' + rIdx">
|
|
<div class="flex items-center gap-1 mb-1">
|
|
<span class="text-[10px] text-gray-400 shrink-0 w-4" x-text="rIdx + 1"></span>
|
|
<template x-for="(cell, cIdx) in row" :key="'pc_' + rIdx + '_' + cIdx">
|
|
<input type="text" :value="cell"
|
|
@input="let b = getSelectedBlock(); b.props.rows[rIdx][cIdx] = $event.target.value; markDirty()"
|
|
@change="pushHistory()"
|
|
class="prop-input flex-1 border border-gray-200 rounded px-1.5 py-0.5 focus:ring-1 focus:ring-blue-500"
|
|
style="min-width: 0;">
|
|
</template>
|
|
<button @click="removeTableRow(getSelectedBlock(), rIdx)"
|
|
class="text-gray-400 hover:text-red-500 shrink-0">
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
<button @click="addTableRow(getSelectedBlock())"
|
|
class="text-xs text-blue-600 hover:text-blue-800 mt-1">+ 행 추가</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Columns 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'columns'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">단 수</label>
|
|
<select :value="getSelectedBlock()?.props.count"
|
|
@change="
|
|
let b = getSelectedBlock();
|
|
let newCount = parseInt($event.target.value);
|
|
let old = b.props.children || [];
|
|
while (old.length < newCount) old.push([]);
|
|
b.props.children = old.slice(0, newCount);
|
|
b.props.count = newCount;
|
|
pushHistory();
|
|
markDirty();
|
|
"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
<option value="2">2단</option>
|
|
<option value="3">3단</option>
|
|
<option value="4">4단</option>
|
|
</select>
|
|
</div>
|
|
<p class="text-xs text-gray-400">
|
|
Phase 2에서 열 내부에 블록을 추가하는 기능이 구현됩니다.
|
|
</p>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Divider 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'divider'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">스타일</label>
|
|
<select :value="getSelectedBlock()?.props.style"
|
|
@change="updateBlockProp('style', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
<option value="solid">실선</option>
|
|
<option value="dashed">점선</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Spacer 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'spacer'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">높이 (px)</label>
|
|
<input type="number" :value="getSelectedBlock()?.props.height"
|
|
@input="updateBlockProp('height', parseInt($event.target.value) || 20); pushHistory()"
|
|
min="5" max="200" step="5"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Text Field 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'text_field'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">라벨</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.label"
|
|
@input="updateBlockProp('label', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">플레이스홀더</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.placeholder"
|
|
@input="updateBlockProp('placeholder', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">데이터 바인딩</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.binding"
|
|
@input="updateBlockProp('binding', $event.target.value); pushHistory()"
|
|
placeholder="예: item.name, lot.number"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="flex items-center gap-2 text-xs font-medium text-gray-500">
|
|
<input type="checkbox" :checked="getSelectedBlock()?.props.required"
|
|
@change="updateBlockProp('required', $event.target.checked); pushHistory()"
|
|
class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
|
|
필수 입력
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Number Field 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'number_field'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">라벨</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.label"
|
|
@input="updateBlockProp('label', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">최소값</label>
|
|
<input type="number" :value="getSelectedBlock()?.props.min"
|
|
@input="updateBlockProp('min', $event.target.value ? Number($event.target.value) : null); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">최대값</label>
|
|
<input type="number" :value="getSelectedBlock()?.props.max"
|
|
@input="updateBlockProp('max', $event.target.value ? Number($event.target.value) : null); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">단위</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.unit"
|
|
@input="updateBlockProp('unit', $event.target.value); pushHistory()"
|
|
placeholder="mm, kg"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">소수점</label>
|
|
<input type="number" :value="getSelectedBlock()?.props.decimal"
|
|
@input="updateBlockProp('decimal', parseInt($event.target.value) || 0); pushHistory()"
|
|
min="0" max="6"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Date Field 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'date_field'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">라벨</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.label"
|
|
@input="updateBlockProp('label', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">바인딩</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.binding"
|
|
@input="updateBlockProp('binding', $event.target.value); pushHistory()"
|
|
placeholder="예: @{{today}}"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Select Field 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'select_field'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">라벨</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.label"
|
|
@input="updateBlockProp('label', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">옵션</label>
|
|
<template x-for="(opt, oi) in getSelectedBlock()?.props.options" :key="'so_' + oi">
|
|
<div class="flex items-center gap-1 mb-1">
|
|
<input type="text" :value="opt"
|
|
@input="let b = getSelectedBlock(); b.props.options[oi] = $event.target.value; markDirty()"
|
|
@change="pushHistory()"
|
|
class="prop-input flex-1 border border-gray-200 rounded px-2 py-1 focus:ring-1 focus:ring-blue-500">
|
|
<button @click="let b = getSelectedBlock(); b.props.options.splice(oi, 1); pushHistory(); markDirty()"
|
|
class="text-gray-400 hover:text-red-500 shrink-0">
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
<button @click="let b = getSelectedBlock(); b.props.options.push('새 옵션'); pushHistory(); markDirty()"
|
|
class="text-xs text-blue-600 hover:text-blue-800 mt-1">+ 옵션 추가</button>
|
|
</div>
|
|
<div>
|
|
<label class="flex items-center gap-2 text-xs font-medium text-gray-500">
|
|
<input type="checkbox" :checked="getSelectedBlock()?.props.multiple"
|
|
@change="updateBlockProp('multiple', $event.target.checked); pushHistory()"
|
|
class="rounded border-gray-300 text-blue-600 focus:ring-blue-500">
|
|
다중 선택
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Checkbox Field 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'checkbox_field'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">라벨</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.label"
|
|
@input="updateBlockProp('label', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">항목</label>
|
|
<template x-for="(opt, oi) in getSelectedBlock()?.props.options" :key="'co_' + oi">
|
|
<div class="flex items-center gap-1 mb-1">
|
|
<input type="text" :value="opt"
|
|
@input="let b = getSelectedBlock(); b.props.options[oi] = $event.target.value; markDirty()"
|
|
@change="pushHistory()"
|
|
class="prop-input flex-1 border border-gray-200 rounded px-2 py-1 focus:ring-1 focus:ring-blue-500">
|
|
<button @click="let b = getSelectedBlock(); b.props.options.splice(oi, 1); pushHistory(); markDirty()"
|
|
class="text-gray-400 hover:text-red-500 shrink-0">
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
<button @click="let b = getSelectedBlock(); b.props.options.push('새 항목'); pushHistory(); markDirty()"
|
|
class="text-xs text-blue-600 hover:text-blue-800 mt-1">+ 항목 추가</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Textarea Field 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'textarea_field'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">라벨</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.label"
|
|
@input="updateBlockProp('label', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">행 수</label>
|
|
<input type="number" :value="getSelectedBlock()?.props.rows"
|
|
@input="updateBlockProp('rows', parseInt($event.target.value) || 3); pushHistory()"
|
|
min="1" max="20"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== Signature Field 속성 ===== --}}
|
|
<template x-if="getSelectedBlock()?.type === 'signature_field'">
|
|
<div class="space-y-3">
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">라벨</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.label"
|
|
@input="updateBlockProp('label', $event.target.value); pushHistory()"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">서명자</label>
|
|
<input type="text" :value="getSelectedBlock()?.props.signer"
|
|
@input="updateBlockProp('signer', $event.target.value); pushHistory()"
|
|
placeholder="예: inspector, manager"
|
|
class="prop-input w-full border border-gray-200 rounded-md px-2 py-1.5 focus:ring-1 focus:ring-blue-500">
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- ===== 공통: 블록 ID (디버그) ===== --}}
|
|
<div class="mt-6 pt-3 border-t border-gray-100">
|
|
<div class="text-[10px] text-gray-300">
|
|
ID: <span x-text="getSelectedBlock()?.id"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|