Add a per-user lead agent and make the right pane task-focused
This commit is contained in:
+34
-64
@@ -1,86 +1,56 @@
|
||||
import { mountAdmin } from "./admin.js";
|
||||
import type { TaskTab } from "./api.js";
|
||||
import { mountChanges } from "./changes.js";
|
||||
import { h, replace } from "./dom.js";
|
||||
import { mountFiles } from "./files.js";
|
||||
import { mountInbox } from "./inbox.js";
|
||||
import { mountSettings } from "./settings.js";
|
||||
import { mountLead } from "./lead.js";
|
||||
import { focusTab, on, state, tabs } from "./state.js";
|
||||
import { mountTranscript } from "./task.js";
|
||||
import { mountTasks } from "./tasks.js";
|
||||
import { mountTodo } from "./todo.js";
|
||||
|
||||
export type View = "transcript" | "changes" | "files" | "tasks" | "todo" | "inbox" | "admin" | "settings";
|
||||
|
||||
const views: Record<View, { label: string; mount: (root: HTMLElement) => () => void }> = {
|
||||
const views: Record<TaskTab, { label: string; mount: (root: HTMLElement) => () => void }> = {
|
||||
transcript: { label: "Transcript", mount: mountTranscript },
|
||||
changes: { label: "Changes", mount: (root) => mountChanges(root) },
|
||||
files: { label: "Files", mount: mountFiles },
|
||||
tasks: { label: "Tasks", mount: mountTasks },
|
||||
todo: { label: "Todo", mount: mountTodo },
|
||||
inbox: { label: "Inbox", mount: mountInbox },
|
||||
admin: { label: "Admin", mount: mountAdmin },
|
||||
settings: { label: "Settings", mount: mountSettings },
|
||||
todo: { label: "Todo", mount: mountTodo },
|
||||
};
|
||||
|
||||
const order: View[] = ["transcript", "changes", "files", "tasks", "todo", "inbox", "admin", "settings"];
|
||||
|
||||
const panes: Pane[] = [];
|
||||
|
||||
export function openTranscript(): void {
|
||||
if (panes.some((p) => p.current() === "transcript")) {
|
||||
return;
|
||||
}
|
||||
(panes.find((p) => p.current() !== "tasks") ?? panes[0])?.show("transcript");
|
||||
export function leadPane(): HTMLElement {
|
||||
const root = h("div", { class: "view view-lead" });
|
||||
mountLead(root);
|
||||
return h("section", { class: "pane" }, h("nav", { class: "pane-tabs" }, h("button", { class: "active" }, "Lead")), h("div", { class: "pane-body" }, root));
|
||||
}
|
||||
|
||||
export function openChanges(from: Element): void {
|
||||
if (panes.some((p) => p.current() === "changes")) {
|
||||
return;
|
||||
}
|
||||
(panes.find((p) => !p.el.contains(from)) ?? panes[0])?.show("changes");
|
||||
}
|
||||
|
||||
export class Pane {
|
||||
readonly el: HTMLElement;
|
||||
private readonly tabs: HTMLElement;
|
||||
private readonly body: HTMLElement;
|
||||
private view: View;
|
||||
private dispose: () => void = () => {};
|
||||
|
||||
constructor(private readonly key: string, fallback: View) {
|
||||
this.tabs = h("nav", { class: "pane-tabs" });
|
||||
this.body = h("div", { class: "pane-body" });
|
||||
this.el = h("section", { class: "pane" }, this.tabs, this.body);
|
||||
|
||||
const saved = localStorage.getItem(this.storageKey()) as View | null;
|
||||
this.view = saved && saved in views ? saved : fallback;
|
||||
this.show(this.view);
|
||||
panes.push(this);
|
||||
}
|
||||
|
||||
current(): View {
|
||||
return this.view;
|
||||
}
|
||||
|
||||
show(view: View): void {
|
||||
this.dispose();
|
||||
this.view = view;
|
||||
localStorage.setItem(this.storageKey(), view);
|
||||
export function taskPane(): HTMLElement {
|
||||
const strip = h("nav", { class: "pane-tabs" });
|
||||
const body = h("div", { class: "pane-body" });
|
||||
let shown: TaskTab | undefined;
|
||||
let dispose: () => void = () => {};
|
||||
|
||||
const render = () => {
|
||||
const first = state.focus.tabs.filter((t, i, all) => tabs.includes(t) && all.indexOf(t) === i);
|
||||
const order = [...first, ...tabs.filter((t) => !first.includes(t))];
|
||||
const tab = state.focus.tab;
|
||||
replace(
|
||||
this.tabs,
|
||||
...order.map((v) => {
|
||||
const b = h("button", { class: v === view ? "active" : "" }, views[v].label);
|
||||
b.onclick = () => this.show(v);
|
||||
strip,
|
||||
...order.map((t) => {
|
||||
const b = h("button", { class: t === tab ? "active" : "" }, views[t].label);
|
||||
b.onclick = () => focusTab(t);
|
||||
return b;
|
||||
}),
|
||||
);
|
||||
if (tab === shown) {
|
||||
return;
|
||||
}
|
||||
dispose();
|
||||
shown = tab;
|
||||
const root = h("div", { class: `view view-${tab}` });
|
||||
replace(body, root);
|
||||
dispose = views[tab].mount(root);
|
||||
};
|
||||
|
||||
const root = h("div", { class: `view view-${view}` });
|
||||
replace(this.body, root);
|
||||
this.dispose = views[view].mount(root);
|
||||
}
|
||||
|
||||
private storageKey(): string {
|
||||
return `byre.pane.${this.key}`;
|
||||
}
|
||||
on("focus", render);
|
||||
render();
|
||||
return h("section", { class: "pane" }, strip, body);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user