Browse Source

Tidy and organize Nostr event embedding markup

- Svelte components and snippets that support embedded event rendering are moved to `src/lib/components/embedded_events` dir.
- Some now-unused components are removed entirely.
- Imports are updated.
master
buttercat1791 7 months ago
parent
commit
98dba98b93
  1. 2
      src/lib/components/CommentViewer.svelte
  2. 100
      src/lib/components/ContentWithEmbeddedEvents.svelte
  3. 83
      src/lib/components/EmbeddedEventRenderer.svelte
  4. 2
      src/lib/components/EventDetails.svelte
  5. 4
      src/lib/components/Notifications.svelte
  6. 2
      src/lib/components/embedded_events/EmbeddedEvent.svelte
  7. 0
      src/lib/components/embedded_events/EmbeddedSnippets.svelte
  8. 2
      src/routes/events/+page.svelte

2
src/lib/components/CommentViewer.svelte

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
import { goto } from "$app/navigation";
import { onMount } from "svelte";
import type { NDKEvent } from "@nostr-dev-kit/ndk";
import EmbeddedEvent from "./EmbeddedEvent.svelte";
import EmbeddedEvent from "./embedded_events/EmbeddedEvent.svelte";
const { event } = $props<{ event: NDKEvent }>();

100
src/lib/components/ContentWithEmbeddedEvents.svelte

@ -1,100 +0,0 @@ @@ -1,100 +0,0 @@
<script lang="ts">
import { onMount } from "svelte";
import { parseBasicmarkup } from "$lib/utils/markup/basicMarkupParser";
import EmbeddedEvent from "./EmbeddedEvent.svelte";
const {
content,
nestingLevel = 0,
} = $props<{
content: string;
nestingLevel?: number;
}>();
let parsedContent = $state("");
let embeddedEvents = $state<Array<{
id: string;
nostrId: string;
nestingLevel: number;
}>>([]);
// Maximum nesting level allowed
const MAX_NESTING_LEVEL = 3;
// AI-NOTE: 2025-01-24 - Component for rendering content with embedded Nostr events
// Processes content and replaces nostr: links with EmbeddedEvent components
$effect(() => {
if (content) {
processContent();
}
});
async function processContent() {
try {
// First parse the basic markup
parsedContent = await parseBasicmarkup(content);
// Then find and extract embedded events
extractEmbeddedEvents();
} catch (error) {
console.error("Error processing content:", error);
parsedContent = content; // Fallback to raw content
}
}
function extractEmbeddedEvents() {
const nostrPattern = /nostr:(npub|nprofile|note|nevent|naddr)[a-zA-Z0-9]{20,}/g;
const events: Array<{
id: string;
nostrId: string;
nestingLevel: number;
}> = [];
let match;
while ((match = nostrPattern.exec(parsedContent)) !== null) {
const nostrId = match[0];
const componentId = `embedded-event-${Math.random().toString(36).substr(2, 9)}`;
events.push({
id: componentId,
nostrId,
nestingLevel: nestingLevel,
});
// Replace the nostr: link with a placeholder
parsedContent = parsedContent.replace(
nostrId,
`<div class="embedded-event-placeholder" data-component-id="${componentId}"></div>`
);
}
embeddedEvents = events;
}
function renderEmbeddedEvent(eventInfo: { id: string; nostrId: string; nestingLevel: number }) {
if (eventInfo.nestingLevel >= MAX_NESTING_LEVEL) {
// At max nesting level, just show the link
return `<a href="/events?id=${eventInfo.nostrId}" class="text-primary-600 dark:text-primary-500 hover:underline break-all">${eventInfo.nostrId}</a>`;
}
// Return a placeholder that will be replaced by the component
return `<div class="embedded-event-placeholder" data-component-id="${eventInfo.id}"></div>`;
}
</script>
<div class="content-with-embedded-events min-w-0 overflow-hidden">
{@html parsedContent}
<!-- Render embedded events -->
{#each embeddedEvents as eventInfo}
<div class="my-4 min-w-0 overflow-hidden" data-component-id={eventInfo.id}>
<EmbeddedEvent
nostrIdentifier={eventInfo.nostrId}
nestingLevel={eventInfo.nestingLevel}
/>
</div>
{/each}
</div>

83
src/lib/components/EmbeddedEventRenderer.svelte

@ -1,83 +0,0 @@ @@ -1,83 +0,0 @@
<script lang="ts">
import { onMount } from "svelte";
import EmbeddedEvent from "./EmbeddedEvent.svelte";
const {
content,
nestingLevel = 0,
} = $props<{
content: string;
nestingLevel?: number;
}>();
let embeddedEvents = $state<Array<{
id: string;
nostrId: string;
nestingLevel: number;
}>>([]);
// AI-NOTE: 2025-01-24 - Component that renders content and replaces embedded event placeholders
// with actual EmbeddedEvent components
$effect(() => {
if (content) {
extractEmbeddedEvents();
}
});
function extractEmbeddedEvents() {
const placeholderPattern = /<div class="embedded-event-placeholder" data-nostr-id="([^"]+)" data-nesting-level="(\d+)" id="([^"]+)"><\/div>/g;
const events: Array<{
id: string;
nostrId: string;
nestingLevel: number;
}> = [];
let match;
while ((match = placeholderPattern.exec(content)) !== null) {
const nostrId = match[1];
const level = parseInt(match[2], 10);
const componentId = match[3];
// Only process event-related identifiers (note, nevent, naddr)
if (nostrId.match(/^nostr:(note|nevent|naddr)/)) {
events.push({
id: componentId,
nostrId,
nestingLevel: level,
});
}
}
embeddedEvents = events;
}
function renderContent() {
let renderedContent = content;
// Replace placeholders with component references
embeddedEvents.forEach(eventInfo => {
const placeholder = `<div class="embedded-event-placeholder" data-nostr-id="${eventInfo.nostrId}" data-nesting-level="${eventInfo.nestingLevel}" id="${eventInfo.id}"></div>`;
const componentRef = `<div class="embedded-event-component" data-component-id="${eventInfo.id}"></div>`;
renderedContent = renderedContent.replace(placeholder, componentRef);
});
return renderedContent;
}
</script>
<div class="embedded-event-renderer">
{@html renderContent()}
<!-- Render embedded events -->
{#each embeddedEvents as eventInfo}
<div class="my-4" data-component-id={eventInfo.id}>
<EmbeddedEvent
nostrIdentifier={eventInfo.nostrId}
nestingLevel={eventInfo.nestingLevel}
/>
</div>
{/each}
</div>

2
src/lib/components/EventDetails.svelte

@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
import { navigateToEvent } from "$lib/utils/nostrEventService";
import ContainingIndexes from "$lib/components/util/ContainingIndexes.svelte";
import Notifications from "$lib/components/Notifications.svelte";
import EmbeddedEvent from "./EmbeddedEvent.svelte";
import EmbeddedEvent from "./embedded_events/EmbeddedEvent.svelte";
const {
event,

4
src/lib/components/Notifications.svelte

@ -18,11 +18,11 @@ @@ -18,11 +18,11 @@
getNotificationType,
fetchAuthorProfiles,
quotedContent,
} from "$lib/components/util/Notifications.svelte";
} from "$lib/components/embedded_events/EmbeddedSnippets.svelte";
import { buildCompleteRelaySet } from "$lib/utils/relay_management";
import { formatDate, neventEncode } from "$lib/utils";
import { NDKRelaySetFromNDK } from "$lib/utils/nostrUtils";
import EmbeddedEvent from "./EmbeddedEvent.svelte";
import EmbeddedEvent from "./embedded_events/EmbeddedEvent.svelte";
const { event } = $props<{ event: NDKEvent }>();

2
src/lib/components/EmbeddedEvent.svelte → src/lib/components/embedded_events/EmbeddedEvent.svelte

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
import { fetchEventWithFallback } from "$lib/utils/nostrUtils";
import { getUserMetadata, toNpub } from "$lib/utils/nostrUtils";
import { userBadge } from "$lib/snippets/UserSnippets.svelte";
import { parsedContent } from "$lib/components/util/Notifications.svelte";
import { parsedContent } from "$lib/components/embedded_events/EmbeddedSnippets.svelte";
import { naddrEncode } from "$lib/utils";
import { activeInboxRelays, ndkInstance } from "$lib/ndk";
import { goto } from "$app/navigation";

0
src/lib/components/util/Notifications.svelte → src/lib/components/embedded_events/EmbeddedSnippets.svelte

2
src/routes/events/+page.svelte

@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
import { getEventType } from "$lib/utils/mime";
import ViewPublicationLink from "$lib/components/util/ViewPublicationLink.svelte";
import { checkCommunity } from "$lib/utils/search_utility";
import EmbeddedEvent from "$lib/components/EmbeddedEvent.svelte";
import EmbeddedEvent from "$lib/components/embedded_events/EmbeddedEvent.svelte";
let loading = $state(false);
let error = $state<string | null>(null);

Loading…
Cancel
Save