feat: add view option to set cover image size in grid mode, closes #2545 (#2551)

This commit is contained in:
Huang Xin
2025-11-26 14:49:51 +08:00
committed by GitHub
parent ba2aa4bee6
commit 1f73f15ad8
36 changed files with 159 additions and 54 deletions
@@ -690,5 +690,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "فشل في الحفظ التلقائي لغلاف الكتاب لشاشة القفل: {{error}}",
"Download from Cloud": "تحميل من السحابة",
"Upload to Cloud": "رفع إلى السحابة",
"Clear Custom Fonts": "مسح الخطوط المخصصة"
"Clear Custom Fonts": "مسح الخطوط المخصصة",
"Columns": "الأعمدة"
}
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "লক স্ক্রিনের জন্য বইয়ের মলাট স্বয়ংক্রিয়ভাবে সংরক্ষণ করতে ব্যর্থ: {{error}}",
"Download from Cloud": "ক্লাউড থেকে ডাউনলোড করুন",
"Upload to Cloud": "ক্লাউডে আপলোড করুন",
"Clear Custom Fonts": "কাস্টম ফন্টস মুছুন"
"Clear Custom Fonts": "কাস্টম ফন্টস মুছুন",
"Columns": "কলামস"
}
@@ -670,5 +670,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "སྒྲོམ་སྒོར་དེབ་གནས་བཅས་པའི་སྤྱོད་བྱས་མ་ཐུབ།: {{error}}",
"Download from Cloud": "སྤྲིན་ནས་ཕབ་སྟེ་འབེབས་",
"Upload to Cloud": "སྤྲིན་ལ་ཡར་སྤེལ་",
"Clear Custom Fonts": "རང་བཞིན་ཡིག་གཟུགས་སུབ་པ།"
"Clear Custom Fonts": "རང་བཞིན་ཡིག་གཟུགས་སུབ་པ།",
"Columns": "མཚན་ཉིད།"
}
@@ -192,7 +192,7 @@
"No supported files found. Supported formats: {{formats}}": "Keine unterstützten Dateien gefunden. Unterstützte Formate: {{formats}}",
"Drop to Import Books": "Zum Importieren von Büchern ablegen",
"Custom": "Eigen",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "Die ganze Welt ist eine Bühne,\nUnd alle Männer und Frauen sind bloß Spieler;\nSie haben ihre Abgänge und ihre Auftritte,\nUnd ein Mann spielt in seinem Leben viele Rollen,\nSeine Taten sind sieben Zeitalter.\n\n— William Shakespeare",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "Die ganze Welt ist eine Bühne,\nUnd alle Männer und Frauen sind bloß Spieler;\nSie haben ihre Abgänge und ihre Auftritte,\nUnd ein Mann spielt in seinem Leben viele Rollen,\nSeine Taten sind sieben Zeitalter.\n\n— William Shakespeare",
"Custom Theme": "Benutzerdefiniertes Thema",
"Theme Name": "Themenname",
"Text Color": "Textfarbe",
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Automatisches Speichern des Buchcovers für den Sperrbildschirm fehlgeschlagen: {{error}}",
"Download from Cloud": "Aus der Cloud herunterladen",
"Upload to Cloud": "In die Cloud hochladen",
"Clear Custom Fonts": "Benutzerdefinierte Schriftarten löschen"
"Clear Custom Fonts": "Benutzerdefinierte Schriftarten löschen",
"Columns": "Spalten"
}
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Αποτυχία αυτόματης αποθήκευσης εξωφύλλου βιβλίου για την οθόνη κλειδώματος: {{error}}",
"Download from Cloud": "Λήψη από το Cloud",
"Upload to Cloud": "Ανέβασμα στο Cloud",
"Clear Custom Fonts": "Καθαρισμός προσαρμοσμένων γραμματοσειρών"
"Clear Custom Fonts": "Καθαρισμός προσαρμοσμένων γραμματοσειρών",
"Columns": "Στήλες"
}
@@ -220,7 +220,7 @@
"No supported files found. Supported formats: {{formats}}": "No se encontraron archivos compatibles. Formatos compatibles: {{formats}}",
"Drop to Import Books": "Soltar para importar libros",
"Custom": "Personalizado",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n—William Shakespeare": "Todo el mundo es un escenario,\nY todos los hombres y mujeres son meros actores;\nTienen sus salidas y sus entradas,\nY un hombre en su tiempo interpreta muchos papeles,\nSus actos son siete edades.\n\n— William Shakespeare",
"All the world's a stage,\nAnd all the men and women merely players;\nThey have their exits and their entrances,\nAnd one man in his time plays many parts,\nHis acts being seven ages.\n\n— William Shakespeare": "Todo el mundo es un escenario,\nY todos los hombres y mujeres son meros actores;\nTienen sus salidas y sus entradas,\nY un hombre en su tiempo interpreta muchos papeles,\nSus actos son siete edades.\n\n— William Shakespeare",
"Custom Theme": "Tema personalizado",
"Theme Name": "Nombre del tema",
"Text Color": "Color del texto",
@@ -678,5 +678,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Error al guardar automáticamente la portada del libro para la pantalla de bloqueo: {{error}}",
"Download from Cloud": "Descargar desde la nube",
"Upload to Cloud": "Subir a la nube",
"Clear Custom Fonts": "Limpiar fuentes personalizadas"
"Clear Custom Fonts": "Limpiar fuentes personalizadas",
"Columns": "Columnas"
}
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "ذخیره‌ی خودکار جلد کتاب برای صفحه‌ی قفل ناموفق بود: {{error}}",
"Download from Cloud": "دانلود از فضای ابری",
"Upload to Cloud": "آپلود به فضای ابری",
"Clear Custom Fonts": "پاک‌کردن فونت‌های سفارشی"
"Clear Custom Fonts": "پاک‌کردن فونت‌های سفارشی",
"Columns": "ستون‌ها"
}
@@ -678,5 +678,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Échec de l'enregistrement automatique de la couverture du livre pour l'écran de verrouillage : {{error}}",
"Download from Cloud": "Télécharger depuis le Cloud",
"Upload to Cloud": "Téléverser vers le Cloud",
"Clear Custom Fonts": "Effacer les Polices Personnalisées"
"Clear Custom Fonts": "Effacer les Polices Personnalisées",
"Columns": "Colonnes"
}
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "लॉक स्क्रीन के लिए पुस्तक कवर स्वचालित रूप से सहेजने में विफल: {{error}}",
"Download from Cloud": "क्लाउड से डाउनलोड करें",
"Upload to Cloud": "क्लाउड पर अपलोड करें",
"Clear Custom Fonts": "कस्टम फ़ॉन्ट साफ़ करें"
"Clear Custom Fonts": "कस्टम फ़ॉन्ट साफ़ करें",
"Columns": "कॉलम"
}
@@ -670,5 +670,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Gagal menyimpan otomatis sampul buku untuk layar kunci: {{error}}",
"Download from Cloud": "Unduh dari Cloud",
"Upload to Cloud": "Unggah ke Cloud",
"Clear Custom Fonts": "Bersihkan Font Kustom"
"Clear Custom Fonts": "Bersihkan Font Kustom",
"Columns": "Kolom"
}
@@ -678,5 +678,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Impossibile salvare automaticamente la copertina del libro per la schermata di blocco: {{error}}",
"Download from Cloud": "Scarica dal Cloud",
"Upload to Cloud": "Carica sul Cloud",
"Clear Custom Fonts": "Pulisci Font Personalizzati"
"Clear Custom Fonts": "Pulisci Font Personalizzati",
"Columns": "Colonne"
}
@@ -670,5 +670,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "ロック画面の本のカバーの自動保存に失敗しました:{{error}}",
"Download from Cloud": "クラウドからダウンロード",
"Upload to Cloud": "クラウドにアップロード",
"Clear Custom Fonts": "カスタムフォントをクリア"
"Clear Custom Fonts": "カスタムフォントをクリア",
"Columns": "列"
}
@@ -670,5 +670,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "잠금 화면용 책 표지 자동 저장 실패: {{error}}",
"Download from Cloud": "클라우드에서 다운로드",
"Upload to Cloud": "클라우드에 업로드",
"Clear Custom Fonts": "사용자 정의 글꼴 지우기"
"Clear Custom Fonts": "사용자 정의 글꼴 지우기",
"Columns": "열"
}
@@ -670,5 +670,6 @@
"Sunset": "Matahari Terbenam",
"Reveal in Finder": "Tunjukkan dalam Finder",
"Reveal in File Explorer": "Tunjukkan dalam File Explorer",
"Reveal in Folder": "Tunjukkan dalam Folder"
"Reveal in Folder": "Tunjukkan dalam Folder",
"Columns": "Lajur"
}
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Automatisch opslaan van boekomslag voor vergrendelscherm mislukt: {{error}}",
"Download from Cloud": "Downloaden van Cloud",
"Upload to Cloud": "Uploaden naar Cloud",
"Clear Custom Fonts": "Aangepaste Lettertypen Wissen"
"Clear Custom Fonts": "Aangepaste Lettertypen Wissen",
"Columns": "Kolommen"
}
@@ -682,5 +682,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Nie udało się automatycznie zapisać okładki książki dla ekranu blokady: {{error}}",
"Download from Cloud": "Pobierz z chmury",
"Upload to Cloud": "Prześlij do chmury",
"Clear Custom Fonts": "Wyczyść niestandardowe czcionki"
"Clear Custom Fonts": "Wyczyść niestandardowe czcionki",
"Columns": "Kolumny"
}
@@ -678,5 +678,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Falha ao salvar automaticamente a capa do livro para a tela de bloqueio: {{error}}",
"Download from Cloud": "Baixar da Nuvem",
"Upload to Cloud": "Enviar para a Nuvem",
"Clear Custom Fonts": "Limpar Fontes Personalizadas"
"Clear Custom Fonts": "Limpar Fontes Personalizadas",
"Columns": "Colunas"
}
@@ -682,5 +682,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Не удалось автоматически сохранить обложку книги для экрана блокировки: {{error}}",
"Download from Cloud": "Скачать из облака",
"Upload to Cloud": "Загрузить в облако",
"Clear Custom Fonts": "Очистить пользовательские шрифты"
"Clear Custom Fonts": "Очистить пользовательские шрифты",
"Columns": "Колонки"
}
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "අගුළු තිරය සඳහා පොත් ආවරණය ස්වයංක්‍රීයව සුරකිීමට අසමත් විය: {{error}}",
"Download from Cloud": "කලාඬයෙන් බාගත කරන්න",
"Upload to Cloud": "කලාඬයට උඩුගත කරන්න",
"Clear Custom Fonts": "අභිරුචි අකුරු පැහැදිලි කරන්න"
"Clear Custom Fonts": "අභිරුචි අකුරු පැහැදිලි කරන්න",
"Columns": "තීරු"
}
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Kunde inte autospara bokomslag för låsskärm: {{error}}",
"Download from Cloud": "Ladda ner från molnet",
"Upload to Cloud": "Ladda upp till molnet",
"Clear Custom Fonts": "Rensa anpassade typsnitt"
"Clear Custom Fonts": "Rensa anpassade typsnitt",
"Columns": "Kolumner"
}
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "பூட்டு திரைக்கான புத்தகக் கோப்பை தானாகச் சேமிக்க முடியவில்லை: {{error}}",
"Download from Cloud": "மேகத்திலிருந்து பதிவிறக்கு செய்யவும்",
"Upload to Cloud": "மேகத்திற்கு பதிவேற்றவும்",
"Clear Custom Fonts": "தனிப்பயன் எழுத்துருக்களை அழிக்கவும்"
"Clear Custom Fonts": "தனிப்பயன் எழுத்துருக்களை அழிக்கவும்",
"Columns": "நெடுவரிசைகள்"
}
@@ -670,5 +670,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "ไม่สามารถบันทึกปกหนังสือสำหรับหน้าจอล็อกโดยอัตโนมัติ: {{error}}",
"Download from Cloud": "ดาวน์โหลดจากคลาวด์",
"Upload to Cloud": "อัปโหลดไปยังคลาวด์",
"Clear Custom Fonts": "ล้างฟอนต์กำหนดเอง"
"Clear Custom Fonts": "ล้างฟอนต์กำหนดเอง",
"Columns": "คอลัมน์"
}
@@ -674,5 +674,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Kitap kapağı kilit ekranı için otomatik kaydedilemedi: {{error}}",
"Download from Cloud": "Buluttan İndir",
"Upload to Cloud": "Buluta Yükle",
"Clear Custom Fonts": "Özel Yazı Tiplerini Temizle"
"Clear Custom Fonts": "Özel Yazı Tiplerini Temizle",
"Columns": "Sütunlar"
}
@@ -682,5 +682,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Не вдалося автоматично зберегти обкладинку книги для екрана блокування: {{error}}",
"Download from Cloud": "Завантажити з хмари",
"Upload to Cloud": "Завантажити в хмару",
"Clear Custom Fonts": "Очистити користувацькі шрифти"
"Clear Custom Fonts": "Очистити користувацькі шрифти",
"Columns": "Стовпці"
}
@@ -670,5 +670,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "Không thể tự động lưu bìa sách cho màn hình khóa: {{error}}",
"Download from Cloud": "Tải xuống từ đám mây",
"Upload to Cloud": "Tải lên đám mây",
"Clear Custom Fonts": "Xóa phông chữ tùy chỉnh"
"Clear Custom Fonts": "Xóa phông chữ tùy chỉnh",
"Columns": "Cột"
}
@@ -670,5 +670,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "自动保存锁屏书籍封面失败:{{error}}",
"Download from Cloud": "从云端下载",
"Upload to Cloud": "上传到云端",
"Clear Custom Fonts": "清除自定义字体"
"Clear Custom Fonts": "清除自定义字体",
"Columns": "列数"
}
@@ -670,5 +670,6 @@
"Failed to auto-save book cover for lock screen: {{error}}": "自動保存鎖定螢幕書籍封面失敗:{{error}}",
"Download from Cloud": "從雲端下載",
"Upload to Cloud": "上傳到雲端",
"Clear Custom Fonts": "清除自訂字型"
"Clear Custom Fonts": "清除自訂字型",
"Columns": "欄數"
}
@@ -322,6 +322,12 @@ const Bookshelf: React.FC<BookshelfProps> = ({
viewMode === 'grid' && 'sm:grid-cols-4 md:grid-cols-6 xl:grid-cols-8 2xl:grid-cols-12',
viewMode === 'list' && 'flex flex-col',
)}
style={{
gridTemplateColumns:
viewMode === 'grid' && !settings.libraryAutoColumns
? `repeat(${settings.libraryColumns}, minmax(0, 1fr))`
: undefined,
}}
role='main'
aria-label={_('Bookshelf')}
>
@@ -105,6 +105,8 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
if (!insets) return null;
const isMobile = appService?.isMobile || window.innerWidth <= 640;
return (
<div
ref={headerRef}
@@ -138,12 +140,12 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
onChange={handleSearchChange}
spellCheck='false'
className={clsx(
'input rounded-badge h-9 w-full pl-10 pr-10 sm:h-7',
'input rounded-badge h-9 w-full pl-10 pr-[30%] sm:h-7',
viewSettings?.isEink
? 'border-1 border-base-content focus:border-base-content'
: 'bg-base-300/45 border-none',
'font-sans text-sm font-light',
'placeholder:text-base-content/50',
'placeholder:text-base-content/50 truncate',
'focus:outline-none focus:ring-0',
)}
/>
@@ -167,14 +169,14 @@ const LibraryHeader: React.FC<LibraryHeaderProps> = ({
label={_('Import Books')}
className={clsx(
'exclude-title-bar-mousedown dropdown-bottom flex h-6 cursor-pointer justify-center',
appService?.isMobile ? 'dropdown-end' : 'dropdown-center',
isMobile ? 'dropdown-end' : 'dropdown-center',
)}
buttonClassName='p-0 h-6 min-h-6 w-6 flex items-center justify-center'
toggleButton={<PiPlus role='none' className='m-0.5 h-5 w-5' />}
>
<ImportMenu onImportBooks={onImportBooks} />
</Dropdown>
{appService?.isMobile ? null : (
{isMobile ? null : (
<button
onClick={onToggleSelectMode}
aria-label={_('Select Books')}
@@ -3,9 +3,11 @@ import { useRouter, useSearchParams } from 'next/navigation';
import { useEnv } from '@/context/EnvContext';
import { useSettingsStore } from '@/store/settingsStore';
import { useTranslation } from '@/hooks/useTranslation';
import { useResponsiveSize } from '@/hooks/useResponsiveSize';
import { LibraryCoverFitType, LibrarySortByType, LibraryViewModeType } from '@/types/settings';
import { saveSysSettings } from '@/helpers/settings';
import { navigateToLibrary } from '@/utils/nav';
import NumberInput from '@/components/settings/NumberInput';
import MenuItem from '@/components/MenuItem';
import Menu from '@/components/Menu';
@@ -16,6 +18,7 @@ interface ViewMenuProps {
const ViewMenu: React.FC<ViewMenuProps> = ({ setIsDropdownOpen }) => {
const _ = useTranslation();
const router = useRouter();
const iconSize = useResponsiveSize(16);
const searchParams = useSearchParams();
const { envConfig } = useEnv();
const { settings } = useSettingsStore();
@@ -24,6 +27,8 @@ const ViewMenu: React.FC<ViewMenuProps> = ({ setIsDropdownOpen }) => {
const sortBy = settings.librarySortBy;
const isAscending = settings.librarySortAscending;
const coverFit = settings.libraryCoverFit;
const autoColumns = settings.libraryAutoColumns;
const columns = settings.libraryColumns;
const viewOptions = [
{ label: _('List'), value: 'list' },
@@ -66,6 +71,16 @@ const ViewMenu: React.FC<ViewMenuProps> = ({ setIsDropdownOpen }) => {
navigateToLibrary(router, `${params.toString()}`);
};
const handleToggleAutoColumns = () => {
const newValue = !settings.libraryAutoColumns;
saveSysSettings(envConfig, 'libraryAutoColumns', newValue);
};
const handleSetColumns = (value: number) => {
saveSysSettings(envConfig, 'libraryColumns', value);
saveSysSettings(envConfig, 'libraryAutoColumns', false);
};
const handleSetSortBy = (value: LibrarySortByType) => {
saveSysSettings(envConfig, 'librarySortBy', value);
setIsDropdownOpen?.(false);
@@ -99,6 +114,28 @@ const ViewMenu: React.FC<ViewMenuProps> = ({ setIsDropdownOpen }) => {
/>
))}
<hr aria-hidden='true' className='border-base-200 my-1' />
<MenuItem label={_('Columns')} buttonClass='h-8' labelClass='text-sm sm:text-xs' disabled />
<MenuItem
label={_('Auto')}
buttonClass='h-10'
toggled={autoColumns}
disabled={viewMode === 'list'}
siblings={
<NumberInput
className='!h-10 !p-0 !pe-1 !ps-0'
iconSize={iconSize}
inputClassName={autoColumns ? 'opacity-50 !p-0 !w-6' : 'p-0 !w-6'}
label={''}
value={columns}
disabled={viewMode === 'list'}
onChange={handleSetColumns}
min={window.innerWidth < 640 ? 1 : window.innerWidth < 1024 ? 2 : 3}
max={window.innerWidth < 640 ? 4 : window.innerWidth < 1024 ? 6 : 12}
/>
}
onClick={() => handleToggleAutoColumns()}
/>
<hr aria-hidden='true' className='border-base-200 my-1' />
<MenuItem
label={_('Book Covers')}
buttonClass='h-8'
@@ -89,6 +89,9 @@ const Dropdown: React.FC<DropdownProps> = ({
};
const handleBlur = (e: React.FocusEvent) => {
if (process.env.NODE_ENV === 'development') {
return;
}
if (!containerRef.current) return;
if (!containerRef.current.contains(e.relatedTarget as Node)) {
setIsFocused(false);
+23 -16
View File
@@ -19,6 +19,7 @@ interface MenuItemProps {
Icon?: React.ReactNode | IconType;
iconClassName?: string;
children?: React.ReactNode;
siblings?: React.ReactNode;
onClick?: () => void;
setIsDropdownOpen?: (isOpen: boolean) => void;
}
@@ -37,6 +38,7 @@ const MenuItem: React.FC<MenuItemProps> = ({
Icon,
iconClassName,
children,
siblings,
onClick,
setIsDropdownOpen,
}) => {
@@ -123,22 +125,27 @@ const MenuItem: React.FC<MenuItemProps> = ({
}
return (
<button
role={disabled ? 'none' : 'menuitem'}
aria-label={toggled !== undefined ? `${label} - ${toggled ? _('ON') : _('OFF')}` : undefined}
aria-live={toggled === undefined ? 'polite' : 'off'}
tabIndex={disabled ? -1 : 0}
className={clsx(
'hover:bg-base-300 text-base-content flex w-full flex-col items-center justify-center rounded-md p-1 py-[10px]',
disabled && 'btn-disabled text-gray-400',
buttonClass,
)}
title={tooltip ? tooltip : ''}
onClick={handleClick}
disabled={disabled}
>
{buttonContent}
</button>
<div className='flex'>
<button
role={disabled ? 'none' : 'menuitem'}
aria-label={
toggled !== undefined ? `${label} - ${toggled ? _('ON') : _('OFF')}` : undefined
}
aria-live={toggled === undefined ? 'polite' : 'off'}
tabIndex={disabled ? -1 : 0}
className={clsx(
'hover:bg-base-300 text-base-content flex w-full flex-col items-center justify-center rounded-md p-1 py-[10px]',
disabled && 'btn-disabled text-gray-400',
buttonClass,
)}
title={tooltip ? tooltip : ''}
onClick={handleClick}
disabled={disabled}
>
{buttonContent}
</button>
{siblings}
</div>
);
};
@@ -5,7 +5,9 @@ import { useTranslation } from '@/hooks/useTranslation';
interface NumberInputProps {
className?: string;
inputClassName?: string;
label: string;
iconSize?: number;
value: number;
min: number;
max: number;
@@ -16,7 +18,9 @@ interface NumberInputProps {
const NumberInput: React.FC<NumberInputProps> = ({
className,
inputClassName,
label,
iconSize,
value,
onChange,
min,
@@ -70,6 +74,7 @@ const NumberInput: React.FC<NumberInputProps> = ({
return (
<div className={clsx('config-item', className)}>
<span className='text-base-content line-clamp-2'>{label}</span>
{iconSize && <span style={{ minWidth: `${iconSize}px` }} />}
<div className='text-base-content flex items-center gap-2'>
<input
type='text'
@@ -79,14 +84,15 @@ const NumberInput: React.FC<NumberInputProps> = ({
onChange={handleChange}
onBlur={handleOnBlur}
className={clsx(
'input input-ghost settings-content text-base-content w-16 max-w-xs rounded border-0 bg-transparent py-1 pe-3 ps-1 text-right !outline-none',
'input input-ghost settings-content text-base-content w-16 max-w-xs rounded border-0 bg-transparent pe-3 !outline-none',
label && 'py-1 ps-1 text-right',
disabled && 'input-disabled cursor-not-allowed disabled:bg-transparent',
inputClassName,
)}
onFocus={(e) => e.target.select()}
/>
<button
tabIndex={disabled ? -1 : 0}
disabled={value <= min || disabled}
aria-label={_('Decrease')}
onClick={decrement}
className={`btn btn-circle btn-sm ${value <= min || disabled ? 'btn-disabled !bg-opacity-5' : ''}`}
@@ -95,7 +101,6 @@ const NumberInput: React.FC<NumberInputProps> = ({
</button>
<button
tabIndex={disabled ? -1 : 0}
disabled={value >= max || disabled}
aria-label={_('Increase')}
onClick={increment}
className={`btn btn-circle btn-sm ${value >= max || disabled ? 'btn-disabled !bg-opacity-5' : ''}`}
+12 -2
View File
@@ -53,6 +53,7 @@ import {
DEFAULT_TRANSLATOR_CONFIG,
DEFAULT_FIXED_LAYOUT_VIEW_SETTINGS,
SETTINGS_FILENAME,
DEFAULT_MOBILE_SYSTEM_SETTINGS,
} from './constants';
import { fetch as tauriFetch } from '@tauri-apps/plugin-http';
import { getOSPlatform, getTargetLang, isCJKEnv, isContentURI, isValidURL } from '@/utils/misc';
@@ -195,6 +196,7 @@ export abstract class BaseAppService implements AppService {
async loadSettings(): Promise<SystemSettings> {
const defaultSettings: SystemSettings = {
...DEFAULT_SYSTEM_SETTINGS,
...(this.isMobile ? DEFAULT_MOBILE_SYSTEM_SETTINGS : {}),
version: SYSTEM_SETTINGS_VERSION,
localBooksDir: await this.fs.getPrefix('Books'),
koreaderSyncDeviceId: uuidv4(),
@@ -215,8 +217,16 @@ export abstract class BaseAppService implements AppService {
if (this.isAppDataSandbox || version < SYSTEM_SETTINGS_VERSION) {
settings.version = SYSTEM_SETTINGS_VERSION;
}
settings = { ...DEFAULT_SYSTEM_SETTINGS, ...settings };
settings.globalReadSettings = { ...DEFAULT_READSETTINGS, ...settings.globalReadSettings };
settings = {
...DEFAULT_SYSTEM_SETTINGS,
...(this.isMobile ? DEFAULT_MOBILE_SYSTEM_SETTINGS : {}),
...settings,
};
settings.globalReadSettings = {
...DEFAULT_READSETTINGS,
...(this.isMobile ? DEFAULT_MOBILE_READSETTINGS : {}),
...settings.globalReadSettings,
};
settings.globalViewSettings = {
...this.getDefaultViewSettings(),
...settings.globalViewSettings,
@@ -72,6 +72,8 @@ export const DEFAULT_SYSTEM_SETTINGS: Partial<SystemSettings> = {
librarySortBy: 'updated',
librarySortAscending: false,
libraryCoverFit: 'crop',
libraryAutoColumns: true,
libraryColumns: 6,
kosync: DEFAULT_KOSYNC_SETTINGS,
@@ -80,6 +82,10 @@ export const DEFAULT_SYSTEM_SETTINGS: Partial<SystemSettings> = {
lastSyncedAtNotes: 0,
};
export const DEFAULT_MOBILE_SYSTEM_SETTINGS: Partial<SystemSettings> = {
libraryColumns: 3,
};
export const HIGHLIGHT_COLOR_HEX: Record<HighlightColor, string> = {
red: '#f87171', // red-400
yellow: '#facc15', // yellow-400
+2
View File
@@ -63,6 +63,8 @@ export interface SystemSettings {
librarySortBy: LibrarySortByType;
librarySortAscending: boolean;
libraryCoverFit: LibraryCoverFitType;
libraryAutoColumns: boolean;
libraryColumns: number;
customFonts: CustomFont[];
customTextures: CustomTexture[];