diff --git a/client/static/app.js b/client/static/app.js index 8235617..c3fe907 100644 --- a/client/static/app.js +++ b/client/static/app.js @@ -12,6 +12,8 @@ let items = []; let editMode = false; const selectedIds = new Set(); let progressTimer = null; +let selectedItemId = null; +let selectedDownloadUrl = null; function startProgress() { let value = 0; @@ -50,10 +52,13 @@ function finishProgress(success = true) { function setEditMode(isEdit) { editMode = isEdit; selectedIds.clear(); + selectedItemId = null; + selectedDownloadUrl = null; editBtn.classList.toggle("hidden", editMode); deleteBtn.classList.toggle("hidden", !editMode); cancelBtn.classList.toggle("hidden", !editMode); downloadLink.classList.add("hidden"); + downloadLink.href = "#"; renderList(); } @@ -62,6 +67,9 @@ function renderList() { items.forEach((item) => { const li = document.createElement("li"); li.className = "tts-item"; + if (!editMode && selectedItemId === item.id) { + li.classList.add("selected"); + } if (editMode) { const checkbox = document.createElement("input"); @@ -139,6 +147,15 @@ async function handleItemClick(item) { return; } + if (selectedItemId === item.id) { + selectedItemId = null; + selectedDownloadUrl = null; + downloadLink.href = "#"; + downloadLink.classList.add("hidden"); + renderList(); + return; + } + const res = await fetch(`/api/tts/${item.id}`); if (!res.ok) { alert("항목을 불러오지 못했습니다."); @@ -147,9 +164,11 @@ async function handleItemClick(item) { const data = await res.json(); textInput.value = data.text || ""; - downloadLink.href = data.download_url; + selectedItemId = item.id; + selectedDownloadUrl = data.download_url; + downloadLink.href = selectedDownloadUrl; downloadLink.classList.remove("hidden"); - downloadLink.click(); + renderList(); } async function handleDelete() { @@ -174,6 +193,8 @@ async function handleDelete() { const deletedSet = new Set(data.deleted || []); items = items.filter((item) => !deletedSet.has(item.id)); textInput.value = ""; + selectedItemId = null; + selectedDownloadUrl = null; downloadLink.href = "#"; downloadLink.classList.add("hidden"); setEditMode(false); @@ -183,5 +204,11 @@ saveBtn.addEventListener("click", handleSave); editBtn.addEventListener("click", () => setEditMode(true)); cancelBtn.addEventListener("click", () => setEditMode(false)); deleteBtn.addEventListener("click", handleDelete); +downloadLink.addEventListener("click", (event) => { + if (!selectedDownloadUrl) { + event.preventDefault(); + alert("다운로드할 항목을 선택하세요."); + } +}); loadList(); diff --git a/client/static/styles.css b/client/static/styles.css index da0ffe6..9b70272 100644 --- a/client/static/styles.css +++ b/client/static/styles.css @@ -101,6 +101,12 @@ button.danger { background: #f1f6f9; } +.tts-item.selected { + background: #f7f7f7; + border-left: 4px solid #e2e2e2; + padding-left: 2px; +} + .bullet { font-size: 18px; color: #555;