/** @jsx h */ import { createRef, h } from "https://esm.sh/preact@10.17.1"; import { Avatar } from "./components/avatar.tsx"; import { BackgroundColor_HoverButton, DividerBackgroundColor, PlaceholderColor, PrimaryTextColor, SecondaryBackgroundColor, TextColor_Primary, } from "./style/colors.ts"; import { Component } from "https://esm.sh/preact@10.17.1"; import { Channel } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts"; import { emitFunc } from "../event-bus.ts"; import { SearchUpdate } from "./search_model.ts"; import { Profile_Nostr_Event } from "../nostr.ts"; import { PublicKey } from "../../libs/nostr.ts/key.ts"; import { robohash } from "./relay-detail.tsx"; export type SearchResultChannel = Channel; type SearchResult = { picture: string | undefined; text: string; id: string; }; export interface ProfileSetter { setProfile(profileEvent: Profile_Nostr_Event, relayURL: string): void; } export interface ProfileGetter { getProfilesByText(input: string): Profile_Nostr_Event[]; getProfilesByPublicKey(pubkey: PublicKey): Profile_Nostr_Event | undefined; getUniqueProfileCount(): number; } type Props = { placeholder: string; profileGetter: ProfileGetter; emit: emitFunc; }; type State = { searchResults: Profile_Nostr_Event[] | PublicKey; offset: number; }; const page_size = 9; export class Search extends Component { state: State = { searchResults: [], offset: 0, }; inputRef = createRef(); styles = { container: `flex flex-col h-full w-full bg-[${SecondaryBackgroundColor}]`, searchInput: `p-2 w-full border-b border-[${DividerBackgroundColor}] focus-visible:outline-none bg-[${SecondaryBackgroundColor}] text-[${PrimaryTextColor}] placeholder-[${PlaceholderColor}]`, result: { container: `flex-1 list-none p-1 overflow-y-auto`, item: { container: `w-full flex items-center px-4 py-2 text-[#B8B9BF] hover:bg-[#404249] rounded cursor-pointer`, avatar: `w-8 h-8 mr-2`, text: `truncate`, }, }, }; componentDidMount() { if (this.inputRef.current) { this.inputRef.current.focus(); } } search = (e: h.JSX.TargetedEvent) => { this.setState({ offset: 0, }); const text = e.currentTarget.value; const pubkey = PublicKey.FromString(text); if (pubkey instanceof Error) { const profiles = this.props.profileGetter.getProfilesByText(text); this.setState({ searchResults: profiles, }); } else { const profile_event = this.props.profileGetter.getProfilesByPublicKey(pubkey); this.setState({ searchResults: profile_event ? [profile_event] : pubkey, }); } }; onSelect = (profile: Profile_Nostr_Event | PublicKey) => () => { if (this.inputRef.current) { this.inputRef.current.value = ""; } this.setState({ searchResults: [], }); this.props.emit({ type: "SelectConversation", pubkey: profile instanceof PublicKey ? profile : profile.publicKey, }); }; render() { return (
{this.state.searchResults instanceof PublicKey ? this.pubkeyItem(this.state.searchResults) : this.state.searchResults.length > 0 ? (
    {this.state.searchResults.slice( this.state.offset, this.state.offset + page_size, ).map(this.profileItem)}
) : undefined}
); } pubkeyItem = (pubkey: PublicKey) => { return (
  • {pubkey.bech32()}

  • ); }; profileItem = (result: Profile_Nostr_Event) => { return (
  • {result.profile.name || result.profile.display_name}

  • ); }; }