refactor(a11y): add basic lint for accessibility (#2021)

This commit is contained in:
Huang Xin
2025-09-12 00:57:04 +08:00
committed by GitHub
parent 2571ceede4
commit 9fd152d727
56 changed files with 511 additions and 314 deletions
@@ -171,7 +171,7 @@ const BookDetailEdit: React.FC<BookDetailEditProps> = ({
<div className='bg-base-100 relative w-full rounded-lg'>
<div className='mb-6 flex items-start gap-4'>
<div className='flex w-[30%] max-w-32 flex-col gap-2'>
<div
<button
className='aspect-[28/41] h-full shadow-md'
onClick={!isCoverLocked ? handleSelectLocalImage : undefined}
>
@@ -186,7 +186,7 @@ const BookDetailEdit: React.FC<BookDetailEditProps> = ({
...(newCoverImageUrl ? { coverImageUrl: newCoverImageUrl } : {}),
}}
/>
</div>
</button>
<div className='flex w-full gap-1'>
<button
onClick={handleSelectLocalImage}
@@ -232,12 +232,14 @@ const BookDetailModal: React.FC<BookDetailModalProps> = ({
</Dialog>
{/* Source Selection Modal */}
<SourceSelector
sources={availableSources}
isOpen={showSourceSelection}
onSelect={handleSourceSelection}
onClose={handleCloseSourceSelection}
/>
{showSourceSelection && (
<SourceSelector
sources={availableSources}
isOpen={showSourceSelection}
onSelect={handleSourceSelection}
onClose={handleCloseSourceSelection}
/>
)}
{activeDeleteAction && currentDeleteConfig && (
<div
@@ -75,10 +75,9 @@ const BookDetailView: React.FC<BookDetailViewProps> = ({
toggleButton={<MdOutlineDelete className='fill-red-500' />}
>
<div
tabIndex={0}
className={clsx(
'delete-menu dropdown-content dropdown-center no-triangle',
'border-base-200 z-20 mt-1 max-w-[90vw] shadow-2xl',
'border-base-300 !bg-base-200 z-20 mt-1 max-w-[90vw] shadow-2xl',
)}
>
<MenuItem
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useRef } from 'react';
import { MdOutlineCheck, MdOutlineEdit } from 'react-icons/md';
import { BookMetadata } from '@/libs/document';
@@ -24,6 +24,13 @@ interface SourceSelectorProps {
const SourceSelector: React.FC<SourceSelectorProps> = ({ sources, isOpen, onSelect, onClose }) => {
const _ = useTranslation();
const modalRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (isOpen && modalRef.current) {
modalRef.current.focus();
}
}, [isOpen]);
const getConfidenceIcon = (confidence: number) => {
if (confidence >= 90) return <MdOutlineCheck className='text-green-500' />;
@@ -34,16 +41,23 @@ const SourceSelector: React.FC<SourceSelectorProps> = ({ sources, isOpen, onSele
if (!isOpen) return null;
return (
<div className='fixed inset-0 z-50 flex items-center justify-center bg-black/50'>
<div className='bg-base-100 mx-4 max-h-[80vh] w-full max-w-md overflow-y-auto rounded-lg p-6'>
<div className='source-selector fixed inset-0 z-[60] flex items-center justify-center bg-black/50'>
<div
ref={modalRef}
tabIndex={-1}
role='dialog'
aria-modal='true'
className='bg-base-100 mx-4 max-h-[80vh] w-full max-w-md overflow-y-auto rounded-lg p-6'
>
<h3 className='mb-4 text-lg font-semibold'>{_('Select Metadata Source')}</h3>
<div className='space-y-3'>
{sources.map((source, index) => (
<div
<button
tabIndex={0}
key={index}
onClick={() => onSelect(source)}
className='hover:bg-base-200 cursor-pointer rounded-md border p-3 transition-colors'
className='hover:bg-base-300/75 bg-base-200 border-base-200 cursor-pointer rounded-md border p-3 transition-colors'
>
<div className='flex items-start gap-4'>
<div className='aspect-[28/41] h-full w-[40%] max-w-32 shadow-md'>
@@ -86,18 +100,19 @@ const SourceSelector: React.FC<SourceSelectorProps> = ({ sources, isOpen, onSele
</div>
</div>
</div>
</div>
</button>
))}
<div
<button
tabIndex={0}
onClick={onClose}
className='hover:bg-base-200 cursor-pointer rounded-md border p-3 transition-colors'
className='hover:bg-base-300/75 border-base-200 bg-base-200 cursor-pointer rounded-md border p-3 transition-colors'
>
<div className='flex items-center gap-2'>
<MdOutlineEdit className='h-4 w-4' />
<span className='font-medium'>{_('Keep manual input')}</span>
</div>
</div>
</button>
</div>
<div className='mt-6 flex justify-end gap-2'>