Browse Source

Add Publication -> visualize, tag expand depth

tag expand depth: For every tag, pull in other events containing the
same tag, do it up to set value
master
limina1 10 months ago
parent
commit
dddba323a1
  1. 14
      package.json
  2. 11
      src/lib/components/util/ArticleNav.svelte
  3. 61
      src/routes/visualize/+page.svelte
  4. 9
      src/routes/visualize/+page.ts

14
package.json

@ -14,6 +14,8 @@
"test": "vitest" "test": "vitest"
}, },
"dependencies": { "dependencies": {
"@noble/curves": "^1.9.1",
"@noble/hashes": "^1.8.0",
"@nostr-dev-kit/ndk": "2.11.x", "@nostr-dev-kit/ndk": "2.11.x",
"@nostr-dev-kit/ndk-cache-dexie": "2.5.x", "@nostr-dev-kit/ndk-cache-dexie": "2.5.x",
"@popperjs/core": "2.11.x", "@popperjs/core": "2.11.x",
@ -22,19 +24,19 @@
"asciidoctor": "3.0.x", "asciidoctor": "3.0.x",
"bech32": "^2.0.0", "bech32": "^2.0.0",
"d3": "^7.9.0", "d3": "^7.9.0",
"he": "1.2.x", "he": "1.2.0",
"highlight.js": "^11.11.1", "highlight.js": "^11.11.1",
"node-emoji": "^2.2.0", "node-emoji": "^2.2.0",
"nostr-tools": "2.10.x", "nostr-tools": "2.10.x",
"qrcode": "^1.5.4" "qrcode": "^1.5.4"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.50.1", "@playwright/test": "^1.52.0",
"@sveltejs/adapter-auto": "3.x", "@sveltejs/adapter-auto": "~3.3.1",
"@sveltejs/adapter-node": "^5.2.12", "@sveltejs/adapter-node": "^5.2.12",
"@sveltejs/adapter-static": "3.x", "@sveltejs/adapter-static": "~3.0.8",
"@sveltejs/kit": "^2.16.0", "@sveltejs/kit": "^2.21.0",
"@sveltejs/vite-plugin-svelte": "4.x", "@sveltejs/vite-plugin-svelte": "~4.0.4",
"@types/d3": "^7.4.3", "@types/d3": "^7.4.3",
"@types/he": "1.2.x", "@types/he": "1.2.x",
"@types/node": "22.x", "@types/node": "22.x",

11
src/lib/components/util/ArticleNav.svelte

@ -1,10 +1,11 @@
<script lang="ts"> <script lang="ts">
import { BookOutline, CaretLeftOutline, CloseOutline, GlobeOutline } from "flowbite-svelte-icons"; import { BookOutline, CaretLeftOutline, CloseOutline, GlobeOutline, ChartOutline } from "flowbite-svelte-icons";
import { Button } from "flowbite-svelte"; import { Button } from "flowbite-svelte";
import { publicationColumnVisibility } from "$lib/stores"; import { publicationColumnVisibility } from "$lib/stores";
import { userBadge } from "$lib/snippets/UserSnippets.svelte"; import { userBadge } from "$lib/snippets/UserSnippets.svelte";
import type { NDKEvent } from "@nostr-dev-kit/ndk"; import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { onDestroy, onMount } from "svelte"; import { onDestroy, onMount } from "svelte";
import { goto } from "$app/navigation";
let { let {
publicationType, publicationType,
@ -94,6 +95,11 @@
} }
} }
function visualizePublication() {
const eventId = indexEvent.id;
goto(`/visualize?event=${eventId}`);
}
let unsubscribe: () => void; let unsubscribe: () => void;
onMount(() => { onMount(() => {
window.addEventListener('scroll', handleScroll); window.addEventListener('scroll', handleScroll);
@ -143,6 +149,9 @@
<GlobeOutline class="!fill-none inline mr-1" /><span class="hidden sm:inline">Discussion</span> <GlobeOutline class="!fill-none inline mr-1" /><span class="hidden sm:inline">Discussion</span>
</Button> </Button>
{/if} {/if}
<Button class="btn-leather !w-auto" outline={true} onclick={visualizePublication} title="Visualize publication network">
<ChartOutline class="!fill-none inline mr-1" /><span class="hidden sm:inline">Visualize</span>
</Button>
</div> </div>
</div> </div>
</nav> </nav>

61
src/routes/visualize/+page.svelte

@ -11,12 +11,16 @@
import type { NDKEvent } from "@nostr-dev-kit/ndk"; import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { filterValidIndexEvents } from "$lib/utils"; import { filterValidIndexEvents } from "$lib/utils";
import { networkFetchLimit } from "$lib/state"; import { networkFetchLimit } from "$lib/state";
import type { PageData } from './$types';
// Configuration // Configuration
const DEBUG = true; // Set to true to enable debug logging const DEBUG = true; // Set to true to enable debug logging
const INDEX_EVENT_KIND = 30040; const INDEX_EVENT_KIND = 30040;
const CONTENT_EVENT_KINDS = [30041, 30818]; const CONTENT_EVENT_KINDS = [30041, 30818];
// Props from load function
export let data: PageData;
/** /**
* Debug logging function that only logs when DEBUG is true * Debug logging function that only logs when DEBUG is true
*/ */
@ -42,28 +46,47 @@
*/ */
async function fetchEvents() { async function fetchEvents() {
debug("Fetching events with limit:", $networkFetchLimit); debug("Fetching events with limit:", $networkFetchLimit);
debug("Event ID from URL:", data.eventId);
try { try {
loading = true; loading = true;
error = null; error = null;
// Step 1: Fetch index events let validIndexEvents: Set<NDKEvent>;
debug(`Fetching index events (kind ${INDEX_EVENT_KIND})`);
const indexEvents = await $ndkInstance.fetchEvents( if (data.eventId) {
{ // Fetch specific publication
kinds: [INDEX_EVENT_KIND], debug(`Fetching specific publication: ${data.eventId}`);
limit: $networkFetchLimit const event = await $ndkInstance.fetchEvent(data.eventId);
},
{ if (!event) {
groupable: true, throw new Error(`Publication not found: ${data.eventId}`);
skipVerification: false, }
skipValidation: false,
}, if (event.kind !== INDEX_EVENT_KIND) {
); throw new Error(`Event ${data.eventId} is not a publication index (kind ${INDEX_EVENT_KIND})`);
debug("Fetched index events:", indexEvents.size); }
validIndexEvents = new Set([event]);
} else {
// Original behavior: fetch all publications
debug(`Fetching index events (kind ${INDEX_EVENT_KIND})`);
const indexEvents = await $ndkInstance.fetchEvents(
{
kinds: [INDEX_EVENT_KIND],
limit: $networkFetchLimit
},
{
groupable: true,
skipVerification: false,
skipValidation: false,
},
);
debug("Fetched index events:", indexEvents.size);
// Step 2: Filter valid index events according to NIP-62 // Filter valid index events according to NIP-62
const validIndexEvents = filterValidIndexEvents(indexEvents); validIndexEvents = filterValidIndexEvents(indexEvents);
debug("Valid index events after filtering:", validIndexEvents.size); debug("Valid index events after filtering:", validIndexEvents.size);
}
// Step 3: Extract content event IDs from index events // Step 3: Extract content event IDs from index events
const contentEventIds = new Set<string>(); const contentEventIds = new Set<string>();
@ -197,7 +220,9 @@
<div class="leather w-full p-4 relative"> <div class="leather w-full p-4 relative">
<!-- Header with title and settings button --> <!-- Header with title and settings button -->
<div class="flex items-center mb-4"> <div class="flex items-center mb-4">
<h1 class="h-leather">Publication Network</h1> <h1 class="h-leather">
{data.eventId ? 'Publication Visualization' : 'Publication Network'}
</h1>
</div> </div>
<!-- Loading spinner --> <!-- Loading spinner -->
{#if loading} {#if loading}

9
src/routes/visualize/+page.ts

@ -0,0 +1,9 @@
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ url }) => {
const eventId = url.searchParams.get('event');
return {
eventId
};
};
Loading…
Cancel
Save