From fc2cad39807608ba020c245a8e21a4dd94ffe19d Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Tue, 21 Jan 2025 19:49:41 +0100 Subject: [PATCH] Make dialogs responsive for mobile devices (#209) * Make dialogs responsive for mobile devices * Support mouse backward/forward buttons * Use back icon to close layer 2 components on mobile devices Currently layer 2 components are: 1. sidebar 2. notebook 3. dialogs They are all fullscreen on mobile devices. * Add translations --- .../public/locales/de/translation.json | 5 +- .../public/locales/el/translation.json | 5 +- .../public/locales/es/translation.json | 5 +- .../public/locales/fr/translation.json | 5 +- .../public/locales/hi/translation.json | 5 +- .../public/locales/id/translation.json | 5 +- .../public/locales/it/translation.json | 5 +- .../public/locales/ja/translation.json | 5 +- .../public/locales/ko/translation.json | 5 +- .../public/locales/pl/translation.json | 5 +- .../public/locales/pt/translation.json | 5 +- .../public/locales/ru/translation.json | 5 +- .../public/locales/tr/translation.json | 5 +- .../public/locales/uk/translation.json | 5 +- .../public/locales/vi/translation.json | 5 +- .../public/locales/zh-CN/translation.json | 5 +- .../public/locales/zh-TW/translation.json | 5 +- .../app/library/components/LibraryHeader.tsx | 22 +- .../src/app/reader/components/HeaderBar.tsx | 8 +- .../reader/components/annotator/Annotator.tsx | 1 + .../app/reader/components/notebook/Header.tsx | 13 +- .../components/settings/FontDropDown.tsx | 2 +- .../components/settings/SettingsDialog.tsx | 132 ++++++----- .../app/reader/components/sidebar/Header.tsx | 24 +- .../src/app/reader/hooks/useClickEvent.ts | 16 +- .../app/reader/utils/iframeEventHandlers.ts | 4 +- .../src/components/AboutWindow.tsx | 118 +++++----- apps/readest-app/src/components/Alert.tsx | 2 +- .../src/components/BookDetailModal.tsx | 218 +++++++++--------- apps/readest-app/src/components/Dialog.tsx | 111 +++++++++ 30 files changed, 472 insertions(+), 284 deletions(-) create mode 100644 apps/readest-app/src/components/Dialog.tsx diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index 1409ecae..693935b3 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Auf dieses Buch anwenden", "Unable to fetch the translation. Try again later.": "Übersetzung konnte nicht abgerufen werden. Versuchen Sie es später erneut.", "Update Now!": "Jetzt aktualisieren!", - "Update": "Aktualisieren" + "Update": "Aktualisieren", + "Check update": "Aktualisierung prüfen", + "Already the latest version": "Bereits die neueste Version", + "Book Details": "Buchdetails" } diff --git a/apps/readest-app/public/locales/el/translation.json b/apps/readest-app/public/locales/el/translation.json index 366f0c3d..43ee7b30 100644 --- a/apps/readest-app/public/locales/el/translation.json +++ b/apps/readest-app/public/locales/el/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Εφαρμογή σε αυτό το βιβλίο", "Unable to fetch the translation. Try again later.": "Αδυναμία λήψης της μετάφρασης. Δοκιμάστε ξανά αργότερα.", "Update Now!": "Ενημέρωση τώρα!", - "Update": "Ενημέρωση" + "Update": "Ενημέρωση", + "Check update": "Έλεγχος ενημέρωσης", + "Already the latest version": "Ήδη η τελευταία έκδοση", + "Book Details": "Λεπτομέρειες βιβλίου" } diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index 0fb72532..81e674ec 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Aplicar a este libro", "Unable to fetch the translation. Try again later.": "No se puede obtener la traducción. Inténtalo de nuevo más tarde.", "Update Now!": "¡Actualizar ahora!", - "Update": "Actualizar" + "Update": "Actualizar", + "Check update": "Comprobar actualización", + "Already the latest version": "Ya es la última versión", + "Book Details": "Detalles del libro" } diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index 282aba16..5d13cb4b 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Appliquer à ce livre", "Unable to fetch the translation. Try again later.": "Impossible de récupérer la traduction. Réessayez plus tard.", "Update Now!": "Mettre à jour maintenant !", - "Update": "Mettre à jour" + "Update": "Mettre à jour", + "Check update": "Vérifier la mise à jour", + "Already the latest version": "Déjà la dernière version", + "Book Details": "Détails du livre" } diff --git a/apps/readest-app/public/locales/hi/translation.json b/apps/readest-app/public/locales/hi/translation.json index 6fb2839e..19165a60 100644 --- a/apps/readest-app/public/locales/hi/translation.json +++ b/apps/readest-app/public/locales/hi/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "इस पुस्तक पर लागू करें", "Unable to fetch the translation. Try again later.": "अनुवाद प्राप्त करने में असमर्थ। बाद में पुनः प्रयास करें।", "Update Now!": "अभी अपडेट करें!", - "Update": "अपडेट करें" + "Update": "अपडेट करें", + "Check update": "अपडेट जांचें", + "Already the latest version": "पहले से ही नवीनतम संस्करण", + "Book Details": "पुस्तक विवरण" } diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index e70da410..a85b6128 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Terapkan ke buku ini", "Unable to fetch the translation. Try again later.": "Tidak dapat mengambil terjemahan. Coba lagi nanti.", "Update Now!": "Perbarui Sekarang!", - "Update": "Perbarui" + "Update": "Perbarui", + "Check update": "Periksa pembaruan", + "Already the latest version": "Sudah versi terbaru", + "Book Details": "Detail Buku" } diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index b4461c89..a887cf1c 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Applica a questo libro", "Unable to fetch the translation. Try again later.": "Impossibile recuperare la traduzione. Riprova più tardi.", "Update Now!": "Aggiorna ora!", - "Update": "Aggiorna" + "Update": "Aggiorna", + "Check update": "Controlla aggiornamento", + "Already the latest version": "Già l'ultima versione", + "Book Details": "Dettagli libro" } diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index 99425850..1e537165 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "この書籍に適用", "Unable to fetch the translation. Try again later.": "翻訳を取得できません。後で再試行してください。", "Update Now!": "今すぐ更新!", - "Update": "更新" + "Update": "更新", + "Check update": "更新を確認", + "Already the latest version": "すでに最新バージョン", + "Book Details": "書籍の詳細" } diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index f686edf2..5bab4b11 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "이 책에 적용", "Unable to fetch the translation. Try again later.": "번역을 가져올 수 없습니다. 나중에 다시 시도하세요.", "Update Now!": "지금 업데이트!", - "Update": "업데이트" + "Update": "업데이트", + "Check update": "업데이트 확인", + "Already the latest version": "이미 최신 버전", + "Book Details": "책 세부 정보" } diff --git a/apps/readest-app/public/locales/pl/translation.json b/apps/readest-app/public/locales/pl/translation.json index 59caa096..c138e20e 100644 --- a/apps/readest-app/public/locales/pl/translation.json +++ b/apps/readest-app/public/locales/pl/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Zastosuj do tej książki", "Unable to fetch the translation. Try again later.": "Nie udało się pobrać tłumaczenia. Spróbuj ponownie później.", "Update Now!": "Zaktualizuj teraz!", - "Update": "Zaktualizuj" + "Update": "Zaktualizuj", + "Check update": "Sprawdź aktualizację", + "Already the latest version": "Już najnowsza wersja", + "Book Details": "Szczegóły książki" } diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 28a68158..f2a2371f 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Aplicar a este livro", "Unable to fetch the translation. Try again later.": "Não foi possível buscar a tradução. Tente novamente mais tarde.", "Update Now!": "Atualizar Agora!", - "Update": "Atualizar" + "Update": "Atualizar", + "Check update": "Verificar atualização", + "Already the latest version": "Já é a versão mais recente", + "Book Details": "Detalhes do Livro" } diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 41352024..d717940b 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Применить к этой книге", "Unable to fetch the translation. Try again later.": "Не удалось получить перевод. Попробуйте позже.", "Update Now!": "Обновить сейчас!", - "Update": "Обновить" + "Update": "Обновить", + "Check update": "Проверить обновление", + "Already the latest version": "Уже последняя версия", + "Book Details": "Детали книги" } diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 6dba469f..9fe80aa9 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Bu kitaba uygula", "Unable to fetch the translation. Try again later.": "Çeviri alınamıyor. Daha sonra tekrar deneyin.", "Update Now!": "Şimdi Güncelle!", - "Update": "Güncelle" + "Update": "Güncelle", + "Check update": "Güncellemeyi kontrol et", + "Already the latest version": "Zaten en son sürüm", + "Book Details": "Kitap Detayları" } diff --git a/apps/readest-app/public/locales/uk/translation.json b/apps/readest-app/public/locales/uk/translation.json index 36217d4d..459823b4 100644 --- a/apps/readest-app/public/locales/uk/translation.json +++ b/apps/readest-app/public/locales/uk/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Застосувати до цієї книги", "Unable to fetch the translation. Try again later.": "Не вдалося отримати переклад. Спробуйте пізніше.", "Update Now!": "Оновити зараз!", - "Update": "Оновити" + "Update": "Оновити", + "Check update": "Перевірити оновлення", + "Already the latest version": "Вже остання версія", + "Book Details": "Деталі книги" } diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index 3a630eff..765988b7 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "Áp dụng cho sách này", "Unable to fetch the translation. Try again later.": "Không thể tải dịch vụ. Vui lòng thử lại sau.", "Update Now!": "Cập nhật ngay!", - "Update": "Cập nhật" + "Update": "Cập nhật", + "Check update": "Kiểm tra cập nhật", + "Already the latest version": "Đã là phiên bản mới nhất", + "Book Details": "Chi tiết sách" } diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index b6cfb3ec..a90f6a79 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "应用于此书籍", "Unable to fetch the translation. Try again later.": "无法获取翻译,请稍后重试。", "Update Now!": "立即更新!", - "Update": "更新" + "Update": "更新", + "Check update": "检查更新", + "Already the latest version": "已经是最新版本", + "Book Details": "书籍详情" } diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index 8cf0c0c3..1ae7600f 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -135,5 +135,8 @@ "Apply to this book": "應用於此書籍", "Unable to fetch the translation. Try again later.": "無法獲取翻譯,請稍後再試。", "Update Now!": "立即更新!", - "Update": "更新" + "Update": "更新", + "Check update": "檢查更新", + "Already the latest version": "已經是最新版本", + "Book Details": "書籍詳情" } diff --git a/apps/readest-app/src/app/library/components/LibraryHeader.tsx b/apps/readest-app/src/app/library/components/LibraryHeader.tsx index 74d86ff0..196ed6f3 100644 --- a/apps/readest-app/src/app/library/components/LibraryHeader.tsx +++ b/apps/readest-app/src/app/library/components/LibraryHeader.tsx @@ -48,8 +48,8 @@ const LibraryHeader: React.FC = ({ isTrafficLightVisible ? 'pl-16' : 'pl-2', )} > -
-
+
+
@@ -97,20 +97,22 @@ const LibraryHeader: React.FC = ({
-
+
} > - + {!isTrafficLightVisible && appService?.appPlatform !== 'web' && ( + + )}
diff --git a/apps/readest-app/src/app/reader/components/HeaderBar.tsx b/apps/readest-app/src/app/reader/components/HeaderBar.tsx index 7b76286a..14f081a0 100644 --- a/apps/readest-app/src/app/reader/components/HeaderBar.tsx +++ b/apps/readest-app/src/app/reader/components/HeaderBar.tsx @@ -84,8 +84,12 @@ const HeaderBar: React.FC = ({ onCloseBook(bookKey)} />
diff --git a/apps/readest-app/src/app/reader/components/annotator/Annotator.tsx b/apps/readest-app/src/app/reader/components/annotator/Annotator.tsx index c7159eb2..9327b300 100644 --- a/apps/readest-app/src/app/reader/components/annotator/Annotator.tsx +++ b/apps/readest-app/src/app/reader/components/annotator/Annotator.tsx @@ -305,6 +305,7 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => { if (!selection || !selection.text) return; const { sectionHref: href } = progress; selection.href = href; + setShowAnnotPopup(false); setHighlightOptionsVisible(false); setNotebookVisible(true); setNotebookNewAnnotation(selection); diff --git a/apps/readest-app/src/app/reader/components/notebook/Header.tsx b/apps/readest-app/src/app/reader/components/notebook/Header.tsx index 30a538c3..09d04f4f 100644 --- a/apps/readest-app/src/app/reader/components/notebook/Header.tsx +++ b/apps/readest-app/src/app/reader/components/notebook/Header.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { FiSearch } from 'react-icons/fi'; import { LuNotebookPen } from 'react-icons/lu'; -import { MdOutlinePushPin, MdPushPin } from 'react-icons/md'; +import { MdArrowBackIosNew, MdOutlinePushPin, MdPushPin } from 'react-icons/md'; import { useTranslation } from '@/hooks/useTranslation'; const NotebookHeader: React.FC<{ @@ -18,7 +18,7 @@ const NotebookHeader: React.FC<{
{_('Notebook')}
-
+
- ))} -
-
- } - > - - - setFontLayoutSettingsDialogOpen(false)} - /> -
-
+ const handleClose = () => { + setFontLayoutSettingsDialogOpen(false); + }; -
- {activePanel === 'Font' && } - {activePanel === 'Layout' && } - {activePanel === 'Color' && } - {activePanel === 'Misc' && } -
- - + return ( + <> + + +
+ {tabConfig.map(({ tab, icon: Icon, label }) => ( + + ))} +
+
+ } + > + + + +
+ + } + > + {activePanel === 'Font' && } + {activePanel === 'Layout' && } + {activePanel === 'Color' && } + {activePanel === 'Misc' && } +
+ ); }; diff --git a/apps/readest-app/src/app/reader/components/sidebar/Header.tsx b/apps/readest-app/src/app/reader/components/sidebar/Header.tsx index 1ea5952d..4fb2c4c3 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/Header.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/Header.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { GiBookshelf } from 'react-icons/gi'; import { FiSearch } from 'react-icons/fi'; import { MdOutlineMenu, MdOutlinePushPin, MdPushPin } from 'react-icons/md'; +import { MdArrowBackIosNew } from 'react-icons/md'; import useTrafficLight from '@/hooks/useTrafficLight'; import Dropdown from '@/components/Dropdown'; @@ -24,12 +25,18 @@ const SidebarHeader: React.FC<{ isTrafficLightVisible ? 'pl-20' : 'pl-1.5', )} > -
+
+
-
+
-
diff --git a/apps/readest-app/src/app/reader/hooks/useClickEvent.ts b/apps/readest-app/src/app/reader/hooks/useClickEvent.ts index 7acd0235..d855b772 100644 --- a/apps/readest-app/src/app/reader/hooks/useClickEvent.ts +++ b/apps/readest-app/src/app/reader/hooks/useClickEvent.ts @@ -46,6 +46,12 @@ export const useClickEvent = ( } else if (deltaY < 0) { viewRef.current?.prev(1); } + } else if (msg.data.type === 'iframe-mouseup') { + if (msg.data.button === 3) { + viewRef.current?.history.back(); + } else if (msg.data.button === 4) { + viewRef.current?.history.forward(); + } } } } else { @@ -115,14 +121,18 @@ export const useTouchEvent = ( const touch = e.targetTouches[0]; if (touch) { touchEnd = touch; - }; + } const windowWidth = window.innerWidth; if (touchEnd) { const deltaY = touchEnd.screenY - touchStart.screenY; const deltaX = touchEnd.screenX - touchStart.screenX; // also check for deltaX to prevent swipe page turn from triggering the toggle - if (deltaY < -10 && Math.abs(deltaY) > Math.abs(deltaX) && Math.abs(deltaX) < windowWidth * 0.3) { + if ( + deltaY < -10 && + Math.abs(deltaY) > Math.abs(deltaX) && + Math.abs(deltaX) < windowWidth * 0.3 + ) { // swipe up to toggle the header bar and the footer bar setHoveredBookKey(hoveredBookKey ? null : bookKey); } @@ -151,4 +161,4 @@ export const useTouchEvent = ( }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [hoveredBookKey, viewRef]); -} +}; diff --git a/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts b/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts index b3852144..336cbfda 100644 --- a/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts +++ b/apps/readest-app/src/app/reader/utils/iframeEventHandlers.ts @@ -30,6 +30,7 @@ export const handleMousedown = (bookKey: string, event: MouseEvent) => { { type: 'iframe-mousedown', bookKey, + button: event.button, screenX: event.screenX, screenY: event.screenY, clientX: event.clientX, @@ -46,6 +47,7 @@ export const handleMouseup = (bookKey: string, event: MouseEvent) => { { type: 'iframe-mouseup', bookKey, + button: event.button, screenX: event.screenX, screenY: event.screenY, clientX: event.clientX, @@ -150,7 +152,7 @@ const handleTouchEv = (bookKey: string, event: TouchEvent, type: string) => { }, '*', ); -} +}; export const handleTouchStart = (bookKey: string, event: TouchEvent) => { handleTouchEv(bookKey, event, 'iframe-touchstart'); diff --git a/apps/readest-app/src/components/AboutWindow.tsx b/apps/readest-app/src/components/AboutWindow.tsx index 144f6f2c..53fb93b7 100644 --- a/apps/readest-app/src/components/AboutWindow.tsx +++ b/apps/readest-app/src/components/AboutWindow.tsx @@ -1,10 +1,10 @@ import React from 'react'; import Image from 'next/image'; import packageJson from '../../package.json'; -import WindowButtons from './WindowButtons'; import { useTranslation } from '@/hooks/useTranslation'; import { hasUpdater } from '@/services/environment'; import { checkForAppUpdates } from '@/helpers/updater'; +import Dialog from './Dialog'; export const setAboutDialogVisible = (visible: boolean) => { const dialog = document.getElementById('about_window'); @@ -27,67 +27,67 @@ export const AboutWindow = () => { }; return ( - -
-
- setAboutDialogVisible(false)} - /> -
-
-
- App Logo + <> + setAboutDialogVisible(false)} + boxClassName='sm:!w-96' + > +
+
+
+ App Logo +
+

Readest

+

+ {_('Version {{version}}', { version: packageJson.version })} +

+ {hasUpdater() && !isUpdated && ( + + {_('Check update')} + + )} + {isUpdated && ( +

{_('Already the latest version')}

+ )}
-

Readest

-

- {_('Version {{version}}', { version: packageJson.version })} -

- {hasUpdater() && !isUpdated && ( - - {_('Check update')} - - )} - {isUpdated && ( -

{_('Already the latest version')}

- )} -
-
+
-
-

- © {new Date().getFullYear()} Bilingify LLC. All rights reserved. -

-

- This software is licensed under the{' '} - - GNU Affero General Public License v3.0 - - . You are free to use, modify, and distribute this software under the terms of the AGPL - v3 license. Please see the license for more details. -

-

- Source code is available at{' '} - - GitHub - - . -

+
+

+ © {new Date().getFullYear()} Bilingify LLC. All rights reserved. +

+

+ This software is licensed under the{' '} + + GNU Affero General Public License v3.0 + + . You are free to use, modify, and distribute this software under the terms of the + AGPL v3 license. Please see the license for more details. +

+

+ Source code is available at{' '} + + GitHub + + . +

+
- -
+
+ ); }; diff --git a/apps/readest-app/src/components/Alert.tsx b/apps/readest-app/src/components/Alert.tsx index b0b05acb..c1afebff 100644 --- a/apps/readest-app/src/components/Alert.tsx +++ b/apps/readest-app/src/components/Alert.tsx @@ -13,7 +13,7 @@ const Alert: React.FC<{
{ const { settings } = useSettingsStore(); const { deleteBook } = useLibraryStore(); - useEffect(() => { - if (!isOpen) return; - - const handleKeyDown = (event: KeyboardEvent) => { - if (event.key === 'Escape') { - onClose(); - } - }; - - window.addEventListener('keydown', handleKeyDown); - return () => { - window.removeEventListener('keydown', handleKeyDown); - }; - }, [isOpen, onClose]); - useEffect(() => { const loadingTimeout = setTimeout(() => setLoading(true), 300); const fetchBookDetails = async () => { @@ -63,7 +48,7 @@ const BookDetailModal = ({ book, isOpen, onClose }: BookDetailModalProps) => { const handleDelete = () => { setShowDeleteAlert(true); - } + }; const confirmDelete = () => { deleteBook(envConfig, book); @@ -71,8 +56,6 @@ const BookDetailModal = ({ book, isOpen, onClose }: BookDetailModalProps) => { setShowDeleteAlert(false); }; - if (!isOpen) return null; - if (!bookMeta) return ( loading && ( @@ -83,113 +66,132 @@ const BookDetailModal = ({ book, isOpen, onClose }: BookDetailModalProps) => { ); return ( -
-
-
+ <> + +
+
+
+
+ {book.title} { + (e.target as HTMLImageElement).style.display = 'none'; + (e.target as HTMLImageElement).nextElementSibling?.classList.remove( + 'invisible', + ); + }} + /> +
+ {book.title} +
+
-
-
- -
- -
-
- {book.title} { - (e.target as HTMLImageElement).style.display = 'none'; - (e.target as HTMLImageElement).nextElementSibling?.classList.remove('invisible'); - }} - /> -
+
+

+ {book.title || _('Untitled')} +

+

{book.author || _('Unknown')}

+
+ {window.innerWidth >= 400 && ( +
+ + +
)} - > - {book.title}
-
-
-

- {book.title || _('Untitled')} -

-

{book.author || _('Unknown')}

+ {window.innerWidth < 400 && ( +
+ +
- - -
-
+ )} -
-
-
- {_('Publisher:')} -

- {formatPublisher(bookMeta.publisher || '') || _('Unknown')} -

-
-
- {_('Published:')} -

- {formatDate(bookMeta.published) || _('Unknown')} -

-
-
- {_('Updated:')} -

{formatDate(book.lastUpdated) || ''}

-
-
+
+
+
+ {_('Publisher:')} +

+ {formatPublisher(bookMeta.publisher || '') || _('Unknown')} +

+
+
+ {_('Published:')} +

+ {formatDate(bookMeta.published) || _('Unknown')} +

+
+
+ {_('Updated:')} +

+ {formatDate(book.lastUpdated) || ''} +

+
-
-
- {_('Language:')} -

- {formatLanguage(bookMeta.language) || _('Unknown')} -

-
-
- {_('Identifier:')} -

- {bookMeta.identifier || 'N/A'} -

-
-
- {_('Subjects:')} -

- {formatSubject(bookMeta.subject) || _('Unknown')} -

+
+ {_('Language:')} +

+ {formatLanguage(bookMeta.language) || _('Unknown')} +

+
+
+ {_('Identifier:')} +

+ {bookMeta.identifier || 'N/A'} +

+
+
+ {_('Subjects:')} +

+ {formatSubject(bookMeta.subject) || _('Unknown')} +

+
-
+
{showDeleteAlert && ( { setShowDeleteAlert(false); handleClose(); }} + onClickCancel={() => { + setShowDeleteAlert(false); + }} onClickConfirm={confirmDelete} /> )} -
+ ); }; diff --git a/apps/readest-app/src/components/Dialog.tsx b/apps/readest-app/src/components/Dialog.tsx new file mode 100644 index 00000000..4ae1e1bc --- /dev/null +++ b/apps/readest-app/src/components/Dialog.tsx @@ -0,0 +1,111 @@ +import clsx from 'clsx'; +import React, { ReactNode, useEffect } from 'react'; +import { MdArrowBackIosNew } from 'react-icons/md'; + +interface DialogProps { + id?: string; + isOpen: boolean; + children: ReactNode; + header?: ReactNode; + title?: string; + className?: string; + boxClassName?: string; + contentClassName?: string; + onClose: () => void; +} + +const Dialog: React.FC = ({ + id, + isOpen, + children, + header, + title, + className, + boxClassName, + contentClassName, + onClose, +}) => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + onClose(); + } + }; + + useEffect(() => { + window.addEventListener('keydown', handleKeyDown); + return () => { + window.removeEventListener('keydown', handleKeyDown); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + +
+
+ {header ? ( + header + ) : ( +
+ +
+ {title ?? ''} +
+ +
+ )} +
+ +
+ {children} +
+
+
+ ); +}; + +export default Dialog;