/** * Brain-5D Dashboard — Console Log (pure output component) * * This module provides only the console log output. It does not send * control commands; it only displays command results and system events. * * The dashboard shell, operator experience, real-body embodiment view and * Wesen workspace are imported for presentation/read-only side effects. * * @version 1.4.6 * @license MIT */ "use strict"; import "./dashboard-shell.js"; import "./dashboard-experience.js"; import "./embodiment-self-model.js"; import "./wesen.js"; import "./wesen-organism-v2.js"; import "./wesen-anatomy-v3.js"; import "./wesen-neural-symbiosis.js"; import "./neuron-model-viewer.js"; import "./frontend-architecture.js"; import "./footer-controller.js"; const CANONICAL_WESEN_STYLES = Object.freeze([ "/wesen.css", "/wesen-adaptive.css", "/wesen-organism.css", "/wesen-anatomy-v3.css", "/wesen-neural-symbiosis.css", ]); function byId(id) { return document.getElementById(id); } function escapeHtml(str) { if (!str) return ""; const div = document.createElement("div"); div.textContent = String(str); return div.innerHTML; } function formatTime(date = new Date()) { return date.toLocaleTimeString("en-US", { hour12: false }); } function ensureWesenStylesheet() { return CANONICAL_WESEN_STYLES; } function activateLegacyWorkspace(name) { const button = document.querySelector(`.tab-btn[data-tab="${name}"]`); if (button) { button.click(); return; } document.querySelectorAll(".tab-btn[data-tab]").forEach((item) => item.classList.remove("active")); document.querySelectorAll(".tab-content[id^='tab-']").forEach((tab) => { const active = tab.id === `tab-${name}`; tab.classList.toggle("active", active); tab.hidden = !active; }); document.body.dataset.currentTab = name; document.body.dataset.experienceWorkspace = name; } function adaptDashboardNavigation() { // Keep legacy route buttons in the DOM so app.js remains the sole lifecycle // owner and can lazy-initialize Network/Release/Settings when contextual // navigation activates them. The three-area shell hides the legacy nav. for (const name of ["network", "gate"]) { const button = document.querySelector(`.tab-btn[data-tab="${name}"]`); if (button) { button.classList.add("wesen-utility-hidden"); button.setAttribute("aria-hidden", "true"); button.tabIndex = -1; } } document.querySelectorAll('.experience-command-item[data-command-id="workspace:network"], .experience-command-item[data-command-id="workspace:gate"]').forEach((node) => node.remove()); document.querySelectorAll('[data-jump-workspace="network"]').forEach((node) => { node.dataset.jumpWorkspace = "wesen"; const strong = node.querySelector("strong"); const small = node.querySelector("small"); if (strong) strong.textContent = "Wesen beobachten"; if (small) small.textContent = "Körper, Zustände, Rückkopplung"; }); document.querySelectorAll('[data-jump-workspace="gate"]').forEach((node) => node.remove()); const bodyShortcut = document.querySelector('[data-overview-tab="embodiment"]'); if (bodyShortcut) { bodyShortcut.dataset.overviewTab = "wesen"; bodyShortcut.textContent = "◉ Wesen öffnen"; } } function ensureReleaseFooterButton() { const footer = document.querySelector(".site-footer"); if (!footer || footer.querySelector(".footer-tools, [data-footer-release]")) return; const target = byId("footer-status") || footer.lastElementChild || footer; const button = document.createElement("button"); button.type = "button"; button.className = "wesen-release-button"; button.dataset.footerRelease = "true"; button.textContent = "Release"; button.title = "Scientific Gate und Release Readiness öffnen"; button.addEventListener("click", () => activateLegacyWorkspace("gate")); target.appendChild(button); } function simplifyEmbodimentCopy() { const tab = byId("tab-embodiment"); if (!tab || tab.querySelector("[data-simple-embodiment-note]")) return; const header = tab.querySelector(".workspace-header, .dashboard-generated-header"); if (header) { const title = header.querySelector("h2"); const paragraph = header.querySelector("p"); if (title) title.textContent = "Embodiment"; if (paragraph) paragraph.textContent = "Reale Sensoren, Geräte, Aktoren und Körpergrenzen konfigurieren und beobachten."; } const note = document.createElement("div"); note.dataset.simpleEmbodimentNote = "true"; note.className = "dashboard-utility-bar"; note.innerHTML = 'Embodiment bleibt die einfache technische Schnittstellen-Seite. Die adaptive Echtzeitdarstellung befindet sich unter Wesen.'; header?.insertAdjacentElement("afterend", note); } function initWesenShellIntegration() { ensureWesenStylesheet(); adaptDashboardNavigation(); ensureReleaseFooterButton(); simplifyEmbodimentCopy(); requestAnimationFrame(() => adaptDashboardNavigation()); } ensureWesenStylesheet(); if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", initWesenShellIntegration, { once: true }); } else { initWesenShellIntegration(); } /** * Console log output controller. */ export class ConsoleLog { constructor(containerId, options = {}) { this.container = byId(containerId); this.entries = []; this.maxEntries = options.maxEntries || 1000; this.autoScroll = options.autoScroll !== false; } /** * Log a message. * @param {string} message * @param {string} type - 'info', 'success', 'error', 'warning', 'debug' */ log(message, type = "info") { const entry = { timestamp: new Date(), message: String(message), type, }; this.entries.push(entry); if (this.entries.length > this.maxEntries) { this.entries.shift(); } this.render(entry); } /** * Render a single entry. * @param {object} entry */ render(entry) { if (!this.container) return; const div = document.createElement("div"); div.className = `log-entry log-${entry.type}`; div.innerHTML = `[${formatTime(entry.timestamp)}] ${escapeHtml(entry.message)}`; this.container.appendChild(div); if (this.autoScroll) { this.container.scrollTop = this.container.scrollHeight; } while (this.container.children.length > this.maxEntries) { this.container.removeChild(this.container.firstChild); } } /** Clear the log. */ clear() { if (this.container) this.container.innerHTML = ""; this.entries = []; } /** Get all entries. */ getEntries() { return [...this.entries]; } } export const consoleLog = new ConsoleLog("console-output");