ui: add per_line dedicated control in Builder detail panel (v0.8)

- 노드 설정에 '한 줄에 N개씩' 숫자 입력란 추가 (어트리뷰트 수동 입력 불필요)
- 캔버스 카드 footer에 ×N 배지로 per_line 값 표시
- setPerLine() 함수: 빈값/0이면 속성 자동 제거

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 17:17:50 +09:00
parent f64f8f3eb8
commit c215f28a2f

View File

@@ -279,7 +279,7 @@ input,textarea,button,select{font-family:inherit}
<header class="app-header">
<span style="font-size:18px">🏗️</span>
<h1>CTStruct</h1>
<span class="badge">v0.7</span>
<span class="badge">v0.8</span>
</header>
<nav class="main-nav">
@@ -808,6 +808,7 @@ function renderCanvas(){
const p=pos.get(node.id); if(!p) return;
const sel=node.id===selectedNodeId;
const col=node.settings?.attributes?.collect==='true';
const pl=node.settings?.attributes?.per_line;
const vals=node.values.filter(v=>v.type!=='node').length;
const kids=node.values.filter(v=>v.type==='node').length;
const hint=[vals?`${vals}`:'',kids?`하위 ${kids}`:''].filter(Boolean).join(' · ')||'비어있음';
@@ -819,6 +820,7 @@ function renderCanvas(){
</div>
<div class="cnode-foot">
<span class="cnode-vals">${hint}</span>
${pl?`<span style="font-size:9px;color:var(--muted);background:var(--surface-alt);border:1px solid var(--border);border-radius:3px;padding:1px 4px;flex-shrink:0">×${esc(pl)}</span>`:''}
<div class="cnode-btns">
<button class="cnode-btn" title="위로" onclick="event.stopPropagation();moveNode('${node.id}',-1)">↑</button>
<button class="cnode-btn" title="아래로" onclick="event.stopPropagation();moveNode('${node.id}',1)">↓</button>
@@ -950,9 +952,22 @@ function setCollect(nid, on){
refresh();
}
function setPerLine(nid, val){
const n=nodeMap[nid]; if(!n) return;
const v=parseInt(val);
if(!n.settings.attributes) n.settings.attributes={};
if(v>0) n.settings.attributes.per_line=String(v);
else {
delete n.settings.attributes.per_line;
if(!Object.keys(n.settings.attributes).length) delete n.settings.attributes;
}
renderCanvas(); updatePreview(); save();
}
function renderStructSettings(node){
const nid=node.id, nl=node.nameNewline??true;
const col=node.settings?.attributes?.collect==='true';
const pl=node.settings?.attributes?.per_line||'';
return `
<div class="struct-sep">
<div class="sep-bar-row">
@@ -965,6 +980,16 @@ function renderStructSettings(node){
<span class="sep-chip${!col?' on':''}" onclick="setCollect('${nid}',false)" title="값이 항상 고정 출력됩니다">🔒 고정</span>
<span class="sep-chip${col?' on':''}" onclick="setCollect('${nid}',true)" title="합치기 시 값이 수집됩니다">📥 수집</span>
</div>
<div class="sep-bar-row">
<span class="sep-bar-lbl">한 줄에</span>
<input type="number" min="1" max="99"
style="width:52px;font-size:12px;border:1px solid var(--border);border-radius:4px;padding:2px 5px;outline:none;background:var(--surface-alt);text-align:center"
value="${esc(pl)}" placeholder="∞"
oninput="setPerLine('${nid}',this.value)"
onfocus="this.style.borderColor='var(--border-focus)'"
onblur="this.style.borderColor='var(--border)'">
<span style="font-size:11px;color:var(--muted)">개씩</span>
</div>
</div>`;
}