From 943b24c371f60acc290ef3745cc2fecd1170b37b Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 15 Feb 2026 19:19:34 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20accessibility=20pass=20=E2=80=94=20sema?= =?UTF-8?q?ntic=20HTML,=20ARIA,=20focus=20indicators,=20high=20contrast?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/board/BoardView.tsx | 37 +++++++++++++++++++++++++- src/components/board/CardThumbnail.tsx | 2 ++ src/components/board/KanbanColumn.tsx | 26 ++++++++++-------- src/index.css | 11 ++++++++ 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/components/board/BoardView.tsx b/src/components/board/BoardView.tsx index bb5437f..7c1e3f4 100644 --- a/src/components/board/BoardView.tsx +++ b/src/components/board/BoardView.tsx @@ -248,14 +248,49 @@ export function BoardView() { const columnIds = board.columns.map((c) => c.id); + const [announcement, setAnnouncement] = useState(""); + + const handleDragEndWithAnnouncement = useCallback( + (event: DragEndEvent) => { + handleDragEnd(event); + const { active, over } = event; + if (over && board) { + const type = active.data.current?.type; + if (type === "card") { + const card = board.cards[active.id as string]; + const targetCol = over.data.current?.type === "column" + ? board.columns.find((c) => c.id === (over.data.current?.columnId ?? over.id)) + : findColumnByCardId(board, over.id as string); + if (card && targetCol) { + setAnnouncement(`Moved card "${card.title}" to ${targetCol.title}`); + } + } else if (type === "column") { + const col = board.columns.find((c) => c.id === (active.id as string)); + if (col) { + setAnnouncement(`Reordered column "${col.title}"`); + } + } + } + }, + [handleDragEnd, board] + ); + return ( <> + {/* Visually hidden live region for drag-and-drop announcements */} +
+ {announcement} +
{/* Label dots */} {card.labels.length > 0 && ( diff --git a/src/components/board/KanbanColumn.tsx b/src/components/board/KanbanColumn.tsx index 9b098d7..8becd30 100644 --- a/src/components/board/KanbanColumn.tsx +++ b/src/components/board/KanbanColumn.tsx @@ -60,11 +60,14 @@ export function KanbanColumn({ column, onCardClick }: KanbanColumnProps) { width, }; + const cardCount = column.cardIds.length; + return ( - -
+
    {column.cardIds.map((cardId) => { const card = board?.cards[cardId]; if (!card) return null; return ( - +
  • + +
  • ); })} -
+
@@ -118,6 +122,6 @@ export function KanbanColumn({ column, onCardClick }: KanbanColumnProps) { )} - + ); } diff --git a/src/index.css b/src/index.css index 69c9087..7bf2bcd 100644 --- a/src/index.css +++ b/src/index.css @@ -146,6 +146,17 @@ @apply bg-background text-foreground; font-family: "Satoshi", system-ui, -apple-system, sans-serif; } + :focus-visible { + outline: 2px solid var(--pylon-accent); + outline-offset: 2px; + } +} + +@media (prefers-contrast: more) { + :root { + --pylon-text: oklch(10% 0.02 50); + --pylon-text-secondary: oklch(35% 0.01 50); + } } @media (prefers-reduced-motion: reduce) {