fix: comprehensive UI/UX accessibility and usability improvements
Public site: skip-to-content link, mobile menu focus trap + Escape key, aria-current on nav, keyboard navigation for carousels/tabs/articles, ARIA roles (tablist/tab/tabpanel, combobox/listbox, region, dialog), form labels + aria-describedby, 44px touch targets, semantic HTML (<time>, <del>), prefers-reduced-motion on Hero scroll hijack, mobile schedule filters, URL hash sync on scroll for correct refresh. Admin panel: password toggle aria-label, toast aria-live regions, SelectField keyboard navigation (Arrow/Enter/Escape), aria-invalid on validation errors, sidebar hamburger aria-label/expanded, nav aria-label, ArrayEditor aria-expanded on collapsible items.
This commit is contained in:
@@ -24,7 +24,12 @@ export function Hero({ data: hero }: HeroProps) {
|
||||
const centerVideo = videos[Math.floor(videos.length / 2)] || videos[0];
|
||||
const totalVideos = videos.slice(0, 3).length + 1; // desktop (3) + mobile (1)
|
||||
|
||||
useEffect(() => { setMounted(true); }, []);
|
||||
const prefersReducedMotion = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
prefersReducedMotion.current = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
}, []);
|
||||
|
||||
const handleVideoReady = useCallback(() => {
|
||||
readyCount.current += 1;
|
||||
@@ -48,6 +53,7 @@ export function Hero({ data: hero }: HeroProps) {
|
||||
if (!el) return;
|
||||
|
||||
function handleWheel(e: WheelEvent) {
|
||||
if (prefersReducedMotion.current) return;
|
||||
if (e.deltaY <= 0 || scrolledRef.current) return;
|
||||
if (window.scrollY > 10) return;
|
||||
scrolledRef.current = true;
|
||||
@@ -60,6 +66,7 @@ export function Hero({ data: hero }: HeroProps) {
|
||||
}
|
||||
|
||||
function handleTouchEnd(e: TouchEvent) {
|
||||
if (prefersReducedMotion.current) return;
|
||||
const startY = Number((el as HTMLElement).dataset.touchY);
|
||||
const endY = e.changedTouches[0].clientY;
|
||||
if (startY - endY > 50 && !scrolledRef.current && window.scrollY < 10) {
|
||||
@@ -80,7 +87,7 @@ export function Hero({ data: hero }: HeroProps) {
|
||||
}, [scrollToNext]);
|
||||
|
||||
return (
|
||||
<section id="hero" ref={sectionRef} className="relative flex min-h-svh items-center justify-center overflow-hidden bg-neutral-950">
|
||||
<section id="hero" ref={sectionRef} aria-label="Главный баннер" className="relative flex min-h-svh items-center justify-center overflow-hidden bg-neutral-950">
|
||||
{/* Videos render only after hydration to avoid SSR mismatch */}
|
||||
{mounted && (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user