UI changes (#166)
* Change read mark for messages * Change logout button * Change dm chat description * Fix creating dm channel * Fix reaction icon * Add tooltips to reaction buttons * Add reaction picker * Add reaction svg sizes * Extract Reactions
This commit is contained in:
parent
626f70c576
commit
64d2dec3f9
|
@ -22,6 +22,7 @@ import { HideIcon } from "./Icons/HideIcon";
|
||||||
import { Icon } from "./Icons/Icon";
|
import { Icon } from "./Icons/Icon";
|
||||||
import { MoreIcon } from "./Icons/MoreIcon";
|
import { MoreIcon } from "./Icons/MoreIcon";
|
||||||
import { ReadIcon } from "./Icons/ReadIcon";
|
import { ReadIcon } from "./Icons/ReadIcon";
|
||||||
|
import { ReadMessageIcon } from "./Icons/ReadMessageIcon";
|
||||||
import { ReplyIcon } from "./Icons/ReplyActivityIcon";
|
import { ReplyIcon } from "./Icons/ReplyActivityIcon";
|
||||||
import { ShowIcon } from "./Icons/ShowIcon";
|
import { ShowIcon } from "./Icons/ShowIcon";
|
||||||
import { UntrustworthIcon } from "./Icons/UntrustworthIcon";
|
import { UntrustworthIcon } from "./Icons/UntrustworthIcon";
|
||||||
|
@ -247,7 +248,7 @@ function ActivityMessage({
|
||||||
}}
|
}}
|
||||||
className={`${activity.isRead && "read"}`}
|
className={`${activity.isRead && "read"}`}
|
||||||
>
|
>
|
||||||
<ReadIcon isRead={activity.isRead} />
|
<ReadMessageIcon isRead={activity.isRead} />
|
||||||
</ActivityBtn>
|
</ActivityBtn>
|
||||||
<Tooltip tip="Mark Read" className="read" />
|
<Tooltip tip="Mark Read" className="read" />
|
||||||
</BtnWrapper>
|
</BtnWrapper>
|
||||||
|
|
|
@ -27,7 +27,8 @@ export function ChatCreation({
|
||||||
(member) => member?.customName ?? member.trueName
|
(member) => member?.customName ?? member.trueName
|
||||||
) ?? []
|
) ?? []
|
||||||
);
|
);
|
||||||
const { contacts, createGroupChat, addMembers } = useMessengerContext();
|
const { contacts, createGroupChat, addMembers, setChannel } =
|
||||||
|
useMessengerContext();
|
||||||
const setChatState = useChatState()[1];
|
const setChatState = useChatState()[1];
|
||||||
|
|
||||||
const addMember = useCallback(
|
const addMember = useCallback(
|
||||||
|
@ -50,7 +51,14 @@ export function ChatCreation({
|
||||||
if (identity) {
|
if (identity) {
|
||||||
const newGroup = group.slice();
|
const newGroup = group.slice();
|
||||||
newGroup.push(bufToHex(identity.publicKey));
|
newGroup.push(bufToHex(identity.publicKey));
|
||||||
group.length > 1 ? createGroupChat(newGroup) : createGroupChat(newGroup);
|
group.length > 1
|
||||||
|
? createGroupChat(newGroup)
|
||||||
|
: setChannel({
|
||||||
|
id: newGroup[0],
|
||||||
|
name: newGroup[0],
|
||||||
|
type: "dm",
|
||||||
|
description: `Chatkey: ${newGroup[0]} `,
|
||||||
|
});
|
||||||
setChatState(ChatState.ChatBody);
|
setChatState(ChatState.ChatBody);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -197,7 +197,7 @@ const ContentWrapper = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const MentionBLock = styled.div`
|
const MentionBLock = styled.div`
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
color: ${({ theme }) => theme.mentionColor};
|
color: ${({ theme }) => theme.mentionColor};
|
||||||
background: ${({ theme }) => theme.mentionBgHover};
|
background: ${({ theme }) => theme.mentionBgHover};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { Emoji, getEmojiDataFromNative } from "emoji-mart";
|
||||||
|
import data from "emoji-mart/data/all.json";
|
||||||
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const emojiHeart = getEmojiDataFromNative("❤️", "twitter", data);
|
||||||
|
const emojiLike = getEmojiDataFromNative("👍", "twitter", data);
|
||||||
|
const emojiDislike = getEmojiDataFromNative("👎", "twitter", data);
|
||||||
|
const emojiLaughing = getEmojiDataFromNative("😆", "twitter", data);
|
||||||
|
const emojiDisappointed = getEmojiDataFromNative("😥", "twitter", data);
|
||||||
|
const emojiRage = getEmojiDataFromNative("😡", "twitter", data);
|
||||||
|
|
||||||
|
const emojiArr = [
|
||||||
|
emojiHeart,
|
||||||
|
emojiLike,
|
||||||
|
emojiDislike,
|
||||||
|
emojiLaughing,
|
||||||
|
emojiDisappointed,
|
||||||
|
emojiRage,
|
||||||
|
];
|
||||||
|
|
||||||
|
export function ReactionPicker() {
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
{emojiArr.map((emoji) => (
|
||||||
|
<EmojiBtn key={emoji.id}>
|
||||||
|
{" "}
|
||||||
|
<Emoji
|
||||||
|
emoji={emoji}
|
||||||
|
set={"twitter"}
|
||||||
|
skin={emoji.skin || 1}
|
||||||
|
size={32}
|
||||||
|
/>
|
||||||
|
</EmojiBtn>
|
||||||
|
))}
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
width: 266px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: -78px;
|
||||||
|
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||||
|
box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
border-radius: 16px 16px 4px 16px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
visibility: hidden;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const EmojiBtn = styled.button`
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 8px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: ${({ theme }) => theme.inputColor};
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,80 @@
|
||||||
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import { Reply } from "../../hooks/useReply";
|
||||||
|
import { ChatMessage } from "../../models/ChatMessage";
|
||||||
|
import { ReactionSvg } from "../Icons/ReactionIcon";
|
||||||
|
import { ReplySvg } from "../Icons/ReplyIcon";
|
||||||
|
|
||||||
|
import { Tooltip } from "./Tooltip";
|
||||||
|
|
||||||
|
interface ReactionsProps {
|
||||||
|
message: ChatMessage;
|
||||||
|
showReactions: boolean;
|
||||||
|
setShowReactions: (val: boolean) => void;
|
||||||
|
setReply: (val: Reply | undefined) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Reactions({
|
||||||
|
message,
|
||||||
|
showReactions,
|
||||||
|
setShowReactions,
|
||||||
|
setReply,
|
||||||
|
}: ReactionsProps) {
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
<ReactionBtn onClick={() => setShowReactions(!showReactions)}>
|
||||||
|
<ReactionSvg width={22} height={22} />
|
||||||
|
<Tooltip tip="Add reaction" />
|
||||||
|
</ReactionBtn>
|
||||||
|
<ReactionBtn
|
||||||
|
onClick={() =>
|
||||||
|
setReply({
|
||||||
|
sender: message.sender,
|
||||||
|
content: message.content,
|
||||||
|
image: message.image,
|
||||||
|
id: message.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ReplySvg width={22} height={22} />
|
||||||
|
<Tooltip tip="Reply" />
|
||||||
|
</ReactionBtn>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: -18px;
|
||||||
|
box-shadow: 0px 4px 12px rgba(0, 34, 51, 0.08);
|
||||||
|
border-radius: 8px;
|
||||||
|
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||||
|
padding: 2px;
|
||||||
|
visibility: hidden;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ReactionBtn = styled.button`
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 8px;
|
||||||
|
align-self: center;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: ${({ theme }) => theme.buttonBgHover};
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover > svg {
|
||||||
|
fill: ${({ theme }) => theme.tertiary};
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover > div {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -17,5 +17,5 @@ export const LogoutIcon = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Icon = styled.svg`
|
const Icon = styled.svg`
|
||||||
fill: ${({ theme }) => theme.primary};
|
fill: ${({ theme }) => theme.tertiary};
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -2,14 +2,16 @@ import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
type ReactionProps = {
|
type ReactionProps = {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function ReactionSvg({ className }: ReactionProps) {
|
export function ReactionSvg({ width, height, className }: ReactionProps) {
|
||||||
return (
|
return (
|
||||||
<Icon
|
<Icon
|
||||||
width="22"
|
width={width}
|
||||||
height="22"
|
height={height}
|
||||||
viewBox="0 0 22 22"
|
viewBox="0 0 22 22"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className={className}
|
className={className}
|
||||||
|
@ -33,11 +35,6 @@ export function ReactionSvg({ className }: ReactionProps) {
|
||||||
d="M15.4971 6.45233C15.2392 6.14281 14.7792 6.101 14.4696 6.35892L11.9685 8.44324C11.7325 8.63987 11.645 8.96322 11.7496 9.25201C11.8541 9.5408 12.1284 9.73318 12.4355 9.73318C13.5921 9.73318 15.2769 10.1077 16.2174 10.6957C16.559 10.9093 17.0091 10.8055 17.2227 10.4639C17.4363 10.1223 17.3325 9.67217 16.9909 9.45857C16.3482 9.05678 15.5056 8.75255 14.6556 8.55308C14.4845 8.51292 14.4285 8.29242 14.5635 8.1799L15.4037 7.47977C15.7132 7.22185 15.755 6.76184 15.4971 6.45233Z"
|
d="M15.4971 6.45233C15.2392 6.14281 14.7792 6.101 14.4696 6.35892L11.9685 8.44324C11.7325 8.63987 11.645 8.96322 11.7496 9.25201C11.8541 9.5408 12.1284 9.73318 12.4355 9.73318C13.5921 9.73318 15.2769 10.1077 16.2174 10.6957C16.559 10.9093 17.0091 10.8055 17.2227 10.4639C17.4363 10.1223 17.3325 9.67217 16.9909 9.45857C16.3482 9.05678 15.5056 8.75255 14.6556 8.55308C14.4845 8.51292 14.4285 8.29242 14.5635 8.1799L15.4037 7.47977C15.7132 7.22185 15.755 6.76184 15.4971 6.45233Z"
|
||||||
/>
|
/>
|
||||||
</g>
|
</g>
|
||||||
<defs>
|
|
||||||
<clipPath id="clip0_1136_291537">
|
|
||||||
<rect width="22" height="22" />
|
|
||||||
</clipPath>
|
|
||||||
</defs>
|
|
||||||
</Icon>
|
</Icon>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
interface ReadMessageIconProps {
|
||||||
|
isRead?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ReadMessageIcon = ({ isRead }: ReadMessageIconProps) => {
|
||||||
|
return (
|
||||||
|
<Icon
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
className={`${isRead && "read"}`}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fillRule="evenodd"
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M20.7751 5.57055C21.1415 5.90642 21.1662 6.47573 20.8304 6.84214L10.2605 18.3729C10.0946 18.5539 9.862 18.6592 9.61658 18.6646C9.37116 18.6699 9.13421 18.5747 8.96064 18.4012L3.19524 12.6358C2.84377 12.2843 2.84377 11.7145 3.19524 11.363C3.54672 11.0115 4.11656 11.0115 4.46804 11.363L9.1995 16.0945C9.40079 16.2957 9.72928 16.2886 9.92163 16.0788L19.5035 5.62584C19.8394 5.25943 20.4087 5.23468 20.7751 5.57055Z"
|
||||||
|
/>
|
||||||
|
</Icon>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Icon = styled.svg`
|
||||||
|
fill: ${({ theme }) => theme.tertiary};
|
||||||
|
|
||||||
|
&.read {
|
||||||
|
fill: ${({ theme }) => theme.secondary};
|
||||||
|
}
|
||||||
|
`;
|
|
@ -29,14 +29,16 @@ export function Member({
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
|
|
||||||
const onMemberClick = () => {
|
const onMemberClick = () => {
|
||||||
switchShowMembers?.();
|
if (!isYou) {
|
||||||
setChannel({
|
switchShowMembers?.();
|
||||||
id: contact.id,
|
setChannel({
|
||||||
name: contact?.customName ?? contact.trueName,
|
id: contact.id,
|
||||||
type: "dm",
|
name: contact?.customName ?? contact.trueName,
|
||||||
description: "Contact",
|
type: "dm",
|
||||||
members: [contact],
|
description: `Chatkey: ${contact.id} `,
|
||||||
});
|
members: [contact],
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -82,6 +84,7 @@ export const MemberData = styled.div`
|
||||||
|
|
||||||
&.you {
|
&.you {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
cursor: default;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {
|
||||||
useSetIdentity,
|
useSetIdentity,
|
||||||
} from "../../contexts/identityProvider";
|
} from "../../contexts/identityProvider";
|
||||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||||
import { TopBtn } from "../Chat/ChatTopbar";
|
import { buttonStyles } from "../Buttons/buttonStyle";
|
||||||
import { LogoutIcon } from "../Icons/LogoutIcon";
|
import { LogoutIcon } from "../Icons/LogoutIcon";
|
||||||
|
|
||||||
import { Member } from "./Member";
|
import { Member } from "./Member";
|
||||||
|
@ -56,12 +56,11 @@ export function MembersList({ switchShowMembers }: MembersListProps) {
|
||||||
customName: nickname,
|
customName: nickname,
|
||||||
trueName: utils.bufToHex(identity.publicKey),
|
trueName: utils.bufToHex(identity.publicKey),
|
||||||
}}
|
}}
|
||||||
switchShowMembers={switchShowMembers}
|
|
||||||
isYou={true}
|
isYou={true}
|
||||||
/>
|
/>
|
||||||
<TopBtn onClick={() => logout(undefined)}>
|
<LogoutBtn onClick={() => logout(undefined)}>
|
||||||
<LogoutIcon />
|
<LogoutIcon />
|
||||||
</TopBtn>
|
</LogoutBtn>
|
||||||
</Row>
|
</Row>
|
||||||
</MemberCategory>
|
</MemberCategory>
|
||||||
)}
|
)}
|
||||||
|
@ -124,3 +123,11 @@ const Row = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const LogoutBtn = styled.button`
|
||||||
|
${buttonStyles}
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 0;
|
||||||
|
`;
|
||||||
|
|
|
@ -11,9 +11,9 @@ import { ChatMessage } from "../../models/ChatMessage";
|
||||||
import { equalDate } from "../../utils";
|
import { equalDate } from "../../utils";
|
||||||
import { ChatMessageContent } from "../Chat/ChatMessageContent";
|
import { ChatMessageContent } from "../Chat/ChatMessageContent";
|
||||||
import { ContactMenu } from "../Form/ContactMenu";
|
import { ContactMenu } from "../Form/ContactMenu";
|
||||||
|
import { ReactionPicker } from "../Form/ReactionPicker";
|
||||||
|
import { Reactions } from "../Form/Reactions";
|
||||||
import { Icon } from "../Icons/Icon";
|
import { Icon } from "../Icons/Icon";
|
||||||
import { ReactionSvg } from "../Icons/ReactionIcon";
|
|
||||||
import { ReplySvg } from "../Icons/ReplyIcon";
|
|
||||||
import { UntrustworthIcon } from "../Icons/UntrustworthIcon";
|
import { UntrustworthIcon } from "../Icons/UntrustworthIcon";
|
||||||
import { UserLogo } from "../Members/UserLogo";
|
import { UserLogo } from "../Members/UserLogo";
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ export function UiMessage({
|
||||||
[message.sender, contacts]
|
[message.sender, contacts]
|
||||||
);
|
);
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
|
const [showReactions, setShowReactions] = useState(false);
|
||||||
const [mentioned, setMentioned] = useState(false);
|
const [mentioned, setMentioned] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -147,23 +148,13 @@ export function UiMessage({
|
||||||
</MessageText>
|
</MessageText>
|
||||||
</ContentWrapper>
|
</ContentWrapper>
|
||||||
</UserMessageWrapper>
|
</UserMessageWrapper>
|
||||||
<Reactions>
|
{showReactions && <ReactionPicker />}
|
||||||
<ReactionBtn>
|
<Reactions
|
||||||
<ReactionSvg />
|
message={message}
|
||||||
</ReactionBtn>
|
setReply={setReply}
|
||||||
<ReactionBtn
|
showReactions={showReactions}
|
||||||
onClick={() =>
|
setShowReactions={setShowReactions}
|
||||||
setReply({
|
/>
|
||||||
sender: message.sender,
|
|
||||||
content: message.content,
|
|
||||||
image: message.image,
|
|
||||||
id: message.id,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<ReplySvg width={22} height={22} />
|
|
||||||
</ReactionBtn>
|
|
||||||
</Reactions>
|
|
||||||
</MessageWrapper>
|
</MessageWrapper>
|
||||||
</MessageOuterWrapper>
|
</MessageOuterWrapper>
|
||||||
);
|
);
|
||||||
|
@ -173,32 +164,3 @@ const UserMessageWrapper = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Reactions = styled.div`
|
|
||||||
display: flex;
|
|
||||||
position: absolute;
|
|
||||||
right: 20px;
|
|
||||||
top: -18px;
|
|
||||||
box-shadow: 0px 4px 12px rgba(0, 34, 51, 0.08);
|
|
||||||
border-radius: 8px;
|
|
||||||
background: ${({ theme }) => theme.bodyBackgroundColor};
|
|
||||||
visibility: hidden;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ReactionBtn = styled.button`
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 8px;
|
|
||||||
align-self: center;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: ${({ theme }) => theme.buttonBgHover};
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover > svg {
|
|
||||||
fill: ${({ theme }) => theme.tertiary};
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
Loading…
Reference in New Issue