Browse Source

feat: event previews for issues, patches and repos

to be displayed when they are embedded into events
master
DanConwayDev 2 years ago
parent
commit
ea07b55491
No known key found for this signature in database
GPG Key ID: 68E15486D73F75E1
  1. 2
      src/lib/components/events/EventWrapperLite.svelte
  2. 21
      src/lib/components/events/content/IssuePreview.svelte
  3. 2
      src/lib/components/events/content/ParsedContent.svelte
  4. 335
      src/lib/components/events/content/Patch.svelte
  5. 19
      src/lib/components/events/content/Repo.svelte
  6. 41
      src/lib/components/events/content/utils.ts
  7. 24
      src/lib/wrappers/EventCard.svelte
  8. 102
      src/lib/wrappers/EventPreview.svelte

2
src/lib/components/events/EventWrapperLite.svelte

@ -18,6 +18,6 @@
<UserHeader user={author} inline /> <UserHeader user={author} inline />
</div> </div>
</div> </div>
<span class="m-auto pr-1 text-xs">{created_at_ago}</span> <span class="m-auto flex-none py-1 text-xs">{created_at_ago}</span>
</div> </div>
</div> </div>

21
src/lib/components/events/content/IssuePreview.svelte

@ -0,0 +1,21 @@
<script lang="ts">
import { extractAReference } from '$lib/components/repo/utils'
import { extractRepoAFromProposalEvent } from '$lib/stores/Proposals'
import type { NDKEvent } from '@nostr-dev-kit/ndk'
import { nip19 } from 'nostr-tools'
export let event: NDKEvent
let nevent = nip19.neventEncode({
id: event.id,
relays: event.relay ? [event.relay.url] : undefined,
})
let a_string = extractRepoAFromProposalEvent(event)
let pointer = a_string ? extractAReference(a_string) : undefined
let naddr = pointer ? nip19.naddrEncode(pointer) : undefined
</script>
<span>
Git Issue for <a class="opacity-50" href={`/e/${naddr}`}
>{pointer?.identifier}</a
>: <a href={`/e/${nevent}`}>{event.content?.split('\n')[0]}</a> by
</span>

2
src/lib/components/events/content/ParsedContent.svelte

@ -43,7 +43,7 @@
<UserHeader user={part.hex} inline={true} size="sm" /> <UserHeader user={part.hex} inline={true} size="sm" />
</div> </div>
{:else if isParsedNevent(part) || isParsedNote(part) || isParsedNaddr(part)} {:else if isParsedNevent(part) || isParsedNote(part) || isParsedNaddr(part)}
<EventPreview parsed_nostr_ref={part} /> <EventPreview pointer={part.data} />
{:else if isParsedText(part)} {:else if isParsedText(part)}
{part.value} {part.value}
{/if} {/if}

335
src/lib/components/events/content/Patch.svelte

@ -1,20 +1,28 @@
<script lang="ts"> <script lang="ts">
import type { NDKTag } from '@nostr-dev-kit/ndk' import type { NDKEvent, NDKTag } from '@nostr-dev-kit/ndk'
import parseDiff from 'parse-diff' import parseDiff from 'parse-diff'
import hljs from 'highlight.js/lib/common' import hljs from 'highlight.js/lib/common'
import 'highlight.js/styles/agate.min.css' import 'highlight.js/styles/agate.min.css'
import type { Change, AddChange, DeleteChange } from 'parse-diff' import type { Change, AddChange, DeleteChange } from 'parse-diff'
import ParsedContent from './ParsedContent.svelte' import ParsedContent from './ParsedContent.svelte'
import { extractPatchMessage } from './utils' import { extractPatchMessage, extractTagContent } from './utils'
import { nip19 } from 'nostr-tools'
import { extractRepoAFromProposalEvent } from '$lib/stores/Proposals'
import { extractAReference } from '$lib/components/repo/utils'
export let event: NDKEvent
export let preview = false
let content: string = event ? event.content : ''
let tags: NDKTag[] = event ? event.tags : []
export let content: string = ''
export let tags: NDKTag[] = []
let commit_id_shorthand = let commit_id_shorthand =
extractTagContent('commit')?.substring(0, 8) || '[commit_id unknown]' extractTagContent('commit', tags)?.substring(0, 8) || '[commit_id unknown]'
let commit_message = let commit_message =
extractTagContent('description') || extractTagContent('description', tags) ||
extractPatchMessage(content) || extractPatchMessage(content) ||
'[untitled]' '[untitled]'
let commit_title = commit_message.split('\n')[0]
let files = parseDiff(content) let files = parseDiff(content)
let expand_files = files.map((file) => file.deletions + file.additions < 20) let expand_files = files.map((file) => file.deletions + file.additions < 20)
@ -27,11 +35,6 @@
let expand_full_files = files.map((_) => false) let expand_full_files = files.map((_) => false)
function extractTagContent(name: string): string | undefined {
let tag = tags.find((tag) => tag[0] === name)
return tag ? tag[1] : undefined
}
let isAddChange = (change: Change): change is AddChange => let isAddChange = (change: Change): change is AddChange =>
change.type == 'add' change.type == 'add'
let isDeleteChange = (change: Change): change is DeleteChange => let isDeleteChange = (change: Change): change is DeleteChange =>
@ -59,175 +62,191 @@
return undefined return undefined
} }
} }
let nevent = nip19.neventEncode({
id: event.id,
relays: event.relay ? [event.relay.url] : undefined,
})
let a_string = extractRepoAFromProposalEvent(event)
let pointer = a_string ? extractAReference(a_string) : undefined
let naddr = pointer ? nip19.naddrEncode(pointer) : undefined
</script> </script>
<div class=""> {#if preview}
<div class="flex rounded-t bg-base-300 p-1"> <span>
<article class="ml-2 flex-grow font-mono text-sm"> Git Patch for <a class="opacity-50" href={`/e/${naddr}`}
<ParsedContent content={commit_message} /> >{pointer?.identifier}</a
</article> >: <a href={`/e/${nevent}`}>{commit_title}</a> by
<div class="flex-none p-1 align-middle text-xs text-neutral">commit</div> </span>
</div> {:else}
<div class="">
<div class="flex rounded-t bg-base-300 p-1">
<article class="ml-2 flex-grow font-mono text-sm">
<ParsedContent content={commit_message} />
</article>
<div class="flex-none p-1 align-middle text-xs text-neutral">commit</div>
</div>
<div class="flex p-3"> <div class="flex p-3">
<div class="flex-grow text-xs">Changes:</div> <div class="flex-grow text-xs">Changes:</div>
<div class="flex-none text-right font-mono text-xs"> <div class="flex-none text-right font-mono text-xs">
{commit_id_shorthand} {commit_id_shorthand}
</div>
</div> </div>
</div>
{#each files as file, index} {#each files as file, index}
<div <div
class="my-2 border border-base-300 {expand_full_files[index] class="my-2 border border-base-300 {expand_full_files[index]
? 'absolute left-0 z-10 w-screen bg-base-300 px-5' ? 'absolute left-0 z-10 w-screen bg-base-300 px-5'
: ''}" : ''}"
> >
<div class="flex w-full bg-base-200"> <div class="flex w-full bg-base-200">
<button <button
class="flex shrink flex-grow p-3 text-sm" class="flex shrink flex-grow p-3 text-sm"
on:click={() => { on:click={() => {
if (expand_full_files[index]) { if (expand_full_files[index]) {
expand_full_files[index] = false
expand_files[index] = false
} else if (expand_files[index]) {
expand_full_files[index] = true
} else {
expand_files[index] = true
}
}}
><div class="shrink text-wrap text-left">
<span class="pr-3">{file.to || file.from}</span>
<span
class="text-middle flex-none align-middle font-mono text-xs opacity-70"
>{#if file.new}<span>created&nbsp;file</span
>&nbsp;{/if}{#if file.deleted}<span>deleted&nbsp;file</span
>&nbsp;{/if}{#if !file.deleted}<span class="text-success"
>+{file.additions}</span
>{/if}&nbsp;{#if !file.new}<span class="text-error"
>-{file.deletions}</span
>{/if}
</span>
</div>
<div class="flex-grow"></div>
</button>
<button
class="flex-none p-3 text-right text-xs opacity-40"
on:click={() => {
expand_files[index] = !expand_files[index]
expand_full_files[index] = false expand_full_files[index] = false
expand_files[index] = false }}
} else if (expand_files[index]) { >
expand_full_files[index] = true {expand_files[index] ? 'colapse' : 'expand'}
} else { </button>
expand_files[index] = true <button
} class="flex-none p-3 text-right text-xs opacity-40"
}} on:click={() => {
><div class="shrink text-wrap text-left"> expand_full_files[index] = !expand_full_files[index]
<span class="pr-3">{file.to || file.from}</span> if (expand_full_files[index]) expand_files[index] = true
<span }}
class="text-middle flex-none align-middle font-mono text-xs opacity-70" >
>{#if file.new}<span>created&nbsp;file</span full
>&nbsp;{/if}{#if file.deleted}<span>deleted&nbsp;file</span </button>
>&nbsp;{/if}{#if !file.deleted}<span class="text-success" </div>
>+{file.additions}</span {#if expand_files[index]}
>{/if}&nbsp;{#if !file.new}<span class="text-error" <div class="border-t-1 flex border-base-300 font-mono text-xs">
>-{file.deletions}</span <div class="flex-full select-none text-right">
>{/if}
</span>
</div>
<div class="flex-grow"></div>
</button>
<button
class="flex-none p-3 text-right text-xs opacity-40"
on:click={() => {
expand_files[index] = !expand_files[index]
expand_full_files[index] = false
}}
>
{expand_files[index] ? 'colapse' : 'expand'}
</button>
<button
class="flex-none p-3 text-right text-xs opacity-40"
on:click={() => {
expand_full_files[index] = !expand_full_files[index]
if (expand_full_files[index]) expand_files[index] = true
}}
>
full
</button>
</div>
{#if expand_files[index]}
<div class="border-t-1 flex border-base-300 font-mono text-xs">
<div class="flex-full select-none text-right">
{#each file.chunks as chunk, index}
{#if index !== 0}
<div class="flex w-full bg-base-200">
<div
class="w-8 flex-none whitespace-pre pb-2 pr-2 pt-1 opacity-50"
>
...
</div>
</div>
{/if}
{#each chunk.changes as change, i}
<div class="flex w-full bg-base-100">
<div
class="w-8 flex-none whitespace-pre {change.type == 'add'
? 'bg-success/50'
: change.type == 'del'
? 'bg-error/50'
: 'bg-slate-500/20'} pr-2 opacity-50"
class:pt-3={index === 0 && i === 0}
class:pb-3={index === file.chunks.length - 1 &&
i === chunk.changes.length - 1}
>
{isAddChange(change) &&
i !== 0 &&
isDeleteChange(chunk.changes[i - 1])
? ' '
: extractChangeLine(change)}
</div>
</div>
{/each}
{/each}
</div>
<div class="flex-auto overflow-x-auto">
<div class="w-fit">
{#each file.chunks as chunk, index} {#each file.chunks as chunk, index}
{#if index !== 0} {#if index !== 0}
<div class="flex h-7 w-full bg-base-200"></div> <div class="flex w-full bg-base-200">
<div
class="w-8 flex-none whitespace-pre pb-2 pr-2 pt-1 opacity-50"
>
...
</div>
</div>
{/if} {/if}
{#each chunk.changes as change, i} {#each chunk.changes as change, i}
<div class="flex w-full bg-base-100"> <div class="flex w-full bg-base-100">
<div <div
class="w-full flex-grow whitespace-pre {change.type == class="w-8 flex-none whitespace-pre {change.type == 'add'
'add' ? 'bg-success/50'
? 'bg-success/20'
: change.type == 'del' : change.type == 'del'
? 'bg-error/20' ? 'bg-error/50'
: ''}" : 'bg-slate-500/20'} pr-2 opacity-50"
class:pt-3={index === 0 && i === 0} class:pt-3={index === 0 && i === 0}
class:pb-3={index === file.chunks.length - 1 && class:pb-3={index === file.chunks.length - 1 &&
i === chunk.changes.length - 1} i === chunk.changes.length - 1}
> >
{#if getFortmattedDiffHtml(change, (file.to || file.from) {isAddChange(change) &&
?.split('.') i !== 0 &&
.pop() || '')} isDeleteChange(chunk.changes[i - 1])
<!-- eslint-disable-next-line svelte/no-at-html-tags --> ? ' '
{@html getFortmattedDiffHtml( : extractChangeLine(change)}
change,
(file.to || file.from)?.split('.').pop() || ''
)}
{:else}
{change.type == 'normal'
? change.content
: change.content.substring(1)}
{/if}
{#if (change.type == 'normal' ? change.content : change.content.substring(1)).length === 0}
<!-- force empty line to have height -->
<span></span>
{/if}
</div> </div>
</div> </div>
{/each} {/each}
{/each} {/each}
</div> </div>
<div class="flex-auto overflow-x-auto">
<div class="w-fit">
{#each file.chunks as chunk, index}
{#if index !== 0}
<div class="flex h-7 w-full bg-base-200"></div>
{/if}
{#each chunk.changes as change, i}
<div class="flex w-full bg-base-100">
<div
class="w-full flex-grow whitespace-pre {change.type ==
'add'
? 'bg-success/20'
: change.type == 'del'
? 'bg-error/20'
: ''}"
class:pt-3={index === 0 && i === 0}
class:pb-3={index === file.chunks.length - 1 &&
i === chunk.changes.length - 1}
>
{#if getFortmattedDiffHtml(change, (file.to || file.from)
?.split('.')
.pop() || '')}
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
{@html getFortmattedDiffHtml(
change,
(file.to || file.from)?.split('.').pop() || ''
)}
{:else}
{change.type == 'normal'
? change.content
: change.content.substring(1)}
{/if}
{#if (change.type == 'normal' ? change.content : change.content.substring(1)).length === 0}
<!-- force empty line to have height -->
<span></span>
{/if}
</div>
</div>
{/each}
{/each}
</div>
</div>
</div> </div>
{/if}
</div>
<!-- vertical padding for full width so that content retains it space -->
{#if expand_full_files[index]}
<div class="w-full whitespace-pre font-mono text-xs">
<span class="block p-3 text-sm"> </span>
{#each file.chunks as chunk, index}
{#if index !== 0}
<span class="block h-7 p-3"> </span>
{/if}
{#each chunk.changes as _, i}
<span
class="block"
class:pt-3={index === 0 && i === 0}
class:pb-3={index === file.chunks.length - 1 &&
i === chunk.changes.length - 1}
>&nbsp;
</span>
{/each}
{/each}
</div> </div>
{/if} {/if}
</div> {/each}
<!-- vertical padding for full width so that content retains it space --> </div>
{#if expand_full_files[index]} {/if}
<div class="w-full whitespace-pre font-mono text-xs">
<span class="block p-3 text-sm"> </span>
{#each file.chunks as chunk, index}
{#if index !== 0}
<span class="block h-7 p-3"> </span>
{/if}
{#each chunk.changes as _, i}
<span
class="block"
class:pt-3={index === 0 && i === 0}
class:pb-3={index === file.chunks.length - 1 &&
i === chunk.changes.length - 1}
>&nbsp;
</span>
{/each}
{/each}
</div>
{/if}
{/each}
</div>

19
src/lib/components/events/content/Repo.svelte

@ -0,0 +1,19 @@
<script lang="ts">
import type { RepoEvent } from '$lib/components/repo/type'
import { eventToRepoEvent } from '$lib/stores/repos'
import type { NDKEvent } from '@nostr-dev-kit/ndk'
export let event: NDKEvent | RepoEvent
const isRepoEvent = (event: NDKEvent | RepoEvent): event is RepoEvent => {
return Object.keys(event).includes('web')
}
let repo = isRepoEvent(event) ? event : eventToRepoEvent(event)
</script>
{#if repo}
<span class="">
Git Repository: <a href={`/r/${repo.naddr}`}>{repo.name}</a> by
</span>
{/if}

41
src/lib/components/events/content/utils.ts

@ -1,5 +1,6 @@
import type { NDKTag } from '@nostr-dev-kit/ndk' import type { NDKTag } from '@nostr-dev-kit/ndk'
import { nip19 } from 'nostr-tools' import { nip19 } from 'nostr-tools'
import type { AddressPointer, EventPointer } from 'nostr-tools/lib/types/nip19'
import { last } from 'ramda' import { last } from 'ramda'
export const TOPIC = 'topic' export const TOPIC = 'topic'
@ -67,31 +68,29 @@ export const NOSTR_NOTE = 'nostr:note'
type PartTypeNote = 'nostr:note' type PartTypeNote = 'nostr:note'
export type ParsedNote = { export type ParsedNote = {
type: PartTypeNote type: PartTypeNote
id: string data: EventPointer
relays: string[]
} }
export const NOSTR_NEVENT = 'nostr:nevent' export const NOSTR_NEVENT = 'nostr:nevent'
type PartTypeNevent = 'nostr:nevent' type PartTypeNevent = 'nostr:nevent'
export type ParsedNevent = { export type ParsedNevent = {
type: PartTypeNevent type: PartTypeNevent
id: string data: EventPointer
relays: string[]
} }
export const NOSTR_NADDR = 'nostr:naddr' export const NOSTR_NADDR = 'nostr:naddr'
type PartTypeNaddr = 'nostr:naddr' type PartTypeNaddr = 'nostr:naddr'
export type ParsedNaddr = { export type ParsedNaddr = {
type: PartTypeNaddr type: PartTypeNaddr
identifier: string data: AddressPointer
pubkey: string
kind: number
relays: string[]
} }
export type ParsedNostrLink =
export type ParsedNostrLink = ParsedNpub | ParsedNprofile | ParsedNevent | ParsedNote | ParsedNaddr | ParsedNpub
| ParsedNprofile
| ParsedNevent
| ParsedNote
| ParsedNaddr
export const TEXT = 'text' export const TEXT = 'text'
type PartTypeText = 'text' type PartTypeText = 'text'
@ -113,7 +112,11 @@ export const isParsedLink = (part: ParsedPart): part is ParsedLink =>
part.type == LINK part.type == LINK
export const isParsedNostrLink = (part: ParsedPart): part is ParsedNostrLink => export const isParsedNostrLink = (part: ParsedPart): part is ParsedNostrLink =>
part.type == NOSTR_NPUB || part.type == NOSTR_NPROFILE || part.type == NOSTR_NEVENT || part.type == NOSTR_NOTE || part.type == NOSTR_NADDR part.type == NOSTR_NPUB ||
part.type == NOSTR_NPROFILE ||
part.type == NOSTR_NEVENT ||
part.type == NOSTR_NOTE ||
part.type == NOSTR_NADDR
export const isParsedNpub = (part: ParsedPart): part is ParsedNpub => export const isParsedNpub = (part: ParsedPart): part is ParsedNpub =>
part.type == NOSTR_NPUB part.type == NOSTR_NPUB
@ -219,13 +222,13 @@ export const parseContent = (content: string, tags: NDKTag[]): ParsedPart[] => {
return [bech32, { type: NOSTR_NPUB, hex: decoded.data.pubkey }] return [bech32, { type: NOSTR_NPUB, hex: decoded.data.pubkey }]
} }
if (decoded.type === 'note') { if (decoded.type === 'note') {
return [bech32, { type: NOSTR_NOTE, id: decoded.data, relays: [] }] return [bech32, { type: NOSTR_NOTE, data: { id: decoded.data } }]
} }
if (decoded.type === 'nevent') { if (decoded.type === 'nevent') {
return [bech32, { type: NOSTR_NEVENT, id: decoded.data.id, relays: decoded.data.relays || [] }] return [bech32, { type: NOSTR_NEVENT, data: decoded.data }]
} }
if (decoded.type === 'naddr') { if (decoded.type === 'naddr') {
return [bech32, { ...decoded.data, type: NOSTR_NADDR, relays: decoded.data.relays || [] }] return [bech32, { type: NOSTR_NADDR, data: decoded.data }]
} }
} catch {} } catch {}
} }
@ -266,6 +269,14 @@ export const isCoverLetter = (s: string): boolean => {
return s.indexOf('PATCH 0/') > 0 return s.indexOf('PATCH 0/') > 0
} }
export function extractTagContent(
name: string,
tags: NDKTag[]
): string | undefined {
const tag = tags.find((tag) => tag[0] === name)
return tag ? tag[1] : undefined
}
/** this doesn't work for all patch formats and options */ /** this doesn't work for all patch formats and options */
export const extractPatchMessage = (s: string): string | undefined => { export const extractPatchMessage = (s: string): string | undefined => {
try { try {

24
src/lib/wrappers/EventCard.svelte

@ -5,7 +5,12 @@
import Patch from '$lib/components/events/content/Patch.svelte' import Patch from '$lib/components/events/content/Patch.svelte'
import ParsedContent from '$lib/components/events/content/ParsedContent.svelte' import ParsedContent from '$lib/components/events/content/ParsedContent.svelte'
import { defaults as user_defaults } from '$lib/components/users/type' import { defaults as user_defaults } from '$lib/components/users/type'
import { patch_kind, proposal_status_kinds } from '$lib/kinds' import {
issue_kind,
patch_kind,
proposal_status_kinds,
repo_kind,
} from '$lib/kinds'
import { ensureUser } from '$lib/stores/users' import { ensureUser } from '$lib/stores/users'
import type { NDKEvent } from '@nostr-dev-kit/ndk' import type { NDKEvent } from '@nostr-dev-kit/ndk'
import { onDestroy } from 'svelte' import { onDestroy } from 'svelte'
@ -14,9 +19,12 @@
extractPatchMessage, extractPatchMessage,
isCoverLetter, isCoverLetter,
} from '$lib/components/events/content/utils' } from '$lib/components/events/content/utils'
import Repo from '$lib/components/events/content/Repo.svelte'
import IssuePreview from '$lib/components/events/content/IssuePreview.svelte'
export let event: NDKEvent export let event: NDKEvent
export let type: 'proposal' | 'issue' = 'proposal' export let type: 'proposal' | 'issue' = 'proposal'
export let preview = false
let author = writable({ ...user_defaults }) let author = writable({ ...user_defaults })
let author_unsubsriber: Unsubscriber let author_unsubsriber: Unsubscriber
@ -45,6 +53,18 @@
<EventWrapperLite author={$author} created_at={event.created_at}> <EventWrapperLite author={$author} created_at={event.created_at}>
added to '{getDtag(event) || 'unknown'}' list by added to '{getDtag(event) || 'unknown'}' list by
</EventWrapperLite> </EventWrapperLite>
{:else if event.kind && event.kind == repo_kind}
<EventWrapperLite author={$author} created_at={event.created_at}>
<Repo {event} />
</EventWrapperLite>
{:else if preview && event.kind && event.kind === patch_kind}
<EventWrapperLite author={$author} created_at={event.created_at}>
<Patch {event} {preview} />
</EventWrapperLite>
{:else if preview && event.kind && event.kind === issue_kind}
<EventWrapperLite author={$author} created_at={event.created_at}>
<IssuePreview {event} />
</EventWrapperLite>
{:else} {:else}
<EventWrapper {type} author={$author} created_at={event.created_at} {event}> <EventWrapper {type} author={$author} created_at={event.created_at} {event}>
{#if event.kind == patch_kind} {#if event.kind == patch_kind}
@ -54,7 +74,7 @@
tags={event.tags} tags={event.tags}
/> />
{:else} {:else}
<Patch content={event.content} tags={event.tags} /> <Patch {event} />
{/if} {/if}
{:else if event.kind && proposal_status_kinds.includes(event.kind)} {:else if event.kind && proposal_status_kinds.includes(event.kind)}
<Status {type} status={event.kind} /> <Status {type} status={event.kind} />

102
src/lib/wrappers/EventPreview.svelte

@ -1,58 +1,72 @@
<script lang="ts"> <script lang="ts">
import EventWrapper from '$lib/components/events/EventWrapper.svelte'
import EventWrapperLite from '$lib/components/events/EventWrapperLite.svelte'
import Status from '$lib/components/events/content/Status.svelte'
import Patch from '$lib/components/events/content/Patch.svelte'
import ParsedContent from '$lib/components/events/content/ParsedContent.svelte'
import { defaults as user_defaults } from '$lib/components/users/type'
import { patch_kind, proposal_status_kinds } from '$lib/kinds'
import { ensureUser } from '$lib/stores/users'
import { NDKRelaySet, type NDKEvent } from '@nostr-dev-kit/ndk' import { NDKRelaySet, type NDKEvent } from '@nostr-dev-kit/ndk'
import { onDestroy, onMount } from 'svelte' import { onMount } from 'svelte'
import { get, writable, type Unsubscriber, type Writable } from 'svelte/store' import { get, writable, type Writable } from 'svelte/store'
import {
extractPatchMessage,
isCoverLetter,
isParsedNaddr,
type ParsedNaddr,
type ParsedNevent,
type ParsedNote,
} from '$lib/components/events/content/utils'
import { base_relays, ndk } from '$lib/stores/ndk' import { base_relays, ndk } from '$lib/stores/ndk'
import EventCard from './EventCard.svelte' import EventCard from './EventCard.svelte'
import type {
AddressPointer,
EventPointer,
} from 'nostr-tools/lib/types/nip19'
import { repo_kind } from '$lib/kinds'
import { ensureRepo } from '$lib/stores/repos'
import EventWrapperLite from '$lib/components/events/EventWrapperLite.svelte'
import Repo from '$lib/components/events/content/Repo.svelte'
export let parsed_nostr_ref: ParsedNaddr | ParsedNevent | ParsedNote export let pointer: AddressPointer | EventPointer
let cannot_find_event = false; let cannot_find_event = false
let event: Writable<undefined | NDKEvent> = writable(undefined) let event: Writable<undefined | NDKEvent> = writable(undefined)
const isAddressPointer = (
pointer: AddressPointer | EventPointer
): pointer is AddressPointer => {
return Object.keys(pointer).includes('identifier')
}
let is_repo = isAddressPointer(pointer) && pointer.kind == repo_kind
let repo =
is_repo && isAddressPointer(pointer)
? ensureRepo(`${pointer.kind}:${pointer.pubkey}:${pointer.identifier}`)
: undefined
onMount(() => { onMount(() => {
let sub = ndk.subscribe( if (!is_repo) {
isParsedNaddr(parsed_nostr_ref) ? { let sub = ndk.subscribe(
'#a': [`${parsed_nostr_ref.kind}:${parsed_nostr_ref.pubkey}:${parsed_nostr_ref.identifier}`], isAddressPointer(pointer)
} : ? {
{ ids: [parsed_nostr_ref.id] }, '#a': [`${pointer.kind}:${pointer.pubkey}:${pointer.identifier}`],
{closeOnEose: true}, }
NDKRelaySet.fromRelayUrls([ ...base_relays, ...parsed_nostr_ref.relays ], ndk) : { ids: [pointer.id] },
) { closeOnEose: true },
NDKRelaySet.fromRelayUrls(
pointer.relays ? [...base_relays, ...pointer.relays] : base_relays,
ndk
)
)
sub.on('event', (e: NDKEvent) => { sub.on('event', (e: NDKEvent) => {
event.set(e) event.set(e)
}) })
sub.on('eose', () => { sub.on('eose', () => {
if (!get(event)) cannot_find_event = true if (!get(event)) cannot_find_event = true
}) })
}
}) })
</script> </script>
<div class="card shadow-xl border border-base-400 p-2 pt-0 my-3"> <div class="card my-3 border border-base-400 shadow-xl">
{#if $event && $event.pubkey} {#if repo && $repo}
<EventCard event={$event} /> <EventWrapperLite author={$repo?.author} created_at={$repo?.created_at}>
{:else if cannot_find_event} <Repo event={$repo} />
cannot find event </EventWrapperLite>
{:else} {:else if $event && $event.pubkey}
loading... <div class="p-2 pt-0">
{/if} <EventCard event={$event} preview={true} />
</div> </div>
{:else if cannot_find_event}
<div class="m-3 text-center text-sm">cannot find event</div>
{:else}
<div class="m-3 text-center text-sm">loading...</div>
{/if}
</div>

Loading…
Cancel
Save