From cfb7ec1c71d9017af7d87f8e7ed16fa827ea6c61 Mon Sep 17 00:00:00 2001 From: Kenny Van de Maele Date: Tue, 2 Jun 2026 13:55:05 +0200 Subject: [PATCH] Accessibility: add labels and toggle states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Accessibility: ARIA labels and toggle states Screen readers couldn't name several icon-only controls or tell whether the tool toggles were on. This adds accessible names and exposes toggle state, with no behavior or layout change. - Icon-only buttons get aria-label: web/shell tool toggles, the "more tools" overflow button (+ aria-haspopup), and the color-reset buttons. - Unlabeled inputs/selects get aria-label: memory + skills search, model-picker search, memory sort, theme font/density selects, and the new-memory / skill (title, when-to-use, how, tags) fields, which only had a visual floating label. - Toggle state via aria-pressed, kept in sync at the existing .active write sites: web/shell toggles (setupToggle) and the Agent/Chat mode buttons (initModeToggle). Static aria-pressed added in the markup so the attribute exists before JS runs. Scope: first slice of the ROADMAP accessibility pass. Focus-visible/contrast, reduced-motion, and modal dialog roles/focus-trap are left for follow-ups. Checks: node --check static/app.js. No Python touched. * Accessibility: mark chat log busy while streaming The chat log is an aria-live="polite" region, so streaming a response token-by-token made screen readers announce every partial update — noisy and unreadable. Set aria-busy="true" on #chat-history while a response streams and back to "false" in the stream's finally block. Assistive tech then waits for the settled message and announces it once. Checks: node --check static/js/chat.js. --- static/app.js | 4 +++ static/index.html | 70 +++++++++++++++++++++++------------------------ static/js/chat.js | 8 ++++++ 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/static/app.js b/static/app.js index 8d1b7b7..887bb9d 100644 --- a/static/app.js +++ b/static/app.js @@ -1564,6 +1564,8 @@ function initializeEventListeners() { saveToggleState(st); agentBtn.classList.toggle('active', mode === 'agent'); chatBtn.classList.toggle('active', mode === 'chat'); + agentBtn.setAttribute('aria-pressed', String(mode === 'agent')); + chatBtn.setAttribute('aria-pressed', String(mode === 'chat')); // Slide the pill to the active button const toggle = agentBtn.closest('.mode-toggle'); if (toggle) toggle.classList.toggle('mode-chat', mode === 'chat'); @@ -1621,11 +1623,13 @@ function initializeEventListeners() { const chk = el(checkboxId); if (chk) chk.checked = saved; btn.classList.toggle('active', saved); + btn.setAttribute('aria-pressed', String(saved)); btn.addEventListener('click', () => { const curMode = (loadToggleState().mode) || 'chat'; const chk = el(checkboxId); chk.checked = !chk.checked; btn.classList.toggle('active', chk.checked); + btn.setAttribute('aria-pressed', String(chk.checked)); saveToolPref(stateKey, curMode, chk.checked); showToolToggleToast(stateKey, chk.checked); if (chk.checked) _showToolSplash(stateKey); diff --git a/static/index.html b/static/index.html index 014880b..55aa79e 100644 --- a/static/index.html +++ b/static/index.html @@ -265,7 +265,7 @@

Long-term facts the AI remembers across chats — recall, edit, or curate.

- @@ -274,7 +274,7 @@
- +
@@ -304,7 +304,7 @@

- + Add a memory — e.g. 'I prefer concise replies'
@@ -315,19 +315,19 @@

Create a skill by hand — title, what it solves, and an approach.

- + Title — short name, e.g. “build-vllm-wheel”
- + When to use — what problem does this skill solve?
- + How — the approach, steps, commands, or rules to follow
- + Tags — comma-separated, e.g. python, build, vllm
@@ -368,7 +368,7 @@
- + @@ -464,12 +464,12 @@

Colors

-
-
-
-
-
-
+
+
+
+
+
+
@@ -479,38 +479,38 @@
Chat Bubbles
-
-
-
+
+
+
Sidebar
-
-
+
+
Chat Input / Prompt Area
-
-
-
-
+
+
+
+
Code Blocks
-
-
+
+
Controls
-
+
@@ -559,7 +559,7 @@
- @@ -567,7 +567,7 @@
- @@ -993,7 +993,7 @@