feat(project): 댓글 팝업 고정크기 500x850·업무제목 앞 상태아이콘→댓글아이콘 정리
- 댓글 팝업 제목을 업무 제목으로 표시, 우상단 닫기(X) 버튼 추가 - 팝업 크기 500x850 고정, 내용 많으면 목록만 스크롤(팝업 크기 유지) - 카드/내 업무 목록의 완료여부 원형 아이콘 제거, 그 자리를 댓글 아이콘 전용 슬롯으로 교체 - 댓글 유무와 무관하게 슬롯 폭을 고정해 업무 제목이 항상 같은 위치에서 시작(세로 정렬) 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=20260915f" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260915g" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -45,5 +45,5 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script src="/static/project.js?v=20260915e" defer></script>
|
||||
<script src="/static/project.js?v=20260915f" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260915f" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260915g" />
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
{% endblock %}
|
||||
|
||||
@@ -68,7 +68,13 @@
|
||||
{% for t in p.task_preview %}
|
||||
<li class="pj-project-taskrow {% if t.completed_at %}is-done{% endif %}">
|
||||
<a href="/project/p/{{ p.id }}?task={{ t.id }}" data-task-id="{{ t.id }}" class="pj-task-popup-link">
|
||||
<span class="material-symbols-outlined pj-project-task-ic">{% if t.completed_at %}task_alt{% else %}radio_button_unchecked{% endif %}</span>
|
||||
<span class="pj-project-task-lead">
|
||||
{% if t.comment_count %}
|
||||
<span class="pj-cmt-badge" data-task-id="{{ t.id }}" data-count="{{ t.comment_count }}" title="댓글 {{ t.comment_count }}개">
|
||||
<span class="pj-cmt-ic">💬</span><span class="pj-cmt-n">{{ t.comment_count }}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
<span class="pj-project-task-title">{{ t.title }}</span>
|
||||
{% if t.stage_name %}<span class="pj-project-task-stage">{{ t.stage_name }}</span>{% endif %}
|
||||
{% if t.assignee_display %}
|
||||
@@ -82,11 +88,6 @@
|
||||
{% if t.due_date %}
|
||||
<span class="pj-project-task-due {% if t.due_overdue %}is-overdue{% endif %}">{{ t.due_label }}</span>
|
||||
{% endif %}
|
||||
{% if t.comment_count %}
|
||||
<span class="pj-cmt-badge" data-task-id="{{ t.id }}" data-count="{{ t.comment_count }}" title="댓글 {{ t.comment_count }}개">
|
||||
<span class="pj-cmt-ic">💬</span><span class="pj-cmt-n">{{ t.comment_count }}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
@@ -162,7 +163,13 @@
|
||||
{% for t in p.tasks %}
|
||||
<li class="pj-mytree-task {% if t.completed_at %}is-done{% endif %}">
|
||||
<a href="/project/p/{{ t.project_id }}?task={{ t.id }}" data-task-id="{{ t.id }}" class="pj-task-popup-link">
|
||||
<span class="material-symbols-outlined pj-mytree-ic" style="color: {{ t.project_color }};">{% if t.completed_at %}task_alt{% else %}radio_button_unchecked{% endif %}</span>
|
||||
<span class="pj-mytree-lead">
|
||||
{% if t.comment_count %}
|
||||
<span class="pj-cmt-badge" data-task-id="{{ t.id }}" data-count="{{ t.comment_count }}" title="댓글 {{ t.comment_count }}개">
|
||||
<span class="pj-cmt-ic">💬</span><span class="pj-cmt-n">{{ t.comment_count }}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
<span class="pj-mytree-body">
|
||||
<span class="pj-mytree-title">{{ t.title }}</span>
|
||||
{% if t.start_date or t.due_date %}
|
||||
@@ -173,11 +180,6 @@
|
||||
</span>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if t.comment_count %}
|
||||
<span class="pj-cmt-badge" data-task-id="{{ t.id }}" data-count="{{ t.comment_count }}" title="댓글 {{ t.comment_count }}개">
|
||||
<span class="pj-cmt-ic">💬</span><span class="pj-cmt-n">{{ t.comment_count }}</span>
|
||||
</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
@@ -307,7 +309,12 @@
|
||||
<!-- 댓글만 보는 팝업 (업무 카드의 말풍선 아이콘 더블클릭) -->
|
||||
<div class="pj-modal" id="pj-modal-comments" hidden>
|
||||
<div class="pj-modal-card pj-modal-chat">
|
||||
<h3>댓글</h3>
|
||||
<div class="pj-chat-head">
|
||||
<h3 id="pj-cm-title">댓글</h3>
|
||||
<button type="button" class="pj-icon-btn" data-close title="닫기">
|
||||
<span class="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<input type="hidden" id="pj-cm-task-id" />
|
||||
<ul class="pj-chat-list" id="pj-chat-list"></ul>
|
||||
<div class="pj-comment-form">
|
||||
@@ -323,5 +330,5 @@
|
||||
<script>
|
||||
window.PJ_COLORS = {{ ["#4573d2","#37a3a3","#62a420","#e8a33d","#e8384f","#aa62e3","#f06a6a","#5a6772"] | tojson }};
|
||||
</script>
|
||||
<script src="/static/project.js?v=20260915e" defer></script>
|
||||
<script src="/static/project.js?v=20260915f" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "erp_base.html" %}
|
||||
|
||||
{% block head_extra %}
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260915f" />
|
||||
<link rel="stylesheet" href="/static/project.css?v=20260915g" />
|
||||
<!-- 구글 머티리얼 심볼(담당자 아이콘 등) — self-host -->
|
||||
<link rel="stylesheet" href="/static/vendor/material-symbols/material-symbols.css" />
|
||||
<!-- 타임라인 vis-timeline — self-host -->
|
||||
@@ -291,5 +291,5 @@
|
||||
</script>
|
||||
|
||||
<script src="/static/vendor/vis-timeline/vis-timeline-graph2d.min.js"></script>
|
||||
<script src="/static/project.js?v=20260915e" defer></script>
|
||||
<script src="/static/project.js?v=20260915f" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
+13
-5
@@ -73,7 +73,8 @@
|
||||
text-decoration: none; color: inherit;
|
||||
}
|
||||
.pj-project-taskrow a:hover { background: #f6f7f8; }
|
||||
.pj-project-task-ic { font-size: 16px; flex: 0 0 auto; color: #b7bdc5; }
|
||||
/* 댓글 아이콘 자리 — 댓글이 없어도 폭을 고정해 제목이 항상 같은 위치에서 시작(세로 정렬)되게 한다. */
|
||||
.pj-project-task-lead { flex: 0 0 32px; display: inline-flex; align-items: center; }
|
||||
.pj-project-task-title {
|
||||
font-size: 12.5px; font-weight: 600; flex: 1; min-width: 0;
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
@@ -90,7 +91,6 @@
|
||||
.pj-project-task-due { font-size: 11px; color: #9aa1a9; flex: 0 0 auto; }
|
||||
.pj-project-task-due.is-overdue { color: #c22b10; font-weight: 700; }
|
||||
.pj-project-taskrow.is-done .pj-project-task-title { text-decoration: line-through; color: #9aa1a9; }
|
||||
.pj-project-taskrow.is-done .pj-project-task-ic { color: #9aa5b1; }
|
||||
.pj-project-more {
|
||||
display: block; padding: 6px 16px 12px; font-size: 12px; font-weight: 600;
|
||||
color: #6b7280; text-decoration: none;
|
||||
@@ -210,7 +210,8 @@
|
||||
.pj-mytree-tasks { list-style: none; margin: 2px 0 0; padding: 0 0 0 8px; border-left: 2px solid #eef0f2; margin-left: 10px; }
|
||||
.pj-mytree-task a { display: flex; align-items: flex-start; gap: 7px; padding: 6px 6px; border-radius: 7px; text-decoration: none; color: inherit; }
|
||||
.pj-mytree-task a:hover { background: #f6f7f8; }
|
||||
.pj-mytree-ic { font-size: 16px; flex: 0 0 auto; margin-top: 1px; }
|
||||
/* 댓글 아이콘 자리 — 댓글이 없어도 폭을 고정해 제목이 항상 같은 위치에서 시작(세로 정렬)되게 한다. */
|
||||
.pj-mytree-lead { flex: 0 0 32px; display: inline-flex; align-items: center; margin-top: 1px; }
|
||||
.pj-mytree-body { display: flex; flex-direction: column; min-width: 0; }
|
||||
.pj-mytree-title { font-size: 13px; font-weight: 600; }
|
||||
.pj-mytree-dates { font-size: 11px; color: #9aa1a9; margin-top: 1px; }
|
||||
@@ -351,8 +352,15 @@
|
||||
.pj-member-pick input { width: auto !important; margin: 0 !important; }
|
||||
|
||||
/* ── 댓글만 보는 채팅형 팝업(카톡 대화창 느낌) ── */
|
||||
.pj-modal-chat { width: min(420px, 92vw); display: flex; flex-direction: column; }
|
||||
.pj-chat-list { list-style: none; margin: 0 0 10px; padding: 4px; max-height: 420px; min-height: 120px; overflow-y: auto; background: #eef0f2; border-radius: 10px; display: flex; flex-direction: column; gap: 8px; }
|
||||
/* 크기 고정(500x850) — 내용이 많아도 팝업 크기는 그대로, 목록만 스크롤. */
|
||||
.pj-modal-chat {
|
||||
width: 500px; height: 850px; max-width: 96vw; max-height: 92vh;
|
||||
box-sizing: border-box; display: flex; flex-direction: column;
|
||||
}
|
||||
.pj-chat-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 14px; flex: 0 0 auto; }
|
||||
.pj-chat-head h3 { margin: 0; font-size: 17px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.pj-chat-list { list-style: none; margin: 0 0 10px; padding: 4px; flex: 1 1 auto; min-height: 0; overflow-y: auto; background: #eef0f2; border-radius: 10px; display: flex; flex-direction: column; gap: 8px; }
|
||||
.pj-modal-chat .pj-comment-form { flex: 0 0 auto; }
|
||||
.pj-chat-msg { display: flex; flex-direction: column; align-items: flex-start; max-width: 78%; }
|
||||
.pj-chat-msg.mine { align-self: flex-end; align-items: flex-end; }
|
||||
.pj-chat-name { font-size: 11px; color: #6b7280; margin-bottom: 2px; padding: 0 2px; }
|
||||
|
||||
+10
-4
@@ -190,13 +190,17 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 카드/내 업무 클릭 팝업 + 댓글 팝업 공용 — 업무 원본 데이터(제목 등).
|
||||
const homeDataEl = el("pj-home-data");
|
||||
let homeTasks = {};
|
||||
if (homeDataEl) {
|
||||
try { homeTasks = JSON.parse(homeDataEl.textContent) || {}; } catch (_) {}
|
||||
}
|
||||
|
||||
// ── 업무 편집 팝업 (카드/내 업무 클릭 시 페이지 이동 없이) ──
|
||||
const homeTaskModal = el("pj-modal-task");
|
||||
const homeDataEl = el("pj-home-data");
|
||||
if (homeTaskModal && homeDataEl) {
|
||||
if (homeTaskModal) {
|
||||
wireModalClose(homeTaskModal);
|
||||
let homeTasks = {};
|
||||
try { homeTasks = JSON.parse(homeDataEl.textContent) || {}; } catch (_) {}
|
||||
|
||||
async function fillAssignee(pid, currentEmail) {
|
||||
const sel = el("pj-t-assignee");
|
||||
@@ -474,6 +478,8 @@
|
||||
|
||||
async function openCommentsModal(taskId) {
|
||||
el("pj-cm-task-id").value = taskId;
|
||||
const task = homeTasks[taskId];
|
||||
el("pj-cm-title").textContent = (task && task.title) || "댓글";
|
||||
openModal(commentsModal);
|
||||
const n = await renderChat(taskId);
|
||||
if (n !== null) { markSeen(taskId, n); syncBadge(taskId, n); }
|
||||
|
||||
Reference in New Issue
Block a user