Refactoring LibraryPage to separate directory
This commit is contained in:
@@ -1,48 +0,0 @@
|
||||
.libraryContainer {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.viewToggle {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.viewToggle button {
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.viewToggle button.active {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.bookCard {
|
||||
text-align: center;
|
||||
border: 1px solid #eaeaea;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.bookCard img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.bookCard h3 {
|
||||
margin-top: 12px;
|
||||
}
|
||||
+2
-2
@@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { Book, BooksGroup } from '../types/book';
|
||||
import { Book, BooksGroup } from '@/types/book';
|
||||
import { FaPlus } from 'react-icons/fa';
|
||||
|
||||
type BookshelfItem = Book | BooksGroup;
|
||||
@@ -59,7 +59,7 @@ const Bookshelf: React.FC<BookshelfProps> = ({ libraryBooks, onImportBooks }) =>
|
||||
{/* Books Grid */}
|
||||
<div className='grid grid-cols-3 gap-6 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8'>
|
||||
{bookshelfItems.map((item, index) => (
|
||||
<div key={`library-item-${index}`} className='flex h-full flex-col'>
|
||||
<div key={`library-item-${index}`} className='hover:bg-base-200 flex h-full flex-col'>
|
||||
<div className='flex-grow'>
|
||||
{'format' in item ? (
|
||||
<div className='bookItem cursor-pointer' onClick={() => handleBookClick(item.hash)}>
|
||||
@@ -0,0 +1,98 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { useState, useRef } from 'react';
|
||||
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
|
||||
import Spinner from '@/components/Spinner';
|
||||
import SearchBar from '@/app/library/components/SearchBar';
|
||||
import Bookshelf from '@/app/library/components/Bookshelf';
|
||||
|
||||
const LibraryPage = () => {
|
||||
const { envConfig, appService, getAppService } = useEnv();
|
||||
const { library: libraryBooks, setLibrary } = useReaderStore();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const isInitiating = useRef(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isInitiating.current) return;
|
||||
isInitiating.current = true;
|
||||
setLoading(true);
|
||||
getAppService(envConfig).then(async (appService) => {
|
||||
console.log('Loading library books...');
|
||||
setLibrary(await appService.loadLibraryBooks());
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const importBooks = async (files: [string | File]) => {
|
||||
setLoading(true);
|
||||
for (const file of files) {
|
||||
await appService?.importBook(file, libraryBooks);
|
||||
setLibrary(libraryBooks);
|
||||
}
|
||||
appService?.saveLibraryBooks(libraryBooks);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const selectFilesTauri = async () => {
|
||||
return appService?.selectFiles('Select Books', ['epub', 'pdf']);
|
||||
};
|
||||
|
||||
const selectFilesWeb = () => {
|
||||
return new Promise((resolve) => {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.accept = '.epub, .pdf';
|
||||
fileInput.multiple = true;
|
||||
fileInput.click();
|
||||
|
||||
fileInput.onchange = () => {
|
||||
resolve(fileInput.files);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleImportBooks = async () => {
|
||||
console.log('Importing books...');
|
||||
const { type } = await import('@tauri-apps/plugin-os');
|
||||
let files;
|
||||
if (['android', 'ios'].includes(type())) {
|
||||
files = (await selectFilesWeb()) as [File];
|
||||
} else {
|
||||
files = (await selectFilesTauri()) as [string];
|
||||
}
|
||||
importBooks(files);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='min-h-screen bg-gray-100'>
|
||||
<SearchBar onImportBooks={handleImportBooks} />
|
||||
<div className='min-h-screen p-2 pt-16'>
|
||||
<div className='hero-content'>
|
||||
<Spinner loading={loading} />
|
||||
<Bookshelf libraryBooks={libraryBooks} onImportBooks={handleImportBooks} />
|
||||
</div>
|
||||
{!loading && libraryBooks.length === 0 && (
|
||||
<div className='hero min-h-screen'>
|
||||
<div className='hero-content text-neutral-content text-center'>
|
||||
<div className='max-w-md'>
|
||||
<h1 className='mb-5 text-5xl font-bold'>Your Library</h1>
|
||||
<p className='mb-5'>
|
||||
Welcome to your library. You can upload your books here and read them anytime.
|
||||
</p>
|
||||
<button className='btn btn-primary' onClick={handleImportBooks}>
|
||||
Upload Books
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LibraryPage;
|
||||
@@ -1,98 +1,18 @@
|
||||
'use client';
|
||||
|
||||
import * as React from 'react';
|
||||
import { useState, useRef } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
|
||||
import SearchBar from '@/components/SearchBar';
|
||||
import Spinner from '@/components/Spinner';
|
||||
import Bookshelf from '@/components/Bookshelf';
|
||||
|
||||
const LibraryPage = () => {
|
||||
const { envConfig, appService, getAppService } = useEnv();
|
||||
const { library: libraryBooks, setLibrary } = useReaderStore();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const isInitiating = useRef(false);
|
||||
const HomePage = () => {
|
||||
const router = useRouter();
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isInitiating.current) return;
|
||||
isInitiating.current = true;
|
||||
setLoading(true);
|
||||
getAppService(envConfig).then(async (appService) => {
|
||||
console.log('Loading library books...');
|
||||
setLibrary(await appService.loadLibraryBooks());
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
router.push('/library');
|
||||
}, [router]);
|
||||
|
||||
const importBooks = async (files: [string | File]) => {
|
||||
setLoading(true);
|
||||
for (const file of files) {
|
||||
await appService?.importBook(file, libraryBooks);
|
||||
setLibrary(libraryBooks);
|
||||
}
|
||||
appService?.saveLibraryBooks(libraryBooks);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const selectFilesTauri = async () => {
|
||||
return appService?.selectFiles('Select Books', ['epub', 'pdf']);
|
||||
};
|
||||
|
||||
const selectFilesWeb = () => {
|
||||
return new Promise((resolve) => {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.accept = '.epub, .pdf';
|
||||
fileInput.multiple = true;
|
||||
fileInput.click();
|
||||
|
||||
fileInput.onchange = () => {
|
||||
resolve(fileInput.files);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleImportBooks = async () => {
|
||||
console.log('Importing books...');
|
||||
const { type } = await import('@tauri-apps/plugin-os');
|
||||
let files;
|
||||
if (['android', 'ios'].includes(type())) {
|
||||
files = (await selectFilesWeb()) as [File];
|
||||
} else {
|
||||
files = (await selectFilesTauri()) as [string];
|
||||
}
|
||||
importBooks(files);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='min-h-screen bg-gray-100'>
|
||||
<SearchBar onImportBooks={handleImportBooks} />
|
||||
<div className='min-h-screen p-2 pt-16'>
|
||||
<div className='hero-content'>
|
||||
<Spinner loading={loading} />
|
||||
<Bookshelf libraryBooks={libraryBooks} onImportBooks={handleImportBooks} />
|
||||
</div>
|
||||
{!loading && libraryBooks.length === 0 && (
|
||||
<div className='hero min-h-screen'>
|
||||
<div className='hero-content text-neutral-content text-center'>
|
||||
<div className='max-w-md'>
|
||||
<h1 className='mb-5 text-5xl font-bold'>Your Library</h1>
|
||||
<p className='mb-5'>
|
||||
Welcome to your library. You can upload your books here and read them anytime.
|
||||
</p>
|
||||
<button className='btn btn-primary' onClick={handleImportBooks}>
|
||||
Upload Books
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
return <Spinner loading={true} />;
|
||||
};
|
||||
|
||||
export default LibraryPage;
|
||||
export default HomePage;
|
||||
|
||||
Reference in New Issue
Block a user