diff --git a/packages/app/package.json b/packages/app/package.json index fe51c1cc3..03d0d68a5 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -36,6 +36,7 @@ "marked": "^9.1.0", "marked-footnote": "^1.0.0", "match-sorter": "^6.3.1", + "plebnames": "^0.2.4", "qr-code-styling": "^1.6.0-rc.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/packages/app/src/Components/SearchBox/SearchBox.tsx b/packages/app/src/Components/SearchBox/SearchBox.tsx index 3c44eb1aa..a8b7dbdc8 100644 --- a/packages/app/src/Components/SearchBox/SearchBox.tsx +++ b/packages/app/src/Components/SearchBox/SearchBox.tsx @@ -1,6 +1,7 @@ import "./SearchBox.css"; -import { NostrLink, tryParseNostrLink } from "@snort/system"; +import { NostrLink, NostrPrefix, tryParseNostrLink } from "@snort/system"; +import { bitcoinExplorer, PlebNameData, PlebNameHistory } from "plebnames"; import { ChangeEvent, useEffect, useRef, useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { useLocation, useNavigate } from "react-router-dom"; @@ -8,7 +9,9 @@ import { useLocation, useNavigate } from "react-router-dom"; import Icon from "@/Components/Icons/Icon"; import Spinner from "@/Components/Icons/Spinner"; import ProfileImage from "@/Components/User/ProfileImage"; +import { FuzzySearchResult } from "@/Db/FuzzySearch"; import useProfileSearch from "@/Hooks/useProfileSearch"; +import { bech32ToHex, hexToBech32 } from "@/Utils"; import { fetchNip05Pubkey } from "@/Utils/Nip05/Verifier"; const MAX_RESULTS = 3; @@ -18,6 +21,7 @@ export default function SearchBox() { const [search, setSearch] = useState(""); const [searching, setSearching] = useState(false); const [isFocused, setIsFocused] = useState(false); + const [plebname, setPlebname] = useState(undefined) const navigate = useNavigate(); const location = useLocation(); const inputRef = useRef(null); @@ -26,6 +30,9 @@ export default function SearchBox() { const resultListRef = useRef(null); const results = useProfileSearch(search); + if (plebname && plebname.name === search) { + results.unshift(plebname) + } useEffect(() => { const handleGlobalKeyDown = (e: KeyboardEvent) => { @@ -81,6 +88,21 @@ export default function SearchBox() { navigate(`/${val.trim()}`); e.preventDefault(); } else { + if (val.endsWith('.btc')) { + bitcoinExplorer.followNameHistory(val.substring(0, '.btc'.length)).then((nameHistory: PlebNameHistory|'unclaimed') => { + if (nameHistory === 'unclaimed') { + return + } + const nameData: PlebNameData = nameHistory.getData() + if (!nameData.nostr) { + return + } + setPlebname({ + pubkey: bech32ToHex(nameData.nostr), + name: val + }) + }).catch(reason => console.warn(`failed to fetch history of plebname '${val}'`, reason)) + } setSearch(val); } }; @@ -146,7 +168,7 @@ export default function SearchBox() { activeIndex === idx + 1 ? "bg-secondary" : "bg-background hover:bg-secondary" }`} onMouseEnter={() => setActiveIndex(idx + 1)}> - + ))} @@ -154,3 +176,21 @@ export default function SearchBox() { ); } + +function getSubHeader(result: FuzzySearchResult): JSX.Element { + if (result.name && result.name.endsWith('.btc')) { + return {result.name} + } + + if (result.nip05) { + return {result.nip05} + } + + try { + const npub: string = hexToBech32(NostrPrefix.PublicKey, result.pubkey) + return {npub.slice(0, 12)}...{npub.slice(-12)} + } catch (error) { + console.warn(`"${result.pubkey}" is not a valid pubkey`, error) + return invalid pubkey + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 1af22cc24..54158cfc0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4754,6 +4754,7 @@ __metadata: marked: "npm:^9.1.0" marked-footnote: "npm:^1.0.0" match-sorter: "npm:^6.3.1" + plebnames: "npm:^0.2.4" postcss: "npm:^8.4.31" postcss-preset-env: "npm:^9.2.0" prettier: "npm:2.8.3" @@ -6862,6 +6863,13 @@ __metadata: languageName: node linkType: hard +"bech32@npm:^2.0.0": + version: 2.0.0 + resolution: "bech32@npm:2.0.0" + checksum: 10/fa15acb270b59aa496734a01f9155677b478987b773bf701f465858bf1606c6a970085babd43d71ce61895f1baa594cb41a2cd1394bd2c6698f03cc2d811300e + languageName: node + linkType: hard + "binary-extensions@npm:^2.0.0": version: 2.2.0 resolution: "binary-extensions@npm:2.2.0" @@ -12141,6 +12149,15 @@ __metadata: languageName: node linkType: hard +"plebnames@npm:^0.2.4": + version: 0.2.4 + resolution: "plebnames@npm:0.2.4" + dependencies: + bech32: "npm:^2.0.0" + checksum: 10/c79704a87d205c5b955c95f807f113703154546072ca5db65b0456a9225bd81559b16f152f8640c461434e409bedeb4f6122a93ca6ec24f26aecc021abd3a570 + languageName: node + linkType: hard + "polished@npm:4": version: 4.2.2 resolution: "polished@npm:4.2.2"