You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

141 lines
3.9 KiB

<script lang="ts">
import { sessionManager } from '../../services/auth/session-manager.js';
import { signAndPublish } from '../../services/nostr/auth-handler.js';
import { relayManager } from '../../services/nostr/relay-manager.js';
import type { NostrEvent } from '../../types/nostr.js';
interface Props {
parentEvent: NostrEvent; // The event to reply to
onPublished?: () => void;
onCancel?: () => void;
}
let { parentEvent, onPublished, onCancel }: Props = $props();
let content = $state('');
let publishing = $state(false);
let includeClientTag = $state(true);
async function publish() {
if (!sessionManager.isLoggedIn()) {
alert('Please log in to reply');
return;
}
if (!content.trim()) {
alert('Reply cannot be empty');
return;
}
publishing = true;
try {
const tags: string[][] = [];
// Add NIP-10 threading tags for reply
const rootTag = parentEvent.tags.find((t) => t[0] === 'root');
const rootId = rootTag?.[1] || parentEvent.id;
tags.push(['e', parentEvent.id, '', 'reply']);
tags.push(['p', parentEvent.pubkey]);
tags.push(['root', rootId]);
if (includeClientTag) {
tags.push(['client', 'Aitherboard']);
}
const event: Omit<NostrEvent, 'id' | 'sig'> = {
kind: 1,
pubkey: sessionManager.getCurrentPubkey()!,
created_at: Math.floor(Date.now() / 1000),
tags,
content: content.trim()
};
// Get target inbox if replying
let targetInbox: string[] | undefined;
try {
const { fetchRelayLists } = await import('../../services/user-data.js');
const { inbox } = await fetchRelayLists(parentEvent.pubkey);
targetInbox = inbox;
} catch {
// Ignore errors, just use default relays
}
const relays = relayManager.getFeedPublishRelays(targetInbox);
const result = await signAndPublish(event, relays);
if (result.success.length > 0) {
content = '';
onPublished?.();
} else {
alert('Failed to publish reply');
}
} catch (error) {
console.error('Error publishing reply:', error);
alert('Error publishing reply');
} finally {
publishing = false;
}
}
</script>
<div class="reply-to-Feed-form">
<div class="reply-context mb-2 p-2 bg-fog-highlight dark:bg-fog-dark-highlight rounded text-sm">
<span class="font-semibold">Replying to:</span> {parentEvent.content.slice(0, 100)}...
</div>
<textarea
bind:value={content}
placeholder="Write a reply..."
class="w-full p-3 border border-fog-border dark:border-fog-dark-border rounded bg-fog-post dark:bg-fog-dark-post text-fog-text dark:text-fog-dark-text"
rows="6"
disabled={publishing}
></textarea>
<div class="flex items-center justify-between mt-2">
<label class="flex items-center gap-2 text-sm text-fog-text dark:text-fog-dark-text">
<input
type="checkbox"
bind:checked={includeClientTag}
class="rounded"
/>
Include client tag
</label>
<div class="flex gap-2">
{#if onCancel}
<button
onclick={onCancel}
class="px-4 py-2 text-sm border border-fog-border dark:border-fog-dark-border rounded hover:bg-fog-highlight dark:hover:bg-fog-dark-highlight"
disabled={publishing}
>
Cancel
</button>
{/if}
<button
onclick={publish}
class="px-4 py-2 text-sm bg-fog-accent dark:bg-fog-dark-accent text-white rounded hover:opacity-90 disabled:opacity-50"
disabled={publishing || !content.trim()}
>
{publishing ? 'Publishing...' : 'Reply'}
</button>
</div>
</div>
</div>
<style>
.reply-to-Feed-form {
margin-bottom: 1rem;
}
textarea {
resize: vertical;
min-height: 120px;
}
textarea:focus {
outline: none;
border-color: var(--fog-accent, #64748b);
}
</style>