Skip to content

Commit 3018e62

Browse files
committed
fix accessibility issues
1 parent 2f21e6c commit 3018e62

File tree

7 files changed

+130
-34
lines changed

7 files changed

+130
-34
lines changed

astro/components/Benchmarks.astro

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
<section>
1+
<section aria-labelledby="benchmarks-heading">
22
<header>
3-
<h2>Ada is fast</h2>
3+
<h2 id="benchmarks-heading">Ada is fast</h2>
44
<p>
55
On a benchmark where we need to validate and normalize{" "}
66
<a
@@ -12,8 +12,27 @@
1212
</header>
1313
<div>
1414
<div style="width: 800px;" class="container-chart">
15-
<canvas id="acquisitions"></canvas>
15+
<canvas
16+
id="acquisitions"
17+
role="img"
18+
aria-label="Bar chart comparing URL parsing speed: Ada 188 ns/URL, Servo URL 664 ns/URL, cURL 1471 ns/URL"
19+
></canvas>
1620
</div>
21+
<!-- Visually-hidden text alternative for screen readers -->
22+
<table class="sr-only">
23+
<caption>URL parsing speed comparison (lower is faster)</caption>
24+
<thead>
25+
<tr>
26+
<th scope="col">Parser</th>
27+
<th scope="col">Speed (ns/URL)</th>
28+
</tr>
29+
</thead>
30+
<tbody>
31+
<tr><td>Ada</td><td>188</td></tr>
32+
<tr><td>Servo URL</td><td>664</td></tr>
33+
<tr><td>cURL</td><td>1471</td></tr>
34+
</tbody>
35+
</table>
1736
</div>
1837
</section>
1938

@@ -59,6 +78,19 @@
5978
margin-inline: auto;
6079
}
6180

81+
/* Visually hidden but accessible to screen readers */
82+
.sr-only {
83+
position: absolute;
84+
width: 1px;
85+
height: 1px;
86+
padding: 0;
87+
margin: -1px;
88+
overflow: hidden;
89+
clip: rect(0, 0, 0, 0);
90+
white-space: nowrap;
91+
border-width: 0;
92+
}
93+
6294
:root[data-theme="dark"] {
6395
& p {
6496
color: var(--sl-color-gray-2);
@@ -94,15 +126,37 @@
94126

95127
<script>
96128
import Chart from "chart.js/auto";
97-
98-
(async function () {
99-
const data = [
100-
{ competitors: "Ada", count: 188 },
101-
{ competitors: "Servo URL", count: 664 },
102-
{ competitors: "cURL", count: 1471 },
103-
];
104-
105-
new Chart(document.getElementById("acquisitions") as HTMLCanvasElement, {
129+
130+
function getChartColors() {
131+
const style = getComputedStyle(document.documentElement);
132+
// Use Starlight's own grey tokens so colours adapt to both themes
133+
const tickColor =
134+
style.getPropertyValue("--sl-color-gray-3").trim() || "#6b7280";
135+
const gridColor =
136+
style.getPropertyValue("--sl-color-gray-6").trim() ||
137+
"rgba(107,114,128,0.2)";
138+
return { tickColor, gridColor };
139+
}
140+
141+
const data = [
142+
{ competitors: "Ada", count: 188 },
143+
{ competitors: "Servo URL", count: 664 },
144+
{ competitors: "cURL", count: 1471 },
145+
];
146+
147+
let chart: Chart | null = null;
148+
149+
function buildChart() {
150+
const canvas = document.getElementById(
151+
"acquisitions"
152+
) as HTMLCanvasElement | null;
153+
if (!canvas) return;
154+
155+
if (chart) chart.destroy();
156+
157+
const { tickColor, gridColor } = getChartColors();
158+
159+
chart = new Chart(canvas, {
106160
type: "bar",
107161
options: {
108162
indexAxis: "y",
@@ -114,16 +168,16 @@
114168
callback: function (value) {
115169
return `${value}ns`;
116170
},
117-
color: "#757887",
171+
color: tickColor,
118172
},
119173
grid: {
120174
display: true,
121-
color: "#757887",
175+
color: gridColor,
122176
},
123177
},
124178
y: {
125179
ticks: {
126-
color: "#757887",
180+
color: tickColor,
127181
},
128182
grid: {
129183
display: false,
@@ -161,5 +215,14 @@
161215
],
162216
},
163217
});
164-
})();
165-
</script>
218+
}
219+
220+
buildChart();
221+
222+
// Rebuild the chart whenever Starlight switches between light and dark themes
223+
// so tick/grid colours stay legible in both modes.
224+
new MutationObserver(() => buildChart()).observe(document.documentElement, {
225+
attributes: true,
226+
attributeFilter: ["data-theme"],
227+
});
228+
</script>

astro/components/SiteTitle.astro

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ function pathsMatch(lhs: string, rhs: string): boolean {
1818

1919
<div class="separator"></div>
2020

21-
<div class="menu-items">
21+
<nav aria-label="Main navigation">
2222
{
2323
menuItems.map((menuItem) => (
2424
<a
@@ -31,7 +31,7 @@ function pathsMatch(lhs: string, rhs: string): boolean {
3131
</a>
3232
))
3333
}
34-
</div>
34+
</nav>
3535
</div>
3636

3737
<style>
@@ -66,7 +66,7 @@ function pathsMatch(lhs: string, rhs: string): boolean {
6666
}
6767

6868
@media (min-width: 50rem) {
69-
.menu-items {
69+
nav {
7070
display: flex;
7171
}
7272
.separator {

astro/components/playground/form.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,30 +58,36 @@ export default function PlaygroundForm() {
5858

5959
return (
6060
<div className={`${styles.formContainer} not-content`}>
61-
<form onSubmit={handleSubmit(onSubmit)}>
61+
<form onSubmit={handleSubmit(onSubmit)} aria-label='URL parser'>
6262
<label className={styles.Label}>
63-
<select className={styles.Select} {...register('version')}>
63+
<select className={styles.Select} aria-label='Ada version' {...register('version')}>
6464
{versions.map((value, _index) => (
6565
<option className={styles.Option} value={value} key={value}>
6666
{value}
6767
</option>
6868
))}
6969
</select>
70-
<ChevronDown className={`${styles.Icon} ${styles.Caret}`} />
70+
<ChevronDown aria-hidden='true' className={`${styles.Icon} ${styles.Caret}`} />
7171
</label>
7272

7373
<div>
7474
<input
7575
type='text'
7676
required
77+
aria-label='URL to parse'
7778
placeholder='Please enter a valid URL to parse through Ada'
7879
defaultValue={defaultValue}
7980
{...register('url', { required: true })}
8081
className={styles.Input}
8182
/>
8283

83-
<button type='submit' disabled={formState.isLoading} className={styles.Button}>
84-
{formState.isLoading && <Loader2 className={styles.loader} />}
84+
<button
85+
type='submit'
86+
disabled={formState.isLoading}
87+
aria-busy={formState.isLoading}
88+
className={styles.Button}
89+
>
90+
{formState.isLoading && <Loader2 aria-hidden='true' className={styles.loader} />}
8591
Parse
8692
</button>
8793
</div>

astro/components/playground/result.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,10 @@ function getDiagram(props: WASMResponse) {
136136
export default function ParsingResult(props: WASMResponse) {
137137
const alert = (
138138
<div role='alert' className={styles.Alert}>
139-
<Terminal className={styles.Terminal} />
140-
<h5 className={styles.AlertTitle}>
139+
<Terminal aria-hidden='true' className={styles.Terminal} />
140+
<p className={styles.AlertTitle}>
141141
{props.result === 'success' ? 'Parsing successful!' : 'Parsing failed!'}
142-
</h5>
142+
</p>
143143
<p className={styles.AlertDescription}>
144144
{props.result === 'success'
145145
? `Input resolved into "${props.href}"`
@@ -166,10 +166,14 @@ export default function ParsingResult(props: WASMResponse) {
166166
</Tabs.Trigger>
167167
</Tabs.List>
168168
<Tabs.Content className={styles.TabsContent} value='diagram'>
169-
<pre>{getDiagram(props)}</pre>
169+
<pre role='img' aria-label='ASCII diagram of parsed URL components'>
170+
{getDiagram(props)}
171+
</pre>
170172
</Tabs.Content>
171173
<Tabs.Content className={styles.TabsContent} value='raw'>
172-
<pre>{JSON.stringify(props, null, 2)}</pre>
174+
<section aria-label='Parsed URL components as JSON'>
175+
<pre>{JSON.stringify(props, null, 2)}</pre>
176+
</section>
173177
</Tabs.Content>
174178
</Tabs.Root>
175179
</>

astro/components/playground/styles/form.module.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ form > div {
4343
cursor: pointer;
4444
}
4545

46+
.Button:focus-visible {
47+
outline: 2px solid var(--sl-color-text-accent);
48+
outline-offset: 0.25rem;
49+
}
50+
4651
.Button:disabled {
4752
pointer-events: none;
4853
opacity: 0.5;
@@ -65,6 +70,12 @@ form > div {
6570
border: 1px solid var(--sl-color-white);
6671
}
6772

73+
.Input:focus-visible {
74+
outline: 2px solid var(--sl-color-text-accent);
75+
outline-offset: 0;
76+
border-color: transparent;
77+
}
78+
6879
.Input:disabled {
6980
cursor: not-allowed;
7081
opacity: 0.5;
@@ -104,6 +115,12 @@ form > div {
104115
padding-inline: 1.25rem;
105116
}
106117

118+
.Select:focus-visible {
119+
outline: 2px solid var(--sl-color-text-accent);
120+
outline-offset: 2px;
121+
border-radius: 2px;
122+
}
123+
107124
.Option {
108125
background-color: var(--sl-color-bg-nav);
109126
color: var(--sl-color-gray-1);

astro/components/playground/ui/toast.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,14 @@ const ToastClose = React.forwardRef<
3131
React.ElementRef<typeof ToastPrimitives.Close>,
3232
React.ComponentPropsWithoutRef<typeof ToastPrimitives.Close>
3333
>(({ ...props }, ref) => (
34-
<ToastPrimitives.Close ref={ref} className={styles.Close} toast-close='' {...props}>
35-
<X className={styles.X} />
34+
<ToastPrimitives.Close
35+
ref={ref}
36+
className={styles.Close}
37+
aria-label='Close notification'
38+
toast-close=''
39+
{...props}
40+
>
41+
<X aria-hidden='true' className={styles.X} />
3642
</ToastPrimitives.Close>
3743
))
3844
ToastClose.displayName = ToastPrimitives.Close.displayName

public/site.webmanifest

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "",
3-
"short_name": "",
2+
"name": "Ada URL",
3+
"short_name": "Ada URL",
44
"icons": [
55
{
66
"src": "/android-chrome-192x192.png",

0 commit comments

Comments
 (0)