import { SecondaryPageLink } from '@/PageManager' import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' import { CommandDialog, CommandInput, CommandItem, CommandList } from '@/components/ui/command' import { useSearchProfiles } from '@/hooks' import { toNote, toNoteList, toProfile, toProfileList, toRelay } from '@/lib/link' import { generateImageByPubkey } from '@/lib/pubkey' import { normalizeUrl } from '@/lib/url' import { TProfile } from '@/types' import { Hash, Notebook, Server, UserRound } from 'lucide-react' import { nip19 } from 'nostr-tools' import { Dispatch, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' export function SearchDialog({ open, setOpen }: { open: boolean; setOpen: Dispatch }) { const { t } = useTranslation() const [input, setInput] = useState('') const [debouncedInput, setDebouncedInput] = useState(input) const { profiles } = useSearchProfiles(debouncedInput, 10) const normalizedUrl = useMemo(() => { if (['w', 'ws', 'ws:', 'ws:/', 'wss', 'wss:', 'wss:/'].includes(input)) { return undefined } try { return normalizeUrl(input) } catch { return undefined } }, [input]) const list = useMemo(() => { const search = input.trim() if (!search) return if (/^[0-9a-f]{64}$/.test(search)) { return ( <> setOpen(false)} /> setOpen(false)} /> ) } try { let id = search if (id.startsWith('nostr:')) { id = id.slice(6) } const { type } = nip19.decode(id) if (['nprofile', 'npub'].includes(type)) { return setOpen(false)} /> } if (['nevent', 'naddr', 'note'].includes(type)) { return setOpen(false)} /> } } catch { // ignore } return ( <> setOpen(false)} /> setOpen(false)} /> {!!normalizedUrl && setOpen(false)} />} {profiles.map((profile) => ( setOpen(false)} /> ))} {profiles.length >= 10 && ( setOpen(false)}> setOpen(false)} className="text-center">
{t('Show more...')}
)} ) }, [input, debouncedInput, profiles, setOpen]) useEffect(() => { const handler = setTimeout(() => { setDebouncedInput(input) }, 500) return () => { clearTimeout(handler) } }, [input]) return ( {list} ) } function NormalItem({ search, onClick }: { search: string; onClick?: () => void }) { return (
{search}
) } function HashtagItem({ search, onClick }: { search: string; onClick?: () => void }) { const hashtag = search.match(/[\p{L}\p{N}\p{M}]+/u)?.[0].toLowerCase() return (
{hashtag}
) } function NoteItem({ id, onClick }: { id: string; onClick?: () => void }) { return (
{id}
) } function ProfileIdItem({ id, onClick }: { id: string; onClick?: () => void }) { return (
{id}
) } function ProfileItem({ profile, onClick }: { profile: TProfile; onClick?: () => void }) { return (
{profile.username}
{profile.username}
{profile.about}
) } function RelayItem({ url, onClick }: { url: string; onClick?: () => void }) { return (
{url}
) }