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:
Maria Rushkova 2022-01-04 07:58:06 +01:00 committed by GitHub
parent 626f70c576
commit 64d2dec3f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 229 additions and 73 deletions

View File

@ -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>

View File

@ -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);
} }
}; };

View File

@ -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;

View File

@ -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};
}
`;

View File

@ -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;
}
`;

View File

@ -17,5 +17,5 @@ export const LogoutIcon = () => {
}; };
const Icon = styled.svg` const Icon = styled.svg`
fill: ${({ theme }) => theme.primary}; fill: ${({ theme }) => theme.tertiary};
`; `;

View File

@ -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>
); );
} }

View File

@ -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};
}
`;

View File

@ -29,14 +29,16 @@ export function Member({
const [showMenu, setShowMenu] = useState(false); const [showMenu, setShowMenu] = useState(false);
const onMemberClick = () => { const onMemberClick = () => {
if (!isYou) {
switchShowMembers?.(); switchShowMembers?.();
setChannel({ setChannel({
id: contact.id, id: contact.id,
name: contact?.customName ?? contact.trueName, name: contact?.customName ?? contact.trueName,
type: "dm", type: "dm",
description: "Contact", description: `Chatkey: ${contact.id} `,
members: [contact], members: [contact],
}); });
}
}; };
return ( return (
@ -82,6 +84,7 @@ export const MemberData = styled.div`
&.you { &.you {
margin-bottom: 0; margin-bottom: 0;
cursor: default;
} }
`; `;

View File

@ -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;
`;

View File

@ -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};
}
`;