style(project): 새 프로젝트 모달 멤버 선택도 멤버 배정 창과 동일하게 통일
/api/assignable-users 응답에 avatar 필드 추가하고, 아이콘/이름/체크박스 세로 카드(memberPickHtml)를 공용 함수로 뽑아 새 프로젝트 모달(홈·사이드바 둘 다)과 멤버 배정 모달 3곳이 전부 같은 모양을 쓰도록 통일. 홈 페이지는 avatars 맵이 따로 없어서 이 API 응답의 avatar 필드에만 의존하도록 함.
This commit is contained in:
@@ -750,6 +750,7 @@ async def api_assignable_users(request: Request) -> JSONResponse:
|
|||||||
"email": u["email"],
|
"email": u["email"],
|
||||||
"name": u.get("name") or u["email"].split("@")[0],
|
"name": u.get("name") or u["email"].split("@")[0],
|
||||||
"id": u["email"].split("@")[0],
|
"id": u["email"].split("@")[0],
|
||||||
|
"avatar": u.get("picture") or "",
|
||||||
}
|
}
|
||||||
for u in user_store.list_all()
|
for u in user_store.list_all()
|
||||||
if has_module(u, "project")
|
if has_module(u, "project")
|
||||||
|
|||||||
@@ -45,5 +45,5 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/static/project.js?v=20260917h" defer></script>
|
<script src="/static/project.js?v=20260917i" defer></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -393,5 +393,5 @@
|
|||||||
<script>
|
<script>
|
||||||
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/project.js?v=20260917h" defer></script>
|
<script src="/static/project.js?v=20260917i" defer></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -461,5 +461,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
||||||
<script src="/static/project.js?v=20260917h" defer></script>
|
<script src="/static/project.js?v=20260917i" defer></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
+24
-15
@@ -114,6 +114,21 @@
|
|||||||
return mm + "/" + dd + "(" + wd + ")";
|
return mm + "/" + dd + "(" + wd + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 멤버 선택 후보 카드(아이콘 위 / 이름 가운데 / 체크박스 아래) — 새 프로젝트
|
||||||
|
// 모달(홈·프로젝트 페이지)과 멤버 배정 모달 3곳이 전부 이 함수 하나를 쓴다.
|
||||||
|
// /api/assignable-users 응답의 avatar 필드를 그대로 쓰므로 페이지별
|
||||||
|
// avatars 맵(홈 페이지엔 없음)에 기대지 않는다.
|
||||||
|
function memberPickHtml(u) {
|
||||||
|
const icon = u.avatar
|
||||||
|
? '<img class="pj-avatar pj-member-pick-icon" src="' + escapeHtml(u.avatar) + '" alt="" referrerpolicy="no-referrer" />'
|
||||||
|
: '<span class="material-symbols-outlined pj-gicon pj-member-pick-icon">account_circle</span>';
|
||||||
|
return '<label class="pj-member-pick pj-member-pick-stacked">' +
|
||||||
|
'<span class="pj-member-pick-avatar">' + icon + "</span>" +
|
||||||
|
'<span class="pj-member-pick-name">' + escapeHtml(u.id) + "</span>" +
|
||||||
|
'<input type="checkbox" value="' + u.email + '" data-name="' + escapeHtml(u.name) + '" />' +
|
||||||
|
"</label>";
|
||||||
|
}
|
||||||
|
|
||||||
// ── 색상 팔레트 렌더 ───────────────────────────────────────
|
// ── 색상 팔레트 렌더 ───────────────────────────────────────
|
||||||
function renderColorPalette(container, onPick, initial) {
|
function renderColorPalette(container, onPick, initial) {
|
||||||
const colors = window.PJ_COLORS || ["#4573d2"];
|
const colors = window.PJ_COLORS || ["#4573d2"];
|
||||||
@@ -477,10 +492,9 @@
|
|||||||
try {
|
try {
|
||||||
const res = await api("GET", "/project/api/assignable-users");
|
const res = await api("GET", "/project/api/assignable-users");
|
||||||
const users = res.users || [];
|
const users = res.users || [];
|
||||||
membersBox.innerHTML = users.length ? users.map(function (u) {
|
membersBox.innerHTML = users.length
|
||||||
return '<label class="pj-member-pick"><input type="checkbox" value="' + u.email + '" /> ' +
|
? users.map(memberPickHtml).join("")
|
||||||
escapeHtml(u.id) + "</label>";
|
: "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
|
||||||
}).join("") : "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
membersBox.innerHTML = "<span class='pj-empty-sm'>불러오기 실패</span>";
|
membersBox.innerHTML = "<span class='pj-empty-sm'>불러오기 실패</span>";
|
||||||
}
|
}
|
||||||
@@ -2503,10 +2517,9 @@
|
|||||||
try {
|
try {
|
||||||
const res = await api("GET", "/project/api/assignable-users");
|
const res = await api("GET", "/project/api/assignable-users");
|
||||||
const users = res.users || [];
|
const users = res.users || [];
|
||||||
newProjMembersBox.innerHTML = users.length ? users.map(function (u) {
|
newProjMembersBox.innerHTML = users.length
|
||||||
return '<label class="pj-member-pick"><input type="checkbox" value="' + u.email + '" /> ' +
|
? users.map(memberPickHtml).join("")
|
||||||
escapeHtml(u.id) + "</label>";
|
: "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
|
||||||
}).join("") : "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
newProjMembersBox.innerHTML = "<span class='pj-empty-sm'>불러오기 실패</span>";
|
newProjMembersBox.innerHTML = "<span class='pj-empty-sm'>불러오기 실패</span>";
|
||||||
}
|
}
|
||||||
@@ -2632,13 +2645,9 @@
|
|||||||
const res = await api("GET", "/project/api/assignable-users");
|
const res = await api("GET", "/project/api/assignable-users");
|
||||||
const existing = new Set(members.map(function (m) { return m.user_email; }));
|
const existing = new Set(members.map(function (m) { return m.user_email; }));
|
||||||
const candidates = res.users.filter(function (u) { return !existing.has(u.email); });
|
const candidates = res.users.filter(function (u) { return !existing.has(u.email); });
|
||||||
box.innerHTML = candidates.length ? candidates.map(function (u) {
|
box.innerHTML = candidates.length
|
||||||
return '<label class="pj-member-pick pj-member-pick-stacked">' +
|
? candidates.map(memberPickHtml).join("")
|
||||||
'<span class="pj-member-pick-avatar">' + avatarHtml(u.email, "pj-member-pick-icon") + "</span>" +
|
: "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다(권한 미부여 또는 전원 배정됨)</span>";
|
||||||
'<span class="pj-member-pick-name">' + escapeHtml(u.id) + "</span>" +
|
|
||||||
'<input type="checkbox" value="' + u.email + '" data-name="' + escapeHtml(u.name) + '" />' +
|
|
||||||
"</label>";
|
|
||||||
}).join("") : "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다(권한 미부여 또는 전원 배정됨)</span>";
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
box.innerHTML = "<span class='pj-empty-sm'>불러오기 실패: " + escapeHtml(e.message) + "</span>";
|
box.innerHTML = "<span class='pj-empty-sm'>불러오기 실패: " + escapeHtml(e.message) + "</span>";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user