Skip to content

Commit

Permalink
fix: improve accessibility and address violations (#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
adamalston committed Dec 12, 2023
1 parent 79c7c04 commit 5fb25e4
Show file tree
Hide file tree
Showing 17 changed files with 103 additions and 65 deletions.
4 changes: 2 additions & 2 deletions src/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ export const App = () => {

return isReady ? (
<AppProvider config={config} isMobile={isMobile}>
<div className="app">
<main className="app">
<Toggle />
<Content />
<Buttons />
<Footer />
<Particles />
</div>
</main>
</AppProvider>
) : (
<></>
Expand Down
10 changes: 4 additions & 6 deletions src/App/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,36 @@ import { Email, GitHub, LinkedIn, Resume } from 'icons';
export const config: Config = {
name: {
display: 'Adam Alston',
aria: 'My name is Adam Alston',
},
title: {
display: 'Software Engineer',
aria: 'I am a software engineer',
},
buttons: [
{
name: 'github',
display: 'GitHub',
aria: 'Visit my GitHub profile',
ariaLabel: 'GitHub profile (opens in new window)',
icon: <GitHub />,
href: 'https://github.com/adamalston/',
},
{
name: 'linked-in',
display: 'LinkedIn',
aria: 'Visit my LinkedIn profile',
ariaLabel: 'LinkedIn profile (opens in new window)',
icon: <LinkedIn />,
href: 'https://www.linkedin.com/in/adam-alston/',
},
{
name: 'resume',
display: 'Resume',
aria: 'View my resume in Google Drive',
ariaLabel: 'Resume in Google Drive (opens in new window)',
icon: <Resume />,
href: 'https://drive.google.com/file/d/1VQ_Oeim_e92QEMi64ejGWY5Hf4RRxfeJ/view',
},
{
name: 'email',
display: 'Email',
aria: 'Send me an email',
ariaLabel: 'Email contact (opens in new window)',
icon: <Email />,
href: 'mailto:aalston9@gmail.com',
},
Expand Down
12 changes: 5 additions & 7 deletions src/Index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ describe('application tests', () => {
element: HTMLElement,
display: RegExp,
link?: string,
skipA11yNameCheck?: boolean,
) => {
expect(element).toBeVisible();
expect(element).toHaveAccessibleName();
expect(element).toHaveAccessibleDescription();
if (!skipA11yNameCheck) expect(element).toHaveAccessibleName();
expect(element).toHaveTextContent(display);
if (link) expect(element).toHaveAttribute('href', link);
};
Expand All @@ -54,26 +54,25 @@ describe('application tests', () => {

expect(parent).toBeVisible();
expect(parent).toHaveAccessibleName();
expect(parent).toHaveAccessibleDescription();
expect(parent).toHaveAttribute('href', link);
};

it('should render name: Adam Alston', () => {
const element = screen.getByTestId('name');

checkContent(element, /^Adam Alston$/);
checkContent(element, /^Adam Alston$/, undefined, true);
});

it('should render title: Software Engineer', () => {
const element = screen.getByTestId('title');

checkContent(element, /^Software Engineer$/);
checkContent(element, /^Software Engineer$/, undefined, true);
});

it('should render creator', () => {
const element = screen.getByTestId('creator');

checkContent(element, /^Adam Alston$/, 'https://www.adamalston.com');
checkContent(element, /^Adam Alston$/, 'https://www.adamalston.com/');
});

it('should render link to source code', () => {
Expand Down Expand Up @@ -129,7 +128,6 @@ describe('application tests', () => {
expect(toggle).toHaveAccessibleDescription();

expect(particles).toBeVisible();
expect(particles).toHaveAccessibleName();

// site should default to the dark theme
expect(toggle).toBeChecked();
Expand Down
9 changes: 8 additions & 1 deletion src/appearance/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ export const options: ISourceOptions = {
},
},
color: {
value: ['c912ed', '00bfff', '22dd22', 'ffd500', 'ff8000', 'ff2600'],
value: [
'ff2600', // Red
'ff8000', // Orange
'ffd500', // Yellow
'22dd22', // Green
'00bfff', // Blue
'c912ed', // Violet (Purple)
],
},
shape: {
type: 'circle',
Expand Down
15 changes: 9 additions & 6 deletions src/appearance/themes.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
import { Themes } from 'types';

// Enhance contrast by using white and black text with reduced opacity over
// colored backgrounds instead of gray.
// https://m2.material.io/design/color/text-legibility.html#text-backgrounds
export const themes: Themes = {
dark: {
key: 'dark',
primaryTextColor: '#fff',
secondaryTextColor: '#ccc',
tertiaryTextColor: '#999',
secondaryTextColor: '#ffffffdd',
tertiaryTextColor: '#ffffff99',
background: '#000',
shadowColor: 'rgba(0, 0, 0, 0.5)',
shadowColor: '#0000007f',
},
light: {
key: 'light',
primaryTextColor: '#000',
secondaryTextColor: '#333',
tertiaryTextColor: '#777',
secondaryTextColor: '#000000dd',
tertiaryTextColor: '#00000099',
background: '#fff',
shadowColor: 'rgba(255, 255, 255, 0.5)',
shadowColor: '#ffffff7f',
},
};
9 changes: 4 additions & 5 deletions src/components/Buttons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,18 @@ export const Buttons = () => {

return (
<Container $theme={theme}>
{config.buttons.map(({ name, display, aria, icon, href }) => (
{config.buttons.map(({ name, display, ariaLabel, icon, href }) => (
<span className="button-container" key={name}>
<a
data-v2={`button-${display}`}
className="button"
aria-label={ariaLabel}
href={href}
target="_blank"
rel="noopener noreferrer"
aria-label={aria}
title={aria}
target="_blank"
>
<div className="icon">{icon}</div>
<span className="icon_title" data-v2={display}>
<span data-v2={display} className="icon_title">
{display}
</span>
</a>
Expand Down
19 changes: 5 additions & 14 deletions src/components/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ const sharedStyles = css`
`;

const C = {
Name: styled.div<{ $theme: Theme }>`
Name: styled.h1<{ $theme: Theme }>`
${sharedStyles};
font-size: 6rem;
margin: 0;
color: ${({ $theme }) => $theme.primaryTextColor};
@media only screen and (max-device-width: 820px) and (-webkit-min-device-pixel-ratio: 2) {
font-size: 4.5rem;
}
`,
Title: styled.div<{ $theme: Theme }>`
Title: styled.h2<{ $theme: Theme }>`
${sharedStyles};
font-size: 3.5rem;
margin: 4rem 0;
Expand All @@ -36,20 +37,10 @@ export const Content = () => {

return (
<>
<C.Name
data-v2="name"
aria-label={config.name.aria}
title={config.name.aria}
$theme={theme}
>
<C.Name data-v2="name" $theme={theme}>
{config.name.display}
</C.Name>
<C.Title
data-v2="title"
aria-label={config.title.aria}
title={config.title.aria}
$theme={theme}
>
<C.Title data-v2="title" $theme={theme}>
{config.title.display}
</C.Title>
</>
Expand Down
25 changes: 13 additions & 12 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { AppContext } from 'App/AppContext';
import { Theme } from 'types';

const F = {
Container: styled.div<{ $isMobile: boolean }>`
Container: styled.footer<{ $isMobile: boolean }>`
position: absolute;
bottom: 0;
right: 0;
Expand All @@ -19,8 +19,11 @@ const F = {
`,
Link: styled.a<{ $theme: Theme }>`
transition: color 0.5s linear;
text-decoration: none;
color: ${({ $theme }) => $theme.secondaryTextColor};
text-decoration: none;
&:hover {
text-decoration: underline;
}
`,
};

Expand All @@ -29,17 +32,14 @@ export const Footer = () => {

return (
<F.Container $isMobile={isMobile}>
<F.Text
data-v2="footer"
aria-label="Designed and built by Adam Alston"
$theme={theme}
>
<F.Text data-v2="footer" $theme={theme}>
{'Designed and built by '}
<F.Link
data-v2="creator"
href="https://www.adamalston.com"
aria-label="Adam's website"
title="A link to Adam's personal website"
aria-label="Adam Alston's personal website (opens in new window)"
href="https://www.adamalston.com/"
rel="noopener noreferrer"
target="_blank"
$theme={theme}
>
{'Adam Alston'}
Expand All @@ -49,9 +49,10 @@ export const Footer = () => {
{' | '}
<F.Link
data-v2="source"
aria-label="Source code for this website (opens in new window)"
href="https://github.com/adamalston/v2/"
aria-label="Source code"
title="View this website's source code in GitHub"
rel="noopener noreferrer"
target="_blank"
$theme={theme}
>
{'Source'}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Particles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const Particles = () => {
const { theme } = useContext(AppContext);

return (
<P.Container data-v2="particles" aria-label="Particles" $theme={theme}>
<P.Container data-v2="particles" $theme={theme}>
<ReactParticles width="100vw" height="100vh" options={options} />
</P.Container>
);
Expand Down
31 changes: 25 additions & 6 deletions src/components/Toggle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Moon, Sun } from 'icons';
import { Theme } from 'types';

const T = {
Container: styled.main`
Container: styled.div`
position: fixed;
z-index: 1;
top: 1rem;
Expand Down Expand Up @@ -46,11 +46,26 @@ const T = {
transition: background-color 0.5s linear;
font-size: 0.5rem;
`,
VisuallyHidden: styled.span`
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
white-space: nowrap;
`,
};

export const Toggle = () => {
const { theme, setTheme } = useContext(AppContext);
const isDark: boolean = theme.key === 'dark';
const ariaLabel = `Currently in ${
isDark ? 'dark' : 'light'
} mode, switch to ${!isDark ? 'dark' : 'light'} mode`;
const toggleDescriptionId = 'toggle-description';

const handleToggle = (checked: boolean) => {
const key: string = checked ? 'dark' : 'light';
Expand All @@ -61,19 +76,23 @@ export const Toggle = () => {

return (
<T.Container>
<T.VisuallyHidden id={toggleDescriptionId}>
Switch between dark and light mode for visual comfort.
</T.VisuallyHidden>
<T.Toggle
data-v2="toggle"
id="toggle"
name="toggle"
type="checkbox"
checked={isDark}
onChange={(event: ChangeEvent<HTMLInputElement>) =>
handleToggle(event.target.checked)
}
aria-label="Theme toggle"
title="Theme toggle"
aria-label={ariaLabel}
aria-describedby={toggleDescriptionId}
onChange={({ target }: ChangeEvent<HTMLInputElement>) => {
handleToggle(target.checked);
}}
/>
<T.Switch htmlFor="toggle" $theme={theme}>
<T.VisuallyHidden>{ariaLabel}</T.VisuallyHidden>
{isDark ? <Moon /> : <Sun />}
</T.Switch>
</T.Container>
Expand Down
7 changes: 6 additions & 1 deletion src/icons/Email.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export const Email = () => (
<svg role="img" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<svg
aria-label="Email icon"
role="img"
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M464.004 4.326L15.986 262.714c-23 13.3-20.7 47.198 3.8 57.297l140.206 57.997v101.996c0 30.198 37.802 43.298 56.702 20.299l60.703-73.797L403.8 478.704c19.101 7.9 40.702-4.2 43.802-24.7l64.003-417.08c4.1-26.698-24.601-45.897-47.602-32.598zm-272.01 475.678v-88.796l54.501 22.499zm224.008-30.899l-206.208-85.196L409.302 128.12c4.8-5.6-2.9-13.199-8.5-8.4l-255.31 217.59-113.505-46.797L480.004 32.025z"
Expand Down
7 changes: 6 additions & 1 deletion src/icons/GitHub.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export const GitHub = () => (
<svg role="img" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<svg
aria-label="GitHub icon"
role="img"
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M296.133 354.174c49.885-5.891 102.942-24.029 102.942-110.192 0-24.49-8.624-44.448-22.67-59.869 2.266-5.89 9.515-28.114-2.734-58.947 0 0-18.139-5.898-60.759 22.669-18.139-4.983-38.09-8.163-56.682-8.163-19.053 0-39.011 3.18-56.697 8.163-43.082-28.567-61.22-22.669-61.22-22.669-12.241 30.833-4.983 53.057-2.718 58.947-14.061 15.42-22.677 35.379-22.677 59.869 0 86.163 53.057 104.301 102.942 110.192-6.344 5.452-12.241 15.873-14.507 30.387-12.702 5.438-45.808 15.873-65.758-18.592 0 0-11.795-21.31-34.012-22.669 0 0-22.224-.453-1.813 13.592 0 0 14.96 6.812 24.943 32.653 0 0 13.6 43.089 76.179 29.48v38.543c0 5.906-4.53 12.702-15.865 10.89C96.139 438.977 32.2 354.626 32.2 255.77c0-123.807 100.216-224.022 224.03-224.022 123.347 0 224.023 100.216 223.57 224.022 0 98.856-63.946 182.754-152.828 212.688-11.342 2.266-15.873-4.53-15.873-10.89V395.45c.001-20.873-6.811-34.465-14.966-41.276zM512 256.23C512 114.73 397.263 0 256.23 0 114.73 0 0 114.73 0 256.23 0 397.263 114.73 512 256.23 512 397.263 512 512 397.263 512 256.23z"
Expand Down
7 changes: 6 additions & 1 deletion src/icons/LinkedIn.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export const LinkedIn = () => (
<svg role="img" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<svg
aria-label="LinkedIn icon"
role="img"
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
d="M160.008 423h-70V197h70zm6.984-298.004c0-22.629-18.36-40.996-40.976-40.996C103.312 84 85 102.367 85 124.996 85 147.633 103.313 166 126.016 166c22.617 0 40.976-18.367 40.976-41.004zM422 298.664C422 237.996 409.184 193 338.312 193c-34.054 0-56.914 17.031-66.246 34.742H272V197h-68v226h68V310.79c0-29.388 7.48-57.856 43.906-57.856 35.93 0 37.094 33.605 37.094 59.722V423h69zM512 452V60c0-33.086-26.914-60-60-60H60C26.914 0 0 26.914 0 60v392c0 33.086 26.914 60 60 60h392c33.086 0 60-26.914 60-60zM455.26 32C466.694 32 480 45.305 480 56.74v398.52c0 11.435-13.305 24.74-24.74 24.74H56.74C45.306 480 32 466.695 32 455.26V56.74C32 45.306 45.305 32 56.74 32zM452 40"
Expand Down
1 change: 1 addition & 0 deletions src/icons/Moon.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const Moon = () => (
<svg
aria-label="Moon icon"
role="img"
viewBox="0 0 512 512"
xmlns="http://www.w3.org/2000/svg"
Expand Down
Loading

0 comments on commit 5fb25e4

Please sign in to comment.