113 lines
3.1 KiB
Svelte
113 lines
3.1 KiB
Svelte
<script lang="ts">
|
|
import type { Snippet } from 'svelte';
|
|
import type { PdfThumbnail } from '$lib/pdf-thumbnails';
|
|
import { cn } from '$lib/utils';
|
|
|
|
type Props = {
|
|
thumbnails: PdfThumbnail[];
|
|
selectedPages?: Set<number>;
|
|
onPageClick?: (pageNumber: number) => void;
|
|
thumbnailWidth?: number;
|
|
class?: string;
|
|
pageActions?: Snippet<[pageNumber: number]>;
|
|
cardClass?: (pageNumber: number) => string;
|
|
};
|
|
|
|
let {
|
|
thumbnails,
|
|
selectedPages = new Set<number>(),
|
|
onPageClick,
|
|
thumbnailWidth = 120,
|
|
class: className = '',
|
|
pageActions,
|
|
cardClass
|
|
}: Props = $props();
|
|
</script>
|
|
|
|
<div
|
|
class={cn('grid gap-3', className)}
|
|
style="grid-template-columns: repeat(auto-fill, minmax({thumbnailWidth}px, 1fr));"
|
|
>
|
|
{#each thumbnails as thumb}
|
|
{@const isSelected = selectedPages.has(thumb.pageNumber)}
|
|
{#if onPageClick}
|
|
<button
|
|
type="button"
|
|
class={cn(
|
|
'group relative flex flex-col items-center gap-2 rounded-xl border-2 p-2 transition focus:outline-none focus-visible:ring-2 focus-visible:ring-primary-400',
|
|
isSelected
|
|
? 'border-primary bg-primary/5'
|
|
: 'border-transparent hover:border-primary-200 hover:bg-primary-50/50'
|
|
)}
|
|
onclick={() => onPageClick(thumb.pageNumber)}
|
|
>
|
|
{#if cardClass}
|
|
<div
|
|
class={cn(
|
|
'flex aspect-square w-full items-center justify-center',
|
|
cardClass(thumb.pageNumber)
|
|
)}
|
|
>
|
|
<img
|
|
src={thumb.imageUrl}
|
|
alt="Seite {thumb.pageNumber}"
|
|
class="max-h-full max-w-full rounded border border-primary-100 bg-white object-contain"
|
|
/>
|
|
</div>
|
|
{:else}
|
|
<img
|
|
src={thumb.imageUrl}
|
|
alt="Seite {thumb.pageNumber}"
|
|
class="w-full rounded border border-primary-100 bg-white object-contain"
|
|
style="aspect-ratio: {thumb.width} / {thumb.height};"
|
|
/>
|
|
{/if}
|
|
<span class="text-[12px] font-medium text-primary-700">Seite {thumb.pageNumber}</span>
|
|
{#if isSelected}
|
|
<div
|
|
class="absolute top-1 right-1 flex h-5 w-5 items-center justify-center rounded-full bg-primary text-[10px] font-bold text-white"
|
|
>
|
|
✓
|
|
</div>
|
|
{/if}
|
|
{#if pageActions}
|
|
{@render pageActions(thumb.pageNumber)}
|
|
{/if}
|
|
</button>
|
|
{:else}
|
|
<div
|
|
class={cn(
|
|
'group relative flex flex-col items-center gap-2 rounded-xl border-2 border-transparent p-2',
|
|
isSelected && 'border-primary bg-primary/5'
|
|
)}
|
|
>
|
|
{#if cardClass}
|
|
<div
|
|
class={cn(
|
|
'flex aspect-square w-full items-center justify-center',
|
|
cardClass(thumb.pageNumber)
|
|
)}
|
|
>
|
|
<img
|
|
src={thumb.imageUrl}
|
|
alt="Seite {thumb.pageNumber}"
|
|
class="max-h-full max-w-full rounded border border-primary-100 bg-white object-contain"
|
|
/>
|
|
</div>
|
|
{:else}
|
|
<img
|
|
src={thumb.imageUrl}
|
|
alt="Seite {thumb.pageNumber}"
|
|
class="w-full rounded border border-primary-100 bg-white object-contain"
|
|
style="aspect-ratio: {thumb.width} / {thumb.height};"
|
|
/>
|
|
{/if}
|
|
<span class="text-[12px] font-medium text-primary-700">Seite {thumb.pageNumber}</span>
|
|
{#if pageActions}
|
|
{@render pageActions(thumb.pageNumber)}
|
|
{/if}
|
|
</div>
|
|
{/if}
|
|
{/each}
|
|
</div>
|