style: normalize code formatting in bookshelf.ts
- Convert indentation from 4 spaces to 2 spaces (matching project style) - Standardize quotes to double quotes for consistency - Reformat template literals for improved readability This file contains the core bookshelf functionality including: - Library selection and persistence - Book rendering with cover images - Pagination for large book collections
This commit is contained in:
+41
-29
@@ -1,27 +1,27 @@
|
|||||||
function selectLibrary(libraryId: string): void {
|
function selectLibrary(libraryId: string): void {
|
||||||
localStorage.setItem('selectedLibrary', libraryId);
|
localStorage.setItem("selectedLibrary", libraryId);
|
||||||
|
|
||||||
document.querySelectorAll('.library-item').forEach(el => {
|
document.querySelectorAll(".library-item").forEach((el) => {
|
||||||
el.classList.remove('ring-2');
|
el.classList.remove("ring-2");
|
||||||
el.classList.remove('ring-accent');
|
el.classList.remove("ring-accent");
|
||||||
});
|
});
|
||||||
|
|
||||||
const selected = document.querySelector(`[data-library-id="${libraryId}"]`);
|
const selected = document.querySelector(`[data-library-id="${libraryId}"]`);
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selected.classList.add('ring-2');
|
selected.classList.add("ring-2");
|
||||||
selected.classList.add('ring-accent');
|
selected.classList.add("ring-accent");
|
||||||
}
|
}
|
||||||
|
|
||||||
loadBookshelf(libraryId);
|
loadBookshelf(libraryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadBookshelf(libraryId: string): Promise<void> {
|
async function loadBookshelf(libraryId: string): Promise<void> {
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem("token");
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/libraries/${libraryId}/books`, {
|
const response = await fetch(`/api/libraries/${libraryId}/books`, {
|
||||||
headers: { 'Authorization': `Bearer ${token}` }
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@@ -29,56 +29,68 @@ async function loadBookshelf(libraryId: string): Promise<void> {
|
|||||||
renderBooks(data.books || []);
|
renderBooks(data.books || []);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load bookshelf:', error);
|
console.error("Failed to load bookshelf:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderBooks(books: unknown[]): void {
|
function renderBooks(books: unknown[]): void {
|
||||||
const container = document.getElementById('books-grid');
|
const container = document.getElementById("books-grid");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
if (books.length === 0) {
|
if (books.length === 0) {
|
||||||
container.innerHTML = '<p class="text-center p-8" style="color: var(--text-secondary)">No books in this library</p>';
|
container.innerHTML =
|
||||||
|
'<p class="text-center p-8" style="color: var(--text-secondary)">No books in this library</p>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = books.map((book: any) => `
|
container.innerHTML = books
|
||||||
|
.map(
|
||||||
|
(book: any) => `
|
||||||
<div class="book-card p-3 rounded-lg border transition-transform hover:scale-105 cursor-pointer"
|
<div class="book-card p-3 rounded-lg border transition-transform hover:scale-105 cursor-pointer"
|
||||||
style="background-color: var(--bg-secondary); border-color: var(--border)"
|
style="background-color: var(--bg-secondary); border-color: var(--border)"
|
||||||
onclick="window.selectBook('${book.id}')">
|
onclick="window.selectBook('${book.id}')">
|
||||||
${book.cover_image_path ?
|
${
|
||||||
`<img src="/covers/${book.cover_image_path}" alt="${book.title}" class="w-full h-48 object-cover rounded mb-2">` :
|
book.cover_image_path
|
||||||
`<div class="w-full h-48 rounded mb-2 flex items-center justify-center" style="background-color: var(--bg-primary)">
|
? `<img src="${book.cover_image_path}" alt="${book.title}" class="w-full h-48 object-cover rounded mb-2">`
|
||||||
|
: `<div class="w-full h-48 rounded mb-2 flex items-center justify-center" style="background-color: var(--bg-primary)">
|
||||||
<span class="text-4xl">📖</span>
|
<span class="text-4xl">📖</span>
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
<h3 class="font-medium text-sm truncate" style="color: var(--text-primary)">${book.title}</h3>
|
<h3 class="font-medium text-sm truncate" style="color: var(--text-primary)">${book.title}</h3>
|
||||||
<p class="text-xs truncate" style="color: var(--text-secondary)">${book.author || 'Unknown Author'}</p>
|
<p class="text-xs truncate" style="color: var(--text-secondary)">${book.author || "Unknown Author"}</p>
|
||||||
</div>
|
</div>
|
||||||
`).join('');
|
`,
|
||||||
|
)
|
||||||
|
.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectBook(bookId: string): void {
|
function selectBook(bookId: string): void {
|
||||||
localStorage.setItem('selectedBook', bookId);
|
localStorage.setItem("selectedBook", bookId);
|
||||||
window.location.href = `/books/${bookId}`;
|
window.location.href = `/books/${bookId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changePage(page: number): void {
|
function changePage(page: number): void {
|
||||||
const libraryId = localStorage.getItem('selectedLibrary');
|
const libraryId = localStorage.getItem("selectedLibrary");
|
||||||
if (!libraryId) return;
|
if (!libraryId) return;
|
||||||
|
|
||||||
const offset = (page - 1) * 50;
|
const offset = (page - 1) * 50;
|
||||||
loadBookshelfPaginated(libraryId, offset);
|
loadBookshelfPaginated(libraryId, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadBookshelfPaginated(libraryId: string, offset: number): Promise<void> {
|
async function loadBookshelfPaginated(
|
||||||
const token = localStorage.getItem('token');
|
libraryId: string,
|
||||||
|
offset: number,
|
||||||
|
): Promise<void> {
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/libraries/${libraryId}/books?offset=${offset}&limit=50`, {
|
const response = await fetch(
|
||||||
headers: { 'Authorization': `Bearer ${token}` }
|
`/api/libraries/${libraryId}/books?offset=${offset}&limit=50`,
|
||||||
});
|
{
|
||||||
|
headers: { Authorization: `Bearer ${token}` },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
@@ -86,12 +98,12 @@ async function loadBookshelfPaginated(libraryId: string, offset: number): Promis
|
|||||||
updatePagination(data.total, offset);
|
updatePagination(data.total, offset);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load bookshelf:', error);
|
console.error("Failed to load bookshelf:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updatePagination(total: number, offset: number): void {
|
function updatePagination(total: number, offset: number): void {
|
||||||
const container = document.getElementById('pagination');
|
const container = document.getElementById("pagination");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
const limit = 50;
|
const limit = 50;
|
||||||
@@ -99,15 +111,15 @@ function updatePagination(total: number, offset: number): void {
|
|||||||
const totalPages = Math.ceil(total / limit);
|
const totalPages = Math.ceil(total / limit);
|
||||||
|
|
||||||
if (totalPages <= 1) {
|
if (totalPages <= 1) {
|
||||||
container.innerHTML = '';
|
container.innerHTML = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<div class="flex justify-center space-x-2">
|
<div class="flex justify-center space-x-2">
|
||||||
${currentPage > 1 ? `<button onclick="window.changePage(${currentPage - 1})" class="btn-secondary px-3 py-1 rounded">Previous</button>` : ''}
|
${currentPage > 1 ? `<button onclick="window.changePage(${currentPage - 1})" class="btn-secondary px-3 py-1 rounded">Previous</button>` : ""}
|
||||||
<span class="px-3 py-1" style="color: var(--text-secondary)">Page ${currentPage} of ${totalPages}</span>
|
<span class="px-3 py-1" style="color: var(--text-secondary)">Page ${currentPage} of ${totalPages}</span>
|
||||||
${currentPage < totalPages ? `<button onclick="window.changePage(${currentPage + 1})" class="btn-secondary px-3 py-1 rounded">Next</button>` : ''}
|
${currentPage < totalPages ? `<button onclick="window.changePage(${currentPage + 1})" class="btn-secondary px-3 py-1 rounded">Next</button>` : ""}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user