WIP(style): UI 컴포넌트 하드코딩 제거 및 CSS 통합 (진행 중)
- 작업 상태: 진행 중 (Work In Progress) - 주요 변경 사항: 1. CSS 파일 통합: HWModal, SWModal, ListFactory 등에서 인라인 스타일(style 속성) 전면 제거 및 클래스 기반으로 재작성 2. 폰트/타이포그래피 스케일업: 최소 폰트 14px 기준으로 전체 텍스트 크기 상향 및 굵기(font-weight) 상향 조정 3. GNB(상단바) 레이아웃 개편: 2단 구조(로고 라인 / 메뉴 라인)로 변경 및 카테고리 텍스트 라벨 생략을 통한 간결화 4. 로고 이미지 교체: image 92.png로 업데이트 및 경로 정리 5. 디자인 가이드 분리: README에서 design_rule.md로 디자인 정책 문서 독립 * 참고: 현재 디자인 검토를 위한 중간 반영 상태이며, 피드백에 따라 추가 수정 예정임.
This commit is contained in:
@@ -22,39 +22,6 @@ class HwAssetModal extends BaseModal {
|
||||
|
||||
protected renderFrameHTML(): string {
|
||||
return `
|
||||
<style>
|
||||
.autocomplete-list {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-height: 150px;
|
||||
overflow-y: auto;
|
||||
background-color: white;
|
||||
border: 1px solid var(--border-color, #E2E8F0);
|
||||
border-top: none;
|
||||
border-radius: 0 0 4px 4px;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.autocomplete-item {
|
||||
padding: 8px 12px;
|
||||
font-size: 13px;
|
||||
color: #334155;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.autocomplete-item:hover {
|
||||
background-color: #F1F5F9;
|
||||
color: #1E5149;
|
||||
font-weight: 600;
|
||||
}
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
<div id="hw-asset-modal" class="modal-overlay hidden">
|
||||
<div class="modal-content wide">
|
||||
<div class="modal-header">
|
||||
@@ -100,14 +67,14 @@ class HwAssetModal extends BaseModal {
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>${ASSET_SCHEMA.SERVICE_TYPE.ui}</label>
|
||||
<select id="hw-service_type" name="service_type" style="${inputStyle}">
|
||||
<select id="hw-service_type" name="service_type">
|
||||
<option value="외부">외부</option>
|
||||
<option value="내부">내부</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group full-width" style="grid-column: span 2;">
|
||||
<div class="form-group full-width">
|
||||
<label>${ASSET_SCHEMA.ASSET_PURPOSE.ui}</label>
|
||||
<input type="text" id="hw-asset_purpose" name="asset_purpose" placeholder="자산의 용도를 입력하세요" style="${inputStyle} width: 100%;" />
|
||||
<input type="text" id="hw-asset_purpose" name="asset_purpose" placeholder="자산의 용도를 입력하세요" />
|
||||
</div>
|
||||
<div class="form-group infra-only monitoring-field">
|
||||
<label>${ASSET_SCHEMA.MONITORING.ui}</label>
|
||||
@@ -118,18 +85,18 @@ class HwAssetModal extends BaseModal {
|
||||
</div>
|
||||
|
||||
<!-- [SECTION 2] 조직 및 사용자 정보 -->
|
||||
<div class="form-section-title" style="margin-top: 24px; margin-bottom: 12px;">사용자 및 조직 정보</div>
|
||||
<div class="form-group">
|
||||
<div class="form-section-title org-user-section">사용자 및 조직 정보</div>
|
||||
<div class="form-group org-user-field">
|
||||
<label>${ASSET_SCHEMA.CURRENT_DEPT.ui}</label>
|
||||
<select id="hw-current_dept" name="current_dept">${generateOptionsHTML(ORG_LIST)}</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="form-group org-user-field">
|
||||
<label>${ASSET_SCHEMA.MANAGER_MAIN.ui}</label>
|
||||
<input type="text" id="hw-manager_primary" name="manager_primary" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>${ASSET_SCHEMA.MANAGER_SUB.ui}</label>
|
||||
<input type="text" id="hw-manager_secondary" name="manager_secondary" style="${inputStyle}" />
|
||||
<input type="text" id="hw-manager_secondary" name="manager_secondary" />
|
||||
</div>
|
||||
<div class="form-group personal-only">
|
||||
<label>${ASSET_SCHEMA.CURRENT_USER.ui}</label>
|
||||
@@ -164,17 +131,17 @@ class HwAssetModal extends BaseModal {
|
||||
</div>
|
||||
<div class="form-group spec-only" style="position: relative;">
|
||||
<label>${ASSET_SCHEMA.CPU.ui}</label>
|
||||
<input type="text" id="hw-cpu" name="cpu" autocomplete="off" placeholder="CPU 부품 검색..." style="${inputStyle}" />
|
||||
<input type="text" id="hw-cpu" name="cpu" autocomplete="off" placeholder="CPU 부품 검색..." />
|
||||
<div id="hw-cpu-autocomplete" class="autocomplete-list hidden"></div>
|
||||
</div>
|
||||
<div class="form-group spec-only" style="position: relative;">
|
||||
<label>${ASSET_SCHEMA.RAM.ui}</label>
|
||||
<input type="text" id="hw-ram" name="ram" autocomplete="off" placeholder="RAM 부품 검색..." style="${inputStyle}" />
|
||||
<input type="text" id="hw-ram" name="ram" autocomplete="off" placeholder="RAM 부품 검색..." />
|
||||
<div id="hw-ram-autocomplete" class="autocomplete-list hidden"></div>
|
||||
</div>
|
||||
<div class="form-group spec-only" style="position: relative;">
|
||||
<label>${ASSET_SCHEMA.GPU.ui}</label>
|
||||
<input type="text" id="hw-gpu" name="gpu" autocomplete="off" placeholder="GPU 부품 검색..." style="${inputStyle}" />
|
||||
<input type="text" id="hw-gpu" name="gpu" autocomplete="off" placeholder="GPU 부품 검색..." />
|
||||
<div id="hw-gpu-autocomplete" class="autocomplete-list hidden"></div>
|
||||
</div>
|
||||
<div class="form-group spec-only">
|
||||
@@ -183,7 +150,7 @@ class HwAssetModal extends BaseModal {
|
||||
</div>
|
||||
<div class="form-group spec-only">
|
||||
<label>성능 등급</label>
|
||||
<div id="hw-pc-grade-container" style="display: flex; align-items: center; height: 38px;">
|
||||
<div id="hw-pc-grade-container" class="grade-badge-container">
|
||||
<span class="badge b-yellow" id="hw-pc-grade-badge">-</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -266,7 +233,10 @@ class HwAssetModal extends BaseModal {
|
||||
<div class="modal-history-area">
|
||||
<div class="history-header">
|
||||
<h3>자산 변동 이력</h3>
|
||||
<button type="button" id="btn-add-hw-log" class="btn btn-outline btn-sm">이력 추가</button>
|
||||
<div class="history-actions">
|
||||
<button type="button" id="btn-view-asset-flow" class="btn btn-outline btn-sm">흐름 보기</button>
|
||||
<button type="button" id="btn-add-hw-log" class="btn btn-outline btn-sm">이력 추가</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="hw-history-list" class="history-timeline"></div>
|
||||
</div>
|
||||
|
||||
@@ -24,93 +24,111 @@ const MENU_CONFIG: any = {
|
||||
};
|
||||
|
||||
export function renderNavigation(onTabChange: (tab: string) => void) {
|
||||
const navContainer = document.getElementById('main-nav')!;
|
||||
const headerContainer = document.querySelector('.header-container')!;
|
||||
if (!headerContainer) return;
|
||||
|
||||
const render = () => {
|
||||
navContainer.innerHTML = '';
|
||||
// 1. 헤더 레이아웃 구조 생성
|
||||
headerContainer.innerHTML = `
|
||||
<!-- [TOP ROW] 로고 및 사용자 액션 -->
|
||||
<div class="header-top-row">
|
||||
<div class="brand" id="btn-home-logo" style="cursor: pointer;">
|
||||
<img src="img/image_92.png" class="main-logo" alt="HM Logo" />
|
||||
<h1>IT 자산 통합 관리 <span class="sub-title">ITAM</span></h1>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<div class="role-switcher">
|
||||
<span class="role-label user ${state.currentUserRole === 'user' ? 'active' : ''}">실무자</span>
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="role-toggle-checkbox" ${state.currentUserRole === 'admin' ? 'checked' : ''}>
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span class="role-label admin ${state.currentUserRole === 'admin' ? 'active' : ''}">관리자</span>
|
||||
</div>
|
||||
<div class="notification-area">
|
||||
<button class="icon-btn" title="알림"><i data-lucide="bell" style="width:18px; height:18px;"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- [BOTTOM ROW] 통합 내비게이션 (2단 메뉴) -->
|
||||
<div class="header-bottom-row">
|
||||
<nav class="integrated-nav" id="main-nav-list"></nav>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const navList = document.getElementById('main-nav-list')!;
|
||||
|
||||
// 기존 메뉴 렌더링
|
||||
// 2. 메뉴 그룹화 및 렌더링 (대분류 제목 제외, 간격으로 구분)
|
||||
(Object.keys(MENU_CONFIG) as Array<keyof typeof MENU_CONFIG>).forEach(catKey => {
|
||||
const config = MENU_CONFIG[catKey];
|
||||
|
||||
// 역할에 따라 노출할 서브탭 필터링
|
||||
const visibleTabs = config.tabs.filter((tab: string) => {
|
||||
if (state.currentUserRole === 'admin') {
|
||||
// 관리자(admin)일 경우 대시보드 탭만 노출
|
||||
return tab === '대시보드';
|
||||
} else {
|
||||
// 실무자(user)일 경우 대시보드 제외한 모든 탭 노출
|
||||
return tab !== '대시보드';
|
||||
}
|
||||
if (state.currentUserRole === 'admin') return tab === '대시보드';
|
||||
return tab !== '대시보드';
|
||||
});
|
||||
|
||||
// 노출할 서브탭이 없으면 해당 대분류 GNB 메뉴도 렌더링하지 않음
|
||||
if (visibleTabs.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isActive = state.activeCategory === catKey;
|
||||
if (visibleTabs.length === 0) return;
|
||||
|
||||
const group = document.createElement('div');
|
||||
group.className = `nav-group ${isActive ? 'active is-showing-shelf' : ''}`;
|
||||
group.className = 'nav-group';
|
||||
|
||||
const trigger = document.createElement('div');
|
||||
trigger.className = 'gnb-trigger';
|
||||
trigger.textContent = config.label;
|
||||
const itemsContainer = document.createElement('div');
|
||||
itemsContainer.className = 'nav-group-items';
|
||||
|
||||
trigger.addEventListener('click', () => {
|
||||
if (state.activeCategory !== catKey) {
|
||||
state.activeCategory = catKey as any;
|
||||
const firstTab = visibleTabs[0] || config.tabs[0];
|
||||
state.activeSubTab = firstTab;
|
||||
render();
|
||||
onTabChange(firstTab);
|
||||
}
|
||||
});
|
||||
group.appendChild(trigger);
|
||||
|
||||
const shelf = document.createElement('div');
|
||||
shelf.className = 'lnb-shelf';
|
||||
|
||||
visibleTabs.forEach((tab: string) => {
|
||||
if (tab === '부품 마스터') return; // 메뉴바에서 표시 생략
|
||||
if (tab === '부품 마스터') return;
|
||||
const item = document.createElement('div');
|
||||
item.className = `lnb-item ${isActive && state.activeSubTab === tab ? 'active' : ''}`;
|
||||
const isActive = state.activeSubTab === tab;
|
||||
item.className = `gnb-trigger ${isActive ? 'active' : ''}`;
|
||||
item.textContent = tab;
|
||||
|
||||
item.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
state.activeCategory = catKey as any;
|
||||
state.activeSubTab = tab;
|
||||
render();
|
||||
render(); // 재렌더링하여 활성 상태 반영
|
||||
onTabChange(tab);
|
||||
});
|
||||
shelf.appendChild(item);
|
||||
itemsContainer.appendChild(item);
|
||||
});
|
||||
group.appendChild(shelf);
|
||||
navContainer.appendChild(group);
|
||||
|
||||
group.appendChild(itemsContainer);
|
||||
navList.appendChild(group);
|
||||
});
|
||||
|
||||
// ─── '관리자' 메뉴 별도 추가 (GNB 스타일 - 관리자 역할일 때만 노출) ───
|
||||
// 3. 관리자 전용 '관리도구' (원래 '관리자' 메뉴)
|
||||
if (state.currentUserRole === 'admin') {
|
||||
const adminGroup = document.createElement('div');
|
||||
adminGroup.className = 'nav-group';
|
||||
|
||||
const adminTrigger = document.createElement('div');
|
||||
adminTrigger.className = 'gnb-trigger';
|
||||
adminTrigger.innerHTML = '관리자';
|
||||
adminTrigger.style.color = 'var(--text-muted)';
|
||||
adminTrigger.style.borderLeft = '1px solid var(--border-color)';
|
||||
adminTrigger.style.marginLeft = '1rem';
|
||||
adminTrigger.style.paddingLeft = '1.5rem';
|
||||
|
||||
adminTrigger.addEventListener('click', () => {
|
||||
window.open('/map_editor.html', '_blank');
|
||||
});
|
||||
|
||||
adminTrigger.className = 'gnb-trigger admin-trigger';
|
||||
adminTrigger.innerHTML = '관리도구';
|
||||
adminTrigger.addEventListener('click', () => window.open('/map_editor.html', '_blank'));
|
||||
adminGroup.appendChild(adminTrigger);
|
||||
navContainer.appendChild(adminGroup);
|
||||
navList.appendChild(adminGroup);
|
||||
}
|
||||
|
||||
// 4. 이벤트 바인딩 (로고 클릭 및 역할 전환)
|
||||
document.getElementById('btn-home-logo')?.addEventListener('click', () => location.reload());
|
||||
|
||||
const roleToggle = document.getElementById('role-toggle-checkbox') as HTMLInputElement;
|
||||
roleToggle?.addEventListener('change', () => {
|
||||
state.currentUserRole = roleToggle.checked ? 'admin' : 'user';
|
||||
if (state.currentUserRole === 'admin') {
|
||||
state.activeCategory = 'hw';
|
||||
state.activeSubTab = '대시보드';
|
||||
} else {
|
||||
state.activeCategory = 'hw';
|
||||
state.activeSubTab = '서버';
|
||||
}
|
||||
render();
|
||||
onTabChange(state.activeSubTab);
|
||||
});
|
||||
|
||||
// 아이콘 생성
|
||||
// @ts-ignore
|
||||
if (window.lucide) window.lucide.createIcons();
|
||||
};
|
||||
|
||||
render();
|
||||
|
||||
Reference in New Issue
Block a user