blowater/app/UI/user-detail.tsx

176 lines
6.3 KiB
TypeScript
Raw Normal View History

2023-06-30 14:05:57 +00:00
/** @jsx h */
import { h } from "preact";
2023-06-30 14:05:57 +00:00
import { Avatar } from "./components/avatar.tsx";
import { PublicKey } from "@blowater/nostr-sdk";
2023-06-30 14:05:57 +00:00
import { ProfileData } from "../features/profile.ts";
2023-11-11 11:19:21 +00:00
import { emitFunc } from "../event-bus.ts";
2023-06-30 14:05:57 +00:00
import { DirectMessagePanelUpdate } from "./message-panel.tsx";
2023-11-11 11:19:21 +00:00
import { HomeIcon } from "./icons/home-icon.tsx";
import { KeyIcon } from "./icons/key-icon.tsx";
import { UserIcon } from "./icons/user-icon.tsx";
2023-11-20 04:01:13 +00:00
import { CopyButton } from "./components/copy-button.tsx";
2023-11-26 12:18:00 +00:00
import { LinkColor } from "./style/colors.ts";
2023-12-07 13:18:26 +00:00
import { findUrlInString } from "./message.ts";
import { SelectConversation } from "./search_model.ts";
import { CloseRightPanel } from "./components/right-panel.tsx";
import { robohash } from "@blowater/nostr-sdk";
2023-06-30 14:05:57 +00:00
2024-01-02 12:42:11 +00:00
export type BlockUser = {
type: "BlockUser";
pubkey: PublicKey;
};
export type UnblockUser = {
type: "UnblockUser";
pubkey: PublicKey;
};
2023-06-30 14:05:57 +00:00
type UserDetailProps = {
targetUserProfile: ProfileData;
pubkey: PublicKey;
2024-01-02 12:42:11 +00:00
blocked: boolean;
emit: emitFunc<DirectMessagePanelUpdate | BlockUser | UnblockUser | SelectConversation | CloseRightPanel>;
2023-06-30 14:05:57 +00:00
};
export function UserDetail(props: UserDetailProps) {
2024-03-20 02:20:55 +00:00
const name = props.targetUserProfile.name || props.targetUserProfile.display_name ||
props.pubkey.bech32();
2023-06-30 14:05:57 +00:00
return (
2024-01-02 12:42:11 +00:00
<div class={`px-2 py-3 text-[#7A818C]`}>
2023-06-30 14:05:57 +00:00
<Avatar
2023-12-22 07:51:08 +00:00
class={`w-64 h-64 m-auto`}
picture={props.targetUserProfile.picture || robohash(props.pubkey.hex)}
2023-06-30 14:05:57 +00:00
/>
<div class="flex flex-col items-center">
<h1
class={`text-[#F3F4EA] truncate text-[1.4rem] my-4 max-w-full text-center` +
` inline-block hover:text-[#60a5fa] hover:cursor-pointer`}
onClick={(_) => {
props.emit({
type: "SelectConversation",
pubkey: props.pubkey,
});
props.emit({
type: "CloseRightPanel",
});
}}
>
{name}
</h1>
</div>
2024-01-02 12:42:11 +00:00
<div class={`flex items-start overflow-hidden w-full group`}>
2023-06-30 14:05:57 +00:00
<KeyIcon
2023-12-18 10:23:15 +00:00
class={`w-6 h-6 mr-2`}
2023-06-30 14:05:57 +00:00
style={{
fill: "#7A818C",
}}
/>
<p
2023-12-18 10:23:15 +00:00
class={`flex-1 text-[#7A818C] group-hover:text-[#F3F4EA] break-words overflow-hidden`}
2023-06-30 14:05:57 +00:00
>
{props.pubkey.bech32()}
</p>
2023-11-20 04:01:13 +00:00
<CopyButton text={props.pubkey.bech32()} />
2023-06-30 14:05:57 +00:00
</div>
2023-12-18 10:23:15 +00:00
<div class={`flex items-start overflow-hidden w-full mt-1 group`}>
2023-08-26 19:59:03 +00:00
<KeyIcon
2023-12-18 10:23:15 +00:00
class={`w-6 h-6 mr-2`}
2023-08-26 19:59:03 +00:00
style={{
fill: "#7A818C",
}}
/>
<p
2023-12-18 10:23:15 +00:00
class={`flex-1 text-[#7A818C] group-hover:text-[#F3F4EA] break-words overflow-hidden`}
2023-08-26 19:59:03 +00:00
>
{props.pubkey.hex}
</p>
2023-11-20 04:01:13 +00:00
<CopyButton text={props.pubkey.hex} />
2023-08-26 19:59:03 +00:00
</div>
2023-06-30 14:05:57 +00:00
{props.targetUserProfile.about
? (
2023-12-18 10:23:15 +00:00
<div class={`flex items-start overflow-hidden w-full mt-4 group`}>
2023-06-30 14:05:57 +00:00
<UserIcon
2023-12-18 10:23:15 +00:00
class={`w-6 h-6 mr-2`}
2023-06-30 14:05:57 +00:00
style={{
stroke: "#7A818C",
strokeWidth: "1.5",
fill: "none",
}}
/>
<p
2023-12-18 10:23:15 +00:00
class={`flex-1 break-words overflow-hidden`}
2023-06-30 14:05:57 +00:00
>
2023-12-07 13:18:26 +00:00
{TextWithLinks({ text: props.targetUserProfile.about })}
2023-06-30 14:05:57 +00:00
</p>
</div>
)
: undefined}
{props.targetUserProfile.website
? (
2023-12-18 10:23:15 +00:00
<div class={`flex items-start overflow-hidden w-full mt-4 group`}>
2023-06-30 14:05:57 +00:00
<HomeIcon
2023-12-18 10:23:15 +00:00
class={`w-6 h-6 mr-2`}
2023-06-30 14:05:57 +00:00
style={{
stroke: "#7A818C",
strokeWidth: "1.5",
fill: "none",
}}
/>
<p
2023-12-18 10:23:15 +00:00
class={`flex-1 break-words overflow-hidden`}
2023-06-30 14:05:57 +00:00
>
2023-12-07 13:18:26 +00:00
{TextWithLinks({ text: props.targetUserProfile.website })}
2023-06-30 14:05:57 +00:00
</p>
</div>
)
: undefined}
2024-01-02 12:42:11 +00:00
<div class="py-1"></div>
<div
class="border inline-block select-none px-1 rounded-full
hover:text-[#D4D4D4] hover:cursor-pointer"
2024-06-17 07:42:51 +00:00
onClick={() => {
2024-01-02 12:42:11 +00:00
if (props.blocked) {
props.emit({
type: "UnblockUser",
pubkey: props.pubkey,
});
} else {
props.emit({
type: "BlockUser",
pubkey: props.pubkey,
});
}
}}
>
{props.blocked ? "Unblock" : "Block"}
</div>
2023-06-30 14:05:57 +00:00
</div>
);
}
2023-12-07 13:18:26 +00:00
function TextWithLinks({ text }: { text: string }) {
const parts = findUrlInString(text);
return (
<div>
{parts.map((part, index) => {
if (part instanceof URL) {
return (
<a
2023-12-18 10:23:15 +00:00
class={`text-[${LinkColor}] hover:text-[#F3F4EA]`}
2023-12-07 13:18:26 +00:00
key={index}
href={part.href}
target="_blank"
rel="noopener noreferrer"
>
{part.href}
</a>
);
} else {
return <span key={index}>{part}</span>;
}
})}
</div>
);
}