mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-10-03 08:02:02 +00:00
feat(a11y): announce the app's own dialogs as dialogs, named by their title
The SSH sheet, the worktree form and the in-app alert are dialogs to a screen reader, titled with the question they ask.
This commit is contained in:
+12
-1
@@ -61,8 +61,19 @@ pub(crate) fn popover_rungs(cx: &App) -> Surface {
|
||||
|
||||
/// The card itself, opaque and occluding. Callers add the header, body and
|
||||
/// footer as children, in that order.
|
||||
pub(crate) fn card(width: f32, cx: &App) -> Div {
|
||||
///
|
||||
/// `title` is what a screen reader announces the card as — a dialog, named
|
||||
/// by the question it asks.
|
||||
pub(crate) fn card(
|
||||
id: impl Into<ElementId>,
|
||||
title: impl Into<SharedString>,
|
||||
width: f32,
|
||||
cx: &App,
|
||||
) -> Stateful<Div> {
|
||||
v_flex()
|
||||
.id(id)
|
||||
.role(gpui::Role::Dialog)
|
||||
.aria_label(title)
|
||||
.occlude()
|
||||
.w(px(width))
|
||||
.map(|panel| crate::ui::theme::floating_surface(panel, cx))
|
||||
|
||||
+1
-1
@@ -212,7 +212,7 @@ impl Render for TextPrompt {
|
||||
0..=2 => ALERT_W,
|
||||
_ => ALERT_W_WIDE,
|
||||
};
|
||||
let card = dialog::card(width, cx)
|
||||
let card = dialog::card("prompt-card", self.message.clone(), width, cx)
|
||||
.max_w(gpui::relative(0.9))
|
||||
.gap(px(16.))
|
||||
.pt(px(20.))
|
||||
|
||||
@@ -809,7 +809,7 @@ impl Tty7App {
|
||||
.child(text)
|
||||
};
|
||||
|
||||
let card = dialog::card(SHEET_W, cx)
|
||||
let card = dialog::card("ssh-prompt-card", title.clone(), SHEET_W, cx)
|
||||
.track_focus(&self.ssh_prompt.focus_handle)
|
||||
.key_context("SshPrompt")
|
||||
// The changed-key sheet is the one card allowed a coloured edge:
|
||||
|
||||
+62
-57
@@ -363,66 +363,71 @@ impl Tty7App {
|
||||
let start = (!p.agents.is_empty()).then(|| self.render_worktree_start(p, cx));
|
||||
|
||||
let rungs = dialog::popover_rungs(cx);
|
||||
let card = dialog::card(440., cx)
|
||||
.child(dialog::header(t(L10nKey::WorktreePromptTitle), cx))
|
||||
.child(
|
||||
dialog::body()
|
||||
// A click anywhere else in the form closes the Start menu.
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(|this, _: &gpui::MouseDownEvent, _, cx| {
|
||||
this.close_worktree_start_menu(cx)
|
||||
}),
|
||||
)
|
||||
// The path preview hangs off the Name field it follows,
|
||||
// closer to it than the next field is.
|
||||
.child(
|
||||
dialog::labelled(t(L10nKey::WorktreePromptName), Input::new(&p.name), cx)
|
||||
.child(meta(preview)),
|
||||
)
|
||||
.child(dialog::labelled(
|
||||
t(L10nKey::WorktreePromptBranch),
|
||||
Input::new(&p.branch),
|
||||
cx,
|
||||
))
|
||||
.child(
|
||||
dialog::labelled(t(L10nKey::WorktreePromptBase), Input::new(&p.base), cx)
|
||||
.children(setup_note.map(meta)),
|
||||
)
|
||||
.children(start)
|
||||
.when(takes_task, |body| {
|
||||
body.child(dialog::labelled(
|
||||
t(L10nKey::WorktreePromptTask),
|
||||
Input::new(&p.task),
|
||||
cx,
|
||||
))
|
||||
let card = dialog::card(
|
||||
"worktree-prompt-card",
|
||||
t(L10nKey::WorktreePromptTitle),
|
||||
440.,
|
||||
cx,
|
||||
)
|
||||
.child(dialog::header(t(L10nKey::WorktreePromptTitle), cx))
|
||||
.child(
|
||||
dialog::body()
|
||||
// A click anywhere else in the form closes the Start menu.
|
||||
.on_mouse_down(
|
||||
gpui::MouseButton::Left,
|
||||
cx.listener(|this, _: &gpui::MouseDownEvent, _, cx| {
|
||||
this.close_worktree_start_menu(cx)
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
dialog::footer(cx)
|
||||
.child(dialog::button(
|
||||
"worktree-cancel",
|
||||
t(L10nKey::Cancel),
|
||||
Tone::Secondary,
|
||||
true,
|
||||
rungs,
|
||||
)
|
||||
// The path preview hangs off the Name field it follows,
|
||||
// closer to it than the next field is.
|
||||
.child(
|
||||
dialog::labelled(t(L10nKey::WorktreePromptName), Input::new(&p.name), cx)
|
||||
.child(meta(preview)),
|
||||
)
|
||||
.child(dialog::labelled(
|
||||
t(L10nKey::WorktreePromptBranch),
|
||||
Input::new(&p.branch),
|
||||
cx,
|
||||
))
|
||||
.child(
|
||||
dialog::labelled(t(L10nKey::WorktreePromptBase), Input::new(&p.base), cx)
|
||||
.children(setup_note.map(meta)),
|
||||
)
|
||||
.children(start)
|
||||
.when(takes_task, |body| {
|
||||
body.child(dialog::labelled(
|
||||
t(L10nKey::WorktreePromptTask),
|
||||
Input::new(&p.task),
|
||||
cx,
|
||||
cx.listener(|this, _, window, cx| this.cancel_worktree_prompt(window, cx)),
|
||||
))
|
||||
.child(dialog::button(
|
||||
"worktree-create",
|
||||
if p.busy {
|
||||
t(L10nKey::WorktreePromptCreating)
|
||||
} else {
|
||||
t(L10nKey::WorktreePromptCreate)
|
||||
},
|
||||
Tone::Primary,
|
||||
!(p.busy || nothing_to_name),
|
||||
rungs,
|
||||
cx,
|
||||
cx.listener(|this, _, window, cx| this.submit_worktree_prompt(window, cx)),
|
||||
)),
|
||||
);
|
||||
}),
|
||||
)
|
||||
.child(
|
||||
dialog::footer(cx)
|
||||
.child(dialog::button(
|
||||
"worktree-cancel",
|
||||
t(L10nKey::Cancel),
|
||||
Tone::Secondary,
|
||||
true,
|
||||
rungs,
|
||||
cx,
|
||||
cx.listener(|this, _, window, cx| this.cancel_worktree_prompt(window, cx)),
|
||||
))
|
||||
.child(dialog::button(
|
||||
"worktree-create",
|
||||
if p.busy {
|
||||
t(L10nKey::WorktreePromptCreating)
|
||||
} else {
|
||||
t(L10nKey::WorktreePromptCreate)
|
||||
},
|
||||
Tone::Primary,
|
||||
!(p.busy || nothing_to_name),
|
||||
rungs,
|
||||
cx,
|
||||
cx.listener(|this, _, window, cx| this.submit_worktree_prompt(window, cx)),
|
||||
)),
|
||||
);
|
||||
|
||||
Some(
|
||||
div()
|
||||
|
||||
Reference in New Issue
Block a user