/// /// const makeLeftStatusBar = (): HTMLDivElement => { const style = document.createElement("style"); style.textContent = `.status-bar.left { left: 0; right: unset; } .status-bar > div:first-of-type { border-top-left-radius: unset; } .status-bar > div:last-of-type { border-top-right-radius: 3px; }`; document.head.append(style); const statusBar = document.createElement("div"); statusBar.classList.add("status-bar", "left"); const app = document.getElementsByClassName("app")[0]!; app.append(statusBar); return statusBar; }; const bar = makeLeftStatusBar(); export interface UseStatusBarResult { /** 取得した.status-barの領域に情報を表示する */ render: (items: Item[], onClick?: (e: TouchEvent) => void) => void; /** 取得した.statusb-barの領域を削除する */ dispose: () => void; } /** .status-barの一区画を取得し、各種操作函数を返す */ export const useStatusBar = (): UseStatusBarResult => { const status = document.createElement("div"); bar.append(status); let listener: ((e: TouchEvent) => void) | undefined; return { render: (items, onClick) => { status.textContent = ""; if (listener) status.removeEventListener("touchstart", listener); listener = onClick; const child = makeGroup(...items); if (child) { if (listener) status.addEventListener("touchstart", listener); status.append(child); } }, dispose: () => status.remove(), }; }; export interface ItemGroup { type: "group"; items: Item[]; } export type Icon = | "spinner" | "check-circle" | "exclamation-triangle" | `caret-${"up" | "down" | "left" | "right"}` | "copy" | "cut" | "clipboard" | "expand" | "i-cursor" | "undo" | "redo"; export type Item = | { type: Icon; } | { type: "text"; text: string } | ItemGroup; const makeGroup = (...items: Item[]): HTMLSpanElement | undefined => { const nodes = items.flatMap((item) => { switch (item.type) { case "spinner": return [makeIcon("fa", "fa-spinner")]; case "check-circle": return [makeIcon("kamon", "kamon-check-circle")]; case "exclamation-triangle": case "caret-up": case "caret-down": case "caret-left": case "caret-right": case "cut": case "expand": case "i-cursor": case "undo": case "redo": return [makeIcon("fas", `fa-${item.type}`)]; case "copy": case "clipboard": return [makeIcon("far", `fa-${item.type}`)]; case "text": return [makeItem(item.text)]; case "group": { const group = makeGroup(...item.items); return group ? [group] : []; } } }); if (nodes.length === 0) return; if (nodes.length === 1) return nodes[0]; const span = document.createElement("span"); span.classList.add("item-group"); span.append(...nodes); return span; }; const makeItem = (child: string | Node): HTMLSpanElement => { const span = document.createElement("span"); span.classList.add("item"); span.append(child); return span; }; const makeIcon = (...classNames: string[]): HTMLElement => { const i = document.createElement("i"); i.classList.add(...classNames); return makeItem(i); };