Browse Source

publication, wiki, and universal event viewer implemented. still buggy

master
Silberengel 10 months ago
parent
commit
7dd411c43f
  1. 10
      src/lib/components/util/InlineProfile.svelte
  2. 11
      src/lib/wiki.ts
  3. 124
      src/routes/events/+page.svelte
  4. 32
      src/routes/wiki/+page.svelte

10
src/lib/components/util/InlineProfile.svelte

@ -3,7 +3,7 @@
import { type NDKUserProfile } from "@nostr-dev-kit/ndk"; import { type NDKUserProfile } from "@nostr-dev-kit/ndk";
import { ndkInstance } from '$lib/ndk'; import { ndkInstance } from '$lib/ndk';
let { pubkey, title = null } = $props(); let { pubkey, name = null } = $props();
const externalProfileDestination = './events?id=' const externalProfileDestination = './events?id='
let loading = $state(true); let loading = $state(true);
@ -43,11 +43,11 @@
</script> </script>
{#if loading} {#if loading}
{title ?? '…'} {name ?? '…'}
{:else if anon } {:else if anon }
<a class='underline' href={'/events?id=' + npub} title={title ?? npub}>{shortenNpub(npub)}</a> <a class='underline' href={'/events?id=' + npub} title={name ?? npub}>{shortenNpub(npub)}</a>
{:else if npub } {:else if npub }
<a href={'/events?id=' + npub} title={title ?? username}> <a href={'/events?id=' + npub} title={name ?? username}>
<Avatar rounded <Avatar rounded
class='h-6 w-6 mx-1 cursor-pointer inline' class='h-6 w-6 mx-1 cursor-pointer inline'
src={pfp} src={pfp}
@ -55,5 +55,5 @@
<span class='underline'>{username ?? shortenNpub(npub)}</span> <span class='underline'>{username ?? shortenNpub(npub)}</span>
</a> </a>
{:else} {:else}
{title ?? pubkey} {name ?? pubkey}
{/if} {/if}

11
src/lib/wiki.ts

@ -132,18 +132,21 @@ export async function getWikiPageById(id: string, ndk: NDK) {
let html = ''; let html = '';
try { try {
const pharos = new Pharos(ndk); const pharos = new Pharos(ndk);
console.log('Pharos instance:', pharos);
pharos.parse(asciidoc); pharos.parse(asciidoc);
const pharosHtml = pharos.getHtml(); const pharosHtml = pharos.getHtml();
html = await parseBasicmarkup(pharosHtml); console.log('AsciiDoc:', asciidoc);
if (!html) { console.log('Pharos HTML:', pharosHtml);
console.error('getWikiPageById: Parsed HTML is empty for id:', id, 'event:', event); html = await parseBasicmarkup(pharosHtml ?? '');
if (!html || html.trim() === '') {
console.error('getWikiPageById: Parsed HTML is empty for id:', id, 'event:', event, 'asciidoc:', asciidoc, 'pharosHtml:', pharosHtml);
} }
} catch (err) { } catch (err) {
console.error('getWikiPageById: Error parsing content:', err, 'event:', event); console.error('getWikiPageById: Error parsing content:', err, 'event:', event);
return null; return null;
} }
return { title, pubhex, eventId: event.id, summary, hashtags, html }; return { title, pubhex, eventId: event.id, summary, hashtags, html, content: event.content };
} }
/** /**

124
src/routes/events/+page.svelte

@ -78,6 +78,9 @@
error = 'Event not found'; error = 'Event not found';
} else { } else {
console.log('[Events] Event found:', event); console.log('[Events] Event found:', event);
if (typeof event.getMatchingTags !== 'function') {
event = new NDKEvent(event.ndk || $ndkInstance, event);
}
} }
} catch (err) { } catch (err) {
console.error('[Events] Error fetching event:', err, 'Query:', searchQuery); console.error('[Events] Error fetching event:', err, 'Query:', searchQuery);
@ -190,8 +193,7 @@
} }
}); });
$: if (event && event.kind !== 0) { $: if (event && event.kind !== 0 && event.content) {
// Only parse for non-profile events
parseBasicmarkup(event.content).then(html => { parseBasicmarkup(event.content).then(html => {
parsedContent = html; parsedContent = html;
contentPreview = html.slice(0, 250); contentPreview = html.slice(0, 250);
@ -201,6 +203,10 @@
$: profile = event && event.kind === 0 $: profile = event && event.kind === 0
? (() => { try { return JSON.parse(event.content); } catch { return null; } })() ? (() => { try { return JSON.parse(event.content); } catch { return null; } })()
: null; : null;
$: profileTitle = event && event.kind === 0 && profile && profile.name
? profile.name
: null;
</script> </script>
<div class="w-full flex justify-center"> <div class="w-full flex justify-center">
@ -242,7 +248,7 @@
</div> </div>
{/if} {/if}
{#if event} {#if event && typeof event.getMatchingTags === 'function'}
<div class="flex flex-col space-y-6"> <div class="flex flex-col space-y-6">
<!-- Event Identifier (plain text, not a link) --> <!-- Event Identifier (plain text, not a link) -->
<div class="text-sm font-mono text-gray-600 dark:text-gray-400 break-all"> <div class="text-sm font-mono text-gray-600 dark:text-gray-400 break-all">
@ -251,7 +257,11 @@
<!-- Event Details --> <!-- Event Details -->
<div class="flex flex-col space-y-4"> <div class="flex flex-col space-y-4">
<h2 class="text-2xl font-bold text-gray-900 dark:text-gray-100">{getEventTitle(event)}</h2> {#if event.kind !== 0 && getEventTitle(event)}
<h2 class="text-2xl font-bold text-gray-900 dark:text-gray-100">{getEventTitle(event)}</h2>
{:else if event.kind === 0 && profile && profile.name}
<h2 class="text-2xl font-bold text-gray-900 dark:text-gray-100">{profile.name}</h2>
{/if}
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<span class="text-gray-600 dark:text-gray-400">Author:</span> <span class="text-gray-600 dark:text-gray-400">Author:</span>
<InlineProfile pubkey={event.pubkey} /> <InlineProfile pubkey={event.pubkey} />
@ -283,45 +293,63 @@
<span class="text-gray-600 dark:text-gray-400">Content:</span> <span class="text-gray-600 dark:text-gray-400">Content:</span>
{#if event.kind === 0} {#if event.kind === 0}
{#if profile} {#if profile}
<div class="flex flex-col gap-2 mt-2"> <div class="bg-primary-50 dark:bg-primary-900 rounded-lg p-6 mt-2 shadow flex flex-col gap-4">
{#if profile.name} <dl class="grid grid-cols-1 gap-y-2">
<div><span class="font-semibold">Name:</span> {profile.name}</div> {#if profile.name}
{/if} <div class="flex gap-2">
{#if profile.display_name} <dt class="font-semibold min-w-[120px]">Name:</dt>
<div><span class="font-semibold">Display Name:</span> {profile.display_name}</div> <dd>{profile.name}</dd>
{/if} </div>
{#if profile.about} {/if}
<div><span class="font-semibold">About:</span> {profile.about}</div> {#if profile.display_name}
{/if} <div class="flex gap-2">
{#if profile.picture} <dt class="font-semibold min-w-[120px]">Display Name:</dt>
<div class="flex items-center gap-2"> <dd>{profile.display_name}</dd>
<span class="font-semibold">Picture:</span> </div>
<img src={profile.picture} alt="Profile" class="w-16 h-16 rounded-full border" /> {/if}
</div> {#if profile.about}
{/if} <div class="flex gap-2">
{#if profile.banner} <dt class="font-semibold min-w-[120px]">About:</dt>
<div class="flex items-center gap-2"> <dd class="whitespace-pre-line">{profile.about}</dd>
<span class="font-semibold">Banner:</span> </div>
<img src={profile.banner} alt="Banner" class="w-full max-w-xs rounded border" /> {/if}
</div> {#if profile.picture}
{/if} <div class="flex gap-2 items-center">
{#if profile.website} <dt class="font-semibold min-w-[120px]">Picture:</dt>
<div> <dd>
<span class="font-semibold">Website:</span> <img src={profile.picture} alt="Profile" class="w-16 h-16 rounded-full border" />
<a href={profile.website} target="_blank" class="underline text-primary-700">{profile.website}</a> </dd>
</div> </div>
{/if} {/if}
{#if profile.lud16} {#if profile.banner}
<div> <div class="flex gap-2 items-center">
<span class="font-semibold">Lightning Address:</span> {profile.lud16} <dt class="font-semibold min-w-[120px]">Banner:</dt>
</div> <dd>
{/if} <img src={profile.banner} alt="Banner" class="w-full max-w-xs rounded border" />
{#if profile.nip05} </dd>
<div> </div>
<span class="font-semibold">NIP-05:</span> {profile.nip05} {/if}
</div> {#if profile.website}
{/if} <div class="flex gap-2">
<!-- Add more fields as needed --> <dt class="font-semibold min-w-[120px]">Website:</dt>
<dd>
<a href={profile.website} target="_blank" class="underline text-primary-700">{profile.website}</a>
</dd>
</div>
{/if}
{#if profile.lud16}
<div class="flex gap-2">
<dt class="font-semibold min-w-[120px]">Lightning Address:</dt>
<dd>{profile.lud16}</dd>
</div>
{/if}
{#if profile.nip05}
<div class="flex gap-2">
<dt class="font-semibold min-w-[120px]">NIP-05:</dt>
<dd>{profile.nip05}</dd>
</div>
{/if}
</dl>
</div> </div>
{:else} {:else}
<pre class="overflow-x-auto text-xs bg-highlight dark:bg-primary-900 rounded p-2 mt-2">{event.content}</pre> <pre class="overflow-x-auto text-xs bg-highlight dark:bg-primary-900 rounded p-2 mt-2">{event.content}</pre>
@ -362,6 +390,16 @@
</details> </details>
</div> </div>
</div> </div>
{#if !getEventTitle(event) && !event.content}
<div class="p-4 text-gray-500">
No title or content available for this event.
<pre class="text-xs mt-2 bg-gray-100 dark:bg-gray-800 p-2 rounded">
{JSON.stringify(event.rawEvent(), null, 2)}
</pre>
</div>
{/if}
{:else if event}
<div class="text-red-600">Fetched event is not a valid NDKEvent. See console for details.</div>
{/if} {/if}
</main> </main>
</div> </div>

32
src/routes/wiki/+page.svelte

@ -10,7 +10,8 @@
import { neventEncode } from '$lib/utils'; import { neventEncode } from '$lib/utils';
import { processNostrIdentifiers } from '$lib/utils/nostrUtils'; import { processNostrIdentifiers } from '$lib/utils/nostrUtils';
import { standardRelays, wikiKind } from '$lib/consts'; import { standardRelays, wikiKind } from '$lib/consts';
import Pharos from '$lib/parser';
import { parseBasicmarkup } from '$lib/utils/markup/basicMarkupParser';
// @ts-ignore Svelte linter false positive: hashtags is used in the template // @ts-ignore Svelte linter false positive: hashtags is used in the template
let { } = $props<{ let { } = $props<{
title: string; title: string;
@ -28,6 +29,7 @@
summary: string; summary: string;
hashtags: string[]; hashtags: string[];
html: string; html: string;
content: string;
}; };
let searchInput = $state(''); let searchInput = $state('');
@ -124,6 +126,7 @@
summary: pageData.summary, summary: pageData.summary,
hashtags: pageData.hashtags, hashtags: pageData.hashtags,
html: processedHtml, html: processedHtml,
content: pageData.content,
}; };
wikiContent = { wikiContent = {
title: pageData.title, title: pageData.title,
@ -205,6 +208,22 @@
wikiPage = null; wikiPage = null;
} }
}); });
(async () => {
let html = '';
try {
const pharos = new Pharos($ndkInstance);
pharos.parse('= Test\n\nHello world');
const pharosHtml = pharos.getHtml();
if (!pharosHtml || pharosHtml.trim() === '') {
console.error('Pharos failed to parse AsciiDoc:', '= Test\n\nHello world');
}
html = await parseBasicmarkup(pharosHtml ?? '');
console.log('Test parse result:', html);
} catch (err) {
console.error('Pharos parse error:', err);
}
})();
</script> </script>
<div class="flex flex-col items-center min-h-[60vh] pt-8"> <div class="flex flex-col items-center min-h-[60vh] pt-8">
@ -258,14 +277,15 @@
{/if} {/if}
<div class="w-full prose prose-lg dark:prose-invert max-w-none"> <div class="w-full prose prose-lg dark:prose-invert max-w-none">
{#if wikiPage.html && wikiPage.html.trim().length > 0} {#if wikiPage.html && wikiPage.html.trim().length > 0}
{#if event && typeof event.getMatchingTags === 'function'} {@html wikiPage.html}
{@html wikiPage.html}
{:else if event}
<div class="text-red-600">Fetched event is not a valid NDKEvent. See console for details.</div>
{/if}
{:else} {:else}
<div class="text-red-600"> <div class="text-red-600">
No content found for this wiki page. No content found for this wiki page.
{#if wikiPage.content}
<pre class="text-xs mt-2 bg-gray-100 dark:bg-gray-800 p-2 rounded">
{wikiPage.content}
</pre>
{/if}
<pre class="text-xs mt-2 bg-gray-100 dark:bg-gray-800 p-2 rounded"> <pre class="text-xs mt-2 bg-gray-100 dark:bg-gray-800 p-2 rounded">
{JSON.stringify(wikiPage, null, 2)} {JSON.stringify(wikiPage, null, 2)}
</pre> </pre>

Loading…
Cancel
Save