2056 lines
64 KiB
HTML
2056 lines
64 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ko">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||
<title>2026년 2분기 인사총무 프로젝트 현황 — Preview</title>
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.css" />
|
||
<style>
|
||
:root {
|
||
/* 본문 — 참고 이미지 톤 + 상단바 그린 계열 */
|
||
--hrm: #29724f;
|
||
--hrm-soft: #e8f4ef;
|
||
--hrd: #37a184;
|
||
--hrd-soft: #e6f6f0;
|
||
--ex: #4a9480;
|
||
--ex-soft: #eaf3ef;
|
||
--ga: #0d4a38;
|
||
--ga-soft: #e4ece8;
|
||
--dept-accent: #29724f;
|
||
--page-bg: #e9eef2;
|
||
--card-bg: #ffffff;
|
||
--card-border: #d8e2ea;
|
||
--card-shadow: 0 4px 18px rgba(15, 35, 52, 0.07);
|
||
--hub-border: #ccd8e2;
|
||
--postit-bg: #dceee6;
|
||
--postit-bg-deep: #cddfd7;
|
||
--postit-border: rgba(41, 114, 79, 0.14);
|
||
--postit-shadow: 0 5px 16px rgba(22, 72, 52, 0.1), 0 2px 5px rgba(15, 35, 52, 0.05);
|
||
--hub-diamond-bg: linear-gradient(145deg, #1e5c44 0%, #0d3a2a 100%);
|
||
--hub-diamond-border: #2f8a66;
|
||
--conn-line: #b8c6d4;
|
||
--conn-line-width: 4;
|
||
--text-primary: #1a2b3c;
|
||
--text-muted: #5a6b7d;
|
||
/* 헤더 상태 통계(stat-*)와 동일 — 프로젝트 제목 불릿 */
|
||
--status-in-progress: #10b981;
|
||
--status-hold: #ff9f0a;
|
||
--status-done: #b0b0b0;
|
||
--status-issue: #ff5252;
|
||
/* 부서 카드 헤드 — 샴페인 골드 */
|
||
--dept-head-bg-top: #faf6ef;
|
||
--dept-head-bg-bottom: #f0e6d4;
|
||
--dept-head-text: #4a3d2e;
|
||
--dept-head-accent: #9a7b4f;
|
||
--dept-head-line: rgba(180, 152, 108, 0.32);
|
||
}
|
||
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
|
||
body.preview-page {
|
||
font-family:
|
||
"Pretendard Variable",
|
||
Pretendard,
|
||
-apple-system,
|
||
BlinkMacSystemFont,
|
||
system-ui,
|
||
"Malgun Gothic",
|
||
sans-serif;
|
||
background: var(--page-bg);
|
||
color: #1a2b3c;
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* ─── 상단바 (DashboardHeader 동일) ─── */
|
||
.dashboard-header-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
position: relative;
|
||
z-index: 10;
|
||
flex-shrink: 0;
|
||
height: 48px;
|
||
min-height: 48px;
|
||
padding: 0 22px 0 20px;
|
||
background: linear-gradient(180deg, #37a184 0%, #29724f 20%, #07412e 100%);
|
||
border-bottom: 1px solid #135643;
|
||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||
color: #fff;
|
||
}
|
||
|
||
.side-left-group {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
height: 100%;
|
||
}
|
||
|
||
.main_tit {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.5px;
|
||
color: #bad8ca;
|
||
text-shadow:
|
||
-1px -1px 1px rgba(0, 0, 0, 0.25),
|
||
1px -1px 1px rgba(0, 0, 0, 0.25),
|
||
-1px 1px 1px rgba(0, 0, 0, 0.25),
|
||
1px 1px 1px rgba(0, 0, 0, 0.25);
|
||
}
|
||
|
||
.team-status-btn-new,
|
||
.header-action-btn-new,
|
||
.header-view-btn-new {
|
||
display: flex;
|
||
flex-shrink: 0;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 32px;
|
||
height: 32px;
|
||
border: 1.5px solid #1a4d42;
|
||
border-radius: 50%;
|
||
color: #cef1eb;
|
||
cursor: default;
|
||
background: linear-gradient(180deg, #0d3f34 0%, #051f19 100%);
|
||
box-shadow: 0 0 0 1px #000, 0 2px 2px rgba(0, 0, 0, 0.6);
|
||
}
|
||
|
||
.side-right-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
|
||
.header-stats-bar {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 50%;
|
||
z-index: 100;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
height: 40px;
|
||
min-height: 40px;
|
||
padding: 0 48px;
|
||
border-bottom: 1px solid #135643;
|
||
border-radius: 0 0 16px 16px;
|
||
background: linear-gradient(90deg, #093023 20%, #074833 50%, #093023 80%);
|
||
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
.header-stats-bar::before,
|
||
.header-stats-bar::after {
|
||
content: "";
|
||
pointer-events: none;
|
||
position: absolute;
|
||
top: 0;
|
||
width: 36px;
|
||
height: 30px;
|
||
background: transparent;
|
||
z-index: 101;
|
||
}
|
||
|
||
.header-stats-bar::before {
|
||
left: -35px;
|
||
border-top-right-radius: 20px;
|
||
box-shadow: 18px 0 #093023;
|
||
}
|
||
|
||
.header-stats-bar::after {
|
||
right: -35px;
|
||
border-top-left-radius: 20px;
|
||
box-shadow: -18px 0 #093023;
|
||
}
|
||
|
||
.poly-stat-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 18px;
|
||
font-weight: 400;
|
||
letter-spacing: -0.3px;
|
||
white-space: nowrap;
|
||
color: #eeeae3;
|
||
}
|
||
|
||
.header-stat-text {
|
||
text-shadow:
|
||
-1px -1px 0 #00000040,
|
||
1px -1px 0 #00000040,
|
||
-1px 1px 0 #00000040,
|
||
1px 1px 0 #00000040;
|
||
}
|
||
|
||
.poly-stat-quarter { font-weight: 600; color: #ffffffc4; }
|
||
.poly-stat-bullet { color: rgba(238, 234, 227, 0.4); }
|
||
|
||
.poly-stat-divider {
|
||
flex-shrink: 0;
|
||
width: 1px;
|
||
height: 16px;
|
||
margin: 0 4px;
|
||
background-color: rgba(238, 234, 227, 0.4);
|
||
}
|
||
|
||
.poly-click-stat {
|
||
display: inline;
|
||
padding: 2px 6px;
|
||
border-radius: 0;
|
||
line-height: 21px;
|
||
color: #fffc;
|
||
font-size: 18px;
|
||
border: 1px solid #1d6947;
|
||
background: linear-gradient(180deg, #337c5f 0%, #1c4638 100%);
|
||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
.poly-click-stat.active {
|
||
background: linear-gradient(
|
||
180deg,
|
||
rgba(0, 0, 0, 0.54) 0%,
|
||
rgba(0, 0, 0, 0.25) 20%,
|
||
rgba(0, 0, 0, 0.09) 80%,
|
||
rgba(0, 0, 0, 0.54) 100%
|
||
);
|
||
border: 1px solid rgba(0, 0, 0, 0.86);
|
||
box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.3);
|
||
}
|
||
|
||
.poly-stat-val { font-weight: 800; }
|
||
.poly-stat-unit { font-size: 14px; font-weight: 500; opacity: 0.5; }
|
||
|
||
.stat-yellow { color: #ffdb3a; }
|
||
.stat-green { color: #10b981; }
|
||
.stat-orange { color: #ff9f0a; }
|
||
.stat-gray { color: #b0b0b0; }
|
||
.stat-red { color: #ff5252; }
|
||
|
||
.dual-monitor-icon-wrap {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 16px;
|
||
height: 16px;
|
||
}
|
||
|
||
.dual-monitor-icon-wrap svg {
|
||
position: absolute;
|
||
stroke: currentColor;
|
||
fill: none;
|
||
stroke-width: 2;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
}
|
||
|
||
.dual-monitor-icon-wrap .m-back { top: 0; left: -3px; opacity: 0.5; width: 12px; height: 12px; }
|
||
.dual-monitor-icon-wrap .m-front { right: -3px; bottom: 0; width: 12px; height: 12px; }
|
||
|
||
/* ─── 본문 ─── */
|
||
.page-content {
|
||
flex: 1;
|
||
min-height: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
padding: 12px 16px 14px;
|
||
background: var(--page-bg);
|
||
}
|
||
|
||
.board-layout {
|
||
position: relative;
|
||
flex: 1;
|
||
min-height: 0;
|
||
display: grid;
|
||
/* 중앙 허브 확대(다이아몬드 1.1×) — 좌·우 부문 카드 열은 1fr로 자동 축소 */
|
||
grid-template-columns: minmax(0, 1fr) minmax(320px, 396px) minmax(0, 1fr);
|
||
grid-template-rows: 1fr 1fr;
|
||
gap: 12px 24px;
|
||
width: 100%;
|
||
align-items: stretch;
|
||
}
|
||
|
||
.connectors {
|
||
position: absolute;
|
||
inset: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
pointer-events: none;
|
||
z-index: 2;
|
||
overflow: visible;
|
||
}
|
||
|
||
.connectors path,
|
||
.connectors line {
|
||
fill: none;
|
||
stroke-linecap: butt;
|
||
stroke-linejoin: miter;
|
||
vector-effect: non-scaling-stroke;
|
||
}
|
||
|
||
/*
|
||
* ─── [BACKUP] 부문 카드 — A안 적용 전 (2026-06-08) ───
|
||
* 되돌리려면 아래 A안 블록을 지우고 BACKUP 주석을 해제하세요.
|
||
*
|
||
* .dept-card { border-radius:16px; border:1.5px solid var(--card-border);
|
||
* padding:16px 18px 14px; background:var(--card-bg); box-shadow:var(--card-shadow); }
|
||
* .dept-icon { display:flex; width:40px; height:40px; border-radius:50%; … filled circle }
|
||
* .dept-head { margin-bottom:10px; padding-bottom:10px; border-bottom:2px solid;
|
||
* background:none; align-items:flex-end; }
|
||
* .project-sub-card { border-radius:12px; padding:12px 14px;
|
||
* border:1px solid #e2e8ef; background:#f7f9fb; }
|
||
* .project-sub-card--hrm { background:var(--hrm-soft); border-color:#c8dfd5; } …
|
||
* .board-project-list { gap:10px; padding:4px 0 0; }
|
||
*
|
||
* ─── [BACKUP-A] A안 헤더 — 강화 적용 전 (2026-06-08) ───
|
||
* 헤더 강화만 되돌릴 때: BACKUP-A 블록으로 .dept-card / .dept-head / accent 규칙 복원
|
||
*
|
||
* .dept-card { border:1px solid #c8dfd5; (border-top-width 1px, top-color #c8dfd5) }
|
||
* .dept-head { padding:14px 18px 10px; border-bottom:3px solid var(--dept);
|
||
* margin-bottom:0; (no ::after, no #c5d9cc hairline) }
|
||
* .dept-card--hrm .dept-head { border-bottom-color:var(--hrm); } …
|
||
*
|
||
* ─── [BACKUP-B] 헤더 강화 (상단+이중 underline) — 되돌림 (2026-06-08) ───
|
||
* .dept-card { border-top-width:3px; border-top-color:var(--dept); }
|
||
* .dept-head { padding:14px 20px 10px; border-bottom:1px solid #c5d9cc;
|
||
* margin-bottom:3px; } + .dept-head::after { height:3px; bottom:-3px; }
|
||
*
|
||
* ─── [BACKUP-C] 부서별 4색 accent — B안 적용 전 (2026-06-08) ───
|
||
* .dept-card--* .dept-head { border-bottom-color:var(--hrm|hrd|ex|ga); }
|
||
* .board-dept-title--* / .board-dept-title-en--* / .dept-head-count--* /
|
||
* .project-sub-card--* .project-field-label { color: var(--dept); }
|
||
* .donut { --color: var(--hrm|hrd|ex|ga); } (inline)
|
||
*
|
||
* ─── [BACKUP-D] mint 보드형 (A+B) — 데스크/종이 테마 적용 전 (2026-06-08) ───
|
||
* .dept-card { border-radius:12px; border:1px solid #c8dfd5; background:#f8fcfa;
|
||
* box-shadow:none; }
|
||
* .dept-head { border-bottom:3px solid var(--dept-accent);
|
||
* background:linear-gradient(180deg,#f8fcfa 0%,#f0f7f4 100%); }
|
||
* .board-project-list { background:#f8fcfa; }
|
||
* .project-sub-card { border-bottom:1px solid #dce8e3; }
|
||
* .project-sub-card:hover { background:linear-gradient(180deg,#f2f9f6,#eaf3ef); }
|
||
* .project-field-label { color:var(--dept-accent); }
|
||
* .donut::after { background:#f8fcfa; }
|
||
*/
|
||
|
||
/* ─── 부문 카드 — 데스크/게시판 (sage 종이 · 포스트잇·플래너와 동일 재질) ─── */
|
||
.dept-card {
|
||
position: relative;
|
||
z-index: 3;
|
||
height: 100%;
|
||
min-height: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
border-radius: 6px;
|
||
border: 1px solid rgba(41, 114, 79, 0.1);
|
||
padding: 0;
|
||
background: linear-gradient(168deg, #f9fbf9 0%, #f5faf8 100%);
|
||
box-shadow:
|
||
0 3px 12px rgba(15, 35, 52, 0.06),
|
||
0 1px 3px rgba(22, 72, 52, 0.04);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.dept-card::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 1px;
|
||
background: rgba(255, 255, 255, 0.55);
|
||
pointer-events: none;
|
||
z-index: 1;
|
||
}
|
||
|
||
.dept-card--hrm { grid-column: 1; grid-row: 1; }
|
||
.dept-card--hrd { grid-column: 3; grid-row: 1; }
|
||
.dept-card--ex { grid-column: 1; grid-row: 2; }
|
||
.dept-card--ga { grid-column: 3; grid-row: 2; }
|
||
|
||
.dept-icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
width: 36px;
|
||
height: 36px;
|
||
margin-right: 8px;
|
||
border-radius: 10px;
|
||
background: rgba(255, 255, 255, 0.48);
|
||
border: 1px solid rgba(180, 152, 108, 0.24);
|
||
box-shadow:
|
||
inset 0 1px 0 rgba(255, 255, 255, 0.62),
|
||
0 1px 2px rgba(92, 74, 50, 0.06);
|
||
color: var(--dept-head-accent);
|
||
align-self: center;
|
||
}
|
||
|
||
.dept-icon svg {
|
||
width: 32px;
|
||
height: 32px;
|
||
stroke: currentColor;
|
||
fill: none;
|
||
stroke-width: 1.75;
|
||
}
|
||
|
||
.dept-head {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
margin-bottom: 0;
|
||
padding: 9px 16px 9px;
|
||
border-bottom: none;
|
||
background: linear-gradient(180deg, var(--dept-head-bg-top) 0%, var(--dept-head-bg-bottom) 100%);
|
||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.72);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.dept-head::after {
|
||
content: "";
|
||
position: absolute;
|
||
left: 14px;
|
||
right: 14px;
|
||
bottom: 0;
|
||
height: 1px;
|
||
background: linear-gradient(
|
||
90deg,
|
||
transparent 0%,
|
||
var(--dept-head-line) 18%,
|
||
var(--dept-head-line) 82%,
|
||
transparent 100%
|
||
);
|
||
}
|
||
|
||
.dept-head-main {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0;
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.dept-head-count {
|
||
display: inline-flex;
|
||
align-items: baseline;
|
||
flex-shrink: 0;
|
||
font-size: 28px;
|
||
font-weight: 400;
|
||
letter-spacing: -0.4px;
|
||
line-height: 1;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.dept-head-count .poly-stat-val {
|
||
font-weight: 800;
|
||
font-size: 28px;
|
||
line-height: 1;
|
||
}
|
||
|
||
.dept-head-count .poly-stat-unit {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
opacity: 0.55;
|
||
}
|
||
|
||
.dept-card .board-dept-title {
|
||
color: var(--dept-head-text);
|
||
}
|
||
|
||
.dept-card .dept-head-count .poly-stat-val,
|
||
.dept-card .dept-head-count .poly-stat-unit,
|
||
.dept-card .board-dept-title-en {
|
||
color: var(--dept-head-accent);
|
||
}
|
||
|
||
.board-dept-header-main {
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.board-dept-title-wrap {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 8px;
|
||
min-width: 0;
|
||
flex: 1;
|
||
}
|
||
|
||
.board-dept-title {
|
||
margin: 0;
|
||
font-size: 28px;
|
||
font-weight: 800;
|
||
letter-spacing: -0.6px;
|
||
line-height: 1;
|
||
}
|
||
|
||
.board-dept-title-en {
|
||
font-size: 19px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.1px;
|
||
line-height: 1;
|
||
flex-shrink: 0;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
/* ─── 프로젝트 목록 — 종이 메모 리스트 ─── */
|
||
.board-project-list {
|
||
position: relative;
|
||
min-height: 0;
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0;
|
||
overflow-y: auto;
|
||
padding: 10px 14px 10px;
|
||
background: linear-gradient(180deg, #f8fbfa 0%, rgba(248, 251, 250, 0) 20px);
|
||
}
|
||
|
||
.board-project-list::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 3px;
|
||
background: linear-gradient(
|
||
180deg,
|
||
rgba(92, 74, 50, 0.04) 0%,
|
||
transparent 100%
|
||
);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.project-sub-card {
|
||
border-radius: 0;
|
||
padding: 10px 2px 12px;
|
||
border: none;
|
||
border-bottom: 1px dashed #c8d9d0;
|
||
background: rgba(255, 255, 255, 0.38);
|
||
flex-shrink: 0;
|
||
transition: background 0.2s ease;
|
||
}
|
||
|
||
.project-sub-card:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.project-sub-card:hover {
|
||
background: linear-gradient(168deg, #eef6f2 0%, #e4efe9 100%);
|
||
}
|
||
|
||
.project-sub-body {
|
||
display: grid;
|
||
grid-template-columns: 1fr auto auto;
|
||
column-gap: 12px;
|
||
align-items: center;
|
||
}
|
||
|
||
.project-sub-divider {
|
||
display: block;
|
||
width: 1px;
|
||
align-self: stretch;
|
||
margin: 6px 0;
|
||
background: linear-gradient(
|
||
180deg,
|
||
transparent 0%,
|
||
#c8d9d0 14%,
|
||
#c8d9d0 86%,
|
||
transparent 100%
|
||
);
|
||
}
|
||
|
||
.progress-col {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
width: 93px;
|
||
}
|
||
|
||
.project-fields {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 7px;
|
||
min-width: 0;
|
||
/* 불릿(10px) + gap(10px) — 하위 필드는 제목 글자 시작선과 정렬 */
|
||
--project-title-indent: 20px;
|
||
}
|
||
|
||
.project-field {
|
||
display: grid;
|
||
grid-template-columns: 96px 1fr;
|
||
gap: 8px;
|
||
align-items: baseline;
|
||
padding-left: var(--project-title-indent);
|
||
}
|
||
|
||
.project-sub-title {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 10px;
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: #0a2e24;
|
||
line-height: 1.35;
|
||
}
|
||
|
||
.project-sub-title::before {
|
||
content: "";
|
||
flex-shrink: 0;
|
||
width: 10px;
|
||
height: 10px;
|
||
margin-top: 9px;
|
||
border-radius: 50%;
|
||
background: var(--status-bullet, var(--status-in-progress));
|
||
}
|
||
|
||
.project-sub-title-text {
|
||
flex: 1;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 2;
|
||
}
|
||
|
||
.project-sub-title--in-progress { --status-bullet: var(--status-in-progress); }
|
||
.project-sub-title--hold { --status-bullet: var(--status-hold); }
|
||
.project-sub-title--done { --status-bullet: var(--status-done); }
|
||
.project-sub-title--issue { --status-bullet: var(--status-issue); }
|
||
|
||
.project-field-label {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
line-height: 1.45;
|
||
color: #5a6b62;
|
||
}
|
||
|
||
.project-field .project-field-value {
|
||
font-size: 20px;
|
||
font-weight: 500;
|
||
color: #5a6b62;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.project-field-value {
|
||
font-family: inherit;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.dept-card .donut {
|
||
--color: var(--dept-accent);
|
||
background: conic-gradient(var(--color) calc(var(--pct) * 1%), #d4ddd8 0);
|
||
}
|
||
|
||
.donut {
|
||
--pct: 0;
|
||
--color: #29724f;
|
||
position: relative;
|
||
width: 93px;
|
||
height: 93px;
|
||
border-radius: 50%;
|
||
background: conic-gradient(var(--color) calc(var(--pct) * 1%), #dde4ec 0);
|
||
}
|
||
|
||
.donut::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 12px;
|
||
border-radius: 50%;
|
||
background: #f4f9f6;
|
||
}
|
||
|
||
.project-sub-card:hover .donut::after {
|
||
background: #eef6f2;
|
||
}
|
||
|
||
.donut span {
|
||
position: absolute;
|
||
inset: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
z-index: 1;
|
||
font-size: 21px;
|
||
font-weight: 800;
|
||
color: var(--color);
|
||
}
|
||
|
||
/*
|
||
* ─── 중앙 허브 — 단일 컬럼 flex (슬로건·다이아·일정 비율 고정)
|
||
*/
|
||
.hub-column {
|
||
grid-column: 2;
|
||
grid-row: 1 / 3;
|
||
display: grid;
|
||
grid-template-rows: var(--hub-slogan-band-h) 1fr var(--hub-slogan-band-h);
|
||
align-content: stretch;
|
||
min-height: 0;
|
||
min-width: 0;
|
||
width: 100%;
|
||
z-index: 2;
|
||
--hub-row-h: calc((100% - 12px) / 2);
|
||
--hub-band-h: min(calc(var(--hub-row-h) * 0.473), 171px);
|
||
/* 슬로건·일정 밴드 — 다이아몬드 1.1×에 맞춰 높이 축소 (0.624→0.567, 226→205) */
|
||
--hub-slogan-band-h: min(calc(var(--hub-row-h) * 0.567), 205px);
|
||
/* 일정: 박스 top → 제목 (플래너·헤더 띠에서 역산) */
|
||
--hub-title-top: 20px;
|
||
/* 슬로건: 바깥(그리드→포스트잇) + 안(핀 아래→제목). 일정 플래너 14px과 같은 호흡 */
|
||
--hub-slogan-pad-top: 16px;
|
||
--hub-slogan-postit-pad-top: 14px;
|
||
/* 일정: 헤더 띠 + 플래너 (플래너 padding-top도 title-top에서 역산) */
|
||
--hub-head-offset-top: -2px;
|
||
--hub-head-pad-top: 8px;
|
||
--hub-head-pad-bottom: 7px;
|
||
--hub-card-pad-x: 12px;
|
||
--hub-card-pad-bottom: 10px;
|
||
--hub-diamond-scale: 0.99;
|
||
}
|
||
|
||
.hub-box--message {
|
||
grid-row: 1;
|
||
align-self: stretch;
|
||
height: 100%;
|
||
min-height: 0;
|
||
z-index: 3;
|
||
}
|
||
|
||
.hub-box--focus {
|
||
grid-row: 3;
|
||
align-self: stretch;
|
||
height: 100%;
|
||
min-height: 0;
|
||
z-index: 3;
|
||
}
|
||
|
||
.hub-diamond-wrap {
|
||
grid-row: 2;
|
||
min-height: 0;
|
||
align-self: stretch;
|
||
z-index: 1;
|
||
}
|
||
|
||
.hub-box {
|
||
position: relative;
|
||
z-index: 3;
|
||
width: 100%;
|
||
background: var(--card-bg);
|
||
border: 1.5px solid var(--hub-border);
|
||
border-radius: 14px;
|
||
padding: 12px 16px;
|
||
box-shadow: var(--card-shadow);
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
gap: 6px;
|
||
min-height: 0;
|
||
text-align: center;
|
||
}
|
||
|
||
.hub-box-title-row {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.hub-box-icon {
|
||
width: 28px;
|
||
height: 28px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
flex-shrink: 0;
|
||
background: #eef2f6;
|
||
border: 1px solid #d8e2ea;
|
||
}
|
||
|
||
/* 분기 중점 과제 — 2장 겹친 sage 포스트잇 */
|
||
.hub-box--message {
|
||
background: transparent;
|
||
border: none;
|
||
box-shadow: none;
|
||
padding: var(--hub-slogan-pad-top) 0 0;
|
||
overflow: visible;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.hub-box--message .hub-postit-stack {
|
||
flex: 1 1 auto;
|
||
min-height: 0;
|
||
height: auto;
|
||
}
|
||
|
||
.hub-box--message .hub-postit-sheet--front {
|
||
height: 100%;
|
||
min-height: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding:
|
||
var(--hub-slogan-postit-pad-top)
|
||
14px
|
||
8px;
|
||
gap: 0;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.hub-box--message .hub-postit-content {
|
||
flex: 1 1 auto;
|
||
min-height: 0;
|
||
gap: 0;
|
||
justify-content: flex-start;
|
||
align-items: center;
|
||
width: 100%;
|
||
}
|
||
|
||
.hub-box--message .hub-postit-header {
|
||
width: 100%;
|
||
margin: 0;
|
||
padding-top: 0;
|
||
padding-bottom: 6px;
|
||
background: none;
|
||
border-bottom: 1px solid #c5d9cc;
|
||
border-radius: 0;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.hub-box--message .hub-postit-message {
|
||
gap: 2px;
|
||
flex: 1 1 auto;
|
||
min-height: 0;
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.hub-postit-stack {
|
||
position: relative;
|
||
width: 100%;
|
||
height: auto;
|
||
min-height: 0;
|
||
overflow: visible;
|
||
}
|
||
|
||
.hub-postit-sheet--back {
|
||
position: absolute;
|
||
top: 1px;
|
||
left: -3px;
|
||
right: 3px;
|
||
bottom: 3px;
|
||
transform: rotate(-1.5deg);
|
||
background: linear-gradient(168deg, #cddfd7 0%, #bfd5cb 100%);
|
||
border: 1px solid var(--postit-border);
|
||
border-radius: 4px;
|
||
box-shadow: 0 3px 10px rgba(22, 72, 52, 0.09);
|
||
z-index: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.hub-postit-sheet--front {
|
||
position: relative;
|
||
z-index: 2;
|
||
width: 100%;
|
||
height: auto;
|
||
min-height: 0;
|
||
padding: 12px 14px 10px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-start;
|
||
align-items: center;
|
||
gap: 5px;
|
||
background: linear-gradient(168deg, var(--postit-bg) 0%, var(--postit-bg-deep) 100%);
|
||
border: 1px solid var(--postit-border);
|
||
border-radius: 4px;
|
||
box-shadow: var(--postit-shadow);
|
||
overflow: visible;
|
||
}
|
||
|
||
.hub-postit-sheet--front::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 1px;
|
||
background: rgba(255, 255, 255, 0.55);
|
||
pointer-events: none;
|
||
}
|
||
|
||
.hub-postit-content {
|
||
position: relative;
|
||
z-index: 2;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: flex-start;
|
||
gap: 6px;
|
||
width: 100%;
|
||
flex: 0 0 auto;
|
||
min-height: 0;
|
||
padding-top: 0;
|
||
}
|
||
|
||
.hub-postit-header {
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
padding-top: 4px;
|
||
padding-bottom: 6px;
|
||
border-bottom: 1px solid #c5d9cc;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.hub-postit-message {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 2px;
|
||
width: 100%;
|
||
flex: 0 0 auto;
|
||
min-height: 0;
|
||
}
|
||
|
||
.hub-postit-message .board-project-desc {
|
||
margin: 0;
|
||
text-align: center;
|
||
line-height: 1.45;
|
||
}
|
||
|
||
.hub-postit-dept-line {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
/* 오른쪽 하단 접힘 */
|
||
.hub-postit-fold {
|
||
position: absolute;
|
||
right: 0;
|
||
bottom: 0;
|
||
width: 28px;
|
||
height: 28px;
|
||
z-index: 4;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.hub-postit-fold::before {
|
||
content: "";
|
||
position: absolute;
|
||
right: 0;
|
||
bottom: 0;
|
||
width: 28px;
|
||
height: 28px;
|
||
background: linear-gradient(315deg, #edf5f1 0%, #d2e6dc 45%, #bdd8cc 100%);
|
||
clip-path: polygon(100% 0, 0 100%, 100% 100%);
|
||
box-shadow: -2px -2px 5px rgba(15, 35, 52, 0.1);
|
||
}
|
||
|
||
.hub-postit-fold::after {
|
||
content: "";
|
||
position: absolute;
|
||
right: 3px;
|
||
bottom: 3px;
|
||
width: 22px;
|
||
height: 22px;
|
||
background: rgba(15, 35, 52, 0.1);
|
||
clip-path: polygon(100% 0, 0 100%, 100% 100%);
|
||
filter: blur(1px);
|
||
z-index: -1;
|
||
}
|
||
|
||
/* 빨간 원형 핀 */
|
||
.hub-postit-pin {
|
||
position: absolute;
|
||
top: -9px;
|
||
left: 50%;
|
||
width: 20px;
|
||
height: 24px;
|
||
z-index: 6;
|
||
pointer-events: none;
|
||
transform: translateX(-50%);
|
||
filter: drop-shadow(0 3px 4px rgba(90, 20, 20, 0.24));
|
||
}
|
||
|
||
.hub-postit-pin::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 50%;
|
||
background:
|
||
radial-gradient(circle at 28% 22%, rgba(255, 255, 255, 0.92) 0%, rgba(255, 255, 255, 0.22) 16%, transparent 38%),
|
||
radial-gradient(circle at 72% 74%, rgba(70, 10, 10, 0.38) 0%, transparent 52%),
|
||
radial-gradient(circle at 50% 58%, #e86565 0%, #cc4545 42%, #a83232 72%, #7a2222 100%);
|
||
box-shadow:
|
||
0 4px 7px rgba(90, 20, 20, 0.32),
|
||
0 1px 2px rgba(0, 0, 0, 0.18),
|
||
inset 0 -4px 7px rgba(70, 10, 10, 0.42),
|
||
inset 0 3px 5px rgba(255, 210, 210, 0.28);
|
||
}
|
||
|
||
.hub-postit-pin::after {
|
||
content: "";
|
||
position: absolute;
|
||
top: 15px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 2px;
|
||
height: 7px;
|
||
border-radius: 0 0 1px 1px;
|
||
background: linear-gradient(180deg, #c8c8c8 0%, #949494 45%, #6e6e6e 100%);
|
||
box-shadow:
|
||
0 5px 4px -1px rgba(15, 35, 52, 0.2),
|
||
0 0 0 3px rgba(15, 35, 52, 0.07),
|
||
1px 0 0 rgba(255, 255, 255, 0.35);
|
||
}
|
||
|
||
.hub-box--message .hub-box-title-row {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
margin-bottom: 2px;
|
||
}
|
||
|
||
.hub-message-icon {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
line-height: 0;
|
||
}
|
||
|
||
.hub-message-icon svg {
|
||
width: 22px;
|
||
height: 22px;
|
||
stroke: var(--hrm);
|
||
fill: none;
|
||
stroke-width: 2.4;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
}
|
||
|
||
.hub-box--message .hub-box-title-row .board-project-title {
|
||
text-align: center;
|
||
}
|
||
|
||
/* ─── 대시보드 본문 타이포 — 프로젝트 카드 · 허브 공통 ─── */
|
||
.board-project-title {
|
||
margin: 0;
|
||
color: #0a2e24;
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
line-height: 1.35;
|
||
font-family: inherit;
|
||
}
|
||
|
||
.board-project-desc {
|
||
margin: 0;
|
||
color: #5a6b62;
|
||
font-size: 20px;
|
||
font-weight: 500;
|
||
line-height: 1.45;
|
||
font-family: inherit;
|
||
}
|
||
|
||
/* 허브 3구역 — project-sub-title / project-field-value 와 동일 */
|
||
.hub-column .board-project-title {
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
line-height: 1.35;
|
||
color: #0a2e24;
|
||
}
|
||
|
||
.hub-column .board-project-desc {
|
||
font-size: 20px;
|
||
font-weight: 500;
|
||
line-height: 1.45;
|
||
font-family: inherit;
|
||
}
|
||
|
||
.hub-column .hub-routine-item {
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
line-height: 1.35;
|
||
font-family: inherit;
|
||
}
|
||
|
||
.hub-column .hub-schedule-month {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
line-height: 1.45;
|
||
color: #5a6b62;
|
||
}
|
||
|
||
.hub-box .board-project-title,
|
||
.hub-box .board-project-desc {
|
||
text-align: center;
|
||
}
|
||
|
||
.hub-list .board-project-desc {
|
||
padding: 1px 0;
|
||
text-align: center;
|
||
}
|
||
|
||
.hub-list {
|
||
list-style: none;
|
||
text-align: center;
|
||
padding: 0;
|
||
width: 100%;
|
||
}
|
||
|
||
.hub-box--focus {
|
||
background: transparent;
|
||
border: none;
|
||
box-shadow: none;
|
||
padding: 0 0 2px;
|
||
overflow: visible;
|
||
min-height: 0;
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
flex-direction: column;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.hub-box--focus .hub-schedule-planner {
|
||
flex: 1 1 auto;
|
||
height: 100%;
|
||
min-height: 0;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.hub-box--focus .hub-schedule-head {
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.hub-box--focus .hub-schedule-list {
|
||
flex: 1 1 auto;
|
||
min-height: 0;
|
||
justify-content: center;
|
||
padding: 0;
|
||
}
|
||
|
||
.hub-schedule-planner {
|
||
position: relative;
|
||
width: 100%;
|
||
height: auto;
|
||
min-height: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-start;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding:
|
||
calc(var(--hub-title-top) - var(--hub-head-pad-top) - var(--hub-head-offset-top))
|
||
var(--hub-card-pad-x)
|
||
var(--hub-card-pad-bottom);
|
||
background: linear-gradient(180deg, #faf8f3 0%, #f2ece3 100%);
|
||
border: 1px solid #ddd5c8;
|
||
border-radius: 6px;
|
||
box-shadow: 0 3px 12px rgba(15, 35, 52, 0.08);
|
||
overflow: visible;
|
||
}
|
||
|
||
.hub-schedule-planner::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 5px;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 52px;
|
||
height: 5px;
|
||
background: radial-gradient(circle, #bdb5a8 1.5px, transparent 1.5px) center / 13px 100% repeat-x;
|
||
opacity: 0.5;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.hub-schedule-head {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
width: calc(100% + var(--hub-card-pad-x) * 2);
|
||
margin: var(--hub-head-offset-top) calc(-1 * var(--hub-card-pad-x)) 0;
|
||
padding: var(--hub-head-pad-top) var(--hub-card-pad-x) var(--hub-head-pad-bottom);
|
||
background: linear-gradient(180deg, #f6f0e6 0%, #efe8dc 100%);
|
||
border-bottom: 1px solid #e4ddd2;
|
||
border-radius: 5px 5px 0 0;
|
||
}
|
||
|
||
.hub-schedule-head .board-project-title {
|
||
text-align: center;
|
||
}
|
||
|
||
.hub-schedule-icon {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
line-height: 0;
|
||
}
|
||
|
||
.hub-schedule-icon svg {
|
||
width: 22px;
|
||
height: 22px;
|
||
stroke: #8f8578;
|
||
fill: none;
|
||
stroke-width: 2.4;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
}
|
||
|
||
.hub-schedule-list {
|
||
list-style: none;
|
||
margin: 0;
|
||
padding: 4px 0 2px;
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 3px;
|
||
flex: 0 0 auto;
|
||
min-height: 0;
|
||
}
|
||
|
||
.hub-schedule-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 10px;
|
||
width: 100%;
|
||
max-width: 100%;
|
||
padding: 4px 0;
|
||
border-bottom: 1px dashed #e8e0d4;
|
||
}
|
||
|
||
.hub-schedule-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.hub-schedule-month {
|
||
flex-shrink: 0;
|
||
text-align: center;
|
||
}
|
||
|
||
.hub-schedule-item .board-project-desc {
|
||
margin: 0;
|
||
text-align: center;
|
||
line-height: 1.45;
|
||
flex: 0 1 auto;
|
||
}
|
||
|
||
.hub-box--focus .hub-list li::before {
|
||
content: none;
|
||
}
|
||
|
||
.hub-diamond-wrap {
|
||
z-index: 1;
|
||
min-height: 0;
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 0;
|
||
overflow: visible;
|
||
pointer-events: none;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.hub-diamond-wrap > * {
|
||
pointer-events: auto;
|
||
}
|
||
|
||
.hub-diamond-icon {
|
||
width: 36px;
|
||
height: 36px;
|
||
border: 2px solid var(--hrm);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--hrm);
|
||
font-size: 18px;
|
||
font-weight: 700;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.hub-diamond {
|
||
flex-shrink: 0;
|
||
transform: rotate(45deg);
|
||
background: #fff;
|
||
border: 2.5px solid var(--hrm);
|
||
box-shadow: 0 4px 18px rgba(7, 65, 46, 0.1);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.hub-diamond-inner {
|
||
transform: rotate(-45deg);
|
||
width: 88%;
|
||
text-align: center;
|
||
padding: 0 4px;
|
||
}
|
||
|
||
.hub-diamond-icon {
|
||
width: 38px;
|
||
height: 38px;
|
||
margin: 0 auto 6px;
|
||
border: 2px solid var(--hrm);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--hrm);
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.hub-diamond-title {
|
||
font-size: 18px;
|
||
font-weight: 800;
|
||
color: #1e3a5f;
|
||
margin-bottom: 6px;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.hub-diamond ul {
|
||
list-style: none;
|
||
text-align: center;
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
color: #334155;
|
||
font-weight: 500;
|
||
overflow: visible;
|
||
padding: 0;
|
||
}
|
||
|
||
.hub-diamond li {
|
||
padding: 1px 0;
|
||
}
|
||
|
||
.hub-diamond li::before {
|
||
content: "• ";
|
||
color: var(--hrm);
|
||
font-weight: 700;
|
||
}
|
||
|
||
@media (max-width: 1200px) {
|
||
.page-content {
|
||
overflow: auto;
|
||
}
|
||
|
||
.board-layout {
|
||
grid-template-columns: 1fr;
|
||
grid-template-rows: auto;
|
||
flex: none;
|
||
}
|
||
|
||
.connectors { display: none; }
|
||
|
||
.dept-card--hrm, .dept-card--hrd, .dept-card--ex, .dept-card--ga {
|
||
grid-column: 1;
|
||
grid-row: auto;
|
||
}
|
||
|
||
.hub-column {
|
||
grid-column: 1;
|
||
grid-row: auto;
|
||
order: -2;
|
||
display: flex;
|
||
flex-direction: column;
|
||
grid-template-rows: none;
|
||
--hub-band-h: none;
|
||
--hub-slogan-band-h: none;
|
||
}
|
||
|
||
.hub-box--message,
|
||
.hub-box--focus {
|
||
grid-row: auto;
|
||
max-height: none;
|
||
min-height: 0;
|
||
height: auto;
|
||
}
|
||
|
||
.hub-box--message { order: -3; }
|
||
.hub-diamond-wrap {
|
||
grid-row: auto;
|
||
order: -2;
|
||
flex: 0 0 auto;
|
||
height: auto;
|
||
min-height: 220px;
|
||
}
|
||
.hub-box--focus { order: -1; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body class="preview-page">
|
||
<!-- 상단바 (기존 DashboardHeader 스타일) -->
|
||
<header class="dashboard-header-bar">
|
||
<div class="side-left-group">
|
||
<span class="main_tit">
|
||
<span>총괄기획실</span>
|
||
<span>|</span>
|
||
<span>People Growth Hub</span>
|
||
</span>
|
||
<button type="button" class="team-status-btn-new" title="팀 현황" aria-label="팀 현황">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
|
||
<path d="M16 3.128a4 4 0 0 1 0 7.744"/>
|
||
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
|
||
<circle cx="9" cy="7" r="4"/>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="header-stats-bar side-polygon-stats">
|
||
<div class="poly-stat-item">
|
||
<span class="poly-stat-quarter header-stat-text">2026 2분기 업무</span>
|
||
<span class="poly-stat-bullet header-stat-text">·</span>
|
||
<span class="poly-click-stat active header-stat-text">전체 <span class="poly-stat-val stat-yellow">22</span><span class="poly-stat-unit"> 건</span></span>
|
||
<div class="poly-stat-divider" aria-hidden="true"></div>
|
||
<span class="poly-click-stat header-stat-text">진행 <span class="poly-stat-val stat-green">16</span><span class="poly-stat-unit"> 건</span></span>
|
||
<span class="poly-click-stat header-stat-text">보류 <span class="poly-stat-val stat-orange">4</span><span class="poly-stat-unit"> 건</span></span>
|
||
<span class="poly-click-stat header-stat-text">완료 <span class="poly-stat-val stat-gray">2</span><span class="poly-stat-unit"> 건</span></span>
|
||
<div class="poly-stat-divider" aria-hidden="true"></div>
|
||
<span class="poly-click-stat header-stat-text">이슈 <span class="poly-stat-val stat-red">5</span><span class="poly-stat-unit"> 건</span></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="side-right-actions">
|
||
<button type="button" class="header-action-btn-new" title="신규 프로젝트 추가" aria-label="신규 프로젝트 추가">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||
<path d="M5 12h14"/><path d="M12 5v14"/>
|
||
</svg>
|
||
</button>
|
||
<button type="button" class="header-view-btn-new" title="듀얼뷰" aria-label="듀얼뷰">
|
||
<div class="dual-monitor-icon-wrap">
|
||
<svg class="m-back" viewBox="0 0 24 24"><rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/></svg>
|
||
<svg class="m-front" viewBox="0 0 24 24"><rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/></svg>
|
||
</div>
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="page-content">
|
||
<div class="board-layout">
|
||
<!-- HRM -->
|
||
<section class="dept-card dept-card--hrm">
|
||
<div class="dept-head">
|
||
<div class="dept-head-main">
|
||
<div class="dept-icon dept-icon--hrm">
|
||
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
|
||
</div>
|
||
<div class="board-dept-header-main">
|
||
<div class="board-dept-title-wrap">
|
||
<h2 class="board-dept-title board-dept-title--hrm">인사관리</h2>
|
||
<span class="board-dept-title-en board-dept-title-en--hrm">HRM</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="dept-head-count dept-head-count--hrm" aria-label="2건">
|
||
<span class="poly-stat-val">2</span><span class="poly-stat-unit"> 건</span>
|
||
</div>
|
||
</div>
|
||
<div class="board-project-list">
|
||
<article class="project-sub-card project-sub-card--hrm">
|
||
<div class="project-sub-body">
|
||
<div class="project-fields">
|
||
<div class="project-field">
|
||
<span class="project-field-label">프로젝트명</span>
|
||
<span class="project-field-value">상반기 채용 운영</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">작업 기간</span>
|
||
<span class="project-field-value">2026.04 ~ 2026.06</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">주요 내용</span>
|
||
<span class="project-field-value">채용공고, 서류검토, 면접, 사후협의 진행</span>
|
||
</div>
|
||
</div>
|
||
<div class="project-sub-divider" aria-hidden="true"></div>
|
||
<div class="progress-col">
|
||
<div class="donut" style="--pct:75"><span>75%</span></div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
<article class="project-sub-card project-sub-card--hrm">
|
||
<div class="project-sub-body">
|
||
<div class="project-fields">
|
||
<div class="project-field">
|
||
<span class="project-field-label">프로젝트명</span>
|
||
<span class="project-field-value">평가제도 개선</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">기간</span>
|
||
<span class="project-field-value">2026.03 ~ 2026.07</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">주요 내용</span>
|
||
<span class="project-field-value">평가항목 정비, 부서 의견수렴, 피드백 방식 개선</span>
|
||
</div>
|
||
</div>
|
||
<div class="project-sub-divider" aria-hidden="true"></div>
|
||
<div class="progress-col">
|
||
<span class="progress-label">진행/달성률</span>
|
||
<div class="donut" style="--pct:60; --color:#ff9f0a"><span style="color:#ff9f0a">보류</span></div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- HRD -->
|
||
<section class="dept-card dept-card--hrd">
|
||
<div class="dept-head">
|
||
<div class="dept-head-main">
|
||
<div class="dept-icon dept-icon--hrd">
|
||
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><path d="M22 10v6M2 10l10-5 10 5-10 5z"/><path d="M6 12v5c0 1.7 3.3 3 7 3s7-1.3 7-3v-5"/></svg>
|
||
</div>
|
||
<div class="board-dept-header-main">
|
||
<div class="board-dept-title-wrap">
|
||
<h2 class="board-dept-title board-dept-title--hrd">인재육성</h2>
|
||
<span class="board-dept-title-en board-dept-title-en--hrd">HRD</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="dept-head-count dept-head-count--hrd" aria-label="2건">
|
||
<span class="poly-stat-val">2</span><span class="poly-stat-unit"> 건</span>
|
||
</div>
|
||
</div>
|
||
<div class="board-project-list">
|
||
<article class="project-sub-card project-sub-card--hrd">
|
||
<div class="project-sub-body">
|
||
<div class="project-fields">
|
||
<div class="project-field">
|
||
<span class="project-field-label">프로젝트명</span>
|
||
<span class="project-field-value">신규입사자 온보딩 프로그램</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">기간</span>
|
||
<span class="project-field-value">2026.04 ~ 2026.06</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">주요 내용</span>
|
||
<span class="project-field-value">신규입사자 교육, 조직 적응 프로그램 운영</span>
|
||
</div>
|
||
</div>
|
||
<div class="project-sub-divider" aria-hidden="true"></div>
|
||
<div class="progress-col">
|
||
<span class="progress-label">진행/달성률</span>
|
||
<div class="donut" style="--pct:85"><span>85%</span></div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
<article class="project-sub-card project-sub-card--hrd">
|
||
<div class="project-sub-body">
|
||
<div class="project-fields">
|
||
<div class="project-field">
|
||
<span class="project-field-label">프로젝트명</span>
|
||
<span class="project-field-value">팀장 리더십 교육</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">기간</span>
|
||
<span class="project-field-value">2026.05 ~ 2026.06</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">주요 내용</span>
|
||
<span class="project-field-value">팀장 대상 리더십·코칭·피드백 교육 실시</span>
|
||
</div>
|
||
</div>
|
||
<div class="project-sub-divider" aria-hidden="true"></div>
|
||
<div class="progress-col">
|
||
<span class="progress-label">진행/달성률</span>
|
||
<div class="donut" style="--pct:100; --color:#b0b0b0"><span style="color:#b0b0b0">완료</span></div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 중앙 허브 -->
|
||
<div class="hub-column" id="hub-column">
|
||
<!-- 분기 중점 과제 -->
|
||
<div class="hub-box hub-box--message">
|
||
<div class="hub-postit-stack">
|
||
<div class="hub-postit-sheet hub-postit-sheet--back" aria-hidden="true"></div>
|
||
<div class="hub-postit-sheet hub-postit-sheet--front">
|
||
<span class="hub-postit-pin" aria-hidden="true"></span>
|
||
<span class="hub-postit-fold" aria-hidden="true"></span>
|
||
<div class="hub-postit-content">
|
||
<div class="hub-postit-header">
|
||
<div class="hub-box-title-row">
|
||
<span class="hub-message-icon" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||
<circle cx="12" cy="12" r="10"/>
|
||
<circle cx="12" cy="12" r="6"/>
|
||
<circle cx="12" cy="12" r="2"/>
|
||
</svg>
|
||
</span>
|
||
<div class="board-project-title">분기 중점 과제</div>
|
||
</div>
|
||
</div>
|
||
<div class="hub-postit-message">
|
||
<p class="board-project-desc hub-postit-dept-line">
|
||
<span>인사</span><span>육성</span><span>문화</span><span>총무</span>
|
||
</p>
|
||
<p class="board-project-desc">개선과제</p>
|
||
<p class="board-project-desc">정상 추진</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 상시업무 -->
|
||
<div class="hub-diamond-wrap" id="hub-diamond-wrap">
|
||
<div class="hub-diamond" id="hub-diamond">
|
||
<div class="hub-diamond-inner">
|
||
<div class="hub-diamond-head">
|
||
<span class="hub-diamond-icon" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24"><path d="m17 2 4 4-4 4"/><path d="M3 11v-1a4 4 0 0 1 4-4h14"/><path d="m7 22-4-4 4-4"/><path d="M21 13v1a4 4 0 0 1-4 4H3"/></svg>
|
||
</span>
|
||
<div class="board-project-title">상시업무</div>
|
||
</div>
|
||
<div class="hub-diamond-divider" aria-hidden="true"></div>
|
||
<div class="hub-routine-grid">
|
||
<button type="button" class="hub-routine-item">채용 운영</button>
|
||
<button type="button" class="hub-routine-item">교육 운영</button>
|
||
<button type="button" class="hub-routine-item">운영 지원</button>
|
||
<button type="button" class="hub-routine-item">자산·시설</button>
|
||
<button type="button" class="hub-routine-item">문서·행정</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 분기 주요 일정 -->
|
||
<div class="hub-box hub-box--focus">
|
||
<div class="hub-schedule-planner">
|
||
<div class="hub-schedule-head">
|
||
<span class="hub-schedule-icon" aria-hidden="true">
|
||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||
<path d="M8 2v4"/>
|
||
<path d="M16 2v4"/>
|
||
<rect x="3" y="4" width="18" height="18" rx="2"/>
|
||
<path d="M3 10h18"/>
|
||
<path d="M8 14v.01"/>
|
||
<path d="M12 14v.01"/>
|
||
<path d="M16 14v.01"/>
|
||
</svg>
|
||
</span>
|
||
<div class="board-project-title">분기 주요 일정</div>
|
||
</div>
|
||
<ul class="hub-schedule-list">
|
||
<li class="hub-schedule-item">
|
||
<span class="hub-schedule-month">4월</span>
|
||
<span class="board-project-desc">평가제도 시행</span>
|
||
</li>
|
||
<li class="hub-schedule-item">
|
||
<span class="hub-schedule-month">5월</span>
|
||
<span class="board-project-desc">상반기 채용 마감</span>
|
||
</li>
|
||
<li class="hub-schedule-item">
|
||
<span class="hub-schedule-month">6월</span>
|
||
<span class="board-project-desc">복지·안전 점검</span>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- EX -->
|
||
<section class="dept-card dept-card--ex">
|
||
<div class="dept-head">
|
||
<div class="dept-head-main">
|
||
<div class="dept-icon dept-icon--ex">
|
||
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.51 4.04 3 5.5l7 7Z"/></svg>
|
||
</div>
|
||
<div class="board-dept-header-main">
|
||
<div class="board-dept-title-wrap">
|
||
<h2 class="board-dept-title board-dept-title--ex">조직문화</h2>
|
||
<span class="board-dept-title-en board-dept-title-en--ex">EX</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="dept-head-count dept-head-count--ex" aria-label="2건">
|
||
<span class="poly-stat-val">2</span><span class="poly-stat-unit"> 건</span>
|
||
</div>
|
||
</div>
|
||
<div class="board-project-list">
|
||
<article class="project-sub-card project-sub-card--ex">
|
||
<div class="project-sub-body">
|
||
<div class="project-fields">
|
||
<div class="project-field">
|
||
<span class="project-field-label">프로젝트명</span>
|
||
<span class="project-field-value">조직문화 진단</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">기간</span>
|
||
<span class="project-field-value">2026.04 ~ 2026.05</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">주요 내용</span>
|
||
<span class="project-field-value">만족도 조사, 직원 의견수렴, 개선과제 도출</span>
|
||
</div>
|
||
</div>
|
||
<div class="project-sub-divider" aria-hidden="true"></div>
|
||
<div class="progress-col">
|
||
<span class="progress-label">진행/달성률</span>
|
||
<div class="donut" style="--pct:100"><span>100%</span></div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
<article class="project-sub-card project-sub-card--ex">
|
||
<div class="project-sub-body">
|
||
<div class="project-fields">
|
||
<div class="project-field">
|
||
<span class="project-field-label">프로젝트명</span>
|
||
<span class="project-field-value">복리후생제도 개선</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">기간</span>
|
||
<span class="project-field-value">2026.05 ~ 2026.08</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">주요 내용</span>
|
||
<span class="project-field-value">복지제도 이용현황 분석, 개선안 검토</span>
|
||
</div>
|
||
</div>
|
||
<div class="project-sub-divider" aria-hidden="true"></div>
|
||
<div class="progress-col">
|
||
<span class="progress-label">진행/달성률</span>
|
||
<div class="donut" style="--pct:50; --color:#ff9f0a"><span style="color:#ff9f0a">보류</span></div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- GA -->
|
||
<section class="dept-card dept-card--ga">
|
||
<div class="dept-head">
|
||
<div class="dept-head-main">
|
||
<div class="dept-icon dept-icon--ga">
|
||
<svg viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round"><rect width="16" height="20" x="4" y="2" rx="2" ry="2"/><path d="M9 22v-4h6v4"/><path d="M8 6h.01"/><path d="M16 6h.01"/><path d="M12 6h.01"/><path d="M12 10h.01"/><path d="M12 14h.01"/><path d="M16 10h.01"/><path d="M16 14h.01"/><path d="M8 10h.01"/><path d="M8 14h.01"/></svg>
|
||
</div>
|
||
<div class="board-dept-header-main">
|
||
<div class="board-dept-title-wrap">
|
||
<h2 class="board-dept-title board-dept-title--ga">총무관리</h2>
|
||
<span class="board-dept-title-en board-dept-title-en--ga">GA</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="dept-head-count dept-head-count--ga" aria-label="2건">
|
||
<span class="poly-stat-val">2</span><span class="poly-stat-unit"> 건</span>
|
||
</div>
|
||
</div>
|
||
<div class="board-project-list">
|
||
<article class="project-sub-card project-sub-card--ga">
|
||
<div class="project-sub-body">
|
||
<div class="project-fields">
|
||
<div class="project-field">
|
||
<span class="project-field-label">프로젝트명</span>
|
||
<span class="project-field-value">사무공간 재배치</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">기간</span>
|
||
<span class="project-field-value">2026.04 ~ 2026.07</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">주요 내용</span>
|
||
<span class="project-field-value">좌석 재배치, 회의실 운영 개선</span>
|
||
</div>
|
||
</div>
|
||
<div class="project-sub-divider" aria-hidden="true"></div>
|
||
<div class="progress-col">
|
||
<span class="progress-label">진행/달성률</span>
|
||
<div class="donut" style="--pct:70"><span>70%</span></div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
<article class="project-sub-card project-sub-card--ga">
|
||
<div class="project-sub-body">
|
||
<div class="project-fields">
|
||
<div class="project-field">
|
||
<span class="project-field-label">프로젝트명</span>
|
||
<span class="project-field-value">안전·보안 점검 강화</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">기간</span>
|
||
<span class="project-field-value">2026.04 ~ 2026.06</span>
|
||
</div>
|
||
<div class="project-field">
|
||
<span class="project-field-label">주요 내용</span>
|
||
<span class="project-field-value">출입통제, 보안카드, 시설안전, 소방점검 관리</span>
|
||
</div>
|
||
</div>
|
||
<div class="project-sub-divider" aria-hidden="true"></div>
|
||
<div class="progress-col">
|
||
<span class="progress-label">진행/달성률</span>
|
||
<div class="donut" style="--pct:85"><span>85%</span></div>
|
||
</div>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 연결선: JS — 다이아몬드 ↔ 4부문 카드 (꺾임) -->
|
||
<svg class="connectors" aria-hidden="true">
|
||
<g id="connector-lines"></g>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
var SVG_NS = 'http://www.w3.org/2000/svg';
|
||
|
||
function relBox(el, parent) {
|
||
var r = el.getBoundingClientRect();
|
||
var p = parent.getBoundingClientRect();
|
||
return {
|
||
left: r.left - p.left,
|
||
top: r.top - p.top,
|
||
right: r.right - p.left,
|
||
bottom: r.bottom - p.top,
|
||
cx: r.left - p.left + r.width / 2,
|
||
cy: r.top - p.top + r.height / 2,
|
||
width: r.width,
|
||
height: r.height,
|
||
};
|
||
}
|
||
|
||
function diamondVertex(cx, cy, size, vertex) {
|
||
var r = size / Math.SQRT2;
|
||
if (vertex === 'top') return { x: cx, y: cy - r };
|
||
if (vertex === 'right') return { x: cx + r, y: cy };
|
||
if (vertex === 'bottom') return { x: cx, y: cy + r };
|
||
return { x: cx - r, y: cy };
|
||
}
|
||
|
||
function diamondEdgeMidpoint(cx, cy, size, edge) {
|
||
var d = size / (2 * Math.SQRT2);
|
||
if (edge === 'top-left') return { x: cx - d, y: cy - d };
|
||
if (edge === 'top-right') return { x: cx + d, y: cy - d };
|
||
if (edge === 'bottom-left') return { x: cx - d, y: cy + d };
|
||
return { x: cx + d, y: cy + d };
|
||
}
|
||
|
||
function cardEdgeAnchor(cardEl, layout, side, y) {
|
||
var cardBox = relBox(cardEl, layout);
|
||
y = Math.max(cardBox.top + 10, Math.min(cardBox.bottom - 10, y));
|
||
return {
|
||
x: side === 'right' ? cardBox.right : cardBox.left,
|
||
y: y,
|
||
};
|
||
}
|
||
|
||
var FACE_LINKS = [
|
||
{ edge: 'top-left', card: '.dept-card--hrm', side: 'right', vert: 'top', knee: 'left' },
|
||
{ edge: 'top-right', card: '.dept-card--hrd', side: 'left', vert: 'top', knee: 'right' },
|
||
{ edge: 'bottom-left', card: '.dept-card--ex', side: 'right', vert: 'bottom', knee: 'left' },
|
||
{ edge: 'bottom-right', card: '.dept-card--ga', side: 'left', vert: 'bottom', knee: 'right' },
|
||
];
|
||
|
||
function buildBentPath(cardAnchor, edgeMid, side, kneeX, approachX) {
|
||
var C = cardAnchor;
|
||
var M = edgeMid;
|
||
var minLeg = 18;
|
||
var x1 = kneeX;
|
||
|
||
if (side === 'right') {
|
||
if (x1 < C.x + minLeg) x1 = C.x + minLeg;
|
||
return [C, { x: x1, y: C.y }, { x: approachX, y: M.y }, M];
|
||
}
|
||
|
||
if (x1 > C.x - minLeg) x1 = C.x - minLeg;
|
||
return [C, { x: x1, y: C.y }, { x: approachX, y: M.y }, M];
|
||
}
|
||
|
||
function anchorYForSymmetricFace(cy, faceY, runX, vert) {
|
||
return vert === 'top' ? faceY + runX : faceY - runX;
|
||
}
|
||
|
||
function appendPath(lineGroup, points) {
|
||
var path = document.createElementNS(SVG_NS, 'path');
|
||
path.setAttribute('d', pointsToPath(points));
|
||
path.setAttribute('stroke', '#b0bcc8');
|
||
path.setAttribute('stroke-width', '2.5');
|
||
path.setAttribute('opacity', '0.85');
|
||
path.setAttribute('fill', 'none');
|
||
lineGroup.appendChild(path);
|
||
}
|
||
|
||
function drawPolyline(lineGroup, points) {
|
||
appendPath(lineGroup, points);
|
||
}
|
||
|
||
function snap(n) {
|
||
return Math.round(n * 2) / 2;
|
||
}
|
||
|
||
function pointsToPath(points) {
|
||
return points.map(function (p, i) {
|
||
return (i === 0 ? 'M' : 'L') + snap(p.x).toFixed(1) + ' ' + snap(p.y).toFixed(1);
|
||
}).join(' ');
|
||
}
|
||
|
||
function hubColumnBox(layout) {
|
||
var col = document.getElementById('hub-column');
|
||
return col ? relBox(col, layout) : null;
|
||
}
|
||
|
||
function fitDiamond() {
|
||
var wrap = document.getElementById('hub-diamond-wrap');
|
||
var diamond = document.getElementById('hub-diamond');
|
||
if (!wrap || !diamond || window.innerWidth <= 1200) return;
|
||
|
||
var rowW = wrap.clientWidth;
|
||
var rowH = wrap.clientHeight;
|
||
var fitInRow = 1.04 / Math.SQRT2;
|
||
var size = Math.min(rowW * fitInRow, rowH * fitInRow);
|
||
var scale = 0.9;
|
||
var col = document.getElementById('hub-column');
|
||
if (col) {
|
||
var v = getComputedStyle(col).getPropertyValue('--hub-diamond-scale').trim();
|
||
if (v) scale = parseFloat(v) || scale;
|
||
}
|
||
size = Math.max(Math.floor(size * scale), Math.floor(150 * scale));
|
||
diamond.style.width = size + 'px';
|
||
diamond.style.height = size + 'px';
|
||
}
|
||
|
||
function drawConnectors() {
|
||
var layout = document.querySelector('.board-layout');
|
||
var wrap = document.getElementById('hub-diamond-wrap');
|
||
var diamond = document.getElementById('hub-diamond');
|
||
var svg = document.querySelector('.connectors');
|
||
var lineGroup = document.getElementById('connector-lines');
|
||
if (!layout || !wrap || !diamond || !svg || !lineGroup) return;
|
||
|
||
fitDiamond();
|
||
|
||
if (window.innerWidth <= 1200) {
|
||
lineGroup.innerHTML = '';
|
||
svg.removeAttribute('viewBox');
|
||
return;
|
||
}
|
||
|
||
var layoutBox = layout.getBoundingClientRect();
|
||
var diamondBox = relBox(diamond, layout);
|
||
var diamondSize = diamond.offsetWidth;
|
||
var cx = diamondBox.cx;
|
||
var cy = diamondBox.cy;
|
||
|
||
svg.setAttribute('viewBox', '0 0 ' + layoutBox.width + ' ' + layoutBox.height);
|
||
lineGroup.innerHTML = '';
|
||
|
||
var topV = diamondVertex(cx, cy, diamondSize, 'top');
|
||
var bottomV = diamondVertex(cx, cy, diamondSize, 'bottom');
|
||
|
||
var msgBox = document.querySelector('.hub-postit-sheet--front');
|
||
var focusBox = document.querySelector('.hub-schedule-planner');
|
||
|
||
var hubBox = hubColumnBox(layout);
|
||
var hrmBox = document.querySelector('.dept-card--hrm');
|
||
var exBox = document.querySelector('.dept-card--ex');
|
||
var hrdBox = document.querySelector('.dept-card--hrd');
|
||
var gaBox = document.querySelector('.dept-card--ga');
|
||
var kneeXs = { left: 0, right: 0 };
|
||
|
||
if (hubBox && hrmBox && exBox) {
|
||
var innerLeft = Math.max(relBox(hrmBox, layout).right, relBox(exBox, layout).right);
|
||
kneeXs.left = (innerLeft + hubBox.left) / 2;
|
||
}
|
||
if (hubBox && hrdBox && gaBox) {
|
||
var innerRight = Math.min(relBox(hrdBox, layout).left, relBox(gaBox, layout).left);
|
||
kneeXs.right = (innerRight + hubBox.right) / 2;
|
||
}
|
||
|
||
var d = diamondSize / (2 * Math.SQRT2);
|
||
var approachGap = 32;
|
||
var leftApproachX = cx - d - approachGap;
|
||
var rightApproachX = cx + d + approachGap;
|
||
var leftRunX = Math.max(12, leftApproachX - kneeXs.left);
|
||
var rightRunX = Math.max(12, kneeXs.right - rightApproachX);
|
||
|
||
FACE_LINKS.forEach(function (link) {
|
||
var cardEl = document.querySelector(link.card);
|
||
if (!cardEl) return;
|
||
|
||
var edgeMid = diamondEdgeMidpoint(cx, cy, diamondSize, link.edge);
|
||
var runX = link.knee === 'left' ? leftRunX : rightRunX;
|
||
var approachX = link.knee === 'left' ? leftApproachX : rightApproachX;
|
||
var anchorY = anchorYForSymmetricFace(cy, edgeMid.y, runX, link.vert);
|
||
var cardAnchor = cardEdgeAnchor(cardEl, layout, link.side, anchorY);
|
||
var pathPoints = buildBentPath(cardAnchor, edgeMid, link.side, kneeXs[link.knee], approachX);
|
||
drawPolyline(lineGroup, pathPoints);
|
||
});
|
||
|
||
if (msgBox) {
|
||
var msg = relBox(msgBox, layout);
|
||
var msgAnchor = { x: cx, y: msg.bottom };
|
||
drawPolyline(lineGroup, [topV, msgAnchor]);
|
||
}
|
||
|
||
if (focusBox) {
|
||
var focus = relBox(focusBox, layout);
|
||
var focusAnchor = { x: cx, y: focus.top };
|
||
drawPolyline(lineGroup, [bottomV, focusAnchor]);
|
||
}
|
||
}
|
||
|
||
window.addEventListener('load', drawConnectors);
|
||
window.addEventListener('resize', drawConnectors);
|
||
if (document.fonts && document.fonts.ready) {
|
||
document.fonts.ready.then(function () {
|
||
requestAnimationFrame(function () {
|
||
requestAnimationFrame(drawConnectors);
|
||
});
|
||
});
|
||
}
|
||
|
||
var layoutEl = document.querySelector('.board-layout');
|
||
if (layoutEl && typeof ResizeObserver !== 'undefined') {
|
||
var resizeTimer;
|
||
new ResizeObserver(function () {
|
||
clearTimeout(resizeTimer);
|
||
resizeTimer = setTimeout(drawConnectors, 50);
|
||
}).observe(layoutEl);
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|