Skip to content

Commit

Permalink
feat: improve accessibility including voiceover
Browse files Browse the repository at this point in the history
  • Loading branch information
satnaing committed Nov 28, 2022
2 parents 9d3c897 + 3442232 commit 5860254
Show file tree
Hide file tree
Showing 17 changed files with 150 additions and 103 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

# Except these files & folders
!/src
!/public
!/.github
!tsconfig.json
!astro.config.mjs
Expand Down
52 changes: 52 additions & 0 deletions public/toggle-theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const primaryColorScheme = ""; // "light" | "dark"

// Get theme data from local storage
const currentTheme = localStorage.getItem("theme");

function getPreferTheme() {
// return theme value in local storage if it is set
if (currentTheme) return currentTheme;

// return primary color scheme if it is set
if (primaryColorScheme) return primaryColorScheme;

// return user device's prefer color scheme
return window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
}

let themeValue = getPreferTheme();

function setPreference() {
localStorage.setItem("theme", themeValue);
reflectPreference();
}

function reflectPreference() {
document.firstElementChild.setAttribute("data-theme", themeValue);

document.querySelector("#theme-btn")?.setAttribute("aria-label", themeValue);
}

// set early so no page flashes / CSS is made aware
reflectPreference();

window.onload = () => {
// set on load so screen readers can get the latest value on the button
reflectPreference();

// now this script can find and listen for clicks on the control
document.querySelector("#theme-btn").addEventListener("click", () => {
themeValue = themeValue === "light" ? "dark" : "light";
setPreference();
});
};

// sync with system changes
window
.matchMedia("(prefers-color-scheme: dark)")
.addEventListener("change", ({ matches: isDark }) => {
themeValue = isDark ? "dark" : "light";
setPreference();
});
2 changes: 1 addition & 1 deletion src/assets/socialIcons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const socialIcons: SocialIcons = {
<circle cx="12" cy="12" r="3"></circle>
<line x1="16.5" y1="7.5" x2="16.5" y2="7.501"></line>
</svg>`,
Linkedin: `<svg
LinkedIn: `<svg
xmlns="http://www.w3.org/2000/svg"
class="icon-tabler"
stroke-linecap="round"
Expand Down
16 changes: 10 additions & 6 deletions src/components/Breadcrumbs.astro
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ breadcrumbList[0] === "posts" &&

<nav class="breadcrumb" aria-label="breadcrumb">
<ul>
<li><a href="/">Home</a></li>
<li>
<a href="/">Home</a>
<span aria-hidden="true">&#62;</span>
</li>
{
breadcrumbList.map((breadcrumb, index) => (
<li>
Expand All @@ -36,12 +39,13 @@ breadcrumbList[0] === "posts" &&
@apply max-w-3xl mx-auto px-4 w-full mt-8 mb-1;
}
.breadcrumb ul li {
@apply inline opacity-70 capitalize;
@apply inline;
}
.breadcrumb ul li + li {
@apply text-skin-base before:content-[">"];
.breadcrumb ul li a,
.breadcrumb ul li span {
@apply opacity-70 capitalize;
}
.breadcrumb ul li:not(:last-child) {
@apply hover:opacity-100 hover:before:opacity-70;
.breadcrumb ul li:not(:last-child) a {
@apply hover:opacity-100;
}
</style>
30 changes: 27 additions & 3 deletions src/components/Datetime.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import formatDatetime from "@utils/formatDatetime";

export interface Props {
datetime: string;
size?: "sm" | "lg";
Expand All @@ -14,13 +12,39 @@ export default function Datetime({ datetime, size = "sm", className }: Props) {
className={`${
size === "sm" ? "scale-90" : "scale-100"
} w-6 h-6 inline-block fill-skin-base`}
aria-hidden="true"
>
<path d="M7 11h2v2H7zm0 4h2v2H7zm4-4h2v2h-2zm0 4h2v2h-2zm4-4h2v2h-2zm0 4h2v2h-2z"></path>
<path d="M5 22h14c1.103 0 2-.897 2-2V6c0-1.103-.897-2-2-2h-2V2h-2v2H9V2H7v2H5c-1.103 0-2 .897-2 2v14c0 1.103.897 2 2 2zM19 8l.001 12H5V8h14z"></path>
</svg>
<span className="sr-only">Posted on:</span>
<span className={`italic ${size === "sm" ? "text-sm" : "text-base"}`}>
{formatDatetime(datetime)}
<FormattedDatetime datetime={datetime} />
</span>
</div>
);
}

const FormattedDatetime = ({ datetime }: { datetime: string }) => {
const myDatetime = new Date(datetime);

const date = myDatetime.toLocaleDateString([], {
year: "numeric",
month: "long",
day: "numeric",
});

const time = myDatetime.toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
});

return (
<>
{date}
<span aria-hidden="true"> | </span>
<span className="sr-only">&nbsp;at&nbsp;</span>
{time}
</>
);
};
33 changes: 13 additions & 20 deletions src/components/Header.astro
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@ const { activeNav } = Astro.props;
<div class="button-wrapper">
<LinkButton
href="/search"
className={`focus-outline p-1 ${
className={`focus-outline p-3 sm:p-1 ${
activeNav === "search" ? "active" : ""
}`}
ariaLabel="search"
title="Search"
>
<svg xmlns="http://www.w3.org/2000/svg"
<svg xmlns="http://www.w3.org/2000/svg" class="scale-125 sm:scale-100"
><path
d="M19.023 16.977a35.13 35.13 0 0 1-1.367-1.384c-.372-.378-.596-.653-.596-.653l-2.8-1.337A6.962 6.962 0 0 0 16 9c0-3.859-3.14-7-7-7S2 5.141 2 9s3.14 7 7 7c1.763 0 3.37-.66 4.603-1.739l1.337 2.8s.275.224.653.596c.387.363.896.854 1.384 1.367l1.358 1.392.604.646 2.121-2.121-.646-.604c-.379-.372-.885-.866-1.391-1.36zM9 14c-2.757 0-5-2.243-5-5s2.243-5 5-5 5 2.243 5 5-2.243 5-5 5z"
></path>
Expand All @@ -76,7 +76,9 @@ const { activeNav } = Astro.props;
<button
id="theme-btn"
class="focus-outline"
aria-label="switch theme"
title="Toggles light & dark"
aria-label="auto"
aria-live="polite"
>
<svg xmlns="http://www.w3.org/2000/svg" id="moon-svg">
<path d="M20.742 13.045a8.088 8.088 0 0 1-2.077.271c-2.135 0-4.14-.83-5.646-2.336a8.025 8.025 0 0 1-2.064-7.723A1 1 0 0 0 9.73 2.034a10.014 10.014 0 0 0-4.489 2.582c-3.898 3.898-3.898 10.243 0 14.143a9.937 9.937 0 0 0 7.072 2.93 9.93 9.93 0 0 0 7.07-2.929 10.007 10.007 0 0 0 2.583-4.491 1.001 1.001 0 0 0-1.224-1.224zm-2.772 4.301a7.947 7.947 0 0 1-5.656 2.343 7.953 7.953 0 0 1-5.658-2.344c-3.118-3.119-3.118-8.195 0-11.314a7.923 7.923 0 0 1 2.06-1.483 10.027 10.027 0 0 0 2.89 7.848 9.972 9.972 0 0 0 7.848 2.891 8.036 8.036 0 0 1-1.484 2.059z" />
Expand Down Expand Up @@ -117,16 +119,16 @@ const { activeNav } = Astro.props;
@apply fill-skin-base w-6 h-6 scale-125;
}
nav {
@apply w-full py-2 sm:py-0 flex flex-col items-center sm:justify-end sm:flex-row sm:space-x-4 bg-skin-fill;
@apply w-full py-2 sm:py-0 sm:pr-4 flex flex-col items-center sm:justify-end sm:flex-row sm:space-x-4 bg-skin-fill;
}
nav ul {
@apply flex flex-col sm:flex-row sm:space-x-4;
}
nav li {
@apply py-2 text-center my-2 sm:my-0;
@apply py-3 sm:py-2 text-center my-1 sm:my-0;
}
nav a {
@apply py-2 px-3 font-medium hover:text-skin-accent;
@apply px-6 py-3 sm:py-2 sm:px-3 font-medium hover:text-skin-accent;
}
nav a.active {
@apply underline underline-offset-4 decoration-wavy decoration-2;
Expand All @@ -143,8 +145,12 @@ const { activeNav } = Astro.props;
nav button svg {
@apply w-6 h-6 fill-skin-base hover:fill-skin-accent;
}
#theme-btn {
/* @apply w-12 h-12 sm:w-9 sm:h-9 flex justify-center items-center sm:inline-block; */
@apply p-3 sm:p-1;
}
#theme-btn svg {
@apply hover:rotate-12;
@apply hover:rotate-12 scale-125 sm:scale-100;
}

.icon-container {
Expand All @@ -165,19 +171,6 @@ const { activeNav } = Astro.props;
</style>

<script>
// Toggle Theme
const themeBtn = document.querySelector("#theme-btn");
const htmlClassList = document.querySelector("html")?.classList;
themeBtn?.addEventListener("click", function () {
if (htmlClassList?.contains("theme-dark")) {
localStorage.setItem("theme", "light");
htmlClassList?.remove("theme-dark");
} else {
localStorage.setItem("theme", "dark");
htmlClassList?.add("theme-dark");
}
});

// Toggle menu
const menuBtn = document.querySelector(".hamburger-menu");
const navClassList = document.querySelector("nav")?.classList;
Expand Down
5 changes: 3 additions & 2 deletions src/components/Hr.astro
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
---
export interface Props {
noPadding?: boolean;
ariaHidden?: boolean;
}
const { noPadding = false } = Astro.props;
const { noPadding = false, ariaHidden = true } = Astro.props;
---

<div class={`max-w-3xl mx-auto ${noPadding ? "px-0" : "px-4"}`}>
<hr class="border-skin-line" />
<hr class="border-skin-line" aria-hidden={ariaHidden} />
</div>
9 changes: 5 additions & 4 deletions src/components/LinkButton.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ export interface Props {
className?: string;
ariaLabel?: string;
title?: string;
tabindex?: string;
disabled?: boolean;
}
const { href, className, ariaLabel, title, tabindex } = Astro.props;
const { href, className, ariaLabel, title, disabled = false } = Astro.props;
---

<a
type="button"
href={href}
tabindex={tabindex}
href={disabled ? "#" : href}
tabindex={disabled ? "-1" : "0"}
class={`group ${className}`}
aria-label={ariaLabel}
title={title}
aria-disabled={disabled}
>
<slot />
</a>
Expand Down
3 changes: 1 addition & 2 deletions src/components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,8 @@ export default function SearchBar({ searchList }: Props) {
return (
<>
<label className="relative block">
<span className="sr-only">Search</span>
<span className="absolute inset-y-0 left-0 flex items-center pl-2 opacity-75">
<svg xmlns="http://www.w3.org/2000/svg">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path d="M19.023 16.977a35.13 35.13 0 0 1-1.367-1.384c-.372-.378-.596-.653-.596-.653l-2.8-1.337A6.962 6.962 0 0 0 16 9c0-3.859-3.14-7-7-7S2 5.141 2 9s3.14 7 7 7c1.763 0 3.37-.66 4.603-1.739l1.337 2.8s.275.224.653.596c.387.363.896.854 1.384 1.367l1.358 1.392.604.646 2.121-2.121-.646-.604c-.379-.372-.885-.866-1.391-1.36zM9 14c-2.757 0-5-2.243-5-5s2.243-5 5-5 5 2.243 5 5-2.243 5-5 5z"></path>
</svg>
</span>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Socials.astro
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const { centered = false } = Astro.props;
<LinkButton
href={social.href}
className="link-button"
title={social.name}
title={social.linkTitle}
>
<Fragment set:html={socialIcons[social.name]} />
</LinkButton>
Expand Down
Loading

0 comments on commit 5860254

Please sign in to comment.