UI fixes & improvements (#185)
* Return back arrow button * Hide activity center in narrow mode * Extract back button * Add back button to chat creation narrow mode * Extract activity center components * Add activity center to chat creation mode * Remove activity center button border * Change cursor for picture input * Member name wrapping
This commit is contained in:
parent
78296b041d
commit
39a02cc0ed
|
@ -0,0 +1,108 @@
|
||||||
|
import React, { useMemo, useRef, useState } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import { useActivities } from "../../contexts/activityProvider";
|
||||||
|
import { useIdentity } from "../../contexts/identityProvider";
|
||||||
|
import { useClickOutside } from "../../hooks/useClickOutside";
|
||||||
|
import { TopBtn } from "../Chat/ChatTopbar";
|
||||||
|
import { ActivityIcon } from "../Icons/ActivityIcon";
|
||||||
|
|
||||||
|
import { ActivityCenter } from "./ActivityCenter";
|
||||||
|
|
||||||
|
interface ActivityButtonProps {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ActivityButton({ className }: ActivityButtonProps) {
|
||||||
|
const { activities } = useActivities();
|
||||||
|
const identity = useIdentity();
|
||||||
|
const disabled = useMemo(() => !identity, [identity]);
|
||||||
|
const ref = useRef(null);
|
||||||
|
useClickOutside(ref, () => setShowActivityCenter(false));
|
||||||
|
|
||||||
|
const [showActivityCenter, setShowActivityCenter] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ActivityWrapper ref={ref} className={className}>
|
||||||
|
<TopBtn
|
||||||
|
onClick={() => setShowActivityCenter(!showActivityCenter)}
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
|
<ActivityIcon />
|
||||||
|
{activities.length > 0 && (
|
||||||
|
<NotificationBagde
|
||||||
|
className={
|
||||||
|
activities.length > 99
|
||||||
|
? "countless"
|
||||||
|
: activities.length > 9
|
||||||
|
? "wide"
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{activities.length < 100 ? activities.length : "∞"}
|
||||||
|
</NotificationBagde>
|
||||||
|
)}
|
||||||
|
</TopBtn>
|
||||||
|
{showActivityCenter && (
|
||||||
|
<ActivityCenter setShowActivityCenter={setShowActivityCenter} />
|
||||||
|
)}
|
||||||
|
</ActivityWrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ActivityWrapper = styled.div`
|
||||||
|
padding-left: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 50%;
|
||||||
|
width: 2px;
|
||||||
|
height: 24px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
border-radius: 1px;
|
||||||
|
background: ${({ theme }) => theme.primary};
|
||||||
|
opacity: 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.creation {
|
||||||
|
padding-left: 0px;
|
||||||
|
margin-left: 16px;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const NotificationBagde = styled.div`
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
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};
|
||||||
|
border-radius: 9px;
|
||||||
|
|
||||||
|
&.wide {
|
||||||
|
width: 26px;
|
||||||
|
right: -7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.countless {
|
||||||
|
width: 22px;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -0,0 +1,184 @@
|
||||||
|
import React, { useMemo, useState } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import { useActivities } from "../../contexts/activityProvider";
|
||||||
|
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||||
|
import { buttonTransparentStyles } from "../Buttons/buttonStyle";
|
||||||
|
import { Tooltip } from "../Form/Tooltip";
|
||||||
|
import { HideIcon } from "../Icons/HideIcon";
|
||||||
|
import { ReadIcon } from "../Icons/ReadIcon";
|
||||||
|
import { ShowIcon } from "../Icons/ShowIcon";
|
||||||
|
|
||||||
|
import { ActivityMessage } from "./ActivityMessage";
|
||||||
|
|
||||||
|
interface ActivityCenterProps {
|
||||||
|
setShowActivityCenter: (val: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ActivityCenter({ setShowActivityCenter }: ActivityCenterProps) {
|
||||||
|
const { activities } = useActivities();
|
||||||
|
const { contacts } = useMessengerContext();
|
||||||
|
|
||||||
|
const shownActivities = useMemo(
|
||||||
|
() =>
|
||||||
|
activities.filter(
|
||||||
|
(activity) => !contacts?.[activity.user]?.blocked ?? true
|
||||||
|
),
|
||||||
|
[contacts, activities, activities.length]
|
||||||
|
);
|
||||||
|
|
||||||
|
const [hideRead, setHideRead] = useState(false);
|
||||||
|
|
||||||
|
const [filter, setFilter] = useState("");
|
||||||
|
|
||||||
|
const filteredActivities = shownActivities.filter((activity) =>
|
||||||
|
filter
|
||||||
|
? activity.type === filter
|
||||||
|
: hideRead
|
||||||
|
? activity.isRead !== true
|
||||||
|
: activity
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ActivityBlock>
|
||||||
|
<ActivityFilter>
|
||||||
|
<FlexDiv>
|
||||||
|
<FilterBtn onClick={() => setFilter("")}>All</FilterBtn>
|
||||||
|
<FilterBtn onClick={() => setFilter("mention")}>Mentions</FilterBtn>
|
||||||
|
<FilterBtn onClick={() => setFilter("reply")}>Replies</FilterBtn>
|
||||||
|
<FilterBtn onClick={() => setFilter("request")}>
|
||||||
|
Contact requests
|
||||||
|
</FilterBtn>
|
||||||
|
</FlexDiv>
|
||||||
|
<Btns>
|
||||||
|
<BtnWrapper>
|
||||||
|
<ActivityBtn
|
||||||
|
onClick={() => {
|
||||||
|
shownActivities.map((activity) => (activity.isRead = true));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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}
|
||||||
|
setShowActivityCenter={setShowActivityCenter}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Activities>
|
||||||
|
) : (
|
||||||
|
<EmptyActivities>Notifications will appear here</EmptyActivities>
|
||||||
|
)}
|
||||||
|
</ActivityBlock>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ActivityBlock = styled.div`
|
||||||
|
width: 600px;
|
||||||
|
height: 770px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||||
|
box-shadow: 0px 12px 24px rgba(0, 34, 51, 0.1);
|
||||||
|
border-radius: 8px;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 4px);
|
||||||
|
right: 0;
|
||||||
|
z-index: 100;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const ActivityFilter = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 13px 16px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FlexDiv = styled.div`
|
||||||
|
display: flex;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const FilterBtn = styled.button`
|
||||||
|
${buttonTransparentStyles}
|
||||||
|
|
||||||
|
& + & {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const BtnWrapper = styled.div`
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover > div {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ActivityBtn = 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};
|
||||||
|
}
|
||||||
|
|
||||||
|
&.read {
|
||||||
|
&:hover {
|
||||||
|
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.accept {
|
||||||
|
&:hover {
|
||||||
|
background: rgba(78, 188, 96, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.decline {
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 45, 85, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& + & {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Activities = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const EmptyActivities = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
color: ${({ theme }) => theme.secondary};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Btns = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
|
@ -1,32 +1,25 @@
|
||||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { useActivities } from "../contexts/activityProvider";
|
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||||
import { useMessengerContext } from "../contexts/messengerProvider";
|
import { useModal } from "../../contexts/modalProvider";
|
||||||
import { useModal } from "../contexts/modalProvider";
|
import { Activity } from "../../models/Activity";
|
||||||
import { useClickOutside } from "../hooks/useClickOutside";
|
import { equalDate } from "../../utils/equalDate";
|
||||||
import { Activity } from "../models/Activity";
|
import { DownloadButton } from "../Buttons/DownloadButton";
|
||||||
import { equalDate } from "../utils/equalDate";
|
import { Mention } from "../Chat/ChatMessageContent";
|
||||||
|
import { Logo } from "../CommunityIdentity";
|
||||||
import { DownloadButton } from "./Buttons/DownloadButton";
|
import { ContactMenu } from "../Form/ContactMenu";
|
||||||
import { buttonTransparentStyles } from "./Buttons/buttonStyle";
|
import { Tooltip } from "../Form/Tooltip";
|
||||||
import { Mention } from "./Chat/ChatMessageContent";
|
import { CheckSvg } from "../Icons/CheckIcon";
|
||||||
import { Logo } from "./CommunityIdentity";
|
import { ClearSvg } from "../Icons/ClearIcon";
|
||||||
import { ContactMenu } from "./Form/ContactMenu";
|
import { CommunityIcon } from "../Icons/CommunityIcon";
|
||||||
import { Tooltip } from "./Form/Tooltip";
|
import { GroupIcon } from "../Icons/GroupIcon";
|
||||||
import { CheckSvg } from "./Icons/CheckIcon";
|
import { Icon } from "../Icons/Icon";
|
||||||
import { ClearSvg } from "./Icons/ClearIcon";
|
import { MoreIcon } from "../Icons/MoreIcon";
|
||||||
import { CommunityIcon } from "./Icons/CommunityIcon";
|
import { ReadMessageIcon } from "../Icons/ReadMessageIcon";
|
||||||
import { GroupIcon } from "./Icons/GroupIcon";
|
import { ReplyIcon } from "../Icons/ReplyActivityIcon";
|
||||||
import { HideIcon } from "./Icons/HideIcon";
|
import { UntrustworthIcon } from "../Icons/UntrustworthIcon";
|
||||||
import { Icon } from "./Icons/Icon";
|
import { UserIcon } from "../Icons/UserIcon";
|
||||||
import { MoreIcon } from "./Icons/MoreIcon";
|
|
||||||
import { ReadIcon } from "./Icons/ReadIcon";
|
|
||||||
import { ReadMessageIcon } from "./Icons/ReadMessageIcon";
|
|
||||||
import { ReplyIcon } from "./Icons/ReplyActivityIcon";
|
|
||||||
import { ShowIcon } from "./Icons/ShowIcon";
|
|
||||||
import { UntrustworthIcon } from "./Icons/UntrustworthIcon";
|
|
||||||
import { UserIcon } from "./Icons/UserIcon";
|
|
||||||
import {
|
import {
|
||||||
ContentWrapper,
|
ContentWrapper,
|
||||||
DateSeparator,
|
DateSeparator,
|
||||||
|
@ -37,9 +30,11 @@ import {
|
||||||
UserAddress,
|
UserAddress,
|
||||||
UserName,
|
UserName,
|
||||||
UserNameWrapper,
|
UserNameWrapper,
|
||||||
} from "./Messages/Styles";
|
} from "../Messages/Styles";
|
||||||
import { ProfileModalName } from "./Modals/ProfileModal";
|
import { ProfileModalName } from "../Modals/ProfileModal";
|
||||||
import { textMediumStyles, textSmallStyles } from "./Text";
|
import { textMediumStyles, textSmallStyles } from "../Text";
|
||||||
|
|
||||||
|
import { ActivityBtn, FlexDiv } from "./ActivityCenter";
|
||||||
|
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
|
|
||||||
|
@ -48,7 +43,7 @@ type ActivityMessageProps = {
|
||||||
setShowActivityCenter: (val: boolean) => void;
|
setShowActivityCenter: (val: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function ActivityMessage({
|
export function ActivityMessage({
|
||||||
activity,
|
activity,
|
||||||
setShowActivityCenter,
|
setShowActivityCenter,
|
||||||
}: ActivityMessageProps) {
|
}: ActivityMessageProps) {
|
||||||
|
@ -258,121 +253,11 @@ function ActivityMessage({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ActivityCenterProps {
|
|
||||||
setShowActivityCenter: (val: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ActivityCenter({ setShowActivityCenter }: ActivityCenterProps) {
|
|
||||||
const { activities } = useActivities();
|
|
||||||
const { contacts } = useMessengerContext();
|
|
||||||
|
|
||||||
const ref = useRef(null);
|
|
||||||
useClickOutside(ref, () => setShowActivityCenter(false));
|
|
||||||
|
|
||||||
const shownActivities = useMemo(
|
|
||||||
() =>
|
|
||||||
activities.filter(
|
|
||||||
(activity) => !contacts?.[activity.user]?.blocked ?? true
|
|
||||||
),
|
|
||||||
[contacts, activities, activities.length]
|
|
||||||
);
|
|
||||||
|
|
||||||
const [hideRead, setHideRead] = useState(false);
|
|
||||||
|
|
||||||
const [filter, setFilter] = useState("");
|
|
||||||
|
|
||||||
const filteredActivities = shownActivities.filter((activity) =>
|
|
||||||
filter
|
|
||||||
? activity.type === filter
|
|
||||||
: hideRead
|
|
||||||
? activity.isRead !== true
|
|
||||||
: activity
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ActivityBlock ref={ref}>
|
|
||||||
<ActivityFilter>
|
|
||||||
<FlexDiv>
|
|
||||||
<FilterBtn onClick={() => setFilter("")}>All</FilterBtn>
|
|
||||||
<FilterBtn onClick={() => setFilter("mention")}>Mentions</FilterBtn>
|
|
||||||
<FilterBtn onClick={() => setFilter("reply")}>Replies</FilterBtn>
|
|
||||||
<FilterBtn onClick={() => setFilter("request")}>
|
|
||||||
Contact requests
|
|
||||||
</FilterBtn>
|
|
||||||
</FlexDiv>
|
|
||||||
<Btns>
|
|
||||||
<BtnWrapper>
|
|
||||||
<ActivityBtn
|
|
||||||
onClick={() => {
|
|
||||||
shownActivities.map((activity) => (activity.isRead = true));
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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}
|
|
||||||
setShowActivityCenter={setShowActivityCenter}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Activities>
|
|
||||||
) : (
|
|
||||||
<EmptyActivities>Notifications will appear here</EmptyActivities>
|
|
||||||
)}
|
|
||||||
</ActivityBlock>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ActivityBlock = styled.div`
|
|
||||||
width: 600px;
|
|
||||||
height: 770px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: ${({ theme }) => theme.bodyBackgroundColor};
|
|
||||||
box-shadow: 0px 12px 24px rgba(0, 34, 51, 0.1);
|
|
||||||
border-radius: 8px;
|
|
||||||
position: absolute;
|
|
||||||
top: 48px;
|
|
||||||
right: 8px;
|
|
||||||
z-index: 100;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ActivityFilter = styled.div`
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 13px 16px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const FlexDiv = styled.div`
|
|
||||||
display: flex;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const InviteDiv = styled.div`
|
const InviteDiv = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: -4px;
|
margin-top: -4px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const FilterBtn = styled.button`
|
|
||||||
${buttonTransparentStyles}
|
|
||||||
|
|
||||||
& + & {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const BtnWrapper = styled.div`
|
const BtnWrapper = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@ -381,58 +266,6 @@ const BtnWrapper = styled.div`
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ActivityBtn = 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};
|
|
||||||
}
|
|
||||||
|
|
||||||
&.read {
|
|
||||||
&:hover {
|
|
||||||
background: ${({ theme }) => theme.bodyBackgroundColor};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.accept {
|
|
||||||
&:hover {
|
|
||||||
background: rgba(78, 188, 96, 0.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.decline {
|
|
||||||
&:hover {
|
|
||||||
background: rgba(255, 45, 85, 0.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& + & {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const Activities = styled.div`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
overflow: auto;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const EmptyActivities = styled.div`
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
flex: 1;
|
|
||||||
width: 100%;
|
|
||||||
color: ${({ theme }) => theme.secondary};
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ActivityDate = styled(DateSeparator)`
|
const ActivityDate = styled(DateSeparator)`
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
|
@ -513,10 +346,6 @@ const ActivityUserName = styled(UserName)`
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
const Btns = styled.div`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const ReplyWrapper = styled.div`
|
const ReplyWrapper = styled.div`
|
||||||
max-width: 100%;
|
max-width: 100%;
|
|
@ -0,0 +1,31 @@
|
||||||
|
import React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
import { LeftIconSvg } from "../Icons/LeftIcon";
|
||||||
|
|
||||||
|
interface BackButtonProps {
|
||||||
|
onBtnClick: () => void;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BackButton({ onBtnClick, className }: BackButtonProps) {
|
||||||
|
return (
|
||||||
|
<BackBtn onClick={onBtnClick} className={className}>
|
||||||
|
<LeftIconSvg width={24} height={24} className="black" />
|
||||||
|
</BackBtn>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BackBtn = styled.button`
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 8px;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
&.narrow {
|
||||||
|
position: static;
|
||||||
|
margin-right: 13px;
|
||||||
|
}
|
||||||
|
`;
|
|
@ -5,7 +5,10 @@ import styled from "styled-components";
|
||||||
import { ChatState, useChatState } from "../../contexts/chatStateProvider";
|
import { ChatState, useChatState } from "../../contexts/chatStateProvider";
|
||||||
import { useIdentity } from "../../contexts/identityProvider";
|
import { useIdentity } from "../../contexts/identityProvider";
|
||||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||||
|
import { useNarrow } from "../../contexts/narrowProvider";
|
||||||
import { ChannelData } from "../../models/ChannelData";
|
import { ChannelData } from "../../models/ChannelData";
|
||||||
|
import { ActivityButton } from "../ActivityCenter/ActivityButton";
|
||||||
|
import { BackButton } from "../Buttons/BackButton";
|
||||||
import { buttonStyles } from "../Buttons/buttonStyle";
|
import { buttonStyles } from "../Buttons/buttonStyle";
|
||||||
import { CrossIcon } from "../Icons/CrossIcon";
|
import { CrossIcon } from "../Icons/CrossIcon";
|
||||||
import { Member } from "../Members/Member";
|
import { Member } from "../Members/Member";
|
||||||
|
@ -20,6 +23,7 @@ export function ChatCreation({
|
||||||
setEditGroup,
|
setEditGroup,
|
||||||
activeChannel,
|
activeChannel,
|
||||||
}: ChatCreationProps) {
|
}: ChatCreationProps) {
|
||||||
|
const narrow = useNarrow();
|
||||||
const identity = useIdentity();
|
const identity = useIdentity();
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
const [styledGroup, setStyledGroup] = useState<string[]>(
|
const [styledGroup, setStyledGroup] = useState<string[]>(
|
||||||
|
@ -76,6 +80,12 @@ export function ChatCreation({
|
||||||
return (
|
return (
|
||||||
<CreationWrapper>
|
<CreationWrapper>
|
||||||
<CreationBar>
|
<CreationBar>
|
||||||
|
{narrow && (
|
||||||
|
<BackButton
|
||||||
|
onBtnClick={() => setChatState(ChatState.ChatBody)}
|
||||||
|
className="narrow"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<InputBar>
|
<InputBar>
|
||||||
<InputText>To:</InputText>
|
<InputText>To:</InputText>
|
||||||
<StyledList>
|
<StyledList>
|
||||||
|
@ -118,6 +128,7 @@ export function ChatCreation({
|
||||||
>
|
>
|
||||||
Confirm
|
Confirm
|
||||||
</CreationBtn>
|
</CreationBtn>
|
||||||
|
{!narrow && <ActivityButton className="creation" />}
|
||||||
</CreationBar>
|
</CreationBar>
|
||||||
{!setEditGroup && !query && (
|
{!setEditGroup && !query && (
|
||||||
<Contacts>
|
<Contacts>
|
||||||
|
@ -155,6 +166,7 @@ const CreationWrapper = styled.div`
|
||||||
|
|
||||||
const CreationBar = styled.div`
|
const CreationBar = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
margin-bottom: 32px;
|
margin-bottom: 32px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -167,6 +179,7 @@ const InputBar = styled.div`
|
||||||
border: 1px solid ${({ theme }) => theme.inputColor};
|
border: 1px solid ${({ theme }) => theme.inputColor};
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
|
margin-right: 16px;
|
||||||
|
|
||||||
${textMediumStyles}
|
${textMediumStyles}
|
||||||
`;
|
`;
|
||||||
|
@ -193,7 +206,6 @@ const InputText = styled.div`
|
||||||
|
|
||||||
const CreationBtn = styled.button`
|
const CreationBtn = styled.button`
|
||||||
padding: 11px 24px;
|
padding: 11px 24px;
|
||||||
margin-left: 16px;
|
|
||||||
${buttonStyles}
|
${buttonStyles}
|
||||||
|
|
||||||
&:disabled {
|
&:disabled {
|
||||||
|
|
|
@ -411,6 +411,14 @@ const AddPictureInputWrapper = styled.div`
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
|
|
||||||
|
& > input[type="file"]::-webkit-file-upload-button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > input:disabled::-webkit-file-upload-button {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AddPictureInput = styled.input`
|
const AddPictureInput = styled.input`
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useState } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { useActivities } from "../../contexts/activityProvider";
|
|
||||||
import { useIdentity } from "../../contexts/identityProvider";
|
|
||||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||||
import { useNarrow } from "../../contexts/narrowProvider";
|
import { useNarrow } from "../../contexts/narrowProvider";
|
||||||
import { ActivityCenter } from "../ActivityCenter";
|
import {
|
||||||
|
ActivityButton,
|
||||||
|
ActivityWrapper,
|
||||||
|
} from "../ActivityCenter/ActivityButton";
|
||||||
import { Channel } from "../Channels/Channel";
|
import { Channel } from "../Channels/Channel";
|
||||||
import { Community } from "../Community";
|
import { Community } from "../Community";
|
||||||
import { ChannelMenu } from "../Form/ChannelMenu";
|
import { ChannelMenu } from "../Form/ChannelMenu";
|
||||||
|
@ -63,12 +64,9 @@ export function ChatTopbar({
|
||||||
setEditGroup,
|
setEditGroup,
|
||||||
}: ChatTopbarProps) {
|
}: ChatTopbarProps) {
|
||||||
const { messenger, activeChannel, communityData } = useMessengerContext();
|
const { messenger, activeChannel, communityData } = useMessengerContext();
|
||||||
const { activities } = useActivities();
|
|
||||||
const narrow = useNarrow();
|
const narrow = useNarrow();
|
||||||
const [showChannelMenu, setShowChannelMenu] = useState(false);
|
const [showChannelMenu, setShowChannelMenu] = useState(false);
|
||||||
const [showActivityCenter, setShowActivityCenter] = useState(false);
|
|
||||||
const identity = useIdentity();
|
|
||||||
const disabled = useMemo(() => !identity, [identity]);
|
|
||||||
|
|
||||||
if (!activeChannel) {
|
if (!activeChannel) {
|
||||||
return <ChatTopbarLoading />;
|
return <ChatTopbarLoading />;
|
||||||
|
@ -110,27 +108,7 @@ export function ChatTopbar({
|
||||||
<TopBtn onClick={() => setShowChannelMenu(!showChannelMenu)}>
|
<TopBtn onClick={() => setShowChannelMenu(!showChannelMenu)}>
|
||||||
<MoreIcon />
|
<MoreIcon />
|
||||||
</TopBtn>
|
</TopBtn>
|
||||||
<ActivityWrapper>
|
{!narrow && <ActivityButton />}
|
||||||
<TopBtn
|
|
||||||
onClick={() => setShowActivityCenter(!showActivityCenter)}
|
|
||||||
disabled={disabled}
|
|
||||||
>
|
|
||||||
<ActivityIcon />
|
|
||||||
{activities.length > 0 && (
|
|
||||||
<NotificationBagde
|
|
||||||
className={
|
|
||||||
activities.length > 99
|
|
||||||
? "countless"
|
|
||||||
: activities.length > 9
|
|
||||||
? "wide"
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{activities.length < 100 ? activities.length : "∞"}
|
|
||||||
</NotificationBagde>
|
|
||||||
)}
|
|
||||||
</TopBtn>
|
|
||||||
</ActivityWrapper>
|
|
||||||
</MenuWrapper>
|
</MenuWrapper>
|
||||||
{!messenger && !communityData && <Loading />}
|
{!messenger && !communityData && <Loading />}
|
||||||
{showChannelMenu && (
|
{showChannelMenu && (
|
||||||
|
@ -141,9 +119,6 @@ export function ChatTopbar({
|
||||||
setEditGroup={setEditGroup}
|
setEditGroup={setEditGroup}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showActivityCenter && (
|
|
||||||
<ActivityCenter setShowActivityCenter={setShowActivityCenter} />
|
|
||||||
)}
|
|
||||||
</Topbar>
|
</Topbar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -203,30 +178,12 @@ const MenuWrapper = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const ActivityWrapper = styled.div`
|
|
||||||
padding-left: 10px;
|
|
||||||
margin-left: 10px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 50%;
|
|
||||||
width: 2px;
|
|
||||||
height: 24px;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
border-radius: 1px;
|
|
||||||
background: ${({ theme }) => theme.primary};
|
|
||||||
opacity: 0.1;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const TopBtn = styled.button`
|
export const TopBtn = styled.button`
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: ${({ theme }) => theme.inputColor};
|
background: ${({ theme }) => theme.inputColor};
|
||||||
|
@ -240,31 +197,3 @@ export const TopBtn = styled.button`
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const NotificationBagde = styled.div`
|
|
||||||
width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
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};
|
|
||||||
border-radius: 9px;
|
|
||||||
|
|
||||||
&.wide {
|
|
||||||
width: 26px;
|
|
||||||
right: -7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.countless {
|
|
||||||
width: 22px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
|
@ -9,29 +9,22 @@ type LeftIconSvgProps = {
|
||||||
|
|
||||||
export function LeftIconSvg({ width, height, className }: LeftIconSvgProps) {
|
export function LeftIconSvg({ width, height, className }: LeftIconSvgProps) {
|
||||||
return (
|
return (
|
||||||
<svg
|
<Icon
|
||||||
width={width}
|
width={width}
|
||||||
height={height}
|
height={height}
|
||||||
viewBox="0 0 16 16"
|
viewBox="0 0 16 16"
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
className={className}
|
className={className}
|
||||||
>
|
>
|
||||||
<path d="M7.01957 4.35355C7.21483 4.15829 7.21483 3.84171 7.01957 3.64645C6.82431 3.45118 6.50772 3.45118 6.31246 3.64645L2.31246 7.64645C2.1172 7.84171 2.1172 8.15829 2.31246 8.35355L6.31246 12.3536C6.50772 12.5488 6.82431 12.5488 7.01957 12.3536C7.21483 12.1583 7.21483 11.8417 7.01957 11.6464L4.44216 9.06904C4.23217 8.85905 4.38089 8.5 4.67786 8.5H13.3327C13.6088 8.5 13.8327 8.27614 13.8327 8C13.8327 7.72386 13.6088 7.5 13.3327 7.5H4.67786C4.38089 7.5 4.23217 7.14095 4.44216 6.93096L7.01957 4.35355Z" />
|
<path d="M7.01957 4.35355C7.21483 4.15829 7.21483 3.84171 7.01957 3.64645C6.82431 3.45118 6.50772 3.45118 6.31246 3.64645L2.31246 7.64645C2.1172 7.84171 2.1172 8.15829 2.31246 8.35355L6.31246 12.3536C6.50772 12.5488 6.82431 12.5488 7.01957 12.3536C7.21483 12.1583 7.21483 11.8417 7.01957 11.6464L4.44216 9.06904C4.23217 8.85905 4.38089 8.5 4.67786 8.5H13.3327C13.6088 8.5 13.8327 8.27614 13.8327 8C13.8327 7.72386 13.6088 7.5 13.3327 7.5H4.67786C4.38089 7.5 4.23217 7.14095 4.44216 6.93096L7.01957 4.35355Z" />
|
||||||
</svg>
|
</Icon>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LeftIconIcon = () => {
|
const Icon = styled.svg`
|
||||||
return <Icon width={16} height={16} />;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Icon = styled(LeftIconSvg)`
|
|
||||||
& > path {
|
|
||||||
fill: ${({ theme }) => theme.tertiary};
|
fill: ${({ theme }) => theme.tertiary};
|
||||||
}
|
|
||||||
|
|
||||||
&:hover > path {
|
&.black {
|
||||||
fill: ${({ theme }) => theme.bodyBackgroundColor};
|
fill: ${({ theme }) => theme.primary};
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -137,7 +137,11 @@ export const MemberIcon = styled(Icon)`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Column = styled.div`
|
const Column = styled.div`
|
||||||
|
width: calc(100% - 69px);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
import { Channels } from "../Channels/Channels";
|
import { Channels } from "../Channels/Channels";
|
||||||
|
|
||||||
import { NarrowTopbar } from "./NarrowTopbar";
|
import { ListWrapper, NarrowTopbar } from "./NarrowTopbar";
|
||||||
|
|
||||||
interface NarrowChannelsProps {
|
interface NarrowChannelsProps {
|
||||||
setShowChannels: (val: boolean) => void;
|
setShowChannels: (val: boolean) => void;
|
||||||
|
@ -12,14 +11,8 @@ interface NarrowChannelsProps {
|
||||||
export function NarrowChannels({ setShowChannels }: NarrowChannelsProps) {
|
export function NarrowChannels({ setShowChannels }: NarrowChannelsProps) {
|
||||||
return (
|
return (
|
||||||
<ListWrapper>
|
<ListWrapper>
|
||||||
<NarrowTopbar list="Channels" />
|
<NarrowTopbar list="Channels" onBtnClick={() => setShowChannels(false)} />
|
||||||
<Channels onCommunityClick={() => setShowChannels(false)} />
|
<Channels onCommunityClick={() => setShowChannels(false)} />
|
||||||
</ListWrapper>
|
</ListWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListWrapper = styled.div`
|
|
||||||
padding: 0px 18px 18px;
|
|
||||||
background: ${({ theme }) => theme.bodyBackgroundColor};
|
|
||||||
overflow: auto;
|
|
||||||
`;
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
|
||||||
|
|
||||||
import { MembersList } from "../Members/MembersList";
|
import { MembersList } from "../Members/MembersList";
|
||||||
|
|
||||||
import { NarrowTopbar } from "./NarrowTopbar";
|
import { ListWrapper, NarrowTopbar } from "./NarrowTopbar";
|
||||||
|
|
||||||
interface NarrowMembersProps {
|
interface NarrowMembersProps {
|
||||||
switchShowMembersList: () => void;
|
switchShowMembersList: () => void;
|
||||||
|
@ -12,14 +11,11 @@ interface NarrowMembersProps {
|
||||||
export function NarrowMembers({ switchShowMembersList }: NarrowMembersProps) {
|
export function NarrowMembers({ switchShowMembersList }: NarrowMembersProps) {
|
||||||
return (
|
return (
|
||||||
<ListWrapper>
|
<ListWrapper>
|
||||||
<NarrowTopbar list="Community members" />
|
<NarrowTopbar
|
||||||
|
list="Community members"
|
||||||
|
onBtnClick={switchShowMembersList}
|
||||||
|
/>
|
||||||
<MembersList switchShowMembers={switchShowMembersList} />
|
<MembersList switchShowMembers={switchShowMembersList} />
|
||||||
</ListWrapper>
|
</ListWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListWrapper = styled.div`
|
|
||||||
padding: 0px 18px 18px;
|
|
||||||
background: ${({ theme }) => theme.bodyBackgroundColor};
|
|
||||||
overflow: auto;
|
|
||||||
`;
|
|
||||||
|
|
|
@ -2,28 +2,39 @@ import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { useMessengerContext } from "../../contexts/messengerProvider";
|
import { useMessengerContext } from "../../contexts/messengerProvider";
|
||||||
|
import { BackButton } from "../Buttons/BackButton";
|
||||||
|
|
||||||
interface NarrowTopbarProps {
|
interface NarrowTopbarProps {
|
||||||
list: string;
|
list: string;
|
||||||
|
onBtnClick: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NarrowTopbar({ list }: NarrowTopbarProps) {
|
export function NarrowTopbar({ list, onBtnClick }: NarrowTopbarProps) {
|
||||||
const { communityData } = useMessengerContext();
|
const { communityData } = useMessengerContext();
|
||||||
return (
|
return (
|
||||||
<TopbarWrapper>
|
<TopbarWrapper>
|
||||||
|
<BackButton onBtnClick={onBtnClick} />
|
||||||
|
<HeadingWrapper>
|
||||||
<Heading>{list}</Heading>
|
<Heading>{list}</Heading>
|
||||||
<SubHeading>{communityData?.name}</SubHeading>
|
<SubHeading>{communityData?.name}</SubHeading>
|
||||||
|
</HeadingWrapper>
|
||||||
</TopbarWrapper>
|
</TopbarWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TopbarWrapper = styled.div`
|
const TopbarWrapper = styled.div`
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: ${({ theme }) => theme.bodyBackgroundColor};
|
||||||
|
margin-bottom: 16px;
|
||||||
|
position: relative;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const HeadingWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: ${({ theme }) => theme.bodyBackgroundColor};
|
|
||||||
padding: 14px 0;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Heading = styled.p`
|
const Heading = styled.p`
|
||||||
|
@ -35,3 +46,9 @@ const SubHeading = styled.p`
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: ${({ theme }) => theme.secondary};
|
color: ${({ theme }) => theme.secondary};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const ListWrapper = styled.div`
|
||||||
|
padding: 16px;
|
||||||
|
background: ${({ theme }) => theme.bodyBackgroundColor};
|
||||||
|
overflow: auto;
|
||||||
|
`;
|
||||||
|
|
Loading…
Reference in New Issue