feat(org-chart): finalize chart features and AI generation rules

This commit is contained in:
shkim4 committed 2026-10-13 14:39:42 +09:00
1 parent 7614507583
commit d0828a7ff4
80 files changed
+8152 -221

No files matched your search

@@ -19,6 +19,13 @@ export function decorateExpandedNode(node: HTMLElement, value: RenderEngineNode,
node.dataset.organizationType = organization.type;
node.dataset.companyId = companyId;
node.dataset.collapsed = String(collapsed);
node.draggable = false;
const counts = context.summary.raw.byOrganization[organization.id];
node.dataset.directEmployeeCount = String(counts?.direct ?? 0);
node.dataset.inclusiveEmployeeCount = String(counts?.inclusive ?? 0);
const vertical = value.vertical === true || (context.autoLayout?.type === 'hybrid' && Number(value.depth) + 1 >= context.autoLayout.hybridStartDepth);
node.dataset.verticalLayout = String(vertical);
const layoutDirection = context.autoLayout?.type === 'lr' || vertical ? 'left' : 'top';
node.style.setProperty('--hm-orgchart-expanded-primary', preset.primary);
node.style.setProperty('--hm-orgchart-expanded-title-ink', ['saman', 'jangheon-industry'].includes(companyId) ? 'var(--hm-orgchart-resolved-fg-primary)' : 'var(--hm-orgchart-resolved-on-action-primary)');
preset.secondary.forEach((color, index) => node.style.setProperty(`--hm-orgchart-expanded-secondary-${index + 1}`, color));
@@ -34,10 +41,11 @@ export function decorateExpandedNode(node: HTMLElement, value: RenderEngineNode,
button.className = 'hm-orgchart-expanded-toggle';
button.dataset.organizationId = organization.id;
button.textContent = `${top?.organizationName ?? organization.name} ${hasChildren ? collapsed ? '▸' : '▾' : '·'}`;
button.setAttribute('aria-label', `${top?.organizationName ?? organization.name} 하위 조직·직원`);
button.setAttribute('aria-label', `${top?.organizationName ?? organization.name} 하위 조직·직원 · 직접 ${counts?.direct ?? 0}명 · 하위 포함 ${counts?.inclusive ?? 0}명`);
button.setAttribute('aria-expanded', String(!collapsed));
button.disabled = !hasChildren;
button.addEventListener('click', event => { event.stopPropagation(); context.toggleExpanded?.(organization.id); }, { signal });
// Empty titles remain focusable move sources/targets. Collapse is independent.
button.setAttribute('aria-disabled', String(!hasChildren || context.interactions?.collapse === false));
button.addEventListener('click', event => { event.stopPropagation(); if (hasChildren && context.interactions?.collapse !== false) context.toggleExpanded?.(organization.id); }, { signal });
heading.append(button);
const href = context.organizationLinks?.[organization.id];
if (href) {
@@ -51,6 +59,7 @@ export function decorateExpandedNode(node: HTMLElement, value: RenderEngineNode,
}
article.append(heading);
const colorCard = (card: HTMLElement, affiliationId: string) => {
card.draggable = false;
const employeePreset = getCompanyColorPreset(affiliationId) ?? preset;
card.dataset.companyId = employeePreset.companyId;
card.style.setProperty('--hm-orgchart-expanded-card-primary', `var(--hm-orgchart-company-${employeePreset.companyId})`);
@@ -59,7 +68,7 @@ export function decorateExpandedNode(node: HTMLElement, value: RenderEngineNode,
if (leader && top?.display !== 'hidden' && top?.display !== 'titleOnly') {
const presentation = top ? { ...leader, position: top.title ?? leader.position, name: top.name ?? leader.name, profileImage: top.profileImage === undefined ? leader.profileImage : top.profileImage } : leader;
const card = colorCard(createEmployeeCard(document, presentation, { kind: organization.parentId === null ? 'topLeader' : 'leader', expandedPresentation: true, hideStatusLabel: true }, signal), leader.affiliationId);
card.dataset.connectionDirection = 'top';
card.dataset.connectionDirection = context.autoLayout?.type === 'lr' ? 'left' : 'top';
article.append(card);
} else if (leader && top?.display === 'titleOnly') {
const title = document.createElement('p');
@@ -70,7 +79,7 @@ export function decorateExpandedNode(node: HTMLElement, value: RenderEngineNode,
if (!collapsed && staff.length) {
const employees = document.createElement('div');
employees.className = 'hm-orgchart-employees';
const direction = context.employeeConnections?.[organization.id] ?? 'top';
const direction = context.employeeConnections?.[organization.id] ?? layoutDirection;
employees.dataset.connectionDirection = direction;
for (const employee of staff) {
const card = colorCard(createEmployeeCard(document, employee, { kind: 'employee', expandedPresentation: true, hideStatusLabel: true }, signal), employee.affiliationId);
@@ -86,6 +95,10 @@ export function createExpandedOrgChartContent(document: Document, context: Rende
content.className = 'hm-orgchart-expanded';
content.dataset.component = 'ExpandedOrgChartContent';
content.dataset.layoutMode = 'auto';
content.dataset.autoLayout = context.autoLayout?.type ?? 'tb';
content.dataset.hybridStartDepth = String(context.autoLayout?.hybridStartDepth ?? 3);
content.dataset.initialVisibleDepth = String(context.autoLayout?.initialVisibleDepth ?? 'all');
content.dataset.groupHybrid = String(!!context.autoLayout?.hybridOrganizationIds.length);
content.dataset.layoutStatus = 'hierarchical';
content.dataset.cardDesignStatus = 'current-presentation';
for (const company of new Set([...context.organizationCompanies!.values(), ...context.data.employees.map(employee => employee.affiliationId)])) {
@@ -94,6 +107,6 @@ export function createExpandedOrgChartContent(document: Document, context: Rende
}
tree.setAttribute('aria-label', '확장형 조직 계층도 · Ctrl 또는 Command + 휠로 확대 · 드래그로 이동');
content.append(createHeading(document, context), tree);
alignExpandedLevels(tree, signal, layoutReady);
alignExpandedLevels(tree, signal, layoutReady, context.autoLayout);
return content;
}