added new chat modal

This commit is contained in:
Ren Amamiya 2023-04-07 14:13:40 +07:00
parent 8db5d5f87d
commit 38b34f5c04
7 changed files with 126 additions and 11 deletions

View File

@ -1,4 +1,5 @@
import { ChatListItem } from '@components/chats/chatListItem';
import { ChatModal } from '@components/chats/chatModal';
import { ImageWithFallback } from '@components/imageWithFallback';
import { RelayContext } from '@components/relaysProvider';
@ -19,7 +20,7 @@ export default function ChatList() {
const [list, setList] = useState(new Set());
const openSelfChat = () => {
router.replace({
router.push({
pathname: '/chats/[pubkey]',
query: { pubkey: activeAccount.pubkey },
});
@ -70,6 +71,7 @@ export default function ChatList() {
{[...list].map((item: string, index) => (
<ChatListItem key={index} pubkey={item} />
))}
<ChatModal />
</div>
);
}

View File

@ -12,7 +12,7 @@ export const ChatListItem = ({ pubkey }: { pubkey: string }) => {
const profile = useMetadata(pubkey);
const openChat = () => {
router.replace({
router.push({
pathname: '/chats/[pubkey]',
query: { pubkey: pubkey },
});
@ -23,7 +23,7 @@ export const ChatListItem = ({ pubkey }: { pubkey: string }) => {
onClick={() => openChat()}
className="inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-900"
>
<div className="relative h-5 w-5 shrink overflow-hidden rounded bg-white">
<div className="relative h-5 w-5 shrink overflow-hidden rounded">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}

View File

@ -0,0 +1,63 @@
import { ChatModalUser } from '@components/chats/chatModalUser';
import { activeAccountAtom } from '@stores/account';
import * as Dialog from '@radix-ui/react-dialog';
import { Cross1Icon, PlusIcon } from '@radix-ui/react-icons';
import { useAtomValue } from 'jotai';
import { useCallback, useEffect, useState } from 'react';
export const ChatModal = () => {
const [plebs, setPlebs] = useState([]);
const activeAccount: any = useAtomValue(activeAccountAtom);
const fetchPlebsByAccount = useCallback(async (id) => {
const { getPlebs } = await import('@utils/bindings');
return await getPlebs({ account_id: id });
}, []);
useEffect(() => {
fetchPlebsByAccount(activeAccount.id)
.then((res) => setPlebs(res))
.catch(console.error);
}, [activeAccount.id, fetchPlebsByAccount]);
return (
<Dialog.Root>
<Dialog.Trigger asChild>
<div className="group inline-flex items-center gap-2 rounded-md px-2.5 py-1.5 hover:bg-zinc-950">
<div className="inline-flex h-5 w-5 shrink items-center justify-center rounded bg-zinc-900">
<PlusIcon className="h-3 w-3 text-zinc-500" />
</div>
<div>
<h5 className="text-sm font-medium text-zinc-500 group-hover:text-zinc-400">Add a new chat</h5>
</div>
</div>
</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 z-50 bg-black bg-opacity-30 backdrop-blur-sm data-[state=open]:animate-overlayShow" />
<Dialog.Content className="fixed inset-0 z-50 overflow-y-auto">
<div className="flex min-h-full items-center justify-center">
<div className="relative flex h-[500px] w-full max-w-2xl flex-col rounded-lg bg-zinc-900 text-zinc-100 ring-1 ring-zinc-800">
<div className="sticky left-0 top-0 flex h-12 w-full shrink-0 items-center justify-between rounded-t-lg border-b border-zinc-800 bg-zinc-950 px-3">
<div className="flex items-center gap-2">
<Dialog.Close asChild>
<button className="inline-flex h-5 w-5 items-center justify-center rounded bg-zinc-900">
<Cross1Icon className="h-3 w-3 text-zinc-300" />
</button>
</Dialog.Close>
<h5 className="font-semibold leading-none text-zinc-500">New chat</h5>
</div>
</div>
<div className="flex flex-col overflow-y-auto">
{plebs.map((pleb) => (
<ChatModalUser key={pleb.id} data={pleb} />
))}
</div>
</div>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
};

View File

@ -0,0 +1,48 @@
import { ImageWithFallback } from '@components/imageWithFallback';
import { DEFAULT_AVATAR } from '@stores/constants';
import { truncate } from '@utils/truncate';
import { useRouter } from 'next/router';
export const ChatModalUser = ({ data }: { data: any }) => {
const router = useRouter();
const profile = JSON.parse(data.metadata);
const openNewChat = () => {
router.push({
pathname: '/chats/[pubkey]',
query: { pubkey: data.pubkey },
});
};
return (
<div className="group flex items-center justify-between px-3 py-2 hover:bg-zinc-800">
<div className="flex items-center gap-2">
<div className="relative h-10 w-10 shrink overflow-hidden rounded-md">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={data.pubkey}
fill={true}
className="rounded-md object-cover"
/>
</div>
<div className="flex w-full flex-1 flex-col items-start text-start">
<span className="truncate text-sm font-semibold leading-tight text-zinc-200">
{profile?.display_name || profile?.name}
</span>
<span className="text-sm leading-tight text-zinc-400">{truncate(data.pubkey, 16, ' .... ')}</span>
</div>
</div>
<div>
<button
onClick={() => openNewChat()}
className="hidden h-8 items-center justify-center rounded-md bg-fuchsia-500 px-3 text-sm font-medium shadow-button hover:bg-fuchsia-600 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 group-hover:inline-flex"
>
Send message
</button>
</div>
</div>
);
};

View File

@ -37,6 +37,8 @@ export const MessageList = ({ data }: { data: any }) => {
initialTopMostItemIndex={data.length - 1}
alignToBottom={true}
followOutput={true}
overscan={50}
increaseViewportBy={{ top: 200, bottom: 200 }}
className="scrollbar-hide h-full w-full overflow-y-auto"
/>
</div>

View File

@ -1,4 +1,4 @@
import { MessageUser } from '@components/chats/user';
import { MessageUser } from '@components/chats/messageUser';
import { nip04 } from 'nostr-tools';
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
@ -33,10 +33,10 @@ const MessageListItem = ({
}, [decryptContent]);
return (
<div className="flex h-min min-h-min w-full select-text flex-col px-3 py-2.5 hover:bg-black/20">
<div className="flex h-min min-h-min w-full select-text flex-col px-5 py-2 hover:bg-black/20">
<div className="flex flex-col">
<MessageUser pubkey={data.pubkey} time={data.created_at} />
<div className="-mt-4 pl-[44px]">
<div className="-mt-[17px] pl-[48px]">
<div className="flex flex-col gap-2">
<div className="prose prose-zinc max-w-none break-words text-sm leading-tight dark:prose-invert prose-p:m-0 prose-p:text-sm prose-p:leading-tight prose-a:font-normal prose-a:text-fuchsia-500 prose-a:no-underline prose-img:m-0 prose-video:m-0">
{content}

View File

@ -14,8 +14,8 @@ export const MessageUser = ({ pubkey, time }: { pubkey: string; time: number })
const profile = useMetadata(pubkey);
return (
<div className="group flex items-start gap-2">
<div className="relative h-9 w-9 shrink overflow-hidden rounded-md bg-white">
<div className="group flex items-start gap-3">
<div className="relative h-9 w-9 shrink overflow-hidden rounded-md">
<ImageWithFallback
src={profile?.picture || DEFAULT_AVATAR}
alt={pubkey}
@ -25,11 +25,11 @@ export const MessageUser = ({ pubkey, time }: { pubkey: string; time: number })
</div>
<div className="flex w-full flex-1 items-start justify-between">
<div className="flex items-baseline gap-2 text-sm">
<span className="font-semibold leading-tight text-zinc-200 group-hover:underline">
<span className="font-semibold leading-none text-zinc-200 group-hover:underline">
{profile?.display_name || profile?.name || truncate(pubkey, 16, ' .... ')}
</span>
<span className="leading-tight text-zinc-500">·</span>
<span className="text-zinc-500">{dayjs().to(dayjs.unix(time))}</span>
<span className="leading-none text-zinc-500">·</span>
<span className="leading-none text-zinc-500">{dayjs().to(dayjs.unix(time))}</span>
</div>
</div>
</div>