library: various fixes on metadata editor and bookshelf (#1663)
* i18n: update translations * library: various fixes on metadata editor and bookshelf * chore: enable parallel web builds checking
This commit is contained in:
@@ -32,6 +32,11 @@ jobs:
|
||||
|
||||
build_web_app:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- platform: 'web'
|
||||
- platform: 'tauri'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -54,6 +59,13 @@ jobs:
|
||||
pnpm install && pnpm setup-pdfjs
|
||||
|
||||
- name: build the web App
|
||||
if: matrix.config.platform == 'web'
|
||||
working-directory: apps/readest-app
|
||||
run: |
|
||||
pnpm build-check
|
||||
pnpm build-web && pnpm check:all
|
||||
|
||||
- name: build the Tauri App
|
||||
if: matrix.config.platform == 'tauri'
|
||||
working-directory: apps/readest-app
|
||||
run: |
|
||||
pnpm build && pnpm check:all
|
||||
|
||||
@@ -467,5 +467,7 @@
|
||||
"Fiction, Science, History": "خيال، علوم، تاريخ",
|
||||
"Select Cover Image": "اختر صورة الغلاف",
|
||||
"Open Book in New Window": "فتح الكتاب في نافذة جديدة",
|
||||
"Voices for {{lang}}": "الأصوات لـ {{lang}}"
|
||||
"Voices for {{lang}}": "الأصوات لـ {{lang}}",
|
||||
"Yandex Translate": "ترجمة Yandex",
|
||||
"YYYY or YYYY-MM-DD": "YYYY أو YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -451,5 +451,7 @@
|
||||
"Fiction, Science, History": "Belletristik, Wissenschaft, Geschichte",
|
||||
"Select Cover Image": "Coverbild auswählen",
|
||||
"Open Book in New Window": "Buch in neuem Fenster öffnen",
|
||||
"Voices for {{lang}}": "Stimmen für {{lang}}"
|
||||
"Voices for {{lang}}": "Stimmen für {{lang}}",
|
||||
"Yandex Translate": "Yandex Übersetzer",
|
||||
"YYYY or YYYY-MM-DD": "YYYY oder YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -451,5 +451,7 @@
|
||||
"Fiction, Science, History": "Μυθοπλασία, Επιστήμη, Ιστορία",
|
||||
"Select Cover Image": "Επιλέξτε εικόνα εξωφύλλου",
|
||||
"Open Book in New Window": "Άνοιγμα βιβλίου σε νέο παράθυρο",
|
||||
"Voices for {{lang}}": "Φωνές για {{lang}}"
|
||||
"Voices for {{lang}}": "Φωνές για {{lang}}",
|
||||
"Yandex Translate": "Μετάφραση Yandex",
|
||||
"YYYY or YYYY-MM-DD": "YYYY ή YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -455,5 +455,7 @@
|
||||
"Fiction, Science, History": "Ficción, Ciencia, Historia",
|
||||
"Select Cover Image": "Seleccionar imagen de portada",
|
||||
"Open Book in New Window": "Abre el libro en una nueva ventana",
|
||||
"Voices for {{lang}}": "Voces para {{lang}}"
|
||||
"Voices for {{lang}}": "Voces para {{lang}}",
|
||||
"Yandex Translate": "Yandex Translate",
|
||||
"YYYY or YYYY-MM-DD": "YYYY o YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -455,5 +455,7 @@
|
||||
"Fiction, Science, History": "Fiction, Science, Histoire",
|
||||
"Select Cover Image": "Sélectionner l'image de couverture",
|
||||
"Open Book in New Window": "Ouvrir dans une nouvelle fenêtre",
|
||||
"Voices for {{lang}}": "Voix pour {{lang}}"
|
||||
"Voices for {{lang}}": "Voix pour {{lang}}",
|
||||
"Yandex Translate": "Yandex Traduction",
|
||||
"YYYY or YYYY-MM-DD": "YYYY ou YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -451,5 +451,7 @@
|
||||
"Fiction, Science, History": "काल्पनिक, विज्ञान, इतिहास",
|
||||
"Select Cover Image": "कवर इमेज चुनें",
|
||||
"Open Book in New Window": "नई विंडो में पुस्तक खोलें",
|
||||
"Voices for {{lang}}": "{{lang}} के लिए आवाज़ें"
|
||||
"Voices for {{lang}}": "{{lang}} के लिए आवाज़ें",
|
||||
"Yandex Translate": "यांडेक्स अनुवाद",
|
||||
"YYYY or YYYY-MM-DD": "YYYY या YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -447,5 +447,7 @@
|
||||
"Fiction, Science, History": "Fiksi, Sains, Sejarah",
|
||||
"Select Cover Image": "Pilihan Gambar Sampul",
|
||||
"Open Book in New Window": "Buka Buku di Jendela Baru",
|
||||
"Voices for {{lang}}": "Suara untuk {{lang}}"
|
||||
"Voices for {{lang}}": "Suara untuk {{lang}}",
|
||||
"Yandex Translate": "Yandex Translate",
|
||||
"YYYY or YYYY-MM-DD": "YYYY atau YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -455,5 +455,7 @@
|
||||
"Fiction, Science, History": "Narrativa, Scienza, Storia",
|
||||
"Select Cover Image": "Seleziona immagine di copertina",
|
||||
"Open Book in New Window": "Apri libro in una nuova finestra",
|
||||
"Voices for {{lang}}": "Voci per {{lang}}"
|
||||
"Voices for {{lang}}": "Voci per {{lang}}",
|
||||
"Yandex Translate": "Yandex Translate",
|
||||
"YYYY or YYYY-MM-DD": "AAAA o AAAA-MM-GG"
|
||||
}
|
||||
|
||||
@@ -447,5 +447,7 @@
|
||||
"Fiction, Science, History": "小説、科学、歴史",
|
||||
"Select Cover Image": "表紙画像を選択",
|
||||
"Open Book in New Window": "新しいウィンドウで本を開く",
|
||||
"Voices for {{lang}}": "{{lang}}の音声"
|
||||
"Voices for {{lang}}": "{{lang}}の音声",
|
||||
"Yandex Translate": "Yandex翻訳",
|
||||
"YYYY or YYYY-MM-DD": "YYYYまたはYYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -447,5 +447,7 @@
|
||||
"Fiction, Science, History": "소설, 과학, 역사",
|
||||
"Select Cover Image": "표지 이미지 선택",
|
||||
"Open Book in New Window": "새 창에서 책 열기",
|
||||
"Voices for {{lang}}": "{{lang}}의 음성"
|
||||
"Voices for {{lang}}": "{{lang}}의 음성",
|
||||
"Yandex Translate": "Yandex 번역",
|
||||
"YYYY or YYYY-MM-DD": "YYYY 또는 YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -451,5 +451,7 @@
|
||||
"Fiction, Science, History": "Fictie, Wetenschap, Geschiedenis",
|
||||
"Select Cover Image": "Selecteer omslagafbeelding",
|
||||
"Open Book in New Window": "Open boek in nieuw venster",
|
||||
"Voices for {{lang}}": "Stemmen voor {{lang}}"
|
||||
"Voices for {{lang}}": "Stemmen voor {{lang}}",
|
||||
"Yandex Translate": "Yandex Vertalen",
|
||||
"YYYY or YYYY-MM-DD": "YYYY of YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -459,5 +459,7 @@
|
||||
"Fiction, Science, History": "Beletrystyka, Nauka, Historia",
|
||||
"Select Cover Image": "Zaznacz obraz okładki",
|
||||
"Open Book in New Window": "Otwórz książkę w nowym oknie",
|
||||
"Voices for {{lang}}": "{{lang}} Głosy"
|
||||
"Voices for {{lang}}": "{{lang}} Głosy",
|
||||
"Yandex Translate": "Yandex Tłumacz",
|
||||
"YYYY or YYYY-MM-DD": "YYYY lub YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -455,5 +455,7 @@
|
||||
"Fiction, Science, History": "Ficção, Ciência, História",
|
||||
"Select Cover Image": "Selecionar imagem da capa",
|
||||
"Open Book in New Window": "Abrir livro em nova janela",
|
||||
"Voices for {{lang}}": "Vozes para {{lang}}"
|
||||
"Voices for {{lang}}": "Vozes para {{lang}}",
|
||||
"Yandex Translate": "Yandex Translate",
|
||||
"YYYY or YYYY-MM-DD": "YYYY ou YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -459,5 +459,7 @@
|
||||
"Fiction, Science, History": "Художественная литература, Наука, История",
|
||||
"Select Cover Image": "Выбрать изображение обложки",
|
||||
"Open Book in New Window": "Открыть книгу в новом окне",
|
||||
"Voices for {{lang}}": "Голоса для {{lang}}"
|
||||
"Voices for {{lang}}": "Голоса для {{lang}}",
|
||||
"Yandex Translate": "Yandex Translate",
|
||||
"YYYY or YYYY-MM-DD": "YYYY или YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -447,5 +447,7 @@
|
||||
"Fiction, Science, History": "นิยาย, วิทยาศาสตร์, ประวัติศาสตร์",
|
||||
"Select Cover Image": "เลือกภาพปก",
|
||||
"Open Book in New Window": "เปิดหนังสือในหน้าต่างใหม่",
|
||||
"Voices for {{lang}}": "เสียงสำหรับ {{lang}}"
|
||||
"Voices for {{lang}}": "เสียงสำหรับ {{lang}}",
|
||||
"Yandex Translate": "Yandex Translate",
|
||||
"YYYY or YYYY-MM-DD": "YYYY หรือ YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -451,5 +451,7 @@
|
||||
"Fiction, Science, History": "Kurgu, Bilim, Tarih",
|
||||
"Select Cover Image": "Kapak Resmi Seç",
|
||||
"Open Book in New Window": "Kitabı Yeni Pencerede Aç",
|
||||
"Voices for {{lang}}": "{{lang}} için Sesler"
|
||||
"Voices for {{lang}}": "{{lang}} için Sesler",
|
||||
"Yandex Translate": "Yandex Çeviri",
|
||||
"YYYY or YYYY-MM-DD": "YYYY veya YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -459,5 +459,7 @@
|
||||
"Fiction, Science, History": "Художня література, Наукова фантастика, Історія",
|
||||
"Select Cover Image": "Оберіть зображення обкладинки",
|
||||
"Open Book in New Window": "Відкрити книгу в новому вікні",
|
||||
"Voices for {{lang}}": "Голоси для {{lang}}"
|
||||
"Voices for {{lang}}": "Голоси для {{lang}}",
|
||||
"Yandex Translate": "Yandex Перекладач",
|
||||
"YYYY or YYYY-MM-DD": "YYYY або YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -446,6 +446,8 @@
|
||||
"Open Library": "Open Library",
|
||||
"Fiction, Science, History": "Tiểu thuyết, Khoa học, Lịch sử",
|
||||
"Select Cover Image": "Chọn ảnh bìa",
|
||||
"Open Book in New Window": "Open Sách trong Cửa sổ Mới",
|
||||
"Voices for {{lang}}": "Giọng nói cho {{lang}}"
|
||||
"Open Book in New Window": "Mở Sách trong Cửa sổ Mới",
|
||||
"Voices for {{lang}}": "Giọng nói cho {{lang}}",
|
||||
"Yandex Translate": "Yandex Dịch",
|
||||
"YYYY or YYYY-MM-DD": "YYYY hoặc YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -447,5 +447,7 @@
|
||||
"Fiction, Science, History": "小说,科学,历史",
|
||||
"Select Cover Image": "选择封面图片",
|
||||
"Open Book in New Window": "在新窗口中打开书籍",
|
||||
"Voices for {{lang}}": "{{lang}} 的语音"
|
||||
"Voices for {{lang}}": "{{lang}} 的语音",
|
||||
"Yandex Translate": "Yandex 翻译",
|
||||
"YYYY or YYYY-MM-DD": "YYYY 或 YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -447,5 +447,7 @@
|
||||
"Fiction, Science, History": "小說,科學,歷史",
|
||||
"Select Cover Image": "選擇封面圖片",
|
||||
"Open Book in New Window": "在新視窗中打開書籍",
|
||||
"Voices for {{lang}}": "{{lang}} 的語音"
|
||||
"Voices for {{lang}}": "{{lang}} 的語音",
|
||||
"Yandex Translate": "Yandex 翻譯",
|
||||
"YYYY or YYYY-MM-DD": "YYYY 或 YYYY-MM-DD"
|
||||
}
|
||||
|
||||
@@ -179,6 +179,7 @@ const Bookshelf: React.FC<BookshelfProps> = ({
|
||||
};
|
||||
|
||||
const openBookDetails = () => {
|
||||
handleSetSelectMode(false);
|
||||
const book = libraryBooks.find((book) => book.hash === selectedBooks[0]);
|
||||
if (book) {
|
||||
handleShowDetailsBook(book);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import clsx from 'clsx';
|
||||
import { useCallback } from 'react';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { navigateToLibrary, navigateToReader, showReaderWindow } from '@/utils/nav';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
@@ -8,8 +9,9 @@ import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useLongPress } from '@/hooks/useLongPress';
|
||||
import { Menu, MenuItem } from '@tauri-apps/api/menu';
|
||||
import { revealItemInDir } from '@tauri-apps/plugin-opener';
|
||||
import { getOSPlatform } from '@/utils/misc';
|
||||
import { getLocalBookFilename } from '@/utils/book';
|
||||
import { getOSPlatform } from '@/utils/misc';
|
||||
import { throttle } from '@/utils/throttle';
|
||||
import { LibraryCoverFitType, LibraryViewModeType } from '@/types/settings';
|
||||
import { BOOK_UNGROUPED_ID, BOOK_UNGROUPED_NAME } from '@/services/constants';
|
||||
import { FILE_REVEAL_LABELS, FILE_REVEAL_PLATFORMS } from '@/utils/os';
|
||||
@@ -138,28 +140,36 @@ const BookshelfItem: React.FC<BookshelfItemProps> = ({
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleBookClick = async (book: Book) => {
|
||||
if (isSelectMode) {
|
||||
toggleSelection(book.hash);
|
||||
} else {
|
||||
if (!(await makeBookAvailable(book))) return;
|
||||
if (appService?.hasWindow && settings.openBookInNewWindow) {
|
||||
showReaderWindow(appService, [book.hash]);
|
||||
const handleBookClick = useCallback(
|
||||
async (book: Book) => {
|
||||
if (isSelectMode) {
|
||||
toggleSelection(book.hash);
|
||||
} else {
|
||||
navigateToReader(router, [book.hash]);
|
||||
if (!(await makeBookAvailable(book))) return;
|
||||
if (appService?.hasWindow && settings.openBookInNewWindow) {
|
||||
showReaderWindow(appService, [book.hash]);
|
||||
} else {
|
||||
navigateToReader(router, [book.hash]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[isSelectMode, settings.openBookInNewWindow, appService],
|
||||
);
|
||||
|
||||
const handleGroupClick = (group: BooksGroup) => {
|
||||
if (isSelectMode) {
|
||||
toggleSelection(group.id);
|
||||
} else {
|
||||
const params = new URLSearchParams(searchParams?.toString());
|
||||
params.set('group', group.id);
|
||||
navigateToLibrary(router, `${params.toString()}`);
|
||||
}
|
||||
};
|
||||
const handleGroupClick = useCallback(
|
||||
(group: BooksGroup) => {
|
||||
if (isSelectMode) {
|
||||
toggleSelection(group.id);
|
||||
} else {
|
||||
const params = new URLSearchParams(searchParams?.toString());
|
||||
params.set('group', group.id);
|
||||
navigateToLibrary(router, `${params.toString()}`);
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[isSelectMode, searchParams],
|
||||
);
|
||||
|
||||
const bookContextMenuHandler = async (book: Book) => {
|
||||
if (!appService?.hasContextMenu) return;
|
||||
@@ -241,8 +251,9 @@ const BookshelfItem: React.FC<BookshelfItemProps> = ({
|
||||
menu.popup();
|
||||
};
|
||||
|
||||
const { pressing, handlers } = useLongPress({
|
||||
onLongPress: async () => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const handleSelectItem = useCallback(
|
||||
throttle(() => {
|
||||
if (!isSelectMode) {
|
||||
handleSetSelectMode(true);
|
||||
}
|
||||
@@ -251,22 +262,56 @@ const BookshelfItem: React.FC<BookshelfItemProps> = ({
|
||||
} else {
|
||||
toggleSelection((item as BooksGroup).id);
|
||||
}
|
||||
},
|
||||
onTap: () => {
|
||||
}, 100),
|
||||
[isSelectMode],
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const handleOpenItem = useCallback(
|
||||
throttle(() => {
|
||||
if (isSelectMode) {
|
||||
handleSelectItem();
|
||||
return;
|
||||
}
|
||||
if ('format' in item) {
|
||||
handleBookClick(item as Book);
|
||||
} else {
|
||||
handleGroupClick(item as BooksGroup);
|
||||
}
|
||||
},
|
||||
onContextMenu: () => {
|
||||
}, 100),
|
||||
[handleSelectItem, handleBookClick, handleGroupClick],
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const handleContextMenu = useCallback(
|
||||
throttle(() => {
|
||||
if ('format' in item) {
|
||||
bookContextMenuHandler(item as Book);
|
||||
} else {
|
||||
groupContextMenuHandler(item as BooksGroup);
|
||||
}
|
||||
}, 100),
|
||||
[],
|
||||
);
|
||||
|
||||
const { pressing, handlers } = useLongPress(
|
||||
{
|
||||
onLongPress: () => {
|
||||
handleSelectItem();
|
||||
},
|
||||
onTap: () => {
|
||||
handleOpenItem();
|
||||
},
|
||||
onContextMenu: () => {
|
||||
if (appService?.hasContextMenu) {
|
||||
handleContextMenu();
|
||||
} else if (appService?.isAndroidApp) {
|
||||
handleSelectItem();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
[isSelectMode, handleSelectItem, handleOpenItem, handleContextMenu],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={clsx(mode === 'list' && 'sm:hover:bg-base-300/50 px-4 sm:px-6')}>
|
||||
@@ -275,6 +320,7 @@ const BookshelfItem: React.FC<BookshelfItemProps> = ({
|
||||
'group',
|
||||
mode === 'grid' && 'sm:hover:bg-base-300/50 flex h-full flex-col px-0 py-4 sm:px-4',
|
||||
mode === 'list' && 'border-base-300 flex flex-col border-b py-2',
|
||||
appService?.isMobileApp && 'no-context-menu',
|
||||
pressing ? (mode === 'grid' ? 'scale-95' : 'scale-98') : 'scale-100',
|
||||
)}
|
||||
style={{
|
||||
|
||||
@@ -48,10 +48,7 @@ const BookCover: React.FC<BookCoverProps> = ({
|
||||
return (
|
||||
<div
|
||||
ref={coverRef}
|
||||
className={clsx(
|
||||
'book-cover-container no-context-menu relative flex h-full w-full',
|
||||
className,
|
||||
)}
|
||||
className={clsx('book-cover-container relative flex h-full w-full', className)}
|
||||
>
|
||||
{coverFit === 'crop' ? (
|
||||
<Image
|
||||
|
||||
@@ -114,7 +114,7 @@ const BookDetailEdit: React.FC<BookDetailEditProps> = ({
|
||||
field: 'published',
|
||||
label: _('Publication Date'),
|
||||
value: metadata.published || '',
|
||||
placeholder: 'YYYY or YYYY-MM-DD',
|
||||
placeholder: _('YYYY or YYYY-MM-DD'),
|
||||
},
|
||||
{
|
||||
field: 'language',
|
||||
@@ -178,9 +178,12 @@ const BookDetailEdit: React.FC<BookDetailEditProps> = ({
|
||||
let files;
|
||||
if (isTauriAppPlatform()) {
|
||||
files = (await selectImageFileTauri()) as string[];
|
||||
if (files.length > 0) {
|
||||
if (appService && files.length > 0) {
|
||||
metadata.coverImageFile = files[0]!;
|
||||
metadata.coverImageUrl = appService?.fs.getURL(files[0]!);
|
||||
const tempName = 'cover-temp.png';
|
||||
const cachePrefix = appService.fs.getPrefix('Cache');
|
||||
await appService.fs.copyFile(files[0]!, tempName, 'Cache');
|
||||
metadata.coverImageUrl = await appService.fs.getURL(`${cachePrefix}/${tempName}`);
|
||||
setNewCoverImageUrl(metadata.coverImageUrl!);
|
||||
}
|
||||
} else {
|
||||
@@ -196,7 +199,10 @@ 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 className='aspect-[28/41] h-full shadow-md'>
|
||||
<div
|
||||
className='aspect-[28/41] h-full shadow-md'
|
||||
onClick={!isCoverLocked ? handleSelectLocalImage : undefined}
|
||||
>
|
||||
<BookCover
|
||||
mode='list'
|
||||
book={{
|
||||
@@ -222,7 +228,12 @@ const BookDetailEdit: React.FC<BookDetailEditProps> = ({
|
||||
)}
|
||||
title={_('Change cover image')}
|
||||
>
|
||||
<MdEdit className='h-5 w-5 sm:h-4 sm:w-4' />
|
||||
<MdEdit
|
||||
className={clsx(
|
||||
'h-5 w-5 sm:h-4 sm:w-4',
|
||||
isCoverLocked ? 'fill-base-content' : 'fill-gray-600',
|
||||
)}
|
||||
/>
|
||||
<span className='hidden sm:inline'>{_('Replace')}</span>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ const BookDetailView: React.FC<BookDetailViewProps> = ({
|
||||
<div className='overflow-hidden'>
|
||||
<span className='font-bold'>{_('Published')}</span>
|
||||
<p className='text-neutral-content text-sm'>
|
||||
{formatDate(metadata.published) || _('Unknown')}
|
||||
{formatDate(metadata.published, true) || _('Unknown')}
|
||||
</p>
|
||||
</div>
|
||||
<div className='overflow-hidden'>
|
||||
|
||||
@@ -21,14 +21,17 @@ interface UseLongPressResult {
|
||||
};
|
||||
}
|
||||
|
||||
export const useLongPress = ({
|
||||
onTap,
|
||||
onLongPress,
|
||||
onContextMenu,
|
||||
onCancel,
|
||||
threshold = 500,
|
||||
moveThreshold = 10,
|
||||
}: UseLongPressOptions): UseLongPressResult => {
|
||||
export const useLongPress = (
|
||||
{
|
||||
onTap,
|
||||
onLongPress,
|
||||
onContextMenu,
|
||||
onCancel,
|
||||
threshold = 500,
|
||||
moveThreshold = 10,
|
||||
}: UseLongPressOptions,
|
||||
deps: React.DependencyList,
|
||||
): UseLongPressResult => {
|
||||
const [pressing, setPressing] = useState(false);
|
||||
const timerRef = useRef<NodeJS.Timeout>();
|
||||
const startPosRef = useRef<{ x: number; y: number } | null>(null);
|
||||
@@ -114,15 +117,17 @@ export const useLongPress = ({
|
||||
e.stopPropagation();
|
||||
onContextMenu();
|
||||
}
|
||||
reset();
|
||||
},
|
||||
[onContextMenu],
|
||||
[onContextMenu, reset],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearTimeout(timerRef.current);
|
||||
};
|
||||
}, []);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, deps);
|
||||
|
||||
return {
|
||||
pressing,
|
||||
|
||||
@@ -123,7 +123,7 @@ export const getPrimaryLanguage = (lang: string | string[] | undefined) => {
|
||||
return Array.isArray(lang) ? lang[0] : lang;
|
||||
};
|
||||
|
||||
export const formatDate = (date: string | number | Date | null | undefined) => {
|
||||
export const formatDate = (date: string | number | Date | null | undefined, isUTC = false) => {
|
||||
if (!date) return;
|
||||
const userLang = getUserLang();
|
||||
try {
|
||||
@@ -131,6 +131,7 @@ export const formatDate = (date: string | number | Date | null | undefined) => {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
timeZone: isUTC ? 'UTC' : undefined,
|
||||
});
|
||||
} catch {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user