- 셸 = 위 머리 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>
108 lines
4.2 KiB
TypeScript
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();
|
|
}
|