feat(project): 좌측 프로젝트 트리도 완료 프로젝트 별도 섹션으로 분류
홈 카드와 같은 원칙 — "프로젝트" 목록 아래 "완료 프로젝트" 섹션을 따로 둔다. 서버 렌더(project.html, rejectattr/selectattr로 분리)와 클라이언트 재렌더(project.js renderTree) 둘 다 반영. 완료 섹션이 처음엔 없어도 (완료 프로젝트가 하나도 없던 상태로 열었을 때) 완료로 바뀌는 순간 JS가 동적으로 섹션을 만들고, 마지막 하나가 해제/삭제되면 다시 치운다. 드래그 재정렬은 각 섹션 안에서만(홈 카드와 동일). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260918c" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260918d" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script src="/static/project.js?v=20260918c" defer></script>
|
||||
<script src="/static/project.js?v=20260918d" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260918c" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260918d" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -428,5 +428,5 @@
|
||||
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
||||
window.PJ_STAGE_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772","#e8398a","#a15c43"] | tojson }};
|
||||
</script>
|
||||
<script src="/static/project.js?v=20260918c" defer></script>
|
||||
<script src="/static/project.js?v=20260918d" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260918c" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260918d" />
|
||||
<!-- 구글 머티리얼 심볼(담당자 아이콘 등) — self-host -->
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
<!-- 타임라인 vis-timeline — self-host -->
|
||||
@@ -36,9 +36,7 @@
|
||||
<button type="button" class="pj-icon-btn" id="pj-new-project-side" title="새 프로젝트">+</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if nav_projects %}
|
||||
<ul class="pj-tree" id="pj-tree-root">
|
||||
{% for p in nav_projects %}
|
||||
{% macro nav_li(p) %}
|
||||
<li class="pj-tree-li" data-id="{{ p.id }}"
|
||||
data-name="{{ p.name }}" data-desc="{{ p.description or '' }}"
|
||||
data-start="{{ p.start_date or '' }}" data-due="{{ p.due_date or '' }}"
|
||||
@@ -57,11 +55,22 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endmacro %}
|
||||
{% set nav_active = nav_projects | rejectattr("status", "equalto", "completed") | list %}
|
||||
{% set nav_done = nav_projects | selectattr("status", "equalto", "completed") | list %}
|
||||
{% if nav_active %}
|
||||
<ul class="pj-tree" id="pj-tree-root">
|
||||
{% for p in nav_active %}{{ nav_li(p) }}{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<div class="pj-empty-sm">프로젝트 없음</div>
|
||||
{% endif %}
|
||||
{% if nav_done %}
|
||||
<div class="pj-side-head pj-side-head-done"><span>완료 프로젝트</span></div>
|
||||
<ul class="pj-tree" id="pj-tree-root-done">
|
||||
{% for p in nav_done %}{{ nav_li(p) }}{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="pj-side-block">
|
||||
@@ -544,5 +553,5 @@
|
||||
</script>
|
||||
|
||||
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
||||
<script src="/static/project.js?v=20260918c" defer></script>
|
||||
<script src="/static/project.js?v=20260918d" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -216,6 +216,9 @@
|
||||
|
||||
.pj-side-block { margin-bottom: 22px; }
|
||||
.pj-side-head { display: flex; align-items: center; justify-content: space-between; font-size: 14px; font-weight: 800; color: #6b7280; text-transform: uppercase; letter-spacing: .04em; margin-bottom: 8px; }
|
||||
.pj-side-head-done { margin-top: 14px; }
|
||||
#pj-tree-root-done .pj-tree-avatar,
|
||||
#pj-tree-root-done .pj-tree-name { opacity: .6; }
|
||||
/* 굵게 지정해도 연한 회색 + 12px 라서 눈에 잘 안 띄었음 — 텍스트만 진한
|
||||
잉크색으로 대비를 올린다("+" 버튼은 원래 색 유지). */
|
||||
.pj-side-head span { color: var(--pj-ink); }
|
||||
|
||||
+29
-1
@@ -3338,8 +3338,35 @@
|
||||
function renderTree() {
|
||||
const rootUl = el("pj-tree-root");
|
||||
if (!rootUl) return;
|
||||
rootUl.innerHTML = projectsMeta.map(treeProjLi).join("");
|
||||
const active = projectsMeta.filter(function (p) { return p.status !== "completed"; });
|
||||
const done = projectsMeta.filter(function (p) { return p.status === "completed"; });
|
||||
rootUl.innerHTML = active.map(treeProjLi).join("");
|
||||
wireTreeHandlers(rootUl);
|
||||
|
||||
// "완료 프로젝트" 섹션 — 처음 페이지를 열었을 때 완료 프로젝트가
|
||||
// 하나도 없었으면 서버가 아예 안 그려서 DOM에 없다. 완료로 바뀌는
|
||||
// 순간 필요해지면 그때 만든다(반대로 마지막 하나가 해제/삭제되면 통째로 치운다).
|
||||
let doneUl = el("pj-tree-root-done");
|
||||
if (done.length) {
|
||||
if (!doneUl) {
|
||||
const block = rootUl.closest(".pj-side-block");
|
||||
const head = document.createElement("div");
|
||||
head.className = "pj-side-head pj-side-head-done";
|
||||
head.innerHTML = "<span>완료 프로젝트</span>";
|
||||
doneUl = document.createElement("ul");
|
||||
doneUl.className = "pj-tree";
|
||||
doneUl.id = "pj-tree-root-done";
|
||||
block.appendChild(head);
|
||||
block.appendChild(doneUl);
|
||||
wireTreeDrag(doneUl);
|
||||
}
|
||||
doneUl.innerHTML = done.map(treeProjLi).join("");
|
||||
wireTreeHandlers(doneUl);
|
||||
} else if (doneUl) {
|
||||
const head = doneUl.previousElementSibling;
|
||||
if (head && head.classList.contains("pj-side-head-done")) head.remove();
|
||||
doneUl.remove();
|
||||
}
|
||||
}
|
||||
// 좌측 프로젝트 목록 드래그 순서 변경 — 홈 화면 카드 정렬과 같은 API/원칙
|
||||
// (관리자 전용, 최상위 프로젝트만). rootUl 자체는 renderTree() 가 innerHTML
|
||||
@@ -3398,6 +3425,7 @@
|
||||
}
|
||||
renderTree();
|
||||
wireTreeDrag(el("pj-tree-root"));
|
||||
wireTreeDrag(el("pj-tree-root-done"));
|
||||
|
||||
// 새 최상위 프로젝트 (관리자)
|
||||
const newProjSide = el("pj-new-project-side");
|
||||
|
||||
Reference in New Issue
Block a user