pediatric-ai-scribe-v3/public/components/assistant.html
Daniel 74aa0c1b89
Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 54s
Forgejo Docker Build / Root app tests (push) Successful in 48s
Forgejo Android APK / Build signed APK (push) Successful in 2m23s
Forgejo Docker Build / Build Docker image (push) Successful in 9s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s
feat: Enter sends in the assistant, and the person chooses
Enter made a newline and Ctrl+Enter sent, which is backwards from every chat
people use. Enter now sends by default, with a toggle in the composer's + menu
to put it back.

Two rules hold whatever is chosen, because they are the habits people arrive
with and a setting that broke either would be worse than no setting:
Shift+Enter is always a newline, Ctrl/Cmd+Enter always sends. Both are checked
before the preference, so neither can be switched off.

A keystroke during IME composition never sends. Enter accepts a candidate word
in Chinese, Japanese and Korean, and on predictive Android keyboards; sending
there would cut a sentence off mid-word.

Stored per device rather than per account, because a keyboard preference
belongs to the keyboard: Enter-to-send suits a desk and usually does not suit a
phone, where Enter is how you get a second line. Unset, it defaults by device
class — send where there is a real keyboard, newline on a touch screen — and a
blocked localStorage falls through to that default rather than throwing.

The composer's tooltip says which key sends, where someone already looks when
they wonder.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
2026-09-12 18:05:36 +02:00

143 lines
11 KiB
HTML

<div class="assistant-layout" id="assistant-layout">
<div class="assistant-drawer-backdrop" id="assistant-drawer-backdrop"></div>
<aside class="assistant-history">
<button id="btn-assistant-drawer-close" class="assistant-drawer-close" type="button" aria-label="Close saved chats"><i class="fas fa-xmark"></i></button>
<!-- Brand, collapse and search share one row, as in the reference UIs.
Three stacked full-width rows wasted the top of the menu. -->
<div class="menu-head">
<button type="button" class="menu-icon-btn assistant-menu-toggle" data-menu-toggle aria-expanded="true" title="Hide menu" aria-label="Hide menu"><i class="fas fa-angles-left"></i></button>
<div class="menu-brand">
<i class="fas fa-stethoscope"></i>
<h1>PedAI</h1>
</div>
<button type="button" class="menu-icon-btn" data-menu-search title="Search" aria-label="Search"><i class="fas fa-magnifying-glass"></i></button>
</div>
<div class="assistant-mode-switch" role="tablist" aria-label="Assistant or workspace">
<button type="button" role="tab" class="active" aria-selected="true" data-assistant-mode="assistant"><i class="fas fa-brain"></i> Assistant</button>
<button type="button" role="tab" aria-selected="false" data-assistant-mode="workspace"><i class="fas fa-grip"></i> Workspace</button>
</div>
<div class="assistant-rail-actions">
<button id="btn-assistant-clear" class="assistant-new-chat" type="button"><i class="fas fa-plus"></i> <span>New chat</span><kbd class="assistant-kbd">Ctrl+Shift+O</kbd></button>
</div>
<!-- Workspace mode replaces the saved chats here with the app's own
menu, so the rail is never left empty. Same source as the cards. -->
<nav class="assistant-rail-workspace" id="assistant-rail-workspace" aria-label="Workspace">
<div id="assistant-workspace-links" class="assistant-rail-links"></div>
</nav>
<div class="card">
<div id="assistant-saved-chats" class="assistant-saved-chats" aria-label="Saved chats">
<p class="assistant-muted">Chats save automatically as you go.</p>
</div>
</div>
<!-- Account card. The same markup renders in the assistant rail, so the
two menus end the same way. Settings and Log out were only reachable
from icon buttons in the header, which the slim bar no longer has
room to explain. -->
<div class="account-card">
<button type="button" class="account-card-btn" id="btn-account-menu-rail" aria-haspopup="true" aria-expanded="false" aria-controls="account-menu-rail">
<span class="account-avatar" id="account-avatar-rail" aria-hidden="true"></span>
<span class="account-id">
<span class="account-name" id="account-name-rail"></span>
<span class="account-email" id="account-email-rail"></span>
</span>
<i class="fas fa-chevron-right account-chevron"></i>
</button>
<div class="account-menu" id="account-menu-rail" role="menu" hidden>
<button type="button" class="account-menu-item" role="menuitem" data-account-tab="settings"><i class="fas fa-gear"></i> Settings</button>
<button type="button" class="account-menu-item" role="menuitem" data-account-tab="faq"><i class="fas fa-circle-question"></i> FAQ</button>
<button type="button" class="account-menu-item" role="menuitem" data-account-logout><i class="fas fa-right-from-bracket"></i> Log out</button>
</div>
</div>
</aside>
<section class="assistant-main card">
<!-- Workspace launcher, rendered from the app's real .tab-btn list so
it cannot drift from the menu it mirrors. Desktop only: on a phone
the drawer already is the menu. -->
<!-- No hidden attribute: this view is revealed by CSS on
body.assistant-mode-workspace, and [hidden]{display:none!important}
outranks that. .assistant-workspace-view is display:none by
default, so it starts hidden either way. -->
<div id="assistant-workspace-view" class="assistant-workspace-view">
<div id="assistant-workspace-cards" class="assistant-workspace-cards"></div>
</div>
<div id="assistant-chat-view">
<div id="assistant-messages" class="assistant-messages" aria-live="polite">
<div class="assistant-empty">
<h3>Pediatric Clinical Assistant</h3>
<p class="assistant-empty-badge"><i class="fas fa-book-medical"></i> Answers built only from your indexed library</p>
<div class="assistant-examples">
<button type="button" data-assistant-example="In a 4-year-old with acute wheeze, when should magnesium sulfate be considered and what dose is recommended?">Status asthma escalation</button>
<button type="button" data-assistant-example="What are the red flags for bilious vomiting in neonates, and what immediate workup is recommended?">Bilious vomiting</button>
<button type="button" data-assistant-example="Compare bronchiolitis and asthma management in infants, citing clinical references.">Bronchiolitis vs asthma</button>
</div>
</div>
</div>
<form id="assistant-form" class="assistant-composer">
<label for="assistant-input">Clinical question</label>
<textarea id="assistant-input" rows="1" placeholder="Ask a focused clinical question..." autocomplete="off" aria-describedby="assistant-context-warning"></textarea>
<div id="assistant-context-warning" role="alert" hidden></div>
<div id="assistant-attachments" class="assistant-attachments" aria-label="Attached images" hidden></div>
<div class="assistant-composer-footer">
<div class="assistant-tools">
<!-- One + for everything that acts on the conversation, so the
top of the view stays empty and both modes line up. -->
<div class="assistant-plus">
<button id="btn-assistant-plus" class="assistant-plus-btn" type="button" aria-haspopup="true" aria-expanded="false" aria-controls="assistant-plus-menu" title="Attach and export" aria-label="Attach and export"><i class="fas fa-plus"></i></button>
<div id="assistant-plus-menu" class="assistant-plus-menu" role="menu" hidden>
<label class="assistant-plus-item" for="assistant-attach-input" role="menuitem"><i class="fas fa-paperclip"></i> Attach images</label>
<button id="btn-assistant-create-image" class="assistant-plus-item" type="button" role="menuitem"><i class="fas fa-wand-magic-sparkles"></i> Create image</button>
<button id="btn-assistant-takehome" class="assistant-plus-item" type="button" role="menuitem"><i class="fas fa-heart"></i> Patient take home</button>
<button id="btn-assistant-export-pdf" class="assistant-plus-item" type="button" role="menuitem"><i class="fas fa-file-pdf"></i> Export PDF</button>
<button id="btn-assistant-download-chat" class="assistant-plus-item" type="button" role="menuitem"><i class="fas fa-download"></i> Download transcript</button>
<!-- A keyboard preference belongs to the keyboard, so it
lives beside the composer rather than in Settings,
and is remembered per device: Enter-to-send suits a
desk and often does not suit a phone. -->
<label class="assistant-plus-item" role="menuitemcheckbox" style="cursor:pointer;">
<input type="checkbox" id="assistant-enter-sends" style="margin-right:8px;">
Enter sends the message
</label>
</div>
</div>
<input type="file" id="assistant-attach-input" accept="image/png,image/jpeg,image/webp" multiple hidden>
<span id="assistant-autosave-state" class="assistant-autosave-state" aria-live="polite"></span>
<span class="assistant-status" id="assistant-status"><span class="assistant-dot"></span><span id="assistant-status-text">Ready</span></span>
</div>
<div class="assistant-composer-right">
<!-- The select stays as the state holder (it persists the
choice and holds the allowed list); the button is its
compact face, so the composer is not as wide as the
longest model id. -->
<div class="assistant-model-pill" id="assistant-model-pill" hidden>
<select id="assistant-chat-model-select" class="assistant-model-control assistant-model-state" aria-label="Chat model" tabindex="-1" aria-hidden="true"></select>
<button type="button" id="btn-assistant-model" class="assistant-model-btn" aria-haspopup="listbox" aria-expanded="false" aria-controls="assistant-model-menu" title="Choose the chat model">
<i class="fas fa-microchip"></i> <span>Model</span>
</button>
<div id="assistant-model-menu" class="assistant-model-menu" role="listbox" aria-label="Chat model" hidden></div>
</div>
<button id="btn-assistant-voice" class="assistant-voice-btn" type="button" title="Voice conversation"><i class="fas fa-headset"></i></button>
<button id="btn-assistant-mic" class="assistant-mic" type="button" title="Dictate your question"><i class="fas fa-microphone"></i></button>
<button id="btn-assistant-send" class="btn-send" type="submit"><i class="fas fa-arrow-up"></i></button>
</div>
</div>
</form>
</div>
</section>
<button type="button" id="btn-assistant-sources" class="assistant-sources-fab" hidden aria-expanded="false" aria-controls="assistant-sources">
<i class="fas fa-quote-right"></i> <span id="assistant-sources-count">Sources</span>
</button>
<aside class="assistant-side">
<div class="card">
<div class="card-header"><h3><i class="fas fa-quote-right"></i> Sources</h3></div>
<div id="assistant-sources" class="assistant-sources">
<p class="assistant-muted">Citations appear here after an answer.</p>
</div>
</div>
</aside>
</div>
<link rel="stylesheet" href="/css/assistant.css">