add ARIA labels, pressed states, and fix keyboard visibility across card detail components
This commit is contained in:
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user