fix: resolve endless loading indicator (#2502)

This commit is contained in:
Huang Xin
2025-11-21 19:28:55 +05:30
committed by GitHub
parent 9028059919
commit 273bcafe01
30 changed files with 188 additions and 84 deletions
@@ -8,7 +8,6 @@
"Auto Mode": "الوضع التلقائي",
"Behavior": "السلوك",
"Book": "الكتاب",
"Book Cover": "غلاف الكتاب",
"Bookmark": "علامة مرجعية",
"Cancel": "إلغاء",
"Chapter": "الفصل",
@@ -672,5 +671,6 @@
"Update email": "تحديث البريد الإلكتروني",
"Current email": "البريد الإلكتروني الحالي",
"Update Email": "تحديث البريد الإلكتروني",
"All": "الكل"
"All": "الكل",
"Unable to open book": "غير قادر على فتح الكتاب"
}
@@ -302,7 +302,6 @@
"Link Color": "লিঙ্ক রঙ",
"Preview": "প্রিভিউ",
"Font & Layout": "ফন্ট ও লেআউট",
"Book Cover": "বইয়ের মলাট",
"More Info": "আরো তথ্য",
"Parallel Read": "সমান্তরাল পড়া",
"Disable": "নিষ্ক্রিয়",
@@ -656,5 +655,6 @@
"Update email": " ",
"Current email": " ",
"Update Email": " ",
"All": "সব"
"All": "",
"Unable to open book": " "
}
@@ -8,7 +8,6 @@
"Auto Mode": "རང་འགུལ་བརྗོད་བྱ།",
"Behavior": "བྱ་སྤྱོད།",
"Book": "དཔེ་དེབ།",
"Book Cover": "དཔེ་དེབ་ཀྱི་སྟོང་ངོས།",
"Bookmark": "དཔེ་རྟགས།",
"Cancel": "འདོར་བ།",
"Chapter": "ལེའུ།",
@@ -652,5 +651,6 @@
"Update email": "ཡིག་འཕྲིན་གསར་བསྒྱུར།",
"Current email": "མིག་སྔའི་ཡིག་འཕྲིན།",
"Update Email": "ཡིག་འཕྲིན་གསར་བསྒྱུར།",
"All": "ཆེན་མོ།"
"All": "ཆེན་མོ།",
"Unable to open book": "དེབ་ཀྱི་སྤྱོད་བྱས་མ་ཐུབ།"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Automatischer Modus",
"Behavior": "Verhalten",
"Book": "Buch",
"Book Cover": "Buchcover",
"Bookmark": "Lesezeichen",
"Cancel": "Abbrechen",
"Chapter": "Kapitel",
@@ -656,5 +655,6 @@
"Update email": "E-Mail aktualisieren",
"Current email": "Aktuelle E-Mail",
"Update Email": "E-Mail aktualisieren",
"All": "Alle"
"All": "Alle",
"Unable to open book": "Buch kann nicht geöffnet werden"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Αυτόματη λειτουργία",
"Behavior": "Συμπεριφορά",
"Book": "Βιβλίο",
"Book Cover": "Εξώφυλλο βιβλίου",
"Bookmark": "Σελιδοδείκτης",
"Cancel": "Ακύρωση",
"Chapter": "Κεφάλαιο",
@@ -656,5 +655,6 @@
"Update email": "Ενημέρωση email",
"Current email": "Τρέχον email",
"Update Email": "Ενημέρωση email",
"All": "Όλα"
"All": "Όλα",
"Unable to open book": "Αδύνατη η άνοιγμα του βιβλίου"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Modo automático",
"Behavior": "Comportamiento",
"Book": "Libro",
"Book Cover": "Portada del libro",
"Bookmark": "Marcador",
"Cancel": "Cancelar",
"Chapter": "Capítulo",
@@ -660,5 +659,6 @@
"Update email": "Actualizar correo electrónico",
"Current email": "Correo electrónico actual",
"Update Email": "Actualizar correo electrónico",
"All": "Todos"
"All": "Todos",
"Unable to open book": "No se puede abrir el libro"
}
@@ -8,7 +8,6 @@
"Auto Mode": "حالت خودکار",
"Behavior": "رفتار",
"Book": "کتاب",
"Book Cover": "جلد کتاب",
"Bookmark": "نشانک",
"Cancel": "لغو",
"Chapter": "فصل",
@@ -656,5 +655,6 @@
"Update email": "به‌روزرسانی ایمیل",
"Current email": "ایمیل فعلی",
"Update Email": "به‌روزرسانی ایمیل",
"All": "همه"
"All": "همه",
"Unable to open book": "قادر به باز کردن کتاب نیست"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Mode automatique",
"Behavior": "Comportement",
"Book": "Livre",
"Book Cover": "Couverture du livre",
"Bookmark": "Signet",
"Cancel": "Annuler",
"Chapter": "Chapitre",
@@ -660,5 +659,6 @@
"Update email": "Mettre à jour le-mail",
"Current email": "E-mail actuel",
"Update Email": "Mettre à jour le-mail",
"All": "Tous"
"All": "Tous",
"Unable to open book": "Impossible d'ouvrir le livre"
}
@@ -8,7 +8,6 @@
"Auto Mode": "स्वचालित मोड",
"Behavior": "व्यवहार",
"Book": "पुस्तक",
"Book Cover": "पुस्तक का कवर",
"Bookmark": "बुकमार्क",
"Cancel": "रद्द करें",
"Chapter": "अध्याय",
@@ -656,5 +655,6 @@
"Update email": "ईमेल अपडेट करें",
"Current email": "वर्तमान ईमेल",
"Update Email": "ईमेल अपडेट करें",
"All": "सभी"
"All": "सभी",
"Unable to open book": "पुस्तक खोलने में असमर्थ"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Mode Otomatis",
"Behavior": "Perilaku",
"Book": "Buku",
"Book Cover": "Sampul Buku",
"Bookmark": "Penanda",
"Cancel": "Batal",
"Chapter": "Bab",
@@ -652,5 +651,6 @@
"Update email": "Perbarui email",
"Current email": "Email saat ini",
"Update Email": "Perbarui email",
"All": "Semua"
"All": "Semua",
"Unable to open book": "Tidak dapat membuka buku"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Modalità automatica",
"Behavior": "Comportamento",
"Book": "Libro",
"Book Cover": "Copertina",
"Bookmark": "Segnalibro",
"Cancel": "Annulla",
"Chapter": "Capitolo",
@@ -660,5 +659,6 @@
"Update email": "Aggiorna email",
"Current email": "Email attuale",
"Update Email": "Aggiorna email",
"All": "Tutti"
"All": "Tutti",
"Unable to open book": "Impossibile aprire il libro"
}
@@ -8,7 +8,6 @@
"Auto Mode": "自動モード",
"Behavior": "動作",
"Book": "書籍",
"Book Cover": "表紙",
"Bookmark": "ブックマーク",
"Cancel": "キャンセル",
"Chapter": "章",
@@ -652,5 +651,6 @@
"Update email": "メールを更新",
"Current email": "現在のメールアドレス",
"Update Email": "メールを更新",
"All": "すべて"
"All": "すべて",
"Unable to open book": "本を開くことができません"
}
@@ -8,7 +8,6 @@
"Auto Mode": "자동 모드",
"Behavior": "동작",
"Book": "책",
"Book Cover": "책 표지",
"Bookmark": "북마크",
"Cancel": "취소",
"Chapter": "챕터",
@@ -652,5 +651,6 @@
"Update email": "이메일 업데이트",
"Current email": "현재 이메일",
"Update Email": "이메일 업데이트",
"All": "전체"
"All": "전체",
"Unable to open book": "책을 열 수 없습니다"
}
@@ -196,7 +196,6 @@
"Link Color": "Linkkleur",
"Preview": "Voorbeeld",
"Font & Layout": "Lettertype & opmaak",
"Book Cover": "Boekomslag",
"More Info": "Meer informatie",
"Parallel Read": "Parallel lezen",
"Export Annotations": "Annotaties exporteren",
@@ -656,5 +655,6 @@
"Update email": "E-mail bijwerken",
"Current email": "Huidig e-mailadres",
"Update Email": "E-mail bijwerken",
"All": "Alles"
"All": "Alles",
"Unable to open book": "Kan boek niet openen"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Tryb automatyczny",
"Behavior": "Zachowanie",
"Book": "Książka",
"Book Cover": "Okładka książki",
"Bookmark": "Zakładka",
"Cancel": "Anuluj",
"Chapter": "Rozdział",
@@ -664,5 +663,6 @@
"Update email": "Zaktualizuj e-mail",
"Current email": "Obecny e-mail",
"Update Email": "Zaktualizuj e-mail",
"All": "Wszystkie"
"All": "Wszystkie",
"Unable to open book": "Nie można otworzyć książki"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Modo Automático",
"Behavior": "Comportamento",
"Book": "Livro",
"Book Cover": "Capa do Livro",
"Bookmark": "Marcador",
"Cancel": "Cancelar",
"Chapter": "Capítulo",
@@ -660,5 +659,6 @@
"Update email": "Atualizar e-mail",
"Current email": "E-mail atual",
"Update Email": "Atualizar e-mail",
"All": "Todos"
"All": "Todos",
"Unable to open book": "Não foi possível abrir o livro"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Автоматический режим",
"Behavior": "Поведение",
"Book": "Книга",
"Book Cover": "Обложка книги",
"Bookmark": "Закладка",
"Cancel": "Отмена",
"Chapter": "Глава",
@@ -664,5 +663,6 @@
"Update email": "Обновить электронную почту",
"Current email": "Текущий адрес электронной почты",
"Update Email": "Обновить электронную почту",
"All": "Все"
"All": "Все",
"Unable to open book": "Не удалось открыть книгу"
}
@@ -302,7 +302,6 @@
"Link Color": "සබැඳි වර්ණය",
"Preview": "පෙර දසුන",
"Font & Layout": "අකුරු සහ පිරිසැලසුම",
"Book Cover": "පොත් ආවරණය",
"More Info": "තවත් තොරතුරු",
"Parallel Read": "සමාන්තර කියවීම",
"Disable": "අබල කරන්න",
@@ -656,5 +655,6 @@
"Update email": "විද්‍යුත් තැපැල් යාවත්කාලීන කරන්න",
"Current email": "වත්මන් විද්‍යුත් තැපැල්",
"Update Email": "විද්‍යුත් තැපැල් යාවත්කාලීන කරන්න",
"All": "සියල්ල"
"All": "සියල්ල",
"Unable to open book": "පොත විවෘත කිරීමට නොහැක"
}
@@ -241,7 +241,6 @@
"{{count}} pages left in chapter_other": "{{count}} sidor kvar i kapitlet",
"On {{current}} of {{total}} page": "På {{current}} av {{total}} sidor",
"Section Title": "Sektionstitel",
"Book Cover": "Bokomslag",
"More Info": "Mer info",
"Parallel Read": "Parallell läsning",
"Disable": "Inaktivera",
@@ -656,5 +655,6 @@
"Update email": "Uppdatera e-post",
"Current email": "Nuvarande e-post",
"Update Email": "Uppdatera e-post",
"All": "Alla"
"All": "Alla",
"Unable to open book": "Kunde inte öppna bok"
}
@@ -302,7 +302,6 @@
"Link Color": "இணைப்பு நிறம்",
"Preview": "முன்னோட்டம்",
"Font & Layout": "எழுத்துரு மற்றும் அமைப்பு",
"Book Cover": "புத்தக அட்டை",
"More Info": "மேலும் தகவல்",
"Parallel Read": "இணை வாசிப்பு",
"Disable": "முடக்கவும்",
@@ -656,5 +655,6 @@
"Update email": "மின்னஞ்சல் புதுப்பிக்கவும்",
"Current email": "தற்போதைய மின்னஞ்சல்",
"Update Email": "மின்னஞ்சல் புதுப்பிக்கவும்",
"All": "அனைத்து"
"All": "அனைத்து",
"Unable to open book": "புத்தகத்தைத் திறக்க முடியவில்லை"
}
@@ -255,7 +255,6 @@
"Link Color": "สีลิงก์",
"Preview": "ดูตัวอย่าง",
"Font & Layout": "ฟอนต์และเลย์เอาต์",
"Book Cover": "ปกหนังสือ",
"More Info": "ข้อมูลเพิ่มเติม",
"Parallel Read": "อ่านคู่ขนาน",
"Disable": "ปิด",
@@ -652,5 +651,6 @@
"Update email": "อัปเดตอีเมล",
"Current email": "อีเมลปัจจุบัน",
"Update Email": "อัปเดตอีเมล",
"All": "ทั้งหมด"
"All": "ทั้งหมด",
"Unable to open book": "ไม่สามารถเปิดหนังสือได้"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Otomatik Mod",
"Behavior": "Davranış",
"Book": "Kitap",
"Book Cover": "Kitap Kapağı",
"Bookmark": "Yer İmi",
"Cancel": "İptal",
"Chapter": "Bölüm",
@@ -656,5 +655,6 @@
"Update email": "E-postayı güncelle",
"Current email": "Mevcut e-posta",
"Update Email": "E-postayı güncelle",
"All": "Tümü"
"All": "Tümü",
"Unable to open book": "Kitap açılamıyor"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Автоматичний режим",
"Behavior": "Поведінка",
"Book": "Книга",
"Book Cover": "Обкладинка книги",
"Bookmark": "Закладка",
"Cancel": "Скасувати",
"Chapter": "Розділ",
@@ -664,5 +663,6 @@
"Update email": "Оновити електронну пошту",
"Current email": "Поточна електронна пошта",
"Update Email": "Оновити електронну пошту",
"All": "Всі"
"All": "Всі",
"Unable to open book": "Не вдалося відкрити книгу"
}
@@ -8,7 +8,6 @@
"Auto Mode": "Chế độ tự động",
"Behavior": "Hành vi",
"Book": "Sách",
"Book Cover": "Bìa sách",
"Bookmark": "Đánh dấu",
"Cancel": "Hủy",
"Chapter": "Chương",
@@ -652,5 +651,6 @@
"Update email": "Cập nhật email",
"Current email": "Email hiện tại",
"Update Email": "Cập nhật email",
"All": "Tất cả"
"All": "Tất cả",
"Unable to open book": "Không thể mở sách"
}
@@ -8,7 +8,6 @@
"Auto Mode": "自动主题",
"Behavior": "行为",
"Book": "书籍",
"Book Cover": "书籍封面",
"Bookmark": "书签",
"Cancel": "取消",
"Chapter": "章节",
@@ -652,5 +651,6 @@
"Update email": "更新邮箱",
"Current email": "当前邮箱",
"Update Email": "更新邮箱",
"All": "全部"
"All": "全部",
"Unable to open book": "无法打开书籍"
}
@@ -8,7 +8,6 @@
"Auto Mode": "自動主題",
"Behavior": "行為",
"Book": "書籍",
"Book Cover": "書籍封面",
"Bookmark": "書籤",
"Cancel": "取消",
"Chapter": "章節",
@@ -652,5 +651,6 @@
"Update email": "更新電子郵件",
"Current email": "當前電子郵件",
"Update Email": "更新電子郵件",
"All": "全部"
"All": "全部",
"Unable to open book": "無法打開書籍"
}
@@ -129,22 +129,22 @@ export const useBooksSync = () => {
if (newBooks.length > 0) {
setIsSyncing(true);
}
const batchSize = 10;
for (let i = 0; i < newBooks.length; i += batchSize) {
const batch = newBooks.slice(i, i + batchSize);
await appService?.downloadBookCovers(batch);
await Promise.all(batch.map(processNewBook));
const progress = Math.min((i + batchSize) / newBooks.length, 1);
setLibrary([...updatedLibrary]);
setSyncProgress(progress);
}
setLibrary(updatedLibrary);
appService?.saveLibraryBooks(updatedLibrary);
if (newBooks.length > 0) {
setIsSyncing(false);
try {
const batchSize = 10;
for (let i = 0; i < newBooks.length; i += batchSize) {
const batch = newBooks.slice(i, i + batchSize);
await appService?.downloadBookCovers(batch);
await Promise.all(batch.map(processNewBook));
const progress = Math.min((i + batchSize) / newBooks.length, 1);
setLibrary([...updatedLibrary]);
setSyncProgress(progress);
}
setLibrary(updatedLibrary);
appService?.saveLibraryBooks(updatedLibrary);
} finally {
if (newBooks.length > 0) {
setIsSyncing(false);
}
}
};
@@ -9,6 +9,7 @@ import { useSettingsStore } from '@/store/settingsStore';
import { useBookDataStore } from '@/store/bookDataStore';
import { useReaderStore } from '@/store/readerStore';
import { useSidebarStore } from '@/store/sidebarStore';
import { useTranslation } from '@/hooks/useTranslation';
import { SystemSettings } from '@/types/settings';
import { parseOpenWithFiles } from '@/helpers/openWith';
import { getCurrentWindow } from '@tauri-apps/api/window';
@@ -30,6 +31,7 @@ import Notebook from './notebook/Notebook';
import BooksGrid from './BooksGrid';
const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ ids, settings }) => {
const _ = useTranslation();
const router = useRouter();
const searchParams = useSearchParams();
const { envConfig, appService } = useEnv();
@@ -42,6 +44,7 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i
const [showDetailsBook, setShowDetailsBook] = useState<Book | null>(null);
const isInitiating = useRef(false);
const [loading, setLoading] = useState(false);
const [errorLoading, setErrorLoading] = useState(false);
useBookShortcuts({ sideBarBookKey, bookKeys });
@@ -62,6 +65,13 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i
if (!getViewState(key)) {
initViewState(envConfig, id, key, isPrimary).catch((error) => {
console.log('Error initializing book', key, error);
setErrorLoading(true);
eventDispatcher.dispatch('toast', {
message: _('Unable to open book'),
callback: () => navigateBackToLibrary(),
timeout: 2000,
type: 'error',
});
});
if (index === 0) setSideBarBookKey(key);
}
@@ -188,7 +198,8 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i
if (!bookData || !bookData.book || !bookData.bookDoc || !viewSettings) {
setTimeout(() => setLoading(true), 200);
return (
loading && (
loading &&
!errorLoading && (
<div className='hero hero-content h-[100vh]'>
<Spinner loading={true} />
</div>
+107 -15
View File
@@ -11,6 +11,7 @@ export const Toast = () => {
const [toastType, setToastType] = useState<ToastType>('info');
const [toastTimeout, setToastTimeout] = useState(5000);
const [messageClass, setMessageClass] = useState('');
const [isVisible, setIsVisible] = useState(false);
const toastDismissTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
const toastClassMap = {
@@ -22,26 +23,81 @@ export const Toast = () => {
const alertClassMap = {
info: 'alert-primary border-base-300',
success: 'alert-success border-0',
warning: 'alert-warning border-0',
error: 'alert-error border-0',
success: 'alert-success border-0 bg-gradient-to-r from-green-500 to-emerald-500',
warning: 'alert-warning border-0 bg-gradient-to-r from-amber-500 to-orange-500',
error: 'alert-error border-0 bg-gradient-to-r from-red-500 to-rose-500',
};
const iconMap = {
info: (
<svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
<path
fillRule='evenodd'
d='M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z'
clipRule='evenodd'
/>
</svg>
),
success: (
<svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
<path
fillRule='evenodd'
d='M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z'
clipRule='evenodd'
/>
</svg>
),
warning: (
<svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
<path
fillRule='evenodd'
d='M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z'
clipRule='evenodd'
/>
</svg>
),
error: (
<svg className='h-5 w-5' fill='currentColor' viewBox='0 0 20 20'>
<path
fillRule='evenodd'
d='M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z'
clipRule='evenodd'
/>
</svg>
),
};
useEffect(() => {
if (toastDismissTimeout.current) clearTimeout(toastDismissTimeout.current);
const timeout = setTimeout(() => setToastMessage(''), toastTimeout);
toastDismissTimeout.current = timeout;
if (toastMessage) {
setTimeout(() => {
setIsVisible(true);
}, 0);
}
}, [toastMessage]);
return () => {
if (timeout) clearTimeout(timeout);
};
useEffect(() => {
if (toastDismissTimeout.current) clearTimeout(toastDismissTimeout.current);
if (toastMessage) {
const timeout = setTimeout(() => {
setIsVisible(false);
setTimeout(() => setToastMessage(''), 300);
}, toastTimeout);
toastDismissTimeout.current = timeout;
return () => {
if (timeout) clearTimeout(timeout);
};
}
return;
}, [toastMessage, toastTimeout]);
const handleShowToast = async (event: CustomEvent) => {
const { message, type = 'info', timeout, className = '' } = event.detail;
const { message, type = 'info', timeout, className = '', callback = null } = event.detail;
setToastMessage(message);
setToastType(type);
if (timeout) setToastTimeout(timeout);
if (callback && typeof callback === 'function') {
setTimeout(() => callback(), timeout || 5000);
}
setMessageClass(className);
};
@@ -52,12 +108,19 @@ export const Toast = () => {
};
}, []);
const handleDismiss = () => {
setIsVisible(false);
setTimeout(() => setToastMessage(''), 300);
if (toastDismissTimeout.current) clearTimeout(toastDismissTimeout.current);
};
return (
toastMessage && (
<div
className={clsx(
'toast toast-center toast-middle z-50 w-auto max-w-screen-sm',
'toast z-50 w-auto max-w-screen-sm transition-all duration-300',
toastClassMap[toastType],
isVisible ? 'scale-100 opacity-100' : 'scale-95 opacity-0',
)}
style={{
top: toastClassMap[toastType].includes('toast-top')
@@ -65,11 +128,22 @@ export const Toast = () => {
: undefined,
}}
>
<div className={clsx('alert flex items-center justify-center', alertClassMap[toastType])}>
<div
className={clsx(
'alert flex items-center gap-3 shadow-2xl backdrop-blur-sm',
'min-h-0 rounded-2xl px-5 py-4',
alertClassMap[toastType],
toastType !== 'info' && 'text-white',
)}
>
{/* Icon */}
<div className='flex-shrink-0'>{iconMap[toastType]}</div>
{/* Message */}
<span
className={clsx(
'max-h-[50vh] min-w-32 overflow-y-auto',
'text-center font-sans text-base font-normal sm:text-sm',
'max-h-[50vh] flex-1 overflow-y-auto',
'font-sans text-base font-medium leading-snug sm:text-sm',
toastType === 'info'
? 'max-w-[80vw] overflow-x-hidden'
: 'min-w-[60vw] max-w-[80vw] whitespace-normal break-words sm:min-w-40 sm:max-w-80',
@@ -79,10 +153,28 @@ export const Toast = () => {
{toastMessage.split('\n').map((line, idx) => (
<React.Fragment key={idx}>
{line || <>&nbsp;</>}
<br />
{idx < toastMessage.split('\n').length - 1 && <br />}
</React.Fragment>
))}
</span>
{/* Close button */}
<button
onClick={handleDismiss}
className={clsx(
'flex-shrink-0 rounded-lg p-1 transition-colors',
toastType === 'info' ? 'hover:bg-base-300' : 'hover:bg-white/20 active:bg-white/30',
)}
aria-label='Dismiss'
>
<svg className='h-4 w-4' fill='currentColor' viewBox='0 0 20 20'>
<path
fillRule='evenodd'
d='M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z'
clipRule='evenodd'
/>
</svg>
</button>
</div>
</div>
)
@@ -231,6 +231,7 @@ export const useReaderStore = create<ReaderStore>((set, get) => ({
},
},
}));
throw error;
}
},
getViewSettings: (key: string) => get().viewStates[key]?.viewSettings || null,