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.
147 lines
5.3 KiB
147 lines
5.3 KiB
import { Event, kinds, nip19 } from 'nostr-tools' |
|
import { ExtendedKind } from '@/constants' |
|
import { getNoteBech32Id, isReplaceableEvent } from './event' |
|
import { TSearchParams } from '@/types' |
|
|
|
/** Same kinds as {@link useMenuActions} `isArticleType` for naddr + Alexandria publication URLs. */ |
|
const ALEXANDRIA_PUBLICATION_NADDR_KINDS = new Set<number>([ |
|
kinds.LongFormArticle, |
|
ExtendedKind.PUBLICATION, |
|
ExtendedKind.PUBLICATION_CONTENT, |
|
ExtendedKind.WIKI_ARTICLE, |
|
ExtendedKind.WIKI_ARTICLE_MARKDOWN |
|
]) |
|
|
|
/** NIP-19 `naddr` for article-like replaceable events (`d` tag required). */ |
|
export function encodeArticleLikePublicationNaddr(event: Event): string | null { |
|
if (!ALEXANDRIA_PUBLICATION_NADDR_KINDS.has(event.kind)) return null |
|
const d = event.tags.find((t) => t[0] === 'd')?.[1] |
|
if (!d) return null |
|
try { |
|
const relays = event.tags |
|
.filter((tag) => tag[0] === 'relay') |
|
.map((tag) => tag[1]) |
|
.filter(Boolean) as string[] |
|
return nip19.naddrEncode({ |
|
kind: event.kind, |
|
pubkey: event.pubkey, |
|
identifier: d, |
|
relays: relays.length > 0 ? relays : undefined |
|
}) |
|
} catch { |
|
return null |
|
} |
|
} |
|
|
|
/** Full Alexandria reader URL for a publication `naddr` (matches NoteOptions “View on Alexandria”). */ |
|
export function getAlexandriaPublicationUrlFromNaddr(naddr: string): string { |
|
return `https://next-alexandria.gitcitadel.eu/publication/naddr/${naddr}` |
|
} |
|
|
|
export function openAlexandriaPublicationFromNaddr(naddr: string): void { |
|
const trimmed = naddr.trim() |
|
if (!trimmed) return |
|
window.open(getAlexandriaPublicationUrlFromNaddr(trimmed), '_blank', 'noopener,noreferrer') |
|
} |
|
|
|
/** |
|
* Note URL path segment. When `eventOrId` is a 64-char hex id and `hexResolutionEvent` is a loaded |
|
* replaceable/addressable event for that note, use its naddr/nevent so links stay canonical. |
|
*/ |
|
export const toNote = (eventOrId: Event | string, hexResolutionEvent?: Event) => { |
|
if (typeof eventOrId === 'string') { |
|
if ( |
|
hexResolutionEvent && |
|
/^[0-9a-f]{64}$/i.test(eventOrId.trim()) && |
|
isReplaceableEvent(hexResolutionEvent.kind) |
|
) { |
|
return `/notes/${getNoteBech32Id(hexResolutionEvent)}` |
|
} |
|
return `/notes/${eventOrId}` |
|
} |
|
const nevent = getNoteBech32Id(eventOrId) |
|
return `/notes/${nevent}` |
|
} |
|
export const toNoteList = ({ |
|
hashtag, |
|
search, |
|
externalContentId, |
|
domain, |
|
kinds |
|
}: { |
|
hashtag?: string |
|
search?: string |
|
externalContentId?: string |
|
domain?: string |
|
kinds?: number[] |
|
}) => { |
|
const path = '/notes' |
|
const query = new URLSearchParams() |
|
if (hashtag) query.set('t', hashtag.toLowerCase()) |
|
if (kinds?.length) { |
|
kinds.forEach((k) => query.append('k', k.toString())) |
|
} |
|
if (search) query.set('s', search) |
|
if (externalContentId) query.set('i', externalContentId) |
|
if (domain) query.set('d', domain) |
|
return `${path}?${query.toString()}` |
|
} |
|
export const toProfile = (userId: string) => { |
|
if (userId.startsWith('npub') || userId.startsWith('nprofile')) return `/users/${userId}` |
|
const npub = nip19.npubEncode(userId) |
|
return `/users/${npub}` |
|
} |
|
export const toProfileList = ({ search, domain }: { search?: string; domain?: string }) => { |
|
const path = '/users' |
|
const query = new URLSearchParams() |
|
if (search) query.set('s', search) |
|
if (domain) query.set('d', domain) |
|
return `${path}?${query.toString()}` |
|
} |
|
export const toFollowingList = (pubkey: string) => { |
|
const npub = nip19.npubEncode(pubkey) |
|
return `/users/${npub}/following` |
|
} |
|
export const toOthersRelaySettings = (pubkey: string) => { |
|
const npub = nip19.npubEncode(pubkey) |
|
return `/users/${npub}/relays` |
|
} |
|
export const toSearch = (params?: TSearchParams) => { |
|
if (!params) return '/search' |
|
const query = new URLSearchParams() |
|
query.set('t', params.type) |
|
query.set('q', params.search) |
|
if (params.input) { |
|
query.set('i', params.input) |
|
} |
|
return `/search?${query.toString()}` |
|
} |
|
export const toRelaySettings = (tag?: 'mailbox' | 'favorite-relays') => { |
|
return '/settings/relays' + (tag ? '#' + tag : '') |
|
} |
|
export const toWallet = () => '/settings/wallet' |
|
export const toPostSettings = () => '/settings/posts' |
|
export const toGeneralSettings = () => '/settings/general' |
|
export const toRssFeedSettings = () => '/settings/rss-feeds' |
|
export const toFollowSetsSettings = () => '/settings/follow-sets' |
|
export const toEmojiSetsSettings = () => '/settings/emoji-sets' |
|
export const toCacheSettings = () => '/settings/cache' |
|
export const toPersonalListsSettings = () => '/settings/personal-lists' |
|
export const toProfileEditor = () => '/profile-editor' |
|
export const toRelay = (url: string) => `/relays/${encodeURIComponent(url)}` |
|
export const toRelayReviews = (url: string) => `/relays/${encodeURIComponent(url)}/reviews` |
|
export const toMuteList = () => '/mutes' |
|
|
|
export const toBookmarksList = () => '/bookmarks' |
|
|
|
export const toNotificationThreadFollowList = () => '/notification-thread-follow' |
|
export const toNotificationThreadMuteList = () => '/notification-thread-mute' |
|
|
|
export const toPinsList = () => '/pins' |
|
export const toInterestsList = () => '/interests' |
|
export const toUserEmojiList = () => '/user-emojis' |
|
|
|
export const toChachiChat = (relay: string, d: string) => { |
|
return `https://chachi.chat/${relay.replace(/^wss?:\/\//, '').replace(/\/$/, '')}/${d}` |
|
} |
|
export const toAlexandria = (id: string) => `https://next-alexandria.gitcitadel.eu/events?id=${encodeURIComponent(id)}`
|
|
|