feat(project): 내 업무 개수 배지 - 마우스 따라다니는 툴팁으로 진행/완료 표시

네이티브 title 대신 커서를 따라 움직이는 작은 말풍선(공용 [data-tip]
유틸, initHoverTips). 헤드리스 크롬에서 synthetic mouse event로 동작
검증(진행/완료 텍스트 + 좌표 갱신 확인).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 15:36:45 +09:00
parent a82d54574f
commit 8cc466dd17
5 changed files with 46 additions and 12 deletions
+10 -2
View File
@@ -418,8 +418,16 @@
font-size: 10.5px; font-weight: 800;
}
/* 파스텔톤 — 배경은 연하게, 글자는 진하게(눈에 덜 튀면서도 대비는 유지) */
.pj-mtc-num.pj-mtc-open { background: #dcf1fc; color: #0284c7; } /* 진행 = 연한 하늘색 */
.pj-mtc-num.pj-mtc-done { background: #fbe3df; color: #c22b10; } /* 완료 = 연한 빨강 */
.pj-mtc-num.pj-mtc-open { background: #dcf1fc; color: #0284c7; cursor: default; } /* 진행 = 연한 하늘색 */
.pj-mtc-num.pj-mtc-done { background: #fbe3df; color: #c22b10; cursor: default; } /* 완료 = 연한 빨강 */
/* 마우스를 따라다니는 작은 툴팁([data-tip] 공용) */
.pj-hovertip {
position: fixed; z-index: 4000; pointer-events: none;
background: #1e1f21; color: #fff; font-size: 11px; font-weight: 700;
padding: 4px 8px; border-radius: 6px; white-space: nowrap;
box-shadow: 0 3px 10px rgba(0,0,0,.25);
}
.pj-hovertip[hidden] { display: none; }
.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-group.is-collapsed .pj-mytree-tasks { display: none; }
.pj-mytree-task a { display: flex; align-items: flex-start; gap: 7px; padding: 6px 6px; border-radius: 7px; text-decoration: none; color: inherit; }
+26
View File
@@ -4427,6 +4427,31 @@
.forEach(attachScrollIndicator);
}
// ── 마우스를 따라다니는 작은 툴팁 — [data-tip] 달린 요소 아무데나 공용.
// 지금은 "내 업무" 개수 배지(진행/완료)에 쓴다. 배지는 서버가 한 번
// 렌더한 뒤 텍스트만 바뀌고 재생성되지 않으므로(updateMyTreeCounts),
// 페이지 로드 시 한 번만 wiring 하면 된다(동적으로 새로 생기는 요소 없음).
function initHoverTips() {
let tipEl = null;
function show(text, x, y) {
if (!tipEl) {
tipEl = document.createElement("div");
tipEl.className = "pj-hovertip";
document.body.appendChild(tipEl);
}
tipEl.textContent = text;
tipEl.style.left = (x + 14) + "px";
tipEl.style.top = (y + 18) + "px";
tipEl.hidden = false;
}
function hide() { if (tipEl) tipEl.hidden = true; }
document.querySelectorAll("[data-tip]").forEach(function (el) {
el.addEventListener("mouseenter", function (e) { show(el.dataset.tip, e.clientX, e.clientY); });
el.addEventListener("mousemove", function (e) { show(el.dataset.tip, e.clientX, e.clientY); });
el.addEventListener("mouseleave", hide);
});
}
document.addEventListener("DOMContentLoaded", function () {
initHome();
initProject();
@@ -4435,5 +4460,6 @@
initLiveRefresh();
wireMyTreeToggles();
initScrollIndicators();
initHoverTips();
});
})();