From c402b97bf3da1243b0dc3179e637e9a367b29ffd Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Tue, 17 Mar 2026 21:32:54 -0400 Subject: [PATCH] UI: context panel popover, light/dark theme, contrast improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Light/dark mode: full palette via @media + [data-theme] override; theme toggle button (☾/☀) persists to localStorage; no flash on load - Dark mode softened: #1a1228 bg (was near-pure black), improved muted text contrast (#9080a8) - CSS variables: --shadow, --modal-overlay, --code-bg, --pre-bg, --success, --success-dim replace all hardcoded rgba/hex values - Context panel: ⚙ header button opens dropdown (like Sessions); tier badge shows current tier; closes on outside click - Removed always-visible context bar; controls now in panel Co-Authored-By: Claude Sonnet 4.6 --- cortex/static/index.html | 297 +++++++++++++++++++++++++++++---------- 1 file changed, 225 insertions(+), 72 deletions(-) diff --git a/cortex/static/index.html b/cortex/static/index.html index 01e9214..c82ad48 100644 --- a/cortex/static/index.html +++ b/cortex/static/index.html @@ -1,28 +1,113 @@ - + Cortex — Inara + + @@ -691,9 +805,42 @@ + +
+ + +
+
+
Context Tier
+
+ + + + +
+
+
+
Memory Layers
+
+ + + +
+
+
+
Distill Memory
+
+ + + + +
+
+
+
@@ -718,27 +865,6 @@
- -
- Tier: - - - - - - Mem: - - - - - Distill: - - - - - -
-
@@ -1505,29 +1631,62 @@ } }; - // ── Context bar — tier + memory toggles + distill ──────────── - let currentTier = parseInt(localStorage.getItem('ctx-tier') || '2'); - let memLong = localStorage.getItem('mem-long') !== 'false'; - let memMid = localStorage.getItem('mem-mid') !== 'false'; - let memShort = localStorage.getItem('mem-short') !== 'false'; + // ── Theme toggle ────────────────────────────────────────────── + const themeBtn = document.getElementById('theme-btn'); + function applyTheme(theme) { + document.documentElement.setAttribute('data-theme', theme); + themeBtn.textContent = theme === 'dark' ? '☀' : '☾'; + themeBtn.title = theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'; + } + + { + const saved = localStorage.getItem('theme'); + const sysDark = window.matchMedia('(prefers-color-scheme: dark)').matches; + applyTheme(saved || (sysDark ? 'dark' : 'light')); + } + + themeBtn.addEventListener('click', () => { + const current = document.documentElement.getAttribute('data-theme'); + const next = current === 'dark' ? 'light' : 'dark'; + localStorage.setItem('theme', next); + applyTheme(next); + }); + + // ── Context panel — tier + memory toggles + distill ─────────── + const ctxOpenBtn = document.getElementById('ctx-open-btn'); + const ctxPanel = document.getElementById('ctx-panel'); const distillStatus = document.getElementById('ctx-distill-status'); + let currentTier = parseInt(localStorage.getItem('ctx-tier') || '2'); + let memLong = localStorage.getItem('mem-long') !== 'false'; + let memMid = localStorage.getItem('mem-mid') !== 'false'; + let memShort = localStorage.getItem('mem-short') !== 'false'; + function updateTierUI() { document.querySelectorAll('.ctx-btn[data-tier]').forEach(btn => { btn.classList.toggle('active', parseInt(btn.dataset.tier) === currentTier); }); + ctxOpenBtn.querySelector('.tier-badge').textContent = currentTier; } function updateMemUI() { document.getElementById('mem-long-btn').classList.toggle('mem-on', memLong); document.getElementById('mem-mid-btn').classList.toggle('mem-on', memMid); document.getElementById('mem-short-btn').classList.toggle('mem-on', memShort); - document.getElementById('mem-long-btn').classList.toggle('active', false); - document.getElementById('mem-mid-btn').classList.toggle('active', false); - document.getElementById('mem-short-btn').classList.toggle('active', false); } + ctxOpenBtn.addEventListener('click', (e) => { + e.stopPropagation(); + ctxPanel.classList.toggle('open'); + }); + + document.addEventListener('click', (e) => { + if (!ctxPanel.contains(e.target) && e.target !== ctxOpenBtn) { + ctxPanel.classList.remove('open'); + } + }); + document.querySelectorAll('.ctx-btn[data-tier]').forEach(btn => { btn.addEventListener('click', () => { currentTier = parseInt(btn.dataset.tier); @@ -1537,26 +1696,20 @@ }); document.getElementById('mem-long-btn').addEventListener('click', () => { - memLong = !memLong; - localStorage.setItem('mem-long', memLong); - updateMemUI(); + memLong = !memLong; localStorage.setItem('mem-long', memLong); updateMemUI(); }); document.getElementById('mem-mid-btn').addEventListener('click', () => { - memMid = !memMid; - localStorage.setItem('mem-mid', memMid); - updateMemUI(); + memMid = !memMid; localStorage.setItem('mem-mid', memMid); updateMemUI(); }); document.getElementById('mem-short-btn').addEventListener('click', () => { - memShort = !memShort; - localStorage.setItem('mem-short', memShort); - updateMemUI(); + memShort = !memShort; localStorage.setItem('mem-short', memShort); updateMemUI(); }); function showDistillStatus(msg, isErr) { distillStatus.textContent = msg; distillStatus.classList.toggle('err', !!isErr); distillStatus.classList.add('show'); - setTimeout(() => distillStatus.classList.remove('show'), 4000); + setTimeout(() => distillStatus.classList.remove('show'), 5000); } async function runDistill(endpoint) {