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"],
|
||||
"name": u.get("name") or u["email"].split("@")[0],
|
||||
"id": u["email"].split("@")[0],
|
||||
"avatar": u.get("picture") or "",
|
||||
}
|
||||
for u in user_store.list_all()
|
||||
if has_module(u, "project")
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script src="/static/project.js?v=20260917h" defer></script>
|
||||
<script src="/static/project.js?v=20260917i" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -393,5 +393,5 @@
|
||||
<script>
|
||||
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
||||
</script>
|
||||
<script src="/static/project.js?v=20260917h" defer></script>
|
||||
<script src="/static/project.js?v=20260917i" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -461,5 +461,5 @@
|
||||
</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 %}
|
||||
|
||||
+24
-15
@@ -114,6 +114,21 @@
|
||||
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) {
|
||||
const colors = window.PJ_COLORS || ["#4573d2"];
|
||||
@@ -477,10 +492,9 @@
|
||||
try {
|
||||
const res = await api("GET", "/project/api/assignable-users");
|
||||
const users = res.users || [];
|
||||
membersBox.innerHTML = users.length ? users.map(function (u) {
|
||||
return '<label class="pj-member-pick"><input type="checkbox" value="' + u.email + '" /> ' +
|
||||
escapeHtml(u.id) + "</label>";
|
||||
}).join("") : "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
|
||||
membersBox.innerHTML = users.length
|
||||
? users.map(memberPickHtml).join("")
|
||||
: "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
|
||||
} catch (e) {
|
||||
membersBox.innerHTML = "<span class='pj-empty-sm'>불러오기 실패</span>";
|
||||
}
|
||||
@@ -2503,10 +2517,9 @@
|
||||
try {
|
||||
const res = await api("GET", "/project/api/assignable-users");
|
||||
const users = res.users || [];
|
||||
newProjMembersBox.innerHTML = users.length ? users.map(function (u) {
|
||||
return '<label class="pj-member-pick"><input type="checkbox" value="' + u.email + '" /> ' +
|
||||
escapeHtml(u.id) + "</label>";
|
||||
}).join("") : "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
|
||||
newProjMembersBox.innerHTML = users.length
|
||||
? users.map(memberPickHtml).join("")
|
||||
: "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다.</span>";
|
||||
} catch (e) {
|
||||
newProjMembersBox.innerHTML = "<span class='pj-empty-sm'>불러오기 실패</span>";
|
||||
}
|
||||
@@ -2632,13 +2645,9 @@
|
||||
const res = await api("GET", "/project/api/assignable-users");
|
||||
const existing = new Set(members.map(function (m) { return m.user_email; }));
|
||||
const candidates = res.users.filter(function (u) { return !existing.has(u.email); });
|
||||
box.innerHTML = candidates.length ? candidates.map(function (u) {
|
||||
return '<label class="pj-member-pick pj-member-pick-stacked">' +
|
||||
'<span class="pj-member-pick-avatar">' + avatarHtml(u.email, "pj-member-pick-icon") + "</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>";
|
||||
box.innerHTML = candidates.length
|
||||
? candidates.map(memberPickHtml).join("")
|
||||
: "<span class='pj-empty-sm'>배정 가능한 직원이 없습니다(권한 미부여 또는 전원 배정됨)</span>";
|
||||
} catch (e) {
|
||||
box.innerHTML = "<span class='pj-empty-sm'>불러오기 실패: " + escapeHtml(e.message) + "</span>";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user