///
///
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);
};