feat: add VoiceOver accessibility labels to icon-only buttons

Icon-only buttons exposed no usable text to VoiceOver, so they were
announced only as "Button" with no indication of their action. This
adds accessibilityLabel to every icon-only control across the app:

- Floating create button and the expandable action-menu toggle
- Repository star toggle (label reflects star/unstar state)
- File edit, comment edit, instance add/edit buttons
- Commit-history and open-in-browser toolbar buttons
- The markdown editor formatting toolbar (bold, italic, code, etc.)

No behavior or visual changes; labels are additive. Existing
accessibility identifiers are preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
systemBlue 2026-06-02 17:46:12 -04:00
parent b0f50eca38
commit a14a2e172f
8 changed files with 21 additions and 10 deletions

View file

@ -36,6 +36,7 @@ struct CommentView: View {
.foregroundStyle(.secondary)
}
.buttonStyle(.plain)
.accessibilityLabel("Edit comment")
}
}

View file

@ -113,6 +113,7 @@ struct FileViewerView: View {
} label: {
Image(systemName: "pencil")
}
.accessibilityLabel("Edit file")
.accessibilityIdentifier("file-edit-button")
}
}

View file

@ -11,6 +11,7 @@ struct FloatingCreateButton: View {
.frame(width: 56, height: 56)
}
.glassEffect(.regular.tint(.blue).interactive())
.accessibilityLabel("Create")
.padding(.trailing, 20)
.padding(.bottom, 20)
}
@ -36,6 +37,7 @@ struct ExpandableActionMenu<Content: View>: View {
.frame(width: 40, height: 40)
}
.buttonStyle(.glass)
.accessibilityLabel("Actions")
.accessibilityIdentifier("action-menu-toggle")
.accessibilityValue(isExpanded ? "expanded" : "collapsed")
}

View file

@ -79,6 +79,7 @@ struct InstanceListView: View {
} label: {
Image(systemName: "plus")
}
.accessibilityLabel("Add instance")
.accessibilityIdentifier("instance-add-button")
}
}
@ -129,6 +130,7 @@ struct InstanceListView: View {
.foregroundStyle(.secondary)
}
.buttonStyle(.plain)
.accessibilityLabel("Edit instance")
.accessibilityIdentifier("instance-edit-button")
}
}

View file

@ -64,22 +64,23 @@ private struct MarkdownToolbar: View {
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 12) {
toolbarButton("bold", icon: "bold") { wrap("**") }
toolbarButton("italic", icon: "italic") { wrap("_") }
toolbarButton("heading", icon: "number") { prefix("# ") }
toolbarButton("code", icon: "chevron.left.forwardslash.chevron.right") { wrap("`") }
toolbarButton("codeblock", icon: "text.page") { wrapBlock("```") }
toolbarButton("link", icon: "link") { insertLink() }
toolbarButton("list", icon: "list.bullet") { prefix("- ") }
toolbarButton("quote", icon: "text.quote") { prefix("> ") }
toolbarButton("task", icon: "checklist") { prefix("- [ ] ") }
toolbarButton("bold", icon: "bold", label: "Bold") { wrap("**") }
toolbarButton("italic", icon: "italic", label: "Italic") { wrap("_") }
toolbarButton("heading", icon: "number", label: "Heading") { prefix("# ") }
toolbarButton("code", icon: "chevron.left.forwardslash.chevron.right",
label: "Inline code") { wrap("`") }
toolbarButton("codeblock", icon: "text.page", label: "Code block") { wrapBlock("```") }
toolbarButton("link", icon: "link", label: "Insert link") { insertLink() }
toolbarButton("list", icon: "list.bullet", label: "Bulleted list") { prefix("- ") }
toolbarButton("quote", icon: "text.quote", label: "Quote") { prefix("> ") }
toolbarButton("task", icon: "checklist", label: "Task list") { prefix("- [ ] ") }
}
.padding(.horizontal, 8)
.padding(.vertical, 6)
}
}
private func toolbarButton(_ id: String, icon: String, action: @escaping () -> Void) -> some View {
private func toolbarButton(_ id: String, icon: String, label: String, action: @escaping () -> Void) -> some View {
Button(action: action) {
Image(systemName: icon)
.font(.subheadline)
@ -88,6 +89,7 @@ private struct MarkdownToolbar: View {
}
.buttonStyle(.plain)
.foregroundStyle(.primary)
.accessibilityLabel(label)
.accessibilityIdentifier("markdown-toolbar-\(id)")
}

View file

@ -211,6 +211,7 @@ struct RepositoryDetailView: View {
} label: {
Image(systemName: "clock.arrow.circlepath")
}
.accessibilityLabel("Commit history")
.accessibilityIdentifier("commits-button")
}
}

View file

@ -280,6 +280,7 @@ struct RepositoryRow: View {
}
.buttonStyle(.borderless)
.disabled(isStarring)
.accessibilityLabel(isStarred ? "Unstar repository" : "Star repository")
.accessibilityIdentifier("star-button")
}

View file

@ -48,6 +48,7 @@ struct WorkflowRunDetailView: View {
Link(destination: parsed) {
Image(systemName: "safari")
}
.accessibilityLabel("Open in browser")
.accessibilityIdentifier("workflow-run-open-browser")
}
}