2023-06-30 14:05:57 +00:00
|
|
|
/** @jsx h */
|
2023-07-30 06:39:53 +00:00
|
|
|
import { Fragment, h, VNode } from "https://esm.sh/preact@10.11.3";
|
2023-06-30 14:05:57 +00:00
|
|
|
import { tw } from "https://esm.sh/twind@0.16.16";
|
|
|
|
import { EventEmitter } from "../event-bus.ts";
|
|
|
|
import { sleep } from "https://raw.githubusercontent.com/BlowaterNostr/csp/master/csp.ts";
|
|
|
|
|
|
|
|
import { SearchModel, SearchUpdate } from "./search_model.ts";
|
|
|
|
import { Avatar } from "./components/avatar.tsx";
|
|
|
|
|
2023-07-30 06:39:53 +00:00
|
|
|
export function Popover(props: {
|
|
|
|
eventEmitter: EventEmitter<SearchUpdate>;
|
2023-06-30 14:05:57 +00:00
|
|
|
model: SearchModel;
|
2023-07-30 06:39:53 +00:00
|
|
|
child: VNode;
|
2023-06-30 14:05:57 +00:00
|
|
|
}) {
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
onKeyDown={(e) => {
|
|
|
|
if (e.code === "Escape") {
|
2023-07-30 06:39:53 +00:00
|
|
|
props.eventEmitter.emit({ type: "CancelPopOver" });
|
2023-06-30 14:05:57 +00:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
class={tw`fixed inset-0 bg-[#000000C0] items-center justify-center flex z-20`}
|
|
|
|
>
|
|
|
|
<div
|
|
|
|
class={tw`fixed inset-0 z-[-1]`}
|
|
|
|
onClick={() => {
|
2023-07-30 06:39:53 +00:00
|
|
|
props.eventEmitter.emit({ type: "CancelPopOver" });
|
2023-06-30 14:05:57 +00:00
|
|
|
}}
|
|
|
|
>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
class={tw`absolute max-w-[40rem] w-3/5 max-h-[24.72rem] bg-[#2B2D31] rounded-2xl px-4 py-3 flex flex-col z-10`}
|
|
|
|
>
|
2023-07-30 06:39:53 +00:00
|
|
|
{props.child}
|
2023-06-30 14:05:57 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
2023-07-30 06:39:53 +00:00
|
|
|
|
|
|
|
export function Search(props: {
|
|
|
|
eventEmitter: EventEmitter<SearchUpdate>;
|
|
|
|
model: SearchModel;
|
|
|
|
}) {
|
|
|
|
return (
|
|
|
|
<Fragment>
|
|
|
|
<input
|
|
|
|
ref={async (e) => {
|
|
|
|
await sleep(0); // wait util element mounted
|
|
|
|
e?.focus();
|
|
|
|
}}
|
|
|
|
onInput={(e) => {
|
|
|
|
props.eventEmitter.emit({
|
|
|
|
type: "Search",
|
|
|
|
text: e.currentTarget.value,
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
type="text"
|
|
|
|
class={tw`p-2 rounded focus-visible:outline-none bg-[#1E1F22] text-[#DADBDF] placeholder-[#86888B]`}
|
|
|
|
placeholder="Search a user's public key"
|
|
|
|
/>
|
|
|
|
{props.model.searchResults.length > 0
|
|
|
|
? (
|
|
|
|
<ul
|
|
|
|
class={tw`flex-1 list-none mt-4 p-1 overflow-y-auto`}
|
|
|
|
>
|
|
|
|
{props.model.searchResults.map((result) => {
|
|
|
|
return (
|
|
|
|
<li
|
|
|
|
onClick={() => {
|
|
|
|
props.eventEmitter.emit({
|
|
|
|
type: "SelectProfile",
|
|
|
|
pubkey: result.pubkey,
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
class={tw`w-full flex items-center px-4 py-2 text-[#B8B9BF] hover:bg-[#404249] rounded cursor-pointer`}
|
|
|
|
>
|
|
|
|
<Avatar
|
|
|
|
class={tw`w-8 h-8 mr-2`}
|
|
|
|
picture={result.profile?.picture}
|
|
|
|
/>
|
|
|
|
<p class={tw`truncate`}>
|
|
|
|
{result.profile?.name ? result.profile.name : result.pubkey.bech32()}
|
|
|
|
</p>
|
|
|
|
</li>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</ul>
|
|
|
|
)
|
|
|
|
: undefined}
|
|
|
|
</Fragment>
|
|
|
|
);
|
|
|
|
}
|