diff --git a/app/modules/project/templates/project/inbox.html b/app/modules/project/templates/project/inbox.html index 50496e6..ef446ac 100644 --- a/app/modules/project/templates/project/inbox.html +++ b/app/modules/project/templates/project/inbox.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + {% endblock %} @@ -45,5 +45,5 @@ {% endif %} - + {% endblock %} diff --git a/app/modules/project/templates/project/index.html b/app/modules/project/templates/project/index.html index e81f37a..24aae5b 100644 --- a/app/modules/project/templates/project/index.html +++ b/app/modules/project/templates/project/index.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + {% endblock %} @@ -376,5 +376,5 @@ - + {% endblock %} diff --git a/app/modules/project/templates/project/project.html b/app/modules/project/templates/project/project.html index ceec7dd..4aa2966 100644 --- a/app/modules/project/templates/project/project.html +++ b/app/modules/project/templates/project/project.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + @@ -138,8 +138,13 @@ - +
+
+ +
@@ -374,5 +379,5 @@ - + {% endblock %} diff --git a/app/static/project.css b/app/static/project.css index ed656a8..a80a31b 100644 --- a/app/static/project.css +++ b/app/static/project.css @@ -44,7 +44,7 @@ .pj-chip-sm { padding: 1px 6px; font-size: 10px; } /* ── 홈 ── */ -.pj-home { display: grid; grid-template-columns: 1fr 320px; gap: 28px; align-items: start; } +.pj-home { display: grid; grid-template-columns: 1fr 300px; gap: 28px; align-items: start; } @media (max-width: 980px) { .pj-home { grid-template-columns: 1fr; } } .pj-project-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; align-items: start; } @@ -116,7 +116,7 @@ .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; } +.pj-home-side { width: 300px; 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; } .pj-mytask a { display: flex; align-items: center; gap: 8px; padding: 9px 6px; border-radius: 8px; text-decoration: none; color: inherit; } @@ -130,9 +130,9 @@ 가운데 칸에 min-width:0 이 없으면 보드에 세션이 많이 늘어날 때 grid 트랙 자체가 넓어져 페이지 전체가 가로 스크롤된다(overflow-x:auto 는 .pj-board 안에서만 작동해야 한다) — 반드시 필요한 규칙. */ -.pj-layout { display: grid; grid-template-columns: 230px 1fr 260px; gap: 22px; align-items: start; } +.pj-layout { display: grid; grid-template-columns: 230px 1fr 300px; gap: 22px; align-items: start; } .pj-main { min-width: 0; } -.pj-project-mytasks { min-width: 0; } +.pj-project-mytasks { min-width: 0; width: 300px; } @media (max-width: 1280px) { .pj-layout { grid-template-columns: 230px 1fr; } .pj-project-mytasks { display: none; } @@ -191,11 +191,21 @@ transform-origin: top center; } -/* ── 보드(칸반) ── */ -.pj-board { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 8px; align-items: flex-start; } +/* ── 보드(칸반) — 4열 x 2행 그리드. 세션이 8개를 넘으면 이 영역 안에서만 + 세로 스크롤되고, "+ 세션 추가" 버튼은 이 영역 밖(pj-board-toolbar)에 + 있어 스크롤과 무관하게 항상 보인다. ── */ +.pj-board-toolbar { display: flex; justify-content: flex-end; margin-bottom: 10px; } +.pj-board-toolbar .pj-add-stage { width: auto; padding: 8px 18px; } +.pj-board { + display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: min-content; + gap: 16px; align-content: start; max-height: 74vh; overflow-y: auto; padding-right: 4px; padding-bottom: 8px; +} +@media (max-width: 1400px) { .pj-board { grid-template-columns: repeat(3, minmax(0, 1fr)); } } +@media (max-width: 1100px) { .pj-board { grid-template-columns: repeat(2, minmax(0, 1fr)); } } +@media (max-width: 700px) { .pj-board { grid-template-columns: 1fr; } } /* 세션(보드 컬럼) — 배경이 페이지와 거의 같으면 구분이 안 되므로(#f6f5fb ≈ 흰 배경) 뚜렷한 회색 톤 + 테두리로 아사나처럼 컬럼 경계를 분명히 준다. */ -.pj-col { flex: 0 0 280px; background: #eef0f4; border: 1px solid #e2e4ea; border-radius: 14px; padding: 12px; } +.pj-col { background: #eef0f4; border: 1px solid #e2e4ea; border-radius: 14px; padding: 12px; min-width: 0; } .pj-col-head { display: flex; align-items: center; gap: 6px; font-weight: 700; font-size: 13px; padding: 2px 6px 12px; margin-bottom: 4px; color: var(--pj-ink); @@ -476,7 +486,6 @@ .pj-col:hover .pj-col-ctrls { display: inline-flex; } .pj-col-ctrls .pj-icon-btn { width: 20px; height: 20px; font-size: 13px; } .pj-icon-btn[disabled] { opacity: .3; cursor: default; } -.pj-col-add { background: transparent; flex: 0 0 180px; } .pj-add-stage { width: 100%; padding: 10px; border: 1px dashed #c9cdd3; border-radius: 12px; background: #fff; color: #6b7280; font-size: 13px; font-weight: 600; cursor: pointer; } .pj-add-stage:hover { border-color: #1e1f21; color: #1e1f21; } diff --git a/app/static/project.js b/app/static/project.js index f45147e..6f9168c 100644 --- a/app/static/project.js +++ b/app/static/project.js @@ -1085,10 +1085,27 @@ // 완료토글·삭제·추가·드래그 재정렬). // scope==="all" → 여러 프로젝트를 세션 '이름' 기준으로 합쳐 보여준다(기존 // 동작 그대로 — 세션 하나를 특정할 수 없어 관리 컨트롤은 없다). + // "+ 세션 추가" 버튼은 보드(스크롤 영역) 밖 고정 위치에 있어 세션이 + // 늘어나 스크롤이 생겨도 항상 보인다 — 한 번만 wiring, 표시 여부만 매 + // 렌더마다 토글. + const boardAddStageBtn = el("pj-board-addstage"); + if (boardAddStageBtn) { + boardAddStageBtn.addEventListener("click", async function () { + const name = prompt("새 세션 이름"); + if (!name || !name.trim()) return; + try { + await api("POST", "/project/api/projects/" + projectId + "/stages", { name: name.trim() }); + await reloadStagesForCurrentProject(); + renderBoard(); + } catch (e) { alert("추가 실패: " + e.message); } + }); + } + function renderBoard() { const board = el("pj-board"); board.innerHTML = ""; const vis = visibleTasks(); + if (boardAddStageBtn) boardAddStageBtn.hidden = !(viewScope === "project" && canManage); if (viewScope === "project") renderBoardByStage(board, vis); else renderBoardByName(board, vis); } @@ -1153,8 +1170,8 @@ if (!list.length && !vis.length) { const empty = document.createElement("div"); empty.className = "pj-empty"; - empty.style.flex = "1 1 auto"; - empty.textContent = "세션이 없습니다. 아래 \"+ 세션 추가\"로 만들어 보세요."; + empty.style.gridColumn = "1 / -1"; + empty.textContent = "세션이 없습니다. 위 \"+ 세션 추가\"로 만들어 보세요."; board.appendChild(empty); } list.forEach(function (s) { @@ -1202,21 +1219,6 @@ board.appendChild(col); } - if (canManage) { - const addCol = document.createElement("div"); - addCol.className = "pj-col pj-col-add"; - addCol.innerHTML = ''; - addCol.querySelector(".pj-add-stage").addEventListener("click", async function () { - const name = prompt("새 세션 이름"); - if (!name || !name.trim()) return; - try { - await api("POST", "/project/api/projects/" + projectId + "/stages", { name: name.trim() }); - await reloadStagesForCurrentProject(); - renderBoard(); - } catch (e) { alert("추가 실패: " + e.message); } - }); - board.appendChild(addCol); - } } async function reloadStagesForCurrentProject() {