Browse Source

Render publication content and headers

Incomplete.  Some headers are still missing, and we don't yet gracefully handle events that can't be found.
master
buttercat1791 11 months ago
parent
commit
03612ad6de
  1. 10
      src/lib/components/Publication.svelte
  2. 84
      src/lib/components/PublicationSection.svelte
  3. 2
      src/routes/publication/+page.svelte

10
src/lib/components/Publication.svelte

@ -39,8 +39,9 @@ @@ -39,8 +39,9 @@
for (let i = 0; i < count; i++) {
const nextItem = await publicationTree.next();
if (nextItem.done) {
break;
if (leaves.includes(nextItem.value) || nextItem.done) {
isLoading = false;
return;
}
leaves.push(nextItem.value);
}
@ -136,11 +137,11 @@ @@ -136,11 +137,11 @@
observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !isLoading) {
loadMore(8);
loadMore(4);
}
});
}, { threshold: 0.5 });
loadMore(16);
loadMore(8);
return () => {
window.removeEventListener("hashchange", scrollToElementWithOffset);
@ -186,6 +187,7 @@ @@ -186,6 +187,7 @@
{#each leaves as leaf, i}
<PublicationSection
rootAddress={rootAddress}
leaves={leaves}
address={leaf.tagAddress()}
ref={(el) => setLastElementRef(el, i)}
/>

84
src/lib/components/PublicationSection.svelte

@ -1,27 +1,82 @@ @@ -1,27 +1,82 @@
<script lang='ts'>
import type { PublicationTree } from "$lib/data_structures/publication_tree";
import { contentParagraph } from "$lib/snippets/PublicationSnippets.svelte";
import { contentParagraph, sectionHeading } from "$lib/snippets/PublicationSnippets.svelte";
import { NDKEvent } from "@nostr-dev-kit/ndk";
import { TextPlaceholder } from "flowbite-svelte";
import { getContext } from "svelte";
import type { Asciidoctor, Document } from "asciidoctor";
let {
address,
rootAddress,
leaves,
ref,
}: {
address: string,
rootAddress: string,
leaves: NDKEvent[],
ref: (ref: HTMLElement) => void,
} = $props();
const publicationTree = getContext<PublicationTree>('publicationTree');
const publicationTree: PublicationTree = getContext('publicationTree');
const asciidoctor: Asciidoctor = getContext('asciidoctor');
let sectionEvent = $derived.by(async () => await publicationTree.getEvent(address));
let rootEvent = $derived.by(async () => await publicationTree.getEvent(rootAddress));
let publicationType = $derived.by(async () =>
let leafEvent: Promise<NDKEvent | null> = $derived.by(async () =>
await publicationTree.getEvent(address));
let rootEvent: Promise<NDKEvent | null> = $derived.by(async () =>
await publicationTree.getEvent(rootAddress));
let publicationType: Promise<string | undefined> = $derived.by(async () =>
(await rootEvent)?.getMatchingTags('type')[0]?.[1]);
let hierarchy = $derived.by(async () => await publicationTree.getHierarchy(address));
let depth = $derived.by(async () => (await hierarchy).length);
let leafHierarchy: Promise<NDKEvent[]> = $derived.by(async () =>
await publicationTree.getHierarchy(address));
let leafContent: Promise<string | Document> = $derived.by(async () =>
asciidoctor.convert((await leafEvent)?.content ?? ''));
let previousLeafEvent: NDKEvent | null = $derived.by(() => {
const index = leaves.findIndex(leaf => leaf.tagAddress() === address);
if (index === 0) {
return null;
}
return leaves[index - 1];
});
let previousLeafHierarchy: Promise<NDKEvent[] | null> = $derived.by(async () => {
const previousLeaf = await previousLeafEvent;
if (!previousLeaf) {
return null;
}
return await publicationTree.getHierarchy(previousLeafEvent?.tagAddress() ?? '')
});
let divergingBranches = $derived.by(async () => {
const currentHierarchy = await leafHierarchy;
const previousHierarchy = await previousLeafHierarchy;
const branches: [NDKEvent, number][] = [];
if (!previousHierarchy) {
for (let i = 0; i < currentHierarchy.length - 1; i++) {
branches.push([currentHierarchy[i], i]);
}
return branches;
}
const minLength = Math.min(currentHierarchy.length, previousHierarchy.length);
// Find the first diverging node.
let divergingIndex = 0;
while (
divergingIndex < minLength &&
currentHierarchy[divergingIndex].tagAddress() === previousHierarchy[divergingIndex].tagAddress()
) {
divergingIndex++;
}
// Add all branches from the first diverging node to the current leaf.
for (let i = divergingIndex; i < currentHierarchy.length - 1; i++) {
branches.push([currentHierarchy[i], i]);
}
return branches;
});
let sectionRef: HTMLElement;
@ -31,16 +86,19 @@ @@ -31,16 +86,19 @@
}
ref(sectionRef);
})
});
</script>
<!-- TODO: Correctly handle events that are the start of a content section. -->
<section bind:this={sectionRef}>
{#await Promise.all([sectionEvent, publicationType])}
{#await Promise.all([leafContent, publicationType, divergingBranches])}
<TextPlaceholder size='xxl' />
{:then [sectionEvent, publicationType]}
<!-- TODO: Gracefully handle nulls. -->
{@render contentParagraph(sectionEvent?.content ?? '', publicationType ?? 'article', false)}
{:then [leafContent, publicationType, divergingBranches]}
<!-- TODO: Ensure we render all headings, not just the first one. -->
{#each divergingBranches as [branch, depth]}
{@render sectionHeading(branch.getMatchingTags('title')[0]?.[1] ?? '', depth)}
{/each}
{@render contentParagraph(leafContent.toString(), publicationType ?? 'article', false)}
{/await}
</section>

2
src/routes/publication/+page.svelte

@ -4,12 +4,14 @@ @@ -4,12 +4,14 @@
import type { PageProps } from "./$types";
import { onDestroy, setContext } from "svelte";
import { PublicationTree } from "$lib/data_structures/publication_tree";
import Processor from "asciidoctor";
let { data }: PageProps = $props();
const publicationTree = new PublicationTree(data.indexEvent, data.ndk);
setContext('publicationTree', publicationTree);
setContext('asciidoctor', Processor());
// Get publication metadata for OpenGraph tags
let title = $derived(data.indexEvent?.getMatchingTags('title')[0]?.[1] || data.parser?.getIndexTitle(data.parser?.getRootIndexId()) || 'Alexandria Publication');

Loading…
Cancel
Save