add ARIA labels, pressed states, and fix keyboard visibility across card detail components

This commit is contained in:
Your Name
2026-02-19 19:54:22 +02:00
parent 56eab06dc4
commit d66e90a6d5
6 changed files with 19 additions and 5 deletions

View File

@@ -52,6 +52,7 @@ export function AttachmentSection({
size="icon-xs"
onClick={handleAdd}
className="text-pylon-text-secondary hover:text-pylon-text"
aria-label="Add attachment"
>
<Plus className="size-3.5" />
</Button>
@@ -71,14 +72,14 @@ export function AttachmentSection({
</span>
<button
onClick={() => openPath(att.path)}
className="shrink-0 rounded p-0.5 text-pylon-text-secondary opacity-0 transition-opacity hover:bg-pylon-accent/10 hover:text-pylon-accent group-hover/att:opacity-100"
className="shrink-0 rounded p-0.5 text-pylon-text-secondary opacity-0 transition-opacity hover:bg-pylon-accent/10 hover:text-pylon-accent group-hover/att:opacity-100 focus-visible:opacity-100"
aria-label="Open attachment"
>
<ExternalLink className="size-3" />
</button>
<button
onClick={() => removeAttachment(cardId, att.id)}
className="shrink-0 rounded p-0.5 text-pylon-text-secondary opacity-0 transition-opacity hover:bg-pylon-danger/10 hover:text-pylon-danger group-hover/att:opacity-100"
className="shrink-0 rounded p-0.5 text-pylon-text-secondary opacity-0 transition-opacity hover:bg-pylon-danger/10 hover:text-pylon-danger group-hover/att:opacity-100 focus-visible:opacity-100"
aria-label="Remove attachment"
>
<X className="size-3" />

View File

@@ -121,6 +121,7 @@ export function ChecklistSection({ cardId, checklist }: ChecklistSectionProps) {
onChange={(e) => setNewItemText(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Add item..."
aria-label="New checklist item"
className="h-7 flex-1 rounded-md bg-pylon-column px-2 text-sm text-pylon-text outline-none placeholder:text-pylon-text-secondary/60 focus:ring-1 focus:ring-pylon-accent"
/>
</div>
@@ -176,7 +177,8 @@ function ChecklistRow({ item, onToggle, onUpdate, onDelete }: ChecklistRowProps)
{...attributes}
>
<span
className="shrink-0 cursor-grab text-pylon-text-secondary opacity-0 group-hover/item:opacity-100"
className="shrink-0 cursor-grab text-pylon-text-secondary opacity-0 group-hover/item:opacity-100 focus-visible:opacity-100"
aria-label="Reorder item"
{...listeners}
>
<GripVertical className="size-3" />
@@ -185,6 +187,7 @@ function ChecklistRow({ item, onToggle, onUpdate, onDelete }: ChecklistRowProps)
type="checkbox"
checked={item.checked}
onChange={onToggle}
aria-label={`Mark "${item.text}" as ${item.checked ? "incomplete" : "complete"}`}
className="size-3.5 shrink-0 cursor-pointer accent-pylon-accent"
/>
@@ -215,7 +218,7 @@ function ChecklistRow({ item, onToggle, onUpdate, onDelete }: ChecklistRowProps)
<button
onClick={onDelete}
className="shrink-0 rounded p-0.5 text-pylon-text-secondary opacity-0 transition-opacity hover:bg-pylon-danger/10 hover:text-pylon-danger group-hover/item:opacity-100"
className="shrink-0 rounded p-0.5 text-pylon-text-secondary opacity-0 transition-opacity hover:bg-pylon-danger/10 hover:text-pylon-danger group-hover/item:opacity-100 focus-visible:opacity-100"
aria-label="Delete item"
>
<X className="size-3" />

View File

@@ -47,6 +47,7 @@ export function CommentsSection({ cardId, comments }: CommentsSectionProps) {
onKeyDown={handleKeyDown}
placeholder="Add a comment... (Enter to send, Shift+Enter for newline)"
rows={2}
aria-label="Add a comment"
className="flex-1 resize-none rounded-md bg-pylon-column px-2 py-1.5 text-sm text-pylon-text outline-none placeholder:text-pylon-text-secondary/60 focus:ring-1 focus:ring-pylon-accent"
/>
<Button
@@ -82,7 +83,7 @@ export function CommentsSection({ cardId, comments }: CommentsSectionProps) {
</div>
<button
onClick={() => deleteComment(cardId, comment.id)}
className="shrink-0 self-start rounded p-0.5 text-pylon-text-secondary opacity-0 transition-opacity hover:bg-pylon-danger/10 hover:text-pylon-danger group-hover/comment:opacity-100"
className="shrink-0 self-start rounded p-0.5 text-pylon-text-secondary opacity-0 transition-opacity hover:bg-pylon-danger/10 hover:text-pylon-danger group-hover/comment:opacity-100 focus-visible:opacity-100"
aria-label="Delete comment"
>
<X className="size-3" />

View File

@@ -70,6 +70,7 @@ export function LabelPicker({
variant="ghost"
size="icon-xs"
className="text-pylon-text-secondary hover:text-pylon-text"
aria-label="Manage labels"
>
<Plus className="size-3.5" />
</Button>
@@ -95,6 +96,8 @@ export function LabelPicker({
key={label.id}
onClick={() => toggleCardLabel(cardId, label.id)}
className="flex items-center gap-2 rounded px-2 py-1 text-left text-sm transition-colors hover:bg-pylon-column"
aria-pressed={isSelected}
aria-label={`${isSelected ? "Remove" : "Add"} label: ${label.name}`}
>
<span
className="size-3 shrink-0 rounded-full"
@@ -122,6 +125,7 @@ export function LabelPicker({
onChange={(e) => setNewLabelName(e.target.value)}
onKeyDown={handleCreateKeyDown}
placeholder="Label name..."
aria-label="New label name"
className="h-7 rounded-md bg-pylon-column px-2 text-sm text-pylon-text outline-none placeholder:text-pylon-text-secondary/60 focus:ring-1 focus:ring-pylon-accent"
/>
<div className="flex flex-wrap gap-1.5">
@@ -130,6 +134,7 @@ export function LabelPicker({
key={color}
onClick={() => setNewLabelColor(color)}
className="size-5 rounded-full transition-transform hover:scale-110"
aria-label={`Color ${color}`}
style={{
backgroundColor: color,
outline:

View File

@@ -76,6 +76,7 @@ export function MarkdownEditor({ cardId, value }: MarkdownEditorProps) {
variant={mode === "edit" ? "secondary" : "ghost"}
size="xs"
onClick={() => setMode("edit")}
aria-pressed={mode === "edit"}
className="font-mono text-xs"
>
Edit
@@ -83,6 +84,7 @@ export function MarkdownEditor({ cardId, value }: MarkdownEditorProps) {
<Button
variant={mode === "preview" ? "secondary" : "ghost"}
size="xs"
aria-pressed={mode === "preview"}
onClick={() => {
// Save before switching to preview
if (mode === "edit") {
@@ -113,6 +115,7 @@ export function MarkdownEditor({ cardId, value }: MarkdownEditorProps) {
onChange={handleChange}
onBlur={handleBlur}
placeholder="Add a description... (Markdown supported)"
aria-label="Card description (Markdown)"
className="min-h-[100px] w-full resize-none overflow-hidden bg-transparent px-3 py-2 text-sm text-pylon-text outline-none placeholder:text-pylon-text-secondary/60"
/>
</OverlayScrollbarsComponent>

View File

@@ -27,6 +27,7 @@ export function PriorityPicker({ cardId, priority }: PriorityPickerProps) {
<button
key={value}
onClick={() => updateCard(cardId, { priority: value })}
aria-pressed={priority === value}
className={`rounded-full px-3 py-1 text-xs font-medium transition-all ${
priority === value
? "text-white shadow-sm"