[object Object]

← back to AbramsOS

chat: move Model/Agent pickers to a centered top-middle nav bar; panel drops from it (was a corner bubble) (TK-11084)

ee61b912e8892319eb1dc5b3f76b82f1a2883427 · 2026-09-01 17:57:19 -0700 · Steve

Files touched

Diff

commit ee61b912e8892319eb1dc5b3f76b82f1a2883427
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Sep 1 17:57:19 2026 -0700

    chat: move Model/Agent pickers to a centered top-middle nav bar; panel drops from it (was a corner bubble) (TK-11084)
---
 public/css/app.css        | 30 ++++++++++++++++++++++++++++--
 public/js/chat.js         |  2 ++
 views/partials/chat.ejs   | 31 ++++++-------------------------
 views/partials/header.ejs | 19 +++++++++++++++++++
 4 files changed, 55 insertions(+), 27 deletions(-)

diff --git a/public/css/app.css b/public/css/app.css
index ad98325..d721bf4 100644
--- a/public/css/app.css
+++ b/public/css/app.css
@@ -428,9 +428,35 @@ html.nav-collapsed .side-actions { flex-direction: column; }
 }
 .aos-chat-launcher:hover { background: var(--surface-strong); }
 
+/* Top-middle chat nav bar (the Model/Agent pickers live here) */
+.aos-topbar {
+  position: sticky; top: 0; z-index: 42;
+  margin: 0 0 14px; padding: 8px 12px;
+  border: 1px solid var(--border);
+  display: flex; justify-content: center;
+}
+.aos-topbar-inner {
+  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; justify-content: center;
+  width: 100%; max-width: 900px;
+}
+.aos-tb-field { display: inline-flex; align-items: center; gap: 6px; }
+.aos-tb-label { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); }
+.aos-topbar select {
+  background: var(--surface-strong); color: var(--text);
+  border: 1px solid var(--border); border-radius: var(--radius-sm);
+  padding: 6px 8px; font-size: 13px; max-width: 220px;
+}
+.aos-tb-ask {
+  background: var(--surface-strong); color: var(--text);
+  border: 1px solid var(--border-strong); border-radius: 999px;
+  cursor: pointer; padding: 6px 14px; font-size: 13px; font-weight: 600;
+}
+.aos-tb-ask:hover { filter: brightness(1.1); }
+.aos-chat-title { font-size: 13px; }
+
 .aos-chat-panel {
-  position: fixed; right: 20px; bottom: 84px; z-index: 41;
-  width: 420px; max-width: calc(100vw - 32px);
+  position: fixed; top: 60px; left: 50%; transform: translateX(-50%); z-index: 41;
+  width: 460px; max-width: calc(100vw - 32px);
   height: 560px; max-height: calc(100vh - 120px);
   display: flex; flex-direction: column; overflow: hidden;
   padding: 0;
diff --git a/public/js/chat.js b/public/js/chat.js
index af6085a..1ee22cf 100644
--- a/public/js/chat.js
+++ b/public/js/chat.js
@@ -89,6 +89,7 @@
   }
 
   function showSpec(kind) {
+    panel.hidden = false; // triggered from the top-bar ⓘ — make sure the panel is open
     rosterEl.hidden = true;
     specEl.hidden = false;
     specEl.innerHTML = '';
@@ -97,6 +98,7 @@
   }
 
   function toggleAllSpecs() {
+    panel.hidden = false; // triggered from the top-bar "All specs" — open the panel
     specEl.hidden = true;
     if (!rosterEl.hidden) { rosterEl.hidden = true; return; }
     rosterEl.hidden = false;
diff --git a/views/partials/chat.ejs b/views/partials/chat.ejs
index 5a8cd2d..175f98a 100644
--- a/views/partials/chat.ejs
+++ b/views/partials/chat.ejs
@@ -1,30 +1,11 @@
-<!-- Nav-bar chat: model + agent pickers, spec cards, chat panel. Rendered on
-     every page via footer.ejs. Dynamic roster comes from /api/chat/registry. -->
-<button id="aosChatLauncher" class="aos-chat-launcher glass" aria-label="Open chat" title="Chat">💬</button>
-
+<!-- Nav-bar chat PANEL. The Model/Agent pickers + lane badge + "All specs" +
+     "💬 Ask" launcher live in the TOP BAR (views/partials/header.ejs, top-middle).
+     This is just the conversation drop-down the top bar opens. Rendered on every
+     page via footer.ejs. Roster/specs come from /api/chat/registry. -->
 <section id="aosChatPanel" class="aos-chat-panel glass" hidden aria-label="AbramsOS chat">
   <header class="aos-chat-head">
-    <div class="aos-chat-pickers">
-      <label class="aos-chat-field">
-        <span>Model</span>
-        <span class="aos-chat-selwrap">
-          <select id="aosChatModel"></select>
-          <button type="button" class="aos-chat-info" data-spec="model" title="Model spec">ⓘ</button>
-        </span>
-      </label>
-      <label class="aos-chat-field">
-        <span>Agent</span>
-        <span class="aos-chat-selwrap">
-          <select id="aosChatAgent"></select>
-          <button type="button" class="aos-chat-info" data-spec="agent" title="Agent spec">ⓘ</button>
-        </span>
-      </label>
-    </div>
-    <div class="aos-chat-head-right">
-      <span id="aosChatLane" class="aos-chat-lane" title="Where your data goes"></span>
-      <button type="button" id="aosChatAllSpecs" class="aos-chat-allspecs" title="All specs">All specs</button>
-      <button type="button" id="aosChatClose" class="aos-chat-close" aria-label="Close">✕</button>
-    </div>
+    <strong class="aos-chat-title">Assistant</strong>
+    <button type="button" id="aosChatClose" class="aos-chat-close" aria-label="Close">✕</button>
   </header>
 
   <div id="aosChatSpec" class="aos-chat-spec" hidden></div>
diff --git a/views/partials/header.ejs b/views/partials/header.ejs
index dfa6be4..c2e2814 100644
--- a/views/partials/header.ejs
+++ b/views/partials/header.ejs
@@ -78,4 +78,23 @@
       </script>
     </aside>
     <div class="content-wrap">
+    <% if (typeof userId !== 'undefined' && userId) { %>
+    <div class="aos-topbar glass">
+      <div class="aos-topbar-inner">
+        <span class="aos-tb-field">
+          <span class="aos-tb-label">Model</span>
+          <select id="aosChatModel"></select>
+          <button type="button" class="aos-chat-info" data-spec="model" title="Model spec">ⓘ</button>
+        </span>
+        <span class="aos-tb-field">
+          <span class="aos-tb-label">Agent</span>
+          <select id="aosChatAgent"></select>
+          <button type="button" class="aos-chat-info" data-spec="agent" title="Agent spec">ⓘ</button>
+        </span>
+        <span id="aosChatLane" class="aos-chat-lane" title="Where your data goes"></span>
+        <button type="button" id="aosChatAllSpecs" class="aos-chat-allspecs" title="All specs">All specs</button>
+        <button type="button" id="aosChatLauncher" class="aos-tb-ask">💬 Ask</button>
+      </div>
+    </div>
+    <% } %>
     <main>

← 8205414 chat: drop dead Gemini models from picker (Google prepay $0)  ·  back to AbramsOS  ·  chat: guard registry+chat fetch against creds-in-URL (resolv cf095c7 →