feat(web): NetX workbench, UME-only UI, i18n, and header status

- Replace sidebar app with workbench home and module tabs (openOrFocusModule)

- Remove legacy pages; add module registry, shared tab channel, WEB.md

- Add zh/en i18n, global ToastProvider, restore oclaw bridge pill in header

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-05-27 11:18:30 +08:00
parent 664775927b
commit 282dbe75af
33 changed files with 1631 additions and 1677 deletions

View file

@ -0,0 +1,68 @@
import { getModuleById } from "../config/modules";
import {
broadcastMessage,
createFocusRequestId,
focusWindowSafe,
registerBroadcastListener,
waitForFocusAck,
} from "./tabChannel";
export type ModuleWindowSpec = {
moduleId: string;
path: string;
};
const MODULE_CHANNEL = "netx-module-nav";
type FocusModuleMessage = {
type: "focus-module";
moduleId: string;
path: string;
requestId: string;
};
export function moduleWindowName(moduleId: string): string {
return `netx-module-${moduleId}`;
}
function moduleAckKey(moduleId: string): string {
return `netx-mod-focus-ack-${moduleId}`;
}
export function registerModuleWindow(moduleId: string): () => void {
try {
window.name = moduleWindowName(moduleId);
} catch {
/* ignore */
}
return registerBroadcastListener<FocusModuleMessage>(MODULE_CHANNEL, moduleAckKey(moduleId), (data) => {
const targetPath = String(data.path || "").trim();
if (targetPath && window.location.pathname !== targetPath) {
window.location.assign(targetPath);
}
window.focus();
});
}
export function openOrFocusModule({ moduleId, path }: ModuleWindowSpec): void {
const mod = getModuleById(moduleId);
const targetPath = mod?.path ?? path;
const requestId = createFocusRequestId(`mod-${moduleId}`);
const name = moduleWindowName(moduleId);
broadcastMessage<FocusModuleMessage>(MODULE_CHANNEL, {
type: "focus-module",
moduleId,
path: targetPath,
requestId,
});
focusWindowSafe(window.open(targetPath, name));
waitForFocusAck(moduleAckKey(moduleId), requestId, () => {
focusWindowSafe(window.open(targetPath, name));
});
}
export { moduleIdFromPath } from "../config/modules";