Skip to content

Commit 23a8e00

Browse files
authored
47 Accessibility (#58)
* #47 main block * #47 remove tabindex * #47 use buttons for kbd navigation * #47 adjust colors * #47 colors * #47 tests * #47 language selector
1 parent 2bb0400 commit 23a8e00

File tree

13 files changed

+108
-25
lines changed

13 files changed

+108
-25
lines changed

src/components/Badge/Badge.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const Badge = ({ children, className, testId = 'badge' }: BadgeProps): JSX.Eleme
88
return (
99
<div
1010
className={classNames(
11-
'rounded-full bg-red-600 px-1 py-0.5 text-[10px] font-bold leading-none text-white dark:opacity-75',
11+
'rounded-full bg-red-600 px-1 py-0.5 text-[10px] font-bold leading-none text-white dark:bg-red-700 dark:opacity-75',
1212
className,
1313
)}
1414
data-testid={testId}

src/components/Button/LanguageToggle.tsx

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PropsWithClassName } from '@leanstacks/react-common';
1+
import { ButtonVariant, PropsWithClassName } from '@leanstacks/react-common';
22
import { useTranslation } from 'react-i18next';
33

44
import { StorageKeys } from 'utils/constants';
@@ -7,6 +7,7 @@ import Dropdown from 'components/Dropdown/Dropdown';
77
import Icon from 'components/Icon/Icon';
88
import DropdownContent from 'components/Dropdown/DropdownContent';
99
import DropdownItem from 'components/Dropdown/DropdownItem';
10+
import Button from './Button';
1011

1112
/**
1213
* Properties for the `LanguageToggle` component.
@@ -34,17 +35,27 @@ const LanguageToggle = ({ className }: LanguageToggleProps): JSX.Element => {
3435

3536
return (
3637
<Dropdown
37-
toggle={<Icon name="language" className="px-2 py-1" />}
38+
toggle={
39+
<Button variant={ButtonVariant.Text}>
40+
<Icon name="language" />
41+
</Button>
42+
}
3843
content={
3944
<DropdownContent className="text-sm">
4045
<DropdownItem onClick={() => setLanguage('en')} testId="dropdown-item-en">
41-
English
46+
<Button variant={ButtonVariant.Text} className="!p-0">
47+
English
48+
</Button>
4249
</DropdownItem>
4350
<DropdownItem onClick={() => setLanguage('fr')} testId="dropdown-item-fr">
44-
French
51+
<Button variant={ButtonVariant.Text} className="!p-0">
52+
French
53+
</Button>
4554
</DropdownItem>
4655
<DropdownItem onClick={() => setLanguage('es')} testId="dropdown-item-es">
47-
Spanish
56+
<Button variant={ButtonVariant.Text} className="!p-0">
57+
Spanish
58+
</Button>
4859
</DropdownItem>
4960
</DropdownContent>
5061
}

src/components/Layout/StandardLayout.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ const StandardLayout = ({
2525
return (
2626
<div className={className} data-testid={testId}>
2727
<Header />
28-
<Outlet />
28+
<main>
29+
<Outlet />
30+
</main>
2931
<Footer />
3032
<Toasts />
3133
</div>

src/components/Link/Link.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ interface LinkProps extends RouterLinkProps, PropsWithTestId {}
2020
const Link = ({ children, className, testId = 'link', ...props }: LinkProps): JSX.Element => {
2121
return (
2222
<RouterLink
23-
className={classNames('text-blue-600 hover:underline hover:opacity-75', className)}
23+
className={classNames(
24+
'text-blue-600 hover:underline hover:opacity-75 dark:text-blue-400',
25+
className,
26+
)}
2427
data-testid={testId}
2528
{...props}
2629
>

src/components/Text/CodeSnippet.tsx

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,37 @@
11
import { SandpackProvider, SandpackLayout, SandpackCodeEditor } from '@codesandbox/sandpack-react';
22
import { PropsWithClassName, PropsWithTestId } from '@leanstacks/react-common';
33
import { useSettings } from 'hooks/useSettings';
4+
5+
/**
6+
* The GitHub light Sandpack theme.
7+
* @see {@link https://sandpack.codesandbox.io/theme}
8+
*/
9+
const themeLight = {
10+
colors: {
11+
surface1: '#ffffff',
12+
surface2: '#F3F3F3',
13+
surface3: '#f5f5f5',
14+
clickable: '#959da5',
15+
base: '#24292e',
16+
disabled: '#d1d4d8',
17+
hover: '#24292e',
18+
accent: '#24292e',
19+
},
20+
syntax: {
21+
keyword: '#d73a49',
22+
property: '#005cc5',
23+
plain: '#24292e',
24+
static: '#032f62',
25+
string: '#032f62',
26+
definition: '#6f42c1',
27+
punctuation: '#24292e',
28+
tag: '#22863a',
29+
comment: {
30+
color: '#6a737d',
31+
},
32+
},
33+
};
34+
435
/**
536
* Properties for the `CodeSnippet` React component.
637
* @param {string} code - The code snippet.
@@ -29,7 +60,11 @@ const CodeSnippet = ({
2960

3061
return (
3162
<div className={className} data-testid={testId}>
32-
<SandpackProvider template="react" theme={theme} files={files}>
63+
<SandpackProvider
64+
template="react"
65+
theme={theme === 'light' ? themeLight : 'dark'}
66+
files={files}
67+
>
3368
<SandpackLayout>
3469
<SandpackCodeEditor
3570
className="!h-fit rounded-lg"

src/components/Text/__tests__/CodeSnippet.test.tsx

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1-
import { describe, expect, it } from 'vitest';
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
22
import { render, screen } from 'test/test-utils';
3+
4+
import * as UseSettings from 'hooks/useSettings';
5+
36
import CodeSnippet from '../CodeSnippet';
47

58
describe('CodeSnippet', () => {
9+
const useSettingsSpy = vi.spyOn(UseSettings, 'useSettings');
10+
11+
beforeEach(() => {
12+
useSettingsSpy.mockReturnValue({ theme: 'light' });
13+
});
14+
615
it('should render successfully', async () => {
716
// ARRANGE
817
render(<CodeSnippet code="<></>" />);
@@ -38,4 +47,14 @@ describe('CodeSnippet', () => {
3847
// ASSERT
3948
expect(screen.getByTestId('code-snippet').textContent).toBe('<div>content</div>');
4049
});
50+
51+
it('should use dark theme', async () => {
52+
// ARRANGE
53+
useSettingsSpy.mockReturnValue({ theme: 'dark' });
54+
render(<CodeSnippet code="<></>" />);
55+
await screen.findByTestId('code-snippet');
56+
57+
// ASSERT
58+
expect(screen.getByTestId('code-snippet').querySelector('.dark')).not.toBeNull();
59+
});
4160
});

src/pages/ComponentsPage/components/AvatarComponents.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ const AvatarComponents = ({
4747
const columnHelper = createColumnHelper<ComponentProperty>();
4848
const columns = [
4949
columnHelper.accessor('name', {
50-
cell: (info) => <span className="font-mono text-sky-600">{info.getValue()}</span>,
50+
cell: (info) => (
51+
<span className="font-mono text-sky-700 dark:text-sky-500">{info.getValue()}</span>
52+
),
5153
header: () => 'Name',
5254
}),
5355
columnHelper.accessor('description', {

src/pages/ComponentsPage/components/BadgeComponents.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ const BadgeComponents = ({
4141
const columnHelper = createColumnHelper<ComponentProperty>();
4242
const columns = [
4343
columnHelper.accessor('name', {
44-
cell: (info) => <span className="font-mono text-sky-600">{info.getValue()}</span>,
44+
cell: (info) => (
45+
<span className="font-mono text-sky-700 dark:text-sky-500">{info.getValue()}</span>
46+
),
4547
header: () => 'Name',
4648
}),
4749
columnHelper.accessor('description', {
@@ -86,25 +88,31 @@ const BadgeComponents = ({
8688

8789
<div className="my-8">
8890
<div className="mb-2 flex place-content-center rounded border border-neutral-500/10 p-4 dark:bg-neutral-700/25">
89-
<Badge className="!bg-blue-500" testId="my-badge">
91+
<Badge className="!bg-blue-600 dark:!bg-blue-700" testId="my-badge">
9092
19
9193
</Badge>
9294
</div>
9395
<CodeSnippet
9496
className="my-2"
95-
code={`<Badge className='!bg-blue-500' testId='my-badge'>19</Badge>`}
97+
code={`<Badge className='!bg-blue-600 dark:!bg-blue-700' testId='my-badge'>19</Badge>`}
9698
/>
9799
</div>
98100

99101
<div className="my-8">
100102
<div className="mb-2 flex place-content-center rounded border border-neutral-500/10 p-4 dark:bg-neutral-700/25">
101-
<Badge className="!bg-neutral-500 uppercase" testId="badge-status-closed">
103+
<Badge
104+
className="!bg-neutral-500 uppercase dark:!bg-neutral-300 dark:text-black"
105+
testId="badge-status-closed"
106+
>
102107
Closed
103108
</Badge>
104109
</div>
105110
<CodeSnippet
106111
className="my-2"
107-
code={`<Badge className="!bg-neutral-500 uppercase" testId="badge-status-closed">
112+
code={`<Badge
113+
className="!bg-neutral-500 uppercase dark:!bg-neutral-300 dark:text-black"
114+
testId="badge-status-closed"
115+
>
108116
Closed
109117
</Badge>`}
110118
/>

src/pages/ComponentsPage/components/ButtonComponents.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ const ButtonComponents = ({
4949
const columnHelper = createColumnHelper<ComponentProperty>();
5050
const columns = [
5151
columnHelper.accessor('name', {
52-
cell: (info) => <span className="font-mono text-sky-600">{info.getValue()}</span>,
52+
cell: (info) => (
53+
<span className="font-mono text-sky-700 dark:text-sky-500">{info.getValue()}</span>
54+
),
5355
header: () => 'Name',
5456
}),
5557
columnHelper.accessor('description', {

src/pages/ComponentsPage/components/CardComponents.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ const CardComponents = ({
6464
];
6565
const columns = [
6666
columnHelper.accessor('name', {
67-
cell: (info) => <span className="font-mono text-sky-600">{info.getValue()}</span>,
67+
cell: (info) => (
68+
<span className="font-mono text-sky-700 dark:text-sky-500">{info.getValue()}</span>
69+
),
6870
header: () => 'Name',
6971
}),
7072
columnHelper.accessor('description', {

0 commit comments

Comments
 (0)