feat(project): 홈 카드에 세션 추가, 새 업무 팝업 480x700 고정
- 홈 프로젝트 카드 hover 액션에 "세션 추가" 아이콘 추가(기존 세션 추가
모달을 그대로 재사용, 카드별 projectId 를 들고 다녀 대상 지정)
- "새 업무" 작성 팝업(하위업무/첨부/연결/댓글 칸이 다 숨어 홑겹인 상태)만
480x700 고정 크기로("업무 편집"은 기존 800x1100 그대로), 홈/프로젝트
화면 공용 setTaskModalCompact() 로 토글
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -517,6 +517,15 @@
|
||||
.pj-modal-col-main, .pj-modal-col-side { overflow: visible; height: auto; padding-right: 0; }
|
||||
.pj-modal-col-side .pj-task-extra:first-child { border-top: 1px solid #eef0f2; margin-top: 14px; padding-top: 12px; }
|
||||
}
|
||||
/* "새 업무" 작성 — 하위업무/첨부/연결/댓글 칸이 전부 숨는 홑겹 폼이라
|
||||
800x1100 대신 작게 고정(뷰포트 너비와 무관하게 항상 이 크기). */
|
||||
.pj-task-modal-card.pj-modal-compact {
|
||||
width: 480px; max-width: 96vw; height: 700px; max-height: 90vh;
|
||||
display: block; overflow-y: auto;
|
||||
}
|
||||
.pj-task-modal-card.pj-modal-compact .pj-modal-body { display: block; height: auto; }
|
||||
.pj-task-modal-card.pj-modal-compact .pj-modal-col-main,
|
||||
.pj-task-modal-card.pj-modal-compact .pj-modal-col-side { overflow: visible; height: auto; padding-right: 0; }
|
||||
.pj-modal-card h3 { margin: 0 0 16px; font-size: 17px; }
|
||||
.pj-modal-hint { margin: -6px 0 14px; font-size: 12px; color: #6b7280; }
|
||||
|
||||
|
||||
+51
-2
@@ -157,6 +157,14 @@
|
||||
return "rgba(" + r + "," + g + "," + b + "," + alpha + ")";
|
||||
}
|
||||
|
||||
// 업무 모달(#pj-modal-task) 크기 — 기존 업무 편집은 하위업무/첨부/연결/
|
||||
// 댓글까지 보여야 해서 800x1100 고정, "새 업무" 작성은 그 칸들이 전부
|
||||
// 숨는 홑겹 폼이라 480x700 로 작게(홈 카드·프로젝트 화면 양쪽에서 공용).
|
||||
function setTaskModalCompact(compact) {
|
||||
const card = document.querySelector("#pj-modal-task .pj-task-modal-card");
|
||||
if (card) card.classList.toggle("pj-modal-compact", !!compact);
|
||||
}
|
||||
|
||||
// 멤버 선택 후보 카드(아이콘 위 / 이름 가운데 / 체크박스 아래) — 새 프로젝트
|
||||
// 모달(홈·프로젝트 페이지)과 멤버 배정 모달 3곳이 전부 이 함수 하나를 쓴다.
|
||||
// /api/assignable-users 응답의 avatar 필드를 그대로 쓰므로 페이지별
|
||||
@@ -566,6 +574,8 @@
|
||||
(p.due_date ? '<span class="pj-chip">마감 ' + fmtDateKr(p.due_date) + "</span>" : "") +
|
||||
"</div></div></a>" +
|
||||
'<div class="pj-card-actions">' +
|
||||
'<button type="button" class="pj-icon-btn pj-card-addstage" title="세션 추가">' +
|
||||
'<span class="material-symbols-outlined">view_column</span></button>' +
|
||||
'<button type="button" class="pj-icon-btn pj-card-addtask" data-project-id="' + p.id + '" title="업무 추가">' +
|
||||
'<span class="material-symbols-outlined">add_task</span></button>' +
|
||||
'<button type="button" class="pj-icon-btn pj-card-edit" title="프로젝트 수정">' +
|
||||
@@ -575,8 +585,38 @@
|
||||
wrap.innerHTML = html;
|
||||
return wrap.firstElementChild;
|
||||
}
|
||||
// 카드 하나에 수정/업무추가/우클릭 메뉴를 건다 — 최초 로드된 카드·새로
|
||||
// 만든 카드 모두 이 함수 하나로 통일(initHome 맨 끝에서 전체 카드에 호출).
|
||||
// ── 세션 추가(홈 카드 hover 아이콘) — 프로젝트 화면 보드의 "+ 세션 추가"와
|
||||
// 같은 폼(이름+색상)을 그대로 재사용. 홈에는 "현재 프로젝트" 개념이
|
||||
// 없으므로 어느 카드에서 눌렀는지 projectId 를 직접 들고 다닌다.
|
||||
const stageModal = el("pj-modal-stage");
|
||||
let getStageColor = null;
|
||||
let stageModalProjectId = null;
|
||||
if (stageModal) wireModalClose(stageModal);
|
||||
function openStageModalForProject(projectId, projectName) {
|
||||
if (!stageModal) return;
|
||||
stageModalProjectId = projectId;
|
||||
el("pj-stage-modal-title").textContent = (projectName ? "\"" + projectName + "\" " : "") + "세션 추가";
|
||||
el("pj-stg-id").value = "";
|
||||
el("pj-stg-name").value = "";
|
||||
getStageColor = renderColorPalette(el("pj-stg-colors"), null, null, window.PJ_STAGE_COLORS);
|
||||
openModal(stageModal);
|
||||
}
|
||||
const saveStageBtn = el("pj-save-stage");
|
||||
if (saveStageBtn) saveStageBtn.addEventListener("click", async function () {
|
||||
const name = el("pj-stg-name").value.trim();
|
||||
if (!name) { alert("세션 이름을 입력하세요."); return; }
|
||||
if (!stageModalProjectId) return;
|
||||
const color = getStageColor ? getStageColor() : null;
|
||||
try {
|
||||
await api("POST", "/project/api/projects/" + stageModalProjectId + "/stages", { name: name, color: color });
|
||||
closeModal(stageModal);
|
||||
showToast("세션이 추가되었습니다.", "success");
|
||||
} catch (e) { showToast("추가 실패: " + e.message, "error"); }
|
||||
});
|
||||
|
||||
// 카드 하나에 수정/업무추가/세션추가/우클릭 메뉴를 건다 — 최초 로드된
|
||||
// 카드·새로 만든 카드 모두 이 함수 하나로 통일(initHome 맨 끝에서 전체
|
||||
// 카드에 호출).
|
||||
function wireProjectCard(card) {
|
||||
if (isAdmin) {
|
||||
card.draggable = true;
|
||||
@@ -595,12 +635,18 @@
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
if (openNewTaskModalRef) openNewTaskModalRef(card.dataset.id, card.dataset.name);
|
||||
});
|
||||
const addStageBtn = card.querySelector(".pj-card-addstage");
|
||||
if (addStageBtn) addStageBtn.addEventListener("click", function (e) {
|
||||
e.preventDefault(); e.stopPropagation();
|
||||
openStageModalForProject(card.dataset.id, card.dataset.name);
|
||||
});
|
||||
card.addEventListener("contextmenu", function (e) {
|
||||
if (!card.querySelector(".pj-card-edit")) return; // 관리 권한 없는 카드는 메뉴 없음
|
||||
e.preventDefault();
|
||||
showContextMenu(e.clientX, e.clientY, [
|
||||
{ label: "열기", onClick: function () { location.href = "/project/p/" + card.dataset.id; } },
|
||||
{ label: "업무 추가", onClick: function () { if (openNewTaskModalRef) openNewTaskModalRef(card.dataset.id, card.dataset.name); } },
|
||||
{ label: "세션 추가", onClick: function () { openStageModalForProject(card.dataset.id, card.dataset.name); } },
|
||||
{ label: "수정", onClick: function () { openCardEditModal(card); } },
|
||||
null,
|
||||
{ label: "삭제", danger: true, onClick: function () { deleteProjectCard(card); } },
|
||||
@@ -1085,6 +1131,7 @@
|
||||
});
|
||||
|
||||
async function openHomeTaskModal(task) {
|
||||
setTaskModalCompact(false);
|
||||
el("pj-task-modal-title").textContent = "[" + (task.project_name || "") + "]의 업무 편집";
|
||||
el("pj-t-id").value = task.id;
|
||||
el("pj-t-project-id").value = task.project_id;
|
||||
@@ -1122,6 +1169,7 @@
|
||||
|
||||
// 카드 이름 옆 "업무 추가" 버튼 — 같은 모달을 새 업무 작성용으로 초기화해 연다.
|
||||
async function openHomeNewTaskModal(projectId, projectName) {
|
||||
setTaskModalCompact(true);
|
||||
el("pj-task-modal-title").textContent = "[" + (projectName || "") + "]의 새 업무";
|
||||
el("pj-t-id").value = "";
|
||||
el("pj-t-project-id").value = projectId;
|
||||
@@ -2920,6 +2968,7 @@
|
||||
}
|
||||
|
||||
function openTaskModal(task, presetStageId) {
|
||||
setTaskModalCompact(!task);
|
||||
const projName = task ? (task.project_name || currentProject.name || "") : (currentProject.name || "");
|
||||
el("pj-task-modal-title").textContent = "[" + projName + "]의 " + (task ? "업무 편집" : "새 업무");
|
||||
el("pj-t-id").value = task ? task.id : "";
|
||||
|
||||
Reference in New Issue
Block a user