Run ui-ux-agent: Improve landing page a11y and add style guide

- Created `docs/style-guide.md` documenting design system.
- Refined `landing/index.html` with ARIA attributes and keyboard navigation for agent selection.
- Verified changes with Playwright script.

Co-authored-by: PR0M3TH3AN <[email protected]>
This commit is contained in:
google-labs-jules[bot]andPR0M3TH3AN committed 2026-02-25 05:35:27 +00:00
1 parent 289bad78a8
commit de8b62ef02
7 files changed
+233 -10

No files matched your search

+95
View File
@@ -0,0 +1,95 @@
# TORCH Style Guide
This document outlines the design system, color palette, and typography used in the TORCH project (`dashboard/` and `landing/`).
## Color Palette
The project uses a dark theme with high-contrast text and vibrant accents.
### Core Colors
| Name | CSS Variable | Hex | Usage |
|:---------------|:-------------------|:----------|:-------------------------------------------|
| **Surface** | `--surface` | `#0b1020` | Main background color. |
| **Surface Alt**| `--surface-alt` | `#151b2f` | Card backgrounds, headers, secondary areas.|
| **Text** | `--text` | `#dbe4ff` | Primary body text (slightly blue-tinted). |
| **Text Strong**| `--text-strong` | `#ffffff` | Headings, emphasized text. |
| **Muted** | `--muted` | `#9aa6c6` | Secondary text, metadata, descriptions. |
| **Border** | `--border` | `#2a3456` | Borders for cards, inputs, dividers. |
### Brand & Functional Colors
| Name | CSS Variable | Hex | Usage |
|:---------------|:-------------------|:----------|:-------------------------------------------|
| **Accent** | `--accent` | `#4f8cff` | Primary buttons, active states, links. |
| **Accent Strong**| `--accent-strong`| `#2f6be5` | Hover states for accent elements. |
| **Info** | `--info` | `#46b7ff` | Informational messages, icons. |
| **Info Strong**| `--info-strong` | `#8ad4ff` | Stronger info emphasis. |
| **Success** | `--success` | `#35c47c` | Success messages, "Active" statuses. |
| **Warning** | `--warning` | `#f5b84b` | Warning alerts. |
| **Danger** | `--danger` | `#ff6b6b` | Error messages, destructive actions. |
### Auxiliary Colors
| Name | CSS Variable | Hex |
|:---------------|:-------------------|:----------|
| **Purple** | `--purple` | `#a855f7` |
| **Pink** | `--pink` | `#ec4899` |
| **Teal** | `--teal` | `#2dd4bf` |
## Typography
### Font Families
* **Primary**: `Inter`, `system-ui`, `-apple-system`, `Segoe UI`, `Roboto`, `sans-serif`
* **Monospace**: `ui-monospace`, `SFMono-Regular`, `Menlo`, `Monaco`, `Consolas`, `monospace`
### Hierarchy
* **Headings**: Bold (`700`), `Text Strong`.
* **Body**: Regular (`400`), `Text`.
* **Small/Meta**: Small size, `Muted`.
## Components
### Buttons
* **Primary CTA**:
* Background: `var(--accent)`
* Text: `white`
* Border Radius: `9999px` (Pill shape)
* Hover: `var(--accent-strong)`, slight transform up.
* **Secondary CTA**:
* Background: Transparent or low opacity white.
* Border: `var(--border)`
* Text: `var(--text)`
* Hover: Lighter background, `Text Strong`.
### Cards
* Background: `var(--surface-alt)`
* Border: `1px solid var(--border)`
* Radius: `12px` or `1rem`
* Hover: Border color changes to `var(--accent)`, slight lift (`transform: translateY(-5px)`).
### Status Badges
* Small, pill-shaped (`border-radius: 99px`).
* Uppercase, bold, small font size.
* Active: Background `var(--accent)`, Text `var(--surface)`.
* Disabled/Inactive: Background `rgba(255,255,255,0.1)`, Text `var(--muted)`.
## Layout
* **Container**: Max-width `1200px` centered.
* **Grid**: Responsive grids using `grid-template-columns: repeat(auto-fit, minmax(..., 1fr))`.
* **Spacing**: Uses `rem` units (e.g., `1rem`, `2rem`, `4rem`).
## Accessibility Guidelines
* **Contrast**: Ensure text passes WCAG AA standards against the dark background.
* **Interactive Elements**:
* Must have `role="button"` or be `<button>`/`<a>`.
* Must be keyboard accessible (`tabindex="0"`).
* Must have visible focus states (`focus:ring`).
* **Images**: All images must have `alt` text. Decorative images should use `aria-hidden="true"`.
+24 -10
View File
@@ -809,7 +809,7 @@
</head>
<body>
<div class="background-decoration">
<div class="background-decoration" aria-hidden="true">
<svg viewBox="0 0 1440 1024" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice">
<defs>
<linearGradient id="warmGradient" x1="0%" y1="0%" x2="100%" y2="0%">
@@ -874,8 +874,8 @@
<div class="install-container scroll-reveal">
<h2 class="mb-8 text-text-strong" style="font-size: 2rem;">Choose Your Agent</h2>
<div class="agent-selector">
<div id="card-jules" onclick="selectAgent('jules')" class="agent-card active" style="cursor: pointer;">
<div class="agent-selector" role="radiogroup" aria-label="Select an Agent">
<div id="card-jules" onclick="selectAgent('jules')" class="agent-card active" style="cursor: pointer;" role="radio" aria-checked="true" tabindex="0">
<div class="agent-header">
<span class="agent-name">Jules</span>
<span class="agent-status">Active</span>
@@ -883,7 +883,7 @@
<p class="agent-desc">Web-based tool with Auto-Scheduler. Optimized for Google's latest coding agent. <a href="https://jules.google/" target="_blank" onclick="event.stopPropagation()">Learn more</a>.</p>
</div>
<div id="card-codex" onclick="selectAgent('codex')" class="agent-card" style="cursor: pointer;">
<div id="card-codex" onclick="selectAgent('codex')" class="agent-card" style="cursor: pointer;" role="radio" aria-checked="false" tabindex="0">
<div class="agent-header">
<span class="agent-name">Codex CLI</span>
<span class="agent-status">Active</span>
@@ -891,7 +891,7 @@
<p class="agent-desc">Advanced reasoning for complex tasks. (Requires full access permissions) <a href="https://openai.com/blog/openai-codex" target="_blank" onclick="event.stopPropagation()">Learn more</a>.</p>
</div>
<div id="card-opencode" onclick="selectAgent('opencode')" class="agent-card" style="cursor: pointer;">
<div id="card-opencode" onclick="selectAgent('opencode')" class="agent-card" style="cursor: pointer;" role="radio" aria-checked="false" tabindex="0">
<div class="agent-header">
<span class="agent-name">OpenCode CLI</span>
<span class="agent-status">Active</span>
@@ -899,7 +899,7 @@
<p class="agent-desc">Open source models running locally. <a href="https://opencode.ai/" target="_blank" onclick="event.stopPropagation()">Learn more</a>.</p>
</div>
<div id="card-claude" onclick="selectAgent('claude')" class="agent-card" style="cursor: pointer;">
<div id="card-claude" onclick="selectAgent('claude')" class="agent-card" style="cursor: pointer;" role="radio" aria-checked="false" tabindex="0">
<div class="agent-header">
<span class="agent-name">Claude Code CLI</span>
<span class="agent-status">Active</span>
@@ -907,7 +907,7 @@
<p class="agent-desc">Long-context understanding and safety. (CLI Required, needs cronjob) <a href="https://claude.ai/" target="_blank" onclick="event.stopPropagation()">Learn more</a>.</p>
</div>
<div id="card-gemini" onclick="selectAgent('gemini')" class="agent-card" style="cursor: pointer;">
<div id="card-gemini" onclick="selectAgent('gemini')" class="agent-card" style="cursor: pointer;" role="radio" aria-checked="false" tabindex="0">
<div class="agent-header">
<span class="agent-name">Gemini CLI</span>
<span class="agent-status">Active</span>
@@ -915,7 +915,7 @@
<p class="agent-desc">Google's multimodal AI model. (CLI Required, needs cronjob) <a href="https://deepmind.google/technologies/gemini/" target="_blank" onclick="event.stopPropagation()">Learn more</a>.</p>
</div>
<div id="card-qwen" onclick="selectAgent('qwen')" class="agent-card" style="cursor: pointer;">
<div id="card-qwen" onclick="selectAgent('qwen')" class="agent-card" style="cursor: pointer;" role="radio" aria-checked="false" tabindex="0">
<div class="agent-header">
<span class="agent-name">Qwen Coder CLI</span>
<span class="agent-status">Active</span>
@@ -923,7 +923,7 @@
<p class="agent-desc">Alibaba's open weights coding model. (CLI Required, needs cronjob) <a href="https://qwenlm.github.io/" target="_blank" onclick="event.stopPropagation()">Learn more</a>.</p>
</div>
<div id="card-antigravity" onclick="selectAgent('antigravity')" class="agent-card" style="cursor: pointer;">
<div id="card-antigravity" onclick="selectAgent('antigravity')" class="agent-card" style="cursor: pointer;" role="radio" aria-checked="false" tabindex="0">
<div class="agent-header">
<span class="agent-name">Antigravity IDE</span>
<span class="agent-status">Active</span>
@@ -1527,14 +1527,28 @@ npm install https://github.com/PR0M3TH3AN/TORCH/archive/refs/heads/main.tar.gz &
.replace(/'/g, "&#039;");
}
// Handle keyboard navigation for agent cards
document.querySelectorAll('.agent-card').forEach(card => {
card.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
card.click();
}
});
});
function selectAgent(agent) {
// Remove active class from all cards
document.querySelectorAll('.agent-card').forEach(card => card.classList.remove('active'));
document.querySelectorAll('.agent-card').forEach(card => {
card.classList.remove('active');
card.setAttribute('aria-checked', 'false');
});
// Add active class to selected card
const selectedCard = document.getElementById('card-' + agent);
if (selectedCard) {
selectedCard.classList.add('active');
selectedCard.setAttribute('aria-checked', 'true');
}
// Update prompt text
@@ -0,0 +1,22 @@
---
agent: ui-ux-agent
cadence: weekly
run-start: 2026-02-25T05:34:21Z
status: completed
---
## task_log
**Goal:** Improve UI/UX, documentation, and accessibility.
**Steps Taken:**
1. Created `docs/style-guide.md` documenting the design system (colors, typography, components).
2. Refined `landing/index.html` for accessibility:
* Added `aria-hidden="true"` to decorative background.
* Implemented keyboard navigation for agent cards (`tabindex="0"`, `keydown` handler).
* Added ARIA roles (`radiogroup`, `radio`) and states (`aria-checked`).
3. Verified changes using a Playwright script (`verify_landing.py`) to confirm keyboard navigation and state updates.
4. Ran repository validation (`npm run lint`, `npm test`).
**Result:**
The landing page is now more accessible and keyboard-friendly. A comprehensive style guide is available for future reference.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

+43
View File
@@ -0,0 +1,43 @@
from playwright.sync_api import sync_playwright
def run(playwright):
browser = playwright.chromium.launch(headless=True)
page = browser.new_page()
page.goto("http://localhost:8080/landing/index.html")
# Wait for the page to load
page.wait_for_selector(".agent-selector")
# 1. Verify default state (Jules selected)
jules_card = page.locator("#card-jules")
codex_card = page.locator("#card-codex")
print("Checking default state...")
assert jules_card.get_attribute("aria-checked") == "true", "Jules card should be checked by default"
assert codex_card.get_attribute("aria-checked") == "false", "Codex card should not be checked by default"
# 2. Test keyboard navigation and selection
print("Testing keyboard interaction...")
# Focus on the first card (Jules) - assume tab order is correct
jules_card.focus()
# Tab to Codex
page.keyboard.press("Tab")
# Verify focus is on Codex (simulated by checking active element or just pressing Enter)
# Actually, pressing Tab from Jules should go to Codex if tabindex="0" on both.
# Press Enter to select Codex
page.keyboard.press("Enter")
# Verify Codex is selected
assert codex_card.get_attribute("aria-checked") == "true", "Codex card should be checked after Enter"
assert jules_card.get_attribute("aria-checked") == "false", "Jules card should be unchecked after selection change"
# 3. Take screenshot
print("Taking screenshot...")
page.screenshot(path="verification.png")
browser.close()
with sync_playwright() as playwright:
run(playwright)
+49
View File
@@ -0,0 +1,49 @@
from playwright.sync_api import sync_playwright
def run(playwright):
browser = playwright.chromium.launch(headless=True)
page = browser.new_page()
page.goto("http://localhost:8080/landing/index.html")
# Wait for the page to load
page.wait_for_selector(".agent-selector")
# 1. Verify default state (Jules selected)
jules_card = page.locator("#card-jules")
codex_card = page.locator("#card-codex")
print("Checking default state...")
assert jules_card.get_attribute("aria-checked") == "true", "Jules card should be checked by default"
assert codex_card.get_attribute("aria-checked") == "false", "Codex card should not be checked by default"
# 2. Test keyboard navigation and selection
print("Testing keyboard interaction...")
# Focus on the first card (Jules)
jules_card.focus()
# Tab to link inside Jules card
page.keyboard.press("Tab")
# Tab to Codex card
page.keyboard.press("Tab")
# Check if focused element is Codex card
focused_id = page.evaluate("document.activeElement.id")
assert focused_id == "card-codex", f"Expected focus on card-codex, but got {focused_id}"
# Press Enter to select Codex
page.keyboard.press("Enter")
# Verify Codex is selected
assert codex_card.get_attribute("aria-checked") == "true", "Codex card should be checked after Enter"
assert jules_card.get_attribute("aria-checked") == "false", "Jules card should be unchecked after selection change"
# 3. Take screenshot
print("Taking screenshot...")
page.screenshot(path="verification.png")
browser.close()
if __name__ == "__main__":
with sync_playwright() as playwright:
run(playwright)