From 5940ebede7507f4c7e857923ac1719e71e0e65e6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 10 Sep 2026 00:00:12 +0200 Subject: [PATCH] fix: Workspace swaps the menu, it does not jump to a page of its own MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workspace mode rendered the app menu twice — once in the rail and again as a card grid that replaced the chat column — so clicking it landed you somewhere that looked nothing like the assistant. There is one menu now: the rail swaps, the chat column stays where it is. The Sources panel was already hidden in workspace mode, but its 330px grid track was not, leaving an empty gutter. Both collapse states now drop the track. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01BkfrkQwA4YGrGw9LZSpeAq --- public/components/assistant.html | 7 ------- public/css/assistant.css | 16 +++++----------- public/js/clinicalAssistant.js | 17 ++--------------- test/assistant-workspace-layout.test.js | 14 +++++++++----- 4 files changed, 16 insertions(+), 38 deletions(-) diff --git a/public/components/assistant.html b/public/components/assistant.html index 4c0ec274..37671251 100644 --- a/public/components/assistant.html +++ b/public/components/assistant.html @@ -39,13 +39,6 @@
-
diff --git a/public/css/assistant.css b/public/css/assistant.css index 91c49b2b..0807b78a 100644 --- a/public/css/assistant.css +++ b/public/css/assistant.css @@ -19,7 +19,7 @@ body.assistant-workspace .assistant-topbar-title h2 { position:absolute; width:1 .assistant-new-chat:hover { border-color:var(--purple); background:var(--purple-light); } .assistant-main { display:flex; flex-direction:column; min-height:calc(100vh - 200px); min-width:0; } #assistant-chat-view { display:grid; grid-template-rows:auto minmax(420px,1fr) auto; min-height:calc(100vh - 200px); min-width:0; } -#assistant-chat-view[hidden], .assistant-workspace-view[hidden] { display:none; } +#assistant-chat-view[hidden] { display:none; } .assistant-toolbar { display:flex; justify-content:space-between; align-items:center; gap:10px; padding:10px 14px; border-bottom:1px solid var(--g200); background:var(--g50); } .assistant-toolbar-actions { display:flex; gap:6px; flex-wrap:wrap; } .assistant-messages { padding:16px; max-height:65vh; overflow-y:auto; overflow-x:hidden; background:linear-gradient(180deg,#fff,var(--g50)); min-width:0; } @@ -161,16 +161,10 @@ body.assistant-workspace .assistant-topbar-title h2 { position:absolute; width:1 .assistant-mode-switch button i { font-size:11px; } .assistant-mode-switch button.active { background:white; color:var(--purple); box-shadow:var(--shadow); } -/* Workspace mode fills the chat column with the app's own menu. */ -.assistant-workspace-view { padding:22px; overflow-y:auto; min-height:0; } -.assistant-workspace-head h2 { margin:0 0 4px; font-size:18px; color:var(--g900); } -.assistant-workspace-head p { margin:0 0 18px; font-size:13px; color:var(--g500); } -.assistant-workspace-cards { display:grid; grid-template-columns:repeat(auto-fill,minmax(190px,1fr)); gap:10px; } -.assistant-workspace-card { display:flex; align-items:center; gap:10px; border:1px solid var(--g200); background:white; border-radius:12px; padding:14px; font-size:13px; color:var(--g800); text-align:left; cursor:pointer; } -.assistant-workspace-card:hover { border-color:var(--purple-light); background:#faf5ff; color:var(--purple); } -.assistant-workspace-card i { width:18px; text-align:center; color:var(--g400); font-size:14px; } -.assistant-workspace-card:hover i { color:var(--purple); } -@media (max-width:640px) { .assistant-workspace-view { padding:14px; } .assistant-workspace-cards { grid-template-columns:1fr 1fr; } } +/* Workspace mode: the sources column goes with it, and the track goes too — + hiding the panel alone left an empty 330px gutter. */ +body.assistant-mode-workspace .assistant-layout { grid-template-columns:260px minmax(0,1fr); } +body.assistant-mode-workspace .assistant-layout.history-collapsed { grid-template-columns:0 minmax(0,1fr); } /* Workspace section in the rail: the app's own menu, one level down, the way Claude's sidebar carries both its chats and its top-level navigation. */ diff --git a/public/js/clinicalAssistant.js b/public/js/clinicalAssistant.js index fc7d1b6a..10b5535c 100644 --- a/public/js/clinicalAssistant.js +++ b/public/js/clinicalAssistant.js @@ -165,10 +165,8 @@ import { // added, renamed or hidden in index.html shows up here with no extra work. var renderWorkspaceLinks = function() { var host = document.getElementById('assistant-workspace-links'); - var cards = document.getElementById('assistant-workspace-cards'); if (!host) return; host.innerHTML = ''; - if (cards) cards.innerHTML = ''; Array.prototype.forEach.call(document.querySelectorAll('.tab-btn'), function(tab) { var name = tab.getAttribute('data-tab'); if (!name || name === 'assistant' || tab.classList.contains('hidden')) return; @@ -181,15 +179,6 @@ import { link.innerHTML = '' + '' + escapeHtml(label ? label.textContent : name) + ''; host.appendChild(link); - if (cards) { - var card = document.createElement('button'); - card.type = 'button'; - card.className = 'assistant-workspace-card'; - card.setAttribute('data-assistant-workspace-tab', name); - card.innerHTML = '' + - '' + escapeHtml(label ? label.textContent : name) + ''; - cards.appendChild(card); - } }); }; @@ -202,15 +191,13 @@ import { var chats = document.querySelector('.assistant-history .card'); var newChat = document.getElementById('btn-assistant-clear'); var createImage = document.getElementById('btn-assistant-create-image'); - var chatView = document.getElementById('assistant-chat-view'); - var workspaceView = document.getElementById('assistant-workspace-view'); if (workspace) renderWorkspaceLinks(); if (rail) rail.hidden = !workspace; if (chats) chats.hidden = workspace; if (newChat) newChat.hidden = workspace; if (createImage) createImage.hidden = workspace; - if (chatView) chatView.hidden = workspace; - if (workspaceView) workspaceView.hidden = !workspace; + // The chat column stays put. Only the rail swaps, so switching modes is a + // change of menu rather than a jump to a page that looks nothing like it. var side = document.querySelector('.assistant-side'); if (side) side.hidden = workspace || !citationsOn; document.body.classList.toggle('assistant-mode-workspace', workspace); diff --git a/test/assistant-workspace-layout.test.js b/test/assistant-workspace-layout.test.js index 010df918..2544307d 100644 --- a/test/assistant-workspace-layout.test.js +++ b/test/assistant-workspace-layout.test.js @@ -188,14 +188,18 @@ test('the rail switches between Assistant and Workspace like Home and Code', () assert.match(html, /assistant-mode-switch/, 'a two-pill switch sits at the top of the rail'); assert.match(html, /data-assistant-mode="assistant"/); assert.match(html, /data-assistant-mode="workspace"/); - assert.match(html, /id="assistant-workspace-view"[^>]*hidden/, 'workspace view starts hidden'); + // ONE menu, not two: switching modes swaps the rail, it does not jump to a + // page that looks nothing like the assistant. + assert.doesNotMatch(html, /assistant-workspace-cards/, 'no second copy of the menu in the main column'); const js = fs.readFileSync(path.join(root, 'public/js/clinicalAssistant.js'), 'utf8'); - // Workspace must REPLACE the chat column and the sources panel, not sit beside them. - assert.match(js, /if \(chatView\) chatView\.hidden = workspace;/); - assert.match(js, /if \(workspaceView\) workspaceView\.hidden = !workspace;/); - assert.match(js, /if \(side\) side\.hidden = workspace \|\| !citationsOn;/, 'sources go too'); + assert.match(js, /if \(side\) side\.hidden = workspace \|\| !citationsOn;/, 'sources are hidden in workspace mode'); assert.match(js, /if \(chats\) chats\.hidden = workspace;/, 'and the saved-chat list'); + + const css = fs.readFileSync(path.join(root, 'public/css/assistant.css'), 'utf8'); + // Hiding the panel without dropping its track leaves an empty 330px gutter. + assert.match(css, /body\.assistant-mode-workspace \.assistant-layout \{ grid-template-columns:260px minmax\(0,1fr\); \}/); + assert.match(css, /body\.assistant-mode-workspace \.assistant-layout\.history-collapsed \{ grid-template-columns:0 minmax\(0,1fr\); \}/); }); test('Learning Hub sits with the content tools, not above the clinical ones', () => {