Browse Source

Create Svelte-specific wrapper that proxies `PublicationTree`

The wrapper keeps the core implementation framework-agnostic, but lets us build Svelte's reactivity into the wrapper.
master
buttercat1791 10 months ago
parent
commit
c6effb3839
  1. 4
      src/lib/components/publications/Publication.svelte
  2. 3
      src/lib/components/publications/PublicationSection.svelte
  3. 56
      src/lib/components/publications/svelte_publication_tree.svelte.ts
  4. 9
      src/lib/data_structures/publication_tree.ts
  5. 5
      src/routes/publication/+page.svelte

4
src/lib/components/publications/Publication.svelte

@ -15,13 +15,13 @@
} from "flowbite-svelte-icons"; } from "flowbite-svelte-icons";
import type { NDKEvent } from "@nostr-dev-kit/ndk"; import type { NDKEvent } from "@nostr-dev-kit/ndk";
import PublicationSection from "./PublicationSection.svelte"; import PublicationSection from "./PublicationSection.svelte";
import type { PublicationTree } from "$lib/data_structures/publication_tree";
import Details from "$components/util/Details.svelte"; import Details from "$components/util/Details.svelte";
import { publicationColumnVisibility } from "$lib/stores"; import { publicationColumnVisibility } from "$lib/stores";
import BlogHeader from "$components/cards/BlogHeader.svelte"; import BlogHeader from "$components/cards/BlogHeader.svelte";
import Interactions from "$components/util/Interactions.svelte"; import Interactions from "$components/util/Interactions.svelte";
import TocToggle from "$components/util/TocToggle.svelte"; import TocToggle from "$components/util/TocToggle.svelte";
import { pharosInstance } from '$lib/parser'; import { pharosInstance } from '$lib/parser';
import type { SveltePublicationTree } from "./svelte_publication_tree.svelte";
let { rootAddress, publicationType, indexEvent } = $props<{ let { rootAddress, publicationType, indexEvent } = $props<{
rootAddress: string; rootAddress: string;
@ -29,7 +29,7 @@
indexEvent: NDKEvent; indexEvent: NDKEvent;
}>(); }>();
const publicationTree = getContext("publicationTree") as PublicationTree; const publicationTree = getContext("publicationTree") as SveltePublicationTree;
// #region Loading // #region Loading

3
src/lib/components/publications/PublicationSection.svelte

@ -6,6 +6,7 @@
import { getContext } from "svelte"; import { getContext } from "svelte";
import type { Asciidoctor, Document } from "asciidoctor"; import type { Asciidoctor, Document } from "asciidoctor";
import { getMatchingTags } from '$lib/utils/nostrUtils'; import { getMatchingTags } from '$lib/utils/nostrUtils';
import type { SveltePublicationTree } from "./svelte_publication_tree.svelte";
let { let {
address, address,
@ -19,7 +20,7 @@
ref: (ref: HTMLElement) => void, ref: (ref: HTMLElement) => void,
} = $props(); } = $props();
const publicationTree: PublicationTree = getContext('publicationTree'); const publicationTree: SveltePublicationTree = getContext('publicationTree');
const asciidoctor: Asciidoctor = getContext('asciidoctor'); const asciidoctor: Asciidoctor = getContext('asciidoctor');
let leafEvent: Promise<NDKEvent | null> = $derived.by(async () => let leafEvent: Promise<NDKEvent | null> = $derived.by(async () =>

56
src/lib/components/publications/svelte_publication_tree.svelte.ts

@ -0,0 +1,56 @@
import { SvelteSet } from "svelte/reactivity";
import { PublicationTree } from "../../data_structures/publication_tree.ts";
import { NDKEvent } from "../../utils/nostrUtils.ts";
import NDK from "@nostr-dev-kit/ndk";
export class SveltePublicationTree {
resolvedAddresses: SvelteSet<string> = new SvelteSet();
#publicationTree: PublicationTree;
constructor(rootEvent: NDKEvent, ndk: NDK) {
this.#publicationTree = new PublicationTree(rootEvent, ndk);
this.#publicationTree.onNodeResolved(this.#handleNodeResolved);
}
// #region Proxied Public Methods
getEvent(address: string): Promise<NDKEvent | null> {
return this.#publicationTree.getEvent(address);
}
getHierarchy(address: string): Promise<NDKEvent[]> {
return this.#publicationTree.getHierarchy(address);
}
setBookmark(address: string) {
this.#publicationTree.setBookmark(address);
}
// #endregion
// #region Proxied Async Iterator Methods
[Symbol.asyncIterator](): AsyncIterator<NDKEvent | null> {
return this;
}
next(): Promise<IteratorResult<NDKEvent | null>> {
return this.#publicationTree.next();
}
previous(): Promise<IteratorResult<NDKEvent | null>> {
return this.#publicationTree.previous();
}
// #endregion
// #region Private Methods
#handleNodeResolved(address: string) {
this.resolvedAddresses.add(address);
}
// #endregion
}

9
src/lib/data_structures/publication_tree.ts

@ -22,14 +22,6 @@ interface PublicationTreeNode {
} }
export class PublicationTree implements AsyncIterable<NDKEvent | null> { export class PublicationTree implements AsyncIterable<NDKEvent | null> {
// TODO: Abstract this into a `SveltePublicationTree` wrapper class.
/**
* A reactive set of addresses of the events that have been resolved (loaded) into the tree.
* Svelte components can use this set in reactive code blocks to trigger updates when new nodes
* are added to the tree.
*/
resolvedAddresses: SvelteSet<string> = new SvelteSet();
/** /**
* The root node of the tree. * The root node of the tree.
*/ */
@ -524,7 +516,6 @@ export class PublicationTree implements AsyncIterable<NDKEvent | null> {
} }
this.#events.set(address, event); this.#events.set(address, event);
this.resolvedAddresses.add(address);
const childAddresses = event.tags.filter(tag => tag[0] === 'a').map(tag => tag[1]); const childAddresses = event.tags.filter(tag => tag[0] === 'a').map(tag => tag[1]);

5
src/routes/publication/+page.svelte

@ -3,13 +3,12 @@
import { TextPlaceholder } from "flowbite-svelte"; import { TextPlaceholder } from "flowbite-svelte";
import type { PageProps } from "./$types"; import type { PageProps } from "./$types";
import { onDestroy, setContext } from "svelte"; import { onDestroy, setContext } from "svelte";
import { PublicationTree } from "$lib/data_structures/publication_tree";
import Processor from "asciidoctor"; import Processor from "asciidoctor";
import ArticleNav from "$components/util/ArticleNav.svelte"; import ArticleNav from "$components/util/ArticleNav.svelte";
import { SveltePublicationTree } from "$lib/components/publications/svelte_publication_tree.svelte";
let { data }: PageProps = $props(); let { data }: PageProps = $props();
const publicationTree = new PublicationTree(data.indexEvent, data.ndk); const publicationTree = new SveltePublicationTree(data.indexEvent, data.ndk);
setContext("publicationTree", publicationTree); setContext("publicationTree", publicationTree);
setContext("asciidoctor", Processor()); setContext("asciidoctor", Processor());

Loading…
Cancel
Save