* feat(ui): opt-in chat bubble layout Closes #336. Adds a settings toggle that right-aligns user messages and left-aligns assistant replies. Off by default - the current full-width layout is friendlier to code blocks and tool output, so bubbles are strictly opt-in per the maintainer note on the issue. Wiring follows the existing token-usage / cli-sessions pattern: - api/config.py: new bubble_layout bool in _SETTINGS_DEFAULTS and _SETTINGS_BOOL_KEYS, validated + persisted like the rest. - static/style.css: .bubble-layout gated selectors using :has() to tag msg-rows by .msg-role.user / .msg-role.assistant without any JS changes to message creation. User rows get align-self: flex-end, max-width: 75%, and a row-reverse header; assistant rows flex-start. A 700px media query widens the max to 92% on narrow screens. - static/index.html: new checkbox with i18n keys next to the existing token-usage toggle. - static/panels.js: loads the setting into the checkbox, saves it back, and toggles body.bubble-layout immediately on save. - static/boot.js: applies the class on initial load so refreshed tabs honor the persisted setting without a flash. - static/i18n.js: English label + description. Test suite errors are environmental (test server fails to start on port 8788 on main as well). * i18n(es): add Spanish translations for bubble_layout setting * fix+test: boot.js bubble-layout reset on failure; add 22 tests for issue #336 * docs: v0.50.24 release — version badge and CHANGELOG --------- Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
This commit is contained in:
@@ -479,7 +479,7 @@ function applyBotName(){
|
||||
(async()=>{
|
||||
// Load send key preference
|
||||
let _bootSettings={};
|
||||
try{const s=await api('/api/settings');_bootSettings=s;window._sendKey=s.send_key||'enter';window._showTokenUsage=!!s.show_token_usage;window._showCliSessions=!!s.show_cli_sessions;window._soundEnabled=!!s.sound_enabled;window._notificationsEnabled=!!s.notifications_enabled;window._botName=s.bot_name||'Hermes';const _theme=s.theme||'dark';document.documentElement.dataset.theme=_theme;localStorage.setItem('hermes-theme',_theme);if(s.language&&typeof setLocale==='function'){setLocale(s.language);if(typeof applyLocaleToDOM==='function')applyLocaleToDOM();}applyBotName();}catch(e){window._sendKey='enter';window._showTokenUsage=false;window._showCliSessions=false;window._soundEnabled=false;window._notificationsEnabled=false;window._botName='Hermes';_bootSettings={check_for_updates:false};}
|
||||
try{const s=await api('/api/settings');_bootSettings=s;window._sendKey=s.send_key||'enter';window._showTokenUsage=!!s.show_token_usage;window._showCliSessions=!!s.show_cli_sessions;window._soundEnabled=!!s.sound_enabled;window._notificationsEnabled=!!s.notifications_enabled;window._botName=s.bot_name||'Hermes';const _theme=s.theme||'dark';document.documentElement.dataset.theme=_theme;localStorage.setItem('hermes-theme',_theme);document.body.classList.toggle('bubble-layout',!!s.bubble_layout);if(s.language&&typeof setLocale==='function'){setLocale(s.language);if(typeof applyLocaleToDOM==='function')applyLocaleToDOM();}applyBotName();}catch(e){window._sendKey='enter';window._showTokenUsage=false;window._showCliSessions=false;window._soundEnabled=false;window._notificationsEnabled=false;window._botName='Hermes';_bootSettings={check_for_updates:false};document.body.classList.remove('bubble-layout');}
|
||||
// Non-blocking update check (fire-and-forget, once per tab session)
|
||||
// ?test_updates=1 in URL forces banner display for testing (bypasses sessionStorage guards)
|
||||
const _testUpdates=new URLSearchParams(location.search).get('test_updates')==='1';
|
||||
|
||||
Reference in New Issue
Block a user