fix(a11y): add missing aria labels and fix iOS safe insets (#3149)

This commit is contained in:
Huang Xin
2026-02-03 19:50:24 +08:00
committed by GitHub
parent 9cd88fe839
commit e3d52891fb
33 changed files with 154 additions and 27 deletions
@@ -1054,5 +1054,8 @@
"From Current Page": "من الصفحة الحالية",
"Start from where you are currently reading": "البدء من حيث تقرأ حالياً",
"From Selection": "من التحديد",
"Speed Reading Mode": "وضع القراءة السريعة"
"Speed Reading Mode": "وضع القراءة السريعة",
"Scroll left": "تمرير لليسار",
"Scroll right": "تمرير لليمين",
"Library Sync Progress": "تقدم تزامن المكتبة"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "বর্তমান পৃষ্ঠা থেকে",
"Start from where you are currently reading": "আপনি বর্তমানে যেখানে পড়ছেন সেখান থেকে শুরু করুন",
"From Selection": "নির্বাচন থেকে",
"Speed Reading Mode": "দ্রুত পাঠ্য মোড"
"Speed Reading Mode": "দ্রুত পাঠ্য মোড",
"Scroll left": "বামে স্ক্রোল করুন",
"Scroll right": "ডানে স্ক্রোল করুন",
"Library Sync Progress": "লাইব্রেরি সিঙ্ক অগ্রগতি"
}
@@ -994,5 +994,8 @@
"From Current Page": "ད་ལྟའི་ཤོག་ལྷེ་ནས།",
"Start from where you are currently reading": "ད་ལྟ་ཀློག་བཞིན་པའི་གནས་ནས་འགོ་འཛུགས་པ།",
"From Selection": "བདམས་པའི་ནང་དོན་ནས།",
"Speed Reading Mode": "མྱུར་ཀློག་རྣམ་པ།"
"Speed Reading Mode": "མྱུར་ཀློག་རྣམ་པ།",
"Scroll left": "གཡོན་ལ་བཤུད་དགོས།",
"Scroll right": "གཡས་ལ་བཤུད་དགོས།",
"Library Sync Progress": "དཔེ་མཛོད་མཉམ་འབྱུང་གི་རིམ་པ།"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "Von der aktuellen Seite",
"Start from where you are currently reading": "Dort beginnen, wo Sie gerade lesen",
"From Selection": "Von der Auswahl",
"Speed Reading Mode": "Schnelllesemodus"
"Speed Reading Mode": "Schnelllesemodus",
"Scroll left": "Nach links scrollen",
"Scroll right": "Nach rechts scrollen",
"Library Sync Progress": "Bibliotheks-Synchronisierungsfortschritt"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "Από την τρέχουσα σελίδα",
"Start from where you are currently reading": "Ξεκινήστε από εκεί που διαβάζετε αυτή τη στιγμή",
"From Selection": "Από την επιλογή",
"Speed Reading Mode": "Λειτουργία ταχείας ανάγνωσης"
"Speed Reading Mode": "Λειτουργία ταχείας ανάγνωσης",
"Scroll left": "Κύλιση αριστερά",
"Scroll right": "Κύλιση δεξιά",
"Library Sync Progress": "Πρόοδος συγχρονισμού βιβλιοθήκης"
}
@@ -1018,5 +1018,8 @@
"From Current Page": "Desde la página actual",
"Start from where you are currently reading": "Empezar desde donde estás leyendo actualmente",
"From Selection": "Desde la selección",
"Speed Reading Mode": "Modo de lectura rápida"
"Speed Reading Mode": "Modo de lectura rápida",
"Scroll left": "Desplazar a la izquierda",
"Scroll right": "Desplazar a la derecha",
"Library Sync Progress": "Progreso de sincronización de la biblioteca"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "از صفحه فعلی",
"Start from where you are currently reading": "شروع از جایی که در حال مطالعه هستید",
"From Selection": "از انتخاب",
"Speed Reading Mode": "حالت مطالعه سریع"
"Speed Reading Mode": "حالت مطالعه سریع",
"Scroll left": "اسکرول به چپ",
"Scroll right": "اسکرول به راست",
"Library Sync Progress": "پیشرفت همگام‌سازی کتابخانه"
}
@@ -1018,5 +1018,8 @@
"From Current Page": "Depuis la page actuelle",
"Start from where you are currently reading": "Commencer là où vous lisez actuellement",
"From Selection": "Depuis la sélection",
"Speed Reading Mode": "Mode lecture rapide"
"Speed Reading Mode": "Mode lecture rapide",
"Scroll left": "Défiler vers la gauche",
"Scroll right": "Défiler vers la droite",
"Library Sync Progress": "Progression de la synchronisation de la bibliothèque"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "वर्तमान पृष्ठ से",
"Start from where you are currently reading": "जहाँ आप अभी पढ़ रहे हैं वहीं से शुरू करें",
"From Selection": "चयन से",
"Speed Reading Mode": "त्वरित पठन मोड"
"Speed Reading Mode": "त्वरित पठन मोड",
"Scroll left": "बाएं स्क्रॉल करें",
"Scroll right": "दाएं स्क्रॉल करें",
"Library Sync Progress": "पुस्तकालय सिंक प्रगति"
}
@@ -994,5 +994,8 @@
"From Current Page": "Dari Halaman Saat Ini",
"Start from where you are currently reading": "Mulai dari tempat Anda sedang membaca",
"From Selection": "Dari Pilihan",
"Speed Reading Mode": "Mode Baca Cepat"
"Speed Reading Mode": "Mode Baca Cepat",
"Scroll left": "Gulir ke kiri",
"Scroll right": "Gulir ke kanan",
"Library Sync Progress": "Kemajuan Sinkronisasi Pustaka"
}
@@ -1018,5 +1018,8 @@
"From Current Page": "Dalla pagina corrente",
"Start from where you are currently reading": "Inizia da dove stai leggendo",
"From Selection": "Dalla selezione",
"Speed Reading Mode": "Modalità lettura veloce"
"Speed Reading Mode": "Modalità lettura veloce",
"Scroll left": "Scorri a sinistra",
"Scroll right": "Scorri a destra",
"Library Sync Progress": "Avanzamento sincronizzazione libreria"
}
@@ -994,5 +994,8 @@
"From Current Page": "現在のページから",
"Start from where you are currently reading": "現在読んでいる場所から開始する",
"From Selection": "選択範囲から",
"Speed Reading Mode": "速読モード"
"Speed Reading Mode": "速読モード",
"Scroll left": "左にスクロール",
"Scroll right": "右にスクロール",
"Library Sync Progress": "ライブラリ同期の進捗"
}
@@ -994,5 +994,8 @@
"From Current Page": "현재 페이지부터",
"Start from where you are currently reading": "현재 읽고 있는 위치부터 시작",
"From Selection": "선택 범위부터",
"Speed Reading Mode": "속독 모드"
"Speed Reading Mode": "속독 모드",
"Scroll left": "왼쪽으로 스크롤",
"Scroll right": "오른쪽으로 스크롤",
"Library Sync Progress": "라이브러리 동기화 진행 상황"
}
@@ -994,5 +994,8 @@
"From Current Page": "Dari Halaman Semasa",
"Start from where you are currently reading": "Mula dari tempat anda sedang membaca",
"From Selection": "Dari Pilihan",
"Speed Reading Mode": "Mod Bacaan Pantas"
"Speed Reading Mode": "Mod Bacaan Pantas",
"Scroll left": "Tatal ke kiri",
"Scroll right": "Tatal ke kanan",
"Library Sync Progress": "Kemajuan Segerak Perpustakaan"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "Vanaf huidige pagina",
"Start from where you are currently reading": "Begin waar u momenteel leest",
"From Selection": "Vanaf selectie",
"Speed Reading Mode": "Snelle leesmodus"
"Speed Reading Mode": "Snelle leesmodus",
"Scroll left": "Naar links scrollen",
"Scroll right": "Naar rechts scrollen",
"Library Sync Progress": "Voortgang bibliotheeksynchronisatie"
}
@@ -1030,5 +1030,8 @@
"From Current Page": "Od bieżącej strony",
"Start from where you are currently reading": "Zacznij od miejsca, w którym aktualnie czytasz",
"From Selection": "Z zaznaczenia",
"Speed Reading Mode": "Tryb szybkiego czytania"
"Speed Reading Mode": "Tryb szybkiego czytania",
"Scroll left": "Przewiń w lewo",
"Scroll right": "Przewiń w prawo",
"Library Sync Progress": "Postęp synchronizacji biblioteki"
}
@@ -1018,5 +1018,8 @@
"From Current Page": "Da página atual",
"Start from where you are currently reading": "Começar de onde está lendo no momento",
"From Selection": "Da seleção",
"Speed Reading Mode": "Modo de leitura rápida"
"Speed Reading Mode": "Modo de leitura rápida",
"Scroll left": "Rolar para a esquerda",
"Scroll right": "Rolar para a direita",
"Library Sync Progress": "Progresso de sincronização da biblioteca"
}
@@ -1030,5 +1030,8 @@
"From Current Page": "С текущей страницы",
"Start from where you are currently reading": "Начать с того места, где вы сейчас читаете",
"From Selection": "Из выбранного",
"Speed Reading Mode": "Режим быстрого чтения"
"Speed Reading Mode": "Режим быстрого чтения",
"Scroll left": "Прокрутить влево",
"Scroll right": "Прокрутить вправо",
"Library Sync Progress": "Прогресс синхронизации библиотеки"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "වත්මන් පිටුවේ සිට",
"Start from where you are currently reading": "ඔබ දැනට කියවන තැනින් ආරම්භ කරන්න",
"From Selection": "තේරීමෙන්",
"Speed Reading Mode": "වේගයෙන් කියවීමේ ක්‍රමය"
"Speed Reading Mode": "වේගයෙන් කියවීමේ ක්‍රමය",
"Scroll left": "වමට අනුචලනය කරන්න",
"Scroll right": "දකුණට අනුචලනය කරන්න",
"Library Sync Progress": "පුස්තකාල සමමුහුර්ත කිරීමේ ප්‍රගතිය"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "Från den aktuella sidan",
"Start from where you are currently reading": "Börja där du läser just nu",
"From Selection": "Från markeringen",
"Speed Reading Mode": "Snabbläsningsläge"
"Speed Reading Mode": "Snabbläsningsläge",
"Scroll left": "Scrolla åt vänster",
"Scroll right": "Scrolla åt höger",
"Library Sync Progress": "Synkroniseringsframsteg för bibliotek"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "தற்போதைய பக்கத்திலிருந்து",
"Start from where you are currently reading": "நீங்கள் தற்போது வாசிக்கும் இடத்திலிருந்து தொடங்கு",
"From Selection": "தேர்விலிருந்து",
"Speed Reading Mode": "வேக வாசிப்பு முறை"
"Speed Reading Mode": "வேக வாசிப்பு முறை",
"Scroll left": "இடதுபுறம் உருட்டவும்",
"Scroll right": "வலதுபுறம் உருட்டவும்",
"Library Sync Progress": "நூலக ஒத்திசைவு நிலை"
}
@@ -994,5 +994,8 @@
"From Current Page": "จากหน้าปัจจุบัน",
"Start from where you are currently reading": "เริ่มจากจุดที่คุณกำลังอ่านอยู่ตอนนี้",
"From Selection": "จากส่วนที่เลือก",
"Speed Reading Mode": "โหมดการอ่านเร็ว"
"Speed Reading Mode": "โหมดการอ่านเร็ว",
"Scroll left": "เลื่อนไปทางซ้าย",
"Scroll right": "เลื่อนไปทางขวา",
"Library Sync Progress": "ความคืบหน้าการซิงค์ห้องสมุด"
}
@@ -1006,5 +1006,8 @@
"From Current Page": "Mevcut Sayfadan",
"Start from where you are currently reading": "Şu anda okuduğunuz yerden başlayın",
"From Selection": "Seçimden",
"Speed Reading Mode": "Hızlı Okuma Modu"
"Speed Reading Mode": "Hızlı Okuma Modu",
"Scroll left": "Sola kaydır",
"Scroll right": "Sağa kaydır",
"Library Sync Progress": "Kütüphane Senkronizasyon İlerlemesi"
}
@@ -1030,5 +1030,8 @@
"From Current Page": "З поточної сторінки",
"Start from where you are currently reading": "Почати з того місця, де ви зараз читаєте",
"From Selection": "З виділеного",
"Speed Reading Mode": "Режим швидкого читання"
"Speed Reading Mode": "Режим швидкого читання",
"Scroll left": "Прокрутити вліво",
"Scroll right": "Прокрутити вправо",
"Library Sync Progress": "Прогрес синхронізації бібліотеки"
}
@@ -994,5 +994,8 @@
"From Current Page": "Từ trang hiện tại",
"Start from where you are currently reading": "Bắt đầu từ nơi bạn hiện đang đọc",
"From Selection": "Từ phần đã chọn",
"Speed Reading Mode": "Chế độ đọc nhanh"
"Speed Reading Mode": "Chế độ đọc nhanh",
"Scroll left": "Cuộn sang trái",
"Scroll right": "Cuộn sang phải",
"Library Sync Progress": "Tiến trình đồng bộ hóa thư viện"
}
@@ -994,5 +994,8 @@
"From Current Page": "从当前页",
"Start from where you are currently reading": "从当前正在阅读的位置开始",
"From Selection": "从选中内容",
"Speed Reading Mode": "快读模式"
"Speed Reading Mode": "快读模式",
"Scroll left": "向左滚动",
"Scroll right": "向右滚动",
"Library Sync Progress": "库同步进度"
}
@@ -994,5 +994,8 @@
"From Current Page": "從當前頁",
"Start from where you are currently reading": "從當前正在閱讀的位置開始",
"From Selection": "從選取內容",
"Speed Reading Mode": "快讀模式"
"Speed Reading Mode": "快讀模式",
"Scroll left": "向左捲動",
"Scroll right": "向右捲動",
"Library Sync Progress": "資料庫同步進度"
}
@@ -160,6 +160,7 @@ const BookItem: React.FC<BookItemProps> = ({
) : (
(!book.uploadedAt || (book.uploadedAt && !book.downloadedAt)) && (
<button
aria-label={!book.uploadedAt ? _('Upload Book') : _('Download Book')}
className='show-cloud-button -m-2 p-2'
onPointerDown={(e) => e.stopPropagation()}
onClick={() => {
@@ -2,6 +2,7 @@ import clsx from 'clsx';
import { useEffect, useRef, useState } from 'react';
import { MdCheckCircle, MdCheckCircleOutline, MdChevronRight, MdChevronLeft } from 'react-icons/md';
import { useEnv } from '@/context/EnvContext';
import { useTranslation } from '@/hooks/useTranslation';
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
import { BooksGroup } from '@/types/book';
import { LibraryViewModeType } from '@/types/settings';
@@ -15,6 +16,7 @@ interface GroupItemProps {
}
const GroupItem: React.FC<GroupItemProps> = ({ mode, group, isSelectMode, groupSelected }) => {
const _ = useTranslation();
const { appService } = useEnv();
const iconSize15 = useResponsiveSize(15);
const scrollContainerRef = useRef<HTMLDivElement>(null);
@@ -147,6 +149,7 @@ const GroupItem: React.FC<GroupItemProps> = ({ mode, group, isSelectMode, groupS
<div className='absolute left-[-0.5px] top-0 h-full w-12'>
<div className='from-base-200/85 via-base-200/20 absolute inset-0 bg-gradient-to-r to-transparent'></div>
<button
aria-label={_('Scroll left')}
onClick={handleLeftArrowClick}
onPointerDown={(e) => stopEvent(e)}
onPointerUp={(e) => stopEvent(e)}
@@ -168,6 +171,7 @@ const GroupItem: React.FC<GroupItemProps> = ({ mode, group, isSelectMode, groupS
<div className='absolute right-[-0.5px] top-0 h-full w-12'>
<div className='from-base-200/85 via-base-200/20 absolute inset-0 bg-gradient-to-l to-transparent'></div>
<button
aria-label={_('Scroll right')}
onClick={handleRightArrowClick}
onPointerDown={(e) => stopEvent(e)}
onPointerUp={(e) => stopEvent(e)}
@@ -755,6 +755,8 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP
onDeselectAll={handleDeselectAll}
/>
<progress
aria-label={_('Library Sync Progress')}
aria-hidden={isSyncing ? 'false' : 'true'}
className={clsx(
'progress progress-success absolute bottom-0 left-0 right-0 h-1 translate-y-[2px] transition-opacity duration-200 sm:translate-y-[4px]',
isSyncing ? 'opacity-100' : 'opacity-0',
@@ -182,6 +182,7 @@ const Dialog: React.FC<DialogProps> = ({
id={id ?? 'dialog'}
tabIndex={-1}
open={isOpen}
aria-label={title}
aria-hidden={!isOpen}
className={clsx(
'modal sm:min-w-90 z-50 h-full w-full !items-start !bg-transparent sm:w-full sm:!items-center',
@@ -119,6 +119,7 @@ const Dropdown: React.FC<DropdownProps> = ({
{isOpen && <Overlay onDismiss={() => setIsDropdownOpen(false)} />}
<div className={clsx('relative', isOpen && 'z-50')}>
<button
tabIndex={0}
aria-haspopup='menu'
aria-expanded={isOpen}
aria-label={label}
@@ -7,6 +7,8 @@ import { getSafeAreaInsets } from '@/utils/bridge';
export const useSafeAreaInsets = () => {
const { appService } = useEnv();
const currentInsets = useRef({ top: 0, right: 0, bottom: 0, left: 0 });
const retryCount = useRef(0);
const maxRetries = 3;
const { updateSafeAreaInsets } = useThemeStore();
@@ -61,6 +63,20 @@ export const useSafeAreaInsets = () => {
bottom: Math.round(bottom),
left: Math.round(left),
};
const allZero = top === 0 && right === 0 && bottom === 0 && left === 0;
if (appService.isIOSApp && allZero && retryCount.current < maxRetries) {
retryCount.current++;
setTimeout(() => {
onUpdateInsets();
}, 50 * retryCount.current);
return;
}
if (!allZero) {
retryCount.current = 0;
}
updateInsets(insets);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -68,17 +84,38 @@ export const useSafeAreaInsets = () => {
useEffect(() => {
onUpdateInsets();
// Listen for orientation changes
if (window.screen?.orientation) {
window.screen.orientation.addEventListener('change', onUpdateInsets);
} else {
window.addEventListener('orientationchange', onUpdateInsets);
}
// Listen for visibility changes (app returning from background)
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
retryCount.current = 0;
onUpdateInsets();
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
// Listen for window focus (additional safeguard for iOS)
const handleFocus = () => {
retryCount.current = 0;
onUpdateInsets();
};
window.addEventListener('focus', handleFocus);
return () => {
if (window.screen?.orientation) {
window.screen.orientation.removeEventListener('change', onUpdateInsets);
} else {
window.removeEventListener('orientationchange', onUpdateInsets);
}
document.removeEventListener('visibilitychange', handleVisibilityChange);
window.removeEventListener('focus', handleFocus);
};
}, [onUpdateInsets]);
};