feat(a11y): contrast tokens, accent-solid, responsive drawer, keyboard menus
- Contrast: --fg-muted reaches 4.5:1 on every surface in all nine themes (dark default was 2.55:1); status chips and accent text clear 4.5:1 on their own tints. New --accent-solid(/-hover) + tailwind `accent-solid` is the fill behind white text (.btn-primary, Switch on, Checkbox tick); --accent is now a text colour. Switch off / unchecked Checkbox get a >=3:1 edge. - <html lang> follows the chosen language; a global prefers-reduced-motion rule; index.html body uses a token instead of text-gray-200. - Layout: the sidebar starts collapsed below lg and becomes an off-canvas drawer below md (menu button, backdrop, Escape, useDialog). - ContextMenu: focus moves in, arrows/Home/End, Escape/Tab close, focus returns, a keyboard-opened menu anchors to its target. Select is a real listbox button (aria-expanded, activedescendant, type-ahead). PageTabs implements APG tabs with a tabpanel. New .btn-secondary/.btn-danger/ .btn-icon and a .select class for native selects, all with focus rings. - StatusBar announces connection and "N need you" politely; Sidebar's connection modal uses useDialog; EmptyState/Skeleton/AiToolIcon a11y. - api.ts request(): a non-JSON 200 throws a translated EBADRESPONSE instead of "Unexpected token '<'".
This commit is contained in:
@@ -82,10 +82,13 @@ export interface CheckboxProps {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
// Fill + tick per tone. Accent fills with `accent-solid` under a white tick.
|
||||
// The status colours are TEXT shades — light in dark mode, dark in light mode —
|
||||
// so their tick takes the page colour (surface-0), which contrasts both ways.
|
||||
const TONE = {
|
||||
accent: "bg-accent border-accent",
|
||||
danger: "bg-status-danger border-status-danger",
|
||||
warning: "bg-status-warning border-status-warning",
|
||||
accent: "bg-accent-solid border-accent-solid text-white",
|
||||
danger: "bg-status-danger border-status-danger text-surface-0",
|
||||
warning: "bg-status-warning border-status-warning text-surface-0",
|
||||
} as const;
|
||||
|
||||
/**
|
||||
@@ -114,11 +117,11 @@ export function Checkbox({
|
||||
className={`group inline-flex items-center gap-2 text-left disabled:cursor-not-allowed disabled:opacity-50 focus-visible:outline-none ${className ?? ""}`}
|
||||
>
|
||||
<span
|
||||
className={`flex h-4 w-4 flex-shrink-0 items-center justify-center rounded-[5px] border transition-colors group-focus-visible:ring-2 group-focus-visible:ring-accent/40 ${
|
||||
checked ? TONE[tone] : "bg-surface-2 border-border group-hover:border-border-light"
|
||||
className={`flex h-4 w-4 flex-shrink-0 items-center justify-center rounded-[5px] border transition-colors group-focus-visible:ring-2 group-focus-visible:ring-accent/60 ${
|
||||
checked ? TONE[tone] : "bg-surface-2 border-fg-muted group-hover:border-fg-secondary"
|
||||
}`}
|
||||
>
|
||||
{checked && <Check className="h-3 w-3 text-white" strokeWidth={3} />}
|
||||
{checked && <Check className="h-3 w-3" strokeWidth={3} aria-hidden />}
|
||||
</span>
|
||||
{label != null && (
|
||||
<span
|
||||
|
||||
Reference in New Issue
Block a user