Browse Source

implemented d-tag searches and corrected wikilinks to use them

master
Silberengel 8 months ago
parent
commit
d396b6f292
  1. 65
      src/lib/components/EventSearch.svelte
  2. 2
      src/lib/utils/markup/MarkupInfo.md
  3. 2
      src/lib/utils/markup/basicMarkupParser.ts
  4. 92
      src/routes/events/+page.svelte

65
src/lib/components/EventSearch.svelte

@ -6,12 +6,15 @@ @@ -6,12 +6,15 @@
import { goto } from '$app/navigation';
import type { NDKEvent } from '$lib/utils/nostrUtils';
import RelayDisplay from './RelayDisplay.svelte';
import { getActiveRelays } from '$lib/ndk';
const { loading, error, searchValue, onEventFound, event } = $props<{
const { loading, error, searchValue, dTagValue, onEventFound, onSearchResults, event } = $props<{
loading: boolean;
error: string | null;
searchValue: string | null;
dTagValue: string | null;
onEventFound: (event: NDKEvent) => void;
onSearchResults: (results: NDKEvent[]) => void;
event: NDKEvent | null;
}>();
@ -27,15 +30,70 @@ @@ -27,15 +30,70 @@
}
});
$effect(() => {
if (dTagValue) {
searchByDTag(dTagValue);
}
});
$effect(() => {
foundEvent = event;
});
async function searchByDTag(dTag: string) {
localError = null;
searching = true;
try {
console.log('[Events] Searching for events with d-tag:', dTag);
const ndk = $ndkInstance;
if (!ndk) {
localError = 'NDK not initialized';
return;
}
const filter = { '#d': [dTag] };
const relaySet = getActiveRelays(ndk);
// Fetch multiple events with the same d-tag
const events = await ndk.fetchEvents(filter, { closeOnEose: true }, relaySet);
const eventArray = Array.from(events);
if (eventArray.length === 0) {
localError = `No events found with d-tag: ${dTag}`;
onSearchResults([]);
} else if (eventArray.length === 1) {
// If only one event found, treat it as a single event result
handleFoundEvent(eventArray[0]);
} else {
// Multiple events found, show as search results
console.log(`[Events] Found ${eventArray.length} events with d-tag: ${dTag}`);
onSearchResults(eventArray);
}
} catch (err) {
console.error('[Events] Error searching by d-tag:', err);
localError = 'Error searching for events with this d-tag.';
onSearchResults([]);
} finally {
searching = false;
}
}
async function searchEvent(clearInput: boolean = true, queryOverride?: string) {
localError = null;
const query = (queryOverride !== undefined ? queryOverride : searchQuery).trim();
if (!query) return;
// Check if this is a d-tag search
if (query.startsWith('d:')) {
const dTag = query.slice(2).trim();
if (dTag) {
const encoded = encodeURIComponent(dTag);
goto(`?d=${encoded}`, { replaceState: false, keepFocus: true, noScroll: true });
return;
}
}
// Only update the URL if this is a manual search
if (clearInput) {
const encoded = encodeURIComponent(query);
@ -162,7 +220,7 @@ @@ -162,7 +220,7 @@
<div class="flex gap-2">
<Input
bind:value={searchQuery}
placeholder="Enter event ID, nevent, or naddr..."
placeholder="Enter event ID, nevent, naddr, or d:tag-name..."
class="flex-grow"
on:keydown={(e: KeyboardEvent) => e.key === 'Enter' && searchEvent(true)}
/>
@ -197,8 +255,5 @@ @@ -197,8 +255,5 @@
{#if !foundEvent && Object.values(relayStatuses).some(s => s === 'pending')}
<div class="text-gray-700 dark:text-gray-300 mt-2">Searching relays...</div>
{/if}
{#if !foundEvent && !searching && Object.values(relayStatuses).every(s => s !== 'pending')}
<div class="text-red-500 mt-2">Event not found on any relay.</div>
{/if}
</div>
</div>

2
src/lib/utils/markup/MarkupInfo.md

@ -30,7 +30,7 @@ The **advanced markup parser** includes all features of the basic parser, plus: @@ -30,7 +30,7 @@ The **advanced markup parser** includes all features of the basic parser, plus:
- **Tables:** Pipe-delimited tables with or without headers
- **Footnotes:** `[^1]` or `[^Smith]`, which should appear where the footnote shall be placed, and will be displayed as unique, consecutive numbers
- **Footnote References:** `[^1]: footnote text` or `[^Smith]: Smith, Adam. 1984 "The Wiggle Mysteries`, which will be listed in order, at the bottom of the event, with back-reference links to the footnote, and text footnote labels appended
- **Wikilinks:** `[[NIP-54]]` will render as a hyperlink and goes to [NIP-54](./wiki?d=nip-54)
- **Wikilinks:** `[[NIP-54]]` will render as a hyperlink and goes to [NIP-54](./events?d=nip-54)
## Publications and Wikis

2
src/lib/utils/markup/basicMarkupParser.ts

@ -142,7 +142,7 @@ function replaceWikilinks(text: string): string { @@ -142,7 +142,7 @@ function replaceWikilinks(text: string): string {
return text.replace(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/g, (_match, target, label) => {
const normalized = normalizeDTag(target.trim());
const display = (label || target).trim();
const url = `./wiki?d=${normalized}`;
const url = `./events?d=${normalized}`;
// Output as a clickable <a> with the [[display]] format and matching link colors
return `<a class="wikilink text-primary-600 dark:text-primary-500 hover:underline" data-dtag="${normalized}" data-url="${url}" href="${url}">${display}</a>`;
});

92
src/routes/events/+page.svelte

@ -7,11 +7,15 @@ @@ -7,11 +7,15 @@
import EventDetails from '$lib/components/EventDetails.svelte';
import RelayActions from '$lib/components/RelayActions.svelte';
import CommentBox from '$lib/components/CommentBox.svelte';
import { userBadge } from '$lib/snippets/UserSnippets.svelte';
import { getMatchingTags, toNpub } from '$lib/utils/nostrUtils';
let loading = $state(false);
let error = $state<string | null>(null);
let searchValue = $state<string | null>(null);
let dTagValue = $state<string | null>(null);
let event = $state<NDKEvent | null>(null);
let searchResults = $state<NDKEvent[]>([]);
let profile = $state<{
name?: string;
display_name?: string;
@ -27,6 +31,7 @@ @@ -27,6 +31,7 @@
function handleEventFound(newEvent: NDKEvent) {
event = newEvent;
searchResults = [];
if (newEvent.kind === 0) {
try {
profile = JSON.parse(newEvent.content);
@ -38,10 +43,33 @@ @@ -38,10 +43,33 @@
}
}
function handleSearchResults(results: NDKEvent[]) {
searchResults = results;
event = null;
profile = null;
}
function getSummary(event: NDKEvent): string | undefined {
return getMatchingTags(event, 'summary')[0]?.[1];
}
function getDeferrelNaddr(event: NDKEvent): string | undefined {
// Look for a 'deferrel' tag, e.g. ['deferrel', 'naddr1...']
return getMatchingTags(event, 'deferrel')[0]?.[1];
}
$effect(() => {
const id = $page.url.searchParams.get('id');
const dTag = $page.url.searchParams.get('d');
if (id !== searchValue) {
searchValue = id;
dTagValue = null;
}
if (dTag !== dTagValue) {
dTagValue = dTag;
searchValue = null;
}
});
@ -60,9 +88,19 @@ @@ -60,9 +88,19 @@
<P class="mb-3">
Use this page to view any event (npub, nprofile, nevent, naddr, note, pubkey, or eventID).
You can also search for events by d-tag using the format "d:tag-name".
</P>
<EventSearch {loading} {error} {searchValue} {event} onEventFound={handleEventFound} />
<EventSearch
{loading}
{error}
{searchValue}
{dTagValue}
{event}
onEventFound={handleEventFound}
onSearchResults={handleSearchResults}
/>
{#if event}
<EventDetails {event} {profile} {searchValue} />
<RelayActions {event} />
@ -77,5 +115,57 @@ @@ -77,5 +115,57 @@
</div>
{/if}
{/if}
{#if searchResults.length > 0}
<div class="mt-8">
<Heading tag="h2" class="h-leather mb-4">
Search Results for d-tag: "{dTagValue}" ({searchResults.length} events)
</Heading>
<div class="space-y-4">
{#each searchResults as result, index}
<button
class="w-full text-left border border-gray-300 dark:border-gray-600 rounded-lg p-4 bg-white dark:bg-primary-900/70 hover:bg-gray-100 dark:hover:bg-primary-800 focus:bg-gray-100 dark:focus:bg-primary-800 focus:outline-none focus:ring-2 focus:ring-primary-500 transition-colors overflow-hidden"
onclick={() => handleEventFound(result)}
>
<div class="flex flex-col gap-1">
<div class="flex items-center gap-2 mb-1">
<span class="font-medium text-gray-800 dark:text-gray-100">Event {index + 1}</span>
<span class="text-xs text-gray-600 dark:text-gray-400">Kind: {result.kind}</span>
<span class="text-xs text-gray-600 dark:text-gray-400">
{@render userBadge(toNpub(result.pubkey) as string, undefined)}
</span>
<span class="text-xs text-gray-500 dark:text-gray-400 ml-auto">
{result.created_at ? new Date(result.created_at * 1000).toLocaleDateString() : 'Unknown date'}
</span>
</div>
{#if getSummary(result)}
<div class="text-sm text-primary-900 dark:text-primary-200 mb-1 line-clamp-2">
{getSummary(result)}
</div>
{/if}
{#if getDeferrelNaddr(result)}
<div class="text-xs text-primary-800 dark:text-primary-300 mb-1">
Read
<a
class="underline text-primary-700 dark:text-primary-400 hover:text-primary-900 dark:hover:text-primary-200 break-all"
href={'/publications?d=' + encodeURIComponent(dTagValue || '')}
onclick={e => e.stopPropagation()}
tabindex="0"
>
{getDeferrelNaddr(result)}
</a>
</div>
{/if}
{#if result.content}
<div class="text-sm text-gray-800 dark:text-gray-200 mt-1 line-clamp-2 break-words">
{result.content.slice(0, 200)}{result.content.length > 200 ? '...' : ''}
</div>
{/if}
</div>
</button>
{/each}
</div>
</div>
{/if}
</main>
</div>

Loading…
Cancel
Save