/** @jsx h */ import { createRef, h } from "preact"; import { Avatar } from "./components/avatar.tsx"; import { BackgroundColor_HoverButton, DividerBackgroundColor, PlaceholderColor, PrimaryTextColor, SecondaryBackgroundColor, TextColor_Primary, } from "./style/colors.ts"; import { Component } from "preact"; import { Channel } from "@blowater/csp"; import { emitFunc } from "../event-bus.ts"; import { SearchUpdate } from "./search_model.ts"; import { Profile_Nostr_Event } from "../nostr.ts"; import { PublicKey, robohash } from "@blowater/nostr-sdk"; export type SearchResultChannel = Channel; type SearchResult = { picture: string | undefined; text: string; id: string; }; export interface ProfileSetter { setProfile(profileEvent: Profile_Nostr_Event, relayURL: URL): void; } export type func_GetProfileByPublicKey = ( pubkey: PublicKey | string, spaceURL: URL | undefined, ) => Profile_Nostr_Event | undefined; export type func_GetProfilesByText = (name: string, spaceURL: URL | undefined) => Profile_Nostr_Event[]; export interface ProfileGetter { getProfileByPublicKey: func_GetProfileByPublicKey; getProfilesByText: func_GetProfilesByText; getUniqueProfileCount: (spaceURL: URL) => number; } type Props = { placeholder: string; getProfileByPublicKey: func_GetProfileByPublicKey; getProfilesByText: func_GetProfilesByText; 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) { // todo: decide if search is per space scoped const profiles = this.props.getProfilesByText(text, undefined); this.setState({ searchResults: profiles, }); } else { // todo: decide if search is per space scoped const profile_event = this.props.getProfileByPublicKey(pubkey, undefined); 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}

  • ); }; }