feat: add an option in the view menu to crop or fit book covers of the library page (#1469)
This commit is contained in:
@@ -378,5 +378,8 @@
|
||||
"Custom Content CSS": "CSS مخصص للمحتوى",
|
||||
"Enter CSS for book content styling...": "أدخل CSS لتنسيق محتوى الكتاب...",
|
||||
"Custom Reader UI CSS": "CSS مخصص لواجهة القارئ",
|
||||
"Enter CSS for reader interface styling...": "أدخل CSS لتنسيق واجهة القارئ..."
|
||||
"Enter CSS for reader interface styling...": "أدخل CSS لتنسيق واجهة القارئ...",
|
||||
"Crop": "قص",
|
||||
"Book Covers": "أغلفة الكتب",
|
||||
"Fit": "ملاءمة"
|
||||
}
|
||||
|
||||
@@ -366,5 +366,8 @@
|
||||
"Custom Content CSS": "Benutzerdefiniertes Inhalts-CSS",
|
||||
"Enter CSS for book content styling...": "CSS für die Buchinhaltsgestaltung eingeben...",
|
||||
"Custom Reader UI CSS": "Benutzerdefiniertes CSS für die Leseroberfläche",
|
||||
"Enter CSS for reader interface styling...": "CSS für die Leseroberfläche eingeben..."
|
||||
"Enter CSS for reader interface styling...": "CSS für die Leseroberfläche eingeben...",
|
||||
"Crop": "Zuschneiden",
|
||||
"Book Covers": "Buchcover",
|
||||
"Fit": "Anpassen"
|
||||
}
|
||||
|
||||
@@ -366,5 +366,8 @@
|
||||
"Custom Content CSS": "Προσαρμοσμένο CSS περιεχομένου",
|
||||
"Enter CSS for book content styling...": "Εισαγάγετε CSS για στυλ περιεχομένου βιβλίου...",
|
||||
"Custom Reader UI CSS": "Προσαρμοσμένο CSS διεπαφής αναγνώστη",
|
||||
"Enter CSS for reader interface styling...": "Εισαγάγετε CSS για στυλ διεπαφής αναγνώστη..."
|
||||
"Enter CSS for reader interface styling...": "Εισαγάγετε CSS για στυλ διεπαφής αναγνώστη...",
|
||||
"Crop": "Περικοπή",
|
||||
"Book Covers": "Εξώφυλλα βιβλίων",
|
||||
"Fit": "Προσαρμογή"
|
||||
}
|
||||
|
||||
@@ -369,5 +369,8 @@
|
||||
"Custom Content CSS": "CSS del contenido",
|
||||
"Enter CSS for book content styling...": "Introduce CSS para el contenido del libro...",
|
||||
"Custom Reader UI CSS": "CSS de la interfaz",
|
||||
"Enter CSS for reader interface styling...": "Introduce CSS para la interfaz de lectura..."
|
||||
"Enter CSS for reader interface styling...": "Introduce CSS para la interfaz de lectura...",
|
||||
"Crop": "Recortar",
|
||||
"Book Covers": "Portadas de libros",
|
||||
"Fit": "Encajar"
|
||||
}
|
||||
|
||||
@@ -369,5 +369,8 @@
|
||||
"Custom Content CSS": "CSS du contenu",
|
||||
"Enter CSS for book content styling...": "Saisissez le CSS pour le contenu du livre...",
|
||||
"Custom Reader UI CSS": "CSS de l’interface",
|
||||
"Enter CSS for reader interface styling...": "Saisissez le CSS pour l’interface de lecture..."
|
||||
"Enter CSS for reader interface styling...": "Saisissez le CSS pour l’interface de lecture...",
|
||||
"Crop": "Rogner",
|
||||
"Book Covers": "Couvertures de livres",
|
||||
"Fit": "Adapter"
|
||||
}
|
||||
|
||||
@@ -366,5 +366,8 @@
|
||||
"Custom Content CSS": "सामग्री का CSS",
|
||||
"Enter CSS for book content styling...": "पुस्तक सामग्री के लिए CSS दर्ज करें...",
|
||||
"Custom Reader UI CSS": "इंटरफ़ेस का CSS",
|
||||
"Enter CSS for reader interface styling...": "रीडर इंटरफ़ेस के लिए CSS दर्ज करें..."
|
||||
"Enter CSS for reader interface styling...": "रीडर इंटरफ़ेस के लिए CSS दर्ज करें...",
|
||||
"Crop": "काटें",
|
||||
"Book Covers": "पुस्तक कवर",
|
||||
"Fit": "फिट"
|
||||
}
|
||||
|
||||
@@ -363,5 +363,8 @@
|
||||
"Custom Content CSS": "CSS konten",
|
||||
"Enter CSS for book content styling...": "Masukkan CSS untuk gaya konten buku...",
|
||||
"Custom Reader UI CSS": "CSS antarmuka",
|
||||
"Enter CSS for reader interface styling...": "Masukkan CSS untuk gaya antarmuka pembaca..."
|
||||
"Enter CSS for reader interface styling...": "Masukkan CSS untuk gaya antarmuka pembaca...",
|
||||
"Crop": "Potong",
|
||||
"Book Covers": "Sampul Buku",
|
||||
"Fit": "Pas"
|
||||
}
|
||||
|
||||
@@ -369,5 +369,8 @@
|
||||
"Custom Content CSS": "CSS contenuto",
|
||||
"Enter CSS for book content styling...": "Inserisci il CSS per il contenuto del libro...",
|
||||
"Custom Reader UI CSS": "CSS interfaccia",
|
||||
"Enter CSS for reader interface styling...": "Inserisci il CSS per l'interfaccia di lettura..."
|
||||
"Enter CSS for reader interface styling...": "Inserisci il CSS per l'interfaccia di lettura...",
|
||||
"Crop": "Ritaglia",
|
||||
"Book Covers": "Copertine libri",
|
||||
"Fit": "Adatta"
|
||||
}
|
||||
|
||||
@@ -363,5 +363,8 @@
|
||||
"Custom Content CSS": "コンテンツCSS",
|
||||
"Enter CSS for book content styling...": "本のコンテンツ用CSSを入力...",
|
||||
"Custom Reader UI CSS": "リーダーUIのCSS",
|
||||
"Enter CSS for reader interface styling...": "リーダーインターフェース用CSSを入力..."
|
||||
"Enter CSS for reader interface styling...": "リーダーインターフェース用CSSを入力...",
|
||||
"Crop": "トリミング",
|
||||
"Book Covers": "書籍の表紙",
|
||||
"Fit": "フィット"
|
||||
}
|
||||
|
||||
@@ -363,5 +363,8 @@
|
||||
"Custom Content CSS": "콘텐츠 CSS",
|
||||
"Enter CSS for book content styling...": "도서 콘텐츠 스타일을 위한 CSS 입력...",
|
||||
"Custom Reader UI CSS": "리더 UI CSS",
|
||||
"Enter CSS for reader interface styling...": "리더 인터페이스 스타일용 CSS 입력..."
|
||||
"Enter CSS for reader interface styling...": "리더 인터페이스 스타일용 CSS 입력...",
|
||||
"Crop": "자르기",
|
||||
"Book Covers": "책 표지",
|
||||
"Fit": "맞춤"
|
||||
}
|
||||
|
||||
@@ -366,5 +366,8 @@
|
||||
"Custom Content CSS": "Aangepaste inhoud-CSS",
|
||||
"Enter CSS for book content styling...": "Voer CSS in voor de opmaak van de boekinhoud...",
|
||||
"Custom Reader UI CSS": "Aangepaste interface-CSS",
|
||||
"Enter CSS for reader interface styling...": "Voer CSS in voor de opmaak van de leesinterface..."
|
||||
"Enter CSS for reader interface styling...": "Voer CSS in voor de opmaak van de leesinterface...",
|
||||
"Crop": "Bijsnijden",
|
||||
"Book Covers": "Boekomslagen",
|
||||
"Fit": "Passend maken"
|
||||
}
|
||||
|
||||
@@ -372,5 +372,8 @@
|
||||
"Custom Content CSS": "CSS treści",
|
||||
"Enter CSS for book content styling...": "Wprowadź CSS dla stylu treści książki...",
|
||||
"Custom Reader UI CSS": "CSS interfejsu",
|
||||
"Enter CSS for reader interface styling...": "Wprowadź CSS dla stylu interfejsu czytnika..."
|
||||
"Enter CSS for reader interface styling...": "Wprowadź CSS dla stylu interfejsu czytnika...",
|
||||
"Crop": "Przytnij",
|
||||
"Book Covers": "Okładki książek",
|
||||
"Fit": "Pasuje"
|
||||
}
|
||||
|
||||
@@ -369,5 +369,8 @@
|
||||
"Custom Content CSS": "CSS do conteúdo",
|
||||
"Enter CSS for book content styling...": "Insira o CSS para o estilo do conteúdo do livro...",
|
||||
"Custom Reader UI CSS": "CSS da interface",
|
||||
"Enter CSS for reader interface styling...": "Insira o CSS para o estilo da interface de leitura..."
|
||||
"Enter CSS for reader interface styling...": "Insira o CSS para o estilo da interface de leitura...",
|
||||
"Crop": "Cortar",
|
||||
"Book Covers": "Capas de Livros",
|
||||
"Fit": "Encaixar"
|
||||
}
|
||||
|
||||
@@ -372,5 +372,8 @@
|
||||
"Custom Content CSS": "CSS содержимого",
|
||||
"Enter CSS for book content styling...": "Введите CSS для оформления содержимого книги...",
|
||||
"Custom Reader UI CSS": "CSS интерфейса",
|
||||
"Enter CSS for reader interface styling...": "Введите CSS для оформления интерфейса ридера..."
|
||||
"Enter CSS for reader interface styling...": "Введите CSS для оформления интерфейса ридера...",
|
||||
"Crop": "Обрезать",
|
||||
"Book Covers": "Обложки книг",
|
||||
"Fit": "Подогнать"
|
||||
}
|
||||
|
||||
@@ -366,5 +366,8 @@
|
||||
"Custom Content CSS": "Özel İçerik CSS'si",
|
||||
"Enter CSS for book content styling...": "Kitap içeriği stili için CSS girin...",
|
||||
"Custom Reader UI CSS": "Özel Okuyucu Arayüzü CSS'si",
|
||||
"Enter CSS for reader interface styling...": "Okuyucu arayüzü stili için CSS girin..."
|
||||
"Enter CSS for reader interface styling...": "Okuyucu arayüzü stili için CSS girin...",
|
||||
"Crop": "Kes",
|
||||
"Book Covers": "Kitap Kapağı",
|
||||
"Fit": "Uygun"
|
||||
}
|
||||
|
||||
@@ -372,5 +372,8 @@
|
||||
"Custom Content CSS": "CSS вмісту",
|
||||
"Enter CSS for book content styling...": "Введіть CSS для стилізації вмісту книги...",
|
||||
"Custom Reader UI CSS": "CSS інтерфейсу",
|
||||
"Enter CSS for reader interface styling...": "Введіть CSS для стилізації інтерфейсу рідера..."
|
||||
"Enter CSS for reader interface styling...": "Введіть CSS для стилізації інтерфейсу рідера...",
|
||||
"Crop": "Обрізати",
|
||||
"Book Covers": "Обкладинки книг",
|
||||
"Fit": "Вписати"
|
||||
}
|
||||
|
||||
@@ -363,5 +363,8 @@
|
||||
"Custom Content CSS": "CSS nội dung",
|
||||
"Enter CSS for book content styling...": "Nhập CSS cho phần nội dung sách...",
|
||||
"Custom Reader UI CSS": "CSS giao diện đọc",
|
||||
"Enter CSS for reader interface styling...": "Nhập CSS cho giao diện trình đọc..."
|
||||
"Enter CSS for reader interface styling...": "Nhập CSS cho giao diện trình đọc...",
|
||||
"Crop": "Cắt",
|
||||
"Book Covers": "Bìa sách",
|
||||
"Fit": "Vừa vặn"
|
||||
}
|
||||
|
||||
@@ -363,5 +363,8 @@
|
||||
"Custom Content CSS": "自定义内容 CSS",
|
||||
"Enter CSS for book content styling...": "输入书籍内容样式的CSS…",
|
||||
"Custom Reader UI CSS": "自定义界面 CSS",
|
||||
"Enter CSS for reader interface styling...": "输入阅读器界面样式的CSS…"
|
||||
"Enter CSS for reader interface styling...": "输入阅读器界面样式的CSS…",
|
||||
"Crop": "裁剪",
|
||||
"Book Covers": "书籍封面",
|
||||
"Fit": "适应"
|
||||
}
|
||||
|
||||
@@ -363,5 +363,8 @@
|
||||
"Custom Content CSS": "自訂內容 CSS",
|
||||
"Enter CSS for book content styling...": "輸入書籍內容樣式的CSS…",
|
||||
"Custom Reader UI CSS": "自訂介面 CSS",
|
||||
"Enter CSS for reader interface styling...": "輸入閱讀器介面樣式的CSS…"
|
||||
"Enter CSS for reader interface styling...": "輸入閱讀器介面樣式的CSS…",
|
||||
"Crop": "裁剪",
|
||||
"Book Covers": "書籍封面",
|
||||
"Fit": "適應"
|
||||
}
|
||||
|
||||
@@ -11,15 +11,16 @@ import { useEnv } from '@/context/EnvContext';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
|
||||
import { LibraryViewModeType } from '@/types/settings';
|
||||
import { LibraryCoverFitType, LibraryViewModeType } from '@/types/settings';
|
||||
import { navigateToLogin } from '@/utils/nav';
|
||||
import { formatAuthors } from '@/utils/book';
|
||||
import ReadingProgress from './ReadingProgress';
|
||||
import BookCover from '@/components/BookCover';
|
||||
|
||||
interface BookItemProps {
|
||||
mode: LibraryViewModeType;
|
||||
book: Book;
|
||||
mode: LibraryViewModeType;
|
||||
coverFit: LibraryCoverFitType;
|
||||
isSelectMode: boolean;
|
||||
selectedBooks: string[];
|
||||
transferProgress: number | null;
|
||||
@@ -29,8 +30,9 @@ interface BookItemProps {
|
||||
}
|
||||
|
||||
const BookItem: React.FC<BookItemProps> = ({
|
||||
mode,
|
||||
book,
|
||||
mode,
|
||||
coverFit,
|
||||
isSelectMode,
|
||||
selectedBooks,
|
||||
transferProgress,
|
||||
@@ -59,11 +61,11 @@ const BookItem: React.FC<BookItemProps> = ({
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
'bg-base-100 relative flex aspect-[28/41] items-center justify-center overflow-hidden shadow-md',
|
||||
'relative flex aspect-[28/41] items-center justify-center',
|
||||
mode === 'list' && 'min-w-20',
|
||||
)}
|
||||
>
|
||||
<BookCover mode={mode} book={book} />
|
||||
<BookCover mode={mode} book={book} coverFit={coverFit} className='drop-shadow-md' />
|
||||
{selectedBooks.includes(book.hash) && (
|
||||
<div className='absolute inset-0 bg-black opacity-30 transition-opacity duration-300'></div>
|
||||
)}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { MdDelete, MdOpenInNew, MdOutlineCancel, MdInfoOutline } from 'react-ico
|
||||
import { LuFolderPlus } from 'react-icons/lu';
|
||||
import { PiPlus } from 'react-icons/pi';
|
||||
import { Book, BooksGroup } from '@/types/book';
|
||||
import { LibraryViewModeType } from '@/types/settings';
|
||||
import { LibraryCoverFitType, LibraryViewModeType } from '@/types/settings';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useLibraryStore } from '@/store/libraryStore';
|
||||
@@ -66,6 +66,7 @@ const Bookshelf: React.FC<BookshelfProps> = ({
|
||||
const [sortOrder, setSortOrder] = useState(
|
||||
searchParams?.get('order') || (settings.librarySortAscending ? 'asc' : 'desc'),
|
||||
);
|
||||
const [coverFit, setCoverFit] = useState(searchParams?.get('cover') || settings.libraryCoverFit);
|
||||
const isImportingBook = useRef(false);
|
||||
|
||||
const { setCurrentBookshelf, setLibrary } = useLibraryStore();
|
||||
@@ -106,6 +107,7 @@ const Bookshelf: React.FC<BookshelfProps> = ({
|
||||
const view = searchParams?.get('view') || settings.libraryViewMode;
|
||||
const sort = searchParams?.get('sort') || settings.librarySortBy;
|
||||
const order = searchParams?.get('order') || (settings.librarySortAscending ? 'asc' : 'desc');
|
||||
const cover = searchParams?.get('cover') || settings.libraryCoverFit;
|
||||
const params = new URLSearchParams(searchParams?.toString());
|
||||
if (query) {
|
||||
params.set('q', query);
|
||||
@@ -132,6 +134,10 @@ const Bookshelf: React.FC<BookshelfProps> = ({
|
||||
} else {
|
||||
params.delete('view');
|
||||
}
|
||||
setCoverFit(cover);
|
||||
if (cover === 'crop') {
|
||||
params.delete('cover');
|
||||
}
|
||||
if (sort === 'updated' && order === 'desc' && view === 'grid') {
|
||||
params.delete('sort');
|
||||
params.delete('order');
|
||||
@@ -288,8 +294,9 @@ const Bookshelf: React.FC<BookshelfProps> = ({
|
||||
{filteredBookshelfItems.map((item, index) => (
|
||||
<BookshelfItem
|
||||
key={`library-item-${index}`}
|
||||
mode={viewMode as LibraryViewModeType}
|
||||
item={item}
|
||||
mode={viewMode as LibraryViewModeType}
|
||||
coverFit={coverFit as LibraryCoverFitType}
|
||||
isSelectMode={isSelectMode}
|
||||
selectedBooks={selectedBooks}
|
||||
setLoading={setLoading}
|
||||
|
||||
@@ -10,7 +10,7 @@ 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 { LibraryViewModeType } from '@/types/settings';
|
||||
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';
|
||||
import { Book, BookGroupType, BooksGroup } from '@/types/book';
|
||||
@@ -73,6 +73,7 @@ export const generateGroupsList = (items: Book[]): BookGroupType[] => {
|
||||
interface BookshelfItemProps {
|
||||
mode: LibraryViewModeType;
|
||||
item: BookshelfItem;
|
||||
coverFit: LibraryCoverFitType;
|
||||
isSelectMode: boolean;
|
||||
selectedBooks: string[];
|
||||
transferProgress: number | null;
|
||||
@@ -88,6 +89,7 @@ interface BookshelfItemProps {
|
||||
const BookshelfItem: React.FC<BookshelfItemProps> = ({
|
||||
mode,
|
||||
item,
|
||||
coverFit,
|
||||
isSelectMode,
|
||||
selectedBooks,
|
||||
transferProgress,
|
||||
@@ -276,6 +278,7 @@ const BookshelfItem: React.FC<BookshelfItemProps> = ({
|
||||
<BookItem
|
||||
mode={mode}
|
||||
book={item}
|
||||
coverFit={coverFit}
|
||||
isSelectMode={isSelectMode}
|
||||
selectedBooks={selectedBooks}
|
||||
transferProgress={transferProgress}
|
||||
|
||||
@@ -22,7 +22,7 @@ import WindowButtons from '@/components/WindowButtons';
|
||||
import Dropdown from '@/components/Dropdown';
|
||||
import SettingsMenu from './SettingsMenu';
|
||||
import ImportMenu from './ImportMenu';
|
||||
import SortMenu from './SortMenu';
|
||||
import ViewMenu from './ViewMenu';
|
||||
|
||||
interface LibraryHeaderProps {
|
||||
isSelectMode: boolean;
|
||||
@@ -228,7 +228,7 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
|
||||
buttonClassName='btn btn-ghost h-8 min-h-8 w-8 p-0'
|
||||
toggleButton={<PiDotsThreeCircle size={iconSize18} />}
|
||||
>
|
||||
<SortMenu />
|
||||
<ViewMenu />
|
||||
</Dropdown>
|
||||
<Dropdown
|
||||
className='exclude-title-bar-mousedown dropdown-bottom dropdown-end'
|
||||
|
||||
+37
-4
@@ -4,15 +4,15 @@ import { MdCheck } from 'react-icons/md';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { LibrarySortByType, LibraryViewModeType } from '@/types/settings';
|
||||
import { LibraryCoverFitType, LibrarySortByType, LibraryViewModeType } from '@/types/settings';
|
||||
import { navigateToLibrary } from '@/utils/nav';
|
||||
import MenuItem from '@/components/MenuItem';
|
||||
|
||||
interface SortMenuProps {
|
||||
interface ViewMenuProps {
|
||||
setIsDropdownOpen?: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
const SortMenu: React.FC<SortMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
const ViewMenu: React.FC<ViewMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
const _ = useTranslation();
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
@@ -22,12 +22,18 @@ const SortMenu: React.FC<SortMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
const viewMode = settings.libraryViewMode;
|
||||
const sortBy = settings.librarySortBy;
|
||||
const isAscending = settings.librarySortAscending;
|
||||
const coverFit = settings.libraryCoverFit;
|
||||
|
||||
const viewOptions = [
|
||||
{ label: _('List'), value: 'list' },
|
||||
{ label: _('Grid'), value: 'grid' },
|
||||
];
|
||||
|
||||
const coverFitOptions = [
|
||||
{ label: _('Crop'), value: 'crop' },
|
||||
{ label: _('Fit'), value: 'fit' },
|
||||
];
|
||||
|
||||
const sortByOptions = [
|
||||
{ label: _('Title'), value: 'title' },
|
||||
{ label: _('Author'), value: 'author' },
|
||||
@@ -52,6 +58,17 @@ const SortMenu: React.FC<SortMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
navigateToLibrary(router, `${params.toString()}`);
|
||||
};
|
||||
|
||||
const handleToggleCropCovers = (value: LibraryCoverFitType) => {
|
||||
settings.libraryCoverFit = value;
|
||||
setSettings(settings);
|
||||
saveSettings(envConfig, settings);
|
||||
setIsDropdownOpen?.(false);
|
||||
|
||||
const params = new URLSearchParams(searchParams?.toString());
|
||||
params.set('cover', value);
|
||||
navigateToLibrary(router, `${params.toString()}`);
|
||||
};
|
||||
|
||||
const handleSetSortBy = (value: LibrarySortByType) => {
|
||||
settings.librarySortBy = value;
|
||||
setSettings(settings);
|
||||
@@ -89,6 +106,22 @@ const SortMenu: React.FC<SortMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
/>
|
||||
))}
|
||||
<hr className='border-base-200 my-1' />
|
||||
<MenuItem
|
||||
label={_('Book Covers')}
|
||||
buttonClass='h-8'
|
||||
labelClass='text-sm sm:text-xs'
|
||||
disabled
|
||||
/>
|
||||
{coverFitOptions.map((option) => (
|
||||
<MenuItem
|
||||
key={option.value}
|
||||
label={option.label}
|
||||
buttonClass='h-8'
|
||||
Icon={coverFit === option.value ? MdCheck : undefined}
|
||||
onClick={() => handleToggleCropCovers(option.value as LibraryCoverFitType)}
|
||||
/>
|
||||
))}
|
||||
<hr className='border-base-200 my-1' />
|
||||
<MenuItem
|
||||
label={_('Sort by...')}
|
||||
buttonClass='h-8'
|
||||
@@ -118,4 +151,4 @@ const SortMenu: React.FC<SortMenuProps> = ({ setIsDropdownOpen }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default SortMenu;
|
||||
export default ViewMenu;
|
||||
@@ -1,23 +1,38 @@
|
||||
import clsx from 'clsx';
|
||||
import Image from 'next/image';
|
||||
import { Book } from '@/types/book';
|
||||
import { LibraryViewModeType } from '@/types/settings';
|
||||
import { LibraryCoverFitType, LibraryViewModeType } from '@/types/settings';
|
||||
import { formatAuthors, formatTitle } from '@/utils/book';
|
||||
|
||||
interface BookCoverProps {
|
||||
book: Book;
|
||||
isPreview?: boolean;
|
||||
mode?: LibraryViewModeType;
|
||||
coverFit?: LibraryCoverFitType;
|
||||
className?: string;
|
||||
imageClassName?: string;
|
||||
isPreview?: boolean;
|
||||
}
|
||||
|
||||
const BookCover: React.FC<BookCoverProps> = ({ mode = 'grid', book, isPreview }) => {
|
||||
const BookCover: React.FC<BookCoverProps> = ({
|
||||
book,
|
||||
mode = 'grid',
|
||||
coverFit = 'crop',
|
||||
className,
|
||||
imageClassName,
|
||||
isPreview,
|
||||
}) => {
|
||||
return (
|
||||
<div className={clsx('relative flex h-full w-full')}>
|
||||
<div className={clsx('relative flex h-full w-full', className)}>
|
||||
<Image
|
||||
src={book.coverImageUrl!}
|
||||
alt={book.title}
|
||||
fill={true}
|
||||
className='object-cover'
|
||||
className={clsx(
|
||||
coverFit === 'crop'
|
||||
? 'object-cover'
|
||||
: `object-contain ${mode === 'grid' ? 'object-bottom' : ''}`,
|
||||
imageClassName,
|
||||
)}
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).style.display = 'none';
|
||||
(e.target as HTMLImageElement).nextElementSibling?.classList.remove('invisible');
|
||||
@@ -27,7 +42,7 @@ const BookCover: React.FC<BookCoverProps> = ({ mode = 'grid', book, isPreview })
|
||||
className={clsx(
|
||||
'invisible absolute inset-0 rounded-none p-2',
|
||||
'text-neutral-content text-center font-serif font-medium',
|
||||
isPreview && 'bg-base-200/50',
|
||||
isPreview ? 'bg-base-200/50' : 'bg-base-100',
|
||||
)}
|
||||
>
|
||||
<div className='flex h-1/2 items-center justify-center'>
|
||||
|
||||
@@ -47,6 +47,7 @@ export const DEFAULT_SYSTEM_SETTINGS: Partial<SystemSettings> = {
|
||||
libraryViewMode: 'grid',
|
||||
librarySortBy: 'updated',
|
||||
librarySortAscending: false,
|
||||
libraryCoverFit: 'crop',
|
||||
|
||||
lastSyncedAtBooks: 0,
|
||||
lastSyncedAtConfigs: 0,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { HighlightColor, HighlightStyle, ViewSettings } from './book';
|
||||
export type ThemeType = 'light' | 'dark' | 'auto';
|
||||
export type LibraryViewModeType = 'grid' | 'list';
|
||||
export type LibrarySortByType = 'title' | 'author' | 'updated' | 'created' | 'size' | 'format';
|
||||
export type LibraryCoverFitType = 'crop' | 'fit';
|
||||
|
||||
export interface ReadSettings {
|
||||
sideBarWidth: string;
|
||||
@@ -36,6 +37,7 @@ export interface SystemSettings {
|
||||
libraryViewMode: LibraryViewModeType;
|
||||
librarySortBy: LibrarySortByType;
|
||||
librarySortAscending: boolean;
|
||||
libraryCoverFit: LibraryCoverFitType;
|
||||
|
||||
lastSyncedAtBooks: number;
|
||||
lastSyncedAtConfigs: number;
|
||||
|
||||
Reference in New Issue
Block a user