mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
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:
co-authored by
Claude Opus 4.6
parent
26068db24b
commit
55b5a462a2
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user