From ae73e2b383075cb9ad2ae701b05c9338740f1c14 Mon Sep 17 00:00:00 2001 From: Martti Malmi Date: Mon, 27 Nov 2023 11:45:04 +0200 Subject: [PATCH] chat layout --- .../app/src/Element/Chat/ChatParticipant.tsx | 9 +- packages/app/src/Element/Chat/DM.css | 36 +----- packages/app/src/Element/Chat/DM.tsx | 18 ++- packages/app/src/Element/Chat/DmWindow.css | 32 ----- packages/app/src/Element/Chat/DmWindow.tsx | 47 ++++++-- packages/app/src/Element/Text.css | 2 +- .../app/src/Element/User/ProfileImage.tsx | 4 +- .../app/src/Element/User/ProfilePreview.tsx | 5 +- .../app/src/Pages/Messages/MessagesPage.css | 109 ------------------ .../app/src/Pages/Messages/MessagesPage.tsx | 16 ++- 10 files changed, 78 insertions(+), 200 deletions(-) delete mode 100644 packages/app/src/Element/Chat/DmWindow.css delete mode 100644 packages/app/src/Pages/Messages/MessagesPage.css diff --git a/packages/app/src/Element/Chat/ChatParticipant.tsx b/packages/app/src/Element/Chat/ChatParticipant.tsx index 9cd8bc0c..20d52b27 100644 --- a/packages/app/src/Element/Chat/ChatParticipant.tsx +++ b/packages/app/src/Element/Chat/ChatParticipant.tsx @@ -10,5 +10,12 @@ export function ChatParticipantProfile({ participant }: { participant: ChatParti if (participant.id === publicKey) { return ; } - return ; + return ( + + ); } diff --git a/packages/app/src/Element/Chat/DM.css b/packages/app/src/Element/Chat/DM.css index 9c5a17ba..766672f0 100644 --- a/packages/app/src/Element/Chat/DM.css +++ b/packages/app/src/Element/Chat/DM.css @@ -1,37 +1,7 @@ -.dm { - margin-top: 16px; - min-width: 100px; - max-width: 90%; - white-space: pre-wrap; - color: var(--font-color); -} - -.dm a { - color: var(--font-color) !important; -} - -.dm > div:last-child { - color: var(--gray-light); - font-size: small; - margin-top: 3px; -} - -.dm.other > div:first-child { - padding: 12px 16px; - background: var(--gray-secondary); - border-radius: 16px 16px 16px 0px; -} - -.dm.me { - align-self: flex-end; -} - -.dm.me > div:first-child { - padding: 12px 16px; +.dm-gradient { background: var(--dm-gradient); - border-radius: 16px 16px 0px 16px; } -.dm.me > div:last-child { - text-align: end; +.other { + background: var(--gray-superdark); } diff --git a/packages/app/src/Element/Chat/DM.tsx b/packages/app/src/Element/Chat/DM.tsx index 831d7a66..69d44a60 100644 --- a/packages/app/src/Element/Chat/DM.tsx +++ b/packages/app/src/Element/Chat/DM.tsx @@ -1,4 +1,5 @@ import "./DM.css"; + import { useEffect, useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { useInView } from "react-intersection-observer"; @@ -55,8 +56,19 @@ export default function DM(props: DMProps) { }, [inView]); return ( -
-
+
+
{sender()} {content ? ( @@ -64,7 +76,7 @@ export default function DM(props: DMProps) { )}
-
+
diff --git a/packages/app/src/Element/Chat/DmWindow.css b/packages/app/src/Element/Chat/DmWindow.css deleted file mode 100644 index 1c66b73d..00000000 --- a/packages/app/src/Element/Chat/DmWindow.css +++ /dev/null @@ -1,32 +0,0 @@ -.dm-window { - display: flex; - flex-direction: column; - height: calc(100vh - 62px); -} -.dm-window > div:nth-child(1) { - padding: 12px 0; -} - -.dm-window > div:nth-child(2) { - overflow-y: auto; - padding: 0 10px 10px 10px; - flex-grow: 1; - display: flex; - flex-direction: column-reverse; -} - -.dm-window > div:nth-child(3) { - display: flex; - align-items: center; - gap: 10px; - padding: 5px 10px; -} - -.pfp-overlap .pfp:not(:last-of-type) { - margin-right: -20px; -} - -.pfp-overlap .avatar { - width: 32px; - height: 32px; -} diff --git a/packages/app/src/Element/Chat/DmWindow.tsx b/packages/app/src/Element/Chat/DmWindow.tsx index c7c07062..f8e52495 100644 --- a/packages/app/src/Element/Chat/DmWindow.tsx +++ b/packages/app/src/Element/Chat/DmWindow.tsx @@ -1,6 +1,4 @@ -import "./DmWindow.css"; -import { useMemo } from "react"; - +import { useEffect, useMemo, useRef } from "react"; import ProfileImage from "@/Element/User/ProfileImage"; import DM from "@/Element/Chat/DM"; import useLogin from "@/Hooks/useLogin"; @@ -18,7 +16,7 @@ export default function DmWindow({ id }: { id: string }) { return ; } else { return ( -
+
{chat.participants.map(v => ( ))} @@ -29,12 +27,12 @@ export default function DmWindow({ id }: { id: string }) { } return ( -
-
{sender()}
-
+
+
{sender()}
+
{chat && }
-
+
@@ -43,6 +41,9 @@ export default function DmWindow({ id }: { id: string }) { function DmChatSelected({ chat }: { chat: Chat }) { const { publicKey: myPubKey } = useLogin(s => ({ publicKey: s.publicKey })); + const messagesContainerRef = useRef(null); + const messagesEndRef = useRef(null); + const sortedDms = useMemo(() => { const myDms = chat?.messages; if (myPubKey && myDms) { @@ -52,11 +53,37 @@ function DmChatSelected({ chat }: { chat: Chat }) { return []; }, [chat, myPubKey]); + const scrollToBottom = () => { + messagesEndRef.current?.scrollIntoView({ behavior: "instant" }); + }; + + useEffect(() => { + const observer = new ResizeObserver(() => { + scrollToBottom(); + }); + + // Start observing the element that you want to keep in view + if (messagesContainerRef.current) { + observer.observe(messagesContainerRef.current); + } + + // Make sure to scroll to bottom on initial load + scrollToBottom(); + + // Clean up the observer on component unmount + return () => { + if (messagesContainerRef.current) { + observer.unobserve(messagesContainerRef.current); + } + }; + }, [sortedDms]); + return ( - <> +
{sortedDms.map(a => ( ))} - +
+
); } diff --git a/packages/app/src/Element/Text.css b/packages/app/src/Element/Text.css index 6710d669..5d089bc4 100644 --- a/packages/app/src/Element/Text.css +++ b/packages/app/src/Element/Text.css @@ -7,7 +7,7 @@ text-overflow: ellipsis; white-space: pre-wrap; display: inline; - overflow-wrap: break-word; + overflow-wrap: anywhere; } .text .text-frag > a { diff --git a/packages/app/src/Element/User/ProfileImage.tsx b/packages/app/src/Element/User/ProfileImage.tsx index 9f238257..1cdc1f21 100644 --- a/packages/app/src/Element/User/ProfileImage.tsx +++ b/packages/app/src/Element/User/ProfileImage.tsx @@ -20,6 +20,7 @@ export interface ProfileImageProps { link?: string; defaultNip?: string; verifyNip?: boolean; + showNip05?: boolean; overrideUsername?: string; profile?: UserMetadata; size?: number; @@ -38,6 +39,7 @@ export default function ProfileImage({ link, defaultNip, verifyNip, + showNip05 = true, overrideUsername, profile, size, @@ -93,7 +95,7 @@ export default function ProfileImage({
{overrideUsername ? overrideUsername : } - {nip05 && } + {showNip05 && nip05 && }
{subHeader}
diff --git a/packages/app/src/Element/User/ProfilePreview.tsx b/packages/app/src/Element/User/ProfilePreview.tsx index 4d51e153..0e3911ac 100644 --- a/packages/app/src/Element/User/ProfilePreview.tsx +++ b/packages/app/src/Element/User/ProfilePreview.tsx @@ -38,7 +38,10 @@ export default function ProfilePreview(props: ProfilePreviewProps) { return ( <> -
+
{inView && ( <> div:nth-child(1)::-webkit-scrollbar-track { - background: transparent !important; -} - -/* These should match what is in code too */ -@media (max-width: 768px) { - .dm-page { - grid-template-columns: 100vw; - height: calc(100vh - 62px); - } - - .dm-page > div:nth-child(1) { - margin: 0 !important; - } -} - -@media (min-width: 1500px) { - .dm-page { - grid-template-columns: 400px auto 400px; - } -} - -/* User list */ -.dm-page > div:nth-child(1) { - overflow-y: auto; - padding: 0 5px; -} - -/* Chat window */ -.dm-page > div:nth-child(2) { - padding: 0 12px; - margin: 0 4px; - height: 100vh; - background-color: var(--gray-superdark); - border-radius: 16px; -} - -/* Profile pannel */ -.dm-page > div:nth-child(3) { - margin: 16px; -} - -.dm-page > div:nth-child(3) .avatar { - margin-left: auto; - margin-right: auto; -} - -.dm-page > div:nth-child(3) .card { - cursor: pointer; -} - -.dm-page .new-chat { - min-width: 100px; -} - -.dm-page .chat-list > div.active { - background-color: var(--gray-superdark); - border-radius: 16px; -} - -.new-chat-modal .user-list { - max-height: 50vh; - overflow-y: auto; -} - -.new-chat-modal .user-list > div { - padding: 8px 12px; - cursor: pointer; -} - -/* user in list selected */ -.new-chat-modal .user-list > div.active { - background-color: var(--gray-dark); - border-radius: 16px; -} - -.new-chat-modal .modal-body { - padding: 24px 32px; -} - -.new-chat-modal h2, -.new-chat-modal h3, -.new-chat-modal p { - font-weight: 600; - margin: 0; -} - -.new-chat-modal h2 { - font-size: 21px; -} - -.new-chat-modal h3 { - font-size: 16px; -} - -.new-chat-modal p { - font-size: 11px; - letter-spacing: 1.21px; - text-transform: uppercase; -} diff --git a/packages/app/src/Pages/Messages/MessagesPage.tsx b/packages/app/src/Pages/Messages/MessagesPage.tsx index 0a9f6259..de59ac3a 100644 --- a/packages/app/src/Pages/Messages/MessagesPage.tsx +++ b/packages/app/src/Pages/Messages/MessagesPage.tsx @@ -1,5 +1,3 @@ -import "./MessagesPage.css"; - import React, { useEffect, useMemo, useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; import { useNavigate, useParams } from "react-router-dom"; @@ -74,7 +72,7 @@ export default function MessagesPage() { const isActive = cx.id === chat; return (
openChat(e, cx.type, cx.id)}> {conversationIdent(cx)} @@ -92,11 +90,11 @@ export default function MessagesPage() { } return ( -
+
{(pageWidth >= TwoCol || !chat) && ( -
-
- @@ -113,9 +111,9 @@ export default function MessagesPage() { .map(conversation)}
)} - {chat ? : pageWidth >= TwoCol &&
} + {chat ? : pageWidth >= TwoCol &&
} {pageWidth >= ThreeCol && chat && ( -
+
)}