fix(mobile): adapt settings dialog and message controls for mobile screens (#919)

* fix(mobile): adapt settings dialog and message controls for mobile screens (#915)

Co-authored-by: bsgdigital

* fix(mobile): adapt settings dialog and message controls for mobile screens (v0.50.177, #915)

Co-authored-by: bsgdigital

---------

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
This commit is contained in:
nesquena-hermes
2026-04-23 15:12:07 -07:00
committed by GitHub
parent 1175ee363f
commit 07caaec6ef
4 changed files with 47 additions and 10 deletions

View File

@@ -29,6 +29,11 @@
workspace subtree) and never enumerate blocked system roots. (`api/routes.py`,
`api/workspace.py`, `static/panels.js`, `static/style.css`) (partial for #616)
## [v0.50.177] — 2026-04-23
### Fixed
- **Settings dialog and message controls unusable on mobile** — three mobile usability fixes: (1) settings tab strip replaced by a native `<select>` dropdown on narrow viewports, panel goes full-width; (2) provider card Save/Remove buttons become icon-only on mobile so the API key input fills the available width; (3) message timestamps, copy, and edit buttons are always visible on touch screens (no hover state on mobile). (`static/index.html`, `static/panels.js`, `static/style.css`) Co-authored by @bsgdigital.
## [v0.50.176] — 2026-04-23
### Fixed

View File

@@ -446,6 +446,13 @@
</div>
<div class="settings-body">
<div class="settings-shell">
<select id="settingsSectionDropdown" class="settings-section-dropdown" aria-label="Settings section" onchange="switchSettingsSection(this.value)">
<option value="conversation">Conversation</option>
<option value="appearance">Appearance</option>
<option value="preferences">Preferences</option>
<option value="providers">Providers</option>
<option value="system">System</option>
</select>
<div class="settings-tabs" role="tablist" aria-label="Hermes control center sections">
<button class="settings-tab active" id="settingsTabConversation" type="button" role="tab" aria-selected="true" aria-controls="settingsPaneConversation" onclick="switchSettingsSection('conversation')">
<svg class="settings-tab-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>

View File

@@ -1291,6 +1291,9 @@ function switchSettingsSection(name){
}
if(pane) pane.classList.toggle('active',active);
});
// Sync mobile dropdown
const dd=$('settingsSectionDropdown');
if(dd && dd.value!==section) dd.value=section;
// Lazy-load providers when the tab is opened
if(section==='providers') loadProvidersPanel();
}
@@ -1590,24 +1593,25 @@ function _buildProviderCard(p){
}else{
const actions=document.createElement('div');
actions.className='provider-card-actions';
actions.style.cssText='margin-top:6px;display:flex;gap:6px;align-items:center';
const input=document.createElement('input');
input.type='password';
input.placeholder=p.has_key?t('providers_key_placeholder_replace'):t('providers_key_placeholder_new');
input.style.cssText='flex:1;padding:6px 8px;background:var(--code-bg);color:var(--text);border:1px solid var(--border2);border-radius:6px;font-size:12px;font-family:monospace';
input.style.cssText='flex:1;min-width:0;padding:6px 8px;background:var(--code-bg);color:var(--text);border:1px solid var(--border2);border-radius:6px;font-size:12px;font-family:monospace';
input.autocomplete='off';
const saveBtn=document.createElement('button');
saveBtn.className='sm-btn provider-save-btn';
saveBtn.style.cssText='padding:5px 12px;font-size:12px;white-space:nowrap';
saveBtn.textContent=t('providers_save');
saveBtn.setAttribute('aria-label',t('providers_save'));
saveBtn.title=t('providers_save');
saveBtn.innerHTML='<svg class="provider-btn-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg><span class="provider-btn-label">'+t('providers_save')+'</span>';
saveBtn.onclick=()=>_saveProviderKey(p.id);
actions.appendChild(input);
actions.appendChild(saveBtn);
if(p.has_key){
const removeBtn=document.createElement('button');
removeBtn.className='sm-btn';
removeBtn.style.cssText='padding:5px 10px;font-size:12px;color:var(--error);border-color:rgba(233,69,96,.25);white-space:nowrap';
removeBtn.textContent=t('providers_remove');
removeBtn.className='sm-btn provider-remove-btn';
removeBtn.setAttribute('aria-label',t('providers_remove'));
removeBtn.title=t('providers_remove');
removeBtn.innerHTML='<svg class="provider-btn-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg><span class="provider-btn-label">'+t('providers_remove')+'</span>';
removeBtn.onclick=()=>_removeProviderKey(p.id);
actions.appendChild(removeBtn);
}

View File

@@ -756,9 +756,6 @@
.topbar-meta{display:none;}
.topbar-chips{flex-wrap:nowrap;gap:4px;overflow-x:auto;-webkit-overflow-scrolling:touch;}
.topbar-chips .chip,.topbar-chips .ws-chip,.topbar-chips button{font-size:11px!important;padding:4px 8px!important;white-space:nowrap;}
.settings-shell{grid-template-columns:1fr;gap:0;}
.settings-tabs{flex-direction:row;overflow-x:auto;padding:10px 12px;border-right:none;border-bottom:1px solid var(--border);gap:6px;}
.settings-tab{flex-shrink:0;}
.settings-main{padding:18px 16px;}
.hermes-action-grid{grid-template-columns:1fr;}
.messages-inner{padding:12px 10px 20px;}
@@ -1485,6 +1482,7 @@ body.resizing{user-select:none;cursor:col-resize;}
.settings-main{overflow-y:auto;padding:22px 24px;min-width:0;}
.settings-pane{display:none;}
.settings-pane.active{display:block;}
.settings-section-dropdown{display:none;}
.settings-section-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:14px;}
.settings-section-title{font-size:13px;font-weight:700;letter-spacing:.01em;color:var(--text);}
.settings-section-meta{font-size:11px;color:var(--muted);margin-top:3px;line-height:1.5;}
@@ -1507,6 +1505,11 @@ body.resizing{user-select:none;cursor:col-resize;}
.provider-card:hover{border-color:var(--border2);}
.provider-card-name{font-weight:600;font-size:13px;}
.provider-card .sm-btn:disabled{opacity:.4;cursor:not-allowed;}
.provider-card-actions{margin-top:6px;display:flex;gap:6px;align-items:center;width:100%;}
.provider-save-btn{padding:5px 12px;font-size:12px;white-space:nowrap;display:inline-flex;align-items:center;gap:5px;flex:none;}
.provider-remove-btn{padding:5px 10px;font-size:12px;color:var(--error);border-color:rgba(233,69,96,.25);white-space:nowrap;display:inline-flex;align-items:center;gap:5px;flex:none;}
.provider-btn-icon{flex-shrink:0;}
.provider-btn-label{}
/* ── Session pin indicator (inline, only when pinned) ── */
.session-pin-indicator{
@@ -1888,3 +1891,21 @@ body.resizing{user-select:none;cursor:col-resize;}
.msg-row[data-role="user"] .msg-body { padding: 8px 12px; }
.msg-row[data-error="1"] .msg-body { padding: 8px 12px; }
}
/* Mobile overrides — must live after all base rules to win the cascade without !important */
@media(max-width:640px){
/* Settings dialog: replace left tab strip with a dropdown, panel goes full-width */
.settings-shell{display:flex;flex-direction:column;gap:0;}
.settings-section-dropdown{display:block;margin:10px 14px;width:calc(100% - 28px);}
.settings-tabs{display:none;}
.settings-main{padding:18px 16px;width:100%;}
/* Provider buttons: icon-only on mobile, input fills remaining space */
.provider-save-btn,.provider-remove-btn{padding:7px;gap:0;flex-shrink:0;}
.provider-btn-label{display:none;}
/* Message controls: always visible on touch screens (no hover available) */
.msg-row[data-role="user"] .msg-foot,
.msg-row[data-role="assistant"] .msg-foot,
.assistant-turn .msg-foot{opacity:1;}
.msg-actions{opacity:1;}
}