Files
Aislo/B01_Dashboard/B01_Dashboard_UI_Nav.ts
T
eomsangdonandClaude Opus 5.5 e505f4014d feat(B01): 대시보드 새 틀 — 셸 · 왼쪽 메뉴 · 세부 페이지 등록부 (546-1)
- 셸 = 위 머리 48(AISLO · 회사 이름 — 시스템 관리자 회사 전환 · 찾기 자리 · [?] · 알림 자리 · 사용자 메뉴) + 왼쪽 메뉴 210 + 챗봇 단추
- 등록부 B01_Dashboard_UI_Views.ts — { key, title, group, roles, icon, mount(host, ctx) } · 주소 ?view= · 같은 주소 안 이동 = 페이지만 갈아 끼움(MountedPage)
- 역할 넷(일반 · 회사 관리자 · 산림청 · 시스템 관리자) · 권한 없는 묶음 · 항목 숨김 · 권한 없는 열쇠 = 홈
- 열쇠마다 옛 구역 부품 그대로 얹음(B01_Dashboard_UI_Legacy.ts) — 기능 빠짐 0
- 옛 ☰ 서랍 · 구역 접기 · 회사 알약 걷음 — 테마 · 언어 · 터치 · 설정 · 로그아웃은 사용자 메뉴로
- 아이콘 = Tabler(MIT) 선 아이콘 몇 개(ui_template_icons.ts · 라이센스 글 함께)
- 시험 — test_b01_settings_cards 옛 한 페이지 단정(buildPage · 접힘 · 알약) 지움 · 셸 회사 고르기 단정으로 바꿈 · test_546_b01_shell 새로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 18:05:56 +09:00

108 lines
4.2 KiB
TypeScript

/* =============================================================================
* B01_Dashboard_UI_Nav.ts
* 대시보드 왼쪽 메뉴(546) — 묶음(작업 · 회사 관리 · 시스템 관리 · 도움) · 권한 없는 항목 · 빈 묶음 숨김
* 항목 = 주소 링크(뒤로 가기 · 새 탭) · 지금 위치 강조 · 오른쪽 수 배지 · 작은 화면 = 아이콘 레일(CSS)
* 도움 묶음 페이지(가이드 · 챗봇)도 여기 — 창을 여는 일만 함
* ========================================================================== */
import { ROUTES } from "@config/config_frontend";
import { createButton } from "@ui/ui_template_elements";
import { icon } from "@ui/ui_template_icons";
import { createHelpButton } from "@ui/ui_template_help";
import type { View, ViewGroup } from "./B01_Dashboard_UI_Views";
const GROUPS: [ViewGroup, string][] = [
["work", "작업"],
["company", "회사 관리"],
["system", "시스템 관리"],
["help", "도움"],
];
export const viewHref = (key: string, params: Record<string, string> = {}): string =>
`#/${ROUTES.B01_ACCOUNT}?${new URLSearchParams({ view: key, ...params })}`;
export interface DashboardNav {
root: HTMLElement;
setActive: (key: string) => void;
/** 수 배지 — 0 이하면 숨김 · alert = 빨강(처리할 일) */
setBadge: (key: string, count: number, alert?: boolean) => void;
}
/** views = 이 역할에 보이는 것만 받음 */
export function buildNav(views: View[]): DashboardNav {
const root = document.createElement("nav");
root.className = "b01-shell__nav";
root.setAttribute("aria-label", "대시보드 메뉴");
const items = new Map<string, HTMLAnchorElement>();
for (const [group, label] of GROUPS) {
const inGroup = views.filter((v) => v.group === group);
if (!inGroup.length) continue;
const head = document.createElement("div");
head.className = "b01-shell__nav-group";
head.textContent = label;
root.append(head);
for (const view of inGroup) {
const a = document.createElement("a");
a.className = "b01-shell__nav-item";
a.href = viewHref(view.key);
a.title = view.title;
a.dataset.view = view.key;
const text = document.createElement("span");
text.className = "b01-shell__nav-label";
text.textContent = view.title;
const badge = document.createElement("span");
badge.className = "b01-shell__badge";
badge.hidden = true;
a.append(icon(view.icon ?? "home"), text, badge);
root.append(a);
items.set(view.key, a);
}
}
return {
root,
setActive: (key) => {
for (const [k, a] of items) {
a.classList.toggle("is-active", k === key);
if (k === key) a.setAttribute("aria-current", "page");
else a.removeAttribute("aria-current");
}
},
setBadge: (key, count, alert = false) => {
const badge = items.get(key)?.querySelector<HTMLElement>(".b01-shell__badge");
if (!badge) return;
badge.hidden = count <= 0;
badge.textContent = String(count);
badge.classList.toggle("is-alert", alert);
},
};
}
function helpCard(text: string, action: HTMLElement): HTMLElement {
const card = document.createElement("div");
card.className = "b01-shell__card b01-shell__help";
const p = document.createElement("p");
p.textContent = text;
card.append(p, action);
return card;
}
/** 사용자 가이드 — 위 머리 [?] 와 같은 창을 엶 */
export function mountGuide(host: HTMLElement): void {
const button = createHelpButton();
host.append(helpCard("대시보드 사용법을 그림과 함께 봅니다.", button));
button.click();
}
/** 지식 챗봇 — 오른쪽 아래 둥근 단추 창을 엶 */
export function mountChat(host: HTMLElement): void {
const toggle = (): HTMLButtonElement | null =>
document.querySelector<HTMLButtonElement>(".b01-knowledge-chat__toggle");
const open = (): void => {
const t = toggle();
if (t?.getAttribute("aria-expanded") !== "true") t?.click();
};
const button = createButton({ label: "챗봇 열기", variant: "filled", onClick: open });
host.append(helpCard("임도 · 사방 법령과 기술 자료를 물어봅니다.", button));
open();
}