wip: update chats to new ui

This commit is contained in:
Ren Amamiya
2023-08-03 14:09:12 +07:00
parent ae1e84655a
commit d10462cd4a
21 changed files with 335 additions and 140 deletions

View File

@@ -7,15 +7,16 @@ import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfile } from '@utils/hooks/useProfile';
import { displayNpub } from '@utils/shortenKey';
import { Chats } from '@utils/types';
export function ChatsListItem({ data }: { data: any }) {
export function ChatsListItem({ data }: { data: Chats }) {
const { status, user } = useProfile(data.sender_pubkey);
if (status === 'loading') {
return (
<div className="inline-flex h-9 items-center gap-2.5 rounded-md px-2">
<div className="relative h-6 w-6 shrink-0 animate-pulse rounded bg-zinc-800" />
<div className="h-2.5 w-2/3 animate-pulse rounded bg-zinc-800" />
<div className="relative h-6 w-6 shrink-0 animate-pulse rounded bg-white/10" />
<div className="h-2.5 w-2/3 animate-pulse rounded bg-white/10" />
</div>
);
}
@@ -41,7 +42,7 @@ export function ChatsListItem({ data }: { data: any }) {
<h5 className="max-w-[10rem] truncate">
{user?.nip05 ||
user?.name ||
user?.displayName ||
user?.display_name ||
displayNpub(data.sender_pubkey, 16)}
</h5>
<div className="flex items-center">

View File

@@ -51,10 +51,10 @@ export function ChatMessageForm({
onKeyDown={handleEnterPress}
spellCheck={false}
placeholder="Message"
className="relative h-11 w-full resize-none rounded-md bg-zinc-800 px-5 !outline-none placeholder:text-zinc-500"
className="relative h-11 w-full resize-none rounded-md bg-white/10 px-5 text-white !outline-none placeholder:text-white/50"
/>
<div className="absolute right-2 top-0 h-11">
<div className="flex h-full items-center justify-end gap-3 text-zinc-500">
<div className="flex h-full items-center justify-end gap-3 text-white/50">
<MediaUploader setState={setValue} />
<button
type="button"

View File

@@ -26,7 +26,7 @@ export function ChatMessageItem({
const content = parser(data);
return (
<div className="flex h-min min-h-min w-full select-text flex-col px-5 py-3 hover:bg-black/20">
<div className="flex h-min min-h-min w-full select-text flex-col px-5 py-3 hover:bg-white/10">
<div className="flex flex-col">
<User pubkey={data.sender_pubkey} time={data.created_at} isChat={true} />
<div className="-mt-[20px] pl-[49px]">

View File

@@ -5,7 +5,7 @@ import { Image } from '@shared/image';
import { DEFAULT_AVATAR } from '@stores/constants';
import { useProfile } from '@utils/hooks/useProfile';
import { shortenKey } from '@utils/shortenKey';
import { displayNpub } from '@utils/shortenKey';
export function ChatSidebar({ pubkey }: { pubkey: string }) {
const { user } = useProfile(pubkey);
@@ -24,17 +24,17 @@ export function ChatSidebar({ pubkey }: { pubkey: string }) {
<div className="flex flex-col gap-4">
<div className="flex flex-col gap-1">
<h3 className="text-lg font-semibold leading-none">
{user?.displayName || user?.name}
{user?.display_name || user?.name}
</h3>
<h5 className="leading-none text-white/50">
{user?.nip05 || shortenKey(pubkey)}
{user?.nip05 || displayNpub(pubkey, 16)}
</h5>
</div>
<div>
<p className="leading-tight">{user?.bio || user?.about}</p>
<Link
to={`/app/users/${pubkey}`}
className="mt-3 inline-flex h-10 w-full items-center justify-center rounded-md bg-zinc-900 text-sm font-medium text-zinc-300 hover:bg-zinc-800 hover:text-white"
className="mt-3 inline-flex h-10 w-full items-center justify-center rounded-md bg-white/10 text-sm font-medium text-white hover:bg-fuchsia-500"
>
View full profile
</Link>

View File

@@ -14,6 +14,7 @@ import { createChat, getChatMessages } from '@libs/storage';
import { useStronghold } from '@stores/stronghold';
import { useAccount } from '@utils/hooks/useAccount';
import { Chats } from '@utils/types';
export function ChatScreen() {
const queryClient = useQueryClient();
@@ -34,7 +35,7 @@ export function ChatScreen() {
const userPrivkey = useStronghold((state) => state.privkey);
const itemContent: any = useCallback(
const itemContent = useCallback(
(index: string | number) => {
return (
<ChatMessageItem
@@ -55,7 +56,7 @@ export function ChatScreen() {
);
const chat = useMutation({
mutationFn: (data: any) => {
mutationFn: (data: Chats) => {
return createChat(
data.id,
data.receiver_pubkey,
@@ -100,16 +101,10 @@ export function ChatScreen() {
}, [pubkey]);
return (
<div className="grid h-full w-full grid-cols-3">
<div className="col-span-2 flex flex-col justify-between border-r border-zinc-900">
<div
data-tauri-drag-region
className="inline-flex h-11 w-full shrink-0 items-center justify-center border-b border-zinc-900"
>
<h3 className="font-semibold text-white">Encrypted Chat</h3>
</div>
<div className="grid h-full w-full grid-cols-3 bg-white/10">
<div className="col-span-2 border-r border-white/5">
<div className="h-full w-full flex-1 p-3">
<div className="flex h-full flex-col justify-between overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900">
<div className="flex h-full flex-col justify-between overflow-hidden rounded-xl bg-white/10">
<div className="h-full w-full flex-1">
{status === 'loading' ? (
<p>Loading...</p>
@@ -131,7 +126,7 @@ export function ChatScreen() {
/>
)}
</div>
<div className="z-50 shrink-0 rounded-b-xl border-t border-zinc-800 bg-zinc-900 p-3 px-5">
<div className="z-50 shrink-0 rounded-b-xl border-t border-white/5 bg-white/10 p-3 px-5">
<ChatMessageForm
receiverPubkey={pubkey}
userPubkey={account.pubkey}
@@ -141,11 +136,7 @@ export function ChatScreen() {
</div>
</div>
</div>
<div className="col-span-1">
<div
data-tauri-drag-region
className="inline-flex h-11 w-full shrink-0 items-center justify-center border-b border-zinc-900"
/>
<div className="col-span-1 pt-3">
<ChatSidebar pubkey={pubkey} />
</div>
</div>

View File

@@ -40,9 +40,10 @@ export function FollowingBlock() {
});
const itemsVirtualizer = rowVirtualizer.getVirtualItems();
const totalSize = rowVirtualizer.getTotalSize();
useEffect(() => {
const [lastItem] = [...rowVirtualizer.getVirtualItems()].reverse();
const [lastItem] = [...itemsVirtualizer].reverse();
if (!lastItem) {
return;
@@ -51,7 +52,7 @@ export function FollowingBlock() {
if (lastItem.index >= notes.length - 1 && hasNextPage && !isFetchingNextPage) {
fetchNextPage();
}
}, [notes.length, fetchNextPage, rowVirtualizer.getVirtualItems()]);
}, [notes.length, fetchNextPage, itemsVirtualizer]);
const renderItem = useCallback(
(index: string | number) => {
@@ -159,7 +160,7 @@ export function FollowingBlock() {
<div
className="relative w-full"
style={{
height: `${rowVirtualizer.getTotalSize()}px`,
height: `${totalSize}px`,
}}
>
<div

View File

@@ -18,11 +18,7 @@ import { LoaderIcon } from '@shared/icons';
import { Block } from '@utils/types';
export function SpaceScreen() {
const {
status,
data: blocks,
isFetching,
} = useQuery(
const { status, data: blocks } = useQuery(
['blocks'],
async () => {
return await getBlocks();
@@ -60,27 +56,12 @@ export function SpaceScreen() {
<FollowingBlock />
{status === 'loading' ? (
<div className="flex w-[350px] shrink-0 flex-col">
<div
data-tauri-drag-region
className="group flex h-11 w-full items-center justify-between overflow-hidden px-3"
/>
<div className="flex w-full flex-1 items-center justify-center p-3">
<LoaderIcon className="h-5 w-5 animate-spin text-white/10" />
</div>
</div>
) : (
blocks.map((block: Block) => renderBlock(block))
)}
{isFetching && (
<div className="flex w-[350px] shrink-0 flex-col">
<div
data-tauri-drag-region
className="group flex h-11 w-full items-center justify-between overflow-hidden px-3"
/>
<div className="flex w-full flex-1 items-center justify-center p-3">
<LoaderIcon className="h-5 w-5 animate-spin text-white" />
</div>
</div>
blocks.map((block) => renderBlock(block))
)}
<div className="flex w-[350px] shrink-0 flex-col">
<div className="inline-flex h-full w-full flex-col items-center justify-center gap-1">

View File

@@ -15,7 +15,7 @@ button {
}
.markdown {
@apply prose max-w-none select-text hyphens-auto text-white dark:prose-invert prose-p:mb-2 prose-p:mt-0 prose-p:break-words prose-p:[word-break:break-word] prose-p:last:mb-0 prose-a:break-words prose-a:break-all prose-a:font-normal prose-a:leading-tight prose-a:text-fuchsia-400 prose-a:after:content-['_↗'] hover:prose-a:text-fuchsia-500 prose-blockquote:m-0 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-li:leading-tight prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2;
@apply prose prose-white max-w-none select-text hyphens-auto text-white prose-p:mb-2 prose-p:mt-0 prose-p:break-words prose-p:[word-break:break-word] prose-p:last:mb-0 prose-a:break-words prose-a:break-all prose-a:font-normal prose-a:leading-tight prose-a:after:content-['_↗'] hover:prose-a:text-fuchsia-500 prose-blockquote:m-0 prose-pre:whitespace-pre-wrap prose-pre:break-words prose-pre:break-all prose-ol:m-0 prose-ol:mb-1 prose-ul:mb-1 prose-li:leading-tight prose-img:mb-2 prose-img:mt-3 prose-hr:mx-0 prose-hr:my-2;
}
.ProseMirror p.is-empty::before {

View File

@@ -26,26 +26,22 @@ export function MediaUploader({ setState }: { setState: any }) {
<button
type="button"
onClick={() => uploadMedia()}
className="group inline-flex h-6 w-6 items-center justify-center rounded bg-zinc-700 hover:bg-zinc-600"
className="group inline-flex h-8 w-8 items-center justify-center rounded hover:bg-white/10"
>
{loading ? (
<LoaderIcon className="h-4 w-4 animate-spin text-black dark:text-white" />
<LoaderIcon className="h-5 w-5 animate-spin text-black dark:text-white" />
) : (
<MediaIcon
width={14}
height={14}
className="text-white/50 group-hover:text-zinc-200"
/>
<MediaIcon className="h-5 w-5 text-white/50 group-hover:text-white" />
)}
</button>
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content
className="-left-10 select-none rounded-md bg-zinc-800/80 px-3.5 py-1.5 text-sm leading-none text-white backdrop-blur-lg will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade"
className="-left-10 select-none rounded-md bg-black px-3.5 py-1.5 text-sm leading-none text-white will-change-[transform,opacity] data-[state=delayed-open]:data-[side=bottom]:animate-slideUpAndFade data-[state=delayed-open]:data-[side=left]:animate-slideRightAndFade data-[state=delayed-open]:data-[side=right]:animate-slideLeftAndFade data-[state=delayed-open]:data-[side=top]:animate-slideDownAndFade"
sideOffset={5}
>
Upload media
<Tooltip.Arrow className="fill-zinc-800/80 backdrop-blur-lg" />
<Tooltip.Arrow className="fill-black" />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>

View File

@@ -17,7 +17,7 @@ export function Repost({ event }: { event: LumeEvent }) {
if (status === 'loading') {
return (
<div className="relative overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 pt-3">
<div className="relative overflow-hidden rounded-xl bg-white/10 px-3 py-3">
<NoteSkeleton />
</div>
);
@@ -25,7 +25,7 @@ export function Repost({ event }: { event: LumeEvent }) {
if (status === 'error') {
return (
<div className="flex items-center justify-center overflow-hidden rounded-xl border-t border-zinc-800/50 bg-zinc-900 px-3 py-3">
<div className="flex items-center justify-center overflow-hidden rounded-xl bg-white/10 px-3 py-3">
<p className="text-white/50">Failed to fetch</p>
</div>
);

View File

@@ -8,7 +8,7 @@ export function SubNote({ id, root }: { id: string; root?: string }) {
if (status === 'loading') {
return (
<div className="relative mb-5 overflow-hidden rounded-xl bg-zinc-900 pt-3">
<div className="relative mb-5 overflow-hidden rounded-xl bg-white/10 py-3">
<NoteSkeleton />
</div>
);
@@ -16,7 +16,7 @@ export function SubNote({ id, root }: { id: string; root?: string }) {
if (status === 'error') {
return (
<div className="mb-5 flex overflow-hidden rounded-xl bg-zinc-800 px-3 py-3">
<div className="mb-5 flex overflow-hidden rounded-xl bg-white/10 px-3 py-3">
<p className="text-white/50">Failed to fetch</p>
</div>
);

View File

@@ -13,11 +13,11 @@ export function NoteKindUnsupport({ event }: { event: LumeEvent }) {
<div className="w-11 shrink-0" />
<div className="flex-1">
<div className="mt-3 flex w-full flex-col gap-2">
<div className="inline-flex flex-col gap-1 rounded-md bg-zinc-800 px-2 py-2">
<span className="text-sm font-medium leading-none text-zinc-500">
<div className="inline-flex flex-col gap-1 rounded-md bg-white/10 px-2 py-2">
<span className="text-sm font-medium leading-none text-white/50">
Kind: {event.kind}
</span>
<p className="text-sm leading-none text-fuchsia-500">
<p className="text-sm leading-none text-white">
Lume isn&apos;t fully support this kind
</p>
</div>

View File

@@ -22,7 +22,7 @@ export function ImagePreview({ urls, truncate }: { urls: string[]; truncate?: bo
alt="image"
className={`${
truncate ? 'h-auto max-h-[300px]' : 'h-auto'
} w-full rounded-lg border border-zinc-800/50 object-cover`}
} w-full rounded-lg border border-white/10 object-cover`}
/>
<button
type="button"

View File

@@ -1,17 +1,15 @@
export function NoteSkeleton() {
return (
<div className="flex h-min flex-col pb-3">
<div className="flex h-min flex-col">
<div className="flex items-start gap-3">
<div className="relative h-11 w-11 shrink overflow-hidden rounded-lg bg-zinc-700" />
<div className="flex flex-col gap-0.5">
<div className="h-3 w-20 rounded bg-zinc-700" />
</div>
<div className="relative h-11 w-11 shrink overflow-hidden rounded-lg bg-white/10" />
<div className="h-3 w-20 rounded bg-white/10" />
</div>
<div className="-mt-5 animate-pulse pl-[49px]">
<div className="-mt-6 animate-pulse pl-[49px]">
<div className="flex flex-col gap-1">
<div className="h-3 w-full rounded bg-zinc-700" />
<div className="h-3 w-2/3 rounded bg-zinc-700" />
<div className="h-3 w-1/2 rounded bg-zinc-700" />
<div className="h-3 w-full rounded bg-white/10" />
<div className="h-3 w-2/3 rounded bg-white/10" />
<div className="h-3 w-1/2 rounded bg-white/10" />
</div>
</div>
</div>

View File

@@ -2,7 +2,6 @@ import * as Popover from '@radix-ui/react-popover';
import { Link } from 'react-router-dom';
import { twMerge } from 'tailwind-merge';
import { VerticalDotsIcon } from '@shared/icons';
import { Image } from '@shared/image';
import { DEFAULT_AVATAR } from '@stores/constants';
@@ -40,10 +39,10 @@ export function User({
<div
className={`${avatarWidth} ${avatarHeight} ${
size === 'small' ? 'rounded' : 'rounded-lg'
} relative z-10 shrink-0 animate-pulse overflow-hidden bg-zinc-800`}
} relative z-10 shrink-0 animate-pulse overflow-hidden bg-white/10`}
/>
<div className="flex flex-wrap items-baseline gap-1">
<div className="h-3.5 w-36 animate-pulse rounded bg-zinc-800" />
<div className="h-3.5 w-36 animate-pulse rounded bg-white/10" />
</div>
</div>
);
@@ -107,7 +106,7 @@ export function User({
<div className="flex flex-1 flex-col gap-2">
<div className="inline-flex flex-col gap-1">
<h5 className="text-sm font-semibold leading-none">
{user?.displayName || user?.name}
{user?.display_name || user?.name || user?.username}
</h5>
<span className="max-w-[10rem] truncate text-sm leading-none text-white/50">
{user?.nip05 || displayNpub(pubkey, 16)}

View File

@@ -40,13 +40,13 @@ export interface Block {
export interface Chats {
id: string;
event_id: string;
event_id?: string;
receiver_pubkey: string;
sender_pubkey: string;
content: string;
tags: string[][];
created_at: number;
new_messages: number;
new_messages?: number;
}
export interface Settings {