- 개요 = 숫자 카드 넷 + CPU · 메모리 · 디스크 게이지(70 % 주황 · 90 % 빨강) + 7 일 SVG 그래프 - 회사 = 목록(찾기 · ⋯) → 상세(정보 · 사람 · 프로젝트 탭) · 사용자 = 회사 · 역할 · 찾기 거르기 · ⋯ - 설계 기본값 = 설정 카드를 묶음 제목 + 줄로 · 시스템 로그 = 동작 · 기간 · 찾기 거르기 + 이전 기록 더 보기 - 내 정보 = Linear 꼴 설정 줄(기본정보 · 비밀번호 · 테마 · 내 설계 기본값) - 옛 구역(리소스 패널 · 옛 내 정보 폼) 지움 · 지킴 시험 test_549 추가 · test_546 stub 맞춤 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
83 lines
3.0 KiB
TypeScript
83 lines
3.0 KiB
TypeScript
/* =============================================================================
|
|
* B01_Dashboard_UI_View_Parts.ts
|
|
* 시스템 관리 · 내 정보 페이지(549-2) 곁부품 — 불러오기 틀 · 거르기 줄 · 묶음 제목.
|
|
* 공용 조각(`B01_Dashboard_UI_PageKit.ts` · sub4)에 없는 것만 · 모양은 `Style_Pages.css` 아래 「시스템 관리」 쪽.
|
|
* ========================================================================== */
|
|
|
|
import { createButton } from "@ui/ui_template_elements";
|
|
import { emptyState } from "./B01_Dashboard_UI_PageKit";
|
|
|
|
export const el = <K extends keyof HTMLElementTagNameMap>(
|
|
tag: K,
|
|
className = "",
|
|
text?: string,
|
|
): HTMLElementTagNameMap[K] => {
|
|
const node = document.createElement(tag);
|
|
if (className) node.className = className;
|
|
if (text !== undefined) node.textContent = text;
|
|
return node;
|
|
};
|
|
|
|
/**
|
|
* 자료를 읽는 동안 안내 → 다 읽으면 build 가 stage 에 그린 것으로 바꿈.
|
|
* 실패하면 까닭 + [다시 시도] · 그 사이 떠났으면(host 떨어짐) 안 그림.
|
|
*/
|
|
export function loadPage(host: HTMLElement, build: (stage: HTMLElement) => Promise<void>): void {
|
|
const run = (): void => {
|
|
host.replaceChildren(el("p", "b01-sys-loading", "불러오는 중…"));
|
|
const stage = el("div", "b01-sys-stage");
|
|
build(stage).then(
|
|
() => host.isConnected && host.replaceChildren(...stage.childNodes),
|
|
(error: unknown) => {
|
|
if (!host.isConnected) return;
|
|
const retry = createButton({ label: "다시 시도", variant: "ghost", onClick: run });
|
|
const page = el("div", "b01-pg");
|
|
page.append(
|
|
emptyState({
|
|
icon: "bell",
|
|
text: error instanceof Error ? error.message : "불러오지 못했습니다.",
|
|
action: retry,
|
|
}),
|
|
);
|
|
host.replaceChildren(page);
|
|
},
|
|
);
|
|
};
|
|
run();
|
|
}
|
|
|
|
/** 거르기 줄 */
|
|
export function toolbar(...items: HTMLElement[]): HTMLElement {
|
|
const bar = el("div", "b01-sys-tool");
|
|
bar.append(...items);
|
|
return bar;
|
|
}
|
|
|
|
export function searchBox(placeholder: string, onInput: (value: string) => void): HTMLInputElement {
|
|
const input = el("input", "b01-sys-input");
|
|
input.type = "search";
|
|
input.placeholder = placeholder;
|
|
input.ariaLabel = placeholder;
|
|
input.addEventListener("input", () => onInput(input.value.trim().toLowerCase()));
|
|
return input;
|
|
}
|
|
|
|
export function selectBox(
|
|
label: string,
|
|
options: [value: string, text: string][],
|
|
onChange: (value: string) => void,
|
|
): HTMLSelectElement {
|
|
const select = el("select", "b01-sys-input");
|
|
select.ariaLabel = label;
|
|
for (const [value, text] of options) select.append(new Option(text, value));
|
|
select.addEventListener("change", () => onChange(select.value));
|
|
return select;
|
|
}
|
|
|
|
/** 묶음 — 제목 + 아래 내용(설정 카드 · 표) */
|
|
export function group(title: string, content: Node): HTMLElement {
|
|
const box = el("section", "b01-sys-group");
|
|
box.append(el("h3", "b01-sys-group__title", title), content);
|
|
return box;
|
|
}
|