149 lines
8.7 KiB
HTML
149 lines
8.7 KiB
HTML
{{define "base.html"}}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, interactive-widget=resizes-content">
|
|
<title>{{block "title" .}}Chat Switchboard{{end}}</title>
|
|
<link rel="icon" type="image/svg+xml" href="{{.BasePath}}/favicon.svg?v={{.Version}}">
|
|
<link rel="icon" type="image/x-icon" href="{{.BasePath}}/favicon.ico?v={{.Version}}">
|
|
{{/* Decomposed from monolithic styles.css (v0.22.9) */}}
|
|
<link rel="stylesheet" href="{{.BasePath}}/css/variables.css?v={{.Version}}">
|
|
<link rel="stylesheet" href="{{.BasePath}}/css/layout.css?v={{.Version}}">
|
|
<link rel="stylesheet" href="{{.BasePath}}/css/primitives.css?v={{.Version}}">
|
|
<link rel="stylesheet" href="{{.BasePath}}/css/modals.css?v={{.Version}}">
|
|
<link rel="stylesheet" href="{{.BasePath}}/css/chat.css?v={{.Version}}">
|
|
<link rel="stylesheet" href="{{.BasePath}}/css/panels.css?v={{.Version}}">
|
|
<link rel="stylesheet" href="{{.BasePath}}/css/surfaces.css?v={{.Version}}">
|
|
<link rel="stylesheet" href="{{.BasePath}}/css/splash.css?v={{.Version}}">
|
|
{{if eq .Surface "chat"}}{{template "css-chat" .}}{{end}}
|
|
{{if eq .Surface "editor"}}{{template "css-editor" .}}{{end}}
|
|
<style>
|
|
:root {
|
|
--banner-h: 28px;
|
|
--banner-top-h: {{if .Banner.Visible}}var(--banner-h){{else}}0px{{end}};
|
|
--banner-bot-h: {{if .Banner.Visible}}var(--banner-h){{else}}0px{{end}};
|
|
--surface-h: calc(100vh - var(--banner-top-h) - var(--banner-bot-h));
|
|
}
|
|
body { margin: 0; background: var(--bg); color: var(--text); }
|
|
.surface { height: var(--surface-h); overflow: hidden; }
|
|
.banner { flex-shrink: 0; }
|
|
</style>
|
|
<meta name="theme-color" content="#0e0e10">
|
|
<script>
|
|
// Early theme application — prevents flash of wrong theme on all surfaces
|
|
(function() {
|
|
try {
|
|
var p = JSON.parse(localStorage.getItem('cs-appearance') || '{}');
|
|
var mode = p.theme || 'system';
|
|
var resolved = mode;
|
|
if (mode === 'system') resolved = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
if (resolved === 'light') document.documentElement.setAttribute('data-theme', 'light');
|
|
} catch(e) {}
|
|
})();
|
|
</script>
|
|
</head>
|
|
<body data-surface="{{.Surface}}" data-base-path="{{.BasePath}}">
|
|
{{if .Banner.Visible}}
|
|
<div class="banner banner-top active" style="background:{{.Banner.Background}};color:{{.Banner.Color}};height:var(--banner-h);line-height:var(--banner-h);text-align:center;font-size:12px;font-weight:600;overflow:hidden;">
|
|
{{.Banner.Text}}
|
|
</div>
|
|
{{end}}
|
|
|
|
<div class="surface" id="surface">
|
|
{{if eq .Surface "chat"}}{{template "surface-chat" .}}
|
|
{{else if eq .Surface "admin"}}{{template "surface-admin" .}}
|
|
{{else if eq .Surface "editor"}}{{template "surface-editor" .}}
|
|
{{else if eq .Surface "notes"}}{{template "surface-notes" .}}
|
|
{{else if eq .Surface "settings"}}{{template "surface-settings" .}}
|
|
{{else}}<div style="padding:20px">Unknown surface: {{.Surface}}</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
{{if .Banner.Visible}}
|
|
<div class="banner banner-bottom active" style="background:{{.Banner.Background}};color:{{.Banner.Color}};height:var(--banner-h);line-height:var(--banner-h);text-align:center;font-size:12px;font-weight:600;overflow:hidden;">
|
|
{{.Banner.Text}}
|
|
</div>
|
|
{{end}}
|
|
|
|
<script nonce="{{.CSPNonce}}">
|
|
window.__BASE__ = '{{.BasePath}}';
|
|
window.__VERSION__ = '{{.Version}}';
|
|
window.__ENV__ = '{{.Environment}}';
|
|
window.__BRANDING__ = {};
|
|
window.__SURFACE__ = '{{.Surface}}';
|
|
window.__PAGE_DATA__ = {{.Data | toJSON}};
|
|
window.__USER__ = {{.User | toJSON}};
|
|
</script>
|
|
|
|
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/app-state.js?v={{.Version}}"></script>
|
|
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/api.js?v={{.Version}}"></script>
|
|
<script nonce="{{.CSPNonce}}">
|
|
// Hydrate auth tokens for all surfaces (chat surface also calls this in init)
|
|
API.loadTokens();
|
|
</script>
|
|
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/events.js?v={{.Version}}"></script>
|
|
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/ui-primitives.js?v={{.Version}}"></script>
|
|
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/ui-primitives-additions.js?v={{.Version}}"></script>
|
|
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/ui-core.js?v={{.Version}}"></script>
|
|
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/pages.js?v={{.Version}}"></script>
|
|
|
|
{{if eq .Surface "chat"}}{{template "scripts-chat" .}}{{end}}
|
|
{{if eq .Surface "admin"}}{{template "scripts-admin" .}}{{end}}
|
|
{{if eq .Surface "editor"}}{{template "scripts-editor" .}}{{end}}
|
|
{{if eq .Surface "notes"}}{{template "scripts-notes" .}}{{end}}
|
|
{{if eq .Surface "settings"}}{{template "scripts-settings" .}}{{end}}
|
|
|
|
{{/* ── Debug Log Modal (all surfaces) ───── */}}
|
|
<div id="debugModal" class="modal-overlay">
|
|
<div class="modal-content modal-lg">
|
|
<div class="modal-header">
|
|
<h2>Debug Log</h2>
|
|
<button class="modal-close" onclick="closeModal('debugModal')">✕</button>
|
|
</div>
|
|
<div class="modal-tabs">
|
|
<button class="debug-tab active" data-tab="console" onclick="switchDebugTab('console')">Console <span id="debugConsoleCount" class="badge">0</span></button>
|
|
<button class="debug-tab" data-tab="network" onclick="switchDebugTab('network')">Network <span id="debugNetworkCount" class="badge">0</span></button>
|
|
<button class="debug-tab" data-tab="state" onclick="switchDebugTab('state')">State</button>
|
|
<button class="debug-tab" data-tab="repl" onclick="switchDebugTab('repl')">REPL</button>
|
|
</div>
|
|
<div class="modal-body" style="padding:0;height:400px;overflow:hidden;">
|
|
<div id="debugConsoleTab" class="debug-tab-content" style="display:block;height:100%;overflow-y:auto;">
|
|
<div style="padding:8px;display:flex;gap:8px;align-items:center;">
|
|
<label><input type="checkbox" id="debugFilterErrors"> Errors only</label>
|
|
<label><input type="checkbox" id="debugAutoScroll" checked> Auto-scroll</label>
|
|
</div>
|
|
<div id="debugConsoleContent" class="debug-content" style="font-family:monospace;font-size:12px;padding:8px;"></div>
|
|
</div>
|
|
<div id="debugNetworkTab" class="debug-tab-content" style="display:none;height:100%;overflow-y:auto;">
|
|
<div id="debugNetworkContent" class="debug-content" style="font-family:monospace;font-size:12px;padding:8px;"></div>
|
|
</div>
|
|
<div id="debugStateTab" class="debug-tab-content" style="display:none;height:100%;overflow-y:auto;">
|
|
<div id="debugStateContent" class="debug-content" style="font-family:monospace;font-size:12px;padding:8px;white-space:pre-wrap;"></div>
|
|
</div>
|
|
<div id="debugReplTab" class="debug-tab-content" style="display:none;height:100%;display:flex;flex-direction:column;">
|
|
<div id="replOutput" style="flex:1;overflow-y:auto;font-family:monospace;font-size:12px;padding:8px;"></div>
|
|
<div style="border-top:1px solid var(--border);padding:8px;">
|
|
<input type="text" id="replInput" placeholder="Type expression…" style="width:100%;font-family:monospace;font-size:12px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer" style="display:flex;justify-content:space-between;align-items:center;">
|
|
<div style="display:flex;gap:8px;">
|
|
<button class="btn-danger btn-small" onclick="runDebugDiagnostics()">Diagnostics</button>
|
|
<button class="btn-danger btn-small" onclick="purgeCache()">Purge Cache</button>
|
|
</div>
|
|
<div style="display:flex;gap:8px;">
|
|
<button class="btn-secondary btn-small" onclick="clearDebugLog()">Clear</button>
|
|
<button class="btn-secondary btn-small" onclick="copyDebugLog()">Copy</button>
|
|
<button class="btn-secondary btn-small" onclick="exportDebugLog()">Export</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/debug.js?v={{.Version}}"></script>
|
|
<script nonce="{{.CSPNonce}}" src="{{.BasePath}}/js/repl.js?v={{.Version}}"></script>
|
|
</body>
|
|
</html>
|
|
{{end}}
|