fix(site): site accessibility rough edges (#1330)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Darius Cepulis
2026-04-14 09:50:53 -05:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 102dfd2971
commit ddf5622b2f
25 changed files with 168 additions and 91 deletions
+1
View File
@@ -1,4 +1,5 @@
<svg viewBox="0 0 381 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<title>Video.js</title>
<g clip-path="url(#clip0_549_3634)">
<path d="M88.7051 0V14.9579H71.204V0H88.7051ZM88.7051 18.912V66.2311H71.204V18.912H88.7051Z" fill="currentColor" />
<path d="M48.6432 0V52.1057L20.9179 0H0L35.2631 66.2572H48.6432H56.181H66.1444V0H48.6432Z" fill="currentColor" />

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

+16 -11
View File
@@ -55,16 +55,21 @@ export default function CopyButton({ children, copied, copyFrom, className, styl
};
return (
<button
ref={buttonRef}
type="button"
disabled={disabled}
onClick={handleCopy}
className={className}
style={style}
aria-label={isCopied ? 'Copied' : 'Copy to clipboard'}
>
{isCopied ? copied || children : children}
</button>
<>
<button
ref={buttonRef}
type="button"
disabled={disabled}
onClick={handleCopy}
className={className}
style={style}
aria-label={isCopied ? 'Copied' : 'Copy to clipboard'}
>
{isCopied ? copied || children : children}
</button>
<span aria-live="polite" className="sr-only">
{isCopied ? 'Copied' : ''}
</span>
</>
);
}
+41 -36
View File
@@ -82,45 +82,50 @@ export default function CopyMarkdownButton({ className, style }: CopyMarkdownBut
const ariaLabel = state.status === 'success' ? 'Copied' : 'Copy markdown to clipboard';
return (
<button
type="button"
disabled={disabled}
onClick={handleCopy}
className={clsx(
'relative border border-manila-75 dark:border-soot bg-manila-50 dark:bg-warm-gray px-3 py-1 rounded-xs whitespace-nowrap text-p3',
state.status === 'idle' && 'intent:bg-manila-dark dark:intent:bg-soot',
state.status === 'loading' ? 'opacity-70' : 'cursor-100',
disabled ? 'cursor-wait' : 'cursor-pointer',
className
)}
style={style}
aria-label={ariaLabel}
data-llms-ignore
>
<span
<>
<button
type="button"
disabled={disabled}
onClick={handleCopy}
className={clsx(
state.status !== 'idle' && state.status !== 'loading' ? 'opacity-0 pointer-events-none' : 'opacity-100',
'inline-flex items-center justify-center'
'relative border border-manila-75 dark:border-soot bg-manila-50 dark:bg-warm-gray px-3 py-1 rounded-xs whitespace-nowrap text-p3',
state.status === 'idle' && 'intent:bg-manila-dark dark:intent:bg-soot',
state.status === 'loading' ? 'opacity-70' : 'cursor-100',
disabled ? 'cursor-wait' : 'cursor-pointer',
className
)}
style={style}
aria-label={ariaLabel}
data-llms-ignore
>
Copy Markdown
<span
className={clsx(
state.status !== 'idle' && state.status !== 'loading' ? 'opacity-0 pointer-events-none' : 'opacity-100',
'inline-flex items-center justify-center'
)}
>
Copy Markdown
</span>
<span
className={clsx(
state.status !== 'success' ? 'opacity-0 pointer-events-none' : 'opacity-100',
'absolute inset-0 inline-flex items-center justify-center'
)}
>
Copied <CheckIcon className="ml-1 w-4 h-4" />
</span>
<span
className={clsx(
state.status !== 'error' ? 'opacity-0 pointer-events-none' : 'opacity-100',
'absolute inset-0 inline-flex items-center justify-center'
)}
>
Error
</span>
</button>
<span aria-live="polite" className="sr-only">
{state.status === 'success' ? 'Copied' : state.status === 'error' ? 'Error copying markdown' : ''}
</span>
<span
className={clsx(
state.status !== 'success' ? 'opacity-0 pointer-events-none' : 'opacity-100',
'absolute inset-0 inline-flex items-center justify-center'
)}
>
Copied <CheckIcon className="ml-1 w-4 h-4" />
</span>
<span
className={clsx(
state.status !== 'error' ? 'opacity-0 pointer-events-none' : 'opacity-100',
'absolute inset-0 inline-flex items-center justify-center'
)}
>
Error
</span>
</button>
</>
);
}
+2
View File
@@ -68,6 +68,8 @@ export default function DialNav({ left, right }: DialNavProps) {
<DialTag
href={left[0].href}
onClick={(e) => handleClick(e, left[0])}
aria-hidden="true"
tabIndex={-1}
className="w-20 h-20 md:w-32 md:h-32 shrink-0 relative z-10 text-faded-black dark:text-manila-light [--fill:var(--color-manila-light)] dark:[--fill:var(--color-faded-black)]"
>
<DialOuter
+6 -3
View File
@@ -30,7 +30,7 @@ const { class: className } = Astro.props;
className,
]}
>
<nav
<div
class="mb-2 items-start justify-between gap-3 border-faded-black pt-5 sm:mb-0 md:flex-row md:items-start md:border-t dark:border-manila-light"
>
<nav
@@ -51,7 +51,10 @@ const { class: className } = Astro.props;
href={link.href}
class="flex items-center gap-1.5 rounded-xs px-2 py-2 font-display font-bold uppercase md:px-5 intent:bg-manila-dark dark:intent:bg-warm-gray"
>
{link.label} {link.external ? <ArrowUpRight size="1em" /> : null}
{link.label}{" "}
{link.external ? (
<ArrowUpRight size="1em" aria-hidden="true" />
) : null}
</a>
))
}
@@ -109,5 +112,5 @@ const { class: className } = Astro.props;
&copy; 2010&ndash;{new Date().getFullYear()} Video.js contributors
</p>
</div>
</nav>
</div>
</footer>
+6 -3
View File
@@ -30,7 +30,7 @@ const { class: className } = Astro.props;
className,
]}
>
<nav
<div
class="mb-2 items-start justify-between gap-3 border-faded-black px-5 pt-5 sm:mb-0 @4xl:flex-row @4xl:items-start @4xl:border-t @4xl:px-10 dark:border-warm-gray"
>
<nav
@@ -51,7 +51,10 @@ const { class: className } = Astro.props;
href={link.href}
class="flex items-center gap-1.5 rounded-xs px-2 py-2 font-display font-bold uppercase @4xl:px-5 intent:bg-manila-dark dark:intent:bg-warm-gray"
>
{link.label} {link.external ? <ArrowUpRight size="1em" /> : null}
{link.label}{" "}
{link.external ? (
<ArrowUpRight size="1em" aria-hidden="true" />
) : null}
</a>
))
}
@@ -100,5 +103,5 @@ const { class: className } = Astro.props;
class="@5xl:hidden"
/>&copy; 2010&ndash;{new Date().getFullYear()} Video.js contributors
</p>
</nav>
</div>
</footer>
+3 -1
View File
@@ -96,7 +96,7 @@ export default function MobileNav({ navLinks, currentPath, children }: MobileNav
className={className}
aria-current={isActive ? 'page' : undefined}
>
{link.label} {link.external ? <ArrowUpRight size="1em" /> : null}
{link.label} {link.external ? <ArrowUpRight size="1em" aria-hidden="true" /> : null}
</a>
);
})}
@@ -106,6 +106,7 @@ export default function MobileNav({ navLinks, currentPath, children }: MobileNav
'intent:bg-manila-dark dark:intent:bg-warm-gray flex items-center justify-center px-5 py-3.5 font-display uppercase font-bold text-h5 text-center border-t border-faded-black dark:border-manila-dark'
)}
target="_blank"
rel="noopener"
>
Discord
</a>
@@ -116,6 +117,7 @@ export default function MobileNav({ navLinks, currentPath, children }: MobileNav
'border-b'
)}
target="_blank"
rel="noopener"
>
GitHub
</a>
+5 -1
View File
@@ -33,6 +33,7 @@ const { class: className, dark = false } = Astro.props;
---
<nav
aria-label="Video.js"
class:list={[
"flex justify-between",
"mx-auto w-full max-w-305 items-center px-5 py-7 md:py-10",
@@ -64,7 +65,10 @@ const { class: className, dark = false } = Astro.props;
"flex items-center rounded-xs px-5 py-2 font-display font-bold uppercase intent:bg-manila-dark dark:intent:bg-warm-gray",
]}
>
{link.label} {link.external ? <ArrowUpRight size="1em" /> : null}
{link.label}{" "}
{link.external ? (
<ArrowUpRight size="1em" aria-hidden="true" />
) : null}
</a>
))
}
+9 -2
View File
@@ -32,6 +32,7 @@ const { class: className } = Astro.props;
---
<nav
aria-label="Video.js"
class:list={[
"sticky top-0 z-30 mx-auto flex w-full items-center justify-between border-b border-b-manila-75 bg-manila-light px-5 dark:border-warm-gray dark:bg-faded-black",
className,
@@ -55,7 +56,10 @@ const { class: className } = Astro.props;
aria-current={isDocsActive ? "page" : undefined}
>
Docs
<hr class="absolute right-0 -bottom-px left-0 h-px bg-orange" />
<hr
aria-hidden="true"
class="absolute right-0 -bottom-px left-0 h-px bg-orange"
/>
</GetStartedLink>
{
otherNavLinks.map((link) => (
@@ -65,7 +69,10 @@ const { class: className } = Astro.props;
"flex items-center rounded-xs px-5 py-2 font-display text-h3 uppercase intent:bg-manila-dark dark:intent:bg-warm-gray",
]}
>
{link.label} {link.external ? <ArrowUpRight size="1em" /> : null}
{link.label}{" "}
{link.external ? (
<ArrowUpRight size="1em" aria-hidden="true" />
) : null}
</a>
))
}
+6 -5
View File
@@ -94,7 +94,8 @@ interface TabsListProps {
export function TabsList({ label, children, variant = 'compact' }: TabsListProps) {
return (
<div className={clsx('w-full flex items-center p-0 h-12', variant === 'compact' ? 'p-0' : 'px-2.5')}>
<ul
<div
role="tablist"
data-orientation="horizontal"
aria-label={label}
className={clsx(
@@ -103,7 +104,7 @@ export function TabsList({ label, children, variant = 'compact' }: TabsListProps
)}
>
{children}
</ul>
</div>
<CopyButton
copyFrom={{
container: `[data-tabs-root]`,
@@ -219,7 +220,7 @@ export function Tab({ value, children, initial, variant = 'compact' }: TabProps)
}, []);
return (
<li key={value} role="presentation" className={clsx('flex', variant === 'compact' && 'border-r border-manila-75')}>
<div key={value} className={clsx('flex', variant === 'compact' && 'border-r border-manila-75')}>
<button
ref={ref}
type="button"
@@ -252,13 +253,13 @@ export function Tab({ value, children, initial, variant = 'compact' }: TabProps)
)}
<span className="relative">
{/* to prevent layout shift on state change, we have an invisible bold version of the text preserving space */}
<span className="font-bold invisible" data-search-ignore data-llms-ignore>
<span className="font-bold invisible" aria-hidden="true" data-search-ignore data-llms-ignore>
{children}
</span>
<span className={clsx('absolute top-0 left-0', isActive && 'font-bold')}>{children}</span>
</span>
</button>
</li>
</div>
);
}
+1
View File
@@ -85,6 +85,7 @@ export function ThemeToggle() {
return (
<ToggleGroup
aria-label="Color theme"
disabled={preference === null}
value={preference ? [preference] : []}
onChange={(values) => {
@@ -16,7 +16,10 @@ function getGuideUrl(framework: SupportedFramework, slug: string): string {
}
---
<nav class="mx-auto grid w-full max-w-3xl grid-cols-1 gap-4 md:grid-cols-2">
<nav
aria-label="Docs pagination"
class="mx-auto grid w-full max-w-3xl grid-cols-1 gap-4 md:grid-cols-2"
>
{
prev ? (
<a
+1 -1
View File
@@ -19,7 +19,7 @@ const filteredSidebar = filterSidebar(framework);
<div class={clsx("bg-manila-light dark:bg-faded-black", className)}>
<slot />
<PreferenceUpdater client:idle currentFramework={framework} />
<nav class="p-6">
<nav aria-label="Docs sidebar" class="p-6">
{
filteredSidebar.map((item) => (
<SidebarItem item={item} framework={framework} docTitles={docTitles} />
+5 -1
View File
@@ -69,7 +69,11 @@ function getGroupRotate(depth: number) {
}
>
<span class="flex-1">{item.sidebarLabel}</span>
<DropdownIcon width={"0.65rem"} className={getGroupRotate(depth)} />
<DropdownIcon
width={"0.65rem"}
className={getGroupRotate(depth)}
aria-hidden="true"
/>
</summary>
<div>
{item.contents.map((contentItem) => (
@@ -38,6 +38,7 @@ import GetStartedLink from '../NavBar/GetStartedLink';
<GetStartedLink
client:idle
aria-label="Get started"
className={clsx(
"relative z-10 ml-auto flex h-15 items-center justify-center text-faded-black lg:h-25 lg:w-40 lg:pr-2.5 dark:text-orange",
)}
+7 -12
View File
@@ -4,21 +4,15 @@ import BetaPill from '@/components/BetaPill';
import FrameworkControl from '@/components/home/FrameworkControl';
import HeroVideo from '@/components/home/HeroVideo';
import SkinControl from '@/components/home/SkinControl';
import { MUX_URL, VJS10_DEMO_VIDEO } from '@/consts';
import { MUX_URL } from '@/consts';
const times = [0, 12.9, 17.61, 15.8, 7.72, 4.8, 3.3];
const posterTime = times[Math.floor(Math.random() * times.length)];
const poster = `${VJS10_DEMO_VIDEO.poster}?time=${posterTime}`;
interface Props {
poster: string;
}
const { poster } = Astro.props;
---
<link
rel="preload"
href={poster}
as="image"
type="image/webp"
fetchpriority="high"
slot="priority-head"
/>
<header
class="relative mx-auto mb-25 grid w-full max-w-305 grid-cols-1 px-5 pt-19 [grid-template-areas:var(--grid-template-areas)] md:py-0 md:[grid-template-areas:var(--md-grid-template-areas)]"
style="--grid-template-areas: 'pill' 'title' 'description' 'video' 'mux' 'control'; --md-grid-template-areas: 'video' 'mux' 'description' 'control'"
@@ -60,6 +54,7 @@ const poster = `${VJS10_DEMO_VIDEO.poster}?time=${posterTime}`;
href={MUX_URL}
target="_blank"
rel="noopener"
aria-label="Mux"
>
<MuxLogoSmall width="100%" />
</a>
+20 -5
View File
@@ -10,6 +10,7 @@ import { MUX_URL } from '@/consts';
type SponsorItem = {
Logo: ComponentType<SVGProps<SVGSVGElement>>;
name: string;
label: string;
href: string;
width: string;
@@ -17,10 +18,22 @@ type SponsorItem = {
};
const sponsors: SponsorItem[] = [
{ Logo: FastlyLogo, label: 'CDN', href: 'https://fastly.com/', width: '7.8rem' },
{ Logo: BrightcoveLogo, label: 'Emeritus Sponsor', href: 'https://brightcove.com/', width: '11rem' },
{ Logo: BrowserStackLogo, label: 'Device Testing', href: 'https://browserstack.com/', width: '12rem' },
{ Logo: NetlifyLogo, label: 'Static Hosting', href: 'https://netlify.com/', width: '11rem' },
{ Logo: FastlyLogo, name: 'Fastly', label: 'CDN', href: 'https://fastly.com/', width: '7.8rem' },
{
Logo: BrightcoveLogo,
name: 'Brightcove',
label: 'Emeritus Sponsor',
href: 'https://brightcove.com/',
width: '11rem',
},
{
Logo: BrowserStackLogo,
name: 'BrowserStack',
label: 'Device Testing',
href: 'https://browserstack.com/',
width: '12rem',
},
{ Logo: NetlifyLogo, name: 'Netlify', label: 'Static Hosting', href: 'https://netlify.com/', width: '11rem' },
];
---
@@ -41,6 +54,7 @@ const sponsors: SponsorItem[] = [
href={MUX_URL}
target="_blank"
rel="noopener"
aria-label="Mux"
class="flex h-45 items-center justify-center bg-faded-black md:h-full md:min-h-74 dark:bg-soot dark:text-manila-light"
>
<div class="relative w-40 md:w-48">
@@ -70,7 +84,7 @@ const sponsors: SponsorItem[] = [
class="grid gap-4 md:grid-separator-container md:grid-cols-4 md:gap-0 md:border md:border-manila-light dark:border-faded-black dark:text-manila-light"
>
{
sponsors.map(({ Logo, label, href, width, className }) => (
sponsors.map(({ Logo, name, label, href, width, className }) => (
<div
class={clsx(
"h-auto rounded-xs border border-faded-black px-2.5 md:border-0 md:border-manila-dark md:px-0 dark:border-manila-light md:dark:border-warm-gray",
@@ -81,6 +95,7 @@ const sponsors: SponsorItem[] = [
href={href}
target="_blank"
rel="noopener"
aria-label={name}
class="relative flex h-32.5 items-center justify-center bg-manila-light md:grid-separators md:h-37.5 dark:bg-faded-black"
>
<div class="mx-2.5 max-w-full" style={{ width }}>
+4 -1
View File
@@ -16,7 +16,10 @@ const iconClass = variant === 'error' ? 'text-red' : '';
---
<Base title={title} {description}>
<main class="flex min-h-screen items-center justify-center p-6">
<main
id="main-content"
class="flex min-h-screen items-center justify-center p-6"
>
<div class="flex max-w-md flex-col items-center gap-4 text-center">
<Icon size={48} className={iconClass} />
<div>
+6
View File
@@ -157,6 +157,12 @@ const fullTitle =
// background colors are applied here for a more consistent FilmGrain blending
]}
>
<a
href="#main-content"
class="sr-only bg-manila-light font-display text-h3 text-faded-black uppercase focus:not-sr-only focus:fixed focus:top-0 focus:left-0 focus:z-50 focus:px-4 focus:py-2 dark:bg-faded-black dark:text-manila-light"
>
Skip to content
</a>
<PreferenceSync client:idle />
<LegacyBanner />
+1 -1
View File
@@ -27,7 +27,7 @@ const { title, description, canonical, image, twitterImage } = Astro.props;
<slot name="head" slot="head" />
<div class="flex min-h-screen flex-col">
<NavBar />
<main class="mt-10 px-6 pb-20 md:mt-20 md:px-10 md:pb-30">
<main id="main-content" class="mt-10 px-6 pb-20 md:mt-20 md:px-10 md:pb-30">
<slot />
</main>
<Footer class="mt-auto" />
+1 -1
View File
@@ -19,7 +19,7 @@ const { title, description, code = '404', message = 'NOT FOUND' } = Astro.props;
<Base {title} {description} withCompact>
<div class="flex flex-col" style={{ minHeight: "80dvh" }}>
<NavBar />
<main class="w-full">
<main id="main-content" class="w-full">
<div
class="mx-auto grid w-full max-w-305 justify-between gap-8 px-5 py-10 md:flex md:pt-32 md:pb-16"
>
+1 -1
View File
@@ -16,7 +16,7 @@ const { title, subtitle, description } = Astro.props;
<Base title={subtitle ? [title, subtitle] : title} description={description}>
<slot name="head" slot="head" />
<NavBar />
<main class="mt-10 px-6 pb-24 md:mt-20 md:px-10">
<main id="main-content" class="mt-10 px-6 pb-24 md:mt-20 md:px-10">
<article class="@container text-p2 sm:text-p15">
<header
class="mx-auto mb-10 max-w-3xl border-y border-faded-black py-10 dark:border-manila-light"
@@ -124,6 +124,7 @@ const jsonLdSchema = createTechArticleSchema({
<TableOfContents client:idle headings={filteredHeadings} />
</div>
<div
id="main-content"
class="@container flex flex-col px-6 lg:px-12"
style="grid-area: article;"
>
+15 -3
View File
@@ -8,14 +8,26 @@ import Header from '@/components/home/Header.astro';
import RoadMap from '@/components/home/Roadmap.astro';
import Sponsors from '@/components/home/Sponsors.astro';
import NavBar from '@/components/NavBar/NavBar.astro';
import { SITE_DESCRIPTION, SITE_TITLE } from '@/consts';
import { SITE_DESCRIPTION, SITE_TITLE, VJS10_DEMO_VIDEO } from '@/consts';
import Base from '@/layouts/Base.astro';
const times = [0, 12.9, 17.61, 15.8, 7.72, 4.8, 3.3];
const posterTime = times[Math.floor(Math.random() * times.length)];
const poster = `${VJS10_DEMO_VIDEO.poster}?time=${posterTime}`;
---
<Base title={SITE_TITLE} description={SITE_DESCRIPTION}>
<link
rel="preload"
href={poster}
as="image"
type="image/webp"
fetchpriority="high"
slot="priority-head"
/>
<NavBar />
<Header />
<main>
<main id="main-content">
<Header poster={poster} />
<Demo />
<GetStartedBanner />
<Built />
+5 -2
View File
@@ -37,7 +37,10 @@ const tiles = [
description="Get help with Video.js — from community support and contributing to bounties and enterprise-grade service."
>
<NavBar />
<main class="mx-auto w-full max-w-305 px-5 pt-10 pb-20 md:pt-20">
<main
id="main-content"
class="mx-auto w-full max-w-305 px-5 pt-10 pb-20 md:pt-20"
>
<header
class="mb-12 border-y border-faded-black py-4 dark:border-manila-light"
>
@@ -76,7 +79,7 @@ const tiles = [
class="mt-5 inline-flex items-center gap-1 self-end rounded-xs border border-manila-75 bg-manila-50 px-4 py-2.5 text-p3 dark:border-soot dark:bg-warm-gray intent:bg-manila-dark dark:intent:bg-soot"
>
{tile.cta.label}
<ArrowUpRight size="1em" />
<ArrowUpRight size="1em" aria-hidden="true" />
</a>
) : (
<span class="mt-5 inline-flex items-center gap-1 self-end rounded-xs border border-manila-75 px-4 py-2.5 text-p3 text-warm-gray dark:border-soot dark:text-manila-dark">