Initial commit
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { get } from 'svelte/store';
|
||||
import ndk from '$lib/stores/ndk';
|
||||
import { parseDriveEvent, getBlobUrl, fileName, type BlossomFile } from '$lib/blossom';
|
||||
import type { NDKFilter } from '@nostr-dev-kit/ndk';
|
||||
import PdfCover from './PdfCover.svelte';
|
||||
|
||||
export let pubkey: string;
|
||||
export let driveId: string;
|
||||
|
||||
let driveName = '';
|
||||
let description = '';
|
||||
let files: BlossomFile[] = [];
|
||||
let servers: string[] = [];
|
||||
let loading = true;
|
||||
let error = '';
|
||||
let activePdf: string | null = null;
|
||||
|
||||
onMount(() => {
|
||||
const $ndk = get(ndk);
|
||||
|
||||
const filter: NDKFilter = {
|
||||
kinds: [30563 as number],
|
||||
authors: [pubkey],
|
||||
'#d': [driveId]
|
||||
};
|
||||
|
||||
$ndk
|
||||
.fetchEvent(filter)
|
||||
.then((event) => {
|
||||
if (!event) {
|
||||
error = 'Drive not found.';
|
||||
return;
|
||||
}
|
||||
|
||||
const drive = parseDriveEvent(event);
|
||||
driveName = drive.name;
|
||||
description = drive.description;
|
||||
servers = drive.servers;
|
||||
files = drive.files.filter(
|
||||
(f) => f.mimeType === 'application/pdf' || f.path.endsWith('.pdf')
|
||||
);
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
error = e instanceof Error ? e.message : String(e);
|
||||
})
|
||||
.finally(() => {
|
||||
loading = false;
|
||||
});
|
||||
});
|
||||
|
||||
function openPdf(file: BlossomFile) {
|
||||
activePdf = getBlobUrl(file.sha256, servers, '.pdf');
|
||||
}
|
||||
|
||||
function closePdf() {
|
||||
activePdf = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if loading}
|
||||
<p class="animate-pulse text-sm text-gray-500">Loading drive…</p>
|
||||
{:else if error}
|
||||
<p class="text-sm font-medium text-red-600">Error: {error}</p>
|
||||
{:else}
|
||||
<div class="grid grid-cols-2 gap-6 sm:grid-cols-3 md:grid-cols-4">
|
||||
{#each files as file (file.sha256)}
|
||||
{@const blobUrl = getBlobUrl(file.sha256, servers, '.pdf')}
|
||||
{@const name = fileName(file.path)}
|
||||
|
||||
<div class="group flex flex-col gap-2">
|
||||
<!-- Cover — clicking opens the viewer -->
|
||||
<button
|
||||
on:click={() => openPdf(file)}
|
||||
class="block w-full overflow-hidden rounded-lg shadow-md ring-2 ring-transparent transition-all duration-200 group-hover:-translate-y-1 group-hover:shadow-xl group-hover:ring-indigo-400"
|
||||
aria-label="Read {name}"
|
||||
>
|
||||
<PdfCover url={blobUrl} alt={name} />
|
||||
</button>
|
||||
|
||||
<!-- Title -->
|
||||
<p
|
||||
class="truncate px-1 text-center text-xs leading-tight font-medium text-gray-700 transition-colors group-hover:text-indigo-600"
|
||||
title={name}
|
||||
>
|
||||
{name.replace(/\.pdf$/i, '')}
|
||||
</p>
|
||||
|
||||
<!-- Download link -->
|
||||
<a
|
||||
href={blobUrl}
|
||||
download={name}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="text-center text-xs text-gray-400 transition-colors hover:text-indigo-500"
|
||||
>
|
||||
⬇ Download
|
||||
</a>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- PDF Viewer Modal -->
|
||||
{#if activePdf}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-sm"
|
||||
on:click={closePdf}
|
||||
>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="relative flex w-[90vw] max-w-4xl flex-col rounded-xl bg-white p-4 shadow-2xl"
|
||||
on:click|stopPropagation
|
||||
>
|
||||
<!-- Modal header -->
|
||||
<div class="mb-3 flex items-center justify-between">
|
||||
<span class="text-sm font-medium text-gray-700">Fanzine Viewer</span>
|
||||
<button
|
||||
on:click={closePdf}
|
||||
class="text-xl leading-none text-gray-400 transition-colors hover:text-gray-700"
|
||||
aria-label="Close"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- PDF iframe -->
|
||||
<iframe
|
||||
src={activePdf}
|
||||
title="Fanzine PDF"
|
||||
class="w-full rounded border border-gray-200"
|
||||
style="height: 80vh;"
|
||||
></iframe>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
Reference in New Issue
Block a user