feat(project): 홈 화면 진행중/완료 프로젝트 구분, 완료 업무 취소선 유지

- 프로젝트 카드를 "진행중"/"완료" 두 섹션으로 분리(완료는 접기/펼치기)
- 완료된 업무도 미리보기 목록에서 숨기지 않고 취소선으로 계속 표시
- 사이드바 빠른 프로젝트 생성(+)에도 마감일 입력 추가 (홈 새 프로젝트 모달은 기존에 지원)
- 카드 편집/삭제 버튼이 완료 섹션 카드도 인식하도록 수정

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 08:55:50 +09:00
parent 78683a9ae4
commit a09ceee7a5
7 changed files with 125 additions and 102 deletions
+6 -2
View File
@@ -44,8 +44,6 @@
.pj-project-card.is-done { background: #f6f7f8; opacity: .62; }
.pj-project-card.is-done:hover { opacity: .85; }
.pj-project-card.is-done .pj-project-dot { background: #9aa5b1; }
/* 완료 숨기기 토글 */
.pj-project-grid.pj-hide-done .pj-project-card.is-done { display: none; }
/* 카드 수정 버튼 */
.pj-card-edit {
position: absolute; top: 8px; right: 8px; width: 28px; height: 28px;
@@ -80,6 +78,8 @@
}
.pj-project-task-due { font-size: 11px; color: #9aa1a9; flex: 0 0 auto; }
.pj-project-task-due.is-overdue { color: #c22b10; font-weight: 700; }
.pj-project-taskrow.is-done .pj-project-task-title { text-decoration: line-through; color: #9aa1a9; }
.pj-project-taskrow.is-done .pj-project-task-ic { color: #9aa5b1; }
.pj-project-more {
display: block; padding: 6px 16px 12px; font-size: 12px; font-weight: 600;
color: #6b7280; text-decoration: none;
@@ -87,6 +87,10 @@
.pj-project-more:hover { color: #1e1f21; text-decoration: underline; }
.pj-project-tasks-empty { padding: 4px 16px 14px; font-size: 12px; color: #b7bdc5; border-top: 1px solid #f0f1f3; margin-top: 2px; }
/* 완료 프로젝트 섹션 헤더 */
.pj-section-head-done { margin-top: 22px; }
.pj-section-head-done h2 { font-size: 14px; color: #6b7280; }
.pj-home-side { border-left: 1px solid #eef0f2; padding-left: 24px; }
@media (max-width: 980px) { .pj-home-side { border-left: none; padding-left: 0; } }
.pj-mytask-list { list-style: none; margin: 0; padding: 0; }
+10 -8
View File
@@ -71,18 +71,19 @@
return !!cb && cb === me;
}
// ── 완료 프로젝트 숨기기 토글 (localStorage 기억) ──
// ── 완료 프로젝트 섹션 접기/펼치기 (localStorage 기억) ──
const toggleBtn = el("pj-toggle-done");
if (toggleBtn) {
const doneGrid = el("pj-project-grid-done");
if (toggleBtn && doneGrid) {
const KEY = "pj_hide_done";
function apply(hide) {
if (grid) grid.classList.toggle("pj-hide-done", hide);
doneGrid.hidden = hide;
const n = toggleBtn.dataset.count;
toggleBtn.textContent = hide ? "완료 " + n + "개 보기" : "완료 " + n + "개 숨기기";
}
apply(localStorage.getItem(KEY) === "1");
toggleBtn.addEventListener("click", function () {
const hide = !(grid && grid.classList.contains("pj-hide-done"));
const hide = !doneGrid.hidden;
try { localStorage.setItem(KEY, hide ? "1" : "0"); } catch (_) {}
apply(hide);
});
@@ -111,12 +112,12 @@
});
}
// ── 프로젝트 수정 모달 ──
// ── 프로젝트 수정 모달 (진행중/완료 두 그리드 모두 대상) ──
const editModal = el("pj-modal-edit");
if (editModal && grid) {
wireModalClose(editModal);
let getEditColor = null;
grid.querySelectorAll(".pj-card-edit").forEach(function (btn) {
document.querySelectorAll(".pj-project-card .pj-card-edit").forEach(function (btn) {
btn.addEventListener("click", function (e) {
e.preventDefault(); e.stopPropagation();
const card = btn.closest(".pj-project-card");
@@ -148,7 +149,7 @@
});
el("pj-delete-project").addEventListener("click", async function () {
const id = el("pj-e-id").value;
const card = grid.querySelector('.pj-project-card[data-id="' + id + '"]');
const card = document.querySelector('.pj-project-card[data-id="' + id + '"]');
if (card && !canDelete(card.dataset.creator)) { alert("삭제는 만든 사람만 할 수 있습니다."); return; }
if (!confirm("이 프로젝트를 삭제할까요? 안의 업무도 모두 삭제됩니다.")) return;
try { await api("DELETE", "/project/api/projects/" + id); location.reload(); }
@@ -1098,8 +1099,9 @@
if (newProjSide) newProjSide.addEventListener("click", async function () {
const name = prompt("새 프로젝트 이름");
if (!name || !name.trim()) return;
const due = prompt("마감일 (YYYY-MM-DD, 없으면 취소 없이 비워두고 확인)") || "";
try {
await api("POST", "/project/api/projects", { name: name.trim() });
await api("POST", "/project/api/projects", { name: name.trim(), due_date: due.trim() || null });
location.reload();
} catch (e) { alert("생성 실패: " + e.message); }
});