fix(web): improve UX readability and accessibility in chat UI (#910)

* fix(web): improve UX readability and accessibility in chat UI

Soften user bubbles, increase assistant message readability, widen message
gaps, improve disabled button visibility, add keyboard focus-visible rings,
fix attach button specificity, expand tree-row click targets, and increase
log entry hover contrast.

Co-Authored-By: Claude Opus 4.6 <[email protected]>

* fix(web): address PR review — hover guard, accent-soft var, tree-row a11y

- Guard .chat-input button:hover with :not(:disabled) to prevent
  visual feedback on disabled send button
- Add --accent-soft CSS variable, use in .message.user instead of
  hardcoded rgba
- Make tree-rows keyboard-focusable (tabIndex=0, role=treeitem,
  aria-expanded, Enter/Space keydown handlers)

Co-Authored-By: Claude Opus 4.6 <[email protected]>

---------

Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
Illia Polosukhin
2026-03-11 02:31:35 +00:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 26068db24b
commit 55b5a462a2
2 changed files with 49 additions and 20 deletions
+13 -6
View File
@@ -1690,22 +1690,25 @@ function renderNodes(nodes, container, depth) {
const row = document.createElement('div');
row.className = 'tree-row';
row.style.paddingLeft = (depth * 16 + 8) + 'px';
row.tabIndex = 0;
row.setAttribute('role', 'treeitem');
if (node.is_dir) {
row.setAttribute('aria-expanded', node.expanded ? 'true' : 'false');
const arrow = document.createElement('span');
arrow.className = 'expand-arrow' + (node.expanded ? ' expanded' : '');
arrow.textContent = '\u25B6';
arrow.addEventListener('click', (e) => {
e.stopPropagation();
toggleExpand(node);
});
row.appendChild(arrow);
const label = document.createElement('span');
label.className = 'tree-label dir';
label.textContent = node.name;
label.addEventListener('click', () => toggleExpand(node));
row.appendChild(label);
row.addEventListener('click', () => toggleExpand(node));
row.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggleExpand(node); }
});
} else {
const spacer = document.createElement('span');
spacer.className = 'expand-arrow-spacer';
@@ -1714,8 +1717,12 @@ function renderNodes(nodes, container, depth) {
const label = document.createElement('span');
label.className = 'tree-label file';
label.textContent = node.name;
label.addEventListener('click', () => readMemoryFile(node.path));
row.appendChild(label);
row.addEventListener('click', () => readMemoryFile(node.path));
row.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); readMemoryFile(node.path); }
});
}
container.appendChild(row);
+36 -14
View File
@@ -9,6 +9,7 @@
--text-secondary: #a1a1aa;
--accent: #34d399;
--accent-hover: #2fc48d;
--accent-soft: rgba(52, 211, 153, 0.15);
--success: #34d399;
--warning: #F5A623;
--danger: #E64C4C;
@@ -655,11 +656,11 @@ body {
padding: 16px;
display: flex;
flex-direction: column;
gap: 12px;
gap: 16px;
}
.message {
max-width: 80%;
max-width: 72%;
padding: 10px 14px;
border-radius: var(--radius);
font-size: 14px;
@@ -669,8 +670,8 @@ body {
.message.user {
align-self: flex-end;
background: var(--accent);
color: #09090b;
background: var(--accent-soft);
color: var(--accent);
border-bottom-right-radius: 2px;
white-space: pre-wrap;
}
@@ -680,6 +681,9 @@ body {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-bottom-left-radius: 2px;
padding: 14px 18px;
font-size: 15px;
line-height: 1.6;
}
.message.system {
@@ -710,10 +714,10 @@ body {
padding: 0;
}
.message p { margin: 0 0 8px 0; }
.message p { margin: 0 0 10px 0; }
.message p:last-child { margin-bottom: 0; }
.message ul, .message ol { margin: 4px 0; padding-left: 20px; }
.message li { margin: 2px 0; }
.message li { margin: 4px 0; }
.message blockquote {
margin: 6px 0;
padding: 4px 12px;
@@ -1062,7 +1066,7 @@ body {
}
.approval-card .approval-actions button:disabled {
opacity: 0.4;
opacity: 0.5;
cursor: not-allowed;
}
@@ -1241,7 +1245,7 @@ body {
}
.auth-card .auth-actions button:disabled {
opacity: 0.4;
opacity: 0.5;
cursor: not-allowed;
}
@@ -1301,6 +1305,11 @@ body {
box-shadow: 0 0 0 3px rgba(52, 211, 153, 0.1);
}
.chat-input textarea:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.chat-input button {
padding: 8px 20px;
background: var(--accent);
@@ -1314,7 +1323,7 @@ body {
transition: background 0.2s, transform 0.2s;
}
.chat-input button:hover {
.chat-input button:hover:not(:disabled) {
background: var(--accent-hover);
transform: translateY(-1px);
}
@@ -1324,8 +1333,18 @@ body {
}
.chat-input button:disabled {
opacity: 0.5;
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
/* Keyboard accessibility focus rings */
.chat-input textarea:focus-visible,
.chat-input button:focus-visible,
.tab-bar button:focus-visible,
.tree-row:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
/* Memory Tab */
@@ -1425,7 +1444,7 @@ body {
color: var(--text-secondary);
}
.tree-label.file:hover {
.tree-row:hover .tree-label.file {
color: var(--accent);
}
@@ -2307,7 +2326,7 @@ body {
}
.log-entry:hover {
background: var(--bg-secondary);
background: var(--bg-tertiary);
}
.log-ts {
@@ -3781,7 +3800,7 @@ mark {
}
/* Image Upload */
.attach-btn {
.chat-input .attach-btn {
background: none;
border: none;
cursor: pointer;
@@ -3794,10 +3813,13 @@ mark {
display: flex;
align-items: center;
justify-content: center;
font-weight: 400;
}
.attach-btn:hover {
.chat-input .attach-btn:hover {
background: none;
color: var(--text);
transform: none;
}
.image-preview-strip {