From ff8c1132c1f94d66f4ad5fb270f192294550bcf6 Mon Sep 17 00:00:00 2001 From: Daniel Date: Wed, 9 Sep 2026 15:06:47 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20ChatGPT/OWUI=20mobile=20assistant=20?= =?UTF-8?q?=E2=80=94=20viewport-locked=20overlay=20with=20drawer=20(no=20d?= =?UTF-8?q?isjoint=20scrolling),=20plain=20rows=20without=20chat=20icons,?= =?UTF-8?q?=20=E2=8B=AE=20options;=20desktop=20collapsible=20saved-chats?= =?UTF-8?q?=20rail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/components/assistant.html | 1 + public/css/assistant.css | 81 ++++++++++++------------- public/js/clinicalAssistant.js | 21 +++++-- test/assistant-workspace-layout.test.js | 17 ++++++ 4 files changed, 72 insertions(+), 48 deletions(-) diff --git a/public/components/assistant.html b/public/components/assistant.html index 9e5ecf00..6e2404b2 100644 --- a/public/components/assistant.html +++ b/public/components/assistant.html @@ -1,5 +1,6 @@
+

AI Clinical Assistant

diff --git a/public/css/assistant.css b/public/css/assistant.css index 42282c5f..a1559d5f 100644 --- a/public/css/assistant.css +++ b/public/css/assistant.css @@ -160,7 +160,7 @@ .assistant-history .card { flex:1 1 auto; display:flex; flex-direction:column; min-height:0; overflow:hidden; } @media (max-width: 960px) { .assistant-layout { grid-template-columns:minmax(0,1fr) 300px; } .assistant-history { position:static; grid-column:1 / -1; grid-template-columns:auto 1fr; align-items:start; } .assistant-new-chat { grid-column:1; } .assistant-view-switch { grid-column:1; } .assistant-history .card { grid-column:2; grid-row:1 / span 2; } .assistant-main { min-height:auto; } #assistant-chat-view { min-height:auto; grid-template-rows:auto minmax(320px,1fr) auto; } } @media (max-width: 640px) { - /* ── ChatGPT-style mobile: quiet, minimal, content first ── */ + /* ── ChatGPT/OWUI mobile: independent full-screen overlay; the page behind never scrolls ── */ .assistant-topbar { flex-wrap:nowrap; gap:8px; padding:10px 14px; } .assistant-mobile-menu { display:inline-flex; } .assistant-topbar .btn-sm { padding:6px 8px; } @@ -168,29 +168,44 @@ #btn-assistant-goback { padding:8px; } .assistant-topbar-title h2 { font-size:15px; } .assistant-status { margin-left:auto; font-size:11px; } - .assistant-layout { display:block; height:auto; min-height:100dvh; } - /* Saved chats: a left drawer, ChatGPT-style, with the menu button as the opener */ - .assistant-history { position:fixed; inset:0 auto 0 0; width:min(88vw,340px); z-index:130; background:white; border-right:1px solid var(--g100); box-shadow:none; transform:translateX(-105%); transition:transform .18s ease; display:flex; flex-direction:column; padding:12px; overflow-y:auto; overflow-x:hidden; gap:2px; border-radius:0; } + .assistant-toggle-history { display:none; } + /* The assistant fills the viewport exactly; nothing behind can scroll */ + .assistant-layout { display:flex; flex-direction:column; height:100dvh; min-height:0; overflow:hidden; } + .assistant-main { flex:1 1 auto; min-height:0; display:flex; } + .assistant-main.card { box-shadow:none; border:none; margin:0; } + #assistant-chat-view { flex:1 1 auto; min-height:0; height:auto; display:flex; flex-direction:column; } + .assistant-messages { flex:1 1 auto; min-height:0; max-height:none; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:8px 14px 12px; } + .assistant-side { display:none; } + /* Slim toolbar: icon-only actions in one row */ + .assistant-toolbar { padding:6px 10px; flex:0 0 auto; } + .assistant-toolbar > div:first-child { display:none; } + .assistant-toolbar-actions { display:flex; width:100%; justify-content:flex-end; gap:4px; } + .assistant-toolbar-actions .btn-sm { font-size:0; padding:6px 8px; } + .assistant-toolbar-actions .btn-sm i { font-size:13px; } + /* Saved chats: a fixed drawer overlaying the chat */ + .assistant-history { position:fixed; left:0; top:0; bottom:0; width:min(85vw,320px); z-index:130; background:white; border-right:1px solid var(--g100); box-shadow:0 0 40px rgba(15,23,42,.14); transform:translateX(-105%); transition:transform .18s ease; display:flex; flex-direction:column; padding:10px 8px; overflow-y:auto; overflow-x:hidden; gap:2px; border-radius:0; } .assistant-layout.mobile-chats-open .assistant-history { transform:translateX(0); } - .assistant-history .card { box-shadow:none; border:1px solid var(--g200); } - .assistant-new-chat { align-self:stretch; } - .assistant-view-switch { margin:6px 0; } - #assistant-saved-chats { flex-direction:column; padding:0 6px 12px; gap:6px; overflow:visible; } - .assistant-saved-chat { max-width:none; } - .assistant-main { min-height:0; } - #assistant-chat-view { display:flex; flex-direction:column; height:100dvh; } - .assistant-messages { flex:1 1 auto; max-height:none; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:8px 14px 12px; } + .assistant-history .card { border:none; box-shadow:none; background:none; padding:0; } + .assistant-history .card-header { padding:6px 10px 2px; } + #assistant-saved-chats { padding:2px 0 12px; gap:0; overflow:visible; } + .assistant-saved-chat { flex-direction:row; align-items:center; gap:0; border:none; border-radius:8px; padding:11px 34px 11px 12px; min-width:0; width:100%; max-width:none; } + .assistant-saved-chat:hover { background:var(--g100); } + .assistant-saved-chat.active { background:var(--g100); } + .assistant-saved-chat-title { flex:1 1 auto; min-width:0; max-width:none; font-size:14px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; } + .assistant-saved-chat-meta { display:none; } + .assistant-saved-chat-menu { position:absolute; right:6px; top:50%; transform:translateY(-50%); opacity:1; pointer-events:auto; } + .assistant-new-chat, .assistant-goback-rail { display:flex; align-items:center; gap:10px; width:100%; border:none; background:none; color:var(--g700); font-size:14px; padding:10px 12px; border-radius:8px; text-align:left; } + .assistant-new-chat:hover, .assistant-goback-rail:hover { background:var(--g100); } + .assistant-create-image { display:flex; align-items:center; gap:10px; width:100%; background:none; color:var(--purple); font-weight:700; font-size:14px; padding:10px 12px; border-radius:8px; text-align:left; } + .assistant-create-image:hover { background:var(--purple-light,#faf5ff); } + .assistant-view-switch { margin:6px 8px; } .assistant-empty { margin:28px auto; max-width:100%; } .assistant-empty i { font-size:26px; } .assistant-empty h3 { font-size:16px; text-align:left; } .assistant-empty p { text-align:left; font-size:13px; } .assistant-examples { flex-direction:column; align-items:stretch; gap:0; margin:14px 0 0; } .assistant-examples button { border:none; background:none; color:var(--g700); text-align:left; padding:12px 2px; font-size:14px; border-radius:0; border-bottom:1px solid var(--g100); white-space:normal; width:100%; } - /* Toolbar actions move into the drawer */ - .assistant-toolbar { padding:10px 14px 0; } - .assistant-toolbar-actions { display:none; } - .assistant-layout.mobile-chats-open .assistant-toolbar-actions { display:grid; grid-template-columns:1fr 1fr; gap:8px; } - /* Floating pill composer */ + /* Floating pill composer pinned at the bottom */ .assistant-composer { position:static; flex:0 0 auto; margin:0 10px 10px; z-index:60; background:white; border:1px solid var(--g200); border-radius:20px; box-shadow:0 8px 30px rgba(0,0,0,.14); padding:8px 12px 6px; display:flex; flex-direction:column; gap:6px; } #assistant-input { font-size:16px; } .assistant-composer > label { display:none; } @@ -204,7 +219,6 @@ .assistant-composer-footer #btn-assistant-cancel:not([hidden]) { width:auto; padding:8px 12px; } .assistant-mic { font-size:0; } .assistant-mic i { font-size:18px; } - .assistant-side { max-height:60vh; overflow-y:auto; border-top:1px solid var(--g100); padding:12px 14px; } } @@ -242,6 +256,12 @@ /* Full-screen Open WebUI workspace: the assistant replaces the app chrome */ body.assistant-workspace .assistant-layout { height: calc(100vh - 64px); min-height: 0; grid-template-rows: minmax(0, 1fr); overflow: hidden; } +/* Desktop: the saved-chats rail collapses like ChatGPT's sidebar */ +.assistant-toggle-history { border:none; background:none; color:var(--g600); padding:6px 8px; border-radius:8px; cursor:pointer; } +.assistant-toggle-history:hover { background:var(--g100); color:var(--g800); } +.assistant-layout { transition:grid-template-columns .18s ease; } +.assistant-layout.history-collapsed { grid-template-columns:0 minmax(0,1fr) 330px; } +.assistant-layout.history-collapsed .assistant-history { display:none; } body.assistant-workspace .assistant-layout > * { min-height: 0; } body.assistant-workspace .assistant-main, body.assistant-workspace .assistant-main #assistant-chat-view { min-height: 0; } @@ -322,7 +342,6 @@ body.assistant-workspace .assistant-learning-view { min-height: 0; height: 100vh .assistant-goback-rail { display:none; } @media (max-width: 640px) { .assistant-goback-rail { display:inline-flex; align-self:stretch; justify-content:flex-start; margin-bottom:6px; } - .assistant-topbar #btn-assistant-goback { display:none; } } /* Library item hover download */ .assistant-gallery-item-wrap { position:relative; } @@ -336,31 +355,7 @@ body.assistant-workspace .assistant-learning-view { min-height: 0; height: 100vh .assistant-layout.mobile-chats-open .assistant-drawer-backdrop { display:block; } .assistant-drawer-close { display:flex; align-items:center; justify-content:center; align-self:flex-end; width:30px; height:30px; border:none; background:var(--g100); border-radius:50%; color:var(--g600); } } -/* Mobile drawer borrows the main-menu look (icon rows + section labels) */ -@media (max-width: 640px) { - .assistant-history { gap:2px; background:white; padding:10px 8px; } - .assistant-history .card { border:none; box-shadow:none; background:none; } - .assistant-history .card-header h3 { font-size:11px; font-weight:700; color:var(--g500); text-transform:uppercase; letter-spacing:.04em; padding:6px 10px 2px; } - .assistant-new-chat, .assistant-goback-rail { display:flex; align-items:center; gap:10px; width:100%; border:none; background:none; color:var(--g700); font-size:14px; padding:10px 12px; border-radius:8px; text-align:left; } - .assistant-new-chat:hover, .assistant-goback-rail:hover { background:var(--g100); } - .assistant-create-image { display:flex; align-items:center; gap:10px; width:100%; background:none; color:var(--purple); font-weight:700; font-size:14px; padding:10px 12px; border-radius:8px; text-align:left; } - .assistant-create-image:hover { background:var(--purple-light,#faf5ff); } - .assistant-saved-chat { flex-direction:row; align-items:center; gap:10px; border:none; border-radius:8px; padding:9px 12px; min-width:0; width:100%; } - .assistant-saved-chat-icon { font-size:13px; color:var(--g400); width:16px; text-align:center; flex:0 0 auto; } - .assistant-saved-chat-title { flex:1 1 auto; min-width:0; } - .assistant-saved-chat-meta { flex:0 0 auto; } - .assistant-saved-chat-menu { position:static; opacity:1; pointer-events:auto; } -} /* Saved chats: a plain sidebar list, not a card — desktop and mobile */ .assistant-history .card { border:none; box-shadow:none; background:none; padding:0; } .assistant-history .card-header { padding:2px 4px; } .assistant-history .card-header h3 { font-size:11px; font-weight:700; color:var(--g500); text-transform:uppercase; letter-spacing:.04em; } -/* Mobile drawer rows: no icons, hard-truncated titles, ⋮ always visible */ -@media (max-width: 640px) { - .assistant-saved-chat-icon { flex:0 0 16px; } - .assistant-saved-chat { position:relative; overflow:hidden; max-width:100%; padding-right:36px; } - .assistant-saved-chat-title { flex:1 1 auto; min-width:0; max-width:calc(100% - 30px); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; } - .assistant-saved-chat-menu { position:absolute; right:6px; top:50%; transform:translateY(-50%); opacity:1; pointer-events:auto; } - .assistant-saved-chat-meta { display:none; } - .assistant-goback-rail i, .assistant-create-image i, .assistant-new-chat i { display:none; } -} diff --git a/public/js/clinicalAssistant.js b/public/js/clinicalAssistant.js index 2d700360..d1a7f968 100644 --- a/public/js/clinicalAssistant.js +++ b/public/js/clinicalAssistant.js @@ -110,10 +110,6 @@ import { function initIfNeeded() { if (initialized) return; - if (typeof window !== 'undefined' && window.innerWidth <= 640) { - var layoutEl = document.getElementById('assistant-layout'); - if (layoutEl) layoutEl.classList.add('mobile-chats-open'); - } var root = document.getElementById('assistant-tab'); if (typeof window !== 'undefined' && window._userRole && window._userRole !== 'admin') { var downloadBtn = document.getElementById('btn-assistant-download-chat'); @@ -160,6 +156,22 @@ import { if (drawerCloseBtn) drawerCloseBtn.addEventListener('click', closeDrawer); var backdrop = document.getElementById('assistant-drawer-backdrop'); if (backdrop) backdrop.addEventListener('click', closeDrawer); + // Desktop: collapse/expand the saved-chats rail (ChatGPT-style sidebar) + var toggleHistoryBtn = document.getElementById('btn-assistant-toggle-history'); + if (toggleHistoryBtn) toggleHistoryBtn.addEventListener('click', function() { + var layout = document.getElementById('assistant-layout'); + if (!layout) return; + var collapsed = layout.classList.toggle('history-collapsed'); + try { localStorage.setItem('ped_assistant_history_collapsed', collapsed ? '1' : '0'); } catch (e) {} + }); + if (typeof window !== 'undefined' && window.innerWidth > 640) { + try { + if (localStorage.getItem('ped_assistant_history_collapsed') === '1') { + var layoutForPref = document.getElementById('assistant-layout'); + if (layoutForPref) layoutForPref.classList.add('history-collapsed'); + } + } catch (e) {} + } if (form) form.addEventListener('submit', onAsk); var sendBtn = document.getElementById('btn-assistant-send'); @@ -1882,7 +1894,6 @@ import { var title = chat.title || 'Saved chat'; var pinned = isChatPinned(chat.id); return '