Initial commit
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
<script lang="ts">
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import { Circle, Pencil, EllipsisVertical } from '@lucide/svelte';
|
||||
|
||||
import type { Book } from '$lib/schema';
|
||||
import BookThumbnail from './book-thumbnail.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { getBookSelectionState } from '$lib/state/bookSelection.svelte';
|
||||
import { getBookOperationsState } from '$lib/state/bookOperations.svelte';
|
||||
import { getLibraryState } from '$lib/state/library.svelte';
|
||||
import { getBookshelfState } from '$lib/state/bookshelf.svelte';
|
||||
|
||||
let { books }: { books: Book[] } = $props();
|
||||
|
||||
const libraryState = getLibraryState();
|
||||
const selectedState = getBookSelectionState();
|
||||
const bookOps = getBookOperationsState();
|
||||
const bookshelfState = getBookshelfState();
|
||||
</script>
|
||||
|
||||
<div class="grid grid-cols-[repeat(auto-fill,minmax(160px,1fr))] gap-4 p-2">
|
||||
{#each books as book (book.id)}
|
||||
<div class="group relative">
|
||||
<div
|
||||
class="absolute top-2 right-2 z-50 {selectedState.isSelected(book.id)
|
||||
? 'opacity-100'
|
||||
: 'opacity-0'} transition-opacity group-hover:opacity-100"
|
||||
>
|
||||
<Circle
|
||||
onclick={() => {
|
||||
selectedState.toggleSelection(book);
|
||||
}}
|
||||
class="{selectedState.isSelected(book.id)
|
||||
? 'scale-110 text-yellow-300'
|
||||
: 'scale-75 text-white'} transition-all hover:scale-110 hover:cursor-pointer hover:text-yellow-300"
|
||||
/>
|
||||
</div>
|
||||
{#if selectedState.isSelected(book.id)}
|
||||
<div
|
||||
class="absolute top-2 right-2 z-40 {selectedState.isSelected(book.id)
|
||||
? 'opacity-100'
|
||||
: 'opacity-0'} transition-opacity group-hover:opacity-100"
|
||||
>
|
||||
<Circle
|
||||
class="yellow-300 scale-50 fill-yellow-300 text-yellow-300 transition-all hover:scale-75 hover:cursor-pointer hover:text-yellow-300"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<BookThumbnail {book} />
|
||||
{#if !selectedState.selectionModeActive}
|
||||
<div
|
||||
class="absolute bottom-20 left-1 z-50 inline-flex items-center opacity-0 transition-opacity group-hover:opacity-100"
|
||||
>
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger>
|
||||
<EllipsisVertical
|
||||
class="scale-75 text-white transition-all hover:scale-110 hover:cursor-pointer hover:text-yellow-300"
|
||||
/>
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Content>
|
||||
<DropdownMenu.Group>
|
||||
<DropdownMenu.Item
|
||||
onclick={async () => {
|
||||
if (!book.progress?.completed) await bookOps.markBooksAsComplete([book.id]);
|
||||
else await bookOps.markBooksAsIncomplete([book.id]);
|
||||
}}
|
||||
>{!book?.progress?.completed
|
||||
? 'Mark as finished'
|
||||
: 'Mark as unfinished'}</DropdownMenu.Item
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
onclick={() => {
|
||||
bookOps.deleteDialogTitle = `Delete "${book.title}"?`;
|
||||
bookOps.deleteFn = async (deleteFiles: boolean) => {
|
||||
await bookOps.deleteBooks([book.id], deleteFiles);
|
||||
libraryState.activeLibrary!.total!--
|
||||
bookshelfState.deletedBooks([book])
|
||||
};
|
||||
bookOps.deleteDialogOpen = true;
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Group>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Root>
|
||||
</div>
|
||||
<div
|
||||
class="absolute right-2 bottom-20 z-50 inline-flex items-center opacity-0 transition-opacity group-hover:opacity-100"
|
||||
>
|
||||
<Pencil
|
||||
class="scale-75 text-white transition-all hover:scale-110 hover:cursor-pointer hover:text-yellow-300"
|
||||
onclick={() => {
|
||||
bookOps.bookToEdit = book;
|
||||
bookOps.editDialogOpen = true;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
Reference in New Issue
Block a user