Browse Source

bug-fixes

imwald
Silberengel 1 month ago
parent
commit
3598aa3085
  1. 1
      nip66-cron/index.mjs
  2. 18
      src/PageManager.tsx
  3. 2
      src/components/CreateWalletGuideToast/index.tsx
  4. 155
      src/components/Embedded/EmbeddedNote.tsx
  5. 22
      src/components/Note/index.tsx
  6. 45
      src/components/PostEditor/PostRelaySelector.tsx
  7. 2
      src/components/TooManyRelaysAlertDialog/index.tsx
  8. 28
      src/components/WebPreview/index.tsx
  9. 1
      src/constants.ts
  10. 23
      src/contexts/secondary-page-context.tsx
  11. 11
      src/hooks/useFetchWebMetadata.tsx
  12. 8
      src/i18n/locales/ar.ts
  13. 8
      src/i18n/locales/de.ts
  14. 8
      src/i18n/locales/en.ts
  15. 8
      src/i18n/locales/es.ts
  16. 8
      src/i18n/locales/fa.ts
  17. 8
      src/i18n/locales/fr.ts
  18. 8
      src/i18n/locales/hi.ts
  19. 8
      src/i18n/locales/it.ts
  20. 8
      src/i18n/locales/ja.ts
  21. 8
      src/i18n/locales/ko.ts
  22. 8
      src/i18n/locales/pl.ts
  23. 8
      src/i18n/locales/pt-BR.ts
  24. 8
      src/i18n/locales/pt-PT.ts
  25. 8
      src/i18n/locales/ru.ts
  26. 8
      src/i18n/locales/th.ts
  27. 8
      src/i18n/locales/zh.ts
  28. 23
      src/lib/note-renderable-kinds.ts

1
nip66-cron/index.mjs

@ -64,7 +64,6 @@ const DEFAULT_RELAYS_TO_MONITOR = [ @@ -64,7 +64,6 @@ const DEFAULT_RELAYS_TO_MONITOR = [
'wss://relay.nsec.app',
'wss://bucket.coracle.social',
'wss://spatia-arcana.com',
'wss://sendit.nosflare.com',
'wss://nostr-pub.wellorder.net',
'wss://pyramid.fiatjaf.com/',
'wss://nostr.lopp.social/',

18
src/PageManager.tsx

@ -42,6 +42,7 @@ import { normalizeUrl } from './lib/url' @@ -42,6 +42,7 @@ import { normalizeUrl } from './lib/url'
import modalManager from './services/modal-manager.service'
import { routes } from './routes'
import { useScreenSize } from './providers/ScreenSizeProvider'
import { SecondaryPageContext, useSecondaryPage } from '@/contexts/secondary-page-context'
/** Lazy-loaded so PageManager does not synchronously import SpellsPage (avoids HMR cycle: SpellsPage → PrimaryPageLayout → PageManager → SpellsPage). */
const SpellsPageLazy = lazy(() => import('./pages/primary/SpellsPage'))
@ -78,13 +79,6 @@ type TPrimaryPageContext = { @@ -78,13 +79,6 @@ type TPrimaryPageContext = {
display: boolean
}
type TSecondaryPageContext = {
push: (url: string) => void
pop: () => void
currentIndex: number
navigateToPrimaryPage: (page: TPrimaryPageName, props?: object) => void
}
type TStackItem = {
index: number
url: string
@ -203,8 +197,6 @@ function mergePrimaryPageEntry( @@ -203,8 +197,6 @@ function mergePrimaryPageEntry(
export const PrimaryPageContext = createContext<TPrimaryPageContext | undefined>(undefined)
const SecondaryPageContext = createContext<TSecondaryPageContext | undefined>(undefined)
const PrimaryNoteViewContext = createContext<{
setPrimaryNoteView: (view: ReactNode | null, type?: 'note' | 'settings' | 'settings-sub' | 'profile' | 'hashtag' | 'relay' | 'following' | 'mute' | 'others-relay-settings') => void
primaryViewType: 'note' | 'settings' | 'settings-sub' | 'profile' | 'hashtag' | 'relay' | 'following' | 'mute' | 'others-relay-settings' | null
@ -228,13 +220,7 @@ export function usePrimaryPage() { @@ -228,13 +220,7 @@ export function usePrimaryPage() {
return context
}
export function useSecondaryPage() {
const context = useContext(SecondaryPageContext)
if (!context) {
throw new Error('useSecondaryPage must be used within a SecondaryPageContext.Provider')
}
return context
}
export { useSecondaryPage }
export function usePrimaryNoteView() {
const context = useContext(PrimaryNoteViewContext)

2
src/components/CreateWalletGuideToast/index.tsx

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { toWallet } from '@/lib/link'
import { useSecondaryPage } from '@/PageManager'
import { useSecondaryPage } from '@/contexts/secondary-page-context'
import { useNostr } from '@/providers/NostrProvider'
import storage from '@/services/local-storage.service'
import { useEffect } from 'react'

155
src/components/Embedded/EmbeddedNote.tsx

@ -1,14 +1,16 @@ @@ -1,14 +1,16 @@
import { Skeleton } from '@/components/ui/skeleton'
import { FAST_READ_RELAY_URLS, SEARCHABLE_RELAY_URLS, ExtendedKind } from '@/constants'
import { isRenderableNoteKind } from '@/lib/note-renderable-kinds'
import { useFetchEvent } from '@/hooks'
import { normalizeUrl } from '@/lib/url'
import { cn } from '@/lib/utils'
import client from '@/services/client.service'
import { useTranslation } from 'react-i18next'
import { useEffect, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import { Event, nip19 } from 'nostr-tools'
import ClientSelect from '../ClientSelect'
import MainNoteCard from '../NoteCard/MainNoteCard'
import UnknownNote from '../Note/UnknownNote'
import { Button } from '../ui/button'
import { EmbeddedCalendarEvent } from './EmbeddedCalendarEvent'
import { Search } from 'lucide-react'
@ -44,14 +46,140 @@ function canSearchOnExternalRelays(noteId: string): boolean { @@ -44,14 +46,140 @@ function canSearchOnExternalRelays(noteId: string): boolean {
}
}
export function EmbeddedNote({
noteId,
export type EmbeddedNoteIdValidation =
| { valid: true }
| {
valid: false
reason: 'empty' | 'invalid_hex' | 'invalid_bech32' | 'wrong_nip19_type'
decodedType?: string
}
/**
* Only hex (64), note1, nevent1, and naddr1 are valid embedded note targets.
* Malformed bech32, wrong kinds (npub, ), or bad hex length fail before fetch/search UI.
*/
export function validateEmbeddedNotePointer(noteId: string): EmbeddedNoteIdValidation {
const s = noteId.trim()
if (!s) return { valid: false, reason: 'empty' }
if (/^[0-9a-f]{64}$/i.test(s)) return { valid: true }
if (/^[0-9a-f]+$/i.test(s)) {
return { valid: false, reason: 'invalid_hex' }
}
const looksLikeNostrBech32 =
s.startsWith('n') && s.includes('1') && /^[a-z0-9]+$/i.test(s) && s.length >= 10
if (looksLikeNostrBech32) {
try {
const { type } = nip19.decode(s)
if (type === 'note' || type === 'nevent' || type === 'naddr') return { valid: true }
return { valid: false, reason: 'wrong_nip19_type', decodedType: type }
} catch {
return { valid: false, reason: 'invalid_bech32' }
}
}
try {
const { type } = nip19.decode(s)
if (type === 'note' || type === 'nevent' || type === 'naddr') return { valid: true }
return { valid: false, reason: 'wrong_nip19_type', decodedType: type }
} catch {
return { valid: false, reason: 'invalid_bech32' }
}
}
export function EmbeddedNote({
noteId,
className,
containingEvent
}: {
containingEvent
}: {
noteId: string
className?: string
containingEvent?: Event // Event that contains this embedded note - use its author's relays and relay hints
containingEvent?: Event
}) {
const validation = useMemo(() => validateEmbeddedNotePointer(noteId), [noteId])
if (!validation.valid) {
return (
<EmbeddedNoteInvalid
className={className}
noteId={noteId}
validation={validation}
/>
)
}
return (
<EmbeddedNoteContent
noteId={noteId}
className={className}
containingEvent={containingEvent}
/>
)
}
function EmbeddedNoteInvalid({
noteId,
className,
validation
}: {
noteId: string
className?: string
validation: Exclude<EmbeddedNoteIdValidation, { valid: true }>
}) {
const { t } = useTranslation()
const trimmed = noteId.trim()
const isNsecLike = /^nsec1/i.test(trimmed) || validation.decodedType === 'nsec'
const preview =
trimmed.length > 96 ? `${trimmed.slice(0, 96)}` : trimmed || '—'
let message: string
switch (validation.reason) {
case 'empty':
message = t('embeddedNoteInvalidEmpty')
break
case 'invalid_hex':
message = t('embeddedNoteInvalidHex')
break
case 'wrong_nip19_type':
message = t('embeddedNoteInvalidWrongKind', {
type: validation.decodedType ?? 'unknown'
})
break
case 'invalid_bech32':
default:
message = t('embeddedNoteInvalidBech32')
break
}
return (
<div
className={cn('text-left p-3 border border-destructive/30 rounded-lg bg-destructive/5', className)}
onClick={(e) => e.stopPropagation()}
data-embedded-note-invalid
>
<div className="flex flex-col gap-2 text-muted-foreground">
<div className="text-sm font-medium text-destructive">{t('Invalid embedded note reference')}</div>
<p className="text-xs leading-relaxed">{message}</p>
{validation.reason !== 'empty' && !isNsecLike && (
<pre className="text-[10px] font-mono whitespace-pre-wrap break-all rounded bg-muted/50 p-2 text-foreground/80">
{preview}
</pre>
)}
<ClientSelect className="w-full" originalNoteId={trimmed || undefined} />
</div>
</div>
)
}
function EmbeddedNoteContent({
noteId,
className,
containingEvent
}: {
noteId: string
className?: string
containingEvent?: Event
}) {
const { event, isFetching } = useFetchEvent(noteId)
const [retryEvent, setRetryEvent] = useState<Event | undefined>(undefined)
@ -118,6 +246,21 @@ export function EmbeddedNote({ @@ -118,6 +246,21 @@ export function EmbeddedNote({
)
}
if (!isRenderableNoteKind(finalEvent.kind)) {
return (
<div
data-embedded-note
data-embedded-unsupported
onClick={(e) => e.stopPropagation()}
>
<UnknownNote
event={finalEvent}
className={cn('my-0 p-2 sm:p-3 border rounded-lg w-full', className)}
/>
</div>
)
}
// Otherwise, render as regular embedded note
return (
<div data-embedded-note onClick={(e) => e.stopPropagation()}>

22
src/components/Note/index.tsx

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
import { useSmartNoteNavigation } from '@/PageManager'
import { ExtendedKind, SUPPORTED_KINDS } from '@/constants'
import { ExtendedKind } from '@/constants'
import { isRenderableNoteKind } from '@/lib/note-renderable-kinds'
import { getParentBech32Id, isNsfwEvent } from '@/lib/event'
import { toNote } from '@/lib/link'
import logger from '@/lib/logger'
@ -117,24 +118,7 @@ export default function Note({ @@ -117,24 +118,7 @@ export default function Note({
let content: React.ReactNode
const supportedKindsList = [
...SUPPORTED_KINDS,
kinds.CommunityDefinition,
kinds.LiveEvent,
ExtendedKind.GROUP_METADATA,
ExtendedKind.PUBLIC_MESSAGE,
ExtendedKind.ZAP_REQUEST,
ExtendedKind.ZAP_RECEIPT,
ExtendedKind.PUBLICATION_CONTENT, // Only for rendering embedded content, not in feeds
ExtendedKind.FOLLOW_PACK, // Follow-pack feed + embedded previews
ExtendedKind.CITATION_INTERNAL, // Citations for rendering
ExtendedKind.CITATION_EXTERNAL,
ExtendedKind.CITATION_HARDCOPY,
ExtendedKind.CITATION_PROMPT
]
if (!supportedKindsList.includes(event.kind)) {
if (!isRenderableNoteKind(event.kind)) {
logger.debug('Note component - rendering UnknownNote for unsupported kind:', event.kind)
content = <UnknownNote className="mt-2" event={event} />
} else if (mutePubkeySet.has(event.pubkey) && !showMuted) {

45
src/components/PostEditor/PostRelaySelector.tsx

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
import { NOSTR_URI_FOR_REPLY_PUBKEYS_REGEX } from '@/lib/content-patterns'
import { simplifyUrl, isLocalNetworkUrl, normalizeUrl } from '@/lib/url'
import { useCurrentRelays } from '@/providers/CurrentRelaysProvider'
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
@ -71,6 +72,21 @@ export default function PostRelaySelector({ @@ -71,6 +72,21 @@ export default function PostRelaySelector({
return false
}, [_parentEvent])
/**
* Relay selection only cares about nostr: mentions in the draft (see relay-selection.service).
* Depending on full `postContent` re-ran the heavy relay effect on every keystroke.
*/
const contentRelaySignature = useMemo(() => {
if (isDiscussionReply) return ''
if (isPublicMessage && mentions.length > 0) {
// PM recipients come from `mentions` when set; content is ignored by selection service
return ''
}
const matches = [...postContent.matchAll(NOSTR_URI_FOR_REPLY_PUBKEYS_REGEX)].map((m) => m[0])
if (!matches.length) return ''
return [...new Set(matches)].sort().join('\n')
}, [postContent, isDiscussionReply, isPublicMessage, mentions])
// Memoize arrays to prevent unnecessary re-renders
const memoizedFavoriteRelays = useMemo(() => favoriteRelays, [favoriteRelays])
const memoizedBlockedRelays = useMemo(() => blockedRelays, [blockedRelays])
@ -164,7 +180,19 @@ export default function PostRelaySelector({ @@ -164,7 +180,19 @@ export default function PostRelaySelector({
}
updateRelaySelection()
}, [memoizedOpenFrom, _parentEvent, memoizedFavoriteRelays, memoizedBlockedRelays, memoizedRelaySets, isPublicMessage, pubkey, relayList, isDiscussionReply, postContent, mentions])
}, [
memoizedOpenFrom,
_parentEvent,
memoizedFavoriteRelays,
memoizedBlockedRelays,
memoizedRelaySets,
isPublicMessage,
pubkey,
relayList,
isDiscussionReply,
contentRelaySignature,
mentions
])
// Separate effect for mention changes in non-discussion replies
useEffect(() => {
@ -253,7 +281,20 @@ export default function PostRelaySelector({ @@ -253,7 +281,20 @@ export default function PostRelaySelector({
updateRelaySelection()
}
}, [mentions, isDiscussionReply, memoizedFavoriteRelays, memoizedBlockedRelays, memoizedRelaySets, _parentEvent, isPublicMessage, pubkey, relayList, memoizedOpenFrom, previousSelectableCount, hasManualSelection, postContent])
}, [
mentions,
isDiscussionReply,
memoizedFavoriteRelays,
memoizedBlockedRelays,
memoizedRelaySets,
_parentEvent,
isPublicMessage,
pubkey,
relayList,
memoizedOpenFrom,
previousSelectableCount,
hasManualSelection
])
// Update description when selected relays change due to manual selection
useEffect(() => {

2
src/components/TooManyRelaysAlertDialog/index.tsx

@ -16,7 +16,7 @@ import { @@ -16,7 +16,7 @@ import {
DrawerTitle
} from '@/components/ui/drawer'
import { toRelaySettings } from '@/lib/link'
import { useSecondaryPage } from '@/PageManager'
import { useSecondaryPage } from '@/contexts/secondary-page-context'
import { useNostr } from '@/providers/NostrProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import storage from '@/services/local-storage.service'

28
src/components/WebPreview/index.tsx

@ -7,6 +7,7 @@ import { extractBookMetadata } from '@/lib/bookstr-parser' @@ -7,6 +7,7 @@ import { extractBookMetadata } from '@/lib/bookstr-parser'
import { cn } from '@/lib/utils'
import { useContentPolicy } from '@/providers/ContentPolicyProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { Skeleton } from '@/components/ui/skeleton'
import { ExternalLink } from 'lucide-react'
import { nip19, kinds } from 'nostr-tools'
import { useMemo, useEffect, useState } from 'react'
@ -459,15 +460,28 @@ export default function WebPreview({ url, className }: { url: string; className? @@ -459,15 +460,28 @@ export default function WebPreview({ url, className }: { url: string; className?
return null
}
// Always try to fetch OG data for standalone hyperlinks (except internal jumble links)
// Check if we have any opengraph data (title, description, or image)
// Prefer the page's own Open Graph / meta when the fetch returns anything useful.
const hasOpengraphData = !isInternalJumbleLink && (title || description || image)
// Show enhanced fallback link card if:
// 1. No OG data available, OR
// 2. A nostr identifier was detected (we want to show the detailed nostr card even with OG data)
// Note: We always attempt to fetch OG data via useFetchWebMetadata hook above
if (!hasOpengraphData || nostrIdentifier) {
// While OG is loading for external URLs, avoid flashing the nostr / hostname fallback.
if (!isInternalJumbleLink && ogLoading) {
return (
<div
className={cn('p-2 flex w-full border rounded-lg overflow-hidden gap-2 max-w-full', className)}
onClick={(e) => e.stopPropagation()}
>
<Skeleton className="h-20 w-20 sm:w-40 shrink-0 rounded-l-md rounded-r-none" />
<div className="flex-1 min-w-0 space-y-2 py-1">
<Skeleton className="h-3 w-24" />
<Skeleton className="h-4 w-full" />
<Skeleton className="h-3 w-4/5" />
</div>
</div>
)
}
// Nostr-enhanced cards only when the target page did not provide usable preview metadata.
if (!hasOpengraphData) {
// Enhanced card for event URLs (always show if nostr identifier detected, even while loading)
if (nostrType === 'naddr' || nostrType === 'nevent' || nostrType === 'note') {
const eventTypeName = fetchedEvent ? getEventTypeName(fetchedEvent.kind) : null

1
src/constants.ts

@ -183,7 +183,6 @@ export const SEARCHABLE_RELAY_URLS = [ @@ -183,7 +183,6 @@ export const SEARCHABLE_RELAY_URLS = [
'wss://relay.nsec.app',
'wss://bucket.coracle.social',
'wss://spatia-arcana.com',
'wss://sendit.nosflare.com',
'wss://nostr-pub.wellorder.net',
'wss://pyramid.fiatjaf.com/',
'wss://nostr.lopp.social/',

23
src/contexts/secondary-page-context.tsx

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
import { createContext, useContext } from 'react'
/**
* Lives in a dedicated module so lazy chunks (e.g. TooManyRelaysAlertDialog) share the same
* context instance as PageManager. Importing from PageManager into those chunks can duplicate
* the module and break Provider matching (useSecondaryPage throws "must be used within Provider").
*/
export type SecondaryPageContextValue = {
push: (url: string) => void
pop: () => void
currentIndex: number
navigateToPrimaryPage: (page: string, props?: object) => void
}
export const SecondaryPageContext = createContext<SecondaryPageContextValue | undefined>(undefined)
export function useSecondaryPage(): SecondaryPageContextValue {
const context = useContext(SecondaryPageContext)
if (!context) {
throw new Error('useSecondaryPage must be used within a SecondaryPageContext.Provider')
}
return context
}

11
src/hooks/useFetchWebMetadata.tsx

@ -6,14 +6,20 @@ import { isLikelyWebPageUrl } from '@/lib/url' @@ -6,14 +6,20 @@ import { isLikelyWebPageUrl } from '@/lib/url'
export function useFetchWebMetadata(url: string) {
const [metadata, setMetadata] = useState<TWebMetadata>({})
const [ogLoading, setOgLoading] = useState(() => Boolean(url && isLikelyWebPageUrl(url)))
useEffect(() => {
if (!url || !isLikelyWebPageUrl(url)) {
setMetadata({})
setOgLoading(false)
return
}
logger.debug('[useFetchWebMetadata] Fetching OG metadata', { url })
setOgLoading(true)
setMetadata({})
webService.fetchWebMetadata(url)
.then((metadata) => {
logger.debug('[useFetchWebMetadata] Received metadata', { url, hasTitle: !!metadata.title, hasDescription: !!metadata.description, hasImage: !!metadata.image })
@ -22,7 +28,10 @@ export function useFetchWebMetadata(url: string) { @@ -22,7 +28,10 @@ export function useFetchWebMetadata(url: string) {
.catch((error) => {
logger.debug('[useFetchWebMetadata] Failed to fetch metadata', { url, error })
})
.finally(() => {
setOgLoading(false)
})
}, [url])
return metadata
return { ...metadata, ogLoading }
}

8
src/i18n/locales/ar.ts

@ -393,6 +393,14 @@ export default { @@ -393,6 +393,14 @@ export default {
'Seen on': 'شوهد على',
'Temporarily display this reply': 'عرض هذا الرد مؤقتاً',
'Note not found': 'لم يتم العثور على الملاحظة',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/de.ts

@ -402,6 +402,14 @@ export default { @@ -402,6 +402,14 @@ export default {
'Seen on': 'Gesehen auf',
'Temporarily display this reply': 'Antwort vorübergehend anzeigen',
'Note not found': 'Die Notiz wurde nicht gefunden',
'Invalid embedded note reference': 'Ungültige eingebettete Notiz-Referenz',
embeddedNoteInvalidEmpty: 'Dieser eingebettete Link ist leer.',
embeddedNoteInvalidHex:
'Keine gültige Hex-Event-ID (es werden genau 64 hexadezimale Zeichen erwartet).',
embeddedNoteInvalidBech32:
'Keine gültige Nostr-ID (Bech32 konnte nicht gelesen werden). Tippfehler oder abgeschnittene Adresse?',
embeddedNoteInvalidWrongKind:
'Dies ist eine {{type}}-Adresse. Eingebettete Notizen brauchen note1, nevent1, naddr1 oder 64 Zeichen Hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/en.ts

@ -394,6 +394,14 @@ export default { @@ -394,6 +394,14 @@ export default {
'Seen on': 'Seen on',
'Temporarily display this reply': 'Temporarily display this reply',
'Note not found': 'Note not found',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/es.ts

@ -397,6 +397,14 @@ export default { @@ -397,6 +397,14 @@ export default {
'Seen on': 'Visto en',
'Temporarily display this reply': 'Mostrar temporalmente esta respuesta',
'Note not found': 'No se encontró la nota',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/fa.ts

@ -396,6 +396,14 @@ export default { @@ -396,6 +396,14 @@ export default {
'Seen on': 'دیده شده در',
'Temporarily display this reply': 'نمایش موقت این پاسخ',
'Note not found': 'یادداشت یافت نشد',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/fr.ts

@ -396,6 +396,14 @@ export default { @@ -396,6 +396,14 @@ export default {
'Seen on': 'Vu sur',
'Temporarily display this reply': 'Afficher temporairement cette réponse',
'Note not found': 'Note introuvable',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/hi.ts

@ -397,6 +397,14 @@ export default { @@ -397,6 +397,14 @@ export default {
'Seen on': 'पर द गय',
'Temporarily display this reply': 'इस उततर क असप सरदरित कर',
'Note not found': 'नट नहि',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/it.ts

@ -397,6 +397,14 @@ export default { @@ -397,6 +397,14 @@ export default {
'Seen on': 'Visto su',
'Temporarily display this reply': 'Mostra temporaneamente questa replica',
'Note not found': 'Non è stata trovata la nota',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/ja.ts

@ -394,6 +394,14 @@ export default { @@ -394,6 +394,14 @@ export default {
'Seen on': '見た',
'Temporarily display this reply': 'この返信を一時的に表示',
'Note not found': 'ノートが見つかりません',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/ko.ts

@ -393,6 +393,14 @@ export default { @@ -393,6 +393,14 @@ export default {
'Seen on': '출처',
'Temporarily display this reply': '이 답글 임시 표시',
'Note not found': '노트를 찾을 수 없음',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/pl.ts

@ -394,6 +394,14 @@ export default { @@ -394,6 +394,14 @@ export default {
'Seen on': 'Widziany na',
'Temporarily display this reply': 'Tymczasowo wyświetl tę odpowiedź',
'Note not found': 'Nie znaleziono wpisu',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/pt-BR.ts

@ -396,6 +396,14 @@ export default { @@ -396,6 +396,14 @@ export default {
'Seen on': 'Visto em',
'Temporarily display this reply': 'Exibir temporariamente esta resposta',
'Note not found': 'Nota não encontrada',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/pt-PT.ts

@ -396,6 +396,14 @@ export default { @@ -396,6 +396,14 @@ export default {
'Seen on': 'Visto em',
'Temporarily display this reply': 'Exibir temporariamente esta resposta',
'Note not found': 'Nota não encontrada',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/ru.ts

@ -397,6 +397,14 @@ export default { @@ -397,6 +397,14 @@ export default {
'Seen on': 'Просмотрено на',
'Temporarily display this reply': 'Временно отобразить этот ответ',
'Note not found': 'Заметка не найдена',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/th.ts

@ -393,6 +393,14 @@ export default { @@ -393,6 +393,14 @@ export default {
'Seen on': 'เหนเมอ',
'Temporarily display this reply': 'แสดงการตอบกลบนวคราว',
'Note not found': 'ไมพบโนต',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

8
src/i18n/locales/zh.ts

@ -392,6 +392,14 @@ export default { @@ -392,6 +392,14 @@ export default {
'Seen on': '来自',
'Temporarily display this reply': '临时显示此回复',
'Note not found': '未找到该笔记',
'Invalid embedded note reference': 'Invalid embedded note reference',
embeddedNoteInvalidEmpty: 'This embedded link is empty.',
embeddedNoteInvalidHex:
'This is not a valid hex event id (expected exactly 64 hexadecimal characters).',
embeddedNoteInvalidBech32:
'This is not a valid Nostr id (bech32 decode failed). It may be mistyped or truncated.',
embeddedNoteInvalidWrongKind:
'This is a {{type}} id. Embedded notes must use note1, nevent1, naddr1, or 64-character hex.',
'The note was not found on your relays or default relays.':
'The note was not found on your relays or default relays.',
"Try searching author's relays": "Try searching author's relays",

23
src/lib/note-renderable-kinds.ts

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
import { ExtendedKind, SUPPORTED_KINDS } from '@/constants'
import { kinds } from 'nostr-tools'
/** Kinds the main `Note` component renders with a dedicated UI (not `UnknownNote`). */
const RENDERABLE_NOTE_KINDS = new Set<number>([
...SUPPORTED_KINDS,
kinds.CommunityDefinition,
kinds.LiveEvent,
ExtendedKind.GROUP_METADATA,
ExtendedKind.PUBLIC_MESSAGE,
ExtendedKind.ZAP_REQUEST,
ExtendedKind.ZAP_RECEIPT,
ExtendedKind.PUBLICATION_CONTENT,
ExtendedKind.FOLLOW_PACK,
ExtendedKind.CITATION_INTERNAL,
ExtendedKind.CITATION_EXTERNAL,
ExtendedKind.CITATION_HARDCOPY,
ExtendedKind.CITATION_PROMPT
])
export function isRenderableNoteKind(kind: number): boolean {
return RENDERABLE_NOTE_KINDS.has(kind)
}
Loading…
Cancel
Save