Activity UI improvements (#150)
This commit is contained in:
parent
c7065341b4
commit
c06ea9cca0
|
@ -3,6 +3,7 @@ import styled from "styled-components";
|
|||
|
||||
import { useActivities } from "../contexts/activityProvider";
|
||||
import { useMessengerContext } from "../contexts/messengerProvider";
|
||||
import { useModal } from "../contexts/modalProvider";
|
||||
import { useClickOutside } from "../hooks/useClickOutside";
|
||||
import { Activity } from "../models/Activity";
|
||||
import { equalDate } from "../utils/equalDate";
|
||||
|
@ -20,6 +21,7 @@ import {
|
|||
UserNameWrapper,
|
||||
} from "./Chat/ChatMessages";
|
||||
import { ContactMenu } from "./Form/ContactMenu";
|
||||
import { Tooltip } from "./Form/Tooltip";
|
||||
import { CheckSvg } from "./Icons/CheckIcon";
|
||||
import { ClearSvg } from "./Icons/ClearIcon";
|
||||
import { GroupIcon } from "./Icons/GroupIcon";
|
||||
|
@ -31,16 +33,26 @@ import { ReplyIcon } from "./Icons/ReplyActivityIcon";
|
|||
import { ShowIcon } from "./Icons/ShowIcon";
|
||||
import { UntrustworthIcon } from "./Icons/UntrustworthIcon";
|
||||
import { UserIcon } from "./Icons/UserIcon";
|
||||
import { ProfileModalName } from "./Modals/ProfileModal";
|
||||
import { textMediumStyles, textSmallStyles } from "./Text";
|
||||
|
||||
const today = new Date();
|
||||
|
||||
type ActivityMessageProps = {
|
||||
activity: Activity;
|
||||
setShowActivityCenter: (val: boolean) => void;
|
||||
};
|
||||
|
||||
function ActivityMessage({ activity }: ActivityMessageProps) {
|
||||
const { contacts } = useMessengerContext();
|
||||
function ActivityMessage({
|
||||
activity,
|
||||
setShowActivityCenter,
|
||||
}: ActivityMessageProps) {
|
||||
const { contacts, setActiveChannel } = useMessengerContext();
|
||||
const { setModal } = useModal(ProfileModalName);
|
||||
const showChannel = () => {
|
||||
activity.channel && setActiveChannel(activity.channel),
|
||||
setShowActivityCenter(false);
|
||||
};
|
||||
|
||||
const [showMenu, setShowMenu] = useState(false);
|
||||
|
||||
|
@ -68,10 +80,18 @@ function ActivityMessage({ activity }: ActivityMessageProps) {
|
|||
<ActivityContent>
|
||||
<MessageHeaderWrapper>
|
||||
<UserNameWrapper>
|
||||
<UserName>
|
||||
<ActivityUserName
|
||||
onClick={() => {
|
||||
setModal({
|
||||
id: activity.user,
|
||||
renamingState: false,
|
||||
requestState: false,
|
||||
});
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{contact.customName ?? activity.user.slice(0, 10)}
|
||||
</UserName>
|
||||
</ActivityUserName>
|
||||
{contact.customName && (
|
||||
<UserAddress>
|
||||
{activity.user.slice(0, 5)}...{activity.user.slice(-3)}
|
||||
|
@ -102,7 +122,7 @@ function ActivityMessage({ activity }: ActivityMessageProps) {
|
|||
{type === "mention" &&
|
||||
activity.channel &&
|
||||
activity.channel.type !== "dm" && (
|
||||
<Tag>
|
||||
<Tag onClick={showChannel}>
|
||||
{activity.channel.type === "group" ? <GroupIcon /> : "#"}{" "}
|
||||
<span>{` ${activity.channel.name.slice(0, 10)}`}</span>
|
||||
</Tag>
|
||||
|
@ -112,7 +132,7 @@ function ActivityMessage({ activity }: ActivityMessageProps) {
|
|||
{activity.quote.image && (
|
||||
<ContextHeading>Posted an image in</ContextHeading>
|
||||
)}
|
||||
<Tag>
|
||||
<Tag onClick={showChannel}>
|
||||
<ReplyIcon /> <span>{activity.quote.content}</span>
|
||||
</Tag>
|
||||
</ReplyWrapper>
|
||||
|
@ -146,7 +166,9 @@ function ActivityMessage({ activity }: ActivityMessageProps) {
|
|||
setShowMenu((e) => !e);
|
||||
}}
|
||||
>
|
||||
{showMenu && <ContactMenu id="1" setShowMenu={setShowMenu} />}
|
||||
{showMenu && (
|
||||
<ContactMenu id={activity.user} setShowMenu={setShowMenu} />
|
||||
)}
|
||||
<MoreIcon />
|
||||
</ActivityBtn>
|
||||
</>
|
||||
|
@ -161,6 +183,7 @@ function ActivityMessage({ activity }: ActivityMessageProps) {
|
|||
<RequestStatus>Sent</RequestStatus>
|
||||
)}
|
||||
{type !== "request" && (
|
||||
<BtnWrapper>
|
||||
<ActivityBtn
|
||||
onClick={() => {
|
||||
activity.isRead = true;
|
||||
|
@ -169,6 +192,8 @@ function ActivityMessage({ activity }: ActivityMessageProps) {
|
|||
>
|
||||
<ReadIcon isRead={activity.isRead} />
|
||||
</ActivityBtn>
|
||||
<Tooltip tip="Mark Read" className="read" />
|
||||
</BtnWrapper>
|
||||
)}
|
||||
</MessageWrapper>
|
||||
</MessageOuterWrapper>
|
||||
|
@ -218,6 +243,7 @@ export function ActivityCenter({ setShowActivityCenter }: ActivityCenterProps) {
|
|||
</FilterBtn>
|
||||
</Filters>
|
||||
<Btns>
|
||||
<BtnWrapper>
|
||||
<ActivityBtn
|
||||
onClick={() => {
|
||||
shownActivities.map((activity) => (activity.isRead = true));
|
||||
|
@ -225,15 +251,24 @@ export function ActivityCenter({ setShowActivityCenter }: ActivityCenterProps) {
|
|||
>
|
||||
<ReadIcon />
|
||||
</ActivityBtn>
|
||||
<Tooltip tip="Mark all as Read" />
|
||||
</BtnWrapper>
|
||||
<BtnWrapper>
|
||||
<ActivityBtn onClick={() => setHideRead(!hideRead)}>
|
||||
{hideRead ? <ShowIcon /> : <HideIcon />}
|
||||
</ActivityBtn>
|
||||
<Tooltip tip={hideRead ? "Show read" : "Hide read"} />
|
||||
</BtnWrapper>
|
||||
</Btns>
|
||||
</ActivityFilter>
|
||||
{filteredActivities.length > 0 ? (
|
||||
<Activities>
|
||||
{filteredActivities.map((activity) => (
|
||||
<ActivityMessage key={activity.id} activity={activity} />
|
||||
<ActivityMessage
|
||||
key={activity.id}
|
||||
activity={activity}
|
||||
setShowActivityCenter={setShowActivityCenter}
|
||||
/>
|
||||
))}
|
||||
</Activities>
|
||||
) : (
|
||||
|
@ -287,6 +322,14 @@ const FilterBtn = styled.button`
|
|||
}
|
||||
`;
|
||||
|
||||
const BtnWrapper = styled.div`
|
||||
position: relative;
|
||||
|
||||
&:hover > div {
|
||||
visibility: visible;
|
||||
}
|
||||
`;
|
||||
|
||||
const ActivityBtn = styled.button`
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
@ -411,6 +454,13 @@ const ActivityContent = styled(ContentWrapper)`
|
|||
flex: 1;
|
||||
`;
|
||||
|
||||
const ActivityUserName = styled(UserName)`
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
`;
|
||||
const Btns = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
|
@ -135,11 +135,10 @@ const EditBtn = styled.button`
|
|||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
background: ${({ theme }) => theme.border};
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
background: ${({ theme }) => theme.inputColor};
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: ${({ theme }) => theme.sectionBackgroundColor};
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -76,13 +76,20 @@ export function ChatTopbar({
|
|||
<MoreIcon />
|
||||
</TopBtn>
|
||||
<ActivityWrapper>
|
||||
<TopBtn
|
||||
onClick={() => setShowActivityCenter(!showActivityCenter)}
|
||||
className="activity"
|
||||
>
|
||||
<TopBtn onClick={() => setShowActivityCenter(!showActivityCenter)}>
|
||||
<ActivityIcon />
|
||||
{activities.length > 0 && (
|
||||
<NotificationBagde>{activities.length}</NotificationBagde>
|
||||
<NotificationBagde
|
||||
className={
|
||||
activities.length > 99
|
||||
? "countless"
|
||||
: activities.length > 9
|
||||
? "wide"
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{activities.length < 100 ? activities.length : "∞"}
|
||||
</NotificationBagde>
|
||||
)}
|
||||
</TopBtn>
|
||||
</ActivityWrapper>
|
||||
|
@ -184,18 +191,11 @@ const TopBtn = styled.button`
|
|||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
background: ${({ theme }) => theme.sectionBackgroundColor};
|
||||
}
|
||||
|
||||
&:active,
|
||||
&.active {
|
||||
background: ${({ theme }) => theme.inputColor};
|
||||
}
|
||||
|
||||
&.activity {
|
||||
&:hover {
|
||||
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||
}
|
||||
&:active {
|
||||
background: ${({ theme }) => theme.sectionBackgroundColor};
|
||||
}
|
||||
`;
|
||||
|
||||
|
@ -205,14 +205,24 @@ const NotificationBagde = styled.div`
|
|||
position: absolute;
|
||||
top: -2px;
|
||||
right: -2px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
font-weight: 500;
|
||||
background-color: ${({ theme }) => theme.notificationColor};
|
||||
color: ${({ theme }) => theme.bodyBackgroundColor};
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
border-radius: 9px;
|
||||
|
||||
&.wide {
|
||||
width: 26px;
|
||||
right: -7px;
|
||||
}
|
||||
|
||||
&.countless {
|
||||
width: 22px;
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -35,8 +35,7 @@ export const MenuItem = styled.li`
|
|||
|
||||
&:hover,
|
||||
&:hover > span {
|
||||
background: ${({ theme }) => theme.tertiary};
|
||||
color: ${({ theme }) => theme.bodyBackgroundColor};
|
||||
background: ${({ theme }) => theme.border};
|
||||
}
|
||||
|
||||
& > svg {
|
||||
|
@ -46,15 +45,11 @@ export const MenuItem = styled.li`
|
|||
& > svg.red {
|
||||
fill: ${({ theme }) => theme.redColor};
|
||||
}
|
||||
|
||||
&:hover > svg {
|
||||
fill: ${({ theme }) => theme.bodyBackgroundColor};
|
||||
}
|
||||
`;
|
||||
|
||||
export const MenuText = styled.span`
|
||||
margin-left: 6px;
|
||||
color: ${({ theme }) => theme.tertiary};
|
||||
color: ${({ theme }) => theme.primary};
|
||||
|
||||
&.red {
|
||||
color: ${({ theme }) => theme.redColor};
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import { TipIcon } from "../Icons/TipIcon";
|
||||
import { textSmallStyles } from "../Text";
|
||||
|
||||
type TooltipProps = {
|
||||
tip: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function Tooltip({ tip, className }: TooltipProps) {
|
||||
return (
|
||||
<TooltipWrapper className={className}>
|
||||
<TooltipBlock>
|
||||
<TooltipText>{tip}</TooltipText>
|
||||
<TipIcon className={className} />
|
||||
</TooltipBlock>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const TooltipWrapper = styled.div`
|
||||
width: max-content;
|
||||
position: absolute;
|
||||
top: calc(-100% - 12px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
visibility: hidden;
|
||||
|
||||
&.read {
|
||||
left: 18%;
|
||||
}
|
||||
`;
|
||||
const TooltipBlock = styled.div`
|
||||
background: ${({ theme }) => theme.primary};
|
||||
border-radius: 8px;
|
||||
position: relative;
|
||||
padding: 8px;
|
||||
`;
|
||||
|
||||
const TooltipText = styled.p`
|
||||
font-weight: 500;
|
||||
color: ${({ theme }) => theme.bodyBackgroundColor};
|
||||
${textSmallStyles};
|
||||
`;
|
|
@ -14,7 +14,6 @@ export const ActivityIcon = () => {
|
|||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M15.2815 19C14.9452 19 14.7036 19.3279 14.7349 19.6628C14.7449 19.7703 14.7504 19.8827 14.7504 20C14.7504 21.3889 13.5441 22.75 12.0004 22.75C10.4568 22.75 9.25041 21.3889 9.25041 20C9.25041 19.8827 9.25591 19.7703 9.26596 19.6628C9.29725 19.3279 9.05564 19 8.71934 19H5.52151C3.78523 19 2.87368 16.9394 4.04163 15.6547L5.21849 14.3601C5.72921 13.7983 6.06949 13.1028 6.19958 12.3548L7.31505 5.94085C7.71121 3.66293 9.6883 2 12.0004 2C14.3125 2 16.2896 3.66293 16.6858 5.94085L17.8012 12.3548C17.9313 13.1028 18.2716 13.7983 18.7823 14.3601L19.9592 15.6547C21.1271 16.9394 20.2156 19 18.4793 19H15.2815ZM11.0327 19.0283L11.0318 19.0293L11.0395 19.0214L11.0419 19.0188C11.0432 19.0175 11.0438 19.0168 11.0439 19.0167C11.0443 19.0163 11.0439 19.0167 11.0439 19.0167L11.0419 19.0188C11.0529 19.0073 11.0685 19 11.0845 19H12.9164C12.9323 19 12.9474 19.0068 12.9584 19.0183C12.9612 19.0217 12.9684 19.0302 12.9785 19.0438C13.0015 19.0744 13.0394 19.13 13.0796 19.2104C13.1587 19.3687 13.2504 19.6296 13.2504 20C13.2504 20.6111 12.6659 21.25 12.0004 21.25C11.3349 21.25 10.7504 20.6111 10.7504 20C10.7504 19.6296 10.8421 19.3687 10.9212 19.2104C10.9614 19.13 10.9993 19.0744 11.0223 19.0438C11.0325 19.0302 11.0391 19.0222 11.0419 19.0188L11.0395 19.0214L11.0377 19.0233L11.0345 19.0265L11.0327 19.0283ZM5.15154 16.6637L6.3284 15.3691C7.03064 14.5967 7.49853 13.6403 7.6774 12.6118L8.79286 6.19786C9.06407 4.63842 10.4176 3.5 12.0004 3.5C13.5833 3.5 14.9368 4.63842 15.208 6.19786L16.3234 12.6118C16.5023 13.6403 16.9702 14.5967 17.6724 15.3691L18.8493 16.6637C19.1413 16.9849 18.9134 17.5 18.4793 17.5H5.52151C5.08744 17.5 4.85956 16.9849 5.15154 16.6637Z"
|
||||
fill="black"
|
||||
/>
|
||||
</Icon>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
type TipIconProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export const TipIcon = ({ className }: TipIconProps) => {
|
||||
return (
|
||||
<Icon
|
||||
width="26"
|
||||
height="8"
|
||||
viewBox="0 0 26 8"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className={className}
|
||||
>
|
||||
<path d="M0.738296 -2.08325e-08L25.2617 -2.16474e-06C24.525 -2.10033e-06 23.8185 0.216311 23.2975 0.601352L13.491 7.84966C13.2198 8.05011 12.7802 8.05011 12.509 7.84966L2.70248 0.601354C2.18155 0.216314 1.47501 -8.52379e-08 0.738296 -2.08325e-08Z" />
|
||||
</Icon>
|
||||
);
|
||||
};
|
||||
|
||||
const Icon = styled.svg`
|
||||
fill: ${({ theme }) => theme.primary};
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
&.read {
|
||||
left: 62%;
|
||||
}
|
||||
`;
|
Loading…
Reference in New Issue