Compare commits

...

2 Commits

Author SHA1 Message Date
e2caf9a0ba docs(board): 안내 문구에 모바일 상태 드롭다운 사용법 추가
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 16:04:45 +09:00
e7418e7c3c feat(board): 모바일에서 카드 상태 변경 드롭다운 추가(터치로 칸반 이동)
HTML5 드래그가 터치에서 동작 안 하는 문제 — 카드마다 상태 드롭다운을 두어
터치로도 컬럼 이동 가능. 데스크톱은 드래그 유지(드롭다운은 모바일/터치에서만 노출).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 16:03:10 +09:00

View File

@ -11,7 +11,7 @@
<div class="page-header">
<div>
<h1>칸반 보드</h1>
<p class="sub">카드를 드래그해 단계를 옮기세요. 수집 → 검토 → 작업대상 → 완료.</p>
<p class="sub">카드를 드래그(모바일은 카드의 상태 드롭다운)해 단계를 옮기세요. 수집 → 검토 → 작업대상 → 완료.</p>
</div>
<div class="actions">
<button class="btn btn-secondary" onclick="openHelp()"><i data-lucide="help-circle" style="width:15px;"></i> 사용법</button>
@ -65,6 +65,14 @@
.kb-card:hover { border-color: var(--accent); }
.kb-card.dragging { opacity:0.5; }
.kb-count { font-size:0.75rem; font-weight:600; background:var(--surface); border:1px solid var(--border); color:var(--text-2); padding:2px 9px; border-radius:999px; }
/* 모바일 터치용 상태 변경 드롭다운: 데스크톱에서는 숨기고 드래그 사용 */
.kb-status-sel { display:none; width:100%; margin-top:8px; padding:7px 8px; font-size:0.78rem; background:var(--surface-2); border:1px solid var(--border); border-radius:6px; color:var(--text); cursor:pointer; }
@media (hover: none), (max-width: 820px) {
.kb-status-sel { display:block; }
.kb-card { cursor:default; }
#board { grid-template-columns: repeat(5, minmax(260px, 80%)); -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity; }
#board .kb-col { scroll-snap-align: start; }
}
</style>
<script th:inline="javascript">
@ -104,6 +112,8 @@
v.viewsPerHour!=null ? '⚡ '+fmt(Math.round(v.viewsPerHour))+'/h' : '',
db ? '⏱ '+db : ''
].filter(Boolean).join('&nbsp;&nbsp;·&nbsp;&nbsp;');
const status = v.interestStatus || 'NEW';
const statusOpts = COLS.map(c => `<option value="${c.key}"${c.key===status?' selected':''}>${c.label}</option>`).join('');
return `<div class="kb-card" draggable="true" data-id="${v.id}">
<div style="display:flex; gap:8px;">
<img src="${esc(v.thumbnailUrl)}" title="미리보기" data-vid="${v.videoId}" data-title="${esc(v.title)}"
@ -121,6 +131,10 @@
<a href="/rework/${v.id}" title="재가공" class="text-muted hover:text-white"><i data-lucide="wand-2" style="width:14px;"></i></a>
</div>
</div>
<select class="kb-status-sel" title="상태 변경(모바일)" onpointerdown="event.stopPropagation()"
onclick="event.stopPropagation()" onchange="changeStatus('${v.id}', this.value, this)">
${statusOpts}
</select>
</div>`;
}
@ -196,6 +210,28 @@
});
}
// 드롭다운(모바일 터치)으로 상태 변경 — 드래그와 동일한 API 호출
async function changeStatus(id, newStatus, selEl){
const card = document.querySelector('.kb-card[data-id="'+id+'"]');
const targetBody = document.querySelector('.kb-body[data-status="'+newStatus+'"]');
if(!card || !targetBody) return;
const fromBody = card.parentElement;
if(fromBody === targetBody) return;
targetBody.appendChild(card); // optimistic move
updateCounts();
try {
await api(API + '/' + id + '/status', {
method:'POST', headers:{'Content-Type':'application/json'},
body: JSON.stringify({ status: newStatus })
});
if(window.lucide) lucide.createIcons();
} catch(err){
alert('상태 변경 실패: ' + err.message);
if(fromBody){ fromBody.appendChild(card); if(selEl) selEl.value = fromBody.dataset.status; }
updateCounts();
}
}
function openHelp(){ document.getElementById('helpModal').classList.add('open'); }
function closeHelp(){ document.getElementById('helpModal').classList.remove('open'); }